فهرست منبع

升级excel 2 json工具

zxlie 4 ماه پیش
والد
کامیت
9a2f0abe0c
7فایلهای تغییر یافته به همراه782 افزوده شده و 1433 حذف شده
  1. 0 286
      apps/excel2json/CSVParser.js
  2. 0 538
      apps/excel2json/DataGridRenderer.js
  3. 0 190
      apps/excel2json/converter.js
  4. 518 90
      apps/excel2json/index.css
  5. 41 68
      apps/excel2json/index.html
  6. 176 119
      apps/excel2json/index.js
  7. 47 142
      website/docs/excel2json.md

+ 0 - 286
apps/excel2json/CSVParser.js

@@ -1,286 +0,0 @@
-//
-//  CSVParser.js
-//  Mr-Data-Converter
-//
-//  Input CSV or Tab-delimited data and this will parse it into a Data Grid Javascript object
-//
-//  CSV Parsing Function from Ben Nadel, http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm
-
-
-var isDecimal_re     = /^\s*(\+|-)?((\d+([,\.]\d+)?)|([,\.]\d+))\s*$/;
-
-var CSVParser = {
-
-  //---------------------------------------
-  // UTILS
-  //---------------------------------------
-
-  isNumber: function(string) {
-    if( (string == null) || isNaN( new Number(string) ) ) {
-      return false;
-    }
-    return true;
-  },
-
-
-  //---------------------------------------
-  // PARSE
-  //---------------------------------------
-  //var parseOutput = CSVParser.parse(this.inputText, this.headersProvided, this.delimiter, this.downcaseHeaders, this.upcaseHeaders);
-
-  parse: function (input, headersIncluded, delimiterType, downcaseHeaders, upcaseHeaders, decimalSign) {
-
-    var dataArray = [];
-
-    var errors = [];
-
-    //test for delimiter
-    //count the number of commas
-    var RE = new RegExp("[^,]", "gi");
-    var numCommas = input.replace(RE, "").length;
-
-    //count the number of tabs
-    RE = new RegExp("[^\t]", "gi");
-    var numTabs = input.replace(RE, "").length;
-
-    var rowDelimiter = "\n";
-    //set delimiter
-    var columnDelimiter = ",";
-    if (numTabs > numCommas) {
-      columnDelimiter = "\t"
-    };
-
-    if (delimiterType === "comma") {
-      columnDelimiter = ","
-    } else if (delimiterType === "tab") {
-      columnDelimiter = "\t"
-    }
-
-
-    // kill extra empty lines
-    RE = new RegExp("^" + rowDelimiter + "+", "gi");
-    input = input.replace(RE, "");
-    RE = new RegExp(rowDelimiter + "+$", "gi");
-    input = input.replace(RE, "");
-
-    // var arr = input.split(rowDelimiter);
-    //
-    // for (var i=0; i < arr.length; i++) {
-    //   dataArray.push(arr[i].split(columnDelimiter));
-    // };
-
-
-    // dataArray = jQuery.csv(columnDelimiter)(input);
-    dataArray = this.CSVToArray(input, columnDelimiter);
-
-    //escape out any tabs or returns or new lines
-    for (var i = dataArray.length - 1; i >= 0; i--){
-      for (var j = dataArray[i].length - 1; j >= 0; j--){
-        dataArray[i][j] = dataArray[i][j].replace("\t", "\\t");
-        dataArray[i][j] = dataArray[i][j].replace("\n", "\\n");
-        dataArray[i][j] = dataArray[i][j].replace("\r", "\\r");
-      };
-    };
-
-
-    var headerNames = [];
-    var headerTypes = [];
-    var numColumns = dataArray[0].length;
-    var numRows = dataArray.length;
-    if (headersIncluded) {
-
-      //remove header row
-      headerNames = dataArray.splice(0,1)[0];
-      numRows = dataArray.length;
-
-    } else { //if no headerNames provided
-
-      //create generic property names
-      for (var i=0; i < numColumns; i++) {
-        headerNames.push("val"+String(i));
-        headerTypes.push("");
-      };
-
-    }
-
-
-    if (upcaseHeaders) {
-      for (var i = headerNames.length - 1; i >= 0; i--){
-        headerNames[i] = headerNames[i].toUpperCase();
-      };
-    };
-    if (downcaseHeaders) {
-      for (var i = headerNames.length - 1; i >= 0; i--){
-        headerNames[i] = headerNames[i].toLowerCase();
-      };
-    };
-
-    //test all the rows for proper number of columns.
-    for (var i=0; i < dataArray.length; i++) {
-      var numValues = dataArray[i].length;
-      if (numValues != numColumns) {this.log("Error parsing row "+String(i)+". Wrong number of columns.")};
-    };
-
-    //test columns for number data type
-    var numRowsToTest = dataArray.length;
-    var threshold = 0.9;
-    for (var i=0; i < headerNames.length; i++) {
-      var numFloats = 0;
-      var numInts = 0;
-      for (var r=0; r < numRowsToTest; r++) {
-        if (dataArray[r]) {
-          //replace comma with dot if comma is decimal separator
-          if(decimalSign='comma' && isDecimal_re.test(dataArray[r][i])){
-            dataArray[r][i] = dataArray[r][i].replace(",", ".");
-          }
-          if (CSVParser.isNumber(dataArray[r][i])) {
-            numInts++
-            if (String(dataArray[r][i]).indexOf(".") > 0) {
-              numFloats++
-            }
-          };
-        };
-
-      };
-
-      if ((numInts / numRowsToTest) > threshold){
-        if (numFloats > 0) {
-          headerTypes[i] = "float"
-        } else {
-          headerTypes[i] = "int"
-        }
-      } else {
-        headerTypes[i] = "string"
-      }
-    }
-
-
-
-
-
-    return {'dataGrid':dataArray, 'headerNames':headerNames, 'headerTypes':headerTypes, 'errors':this.getLog()}
-
-  },
-
-
-  //---------------------------------------
-  // ERROR LOGGING
-  //---------------------------------------
-  errorLog:[],
-
-  resetLog: function() {
-    this.errorLog = [];
-  },
-
-  log: function(l) {
-    this.errorLog.push(l);
-  },
-
-  getLog: function() {
-    var out = "";
-    if (this.errorLog.length > 0) {
-      for (var i=0; i < this.errorLog.length; i++) {
-        out += ("!!"+this.errorLog[i] + "!!\n");
-      };
-      out += "\n"
-    };
-
-    return out;
-  },
-
-
-
-  //---------------------------------------
-  // UTIL
-  //---------------------------------------
-
-    // This Function from Ben Nadel, http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm
-    // This will parse a delimited string into an array of
-    // arrays. The default delimiter is the comma, but this
-    // can be overriden in the second argument.
-    CSVToArray: function( strData, strDelimiter ){
-      // Check to see if the delimiter is defined. If not,
-      // then default to comma.
-      strDelimiter = (strDelimiter || ",");
-
-      // Create a regular expression to parse the CSV values.
-      var objPattern = new RegExp(
-        (
-          // Delimiters.
-          "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
-
-          // Quoted fields.
-          "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
-
-          // Standard fields.
-          "([^\"\\" + strDelimiter + "\\r\\n]*))"
-        ),
-        "gi"
-        );
-
-
-      // Create an array to hold our data. Give the array
-      // a default empty first row.
-      var arrData = [[]];
-
-      // Create an array to hold our individual pattern
-      // matching groups.
-      var arrMatches = null;
-
-
-      // Keep looping over the regular expression matches
-      // until we can no longer find a match.
-      while (arrMatches = objPattern.exec( strData )){
-
-        // Get the delimiter that was found.
-        var strMatchedDelimiter = arrMatches[ 1 ];
-
-        // Check to see if the given delimiter has a length
-        // (is not the start of string) and if it matches
-        // field delimiter. If id does not, then we know
-        // that this delimiter is a row delimiter.
-        if (
-          strMatchedDelimiter.length &&
-          (strMatchedDelimiter != strDelimiter)
-          ){
-
-          // Since we have reached a new row of data,
-          // add an empty row to our data array.
-          arrData.push( [] );
-
-        }
-
-
-        // Now that we have our delimiter out of the way,
-        // let's check to see which kind of value we
-        // captured (quoted or unquoted).
-
-        if (arrMatches[ 2 ]){
-
-          // We found a quoted value. When we capture
-          // this value, unescape any double quotes.
-          var strMatchedValue = arrMatches[ 2 ].replace(
-            new RegExp( "\"\"", "g" ),
-            "\""
-            );
-
-        } else {
-
-          // We found a non-quoted value.
-          var strMatchedValue = arrMatches[ 3 ];
-
-        }
-
-
-        // Now that we have our value string, let's add
-        // it to the data array.
-        arrData[ arrData.length - 1 ].push( strMatchedValue );
-      }
-
-      // Return the parsed data.
-      return( arrData );
-    }
-
-
-
-}

