| src/api/salesManagement/salesLedger.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/salesLedger/components/ProcessFlowConfigSelectDialog.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/salesLedger/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/salesManagement/salesLedger.js
@@ -151,4 +151,21 @@ url: `/salesLedgerProductProcess/delete/${id}`, method: "delete", }); } // 销售台账-绑定工艺路线 export function saleProcessBind(data) { return request({ url: "/sales/ledger/saleProcessBind", method: "post", data, }); } // 销售台账-查询订单已绑定工艺路线 export function getSaleProcessBindInfo(salesLedgerId) { return request({ url: `/sales/ledger/salesProcess/${salesLedgerId}`, method: "get", }); } src/views/salesManagement/salesLedger/components/ProcessFlowConfigSelectDialog.vue
@@ -7,33 +7,37 @@ @close="handleClose" > <el-row :gutter="20"> <el-col :span="10"> <el-col :span="24"> <div style="font-weight: 600; margin-bottom: 8px;">配置</div> <div style="font-size: 12px; margin-bottom: 8px;"> <span v-if="boundRouteName" style="color: #67c23a;">已绑定:{{ boundRouteName }}</span> <span v-else style="color: #e6a23c;">未绑定</span> </div> <el-select v-model="selectedConfigId" v-model="selectedRouteId" filterable clearable placeholder="请选择工艺路线配置" placeholder="请选择工艺路线" style="width: 100%;" @change="handleConfigChange" @change="handleRouteChange" > <el-option v-for="cfg in configList" :key="cfg.configId" :label="cfg.configName" :value="cfg.configId" v-for="cfg in routeList" :key="cfg.routeId" :label="cfg.processRouteName" :value="cfg.routeId" /> </el-select> <el-divider style="margin: 16px 0;" /> <div style="font-weight: 600; margin-bottom: 8px;">步骤预览</div> <div style="font-size: 12px; color: #909399; margin-bottom: 6px;"> <div style="font-size: 12px; color: #909399; margin-bottom: 10px;"> 根据所选配置展示流程图 </div> </el-col> <el-col :span="14"> <el-col :span="24"> <div class="process-diagram"> <div v-if="steps.length === 0" class="process-diagram-empty">暂无步骤</div> <div @@ -48,7 +52,7 @@ <div v-if="idx < steps.length - 1" class="process-diagram-arrow">→</div> </div> </div> <div v-if="selectedConfigId === null" style="margin-top: 10px; font-size: 12px; color: #909399;"> <div v-if="selectedRouteId === null" style="margin-top: 10px; font-size: 12px; color: #909399;"> 请先选择一条已维护好的工艺路线 </div> </el-col> @@ -67,13 +71,16 @@ <script setup> import { computed, getCurrentInstance, ref, watch } from "vue"; import { salesProcessFlowConfigList, salesProcessFlowConfigGetById } from "@/api/salesManagement/salesProcessFlowConfig.js"; import { salesProcessFlowConfigList, salesProcessFlowConfigItemList } from "@/api/salesManagement/salesProcessFlowConfig.js"; const emit = defineEmits(["update:visible", "confirm"]); const props = defineProps({ visible: { type: Boolean, default: false }, defaultConfigId: { type: [Number, String, null], default: null }, // 打开弹窗时的回显:若业务已绑定工艺路线则传入该 routeId;否则默认展示列表第一条 defaultRouteId: { type: [Number, String, null], default: null }, // 页面提示:订单已绑定的工艺路线名称 boundRouteName: { type: String, default: "" }, }); const { proxy } = getCurrentInstance(); @@ -87,8 +94,8 @@ }, }); const configList = ref([]); const selectedConfigId = ref(null); const routeList = ref([]); const selectedRouteId = ref(null); const steps = ref([]); const saving = ref(false); @@ -102,26 +109,30 @@ })); }; const fetchConfigList = async () => { const res = await salesProcessFlowConfigList(); const list = res?.data ?? res?.records ?? res ?? []; configList.value = Array.isArray(list) ? list : []; const normalizeRouteList = (list) => { if (!Array.isArray(list)) return []; return list.map((r) => ({ routeId: r.routeId ?? r.id ?? null, processRouteName: r.processRouteName ?? r.routeName ?? r.name ?? "", isDefault: Boolean(r.isDefault), })); }; const fetchConfigDetail = async (id) => { if (!id) { const fetchRouteList = async () => { // 选择弹窗:尽量一次性拉全,避免分页影响选择体验 const res = await salesProcessFlowConfigList({ current: 1, size: 1000 }); const records = res?.records ?? res?.data?.records ?? res?.data ?? res ?? []; routeList.value = normalizeRouteList(records).filter((r) => r.routeId !== null && r.routeId !== undefined && r.routeId !== ""); }; const fetchRouteSteps = async (routeId) => { if (!routeId) { steps.value = []; return; } const res = await salesProcessFlowConfigGetById(id); const detail = res?.data ?? res ?? {}; steps.value = normalizeStepsFromApi(detail?.steps ?? []); }; const initDefault = async () => { await fetchConfigList(); selectedConfigId.value = props.defaultConfigId ?? null; await fetchConfigDetail(selectedConfigId.value); const res = await salesProcessFlowConfigItemList(routeId); const raw = res?.data ?? res ?? []; steps.value = normalizeStepsFromApi(raw); }; watch( @@ -129,7 +140,18 @@ async (v) => { if (v) { try { await initDefault(); await fetchRouteList(); // 回显绑定: // 1. 若传入 defaultRouteId,则优先使用它 // 2. 否则优先选中标记为默认(isDefault=true)的工艺路线 // 3. 若都没有,则回退为第一条 const first = routeList.value?.[0] ?? null; const defaultRoute = routeList.value.find((r) => r.isDefault) ?? first; const desired = props.defaultRouteId ?? (defaultRoute ? defaultRoute.routeId : null); selectedRouteId.value = desired ?? null; await fetchRouteSteps(selectedRouteId.value); } catch { proxy?.$modal?.msgError?.("获取工艺路线配置失败"); } @@ -137,8 +159,8 @@ } ); const handleConfigChange = async () => { await fetchConfigDetail(selectedConfigId.value); const handleRouteChange = async () => { await fetchRouteSteps(selectedRouteId.value); }; const handleClose = () => { @@ -148,14 +170,13 @@ const confirmSelect = async () => { if (saving.value) return; if (selectedConfigId.value === null || selectedConfigId.value === undefined || selectedConfigId.value === "") { proxy?.$modal?.msgWarning?.("请选择工艺路线配置"); if (selectedRouteId.value === null || selectedRouteId.value === undefined || selectedRouteId.value === "") { proxy?.$modal?.msgWarning?.("请选择工艺路线"); return; } saving.value = true; try { emit("confirm", selectedConfigId.value); handleClose(); emit("confirm", selectedRouteId.value); } catch (e) { proxy?.$modal?.msgError?.("确认失败,请稍后重试"); } finally { src/views/salesManagement/salesLedger/index.vue
@@ -31,6 +31,8 @@ </div> <ProcessFlowConfigSelectDialog v-model:visible="processFlowSelectDialogVisible" :default-route-id="processFlowSelectDefaultRouteId" :bound-route-name="processFlowSelectBoundRouteName" @confirm="handleProcessFlowSelectConfirm" /> <div> @@ -992,12 +994,14 @@ delLedgerFile, getProductInventory, salesLedgerProductProcessList, saleProcessBind, getSaleProcessBindInfo, } from "@/api/salesManagement/salesLedger.js"; import { modelList, productTreeList } from "@/api/basicData/product.js"; import useFormData from "@/hooks/useFormData.js"; import dayjs from "dayjs"; import { getCurrentDate } from "@/utils/index.js"; import { salesLedgerProductSetProcessFlowConfig } from "@/api/salesManagement/salesProcessFlowConfig.js"; // import { salesLedgerProductSetProcessFlowConfig } from "@/api/salesManagement/salesProcessFlowConfig.js"; const userStore = useUserStore(); const { proxy } = getCurrentInstance(); @@ -1020,6 +1024,9 @@ // 工艺路线配置选择弹窗(绑定到台账产品) const processFlowSelectDialogVisible = ref(false); const processFlowSelectLedgerRow = ref(null); const processFlowSelectDefaultRouteId = ref(null); const processFlowSelectBoundRouteId = ref(null); const processFlowSelectBoundRouteName = ref(""); // 用户信息表单弹框数据 const operationType = ref(""); @@ -1420,52 +1427,79 @@ }; // 打开“工艺路线配置”选择弹窗(必须显式选择) const openProcessFlowSelect = (ledgerRow) => { const openProcessFlowSelect = async (ledgerRow) => { if (!ledgerRow) return; if (!ledgerRow.isEdit) return; processFlowSelectLedgerRow.value = ledgerRow; processFlowSelectDefaultRouteId.value = null; processFlowSelectBoundRouteId.value = null; processFlowSelectBoundRouteName.value = ""; try { const res = await getSaleProcessBindInfo(ledgerRow.id); const info = res?.data ?? res ?? {}; const boundId = info?.processRouteId ?? info?.routeId ?? info?.id ?? null; const boundName = info?.processRouteName ?? info?.routeName ?? info?.name ?? ""; processFlowSelectBoundRouteId.value = boundId; processFlowSelectBoundRouteName.value = boundName; processFlowSelectDefaultRouteId.value = boundId; } catch (e) { // 查询失败时按未绑定处理,不阻塞弹窗 processFlowSelectBoundRouteId.value = null; processFlowSelectBoundRouteName.value = ""; processFlowSelectDefaultRouteId.value = null; } processFlowSelectDialogVisible.value = true; }; // 将配置应用到台账下的所有未发货产品 const handleProcessFlowSelectConfirm = async (configId) => { // 绑定工艺路线到当前台账数据 const handleProcessFlowSelectConfirm = async (routeId) => { const ledgerRow = processFlowSelectLedgerRow.value; if (!ledgerRow?.id) return; const finalConfigId = configId ?? null; if (!finalConfigId) return; const finalRouteId = routeId ?? null; if (!finalRouteId) return; proxy?.$modal?.loading?.("正在应用工艺路线配置,请稍候..."); try { const res = await productList({ salesLedgerId: ledgerRow.id, type: 1 }); const products = res?.data ?? res?.records ?? res ?? []; if (!Array.isArray(products) || products.length === 0) { proxy?.$modal?.msgWarning?.("该台账下没有产品数据"); const oldRouteId = processFlowSelectBoundRouteId.value; if (oldRouteId !== null && oldRouteId !== undefined && oldRouteId !== "" && String(oldRouteId) !== String(finalRouteId)) { try { await ElMessageBox.confirm( "该订单已绑定工艺路线,是否确定更换?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", } ); } catch { return; } } for (const product of products) { // 已发货/审核通过不可编辑,跳过 if (isProductShipped(product)) continue; await salesLedgerProductSetProcessFlowConfig({ salesLedgerProductId: product.id, processFlowConfigId: finalConfigId, }); } proxy?.$modal?.loading?.("正在绑定工艺路线,请稍候..."); try { await saleProcessBind({ salesLedgerId: ledgerRow.id, processRouteId: finalRouteId, }); proxy?.$modal?.msgSuccess?.("工艺路线配置应用成功"); // 若当前行已展开,刷新其子产品列表 if (expandedRowKeys.value.includes(ledgerRow.id)) { const childRes = await productList({ salesLedgerId: ledgerRow.id, type: 1 }); const children = childRes?.data ?? childRes?.records ?? childRes ?? []; const index = tableData.value.findIndex((item) => item.id === ledgerRow.id); if (index > -1) { tableData.value[index].children = children; } } proxy?.$modal?.msgSuccess?.("工艺路线绑定成功"); processFlowSelectDialogVisible.value = false; // 绑定后刷新列表,确保操作列再次点击能回显绑定 await getList(); } catch (e) { proxy?.$modal?.msgError?.("应用失败,请稍后重试"); proxy?.$modal?.msgError?.("绑定失败,请稍后重试"); } finally { proxy?.$modal?.closeLoading?.(); }