Compare commits
No commits in common. "3ee5403ad9360ddaf68edeb18419072f43e835ab" and "7fccfc9869f92862baa1ae14a073c96e661b9e21" have entirely different histories.
3ee5403ad9
...
7fccfc9869
|
|
@ -10,9 +10,6 @@
|
||||||
"@element-plus/icons-vue": "^2.3.2",
|
"@element-plus/icons-vue": "^2.3.2",
|
||||||
"@kjgl77/datav-vue3": "^1.7.1",
|
"@kjgl77/datav-vue3": "^1.7.1",
|
||||||
"@tinymce/tinymce-vue": "5.0.0",
|
"@tinymce/tinymce-vue": "5.0.0",
|
||||||
"@vue-flow/background": "^1.3.2",
|
|
||||||
"@vue-flow/controls": "^1.1.3",
|
|
||||||
"@vue-flow/core": "^1.48.2",
|
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^1.18.1",
|
"axios": "^1.18.1",
|
||||||
"babylonjs": "^6.46.0",
|
"babylonjs": "^6.46.0",
|
||||||
|
|
@ -27,7 +24,6 @@
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"d3": "^7.6.1",
|
"d3": "^7.6.1",
|
||||||
"dagre": "^0.8.5",
|
|
||||||
"dagre-d3": "^0.6.4",
|
"dagre-d3": "^0.6.4",
|
||||||
"dhtmlx-gantt": "^8.0.6",
|
"dhtmlx-gantt": "^8.0.6",
|
||||||
"echarts": "^5.5.1",
|
"echarts": "^5.5.1",
|
||||||
|
|
|
||||||
|
|
@ -516,12 +516,6 @@ export default {
|
||||||
return await http.get(`${config.API_URL}/mtm/routepack/${id}/final_materials/`);
|
return await http.get(`${config.API_URL}/mtm/routepack/${id}/final_materials/`);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
validate: {
|
|
||||||
name: "校验工艺图",
|
|
||||||
req: async function (id) {
|
|
||||||
return await http.get(`${config.API_URL}/mtm/routepack/${id}/validate/`);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: {
|
update: {
|
||||||
name: "更新",
|
name: "更新",
|
||||||
req: async function (id, data) {
|
req: async function (id, data) {
|
||||||
|
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="mnode" :class="'mnode--' + (data.kind || 'mid')">
|
|
||||||
<Handle type="target" :position="Position.Top" class="mnode__handle" />
|
|
||||||
<span class="mnode__tag">{{ kindLabel }}</span>
|
|
||||||
<div class="mnode__name" :title="data.label">{{ data.label }}</div>
|
|
||||||
<Handle type="source" :position="Position.Bottom" class="mnode__handle" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { Handle, Position } from "@vue-flow/core";
|
|
||||||
|
|
||||||
// 物料节点卡片:scFlowEditor(编辑)与 scFlowViewer(查看)共用,保证两端视觉一致
|
|
||||||
export default {
|
|
||||||
name: "MaterialNode",
|
|
||||||
components: { Handle },
|
|
||||||
props: {
|
|
||||||
// { label, kind: raw|mid|final }
|
|
||||||
data: { type: Object, default: () => ({}) },
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return { Position };
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
kindLabel() {
|
|
||||||
return { raw: "原料", final: "成品", mid: "半成品" }[this.data.kind] || "半成品";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.mnode {
|
|
||||||
position: relative;
|
|
||||||
width: 150px;
|
|
||||||
padding: 6px 10px 8px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid #dcdfe6;
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: 0 2px 8px rgba(31, 45, 61, 0.08);
|
|
||||||
text-align: center;
|
|
||||||
transition: box-shadow 0.15s, transform 0.15s;
|
|
||||||
}
|
|
||||||
.mnode:hover {
|
|
||||||
box-shadow: 0 4px 14px rgba(31, 45, 61, 0.16);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
|
||||||
.mnode__tag {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 11px;
|
|
||||||
line-height: 1;
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.mnode__name {
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.3;
|
|
||||||
color: #303133;
|
|
||||||
word-break: break-all;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.mnode--raw {
|
|
||||||
border-color: #f0c78a;
|
|
||||||
background: #fffaf2;
|
|
||||||
}
|
|
||||||
.mnode--raw .mnode__tag {
|
|
||||||
background: #e6a23c;
|
|
||||||
}
|
|
||||||
.mnode--mid {
|
|
||||||
border-color: #a3d0ff;
|
|
||||||
background: #f5faff;
|
|
||||||
}
|
|
||||||
.mnode--mid .mnode__tag {
|
|
||||||
background: #409eff;
|
|
||||||
}
|
|
||||||
.mnode--final {
|
|
||||||
border-color: #a4da89;
|
|
||||||
background: #f6fcf1;
|
|
||||||
}
|
|
||||||
.mnode--final .mnode__tag {
|
|
||||||
background: #67c23a;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
/* Vue Flow 内部元素(非 scoped) */
|
|
||||||
.vue-flow__node-material {
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.vue-flow__handle {
|
|
||||||
width: 9px;
|
|
||||||
height: 9px;
|
|
||||||
background: #fff;
|
|
||||||
border: 2px solid #409eff;
|
|
||||||
}
|
|
||||||
.vue-flow__handle:hover {
|
|
||||||
background: #409eff;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
import dagre from "dagre";
|
|
||||||
|
|
||||||
export const NODE_W = 150;
|
|
||||||
export const NODE_H = 54;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dagre 自动布局,返回带 position 的 nodes
|
|
||||||
* @param {Array} nodes Vue Flow 节点(id 必须为字符串)
|
|
||||||
* @param {Array} edges Vue Flow 边
|
|
||||||
* @param {Object} opts { rankdir: TB|BT|LR|RL, nodeW, nodeH }
|
|
||||||
*/
|
|
||||||
export function layoutGraph(nodes, edges, opts = {}) {
|
|
||||||
const { rankdir = "TB", nodeW = NODE_W, nodeH = NODE_H } = opts;
|
|
||||||
const g = new dagre.graphlib.Graph();
|
|
||||||
g.setGraph({ rankdir, nodesep: 30, ranksep: 56, marginx: 20, marginy: 20 });
|
|
||||||
g.setDefaultEdgeLabel(() => ({}));
|
|
||||||
nodes.forEach((n) => g.setNode(n.id, { width: nodeW, height: nodeH }));
|
|
||||||
edges.forEach((e) => g.setEdge(e.source, e.target));
|
|
||||||
dagre.layout(g);
|
|
||||||
return nodes.map((n) => {
|
|
||||||
const gn = g.node(n.id);
|
|
||||||
return { ...n, position: { x: gn.x - nodeW / 2, y: gn.y - nodeH / 2 } };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
title="绑定定位卡"
|
title="绑定定位卡"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
v-model="pageShow"
|
v-model="pageShow"
|
||||||
|
|
|
||||||
|
|
@ -1,654 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flow-editor" v-loading="loading">
|
|
||||||
<!-- 顶部工具栏 -->
|
|
||||||
<div class="flow-toolbar">
|
|
||||||
<div class="flow-toolbar__left">
|
|
||||||
<el-button v-if="!readonly" type="primary" icon="el-icon-plus" size="small" round @click="addStep">新增工序</el-button>
|
|
||||||
<el-button icon="el-icon-magic-stick" size="small" round @click="relayout">自动布局</el-button>
|
|
||||||
<el-button icon="el-icon-full-screen" size="small" round @click="doFit">适应画布</el-button>
|
|
||||||
<el-button icon="el-icon-circle-check" size="small" round @click="doValidate" :loading="validating">校验</el-button>
|
|
||||||
</div>
|
|
||||||
<div class="flow-legend">
|
|
||||||
<span class="lg lg--raw">原料</span>
|
|
||||||
<span class="lg lg--mid">半成品</span>
|
|
||||||
<span class="lg lg--final">成品</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flow-tip" v-if="!readonly">
|
|
||||||
从左侧拖入原料作为起点 → 从节点圆点拉线到空白处生成下一道工序;单击线条编辑,右键线条删工序 / 右键节点移除物料
|
|
||||||
</div>
|
|
||||||
<div class="flow-tip flow-tip--ro" v-else>当前状态不可编辑(仅创建中的工艺可编辑)</div>
|
|
||||||
|
|
||||||
<div class="flow-body">
|
|
||||||
<!-- 左侧物料面板:拖入画布作为节点 -->
|
|
||||||
<div class="flow-palette" v-if="!readonly">
|
|
||||||
<div class="palette-head">
|
|
||||||
<div class="palette-title">物料库</div>
|
|
||||||
<el-select v-model="matType" size="small" @change="loadMaterials" style="width: 100%">
|
|
||||||
<el-option label="主要原料" value="30"></el-option>
|
|
||||||
<el-option label="成品" value="10"></el-option>
|
|
||||||
<el-option label="半成品" value="20"></el-option>
|
|
||||||
</el-select>
|
|
||||||
<el-input
|
|
||||||
v-model="matKeyword"
|
|
||||||
size="small"
|
|
||||||
clearable
|
|
||||||
prefix-icon="el-icon-search"
|
|
||||||
placeholder="搜索物料"
|
|
||||||
style="margin-top: 6px"
|
|
||||||
></el-input>
|
|
||||||
</div>
|
|
||||||
<div class="palette-list" v-loading="matLoading">
|
|
||||||
<div
|
|
||||||
v-for="m in filteredMaterials"
|
|
||||||
:key="m.id"
|
|
||||||
class="palette-item"
|
|
||||||
:draggable="true"
|
|
||||||
@dragstart="onDragStart($event, m)"
|
|
||||||
:title="m.full_name"
|
|
||||||
>
|
|
||||||
<i class="el-icon-rank palette-item__grip"></i>
|
|
||||||
<span class="palette-item__txt">{{ m.full_name }}</span>
|
|
||||||
</div>
|
|
||||||
<div v-if="!matLoading && filteredMaterials.length === 0" class="palette-empty">无匹配物料</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 画布 -->
|
|
||||||
<div class="flow-canvas" @drop="onDrop" @dragover.prevent>
|
|
||||||
<VueFlow
|
|
||||||
:id="flowId"
|
|
||||||
:default-viewport="{ zoom: 0.9 }"
|
|
||||||
:min-zoom="0.2"
|
|
||||||
:max-zoom="2"
|
|
||||||
:nodes-draggable="true"
|
|
||||||
:nodes-connectable="!readonly"
|
|
||||||
:elements-selectable="true"
|
|
||||||
@nodes-initialized="onNodesInit"
|
|
||||||
@connect-start="onConnectStart"
|
|
||||||
@connect="onConnect"
|
|
||||||
@connect-end="onConnectEnd"
|
|
||||||
@edge-click="onEdgeClick"
|
|
||||||
@edge-context-menu="onEdgeContextMenu"
|
|
||||||
@node-context-menu="onNodeContextMenu"
|
|
||||||
>
|
|
||||||
<!-- 自定义物料节点(与 scFlowViewer 共用) -->
|
|
||||||
<template #node-material="{ data }">
|
|
||||||
<material-node :data="data" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<Background :gap="18" pattern-color="#e6e9ef" />
|
|
||||||
<Controls :show-interactive="false" />
|
|
||||||
</VueFlow>
|
|
||||||
<div v-if="!loading && nodes.length === 0" class="flow-empty">
|
|
||||||
<i class="el-icon-position flow-empty__icon"></i>
|
|
||||||
<div>从左侧把「原料」拖到这里开始搭建工艺路线</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 复用现有单步表单:新增/编辑一条 Route -->
|
|
||||||
<route-form
|
|
||||||
v-if="dialogVisible"
|
|
||||||
ref="routeForm"
|
|
||||||
:count="count"
|
|
||||||
:routepack="routepack"
|
|
||||||
@success="onFormSuccess"
|
|
||||||
@closed="dialogVisible = false"
|
|
||||||
></route-form>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { VueFlow, useVueFlow } from "@vue-flow/core";
|
|
||||||
import { Background } from "@vue-flow/background";
|
|
||||||
import { Controls } from "@vue-flow/controls";
|
|
||||||
import routeForm from "@/views/mtm/route_form.vue";
|
|
||||||
import MaterialNode from "./flow/MaterialNode.vue";
|
|
||||||
import { layoutGraph } from "./flow/dagreLayout";
|
|
||||||
import "@vue-flow/core/dist/style.css";
|
|
||||||
import "@vue-flow/core/dist/theme-default.css";
|
|
||||||
import "@vue-flow/controls/dist/style.css";
|
|
||||||
|
|
||||||
// 每个编辑器实例分配唯一 flowId,避免 Vue Flow 全局 store 按固定 id 缓存导致跨次残留
|
|
||||||
let flowSeq = 0;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "scFlowEditor",
|
|
||||||
components: { VueFlow, Background, Controls, routeForm, MaterialNode },
|
|
||||||
props: {
|
|
||||||
// 工艺包 id
|
|
||||||
routepack: { type: String, default: "" },
|
|
||||||
// 是否只读(非“创建中”状态)
|
|
||||||
readonly: { type: Boolean, default: false },
|
|
||||||
},
|
|
||||||
emits: ["changed"],
|
|
||||||
setup() {
|
|
||||||
const flowId = "route-flow-editor-" + ++flowSeq;
|
|
||||||
const { fitView, screenToFlowCoordinate, project, setNodes, setEdges, addNodes, removeNodes } =
|
|
||||||
useVueFlow(flowId);
|
|
||||||
return { flowId, fitView, screenToFlowCoordinate, project, setNodes, setEdges, addNodes, removeNodes };
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: false,
|
|
||||||
validating: false,
|
|
||||||
routes: [],
|
|
||||||
nodes: [],
|
|
||||||
edges: [],
|
|
||||||
count: 0,
|
|
||||||
dialogVisible: false,
|
|
||||||
// 左侧物料面板
|
|
||||||
matType: "30",
|
|
||||||
matKeyword: "",
|
|
||||||
materials: [],
|
|
||||||
matLoading: false,
|
|
||||||
// 客户端临时种子节点(尚未挂到任何 Route 上)
|
|
||||||
seedNodes: [],
|
|
||||||
// 连线手势内部状态
|
|
||||||
connectSource: null,
|
|
||||||
connectMade: false,
|
|
||||||
// 仅初次加载自动适配一次,避免编辑时视图跳动
|
|
||||||
hasFitted: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
filteredMaterials() {
|
|
||||||
const kw = (this.matKeyword || "").trim().toLowerCase();
|
|
||||||
if (!kw) return this.materials;
|
|
||||||
return this.materials.filter((m) => (m.full_name || "").toLowerCase().includes(kw));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
routepack() {
|
|
||||||
this.reload();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.loadMaterials();
|
|
||||||
if (this.routepack) this.reload();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
/** 加载左侧物料面板列表 */
|
|
||||||
loadMaterials() {
|
|
||||||
this.matLoading = true;
|
|
||||||
this.$API.mtm.material.list
|
|
||||||
.req({ page: 0, type__in: this.matType, is_hidden: false, query: "{full_name,id}" })
|
|
||||||
.then((res) => {
|
|
||||||
this.materials = Array.isArray(res) ? res : res.results || [];
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.matLoading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 重新拉取路线并重建图 */
|
|
||||||
reload() {
|
|
||||||
if (!this.routepack) return;
|
|
||||||
this.loading = true;
|
|
||||||
this.$API.mtm.route.list
|
|
||||||
.req({ page: 0, routepack: this.routepack })
|
|
||||||
.then((res) => {
|
|
||||||
this.routes = Array.isArray(res) ? res : res.results || [];
|
|
||||||
this.count = this.routes.length;
|
|
||||||
this.buildGraph();
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 节点类型:起点原料 / 终点成品 / 中间半成品 */
|
|
||||||
kindOf(id, targetIds) {
|
|
||||||
const isSrc = this.routes.some((r) => String(r.material_in) === id);
|
|
||||||
const isTgt = targetIds.has(id);
|
|
||||||
if (isTgt && !isSrc) return "final";
|
|
||||||
if (!isTgt && isSrc) return "raw";
|
|
||||||
return "mid";
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 由 routes 构建 物料节点 + 工序边,并用 dagre 自动布局;合并未落库的种子节点 */
|
|
||||||
buildGraph() {
|
|
||||||
const matMap = {};
|
|
||||||
const targetIds = new Set();
|
|
||||||
const edges = [];
|
|
||||||
|
|
||||||
this.routes.forEach((r) => {
|
|
||||||
if (r.material_in == null || r.material_out == null) return;
|
|
||||||
const sid = String(r.material_in);
|
|
||||||
const tid = String(r.material_out);
|
|
||||||
if (!matMap[sid]) matMap[sid] = r.material_in_name || sid;
|
|
||||||
if (!matMap[tid]) matMap[tid] = r.material_out_name || tid;
|
|
||||||
targetIds.add(tid);
|
|
||||||
|
|
||||||
const locked = !!r.from_route;
|
|
||||||
edges.push({
|
|
||||||
id: String(r.id),
|
|
||||||
source: sid,
|
|
||||||
target: tid,
|
|
||||||
label: (r.process_name || "") + (locked ? " 🔒" : ""),
|
|
||||||
data: { route: r, locked },
|
|
||||||
type: "smoothstep",
|
|
||||||
markerEnd: "arrowclosed",
|
|
||||||
style: {
|
|
||||||
stroke: locked ? "#c0c4cc" : "#409eff",
|
|
||||||
strokeWidth: locked ? 1.5 : 2,
|
|
||||||
strokeDasharray: locked ? "5 4" : undefined,
|
|
||||||
},
|
|
||||||
labelStyle: { fill: "#5b6370", fontSize: "12px", fontWeight: 500 },
|
|
||||||
labelBgStyle: { fill: "#ffffff", stroke: "#e4e7ed", strokeWidth: 1 },
|
|
||||||
labelBgPadding: [7, 4],
|
|
||||||
labelBgBorderRadius: 6,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const routeNodes = Object.keys(matMap).map((id) => ({
|
|
||||||
id,
|
|
||||||
type: "material",
|
|
||||||
data: { label: matMap[id], kind: this.kindOf(id, targetIds) },
|
|
||||||
position: { x: 0, y: 0 },
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 已落库的物料从种子集合中剔除,其余种子保留在画布上
|
|
||||||
const routeNodeIds = new Set(Object.keys(matMap));
|
|
||||||
this.seedNodes = this.seedNodes.filter((s) => !routeNodeIds.has(s.id));
|
|
||||||
|
|
||||||
this.edges = edges;
|
|
||||||
this.nodes = layoutGraph(routeNodes.concat(this.seedNodes), edges);
|
|
||||||
this.syncStore();
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 把本地 nodes/edges 命令式同步到 Vue Flow store(先节点后边,避免边找不到端点) */
|
|
||||||
syncStore() {
|
|
||||||
this.setEdges([]);
|
|
||||||
this.setNodes(this.nodes);
|
|
||||||
this.setEdges(this.edges);
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 重新布局并适应画布 */
|
|
||||||
relayout() {
|
|
||||||
this.nodes = layoutGraph([...this.nodes], this.edges);
|
|
||||||
this.setNodes(this.nodes);
|
|
||||||
this.doFit();
|
|
||||||
},
|
|
||||||
|
|
||||||
doFit() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
try {
|
|
||||||
this.fitView({ padding: 0.25, maxZoom: 1, duration: 300 });
|
|
||||||
} catch (e) {
|
|
||||||
/* noop */
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/** VueFlow 节点尺寸测量完成:仅首次自动适配一次 */
|
|
||||||
onNodesInit() {
|
|
||||||
if (this.hasFitted) return;
|
|
||||||
if (this.nodes.length === 0) return;
|
|
||||||
this.hasFitted = true;
|
|
||||||
this.doFit();
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ============ 左侧面板拖拽入画布 ============ */
|
|
||||||
onDragStart(evt, mat) {
|
|
||||||
evt.dataTransfer.setData(
|
|
||||||
"application/scflow",
|
|
||||||
JSON.stringify({ id: mat.id, name: mat.full_name })
|
|
||||||
);
|
|
||||||
evt.dataTransfer.effectAllowed = "move";
|
|
||||||
},
|
|
||||||
onDrop(evt) {
|
|
||||||
if (this.readonly) return;
|
|
||||||
const raw = evt.dataTransfer.getData("application/scflow");
|
|
||||||
if (!raw) return;
|
|
||||||
let mat;
|
|
||||||
try {
|
|
||||||
mat = JSON.parse(raw);
|
|
||||||
} catch (e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const pos = this.toFlowPos(evt.clientX, evt.clientY);
|
|
||||||
this.addSeed(mat, pos);
|
|
||||||
},
|
|
||||||
toFlowPos(clientX, clientY) {
|
|
||||||
if (typeof this.screenToFlowCoordinate === "function") {
|
|
||||||
return this.screenToFlowCoordinate({ x: clientX, y: clientY });
|
|
||||||
}
|
|
||||||
if (typeof this.project === "function") {
|
|
||||||
return this.project({ x: clientX, y: clientY });
|
|
||||||
}
|
|
||||||
return { x: clientX, y: clientY };
|
|
||||||
},
|
|
||||||
addSeed(mat, position) {
|
|
||||||
const id = String(mat.id);
|
|
||||||
if (this.nodes.some((n) => n.id === id)) {
|
|
||||||
const inUse = this.routes.some(
|
|
||||||
(r) => String(r.material_in) === id || String(r.material_out) === id
|
|
||||||
);
|
|
||||||
this.$message.info(inUse ? "该物料已在工序中使用" : "该物料已在画布中(右键节点可移除)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const node = {
|
|
||||||
id,
|
|
||||||
type: "material",
|
|
||||||
data: { label: mat.name, kind: "raw" },
|
|
||||||
position,
|
|
||||||
};
|
|
||||||
this.seedNodes.push(node);
|
|
||||||
this.nodes = [...this.nodes, node];
|
|
||||||
// 命令式加入 store:先注册再渲染 Handle,避免 dimensions 竞态
|
|
||||||
this.addNodes([node]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ============ 连线手势 ============ */
|
|
||||||
onConnectStart(params) {
|
|
||||||
this.connectSource = (params && (params.nodeId || params.source)) || null;
|
|
||||||
this.connectMade = false;
|
|
||||||
},
|
|
||||||
/** 连到已有节点:新建一条 Route,预填输入/输出物料 */
|
|
||||||
onConnect(conn) {
|
|
||||||
this.connectMade = true;
|
|
||||||
if (this.readonly) return;
|
|
||||||
const src = this.nodes.find((n) => n.id === conn.source);
|
|
||||||
const tgt = this.nodes.find((n) => n.id === conn.target);
|
|
||||||
// 注意:id 为雪花大整数,必须保持字符串,切勿 Number() 否则精度丢失
|
|
||||||
this.openForm("add", {
|
|
||||||
material_in: conn.source,
|
|
||||||
material_in_name: src ? src.data.label : "",
|
|
||||||
material_out: conn.target,
|
|
||||||
material_out_name: tgt ? tgt.data.label : "",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/** 拉线到空白处:新建工序,输出物料留空由后端自动生成下一节点 */
|
|
||||||
onConnectEnd() {
|
|
||||||
const src = this.connectSource;
|
|
||||||
const made = this.connectMade;
|
|
||||||
this.connectSource = null;
|
|
||||||
this.connectMade = false;
|
|
||||||
if (this.readonly || made || !src) return;
|
|
||||||
const node = this.nodes.find((n) => n.id === src);
|
|
||||||
// id 为雪花大整数,保持字符串
|
|
||||||
this.openForm("add", {
|
|
||||||
material_in: src,
|
|
||||||
material_in_name: node ? node.data.label : "",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 单击边 => 编辑对应 Route(复用 route_form) */
|
|
||||||
onEdgeClick(evt) {
|
|
||||||
const edge = evt.edge || evt;
|
|
||||||
const route = edge.data && edge.data.route;
|
|
||||||
if (!route) return;
|
|
||||||
if (this.readonly) {
|
|
||||||
this.$message.info("当前状态不可编辑");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (edge.data.locked) {
|
|
||||||
this.$message.warning("该工序引用了其他步骤,无法编辑");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.openForm("edit", route);
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 右键边 => 删除对应 Route */
|
|
||||||
onEdgeContextMenu(evt) {
|
|
||||||
const oe = evt.event || evt;
|
|
||||||
if (oe && oe.preventDefault) oe.preventDefault();
|
|
||||||
if (this.readonly) return;
|
|
||||||
const edge = evt.edge || evt;
|
|
||||||
const route = edge.data && edge.data.route;
|
|
||||||
if (!route) return;
|
|
||||||
if (edge.data.locked) {
|
|
||||||
this.$message.warning("该工序被其他步骤引用,无法删除");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.$confirm(`确定删除工序「${route.process_name || ""}」吗?`, "提示", {
|
|
||||||
type: "warning",
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.$API.mtm.route.delete.req(route.id).then(() => {
|
|
||||||
this.$message.success("删除成功");
|
|
||||||
this.reload();
|
|
||||||
this.$emit("changed");
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 右键节点 => 移除未落库的种子节点(已用于工序的物料需删对应工序) */
|
|
||||||
onNodeContextMenu(evt) {
|
|
||||||
const oe = evt.event || evt;
|
|
||||||
if (oe && oe.preventDefault) oe.preventDefault();
|
|
||||||
if (this.readonly) return;
|
|
||||||
const node = evt.node || evt;
|
|
||||||
const nid = node.id;
|
|
||||||
const inUse = this.routes.some(
|
|
||||||
(r) => String(r.material_in) === nid || String(r.material_out) === nid
|
|
||||||
);
|
|
||||||
if (inUse) {
|
|
||||||
this.$message.warning("该物料已用于工序,请删除对应工序");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const label = (node.data && node.data.label) || "";
|
|
||||||
this.$confirm(`从画布移除「${label}」?`, "提示", { type: "warning" })
|
|
||||||
.then(() => {
|
|
||||||
this.seedNodes = this.seedNodes.filter((s) => s.id !== nid);
|
|
||||||
this.nodes = this.nodes.filter((n) => n.id !== nid);
|
|
||||||
this.removeNodes([nid]);
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
},
|
|
||||||
|
|
||||||
addStep() {
|
|
||||||
this.openForm("add", null);
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 打开单步表单;prefill 为 null 表示纯新增 */
|
|
||||||
openForm(mode, prefill) {
|
|
||||||
this.dialogVisible = true;
|
|
||||||
this.$nextTick(() => {
|
|
||||||
const inst = this.$refs.routeForm.open(mode);
|
|
||||||
if (prefill) inst.setData(prefill);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onFormSuccess() {
|
|
||||||
this.dialogVisible = false;
|
|
||||||
this.reload();
|
|
||||||
this.$emit("changed");
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 调后端 validate 接口,实时反馈 DAG 是否合法 */
|
|
||||||
doValidate() {
|
|
||||||
if (!this.routepack) return;
|
|
||||||
this.validating = true;
|
|
||||||
this.$API.mtm.routepack.validate
|
|
||||||
.req(this.routepack)
|
|
||||||
.then((res) => {
|
|
||||||
if (res && res.valid) {
|
|
||||||
this.$message.success("工艺图校验通过");
|
|
||||||
} else {
|
|
||||||
this.$message.error("校验未通过:" + (res ? res.error : "未知错误"));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.validating = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.flow-editor {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
min-height: 480px;
|
|
||||||
}
|
|
||||||
.flow-toolbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 4px 8px;
|
|
||||||
background: #f7f9fc;
|
|
||||||
border: 1px solid #eef1f6;
|
|
||||||
border-radius: 8px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
.flow-toolbar__left {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
.flow-legend {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
.lg {
|
|
||||||
position: relative;
|
|
||||||
padding-left: 16px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #606266;
|
|
||||||
}
|
|
||||||
.lg::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: 1px solid;
|
|
||||||
}
|
|
||||||
.lg--raw::before {
|
|
||||||
background: #fdf6ec;
|
|
||||||
border-color: #e6a23c;
|
|
||||||
}
|
|
||||||
.lg--mid::before {
|
|
||||||
background: #ecf5ff;
|
|
||||||
border-color: #409eff;
|
|
||||||
}
|
|
||||||
.lg--final::before {
|
|
||||||
background: #f0f9eb;
|
|
||||||
border-color: #67c23a;
|
|
||||||
}
|
|
||||||
.flow-tip {
|
|
||||||
color: #909399;
|
|
||||||
font-size: 12px;
|
|
||||||
padding: 3px 2px 4px;
|
|
||||||
}
|
|
||||||
.flow-tip--ro {
|
|
||||||
color: #e6a23c;
|
|
||||||
}
|
|
||||||
.flow-body {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
min-height: 420px;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
.flow-palette {
|
|
||||||
width: 190px;
|
|
||||||
flex: 0 0 190px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
border: 1px solid #eef1f6;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
.palette-head {
|
|
||||||
padding: 8px;
|
|
||||||
border-bottom: 1px solid #f0f2f5;
|
|
||||||
background: #fafbfd;
|
|
||||||
}
|
|
||||||
.palette-title {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #303133;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
.palette-list {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
.palette-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 7px 9px;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
border: 1px solid #ebeef5;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: #fff;
|
|
||||||
cursor: grab;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #303133;
|
|
||||||
transition: all 0.15s;
|
|
||||||
}
|
|
||||||
.palette-item:hover {
|
|
||||||
border-color: #409eff;
|
|
||||||
background: #ecf5ff;
|
|
||||||
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.15);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
|
||||||
.palette-item:active {
|
|
||||||
cursor: grabbing;
|
|
||||||
}
|
|
||||||
.palette-item__grip {
|
|
||||||
color: #c0c4cc;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
.palette-item__txt {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.palette-empty {
|
|
||||||
color: #909399;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
|
||||||
padding: 16px 0;
|
|
||||||
}
|
|
||||||
.flow-canvas {
|
|
||||||
position: relative;
|
|
||||||
flex: 1;
|
|
||||||
min-height: 420px;
|
|
||||||
border: 1px solid #eef1f6;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
background: #fbfcfe;
|
|
||||||
}
|
|
||||||
.flow-empty {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
color: #a8abb2;
|
|
||||||
font-size: 13px;
|
|
||||||
text-align: center;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.flow-empty__icon {
|
|
||||||
font-size: 34px;
|
|
||||||
color: #c8ccd4;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<style>
|
|
||||||
/* Vue Flow 内部元素(非 scoped);物料节点样式在 flow/MaterialNode.vue */
|
|
||||||
.vue-flow__controls {
|
|
||||||
box-shadow: 0 2px 10px rgba(31, 45, 61, 0.12);
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,147 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="sc-flow-viewer">
|
|
||||||
<VueFlow
|
|
||||||
:id="flowId"
|
|
||||||
:min-zoom="0.2"
|
|
||||||
:max-zoom="2"
|
|
||||||
:nodes-draggable="false"
|
|
||||||
:nodes-connectable="false"
|
|
||||||
:elements-selectable="false"
|
|
||||||
@nodes-initialized="onNodesInit"
|
|
||||||
>
|
|
||||||
<template #node-material="{ data }">
|
|
||||||
<material-node :data="data" />
|
|
||||||
</template>
|
|
||||||
<Background :gap="18" pattern-color="#e6e9ef" />
|
|
||||||
<Controls :show-interactive="false" />
|
|
||||||
</VueFlow>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { VueFlow, useVueFlow } from "@vue-flow/core";
|
|
||||||
import { Background } from "@vue-flow/background";
|
|
||||||
import { Controls } from "@vue-flow/controls";
|
|
||||||
import MaterialNode from "./flow/MaterialNode.vue";
|
|
||||||
import { layoutGraph } from "./flow/dagreLayout";
|
|
||||||
import "@vue-flow/core/dist/style.css";
|
|
||||||
import "@vue-flow/core/dist/theme-default.css";
|
|
||||||
import "@vue-flow/controls/dist/style.css";
|
|
||||||
|
|
||||||
// 每个实例分配唯一 flowId,避免 Vue Flow 全局 store 按固定 id 缓存导致多实例互相覆盖
|
|
||||||
let viewerSeq = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 工艺路线只读流程图(Vue Flow 版),与 scFlowEditor 共用节点样式与布局。
|
|
||||||
* props 与 scDegra 对齐:nodes [{id,label}]、edges [{id,source,target,label}]
|
|
||||||
*/
|
|
||||||
export default {
|
|
||||||
name: "scFlowViewer",
|
|
||||||
components: { VueFlow, Background, Controls, MaterialNode },
|
|
||||||
props: {
|
|
||||||
nodes: { type: Array, default: () => [] },
|
|
||||||
edges: { type: Array, default: () => [] },
|
|
||||||
rankdir: { type: String, default: "TB" },
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const flowId = "sc-flow-viewer-" + ++viewerSeq;
|
|
||||||
const { fitView, setNodes, setEdges } = useVueFlow(flowId);
|
|
||||||
return { flowId, fitView, setNodes, setEdges };
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
nodes() {
|
|
||||||
this.rebuild();
|
|
||||||
},
|
|
||||||
edges() {
|
|
||||||
this.rebuild();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.rebuild();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
/** nodes/edges -> Vue Flow 图;节点类型按出入度推断(无入边=原料,无出边=成品) */
|
|
||||||
rebuild() {
|
|
||||||
const sourceIds = new Set();
|
|
||||||
const targetIds = new Set();
|
|
||||||
const rawEdges = (this.edges || [])
|
|
||||||
.filter((e) => e.source != null && e.target != null)
|
|
||||||
.map((e) => {
|
|
||||||
const sid = String(e.source);
|
|
||||||
const tid = String(e.target);
|
|
||||||
sourceIds.add(sid);
|
|
||||||
targetIds.add(tid);
|
|
||||||
return {
|
|
||||||
id: e.id != null ? String(e.id) : sid + "-" + tid,
|
|
||||||
source: sid,
|
|
||||||
target: tid,
|
|
||||||
label: e.label || "",
|
|
||||||
type: "smoothstep",
|
|
||||||
markerEnd: "arrowclosed",
|
|
||||||
style: { stroke: "#409eff", strokeWidth: 2 },
|
|
||||||
labelStyle: { fill: "#5b6370", fontSize: "12px", fontWeight: 500 },
|
|
||||||
labelBgStyle: { fill: "#ffffff", stroke: "#e4e7ed", strokeWidth: 1 },
|
|
||||||
labelBgPadding: [7, 4],
|
|
||||||
labelBgBorderRadius: 6,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
const vNodes = (this.nodes || [])
|
|
||||||
.filter((n) => n.id != null && n.label)
|
|
||||||
.map((n) => {
|
|
||||||
const id = String(n.id);
|
|
||||||
const isSrc = sourceIds.has(id);
|
|
||||||
const isTgt = targetIds.has(id);
|
|
||||||
let kind = "mid";
|
|
||||||
if (isTgt && !isSrc) kind = "final";
|
|
||||||
else if (isSrc && !isTgt) kind = "raw";
|
|
||||||
return { id, type: "material", data: { label: n.label, kind }, position: { x: 0, y: 0 } };
|
|
||||||
});
|
|
||||||
const nodeIds = new Set(vNodes.map((n) => n.id));
|
|
||||||
const vEdges = rawEdges.filter((e) => nodeIds.has(e.source) && nodeIds.has(e.target));
|
|
||||||
|
|
||||||
this.setEdges([]);
|
|
||||||
this.setNodes(layoutGraph(vNodes, vEdges, { rankdir: this.rankdir }));
|
|
||||||
this.setEdges(vEdges);
|
|
||||||
this.doFit();
|
|
||||||
},
|
|
||||||
onNodesInit() {
|
|
||||||
this.doFit();
|
|
||||||
},
|
|
||||||
doFit() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
try {
|
|
||||||
this.fitView({ padding: 0.2, maxZoom: 1, duration: 200 });
|
|
||||||
} catch (e) {
|
|
||||||
/* noop */
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.sc-flow-viewer {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
min-height: 320px;
|
|
||||||
border: 1px solid #eef1f6;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
background: #fbfcfe;
|
|
||||||
}
|
|
||||||
/* 只读视图:隐藏连接点 */
|
|
||||||
.sc-flow-viewer :deep(.vue-flow__handle) {
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.sc-flow-viewer .vue-flow__controls {
|
|
||||||
box-shadow: 0 2px 10px rgba(31, 45, 61, 0.12);
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -62,11 +62,6 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 显式声明 nopadding 的区域不受上面默认内边距影响 */
|
|
||||||
.el-main.nopadding {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 表单卡片化 */
|
/* 表单卡片化 */
|
||||||
.el-main > .el-form {
|
.el-main > .el-form {
|
||||||
background: var(--el-bg-color);
|
background: var(--el-bg-color);
|
||||||
|
|
@ -164,11 +159,6 @@
|
||||||
padding: 14px 10px 14px 14px;
|
padding: 14px 10px 14px 14px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.el-aside.nopadding {
|
|
||||||
background: transparent;
|
|
||||||
border-left: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@
|
||||||
>保 存</el-button
|
>保 存</el-button
|
||||||
>
|
>
|
||||||
</el-footer>
|
</el-footer>
|
||||||
<el-dialog append-to-body title="选择题目" v-model="questionCVisible" width="90%">
|
<el-dialog title="选择题目" v-model="questionCVisible" width="90%">
|
||||||
<Question
|
<Question
|
||||||
style="height: 500px"
|
style="height: 500px"
|
||||||
ref="QuestionChoseRef"
|
ref="QuestionChoseRef"
|
||||||
|
|
@ -219,7 +219,7 @@
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- <el-button type="primary" @click="handleChoose1" icon="el-icon-plus" style="margin-right: 10px;">上传试题</el-button> -->
|
<!-- <el-button type="primary" @click="handleChoose1" icon="el-icon-plus" style="margin-right: 10px;">上传试题</el-button> -->
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
v-model="impDialogVisible"
|
v-model="impDialogVisible"
|
||||||
title="上传试题"
|
title="上传试题"
|
||||||
:left="'200px'"
|
:left="'200px'"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
title="检验"
|
title="检验"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:size="1200"
|
:size="1200"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
:title="titleMap[form.type]"
|
:title="titleMap[form.type]"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:size="1000"
|
:size="1000"
|
||||||
|
|
@ -272,7 +272,7 @@
|
||||||
<el-button @click="visible = false">取消</el-button>
|
<el-button @click="visible = false">取消</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog append-to-body title="设置发货流水位数" v-model="showDigit">
|
<el-dialog title="设置发货流水位数" v-model="showDigit">
|
||||||
<h4>没有找到该前缀的发货编号,请完善发货流水号位数(填整数)</h4>
|
<h4>没有找到该前缀的发货编号,请完善发货流水号位数(填整数)</h4>
|
||||||
<el-form :model="wprParams" label-width="80px">
|
<el-form :model="wprParams" label-width="80px">
|
||||||
<el-form-item label="流水位数">
|
<el-form-item label="流水位数">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
title="标签信息"
|
title="标签信息"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:size="1000"
|
:size="1000"
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,14 @@
|
||||||
</div>
|
</div>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-main class="nopadding">
|
<el-main class="nopadding">
|
||||||
<scFlowViewer :nodes="nodes" :edges="edges"></scFlowViewer>
|
<scDegra
|
||||||
|
style="margin-top: 50px;"
|
||||||
|
ref="degraDialogs"
|
||||||
|
:nodes="nodes"
|
||||||
|
:edges="edges"
|
||||||
|
:rankdir="'DL'"
|
||||||
|
>
|
||||||
|
</scDegra>
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
|
|
@ -123,9 +130,6 @@
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineAsyncComponent } from "vue";
|
|
||||||
// 异步加载:Vue Flow 单独分包
|
|
||||||
const scFlowViewer = defineAsyncComponent(() => import("@/components/scFlowViewer.vue"));
|
|
||||||
const defaultForm = {
|
const defaultForm = {
|
||||||
process: null,
|
process: null,
|
||||||
sort: 1,
|
sort: 1,
|
||||||
|
|
@ -135,7 +139,7 @@ const defaultForm = {
|
||||||
};
|
};
|
||||||
export default {
|
export default {
|
||||||
name: "route",
|
name: "route",
|
||||||
components: { scFlowViewer },
|
components: {},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
apiObj: null,
|
apiObj: null,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
:title="titleMap[mode]"
|
:title="titleMap[mode]"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:size="1000"
|
:size="1000"
|
||||||
append-to-body
|
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
@closed="$emit('closed')"
|
@closed="$emit('closed')"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,17 @@
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-main>
|
<el-main>
|
||||||
<el-container>
|
<el-container>
|
||||||
<el-aside style="width: 50%;overflow: hidden;display: flex;flex-direction: column;">
|
<el-aside style="width: 50%;overflow: scroll;">
|
||||||
<div
|
<div
|
||||||
style="font-weight: 600;color: #303133;font-size: 16px;padding: 10px 0;">
|
style="font-weight: 600;color: #303133;font-size: 16px;padding: 10px 0;position: fixed;">
|
||||||
工艺路线流程图</div>
|
工艺路线流程图</div>
|
||||||
<el-tabs v-if="tabsTitle.length > 1" v-model="activeName" :tab-position="'top'"
|
<el-tabs v-if="tabsTitle.length > 1" v-model="activeName" :tab-position="'left'"
|
||||||
@tab-click="tabshandleClick">
|
style="flex-direction: row;" @tab-click="tabshandleClick">
|
||||||
<el-tab-pane :label="item" v-for="item in tabsTitle" :key="item"></el-tab-pane>
|
<el-tab-pane :label="item" v-for="item in tabsTitle" :key="item"></el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<scFlowViewer v-if="limitedWatch" :nodes="nodes" :edges="edges"
|
<scDegra style="margin-top: 50px;" v-if="limitedWatch" ref="degraDialogs" :nodes="nodes"
|
||||||
style="flex: 1;min-height: 0;">
|
:edges="edges" :rankdir="'DL'" @closeDialog="limitedWatch = false">
|
||||||
</scFlowViewer>
|
</scDegra>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
<el-main class="padding: 1px">
|
<el-main class="padding: 1px">
|
||||||
<scTable ref="tables" :data="tableData" row-key="id" hidePagination hideDo stripe border>
|
<scTable ref="tables" :data="tableData" row-key="id" hidePagination hideDo stripe border>
|
||||||
|
|
@ -70,13 +70,10 @@
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineAsyncComponent } from "vue";
|
|
||||||
import ticketd from '@/views/wf/ticketd.vue'
|
import ticketd from '@/views/wf/ticketd.vue'
|
||||||
// 异步加载:Vue Flow 单独分包,仅打开详情时才下载
|
|
||||||
const scFlowViewer = defineAsyncComponent(() => import("@/components/scFlowViewer.vue"));
|
|
||||||
export default {
|
export default {
|
||||||
emits: ["success", "closed"],
|
emits: ["success", "closed"],
|
||||||
components: { ticketd, scFlowViewer },
|
components: { ticketd },
|
||||||
props: {
|
props: {
|
||||||
t_id: { type: String, default: null },
|
t_id: { type: String, default: null },
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
@closed="$emit('closed')"
|
@closed="$emit('closed')"
|
||||||
>
|
>
|
||||||
<el-container>
|
<el-container>
|
||||||
<el-header style="height: auto; padding: 6px 20px 0">
|
<el-header>
|
||||||
<el-steps
|
<el-steps
|
||||||
:active="active"
|
:active="active"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
|
|
@ -93,27 +93,30 @@
|
||||||
<!--工序!-->
|
<!--工序!-->
|
||||||
<el-main class="nopadding" v-if="active === 1">
|
<el-main class="nopadding" v-if="active === 1">
|
||||||
<el-container>
|
<el-container>
|
||||||
<el-aside class="nopadding" style="width: 55%;overflow: hidden;padding-right: 6px;">
|
<el-aside style="width: 50%;overflow: scroll;">
|
||||||
<scFlowEditor
|
<div style="font-weight: 600;color: #303133;font-size: 16px;padding: 10px 0;position: fixed;width: 30px;">工艺路线流程图</div>
|
||||||
ref="flowEditor"
|
<scDegra
|
||||||
:routepack="routepack"
|
style="margin-top: 50px;"
|
||||||
:readonly="!!(form.state && form.state !== 10)"
|
v-if="limitedWatch"
|
||||||
@changed="handleEditorChanged"
|
ref="degraDialogs"
|
||||||
></scFlowEditor>
|
:nodes="nodes"
|
||||||
|
:edges="edges"
|
||||||
|
:rankdir="'DL'"
|
||||||
|
>
|
||||||
|
</scDegra>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
<el-main class="nopadding" style="width: 45%;overflow: auto;">
|
<el-main style="width: 50%;overflow: scroll;">
|
||||||
<el-container>
|
<el-container>
|
||||||
<el-header style="height: auto; padding: 4px 0">
|
<el-header>
|
||||||
<div class="left-panel">
|
<div class="left-panel" style="margin: 10px">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
size="small"
|
|
||||||
@click="table_add"
|
@click="table_add"
|
||||||
></el-button>
|
></el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-main class="nopadding">
|
<el-main>
|
||||||
<scTable
|
<scTable
|
||||||
ref="tables"
|
ref="tables"
|
||||||
:apiObj="apiObj"
|
:apiObj="apiObj"
|
||||||
|
|
@ -173,7 +176,7 @@
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
</el-main>
|
</el-main>
|
||||||
<el-footer v-if="active === 1" style="height: 44px; display: flex; align-items: center; justify-content: center; gap: 8px;">
|
<el-footer v-if="active === 1" style="text-align: center">
|
||||||
<el-button @click="handleLastStep" style="margin-right: 4px">上一步</el-button>
|
<el-button @click="handleLastStep" style="margin-right: 4px">上一步</el-button>
|
||||||
<ticketd_b :workflow_key="'routepack'" :title="form.name" :t_id="form.id" :ticket_="form.ticket_"
|
<ticketd_b :workflow_key="'routepack'" :title="form.name" :t_id="form.id" :ticket_="form.ticket_"
|
||||||
@success="$emit('closed')"></ticketd_b>
|
@success="$emit('closed')"></ticketd_b>
|
||||||
|
|
@ -191,14 +194,11 @@
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineAsyncComponent } from "vue";
|
|
||||||
import saveDialog from "./route_form.vue";
|
import saveDialog from "./route_form.vue";
|
||||||
import ticketd_b from "@/views/wf/ticketd_b.vue";
|
import ticketd_b from "@/views/wf/ticketd_b.vue";
|
||||||
// 异步加载:Vue Flow + dagre 单独分包,仅打开工艺编辑器时才下载,首屏零影响
|
|
||||||
const scFlowEditor = defineAsyncComponent(() => import("@/components/scFlowEditor.vue"));
|
|
||||||
export default {
|
export default {
|
||||||
name: "routepack_form",
|
name: "routepack_form",
|
||||||
components: { saveDialog, ticketd_b, scFlowEditor },
|
components: { saveDialog, ticketd_b },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
active: 0,
|
active: 0,
|
||||||
|
|
@ -369,7 +369,7 @@ export default {
|
||||||
let that = this;
|
let that = this;
|
||||||
that.$API.mtm.route.delete.req(row.id).then((res) => {
|
that.$API.mtm.route.delete.req(row.id).then((res) => {
|
||||||
that.$message.success("工序步骤删除成功");
|
that.$message.success("工序步骤删除成功");
|
||||||
that.$refs.flowEditor && that.$refs.flowEditor.reload();
|
that.getDEGdatas();
|
||||||
that.$refs.tables.refresh();
|
that.$refs.tables.refresh();
|
||||||
return res;
|
return res;
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
|
@ -378,13 +378,10 @@ export default {
|
||||||
},
|
},
|
||||||
//本地更新数据
|
//本地更新数据
|
||||||
handleSaveSuccess() {
|
handleSaveSuccess() {
|
||||||
|
console.log("handleSaveSuccess");
|
||||||
let that = this;
|
let that = this;
|
||||||
that.$refs.tables.refresh();
|
that.$refs.tables.refresh();
|
||||||
that.$refs.flowEditor && that.$refs.flowEditor.reload();
|
that.getDEGdatas();
|
||||||
},
|
|
||||||
//画布内发生增删改 -> 同步刷新右侧表格
|
|
||||||
handleEditorChanged() {
|
|
||||||
this.$refs.tables && this.$refs.tables.refresh();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
</el-main>
|
</el-main>
|
||||||
<ScBind v-model="showBindBlt" :bindBtl="bindBtl" :bindType="bindType" :bindName="bindName"
|
<ScBind v-model="showBindBlt" :bindBtl="bindBtl" :bindType="bindType" :bindName="bindName"
|
||||||
:bindEmployee="bindEmployee" @success="showBindBltSuccess" @closed="showBindBltClose"></ScBind>
|
:bindEmployee="bindEmployee" @success="showBindBltSuccess" @closed="showBindBltClose"></ScBind>
|
||||||
<el-dialog append-to-body title="提前离厂" v-model="leaveVisible" width="30%">
|
<el-dialog title="提前离厂" v-model="leaveVisible" width="30%">
|
||||||
<el-form ref="dialogForm" label-width="80px">
|
<el-form ref="dialogForm" label-width="80px">
|
||||||
<el-form-item label="离厂原因">
|
<el-form-item label="离厂原因">
|
||||||
<el-input v-model="reason" type="text" clearable></el-input>
|
<el-input v-model="reason" type="text" clearable></el-input>
|
||||||
|
|
@ -112,7 +112,7 @@
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- 人员添加编辑 -->
|
<!-- 人员添加编辑 -->
|
||||||
<el-dialog append-to-body v-model="workerVisible" :title="workDialogTitle">
|
<el-dialog v-model="workerVisible" :title="workDialogTitle">
|
||||||
<el-form ref="workerForm" :model="formworker" label-width="120px">
|
<el-form ref="workerForm" :model="formworker" label-width="120px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :md="24" :sm="12" :xs="24">
|
<el-col :md="24" :sm="12" :xs="24">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
title="打印物料标签"
|
title="打印物料标签"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@
|
||||||
@success="handleSaveSuccess"
|
@success="handleSaveSuccess"
|
||||||
@closed="dialog.save = false"
|
@closed="dialog.save = false"
|
||||||
></save-dialog>
|
></save-dialog>
|
||||||
<el-dialog append-to-body v-model="printVisible" width="1200px">
|
<el-dialog v-model="printVisible" width="1200px">
|
||||||
<print :baseData="form" :tableData="tableData" :type="form.type" mtype="20" @closePrint="printVisible=false"/>
|
<print :baseData="form" :tableData="tableData" :type="form.type" mtype="20" @closePrint="printVisible=false"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<print-dialog
|
<print-dialog
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
:title="titleMap[form.type]"
|
:title="titleMap[form.type]"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:size="1000"
|
:size="1000"
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,7 @@
|
||||||
</scTable>
|
</scTable>
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 输入物料编辑 -->
|
<!-- 输入物料编辑 -->
|
||||||
<el-dialog append-to-body v-model="saveInDialog" title="编辑">
|
<el-dialog v-model="saveInDialog" title="编辑">
|
||||||
<el-form
|
<el-form
|
||||||
:model="saveInForm"
|
:model="saveInForm"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
|
|
@ -444,7 +444,7 @@
|
||||||
@closed="dialog.edit = false"
|
@closed="dialog.edit = false"
|
||||||
>
|
>
|
||||||
</edit-dialog>
|
</edit-dialog>
|
||||||
<el-dialog append-to-body v-model="printVisible" width="1200px">
|
<el-dialog v-model="printVisible" width="1200px">
|
||||||
<print :baseData="mlogItem" :tableData="tableData" :tableData2="tableData2" type="102" @closePrint="printVisible=false"/>
|
<print :baseData="mlogItem" :tableData="tableData" :tableData2="tableData2" type="102" @closePrint="printVisible=false"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
:title="titleMap[mode]"
|
:title="titleMap[mode]"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
style="width: 80%;"
|
style="width: 80%;"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
title="过程检验"
|
title="过程检验"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:size="1000"
|
:size="1000"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<!-- 新增mlogbIn -->
|
<!-- 新增mlogbIn -->
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
title="添加日志详情"
|
title="添加日志详情"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:size="1000"
|
:size="1000"
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@
|
||||||
</sc-form-table>
|
</sc-form-table>
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
title="检验"
|
title="检验"
|
||||||
v-model="checkVisible"
|
v-model="checkVisible"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
|
|
@ -378,7 +378,7 @@
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
title="批量检验"
|
title="批量检验"
|
||||||
v-model="setVisible"
|
v-model="setVisible"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@
|
||||||
<el-button type="primary" @click="mtaskb_submit">提交</el-button>
|
<el-button type="primary" @click="mtaskb_submit">提交</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog append-to-body v-model="printVisible" width="1200px">
|
<el-dialog v-model="printVisible" width="1200px">
|
||||||
<print :baseData="mtaskObj" type="mtask" @closePrint="printVisible=false"/>
|
<print :baseData="mtaskObj" type="mtask" @closePrint="printVisible=false"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
:title="titleMap[mode]"
|
:title="titleMap[mode]"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@
|
||||||
@closed="dialog.check = false"
|
@closed="dialog.check = false"
|
||||||
>
|
>
|
||||||
</check-dialog>
|
</check-dialog>
|
||||||
<el-dialog append-to-body v-model="printVisible" width="1200px">
|
<el-dialog v-model="printVisible" width="1200px">
|
||||||
<print :baseData="fmlogItem" :tableData="tableData" type="101" @closePrint="printVisible=false"/>
|
<print :baseData="fmlogItem" :tableData="tableData" type="101" @closePrint="printVisible=false"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,7 @@
|
||||||
@success="handleSaveSuccess"
|
@success="handleSaveSuccess"
|
||||||
@closed="dialog.save = false"
|
@closed="dialog.save = false"
|
||||||
></save-dialog>
|
></save-dialog>
|
||||||
<el-dialog append-to-body v-model="printVisible" width="1200px">
|
<el-dialog v-model="printVisible" width="1200px">
|
||||||
<print :baseData="form" :tableData="tableData" :type="form.type" mtype="20" @closePrint="printVisible=false"/>
|
<print :baseData="form" :tableData="tableData" :type="form.type" mtype="20" @closePrint="printVisible=false"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<print-dialog
|
<print-dialog
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
:title="titleMap[form.type]"
|
:title="titleMap[form.type]"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
style="width: 80%;"
|
style="width: 80%;"
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@
|
||||||
</scTable>
|
</scTable>
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 输入物料编辑 -->
|
<!-- 输入物料编辑 -->
|
||||||
<el-dialog append-to-body v-model="saveInDialog" title="编辑">
|
<el-dialog v-model="saveInDialog" title="编辑">
|
||||||
<el-form
|
<el-form
|
||||||
:model="saveInForm"
|
:model="saveInForm"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
|
|
@ -359,7 +359,7 @@
|
||||||
@closed="dialog.edit = false"
|
@closed="dialog.edit = false"
|
||||||
>
|
>
|
||||||
</edit-dialog>
|
</edit-dialog>
|
||||||
<el-dialog append-to-body v-model="printVisible" width="1200px">
|
<el-dialog v-model="printVisible" width="1200px">
|
||||||
<print :baseData="mlogItem" :tableData="tableData" :tableData2="tableData2" type="102" @closePrint="printVisible=false"/>
|
<print :baseData="mlogItem" :tableData="tableData" :tableData2="tableData2" type="102" @closePrint="printVisible=false"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<print-dialog
|
<print-dialog
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
:title="titleMap[mode]"
|
:title="titleMap[mode]"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
title="过程检验"
|
title="过程检验"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
style="width: 80%;"
|
style="width: 80%;"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog append-to-body
|
<el-dialog
|
||||||
:title="titleMap[mode]"
|
:title="titleMap[mode]"
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
style="width: 80%;"
|
style="width: 80%;"
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@
|
||||||
<el-button type="primary" @click="mtaskb_submit">提交</el-button>
|
<el-button type="primary" @click="mtaskb_submit">提交</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog append-to-body v-model="printVisible" width="1200px">
|
<el-dialog v-model="printVisible" width="1200px">
|
||||||
<print :baseData="mtaskObj" type="mtask" @closePrint="printVisible=false"/>
|
<print :baseData="mtaskObj" type="mtask" @closePrint="printVisible=false"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue