Quellcode durchsuchen

feature/excel表格

dy vor 11 Monaten
Ursprung
Commit
d92542e56d

+ 6 - 0
index.html

@@ -14,6 +14,12 @@
     />
     <script src="https://cdn.staticfile.org/Sortable/1.10.0-rc2/Sortable.min.js"></script>
     <title>生产线综合管控采集平台</title>
+    <link rel="stylesheet" href="./src/assets/LuckExcel/pluginsCss.css" />
+    <link rel="stylesheet" href="./src/assets/LuckExcel/plugins.css" />
+    <link rel="stylesheet" href="./src/assets/LuckExcel/luckysheet.css" />
+    <link rel="stylesheet" href="./src/assets/LuckExcel/iconfont.css" />
+    <script src="./src/assets/LuckExcel/plugin.js"></script>
+    <script src="./src/assets/LuckExcel/luckysheet.umd.js"></script>
   </head>
 
   <body>

+ 3 - 0
package.json

@@ -51,8 +51,11 @@
     "axios": "^1.6.7",
     "echarts": "^5.5.0",
     "element-plus": "^2.6.0",
+    "exceljs": "^4.4.0",
+    "file-saver": "^2.0.5",
     "html2canvas": "^1.4.1",
     "lodash-es": "^4.17.21",
+    "luckyexcel": "^1.0.1",
     "net": "^1.0.2",
     "nprogress": "^0.2.0",
     "path-browserify": "^1.0.1",

+ 40 - 0
src/api/excel/index.ts

