<template>
|
<div class="app-container">
|
<div class="route-header">
|
<div class="add-route-btn"
|
@click="handleAddRoute">
|
<el-icon>
|
<Plus />
|
</el-icon>
|
<span>新增工艺路线</span>
|
</div>
|
</div>
|
<div class="route-card-list">
|
<div v-for="route in routeList"
|
:key="route.id"
|
class="route-card">
|
<div class="card-header">
|
<div class="route-info">
|
<span class="route-name"><el-icon style="margin-right: 8px;line-height: 30px;">
|
<ScaleToOriginal />
|
</el-icon>{{ route.routeName }}<el-tag style="margin-left: 8px"
|
:type="route.status == 1 ? 'warning' : 'success'">{{ route.status == 1 ? '草稿' : '批准' }}</el-tag></span>
|
<span class="route-code">{{ route.routeCode }}</span>
|
</div>
|
<div class="route-actions">
|
<el-button v-if="route.status === '1'"
|
link
|
type="success"
|
@click="handleApproveRoute(route)">
|
<el-icon>
|
<Check />
|
</el-icon>
|
批准
|
</el-button>
|
<el-button v-if="route.status === '2'"
|
link
|
type="warning"
|
@click="handleRevokeApproveRoute(route)">
|
<el-icon>
|
<Close />
|
</el-icon>
|
撤销批准
|
</el-button>
|
<el-button link
|
type="primary"
|
@click="handleEditRoute(route)">
|
<el-icon>
|
<Edit />
|
</el-icon>
|
编辑
|
</el-button>
|
<el-button link
|
type="danger"
|
@click="handleDeleteRoute(route)">
|
<el-icon>
|
<Delete />
|
</el-icon>
|
删除
|
</el-button>
|
</div>
|
</div>
|
<div class="card-body">
|
<div class="route-desc">{{ route.routeDesc || '暂无描述' }}</div>
|
<el-button type="primary"
|
link
|
@click="toggleExpand(route)">
|
{{ route.expanded ? '收起' : '展开工序路线' }}
|
<el-icon class="expand-icon">
|
<component :is="route.expanded ? 'ArrowUp' : 'ArrowDown'" />
|
</el-icon>
|
</el-button>
|
</div>
|
<div v-if="route.expanded"
|
class="process-route">
|
<div class="process-flow">
|
<div v-for="(process, index) in route.processList"
|
:key="process.id"
|
class="process-flow-item"
|
draggable="true"
|
@dragstart="handleDragStart($event, index, route.id)"
|
@dragover="handleDragOver($event)"
|
@drop="handleDrop($event, index, route.id)"
|
@dragend="handleDragEnd">
|
<div class="process-node"
|
:class="{ expanded: process.expanded }">
|
<div class="process-node-header">
|
<div class="process-number">{{ index + 1 }}</div>
|
<div class="process-actions">
|
<el-button link
|
type="danger"
|
@click="handleDeleteProcess(route.id, process)">
|
<el-icon>
|
<Delete />
|
</el-icon>
|
</el-button>
|
</div>
|
</div>
|
<div class="process-node-body">
|
<div class="process-code">{{ process.processCode }}</div>
|
<div class="process-name">{{ process.processName }}</div>
|
<div class="process-desc">{{ process.processDesc || '暂无描述' }}</div>
|
</div>
|
<div class="process-node-footer">
|
<!-- <el-tag size="small"
|
:type="process.status === '1' ? 'success' : 'info'">
|
{{ process.status === '1' ? '启用' : '停用' }}
|
</el-tag> -->
|
<el-button type="primary"
|
link
|
size="small"
|
@click="toggleProcessParams(process)">
|
{{ process.expanded ? '收起参数' : '展开参数' }}
|
({{ process.paramList?.length || 0 }})
|
</el-button>
|
</div>
|
<div v-if="process.expanded"
|
class="process-params-section">
|
<div class="params-header">
|
<span>参数列表</span>
|
<el-button type="primary"
|
link
|
size="small"
|
@click="handleAddParam(route.id, process)">
|
<el-icon>
|
<Plus />
|
</el-icon>新增
|
</el-button>
|
</div>
|
<div class="params-list">
|
<div v-for="param in process.paramList"
|
:key="param.id"
|
class="param-item">
|
<div class="param-info">
|
<span class="param-code">{{ param.parameterCode }}</span>
|
<span class="param-name">{{ param.parameterName }}</span>
|
<!-- <el-tag size="small"
|
style="margin-right: 20px;"
|
:type="getParamTypeTag(param.parameterType)">
|
{{ param.parameterType }}
|
</el-tag> -->
|
<span class="param-value">标准值:{{ param.standardValue }} {{ param.unit }}</span>
|
</div>
|
<div class="param-actions">
|
<el-button link
|
type="primary"
|
size="small"
|
@click="handleEditParam(route.id, process, param)">
|
编辑
|
</el-button>
|
<el-button link
|
type="danger"
|
size="small"
|
@click="handleDeleteParam(route.id, process, param)">
|
删除
|
</el-button>
|
</div>
|
</div>
|
<el-empty v-if="!process.paramList || process.paramList.length === 0"
|
description="暂无参数"
|
:image-size="50" />
|
</div>
|
</div>
|
</div>
|
<div v-if="index < route.processList.length - 1"
|
class="flow-arrow">
|
<el-icon>
|
<Right />
|
</el-icon>
|
</div>
|
</div>
|
<div class="add-process-node"
|
@click="handleSelectProcess(route, index)">
|
<el-icon>
|
<Plus />
|
</el-icon>
|
<span>新增工序</span>
|
</div>
|
</div>
|
<el-empty v-if="!route.processList || route.processList.length === 0"
|
description="暂无工序"
|
:image-size="80" />
|
</div>
|
</div>
|
</div>
|
<!-- 工艺路线新增/编辑对话框 -->
|
<el-dialog v-model="routeDialogVisible"
|
:title="isRouteEdit ? '编辑工艺路线' : '新增工艺路线'"
|
width="500px">
|
<el-form :model="routeForm"
|
:rules="routeRules"
|
ref="routeFormRef"
|
label-width="120px">
|
<el-form-item label="路线编码"
|
prop="routeCode">
|
<el-input v-model="routeForm.routeCode"
|
placeholder="请输入路线编码" />
|
</el-form-item>
|
<el-form-item label="路线名称"
|
prop="routeName">
|
<el-input v-model="routeForm.routeName"
|
placeholder="请输入路线名称" />
|
</el-form-item>
|
<el-form-item label="路线描述"
|
prop="routeDesc">
|
<el-input v-model="routeForm.routeDesc"
|
type="textarea"
|
:rows="3"
|
placeholder="请输入路线描述" />
|
</el-form-item>
|
<!-- <el-form-item label="状态"
|
prop="status">
|
<el-radio-group v-model="routeForm.status">
|
<el-radio label="1">启用</el-radio>
|
<el-radio label="0">停用</el-radio>
|
</el-radio-group>
|
</el-form-item> -->
|
</el-form>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="routeDialogVisible = false">取消</el-button>
|
<el-button type="primary"
|
@click="handleRouteSubmit">确定</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<!-- 工序新增/编辑对话框 -->
|
<el-dialog v-model="processDialogVisible"
|
:title="isProcessEdit ? '编辑工序' : '新增工序'"
|
width="500px">
|
<el-form :model="processForm"
|
:rules="processRules"
|
ref="processFormRef"
|
label-width="120px">
|
<el-form-item label="工序编码"
|
prop="processCode">
|
<el-input v-model="processForm.processCode"
|
placeholder="请输入工序编码" />
|
</el-form-item>
|
<el-form-item label="工序名称"
|
prop="processName">
|
<el-input v-model="processForm.processName"
|
placeholder="请输入工序名称" />
|
</el-form-item>
|
<el-form-item label="工序描述"
|
prop="processDesc">
|
<el-input v-model="processForm.processDesc"
|
type="textarea"
|
:rows="3"
|
placeholder="请输入工序描述" />
|
</el-form-item>
|
<el-form-item label="状态"
|
prop="status">
|
<el-radio-group v-model="processForm.status">
|
<el-radio label="1">启用</el-radio>
|
<el-radio label="0">停用</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="processDialogVisible = false">取消</el-button>
|
<el-button type="primary"
|
@click="handleProcessSubmit">确定</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<!-- 选择工序对话框 -->
|
<el-dialog v-model="selectProcessDialogVisible"
|
title="选择工序"
|
width="1000px">
|
<div class="process-select-container">
|
<!-- 左侧工序列表 -->
|
<div class="process-list-area">
|
<div class="area-title">可选工序</div>
|
<div class="search-box">
|
<el-input v-model="processSearchKeyword"
|
placeholder="请输入工序名称搜索"
|
clearable
|
size="small"
|
@input="handleProcessSearch">
|
<template #prefix>
|
<el-icon>
|
<Search />
|
</el-icon>
|
</template>
|
</el-input>
|
</div>
|
<el-table :data="filteredProcessList"
|
height="360"
|
border
|
highlight-current-row
|
@current-change="handleProcessSelect">
|
<el-table-column prop="processCode"
|
label="工序编号"
|
width="100" />
|
<el-table-column prop="processName"
|
label="工序名称" />
|
<el-table-column prop="processDesc"
|
label="工序描述" />
|
<el-table-column prop="status"
|
label="状态"
|
width="80">
|
<template #default="scope">
|
<el-tag size="small"
|
:type="scope.row.status === '1' ? 'success' : 'info'">
|
{{ scope.row.status === '1' ? '启用' : '停用' }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
<!-- 右侧工序详情 -->
|
<div class="process-detail-area">
|
<div class="area-title">工序详情</div>
|
<el-form v-if="selectedProcessItem"
|
:model="selectedProcessItem"
|
label-width="100px"
|
class="process-detail-form">
|
<el-form-item label="工序编号">
|
<span class="detail-text">{{ selectedProcessItem.processCode }}</span>
|
</el-form-item>
|
<el-form-item label="工序名称">
|
<span class="detail-text">{{ selectedProcessItem.processName }}</span>
|
</el-form-item>
|
<el-form-item label="工序描述">
|
<span class="detail-text">{{ selectedProcessItem.processDesc || '-' }}</span>
|
</el-form-item>
|
<el-form-item label="状态">
|
<el-tag size="small"
|
:type="selectedProcessItem.status === '1' ? 'success' : 'info'">
|
{{ selectedProcessItem.status === '1' ? '启用' : '停用' }}
|
</el-tag>
|
</el-form-item>
|
<el-form-item label="参数数量">
|
<span class="detail-text">{{ selectedProcessItem.paramCount || 0 }}个</span>
|
</el-form-item>
|
</el-form>
|
<el-empty v-else
|
description="请从左侧选择工序" />
|
</div>
|
</div>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="selectProcessDialogVisible = false">取消</el-button>
|
<el-button type="primary"
|
:disabled="!selectedProcessItem"
|
@click="handleProcessSelectSubmit">确定</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<!-- 参数新增/编辑对话框 -->
|
<el-dialog v-model="paramDialogVisible"
|
:title="isParamEdit ? '编辑参数' : '新增参数'"
|
width="500px">
|
<el-form :model="paramForm"
|
:rules="paramRules"
|
ref="paramFormRef"
|
label-width="120px">
|
<el-form-item label="参数编号"
|
prop="parameterCode">
|
<el-input v-model="paramForm.parameterCode"
|
placeholder="请输入参数编号" />
|
</el-form-item>
|
<el-form-item label="参数名称"
|
prop="parameterName">
|
<el-input v-model="paramForm.parameterName"
|
placeholder="请输入参数名称" />
|
</el-form-item>
|
<el-form-item label="参数模式"
|
prop="parameterType2">
|
<el-select v-model="paramForm.parameterType2"
|
placeholder="请选择参数模式">
|
<el-option label="单值"
|
value="1" />
|
<el-option label="区间"
|
value="2" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="参数类型"
|
prop="parameterType">
|
<el-select v-model="paramForm.parameterType"
|
@change="handleParamTypeChange"
|
placeholder="请选择参数类型">
|
<el-option label="数值格式"
|
value="数值格式" />
|
<el-option label="文本格式"
|
value="文本格式" />
|
<el-option label="下拉选项"
|
value="下拉选项" />
|
<el-option label="时间格式"
|
value="时间格式" />
|
</el-select>
|
</el-form-item>
|
<el-form-item v-if="paramForm.parameterType === '下拉选项'"
|
label="数据字典"
|
prop="parameterFormat">
|
<el-select v-model="paramForm.parameterFormat"
|
placeholder="请选择数据字典">
|
<el-option v-for="item in dictTypes"
|
:key="item.dictType"
|
:label="item.dictName"
|
:value="item.dictType" />
|
</el-select>
|
</el-form-item>
|
<el-form-item v-else-if="paramForm.parameterType === '时间格式'"
|
label="时间格式"
|
prop="parameterFormat">
|
<el-select v-model="paramForm.parameterFormat"
|
placeholder="请选择时间格式">
|
<el-option label="YYYY-MM-DD HH:mm:ss"
|
value="YYYY-MM-DD HH:mm:ss" />
|
<el-option label="YYYY-MM-DD"
|
value="YYYY-MM-DD" />
|
</el-select>
|
</el-form-item>
|
<el-form-item v-else
|
label="参数格式"
|
prop="parameterFormat">
|
<el-input v-model="paramForm.parameterFormat"
|
placeholder="请输入参数格式" />
|
</el-form-item>
|
<el-form-item label="标准值"
|
prop="standardValue">
|
<el-input v-model="paramForm.standardValue"
|
placeholder="请输入标准值" />
|
</el-form-item>
|
<el-form-item label="单位"
|
prop="unit">
|
<el-input v-model="paramForm.unit"
|
placeholder="请输入单位" />
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="paramDialogVisible = false">取消</el-button>
|
<el-button type="primary"
|
@click="handleParamSubmit">确定</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive } from "vue";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
import {
|
Plus,
|
Edit,
|
Delete,
|
ArrowUp,
|
ArrowDown,
|
Right,
|
Search,
|
Check,
|
Close,
|
} from "@element-plus/icons-vue";
|
import { listType } from "@/api/system/dict/type";
|
|
// 工艺路线列表
|
const routeList = ref([]);
|
const dictTypes = ref([]);
|
|
// 工艺路线对话框
|
const routeDialogVisible = ref(false);
|
const isRouteEdit = ref(false);
|
const routeFormRef = ref(null);
|
const routeForm = reactive({
|
id: null,
|
routeCode: "",
|
routeName: "",
|
routeDesc: "",
|
status: "1",
|
});
|
const routeRules = {
|
routeCode: [{ required: true, message: "请输入路线编码", trigger: "blur" }],
|
routeName: [{ required: true, message: "请输入路线名称", trigger: "blur" }],
|
};
|
|
// 工序对话框
|
const processDialogVisible = ref(false);
|
const isProcessEdit = ref(false);
|
const processFormRef = ref(null);
|
const currentRouteId = ref(null);
|
const processForm = reactive({
|
id: null,
|
processCode: "",
|
processName: "",
|
processDesc: "",
|
status: "1",
|
});
|
const processRules = {
|
processCode: [{ required: true, message: "请输入工序编码", trigger: "blur" }],
|
processName: [{ required: true, message: "请输入工序名称", trigger: "blur" }],
|
};
|
|
// 选择工序对话框
|
const selectProcessDialogVisible = ref(false);
|
const availableProcessList = ref([]);
|
const filteredProcessList = ref([]);
|
const selectedProcessItem = ref(null);
|
const processSearchKeyword = ref("");
|
const currentRouteIndex = ref(null);
|
|
// 参数对话框
|
const paramDialogVisible = ref(false);
|
const isParamEdit = ref(false);
|
const paramFormRef = ref(null);
|
const currentProcessId = ref(null);
|
const paramForm = reactive({
|
id: null,
|
parameterCode: "",
|
parameterName: "",
|
parameterType2: "1",
|
parameterType: "",
|
parameterFormat: "",
|
standardValue: "",
|
unit: "",
|
});
|
const paramRules = {
|
parameterCode: [
|
{ required: true, message: "请输入参数编号", trigger: "blur" },
|
],
|
parameterName: [
|
{ required: true, message: "请输入参数名称", trigger: "blur" },
|
],
|
parameterType: [
|
{ required: true, message: "请选择参数类型", trigger: "change" },
|
],
|
};
|
|
// 拖拽相关
|
const draggedItem = ref(null);
|
const draggedRouteId = ref(null);
|
|
// 获取工艺路线列表
|
const getRouteList = () => {
|
routeList.value = [
|
{
|
id: 1,
|
routeCode: "ROUTE001",
|
routeName: "标准砌块生产线",
|
routeDesc: "标准砌块生产流程",
|
status: "1",
|
expanded: false,
|
processList: [
|
{
|
id: 1,
|
processCode: "PROC001",
|
processName: "原料配比",
|
processDesc: "原材料配比工序",
|
status: "1",
|
expanded: false,
|
paramList: [
|
{
|
id: 1,
|
parameterCode: "P001",
|
parameterName: "水泥比例",
|
parameterType2: "1",
|
parameterType: "数值格式",
|
parameterFormat: "",
|
standardValue: "30",
|
unit: "%",
|
},
|
{
|
id: 2,
|
parameterCode: "P002",
|
parameterName: "砂比例",
|
parameterType2: "1",
|
parameterType: "数值格式",
|
parameterFormat: "",
|
standardValue: "60",
|
unit: "%",
|
},
|
],
|
},
|
{
|
id: 2,
|
processCode: "PROC002",
|
processName: "搅拌混合",
|
processDesc: "搅拌混合工序",
|
status: "1",
|
expanded: false,
|
paramList: [
|
{
|
id: 3,
|
parameterCode: "P003",
|
parameterName: "搅拌时间",
|
parameterType2: "1",
|
parameterType: "数值格式",
|
parameterFormat: "",
|
standardValue: "5",
|
unit: "分钟",
|
},
|
],
|
},
|
{
|
id: 3,
|
processCode: "PROC003",
|
processName: "浇筑成型",
|
processDesc: "浇筑成型工序",
|
status: "1",
|
expanded: false,
|
paramList: [],
|
},
|
],
|
},
|
{
|
id: 2,
|
routeCode: "ROUTE002",
|
routeName: "板材生产线",
|
routeDesc: "板材生产流程",
|
status: "1",
|
expanded: false,
|
processList: [
|
{
|
id: 4,
|
processCode: "PROC004",
|
processName: "切割加工",
|
processDesc: "切割加工工序",
|
status: "1",
|
expanded: false,
|
paramList: [
|
{
|
id: 4,
|
parameterCode: "P004",
|
parameterName: "切割尺寸",
|
parameterType2: "1",
|
parameterType: "文本格式",
|
parameterFormat: "",
|
standardValue: "600x200x100",
|
unit: "mm",
|
},
|
],
|
},
|
],
|
},
|
];
|
};
|
|
// 展开/收起工艺路线
|
const toggleExpand = route => {
|
route.expanded = !route.expanded;
|
};
|
|
// 展开/收起工序参数
|
const toggleProcessParams = process => {
|
process.expanded = !process.expanded;
|
};
|
|
// 工艺路线操作
|
const handleAddRoute = () => {
|
isRouteEdit.value = false;
|
routeForm.id = null;
|
routeForm.routeCode = "";
|
routeForm.routeName = "";
|
routeForm.routeDesc = "";
|
routeForm.status = "1";
|
routeDialogVisible.value = true;
|
};
|
|
const handleEditRoute = route => {
|
isRouteEdit.value = true;
|
routeForm.id = route.id;
|
routeForm.routeCode = route.routeCode;
|
routeForm.routeName = route.routeName;
|
routeForm.routeDesc = route.routeDesc;
|
routeForm.status = route.status;
|
routeDialogVisible.value = true;
|
};
|
|
const handleDeleteRoute = route => {
|
ElMessageBox.confirm("确定要删除该工艺路线吗?", "提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning",
|
}).then(() => {
|
ElMessage.success("删除成功");
|
getRouteList();
|
});
|
};
|
|
const handleRouteSubmit = () => {
|
routeFormRef.value.validate(valid => {
|
if (valid) {
|
ElMessage.success(isRouteEdit.value ? "编辑成功" : "新增成功");
|
routeDialogVisible.value = false;
|
getRouteList();
|
}
|
});
|
};
|
|
const handleApproveRoute = route => {
|
ElMessageBox.confirm("确定要批准该工艺路线吗?", "提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "info",
|
}).then(() => {
|
route.status = "2";
|
ElMessage.success("批准成功");
|
});
|
};
|
|
const handleRevokeApproveRoute = route => {
|
ElMessageBox.confirm("确定要撤销批准该工艺路线吗?", "提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning",
|
}).then(() => {
|
route.status = "1";
|
ElMessage.success("撤销批准成功");
|
});
|
};
|
|
// 工序操作
|
const handleSelectProcess = (route, index) => {
|
currentRouteId.value = route.id;
|
currentRouteIndex.value = index;
|
// 获取可选工序列表(假数据)
|
availableProcessList.value = [
|
{
|
id: 1,
|
processCode: "PROC001",
|
processName: "原料配比",
|
processDesc: "原材料配比工序",
|
status: "1",
|
paramCount: 3,
|
},
|
{
|
id: 2,
|
processCode: "PROC002",
|
processName: "搅拌混合",
|
processDesc: "搅拌混合工序",
|
status: "1",
|
paramCount: 2,
|
},
|
{
|
id: 3,
|
processCode: "PROC003",
|
processName: "浇筑成型",
|
processDesc: "浇筑成型工序",
|
status: "1",
|
paramCount: 4,
|
},
|
{
|
id: 4,
|
processCode: "PROC004",
|
processName: "蒸压养护",
|
processDesc: "蒸压养护工序",
|
status: "0",
|
paramCount: 2,
|
},
|
{
|
id: 5,
|
processCode: "PROC005",
|
processName: "切割加工",
|
processDesc: "切割加工工序",
|
status: "1",
|
paramCount: 3,
|
},
|
];
|
filteredProcessList.value = availableProcessList.value;
|
processSearchKeyword.value = "";
|
selectedProcessItem.value = null;
|
selectProcessDialogVisible.value = true;
|
};
|
|
const handleEditProcess = (routeId, process) => {
|
currentRouteId.value = routeId;
|
isProcessEdit.value = true;
|
processForm.id = process.id;
|
processForm.processCode = process.processCode;
|
processForm.processName = process.processName;
|
processForm.processDesc = process.processDesc;
|
processForm.status = process.status;
|
processDialogVisible.value = true;
|
};
|
|
const handleDeleteProcess = (routeId, process) => {
|
ElMessageBox.confirm("确定要删除该工序吗?", "提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning",
|
}).then(() => {
|
ElMessage.success("删除成功");
|
getRouteList();
|
});
|
};
|
|
const handleProcessSubmit = () => {
|
processFormRef.value.validate(valid => {
|
if (valid) {
|
ElMessage.success(isProcessEdit.value ? "编辑成功" : "新增成功");
|
processDialogVisible.value = false;
|
getRouteList();
|
}
|
});
|
};
|
|
// 选择工序相关方法
|
const handleProcessSearch = () => {
|
const keyword = processSearchKeyword.value.trim().toLowerCase();
|
if (!keyword) {
|
filteredProcessList.value = availableProcessList.value;
|
} else {
|
filteredProcessList.value = availableProcessList.value.filter(item =>
|
item.processName.toLowerCase().includes(keyword)
|
);
|
}
|
};
|
|
const handleProcessSelect = row => {
|
selectedProcessItem.value = row;
|
};
|
|
const handleProcessSelectSubmit = () => {
|
if (!selectedProcessItem.value) {
|
ElMessage.warning("请先选择一个工序");
|
return;
|
}
|
|
// 检查工序是否已存在
|
const route = routeList.value[currentRouteIndex.value];
|
const exists = route.processList.some(
|
p => p.id === selectedProcessItem.value.id
|
);
|
if (exists) {
|
ElMessage.warning("该工序已存在于工艺路线中");
|
return;
|
}
|
|
// 添加工序到工艺路线
|
const newProcess = {
|
id: Date.now(),
|
processCode: selectedProcessItem.value.processCode,
|
processName: selectedProcessItem.value.processName,
|
processDesc: selectedProcessItem.value.processDesc,
|
status: selectedProcessItem.value.status,
|
paramList: [],
|
expanded: false,
|
};
|
|
route.processList.push(newProcess);
|
ElMessage.success("添加工序成功");
|
selectProcessDialogVisible.value = false;
|
};
|
|
// 参数操作
|
const handleAddParam = (routeId, process) => {
|
currentRouteId.value = routeId;
|
currentProcessId.value = process.id;
|
isParamEdit.value = false;
|
paramForm.id = null;
|
paramForm.parameterCode = "";
|
paramForm.parameterName = "";
|
paramForm.parameterType2 = "1";
|
paramForm.parameterType = "";
|
paramForm.parameterFormat = "";
|
paramForm.standardValue = "";
|
paramForm.unit = "";
|
paramDialogVisible.value = true;
|
};
|
|
const handleEditParam = (routeId, process, param) => {
|
currentRouteId.value = routeId;
|
currentProcessId.value = process.id;
|
isParamEdit.value = true;
|
paramForm.id = param.id;
|
paramForm.parameterCode = param.parameterCode;
|
paramForm.parameterName = param.parameterName;
|
paramForm.parameterType2 = param.parameterType2 || "1";
|
paramForm.parameterType = param.parameterType;
|
paramForm.parameterFormat = param.parameterFormat;
|
paramForm.standardValue = param.standardValue;
|
paramForm.unit = param.unit;
|
paramDialogVisible.value = true;
|
};
|
|
const handleDeleteParam = (routeId, process, param) => {
|
ElMessageBox.confirm("确定要删除该参数吗?", "提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning",
|
}).then(() => {
|
ElMessage.success("删除成功");
|
getRouteList();
|
});
|
};
|
|
const handleParamSubmit = () => {
|
paramFormRef.value.validate(valid => {
|
if (valid) {
|
ElMessage.success(isParamEdit.value ? "编辑成功" : "新增成功");
|
paramDialogVisible.value = false;
|
getRouteList();
|
}
|
});
|
};
|
|
const handleParamTypeChange = () => {
|
if (paramForm.parameterType === "数值格式") {
|
paramForm.parameterFormat = "#.0000";
|
} else if (paramForm.parameterType === "时间格式") {
|
paramForm.parameterFormat = "YYYY-MM-DD HH:mm:ss";
|
} else {
|
paramForm.parameterFormat = "";
|
}
|
};
|
|
const getParamTypeTag = type => {
|
const typeMap = {
|
数值格式: "primary",
|
文本格式: "info",
|
下拉选项: "warning",
|
时间格式: "success",
|
};
|
return typeMap[type] || "default";
|
};
|
|
// 拖拽排序
|
const handleDragStart = (event, index, routeId) => {
|
draggedItem.value = index;
|
draggedRouteId.value = routeId;
|
event.dataTransfer.effectAllowed = "move";
|
};
|
|
const handleDragOver = event => {
|
event.preventDefault();
|
event.dataTransfer.dropEffect = "move";
|
};
|
|
const handleDrop = (event, dropIndex, routeId) => {
|
event.preventDefault();
|
if (draggedItem.value === null || draggedItem.value === dropIndex) return;
|
|
const route = routeList.value.find(r => r.id === routeId);
|
if (route && route.processList) {
|
const draggedProcess = route.processList[draggedItem.value];
|
route.processList.splice(draggedItem.value, 1);
|
route.processList.splice(dropIndex, 0, draggedProcess);
|
ElMessage.success("排序成功");
|
}
|
};
|
|
const handleDragEnd = () => {
|
draggedItem.value = null;
|
draggedRouteId.value = null;
|
};
|
|
// 获取数据字典
|
const getDictTypes = () => {
|
listType({ pageNum: 1, pageSize: 1000 }).then(res => {
|
dictTypes.value = res.rows || [];
|
});
|
};
|
|
getRouteList();
|
getDictTypes();
|
</script>
|
|
<style scoped lang="scss">
|
.app-container {
|
padding: 20px;
|
background-color: #f0f2f5;
|
min-height: calc(100vh - 84px);
|
}
|
|
.route-header {
|
margin-bottom: 20px;
|
|
.add-route-btn {
|
width: 100%;
|
display: inline-flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
min-width: 120px;
|
height: 100px;
|
border: 2px dashed #dcdfe6;
|
border-radius: 12px;
|
background: #fafafa;
|
cursor: pointer;
|
transition: all 0.3s ease;
|
color: #909399;
|
padding: 0 20px;
|
|
.el-icon {
|
font-size: 24px;
|
margin-bottom: 8px;
|
}
|
|
span {
|
font-size: 13px;
|
}
|
|
&:hover {
|
border-color: #409eff;
|
background: #ecf5ff;
|
color: #409eff;
|
}
|
}
|
}
|
|
.route-card-list {
|
display: flex;
|
flex-direction: column;
|
gap: 20px;
|
}
|
|
.route-card {
|
background: #fff;
|
border-radius: 8px;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
overflow: hidden;
|
|
.card-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 20px 40px;
|
border-bottom: 1px solid #ebeef5;
|
background: #f8f9fa;
|
|
.route-info {
|
display: flex;
|
// flex-direction: column;
|
// justify-content: center;
|
// items-align: center;
|
gap: 4px;
|
|
.route-code {
|
font-size: 12px;
|
color: #909399;
|
font-family: "Courier New", monospace;
|
line-height: 30px;
|
}
|
|
.route-name {
|
font-size: 18px;
|
font-weight: 600;
|
color: #303133;
|
display: flex;
|
align-items: center;
|
}
|
}
|
|
.route-actions {
|
display: flex;
|
gap: 8px;
|
|
// .el-button {
|
// color: #409eff;
|
// }
|
}
|
}
|
|
.card-body {
|
padding: 16px 40px;
|
|
.route-desc {
|
font-size: 14px;
|
color: #606266;
|
margin-bottom: 12px;
|
}
|
|
.expand-icon {
|
margin-left: 4px;
|
}
|
}
|
|
.process-route {
|
padding: 0 20px 20px;
|
background: #f5f7fa;
|
border-top: 1px solid #ebeef5;
|
|
.process-flow {
|
display: flex;
|
align-items: flex-start;
|
gap: 8px;
|
padding: 20px 0;
|
overflow-x: auto;
|
overflow-y: hidden;
|
|
.process-flow-item {
|
display: flex;
|
align-items: center;
|
gap: 8px;
|
|
.process-node {
|
background: #fff;
|
border-radius: 12px;
|
padding: 16px;
|
border: 2px solid #ebeef5;
|
cursor: move;
|
transition: all 0.3s ease;
|
// min-width: 180px;
|
// max-width: 220px;
|
width: 300px;
|
|
&.expanded {
|
width: 400px;
|
}
|
|
&:hover {
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
transform: translateY(-2px);
|
border-color: #409eff;
|
}
|
|
&:active {
|
cursor: grabbing;
|
}
|
|
.process-node-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 12px;
|
|
.process-number {
|
width: 28px;
|
height: 28px;
|
border-radius: 50%;
|
background: #409eff;
|
color: #ffffff;
|
font-size: 12px;
|
font-weight: 600;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
|
.process-actions {
|
display: flex;
|
gap: 4px;
|
}
|
}
|
|
.process-node-body {
|
text-align: center;
|
margin-bottom: 12px;
|
|
.process-code {
|
font-size: 11px;
|
color: #909399;
|
font-family: "Courier New", monospace;
|
margin-bottom: 4px;
|
}
|
|
.process-name {
|
font-size: 15px;
|
font-weight: 600;
|
color: #303133;
|
margin-bottom: 6px;
|
}
|
|
.process-desc {
|
font-size: 12px;
|
color: #606266;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
display: -webkit-box;
|
-webkit-line-clamp: 2;
|
-webkit-box-orient: vertical;
|
}
|
}
|
|
.process-node-footer {
|
display: flex;
|
justify-content: flex-end;
|
align-items: center;
|
padding-top: 10px;
|
border-top: 1px solid #ebeef5;
|
}
|
|
.process-params-section {
|
margin-top: 12px;
|
padding-top: 12px;
|
border-top: 1px solid #ebeef5;
|
|
.params-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 8px;
|
font-size: 13px;
|
font-weight: 600;
|
color: #303133;
|
}
|
|
.params-list {
|
display: flex;
|
flex-direction: column;
|
gap: 6px;
|
max-height: 200px;
|
overflow-y: auto;
|
|
.param-item {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 6px 8px;
|
background: #fafafa;
|
border-radius: 4px;
|
border-left: 2px solid #409eff;
|
font-size: 12px;
|
|
.param-info {
|
display: flex;
|
flex-direction: row;
|
align-items: center;
|
gap: 6px;
|
flex: 1;
|
min-width: 0;
|
|
.param-code {
|
font-size: 11px;
|
color: #e6a23c;
|
font-family: "Courier New", monospace;
|
margin-right: 20px;
|
}
|
|
.param-name {
|
font-size: 12px;
|
color: #303133;
|
font-weight: 500;
|
margin-right: 20px;
|
}
|
|
.param-value {
|
font-size: 11px;
|
color: #606266;
|
}
|
}
|
|
.param-actions {
|
display: flex;
|
gap: 4px;
|
flex-shrink: 0;
|
}
|
}
|
}
|
}
|
}
|
|
.flow-arrow {
|
display: flex;
|
align-items: center;
|
color: #c0c4cc;
|
font-size: 24px;
|
padding: 0 4px;
|
|
.el-icon {
|
font-size: 20px;
|
}
|
}
|
}
|
|
.add-process-node {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
min-width: 100px;
|
height: 175px;
|
border: 2px dashed #dcdfe6;
|
border-radius: 12px;
|
background: #fafafa;
|
cursor: pointer;
|
transition: all 0.3s ease;
|
color: #909399;
|
// margin-left: 10px;
|
|
.el-icon {
|
font-size: 24px;
|
margin-bottom: 8px;
|
}
|
|
span {
|
font-size: 13px;
|
}
|
|
&:hover {
|
border-color: #409eff;
|
background: #ecf5ff;
|
color: #409eff;
|
}
|
}
|
}
|
}
|
}
|
|
// 拖拽时的样式
|
.process-flow-item.dragging {
|
opacity: 0.5;
|
transform: scale(0.98);
|
}
|
|
// 选择工序对话框样式
|
.process-select-container {
|
display: flex;
|
gap: 20px;
|
height: 450px;
|
|
.process-list-area {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
|
.area-title {
|
font-size: 14px;
|
font-weight: 600;
|
color: #303133;
|
margin-bottom: 12px;
|
padding-bottom: 8px;
|
border-bottom: 1px solid #ebeef5;
|
}
|
|
.search-box {
|
margin-bottom: 12px;
|
|
.el-input {
|
width: 100%;
|
}
|
}
|
}
|
|
.process-detail-area {
|
width: 380px;
|
display: flex;
|
flex-direction: column;
|
background: #f5f7fa;
|
border-radius: 8px;
|
padding: 16px;
|
|
.area-title {
|
font-size: 14px;
|
font-weight: 600;
|
color: #303133;
|
margin-bottom: 16px;
|
padding-bottom: 8px;
|
border-bottom: 1px solid #ebeef5;
|
}
|
|
.process-detail-form {
|
.el-form-item {
|
margin-bottom: 12px;
|
|
.el-form-item__label {
|
color: #606266;
|
font-weight: 500;
|
}
|
}
|
|
.detail-text {
|
color: #303133;
|
font-weight: 500;
|
}
|
}
|
}
|
}
|
</style>
|