Prechádzať zdrojové kódy

Merge branch 'xf_dev' of http://maven.jgiot.com:7012/jiaxiaoqiang/JG-CLIENT-TEMP into xf_dev

jiaxiaoqiang 9 mesiacov pred
rodič
commit
d5eac126d3

+ 6 - 0
index.html

@@ -13,6 +13,12 @@
     name="keywords"
   />
   <title>金陵智造 | 鸿蒙工业系统</title>
+  <link rel="stylesheet" href="/LuckExcel/pluginsCss.css" />
+    <link rel="stylesheet" href="/LuckExcel/plugins.css" />
+    <link rel="stylesheet" href="/LuckExcel/luckysheet.css" />
+    <link rel="stylesheet" href="/LuckExcel/iconfont.css" />
+    <script src="/LuckExcel/plugin.js"></script>
+    <script src="/LuckExcel/luckysheet.umd.js"></script>
 </head>
 
 <body>

+ 3 - 0
package.json

@@ -54,7 +54,10 @@
     "dayjs": "^1.11.10",
     "echarts": "^5.5.0",
     "element-plus": "^2.6.0",
+    "exceljs": "^4.4.0",
+    "file-saver": "^2.0.5",
     "lodash-es": "^4.17.21",
+    "luckyexcel": "^1.0.1",
     "mitt": "^3.0.1",
     "net": "^1.0.2",
     "nprogress": "^0.2.0",

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 457 - 0
public/LuckExcel/iconfont.css


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 0
public/LuckExcel/luckysheet.css


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 111621 - 0
public/LuckExcel/luckysheet.umd.formatted.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 27 - 0
public/LuckExcel/luckysheet.umd.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 22392 - 0
public/LuckExcel/plugin.formatted.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 0
public/LuckExcel/plugin.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 10 - 0
public/LuckExcel/plugins.css


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 0
public/LuckExcel/pluginsCss.css


+ 7 - 0
src/api/process/traceability.ts

@@ -75,3 +75,10 @@ export function media(data: any) {
     data,
   });
 }
+export function excel(data: any) {
+  return request({
+    url: "/api/v1/ProcessFormData/page",
+    method: "post",
+    data,
+  });
+}

+ 19 - 0
src/api/prosteps/excel.ts

@@ -0,0 +1,19 @@
+import request from "@/utils/request";
+//获取列表
+export function getExcelData(operationId: string) {
+  return request({
+    url: `/api/v1/ProcessFormData/list/${operationId}`,
+    method: "get",
+  });
+}
+//保存
+export function setExcelData(data: any) {
+  return request({
+    url: "/api/v1/ProcessFormData/add",
+    method: "post",
+    data: data,
+    headers: {
+      "Content-Type": "multipart/form-data",
+    },
+  });
+}

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

@@ -0,0 +1,895 @@
+// 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;
+}
+function exportBlobExcel(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",
+    });
+    return blob;
+  });
+  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, exportBlobExcel };

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

