前端環境:elementUI ?vue2 ? <style lang="scss" scoped>
頁面效果
- jsondata為mock數據,為方便調試其內容可清空,
- 首行(字母坐標)隨數據內容自動變化,首列也是一樣,模擬excel 坐標的樣式
<template><div class="mainBox"><div class="excel-uploader"><el-upload action="" :before-upload="handleFileUpload" :show-file-list="false"><el-button size="small" type="primary">導入表格</el-button></el-upload><!-- <div v-if="jsonData.length" class="json-preview"><h3>解析后的 JSON 數據:</h3><pre>{{ jsonData }}</pre></div> --></div><div class="excel-table-container"><table class="excel-table"><thead><tr><th></th><th v-for="(header, index) in headers" :key="index" class="editable-cell">{{ header }}</th></tr></thead><tbody><tr v-for="(row, rowIndex) in rows" :key="rowIndex"><th class="editable-cell indexno">{{ 1 + rowIndex }}</th><td v-for="(cell, cellIndex) in row" :key="cellIndex" class="editable-cell":class="{ selected: selectedCell.row === rowIndex && selectedCell.col === cellIndex }"@click="selectCell(rowIndex, cellIndex)"><span>{{ cell.value }}</span></td></tr></tbody></table></div>
</div>
</template><script>
import * as XLSX from 'xlsx';
import {saveTemplate,
} from "@/api/template";
export default {data() {return {headers: [],// ['A', 'B', 'C', 'D', 'E']rows: [['A1', 'B1', 'CQ', '', ''],['非貨幣性資產交換', 'B2', '', '', ''],// Add more rows as needed],selectedCell: { row: 0, col: 0 },isEditingCell: false,jsonData: [{"A1": {"value": "項目","formula": null},"B1": {"value": "會計確認的處置收入","formula": null},"C1": {"value": "處置收入調增","formula": null},"D1": {"value": "處置收入調減","formula": null},"E1": {"value": "稅收計算的處置收入","formula": null},"F1": {"value": "處置投資的賬面價值","formula": null},"G1": {"value": "處置投資的計稅基礎","formula": null},"H1": {"value": "會計確認的處置所得或損失","formula": null},"I1": {"value": "稅收計算的處置所得","formula": null},"J1": {"value": "納稅調整金額","formula": null}},{"A2": {"value": "交易性金融資產","formula": null},"E2": {"value": 0,"formula": "B2+C2-D2"},"H2": {"value": 0,"formula": "B2-F2"},"I2": {"value": 0,"formula": "E2-G2"},"J2": {"value": 0,"formula": "I2-H2"}},{"A3": {"value": "可供出售金融資產","formula": null}},{"A4": {"value": "持有至到期投資","formula": null}},{"A5": {"value": "衍生工具","formula": null}},{"A6": {"value": "交易性金融負債","formula": null}},{"A7": {"value": "長期股權投資","formula": null},"E7": {"value": 0,"formula": "B7+C7-D7"},"H7": {"value": 0,"formula": "B7-F7"},"I7": {"value": 0,"formula": "E7-G7"},"J7": {"value": 0,"formula": "I7-H7"}},{"A8": {"value": "短期投資","formula": null},"E8": {"value": 0,"formula": "B8+C8-D8"},"H8": {"value": 0,"formula": "B8-F8"},"I8": {"value": 0,"formula": "E8-G8"},"J8": {"value": 0,"formula": "I8-H8"}},{"A9": {"value": "長期債券投資","formula": null}},{"A10": {"value": "其他","formula": null}},{"A11": {"value": "合計","formula": null},"B11": {"value": 0,"formula": "SUM(B2:B10)"},"E11": {"value": 0,"formula": "SUM(E2:E10)"}}],};},created() {this.transformJsonToTableData();},methods: {selectCell(row, col) {console.log("dff", row, col);this.selectedCell = { row, col };this.startEditing();},startEditing() {this.isEditingCell = true;},stopEditing() {this.isEditingCell = false;},isEditing(row, col) {return this.isEditingCell && this.selectedCell.row === row && this.selectedCell.col === col;},// excel 解析// handleFileUpload(file) {//如果只要 坐標和值用這個,{A1:"值"}// const reader = new FileReader();// reader.onload = (e) => {// const data = new Uint8Array(e.target.result);// const workbook = XLSX.read(data, { type: 'array' });// // 假設我們只解析第一個工作表// const firstSheetName = workbook.SheetNames[0];// const worksheet = workbook.Sheets[firstSheetName];// // 將工作表轉換為坐標格式的 JSON// const jsonData = this.sheetToJsonWithCoordinates(worksheet);// this.jsonData = jsonData;// };// reader.readAsArrayBuffer(file);// // 阻止上傳動作,因為我們只是讀取文件內容// return false;// },// sheetToJsonWithCoordinates(worksheet) {// const range = XLSX.utils.decode_range(worksheet['!ref']);// const result = [];// for (let row = range.s.r; row <= range.e.r; row++) {// const rowData = {};// for (let col = range.s.c; col <= range.e.c; col++) {// const cellAddress = XLSX.utils.encode_cell({ r: row, c: col });// const cell = worksheet[cellAddress];// if (cell && cell.v !== undefined) {// rowData[cellAddress] = cell.v;// }// }// result.push(rowData);// }// return result;// }// },handleFileUpload(file) {const reader = new FileReader();reader.onload = (e) => {const data = new Uint8Array(e.target.result);const workbook = XLSX.read(data, { type: 'array' });// 假設我們只解析第一個工作表const firstSheetName = workbook.SheetNames[0];const worksheet = workbook.Sheets[firstSheetName];// 將工作表轉換為包含坐標、樣式和公式的 JSONconst jsonData = this.sheetToJsonWithCoordinatesStylesAndFormulas(worksheet);this.jsonData = jsonData;};reader.readAsArrayBuffer(file);// 阻止上傳動作,因為我們只是讀取文件內容this.transformJsonToTableData()return false;},sheetToJsonWithCoordinatesStylesAndFormulas(worksheet) {const range = XLSX.utils.decode_range(worksheet['!ref']);const result = [];for (let row = range.s.r; row <= range.e.r; row++) {const rowData = {};for (let col = range.s.c; col <= range.e.c; col++) {const cellAddress = XLSX.utils.encode_cell({ r: row, c: col });const cell = worksheet[cellAddress];if (cell && cell.v !== undefined) {rowData[cellAddress] = {value: cell.v,formula: cell.f || null, // 如果單元格有公式,則包含公式信息// style:this.getCellStyle(cell.s, rowData[cellAddress],cell)};}}result.push(rowData);}return result;},transformJsonToTableData() {// Determine the maximum column index neededlet maxColIndex = 0;this.jsonData.forEach(data => {const keys = Object.keys(data);keys.forEach(key => {const colIndex = key.charCodeAt(0) - 'A'.charCodeAt(0);if (colIndex > maxColIndex) {maxColIndex = colIndex;}});});// Generate headers based on the maximum column indexthis.headers = Array.from({ length: maxColIndex + 1 }, (_, i) => String.fromCharCode(65 + i));// Initialize rows based on the maximum number of columnsthis.rows = this.jsonData.map(data => {const row = Array(this.headers.length).fill({ value: '' });const keys = Object.keys(data);keys.forEach(key => {const colIndex = key.charCodeAt(0) - 'A'.charCodeAt(0);if (colIndex < row.length) {row[colIndex] = data[key];}});return row;});},},mounted() {this.ruleForm.createUserName = this.name}
};
</script><style scoped lang="stylus">
.excel-uploader {margin-bottom :12px;.json-preview {padding: 10px;border: 1px solid #ebeef5;border-radius: 4px;background-color: #f5f7fa;pre {white-space: pre-wrap; /* 保留換行符 */word-wrap: break-word; /* 長單詞換行 */}}
}
.excel-table-container {width: 100%;overflow-x: auto;
}.excel-table {width: 100%;border-collapse: collapse;th, td { border: 1px solid #E6E8EA;padding: 8px;text-align: left;min-width: 100px;}th {background-color: #F4F6F8;min-width: 40px;}.editable-cell {&:hover {background-color: #e0e0e0;cursor: pointer;}&.selected {border: 2px solid #165DFF;}}
}
</style>