@@ -0,0 +1,40 @@
+import request from "@/utils/request";
+//新增模版
+export function addExcel(data: any) {
+  return request({
+    url: "/api/v1/excelForm/add",
+    method: "post",
+    data,
+  });
+}
+//批量删除
+export function delsExcel(data: any) {
+  return request({
+    url: "/api/v1/excelForm/add",
+    method: "post",
+    data,
+  });
+}
+//删除
+export function delExcel(data: any) {
+  return request({
+    url: "/api/v1/excelForm/del",
+    method: "post",
+    data,
+  });
+}
+//获取表格信息
+export function getInfo(materialCode: any) {
+  return request({
+    url: "/api/v1/excelForm/get/" + materialCode,
+    method: "get",
+  });
+}
+//更新
+export function updateExcel(data: any) {
+  return request({
+    url: "/api/v1/excelForm/update",
+    method: "post",
+    data,
+  });
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 457 - 0
src/assets/LuckExcel/iconfont.css


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
src/assets/LuckExcel/luckysheet.css


Datei-Diff unterdrückt, da er zu groß ist
+ 111621 - 0
src/assets/LuckExcel/luckysheet.umd.formatted.js


Datei-Diff unterdrückt, da er zu groß ist
+ 27 - 0
src/assets/LuckExcel/luckysheet.umd.js


Datei-Diff unterdrückt, da er zu groß ist
+ 22392 - 0
src/assets/LuckExcel/plugin.formatted.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
src/assets/LuckExcel/plugin.js


Datei-Diff unterdrückt, da er zu groß ist
+ 10 - 0
src/assets/LuckExcel/plugins.css


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
src/assets/LuckExcel/pluginsCss.css


+ 853 - 0
src/components/ExcelView/export.js

@@ -0,0 +1,853 @@
+// import { createCellPos } from './translateNumToLetter'
+import Excel from "exceljs";
+import FileSaver from "file-saver";
+function exportExcel(luckysheet, name, excelType) {
+  // 1.创建工作簿,可以为工作簿添加属性
+  const workbook = new Excel.Workbook();
+  // 2.创建表格,第二个参数可以配置创建什么样的工作表
+  luckysheet.forEach(function (table) {
+    // debugger
+    if (table.data.length === 0) return true;
+    const worksheet = workbook.addWorksheet(table.name);
+    const merge = (table.config && table.config.merge) || {}; //合并单元格
+    const borderInfo = (table.config && table.config.borderInfo) || {}; //边框
+    const columnWidth = (table.config && table.config.columnlen) || {}; //列宽
+    const rowHeight = (table.config && table.config.rowlen) || {}; //行高
+    const frozen = table.frozen || {}; //冻结
+    const rowhidden = (table.config && table.config.rowhidden) || {}; //行隐藏
+    const colhidden = (table.config && table.config.colhidden) || {}; //列隐藏
+    const filterSelect = table.filter_select || {}; //筛选
+    const hide = table.hide; //工作表 sheet 1隐藏
+    if (hide === 1) {
+      // 隐藏工作表
+      worksheet.state = "hidden";
+    }
+    setStyleAndValue(table.data, worksheet);
+    setMerge(merge, worksheet);
+    setBorder(borderInfo, worksheet);
+    setImages(table, worksheet, workbook);
+    setColumnWidth(columnWidth, worksheet);
+    //行高设置50导出后在ms-excel中打开显示25,在wps-excel中打开显示50这个bug不会修复
+    setRowHeight(rowHeight, worksheet, excelType);
+    setFrozen(frozen, worksheet);
+    setRowHidden(rowhidden, worksheet);
+    setColHidden(colhidden, worksheet);
+    setFilter(filterSelect, worksheet);
+    return true;
+  });
+  const buffer = workbook.xlsx.writeBuffer().then((data) => {
+    // console.log('data', data)
+    const blob = new Blob([data], {
+      type: "application/vnd.ms-excel;charset=utf-8",
+    });
+    console.log("导出成功!");
+    FileSaver.saveAs(blob, name + `.xlsx`);
+  });
+  return buffer;
+}
+
+/**
+ * 列宽
+ * @param columnWidth
+ * @param worksheet
+ */
+var setColumnWidth = function (columnWidth, worksheet) {
+  for (let key in columnWidth) {
+    worksheet.getColumn(parseInt(key) + 1).width = columnWidth[key] / 7.5;
+  }
+};
+
+/**
+ * 行高
+ * @param rowHeight
+ * @param worksheet
+ * @param excelType
+ */
+var setRowHeight = function (rowHeight, worksheet, excelType) {
+  for (let key in rowHeight) {
+    worksheet.getRow(parseInt(key) + 1).height = rowHeight[key] * 0.75;
+  }
+  /*//导出的文件用wps打开和用excel打开显示的行高大一倍
+  if (excelType == "wps") {
+    for (let key in rowHeight) {
+      worksheet.getRow(parseInt(key) + 1).height = rowHeight[key] * 0.75
+    }
+  }
+  if (excelType == "office" || excelType == undefined) {
+    for (let key in rowHeight) {
+      worksheet.getRow(parseInt(key) + 1).height = rowHeight[key] * 1.5
+    }
+  }*/
+};
+
+/**
+ * 合并单元格
+ * @param luckyMerge
+ * @param worksheet
+ */
+var setMerge = function (luckyMerge = {}, worksheet) {
+  const mergearr = Object.values(luckyMerge);
+  mergearr.forEach(function (elem) {
+    // elem格式:{r: 0, c: 0, rs: 1, cs: 2}
+    // 按开始行,开始列,结束行,结束列合并(相当于 K10:M12)
+    worksheet.mergeCells(
+      elem.r + 1,
+      elem.c + 1,
+      elem.r + elem.rs,
+      elem.c + elem.cs
+    );
+  });
+};
+
+/**
+ * 设置边框
+ * @param luckyBorderInfo
+ * @param worksheet
+ */
+var setBorder = function (luckyBorderInfo, worksheet) {
+  if (!Array.isArray(luckyBorderInfo)) return;
+
+  //合并边框信息
+  var mergeCellBorder = function (border1, border2) {
+    if (undefined === border1 || Object.keys(border1).length === 0)
+      return border2;
+    return Object.assign({}, border1, border2);
+  };
+
+  // console.log('luckyBorderInfo', luckyBorderInfo)
+  luckyBorderInfo.forEach(function (elem) {
+    // 现在只兼容到borderType 为range的情况
+    // console.log('ele', elem)
+    if (elem.rangeType === "range") {
+      let border = borderConvert(elem.borderType, elem.style, elem.color);
+      let rang = elem.range[0];
+      let row = rang.row;
+      let column = rang.column;
+
+      let rowBegin = row[0];
+      let rowEnd = row[1];
+      let colBegin = column[0];
+      let colEnd = column[1];
+      //处理外边框的情况 没有直接对应的外边框 需要转换成上下左右
+      if (border.all) {
+        //全部边框
+        let b = border.all;
+        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
+          for (let y = column[0] + 1; y <= column[1] + 1; y++) {
+            let border = {};
+            border["top"] = b;
+            border["bottom"] = b;
+            border["left"] = b;
+            border["right"] = b;
+            worksheet.getCell(i, y).border = border;
+            // console.log(i, y, worksheet.getCell(i, y).border)
+          }
+        }
+      } else if (border.top) {
+        //上边框
+        let b = border.top;
+        let i = row[0] + 1;
+        for (let y = column[0] + 1; y <= column[1] + 1; y++) {
+          let border = {};
+          border["top"] = b;
+          worksheet.getCell(i, y).border = border;
+          // console.log(i, y, worksheet.getCell(i, y).border)
+        }
+      } else if (border.right) {
+        //右边框
+        let b = border.right;
+        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
+          let y = column[1] + 1;
+          let border = {};
+          border["right"] = b;
+          worksheet.getCell(i, y).border = border;
+          // console.log(i, y, worksheet.getCell(i, y).border)
+        }
+      } else if (border.bottom) {
+        //下边框
+        let b = border.bottom;
+        let i = row[1] + 1;
+        for (let y = column[0] + 1; y <= column[1] + 1; y++) {
+          let border = {};
+
+          border["bottom"] = b;
+          worksheet.getCell(i, y).border = border;
+          // console.log(i, y, worksheet.getCell(i, y).border)
+        }
+      } else if (border.left) {
+        //左边框
+        let b = border.left;
+        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
+          let y = column[0] + 1;
+          let border = {};
+          border["left"] = b;
+          worksheet.getCell(i, y).border = border;
+          // console.log(i, y, worksheet.getCell(i, y).border)
+        }
+      } else if (border.outside) {
+        //外边框
+        let b = border.outside;
+        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
+          for (let y = column[0] + 1; y <= column[1] + 1; y++) {
+            let border = {};
+            if (i === rowBegin + 1) {
+              border["top"] = b;
+            }
+            if (i === rowEnd + 1) {
+              border["bottom"] = b;
+            }
+            if (y === colBegin + 1) {
+              border["left"] = b;
+            }
+            if (y === colEnd + 1) {
+              border["right"] = b;
+            }
+            let border1 = worksheet.getCell(i, y).border;
+            worksheet.getCell(i, y).border = mergeCellBorder(border1, border);
+            // console.log(i, y, worksheet.getCell(i, y).border)
+          }
+        }
+      } else if (border.inside) {
+        //内边框
+        let b = border.inside;
+        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
+          for (let y = column[0] + 1; y <= column[1] + 1; y++) {
+            let border = {};
+            if (i !== rowBegin + 1) {
+              border["top"] = b;
+            }
+            if (i !== rowEnd + 1) {
+              border["bottom"] = b;
+            }
+            if (y !== colBegin + 1) {
+              border["left"] = b;
+            }
+            if (y !== colEnd + 1) {
+              border["right"] = b;
+            }
+            let border1 = worksheet.getCell(i, y).border;
+            worksheet.getCell(i, y).border = mergeCellBorder(border1, border);
+            // console.log(i, y, worksheet.getCell(i, y).border)
+          }
+        }
+      } else if (border.horizontal) {
+        //内侧水平边框
+        let b = border.horizontal;
+        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
+          for (let y = column[0] + 1; y <= column[1] + 1; y++) {
+            let border = {};
+            if (i === rowBegin + 1) {
+              border["bottom"] = b;
+            } else if (i === rowEnd + 1) {
+              border["top"] = b;
+            } else {
+              border["top"] = b;
+              border["bottom"] = b;
+            }
+            let border1 = worksheet.getCell(i, y).border;
+            worksheet.getCell(i, y).border = mergeCellBorder(border1, border);
+            // console.log(i, y, worksheet.getCell(i, y).border)
+          }
+        }
+      } else if (border.vertical) {
+        //内侧垂直边框
+        let b = border.vertical;
+        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
+          for (let y = column[0] + 1; y <= column[1] + 1; y++) {
+            let border = {};
+            if (y === colBegin + 1) {
+              border["right"] = b;
+            } else if (y === colEnd + 1) {
+              border["left"] = b;
+            } else {
+              border["left"] = b;
+              border["right"] = b;
+            }
+            let border1 = worksheet.getCell(i, y).border;
+            worksheet.getCell(i, y).border = mergeCellBorder(border1, border);
+            // console.log(i, y, worksheet.getCell(i, y).border)
+          }
+        }
+      } else if (border.none) {
+        //当luckysheet边框为border-none的时候表示没有边框 则将对应的单元格border清空
+        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
+          for (let y = column[0] + 1; y <= column[1] + 1; y++) {
+            worksheet.getCell(i, y).border = {};
+            // console.log(i, y, worksheet.getCell(i, y).border)
+          }
+        }
+      }
+    }
+    if (elem.rangeType === "cell") {
+      // col_index: 2
+      // row_index: 1
+      // b: {
+      //   color: '#d0d4e3'
+      //   style: 1
+      // }
+      const { col_index, row_index } = elem.value;
+      const borderData = Object.assign({}, elem.value);
+      delete borderData.col_index;
+      delete borderData.row_index;
+      let border = addborderToCell(borderData, row_index, col_index);
+      let border1 = worksheet.getCell(row_index + 1, col_index + 1).border;
+      worksheet.getCell(row_index + 1, col_index + 1).border = mergeCellBorder(
+        border1,
+        border
+      );
+      // console.log(row_index + 1, col_index + 1, worksheet.getCell(row_index + 1, col_index + 1).border)
+    }
+  });
+};
+
+var setStyleAndValue = function (cellArr, worksheet) {
+  if (!Array.isArray(cellArr)) return;
+  cellArr.forEach(function (row, rowid) {
+    row.every(function (cell, columnid) {
+      if (!cell) return true;
+      let fill = fillConvert(cell.bg);
+
+      let font = fontConvert(
+        cell.ff,
+        cell.fc,
+        cell.bl,
+        cell.it,
+        cell.fs,
+        cell.cl,
+        cell.ul
+      );
+      let alignment = alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr);
+      let value = "";
+
+      if (cell.f) {
+        value = { formula: cell.f, result: cell.v };
+      } else if (!cell.v && cell.ct && cell.ct.s) {
+        // xls转为xlsx之后,内部存在不同的格式,都会进到富文本里,即值不存在与cell.v,而是存在于cell.ct.s之后
+        // value = cell.ct.s[0].v
+        cell.ct.s.forEach((arr) => {
+          value += arr.v;
+        });
+      } else {
+        value = cell.v;
+      }
+      //  style 填入到_value中可以实现填充色
+      let letter = createCellPos(columnid);
+      let target = worksheet.getCell(letter + (rowid + 1));
+      // console.log('1233', letter + (rowid + 1))
+      for (const key in fill) {
+        target.fill = fill;
+        break;
+      }
+      target.font = font;
+      target.alignment = alignment;
+      target.value = value;
+
+      return true;
+    });
+  });
+};
+/*/!**
+ * 设置带样式的值
+ * @param cellArr
+ * @param worksheet
+ *!/
+var setStyleAndValue = function (cellArr, worksheet) {
+  if (!Array.isArray(cellArr)) return
+  cellArr.forEach(function (row, rowid) {
+    row.every(function (cell, columnid) {
+      if (!cell) return true
+      let fill = fillConvert(cell.bg)
+
+      let font = fontConvert(
+          cell.ff,
+          cell.fc,
+          cell.bl,
+          cell.it,
+          cell.fs,
+          cell.cl,
+          cell.un
+      )
+      let alignment = alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr)
+      let value = ''
+
+      if (cell.f) {
+        value = {formula: cell.f, result: cell.v}
+      } else if (!cell.v && cell.ct && cell.ct.s) {
+        // xls转为xlsx之后,内部存在不同的格式,都会进到富文本里,即值不存在与cell.v,而是存在于cell.ct.s之后
+        let richText = [];
+        let cts = cell.ct.s
+        for (let i = 0; i < cts.length; i++) {
+          let rt = {
+            text: cts[i].v,
+            font: fontConvert(cts[i].ff, cts[i].fc, cts[i].bl, cts[i].it, cts[i].fs, cts[i].cl, cts[i].un)
+          }
+          richText.push(rt)
+        }
+        value = {
+          richText: richText
+        };
+
+      } else {
+        //设置值为数字格式
+        if (cell.v !== undefined && cell.v !== '') {
+          var v = +cell.v;
+          if (isNaN(v)) v = cell.v
+          value = v
+        }
+      }
+      //  style 填入到_value中可以实现填充色
+      let letter = createCellPos(columnid)
+      let target = worksheet.getCell(letter + (rowid + 1))
+      // console.log('1233', letter + (rowid + 1))
+      for (const key in fill) {
+        target.fill = fill
+        break
+      }
+      target.font = font
+      target.alignment = alignment
+      target.value = value
+
+      try {
+        //设置单元格格式
+        target.numFmt = cell.ct.fa;
+      } catch (e) {
+        console.warn(e)
+      }
+
+      return true
+    })
+  })
+}*/
+
+//获取图片在单元格的位置
+var getImagePosition = function (num, arr) {
+  let index = 0;
+  let minIndex;
+  let maxIndex;
+  for (let i = 0; i < arr.length; i++) {
+    if (num < arr[i]) {
+      index = i;
+      break;
+    }
+  }
+
+  if (index == 0) {
+    minIndex = 0;
+    maxIndex = 1;
+    return Math.abs((num - 0) / (arr[maxIndex] - arr[minIndex])) + index;
+  } else if (index == arr.length - 1) {
+    minIndex = arr.length - 2;
+    maxIndex = arr.length - 1;
+  } else {
+    minIndex = index - 1;
+    maxIndex = index;
+  }
+  let min = arr[minIndex];
+  let max = arr[maxIndex];
+  let radio = Math.abs((num - min) / (max - min)) + index;
+  return radio;
+};
+/**
+ * 设置图片
+ * @param images
+ * @param worksheet
+ * @param workbook
+ */
+var setImages = function (table, worksheet, workbook) {
+  let {
+    images,
+    visibledatacolumn, //所有行的位置
+    visibledatarow, //所有列的位置
+  } = { ...table };
+  if (typeof images != "object") return;
+  for (let key in images) {
+    // console.log(images[key]);
+    // "data:image/png;base64,iVBORw0KG..."
+    // 通过 base64  将图像添加到工作簿
+    const myBase64Image = images[key].src;
+    //位置
+    const col_st = getImagePosition(
+      images[key].default.left,
+      visibledatacolumn
+    );
+    const row_st = getImagePosition(images[key].default.top, visibledatarow);
+    /*const tl = {col: images[key].default.left / 72, row: images[key].default.top / 19}*/
+    const tl = { col: col_st, row: row_st };
+    // 大小
+    const ext = {
+      width: images[key].default.width,
+      height: images[key].default.height,
+    };
+    const imageId = workbook.addImage({
+      base64: myBase64Image,
+      //extension: 'png',
+    });
+    worksheet.addImage(imageId, {
+      tl: tl,
+      ext: ext,
+    });
+  }
+};
+
+/**
+ * 冻结行列
+ * @param frozen
+ * @param worksheet
+ */
+var setFrozen = function (frozen = {}, worksheet) {
+  switch (frozen.type) {
+    // 冻结首行
+    case "row": {
+      worksheet.views = [{ state: "frozen", xSplit: 0, ySplit: 1 }];
+      break;
+    }
+    // 冻结首列
+    case "column": {
+      worksheet.views = [{ state: "frozen", xSplit: 1, ySplit: 0 }];
+      break;
+    }
+    // 冻结行列
+    case "both": {
+      worksheet.views = [{ state: "frozen", xSplit: 1, ySplit: 1 }];
+      break;
+    }
+    // 冻结行到选区
+    case "rangeRow": {
+      let row = frozen.range.row_focus + 1;
+      worksheet.views = [{ state: "frozen", xSplit: 0, ySplit: row }];
+      break;
+    }
+    // 冻结列到选区
+    case "rangeColumn": {
+      let column = frozen.range.column_focus + 1;
+      worksheet.views = [{ state: "frozen", xSplit: column, ySplit: 0 }];
+      break;
+    }
+    // 冻结行列到选区
+    case "rangeBoth": {
+      let row = frozen.range.row_focus + 1;
+      let column = frozen.range.column_focus + 1;
+      worksheet.views = [{ state: "frozen", xSplit: column, ySplit: row }];
+    }
+  }
+};
+
+/**
+ * 行隐藏
+ * @param rowhidden
+ * @param worksheet
+ */
+var setRowHidden = function (rowhidden = {}, worksheet) {
+  for (const key in rowhidden) {
+    //如果当前行没有内容则隐藏不生效
+    const row = worksheet.getRow(parseInt(key) + 1);
+    row.hidden = true;
+  }
+};
+
+/**
+ * 列隐藏
+ * @param colhidden
+ * @param worksheet
+ */
+var setColHidden = function (colhidden = {}, worksheet) {
+  for (const key in colhidden) {
+    const column = worksheet.getColumn(parseInt(key) + 1);
+    column.hidden = true;
+  }
+};
+
+/**
+ * 自动筛选器
+ * @param filter
+ * @param worksheet
+ */
+var setFilter = function (filter = {}, worksheet) {
+  if (Object.keys(filter).length === 0) return;
+  const from = {
+    row: filter.row[0] + 1,
+    column: filter.column[0] + 1,
+  };
+
+  const to = {
+    row: filter.row[1] + 1,
+    column: filter.column[1] + 1,
+  };
+
+  worksheet.autoFilter = {
+    from: from,
+    to: to,
+  };
+};
+
+/*var fillConvert = function (bg) {
+  if (!bg) {
+    return {}
+  }
+  // const bgc = bg.replace('#', '')
+  let fill = {
+    type: 'pattern',
+    pattern: 'solid',
+    fgColor: {argb: bg.startsWith("#") ? bg.replace('#', '') : colorRGBtoHex(bg).replace("#", "")},
+  }
+  return fill;
+}
+
+var fontConvert = function (
+    ff = 0,
+    fc = '#000000',
+    bl = 0,
+    it = 0,
+    fs = 10,
+    cl = 0,
+    ul = 0
+) {
+  // luckysheet:ff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线)
+  const luckyToExcel = {
+    0: '微软雅黑',
+    1: '宋体(Song)',
+    2: '黑体(ST Heiti)',
+    3: '楷体(ST Kaiti)',
+    4: '仿宋(ST FangSong)',
+    5: '新宋体(ST Song)',
+    6: '华文新魏',
+    7: '华文行楷',
+    8: '华文隶书',
+    9: 'Arial',
+    10: 'Times New Roman ',
+    11: 'Tahoma ',
+    12: 'Verdana',
+    num2bl: function (num) {
+      return num !== 0
+    }
+  }
+  // 出现Bug,导入的时候ff为luckyToExcel的val
+
+  let font = {
+    name: typeof ff === 'number' ? luckyToExcel[ff] : ff,
+    family: 1,
+    size: fs,
+    color: {argb: fc.startsWith("#") ? fc.replace('#', '') : colorRGBtoHex(fc).replace("#", "")},
+    bold: luckyToExcel.num2bl(bl),
+    italic: luckyToExcel.num2bl(it),
+    underline: luckyToExcel.num2bl(ul),
+    strike: luckyToExcel.num2bl(cl)
+  }
+
+  return font
+}*/
+
+var fillConvert = function (bg) {
+  if (!bg) {
+    return {};
+  }
+  // const bgc = bg.replace('#', '')
+  let fill = {
+    type: "pattern",
+    pattern: "solid",
+    fgColor: { argb: bg.replace("#", "") },
+  };
+  return fill;
+};
+
+var fontConvert = function (
+  ff = 0,
+  fc = "#000000",
+  bl = 0,
+  it = 0,
+  fs = 10,
+  cl = 0,
+  ul = 0
+) {
+  // luckysheet:ff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线)
+  const luckyToExcel = {
+    0: "微软雅黑",
+    1: "宋体(Song)",
+    2: "黑体(ST Heiti)",
+    3: "楷体(ST Kaiti)",
+    4: "仿宋(ST FangSong)",
+    5: "新宋体(ST Song)",
+    6: "华文新魏",
+    7: "华文行楷",
+    8: "华文隶书",
+    9: "Arial",
+    10: "Times New Roman ",
+    11: "Tahoma ",
+    12: "Verdana",
+    num2bl: function (num) {
+      return num === 0 ? false : true;
+    },
+  };
+  // 出现Bug,导入的时候ff为luckyToExcel的val
+
+  let font = {
+    name: typeof ff === "number" ? luckyToExcel[ff] : ff,
+    family: 1,
+    size: fs,
+    color: { argb: fc.replace("#", "") },
+    bold: luckyToExcel.num2bl(bl),
+    italic: luckyToExcel.num2bl(it),
+    underline: luckyToExcel.num2bl(ul),
+    strike: luckyToExcel.num2bl(cl),
+  };
+
+  return font;
+};
+var alignmentConvert = function (
+  vt = "default",
+  ht = "default",
+  tb = "default",
+  tr = "default"
+) {
+  // luckysheet:vt(垂直), ht(水平), tb(换行), tr(旋转)
+  const luckyToExcel = {
+    vertical: {
+      0: "middle",
+      1: "top",
+      2: "bottom",
+      default: "middle",
+    },
+    horizontal: {
+      0: "center",
+      1: "left",
+      2: "right",
+      default: "center",
+    },
+    wrapText: {
+      0: false,
+      1: false,
+      2: true,
+      default: false,
+    },
+    textRotation: {
+      0: 0,
+      1: 45,
+      2: -45,
+      3: "vertical",
+      4: 90,
+      5: -90,
+      default: 0,
+    },
+  };
+
+  let alignment = {
+    vertical: luckyToExcel.vertical[vt],
+    horizontal: luckyToExcel.horizontal[ht],
+    wrapText: luckyToExcel.wrapText[tb],
+    textRotation: luckyToExcel.textRotation[tr],
+  };
+  return alignment;
+};
+
+var borderConvert = function (borderType, style = 1, color = "#000") {
+  // 对应luckysheet的config中borderinfo的的参数
+  if (!borderType) {
+    return {};
+  }
+  const luckyToExcel = {
+    type: {
+      "border-all": "all",
+      "border-top": "top",
+      "border-right": "right",
+      "border-bottom": "bottom",
+      "border-left": "left",
+      "border-outside": "outside",
+      "border-inside": "inside",
+      "border-horizontal": "horizontal",
+      "border-vertical": "vertical",
+      "border-none": "none",
+    },
+    style: {
+      0: "none",
+      1: "thin",
+      2: "hair",
+      3: "dotted",
+      4: "dashDot", // 'Dashed',
+      5: "dashDot",
+      6: "dashDotDot",
+      7: "double",
+      8: "medium",
+      9: "mediumDashed",
+      10: "mediumDashDot",
+      11: "mediumDashDotDot",
+      12: "slantDashDot",
+      13: "thick",
+    },
+  };
+  let border = {};
+  border[luckyToExcel.type[borderType]] = {
+    style: luckyToExcel.style[style],
+    color: { argb: color.replace("#", "") },
+  };
+  return border;
+};
+
+function addborderToCell(borders, row_index, col_index) {
+  let border = {};
+  const luckyExcel = {
+    type: {
+      l: "left",
+      r: "right",
+      b: "bottom",
+      t: "top",
+    },
+    style: {
+      0: "none",
+      1: "thin",
+      2: "hair",
+      3: "dotted",
+      4: "dashDot", // 'Dashed',
+      5: "dashDot",
+      6: "dashDotDot",
+      7: "double",
+      8: "medium",
+      9: "mediumDashed",
+      10: "mediumDashDot",
+      11: "mediumDashDotDot",
+      12: "slantDashDot",
+      13: "thick",
+    },
+  };
+  // console.log('borders', borders)
+  for (const bor in borders) {
+    // console.log(bor)
+    if (borders[bor].color.indexOf("rgb") === -1) {
+      border[luckyExcel.type[bor]] = {
+        style: luckyExcel.style[borders[bor].style],
+        color: { argb: borders[bor].color.replace("#", "") },
+      };
+    } else {
+      border[luckyExcel.type[bor]] = {
+        style: luckyExcel.style[borders[bor].style],
+        color: { argb: borders[bor].color },
+      };
+    }
+  }
+
+  return border;
+}
+
+function createCellPos(n) {
+  let ordA = "A".charCodeAt(0);
+
+  let ordZ = "Z".charCodeAt(0);
+  let len = ordZ - ordA + 1;
+  let s = "";
+  while (n >= 0) {
+    s = String.fromCharCode((n % len) + ordA) + s;
+
+    n = Math.floor(n / len) - 1;
+  }
+  return s;
+}
+
+//rgb(255,255,255)转16进制 #ffffff
+function colorRGBtoHex(color) {
+  color = color.replace("rgb", "").replace("(", "").replace(")", "");
+  var rgb = color.split(",");
+  var r = parseInt(rgb[0]);
+  var g = parseInt(rgb[1]);
+  var b = parseInt(rgb[2]);
+  return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
+}
+export { exportExcel };