@@ -0,0 +1,335 @@
+<template>
+  <div v-if="option.opreaState" class="oprea">
+    <div class="header">
+      <div style="display: flex">
+        <span v-if="option.out" class="btn" @click="downloadExcel">导出</span>
+        <!-- <el-button
+          type="primary"
+          class="btn"
+          v-if="option.out"
+          @click="print"
+          v-print="'#print_html'"
+          >打印</el-button
+        > -->
+        <el-upload
+          v-if="option.in"
+          ref="upload"
+          :auto-upload="false"
+          :on-change="leadingExcel"
+          :show-file-list="false"
+          accept=".xlsx"
+          class="in"
+        >
+          <!--          <template #trigger>
+            <span class="btn">导入</span>
+          </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>
+  <div id="print_html" style="text-align: center"></div>
+</template>
+
+<script setup>
+import { onMounted, ref, watch } from "vue";
+import { exportExcel, exportBlobExcel } from "./export";
+import LuckyExcel from "luckyexcel";
+import resData from "./resetData";
+
+const props = defineProps({
+  //双向绑定的data
+  data: {
+    type: [Object, null],
+    default: null,
+  },
+  //配置项
+  option: {
+    type: Object,
+    default: () => ({
+      //控制上部分展示
+      opreaState: true,
+      in: true,
+      out: true,
+      print: true,
+      edit: true,
+      inName: "",
+    }),
+  },
+  //校验区域
+  verifications: {
+    type: Array,
+    default: () => [],
+  },
+  //校验状态
+  checkStatus: {
+    type: Boolean,
+    default: false,
+  },
+});
+//update:data : v-model表格data ,confirm : 获取此时表格data
+const emits = defineEmits(["update:data", "confirm"]);
+//新增默认表格data
+const resetdata = JSON.parse(resData);
+//展示名称
+const inName = ref("");
+//loading 变量
+const isMaskShow = ref(false);
+//表格初始化默认值
+const resetOb = ref({
+  container: "luckysheet", // 设定DOM容器的id
+  title: "Luckysheet Demo", // 设定表格名称
+  lang: "zh", // 设定表格语言
+  enableAddBackTop: true, //返回头部按钮
+  userInfo: false, // 右上角的用户信息展示样式
+  showinfobar: false, // 是否显示顶部信息栏
+  showConfigWindowResize: true, // 自动缩进界面
+  column: 30,
+  row: 30,
+  showsheetbar: false, // 是否显示底部sheet页按钮
+  showsheetbarConfig: {
+    add: false, //新增sheet
+    menu: false, //sheet管理菜单
+    sheet: false, //sheet页显示
+    print: false,
+  },
+  cellRightClickConfig: {
+    //右键单元格菜单设置
+    copy: true, // 复制
+    copyAs: true, // 复制为
+    paste: true, // 粘贴
+    insertRow: true, // 插入行
+    insertColumn: true, // 插入列
+    deleteRow: true, // 删除选中行
+    deleteColumn: true, // 删除选中列
+    deleteCell: true, // 删除单元格
+    hideRow: true, // 隐藏选中行和显示选中行
+    hideColumn: true, // 隐藏选中列和显示选中列
+    rowHeight: true, // 行高
+    columnWidth: true, // 列宽
+    clear: true, // 清除内容
+    matrix: true, // 矩阵操作选区
+    sort: true, // 排序选区
+    filter: true, // 筛选选区
+    chart: true, // 图表生成
+    image: true, // 插入图片
+    link: true, // 插入链接
+    data: true, // 数据验证
+    cellFormat: true, // 设置单元格格式
+  },
+  data: null,
+});
+//print
+const print = () => {
+  console.log(luckysheet);
+  $("#luckysheet-left-top").click();
+  // 2. 生成选区的截图
+  let src = luckysheet.getScreenshot();
+  let $img = `<img src=${src} style="max-width: 90%;" />`;
+  nextTick(() => {
+    document.querySelector("#print_html").innerHTML = $img;
+  });
+};
+//设置第一个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;
+  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;
+    emits("update:data", data);
+    inName.value = file.name;
+    window.luckysheet.create(resetOb.value);
+  });
+};
+//导出
+const downloadExcel = () => {
+  exportExcel(luckysheet.getAllSheets(), "导出表格");
+};
+//获取当前表格数据的blob
+const downloadBlobExcel = async () => {
+  const sheets = luckysheet.getAllSheets();
+  const [blob] = await Promise.all([exportBlobExcel(sheets, "导出表格")]);
+  return blob;
+};
+//获取此时表格数据
+const confirm = () => emits("confirm", luckysheet.getAllSheets());
+const getData = () => luckysheet.getAllSheets();
+//销毁
+const reset = () => {
+  luckysheet.destroy();
+};
+//保存当次cell数据
+const saveCellData = () => {
+  const enter = () => {
+    let event = new KeyboardEvent("keydown", {
+      key: "Enter",
+      code: "Enter",
+      keyCode: 13,
+      which: 13,
+      shiftKey: false,
+      ctrlKey: false,
+      altKey: false,
+      metaKey: false,
+      bubbles: true,
+      cancelable: true,
+    });
+    // 分发事件到document
+    document.dispatchEvent(event);
+  };
+  enter();
+};
+//配置单元格校验
+const setVerification = () => {
+  for (let i = 0; i < props.verifications.length; i++) {
+    if (
+      !props.verifications[i].checkStr ||
+      props.verifications[i].checkStr === ""
+    ) {
+    } else {
+      let option = {
+        type: "number",
+        type2: "bw",
+        value1: JSON.parse(props.verifications[i].checkStr).down,
+        value2: JSON.parse(props.verifications[i].checkStr).up,
+        hintShow: true,
+        hintText: `请输入${JSON.parse(props.verifications[i].checkStr).down}-${JSON.parse(props.verifications[i].checkStr).up}的数字`,
+      };
+      luckysheet.setDataVerification(
+        { ...option },
+        { range: props.verifications[i].position }
+      );
+    }
+  }
+};
+defineExpose({ confirm, reset, saveCellData, getData, downloadBlobExcel });
+onMounted(() => {
+  if (props.data == null) {
+    inName.value = "表格模版";
+    resetOb.value.data = resetdata;
+  } else {
+    inName.value = props.option.inName;
+    resetOb.value.data = props.data;
+  }
+  if (props.option.edit == false) {
+    resetOb.value.allowEdit = false;
+  }
+  luckysheet.create(resetOb.value);
+});
+watch(
+  () => props.verifications,
+  () => {
+    nextTick(() => {
+      if (props.checkStatus == true && props.verifications.length > 0) {
+        setVerification();
+      }
+    });
+  },
+  { immediate: true }
+);
+</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;
+      margin-top: 1px;
+    }
+
+    .btn {
+      width: 80px;
+      border-radius: 16px;
+      height: 40px;
+      font-size: 20px;
+      margin: 0 10px;
+      border: 2px dashed #000;
+      font-weight: 500;
+      @include flex;
+    }
+
+    .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";
+}

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 0
src/components/ExcelView/resetData.js


+ 8 - 0
src/router/modules/process.ts

