Forráskód Böngészése

生产文件收集

“front-end” 3 éve
szülő
commit
225954f013

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1100 - 0
src/pages/main/collect/collect.vue


+ 353 - 0
src/pages/main/collect/common/export.js

@@ -0,0 +1,353 @@
+// import { createCellPos } from './translateNumToLetter'
+const Excel = require("exceljs");
+import FileSaver from "file-saver";
+export var exportExcel = function (luckysheet, value) {
+    // 参数为luckysheet.getluckysheetfile()获取的对象
+    // 1.创建工作簿,可以为工作簿添加属性
+    const workbook = new Excel.Workbook();
+    // 2.创建表格,第二个参数可以配置创建什么样的工作表
+    if (Object.prototype.toString.call(luckysheet) === "[object Object]") {
+        luckysheet = [luckysheet];
+    }
+    luckysheet.forEach(function (table) {
+        if (table.data.length === 0) return true;
+        // ws.getCell('B2').fill = fills.
+        const worksheet = workbook.addWorksheet(table.name);
+        const merge = (table.config && table.config.merge) || {};
+        const borderInfo = (table.config && table.config.borderInfo) || {};
+        // 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值
+        setStyleAndValue(table.data, worksheet);
+        setMerge(merge, worksheet);
+        setBorder(borderInfo, worksheet);
+        return true;
+    });
+
+    // return
+    // 4.写入 buffer
+    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("导出成功!2");
+        FileSaver.saveAs(blob, `${value}.xlsx`);
+    });
+    return buffer;
+};
+
+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
+        );
+    });
+};
+
+var setBorder = function (luckyBorderInfo, worksheet) {
+    if (!Array.isArray(luckyBorderInfo)) return;
+    // 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];
+            // console.log('range', rang)
+            let row = rang.row;
+            let column = rang.column;
+            for (let i = row[0] + 1; i < row[1] + 2; i++) {
+                for (let y = column[0] + 1; y < column[1] + 2; y++) {
+                    worksheet.getCell(i, y).border = 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);
+            // console.log('bordre', border, borderData)
+            worksheet.getCell(row_index + 1, col_index + 1).border = border;
+        }
+        // console.log(rang.column_focus + 1, rang.row_focus + 1)
+        // worksheet.getCell(rang.row_focus + 1, rang.column_focus + 1).border = 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))
+            // eslint-disable-next-line no-unused-vars
+            for (const key in fill) {
+                target.fill = fill;
+                break;
+            }
+            target.font = font;
+            target.alignment = alignment;
+            target.value = value;
+
+            return true;
+        });
+    });
+};
+
+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: "top",
+        },
+        horizontal: {
+            0: "center",
+            1: "left",
+            2: "right",
+            default: "left",
+        },
+        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",
+        },
+        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 template = {
+        style: luckyToExcel.style[style],
+        color: { argb: color.replace("#", "") },
+    };
+    let border = {};
+    if (luckyToExcel.type[borderType] === "all") {
+        border["top"] = template;
+        border["right"] = template;
+        border["bottom"] = template;
+        border["left"] = template;
+    } else {
+        border[luckyToExcel.type[borderType]] = template;
+    }
+    // console.log('border', border)
+    return border;
+};
+
+function addborderToCell(borders) {
+    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",
+        },
+    };
+    for (const bor in borders) {
+        if (borders[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 },
+                };
+            }
+        } else {
+            border[luckyExcel.type[bor]] = {
+                color: "#000000",
+                style: 1,
+            };
+        }
+    }
+    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;
+}

+ 177 - 0
src/pages/main/collect/components/deptTreeOnly.vue

