<template>
|
<div>
|
<el-dialog
|
v-model="isShow"
|
:title="isEdit ? '编辑工艺路线' : '创建工艺路线'"
|
width="900px"
|
@close="closeModal"
|
>
|
<el-form label-width="140px" :model="formState" label-position="top" ref="formRef">
|
<el-form-item label="工艺路线编号">
|
<el-input v-model="formState.processRouteCode" placeholder="请输入,忽略将自动生成" clearable />
|
</el-form-item>
|
|
<el-form-item
|
label="工艺路线名称"
|
prop="processRouteName"
|
:rules="[
|
{
|
required: true,
|
message: '请输入工艺路线名称',
|
trigger: 'blur',
|
}
|
]"
|
>
|
<el-input v-model="formState.processRouteName" placeholder="请填写" clearable />
|
</el-form-item>
|
|
<div class="section-title">工序列表</div>
|
|
<div class="table-actions">
|
<el-button type="primary" link @click="addRow">
|
<el-icon><Plus /></el-icon> 添加一行
|
</el-button>
|
</div>
|
|
<el-table
|
ref="tableRef"
|
:data="formState.processRouteItems"
|
border
|
style="width: 100%"
|
class="process-table"
|
row-key="tempId"
|
>
|
<el-table-column label="拖拽" width="60" align="center">
|
<template #default>
|
<el-icon class="drag-handle"><Rank /></el-icon>
|
</template>
|
</el-table-column>
|
<el-table-column label="工序" prop="processId" min-width="200">
|
<template #header>
|
<span class="required">工序</span>
|
</template>
|
<template #default="scope">
|
<el-select
|
v-model="scope.row.processId"
|
placeholder="请选择"
|
clearable
|
style="width: 100%"
|
>
|
<el-option
|
v-for="item in processOptions"
|
:key="item.id"
|
:label="item.name"
|
:value="item.id"
|
/>
|
</el-select>
|
</template>
|
</el-table-column>
|
<el-table-column label="是否质检" prop="isQuality" width="100" align="center">
|
<template #default="scope">
|
<el-switch v-model="scope.row.isQuality" />
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="80" align="center" fixed="right">
|
<template #default="scope">
|
<el-button type="danger" link @click="deleteRow(scope.$index)">
|
<el-icon><Delete /></el-icon>
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<el-empty v-if="formState.processRouteItems.length === 0" description="暂无数据" />
|
</el-form>
|
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" @click="handleSubmit">确认</el-button>
|
<el-button @click="closeModal">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import {ref, computed, getCurrentInstance, onMounted, nextTick, watch, onUnmounted} from "vue";
|
import {add, update} from "@/api/productionManagement/processRoute.js";
|
import {findProcessRouteItemList} from "@/api/productionManagement/processRouteItem.js";
|
import {processList} from "@/api/productionManagement/productionProcess.js";
|
import {Plus, Delete, Rank} from '@element-plus/icons-vue';
|
import Sortable from 'sortablejs';
|
|
const props = defineProps({
|
visible: {
|
type: Boolean,
|
required: true,
|
}
|
});
|
|
const emit = defineEmits(['update:visible', 'completed']);
|
|
const isEdit = computed(() => {
|
return formState.value && formState.value.id;
|
});
|
|
const isShow = computed({
|
get() {
|
return props.visible;
|
},
|
set(val) {
|
emit('update:visible', val);
|
},
|
});
|
|
const processOptions = ref([]);
|
|
let { proxy } = getCurrentInstance();
|
|
const tableRef = ref(null);
|
let sortable = null;
|
|
let tempIdCounter = 0;
|
|
const formState = ref({
|
id: undefined,
|
processRouteCode: '',
|
processRouteName: '',
|
processRouteItems: [],
|
});
|
|
const initSortable = () => {
|
if (sortable) {
|
sortable.destroy();
|
sortable = null;
|
}
|
|
nextTick(() => {
|
if (tableRef.value) {
|
const table = tableRef.value.$el.querySelector('.el-table__body-wrapper tbody');
|
if (table) {
|
sortable = Sortable.create(table, {
|
animation: 150,
|
handle: '.drag-handle',
|
ghostClass: 'sortable-ghost',
|
onEnd: (evt) => {
|
const { oldIndex, newIndex } = evt;
|
if (oldIndex !== undefined && newIndex !== undefined && oldIndex !== newIndex) {
|
const item = formState.value.processRouteItems.splice(oldIndex, 1)[0];
|
formState.value.processRouteItems.splice(newIndex, 0, item);
|
}
|
}
|
});
|
}
|
}
|
});
|
};
|
|
const getProcessList = () => {
|
processList({}).then(res => {
|
processOptions.value = res.data || [];
|
}).catch(err => {
|
console.error("获取工序列表失败:", err);
|
});
|
};
|
|
const closeModal = () => {
|
formState.value = {
|
id: undefined,
|
processRouteCode: '',
|
processRouteName: '',
|
processRouteItems: [],
|
};
|
isShow.value = false;
|
};
|
|
const setFormData = async () => {
|
if (isEdit.value) {
|
formState.value = {
|
id: props.record.id,
|
processRouteCode: props.record.processRouteCode || '',
|
processRouteName: props.record.processRouteName || '',
|
processRouteItems: (props.record.processRouteItems || []).map((item, index) => ({
|
tempId: item.id || `temp_${tempIdCounter++}`,
|
processId: item.processId,
|
id: item.id,
|
isQuality: item.isQuality !== undefined ? item.isQuality : false,
|
dragSort: index + 1,
|
})),
|
};
|
} else {
|
formState.value = {
|
id: undefined,
|
processRouteCode: '',
|
processRouteName: '',
|
processRouteItems: [],
|
};
|
}
|
}
|
|
const addRow = () => {
|
formState.value.processRouteItems.push({
|
tempId: `temp_${tempIdCounter++}`,
|
processId: undefined,
|
isQuality: false,
|
});
|
nextTick(() => {
|
initSortable();
|
});
|
};
|
|
const deleteRow = (index) => {
|
formState.value.processRouteItems.splice(index, 1);
|
nextTick(() => {
|
initSortable();
|
});
|
};
|
|
const handleSubmit = () => {
|
proxy.$refs["formRef"].validate(valid => {
|
if (valid) {
|
if (formState.value.processRouteItems.length === 0) {
|
proxy.$modal.msgError("请至少添加一个工序");
|
return;
|
}
|
|
for (let i = 0; i < formState.value.processRouteItems.length; i++) {
|
const row = formState.value.processRouteItems[i];
|
if (!row.processId) {
|
proxy.$modal.msgError(`第${i + 1}行:请选择工序`);
|
return;
|
}
|
}
|
|
const submitData = {
|
id: formState.value.id,
|
processRouteCode: formState.value.processRouteCode,
|
processRouteName: formState.value.processRouteName,
|
processRouteItems: formState.value.processRouteItems.map((item, index) => ({
|
id: item.id,
|
routeId: formState.value.id,
|
processId: item.processId,
|
isQuality: item.isQuality,
|
dragSort: index + 1,
|
})),
|
};
|
|
const apiCall = isEdit.value ? update(submitData) : add(submitData);
|
|
apiCall.then(res => {
|
isShow.value = false;
|
emit('completed');
|
proxy.$modal.msgSuccess(isEdit.value ? "编辑成功" : "新增成功");
|
});
|
}
|
});
|
};
|
|
// 监听 visible 变化
|
watch(() => props.visible, (visible) => {
|
if (visible) {
|
nextTick(() => {
|
initSortable();
|
});
|
}
|
});
|
|
const setData = async (row) => {
|
if (row) {
|
formState.value = {
|
id: row.id,
|
processRouteCode: row.processRouteCode || '',
|
processRouteName: row.processRouteName || '',
|
processRouteItems: [],
|
};
|
|
const res = await findProcessRouteItemList({ routeId: row.id });
|
if (res.data && Array.isArray(res.data)) {
|
formState.value.processRouteItems = res.data.map((item, index) => ({
|
tempId: item.id || `temp_${tempIdCounter++}`,
|
processId: item.processId,
|
id: item.id,
|
isQuality: item.isQuality !== undefined ? item.isQuality : false,
|
dragSort: index + 1,
|
}));
|
}
|
|
nextTick(() => {
|
initSortable();
|
});
|
} else {
|
formState.value = {
|
id: undefined,
|
processRouteCode: '',
|
processRouteName: '',
|
processRouteItems: [],
|
};
|
|
nextTick(() => {
|
initSortable();
|
});
|
}
|
};
|
|
onMounted(() => {
|
getProcessList();
|
});
|
|
onUnmounted(() => {
|
if (sortable) {
|
sortable.destroy();
|
sortable = null;
|
}
|
});
|
|
defineExpose({
|
closeModal,
|
handleSubmit,
|
isShow,
|
setData,
|
});
|
</script>
|
|
<style scoped>
|
.section-title {
|
font-size: 14px;
|
font-weight: bold;
|
margin: 20px 0 10px 0;
|
color: #333;
|
}
|
|
.table-actions {
|
display: flex;
|
gap: 16px;
|
margin-bottom: 10px;
|
}
|
|
.process-table {
|
margin-bottom: 20px;
|
}
|
|
.required::before {
|
content: '*';
|
color: #f56c6c;
|
margin-right: 4px;
|
}
|
|
:deep(.el-dialog__body) {
|
padding-top: 10px;
|
}
|
|
.sortable-ghost {
|
opacity: 0.4;
|
background-color: #f5f7fa;
|
}
|
|
.drag-handle {
|
cursor: move;
|
font-size: 18px;
|
color: #909399;
|
}
|
|
.drag-handle:hover {
|
color: #409eff;
|
}
|
</style>
|