+ 0 - 538
apps/excel2json/DataGridRenderer.js

@@ -1,538 +0,0 @@
-// 
-//  DataGridRenderer.js
-//  Part of Mr-Data-Converter
-//  
-//  Created by Shan Carter on 2010-10-18.
-// 
-
-
-var DataGridRenderer = {
-  
-  //---------------------------------------
-  // Actionscript
-  //---------------------------------------
-  
-  as: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "//";
-    var commentLineEnd = "";
-    var outputText = "[";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    
-    //begin render loops
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      outputText += "{";
-      for (var j=0; j < numColumns; j++) {
-        if ((headerTypes[j] == "int")||(headerTypes[j] == "float")) {
-          var rowOutput = row[j] || "null";
-        } else {
-          var rowOutput = '"'+( row[j] || "" )+'"';
-        };      
-        outputText += (headerNames[j] + ":" + rowOutput)
-        if (j < (numColumns-1)) {outputText+=","};
-      };
-      outputText += "}";
-      if (i < (numRows-1)) {outputText += ","+newLine};
-    };
-    outputText += "];";
-    
-    
-    return outputText;
-  },
-  
-  
-  //---------------------------------------
-  // ASP / VBScript
-  //---------------------------------------
-  
-  asp: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "'";
-    var commentLineEnd = "";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    
-    //begin render loop
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      for (var j=0; j < numColumns; j++) {
-        if ((headerTypes[j] == "int")||(headerTypes[j] == "float")) {
-          var rowOutput = row[j] || "null";
-        } else {
-          var rowOutput = '"'+( row[j] || "" )+'"';
-        };
-      outputText += 'myArray('+j+','+i+') = '+rowOutput+newLine;        
-      };
-    };
-    outputText = 'Dim myArray('+(j-1)+','+(i-1)+')'+newLine+outputText;
-    
-    return outputText;
-  },
-  
-  
-  //---------------------------------------
-  // HTML Table
-  //---------------------------------------
-  
-  html: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "<!--";
-    var commentLineEnd = "-->";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    
-    //begin render loop
-    outputText += "<table>"+newLine;
-    outputText += indent+"<thead>"+newLine;
-    outputText += indent+indent+"<tr>"+newLine;
-    
-    for (var j=0; j < numColumns; j++) {
-      outputText += indent+indent+indent+'<th class="'+headerNames[j]+'-cell">';          
-      outputText += headerNames[j];
-      outputText += '</th>'+newLine;
-    };
-    outputText += indent+indent+"</tr>"+newLine;
-    outputText += indent+"</thead>"+newLine;
-    outputText += indent+"<tbody>"+newLine;
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      var rowClassName = ""
-      if (i === numRows-1) {
-        rowClassName = ' class="lastRow"';
-      } else if (i === 0){
-        rowClassName = ' class="firstRow"';
-      }
-      outputText += indent+indent+"<tr"+rowClassName+">"+newLine;
-      for (var j=0; j < numColumns; j++) {
-        outputText += indent+indent+indent+'<td class="'+headerNames[j]+'-cell">';          
-        outputText += row[j]
-        outputText += '</td>'+newLine
-      };
-      outputText += indent+indent+"</tr>"+newLine;
-    };
-    outputText += indent+"</tbody>"+newLine;
-    outputText += "</table>";
-    
-    return outputText;
-  },
-  
-  
-  //---------------------------------------
-  // JSON properties
-  //---------------------------------------
-  
-  json: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "//";
-    var commentLineEnd = "";
-    var outputText = "[";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    
-    //begin render loop
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      outputText += "{";
-      for (var j=0; j < numColumns; j++) {
-        if ((headerTypes[j] == "int")||(headerTypes[j] == "float")) {
-          var rowOutput = row[j] || "null";
-        } else {
-          var rowOutput = '"' + ( row[j] || "" ) + '"';
-        };
-  
-      outputText += ('"'+headerNames[j] +'"' + ":" + rowOutput );
-  
-        if (j < (numColumns-1)) {outputText+=","};
-      };
-      outputText += "}";
-      if (i < (numRows-1)) {outputText += ","+newLine};
-    };
-    outputText += "]";
-    
-    return outputText;
-  },
-  
-  //---------------------------------------
-  // JSON Array of Columns
-  //---------------------------------------
-  jsonArrayCols: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "//";
-    var commentLineEnd = "";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    
-    //begin render loop
-    outputText += "{"+newLine;
-    for (var i=0; i < numColumns; i++) {
-      outputText += indent+'"'+headerNames[i]+'":[';
-      for (var j=0; j < numRows; j++) {
-        if ((headerTypes[i] == "int")||(headerTypes[i] == "float")) {
-          outputText += dataGrid[j][i] || 0;
-        } else {
-          outputText += '"'+(dataGrid[j][i] || "")+'"' ;
-        }
-        if (j < (numRows-1)) {outputText+=","};
-      };
-      outputText += "]";
-      if (i < (numColumns-1)) {outputText += ","+newLine};
-    };
-    outputText += newLine+"}";
-    
-    
-    return outputText;
-  },
-  
-  
-  //---------------------------------------
-  // JSON Array of Rows
-  //---------------------------------------
-  jsonArrayRows: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "//";
-    var commentLineEnd = "";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    
-    //begin render loop
-    outputText += "["+newLine;
-    for (var i=0; i < numRows; i++) {
-      outputText += indent+"[";
-      for (var j=0; j < numColumns; j++) {
-        if ((headerTypes[j] == "int")||(headerTypes[j] == "float")) {
-          outputText += dataGrid[i][j] || 0;
-        } else {
-          outputText += '"'+(dataGrid[i][j] || "")+'"' ;
-        }
-        if (j < (numColumns-1)) {outputText+=","};
-      };
-      outputText += "]";
-      if (i < (numRows-1)) {outputText += ","+newLine};
-    };
-    outputText += newLine+"]";
-    
-    
-    return outputText;
-  },
-  
-  
-
-  //---------------------------------------
-  // JSON Dictionary
-  //---------------------------------------
-  jsonDict: function(dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "//";
-    var commentLineEnd = "";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-
-    //begin render loop
-    outputText += "{" + newLine;
-    for (var i = 0; i < numRows; i++) {
-      outputText += indent + '"' + dataGrid[i][0] + '": ';
-      if (numColumns == 2) {
-        outputText += _fmtVal(i, 1, dataGrid);
-      } else {
-        outputText += '{ ';
-        for (var j = 1; j < numColumns; j++) {
-          if (j > 1) outputText += ', ';
-          outputText += '"' + headerNames[j] + '"' + ":" + _fmtVal(i, j, dataGrid);
-        }
-        outputText += '}';
-      }
-      if (i < (numRows - 1)) {
-        outputText += "," + newLine;
-      }
-    }
-    outputText += newLine + "}";
-
-    function _fmtVal(i, j) {
-      if ((headerTypes[j] == "int")||(headerTypes[j] == "float")) {
-        return dataGrid[i][j] || 0;
-      } else {
-        return '"'+(dataGrid[i][j] || "")+'"' ;
-      }
-    }
-
-    return outputText;
-  },
-
-
-  //---------------------------------------
-  // MYSQL
-  //---------------------------------------
-  mysql: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "/*";
-    var commentLineEnd = "*/";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    var tableName = "MrDataConverter"
-    
-    //begin render loop
-    outputText += 'CREATE TABLE '+tableName+' (' + newLine;
-    outputText += indent+"id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,"+newLine;
-    for (var j=0; j < numColumns; j++) {
-      var dataType = "VARCHAR(255)";
-      if ((headerTypes[j] == "int")||(headerTypes[j] == "float")) {
-        dataType = headerTypes[j].toUpperCase();
-      };
-      outputText += indent+""+headerNames[j]+" "+dataType;
-      if (j < numColumns - 1) {outputText += ","};
-      outputText += newLine;
-    };
-    outputText += ');' + newLine;
-    outputText += "INSERT INTO "+tableName+" "+newLine+indent+"(";
-    for (var j=0; j < numColumns; j++) {
-      outputText += headerNames[j];
-      if (j < numColumns - 1) {outputText += ","};
-    };
-    outputText += ") "+newLine+"VALUES "+newLine;
-    for (var i=0; i < numRows; i++) {
-      outputText += indent+"(";
-      for (var j=0; j < numColumns; j++) {
-        if ((headerTypes[j] == "int")||(headerTypes[j] == "float"))  {
-          outputText += dataGrid[i][j] || "null";
-        } else {
-          outputText += "'"+( dataGrid[i][j] || "" )+"'";
-        };
-        
-        if (j < numColumns - 1) {outputText += ","};
-      };
-      outputText += ")";
-      if (i < numRows - 1) {outputText += ","+newLine;};
-    };
-    outputText += ";";
-    
-    return outputText;
-  },
-  
-  
-  //---------------------------------------
-  // PHP
-  //---------------------------------------
-  php: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "//";
-    var commentLineEnd = "";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    var tableName = "MrDataConverter"
-    
-    //begin render loop
-    outputText += "array(" + newLine;
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      outputText += indent + "array(";
-      for (var j=0; j < numColumns; j++) {
-        if ((headerTypes[j] == "int")||(headerTypes[j] == "float"))  {
-          var rowOutput = row[j] || "null";
-        } else {
-          var rowOutput = '"'+(row[j] || "")+'"';
-        };          
-        outputText += ('"'+headerNames[j]+'"' + "=>" + rowOutput)
-        if (j < (numColumns-1)) {outputText+=","};
-      };
-      outputText += ")";
-      if (i < (numRows-1)) {outputText += ","+newLine};
-    };
-    outputText += newLine + ");";
-    
-    return outputText;
-  },
-  
-  //---------------------------------------
-  // Python dict
-  //---------------------------------------
-  
-  python: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "//";
-    var commentLineEnd = "";
-    var outputText = "[";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    
-    //begin render loop
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      outputText += "{";
-      for (var j=0; j < numColumns; j++) {
-        if ((headerTypes[j] == "int")||(headerTypes[j] == "float")) {
-          var rowOutput = row[j] || "None";
-        } else {
-          var rowOutput = '"'+(row[j] || "")+'"';
-        };
-  
-      outputText += ('"'+headerNames[j] +'"' + ":" + rowOutput );
-  
-        if (j < (numColumns-1)) {outputText+=","};
-      };
-      outputText += "}";
-      if (i < (numRows-1)) {outputText += ","+newLine};
-    };
-    outputText += "];";
-    
-    return outputText;
-  },
-  
-  
-  //---------------------------------------
-  // Ruby
-  //---------------------------------------
-  ruby: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "#";
-    var commentLineEnd = "";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    var tableName = "MrDataConverter"
-    
-    //begin render loop
-    outputText += "[";
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      outputText += "{";
-      for (var j=0; j < numColumns; j++) {
-        if ((headerTypes[j] == "int")||(headerTypes[j] == "float")) {
-          var rowOutput = row[j] || "nil"
-        } else {
-          var rowOutput = '"'+(row[j] || "")+'"';
-        };         
-        outputText += ('"'+headerNames[j]+'"' + "=>" + rowOutput)
-        if (j < (numColumns-1)) {outputText+=","};
-      };
-      outputText += "}";
-      if (i < (numRows-1)) {outputText += ","+newLine};
-    };
-    outputText += "];";
-    
-    return outputText;
-  },
-  
-  
-  //---------------------------------------
-  // XML Nodes
-  //---------------------------------------
-  xml: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "<!--";
-    var commentLineEnd = "-->";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    
-    //begin render loop
-    outputText = '<?xml version="1.0" encoding="UTF-8"?>' + newLine;
-    outputText += "<rows>"+newLine;
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      outputText += indent+"<row>"+newLine;
-      for (var j=0; j < numColumns; j++) {
-        outputText += indent+indent+'<'+headerNames[j]+'>';          
-        outputText += row[j] || ""
-        outputText += '</'+headerNames[j]+'>'+newLine
-      };
-      outputText += indent+"</row>"+newLine;
-    };
-    outputText += "</rows>";
-    
-    return outputText;
-    
-  },
-  
-  
-  
-  //---------------------------------------
-  // XML properties
-  //---------------------------------------
-  xmlProperties: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "<!--";
-    var commentLineEnd = "-->";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-  
-    //begin render loop
-    outputText = '<?xml version="1.0" encoding="UTF-8"?>' + newLine;
-    outputText += "<rows>"+newLine;
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      outputText += indent+"<row ";
-      for (var j=0; j < numColumns; j++) {
-        outputText += headerNames[j]+'=';          
-        outputText += '"' + row[j] + '" ';
-      };
-      outputText += "></row>"+newLine;
-    };
-    outputText += "</rows>";
-    
-    return outputText;
-    
-  },
-  
-  //---------------------------------------
-  // XML Illustrator
-  //---------------------------------------
-  xmlIllustrator: function (dataGrid, headerNames, headerTypes, indent, newLine) {
-    //inits...
-    var commentLine = "<!--";
-    var commentLineEnd = "-->";
-    var outputText = "";
-    var numRows = dataGrid.length;
-    var numColumns = headerNames.length;
-    
-    //begin render loop
-    outputText = '<?xml version="1.0" encoding="utf-8"?>' + newLine;
-    outputText += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"    "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd" [' + newLine;
-    outputText += indent+'<!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">' + newLine;
-    outputText += indent+'<!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">' + newLine;
-    outputText += indent+'<!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">' + newLine;
-    outputText += indent+'<!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">' + newLine;
-    outputText += indent+'<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">' + newLine;
-    outputText += indent+'<!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">' + newLine;
-    outputText += ']>' + newLine;
-    outputText += '<svg>' + newLine;
-    outputText += '<variableSets  xmlns="&ns_vars;">' + newLine;
-    outputText += indent+'<variableSet  varSetName="binding1" locked="none">' + newLine;
-    outputText += indent+indent+'<variables>' + newLine;
-    for (var i=0; i < numColumns; i++) {
-      outputText += indent+indent+indent+'<variable varName="'+headerNames[i]+'" trait="textcontent" category="&ns_flows;"></variable>' + newLine;
-    };
-    outputText += indent+indent+'</variables>' + newLine;
-    outputText += indent+indent+'<v:sampleDataSets  xmlns:v="http://ns.adobe.com/Variables/1.0/" xmlns="http://ns.adobe.com/GenericCustomNamespace/1.0/">' + newLine;
-    
-    for (var i=0; i < numRows; i++) {
-      var row = dataGrid[i];
-      outputText += indent+indent+indent+'<v:sampleDataSet dataSetName="' + row[0] + '">'+newLine;
-      for (var j=0; j < numColumns; j++) {
-        outputText += indent+indent+indent+indent+'<'+headerNames[j]+'>'+newLine;          
-        outputText += indent+indent+indent+indent+indent+'<p>' + row[j] + '</p>' +newLine;
-        outputText += indent+indent+indent+indent+'</'+headerNames[j]+'>'+newLine
-      };
-      outputText += indent+indent+indent+'</v:sampleDataSet>'+newLine;
-    };
-    
-    outputText += indent+indent+'</v:sampleDataSets>' + newLine;
-    outputText += indent+'</variableSet>' + newLine;
-    outputText += '</variableSets>' + newLine;
-    outputText += '</svg>' + newLine;
-    
-    
-    return outputText;
-    
-  },
-  
-}

