|
@@ -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>
|