| | |
| | | @close="closeModal" |
| | | > |
| | | <div class="operate-button"> |
| | | <el-button |
| | | type="primary" |
| | | @click="isShowProductSelectDialog = true" |
| | | class="mb5" |
| | | style="margin-bottom: 10px;" |
| | | > |
| | | 选择产品 |
| | | </el-button> |
| | | |
| | | <span class="route-tip">后端根据BOM生成工艺路线,可在此调整工序和顺序</span> |
| | | <el-switch |
| | | v-model="isTable" |
| | | inline-prompt |
| | |
| | | <el-select |
| | | v-model="scope.row[item.prop]" |
| | | style="width: 100%;" |
| | | @change="value => handleProcessChange(scope.row, value)" |
| | | @mousedown.stop |
| | | > |
| | | <el-option |
| | |
| | | <div class="step-content"> |
| | | <div class="step-number">{{ index + 1 }}</div> |
| | | <el-card |
| | | :header="item.productName" |
| | | :header="getProcessName(item)" |
| | | class="step-card" |
| | | style="cursor: move;" |
| | | > |
| | | <div class="step-card-content"> |
| | | <p>{{ item.model }}</p> |
| | | <p>{{ item.unit }}</p> |
| | | <p>{{ item.productName || '-' }}</p> |
| | | <p>{{ item.model || '-' }}</p> |
| | | <el-select |
| | | v-model="item.processId" |
| | | style="width: 100%;" |
| | | @change="value => handleProcessChange(item, value)" |
| | | @mousedown.stop |
| | | > |
| | | <el-option |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <ProductSelectDialog |
| | | v-model="isShowProductSelectDialog" |
| | | @confirm="handelSelectProducts" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, getCurrentInstance, onMounted, onUnmounted, nextTick } from "vue"; |
| | | import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; |
| | | import { findProcessRouteItemList, addOrUpdateProcessRouteItem } from "@/api/productionManagement/processRouteItem.js"; |
| | | import { findProcessRouteItemList, saveProcessRouteItems } from "@/api/productionManagement/processRouteItem.js"; |
| | | import { processList } from "@/api/productionManagement/productionProcess.js"; |
| | | import Sortable from 'sortablejs'; |
| | | |
| | |
| | | |
| | | const processOptions = ref([]); |
| | | const tableLoading = ref(false); |
| | | const isShowProductSelectDialog = ref(false); |
| | | const routeItems = ref([]); |
| | | let tableSortable = null; |
| | | let stepsSortable = null; |
| | |
| | | const tableColumn = ref([ |
| | | { label: "产品名称", prop: "productName", width: 180 }, |
| | | { label: "规格名称", prop: "model", width: 150 }, |
| | | { label: "单位", prop: "unit", width: 80 }, |
| | | { label: "工序名称", prop: "processId", width: 180 }, |
| | | { label: "工序名称", prop: "processId", width: 220 }, |
| | | { |
| | | dataType: "action", |
| | | label: "操作", |
| | |
| | | } |
| | | ]); |
| | | |
| | | const getProcessName = item => { |
| | | if (item.processName || item.operationName) { |
| | | return item.processName || item.operationName; |
| | | } |
| | | const process = processOptions.value.find(process => process.id === item.processId); |
| | | return process?.name || "请选择工序"; |
| | | }; |
| | | |
| | | const handleProcessChange = (row, value) => { |
| | | const process = processOptions.value.find(process => process.id === value); |
| | | row.processName = process?.name || ""; |
| | | row.operationName = row.processName; |
| | | row.operationId = value; |
| | | }; |
| | | |
| | | const removeItem = (index) => { |
| | | routeItems.value.splice(index, 1); |
| | | nextTick(() => initSortable()); |
| | |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | const handelSelectProducts = (products) => { |
| | | destroySortable(); |
| | | |
| | | const newData = products.map(({ id, ...product }) => ({ |
| | | ...product, |
| | | productModelId: id, |
| | | routeId: props.record.id, |
| | | id: `${Date.now()}-${Math.random().toString(36).slice(2)}`, |
| | | processId: undefined |
| | | })); |
| | | |
| | | console.log('选择产品前数组:', routeItems.value); |
| | | routeItems.value.push(...newData); |
| | | routeItems.value = [...routeItems.value]; |
| | | console.log('选择产品后数组:', routeItems.value); |
| | | |
| | | // 延迟初始化,确保DOM完全渲染 |
| | | nextTick(() => { |
| | | // 强制重新渲染组件 |
| | | if (proxy?.$forceUpdate) { |
| | | proxy.$forceUpdate(); |
| | | } |
| | | |
| | | const temp = [...routeItems.value]; |
| | | routeItems.value = []; |
| | | nextTick(() => { |
| | | routeItems.value = temp; |
| | | initSortable(); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | const findProcessRouteItems = () => { |
| | | tableLoading.value = true; |
| | | findProcessRouteItemList({ routeId: props.record.id }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | routeItems.value = res.data.map(item => ({ |
| | | // 后端返回 technologyOperationId / technologyOperationName,页面统一用 processId / processName |
| | | routeItems.value = (res.data || []).map(item => ({ |
| | | ...item, |
| | | processId: item.processId === 0 ? undefined : item.processId |
| | | productName: item.productName || "", |
| | | model: item.model || "", |
| | | processName: item.technologyOperationName || item.processName || "", |
| | | processId: item.technologyOperationId || (item.processId === 0 ? undefined : item.processId) |
| | | })); |
| | | // 延迟初始化,确保DOM完全渲染 |
| | | nextTick(() => { |
| | |
| | | proxy?.$modal?.msgError("请为所有项目选择工序"); |
| | | return; |
| | | } |
| | | const processIds = routeItems.value.map(item => item.processId); |
| | | if (new Set(processIds).size !== processIds.length) { |
| | | proxy?.$modal?.msgError("同一道工序不能重复出现在工艺路线中"); |
| | | return; |
| | | } |
| | | |
| | | addOrUpdateProcessRouteItem({ |
| | | routeId: props.record.id, |
| | | processRouteItem: routeItems.value.map(({ id, ...item }) => item) |
| | | // 全量提交:工序顺序即当前列表顺序,未回传的工序会被后端删除 |
| | | saveProcessRouteItems({ |
| | | technologyRoutingId: props.record.id, |
| | | operationList: routeItems.value.map((item, index) => ({ |
| | | id: item.id, |
| | | technologyOperationId: item.processId, |
| | | dragSort: index + 1 |
| | | })) |
| | | }) |
| | | .then(res => { |
| | | isShow.value = false; |
| | |
| | | const moveItem = routeItems.value.splice(evt.oldIndex, 1)[0]; |
| | | routeItems.value.splice(evt.newIndex, 0, moveItem); |
| | | routeItems.value = [...routeItems.value]; |
| | | console.log('排序后数组:', routeItems.value); |
| | | } |
| | | }); |
| | | } else { |
| | |
| | | routeItems.value = [...routeItems.value]; |
| | | } |
| | | }); |
| | | |
| | | // 调试:打印容器和实例,确认绑定成功 |
| | | console.log('步骤条拖拽容器:', stepsList); |
| | | console.log('Sortable实例:', stepsSortable); |
| | | } |
| | | }; |
| | | |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .route-tip { |
| | | color: #606266; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | /* 修改:自定义步骤条容器样式 */ |