+ 0 - 190
apps/excel2json/converter.js

@@ -1,190 +0,0 @@
-//
-//  converter.js
-//  Mr-Data-Converter
-//
-//  Created by Shan Carter on 2010-09-01.
-//
-
-
-
-function DataConverter(nodeId) {
-
-  //---------------------------------------
-  // PUBLIC PROPERTIES
-  //---------------------------------------
-
-  this.nodeId                 = nodeId;
-  this.node                   = $("#"+nodeId);
-
-  this.outputDataTypes        = [
-                                {"text":"Actionscript",           "id":"as",               "notes":""},
-                                {"text":"ASP/VBScript",           "id":"asp",              "notes":""},
-                                {"text":"HTML",                   "id":"html",             "notes":""},
-                                {"text":"JSON - Properties",      "id":"json",             "notes":""},
-                                {"text":"JSON - Column Arrays",   "id":"jsonArrayCols",    "notes":""},
-                                {"text":"JSON - Row Arrays",      "id":"jsonArrayRows",    "notes":""},
-                                {"text":"JSON - Dictionary",      "id":"jsonDict",         "notes":""},
-                                {"text":"MySQL",                  "id":"mysql",            "notes":""},
-                                {"text":"PHP",                    "id":"php",              "notes":""},
-                                {"text":"Python - Dict",          "id":"python",           "notes":""},
-                                {"text":"Ruby",                   "id":"ruby",             "notes":""},
-                                {"text":"XML - Properties",       "id":"xmlProperties",    "notes":""},
-                                {"text":"XML - Nodes",            "id":"xml",              "notes":""},
-                                {"text":"XML - Illustrator",      "id":"xmlIllustrator",   "notes":""}];
-  this.outputDataType         = "json";
-
-  this.columnDelimiter        = "\t";
-  this.rowDelimiter           = "\n";
-
-  this.inputTextArea          = {};
-  this.outputTextArea         = {};
-
-  this.inputHeader            = {};
-  this.outputHeader           = {};
-  this.dataSelect             = {};
-
-  this.inputText              = "";
-  this.outputText             = "";
-
-  this.newLine                = "\n";
-  this.indent                 = "  ";
-
-  this.root                   = "rows";
-  this.child                  = "row";
-
-  this.commentLine            = "//";
-  this.commentLineEnd         = "";
-  this.tableName              = "MrDataConverter"
-
-  this.useUnderscores         = true;
-  this.headersProvided        = true;
-  this.downcaseHeaders        = true;
-  this.upcaseHeaders          = false;
-  this.includeWhiteSpace      = true;
-  this.useTabsForIndent       = false;
-
-}
-
-//---------------------------------------
-// PUBLIC METHODS
-//---------------------------------------
-
-DataConverter.prototype.create = function(w,h) {
-  var self = this;
-
-  //build HTML for converter
-  this.inputHeader = $('<div class="groupHeader" id="inputHeader"><p class="groupHeadline">数据源输入<span class="subhead">(可以直接从Excel/CVS中拷贝内容到这里! <a href="#" id="insertSample">简单示例!</a>)</span></p></div>');
-  this.inputTextArea = $('<textarea class="textInputs" id="dataInput" placeholder="输入CVS或者以tab为间隔的数据"></textarea>');
-  var outputHeaderText = '<div class="groupHeader" id="outputHeader"><p class="groupHeadline">结果转换为<select name="Data Types" id="dataSelector" class="form-control">';
-    for (var i=0; i < this.outputDataTypes.length; i++) {
-
-      outputHeaderText += '<option value="'+this.outputDataTypes[i]["id"]+'" '
-              + (this.outputDataTypes[i]["id"] == this.outputDataType ? 'selected="selected"' : '')
-              + '>'
-              + this.outputDataTypes[i]["text"]+'</option>';
-    };
-    outputHeaderText += '</select><span class="subhead" id="outputNotes"></span></p></div>';
-  this.outputHeader = $(outputHeaderText);
-  this.outputTextArea = $('<textarea class="textInputs" id="dataOutput" placeholder="转换后的结果会显示在这里"></textarea>');
-
-  this.node.append(this.inputHeader);
-  this.node.append(this.inputTextArea);
-  this.node.append(this.outputHeader);
-  this.node.append(this.outputTextArea);
-
-  this.dataSelect = this.outputHeader.find("#dataSelector");
-
-
-  //add event listeners
-
-  // $("#convertButton").bind('click',function(evt){
-  //   evt.preventDefault();
-  //   self.convert();
-  // });
-
-  this.outputTextArea.click(function(evt){this.select();});
-
-
-  $("#insertSample").bind('click',function(evt){
-    evt.preventDefault();
-    self.insertSampleData();
-    self.convert();
-    _gaq.push(['_trackEvent', 'SampleData','InsertGeneric']);
-  });
-
-  $("#dataInput").keyup(function() {self.convert()});
-  $("#dataInput").change(function() {
-    self.convert();
-    _gaq.push(['_trackEvent', 'DataType',self.outputDataType]);
-  });
-
-  $("#dataSelector").bind('change',function(evt){
-       self.outputDataType = $(this).val();
-       self.convert();
-     });
-
-  this.resize(w,h);
-}
-
-DataConverter.prototype.resize = function(w,h) {
-
-  var paneWidth = w;
-  var paneHeight = (h-90)/2-20;
-
-  this.node.css({width:paneWidth});
-  this.inputTextArea.css({width:paneWidth-20,height:paneHeight});
-  this.outputTextArea.css({width: paneWidth-20, height:paneHeight});
-
-}
-
-DataConverter.prototype.convert = function() {
-
-  this.inputText = this.inputTextArea.val();
-  this.outputText = "";
-
-
-  //make sure there is input data before converting...
-  if (this.inputText.length > 0) {
-
-    if (this.includeWhiteSpace) {
-      this.newLine = "\n";
-    } else {
-      this.indent = "";
-      this.newLine = "";
-    }
-
-    CSVParser.resetLog();
-    var parseOutput = CSVParser.parse(this.inputText, this.headersProvided, this.delimiter, this.downcaseHeaders, this.upcaseHeaders);
-
-    var dataGrid = parseOutput.dataGrid;
-    var headerNames = parseOutput.headerNames;
-    var headerTypes = parseOutput.headerTypes;
-    var errors = parseOutput.errors;
-
-    this.outputText = DataGridRenderer[this.outputDataType](dataGrid, headerNames, headerTypes, this.indent, this.newLine);
-
-
-    //验证成功,将会对其中的节点进行替换
-    //否者,直接对数据进行输出
-    if(this.root
-        && this.child
-        && (this.outputDataType === "xmlProperties"
-            || this.outputDataType === "xml")){
-
-      //替换其中的根节点与字节点
-      this.outputText = this.outputText.replace(/rows/g,this.root)
-      this.outputText = this.outputText.replace(/row/g,this.child);
-    }
-    this.outputTextArea.val(errors + this.outputText);
-
-
-
-  }; //end test for existence of input text
-}
-
-
-DataConverter.prototype.insertSampleData = function() {
-  this.inputTextArea.val("NAME\tVALUE\tCOLOR\tDATE\nAlan\t12\tblue\tSep. 25, 2009\nShan\t13\t\"green\tblue\"\tSep. 27, 2009\nJohn\t45\torange\tSep. 29, 2009\nMinna\t27\tteal\tSep. 30, 2009");
-}
-
-

