Ver código fonte

excel转json工具支持单列模式,也支持转SQL

zxlie 4 meses atrás
pai
commit
4978f00d6d
3 arquivos alterados com 186 adições e 11 exclusões
  1. 52 4
      apps/excel2json/index.css
  2. 4 1
      apps/excel2json/index.html
  3. 130 6
      apps/excel2json/index.js

+ 52 - 4
apps/excel2json/index.css

@@ -401,10 +401,14 @@ body {
 }
 .input-ops-row {
     display: flex;
-    align-items: center;
-    gap: 18px;
     flex-wrap: wrap;
-    width: 100%;
+    gap: 10px;
+    align-items: center;
+    position: relative;
+}
+.input-ops-row .btn,
+.input-ops-row .convert-btn {
+    margin-right: 0;
 }
 .input-label {
     white-space: nowrap;
@@ -428,9 +432,14 @@ body {
     margin-right: 4px;
 }
 .convert-btn {
-    margin-left: auto;
     min-width: 140px;
 }
+.btn-group {
+    float: right;
+}
+.btn-group .btn {
+    margin-right: 10px;
+}
 .error-msg {
     color: #e74c3c;
     margin-left: 0;
@@ -568,4 +577,43 @@ body {
     color: #f00;
 }
 
+/* SQL按钮大气时尚样式 */
+#convertSqlBtn {
+    background: linear-gradient(90deg, #ff9800 0%, #ff5722 100%);
+    color: #fff;
+    border: none;
+    border-radius: 8px;
+    font-weight: bold;
+    box-shadow: 0 4px 16px rgba(255,152,0,0.10), 0 1.5px 4px rgba(0,0,0,0.08);
+    padding: 8px 22px;
+    font-size: 16px;
+    letter-spacing: 1px;
+    transition: all 0.18s cubic-bezier(.4,0,.2,1);
+    outline: none;
+    position: relative;
+}
+#convertSqlBtn:hover, #convertSqlBtn:focus {
+    background: linear-gradient(90deg, #ff5722 0%, #ff9800 100%);
+    color: #fff;
+    box-shadow: 0 6px 24px rgba(255,87,34,0.18), 0 2px 8px rgba(0,0,0,0.10);
+    transform: translateY(-2px) scale(1.04);
+}
+#convertSqlBtn:active {
+    transform: scale(0.98);
+    box-shadow: 0 2px 8px rgba(255,152,0,0.10);
+}
+
+/* 适配深色模式 */
+@media (prefers-color-scheme: dark) {
+    #convertSqlBtn {
+        background: linear-gradient(90deg, #ffb74d 0%, #ff7043 100%);
+        color: #222;
+        box-shadow: 0 4px 16px rgba(255,183,77,0.10), 0 1.5px 4px rgba(0,0,0,0.18);
+    }
+    #convertSqlBtn:hover, #convertSqlBtn:focus {
+        background: linear-gradient(90deg, #ff7043 0%, #ffb74d 100%);
+        color: #222;
+    }
+}
+
 

+ 4 - 1
apps/excel2json/index.html

@@ -32,7 +32,6 @@
                                 <a href="#" class="link-btn" data-example="simple">示例:简单表格</a>
                                 <a href="#" class="link-btn" data-example="user">示例:用户信息</a>
                                 <a href="#" class="link-btn" data-example="score">示例:成绩单</a>
-                                <button id="convertBtn" class="btn btn-primary convert-btn"><i class="fas fa-sync-alt"></i> 转换为 JSON</button>
                             </div>
                             <span id="errorMsg" class="error-msg"></span>
                         </div>
@@ -42,6 +41,10 @@
                     <div class="output-zone">
                         <div class="output-header output-header-block">
                             <button id="copyBtn" class="btn btn-outline copy-btn"><i class="fas fa-copy"></i> 复制</button>
+                            <span class="btn-group">
+                                <button id="convertBtn" class="btn btn-primary convert-btn"><i class="fas fa-sync-alt"></i> 转换为 JSON</button>
+                                <button id="convertSqlBtn" class="btn btn-warning convert-btn"><i class="fas fa-database"></i> 转换为SQL Insert</button>
+                            </span>
                         </div>
                         <textarea id="jsonOutput" readonly rows="18" class="output-textarea"></textarea>
                     </div>

+ 130 - 6
apps/excel2json/index.js

@@ -20,6 +20,14 @@ function showError(msg) {
     errorMsg.textContent = msg;
 }
 
+// 自动识别数字类型
+function parseValue(val) {
+    if (/^-?\d+(\.\d+)?$/.test(val)) {
+        return Number(val);
+    }
+    return val;
+}
+
 // 解析CSV文本为JSON
 function csvToJson(csv) {
     const lines = csv.split(/\r?\n/).filter(line => line.trim() !== '');
@@ -29,7 +37,22 @@ function csvToJson(csv) {
         const values = line.split(',');
         const obj = {};
         headers.forEach((h, i) => {
-            obj[h.trim()] = (values[i] || '').trim();
+            obj[h.trim()] = parseValue((values[i] || '').trim());
+        });
+        return obj;
+    });
+}
+
+// 解析TSV文本为JSON
+function tsvToJson(tsv) {
+    const lines = tsv.split(/\r?\n/).filter(line => line.trim() !== '');
+    if (lines.length < 2) return [];
+    const headers = lines[0].split('\t');
+    return lines.slice(1).map(line => {
+        const values = line.split('\t');
+        const obj = {};
+        headers.forEach((h, i) => {
+            obj[h.trim()] = parseValue((values[i] || '').trim());
         });
         return obj;
     });
@@ -89,16 +112,42 @@ convertBtn.addEventListener('click', function () {
         showError('请上传文件或粘贴表格数据!');
         return;
     }
-    // 判断是否为CSV格式
-    if (text.includes(',') && text.includes('\n')) {
+    // 优先判断是否为TSV格式(多列Tab分隔)
+    if (text.includes('\t') && text.includes('\n')) {
+        try {
+            const json = tsvToJson(text);
+            jsonOutput.value = JSON.stringify(json, null, 2);
+        } catch (err) {
+            showError('粘贴内容(TSV)解析失败,请检查格式!');
+        }
+    } else if (text.includes(',') && text.includes('\n')) {
+        // CSV格式
         try {
             const json = csvToJson(text);
             jsonOutput.value = JSON.stringify(json, null, 2);
         } catch (err) {
-            showError('粘贴内容解析失败,请检查格式!');
+            showError('粘贴内容(CSV)解析失败,请检查格式!');
+        }
+    } else if (!text.includes(',') && !text.includes('\t') && text.includes('\n')) {
+        // 处理单列多行的情况
+        try {
+            const lines = text.split(/\r?\n/).filter(line => line.trim() !== '');
+            if (lines.length < 2) {
+                showError('内容格式不正确,至少需要表头和一行数据!');
+                return;
+            }
+            const header = lines[0].trim();
+            const json = lines.slice(1).map(line => {
+                const obj = {};
+                obj[header] = parseValue(line.trim());
+                return obj;
+            });
+            jsonOutput.value = JSON.stringify(json, null, 2);
+        } catch (err) {
+            showError('单列内容解析失败,请检查格式!');
         }
     } else {
-        showError('仅支持CSV格式的粘贴内容!');
+        showError('仅支持CSV、TSV或单列表格的粘贴内容!');
     }
 });
 
@@ -109,7 +158,7 @@ const EXAMPLES = {
     score: `学号,姓名,数学,语文,英语\n1001,王小明,90,88,92\n1002,李小红,85,91,87\n1003,张大伟,78,80,85`
 };
 
-// 绑定“选择文件”a标签点击事件,触发文件选择
+// 绑定"选择文件"a标签点击事件,触发文件选择
 const fileSelectLink = document.querySelector('.btn-file-input');
 if (fileSelectLink) {
     fileSelectLink.addEventListener('click', function(e) {
@@ -185,4 +234,79 @@ if (toolMarketBtn) {
         e.stopPropagation();
         chrome.runtime.openOptionsPage();
     });
+}
+
+// SQL Insert语句生成函数
+function jsonToSqlInsert(jsonArr, tableName = 'my_table') {
+    if (!Array.isArray(jsonArr) || jsonArr.length === 0) return '';
+    const keys = Object.keys(jsonArr[0]);
+    // 多行合并为一条Insert
+    const values = jsonArr.map(row =>
+        '(' + keys.map(k => {
+            const v = row[k];
+            if (typeof v === 'number') {
+                return v;
+            } else {
+                return `'${String(v).replace(/'/g, "''")}'`;
+            }
+        }).join(', ') + ')'
+    ).join(',\n');
+    return `INSERT INTO ${tableName} (${keys.join(', ')}) VALUES\n${values};`;
+}
+
+// 绑定SQL转换按钮
+const convertSqlBtn = document.getElementById('convertSqlBtn');
+if (convertSqlBtn) {
+    convertSqlBtn.addEventListener('click', function () {
+        clearError();
+        const text = pasteInput.value.trim();
+        if (!text) {
+            showError('请上传文件或粘贴表格数据!');
+            return;
+        }
+        let json = [];
+        // 优先TSV
+        if (text.includes('\t') && text.includes('\n')) {
+            try {
+                json = tsvToJson(text);
+            } catch (err) {
+                showError('粘贴内容(TSV)解析失败,请检查格式!');
+                return;
+            }
+        } else if (text.includes(',') && text.includes('\n')) {
+            try {
+                json = csvToJson(text);
+            } catch (err) {
+                showError('粘贴内容(CSV)解析失败,请检查格式!');
+                return;
+            }
+        } else if (!text.includes(',') && !text.includes('\t') && text.includes('\n')) {
+            try {
+                const lines = text.split(/\r?\n/).filter(line => line.trim() !== '');
+                if (lines.length < 2) {
+                    showError('内容格式不正确,至少需要表头和一行数据!');
+                    return;
+                }
+                const header = lines[0].trim();
+                json = lines.slice(1).map(line => {
+                    const obj = {};
+                    obj[header] = parseValue(line.trim());
+                    return obj;
+                });
+            } catch (err) {
+                showError('单列内容解析失败,请检查格式!');
+                return;
+            }
+        } else {
+            showError('仅支持CSV、TSV或单列表格的粘贴内容!');
+            return;
+        }
+        if (!json.length) {
+            showError('没有可用数据生成SQL!');
+            return;
+        }
+        // 默认表名my_table,可后续扩展让用户自定义
+        const sql = jsonToSqlInsert(json, 'your_table_name');
+        jsonOutput.value = sql;
+    });
 }