123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575 |
- /**
- * 假数据生成器主逻辑
- * 使用Vue.js构建交互式界面
- */
- new Vue({
- el: '#pageContainer',
- data: {
- // 当前激活的标签页
- activeTab: 'personal',
-
- // 选中的字段
- selectedFields: {
- // 个人信息
- name: false,
- email: false,
- phone: false,
- idCard: false,
- gender: false,
- age: false,
- birthday: false,
- address: false,
-
- // 商业数据
- company: false,
- department: false,
- position: false,
- salary: false,
- bankCard: false,
- creditCard: false,
- price: false,
- currency: false,
-
- // 技术数据
- uuid: false,
- ip: false,
- mac: false,
- userAgent: false,
- url: false,
- domain: false,
- password: false,
- token: false,
- color: false,
- timestamp: false,
- filename: false,
- mimeType: false
- },
-
- // 自定义字段
- customField: {
- name: '',
- type: 'string',
- rule: ''
- },
- customFields: [],
-
- // 生成配置
- generateCount: 10,
- outputFormat: 'json',
-
- // 生成的数据
- generatedData: '',
- dataSize: '0 B',
-
- // 数据生成器实例
- generator: null,
-
- // 预设模板
- templates: {
- user: {
- name: '用户信息模板',
- fields: ['name', 'email', 'phone', 'gender', 'age', 'address']
- },
- employee: {
- name: '员工信息模板',
- fields: ['name', 'email', 'phone', 'company', 'department', 'position', 'salary']
- },
- product: {
- name: '商品信息模板',
- fields: ['name', 'price', 'currency', 'uuid', 'timestamp']
- },
- order: {
- name: '订单信息模板',
- fields: ['uuid', 'name', 'email', 'phone', 'address', 'price', 'timestamp']
- },
- api: {
- name: 'API测试数据模板',
- fields: ['uuid', 'token', 'ip', 'userAgent', 'timestamp', 'boolean']
- }
- }
- },
-
- mounted() {
- // 初始化数据生成器
- this.generator = new FakeDataGenerator();
-
- // 检查URL参数,如果有模板参数则自动加载
- const urlParams = new URLSearchParams(window.location.search);
- const template = urlParams.get('template');
- if (template && this.templates[template]) {
- this.loadTemplate(template);
- }
- this.loadPatchHotfix();
- },
-
- methods: {
- /**
- * 添加自定义字段
- */
- addCustomField() {
- if (!this.customField.name.trim()) {
- alert('请输入字段名称');
- return;
- }
-
- // 检查字段名是否已存在
- const exists = this.customFields.some(field => field.name === this.customField.name);
- if (exists) {
- alert('字段名已存在');
- return;
- }
-
- this.customFields.push({
- name: this.customField.name,
- type: this.customField.type,
- rule: this.customField.rule
- });
-
- // 重置输入框
- this.customField = {
- name: '',
- type: 'string',
- rule: ''
- };
- },
-
- /**
- * 删除自定义字段
- */
- removeCustomField(index) {
- this.customFields.splice(index, 1);
- },
-
- /**
- * 全选当前标签页的字段
- */
- selectAll() {
- const fieldGroups = {
- personal: ['name', 'email', 'phone', 'idCard', 'gender', 'age', 'birthday', 'address'],
- business: ['company', 'department', 'position', 'salary', 'bankCard', 'creditCard', 'price', 'currency'],
- technical: ['uuid', 'ip', 'mac', 'userAgent', 'url', 'domain', 'password', 'token', 'color', 'timestamp', 'filename', 'mimeType']
- };
-
- const fields = fieldGroups[this.activeTab] || [];
- fields.forEach(field => {
- this.selectedFields[field] = true;
- });
- },
-
- /**
- * 清空所有选择
- */
- clearAll() {
- Object.keys(this.selectedFields).forEach(key => {
- this.selectedFields[key] = false;
- });
- this.customFields = [];
- this.generatedData = '';
- this.dataSize = '0 B';
- },
-
- /**
- * 生成假数据
- */
- generateData() {
- const selectedFieldKeys = Object.keys(this.selectedFields).filter(key => this.selectedFields[key]);
-
- // 检查是否选择了字段
- if (selectedFieldKeys.length === 0 && this.customFields.length === 0) {
- alert('请至少选择一个字段');
- return;
- }
-
- // 生成数据
- const data = [];
- for (let i = 0; i < this.generateCount; i++) {
- const item = {};
-
- // 生成预定义字段
- selectedFieldKeys.forEach(field => {
- item[field] = this.generator.generateByType(field);
- });
-
- // 生成自定义字段
- this.customFields.forEach(field => {
- item[field.name] = this.generateCustomFieldData(field);
- });
-
- data.push(item);
- }
-
- // 格式化输出
- this.formatOutput(data);
- },
-
- /**
- * 生成自定义字段数据
- */
- generateCustomFieldData(field) {
- switch (field.type) {
- case 'string':
- return this.generator.randomString(this.generator.randomInt(5, 20));
- case 'number':
- return this.generator.randomInt(1, 1000);
- case 'boolean':
- return this.generator.generateBoolean();
- case 'date':
- return this.generator.generateDate();
- case 'array':
- const arrayLength = this.generator.randomInt(1, 5);
- const array = [];
- for (let i = 0; i < arrayLength; i++) {
- array.push(this.generator.randomString(5));
- }
- return array;
- default:
- return this.generator.randomString(10);
- }
- },
-
- /**
- * 格式化输出数据
- */
- formatOutput(data) {
- switch (this.outputFormat) {
- case 'json':
- this.generatedData = JSON.stringify(data, null, 2);
- break;
- case 'csv':
- this.generatedData = this.convertToCSV(data);
- break;
- case 'sql':
- this.generatedData = this.convertToSQL(data);
- break;
- case 'xml':
- this.generatedData = this.convertToXML(data);
- break;
- default:
- this.generatedData = JSON.stringify(data, null, 2);
- }
-
- // 计算数据大小
- this.dataSize = this.calculateSize(this.generatedData);
- },
-
- /**
- * 转换为CSV格式
- */
- convertToCSV(data) {
- if (data.length === 0) return '';
-
- const headers = Object.keys(data[0]);
- const csvContent = [
- headers.join(','),
- ...data.map(row =>
- headers.map(header => {
- const value = row[header];
- // 处理包含逗号或引号的值
- if (typeof value === 'string' && (value.includes(',') || value.includes('"'))) {
- return `"${value.replace(/"/g, '""')}"`;
- }
- return value;
- }).join(',')
- )
- ].join('\n');
-
- return csvContent;
- },
-
- /**
- * 转换为SQL INSERT语句
- */
- convertToSQL(data) {
- if (data.length === 0) return '';
-
- const tableName = 'fake_data';
- const headers = Object.keys(data[0]);
-
- let sql = `-- 表结构\nCREATE TABLE ${tableName} (\n`;
- sql += headers.map(header => ` ${header} VARCHAR(255)`).join(',\n');
- sql += '\n);\n\n-- 数据插入\n';
-
- data.forEach(row => {
- const values = headers.map(header => {
- const value = row[header];
- if (typeof value === 'string') {
- return `'${value.replace(/'/g, "''")}'`;
- }
- return value;
- }).join(', ');
-
- sql += `INSERT INTO ${tableName} (${headers.join(', ')}) VALUES (${values});\n`;
- });
-
- return sql;
- },
-
- /**
- * 转换为XML格式
- */
- convertToXML(data) {
- if (data.length === 0) return '';
-
- let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<data>\n';
-
- data.forEach((item, index) => {
- xml += ` <item id="${index + 1}">\n`;
- Object.keys(item).forEach(key => {
- const value = item[key];
- xml += ` <${key}>${this.escapeXML(value)}</${key}>\n`;
- });
- xml += ' </item>\n';
- });
-
- xml += '</data>';
- return xml;
- },
-
- /**
- * XML字符转义
- */
- escapeXML(value) {
- if (typeof value !== 'string') {
- value = String(value);
- }
- return value
- .replace(/&/g, '&')
- .replace(/</g, '<')
- .replace(/>/g, '>')
- .replace(/"/g, '"')
- .replace(/'/g, ''');
- },
-
- /**
- * 计算数据大小
- */
- calculateSize(data) {
- const bytes = new Blob([data]).size;
- const sizes = ['B', 'KB', 'MB', 'GB'];
-
- if (bytes === 0) return '0 B';
-
- const i = Math.floor(Math.log(bytes) / Math.log(1024));
- const size = (bytes / Math.pow(1024, i)).toFixed(2);
-
- return `${size} ${sizes[i]}`;
- },
-
- /**
- * 复制结果到剪贴板
- */
- async copyResult() {
- if (!this.generatedData) {
- alert('没有可复制的数据');
- return;
- }
-
- try {
- await navigator.clipboard.writeText(this.generatedData);
- this.showMessage('数据已复制到剪贴板', 'success');
- } catch (err) {
- console.error('复制失败:', err);
- // 备用方法
- this.fallbackCopyText(this.generatedData);
- }
- },
-
- /**
- * 备用复制方法
- */
- fallbackCopyText(text) {
- const textArea = document.createElement('textarea');
- textArea.value = text;
- textArea.style.position = 'fixed';
- textArea.style.left = '-999999px';
- textArea.style.top = '-999999px';
- document.body.appendChild(textArea);
- textArea.focus();
- textArea.select();
-
- try {
- document.execCommand('copy');
- this.showMessage('数据已复制到剪贴板', 'success');
- } catch (err) {
- this.showMessage('复制失败,请手动选择复制', 'error');
- }
-
- document.body.removeChild(textArea);
- },
-
- /**
- * 下载数据文件
- */
- downloadData() {
- if (!this.generatedData) {
- alert('没有可下载的数据');
- return;
- }
-
- const extensions = {
- json: 'json',
- csv: 'csv',
- sql: 'sql',
- xml: 'xml'
- };
-
- const mimeTypes = {
- json: 'application/json',
- csv: 'text/csv',
- sql: 'application/sql',
- xml: 'application/xml'
- };
-
- const extension = extensions[this.outputFormat] || 'txt';
- const mimeType = mimeTypes[this.outputFormat] || 'text/plain';
-
- const blob = new Blob([this.generatedData], { type: mimeType });
- const url = URL.createObjectURL(blob);
-
- const link = document.createElement('a');
- link.href = url;
- link.download = `fake-data-${Date.now()}.${extension}`;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
-
- URL.revokeObjectURL(url);
- this.showMessage('文件下载已开始', 'success');
- },
-
- /**
- * 加载预设模板
- */
- loadTemplate(templateKey) {
- const template = this.templates[templateKey];
- if (!template) return;
-
- // 清空当前选择
- this.clearAll();
-
- // 选择模板字段
- template.fields.forEach(field => {
- if (this.selectedFields.hasOwnProperty(field)) {
- this.selectedFields[field] = true;
- }
- });
-
- // 切换到相应的标签页
- if (template.fields.some(field => ['name', 'email', 'phone', 'idCard', 'gender', 'age', 'birthday', 'address'].includes(field))) {
- this.activeTab = 'personal';
- } else if (template.fields.some(field => ['company', 'department', 'position', 'salary', 'bankCard', 'creditCard', 'price', 'currency'].includes(field))) {
- this.activeTab = 'business';
- } else {
- this.activeTab = 'technical';
- }
-
- // 自动生成数据
- this.$nextTick(() => {
- this.generateData();
- });
-
- this.showMessage(`已加载 ${template.name} 并生成数据`, 'success');
- },
-
- // 打开工具市场页面
- openOptionsPage: function(event){
- event.preventDefault();
- event.stopPropagation();
- chrome.runtime.openOptionsPage();
- },
- openDonateModal: function(event){
- event.preventDefault();
- event.stopPropagation();
- chrome.runtime.sendMessage({
- type: 'fh-dynamic-any-thing',
- thing: 'open-donate-modal',
- params: { toolName: 'mock-data' }
- });
- },
- /**
- * 显示消息提示
- */
- showMessage(message, type = 'info') {
- // 创建消息元素
- const messageEl = document.createElement('div');
- messageEl.className = `${type}-message`;
- messageEl.textContent = message;
- messageEl.style.position = 'fixed';
- messageEl.style.top = '20px';
- messageEl.style.right = '20px';
- messageEl.style.zIndex = '9999';
- messageEl.style.padding = '10px 15px';
- messageEl.style.borderRadius = '4px';
- messageEl.style.fontSize = '14px';
- messageEl.style.fontWeight = '500';
- messageEl.style.boxShadow = '0 2px 12px rgba(0, 0, 0, 0.15)';
-
- // 设置样式
- if (type === 'success') {
- messageEl.style.background = '#d4edda';
- messageEl.style.color = '#155724';
- messageEl.style.border = '1px solid #c3e6cb';
- } else if (type === 'error') {
- messageEl.style.background = '#f8d7da';
- messageEl.style.color = '#721c24';
- messageEl.style.border = '1px solid #f5c6cb';
- } else {
- messageEl.style.background = '#d1ecf1';
- messageEl.style.color = '#0c5460';
- messageEl.style.border = '1px solid #bee5eb';
- }
-
- document.body.appendChild(messageEl);
-
- // 3秒后自动移除
- setTimeout(() => {
- if (messageEl.parentNode) {
- messageEl.parentNode.removeChild(messageEl);
- }
- }, 3000);
- },
- loadPatchHotfix() {
- // 页面加载时自动获取并注入页面的补丁
- chrome.runtime.sendMessage({
- type: 'fh-dynamic-any-thing',
- thing: 'fh-get-tool-patch',
- toolName: 'mock-data'
- }, patch => {
- if (patch) {
- if (patch.css) {
- const style = document.createElement('style');
- style.textContent = patch.css;
- document.head.appendChild(style);
- }
- if (patch.js) {
- try {
- if (window.evalCore && window.evalCore.getEvalInstance) {
- window.evalCore.getEvalInstance(window)(patch.js);
- }
- } catch (e) {
- console.error('mock-data补丁JS执行失败', e);
- }
- }
- }
- });
- },
- },
-
- watch: {
- // 监听生成数量变化,限制范围
- generateCount(newVal) {
- if (newVal < 1) {
- this.generateCount = 1;
- } else if (newVal > 1000) {
- this.generateCount = 1000;
- }
- }
- }
- });
|