+ 518 - 90
apps/excel2json/index.css

@@ -1,143 +1,571 @@
-@import url("../static/css/bootstrap.min.css");
-
-#pageContainer > .panel-body {
+body {
+    background-color: #f8f9fb;
+    font-family: 'Microsoft YaHei', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
+    margin: 0;
+    padding: 0;
+    color: #2c3e50;
+}
+.wrapper {
     margin: 0 auto;
+    padding: 0;
+    min-height: 100vh;
+    background: #f8f9fb;
+    display: flex;
+    flex-direction: column;
+}
+.main-navbar {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background: #fff;
+    border-bottom: 1px solid #e5e5e5;
+    padding: 12px 30px;
+    box-shadow: 0 2px 10px rgba(0,0,0,0.03);
+}
+.navbar-brand .brand-link {
+    display: flex;
+    align-items: center;
+    text-decoration: none;
+}
+.navbar-brand img {
+    width: 24px;
+    height: 24px;
+    margin-right: 10px;
+}
+.brand-text {
+    font-size: 20px;
+    font-weight: bold;
+    color: #333;
+    margin-right: 10px;
+}
+.brand-subtitle {
+    font-size: 14px;
+    color: #667790;
+    padding-left: 10px;
+    border-left: 1px solid #e0e0e0;
+}
+.navbar-actions {
+    display: flex;
+    align-items: center;
+}
+.nav-item {
+    margin-left: 20px;
+    color: #e74c3c;
+    font-size: 16px;
+    text-decoration: none;
+    cursor: pointer;
+    transition: all 0.2s;
+}
+.nav-item:hover {
+    color: #c0392b;
+}
+.nav-item .nav-icon {
+    font-style: normal;
+    margin-right: 6px;
 }
 