@@ -59,6 +59,14 @@ export default {
           },
         },
         {
+          path: "excel",
+          component: () => import("@/views/pro-steps/components/excel.vue"),
+          name: "Excel",
+          meta: {
+            back: true,
+          },
+        },
+        {
           path: "mingpaibangding",
           component: () =>
             import("@/views/pro-steps/components/mingpaibangding.vue"),

+ 88 - 49
src/views/material-flow/creatTask.vue

@@ -1,11 +1,10 @@
 <template>
   <div>
     <el-row :gutter="20">
-      <el-col :span="16">
-        <div class="type-title">当前料箱</div>
-
+      <el-col :span="24">
         <div style="display: flex; margin-bottom: 15px">
-          <div class="current-box">
+          <div class="type-title">当前料箱</div>
+          <div class="current-box" style="width: 25vw">
             <span class="left">料箱id: {{ boxDetail?.rfid ?? "" }}</span>
             <!--            <span class="right">{{ boxDetail?.code || "未绑定料箱" }}</span>-->
           </div>
@@ -13,30 +12,34 @@
             v-model="currentBox"
             :clearable="true"
             placeholder="请扫描或输入料箱编号"
-            style="width: 50%"
+            style="width: 30vw"
             @keyup.enter="enterBox"
           />
         </div>
-
-        <div class="type-title">请扫码物料</div>
-        <ScanCodeInput
-          v-model="scanCodeInput"
-          placeholder="请扫描或输入物料编码"
-          @keyup.enter="handleScanCodeInput"
-        />
+        <div style="display: flex; margin-bottom: 15px">
+          <div class="type-title">请扫码物料</div>
+          <ScanCodeInput
+            v-model="scanCodeInput"
+            style="width: 30vw"
+            placeholder="请扫描或输入物料编码"
+            @keyup.enter="handleScanCodeInput"
+          />
+        </div>
         <div
           v-loading="map.get('getMaterialInfoByLabel')"
-          style="height: calc(100vh - 450px); margin-top: 15px"
+          style="height: calc(100vh - 350px); margin-top: 15px"
         >
           <el-scrollbar>
             <div class="list-container">
               <div
                 v-for="(item, index) in materialList"
-                :key="index"
+                :key="item"
                 class="list-box"
               >
                 <div>
                   <div class="name">{{ item.materialName }}</div>
+                  <div class="spec">{{ item.materialCode }}</div>
+                  <div class="spec">{{ item.batchNo }}</div>
                   <div class="spec">{{ item.spec }}</div>
                 </div>
                 <div class="bottom">
@@ -58,7 +61,7 @@
           </el-scrollbar>
         </div>
       </el-col>
-      <el-col :span="8">
+      <!-- <el-col :span="8" style="position: relative">
         <div class="type-title">流转终点</div>
         <div class="destination">
           <el-scrollbar>
@@ -70,38 +73,43 @@
               @click="onEndBoxClick(index, item)"
             >
               <div class="name">{{ item.name }}</div>
-              <!--            <div-->
-              <!--              v-if="-->
-              <!--                item.targetType === 'stock' && index === currentDestinationIndex-->
-              <!--              "-->
-              <!--            >-->
-              <!--              <el-select-->
-              <!--                v-model="selectStore"-->
-              <!--                filterable-->
-              <!--                placeholder="请选择"-->
-              <!--                size="large"-->
-              <!--                style="width: 200px"-->
-              <!--                value-key="id"-->
-              <!--              >-->
-              <!--                <el-option-->
-              <!--                  v-for="store in storeMap.get(item.houseNo)"-->
-              <!--                  :key="store.id"-->
-              <!--                  :label="store.name"-->
-              <!--                  :value="store"-->
-              <!--                />-->
-              <!--              </el-select>-->
-              <!--            </div>-->
             </div>
           </el-scrollbar>
         </div>
-        <el-button
-          class="sureBtn el-button-big"
-          type="primary"
-          @click="createTask"
-          >创建任务
-        </el-button>
-      </el-col>
+      </el-col> -->
+      <el-button
+        class="sureBtn el-button-big"
+        type="primary"
+        @click="popStatus = true"
+        >创建任务
+      </el-button>
     </el-row>
+    <!-- 弹窗 -->
+    <div class="midPopUp" v-if="popStatus" @click="handleClose">
+      <div class="container" @click.stop>
+        <div class="body">
+          <div class="destination">
+            <el-scrollbar>
+              <div
+                v-for="(item, index) in destinationList"
+                :key="index"
+                :class="{ selected: index === currentDestinationIndex }"
+                class="end-box"
+                @click="onEndBoxClick(index, item)"
+              >
+                <div class="name">{{ item.name }}</div>
+              </div>
+            </el-scrollbar>
+          </div>
+        </div>
+        <div class="bottomBtn">
+          <el-button class="leftBtn" @click="handleClose">取消</el-button>
+          <el-button class="rightBtn" @click="createTask" type="primary"
+            >确认</el-button
+          >
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -114,7 +122,11 @@ import {
   getStationInfo,
 } from "@/api/process/materialFlow";
 import { useCommonStoreHook, useUserStore } from "@/store";
-
+const popStatus = ref(false);
+const handleClose = () => {
+  popStatus.value = false;
+};
+const submit = () => {};
 const commonS = useCommonStoreHook();
 const userStore = useUserStore();
 const map = commonS.loadingMap;
@@ -233,19 +245,42 @@ const createTask = () => {
 
     scanCodeInput.value = "";
     materialList.value = [];
+    handleClose();
   });
 };
 </script>
 
 <style lang="scss" scoped>
 .type-title {
+  width: 190px;
   font-weight: 500;
   font-size: 30px;
   color: rgba(0, 0, 0, 0.9);
   text-align: left;
   margin-bottom: 15px;
 }