@@ -0,0 +1,177 @@
+<template>
+  <div class="treebox" v-loading="loading">
+    <el-tree
+      :highlight-current="true"
+      :check-strictly="true"
+      ref="tree"
+      :data="treeList"
+      node-key="o"
+      :default-checked-keys="defaultListc"
+      :default-expanded-keys="defaultListc"
+      @node-click="handleNodeClick"
+    >
+      <span class="custom-tree-node" slot-scope="{ node }">
+        <em
+          style="display: inline-block; width: 20px"
+          v-if="node.data.haveUserFlag == 'N' && node.data.children.length == 0"
+        ></em>
+        <i
+          class="el-icon-caret-right"
+          v-if="node.data.haveUserFlag == 'Y' && node.data.children.length == 0"
+        ></i>
+        <el-checkbox
+          @change="handleCheckChange(node)"
+          style="margin-right: 10px"
+          v-model="node.checked"
+          v-if="node.data.type == 1"
+        ></el-checkbox>
+        <span>{{ node.label }}</span>
+      </span>
+    </el-tree>
+  </div>
+</template>
+
+<script>
+export default {
+  props: ["defaultList", "type", "closeList", "resetList", "only"],
+  data() {
+    return {
+      treeList: [],
+      opt: [],
+      defaultProps: {
+        children: "children",
+        label: "label",
+      },
+      defaultListc: [],
+      loading: false,
+    };
+  },
+  methods: {
+    getTree() {
+      this.loading = true;
+      this.$http({
+        url: "/sysmgr/csysdept/queryAllList",
+        method: "post",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        data: {},
+      }).then((res) => {
+        this.treeList = res.data;
+        this.loading = false;
+      });
+      // const info = JSON.parse(sessionStorage.userInfo);
+      // console.log(info, "JSON.parse(sessionStorage.userInfo)");
+      // this.treeList = [
+      //   {
+      //     children: [],
+      //     o: info.groupId,
+      //     label: `${info.groupName}`,
+      //     haveUserFlag: "Y",
+      //     ou: `${info.groupName}`,
+      //   },
+      // ];
+    },
+    handleNodeClick(v) {
+      let s = false;
+      if (v.children && v.children.length == 0) {
+        s = true;
+      }
+      if (v.type) {
+        return;
+      }
+      if (
+        v.children &&
+        v.children.length > 0 &&
+        v.children[v.children.length - 1].type == 1
+      ) {
+        return;
+      }
+      this.loading = true;
+      console.log(v);
+      this.$http({
+        url: "/sysmgr/sysuserinfo/queryList",
+        method: "post",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        data: {
+          groupId: v.o,
+        },
+      }).then((res) => {
+        v.children = v.children ? v.children : [];
+        res.data.forEach((item) => {
+          v.children.push({
+            id: item.groupId,
+            label: item.loginNameStr,
+            type: 1,
+            displayname: v.displayname,
+            loginNoStr: item.loginNoStr,
+            o: item.id,
+          });
+        });
+        this.loading = false;
+      });
+      for (let i = 0; i < this.$refs.tree.store._getAllNodes().length; i++) {
+        if (s && v.o == this.$refs.tree.store._getAllNodes()[i].data.o) {
+          this.$refs.tree.store._getAllNodes()[i].expanded = true;
+        }
+      }
+    },
+    handleCheckChange() {
+      console.log(this.only, "only");
+      const nodeList = this.$refs.tree.store.getCheckedNodes();
+      if (this.only) {
+        if (nodeList.length === 1) {
+          this.$emit("treeCheck", nodeList);
+        } else if (nodeList.length === 0) {
+          this.$refs.tree.setCheckedKeys([]);
+          this.$emit("treeCheck", nodeList);
+        } else {
+          let obj = { ...nodeList[0] };
+          this.$refs.tree.setCheckedKeys([]);
+          this.$nextTick(() => {
+            this.$refs.tree.setChecked(obj, true);
+          });
+          this.$message.error("这里只能选择一个审批人");
+        }
+      } else if (!this.only) {
+        this.$emit("treeCheck", nodeList);
+      }
+    },
+  },
+  created() {
+    this.getTree();
+    this.defaultListc = this.defaultList;
+  },
+  watch: {
+    type() {
+      this.defaultListc = this.defaultList;
+      this.$forceUpdate();
+    },
+    defaultList() {
+      this.$forceUpdate();
+    },
+    closeList() {
+      this.$refs.tree.setCheckedKeys([]);
+      if ([...this.resetList] && [...this.resetList].length > 0) {
+        [...this.resetList].forEach((el) => {
+          this.$nextTick(() => {
+            this.$refs.tree.setChecked(el, true);
+          });
+        });
+      }
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.el-icon-caret-right {
+  color: #ccc;
+  margin: 0 5px;
+}
+.treebox {
+  border: 1px solid #ddd;
+}
+</style>

+ 74 - 0
src/pages/main/collect/components/dialog.vue

@@ -0,0 +1,74 @@
+<template>
+  <el-dialog
+    :modal="modal"
+    :title="title"
+    :visible.sync="visible"
+    :fullscreen="fullscreen"
+    :key="reload"
+    :before-close="handleCancel"
+    :modal-append-to-body="false"
+    :width="width"
+    :destroy-on-close="destroy"
+  >
+    <!-- 表格主体部分 -->
+    <slot></slot>
+    <!-- 表格底部 -->
+    <div slot="footer">
+      <slot name="footer">
+        <el-button @click="handleCancel" size="small">取消</el-button>
+        <el-button @click="handleConfirm" type="primary" size="small"
+          >确定</el-button
+        >
+      </slot>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  props: {
+    visible: {
+      type: Boolean,
+      default: false,
+    },
+    title: {
+      type: String,
+      default: "",
+    },
+    reload: {
+      type: Number,
+      default: 0,
+    },
+    width: {
+      type: String,
+      default: "500px",
+    },
+    fullscreen: {
+      type: Boolean,
+      default: false,
+    },
+    modal: {
+      type: Boolean,
+      default: true,
+    },
+    destroy: {
+      type: Boolean,
+      default: false
+    }
+  },
+  mounted() {
+  },
+  methods: {
+    //   确定的回调
+    handleConfirm() {
+      this.$emit("confirm", false);
+    },
+    //   取消的回调
+    handleCancel() {
+      this.$emit("cancel", false);
+    },
+  },
+};
+</script>
+
+<style></style>

+ 103 - 0
src/pages/main/collect/components/form.vue

@@ -0,0 +1,103 @@
+<!--
+ * @Author       : yuanrunwei
+ * @Date         : 2021-11-01 18:03:02
+ * @LastEditors: Please set LastEditors
+ * @LastEditTime: 2022-01-10 19:27:43
+ * @FilePath     : \spfm-market-front\src\pages\main\performance\components\form.vue
+-->
+<template>
+  <el-form :inline="true" :model="object">
+    <el-row :gutter="24">
+      <el-col
+        v-for="({ props, label, type, dictionary }, index) in form"
+        :key="index"
+        :span="6"
+      >
+        <el-form-item :label="label">
+          <template v-if="type === 'select'">
+            <el-select
+              v-model="object[props]"
+              :placeholder="label"
+              filterable
+              clearable
+            >
+              <el-option
+                :label="label"
+                :value="value"
+                v-for="({ label, value }, index) in dictionary"
+                :key="index"
+              ></el-option>
+            </el-select>
+          </template>
+          <template v-else-if="['datetime', 'date', 'month'].includes(type)">
+            <el-date-picker
+              v-model="object[props]"
+              :type="type"
+              format="yyyy-MM-dd"
+              value-format="yyyy-MM-dd"
+              :placeholder="label"
+            >
+            </el-date-picker>
+          </template>
+          <template v-else>
+            <el-input
+              v-model="object[props]"
+              :placeholder="label"
+              clearable
+            ></el-input>
+          </template>
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">搜索</el-button>
+          <el-button @click="handleSearch(2)" v-if="reset == true">重置</el-button>
+        </el-form-item>
+      </el-col>
+      <el-col class="flex-justify-align-end" :span="24">
+        <el-button
+          v-for="({ label, props, unlogo }, index) in handle"
+          :key="index"
+          @click="handleSubmit(props)"
+        >
+          <i v-if="!unlogo" class="el-icon-document-add font-weight-bold" />{{
+            label
+          }}
+        </el-button>
+      </el-col>
+    </el-row>
+  </el-form>
+</template>
+<script>
+export default {
+  props: {
+    reset:{
+      type:Boolean,
+      default: () => [],
+    },
+    form: {
+      type: Array,
+      default: () => [],
+    },
+    handle: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data: () => ({
+    object: {},
+  }),
+  methods: {
+    handleSearch(e) {
+      if (e === 2) {
+        this.object = [];
+      } else {
+        this.$emit("search", this.object);
+      }
+    },
+    handleSubmit(params) {
+      this.$emit(params, this.object);
+    },
+  },
+};
+</script>

+ 38 - 0
src/pages/main/collect/components/pagination.vue

@@ -0,0 +1,38 @@
+<!--
+ * @Author       : yuanrunwei
+ * @Date         : 2021-11-01 18:11:59
+ * @LastEditors  : yuanrunwei
+ * @LastEditTime : 2021-11-02 14:27:11
+ * @FilePath     : \spfm-front\src\pages\main\dataConfig\components\pagination.vue
+-->
+<template>
+    <el-pagination
+        class="simple-pagination"
+        @current-change="handleChange"
+        layout="prev, pager, next"
+        background
+        :current-page="page"
+        :total="total"
+    >
+    </el-pagination>
+</template>
+<script>
+export default {
+    props: {
+        page: {
+            type: Number,
+            default: 0
+        },
+        total: {
+            type: Number,
+            default: 0
+        }
+    },
+    data: () => ({}),
+    methods: {
+        handleChange(page) {
+            this.$emit("change", page);
+        }
+    }
+};
+</script>

+ 985 - 0
src/pages/main/collect/components/sheet.vue

@@ -0,0 +1,985 @@
+<!--
+ * @Author       : yuanrunwei
+ * @Date         : 2021-12-04 14:23:58
+ * @LastEditors: daiqisheng
+ * @LastEditTime: 2022-03-07 17:40:14
+ * @FilePath     : \spfm-market-front\src\pages\main\performance\components\sheet.vue
+-->
+<template>
+  <div class="sheet-container">
+    <div class="flex-justify-align-end margin-bottom-20">
+      <el-button
+        type="primary"
+        @click="handleVisible"
+        v-if="['template'].includes(attribute)"
+        >权限设置</el-button
+      >
+      <el-button type="primary" @click="handleDownload">导出</el-button>
+      <el-button type="primary" @click="handleFullscreen()">全屏显示</el-button>
+      <template v-if="['edit'].includes(type)">
+        <el-upload
+          v-if="!id"
+          class="margin-right-10 margin-left-10"
+          action
+          :on-change="handleChange"
+          :show-file-list="false"
+        >
+          <el-button type="primary">上传</el-button>
+        </el-upload>
+        <el-button
+          v-if="!status || status === '2'"
+          type="primary"
+          @click="handleSave('2')"
+          :disabled="handleForbid()"
+          >暂存</el-button
+        >
+        <el-button
+          v-if="status === '2' || status === '3'"
+          type="primary"
+          @click="handleResave"
+          :disabled="handleForbid()"
+          >保存</el-button
+        >
+        <el-button
+          v-if="addFlag === '0'"
+          type="primary"
+          @click="handleSave('0')"
+          :disabled="handleForbid()"
+          ><span>{{ id ? "提交" : "新增" }}</span
+          ><span>{{
+            handleForbid() ? `(请先设置权限)` : ""
+          }}</span></el-button
+        >
+      </template>
+    </div>
+    <div id="luckysheet" class="sheet-container-block"></div>
+    <simple-dialog
+      title="权限设置"
+      :visible="visible"
+      :modal="false"
+      width="1400px"
+      @confirm="handleAuth"
+      @cancel="handleVisible"
+    >
+      <el-form ref="form" :model="form" label-width="80px">
+        <el-radio-group
+          v-model="form.permission_type"
+          :disabled="type !== 'edit'"
+        >
+          <el-form-item>
+            <el-radio :label="0"><span>无特殊权限</span></el-radio>
+            <div>
+              <span class="form-content">负责人</span>
+              <el-select
+                v-model="form.person"
+                multiple
+                placeholder="请选择负责人"
+                :disabled="type !== 'edit'"
+              >
+                <el-option
+                  v-for="({ label, value }, index) in charge_list"
+                  :key="index"
+                  :label="label"
+                  :value="value"
+                ></el-option>
+              </el-select>
+            </div>
+          </el-form-item>
+          <el-form-item>
+            <el-radio :label="1"><span>特殊权限:</span></el-radio>
+            <el-form-item
+              label="负责人"
+              prop="charge"
+              v-for="(item, index) in form.charge"
+              :key="index"
+              :rules="{
+                required: true,
+                message: '负责人不能为空',
+                trigger: 'blur',
+              }"
+            >
+              <div class="flex">
+                <el-select
+                  class="margin-bottom-20 margin-right-10"
+                  placeholder="请选择负责人"
+                  v-model="item.person"
+                  filterable
+                  :disabled="type !== 'edit'"
+                >
+                  <el-option
+                    v-for="({ label, value }, index) in charge_list"
+                    :key="index"
+                    :label="label"
+                    :value="value"
+                  ></el-option>
+                </el-select>
+                <div class="form-select">
+                  <span class="form-content">可编辑行:从</span>
+                  <el-input
+                    v-model="item.row_start"
+                    @input="(params) => handleInput(index, 'row_start', params)"
+                    :disabled="type !== 'edit'"
+                  />
+                  <span class="form-content">到</span>
+                  <el-input
+                    v-model="item.row_end"
+                    @input="(params) => handleInput(index, 'row_end', params)"
+                    :disabled="type !== 'edit'"
+                  />
+                </div>
+                <div class="form-select">
+                  <span class="form-content">可编辑列:从</span>
+                  <el-input
+                    :disabled="type !== 'edit'"
+                    v-model="item.col_start"
+                  />
+                  <!-- @input="(params) => handleInput(index, 'col_start', params)" -->
+                  <span class="form-content">到</span>
+                  <el-input
+                    :disabled="type !== 'edit'"
+                    v-model="item.col_end"
+                  />
+                </div>
+              </div>
+            </el-form-item>
+            <div>
+              <el-button
+                @click.prevent="handleCharge('add')"
+                :disabled="type !== 'edit'"
+                >添加</el-button
+              >
+              <el-button
+                v-if="form.charge.length - 1"
+                @click.prevent="handleCharge('delete')"
+                :disabled="type !== 'edit'"
+                >删除</el-button
+              >
+            </div>
+          </el-form-item>
+        </el-radio-group>
+      </el-form>
+      <template v-if="id && status !== '2' && status !== '3'" v-slot:footer
+        ><div></div
+      ></template>
+    </simple-dialog>
+    <simpleDialog
+      title="提交"
+      :visible="manager_approve"
+      :modal="false"
+      @cancel="handleApprove(0)"
+    >
+      <el-form :model="approveForm" label-width="120px">
+        <el-form-item
+          label="审批意见:"
+          :rules="{
+            required: true,
+            message: '请选择审批意见',
+            trigger: 'change',
+          }"
+        >
+          <el-select v-model="approveForm.type">
+            <el-option
+              v-for="item in approveForm.list"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item
+          v-if="approveForm.type === '3'"
+          label="其它审批意见:"
+          :rules="{
+            required: true,
+            message: '请输入审批意见',
+            trigger: 'blur',
+          }"
+          ><el-input v-model="approveForm.comments"
+        /></el-form-item>
+      </el-form>
+      <template v-slot:footer>
+        <div>
+          <el-button @click.prevent="handleApprove('1')">结束</el-button>
+          <el-button @click.prevent="handleApprove('4')" type="primary"
+            >转副总审批</el-button
+          >
+          <el-button @click.prevent="handleApprove('3')" type="primary"
+            >转总经理审批</el-button
+          >
+        </div>
+      </template>
+    </simpleDialog>
+  </div>
+</template>
+
+<script>
+import luckyexcel from "luckyexcel";
+import { exportExcel } from "../common/export";
+import simpleDialog from "./dialog.vue";
+export default {
+  components: {
+    simpleDialog,
+  },
+  props: {
+    type: {
+      type: String,
+      default: "view", // view 查看 edit 编辑
+    },
+    attribute: {
+      type: String,
+      default: "template", // template 模板 order 工单 file 文件
+    },
+    id: {
+      default: null,
+    },
+    receiver: {
+      type: String,
+      default: "",
+    },
+    status: { type: String, default: "" },
+  },
+  data() {
+    return {
+      form: {
+        charge: [
+          {
+            person: [],
+            col_start: "",
+            col_end: "",
+            row_start: "",
+            row_end: "",
+          },
+        ],
+        array: [],
+        type: null,
+        permission_type: null,
+        col_start: "",
+        col_end: "",
+        row_start: "",
+        row_end: "",
+      },
+      approveForm: {
+        type: "",
+        comments: "",
+        list: [
+          {
+            label: "同意",
+            value: "同意",
+          },
+          {
+            label: "不同意",
+            value: "不同意",
+          },
+          {
+            label: "其他",
+            value: "3",
+          },
+        ],
+      },
+
+      // 可提交标志
+      addFlag: "0",
+      rowList: [],
+      isDisable: true,
+      issued_id: null,
+      template_id: null,
+      visible: false,
+      manager_approve: false,
+      row_list: [],
+      column_list: [],
+      charge_list: [],
+      type_options: [
+        {
+          value: 1,
+          label: "按行",
+        },
+        // {
+        //     value: 2,
+        //     label: "按列",
+        // },
+      ],
+    };
+  },
+  methods: {
+    handleInit() {
+      if (this.id) {
+        this.handleQuery();
+      } else {
+        this.handleCreate();
+      }
+    },
+    // // 权限选择
+    // handleRadio(e){
+    //     console.log(e,'e');
+    // },
+    handleAllow({ row, column }) {
+      let public_permisson =
+        (!this.form.permission_type ||
+          this.status === "2" ||
+          this.status === "3") &&
+        this.type === "edit";
+      let editable =
+        this.row_list.includes(row) && this.column_list.includes(column);
+      // let totalBoolean = (public_permisson || editable) && this.id;
+      let totalBoolean = public_permisson || editable;
+      return totalBoolean;
+    },
+    async handleQuery() {
+      let url = "";
+      let params = {};
+      switch (this.attribute) {
+        case "template":
+          url = "/market/CMKFileTemplate/QueryCMKFileTemplateById";
+          params = {
+            templateId: this.id,
+          };
+          break;
+        case "order":
+          url = "/market/CMKIssued/CMKQueryIssuedById";
+          params = {
+            id: this.id,
+          };
+          break;
+        case "file":
+          url = "/market/CMKIssued/CMKIssuedProcessByUser";
+          params = {
+            id: this.id,
+            receiverId: this.receiver,
+          };
+          break;
+      }
+      const {
+        data: {
+          templateContent,
+          templateName,
+          issuedId,
+          templateId,
+          list,
+          addFlag,
+        },
+      } = await this.$http({
+        url,
+        method: "post",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        data: params,
+      });
+      this.template_id = templateId;
+      this.issued_id = issuedId;
+      this.addFlag = addFlag;
+      console.log(JSON.parse(templateContent), "123123");
+      if (list && list.length) {
+        const { type } = list[0];
+        if (type === "1") {
+          // 公共权限
+          // const { allowEditingColumns, rowNum } = list[0];
+          this.form = {
+            permission_type: Number(type) - 1,
+            person: list.map((el) => {
+              return `${el.principalMent}-${el.principalId},${el.principalName}`;
+            }),
+            charge: [
+              {
+                person: "",
+                col_start: "",
+                col_end: "",
+                row_start: "",
+                row_end: "",
+              },
+            ],
+          };
+        } else {
+          // 特殊权限
+          this.form = {
+            permission_type: Number(type) - 1,
+            col_start: "",
+            col_end: "",
+            row_start: "",
+            row_end: "",
+            charge: list.map((el) => ({
+              person: `${el.principalMent}-${el.principalId},${el.principalName}`,
+              col_start: el.allowEditingColumns.split(",")[0],
+              col_end:
+                el.allowEditingColumns.split(",")[
+                  el.allowEditingColumns.split(",").length - 1
+                ],
+              row_start: el.rowNum.split(",")[0],
+              row_end: el.rowNum.split(",")[el.rowNum.split(",").length - 1],
+            })),
+          };
+        }
+        this.row_list =
+          this.type === "edit" && list[0].rowNum
+            ? list[0].rowNum
+                .split(",")
+                .map((element) => JSON.parse(element) - 1)
+            : [];
+        if (this.type === "edit" && list[0].allowEditingColumns) {
+          // this.column_list = list[0].allowEditingColumns
+          //   .split(",")
+          //   .map((element) => JSON.parse(element) - 1);
+          this.column_list =
+            list[0].allowEditingColumnsFlag === "1"
+              ? list[0].allowEditingColumnsShuzi
+                  .split(",")
+                  .map((element) => JSON.parse(element) - 1)
+              : list[0].allowEditingColumns
+                  .split(",")
+                  .map((element) => JSON.parse(element) - 1);
+        } else {
+          this.column_list = [];
+        }
+        // this.formateNumber(list[0].allowEditingColumns);
+      }
+      this.handleCreate({
+        json: templateContent ? JSON.parse(templateContent) : {},
+        name: templateName,
+        type: "json",
+      });
+    },
+    handleForbid() {
+      // const object = {};
+      const { permission_type } = this.form;
+      if (permission_type === 0) {
+        // 公共权限 暂时不用可编辑行和列
+        const { person } = this.form;
+        if (person.length) {
+          return false;
+        }
+        return true;
+      } else if (permission_type === 1) {
+        // 特殊权限
+        let flag = 1;
+        const { charge } = this.form;
+        charge.forEach((el) => {
+          if (
+            Object.values(el).filter((v) => {
+              return v !== "";
+            }).length === 5
+          ) {
+            flag = flag * 1;
+          } else {
+            flag = flag * 0;
+          }
+        });
+        return !flag;
+      } else {
+        return true;
+      }
+    },
+    async handleCreate({ file, json, type, name } = {}) {
+      let that = this;
+      const options = {
+        container: "luckysheet",
+        lang: "zh",
+        showsheetbar: false,
+        hook: {
+          cellEditBefore: function ([
+            { row_focus: row, column_focus: column },
+          ]) {
+            if (!that.handleAllow({ row, column })) {
+              that.$message.error("您没有编辑权限");
+            }
+          },
+          // cellUpdated: function (row, column) {
+          //   that.rowList.push(row);
+          // },
+          cellUpdateBefore: function (row, column) {
+            if (!that.handleAllow({ row, column })) {
+              return false;
+            }
+          },
+          cellRenderAfter: function (cell, position) {
+            const { r: row, c: column } = position;
+            console.log();
+            if (cell) {
+              if (!that.handleAllow({ row, column })) {
+                cell.bg = "#d5d5d5";
+              } else {
+                cell.bg = "#ffffff";
+              }
+            }
+          },
+          updated: function ({ range }) {
+            const middle = range.map((el) => {
+              return that.paramsArr(el.row[0], el.row[1]);
+            });
+            let changedList = middle.join(",").split(",");
+            that.rowList.push(...changedList);
+            console.log(that.rowList, "that.rowList");
+          },
+        },
+      };
+      switch (type) {
+        case "file":
+          if (file) {
+            await new Promise((resolve) => {
+              luckyexcel.transformExcelToLucky(file, (export_json) => {
+                options.data = [
+                  ...export_json.sheets.map((element) => ({
+                    ...element,
+                    zoomRatio: 0.75,
+                  })),
+                ];
+                options.title = export_json.info.name;
+                resolve();
+              });
+            });
+          }
+          break;
+        case "json":
+          if (json) {
+            options.data = [
+              {
+                ...json,
+                zoomRatio: 0.75,
+              },
+            ];
+            options.title = name;
+          }
+          break;
+      }
+      window.luckysheet.create(options);
+
+      let clock = setInterval(() => {
+        if (window.luckysheet) {
+          window.luckysheet.refresh();
+          clearInterval(clock);
+        }
+      }, 1000);
+    },
+    async handleChange(response) {
+      this.handleCreate({ file: response.raw, type: "file" });
+    },
+    handleDownload() {
+      exportExcel(
+        window.luckysheet.getAllSheets(),
+        window.luckysheet.getWorkbookName()
+      );
+    },
+    async handleAddAuth({ id }) {
+      // const object = {};
+      const { permission_type } = this.form;
+      console.log(id, permission_type);
+      let reqdata = {
+        templateId: id,
+        type: permission_type ? 2 : 1,
+      };
+      if (!permission_type) {
+        //  公共权限
+        const { person } = this.form;
+
+        const principalId = [];
+        const principalName = [];
+        const principalMent = [];
+        person.forEach((el) => {
+          principalMent.push(el.split(",")[0].split("-")[0]);
+          principalId.push(el.split(",")[0].split("-")[1]);
+          principalName.push(el.split(",")[1]);
+        });
+        reqdata.principalId = principalId.join(",");
+        reqdata.principalName = principalName.join(",");
+        reqdata.principalMent = principalName.join(",");
+      } else {
+        const { charge } = this.form;
+        //  特殊权限
+        reqdata.specialAuth = charge.map((el) =>
+          JSON.stringify({
+            allowEditingColumns: `${el.col_start},${el.col_end}`,
+            rowNum: `${el.row_start},${el.row_end}`,
+            principalMent: el.person.split(",")[0].split("-")[0],
+            principalId: el.person.split(",")[0].split("-")[1],
+            principalName: el.person.split(",")[1],
+          })
+        );
+      }
+      const {
+        data: { result, desc },
+      } = await this.$http({
+        url: this.id
+          ? "/market/CMKFileTemplateAuthority/CMKFileTemplateAuthorityUpdate"
+          : "/market/CMKFileTemplateAuthority/CMKFileTemplateAuthorityAdd",
+        method: "post",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        data: reqdata,
+      });
+      if (result) {
+        this.$message.error(desc);
+      } else {
+        this.$message.success(desc);
+      }
+      return result;
+    },
+    async handleSave(type) {
+      let edit_url = "";
+      switch (this.attribute) {
+        case "template":
+          edit_url = "";
+          break;
+        case "order":
+          edit_url = "";
+          break;
+        case "file":
+          edit_url = "/market/CMKIssued/CMKIssuedSubmit";
+          break;
+      }
+      const sheet_name = window.luckysheet.getSheet().name;
+      const data = window.luckysheet.getSheet(sheet_name);
+      const workbook_name = window.luckysheet.getWorkbookName();
+      if (!this.id) {
+        // 新增时添加权限
+        const {
+          data: { body },
+        } = await this.$http({
+          url: "/market/CMKFileTemplate/CMKFileTemplateAdd", // 新增
+          method: "post",
+          headers: {
+            "Content-Type": "application/json",
+          },
+          data: {
+            id: this.template_id,
+            templateContent: JSON.stringify(data),
+            templateName: workbook_name,
+            issuedId: this.issued_id,
+            status: type,
+          },
+        });
+        await this.handleAddAuth({ id: body });
+        this.$emit("save");
+      } else {
+        // 职位
+        let duty = JSON.parse(sessionStorage.userInfo).duty;
+        if (duty === "7") {
+          this.manager_approve = true;
+        } else {
+          if (type === "2") {
+            // 暂存
+            await this.$http({
+              url: "/market/CMKFileTemplate/UptateCMKFileTemplateById", // 新增
+              method: "post",
+              headers: {
+                "Content-Type": "application/json",
+              },
+              data: {
+                templateId: this.id,
+                templateContent: JSON.stringify(data),
+                templateName: workbook_name,
+                status: type,
+              },
+            });
+            this.$emit("save");
+            return;
+          }
+          // 员工提交
+          this.rowList.shift();
+          let reqdata = {
+            rowIndex: [...new Set(this.rowList)]
+              .sort(function (a, b) {
+                return a - b;
+              })
+              .join(","),
+            rowContent: [...new Set(this.rowList)]
+              .sort(function (a, b) {
+                return a - b;
+              })
+              .map((el) => {
+                return data.data[el];
+              }),
+          };
+          await this.$http({
+            url: edit_url, //提交
+            method: "post",
+            headers: {
+              "Content-Type": "application/json",
+            },
+            data: {
+              id: this.template_id,
+              templateContent: JSON.stringify(data),
+              templateName: workbook_name,
+              issuedId: this.issued_id,
+              rowJson: JSON.stringify(reqdata),
+            },
+          });
+          this.$emit("save");
+        }
+      }
+    },
+    // 判断数组是否有值
+    confirmArrayData(data) {
+      if (data instanceof Array) {
+        let flag = 0;
+        if (data.length) {
+          data.forEach((el) => {
+            if (el instanceof Object) {
+              flag = flag + 1;
+            }
+          });
+          if (flag) {
+            return true;
+          } else {
+            return false;
+          }
+        } else {
+          return false;
+        }
+      } else {
+        return false;
+      }
+    },
+    async handleAuth() {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.handleForbid()) {
+            this.$message.error("请完善可编辑信息");
+            return false;
+          }
+          if (this.id) {
+            this.handleAddAuth({ id: this.id });
+          }
+          this.handleVisible();
+        }
+      });
+    },
+    // 通用方法用于转化全局
+    paramsArr(start, end) {
+      const arr = [];
+      console.log(start, end);
+      for (let i = Number(start); i <= Number(end); i++) {
+        arr.push(i);
+      }
+      return arr.join(",");
+    },
+    filterName(id, arr) {
+      return arr.filter((el) => el.secLeaderLogin === id)[0].secLeaderName;
+    },
+    handleCharge(type) {
+      switch (type) {
+        case "add":
+          this.form.charge.push({
+            person: "",
+          });
+          this.handleForbid();
+          break;
+        case "delete":
+          this.form.charge.pop();
+          this.handleForbid();
+          break;
+      }
+    },
+    handleVisible() {
+      this.visible = !this.visible;
+    },
+    handleInput(index, name, value) {
+      let reg = /^[0-9]*$/;
+      if (!reg.test(value)) {
+        this.form.charge[index][name] = this.form.charge[index][name].substr(
+          0,
+          this.form.charge[index][name].length - 1
+        );
+        this.$message.error("该处只能填写数字");
+      }
+    },
+    async handleApprove(type) {
+      if (type) {
+        if (this.approveForm.type) {
+          if (this.approveForm.type === "3" && !this.approveForm.comments) {
+            this.$message.error("请输入其他审批意见");
+            return;
+          }
+        } else {
+          this.$message.error("请选择审批意见");
+          return;
+        }
+        const sheet_name = window.luckysheet.getSheet().name;
+        const data = window.luckysheet.getSheet(sheet_name);
+        const workbook_name = window.luckysheet.getWorkbookName();
+        // 经理提交
+        this.rowList.shift();
+        let reqdata = {
+          rowIndex: [...new Set(this.rowList)]
+            .sort(function (a, b) {
+              return a - b;
+            })
+            .join(","),
+          rowContent: [...new Set(this.rowList)]
+            .sort(function (a, b) {
+              return a - b;
+            })
+            .map((el) => {
+              return data.data[el];
+            }),
+        };
+        await this.$http({
+          url: "/market/CMKIssued/CMKIssuedSubmit", // 提交
+          method: "post",
+          headers: {
+            "Content-Type": "application/json",
+          },
+          data: {
+            id: this.template_id,
+            templateContent: JSON.stringify(data),
+            templateName: workbook_name,
+            issuedId: this.issued_id,
+            rowJson: JSON.stringify(reqdata),
+          },
+        });
+        let params = {
+          id: this.issued_id,
+          reviewOpinion:
+            this.approveForm.type === "3"
+              ? this.approveForm.comments
+              : this.approveForm.type,
+        };
+        switch (type) {
+          case "1":
+            params = {
+              ...params,
+              operateName: "结束",
+              status: 3,
+            };
+            break;
+          case "4":
+            params = {
+              ...params,
+              operateName: "转副总审批",
+              reviewType: 2,
+            };
+            break;
+          case "3":
+            params = {
+              ...params,
+              operateName: "转总经理审批",
+              reviewType: 3,
+            };
+            break;
+        }
+        await this.$http({
+          url: "/market/CMKIssued/CMKIssuedCheck", // 审批
+          method: "post",
+          headers: {
+            "Content-Type": "application/json",
+          },
+          data: params,
+        });
+        this.$message({
+          type: "success",
+          message: "审批成功",
+        });
+        this.manager_approve = false;
+        this.$emit("save");
+      } else {
+        this.manager_approve = false;
+      }
+    },
+    handleFullscreen() {
+      const element = document.body;
+      const is_fullscreen =
+        document.fullScreen ||
+        document.mozFullScreen ||
+        document.webkitIsFullScreen;
+      if (!is_fullscreen) {
+        //进入全屏,多重短路表达式
+        (element.requestFullscreen && element.requestFullscreen()) ||
+          (element.mozRequestFullScreen && element.mozRequestFullScreen()) ||
+          (element.webkitRequestFullscreen &&
+            element.webkitRequestFullscreen()) ||
+          (element.msRequestFullscreen && element.msRequestFullscreen());
+      } else {
+        //退出全屏,三目运算符
+        document.exitFullscreen
+          ? document.exitFullscreen()
+          : document.mozCancelFullScreen
+          ? document.mozCancelFullScreen()
+          : document.webkitExitFullscreen
+          ? document.webkitExitFullscreen()
+          : "";
+      }
+    },
+    handleResave() {
+      const sheet_name = window.luckysheet.getSheet().name;
+      const data = window.luckysheet.getSheet(sheet_name);
+      const workbook_name = window.luckysheet.getWorkbookName();
+      this.$http({
+        url: "/market/CMKFileTemplate/UptateCMKFileTemplateById",
+        method: "post",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        data: {
+          templateId: this.id,
+          templateContent: JSON.stringify(data),
+          templateName: workbook_name,
+          status: "0",
+        },
+      }).then(() => {
+        this.$emit("save");
+      });
+    },
+    handleChargeList() {
+      this.$http({
+        url: "/market/techcentergj/queryLeaderList",
+        method: "post",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        data: {},
+      }).then((response) => {
+        this.charge_list = response.data.map((element) => ({
+          label: `${element.ou} ${element.secLeaderName}`,
+          value: `${element.ou}-${element.secLeaderLogin},${element.secLeaderName}`,
+        }));
+      });
+    },
+  },
+  mounted() {
+    console.log(this.destroy, "destroy");
+    this.handleInit();
+    this.handleChargeList();
+  },
+  destroyed() {
+    window.luckysheet.destroy();
+  },
+};
+</script>
+
+<style lang="scss" scope>
+.sheet-container {
+  position: fixed;
+  width: calc(100% - 40px);
+  height: 100%;
+  &-block {
+    overflow: hidden;
+    position: absolute;
+    width: 100%;
+    height: 75%;
+  }
+}
+.form {
+  &-input {
+    margin-top: 5px;
+    .el-input {
+      width: 150px;
+      .el-input__inner {
+        height: 30px !important;
+        line-height: 30px !important;
+      }
+    }
+  }
+  &-content {
+    margin: 0px 10px;
+  }
+  &-select {
+    .el-input {
+      width: 100px;
+      .el-input__inner {
+        height: 30px !important;
+        line-height: 30px !important;
+      }
+    }
+  }
+}
+</style>