-body {
-    overflow: hidden;
+/* 主容器样式 */
+.main-container {
+    width: 98%;
+    margin: 20px auto;
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
 }
 
-#base {
-    padding: 15px;
-    position: relative;
+/* 工具头部样式 */
+.tool-header {
+    display: flex;
+    align-items: center;
+    padding: 15px 20px;
+    background: linear-gradient(135deg, #3498db, #2980b9);
+    border-radius: 10px;
+    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
+    margin-bottom: 10px;
+    color: white;
+}
+.tool-icon {
+    font-size: 32px;
+    background: rgba(255, 255, 255, 0.2);
+    width: 60px;
+    height: 60px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-right: 20px;
+    box-shadow: 0 0 0 5px rgba(255, 255, 255, 0.1);
+}
+.tool-title {
+    flex-grow: 1;
+}
+.tool-title h1 {
+    margin: 0 0 5px 0;
+    font-size: 24px;
+    font-weight: 600;
+}
+.tool-title p {
+    margin: 0;
+    font-size: 14px;
+    opacity: 0.9;
 }
 
-/*header*/
+/* 面板样式 */
 
-#header {
-    width: 300px;
-    overflow: auto;
+/* 操作区域样式 */
+.operation-zone {
+    margin-bottom: 20px;
+}
+.input-flex-row {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    gap: 10px;
+    flex-wrap: wrap;
+    margin-bottom: 15px;
+}
+.input-flex-row > * {
+    margin-bottom: 0 !important;
+}
+.input-section label {
+    font-weight: 600;
+    color: #2c3e50;
+    display: flex;
+    align-items: center;
+    gap: 6px;
+}
+.input-section label i {
+    color: #3498db;
 }
 
-#header a {
-    color: #99FFFF;
+/* 文件输入样式 */
+.file-input-wrapper {
+    position: relative;
+    overflow: hidden;
+}
+.file-input-wrapper input[type="file"] {
+    padding: 8px 12px;
+    border: 1px solid #d1d9e6;
+    border-radius: 6px;
+    background: #f7fafd;
+    font-size: 14px;
+    color: #2c3e50;
+    transition: all 0.3s;
+    box-shadow: 0 2px 5px rgba(0,0,0,0.02);
+}
+.file-input-wrapper input[type="file"]:hover,
+.file-input-wrapper input[type="file"]:focus {
+    border: 1px solid #3498db;
+    background: #f0f7ff;
+    box-shadow: 0 3px 10px rgba(52, 152, 219, 0.1);
 }
 
-#description p {
-    margin-bottom: 18px;
+/* 示例区域样式 */
+.example-section {
+    display: flex;
+    align-items: center;
+    background: #f6f9fe;
+    border-radius: 6px;
+    padding: 8px 15px;
+    box-shadow: 0 2px 6px rgba(0,0,0,0.03);
+    border-left: 3px solid #3498db;
+}
+.example-section span {
+    color: #667790;
+    display: flex;
+    align-items: center;
+    gap: 6px;
+}
+.example-section span i {
+    color: #f39c12;
+}
+.example-btn {
+    display: inline-block;
+    background: #ecf5fe;
+    color: #3498db;
+    border: 1px solid #c4e1ff;
+    margin-right: 4px;
+    font-size: 13px;
+    border-radius: 5px;
+    padding: 5px 12px;
+    transition: all 0.2s;
+    font-weight: 500;
+    text-decoration: none;
+    cursor: pointer;
+    line-height: 1.6;
+}
+.example-btn:last-child {
+    margin-right: 0;
+}
+.example-btn:hover, .example-btn:focus {
+    background: #d9ebfd;
+    color: #2980b9;
+    border-color: #3498db;
+    transform: translateY(-1px);
+    box-shadow: 0 2px 5px rgba(52, 152, 219, 0.15);
+    text-decoration: none;
 }
 
-#header h3 {
-    font-size: 16px;
-    margin: 15px 0 10px 0;
-    padding: 15px 0 0 0;
-    border-top: solid 1px #CCC;
-    text-transform: uppercase;
+
+/* 按钮区域样式 */
+.action-zone {
+    display: flex;
+    align-items: center;
+    margin: 20px 0;
+}
+.btn {
+    padding: 9px 18px;
+    font-size: 14px;
+    border-radius: 6px;
+    cursor: pointer;
+    font-weight: 600;
+    display: inline-flex;
+    align-items: center;
+    gap: 6px;
+    transition: all 0.2s;
+}
+.btn-primary {
+    background: linear-gradient(135deg, #3498db, #2980b9);
+    color: #fff;
+    border: none;
+    box-shadow: 0 4px 10px rgba(52, 152, 219, 0.3);
+}
+.btn-primary:hover {
+    background: linear-gradient(135deg, #2980b9, #2573a7);
+    transform: translateY(-1px);
+    box-shadow: 0 6px 15px rgba(52, 152, 219, 0.4);
+}
+.btn-outline {
+    background: transparent;
+    color: #3498db;
+    border: 1px solid #3498db;
+}
+.btn-outline:hover {
+    background: #f0f7ff;
+    box-shadow: 0 2px 5px rgba(52, 152, 219, 0.15);
+}
+.btn-secondary {
+    background: #ecf5fe;
+    color: #3498db;
+    border: 1px solid #c4e1ff;
+    font-size: 13px;
+    border-radius: 5px;
+    padding: 5px 12px;
+    transition: all 0.2s;
+    font-weight: 500;
+    cursor: pointer;
+    text-decoration: none;
+    line-height: 1.6;
+}
+.btn-secondary:hover, .btn-secondary:focus {
+    background: #d9ebfd;
+    color: #2980b9;
+    border-color: #3498db;
+    transform: translateY(-1px);
+    box-shadow: 0 2px 5px rgba(52, 152, 219, 0.15);
+    text-decoration: none;
 }
 
-h1 {
-    color: #DEDEDE;
-    font-family: palatino, Georgia;
-    font-size: 40px;
-    line-height: 40px;
-    font-weight: bold;
-    margin-bottom: 8px;
-    text-shadow: 1px 1px 3px #000;
+/* 输出区域样式 */
+.output-section {
+    border-top: 1px solid #eaeef3;
+    padding-top: 20px;
+}
+.output-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 10px;
+}
+.output-header label {
+    font-weight: 600;
+    color: #2c3e50;
+    display: flex;
+    align-items: center;
+    gap: 6px;
+}
+.output-header label i {
+    color: #16a085;
 }
 
-p {
-    font-size: 15px;
-    line-height: 22px;
+/* 粘贴输入框样式 */
+#pasteInput,#jsonOutput {
+    font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
+    font-size: 12px;
+    padding: 10px;
+    border-radius: 6px;
+    border: 1px solid #d1d9e6;
+    background: #f8fafc;
+    resize: vertical;
+    transition: all 0.3s;
+    box-shadow: inset 0 2px 4px rgba(0,0,0,0.02);
+}
+#pasteInput:focus,#jsonOutput:focus {
+    border-color: #3498db;
+    box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.15);
+    outline: none;
 }
 
-/*settings*/
-#settings {
-    font-size:12px;
-    line-height: 30px;
+/* 错误信息样式 */
+#errorMsg {
+    color: #e74c3c;
+    font-size: 14px;
+    margin-left: 20px;
+    font-weight: 500;
 }
 
-#settings h5 {
-    line-height: 24px;
+/* 页脚样式 */
+.tool-footer {
+    margin-top: 10px;
+    padding: 15px 20px;
+    background: #fff;
+    border-radius: 10px;
+    box-shadow: 0 2px 8px rgba(0,0,0,0.03);
+    border: 1px solid #eaeef3;
+}
+.footer-info {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+}
+.footer-info p {
+    margin: 0;
+    color: #667790;
+    font-size: 14px;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+}
+.footer-info p i {
+    color: #3498db;
+}
+.footer-info p:last-child i {
+    color: #27ae60;
 }
 
-#settings p {
-    line-height: 24px;
+/* 响应式调整 */
+@media (max-width: 900px) {
+    .main-container {
+        width: 95%;
+    }
+    .input-flex-row {
+        flex-direction: column;
+        align-items: flex-start;
+    }
+    .input-flex-row > * {
+        margin: 8px 0 !important;
+        width: 100%;
+    }
+    #pasteInput {
+        width: 100% !important;
+        max-width: 100% !important;
+        margin-left: 0 !important;
+    }
+    .example-section {
+        margin: 10px 0 !important;
+    }
 }
 
-#settings .settingsGroup p {
-    padding-left: 20px;
+/* Flex主面板布局 */
+.excel2json-flex-panel {
+    display: flex;
+    flex-direction: row;
+    gap: 32px;
+    min-height: 420px;
+    align-items: stretch;
 }
 
-/*converter*/
+.input-zone, .output-zone {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    height: 100%;
 
-#converter {
-    position: absolute;
-    top: 15px;
-    left: 330px;
-    border:1px solid #ccc;
+    background: #fff;
+    border-radius: 10px;
+    box-shadow: 0 5px 20px rgba(0,0,0,0.05);
+    border: 1px solid #eaeef3;
+    overflow: hidden;
+    padding: 10px;
+    border-radius: 10px;
 }
 