+ 260 - 0
src/components/ExcelView/index.vue

@@ -0,0 +1,260 @@
+<template>
+  <div class="oprea" v-if="option.opreaState">
+    <div class="header">
+      <div>
+        <el-button
+          type="primary"
+          class="btn"
+          v-if="option.confirm"
+          @click="confirm"
+          >保存</el-button
+        >
+        <el-button
+          type="primary"
+          class="btn"
+          v-if="option.out"
+          @click="downloadExcel"
+          >导出</el-button
+        >
+        <el-upload
+          accept=".xlsx"
+          ref="upload"
+          :on-change="leadingExcel"
+          :auto-upload="false"
+          :show-file-list="false"
+          class="in"
+          v-if="option.in"
+        >
+          <template #trigger>
+            <el-button type="primary" class="btn">导入</el-button>
+          </template>
+        </el-upload>
+      </div>
+      <div class="info">当前操作表格:{{ inName == "" ? "-" : inName }}</div>
+    </div>
+  </div>
+  <div
+    id="luckysheet"
+    :style="{
+      top:
+        option.opreaState == false ||
+        option.edit == false ||
+        (option.in == false && option.out == false && option.confirm == false)
+          ? 0
+          : 60,
+    }"
+  ></div>
+  <div v-show="isMaskShow" id="tip">Downloading</div>
+</template>
+
+<script setup>
+import { ref, onMounted, watch } from "vue";
+import { exportExcel } from "./export";
+import LuckyExcel from "luckyexcel";
+import resData from "./resetData";
+const props = defineProps({
+  data: {
+    type: [Object, null],
+    default: null,
+  },
+  option: {
+    type: Object,
+    default: () => ({
+      opreaState: true,
+      in: true,
+      out: true,
+      confirm: true,
+      print: true,
+      edit: true,
+    }),
+  },
+});
+const emits = defineEmits(["update:data", "confirm"]);
+const exceldata = ref(null);
+const resetdata = JSON.parse(resData);
+const inName = ref("");
+const isMaskShow = ref(false);
+const selected = ref("");
+const confirm = () => emits("confirm", luckysheet.getAllSheets());
+let sheets = null;
+//表格初始化默认值
+const resetOb = ref({
+  container: "luckysheet", // 设定DOM容器的id
+  title: "Luckysheet Demo", // 设定表格名称
+  lang: "zh", // 设定表格语言
+  title: false, // 工作簿名称
+  enableAddBackTop: true, //返回头部按钮
+  userInfo: false, // 右上角的用户信息展示样式
+  showinfobar: false, // 是否显示顶部信息栏
+  enableAddRow: false, // 是否允许添加行
+  enableAddBackTop: false, // 允许回到顶部
+  showConfigWindowResize: true, // 自动缩进界面
+  // showtoolbar:false, // 工具栏
+  column: 30,
+  row: 30,
+  showsheetbar: false, // 是否显示底部sheet页按钮
+  showsheetbarConfig: {
+    add: false, //新增sheet
+    menu: false, //sheet管理菜单
+    sheet: false, //sheet页显示
+  },
+  data: props.exceldata,
+  showtoolbarConfig: {
+    undoRedo: true, //撤销重做,注意撤消重做是两个按钮,由这一个配置决定显示还是隐藏
+    paintFormat: false, //格式刷
+    currencyFormat: false, //货币格式
+    percentageFormat: false, //百分比格式
+    numberDecrease: false, // '减少小数位数'
+    numberIncrease: false, // '增加小数位数
+    moreFormats: true, // '更多格式'
+    font: true, // '字体'
+    fontSize: true, // '字号大小'
+    bold: true, // '粗体 (Ctrl+B)'
+    italic: true, // '斜体 (Ctrl+I)'
+    strikethrough: true, // '删除线 (Alt+Shift+5)'
+    underline: true, // '下划线 (Alt+Shift+6)'
+    textColor: true, // '文本颜色'
+    fillColor: true, // '单元格颜色'
+    border: true, // '边框'
+    mergeCell: true, // '合并单元格'
+    horizontalAlignMode: true, // '水平对齐方式'
+    verticalAlignMode: true, // '垂直对齐方式'
+    textWrapMode: false, // '换行方式'
+    textRotateMode: false, // '文本旋转方式'
+    image: true, // '插入图片'
+    link: true, // '插入链接'
+    chart: false, // '图表'(图标隐藏,但是如果配置了chart插件,右击仍然可以新建图表)
+    postil: false, //'批注'
+    pivotTable: false, //'数据透视表'
+    function: false, // '公式'
+    frozenMode: false, // '冻结方式'
+    sortAndFilter: false, // '排序和筛选'
+    conditionalFormat: false, // '条件格式'
+    dataVerification: false, // '数据验证'
+    splitColumn: false, // '分列'
+    screenshot: false, // '截图'
+    findAndReplace: true, // '查找替换'
+    protection: false, // '工作表保护'
+    print: true, // '打印'
+  },
+});
+//设置第一个sheet
+const getActiveSheet = (sheets = []) => {
+  let data = [];
+  // 取激活项
+  sheets.some((item) => {
+    if (item.status === "1") {
+      data.push(item);
+      return true;
+    }
+  });
+  // 没有激活项,取第一项
+  if (data.length === 0) {
+    data.push(sheets[0]);
+  }
+  return data;
+};
+//导入
+const leadingExcel = (item, fileList) => {
+  const file = item.raw;
+  console.log("file", file);
+  if (file == null || file.name == "") {
+    return;
+  }
+  let name = file.name;
+  let suffixArr = name.split("."),
+    suffix = suffixArr[suffixArr.length - 1];
+  if (suffix != "xlsx") {
+    ElMessage.error("请导入xlsx格式的文件");
+    return;
+  }
+  LuckyExcel.transformExcelToLucky(file, function (exportJson, luckysheetfile) {
+    if (exportJson.sheets == null || exportJson.sheets.length == 0) {
+      ElMessage.error("请导入xlsx格式的文件");
+      return;
+    }
+    window.luckysheet.destroy();
+    const data = getActiveSheet(exportJson.sheets);
+    resetOb.value.data = data;
+    console.log(data, "data");
+    console.log("exportJson", exportJson);
+    emits("update:data", data);
+    exceldata.value = data;
+    inName.value = file.name;
+    console.log(exceldata.value, "22212312313");
+    window.luckysheet.create(resetOb.value);
+  });
+};
+//导出
+const downloadExcel = () => {
+  exportExcel(luckysheet.getAllSheets(), "TDM-excel");
+};
+const reset = () => {
+  luckysheet.destroy();
+};
+defineExpose({ confirm, reset });
+onMounted(() => {
+  if (props.data == null) {
+    exceldata.value = resetdata;
+    console.log(exceldata.value, "1");
+  } else {
+    console.log(props.data, "22");
+    exceldata.value = props.data;
+  }
+  luckysheet.create(resetOb.value);
+});
+</script>
+
+<style lang="scss" scoped>
+.oprea {
+  padding: 0 20px;
+  width: 100%;
+  height: 60px;
+  .header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    .in {
+      display: inline-block;
+    }
+    .btn {
+      width: 80px;
+      border-radius: 16px;
+      height: 40px;
+      font-size: 16px;
+      margin: 0 10px;
+    }
+    .info {
+      width: 260px;
+    }
+  }
+}
+#luckysheet {
+  margin: 0px;
+  padding: 0px;
+  position: absolute;
+  width: 100%;
+  left: 0px;
+  top: 50px;
+  bottom: 0px;
+}
+
+#uploadBtn {
+  font-size: 16px;
+}
+
+#tip {
+  position: absolute;
+  z-index: 1000000;
+  left: 0px;
+  top: 0px;
+  bottom: 0px;
+  right: 0px;
+  background: rgba(255, 255, 255, 0.8);
+  text-align: center;
+  font-size: 40px;
+  align-items: center;
+  justify-content: center;
+  display: flex;
+}
+</style>