-
+.midPopUp {
+  z-index: 999;
+  .container {
+    display: flex;
+    .body {
+      flex: 1;
+      height: calc(100% - 40px);
+      padding: 0 10%;
+    }
+    .bottomBtn {
+      height: 40px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      .el-button {
+        width: 120px;
+        height: 40px;
+        font-size: 20px;
+      }
+    }
+  }
+}
 .current-box {
   background: rgba(0, 0, 0, 0.06);
   border-radius: 16px 16px 16px 16px;
@@ -278,10 +313,10 @@ const createTask = () => {
   /*列间距*/
   grid-column-gap: 24px;
 
-  grid-template-columns: 1fr 1fr;
+  grid-template-columns: 1fr 1fr 1fr;
 
   .list-box {
-    height: 210px;
+    height: 240px;
     background: #fff;
     border-radius: 16px 16px 16px 16px;
     display: flex;
@@ -327,7 +362,7 @@ const createTask = () => {
 }
 
 .destination {
-  height: calc(100vh - 350px);
+  height: calc(100% - 40px);
   margin-top: 15px;
 
   .end-box {
@@ -365,9 +400,13 @@ const createTask = () => {
   height: 80px;
   background: #0a59f7;
   border-radius: 76px 76px 76px 76px;
-  width: 100%;
+  width: 32vw;
   margin-top: 10px;
   font-size: $f24;
+  position: fixed;
+  top: 70px;
+  right: 24px;
+  z-index: 9;
 }
 
 .number {

+ 3 - 3
src/views/pro-operation/inspect/components/checkForm.vue

@@ -23,7 +23,7 @@
       </el-select>
     </el-form-item>
     <el-form-item label="备注" prop="remark">
-      <el-input type="textarea" v-model="modelValue.remark"></el-input>
+      <el-input type="textarea" v-model="modelValue.remark" />
     </el-form-item>
     <el-form-item label="上传附件">
       <FilesUpload v-model:src="modelValue.filePath" ref="uploadRef" />
@@ -55,8 +55,8 @@ const props = defineProps({
 const SeqArray = ref([]);
 const emits = defineEmits(["update:modelValue", "submit"]);
 const getSeq = async () => {
-  //const { data } = await getSeqData(processStore.scanInfo.id);
-  SeqArray.value = [processStore.useSeqNo]
+  const { data } = await getSeqData(processStore.scanInfo.id);
+  SeqArray.value = data.processWorkSeq;
 };
 onMounted(() => {
   getSeq();

+ 3 - 1
src/views/pro-operation/inspect/index.vue

@@ -180,7 +180,6 @@ const search = ref({
 });
 const downLoad = async (url) => {
   let resUrl = url;
-  console.log(import.meta.env.VITE_APP_API_URL, "res");
   await downloadFile(resUrl, "附件");
 };
 const addCheck = () => {
@@ -215,6 +214,7 @@ const addCheckAsync = async () => {
     operator: checkName.value,
     processId: processStore.scanInfo.id,
     fileName: fileName.value,
+    operationName: processStore.scanInfo.operationName,
   });
   if (code == "200") {
     ElMessage.success("操作成功!");
@@ -241,6 +241,7 @@ const editCheckAsync = async () => {
     operator: checkName.value,
     processId: processStore.scanInfo.id,
     fileName: fileName.value,
+    operationName: processStore.scanInfo.operationName,
   });
   if (code == "200") {
     ElMessage.success("操作成功!");
@@ -276,6 +277,7 @@ const getPagination = async () => {
     operationId: processStore.odersData.operationId,
     workOrderCode: processStore.odersData.workOrderCode,
     seqNo: processStore.useSeqNo,
+    operationName: processStore.scanInfo.operationName,
   });
   search.value.total = data.totalCount;
   dataList.value = data.records;

+ 255 - 0
src/views/pro-steps/components/excel.vue

@@ -0,0 +1,255 @@
+<template>
+  <div v-if="!excelViewStatus">
+    <el-table :data="tableData" class="tableView">
+      <el-table-column fixed prop="formName" label="模板名称" align="center" />
+      <el-table-column prop="writeData" align="center" label="是否已填报">
+        <template #default="scope">
+          <span
+            :class="{
+              'red-text': scope.row.writeData === '',
+              'green-text': scope.row.writeData !== '',
+            }"
+          >
+            {{ scope.row.writeData === "" ? "否" : "是" }}
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" fixed="right" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            v-if="scope.row.writeData !== ''"
+            class="btnText"
+            type="primary"
+            @click="handleLook(scope.row)"
+          >
+            查看
+          </el-button>
+          <el-button
+            link
+            class="btnText"
+            type="primary"
+            @click="handleEdit(scope.row)"
+          >
+            编辑
+          </el-button>
+
+          <el-popconfirm
+            v-if="scope.row.writeData !== ''"
+            :visible="scope.row.dialogVisible"
+            title="您确认重置吗?(重置此操作不可逆)"
+            width="200"
+            @cancel="scope.row.dialogVisible = false"
+            @confirm="reset(scope.row)"
+          >
+            <el-button> 取消 </el-button>
+            <el-button type="primary"> 确认 </el-button>
+            <template #reference>
+              <el-button
+                link
+                class="btnText"
+                type="primary"
+                @click="scope.row.dialogVisible = true"
+                >重置</el-button
+              >
+            </template>
+          </el-popconfirm>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+  <div class="excelView" v-else>
+    <div class="view">
+      <ExcelView
+        v-model:data="excelData"
+        :option="excelOptions"
+        ref="excelViewRef"
+        :checkStatus="true"
+        :verifications="setting"
+      />
+    </div>
+    <div class="opeara">
+      <div>
+        <el-button
+          v-if="excelOptions.edit"
+          type="primary"
+          class="btn"
+          @click="submitData"
+          >提交</el-button
+        >
+        <el-button class="btn" @click="resetData">{{
+          excelOptions.edit ? "取消" : "返回"
+        }}</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup>
+defineOptions({
+  name: "Excel",
+});
+import { getExcelData, setExcelData } from "@/api/prosteps/excel";
+import { useProcessStore } from "@/store";
+import { useDictionaryStore } from "@/store";
+const setting = ref([]);
+const dictS = useDictionaryStore();
+const store = useProcessStore();
+const tableData = ref([]);
+const dataList = async () => {
+  const { data } = await getExcelData(store.scanInfo.id);
+  tableData.value = data;
+};
+const useExcelHook = () => {
+  const excelViewStatus = ref(false);
+  const excelData = ref(null);
+  const excelViewRef = ref(null);
+  const excelSelectRow = ref(null);
+  const excelOptions = ref({
+    opreaState: true,
+    in: true,
+    out: true,
+    print: true,
+    edit: true,
+    inName: "",
+  });
+  const resetData = () => {
+    if (excelViewRef.value) {
+      excelViewRef.value.saveCellData();
+      excelViewRef.value.reset();
+    }
+    excelViewStatus.value = false;
+    excelData.value = null;
+    excelSelectRow.value = null;
+    excelOptions.value = {
+      opreaState: true,
+      in: true,
+      out: true,
+      print: true,
+      edit: true,
+      inName: "",
+    };
+  };
+  const reset = async (row) => {
+    excelData.value = "";
+    const { data, code } = await setExcelData({
+      excelData: excelData.value,
+      formName: row.formName,
+      excelFormId: row.excelFormId,
+      formType: row.formType,
+      processId: store.scanInfo.id,
+    });
+    if (code == "200") {
+      ElMessage.success("操作成功!");
+      row.dialogVisible = false;
+      resetData();
+      dataList();
+    }
+  };
+  const handleEdit = (row) => {
+    excelSelectRow.value = row;
+    if (row.writeData == "") {
+      excelData.value = JSON.parse(row.excelData);
+    } else {
+      excelData.value = JSON.parse(row.writeData);
+    }
+    excelOptions.value.inName = row.formName;
+    excelViewStatus.value = true;
+    setting.value = row.settings;
+  };
+  const handleLook = (row) => {
+    excelOptions.value.edit = false;
+    excelData.value = JSON.parse(row.writeData);
+    excelOptions.value.inName = row.formName;
+    excelViewStatus.value = true;
+  };
+  const submitData = async () => {
+    const blobPromise = excelViewRef.value.downloadBlobExcel();
+    blobPromise.then(async (blob) => {
+      const formData = new FormData();
+      excelData.value = excelViewRef.value.getData();
+      formData.append("file", blob);
+      formData.append("excelData", JSON.stringify(excelData.value)); // 确保非文件数据被正确格式化
+      formData.append("excelFormId", excelSelectRow.value.excelFormId);
+      formData.append("formName", excelSelectRow.value.formName);
+      formData.append("formType", excelSelectRow.value.formType);
+      formData.append("processId", store.scanInfo.id);
+      const { data, code } = await setExcelData(formData);
+      if (code == "200") {
+        ElMessage.success("操作成功!");
+        resetData();
+        dataList();
+      }
+    });
+  };
+  return {
+    excelViewStatus,
+    excelOptions,
+    excelData,
+    excelViewRef,
+    resetData,
+    handleEdit,
+    submitData,
+    handleLook,
+    reset,
+  };
+};
+const {
+  excelViewStatus,
+  excelOptions,
+  excelData,
+  excelViewRef,
+  resetData,
+  handleEdit,
+  submitData,
+  handleLook,
+  reset,
+} = useExcelHook();
+onMounted(() => {
+  dataList();
+});
+</script>
+<style lang="scss" scoped>
+.btnText {
+  font-size: $f20;
+  color: black;
+}
+.excelView {
+  width: 100%;
+  height: calc(100vh - 260px);
+  padding: 20px;
+  display: flex;
+  background-color: white;
+  border-radius: 16px;
+  .view {
+    position: relative;
+    flex: 1;
+    height: calc(100vh - 300px);
+  }
+  .opeara {
+    width: 200px;
+    height: 100%;
+    padding: 10px;
+    display: flex;
+    align-items: center;
+  }
+}
+.tableView {
+  width: 100%;
+  height: calc(100vh - 260px);
+  padding: 20px 0px;
+  border-radius: 16px;
+}
+.btn {
+  width: 180px;
+  border-radius: 16px;
+  height: 40px;
+  font-size: 16px;
+  margin: 10px 0;
+}
+.red-text {
+  color: red;
+}
+.green-text {
+  color: green;
+}
+</style>

+ 8 - 8
src/views/pro-steps/components/operates.vue

@@ -74,6 +74,14 @@ const stepComponents = ref([
     compentType: "liuzhuan",
   },
   {
+    compentName: "检验",
+    compentType: "jianyan",
+  },
+  {
+    compentName: "编号填写",
+    compentType: "bianhao",
+  },
+  {
     compentName: "图纸",
     compentType: "tuzhi",
   },
@@ -89,14 +97,6 @@ const stepComponents = ref([
     compentName: "报工",
     compentType: "baogong",
   },
-  {
-    compentName: "检验",
-    compentType: "jianyan",
-  },
-  {
-    compentName: "编号填写",
-    compentType: "bianhao",
-  },
 ]);
 </script>
 

+ 15 - 5
src/views/pro-steps/components/wuliaocaiji.vue

@@ -14,13 +14,13 @@
   <div v-else class="materialInfoBody">
     <div
       v-for="item in opCompentDataList"
-      :class="
-        item.needNum - item.realNum == 0 ? 'infoMsg infoMsgImg' : 'infoMsg'
-      "
+      :class="[item.needNum - item.realNum === 0 ? 'infoMsg infoMsgImg blueBgClass' : 'infoMsg whiteBgClass']"
+
       @click="toXQPop(item)"
     >
       <div class="leftMsg">
         <div class="nameMsg">{{ item.itemName }}</div>
+        <div class="describe">{{ item.itemCode }}</div>
         <div class="describe">{{ item.itemModel }}</div>
         <div class="describe">需求:{{ item.needNum }}</div>
       </div>
@@ -109,7 +109,7 @@ const submitRecordAdd = async (index) => {
     ElMessage.error("请先选择物料,并确定数量在提交录入信息");
     return;
   }
-  if (!chooseData.num || chooseData.num < 1) {
+  if (!chooseData.num) {
     ElMessage.error("请输入数量!");
     return;
   }
@@ -171,11 +171,21 @@ onMounted(() => {
     background-image: url("@/assets/images/caijiwancheng.png");
     background-position: right top;
     background-repeat: no-repeat;
+    background-size: 100px 100px;
+
+  }
+
+  .blueBgClass {
+    background-color: #64bb5c;
+  }
+
+  .whiteBgClass {
+    background-color: #ffffff;
   }
 
   .infoMsg {
     height: 190px;
-    background-color: white;
+
     border-radius: 16px;
     display: flex;
     padding: $p20;

+ 6 - 0
src/views/pro-steps/index.vue

@@ -161,6 +161,12 @@ const defaultComponents = [
     path: "ceshijilu",
     name: "Ceshijilu",
   },
+  {
+    compentName: "工序表单",
+    iconName: "mingpai",
+    path: "execl",
+    name: "Excel",
+  },
 ];
 //当前路由在setpComponents中的index
 const selectIndex = ref(0);

+ 1 - 0
src/views/pro-steps/popUpView/caijiRightPopUp.vue

@@ -17,6 +17,7 @@
           >
             <div class="leftInfo">
               <div class="titleText">{{ item.materialName }}</div>
+              <div class="describeText">{{ item.materialCode }}</div>
               <div class="describeText">规格:{{ item.spec }}</div>
               <!-- <div class="describeText">批次号:xxx</div>
               <div class="describeText">计划编号:xxx</div>

+ 3 - 1
src/views/pro-steps/popUpView/xiangqingPopUp.vue

@@ -5,6 +5,7 @@
       <div class="infoBox">
         <div class="leftInfo">
           <div class="titleText">{{ showInfo.itemName }}</div>
+          <div class="describeText">{{ showInfo.itemCode }}</div>
           <div class="describeText">{{ showInfo.itemModel }}</div>
           <!-- <div class="describeText">计划编号:{{ showInfo.batchNo }}</div>
           <div class="describeText">订单编号:{{ showInfo.itemName }}</div>
@@ -28,7 +29,8 @@
             v-for="(item, index) in showInfoData"
             :key="index"
           >
-            {{ item.itemSeq }} * {{ item.num }}
+            {{ item.batchNo }} &nbsp;&nbsp;&nbsp;&nbsp;* {{ item.num }}
+            <span style="margin-right: 10px;"></span>
           </div>
           <Empty v-if="showInfoData.length == 0" />
         </div>

+ 5 - 5
src/views/process/components/order.vue

@@ -120,11 +120,11 @@ const planStyle = (val) => {
 }
 
 .productName {
-  font-size: $f24;
+  font-size: $f20;
 }
 
 .msgName {
-  font-size: $f20;
+  font-size: 16px;
   color: $font-default-60;
 }
 
@@ -134,7 +134,7 @@ const planStyle = (val) => {
 
 .msgValue {
   margin-left: 5px;
-  font-size: $f20;
+  font-size: 16px;
 }
 
 .bottomArea {
@@ -158,12 +158,12 @@ const planStyle = (val) => {
 .boxNum {
   text-align: center;
   line-height: 38px;
-  font-size: $f38;
+  font-size: 34px;
 }
 
 .boxText {
   text-align: center;
-  font-size: $f20;
+  font-size: 16px;
   line-height: 20px;
   color: $font-default-60;
 }

+ 108 - 0
src/views/traceability/components/excel.vue

@@ -0,0 +1,108 @@
+<template>
+  <div class="collapseStyle" :height="tableHeight + 100">
+    <el-scrollbar
+      v-loading="loading"
+      style="border: 1px solid #ebeef5"
+      :height="tableHeight"
+    >
+      <el-collapse accordion v-model="activeNames">
+        <el-collapse-item
+          v-for="(item, index) in materialsData"
+          :key="item"
+          :title="item.operationName"
+          :name="index"
+        >
+          <el-table :data="item.children" border>
+            <el-table-column prop="formName" label="表格名称" />
+            <el-table-column prop="formType" label="表格类型">
+              <template #default="scope">
+                {{ dictS.getLableByValue("excel_type", scope.row.formType) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" prop="operation">
+              <template #default="{ row }">
+                <el-button
+                  style="font-size: 18px; color: black"
+                  link
+                  @click="showExcelDialog(row)"
+                  >查看</el-button
+                >
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-collapse-item>
+      </el-collapse>
+      <Empty v-if="materialsData.length < 1" />
+    </el-scrollbar>
+    <Pagination
+      position="right"
+      :page="page"
+      :limit="limit"
+      :total="total"
+      @pagination="getPagination"
+    />
+    <el-dialog
+      v-model="excelDialogVisible"
+      title="查看表单"
+      :append-to-body="true"
+      :destroy-on-close="true"
+      width="70%"
+      height="80%"
+      @close="excelDialogVisible = true"
+    >
+      <TaskExcel v-if="excelDialogVisible" :data="excelData" />
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { useProcessStore } from "@/store";
+import { excel } from "@/api/process/traceability";
+import { useDictionaryStore } from "@/store";
+import TaskExcel from "./taskExcel.vue";
+const dictS = useDictionaryStore();
+const store = useProcessStore();
+const activeNames = ref([0]);
+const updataShow = ref(false);
+const updateTitle = ref("表格数据");
+const page = ref(1);
+const limit = ref(10);
+const total = ref(10);
+const materialsData = ref([]);
+const tableHeight = ref(null);
+const loading = ref(false);
+//  查看excel相关
+const excelDialogVisible = ref(false);
+const showExcelDialog = async (row) => {
+  excelData.value = row;
+  excelDialogVisible.value = true;
+};
+const excelData = ref(null);
+const getPagination = async () => {
+  loading.value = true;
+  try {
+    const { data } = await excel({
+      pageNo: page.value,
+      pageSize: limit.value,
+      seqNo: store.useSeqNo,
+      workOrderCode: store.odersData.workOrderCode,
+    });
+    // total.value = data.totalCount;
+    materialsData.value = data;
+  } catch {
+  } finally {
+    loading.value = false;
+  }
+};
+//动态控制高度
+const setTableHeight = () => {
+  tableHeight.value =
+    Number(document.getElementById("tabBox").offsetHeight) - 110;
+};
+onMounted(() => {
+  getPagination();
+  setTableHeight();
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 342 - 0
src/views/traceability/components/taskExcel.vue

@@ -0,0 +1,342 @@
+<template>
+  <div class="dialogBody">
+    <div class="exView" :key="excelKey1">
+      <ExcelView
+        ref="excelViewRef"
+        :option="options"
+        @confirm="confirm"
+        v-model:data="exceldata"
+        :checkStatus="true"
+        :verifications="setting"
+      />
+    </div>
+    <!--    <div class="btns" v-if="options.edit !== false">-->
+    <!--      <el-button class="btn" type="success" @click="submit">确 定 </el-button>-->
+    <!--      <el-button class="btn" @click="reset">重 置 </el-button>-->
+    <!--      <el-button class="btn" type="info" @click="cancel">取 消 </el-button>-->
+    <!--    </div>-->
+    <!--    <div class="btns" v-else>-->
+    <!--      <el-button class="btn" type="info" @click="cancel">返 回 </el-button>-->
+    <!--    </div>-->
+  </div>
+</template>
+<script setup lang="ts">
+import { ref } from "vue";
+import ExcelView from "@/components/ExcelView/index.vue";
+const setting = ref([]);
+const props = defineProps({
+  data: {
+    type: Object,
+  },
+});
+const rowData = ref({});
+const emits = defineEmits(["update:modelValue", "close", "refresh"]);
+const excelKey1 = ref(false);
+
+const reset = () => {
+  exceldata.value = JSON.parse(rowData.value.excelData);
+  excelKey1.value = !excelKey1.value;
+};
+const cancel = () => {
+  excelKey1.value = !excelKey1.value;
+  options.value.edit = true;
+  emits("close");
+};
+// 存放操作表格相关业务代码
+const useAddTemplateHook = () => {
+  //excelView 组件实例
+  const excelViewRef = ref(null);
+  //表格配置项
+  const options = ref({
+    //头部操作区域
+    opreaState: true,
+    //导入按钮展示
+    in: false,
+    //导出按钮展示
+    out: false,
+    print: true,
+    //编辑状态 false:为查看状态
+    edit: false,
+    //当前操作表格名称
+    inName: "",
+    opreaTitle: false,
+  });
+  //双向绑定表格data变量
+  const exceldata = ref(null);
+  //控制表格组件展示界面变量(包括表格展示页面和操作页面)
+  const excelStatus = ref(true);
+
+  //获取组件内实时数据赋值到外层
+  const confirm = (data: any) => {
+    exceldata.value = data;
+  };
+  return {
+    excelStatus,
+    options,
+    confirm,
+    exceldata,
+    excelViewRef,
+  };
+};
+const { options, confirm, exceldata, excelViewRef } = useAddTemplateHook();
+const useFormHook = () => {
+  //KEY告知组件刷新
+  const excelKey = ref(1);
+  //表单data
+  const formVlaue = reactive({ formType: null, formName: null, state: null });
+  //表单是否为编辑状态变量
+  const operaEditStatus = ref(false);
+  //选中的行id
+  const selectId = ref(null);
+  //表单ref实例
+  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("添加成功!");
+          resetData();
+          dataEditList();
+          editTep(data);
+        }
+      }
+    });
+  };
+  //更新行内信息
+  const updateExForm = async (formEl: any) => {
+    //@ts-ignore;
+    excelViewRef.value.saveCellData();
+    //@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 updateExcel({
+          ...formVlaue,
+          excelData: exceldata.value,
+          id: selectId.value,
+          settings: settings.value,
+        });
+        if (code == "200") {
+          ElMessage.success("修改成功!");
+          resetData();
+          dataEditList();
+        }
+      }
+    });
+  };
+  //表达数据重置
+  const resetForm = (formEl: any) => {
+    if (!formEl) return;
+    formEl.resetFields();
+  };
+  return {
+    formVlaue,
+    formRef,
+    rules,
+    selectId,
+    excelKey,
+    operaEditStatus,
+    submitForm,
+    resetForm,
+    updateExForm,
+  };
+};
+
+const {
+  formVlaue,
+  formRef,
+  rules,
+  selectId,
+  excelKey,
+  operaEditStatus,
+  submitForm,
+  resetForm,
+  updateExForm,
+} = useFormHook();
+//表格新增 分页
+const useAddFormHook = () => {
+  const formRef1 = ref(null);
+  const settings = ref([]);
+  const searchForm = ref({
+    pageNo: 1,
+    pageSize: 5,
+    totalPages: 0,
+  });
+  const addForm = ref({
+    paramName: "",
+    position: "",
+  });
+  const addPage = () => {
+    searchForm.value.pageNo = searchForm.value.pageNo + 1;
+    getSettingData();
+  };
+  const deletePage = () => {
+    searchForm.value.pageNo = searchForm.value.pageNo - 1;
+    getSettingData();
+  };
+  const getSettingData = async () => {
+    const { data } = await getSettingsData({
+      excelFormId: selectId.value,
+      ...searchForm.value,
+    });
+    settings.value = data.records;
+    if (settings.value.length == 0 && searchForm.value.pageNo > 1) {
+      deletePage();
+    }
+    searchForm.value.totalPages = data.totalPages;
+  };
+  const addSettings = async () => {
+    const { data, code } = await addSettingsData({
+      excelFormId: selectId.value,
+      ...addForm.value,
+    });
+    if (code == "200") {
+      ElMessage.success("添加成功");
+      resetAddForm();
+      getSettingData();
+    }
+  };
+  const deleteSettings = async (id: any) => {
+    const { data, code } = await deleteSettingsData({ id: id });
+    if (code == "200") {
+      ElMessage.success("删除成功");
+      getSettingData();
+    }
+  };
+
+  const resetAddForm = () => {
+    addForm.value = {
+      paramName: "",
+      position: "",
+    };
+    searchForm.value = {
+      pageNo: 1,
+      pageSize: 5,
+      totalPages: 0,
+    };
+    settings.value = [];
+  };
+  const creatAddForm = async () => {
+    await formRef1.value.validate(async (valid: any, fields: any) => {
+      if (valid) {
+        addSettings();
+      }
+    });
+  };
+  const addRules = reactive({
+    paramName: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+    position: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+  });
+  return {
+    formRef1,
+    addForm,
+    searchForm,
+    settings,
+    addRules,
+    creatAddForm,
+    resetAddForm,
+    getSettingData,
+    addSettings,
+    addPage,
+    deleteSettings,
+    deletePage,
+  };
+};
+
+const {
+  formRef1,
+  addForm,
+  searchForm,
+  settings,
+  addRules,
+  creatAddForm,
+  deletePage,
+  addPage,
+  resetAddForm,
+  getSettingData,
+  deleteSettings,
+} = useAddFormHook();
+watch(
+  () => props.data,
+  () => {
+    //@ts-ignore
+    rowData.value = props.data;
+    exceldata.value = JSON.parse(rowData.value.excelData);
+    excelKey1.value = !excelKey1.value;
+    if (rowData.value.lookStatus == true) {
+      options.value.edit = false;
+    }
+    setting.value = rowData.value.settings;
+  },
+  { immediate: true }
+);
+</script>
+<style lang="scss" scoped>
+.dialogBody {
+  width: 100%;
+  height: 68vh;
+  display: flex;
+  position: relative;
+  .exView {
+    width: 100%;
+    height: 68vh;
+    //width: 1330px;
+    display: flex;
+    position: relative;
+  }
+  .btns {
+    width: 200px;
+    height: 560px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 40px 0 0 20px;
+    .btn {
+      width: 100%;
+      margin: 10px;
+    }
+  }
+}
+</style>

+ 18 - 3
src/views/traceability/index.vue

@@ -66,10 +66,10 @@
                     <CreditCard />
                   </el-icon>
                 </div>
-                铭牌
+                计划编
               </div>
               <div class="value destext">
-                {{ infoData.materialName ? infoData.materialName : "-" }}
+                {{ infoData.orderCode ? infoData.orderCode : "-" }}
               </div>
             </div>
             <div class="item">
@@ -101,7 +101,7 @@
                 工单出站
               </div>
               <div class="value destext">
-                {{ infoData.nameplateNo ? infoData.nameplateNo : "-" }}
+                1
               </div>
             </div>
             <div class="item" style="flex: 2">
@@ -218,6 +218,20 @@
               </template>
             </keep-alive>
           </el-tab-pane>
+          <el-tab-pane name="f8">
+            <template #label>
+              <el-badge
+                :type="activeName == 'f8' ? 'warning' : 'danger'"
+                :value="tabCountData.excel"
+                >在线表格
+              </el-badge>
+            </template>
+            <keep-alive>
+              <template v-if="activeName == 'f8'">
+                <Excel />
+              </template>
+            </keep-alive>
+          </el-tab-pane>
         </el-tabs>
       </div>
     </div>
@@ -237,6 +251,7 @@ const Check = defineAsyncComponent(() => import("./components/check.vue"));
 const Equit = defineAsyncComponent(() => import("./components/equit.vue"));
 const Fault = defineAsyncComponent(() => import("./components/fault.vue"));
 const Media = defineAsyncComponent(() => import("./components/media.vue"));
+const Excel = defineAsyncComponent(() => import("./components/excel.vue"));
 const store = useProcessStore();
 const activeName = ref("f1");
 const handleClick = () => {};