-p.dataHeaders {
-    height: 30px;
-    padding: 15px 15px 10px;
+.input-zone {
+    width: 700px;
+}
+.output-zone {
 }
 
-.textInputs {
-    border: none;
-    color: #664D63;
-    font-family: monospace;
-    font-size: 12px;
-    height: 300px;
-    line-height: 18px;
+.input-ops {
+    margin-bottom: 12px;
+}
+.input-ops-row {
+    display: flex;
+    align-items: center;
+    gap: 18px;
+    flex-wrap: wrap;
+    width: 100%;
+}
+.input-label {
+    white-space: nowrap;
+    font-weight: 600;
+    margin-right: 8px;
+}
+.example-section {
+    display: flex;
+    align-items: center;
+    margin-right: 8px;
+}
+.example-label {
+    font-size: 14px;
+    color: #888;
+    margin-right: 10px;
+    display: flex;
+    align-items: center;
+    gap: 6px;
+}
+.example-btn:not(:last-child) {
+    margin-right: 4px;
+}
+.convert-btn {
+    margin-left: auto;
+    min-width: 140px;
+}
+.error-msg {
+    color: #e74c3c;
+    margin-left: 0;
+    display: block;
+    margin-top: 8px;
+    font-size: 14px;
+}
+.input-textarea,.output-textarea {
+    flex: 1;
+    min-height: 500px;
+    max-height: 800px;
+    font-size: 15px;
+    font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
     padding: 10px;
-    text-shadow: #DED4DD 0px 1px 0px;
+    border-radius: 6px;
+    border: 1px solid #d1d9e6;
+    background: #f8fafc;
+    resize: vertical;
+    transition: all 0.3s;
+    box-shadow: inset 0 2px 4px rgba(0,0,0,0.02);
+}
+.input-textarea:focus {
+    border-color: #3498db;
+    box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.15);
     outline: none;
-    resize: none;
 }
+.output-header-block {
+    display: block;
+    justify-content: space-between;
+    margin-bottom: 18px;
+}
+.copy-btn {
+    float: right;
+}
+.output-textarea {
+    
+}
+.output-textarea:focus {
+    border-color: #16a085;
+    box-shadow: 0 0 0 3px rgba(22, 160, 133, 0.1);
+    outline: none;
+} 
 
-.groupHeader {
-    width: 100%;
-    color: #000;
-    height: 45px;
-    background-color: #f1f1f1;
+
+
+/* 工具市场按钮样式(保持不变) */
+.panel-title>a.x-other-tools {
+    margin: 1px 0 0;
+    font-size: 13px;
+    cursor: pointer;
+    text-decoration: none;
+    -webkit-user-select: none;
+    user-select: none;
+    color: #333;
+    float: right;
+    background-color: #f5f8ff;
+    padding: 5px 10px;
+    border-radius: 15px;
+    border: 1px solid #d0d9ff;
+    transition: all 0.3s ease;
+    display: flex;
+    align-items: center;
+    position: relative;
+    top: 0px;
+    right: -16px;
 }
 
-p.groupHeadline {
-    padding: 10px;
+.panel-title>a.x-other-tools .icon-plus-circle {
+    display: inline-block;
+    width: 16px;
+    height: 16px;
+    background: url(/static/img/plus-circle.svg) no-repeat center center;
+    background-size: contain;
+    margin-right: 5px;
 }
 
-.groupHeader span.subhead {
-    opacity: 0.7;
+.panel-title>a.x-other-tools .tool-market-badge {
+    display: inline-block;
+    background-color: #4d89fe;
+    color: white;
+    padding: 2px 6px;
+    border-radius: 10px;
+    margin-left: 5px;
     font-size: 12px;
+    font-weight: bold;
 }
 
-.groupHeader a {
-    color: #FF66FF;
+.panel-title>a.x-other-tools:hover {
+    color: #333;
+    background-color: #e6edff;
+    box-shadow: 0 2px 5px rgba(0,0,0,0.15);
+    transform: translateY(-1px);
 }
 
-#outputHeader {
-    border-top:1px solid #ccc;
+
+/* 保持原有的顶部导航样式 */
+.x-donate-link {
+    float: right;
+    line-height: 18px;
+    color: #2563eb;
+    cursor: pointer;
+    text-decoration: none;
+    border: none;
+    white-space: nowrap;
+    margin-right: auto;
+    border-radius: 20px;
+    background-color: #eff6ff;
+    transition: all 0.2s ease;
+    position: relative;
+    display: inline-flex;
+    align-items: center;
+    box-shadow: 0 1px 2px rgba(37, 99, 235, 0.1);
+    position: absolute;
+    right: 230px;
+    top: 14px;
+    padding: 4px 12px;
+    margin: 0 10px;
+    font-size: 12px;
+    font-weight: normal;
 }
 
-#dataInput, #dataOutput {
-    width: 100% !important;
+.x-donate-link:hover {
+    background-color: #dbeafe;
+    color: #1d4ed8;
+    text-decoration: none;
+    box-shadow: 0 2px 4px rgba(37, 99, 235, 0.15);
+    transform: translateY(-1px);
 }
 
-#dataSelector {
-    width: 200px;
-    line-height: 22px;
-    font-size: 12px;
-    position: relative;
-    top: -2px;
-    left: 10px;
+.x-donate-link>a {
+    color: #333;
+    text-decoration: none;
+}
+.x-donate-link>a:hover {
+    color: #f00;
 }
 
-#dataSelector option {
 
-}
-.form-control {
-    display: inline-block;
-    width:200px;
-    height:28px;
-}

+ 41 - 68
apps/excel2json/index.html

@@ -1,83 +1,56 @@
 <!DOCTYPE HTML>
 <html lang="zh-CN">
 <head>
-    <title>Excel/CVS转JSON</title>
+    <title>Excel/CSV 转 JSON 工具 - FeHelper</title>
     <meta charset="UTF-8">
-    <link rel="shortcut icon" href="../static/img/favicon.ico">
     <link rel="stylesheet" href="index.css" />
-    <script type="text/javascript" src="../static/vendor/vue/vue.js"></script>
 </head>
 <body>
-
-<div class="wrapper" id="pageContainer">
-    <div class="panel panel-default" style="margin-bottom: 0px;">
-        <div class="panel-heading">
-            <h3 class="panel-title">
-                <a href="https://www.baidufe.com/fehelper/index/index.html" target="_blank" class="x-a-high">
-                    <img src="../static/img/fe-16.png" alt="fehelper"/> FeHelper</a>:Excel/CVS转JSON
-
-                <a href="#" class="x-donate-link" @click="openDonateModal($event)"><i class="nav-icon">❤&nbsp;</i>打赏鼓励</a>
-                <a class="x-other-tools" @click="openOptionsPage($event)"><i class="icon-plus-circle"></i> 探索更多实用工具 <span class="tool-market-badge">工具市场</span></a>
-            </h3>
+    <div class="wrapper" id="excel2jsonContainer">
+        <div class="main-navbar">
+            <div class="navbar-brand">
+                <a href="https://www.baidufe.com/fehelper/index/index.html" target="_blank" class="brand-link">
+                    <img src="../static/img/fe-16.png" alt="fehelper"/>
+                    <span class="brand-text">FeHelper</span>
+                    <span class="brand-subtitle">Excel/CSV 转 JSON</span>
+                </a>
+            </div>
+            <div class="navbar-actions panel-title">
+                <a href="#" class="x-donate-link"><i class="nav-icon">❤&nbsp;</i>打赏鼓励</a>
+                <a class="x-other-tools"><i class="icon-plus-circle"></i> 探索更多实用工具 <span class="tool-market-badge">工具市场</span></a>
+            </div>
         </div>
-    </div>
-    <div class="panel-body mod-endecode">
-        <div id='base'>
-            <div id='header'>
-
-                <div id='settings'>
-                    <h3>输入配置</h3>
-                    <form id='settingsForm'>
-                        <div><label><input class="settingsElement" type="checkbox" name="" value="" id="headersProvidedCB" checked/>首行为标题</label>
-                        (<span class="settingsGroup">表头转换:
-                            <label><input class="settingsElement" type="radio" name="headerModifications" value="downcase" id='headersDowncase'/>小写&nbsp;&nbsp;</label>
-                            <label><input class="settingsElement" type="radio" name="headerModifications" id='headersUpcase' value="upcase"/> 大写&nbsp;&nbsp;</label>
-                            <label><input class="settingsElement" type="radio" name="headerModifications" id='headersNoTransform' value="none" checked/> 无</label>
-                        </span>)</div>
-
-                        <div>字段分隔符:
-                            <label><input class="settingsElement" type="radio" name="delimiter" id='delimiterAuto' value="auto" checked/>自动&nbsp;&nbsp;</label>
-                            <label><input class="settingsElement" type="radio" name="delimiter" id='delimiterComma' value="comma"/>逗号&nbsp;&nbsp;</label>
-                            <label><input class="settingsElement" type="radio" name="delimiter" id='delimiterTab' value="tab"/>Tab键</label>
-                        </div>
-                        <div>数字分隔符:
-                            <label><input class="settingsElement" type="radio" name="decimal" id='decimalDot' value="dot" checked/>点&nbsp;&nbsp;</label>
-                            <label><input class="settingsElement" type="radio" name="decimal" id='decimalComma' value="comma"/>逗号</label>
-                        </div>
-                    </form>
-
-                    <h3 style="margin-top:40px">输出配置</h3>
-                    <form id="outSettingsForm">
-                        <div>
-                            <label><input class="settingsElement" type="checkbox" name="some_name" value="" id="includeWhiteSpaceCB" checked/>格式调整</label>
-                            (缩进:
-                            <label><input class="settingsElement" type="radio" name="indentType" value="tabs" id='includeWhiteSpaceTabs'/>tab键&nbsp;&nbsp;</label>
-                            <label><input class="settingsElement" type="radio" name="indentType" value="spaces" id='includeWhiteSpaceSpaces' checked/>空格</label>)
-                        </div>
-
-                        <div class="settingsGroup">
-                            <div>
-                            </div>
-                            <div><label>XML节点定义:</label>(仅针对XML结果有效)
-                                <div><label>根节点:<input class="settingsElement form-control" type="text" name="indentType" value="root" id='root'/></label></div>
-                                <div><label>子节点:<input class="settingsElement form-control" type="text" name="indentType" value="row" id='child'/></label></div>
+        <div class="main-container">
+            <div class="panel panel-default">
+                <div class="panel-body excel2json-flex-panel">
+                    <!-- 左侧输入区 -->
+                    <div class="input-zone">
+                        <div class="input-ops">
+                            <div class="input-ops-row">
+                                <input type="file" id="fileInput" accept=".xlsx,.xls,.csv" style="display: none;"/>
+                                <a href="#" class="btn btn-secondary example-btn btn-file-input" data-example="simple">选择Excel/CSV文件</a>
+                                <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>
+                        <textarea id="pasteInput" placeholder="可直接粘贴表格内容(支持CSV格式)" rows="18" class="input-textarea"></textarea>
+                    </div>
+                    <!-- 右侧输出区 -->
+                    <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>
                         </div>
-                    </form>
+                        <textarea id="jsonOutput" readonly rows="18" class="output-textarea"></textarea>
+                    </div>
                 </div>
             </div>
-
-            <div id='converter' class=''></div>
         </div>
     </div>
-</div>
-
-<script type="text/javascript" src="../static/vendor/evalCore.min.js"></script>
-<script src="../static/vendor/jquery/jquery-3.3.1.min.js"></script>
-<script type="text/javascript" src="CSVParser.js"></script>
-<script type="text/javascript" src="DataGridRenderer.js"></script>
-<script type="text/javascript" src="converter.js"></script>
-<script type="text/javascript" src="index.js"></script>
-
+    <!-- xlsx.full.min.js 复用 chart-maker/lib 目录下的文件 -->
+    <script src="../chart-maker/lib/xlsx.full.min.js"></script>
+    <script src="index.js" type="module"></script>
 </body>
-</html>
+</html> 

+ 176 - 119
apps/excel2json/index.js

@@ -1,131 +1,188 @@
-/* code here... */
-
-var _gaq = _gaq || [];
-
-var widthOffset = 375;
-var heightOffset = 90
-
-
-/**
- * @type {DataConverter}
- * 对数据内容进行转换
- */
-var d = new DataConverter('converter');
-
-var sidebar = $('#header');
-
-var win = $(window);
-var base = $('#pageContainer');
-var w = base.width() - widthOffset;
-var h = win.height() - heightOffset;
-
-//重载页面,解决无法显示textarea问题
-d.create(w, h);
-d.resize(w, h);
-sidebar.height(h);
-
-$(".settingsElement").change(updateSettings);
-
-
-/**
- * win发生窗口变化的时候,验证窗口的高宽
- * 修正sidebar的高宽
- */
-$(window).bind('resize', function () {
-
-    w = base.width() - widthOffset;
-    h = win.height() - heightOffset;
-    d.resize(w, h);
-    sidebar.height(h);
-
-});
-
-
-/**
- * 监听dom树,修改设置内容
- * 定界符
- * 第一行标题
- * 输出格式内容
- * @param evt
- */
-function updateSettings(evt) {
-
-    if (evt) {
-        _gaq.push(['_trackEvent', 'Settings', evt.currentTarget.id]);
-    }
-
-    d.includeWhiteSpace = $('#includeWhiteSpaceCB').prop('checked');
-
-    if (d.includeWhiteSpace) {
-        $("input[name=indentType]").removeAttr("disabled");
-        var indentType = $('input[name=indentType]:checked').val();
-        if (indentType === "tabs") {
-            d.indent = "\t";
-        } else if (indentType === "spaces") {
-            d.indent = "  "
-        }
+// Excel/CSV 转 JSON 工具主逻辑
+// 作者:AI进化论-花生
+// 详细中文注释,便于初学者理解
+
+// 选择器
+const fileInput = document.getElementById('fileInput');
+const fileLink = document.querySelector('a.btn-file-input');
+const pasteInput = document.getElementById('pasteInput');
+const convertBtn = document.getElementById('convertBtn');
+const jsonOutput = document.getElementById('jsonOutput');
+const errorMsg = document.getElementById('errorMsg');
+
+// 清空错误提示
+function clearError() {
+    errorMsg.textContent = '';
+}
+
+// 显示错误提示
+function showError(msg) {
+    errorMsg.textContent = msg;
+}
+
+// 解析CSV文本为JSON
+function csvToJson(csv) {
+    const lines = csv.split(/\r?\n/).filter(line => line.trim() !== '');
+    if (lines.length < 2) return [];
+    const headers = lines[0].split(',');
+    return lines.slice(1).map(line => {
+        const values = line.split(',');
+        const obj = {};
+        headers.forEach((h, i) => {
+            obj[h.trim()] = (values[i] || '').trim();
+        });
+        return obj;
+    });
+}
+
+// 处理文件上传
+fileInput.addEventListener('change', function (e) {
+    clearError();
+    const file = e.target.files[0];
+    if (!file) return;
+    const reader = new FileReader();
+    const ext = file.name.split('.').pop().toLowerCase();
+    if (["xlsx", "xls"].includes(ext)) {
+        // 读取Excel文件
+        reader.onload = function (evt) {
+            try {
+                const data = evt.target.result;
+                const workbook = XLSX.read(data, { type: 'binary' });
+                // 默认取第一个sheet
+                const sheetName = workbook.SheetNames[0];
+                const sheet = workbook.Sheets[sheetName];
+                const json = XLSX.utils.sheet_to_json(sheet, { defval: '' });
+                jsonOutput.value = JSON.stringify(json, null, 2);
+                // 生成CSV文本并填充到输入框
+                const csv = XLSX.utils.sheet_to_csv(sheet);
+                pasteInput.value = csv;
+            } catch (err) {
+                showError('Excel文件解析失败,请确认文件格式!');
+            }
+        };
+        reader.readAsBinaryString(file);
+    } else if (ext === 'csv') {
+        // 读取CSV文件
+        reader.onload = function (evt) {
+            try {
+                const csv = evt.target.result;
+                const json = csvToJson(csv);
+                jsonOutput.value = JSON.stringify(json, null, 2);
+                pasteInput.value = csv;
+            } catch (err) {
+                showError('CSV文件解析失败,请确认内容格式!');
+            }
+        };
+        reader.readAsText(file);
     } else {
-        $("input[name=indentType]").attr("disabled", "disabled");
+        showError('仅支持Excel(.xlsx/.xls)或CSV文件!');
     }
+});
 
-    d.headersProvided = $('#headersProvidedCB').prop('checked');
-
-    if (d.headersProvided) {
-        $("input[name=headerModifications]").removeAttr("disabled");
+// 处理转换按钮点击
+convertBtn.addEventListener('click', function () {
+    clearError();
 
-        var hm = $('input[name=headerModifications]:checked').val();
-        if (hm === "downcase") {
-            d.downcaseHeaders = true;
-            d.upcaseHeaders = false;
-        } else if (hm === "upcase") {
-            d.downcaseHeaders = false;
-            d.upcaseHeaders = true;
-        } else if (hm === "none") {
-            d.downcaseHeaders = false;
-            d.upcaseHeaders = false;
+    // 处理粘贴内容
+    const text = pasteInput.value.trim();
+    if (!text) {
+        showError('请上传文件或粘贴表格数据!');
+        return;
+    }
+    // 判断是否为CSV格式
+    if (text.includes(',') && text.includes('\n')) {
+        try {
+            const json = csvToJson(text);
+            jsonOutput.value = JSON.stringify(json, null, 2);
+        } catch (err) {
+            showError('粘贴内容解析失败,请检查格式!');
         }
     } else {
-        $("input[name=headerModifications]").attr("disabled", "disabled");
+        showError('仅支持CSV格式的粘贴内容!');
     }
+});
 
-    d.delimiter = $('input[name=delimiter]:checked').val();
-    d.decimal = $('input[name=decimal]:checked').val();
-
-    d.useUnderscores = true;
-
-
-    d.root = $('#root').val();
-    d.child = $('#child').val();
-
-    d.convert();
+// 示例数据
+const EXAMPLES = {
+    simple: `姓名,年龄,城市\n张三,18,北京\n李四,22,上海`,
+    user: `ID,用户名,邮箱\n1,alice,[email protected]\n2,bob,[email protected]\n3,charlie,[email protected]`,
+    score: `学号,姓名,数学,语文,英语\n1001,王小明,90,88,92\n1002,李小红,85,91,87\n1003,张大伟,78,80,85`
 };
 
-updateSettings();
-  
-
-/**
- * FeHelper 进制转换工具
- */
-new Vue({
-    el: '#pageContainer',
-
-    methods: {
-       
-        openDonateModal: function(event) {
-            event.preventDefault();
-            event.stopPropagation();
-            chrome.runtime.sendMessage({
-                type: 'fh-dynamic-any-thing',
-                thing: 'open-donate-modal',
-                params: { toolName: 'trans-radix' }
-            });
-        },
+// 绑定“选择文件”a标签点击事件,触发文件选择
+const fileSelectLink = document.querySelector('.btn-file-input');
+if (fileSelectLink) {
+    fileSelectLink.addEventListener('click', function(e) {
+        e.preventDefault();
+        fileInput.click();
+    });
+}
+
+// 绑定示例按钮事件(只针对.link-btn)
+const exampleBtns = document.querySelectorAll('.link-btn');
+exampleBtns.forEach(btn => {
+    btn.addEventListener('click', function(e) {
+        e.preventDefault();
+        const type = btn.getAttribute('data-example');
+        if (EXAMPLES[type]) {
+            pasteInput.value = EXAMPLES[type];
+            clearError();
+            jsonOutput.value = '';
+            // 自动触发转换
+            convertBtn.click();
+        }
+    });
+});
 
-        openOptionsPage: function(event) {
-            event.preventDefault();
-            event.stopPropagation();
-            chrome.runtime.openOptionsPage();
-        }   
+// 复制按钮功能
+const copyBtn = document.getElementById('copyBtn');
+if (copyBtn) {
+    copyBtn.addEventListener('click', function() {
+        if (!jsonOutput.value) {
+            showError('暂无内容可复制!');
+            return;
+        }
+        jsonOutput.select();
+        document.execCommand('copy');
         
-    }
-});
+        // 复制成功效果
+        const originalText = copyBtn.innerHTML;
+        copyBtn.innerHTML = '<i class="fas fa-check"></i> 已复制';
+        copyBtn.style.background = '#27ae60';
+        copyBtn.style.color = '#fff';
+        copyBtn.style.borderColor = '#27ae60';
+        
+        setTimeout(() => {
+            copyBtn.innerHTML = originalText;
+            copyBtn.style.background = '';
+            copyBtn.style.color = '';
+            copyBtn.style.borderColor = '';
+        }, 1500);
+        
+        clearError();
+    });
+} 
+
+// 打赏按钮
+const donateBtn = document.querySelector('.x-donate-link');
+if (donateBtn) {
+    donateBtn.addEventListener('click', function(e) {
+        e.preventDefault();
+        e.stopPropagation();
+        chrome.runtime.sendMessage({
+            type: 'fh-dynamic-any-thing',
+            thing: 'open-donate-modal',
+            params: { toolName: 'excel2json' }
+        }); 
+    });
+}
+
+// 工具市场按钮
+const toolMarketBtn = document.querySelector('.x-other-tools');
+if (toolMarketBtn) {
+    toolMarketBtn.addEventListener('click', function(e) {
+        e.preventDefault();
+        e.stopPropagation();
+        chrome.runtime.openOptionsPage();
+    });
+}   

+ 47 - 142
website/docs/excel2json.md

@@ -1,168 +1,73 @@
-# Excel转JSON工具
+# Excel/CSV  JSON 工具(FeHelper)
 
 ## 工具简介
 
-Excel转JSON工具是一个专业的Excel/CSV文件转换工具,可以将Excel表格数据快速转换为JSON格式。该工具支持多种数据格式和转换选项,提供直观的界面和灵活的配置,帮助用户轻松处理数据转换需求。
+FeHelper 的 Excel/CSV 转 JSON 工具,支持将 Excel(.xlsx/.xls)和 CSV 文件,或直接粘贴的 CSV 表格数据,一键转换为标准 JSON 格式。界面简洁,操作便捷,适合前端开发、数据处理、接口调试等多种场景。
+
+---
 
 ## 主要功能
 
-### 1. 数据导入
-- Excel文件导入
-- CSV文件导入
-- 文本数据导入
-- 拖拽上传
-- 剪贴板导入
-
-### 2. 数据转换
-- JSON格式转换
-- 自定义分隔符
-- 表头处理
-- 数据格式化
-- 批量转换
-
-### 3. 输出配置
-- 格式化输出
-- 缩进设置
-- 编码选择
-- 文件导出
-- 复制结果
-
-### 4. 数据处理
-- 表头转换
-- 数据类型
-- 空值处理
-- 特殊字符
-- 数据验证
-
-## 使用说明
-
-### 基本使用
-1. 选择输入文件
-2. 配置转换选项
-3. 设置输出格式
-4. 执行转换
-5. 获取结果
-
-### 转换方式
-1. **文件导入**:
-   - 选择Excel文件
-   - 选择CSV文件
-   - 粘贴文本数据
-   - 拖拽文件
-
-2. **配置选项**:
-   - 设置分隔符
-   - 选择表头
-   - 配置输出
-   - 调整格式
-
-3. **结果处理**:
-   - 查看预览
-   - 复制结果
-   - 导出文件
-   - 保存配置
-
-## 使用技巧
-
-1. **数据准备**:
-   - 规范数据格式
-   - 检查数据完整
-   - 处理特殊字符
-   - 验证数据类型
-
-2. **转换配置**:
-   - 选择合适的格式
-   - 设置正确的编码
-   - 配置输出选项
-   - 保存常用配置
-
-3. **结果处理**:
-   - 验证转换结果
-   - 检查数据完整
-   - 格式化输出
-   - 及时保存
+- **支持文件上传**:可选择 Excel(.xlsx/.xls)或 CSV 文件,自动解析第一个工作表。
+- **支持粘贴数据**:可直接粘贴 CSV 格式的表格文本进行转换。
+- **一键转换**:点击"转换为 JSON"按钮,立即获得格式化的 JSON 结果。
+- **一键复制**:点击"复制"按钮,快速复制转换结果。
+- **示例数据填充**:内置多组示例数据,点击即可自动填充并转换,便于新手体验。
+- **专业UI体验**:左右分栏结构,输入与输出区域等高,所有操作入口集中在顶部,界面美观高效。
 
-## 适用场景
+---
 
-1. **数据处理**:
-   - 数据格式转换
-   - 数据清洗
-   - 数据迁移
-   - 数据整合
+## 使用方法
 
-2. **开发调试**:
-   - 接口测试
-   - 数据模拟
-   - 配置转换
-   - 数据验证
+1. **选择文件**:点击"选择Excel/CSV文件"按钮,上传本地 Excel 或 CSV 文件。
+2. **粘贴数据**:或直接将表格内容(CSV格式)粘贴到左侧输入框。
+3. **使用示例**:点击"示例:简单表格/用户信息/成绩单"可一键填充示例数据。
+4. **转换操作**:点击"转换为 JSON"按钮,右侧立即显示格式化 JSON。
+5. **复制结果**:点击"复制"按钮,将结果复制到剪贴板。
 
-3. **数据分析**:
-   - 数据导入
-   - 格式转换
-   - 数据导出
-   - 结果分析
+---
 
 ## 注意事项
 
-1. 注意数据格式
-2. 检查特殊字符
-3. 验证转换结果
-4. 及时保存数据
-
-## 技术实现
+- 仅支持标准 Excel(.xlsx/.xls)和 CSV 文件,且首行为表头。
+- 粘贴内容仅支持逗号分隔的 CSV 格式。
+- 暂不支持多表头、合并单元格、复杂嵌套等高级表格结构。
+- 文件内容较大时,建议先用表格工具清洗后再导入。
 
-- 基于JavaScript
-- 使用Vue.js开发
-- 支持多种格式
-- 提供完整API
-
-## 更新日志
+---
 
-### v1.0.0
-- 初始版本发布
-- 支持基本转换
-- 提供格式配置
+## 常见问题
 
-### v1.1.0
-- 添加更多格式
-- 优化转换功能
-- 改进用户界面
+**Q: 支持哪些文件格式?**  
+A: 支持 Excel(.xlsx/.xls)和 CSV 文件,以及标准 CSV 文本粘贴。
 
-### v1.2.0
-- 添加批量转换
-- 支持数据验证
-- 提升使用体验
+**Q: 粘贴内容格式有要求吗?**  
+A: 仅支持逗号分隔、首行为表头的标准 CSV 格式。
 
-## 常见问题
+**Q: 转换结果如何复制?**  
+A: 点击右上角"复制"按钮即可一键复制 JSON 结果。
 
-1. **Q: 支持哪些文件格式?**
-   A: 支持Excel、CSV等常见表格格式,以及文本数据。
+**Q: 解析失败怎么办?**  
+A: 请检查文件/内容格式是否规范,或尝试用表格工具清洗数据。
 
-2. **Q: 如何处理特殊字符?**
-   A: 工具会自动处理特殊字符,确保转换结果的正确性。
+---
 
-3. **Q: 如何保存转换配置?**
-   A: 可以保存常用的转换配置,方便下次使用。
+## 适用场景
 
-4. **Q: 转换结果如何验证?**
-   A: 工具提供预览功能,可以查看转换结果并验证数据完整性。
+- 前端/后端开发接口调试
+- 数据格式转换与清洗
+- 配置文件生成
+- 数据分析前的预处理
 
-## 最佳实践
+---
 
-1. **数据准备**:
-   - 规范数据格式
-   - 检查数据完整
-   - 处理特殊字符
-   - 验证数据类型
+## 更新日志
 
-2. **转换配置**:
-   - 选择合适的格式
-   - 设置正确的编码
-   - 配置输出选项
-   - 保存常用配置
+- **v2.0.0**
+  - 全新专业UI,左右分栏,体验升级
+  - 支持一键示例填充与转换
+  - 优化文件与粘贴数据的兼容性
+  - 增强错误提示与交互体验
 
-3. **结果处理**:
-   - 验证转换结果
-   - 检查数据完整
-   - 格式化输出
-   - 及时保存 
+- **v1.x**
+  - 支持Excel/CSV转JSON基础功能