+ 7 - 0
src/components/ExcelView/is.js

@@ -0,0 +1,7 @@
+export function getType(val) {
+  return Object.prototype.toString.call(val).slice(8, -1);
+}
+
+export function isFunction(val) {
+  return getType(val) === "Function";
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
src/components/ExcelView/resetData.js


+ 340 - 0
src/views/base/excel/result/index.vue

@@ -0,0 +1,340 @@
+<template>
+  <div class="mainContentBox">
+    <avue-crud
+      ref="crudRef"
+      v-model:search="search"
+      v-model="form"
+      :data="data"
+      :option="option"
+      v-model:page="page"
+      @row-save="createRow"
+      @row-update="updateRow"
+      @row-del="deleteRow"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+      @size-change="dataList"
+      @current-change="dataList"
+      @selection-change="selectionChange"
+    >
+      <template #drawingPath-form="scope">
+        <!--        <single-upload v-model="form.drawingPath" :generatePdf="true"/>-->
+        <FilesUpload
+          v-model:src-list="srcList"
+          v-model:pdf-list="pdfUrlList"
+          v-model:file-name-list="fileNameList"
+          :limit="10"
+          :generate-pdf="true"
+          @finished="testFiles"
+        />
+      </template>
+      <template #enable="scope">
+        <el-switch
+          active-value="1"
+          inactive-value="0"
+          inline-prompt
+          active-text="启用"
+          inactive-text="禁用"
+          v-model="scope.row.enable"
+          @click="changeItem(scope.row)"
+          class="ml-2"
+          style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
+        />
+      </template>
+      <template #menu="{ row, index, type }">
+        <PDFView
+          :need-to-show-pdf="true"
+          content-type="button"
+          :is-link="true"
+          :pdf-source="filePath + row.pdfPath"
+        />
+        <el-button @click="deleteRecord(row, index, done)" text type="primary"
+          >删除</el-button
+        >
+      </template>
+    </avue-crud>
+
+    <ExcelUpload ref="uploadRef" @finished="uploadFinished" />
+  </div>
+  <CommonTable
+    ref="ctableRef"
+    tableTitle="BOM添加"
+    tableType="MARTERIAL"
+    @selected-sure="onSelectedFinish"
+  />
+</template>
+<script setup lang="ts">
+import { ref, getCurrentInstance } from "vue";
+import { useCrud } from "@/hooks/userCrud";
+import { useCommonStoreHook, useDictionaryStore } from "@/store";
+import { updateDrawaing } from "@/api/drawing";
+import dictDataUtil from "@/common/configs/dictDataUtil";
+import PDFView from "@/components/PDFView/index.vue";
+const { isShowTable, tableType } = toRefs(useCommonStoreHook());
+// 数据字典相关
+const { dicts } = useDictionaryStore();
+const fileUrl = ref(""); //单文件
+const pdfUrlList = ref([]);
+const srcList = ref([]);
+const fileNameList = ref([]);
+const testFiles = () => {
+  form.value.pdfPathList = pdfUrlList.value;
+  form.value.drawingPathList = srcList.value;
+  form.value.drawingPath = srcList.value[0];
+  form.value.fileNameList = fileNameList.value;
+};
+const filePath = import.meta.env.VITE_APP_UPLOAD_URL;
+const test = () => {
+  isShowTable.value = true;
+  tableType.value = tableType.value == 1 ? 2 : 1;
+};
+const ctableRef = ref(null);
+const changeItem = (row) => {
+  updateDrawaing(row).then(() => {
+    ElMessage.success("操作成功");
+    dataList();
+  });
+};
+
+// 传入一个url,后面不带/
+const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
+  useCrud({
+    src: "/api/v1/base/drawing",
+  });
+const {
+  dataEditList,
+  createRow,
+  updateRow,
+  deleteRow,
+  searchChange,
+  dataList,
+  resetChange,
+} = Methords; //增删改查
+const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
+const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等工具
+// checkBtnPerm(ButtonPermKeys.PLAN.BTNS.order_add) :permission="permission"
+// const permission = reactive({
+//   delBtn: checkPerm(buttonPermission.PLAN.BTNS.order_del),
+//   addBtn: checkPerm(buttonPermission.PLAN.BTNS.order_add),
+//   editBtn: checkPerm(buttonPermission.PLAN.BTNS.order_edit),
+//   menu: true,
+// });
+
+const crudRef = ref(null); //crudRef.value 获取avue-crud对象
+const router = useRouter?.();
+
+onMounted?.(() => {
+  // console.log("crudRef", crudRef)
+  dataEditList();
+});
+
+const onSelectedFinish = (selectedValue) => {
+  form.value.associationCode = selectedValue.materialCode;
+  form.value.associationName = selectedValue.materialCode;
+  form.value.materialCode = selectedValue.materialCode;
+};
+
+/**
+ * 上传excel相关
+ */
+const uploadRef = ref(null);
+const uploadFinished = () => {
+  // 上传完成后的刷新操作
+  page.currentPage = 1;
+  dataEditList();
+};
+
+// 设置表格列或者其他自定义的option
+option.value = Object.assign(option.value, {
+  selection: false,
+  viewBtn: false,
+  editBtn: false,
+  delBtn: false,
+  menu: true,
+  column: [
+    {
+      label: "图纸编号",
+      prop: "drawingCode",
+      width: 150,
+      search: true,
+      overHidden: true,
+      rules: [
+        {
+          required: true,
+          message: "请填写图纸编号",
+          trigger: "blur",
+        },
+      ],
+    },
+    {
+      label: "图纸名称",
+      prop: "drawingTitle",
+      width: 150,
+      overHidden: true,
+      search: true,
+      rules: [
+        {
+          required: true,
+          message: "请填写图纸名称",
+          trigger: "blur",
+        },
+      ],
+    },
+    {
+      label: "物料编号",
+      prop: "associationCode",
+      width: 150,
+      search: true,
+      overHidden: true,
+      editDisplay: false,
+      addDisplay: false,
+      rules: [
+        {
+          required: true,
+          message: "请填写物料编号",
+          trigger: "blur",
+        },
+      ],
+    },
+
+    {
+      label: "物料编号",
+      prop: "materialCode",
+      width: 150,
+      overHidden: true,
+      editDisplay: false,
+      hide: true,
+      rules: [
+        {
+          required: true,
+          message: "请填写物料编号",
+          trigger: "blur",
+        },
+      ],
+      click() {
+        if (ctableRef.value) {
+          ctableRef.value.startSelect();
+        }
+      },
+    },
+    {
+      label: "物料名称",
+      prop: "associationName",
+      width: 180,
+      search: true,
+      overHidden: true,
+      disabled: true,
+      rules: [
+        {
+          required: true,
+          message: "请填写物料名称",
+          trigger: "blur",
+        },
+      ],
+    },
+    {
+      label: "图纸类型",
+      prop: "drawingDictValue",
+      search: true,
+      filterable: true,
+      type: "select",
+      width: 100,
+      overHidden: true,
+      dicUrl: dictDataUtil.request_url + "drawing_type",
+      props: { label: "dictLabel", value: "dictValue" },
+      rules: [
+        {
+          required: true,
+          message: "请选择物料属性",
+          trigger: "blur",
+        },
+      ],
+    },
+    {
+      label: "文件",
+      prop: "drawingPath",
+      span: 24,
+      slot: true,
+      hide: true,
+      rules: [
+        {
+          required: true,
+          message: "请选择文件",
+          trigger: "blur",
+        },
+      ],
+    },
+    {
+      label: "文件名称",
+      prop: "fileName",
+      span: 24,
+      width: 120,
+      overHidden: true,
+      display: false,
+    },
+    {
+      label: "文件数组",
+      prop: "drawingPathList",
+      span: 24,
+      hide: true,
+      display: false,
+    },
+    {
+      label: "pdf数组",
+      prop: "pdfPathList",
+      span: 24,
+      hide: true,
+      display: false,
+    },
+
+    {
+      label: "文件名称数组",
+      prop: "fileNameList",
+      span: 24,
+      slot: true,
+      hide: true,
+      display: false,
+    },
+    /*{ label: "文件",
+      prop: "drawing",
+      type: 'img',
+      span: 24,
+      display:false,
+      slot: true,
+      formatter: (row, column, cellValue, index) => {
+        return import.meta.env.VITE_APP_UPLOAD_URL + `${row.drawingPath}`;} },*/
+    {
+      label: "版本",
+      prop: "drawingVersion",
+      type: "number",
+      precision: 1,
+      rules: [
+        {
+          required: true,
+          message: "版本号不能为空",
+          trigger: "blur",
+        },
+      ],
+    },
+    {
+      label: "创建时间",
+      prop: "created",
+      width: 120,
+      overHidden: true,
+      display: false,
+    },
+    {
+      label: "启用状态",
+      slot: true,
+      headerAlign: "center",
+      prop: "enable",
+      width: 100,
+      addDisplay: false,
+    },
+  ],
+});
+
+const deleteRecord = (row, index, done) => {
+  deleteRow(row, index, done);
+  dataEditList();
+};
+</script>

+ 332 - 0
src/views/base/excel/template/index.vue

@@ -0,0 +1,332 @@
+<template>
+  <div class="mainContentBox">
+    <div class="body">
+      <div v-if="!excelStatus">
+        <avue-crud
+          ref="crudRef"
+          v-model:search="search"
+          v-model="form"
+          :data="data"
+          :option="option"
+          v-model:page="page"
+          @row-save="createRow"
+          @row-update="updateRow"
+          @row-del="deleteRow"
+          @search-change="searchChange"
+          @search-reset="resetChange"
+          @size-change="dataList"
+          @current-change="dataList"
+          @selection-change="selectionChange"
+        >
+          <template #menu-left="{}">
+            <el-button
+              @click="addTemplate"
+              class="ml-3"
+              type="primary"
+              icon="el-icon-plus"
+            >
+              新 增
+            </el-button>
+          </template>
+          <template #menu="{ row, index, type }">
+            <el-button @click="lookTep(row)" text type="primary"
+              >查看</el-button
+            >
+            <el-button @click="editTep(row, index, done)" text type="primary"
+              >编辑</el-button
+            >
+            <el-button @click="deleteTep(row, index, done)" text type="primary"
+              >删除</el-button
+            >
+          </template>
+        </avue-crud>
+      </div>
+      <div v-if="excelStatus" :key="excelKey" class="editView">
+        <div class="exView">
+          <ExcelView
+            ref="excelViewRef"
+            :option="options"
+            @confirm="confirm"
+            v-model:data="exceldata"
+          />
+        </div>
+        <div class="form" v-if="options.edit">
+          <div class="title">新建模版</div>
+          <el-form
+            ref="formRef"
+            :model="formVlaue"
+            :rules="rules"
+            label-width="auto"
+            status-icon
+          >
+            <el-form-item label="表格名称" prop="formName">
+              <el-input v-model="formVlaue.formName" />
+            </el-form-item>
+            <el-form-item label="表格类型" prop="formType">
+              <el-input v-model="formVlaue.formType" :disabled="true" />
+            </el-form-item>
+            <el-form-item label="启用状态" prop="state">
+              <el-select v-model="formVlaue.state" placeholder="请选择状态">
+                <el-option label="禁用" :value="0" />
+                <el-option label="启用" :value="1" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <div class="btns">
+                <el-button type="primary" @click="submitForm(formRef)">
+                  创 建
+                </el-button>
+                <el-button @click="resetForm(formRef)">重 置</el-button>
+                <el-button type="primary" @click="resetData"> 取 消 </el-button>
+              </div>
+            </el-form-item>
+          </el-form>
+        </div>
+        <div class="form" v-else>
+          <el-button type="primary" @click="excelStatus = false">
+            返 回
+          </el-button>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import { ref } from "vue";
+import { useCrud } from "@/hooks/userCrud";
+import {
+  addExcel,
+  delsExcel,
+  delExcel,
+  getInfo,
+  updateExcel,
+} from "@/api/excel";
+import dictDataUtil from "@/common/configs/dictDataUtil";
+import ExcelView from "@/components/ExcelView/index.vue";
+//初始化页面数据
+const resetData = () => {
+  excelViewRef.value.reset();
+  excelKey.value = excelKey.value + 1;
+  options.value = {
+    opreaState: true,
+    in: true,
+    out: true,
+    confirm: false,
+    print: true,
+    //编辑状态 false:为查看状态
+    edit: true,
+  };
+  exceldata.value = null;
+  excelStatus.value = false;
+  resetForm(formRef.value);
+};
+// 数据字典相关
+
+// 传入一个url,后面不带/
+const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
+  useCrud({
+    src: "/api/v1/excelForm",
+  });
+const {
+  dataEditList,
+  createRow,
+  updateRow,
+  deleteRow,
+  searchChange,
+  dataList,
+  resetChange,
+} = Methords; //增删改查
+const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
+
+const crudRef = ref(null); //crudRef.value 获取avue-crud对象
+const router = useRouter?.();
+
+// 设置表格列或者其他自定义的option
+option.value = Object.assign(option.value, {
+  selection: false,
+  viewBtn: false,
+  editBtn: false,
+  delBtn: false,
+  addBtn: false,
+  menu: true,
+  column: [
+    {
+      label: "表格名称",
+      prop: "formName",
+
+      search: true,
+      overHidden: true,
+      rules: [
+        {
+          required: true,
+          message: "请填写图纸编号",
+          trigger: "blur",
+        },
+      ],
+    },
+    {
+      label: "表格类型",
+      slot: true,
+      headerAlign: "center",
+      prop: "formType",
+
+      addDisplay: false,
+    },
+    {
+      label: "表格状态",
+      slot: true,
+      headerAlign: "center",
+      prop: "state",
+      addDisplay: false,
+    },
+    {
+      label: "修改时间",
+      slot: true,
+      headerAlign: "center",
+      prop: "updated",
+
+      addDisplay: false,
+    },
+  ],
+});
+const useAddTemplateHook = () => {
+  const excelViewRef = ref(null);
+  const options = ref({
+    opreaState: true,
+    in: true,
+    out: true,
+    confirm: false,
+    print: true,
+    //编辑状态 false:为查看状态
+    edit: true,
+  });
+  const exceldata = ref(null);
+  const excelStatus = ref(false);
+  //新增模版
+  const addTemplate = () => {
+    excelStatus.value = true;
+  };
+  //查看
+  const lookTep = (row:any) => {
+    exceldata.value = JSON.parse(row.excelData);
+    excelStatus.value = true;
+  };
+  //编辑
+  const editTep = () => {};
+  //删除
+  const deleteTep = () => {};
+
+  //获取组件内实时数据赋值到外层
+  const confirm = (data: any) => {
+    exceldata.value = data;
+  };
+  return {
+    excelStatus,
+    options,
+    addTemplate,
+    confirm,
+    exceldata,
+    excelViewRef,
+    lookTep,
+    editTep,
+    deleteTep,
+  };
+};
+const {
+  excelStatus,
+  options,
+  addTemplate,
+  confirm,
+  exceldata,
+  excelViewRef,
+  lookTep,
+  editTep,
+  deleteTep,
+} = useAddTemplateHook();
+const useFormHook = () => {
+  const excelKey = ref(1);
+  const formVlaue = reactive({ formType: "普通", formName: "", state: 0 });
+  const formRef = ref(null);
+  const rules = reactive({
+    formName: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+    formType: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+    state: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+  });
+  const submitForm = async (formEl: any) => {
+    //@ts-ignore;
+    excelViewRef.value.confirm();
+    if (exceldata.value == null) return ElMessage.error("请提供表格数据!");
+    if (!formEl) return;
+    await formEl.validate(async (valid: any, fields: any) => {
+      if (valid) {
+        const { data, code } = await addExcel({
+          ...formVlaue,
+          excelData: exceldata.value,
+        });
+        if (code == "200") {
+          ElMessage.success("添加成功!");
+          exceldata.value = null;
+          excelStatus.value = false;
+          dataEditList();
+        }
+      }
+    });
+  };
+
+  const resetForm = (formEl: any) => {
+    if (!formEl) return;
+    formEl.resetFields();
+  };
+  return { formVlaue, formRef, rules, excelKey, submitForm, resetForm };
+};
+
+const { formVlaue, formRef, rules, excelKey, submitForm, resetForm } =
+  useFormHook();
+
+onMounted?.(() => {
+  dataEditList();
+});
+</script>
+<style lang="scss" scoped>
+.editView {
+  width: 100%;
+  height: calc(100vh - 140px);
+  display: flex;
+
+  .exView {
+    position: relative;
+    width: calc(100% - 300px);
+    height: 100%;
+  }
+  .form {
+    width: 300px;
+    height: 100%;
+    font-size: 24px;
+    padding: 20px;
+    .title {
+      text-align: center;
+      margin-bottom: 10px;
+    }
+    .btns {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+}
+</style>