+ 239 - 0
src/pages/main/collect/components/table.vue

@@ -0,0 +1,239 @@
+<!--
+ * @Author       : yuanrunwei
+ * @Date         : 2021-11-01 18:02:58
+ * @LastEditors: Please set LastEditors
+ * @LastEditTime: 2022-02-10 18:31:51
+ * @FilePath     : /spfm-market-front/src/pages/main/performance/components/table.vue
+-->
+<template>
+  <el-table
+    class="simple-table"
+    :data="computed_list"
+    v-loading="loading"
+    @selection-change="handleSelectionChange"
+  >
+    <el-table-column
+      type="selection"
+      width="55"
+      :selectable="selectable"
+      v-if="multiple"
+    />
+    <el-table-column
+      v-for="(
+        { props, label, type, width, align, children, dictionary, control },
+        index
+      ) in config"
+      :key="index"
+      :prop="props"
+      :width="width"
+      :label="label"
+      :align="align || 'center'"
+    >
+      <template #default="scope">
+        <div v-if="type === 'edit'">
+          <el-input
+            v-if="scope.row[`edit`]"
+            v-model="scope.row[props]"
+            autosize
+            type="textarea"
+            @change="handleModify"
+          />
+        </div>
+        <div v-if="type === 'number'">{{ scope.$index + 1 }}</div>
+        <div v-else-if="type === 'textarea'">
+          <pre class="simple-table-break">{{ scope.row[props] }}</pre>
+        </div>
+        <div v-else-if="type === 'date'">
+          <div>{{ $formatDate(scope.row[props], "YYYY-MM-DD") }}</div>
+        </div>
+        <div v-else-if="type === 'time'">
+          <div>
+            {{ $formatDate(scope.row[props], "YYYY-MM-DD HH:00:00") }}
+          </div>
+        </div>
+        <div v-else-if="type === 'click'">
+          <div
+            v-if="control && Number(scope.row[control]) < 1 && scope.row[props]"
+          >
+            <span
+              v-for="(item, index) in scope.row[props].split(',')"
+              :key="index"
+              class="simple-table-click cursor-pointer"
+              @click="handleClick(props, { ...scope.row, index })"
+            >
+              {{ scope.row[props].split(",")[index] }}
+            </span>
+          </div>
+          <div
+            v-else-if="!control"
+            class="simple-table-click cursor-pointer"
+            @click="handleClick(props, scope.row)"
+          >
+            {{ scope.row[props] }}
+          </div>
+          <div v-else class="cursor-pointer">
+            {{ scope.row[props] }}
+          </div>
+        </div>
+        <div v-else-if="type === 'dictionary'">
+          {{ dictionary[scope.row[props]] }}
+        </div>
+        <div v-else-if="type === 'file'">
+          <div v-if="scope.row[props] && scope.row[props].length">
+            <div
+              v-for="({ fileName }, index) in scope.row[props]"
+              :key="index"
+              @click="downloadFile({ index, rows: scope.row })"
+              class="simple-table-click cursor-pointer margin-left-10"
+            >
+              {{ fileName }}
+            </div>
+          </div>
+          <div v-else></div>
+        </div>
+        <div v-else>{{ scope.row[props] }}</div>
+      </template>
+      <template v-if="children">
+        <el-table-column
+          v-for="({ props, label, width, align, type }, index) in children"
+          :key="index"
+          :prop="props"
+          :width="width"
+          :label="label"
+          :align="align || 'center'"
+        >
+          <template #default="scope">
+            <div v-if="type === 'edit'">
+              <el-input
+                v-model="scope.row[props]"
+                @change="handleModify"
+                autosize
+                type="textarea"
+              />
+            </div>
+            <div v-else>{{ scope.row[props] }}</div>
+          </template>
+          <!-- <template v-if="variable">
+            <div>{{ scope.row[props] }}</div>
+          </template> -->
+        </el-table-column>
+      </template>
+    </el-table-column>
+    <el-table-column
+      v-if="handleRow.length"
+      label="操作"
+      :align="'center'"
+      :width="handleRow.length * 50"
+    >
+      <template slot-scope="scope">
+        <span
+          v-for="({ label, props, popconfirm, visible }, index) in handleRow"
+          :key="index"
+          class="padding-right-5"
+        >
+          <!--            v-if="handleFormat(visible, scope.row)"-->
+          <span v-if="handleFormat(visible, scope.row)">
+            <!-- <el-popconfirm
+              v-if="popconfirm"
+              :title="`确定要${label}吗?`"
+              @confirm="handleClick(props, scope.row)"
+              @cancel="handleCancel"
+            >
+              <el-button slot="reference" type="text" size="small">{{
+                label
+              }}</el-button>
+            </el-popconfirm> -->
+            <el-button
+              v-if="popconfirm"
+              type="text"
+              size="small"
+              @click="handleConfirm(label, props, scope.row)"
+              >{{ label }}</el-button
+            >
+            <el-button
+              v-else
+              @click="handleClick(props, scope.row)"
+              type="text"
+              size="small"
+              >{{ label }}</el-button
+            >
+          </span>
+        </span>
+      </template>
+    </el-table-column>
+  </el-table>
+</template>
+<script>
+export default {
+  props: {
+    list: {
+      type: Array,
+      default: () => [],
+    },
+    config: {
+      type: Array,
+      default: () => [],
+    },
+    multiple: {
+      type: Boolean,
+      default: false,
+    },
+    selectable: {
+      type: Function,
+    },
+    loading: {
+      type: Boolean,
+      default: false,
+    },
+    handleRow: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  computed: {
+    computed_list() {
+      return this.list.map((element) => ({
+        ...element,
+      }));
+    },
+  },
+  methods: {
+    handleFormat(params, data) {
+      let visible = true;
+      if (params) {
+        visible = false;
+        Object.keys(params).forEach((element) => {
+          if (params[element].includes(data[element])) {
+            visible = true;
+          }
+        });
+      }
+      return visible;
+    },
+    handleConfirm(label, props, row) {
+      this.$confirm(`确定要${label}吗?`, "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "error",
+      })
+        .then(() => {
+          this.$emit(props, row);
+        })
+        .catch(() => {});
+    },
+    handleClick(props, row) {
+      this.$emit(props, row);
+    },
+    handleCancel() {},
+    handleSelectionChange(val) {
+      this.$emit("selection", val);
+    },
+    downloadFile(val) {
+      this.$emit("download", val);
+    },
+    handleModify() {
+      this.$emit("modify", this.computed_list);
+    },
+  },
+};
+</script>

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 200 - 0
src/pages/main/collect/index.vue


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1034 - 0
src/pages/main/collect/launch.vue