qinhb 3 недель назад
Родитель
Сommit
d69878f108

+ 5 - 3
src/components/WorkFlows/workFlowCheck.vue

@@ -2,7 +2,7 @@
 import { getNextUser, queryFlowDataList, submitFlow } from "@/api/flow";
 
 const dialogVisible = ref(false);
-const dialogTitle = ref("Workflow Check");
+const dialogTitle = ref("流程模板选择");
 
 const emits = defineEmits(["sureToSave"]);
 
@@ -29,6 +29,7 @@ const flowForm = reactive<any>({
   flow_type: "",
   definitionId: "",
   users: "",
+  flowIns: ""
 });
 
 const close = () => {
@@ -44,8 +45,9 @@ const sureToSave = () => {
 };
 
 // businessId	业务ID   流程类型flow_type  测试类型  testService;   通用工艺提审  commonRouteFlowService;
-const openDialog = (businessId: string, flow_type: string) => {
-  flowForm.businessId = businessId;
+const openDialog = (obj: Object, flow_type: string) => {
+  flowForm.businessId = obj.businessId;
+  flowForm.flowIns = obj.flowIns;
   flowForm.flow_type = flow_type;
   dialogVisible.value = true;
   getFlowList();

+ 23 - 5
src/views/base/craftManagement/routeCommon/index.vue

@@ -64,17 +64,29 @@
           @click="changeLog(row)"
           >修改记录</el-button
         >
+
+        <el-button
+            link
+            type="danger"
+            icon="el-icon-delete"
+            @click="changeLog(row)"
+        >删除</el-button
+        >
+
         <el-button link icon="el-icon-copy-document" @click="bindProcess(row)"
           >绑定</el-button
         >
                 <el-button
                   link
                   icon="el-icon-copy-document"
-                  v-if="row.flowState == '0' || row.flowState == '2'"
+                  v-if="row.flowState == '0' || row.flowState == '2' || row.flowState == '-1'"
                   @click="openCheckView(row)"
                   >提审</el-button
                 >
 
+                <el-button link v-if="row.flowState !== '0'" icon="el-icon-copy-document" @click="showFlowSteps(row)"
+                >流程</el-button>
+
                 <el-button
                   link
                   icon="el-icon-copy-document"
@@ -128,7 +140,7 @@
     >
       <RouteChangeLog :targetRouteId="routeDeatil.id" />
     </el-dialog>
-
+    <LookFlowStep ref="LookFlowStepRef"></LookFlowStep>
     <work-flow-check
       ref="workFlowCheckRef"
       @sureToSave="onWFSave"
@@ -138,13 +150,13 @@
 <script setup>
 import { ref, getCurrentInstance } from "vue";
 import { useCrud } from "@/hooks/userCrud";
-import ButtonPermKeys from "@/common/configs/buttonPermission";
 import dictDataUtil from "@/common/configs/dictDataUtil";
 import { useDictionaryStore } from "@/store";
 import { copyRoute } from "@/api/craft/route/index";
 import { getUserTree } from "@/api/system/user/index";
 import RouteChangeLog from "@/views/base/craftManagement/route/components/routeChangeLog.vue";
 import WorkFlowCheck from "@/components/WorkFlows/workFlowCheck.vue";
+import LookFlowStep from "@/views/flow/common/LookFlowStep.vue";
 import { cancelFlow } from "@/api/flow";
 
 // 数据字典相关
@@ -256,6 +268,7 @@ const bindProcess = (row) => {
 option.value = Object.assign(option.value, {
   searchEnter: true,
   selection: true,
+  delBtn: false,
   labelWidth: 130,
   searchLabelWidth: 110,
   column: [
@@ -418,8 +431,13 @@ option.value = Object.assign(option.value, {
 //  工作流相关
 const workFlowCheckRef = ref(null);
 const openCheckView = (row) => {
+  row.businessId = row.id
   workFlowCheckRef.value &&
-    workFlowCheckRef.value.openDialog(row.id, "routeFlowComService");
+  workFlowCheckRef.value.openDialog(row, "routeFlowComService");
+};
+const LookFlowStepRef = ref(null);
+const showFlowSteps = (row) => {
+  LookFlowStepRef.value && LookFlowStepRef.value.openFlowStepDrawer(row.flowIns);
 };
 const onWFSave = () => {
   dataList();
@@ -429,7 +447,7 @@ const onCancelFlow = (row) => {
   console.log(row);
   cancelFlow({
     businessId: row.id,
-    insId: row.flowIns,
+    flowIns: row.flowIns,
   }).then(() => {
     ElMessage.success("撤销成功");
     dataList();

+ 25 - 18
src/views/flow/common/CheckFlow.vue

@@ -1,9 +1,7 @@
 <script setup lang="ts">
+import { ref, defineProps,defineEmits } from "vue";
 import {
-  getNextUser,
-  queryFlowDataList,
-  queryFlowRecord,
-  audit,
+  getNextUser,audit,
 } from "@/api/flow";
 import {
   ComponentNameClass,
@@ -14,10 +12,15 @@ import {
 import RouteFlowComService from "@/views/flow/common/CheckTopInfos/routeFlowComService.vue";
 
 const dialogVisible = ref(false);
-const dialogTitle = ref("");
 const componentName = ref("");
-
 const emits = defineEmits(["finish", "cancel"]);
+const props = defineProps({
+  operType: {
+        default: "0",
+        type: String,
+      }
+    })
+
 
 const close = () => {
   dialogVisible.value = false;
@@ -65,9 +68,22 @@ const toPass = async () => {
 };
 
 const disAgree = async () => {
+  if(!currentRow.message){
+    currentRow.message = "不同意"
+  }
   const params = {taskId: currentRow.id,message: currentRow.message,state: -1,nextUsers: currentRow.nextUsers}
   auditObj(params)
 };
+
+watch(
+    () => props.operType,
+    (val) => {
+      alert(props.operType)
+    },
+    {
+      immediately: true,
+    }
+);
 </script>
 
 <template>
@@ -95,17 +111,8 @@ const disAgree = async () => {
                 :row="currentRow"
               />
             </el-collapse-item>
-<!--            <el-collapse-item title="Feedback" name="2">
-              <div>
-                {{ componentName }}
-              </div>
-              <div>
-                Visual feedback: reflect current state by updating or
-                rearranging elements of the page.
-              </div>
-            </el-collapse-item>-->
           </el-collapse>
-          <el-form>
+          <el-form style="margin-top:20px;" v-if="props.operType == 'todo'">
             <el-form-item :label="showLabel" v-if="showLabel && userList">
               <el-select
                   v-model="currentRow.nextUsers"
@@ -134,8 +141,8 @@ const disAgree = async () => {
     <template #footer>
       <div style="flex: auto">
         <el-button @click="close">取消</el-button>
-        <el-button type="primary" @click="toPass">通过</el-button>
-        <el-button type="warning" @click="disAgree">不同意</el-button>
+        <el-button v-if="props.operType == 'todo'" type="primary" @click="toPass">通过{{props.operType}}</el-button>
+        <el-button v-if="props.operType == 'todo'" type="warning" @click="disAgree">不同意</el-button>
       </div>
     </template>
   </el-drawer>

+ 456 - 0
src/views/flow/common/CheckTopInfos/components/configs.ts

@@ -0,0 +1,456 @@
+import { useDictionaryStore } from "@/store";
+const { dicts } = useDictionaryStore();
+
+export const getTableConfig = (id: string) => {
+  return {
+    // 获取工序记录项信息信息
+    jiluxiang: {
+      url: `/api/v1/op/operationRecord`,
+      column: [
+        {
+          label: "工序id",
+          prop: "operationId",
+          display: false,
+          hide: true,
+          value: id,
+        },
+        { label: "记录项", prop: "thName" },
+        {
+          label: "单位",
+          prop: "unit",
+          search: true,
+          filterable: true,
+          type: "select",
+          dataType: "string",
+          dicData: dicts.danwei_type,
+          props: { label: "dictLabel", value: "dictValue" },
+        },
+        { label: "标准值", prop: "standard" },
+        { label: "上限值", prop: "upper" },
+        { label: "下限值", prop: "lower" },
+      ],
+    },
+    //工序物料
+    wuliaocaiji: {
+      url: "/api/v1/op/operationItem",
+      column: [
+        {
+          label: "工序id",
+          prop: "operationId",
+          display: false,
+          hide: true,
+          value: id,
+        },
+        {
+          label: "物料名称",
+          prop: "itemName",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "物料版本号",
+          prop: "recordVersion",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "物料编码",
+          prop: "itemCode",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "物料规格",
+          prop: "itemModel",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        { label: "所需数量", prop: "num" },
+        {
+          label: "追溯类型",
+          prop: "traceType",
+          search: true,
+          filterable: true,
+          type: "select",
+          dataType: "string",
+          dicData: dicts.trace_type,
+          props: { label: "dictLabel", value: "dictValue" },
+        },
+        {
+          label: "单位",
+          prop: "unit",
+          search: true,
+          filterable: true,
+          type: "select",
+          dataType: "string",
+          dicData: dicts.danwei_type,
+          props: { label: "dictLabel", value: "dictValue" },
+        },
+        // {
+        //   label: "是否需要",
+        //   prop: "isTrace",
+        //   type: "radio", //类型为单选框
+        //   dicData: [
+        //     {
+        //       label: "需采集物料",
+        //       value: 1,
+        //     },
+        //     {
+        //       label: "非必须采集物料",
+        //       value: 0,
+        //     },
+        //   ],
+        //   value: 1,
+        //   rules: [
+        //     {
+        //       required: true,
+        //       message: "是否需要",
+        //       trigger: "blur",
+        //     },
+        //   ],
+        // },
+      ],
+    },
+    // 辅料采集
+    fuliaoCJ: {
+      url: "/api/v1/operationAccessoryItem",
+      column: [
+        {
+          label: "工序id",
+          prop: "operationId",
+          display: false,
+          hide: true,
+          value: id,
+        },
+        {
+          label: "物料名称",
+          prop: "itemName",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "物料版本号",
+          prop: "recordVersion",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "物料编码",
+          prop: "itemCode",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "物料规格",
+          prop: "itemModel",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        // {
+        //   label: "是否需要",
+        //   prop: "isTrace",
+        //   type: "radio", //类型为单选框
+        //   dicData: [
+        //     {
+        //       label: "需采集物料",
+        //       value: 1,
+        //     },
+        //     {
+        //       label: "非必须采集物料",
+        //       value: 0,
+        //     },
+        //   ],
+        //   value: 1,
+        //   rules: [
+        //     {
+        //       required: true,
+        //       message: "是否需要",
+        //       trigger: "blur",
+        //     },
+        //   ],
+        // },
+      ],
+    },
+    dianjian: {
+      url: `/api/v1/op/operationCheck`,
+      column: [
+        {
+          label: "工序id",
+          prop: "operationId",
+          display: false,
+          hide: true,
+          value: id,
+        },
+        {
+          label: "点检名称",
+          prop: "checkName",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "点检编码",
+          prop: "checkCode",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        { label: "内容", prop: "content" },
+        {
+          label: "单位",
+          prop: "unit",
+          search: true,
+          filterable: true,
+          type: "select",
+          dataType: "string",
+          dicData: dicts.danwei_type,
+          props: { label: "dictLabel", value: "dictValue" },
+        },
+        { label: "标准值", prop: "standard" },
+        { label: "上限值", prop: "upper" },
+        { label: "下限值", prop: "lower" },
+      ],
+    },
+    shebeijilu: {
+      url: "/api/v1/op/operationEquit",
+      column: [
+        {
+          label: "工序id",
+          prop: "operationId",
+          display: false,
+          hide: true,
+          value: id,
+        },
+        { label: "精度要求", prop: "accuracy" },
+        { label: "所需数量", prop: "num", display: false, hide: true },
+        {
+          label: "设备类型",
+          prop: "equitType",
+          search: true,
+          filterable: true,
+          type: "select",
+          dataType: "string",
+          dicData: dicts.device_type,
+          props: { label: "dictLabel", value: "dictValue" },
+        },
+        {
+          label: "必须采集",
+          prop: "collection",
+          type: "radio", //类型为单选框
+          dicData: [
+            {
+              label: "必须",
+              value: 1,
+            },
+            {
+              label: "非必须",
+              value: 0,
+            },
+          ],
+          value: 1,
+          rules: [
+            {
+              required: true,
+              message: "是否必须采集",
+              trigger: "blur",
+            },
+          ],
+        },
+      ],
+    },
+    ESOP: {
+      url: "/api/v1/op/esop",
+      column: [
+        {
+          label: "工序id",
+          prop: "operationId",
+          display: false,
+          hide: true,
+          value: id,
+        },
+
+        { label: "标题", prop: "title", addDisabled: true, editDisabled: true },
+        {
+          label: "展示页数",
+          prop: "showAppointPageNum",
+          type: "number",
+          min: 1,
+        },
+        {
+          label: "总页数",
+          prop: "pageNum",
+          type: "number",
+          hide: true,
+          display: false,
+        },
+        {
+          label: "版本号",
+          prop: "recordVersion",
+          type: "number",
+          addDisabled: true,
+          editDisabled: true,
+          rules: [
+            {
+              required: true,
+              message: "版本号",
+              trigger: "blur",
+            },
+          ],
+          precision: 1,
+        },
+        {
+          label: "图纸编码",
+          prop: "drawingCode",
+          hide: true,
+          addDisabled: true,
+          editDisabled: true,
+        },
+        // {
+        //   label: "内容",
+        //   prop: "content",
+        //   hide: true,
+        //   addDisabled: true,
+        //   editDisabled: true,
+        // },
+        // {
+        //   label: "排序",
+        //   prop: "sortNum",
+        //   hide: true,
+        //   addDisabled: true,
+        //   editDisabled: true,
+        // },
+        {
+          label: "文件",
+          prop: "filePath",
+          span: 24,
+          type: "img",
+          slot: true,
+          viewDisplay: false,
+          addDisabled: true,
+          editDisabled: true,
+        },
+      ],
+    },
+    operationExcel: {
+      url: "/api/v1/opExcelForm",
+      column: [
+        {
+          label: "工序id",
+          prop: "operationId",
+          display: false,
+          hide: true,
+          value: id,
+        },
+
+        {
+          label: "模版名称",
+          prop: "formName",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "模版类型",
+          prop: "formType",
+          addDisabled: true,
+          editDisabled: true,
+          dicData: dicts.excel_type,
+          props: { label: "dictLabel", value: "dictValue" },
+        },
+        {
+          label: "模版数据",
+          prop: "pageNum",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "修改时间",
+          prop: "updated",
+          addDisabled: true,
+          editDisabled: true,
+        },
+        {
+          label: "操作人",
+          prop: "updator",
+          addDisabled: true,
+          editDisabled: true,
+        },
+      ],
+    },
+  };
+};
+
+// 工艺工序组件路径的组件类别
+interface comType {
+  compentName: string;
+  compentType: string;
+  index: number;
+}
+export const comTypes: comType[] = [
+  {
+    compentName: "物料采集",
+    compentType: "wuliaocaiji",
+    index: 0,
+  },
+  {
+    compentName: "设备记录",
+    compentType: "shebeijilu",
+    index: 3,
+  },
+  {
+    compentName: "设备数据",
+    compentType: "ceshishuju",
+    index: 6,
+  },
+  {
+    compentName: "点检",
+    compentType: "dianjian",
+    index: 9,
+  },
+  {
+    compentName: "记录项",
+    compentType: "jiluxiang",
+    index: 12,
+  },
+
+  // {
+  //   compentName: "辅料采集",
+  //   compentType: "fuliaoCJ",
+  // },
+
+  // {
+  //   compentName: "紧固",
+  //   compentType: "jingu",
+  // },
+  // {
+  //   compentName: "调试配对",
+  //   compentType: "tiaoshipipei",
+  // },
+  /*{
+		compentName: "铭牌绑定",
+		compentType: "mingpai",
+	},*/
+
+  {
+    compentName: "工序表单",
+    compentType: "operationExcel",
+    index: 15,
+  },
+
+  // {
+  //   compentName: "数据采集",
+  //   compentType: "screwdriver",
+  // },
+  {
+    compentName: "工序文件",
+    compentType: "gongxuwenjian",
+    index: 18,
+  },
+  {
+    compentName: "多媒体采集",
+    compentType: "duomeiticaiji",
+    index: 21,
+  },
+  {
+    compentName: "ESOP",
+    compentType: "ESOP",
+    index: 24,
+  },
+];

+ 293 - 0
src/views/flow/common/CheckTopInfos/components/op_bottom_table.vue

@@ -0,0 +1,293 @@
+<template>
+  <div>
+    <avue-crud
+      ref="crudRef"
+      v-model:search="search"
+      v-model="form"
+      :data="data"
+      :option="option"
+      v-model:page="page"
+      @row-save="createRow"
+      @row-update="updateRow"
+      @row-del="deleteRow"
+      @selection-change="selectionChange"
+      @sortable-change="onSortChange"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+      @size-change="dataList"
+      @current-change="dataList"
+    >
+
+      <template #filePath-form="scope">
+        <div style="height: 100px; width: 100px; overflow: hidden">
+          <PDFView
+            :need-to-show-pdf="true"
+            content-type="button"
+            :is-link="true"
+            :show-pdf-number="form.showAppointPageNum"
+            :pdf-source="pdfPath"
+          />
+        </div>
+      </template>
+      <template #filePath="{ row }">
+        <PDFView
+          :need-to-show-pdf="true"
+          content-type="button"
+          btnText="查看PDF"
+          :is-link="true"
+          :pdf-source="getSOAPpdf(row)"
+        />
+      </template>
+    </avue-crud>
+    <el-dialog v-model="dialogVisible">
+      <VuePdfEmbed :source="previewImgUrl" annotation-layer text-layer/>
+    </el-dialog>
+  </div>
+</template>
+<script setup>
+import {ref, getCurrentInstance} from "vue";
+import {useCrud} from "@/hooks/userCrud";
+import {getTableConfig} from "./configs";
+import PDFView from "@/components/PDFView/index.vue";
+import VuePdfEmbed from "vue-pdf-embed";
+import {
+  getBomVersion,
+} from "@/api/craft/process/index";
+
+const props = defineProps({
+  tableTitle: {
+    default: "",
+    type: String,
+  },
+  tableType: {
+    default: "",
+    type: String,
+  },
+  groupId: {
+    default: "",
+    type: String,
+  },
+  isTree: {
+    default: "0",
+    type: String,
+  },
+  operationId: {
+    default: "0",
+    type: String,
+  },
+  routeId: {
+    default: "0",
+    type: String,
+  },
+});
+
+const route = useRoute();
+const tableConfig = getTableConfig(props.operationId);
+// 传入一个url,后面不带/
+const {url, form, data, option, search, page, toDeleteIds, Methords, Utils} =
+  useCrud({
+    src: tableConfig[props.tableType].url,
+  });
+
+const {dataList, createRow, updateRow, deleteRow, searchChange, resetChange} =
+  Methords; //增删改查
+const {selectionChange, multipleUpdate} = Methords; //选中和批量删除事件
+
+const crudRef = ref(null); //crudRef.value 获取avue-crud对象
+const bomVersion = ref(null);
+const pdfPath = ref(null);
+
+// 如果物料采集列表有值,就只能选择当前的版本,否则先选择版本
+const versionList = ref([]);
+const versionDV = ref(false);
+const selectedVersion = ref("");
+const goToSelectMaterial = () => {
+  if (!route.fullPath.split("/")[5]) {
+    ElMessage.error("物料编号读取错误");
+    return;
+  }
+  let configParam = {};
+  configParam.materialCode = route.fullPath.split("/")[5];
+  configParam.bomVersion = selectedVersion.value;
+  //根据物料编码和版本号获取对应的物料BOM
+  commonTableType.value = "MARTERIAL_BOM";
+  nextTick(() => {
+    commonTableRef.value?.startSelect(configParam);
+    commonTableRef.value?.refreshDictData("bomVersion", [], "value");
+    commonTableRef.value?.mergeOption({
+      searchShow: true,
+      selection: true,
+      reserveSelection: true,
+    });
+  });
+  selectedVersion.value = "";
+  versionDV.value = false;
+};
+const startCreat = () => {
+  if (props.tableType === "wuliaocaiji") {
+    if (bomVersion.value) {
+      selectedVersion.value = bomVersion.value;
+      goToSelectMaterial();
+    } else {
+      getBomVersion({materialCode: route.fullPath.split("/")[5]}).then(
+        (res) => {
+          versionList.value = res?.data ?? [];
+          versionDV.value = true;
+        }
+      );
+    }
+
+  } else if (props.tableType === "dianjian") {
+    commonTableType.value = "OP_CHECK";
+    nextTick(() => {
+      commonTableRef.value?.startSelect({
+        operationId: route.params.id
+      });
+      commonTableRef.value?.mergeOption({
+        selection: true,
+        reserveSelection: true,
+        header: false,
+        selectable: function (row, index) {
+          return row.isSelect;
+
+        },
+      });
+    });
+  } else if (props.tableType === "ESOP") {
+    commonTableType.value = "ESOP";
+    nextTick(() => {
+      commonTableRef.value?.startSelect({
+        materialCode: route.fullPath.split("/")[5],
+        enable: 1,
+      });
+      commonTableRef.value?.mergeOption({
+        selection: true,
+        reserveSelection: true,
+      });
+    });
+  } else if (props.tableType === "fuliaoCJ") {
+    commonTableType.value = "FULIAO_CAIJI";
+
+    nextTick(() => {
+      commonTableRef.value?.startSelect({
+        accessoriesProperty: "2", //默认直接查所有的部件辅料)
+      });
+      commonTableRef.value?.mergeOption({
+        selection: true,
+        reserveSelection: true,
+      });
+    });
+  } else {
+    crudRef.value && crudRef.value.rowAdd();
+  }
+};
+
+
+
+const saveSortData = async () => {
+  multipleUpdate();
+};
+
+defineExpose({startCreat, saveSortData});
+
+const onSortChange = () => {
+  data.value.forEach((item) => {
+    console.log(item.id);
+  });
+};
+const routeId = ref("");
+// ============公共弹窗table选择相关,物料采集等使用===============
+const commonTableRef = ref({});
+const commonTableType = ref("MARTERIAL_BOM");
+const itemGroup = ref(null);
+const previewImgUrl = ref("");
+const dialogVisible = ref(false);
+const getSOAPpdf = (itemValue) => {
+  return import.meta.env.VITE_APP_UPLOAD_URL + itemValue.filePath;
+};
+
+onMounted(() => {
+  routeId.value = props.routeId
+  search.value.operationId = props.operationId + ""
+  url.value = tableConfig[props.tableType].url;
+  search.value.isTree = props.isTree;
+  if (props.groupId) {
+    search.value.itemGroupId = props.groupId;
+    itemGroup.value=props.groupId;
+  }
+  //物料双规格分组的话没有编辑,删除要自定义
+  if (props.isTree === '1') {
+    option.value = Object.assign(option.value, {
+      searchEnter: true,
+      addBtn: false,
+      editBtn: false,
+      delBtn: false,
+      searchShow: false,
+      header: false,
+      sortable: true,
+      column: tableConfig[props.tableType].column,
+    });
+  } else {
+    option.value = Object.assign(option.value, {
+      searchEnter: true,
+      addBtn: false,
+      editBtn: false,
+      delBtn: false,
+      searchShow: false,
+      header: false,
+      column: tableConfig[props.tableType].column,
+    });
+  }
+  dataList();
+});
+
+watch(
+  () => props.tableType,
+  () => {
+    routeId.value = props.routeId
+    url.value = tableConfig[props.tableType].url;
+    option.value = Object.assign(option.value, {
+      searchEnter: true,
+      addBtn: false,
+      searchShow: false,
+      header: false,
+      sortable: true,
+      column: tableConfig[props.tableType].column,
+    });
+    dataList();
+  }
+);
+
+/**监听分组是否变化*/
+watch(
+  () => props.groupId,
+  () => {
+    routeId.value = props.routeId
+    url.value = tableConfig[props.tableType].url;
+    option.value = Object.assign(option.value, {
+      searchEnter: true,
+      addBtn: false,
+      searchShow: false,
+      header: false,
+      sortable: true,
+      column: tableConfig[props.tableType].column,
+    });
+    search.value.itemGroupId = props.groupId
+    itemGroup.value = props.groupId
+    console.log("aaaa",itemGroup.value);
+    dataList();
+  }
+);
+watch(
+    () => props.operationId,
+    () => {
+
+    }
+);
+watch(
+    () => props.routeId,
+    () => {
+
+    }
+);
+</script>

+ 419 - 0
src/views/flow/common/CheckTopInfos/components/op_component_view.vue

@@ -0,0 +1,419 @@
+<template>
+  <div
+    class="mainContentBox"
+    style="padding: 0; box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.1)"
+  >
+    <div class="types">
+      <VueDraggable
+        v-model="selectProComs"
+        :animation="150"
+        :draggable="false"
+        ghostClass="ghost"
+        style="display: flex"
+      >
+        <div
+          class="typeContainer"
+          v-for="(item, index) in selectProComs"
+          :key="index"
+          @click="clickToolCom(item, index)"
+        >
+          <div class="typeBox others" :class="getNameClass(index)">
+            <svg-icon :icon-class="item.compentType" size="30" />
+            <div class="name">{{ item.compentName }}</div>
+          </div>
+        </div>
+      </VueDraggable>
+    </div>
+    <div class="binContainer">
+      <div v-if="isChanged || selectIndex === -1 || isNoneedEdit">
+        <el-empty :image-size="200" :description="getTipContent()" />
+      </div>
+      <div v-else-if="tipTitle !== '编辑工序表单'">
+        <div class="tipTitle">{{ tipTitle }}</div>
+        <el-tabs
+          v-if="currentCom.compentType === 'wuliaocaiji'"
+          v-model="materialType"
+          type="card"
+          @tab-change="materialTypeChange"
+        >
+          <el-tab-pane label="主料" name="1" />
+          <el-tab-pane label="辅料" name="2" />
+        </el-tabs>
+        <BottomTable ref="bottomTableRef" :tableType="tableType" :route-id="props.clickObj.procecssRouteId" :operation-id="props.clickObj.operationId"/>
+      </div>
+      <div v-else>
+        <div class="tipTitle">{{ tipTitle }}</div>
+        <SetExcel :operation-id="props.clickObj.operationId"/>
+      </div>
+    </div>
+    <el-dialog
+      v-model="dialog.visible"
+      :title="dialog.title"
+      width="900px"
+      @close="dialog.visible = false"
+      :destroy-on-close="true"
+    >
+      <el-container>
+        <el-aside width="200px" style="overflow: hidden">
+          <avue-tree
+            :option="optionTree"
+            :data="treeData"
+            v-model="formTree"
+            @node-click="nodeClick"
+            @update="updateRow"
+          ></avue-tree>
+        </el-aside>
+        <el-main>
+          <BottomTable
+            ref="tableTreeRef"
+            :tableType="tableType"
+            :groupId="groupId"
+            :isTree="'1'"
+          />
+        </el-main>
+      </el-container>
+    </el-dialog>
+  </div>
+</template>
+<script setup>
+import { defineProps, ref } from "vue";
+import { VueDraggable } from "vue-draggable-plus";
+import BottomTable from "./op_bottom_table.vue";
+import SetExcel from "./op_excel_view.vue";
+import { comTypes } from "@/views/base/craftManagement/route/components/configs";
+import {
+  saveCompoents,
+  getCompoentsList,
+  treeDataList,
+  treeDataUpdate,
+} from "@/api/craft/process/index";
+const formTree = ref(null);
+import {
+  processesByRouteId,
+} from "@/api/craft/route/index";
+const prodtCode = ref("");
+const routerId = ref("");
+const router = useRouter();
+const route = useRoute();
+const dialog = reactive({
+  title: "绑定双规格",
+  visible: false,
+});
+//组件是否已经改变,如果改变了需要点击保存,才能展示下面的table
+const isChanged = ref(true);
+const isNoneedEdit = ref(false); //有些组件是不需要编辑的,所以下面也不展示table
+const loadTopList = () => {
+  getCompoentsList(props.clickObj.operationId).then((res) => {
+    selectProComs.value = res.data || [];
+    selectIndex.value = -1;
+    isChanged.value = false;
+  });
+};
+//查询工艺路线的一些信息
+const routeInfo = ref();
+const loadRouteInfo = async () => {
+  const res = await processesByRouteId(props.clickObj.procecssRouteId);
+  if (res.data) {
+    routeInfo.value = res.data;
+  }
+};
+//弹窗传递分组id
+const groupId = ref(null);
+const nodeClick = (data) => {
+  groupId.value = data.id;
+};
+
+const dataDetail = ref({});
+const updateRow = (node, data, done, loading) => {
+  treeDataUpdate(data).then((resouce) => {
+    done();
+    if (resouce.code === "200") {
+      ElMessage.success("修改成功");
+
+      treeDataList(dataDetail.value).then((res) => {
+        treeData.value = res.data;
+      });
+    } else {
+      ElMessage.error(resouce.msg);
+    }
+  });
+};
+const optionTree = {
+  formOption: {
+    labelWidth: 100,
+    column: [
+      {
+        label: "关联名称",
+        prop: "label",
+      },
+    ],
+  },
+  props: {
+    labelText: "标题",
+    label: "label",
+    value: "value",
+    children: "children",
+  },
+};
+const treeData = ref(null);
+const treeParam = ref({});
+onMounted(async () => {
+  routerId.value = props.clickObj.procecssRouteId
+  await loadTopList();
+  loadRouteInfo();
+  dataDetail.value.operationId = props.clickObj.operationId
+  treeParam.value.operationId = props.clickObj.operationId
+  treeParam.value.materialType = "1";
+  dataDetail.value.materialType = "1";
+});
+
+// 顶部====================
+const back = () => {
+  router.back();
+};
+
+const save = async () => {
+  selectProComs.value.forEach((item1) => {
+    comTypes.find((item2) => {
+      if (item2.compentName === item1.compentName) {
+        item1.index = item2.index;
+      }
+    });
+  });
+  selectProComs.value = selectProComs.value.sort((a, b) => {
+    return a.index - b.index;
+  });
+
+  for (let i = 0; i < selectProComs.value.length; i++) {
+    selectProComs.value[i].operationId = route.fullPath.split("/")[4];
+    selectProComs.value[i].sortNum = i;
+  }
+  let p = {
+    operationId: route.fullPath.split("/")[4],
+    dtos: selectProComs.value,
+  };
+  let { res, code } = await saveCompoents(p);
+  if (code == "200") {
+    ElMessage.success("保存成功");
+  }
+  loadTopList();
+};
+
+// Tools顶部组件 ==================
+// 已经存在的工序组件
+const selectProComs = ref([]);
+const selectIndex = ref(-1);
+const currentCom = ref({});
+const handleCommand = (item) => {
+  let status = true;
+  for (let i = 0; i < selectProComs.value.length; i++) {
+    if (selectProComs.value[i].compentName == item.compentName) {
+      status = false;
+    }
+  }
+  if (status == true) {
+    selectProComs.value.push(item);
+    isChanged.value = true;
+    selectIndex.value = -1;
+  } else {
+    ElMessage.error("请勿重复添加");
+  }
+};
+
+// 点击某一个改变下面的table
+const clickToolCom = (com, index) => {
+  tipTitle.value = "编辑" + com.compentName;
+  selectIndex.value = index;
+  currentCom.value = com;
+  if (
+    com.compentType === "jiluxiang" ||
+    com.compentType === "mingpai" ||
+    com.compentType === "duomeiticaiji" ||
+    com.compentType === "tiaoshipipei" ||
+    com.compentType === "jingu" ||
+    com.compentType === "ceshishuju" ||
+    com.compentType === "screwdriver" ||
+    com.compentType === "gongxuwenjian" ||
+    com.compentType === "shebeijilu"
+  ) {
+    isNoneedEdit.value = true;
+  } else {
+    tableType.value = com.compentType;
+    isNoneedEdit.value = false;
+  }
+};
+
+const getNameClass = (index) => {
+  return index === selectIndex.value ? "selected" : "normal";
+};
+
+// 底部table ===============
+let tipTitle = ref({});
+const bottomTableRef = ref({});
+const tableTreeRef = ref({});
+const tableType = ref("MARTERIAL_BOM");
+
+
+const getTipContent = (itemValue) => {
+  if (isNoneedEdit.value) {
+    return "标准组件无需编辑";
+  }
+  if (selectIndex.value === -1 && isChanged.value) {
+    return "请先保存组件,然后再进行操作";
+  }
+
+  return "请先选择组件";
+};
+
+//双向绑定的data
+const props = defineProps({
+  //双向绑定的data
+  clickObj: {
+    type: [Object, null],
+    default: null,
+  }
+})
+watch(
+    () => props.clickObj,
+    (val) => {
+      alert(JSON.stringify(props.clickObj))
+    }
+);
+// 无聊采集组件 主料和辅料
+const materialType = ref("1");
+const materialTypeChange = (val) => {
+  materialType.value = val;
+  dataDetail.value.materialType = val;
+  treeParam.value.materialType = val;
+  if (val === "1") {
+    tableType.value = "wuliaocaiji";
+  } else {
+    tableType.value = "fuliaoCJ";
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.header {
+  height: 50px;
+  display: flex;
+  background-color: #f5f7f9;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+}
+.types {
+  width: 100%;
+  height: 116px;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+  padding: 12px 20px;
+  display: flex;
+  .typeContainer {
+  }
+  .typeBox {
+    height: 80px;
+    width: 80px;
+    border-radius: 4px 4px 4px 4px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    .icon {
+      height: 32px;
+      width: 32px;
+    }
+    .name {
+      width: 56px;
+      height: 16px;
+      font-weight: 500;
+      font-size: 14px;
+      line-height: 16px;
+      text-align: center;
+      font-style: normal;
+      text-transform: none;
+    }
+  }
+
+  .addBtn {
+    border: 1px solid #0a59f7;
+    color: #0a59f7;
+  }
+  .others {
+    color: rgba(0, 0, 0, 0.9);
+    border: 1px solid rgba(0, 0, 0, 0.9);
+    margin-left: 20px;
+    position: relative;
+  }
+  .delete {
+    //position: absolute;
+    //bottom: -20px;
+    //left: 0;
+    margin-left: 50px;
+    width: 1em;
+    height: 1em;
+    color: red;
+    visibility: hidden;
+  }
+  .typeContainer:hover {
+    .delete {
+      visibility: visible;
+    }
+  }
+  .normal {
+    background: #ffffff;
+    border: 1px solid rgba(35, 32, 50, 0.1);
+  }
+  .selected {
+    background: rgba(10, 89, 247, 0.2);
+    border: 1px solid #0a59f7;
+  }
+}
+
+.title,
+.processInfo {
+  line-height: 44px;
+  color: #6f7991;
+  font-size: 14px;
+  font-weight: bold;
+  text-align: left;
+  margin-left: 20px;
+}
+
+.processInfo span {
+  margin-left: 100px;
+}
+
+.processInfo {
+  position: absolute;
+  left: 5%;
+}
+
+.binContainer {
+  height: calc(100vh - 280px);
+  width: 100%;
+  background-color: #f5f7f9;
+  overflow-y: auto;
+  background-color: white;
+  //margin-top: 16px;
+  //margin-left: 20px;
+  padding: 16px 20px;
+}
+.tipTitle {
+  width: 84px;
+  height: 16px;
+  font-weight: 500;
+  font-size: 14px;
+  color: rgba(0, 0, 0, 0.9);
+  line-height: 16px;
+  text-align: left;
+  font-style: normal;
+  text-transform: none;
+  margin-bottom: 16px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+</style>

+ 129 - 0
src/views/flow/common/CheckTopInfos/components/op_excel_view.vue

@@ -0,0 +1,129 @@
+<template>
+  <div>
+    <avue-crud
+      ref="crudRef"
+      v-model:search="search"
+      v-model="form"
+      :data="data"
+      :option="option"
+      v-model:page="page"
+      @row-save="createRow"
+      @row-update="updateRow"
+      @row-del="deleteRow"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+      @size-change="dataList"
+      @current-change="dataList"
+      @selection-change="selectionChange"
+    >
+    </avue-crud>
+  </div>
+</template>
+<script setup>
+import { ref } from "vue";
+import { useCrud } from "@/hooks/userCrud";
+import { useDictionaryStore } from "@/store";
+import { useRoute } from "vue-router";
+const value1 = ref([]);
+const options = ref([]);
+const route = useRoute();
+// 数据字典相关
+const { dicts } = useDictionaryStore();
+
+const props = defineProps({
+  operationId: {
+    default: "0",
+    type: String,
+  },
+  routeId: {
+    default: "0",
+    type: String,
+  },
+});
+// 传入一个url,后面不带/
+const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
+  useCrud({
+    src: "/api/v1/opExcelForm",
+  });
+const setValue1 = () => {
+  value1.value = [];
+  data.value.forEach((el) => {
+    value1.value.push(el.formCode);
+  });
+};
+const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
+  Methords; //增删改查
+const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
+const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等工具
+const crudRef = ref(null); //crudRef.value 获取avue-crud对象
+onMounted(() => {
+  search.value.operationId = props.operationId + ""
+  dataList();
+});
+watch(
+  () => data.value,
+  (val) => {
+    setValue1();
+  },
+  {
+    immediately: true,
+  }
+);
+
+option.value = Object.assign(option.value, {
+  searchEnter: true,
+  selection: false,
+  addBtn: false,
+  menu: true,
+  viewBtn: false,
+  editBtn: false,
+  delBtn: false,
+  searchMenuSpan: 8,
+  column: [
+    {
+      label: "工序id",
+      prop: "operationId",
+      display: false,
+      hide: true,
+    },
+    {
+      label: "模版名称",
+      prop: "formName",
+      addDisabled: true,
+      editDisabled: true,
+    },
+    {
+      label: "模版类型",
+      prop: "formType",
+      addDisabled: true,
+      editDisabled: true,
+      dicData: dicts.excel_type,
+      props: { label: "dictLabel", value: "dictValue" },
+    },
+    {
+      label: "修改时间",
+      prop: "updated",
+      addDisabled: true,
+      editDisabled: true,
+    },
+    {
+      label: "操作人",
+      prop: "updator",
+      addDisabled: true,
+      editDisabled: true,
+    },
+  ],
+});
+</script>
+<style lang="scss" scoped>
+.dialog {
+  width: 100%;
+  height: 120px;
+  position: relative;
+  .btns {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+  }
+}
+</style>

+ 410 - 8
src/views/flow/common/CheckTopInfos/routeFlowComService.vue

@@ -1,7 +1,17 @@
 <script setup lang="ts">
 import { getRouteInfo } from "@/views/flow/common/CheckTopInfos/utils";
+import { formOption } from "@/views/base/craftManagement/route/bindConfig";
+import { VueFlow, useVueFlow, Panel } from "@vue-flow/core";
+import DropzoneBackground from "@/views/base/craftManagement/route/components/DropzoneBackground/index.vue";
+import CustomConnectionLine from "@/views/base/craftManagement/route/components/CustomConnectionLine/index.vue";
+import CustomNode from "@/views/base/craftManagement/route/components/CustomNode/index.vue";
+import useDragAndDrop from "@/hooks/useDnD.js";
+import { MiniMap } from "@vue-flow/minimap";
+import { useCommonStoreHook, useDictionaryStore } from "@/store";
+import { useScreenshot } from "@/views/base/craftManagement/route/screenshot.ts";
+import { useLayout } from "@/hooks/useLayout";
 
-const infoObj = ref<any>(null);
+const infoObj = ref({});
 
 const props = defineProps({
   row: {
@@ -10,23 +20,214 @@ const props = defineProps({
   },
 });
 
-const showRouteFlow = () => {};
 
 onMounted(async () => {
   console.log("CheckTopInfos routeFlowComService mounted", props.row);
   let res = await getRouteInfo(props.row.businessId);
   infoObj.value = res.data;
+  await loadProcessesFlow();
+  flowBoxScreen();
 });
+
+const resetHistory = () => {
+  historyList.value = [];
+};
+const historyList = ref([]);
+const { capture } = useScreenshot();
+const { layout } = useLayout();
+const instance = useVueFlow();
+const { addEdges} =
+    instance;
+const { onDragOver, onDrop, onDragLeave, isDragOver, onDragStart } =
+    useDragAndDrop();
+const onConnectMethod = (edge) => {
+  edge.type = "custom";
+  addEdges(edge);
+};
+
+const flowData = reactive({ edges: [], nodes: [] });
+const flowDataCopy = ref({ edges: [], nodes: [] });
+const currentProcess = ref({});
+const selectNode = ref(null);
+const selectLine = ref(null);
+const { nodes } = toRefs(flowData); //ref(initialNodes);
+const { edges } = toRefs(flowData); //ref(initialEdges);
+//true为可编辑线路
+const usableStatus = ref(true);
+provide("selectNode", selectNode);
+provide("currentProcess", currentProcess);
+provide("selectLine", selectLine);
+const opComVisible = ref(false)
+// 自定义工序项目字段名称相关方法
+const avueKey = ref(false);
+const nodeClick = (event) => {
+  formOption.column.forEach(item=>{
+    item.disabled = true
+  })
+  editStatus.value = true
+  // 所有的批量报工设置为1
+  event.node.batchReport = 1;
+  selectNode.value = event.node;
+  currentProcess.value = {};
+  //让组件重新加载
+  avueKey.value = !avueKey.value;
+  currentProcess.value = event.node;
+};
+//当使用回退时清空选择的node
+
+const printStauts = ref(false);
+const nodeType = ref("custom");
+const editStatus = ref(false);
+provide("editStatus", editStatus);
+const router = useRouter();
+const route = useRoute();
+// 数据字典相关
+const { dicts } = useDictionaryStore();
+//获取画布盒子具体长宽
+const flowBoxH = ref(null);
+const flowBoxW = ref(null);
+const flowBoxScreen = () => {
+  const flowBox = document.getElementById("flowBox");
+  flowBoxH.value = flowBox.clientHeight;
+  flowBoxW.value = flowBox.clientWidth;
+};
+// 顶部====================
+const back = () => {
+  router.back();
+};
+
+const download = () => {};
+
+const errArray = ref([]);
+provide("errArray", errArray);
+
+const routeOperationData = ref(null);
+const cancelStatus = ref(true);
+//通过id获取现存储信息
+const loadProcessesFlow = async () => {
+  if (infoObj.value) {
+    routeOperationData.value = infoObj.value;
+    if (infoObj.value.routeData && infoObj.value.routeData != "") {
+      let jsonData = JSON.parse(infoObj.value.routeData);
+      flowData.nodes = jsonData.nodes;
+      flowData.edges = jsonData.edges;
+      flowDataCopy.value = JSON.parse(JSON.stringify(jsonData));
+      cancelStatus.value = true;
+      if (infoObj.value.usable == 1) {
+        usableStatus.value = false;
+      }
+      resetHistory();
+    } else {
+      cancelStatus.value = false;
+    }
+  }
+};
+
+const formRef = ref(null);
+const reset = () => {
+  currentProcess.value = {};
+  editStatus.value = false;
+  routeOperationData.value = {};
+};
+const editProComponent = () => {
+  if(currentProcess.value && currentProcess.value.operationId){
+    opComVisible.value = true
+  }else{
+    ElMessage.error("请选择工序")
+  }
+
+};
 </script>
 
 <template>
   <div class="box">
-    <el-button type="primary" @click="showRouteFlow">查看工艺路线</el-button>
-    <el-form :inline="true" :model="infoObj" class="demo-form-inline">
-      <el-form-item label="Approved by: ">
-        <span class="info-text" v-text="infoObj?.processRouteCode"></span>
-      </el-form-item>
-    </el-form>
+    <el-card>
+      <el-form label-width="120px">
+        <el-row>
+          <el-form-item label="工艺编号:">
+            <el-text class="mx-1" >{{infoObj.processRouteCode}}</el-text>
+          </el-form-item>
+          <el-form-item label="工艺名称:">
+            <el-text class="mx-1">{{infoObj.processRouteName}}</el-text>
+          </el-form-item>
+          <el-form-item label="执行文件和标准:">
+            <el-text class="mx-1">{{infoObj.executeFileStd}}</el-text>
+          </el-form-item>
+          <el-form-item label="产品负责人:">
+            <el-text class="mx-1">{{infoObj.productManager}}</el-text>
+          </el-form-item>
+        </el-row>
+      </el-form>
+    </el-card>
+    <el-card>
+
+      <div class="binContainer">
+        <div
+            class="flowBox"
+            id="flowBox"
+            style="height: 100%; width: 100%; overflow: hidden"
+        >
+          <div class="dnd-flow" @drop="onDrop">
+            <VueFlow
+                v-model:nodes="nodes"
+                v-model:edges="edges"
+                :apply-default="!editStatus && usableStatus"
+                @connect="onConnectMethod"
+                @dragover="onDragOver"
+                @dragleave="onDragLeave"
+                @node-click="nodeClick($event)"
+            >
+              <MiniMap style="background-color: grey" v-show="!printStauts" />
+              <template #edge-custom="props">
+                <CustomConnectionLine v-bind="props" />
+              </template>
+              <template #connection-line="props">
+                <CustomConnectionLine v-bind="props" />
+              </template>
+              <template #node-custom="props">
+                <CustomNode v-bind="props" />
+              </template>
+              <DropzoneBackground
+                  :style="{
+                backgroundColor: isDragOver ? '#e7f3ff' : 'transparent',
+                transition: 'background-color 0.2s ease',
+              }"
+              >
+                <p v-if="isDragOver">拖拽中</p>
+              </DropzoneBackground>
+            </VueFlow>
+            <div :style="{  width: flowBoxW - 20 + 'px', height: flowBoxH - 20 + 'px', }"
+            ></div>
+          </div>
+        </div>
+        <div class="detailInfo">
+          <div class="opBox">
+            <div style="display: flex">
+              <el-button type="success" @click="editProComponent" >工序组件</el-button >
+            </div>
+          </div>
+          <avue-form
+              v-if="editStatus"
+              ref="formRef"
+              :option="formOption"
+              v-model="currentProcess"
+              :key="avueKey"
+              style="padding: 10px; background-color: transparent"
+          >
+          </avue-form>
+        </div>
+      </div>
+
+    </el-card>
+    <el-dialog
+        v-model="opComVisible"
+        title="工序组件详情"
+        width="85%"
+        append-to-body
+        @close="opComVisible = false"
+        :destroy-on-close="true">
+      <op_component_view :clickObj="currentProcess"></op_component_view>
+    </el-dialog>
   </div>
 </template>
 
@@ -43,4 +244,205 @@ onMounted(async () => {
 :deep(.el-form-item__label) {
   color: rgba(0, 0, 0, 0.5);
 }
+
+.showStyle {
+  transform: translateY(10px) rotate(90deg);
+}
+.fontStyle {
+  transform: rotate(-90deg);
+}
+.binContainer {
+  height: calc(100vh - 165px);
+  background-color: #f5f7f9;
+  // background-color: white;
+  padding: 0;
+  display: flex;
+}
+.btns {
+  display: flex;
+  justify-content: center;
+  margin: 10px 0;
+  div {
+    width: 80px;
+  }
+}
+.btnsChange {
+  margin: 10px 0;
+  div {
+    display: flex;
+    justify-content: center;
+    margin-bottom: 10px;
+  }
+}
+.header {
+  height: 50px;
+  display: flex;
+  background-color: #f5f7f9;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+}
+
+.processTree {
+  width: 220px;
+  height: 100%;
+  border-right: 1px solid rgba(0, 0, 0, 0.1);
+  .treeChild {
+    background: #f2f2f2;
+    padding: 20px 8px 10px 8px;
+    .childItem {
+      width: 100%;
+      height: 28px;
+      background: #ffffff;
+      border-radius: 4px 4px 4px 4px;
+      border: 1px solid rgba(35, 32, 50, 0.1);
+      margin-bottom: 10px;
+      text-align: center;
+    }
+  }
+}
+
+.flowBox {
+  flex: 1;
+  display: flex;
+  justify-content: center;
+  overflow-y: auto;
+  .flowItem:hover {
+    .flowDelete {
+      visibility: visible;
+    }
+  }
+}
+
+.detailInfo {
+  width: 300px;
+  height: 100%;
+  background-color: white;
+  border-left: 1px solid rgba(0, 0, 0, 0.1);
+  .opBox {
+    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+    padding: 0 20px;
+    height: 150px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-evenly;
+    align-items: center;
+  }
+  .editProcces {
+    display: flex;
+    justify-content: center;
+    margin-bottom: 15px;
+  }
+}
+
+.title,
+.processInfo {
+  line-height: 44px;
+  color: #6f7991;
+  font-size: 14px;
+  font-weight: bold;
+  text-align: left;
+  margin-left: 20px;
+}
+
+.processInfo span {
+  margin-left: 100px;
+}
+
+.processInfo {
+  position: absolute;
+  left: 5%;
+}
+.title2 {
+  color: #232032;
+  font-size: 14px;
+  text-align: left;
+  margin-left: 19px;
+}
+.tipContent {
+  width: 100%;
+  text-align: center;
+  margin-top: 20px;
+  color: #e6a23c;
+}
+
+.process-panel,
+.layout-panel {
+  display: flex;
+  gap: 10px;
+}
+
+.process-panel {
+  background-color: #2d3748;
+  padding: 10px;
+  border-radius: 8px;
+  box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
+  display: flex;
+  flex-direction: column;
+}
+
+.process-panel button {
+  border: none;
+  cursor: pointer;
+  background-color: #4a5568;
+  border-radius: 8px;
+  color: white;
+  box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
+}
+
+.process-panel button {
+  font-size: 16px;
+  width: 40px;
+  height: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.checkbox-panel {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.process-panel button:hover,
+.layout-panel button:hover {
+  background-color: #2563eb;
+  transition: background-color 0.2s;
+}
+
+.process-panel label {
+  color: white;
+  font-size: 12px;
+}
+
+.stop-btn svg {
+  display: none;
+}
+
+.stop-btn:hover svg {
+  display: block;
+}
+
+.stop-btn:hover .spinner {
+  display: none;
+}
+
+.spinner {
+  border: 3px solid #f3f3f3;
+  border-top: 3px solid #2563eb;
+  border-radius: 50%;
+  width: 10px;
+  height: 10px;
+  animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+  0% {
+    transform: rotate(0deg);
+  }
+  100% {
+    transform: rotate(360deg);
+  }
+}
 </style>

+ 1 - 0
src/views/flow/common/LookFlowStep.vue

@@ -49,6 +49,7 @@ defineExpose({
                   <el-tag v-if="activity.state === '0'" type="info">待审核</el-tag>
                   <el-tag v-if="activity.state === '1'" type="success">通过</el-tag>
                   <el-tag v-if="activity.state === '-1'" type="error">驳回</el-tag>
+                  <el-tag v-if="activity.state === '2'" type="error">已撤回</el-tag>
                 </h4>
                 <p>
                   <el-text class="mx-1" v-if="activity.currentStep=='开始'">发起人员:{{activity.auditUser}}</el-text>

+ 35 - 16
src/views/flow/done/index.vue

@@ -15,6 +15,16 @@
         @size-change="dataList"
         @current-change="dataList"
     >
+      <template #menu="{ row }">
+        <el-button link icon="el-icon-copy-document" @click="showFlowSteps(row)"
+        >流程</el-button>
+        <el-button
+            link
+            icon="el-icon-copy-document"
+            @click="showFlowDetail(row)"
+        >详情</el-button
+        >
+      </template>
     </avue-crud>
     <el-dialog
         v-model="dialog.visible"
@@ -22,21 +32,24 @@
         width="1250px"
         @close="dialog.visible = false"
     >
-
       <div class="dialog-footer" align="center">
         <el-button @click="dialog.visible = false">取消</el-button>
         <el-button type="primary" @click="printPage">--</el-button>
       </div>
     </el-dialog>
+
+    <LookFlowStep ref="LookFlowStepRef"></LookFlowStep>
+    <CheckFlow ref="CheckFlowRef" @finish="onCheckFinish" :operType="operType"></CheckFlow>
   </div>
 </template>
 <script setup>
+import LookFlowStep from "@/views/flow/common/LookFlowStep.vue";
+import CheckFlow from "@/views/flow/common/CheckFlow.vue";
 import { ref, getCurrentInstance } from "vue";
 import { useCrud } from "@/hooks/userCrud";
 import { useCommonStoreHook } from "@/store";
 import dictDataUtil from "@/common/configs/dictDataUtil";
 const { isShowTable, tableType } = toRefs(useCommonStoreHook());
-const toPrintRef = ref(null);
 // 传入一个url,后面不带/
 const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
     useCrud({
@@ -46,7 +59,7 @@ const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
     Methords; //增删改查
 const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
 const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等工具
-
+const operType = ref("done")
 const crudRef = ref(null); //crudRef.value 获取avue-crud对象
 const dialog = reactive({
   title: "二维码打印",
@@ -58,9 +71,11 @@ option.value = Object.assign(option.value, {
   delBtn: false,
   selection: false,
   addBtn: false,
+  editBtn: false,
+  viewBtn: false,
   column: [
     {
-      label: "待办类型",
+      label: "流程类型",
       prop: "taskType",
       type: "select",
       search: true,
@@ -72,7 +87,7 @@ option.value = Object.assign(option.value, {
       },
     },
     {
-      label: "任务名称",
+      label: "流程名称",
       prop: "taskName",
       editDisabled: true,
     },
@@ -89,26 +104,30 @@ option.value = Object.assign(option.value, {
       label: "审核状态",
       prop: "state",
       type: "select",
-      dicUrl:
-          dictDataUtil.request_url + "flow_state",
+      dicUrl: dictDataUtil.request_url + "flow_state",
       props: {
         label: "dictLabel",
         value: "dictValue",
       },
     },
-    {
-      label: "审核人员",
-      prop: "auditUser",
-    },
-    {
-      label: "审核时间",
-      prop: "auditTime",
-    },
   ],
 });
 
 onMounted(() => {
-  search.value.state = "1"
+  operType.value = "done"
   dataList();
 });
+
+const LookFlowStepRef = ref(null);
+const showFlowSteps = (row) => {
+  LookFlowStepRef.value && LookFlowStepRef.value.openFlowStepDrawer(row.insId);
+};
+
+const CheckFlowRef = ref(null);
+const showFlowDetail = (row) => {
+  CheckFlowRef.value && CheckFlowRef.value.openCheckDrawer(row);
+};
+const onCheckFinish = (value) => {
+  dataList();
+};
 </script>

+ 2 - 2
src/views/flow/todo/index.vue

@@ -40,7 +40,7 @@
     </el-dialog>
 
     <LookFlowStep ref="LookFlowStepRef"></LookFlowStep>
-    <CheckFlow ref="CheckFlowRef" @finish="onCheckFinish"></CheckFlow>
+    <CheckFlow ref="CheckFlowRef" @finish="onCheckFinish" :operType="operType"></CheckFlow>
   </div>
 </template>
 <script setup>
@@ -51,7 +51,6 @@ import { useCrud } from "@/hooks/userCrud";
 import { useCommonStoreHook } from "@/store";
 import dictDataUtil from "@/common/configs/dictDataUtil";
 const { isShowTable, tableType } = toRefs(useCommonStoreHook());
-const toPrintRef = ref(null);
 // 传入一个url,后面不带/
 const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
   useCrud({
@@ -67,6 +66,7 @@ const dialog = reactive({
   title: "二维码打印",
   visible: false,
 });
+const operType = ref("todo")
 // 设置表格列或者其他自定义的option
 option.value = Object.assign(option.value, {
   searchEnter: true,