浏览代码

Merge branch 'test' of http://110.41.163.243:9980/kd-aiot/kd-aiot-frontend-wt

yusheng 7 月之前
父节点
当前提交
bd25b98a3a

+ 95 - 0
src/api/bpm/components/inspectionTemplate/index.js

@@ -0,0 +1,95 @@
+import request from '@/utils/request';
+
+export async function pageByBom(data) {
+  let par = new URLSearchParams(data);
+  const res = await request.get(`/qms/qualitylevel/pageByBom?` + par, {});
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 新增
+export async function save(data) {
+  const res = await request.post(`/qms/qualitytemplate/save`, data);
+  if (res.data.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 编辑
+export async function update(data) {
+  const res = await request.put(`/qms/qualitytemplate/update`, data);
+  if (res.data.code == 0) {
+    return res.data.message;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+// 获取详情
+export async function getById(id) {
+  const res = await request.get(`/qms/qualitytemplate/getById/${id}`);
+  if (res.data.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+//复制
+export async function copyData(id) {
+  const res = await request.get(`/qms/qualitytemplate/copy/${id}`);
+  if (res.data.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 删除
+export async function removeItem(data) {
+  const res = await request.delete('/qms/qualitytemplate/delete', {
+    data
+  });
+  if (res.data.code == 0) {
+    return res.data.message;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+// 列表
+
+export async function getList(data) {
+  let par = new URLSearchParams(data);
+  const res = await request.get(`/qms/qualitytemplate/page?` + par, {});
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+export async function templatecategoryPage(params) {
+  const res = await request.get(`/qms/templatecategory/page`, { params });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 通过方案ids获取质检项
+export async function getQualityTemplateByIds(data) {
+  const res = await request.post(
+    `/qms/qualitytemplate/getQualityTemplateByIds`,
+    data
+  );
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 方案启用
+export async function updateStatus(data) {
+  const res = await request.put(`/qms/qualitytemplate/updateStatus`, data);
+  if (res.data.code == 0) {
+    return res.data.message;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 643 - 0
src/components/templateDiv/customTable.vue

@@ -0,0 +1,643 @@
+<!-- 搜索表单 -->
+<template>
+  <div style="margin-top: 10px">
+    <div v-if="isSelecting" class="selection-box" :style="selectionStyle"></div>
+    <el-button type="primary" @click="addColumn()" v-if="edit"
+      >新增列</el-button
+    >
+    <el-button type="primary" @click="addRow(columns[0].length)" v-if="edit"
+      >新增行</el-button
+    >
+    <el-checkbox v-model="isMerge" style="margin-left: 10px" v-if="edit"
+      >合并单元格</el-checkbox
+    >
+    <div class="table" style="margin-top: 10px" :id="id">
+      <div
+        class="table-body"
+        style="display: flex"
+        @mousedown="startSelecting"
+        @mousemove="updateSelection"
+        @mouseup="stopSelecting"
+      >
+        <!-- <el-popover
+          style="position: fixed; z-index: 2000"
+          width="400"
+          ref="popoverRef"
+          v-model="rightClickShow"
+        >
+          <el-card class="box-card">
+            <div slot="header" class="clearfix" @click="rightClickShow = false">
+              <span>合并单元格</span>
+              <i class="el-icon-close" style="float: right; padding: 3px 0"></i>
+            </div>
+            <div class="text item">
+              向前合并:
+              <el-input v-model="beforeNum" style="width: 100px" type="number">
+              </el-input>
+              列
+            </div>
+            <div class="text item" style="margin-top: 10px">
+              向后合并:
+              <el-input v-model="laterNum" style="width: 100px" type="number">
+              </el-input>
+              列
+            </div>
+            <div>
+              <el-button
+                style="float: right; margin-bottom: 5px"
+                type="primary"
+                @click="save"
+                >确认</el-button
+              >
+            </div>
+          </el-card>
+        </el-popover> -->
+        <template v-for="(row, index) in columns">
+          <div class="column" :style="{ width: row[0].width + 'px' }">
+            <div
+              class="table-body-item tableTd"
+              v-for="(item, rowIndex) in row"
+              :style="{
+                height: item.rowspan * 30 + 'px',
+                display: item.rowspan ? 'block' : 'none',
+                ...item.style,
+                width: item.colspan ? getWidth(item) : 0
+              }"
+              @contextmenu.prevent="onRightClick($event, rowIndex, index)"
+            >
+              <i
+                class="el-icon-delete delete"
+                style="display: none"
+                @click="removeColumn(item, index)"
+                v-if="edit && rowIndex == 0"
+              ></i>
+              <i
+                class="el-icon-circle-plus-outline add"
+                style="display: none"
+                @click="addColumn(item)"
+                v-if="edit && rowIndex == 0"
+              ></i>
+              <i
+                class="el-icon-delete deleteRow"
+                @click="removeRow(rowIndex)"
+                v-if="edit && rowIndex != 0 && item.style?.border != 'none'"
+              ></i>
+              <i
+                class="el-icon-circle-plus-outline addRow"
+                style="display: none"
+                @click="addRow(rowIndex, item)"
+                v-if="edit && rowIndex != 0 && index != columns.length - 1"
+              ></i>
+              <textarea
+                v-if="item.rowspan > 1"
+                v-model="item.value"
+                class="templateInput"
+                :id="item.id"
+                :ref="item.id + 'ref'"
+                :readonly="item.readonly == 2 || readonly"
+                @click="inputClick(item)"
+                @input="calculation"
+                autocomplete="off"
+                style="resize: none"
+              ></textarea>
+              <input
+                v-else
+                v-model="item.value"
+                class="templateInput"
+                :id="item.id"
+                :ref="item.id + 'ref'"
+                :readonly="item.readonly == 2 || readonly"
+                @click="inputClick(item, rowIndex == 0 ? 'columns' : null)"
+                @input="calculation"
+                type="text"
+                autocomplete="off"
+              />
+            </div>
+          </div>
+        </template>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+  import dictMixins from '@/mixins/dictMixins';
+  import { generateRandomString } from '@/utils/util';
+
+  export default {
+    props: {},
+    mixins: [dictMixins],
+    props: {
+      id: '',
+      edit: {
+        default: true,
+        type: Boolean
+      },
+      readonly: {
+        default: false,
+        type: Boolean
+      }
+    },
+    data() {
+      return {
+        form: null,
+        valueObj: {},
+        domId: '',
+        rightClickShow: false,
+        columns: [],
+        units: {},
+        equation: {},
+        beforeNum: 0,
+        laterNum: 0,
+        currentRowIndex: 0,
+        currentColumnIndex: 0,
+        isSelecting: false,
+        startX: 0,
+        startY: 0,
+        endX: 0,
+        endY: 0,
+        selectedItems: [],
+        isMerge: false
+      };
+    },
+    created() {},
+    computed: {
+      selectionStyle() {
+        return {
+          position: 'fixed',
+          left: `${Math.min(this.startX, this.endX)}px`,
+          top: `${Math.min(this.startY, this.endY)}px`,
+          width: `${Math.abs(this.endX - this.startX)}px`,
+          height: `${Math.abs(this.endY - this.startY)}px`,
+          border: '2px dashed black'
+        };
+      }
+    },
+    methods: {
+      startSelecting(event) {
+        if (!this.isMerge) {
+          return;
+        }
+        this.isSelecting = true;
+        this.startX = event.clientX;
+        this.startY = event.clientY;
+        this.endX = this.startX;
+        this.endY = this.startY;
+      },
+      updateSelection(event) {
+        if (this.isSelecting) {
+          this.endX = event.clientX;
+          this.endY = event.clientY;
+        }
+      },
+      stopSelecting() {
+        this.isSelecting = false;
+        // 在这里处理框选结果,例如计算被框选的元素
+        this.calculateSelectedItems();
+      },
+      calculateSelectedItems() {
+        this.selectedItems = [];
+        this.columns.forEach((cell, columnIndex) => {
+          cell.forEach((row, rowIndex) => {
+            const rect = this.$refs[row.id + 'ref'][0].getBoundingClientRect();
+            if (
+              rect.left < this.endX &&
+              rect.right > this.startX &&
+              rect.top < this.endY &&
+              rect.bottom > this.startY
+            ) {
+              row.columnIndex = columnIndex;
+              row.rowIndex = rowIndex;
+              this.selectedItems.push(row);
+            }
+          });
+        });
+        // console.log(this.selectedItems, 'this.selectedItems[0]');
+        // return
+
+        if (this.selectedItems.length < 1) {
+          return;
+        }
+        let _columnIndex = this.selectedItems[0].columnIndex;
+        let _rowIndex = this.selectedItems[0].rowIndex;
+        let _colspan = this.selectedItems[0].colspan;
+        let rowspan = this.selectedItems
+          .filter((item) => item.columnIndex === _columnIndex)
+          .reduce((acc, cur) => acc + cur.rowspan, 0);
+        if (this.verify(_colspan, rowspan, this.selectedItems, _rowIndex)) {
+          return;
+        }
+        for (let index = 0; index < this.selectedItems.length; index++) {
+          let item = this.selectedItems[index];
+          if (index != 0) {
+            if (!this.selectedItems[0].style) {
+              this.selectedItems[0].style = {};
+            }
+            if (
+              this.selectedItems[0].rowIndex == item.rowIndex &&
+              this.selectedItems[0].columnIndex != item.columnIndex
+            ) {
+              this.selectedItems[0].colspan += item.colspan;
+              this.selectedItems[0].colspanKey.push(item.id);
+              this.selectedItems[0].colspanKey.push(...item.colspanKey);
+            }
+            if (
+              this.selectedItems[0].rowIndex != item.rowIndex &&
+              this.selectedItems[0].columnIndex == item.columnIndex
+            ) {
+              this.selectedItems[0].rowspan += item.rowspan;
+              item.rowspan = 0;
+            }
+
+            item.colspan = 0;
+            item.style = {
+              border: 'none'
+            };
+            this.$set(this.columns[item.columnIndex], item.rowIndex, item);
+          }
+        }
+        this.$set(this.columns[_columnIndex], _rowIndex, this.selectedItems[0]);
+      },
+      colspanSum(rowIndex) {
+        return this.selectedItems.filter((item) => item.rowIndex == rowIndex);
+      },
+      verify(_colspan, _rowspan, arr, _rowIndex) {
+        for (let index = 0; index < arr.length; index++) {
+          let item = arr[index];
+          if (_rowIndex === 0 && _rowIndex != item.rowIndex) {
+            //表头不能和其他行合并
+            return true;
+          }
+          if (
+            item.rowIndex != this.selectedItems[0].rowIndex &&
+            _colspan > this.colspanSum(item.rowIndex).length &&
+            item.colspan != 0
+          ) {
+            return true;
+          }
+
+          if (item.rowspan > _rowspan) {
+            return true;
+          }
+        }
+      },
+
+      // 方法:添加新列
+      addColumn(item) {
+        let length = this.columns[0]?.length || 1;
+        if (item) {
+          let _columnIndex = item.columnIndex;
+          if (item.colspan > 1) {
+            _columnIndex += Number(item.colspan - 1);
+          }
+          this.columns.splice(
+            _columnIndex + 1,
+            0,
+            Array(length)
+              .fill(null)
+              .map(() => this.getInput())
+          );
+        } else {
+          this.columns.push(
+            Array(length)
+              .fill(null)
+              .map(() => this.getInput())
+          );
+        }
+      },
+      getInput() {
+        return {
+          readonly: 1,
+          value: '',
+          rowspan: 1,
+          colspan: 1,
+          colspanKey: [],
+          width: 100,
+          style: { width: 100 },
+          id: generateRandomString(5)
+        };
+      },
+      getIndex(id) {
+        let columnIndex, rowIndex;
+        console.log(id);
+        this.columns.forEach((cell, _columnIndex) => {
+          let cellIndex = cell.findIndex((data) => data.id == id);
+          if (cellIndex != '-1') {
+            columnIndex = _columnIndex;
+            rowIndex = cellIndex;
+          }
+        });
+        return { columnIndex, rowIndex };
+      },
+
+      // 方法:删除指定列
+      removeColumn(item, index) {
+        this.columns[index].forEach((cell, rowIndex) => {
+          if (cell.colspanKey.length) {
+            //当前删除的列其他行有合并过单元格的处理
+            let data = this.columns[index + 1][rowIndex];
+
+            data.colspan = cell.colspan - 1;
+            data.rowspan = cell.rowspan;
+            data.style = cell.style;
+            data.colspanKey = cell.colspanKey.filter((item) => item != data.id);
+            if (data.rowspan > 1) {
+              for (let j = 1; j < data.rowspan; j++) {
+                this.$set(this.columns[index + 1][rowIndex + j], 'rowspan', 0);
+              }
+            }
+            this.$set(this.columns[index + 1], rowIndex, data);
+          }
+        });
+        if (item?.colspanKey.length) {
+          item.colspanKey.forEach((id) => {
+            let { columnIndex } = this.getIndex(id);
+            console.log(columnIndex, 'columnIndex');
+
+            this.columns[columnIndex].forEach((cell, rowIndex) => {
+              if (cell.colspanKey.length) {
+                //当前删除的列其他行有合并过单元格的处理
+                let data = this.columns[columnIndex + 1][rowIndex];
+
+                data.colspan = cell.colspan - 1;
+                data.rowspan = cell.rowspan;
+                data.style = cell.style;
+                data.colspanKey = cell.colspanKey.filter(
+                  (item) => item != data.id
+                );
+                if (data.rowspan > 1) {
+                  for (let j = 1; j < data.rowspan; j++) {
+                    this.$set(
+                      this.columns[columnIndex + 1][rowIndex + j],
+                      'rowspan',
+                      0
+                    );
+                  }
+                }
+                this.$set(this.columns[columnIndex + 1], rowIndex, data);
+              }
+            });
+
+            this.columns.splice(index + 1, 1);
+          });
+        }
+        this.columns.splice(index, 1);
+        //当前删除的列合并过单元格的列都删除
+      },
+
+      // 方法:添加新行
+      addRow(rowIndex, row) {
+        let _rowIndex = rowIndex;
+
+        if (row?.rowspan > 1) {
+          _rowIndex += Number(row?.rowspan - 1);
+        }
+
+        this.columns.forEach((item, index) => {
+          this.columns[index].splice(_rowIndex + 1, 0, this.getInput());
+        });
+
+        // }
+      },
+      //找到真正需要改变rowspan的行
+      getPreventRowspan(columnIndex, rowIndex) {
+        let preventRowspan = null;
+        this.columns[columnIndex].forEach((item, newRowIndex) => {
+          if (newRowIndex < rowIndex && item.rowspan > 1) {
+            //向上找到当前列合并过单元格的行
+            preventRowspan = newRowIndex;
+          }
+        });
+
+        return preventRowspan;
+      },
+      // 方法:删除指定行
+      removeRow(rowIndex) {
+        this.columns.forEach((item, columnIndex) => {
+          if (item[rowIndex].rowspan == 0) {
+            // 如果当前列,删除的这一行rowspan为0,则需要找到真正需要改变rowspan的行
+            let preventRowspanIndex = this.getPreventRowspan(
+              columnIndex,
+              rowIndex
+            );
+            if (preventRowspanIndex) {
+              this.$set(
+                this.columns[columnIndex][preventRowspanIndex],
+                'rowspan',
+                this.columns[columnIndex][preventRowspanIndex].rowspan - 1
+              );
+            }
+          } else if (item[rowIndex].rowspan > 1) {
+            //rowspan大于1,代表合并过单元格,需要吧值继承给下一行
+            let data = item[rowIndex];
+            data.rowspan--;
+            this.$set(this.columns[columnIndex], [rowIndex + 1], data);
+          }
+
+          item.splice(rowIndex, 1);
+        });
+      },
+      getWidth(item) {
+        let width = Number(item.style.width) || 100;
+        if (item.colspanKey.length) {
+          this.columns.forEach((cell) => {
+            cell.forEach((row) => {
+              if (item.colspanKey.includes(row.id)) {
+                width += Number(row.style.width || 100);
+              }
+            });
+          });
+        }
+
+        return width + 'px';
+      },
+      calculation() {
+        this.$emit('calculation');
+      },
+      equationValue({ domId, value }) {
+        this.columns.forEach((item, index) => {
+          let cellIndex = item.findIndex((cell) => cell.id == domId);
+          if (cellIndex != '-1') {
+            this.$set(this.columns[index][cellIndex], 'value', value);
+          }
+        });
+      },
+      getValue() {
+        return {
+          form: null,
+          equation: this.equation,
+          units: this.units,
+          valueObj: {
+            columns: this.columns
+          }
+        };
+      },
+      init({ form, valueObj, equation, units }) {
+        this.form = form;
+        this.columns = valueObj.columns;
+        this.equation = equation || {};
+        this.units = units || {};
+      },
+      editInputChange(domObj) {
+        if (domObj.equation) {
+          this.equation[this.domId] = domObj.equation;
+        }
+        if (domObj.units) {
+          this.units[this.domId] = domObj.units;
+        }
+        let dom = document.getElementById(domObj.id);
+
+        this.columns.forEach((item, index) => {
+          let rowsIndex = item.findIndex((cells) => cells.id == this.domId);
+
+          if (rowsIndex >= 0) {
+            let width = domObj.width - dom.parentElement.offsetWidth;
+            let newWidth = this.columns[index][rowsIndex].style.width + width;
+            this.columns[index][0].width = newWidth;
+            this.$set(this.columns[index], rowsIndex, domObj);
+            item.forEach((cell, _index) => {
+              this.$set(this.columns[index][_index].style, 'width', newWidth);
+              this.$set(this.columns[index][_index], 'width', newWidth);
+            });
+          }
+        });
+      },
+      onRightClick(PointerEvent, rowIndex, columnIndex) {
+        this.currentRowIndex = rowIndex;
+        this.currentColumnIndex = columnIndex;
+        if (rowIndex === 0) {
+          this.rightClickShow = true;
+          this.$nextTick(() => {
+            let y = PointerEvent.pageY;
+            let x = PointerEvent.pageX + 10;
+            if (PointerEvent.screenY >= PointerEvent.view.innerHeight) {
+              y -= 80;
+            }
+            this.$refs.popoverRef.$el.style.top = y + 'px';
+            this.$refs.popoverRef.$el.style.left = x + 'px';
+          });
+        }
+      },
+
+      inputClick(item, type) {
+        if (!this.edit) {
+          return;
+        }
+        let dom = document.getElementById(item.id);
+
+        this.domId = item.id;
+        this.$emit('editShow', {
+          templateDivRef: 'customTextRef' + this.id,
+          domObj: {
+            ...item,
+            width: dom.parentElement.offsetWidth,
+            isNoWidth: type != 'columns' ? false : true,
+            equation: this.equation[item.id],
+            units: this.units[item.id] || {}
+          }
+        });
+      }
+    }
+  };
+</script>
+<style lang="scss" scoped>
+  :deep(.templateInput) {
+    width: 100%;
+    height: 100%;
+    border: none;
+
+    text-align: center;
+    background-color: #fff;
+  }
+
+  .table-header {
+    span {
+      display: inline-block;
+      height: 30px;
+      border: 1px solid #ddd;
+      width: 100px;
+      background-color: #f2f2f2 !important;
+    }
+
+    input {
+      background-color: #f2f2f2 !important;
+    }
+  }
+  .table-body {
+    white-space: nowrap;
+    .column {
+      display: inline-block;
+      > div {
+        height: 30px;
+        border: 1px solid #ddd;
+        width: 100%;
+      }
+      > div:nth-of-type(1) {
+        background-color: #f2f2f2 !important;
+        > input {
+          background-color: #f2f2f2 !important;
+        }
+      }
+    }
+  }
+  // th,
+  // td {
+  //   border: 1px solid #ddd;
+  //   padding: 2px;
+  //   text-align: center;
+  //   height: 30px;
+  // }
+  // th {
+  //   background-color: #f2f2f2;
+  //   > input {
+  //     background-color: #f2f2f2 !important;
+  //   }
+  // }
+  tr:nth-child(even) {
+    background-color: #f9f9f9;
+  }
+  input:focus {
+    border-color: #66afe9; /* 改变边框颜色 */
+    outline: none; /* 移除默认的轮廓线 */
+  }
+  .tableTd {
+    position: relative;
+  }
+  .deleteRow {
+    display: block !important;
+    position: absolute;
+    bottom: 0px;
+    right: -15px;
+    color: #f56c6c;
+  }
+  .tableTd:hover {
+    .delete {
+      display: block !important;
+      position: absolute;
+      right: 0;
+      top: 0;
+      color: #f56c6c;
+    }
+
+    .add {
+      display: block !important;
+      position: absolute;
+      right: 20px;
+      top: 0;
+      color: #409eff;
+    }
+    .addRow {
+      display: block !important;
+      position: absolute;
+      bottom: 0px;
+      right: 10px;
+      color: #409eff;
+    }
+  }
+  .selection-box {
+    position: absolute;
+    border: 2px dashed black;
+    z-index: 999;
+    pointer-events: none; /* 确保选择框不会干扰鼠标事件 */
+  }
+</style>

+ 235 - 0
src/components/templateDiv/customText.vue

@@ -0,0 +1,235 @@
+<!-- 搜索表单 -->
+<template>
+  <div>
+    <el-popover
+      style="position: fixed; z-index: 2000"
+      width="130"
+      ref="popoverRef"
+      v-model="rightClickShow"
+      @click.native="rightClickShow = false"
+    >
+      <div>
+        <el-button type="primary" @click="addHtml">插入输入框</el-button>
+      </div>
+    </el-popover>
+    <div
+      v-html="form"
+      :contenteditable="edit"
+      class="contenteditable"
+      :ref="id"
+      :id="id"
+      @contextmenu.prevent="onRightClick($event)"
+    >
+    </div>
+  </div>
+</template>
+
+<script>
+  import dictMixins from '@/mixins/dictMixins';
+  import { generateRandomString } from '@/utils/util';
+
+  export default {
+    props: {},
+    mixins: [dictMixins],
+    props: {
+      id: '',
+      edit: {
+        default: true,
+        type: Boolean
+      },
+      readonly: {
+        default: false,
+        type: Boolean
+      }
+    },
+    data() {
+      return {
+        form: null,
+        valueObj: {},
+        equation: {},
+        units: {},
+        domId: '',
+        rightClickShow: false
+      };
+    },
+    methods: {
+      addHtml() {
+        this.insertInput();
+      },
+      objInit() {
+        if (Object.keys(this.valueObj).length) {
+          for (let key in this.valueObj) {
+            this.$nextTick(() => {
+              let dom = document.getElementById(key);
+              dom.value = this.valueObj[key];
+            });
+          }
+        }
+      },
+      insertInput() {
+        const selection = window.getSelection();
+        if (selection.rangeCount > 0) {
+          const range = selection.getRangeAt(0);
+
+          this.getParentID(range.commonAncestorContainer);
+          if (this.getParentID(range.commonAncestorContainer)) {
+            range.setStart(selection.anchorNode, selection.anchorOffset);
+            range.setEnd(selection.focusNode, selection.focusOffset);
+            range.deleteContents(); // 删除选中的内容(如果需要)
+            range.insertNode(this.getInput()); // 插入input元素
+            // 可以设置光标位置在input之后
+            range.selectNodeContents(this.getInput());
+            range.collapse(false); // 光标放在input之后
+            selection.removeAllRanges();
+            selection.addRange(range);
+          }
+
+          // return
+        }
+      },
+      getParentID(data) {
+        if (data.id == this.id) {
+          return true;
+        }
+        if (data.parentElement) {
+          return this.getParentID(data.parentElement);
+        }
+      },
+
+      getInput() {
+        let id = generateRandomString();
+        const inputElement = document.createElement('input');
+        inputElement.setAttribute('type', 'text');
+        inputElement.setAttribute('class', 'templateInput');
+        inputElement.setAttribute('autocomplete', 'off');
+        inputElement.setAttribute('id', id);
+        return inputElement;
+      },
+      getValue() {
+        let inputs = document.querySelectorAll(
+          '#' + this.id + ' .templateInput'
+        );
+        let data = {};
+        if (inputs.length) {
+          inputs.forEach((item) => {
+            data[item.id] = item.value;
+          });
+        }
+        return {
+          form: this.$refs[this.id].innerHTML,
+          valueObj: data,
+          equation: this.equation,
+          units: this.units
+        };
+      },
+      equationValue({ domId, value }) {
+        if (domId) {
+          let dom = document.getElementById(domId);
+          if (dom) {
+            this.valueObj[domId] = value;
+            dom.value = value;
+          }
+        }
+      },
+      init({ form, valueObj, equation, units }) {
+        this.form = form;
+        this.valueObj = valueObj;
+        this.equation = equation || {};
+        this.units = units || {};
+        this.$nextTick(() => {
+          if (this.readonly) {
+            let inputs = document.querySelectorAll('.templateInput');
+            inputs.forEach((item) => {
+              item.setAttribute('readonly', 'readonly');
+            });
+          }
+        });
+        this.objInit();
+      },
+      editInputChange(domObj) {
+        let dom = document.getElementById(this.domId);
+        dom.style.width = domObj.width + 'px';
+        if (domObj.readonly == 2) {
+          dom.setAttribute('readonly', 'readonly');
+        } else {
+          dom.removeAttribute('readonly');
+        }
+        delete this.valueObj[dom.id];
+        this.valueObj[domObj.id] = dom.value;
+        if (domObj.equation) {
+          this.equation[domObj.id] = domObj.equation;
+        }
+        if (domObj.units) {
+          this.units[domObj.id] = domObj.units;
+        }
+        dom.id = domObj.id;
+      },
+      onRightClick(PointerEvent) {
+        this.rightClickShow = true;
+        this.$nextTick(() => {
+          let y = PointerEvent.pageY;
+          let x = PointerEvent.pageX + 10;
+          if (PointerEvent.screenY >= PointerEvent.view.innerHeight) {
+            y -= 80;
+          }
+          this.$refs.popoverRef.$el.style.top = y + 'px';
+          this.$refs.popoverRef.$el.style.left = x + 'px';
+        });
+      },
+      inputChange(event) {
+        if (event.target && event.target.className == 'templateInput') {
+          this.valueObj[event.target.id] = event.target.value;
+
+          this.$emit('calculation');
+        }
+      },
+      inputClick(event) {
+        if (!this.edit) {
+          return;
+        }
+        if (event.target && event.target.className == 'templateInput') {
+          this.domId = event.target.id;
+          this.$emit('editShow', {
+            templateDivRef: 'customTextRef' + this.id,
+            domObj: {
+              width: event.target.offsetWidth,
+              id: event.target.id,
+              readonly: event.target.readOnly ? 2 : 1,
+              equation: this.equation[this.domId],
+              units: this.units[this.domId] || {}
+            }
+          });
+        }
+      }
+    },
+
+    mounted() {
+      this.$nextTick(() => {
+        document
+          .getElementById(this.id)
+          .addEventListener('input', this.inputChange);
+
+        document
+          .getElementById(this.id)
+          .addEventListener('click', this.inputClick);
+      });
+    }
+  };
+</script>
+<style lang="scss" scoped>
+  :deep(.templateInput) {
+    width: 80px;
+    border: solid 1px #bfbfbf;
+    padding: 1px;
+    margin: 1px;
+    margin-left: 3px;
+    text-align: center;
+  }
+  .contenteditable {
+    // padding: 5px;
+    width: 100%;
+    min-height: 20px;
+    padding-left: 10px;
+    // border: solid 1px #b3b0b0;
+  }
+</style>

+ 549 - 0
src/components/templateDiv/experimentationProcess.vue

@@ -0,0 +1,549 @@
+<template>
+  <div class="ele-body">
+    <el-button type="primary" @click="addHtml('customText')" v-if="edit"
+      >插入自定义文本</el-button
+    >
+    <el-button type="primary" @click="addHtml('customTable')" v-if="edit"
+      >插入表格</el-button
+    >
+    <!-- <el-button type="primary" @click="save()">保存</el-button> -->
+    <div
+      style="
+        display: flex;
+        width: 100%;
+        padding: 10px;
+        border: solid 1px #f1f1f1;
+        margin-top: 10px;
+      "
+    >
+      <vue-draggable
+        v-model="list"
+        group="project1"
+        :animation="300"
+        handle=".sort-handle"
+        style="flex: 1"
+      >
+        <div
+          class="demo-drag-list-item ele-cell"
+          v-for="item in list"
+          :key="item.id"
+        >
+          <div class="listItem">
+            <i
+              class="sort-handle el-icon-_nav move"
+              style="display: none"
+              v-if="edit"
+            ></i>
+            <i
+              class="sort-handle el-icon-delete delete"
+              v-if="edit"
+              style="display: none"
+              @click="del(item.id)"
+            ></i>
+            <customText
+              :ref="'customTextRef' + item.id"
+              style="flex: 1"
+              v-if="item.type == 'customText'"
+              :id="item.id"
+              :form="item.value"
+              :valueObj="item.valueObj"
+              @editShow="editShowFn"
+              @calculation="calculation"
+              :readonly="readonly"
+              :edit="edit"
+            ></customText>
+            <customTable
+              :ref="'customTextRef' + item.id"
+              style="flex: 1"
+              v-if="item.type == 'customTable'"
+              :id="item.id"
+              :form="item.value"
+              :valueObj="item.valueObj"
+              @calculation="calculation"
+              @editShow="editShowFn"
+              :readonly="readonly"
+              :edit="edit"
+            ></customTable>
+          </div>
+        </div>
+      </vue-draggable>
+
+      <el-card class="box-card" v-show="editShow" style="width: 320px">
+        <div slot="header" class="clearfix">
+          <span>配置</span>
+          <el-button
+            style="float: right; padding: 3px 0"
+            type="text"
+            @click="editShow = false"
+            >关闭</el-button
+          >
+        </div>
+        <el-form label-width="80px">
+          <el-form-item label="字段标识:" prop="id">
+            <el-input
+              v-model="domObj.id"
+              placeholder=""
+              @change="editInputChange"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="宽度:" prop="width" v-if="!domObj.isNoWidth">
+            <el-input
+              v-model="domObj.width"
+              type="number"
+              placeholder=""
+              @change="editInputChange"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="是否只读:" prop="readonly">
+            <el-select
+              v-model="domObj.readonly"
+              placeholder="请选择"
+              @change="editInputChange"
+            >
+              <el-option :key="1" label="否" :value="1"> </el-option>
+              <el-option :key="2" label="是" :value="2"> </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="计算公式:" prop="readonly">
+            <el-input
+              :value="domObj.equation?.map((item) => item.value).join('')"
+              type="textarea"
+              placeholder=""
+              disabled
+            ></el-input>
+            <el-button type="primary" @click="setEquation">配置公式</el-button>
+            <el-button type="primary" @click="delEquation">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </el-card>
+    </div>
+    <ele-modal
+      title="配置公式"
+      :visible.sync="visible"
+      :close-on-click-modal="false"
+      append-to-body
+      width="800px"
+      resizable
+      maxable
+    >
+      <div class="formula-builder__selects">
+        <!-- 选择参数:从已填的非计算参数内容里取 -->
+        <el-select
+          v-model="equationUnit.paramSelect"
+          placeholder="选择参数"
+          size="mini"
+          style="width: 100px; margin-right: 8px; flex-shrink: 0"
+          @change="paramSelectChange($event, 'id')"
+          filterable
+        >
+          <el-option
+            v-for="item in idList"
+            :key="item"
+            :label="item"
+            :value="item"
+          />
+        </el-select>
+
+        <!-- 选择运算符 -->
+        <el-select
+          v-model="equationUnit.opSelect"
+          placeholder="选择符号"
+          size="mini"
+          style="width: 100px; flex-shrink: 0; margin-right: 8px"
+          @change="paramSelectChange($event, 'symbol')"
+        >
+          <el-option
+            v-for="op in opSelectOptions"
+            :key="op"
+            :label="op"
+            :value="op"
+          />
+        </el-select>
+        <!-- 选择值 -->
+        <el-input
+          v-model="equationUnit.currentValue"
+          placeholder="输入值"
+          size="mini"
+          style="width: 150px; flex-shrink: 0"
+        >
+          <template slot="append">
+            <span
+              style="cursor: pointer"
+              @click="paramSelectChange(equationUnit.currentValue, 'value')"
+              >确认</span
+            >
+          </template>
+        </el-input>
+        <!-- 替换或者追加 -->
+        <el-select
+          v-if="equationUnit.activeIndex != undefined"
+          v-model="equationUnit.replaceOrAppend"
+          placeholder="选择"
+          size="mini"
+          style="width: 80px; margin-left: 8px; flex-shrink: 0"
+        >
+          <el-option key="append" label="追加" value="append" />
+          <el-option key="replace" label="替换" value="replace" />
+        </el-select>
+        <el-input
+          v-model.number="domObj.units.decimalPlace"
+          placeholder="小数位"
+          size="mini"
+          style="width: 120px; margin-left: 8px; flex-shrink: 0"
+        >
+        </el-input>
+        <el-select
+          v-model="domObj.units.takeValueMethod"
+          placeholder="取值方法"
+          size="mini"
+          style="width: 100px; margin-left: 8px; flex-shrink: 0"
+        >
+          <el-option key="1" label="四舍五入" value="1" />
+          <el-option key="2" label="去尾" value="2" />
+        </el-select>
+      </div>
+
+      <!-- 已组装公式标签展示 -->
+      <div
+        v-if="equationUnit.equation.length"
+        style="
+          display: inline-flex;
+          flex-wrap: wrap;
+          max-width: 100%;
+          margin-top: 5px;
+        "
+      >
+        <el-tag
+          v-for="(p, index) in equationUnit.equation"
+          :key="index"
+          size="mini"
+          closable
+          :type="equationUnit.activeIndex === index ? 'primary' : 'info'"
+          @click="formulaPartsTagClick(index)"
+          @close="tagItemDelete(index)"
+        >
+          {{ p.value }}
+        </el-tag>
+      </div>
+
+      <el-input
+        style="margin-top: 5px"
+        :value="equationUnit.equation?.map((item) => item.value).join('')"
+        type="textarea"
+        placeholder=""
+        disabled
+      ></el-input>
+      <div slot="footer" class="footer">
+        <el-button type="primary" @click="editInputChange('equation')"
+          >确认</el-button
+        >
+        <el-button @click="visible = false">返回</el-button>
+      </div>
+    </ele-modal>
+  </div>
+</template>
+
+<script>
+  import customText from './customText.vue';
+  import customTable from './customTable.vue';
+  import VueDraggable from 'vuedraggable';
+  import { generateRandomString } from '@/utils/util';
+
+  export default {
+    components: {
+      customText,
+      VueDraggable,
+      customTable
+    },
+    props: {
+      edit: {
+        default: true,
+        type: Boolean
+      },
+      readonly: {
+        default: false,
+        type: Boolean
+      }
+    },
+    computed: {},
+    data() {
+      return {
+        list: [],
+        editShow: false,
+        visible: false,
+        templateDivRef: '',
+        domObj: { units: {} },
+        idList: [],
+        opSelectOptions: ['+', '-', '*', '/', '%', '(', ')'],
+        equationUnit: {
+          equation: [],
+          activeIndex: '',
+          paramSelect: '',
+          opSelect: '',
+          currentValue: '',
+          replaceOrAppend: 'append'
+        }
+      };
+    },
+    mounted() {},
+    created() {},
+    methods: {
+      // 计算
+      calculation() {
+        this.getValue();
+        let equation = [];
+
+        this.list.forEach((item) => {
+          equation.push({
+            id: item.id,
+            equation: item.equation
+          });
+        });
+        equation.forEach((item) => {
+          for (const key in item.equation) {
+            let { data, units } = this.getObjValue(); //每次计算都获取最新的值
+            let value = '';
+            if (item.equation[key].length) {
+              item.equation[key].forEach((equationItem) => {
+                if (
+                  equationItem.type == 'symbol' ||
+                  equationItem.type == 'value'
+                ) {
+                  value += equationItem.value;
+                } else if (equationItem.type == 'id') {
+                  value += Number(data[equationItem.value]) || 0;
+                }
+              });
+              if (units[key]?.decimalPlace) {
+                if (units[key]?.takeValueMethod) {
+                  value =
+                    units[key]?.takeValueMethod == 1
+                      ? parseFloat(eval(value).toFixed(units[key].decimalPlace))
+                      : this.truncateToFixedManual(
+                          eval(value),
+                          units[key].decimalPlace
+                        );
+                } else {
+                  value = parseFloat(
+                    eval(value).toFixed(units[key].decimalPlace)
+                  );
+                }
+              } else {
+                value = parseFloat(eval(value).toFixed(2));
+              }
+              if (this.$refs['customTextRef' + item.id][0]) {
+                this.$refs['customTextRef' + item.id][0].equationValue({
+                  domId: key,
+                  value
+                });
+              }
+            }
+          }
+        });
+      },
+
+      truncateToFixedManual(num, decimalPlaces) {
+        let factor = Math.pow(10, decimalPlaces);
+        return Math.floor(num * factor) / factor;
+      },
+      getObjValue() {
+        this.getValue();
+        let data = {};
+        let units = {};
+        this.list.forEach((item) => {
+          units = { ...item.units, ...units };
+
+          if (item.type == 'customText') {
+            data = { ...item.valueObj, ...data };
+          } else {
+            item.valueObj.columns.forEach((row) => {
+              row.forEach((cell) => {
+                data[cell.id] = cell.value;
+              });
+            });
+          }
+        });
+        return { data: data || {}, units: units || {} };
+      },
+
+      setEquation() {
+        this.getValue();
+        this.idList = [];
+        if (this.domObj.equation) {
+          this.equationUnit.equation = JSON.parse(
+            JSON.stringify(this.domObj.equation)
+          );
+          this.equationUnit.activeIndex = this.domObj.equation.length;
+        } else {
+          this.equationUnit.equation = [];
+        }
+        this.list.forEach((item) => {
+          if (item.type == 'customText') {
+            for (let key in item.valueObj) {
+              this.idList.push(key);
+            }
+          } else {
+            item.valueObj.columns.forEach((row) => {
+              row.forEach((cell) => {
+                this.idList.push(cell.id);
+              });
+            });
+          }
+        });
+        this.visible = true;
+      },
+      delEquation() {
+        this.equationUnit.equation = [];
+        this.editInputChange('equation');
+      },
+      tagItemDelete(index) {
+        this.equationUnit.equation.splice(index, 1);
+      },
+      formulaPartsTagClick(index, row) {
+        if (!this.equationUnit.replaceOrAppend) {
+          // 默认追加
+          this.equationUnit_replaceOrAppend = 'append';
+        }
+
+        if (
+          this.equationUnit.activeIndex &&
+          this.equationUnit.activeIndex === index
+        ) {
+          this.$set(this.equationUnit, 'activeIndex', undefined);
+        } else {
+          this.$set(this.equationUnit, 'activeIndex', index);
+        }
+      },
+      paramSelectChange(val, type) {
+        if (!val) {
+          return;
+        }
+        if (type == 'id') {
+          this.setValue({ type: 'id', value: val });
+          this.equationUnit.paramSelect = null;
+        } else if (type == 'symbol') {
+          this.setValue({ type: 'symbol', value: val });
+
+          this.equationUnit.opSelect = null;
+        } else if (type == 'value') {
+          this.setValue({ type: 'value', value: val });
+        }
+      },
+      setValue(val) {
+        if (this.equationUnit.activeIndex != undefined) {
+          if (
+            !this.equationUnit.replaceOrAppend ||
+            this.equationUnit.replaceOrAppend === 'replace'
+          ) {
+            this.equationUnit.equation.splice(
+              this.equationUnit.activeIndex,
+              1,
+              val
+            );
+          } else if (this.equationUnit.replaceOrAppend === 'append') {
+            this.equationUnit.equation.splice(
+              this.equationUnit.activeIndex + 1,
+              0,
+              val
+            );
+            // 追加后activeIndex后移一位
+            this.$set(
+              this.equationUnit,
+              'activeIndex',
+              this.equationUnit.activeIndex + 1
+            );
+          }
+        } else {
+          this.equationUnit.equation.push(val);
+        }
+      },
+
+      init(list) {
+        this.list = JSON.parse(list);
+        this.editShow = false;
+        if (this.list.length) {
+          this.$nextTick(() => {
+            this.list.forEach((item) => {
+              this.$refs['customTextRef' + item.id][0].init({
+                form: item.value,
+                valueObj: item.valueObj,
+                equation: item.equation,
+                units: item.units
+              });
+            });
+          });
+        }
+      },
+      editShowFn({ templateDivRef, domObj }) {
+        this.templateDivRef = templateDivRef;
+        this.$set(this, 'domObj', domObj);
+        this.editShow = true;
+      },
+      editInputChange(type) {
+        if (type == 'equation') {
+          this.visible = false;
+          this.domObj.equation = JSON.parse(
+            JSON.stringify(this.equationUnit.equation)
+          );
+        }
+        this.$nextTick(() => {
+          this.$refs[this.templateDivRef][0].editInputChange(this.domObj);
+        });
+      },
+      del(id) {
+        this.list = this.list.filter((item) => item.id != id);
+      },
+      addHtml(type) {
+        this.list.push({
+          id: generateRandomString(6),
+          type: type,
+          value: '',
+          valueObj: {}
+        });
+      },
+      getValue() {
+        this.list.forEach((item, index) => {
+          let { form, valueObj, equation, units } =
+            this.$refs['customTextRef' + item.id][0].getValue();
+          this.$set(this.list[index], 'value', form);
+          this.$set(this.list[index], 'valueObj', valueObj);
+          this.$set(this.list[index], 'equation', equation);
+          this.$set(this.list[index], 'units', units);
+        });
+        return this.list;
+      }
+    }
+  };
+</script>
+
+<style scoped lang="scss">
+  .listItem {
+    padding: 5px;
+    padding-top: 15px;
+    border: solid 1px #f1f1f1;
+    display: flex;
+    width: 100%;
+    align-items: center;
+    margin-top: 3px;
+    position: relative;
+  }
+  .sort-handle {
+    font-size: 16px;
+    position: absolute;
+    left: 0;
+    top: 0;
+  }
+  .move {
+    cursor: move;
+  }
+  .delete {
+    cursor: pointer;
+    left: 20px;
+    color: #f56c6c;
+  }
+  .listItem:hover {
+    .sort-handle {
+      display: block !important;
+    }
+  }
+</style>

+ 53 - 0
src/components/templateDiv/experimentationProcessDialog.vue

@@ -0,0 +1,53 @@
+<!-- 用户编辑弹窗 -->
+<template>
+  <ele-modal
+    width="80%"
+    :visible.sync="visible"
+    title="编辑模板"
+    :close-on-click-modal="false"
+    :maxable="true"
+    :resizable="true"
+    append-to-body
+  >
+    <experimentationProcess
+      ref="experimentationProcess"
+      :edit="false"
+      :readonly="true"
+    ></experimentationProcess>
+    <template v-slot:footer>
+      <el-button @click="visible = false"> 关闭 </el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+  // import { save } from '@/api/experimentReport';
+  import experimentationProcess from './experimentationProcess.vue';
+
+  export default {
+    components: { experimentationProcess },
+
+    data() {
+      return {
+        visible: false
+      };
+    },
+
+    created() {},
+    methods: {
+      open(data) {
+        this.visible = true;
+        this.$nextTick(() => {
+          this.$refs.experimentationProcess.init(data);
+        });
+      },
+      save() {
+        this.$emit(
+          'success',
+          JSON.stringify(this.$refs.experimentationProcess.getValue())
+        );
+        this.visible = false;
+      }
+    }
+  };
+</script>

+ 6 - 0
src/styles/transition/common.scss

@@ -195,3 +195,9 @@
   height: 32px  !important;
   line-height: 32px  !important;
 }
+.el-input.is-disabled .el-input__inner{
+  color: #333 !important;
+}
+.el-textarea.is-disabled .el-textarea__inner{
+  color: #333 !important;
+}

+ 17 - 0
src/utils/util.js

@@ -151,3 +151,20 @@ export function getSummaries(param, key, unit) {
 
   return sums;
 }
+
+//随机id
+export function generateRandomString(num = 5) {
+  let result = '';
+  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; // 包含字母和数字
+  const charactersNum = '0123456789'; // 包含字母和数字
+  const charactersLength = characters.length;
+  for (let i = 0; i < num; i++) {
+    result += characters.charAt(Math.floor(Math.random() * charactersLength));
+  }
+  for (let j = 0; j < 3; j++) {
+    result += charactersNum.charAt(
+      Math.floor(Math.random() * charactersNum.length)
+    );
+  }
+  return result;
+}

+ 466 - 0
src/views/bpm/handleTask/components/inspectionTemplate/edit.vue

@@ -0,0 +1,466 @@
+<template>
+  <div>
+    <el-form
+      :model="dataForm"
+      :rules="dataRule"
+      ref="dataForm"
+      label-width="80px"
+      :disabled="true"
+    >
+      <el-row style="margin-bottom: 10px">
+        <el-col :span="6"
+          ><el-form-item label="类型 " prop="type">
+            <DictSelection
+              dictName="质检计划类型"
+              v-model="dataForm.type"
+              clearable
+            ></DictSelection> </el-form-item
+        ></el-col>
+        <el-col :span="7">
+          <el-form-item label="名称" prop="qualitySchemeTemplateName">
+            <el-input
+              v-model="dataForm.qualitySchemeTemplateName"
+              placeholder="质检方案名称"
+            ></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="7">
+          <el-form-item label="编码" prop="qualitySchemeTemplateCode">
+            <el-input
+              v-model="dataForm.qualitySchemeTemplateCode"
+              placeholder="质检方案编码"
+              disabled
+            ></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="4"
+          ><el-form-item label="状态 " prop="status">
+            <el-select
+              clearable
+              class="ele-block"
+              v-model="dataForm.status"
+              placeholder="请选择"
+            >
+              <el-option label="失效" :value="0" />
+              <el-option label="有效" :value="1" />
+            </el-select> </el-form-item
+        ></el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="6">
+          <el-form-item label="工序" prop="taskName">
+            <el-input
+              v-model="dataForm.taskName"
+              placeholder="请选择"
+              disabled
+            ></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="18">
+          <el-form-item label="备注" prop="templateRemark">
+            <el-input
+              type="textarea"
+              v-model="dataForm.templateRemark"
+              placeholder="请输入"
+            ></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="24">
+          <div class="title"> 质检参数标准</div>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col style="width: 260px">
+          <el-form-item label="检验方式" prop="qualityMode">
+            <DictSelection
+              dictName="检验方案"
+              clearable
+              v-model="dataForm.qualityMode"
+            >
+            </DictSelection>
+          </el-form-item>
+        </el-col>
+
+        <el-col style="width: 360px" v-if="dataForm.qualityMode == 2">
+          <el-form-item label="取样数量" prop="sampleProportion">
+            <el-input
+              type="number"
+              v-model="dataForm.sampleProportion"
+              placeholder="请输入"
+              style="width: 180px"
+            ></el-input>
+            <DictSelection
+              style="width: 95px"
+              dictName="计量单位"
+              placeholder=" "
+              v-model="dataForm.sampleProportionUnit"
+            ></DictSelection>
+          </el-form-item>
+        </el-col>
+        <el-col style="width: 430px">
+          <el-form-item
+            label="质检报告有效期"
+            prop="validityPeriod"
+            label-width="150px"
+          >
+            <el-input
+              type="number"
+              v-model="dataForm.validityPeriod"
+              placeholder="请输入"
+              style="width: 180px"
+            ></el-input>
+            <el-select
+              style="width: 85px"
+              v-model="dataForm.validityPeriodUnit"
+              placeholder=" "
+            >
+              <el-option label="年" value="年" />
+              <el-option label="月" value="月" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <ele-pro-table
+          ref="table"
+          :columns="columns"
+          :datasource="list"
+          height="400px"
+          full-height="calc(100vh - 76px)"
+          tool-class="ele-toolbar-form"
+        >
+          <template v-slot:textType="{ row }">
+            {{
+              row.textType == 1
+                ? '数值'
+                : row.textType == 2
+                ? '选择'
+                : row.textType == 3
+                ? '上下限'
+                : row.textType == 4
+                ? '规格'
+                : row.textType == 5
+                ? '时间'
+                : row.textType == 6
+                ? '范围'
+                : row.textType == 7
+                ? '文本'
+                : ''
+            }}
+          </template>
+
+          <template v-slot:type="{ row }">
+            {{ getDictValue('质检标准类型', row.qualityStandardType) }}
+          </template>
+
+          <template v-slot:inspectionName="{ row }">
+            <div> <el-input v-model="row.inspectionName"></el-input></div>
+          </template>
+          <template v-slot:sort="{ row }">
+            <el-input
+              v-model="row.sort"
+              type="number"
+              @blur="handleSortBlur"
+              placeholder="输入排序"
+            ></el-input>
+          </template>
+          <template v-slot:defaultValue="{ row, $index }">
+            <div style="width: 100%; display: flex">
+              <DictSelection
+                style="width: 85px"
+                clearable
+                dictName="数学字符"
+                v-model="row.symbol"
+                :isOne="$index === 0"
+              ></DictSelection>
+              <div v-if="row.textType == 3">
+                <el-input v-model="row.minValue" style="width: 80px"></el-input
+                >-
+                <el-input v-model="row.maxValue" style="width: 80px">
+                </el-input>
+              </div>
+
+              <div v-else style="width: 100%">
+                <el-input v-model="row.defaultValue"></el-input>
+              </div>
+
+              <DictSelection
+                dictName="工艺参数单位"
+                clearable
+                filterable
+                v-model="row.unitName"
+                style="width: 100px"
+                :isOne="$index === 0"
+              >
+              </DictSelection>
+            </div>
+          </template>
+          <template v-slot:executionMethod="{ row }">
+            <el-select v-model="row.executionMethod" style="width: 100%">
+              <el-option :value="1" label="常规检验"></el-option>
+              <el-option :value="2" label="实验"></el-option>
+            </el-select>
+          </template>
+          <template v-slot:procedureName="{ row, $index }">
+            <el-input
+              v-model="row.procedureName"
+              readonly
+              style="width: calc(100% - 60px)"
+            >
+            </el-input>
+            <el-button
+              type="primary"
+              @click="viewTemplate(row.procedureJson.tempJson, 5, $index)"
+              v-if="row.procedureJson.tempJson"
+              style="margin-left: 8px"
+              :disabled="false"
+              >预览</el-button
+            >
+          </template>
+          <template v-slot:recordName="{ row, $index }">
+            <el-input
+              v-model="row.recordName"
+              readonly
+              style="width: calc(100% - 60px)"
+            >
+            </el-input>
+            <el-button
+              type="primary"
+              @click="viewTemplate(row.recordJson.tempJson, 7, $index)"
+              v-if="row.recordJson.tempJson"
+              style="margin-left: 8px"
+              :disabled="false"
+              >预览</el-button
+            >
+          </template>
+        </ele-pro-table>
+      </el-row>
+      <el-row>
+        <ele-pro-table
+          ref="table"
+          :columns="categoryColumns"
+          :datasource="templateCategoryList"
+          height="300px"
+          full-height="calc(100vh - 76px)"
+          tool-class="ele-toolbar-form"
+          :need-page="false"
+        >
+        </ele-pro-table>
+      </el-row>
+    </el-form>
+
+    <experimentationProcessDialog
+      ref="experimentationProcessDialog"
+      :edit="false"
+      :readonly="true"
+    ></experimentationProcessDialog>
+  </div>
+</template>
+
+<script>
+  import experimentationProcessDialog from '@/components/templateDiv/experimentationProcessDialog.vue';
+  import {
+    getById,
+    templatecategoryPage
+  } from '@/api/bpm/components/inspectionTemplate';
+
+  import dictMixins from '@/mixins/dictMixins';
+
+  export default {
+    components: { experimentationProcessDialog },
+    mixins: [dictMixins],
+    props: {
+      businessId: {
+        type: String,
+        default: ''
+      }
+    },
+    data() {
+      return {
+        dataForm: {
+          id: 0,
+          type: null,
+          qualitySchemeTemplateName: '',
+          qualitySchemeTemplateCode: '',
+          inspectionItemVOList: [],
+          status: 1,
+          templateRemark: '',
+          sampleProportion: '',
+          sampleProportionUnit: '%',
+          validityPeriod: '',
+          validityPeriodUnit: '',
+          qualityMode: '',
+          taskId: '',
+          taskName: ''
+        },
+        columns: [
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            label: '排序',
+            width: 100,
+            align: 'center',
+            slot: 'sort',
+            prop: 'sort',
+            fixed: 'left'
+          },
+          {
+            prop: 'categoryLevelClassName',
+            label: '质检类型',
+            align: 'center',
+            minWidth: 150
+          },
+          {
+            prop: 'inspectionCode',
+            label: '编码',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 150
+          },
+          {
+            prop: 'inspectionName',
+            slot: 'inspectionName',
+            label: '名称',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 150
+          },
+          {
+            prop: 'defaultValue',
+            slot: 'defaultValue',
+            label: '工艺参数',
+            align: 'center',
+            minWidth: 400,
+            columnKey: 'defaultValue'
+          },
+          {
+            prop: 'executionMethod',
+            slot: 'executionMethod',
+            label: '执行方式',
+            showOverflowTooltip: true,
+            align: 'center',
+            width: 150
+          },
+          {
+            prop: 'procedureName',
+            slot: 'procedureName',
+            label: '实验过程',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 200
+          },
+          {
+            prop: 'recordName',
+            slot: 'recordName',
+            label: '实验记录',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 200
+          }
+        ],
+        categoryColumns: [
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'categoryLevelPath',
+            label: '分类',
+            align: 'center',
+            minWidth: 150
+          },
+          {
+            prop: 'code',
+            label: '编码',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 150
+          },
+          {
+            prop: 'name',
+            label: '名称',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 150
+          },
+          {
+            prop: 'specification',
+            label: '规格',
+            align: 'center',
+            minWidth: 150
+          },
+          {
+            prop: 'modelType',
+            label: '型号',
+            align: 'center',
+            minWidth: 150
+          },
+          {
+            prop: 'brandNum',
+            label: '牌号',
+            align: 'center',
+            minWidth: 150
+          }
+        ],
+        dataRule: {
+          type: [{ required: true, message: '请选择类型', trigger: 'blur' }],
+          qualitySchemeTemplateName: [
+            { required: true, message: '请输入质检方案名称', trigger: 'blur' }
+          ],
+          status: [
+            {
+              required: true,
+              message: '请选择状态',
+              trigger: 'blur'
+            }
+          ]
+        },
+        list: [],
+        templateCategoryList: []
+      };
+    },
+    created() {
+      this.init();
+    },
+    methods: {
+      async viewTemplate(tempJson) {
+        this.$refs.experimentationProcessDialog.open(tempJson);
+      },
+
+      init() {
+        getById(this.businessId).then(({ data }) => {
+          this.dataForm = data;
+          console.log(this.dataForm, 'this.dataForm');
+          this.list = data.inspectionItemVOList || [];
+        });
+        templatecategoryPage({
+          templateId: this.businessId,
+          size: -1
+        }).then((data) => {
+          this.templateCategoryList = data.list;
+        });
+      }
+    }
+  };
+</script>
+<style lang="scss" scoped>
+  .title {
+    font-weight: bold;
+    padding-bottom: 20px;
+    padding-top: 20px;
+  }
+</style>

+ 146 - 0
src/views/bpm/handleTask/components/inspectionTemplate/submit.vue

@@ -0,0 +1,146 @@
+<template>
+  <el-col :span="16" :offset="6">
+    <el-form label-width="100px" ref="formRef" :model="form">
+      <el-form-item
+        label="审批建议"
+        style="margin-bottom: 20px"
+        :rules="{
+          required: true,
+          message: '请选择',
+          trigger: 'change'
+        }"
+      >
+        <el-input
+          type="textarea"
+          v-model="form.reason"
+          placeholder="请输入审批建议"
+        />
+      </el-form-item>
+    </el-form>
+    <div style="margin-left: 10%; margin-bottom: 20px; font-size: 14px">
+      <el-button
+        icon="el-icon-edit-outline"
+        type="success"
+        size="mini"
+        @click="handleAudit(1)"
+        >通过
+      </el-button>
+
+      <el-button
+        icon="el-icon-circle-close"
+        type="danger"
+        size="mini"
+        @click="rejectTask(0)"
+        >驳回
+      </el-button>
+    </div>
+  </el-col>
+</template>
+
+<script>
+  import {
+    approveTaskWithVariables,
+    rejectTask,
+    cancelTask
+  } from '@/api/bpm/task';
+
+  // 流程实例的详情页,可用于审批
+  export default {
+    name: '',
+
+    props: {
+      businessId: {
+        default: ''
+      },
+      taskId: {
+        default: ''
+      },
+      id: {
+        default: ''
+      },
+      taskDefinitionKey: {
+        default: ''
+      }
+    },
+    data() {
+      return {
+        form: {
+          reason: ''
+        }
+      };
+    },
+    created() {},
+    methods: {
+      /** 处理转办审批人 */
+      handleUpdateAssignee() {
+        this.$emit('handleUpdateAssignee');
+      },
+      /** 退回 */
+      handleBackList() {
+        this.$emit('handleBackList');
+      },
+
+      async handleAudit(status) {
+        let API = !!status ? approveTaskWithVariables : rejectTask;
+        API({
+          id: this.taskId,
+          reason: this.form.reason,
+          variables: {
+            pass: !!status
+          }
+        }).then((res) => {
+          if (res.data.code != '-1') {
+            this.$emit('handleAudit', {
+              status,
+              title: status === 0 ? '驳回' : ''
+            });
+          }
+        });
+      },
+      rejectTask(status) {
+        rejectTask({
+          id: this.taskId,
+          reason: this.form.reason,
+          variables: {
+            pass: !!status
+          }
+        }).then((res) => {
+          if (res.data.code != '-1') {
+            this.$emit('handleAudit', {
+              status,
+              title: '驳回'
+            });
+          }
+        });
+      },
+
+      //更多
+      handleCommand(command) {
+        if (command === 'cancel') {
+          this.$confirm('是否确认作废?', {
+            type: 'warning',
+            cancelButtonText: '取消',
+            confirmButtonText: '确定'
+          })
+            .then(() => {
+              cancelTask({
+                id: this.id,
+                taskId: this.taskId,
+                reason: this.form.reason,
+                businessId: this.businessId
+              })
+                .then(() => {
+                  this.$emit('handleClose');
+                })
+                .catch(() => {
+                  this.$message.error('流程作废失败');
+                });
+            })
+            .catch(() => {});
+        }
+      }
+    }
+  };
+</script>
+
+<style lang="scss"></style>