From 4a811fb2cd4ee4e1cbfe284bfd1fe3a7d16204ce Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期四, 02 四月 2026 17:35:48 +0800
Subject: [PATCH] fix: 终检表单优化检验用粉剂/液情况字段
---
src/views/salesManagement/salesLedger/index.vue | 627 +++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 474 insertions(+), 153 deletions(-)
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index d9a180f..671bb86 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -33,11 +33,11 @@
<el-button type="primary" plain @click="handleImport">瀵煎叆</el-button>
<el-button @click="handleOut">瀵煎嚭</el-button>
<el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
- <el-button type="primary" plain @click="handlePrint">鎵撳嵃</el-button>
+ <!-- <el-button type="primary" plain @click="handlePrint">鎵撳嵃</el-button> -->
</div>
</div>
<el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
- :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary style="width: 100%"
+ :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" :row-class-name="tableRowClassName" show-summary style="width: 100%"
:summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 18.5em)">
<el-table-column align="center" type="selection" width="55" fixed="left"/>
<el-table-column type="expand" width="60" fixed="left">
@@ -46,6 +46,8 @@
<el-table-column align="center" label="搴忓彿" type="index"/>
<el-table-column label="浜у搧澶х被" prop="productCategory" />
<el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
+ <el-table-column label="鎵瑰彿" prop="batchNo" />
+ <el-table-column label="UID鐮�" prop="uidNo" />
<el-table-column label="鍗曚綅" prop="unit" />
<el-table-column label="浜у搧鐘舵��"
width="100px"
@@ -110,18 +112,21 @@
<el-table-column label="閿�鍞悎鍚屽彿" prop="salesContractNo" width="180" show-overflow-tooltip />
<el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" width="300" show-overflow-tooltip />
<el-table-column label="涓氬姟鍛�" prop="salesman" width="100" show-overflow-tooltip />
- <el-table-column label="椤圭洰鍚嶇О" prop="projectName" width="180" show-overflow-tooltip />
- <el-table-column label="浠樻鏂瑰紡" prop="paymentMethod" show-overflow-tooltip />
+ <!-- <el-table-column label="椤圭洰鍚嶇О" prop="projectName" width="180" show-overflow-tooltip />
+ <el-table-column label="浠樻鏂瑰紡" prop="paymentMethod" show-overflow-tooltip /> -->
<el-table-column label="鍚堝悓閲戦(鍏�)" prop="contractAmount" width="220" show-overflow-tooltip
:formatter="formattedNumber" />
<el-table-column label="褰曞叆浜�" prop="entryPersonName" width="100" show-overflow-tooltip />
<el-table-column label="褰曞叆鏃ユ湡" prop="entryDate" width="120" show-overflow-tooltip />
<el-table-column label="绛捐鏃ユ湡" prop="executionDate" width="120" show-overflow-tooltip />
+ <el-table-column label="浜や粯鏃ユ湡" prop="deliveryDate" width="120" show-overflow-tooltip />
+ <el-table-column label="澶囨敞" prop="remarks" width="200" show-overflow-tooltip />
<el-table-column fixed="right" label="鎿嶄綔" min-width="100" align="center">
<template #default="scope">
- <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">缂栬緫</el-button>
+ <el-button link type="primary" size="small" @click="openForm('edit', scope.row)" :disabled="!scope.row.isEdit">缂栬緫</el-button>
<!-- <el-button link type="primary" size="small" @click="openForm('view', scope.row)">璇︽儏</el-button>-->
<el-button link type="primary" size="small" @click="downLoadFile(scope.row)">闄勪欢</el-button>
+ <el-button link type="primary" size="small" @click="exportSaleOutbound(scope.row)">鎵撳嵃閿�鍞嚭搴撳崟</el-button>
<!-- <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">鍙戣揣</el-button>-->
</template>
</el-table-column>
@@ -132,6 +137,14 @@
<FormDialog v-model="dialogFormVisible" :title="operationType === 'add' ? '鏂板閿�鍞彴璐﹂〉闈�' : '缂栬緫閿�鍞彴璐﹂〉闈�'" :width="'70%'"
:operation-type="operationType" @close="closeDia" @confirm="submitForm" @cancel="closeDia">
<el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
+ <!-- 鎶ヤ环鍗曞鍏ュ叆鍙o細鏀惧湪琛ㄥ崟椤堕儴锛岄�夋嫨鍚庡弽鏄惧鎴�/涓氬姟鍛樼瓑 -->
+ <el-row v-if="operationType === 'add'" style="margin-bottom: 10px;">
+ <el-col :span="24" style="text-align: right;">
+ <el-button type="primary" plain @click="openQuotationDialog">
+ 浠庨攢鍞姤浠峰鍏�
+ </el-button>
+ </el-col>
+ </el-row>
<el-row :gutter="30">
<el-col :span="12">
<el-form-item label="閿�鍞悎鍚屽彿锛�" prop="salesContractNo">
@@ -160,24 +173,12 @@
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="椤圭洰鍚嶇О锛�" prop="projectName">
- <el-input v-model="form.projectName" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
<el-form-item label="绛捐鏃ユ湡锛�" prop="executionDate">
<el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD"
format="YYYY-MM-DD" type="date" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'" />
</el-form-item>
</el-col>
- <el-col :span="12">
- <el-form-item label="浠樻鏂瑰紡">
- <el-input v-model="form.paymentMethod" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'" />
- </el-form-item>
- </el-col>
- </el-row>
+ </el-row>
<el-row :gutter="30">
<el-col :span="12">
<el-form-item label="褰曞叆浜猴細" prop="entryPerson">
@@ -196,6 +197,14 @@
</el-form-item>
</el-col>
</el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="浜よ揣鏃ユ湡锛�" prop="entryDate">
+ <el-date-picker style="width: 100%" v-model="form.deliveryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
+ type="date" placeholder="璇烽�夋嫨" clearable />
+ </el-form-item>
+ </el-col>
+ </el-row>
<el-row>
<el-form-item label="浜у搧淇℃伅锛�" prop="entryDate">
<el-button v-if="operationType !== 'view'" type="primary" @click="openProductForm('add')">娣诲姞</el-button>
@@ -204,10 +213,13 @@
</el-row>
<el-table :data="productData" border @selection-change="productSelected" show-summary
:summary-method="summarizeMainTable">
- <el-table-column align="center" type="selection" width="55" v-if="operationType !== 'view'" />
+ <el-table-column align="center" type="selection" width="55" v-if="operationType !== 'view'"
+ :selectable="(row) => !isProductShipped(row)" />
<el-table-column align="center" label="搴忓彿" type="index" width="60" />
<el-table-column label="浜у搧澶х被" prop="productCategory" />
<el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
+ <el-table-column label="UID鐮�" prop="uidNo" />
+ <el-table-column label="鎵瑰彿" prop="batchNo" />
<el-table-column label="鍗曚綅" prop="unit" />
<el-table-column label="鏁伴噺" prop="quantity" />
<el-table-column label="绋庣巼(%)" prop="taxRate" />
@@ -216,20 +228,22 @@
<el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
<el-table-column fixed="right" label="鎿嶄綔" min-width="60" align="center" v-if="operationType !== 'view'">
<template #default="scope">
- <el-button link type="primary" size="small" @click="openProductForm('edit', scope.row,scope.$index)">缂栬緫</el-button>
+ <el-button link type="primary" size="small"
+ :disabled="isProductShipped(scope.row)"
+ @click="openProductForm('edit', scope.row,scope.$index)">缂栬緫</el-button>
</template>
</el-table-column>
</el-table>
<el-row :gutter="30">
<el-col :span="24">
- <el-form-item label="澶囨敞路锛�" prop="remark">
- <el-input v-model="form.remark" placeholder="璇疯緭鍏�" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" />
+ <el-form-item label="澶囨敞锛�" prop="remarks">
+ <el-input v-model="form.remarks" placeholder="璇疯緭鍏�" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="30">
<el-col :span="24">
- <el-form-item label="闄勪欢鏉愭枡锛�" prop="remark">
+ <el-form-item label="闄勪欢鏉愭枡锛�" prop="salesLedgerFiles">
<el-upload v-model:file-list="fileList" :action="upload.url" multiple ref="fileUpload" auto-upload
:headers="upload.headers" :before-upload="handleBeforeUpload" :on-error="handleUploadError"
:on-success="handleUploadSuccess" :on-remove="handleRemove">
@@ -285,7 +299,7 @@
<el-table-column prop="customer" label="瀹㈡埛鍚嶇О" min-width="220" show-overflow-tooltip />
<el-table-column prop="salesperson" label="涓氬姟鍛�" width="120" show-overflow-tooltip />
<el-table-column prop="quotationDate" label="鎶ヤ环鏃ユ湡" width="140" />
- <el-table-column prop="status" label="瀹℃壒鐘舵��" width="120" align="center" />
+ <!-- <el-table-column prop="status" label="瀹℃壒鐘舵��" width="120" align="center" /> -->
<el-table-column prop="totalAmount" label="鎶ヤ环閲戦(鍏�)" width="160" align="right">
<template #default="scope">
{{ Number(scope.row.totalAmount ?? 0).toFixed(2) }}
@@ -297,6 +311,15 @@
</template>
</el-table-column>
</el-table>
+
+ <pagination
+ v-show="quotationPage.total > 0"
+ :total="quotationPage.total"
+ layout="total, sizes, prev, pager, next, jumper"
+ :page="quotationPage.current"
+ :limit="quotationPage.size"
+ @pagination="quotationPaginationChange"
+ />
<template #footer>
<el-button @click="quotationDialogVisible = false">鍏抽棴</el-button>
@@ -331,6 +354,39 @@
</el-form-item>
</el-col>
</el-row>
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item label="UID鐮侊細" prop="uidNo">
+ <el-input v-model="productForm.uidNo" placeholder="璇疯緭鍏�" disabled />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item label="鎵瑰彿锛�" prop="batchNo">
+ <el-select v-model="productForm.batchNo"
+ placeholder="璇烽�夋嫨"
+ clearable
+ filterable
+ @change="handleBatchNoChange">
+ <el-option v-for="item in batchNoOptions" :key="item.value" :label="item.label" :value="item.value" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item label="渚涘簲鍟嗭細" prop="customer">
+ <el-select v-model="productForm.customer"
+ placeholder="璇烽�夋嫨"
+ clearable
+ filterable
+ :disabled="!supplierOptions.length">
+ <el-option v-for="item in supplierOptions" :key="item.value" :label="item.label" :value="item.value" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
<el-row :gutter="30">
<el-col :span="12">
<el-form-item label="鍗曚綅锛�" prop="unit">
@@ -483,6 +539,7 @@
<th>浜у搧鍚嶇О</th>
<th>瑙勬牸鍨嬪彿</th>
<th>鍗曚綅</th>
+ <th>UID鐮�</th>
<th>鍗曚环</th>
<th>闆跺敭鏁伴噺</th>
<th>闆跺敭閲戦</th>
@@ -493,6 +550,7 @@
<td>{{ product.productCategory || '' }}</td>
<td>{{ product.specificationModel || '' }}</td>
<td>{{ product.unit || '' }}</td>
+ <td>{{ product.uidNo || '' }}</td>
<td>{{ product.taxInclusiveUnitPrice || '0' }}</td>
<td>{{ product.quantity || '0' }}</td>
<td>{{ product.taxInclusiveTotalPrice || '0' }}</td>
@@ -567,51 +625,6 @@
</el-form-item>
</el-col>
</el-row>
-
- <!-- 瀹℃壒浜洪�夋嫨锛堜豢鍗忓悓瀹℃壒閲岀殑瀹℃壒浜鸿妭鐐归�夋嫨锛� -->
- <el-row>
- <el-col :span="24">
- <el-form-item>
- <template #label>
- <span>瀹℃壒浜洪�夋嫨锛�</span>
- <el-button type="primary" @click="addApproverNode" style="margin-left: 8px;">鏂板鑺傜偣</el-button>
- </template>
- <div style="display: flex; align-items: flex-end; flex-wrap: wrap;">
- <div
- v-for="(node, index) in approverNodes"
- :key="node.id"
- style="margin-right: 20px; text-align: center; margin-bottom: 10px;"
- >
- <div>
- <span>瀹℃壒浜�</span>
- 鈫�
- </div>
- <el-select
- v-model="node.userId"
- placeholder="閫夋嫨浜哄憳"
- filterable
- style="width: 140px; margin-bottom: 8px;"
- >
- <el-option
- v-for="user in userList"
- :key="user.userId"
- :label="user.nickName"
- :value="user.userId"
- />
- </el-select>
- <div>
- <el-button
- type="danger"
- size="small"
- @click="removeApproverNode(index)"
- v-if="approverNodes.length > 1"
- >鍒犻櫎</el-button>
- </div>
- </div>
- </div>
- </el-form-item>
- </el-col>
- </el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
@@ -636,20 +649,22 @@
import FormDialog from '@/components/Dialog/FormDialog.vue';
import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
import {
- ledgerListPage,
- productList,
- customerList,
- addOrUpdateSalesLedger,
- getSalesLedgerWithProducts,
- delLedger,
- addOrUpdateSalesLedgerProduct,
- delProduct,
- delLedgerFile, getProductInventory,
+ ledgerListPage,
+ productList,
+ customerList,
+ addOrUpdateSalesLedger,
+ getSalesLedgerWithProducts,
+ delLedger,
+ addOrUpdateSalesLedgerProduct,
+ delProduct,
+ delLedgerFile, getProductInventory, saleOutboundExport,
} from "@/api/salesManagement/salesLedger.js";
-import { modelList, productTreeList } from "@/api/basicData/product.js";
+import { getStockInventoryAll } from "@/api/inventoryManagement/stockInventory.js";
import useFormData from "@/hooks/useFormData.js";
import dayjs from "dayjs";
import { getCurrentDate } from "@/utils/index.js";
+// 鐢� /stockInventory/getStockInventoryAll 椹卞姩鈥滄壒鍙�/渚涘簲鍟嗏�濊仈鍔�
+import {safeTrainingExport} from "@/api/safeProduction/safetyTrainingAssessment.js";
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
@@ -661,6 +676,7 @@
const customerOption = ref([]);
const productOptions = ref([]);
const modelOptions = ref([]);
+const supplierOptions = ref([]);
const tableLoading = ref(false);
const page = reactive({
current: 1,
@@ -686,6 +702,7 @@
customerId: "",
entryPerson: "",
entryDate: "",
+ deliveryDate: "",
maintenanceTime: "",
productData: [],
executionDate: "",
@@ -695,6 +712,7 @@
customerId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
entryPerson: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ deliveryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
},
});
@@ -707,7 +725,9 @@
const productFormData = reactive({
productForm: {
productCategory: "",
+ customer: "",
specificationModel: "",
+ uidNo: "",
unit: "",
quantity: "",
taxInclusiveUnitPrice: "",
@@ -715,10 +735,13 @@
taxInclusiveTotalPrice: "",
taxExclusiveTotalPrice: "",
invoiceType: "",
+ batchNo: "",
},
productRules: {
productCategory: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ batchNo: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ customer: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
specificationModel: [
{ required: true, message: "璇烽�夋嫨", trigger: "change" },
],
@@ -757,6 +780,12 @@
const quotationSearchForm = reactive({
quotationNo: "",
customer: "",
+});
+// 鎶ヤ环鍗曞脊妗嗗垎椤�
+const quotationPage = reactive({
+ current: 1,
+ size: 10,
+ total: 0,
});
const selectedQuotation = ref(null);
@@ -881,62 +910,203 @@
tableLoading.value = false;
});
};
-// 鑾峰彇浜у搧澶х被tree鏁版嵁
-const getProductOptions = () => {
+let stockInventoryAllTree = [];
+let batchNodeByBatchNo = new Map();
+
+const normalizeStockInventoryTree = (nodes = []) => {
+ const normalizeNodeValue = (node) => {
+ // 鍚庣鏈夋椂浼氬嚭鐜� id=null 鐨勫眰绾э紝杩欓噷缁欎竴涓彲鐢ㄧ殑 key
+ if (node?.id !== null && node?.id !== undefined) return String(node.id);
+ if (node?.nodeType === "batch") return String(node.batchNo ?? node.label ?? "");
+ if (node?.nodeType === "customer") return String(node.customer ?? node.label ?? "");
+ if (node?.nodeType === "model") return String(node.productModelId ?? node.model ?? node.label ?? "");
+ return String(node.productName ?? node.label ?? "");
+ };
+
+ const normalized = (list) =>
+ (list || []).map((n) => {
+ const value = normalizeNodeValue(n);
+ const label = n.label ?? n.productName ?? n.model ?? n.batchNo ?? n.customer ?? "";
+ return {
+ ...n,
+ value,
+ label,
+ children: normalized(n.children),
+ };
+ });
+
+ return normalized(nodes);
+};
+
+// 浠呭睍绀烘渶澶� 3 涓眰绾э細绗� 1 灞�(product) -> 绗� 2 灞�(model) -> 绗� 3 灞�(batch)锛屾洿娣辩殑鑺傜偣涓嶅睍绀�
+const filterStockInventoryFirst3Levels = (nodes = []) => {
+ const MAX_LEVEL = 3;
+
+ const cloneAndFilterByLevel = (list = [], level = 1) => {
+ return (list || [])
+ .map((n) => {
+ // 鍚庣画灞傜骇閲屽鏋滆繕鏈� customer锛岀洿鎺ュ墧闄�
+ if (n.nodeType === "customer") return null;
+
+ // 鍒拌揪灞曠ず娣卞害鍚庯紝涓嶅啀鍚戜笅鎸傚瓙鑺傜偣
+ if (level >= MAX_LEVEL) {
+ return { ...n, children: [] };
+ }
+
+ // 鐗逛緥锛歜atch 鑺傜偣鏈韩涔熶笉鍐嶅睍绀� children锛堜繚鎸佷笌鎺ュ彛鑺傜偣璇箟涓�鑷达級
+ if (n.nodeType === "batch") {
+ return { ...n, children: [] };
+ }
+
+ return { ...n, children: cloneAndFilterByLevel(n.children, level + 1) };
+ })
+ .filter(Boolean);
+ };
+
+ return cloneAndFilterByLevel(nodes, 1);
+};
+
+const findNodeObjByValue = (nodes = [], value) => {
+ for (let i = 0; i < (nodes || []).length; i++) {
+ const node = nodes[i];
+ if (String(node?.value) === String(value)) return node;
+ const children = node?.children || [];
+ if (children.length) {
+ const found = findNodeObjByValue(children, value);
+ if (found) return found;
+ }
+ }
+ return null;
+};
+
+// 鑾峰彇搴撳瓨鏍戯紙鐢ㄤ簬浜у搧澶х被/瑙勬牸鍨嬪彿鑱斿姩锛�
+const getProductOptions = async () => {
// 杩斿洖 Promise锛屼究浜庡湪缂栬緫浜у搧鏃剁瓑寰呭姞杞藉畬鎴�
- return productTreeList().then((res) => {
- productOptions.value = convertIdToValue(res);
- return productOptions.value;
- });
+ const res = await getStockInventoryAll();
+ const data = res?.data || [];
+ stockInventoryAllTree = normalizeStockInventoryTree(data);
+ productOptions.value = filterStockInventoryFirst3Levels(stockInventoryAllTree);
+ return productOptions.value;
};
const formattedNumber = (row, column, cellValue) => {
return parseFloat(cellValue).toFixed(2);
};
-// 鑾峰彇tree瀛愭暟鎹�
+// 鑾峰彇tree瀛愭暟鎹紙鍏堥�変骇鍝侊紝鍐嶉�夎鏍煎瀷鍙凤級
const getModels = (value) => {
- productForm.value.productCategory = findNodeById(productOptions.value, value);
- modelList({ id: value }).then((res) => {
- modelOptions.value = res;
- });
+ const node = findNodeObjByValue(stockInventoryAllTree, value);
+ if (!node) return;
+ if (node.nodeType !== "product") return;
+
+ // 閫夋嫨浜у搧鍚庯紝閲嶇疆涓嬫父瀛楁
+ productForm.value.productCategory = node.label;
+ modelOptions.value = (node.children || [])
+ .filter((c) => c.nodeType === "model")
+ .map((m) => ({
+ id: m.value,
+ model: m.model ?? m.label ?? "",
+ unit: m.unit ?? "",
+ uidNo: m.uidNo ?? m.identifierCode ?? "",
+ }));
+
+ productForm.value.productModelId = null;
+ productForm.value.specificationModel = "";
+ productForm.value.uidNo = "";
+ productForm.value.unit = "";
+ productForm.value.batchNo = "";
+ productForm.value.customer = "";
+ productForm.value.taxInclusiveUnitPrice = "";
+ productForm.value.taxInclusiveTotalPrice = "";
+ productForm.value.taxExclusiveTotalPrice = "";
+
+ modelOptions.value = modelOptions.value || [];
+ batchNoOptions.value = [];
+ supplierOptions.value = [];
+ batchNodeByBatchNo = new Map();
};
+
+// 瑙勬牸鍨嬪彿閫夋嫨鍚庯細鍥炴樉 UID锛屽苟鐢熸垚鈥滄壒鍙蜂笅鎷夆��
const getProductModel = (value) => {
- const index = modelOptions.value.findIndex((item) => item.id === value);
- if (index !== -1) {
- productForm.value.specificationModel = modelOptions.value[index].model;
- productForm.value.unit = modelOptions.value[index].unit;
+ const modelNode = findNodeObjByValue(stockInventoryAllTree, value);
+ if (!modelNode || modelNode.nodeType !== "model") return;
+
+ const prevBatchNo = productForm.value.batchNo;
+ const prevCustomer = productForm.value.customer;
+
+ productForm.value.productModelId = modelNode.value;
+ productForm.value.specificationModel = modelNode.model ?? modelNode.label ?? "";
+ // 鏈変簺鎺ュ彛/鏍戞暟鎹噷鍙兘涓嶅寘鍚� unit锛岃繖绉嶆儏鍐典笅涓嶈瑕嗙洊缂栬緫鏃跺凡鍥炴樉鐨勫��
+ const nextUnit = modelNode.unit ?? "";
+ if (nextUnit !== null && nextUnit !== undefined && String(nextUnit).trim() !== "") {
+ productForm.value.unit = nextUnit;
+ }
+ // 鏈変簺鎺ュ彛/鏍戞暟鎹噷鍙兘涓嶅寘鍚� uidNo锛岃繖绉嶆儏鍐典笅涓嶈瑕嗙洊缂栬緫鏃跺凡鍥炴樉鐨勫��
+ const nextUidNo = modelNode.uidNo ?? modelNode.identifierCode ?? "";
+ if (nextUidNo !== null && nextUidNo !== undefined && String(nextUidNo).trim() !== "") {
+ productForm.value.uidNo = nextUidNo;
+ }
+
+ const batchNodes = (modelNode.children || []).filter((b) => b.nodeType === "batch");
+ batchNodeByBatchNo = new Map(
+ batchNodes.map((b) => {
+ const key = String(b.batchNo ?? b.value ?? b.label ?? "").trim();
+ return [key, b];
+ })
+ );
+ batchNoOptions.value = batchNodes.map((b) => ({
+ label: String(b.batchNo ?? b.label ?? "").trim(),
+ value: String(b.batchNo ?? b.value ?? b.label ?? "").trim(),
+ }));
+
+ // 鎵瑰彿涓嶅啀灞炰簬鏂拌鏍兼椂锛屾竻绌�
+ const batchValues = new Set(batchNoOptions.value.map((x) => x.value));
+ if (!prevBatchNo || !batchValues.has(prevBatchNo)) {
+ productForm.value.batchNo = "";
+ }
+
+ // 闇�瑕佷緵搴斿晢锛氭壒鍙峰洖鏄惧悗鍐嶇敓鎴�
+ productForm.value.customer = "";
+ supplierOptions.value = [];
+ if (productForm.value.batchNo) {
+ handleBatchNoChange(productForm.value.batchNo, prevCustomer);
+ }
+};
+
+const handleBatchNoChange = (batchNo, prevCustomer) => {
+ const safeBatchNo = String(batchNo ?? "").trim();
+ if (!safeBatchNo || !batchNodeByBatchNo.size) {
+ productForm.value.customer = "";
+ supplierOptions.value = [];
+ return;
+ }
+
+ const batchNode = batchNodeByBatchNo.get(String(safeBatchNo));
+ if (!batchNode) {
+ productForm.value.customer = "";
+ supplierOptions.value = [];
+ return;
+ }
+
+ // UID鐮佸彲鑳芥潵婧愪簬 batch 鑺傜偣锛堜笉鍚屾帴鍙e瓧娈靛悕涓嶄竴鑷存椂灏介噺鍏滃簳锛�
+ const nextUidNo = batchNode.uidNo ?? batchNode.identifierCode ?? batchNode.uid ?? "";
+ if (nextUidNo !== null && nextUidNo !== undefined && String(nextUidNo).trim() !== "") {
+ productForm.value.uidNo = nextUidNo;
+ }
+
+ const customers = (batchNode.children || [])
+ .filter((c) => c.nodeType === "customer")
+ .map((c) => c.customer ?? c.label ?? "")
+ .filter(Boolean);
+
+ const uniq = Array.from(new Set(customers));
+ supplierOptions.value = uniq.map((s) => ({ label: s, value: s }));
+
+ // 缂栬緫鍦烘櫙灏介噺鍥炴樉锛涙柊澧炲満鏅笉鍥炴樉
+ if (prevCustomer && uniq.includes(prevCustomer)) {
+ productForm.value.customer = prevCustomer;
} else {
- productForm.value.specificationModel = null;
- productForm.value.unit = null;
+ productForm.value.customer = "";
}
};
-const findNodeById = (nodes, productId) => {
- for (let i = 0; i < nodes.length; i++) {
- if (nodes[i].value === productId) {
- return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣
- }
- if (nodes[i].children && nodes[i].children.length > 0) {
- const foundNode = findNodeById(nodes[i].children, productId);
- if (foundNode) {
- return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝杩斿洖璇ヨ妭鐐�
- }
- }
- }
- return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
-};
-function convertIdToValue(data) {
- return data.map((item) => {
- const { id, children, ...rest } = item;
- const newItem = {
- ...rest,
- value: id, // 灏� id 鏀逛负 value
- };
- if (children && children.length > 0) {
- newItem.children = convertIdToValue(children);
- }
-
- return newItem;
- });
-}
// 鏍规嵁鍚嶇О鍙嶆煡浜у搧澶х被 id锛屼究浜庝粎瀛樺悕绉版椂鐨勫弽鏄�
function findNodeIdByLabel(nodes, label) {
if (!label) return null;
@@ -978,6 +1148,23 @@
} else {
expandedRowKeys.value = [];
}
+};
+
+// 娣诲姞琛ㄨ绫诲悕鏂规硶
+const tableRowClassName = ({ row }) => {
+ if (!row.deliveryDate) return '';
+ if (row.isFh) return '';
+
+ const diff = row.deliveryDaysDiff;
+ if (diff === 15) {
+ return 'yellow';
+ } else if (diff === 10) {
+ return 'pink';
+ } else if (diff === 2) {
+ return 'purple';
+ } else if (diff < 2) {
+ return 'red';
+ }
};
// 涓昏〃鍚堣鏂规硶
const summarizeMainTable = (param) => {
@@ -1035,6 +1222,8 @@
const openQuotationDialog = async () => {
if (operationType.value === "view") return;
quotationDialogVisible.value = true;
+ // 鎵撳紑寮圭獥鏃堕噸缃垎椤靛埌绗竴椤�
+ quotationPage.current = 1;
// 鍏堢‘淇濆鎴峰垪琛ㄥ凡鍔犺浇锛屼究浜庡悗缁洖濉� customerId
if (!customerOption.value || customerOption.value.length === 0) {
try {
@@ -1051,14 +1240,15 @@
quotationLoading.value = true;
try {
const params = {
- // 鍏煎鍚庣鍒嗛〉瀛楁锛氳繖閲屾部鐢ㄦ姤浠烽〉闈㈠凡鏈夊彲鐢ㄧ殑瀛楁鍛藉悕
- currentPage: 1,
- pageSize: 100,
+ // 鍚庣鍒嗛〉瀛楁锛歝urrent / size
+ current: quotationPage.current,
+ size: quotationPage.size,
...quotationSearchForm,
status: "閫氳繃",
};
const res = await getQuotationList(params);
quotationList.value = res?.data?.records || [];
+ quotationPage.total = res?.data?.total || 0;
} finally {
quotationLoading.value = false;
}
@@ -1067,7 +1257,15 @@
const resetQuotationSearch = async () => {
quotationSearchForm.quotationNo = "";
quotationSearchForm.customer = "";
+ quotationPage.current = 1;
await fetchQuotationList();
+};
+
+// 鎶ヤ环鍗曞脊妗嗗垎椤靛垏鎹�
+const quotationPaginationChange = (obj) => {
+ quotationPage.current = obj.page;
+ quotationPage.size = obj.limit;
+ fetchQuotationList();
};
// 閫変腑鎶ヤ环鍗曞悗鍥炲~鍒板彴璐﹁〃鍗�
@@ -1076,10 +1274,14 @@
selectedQuotation.value = row;
// 涓氬姟鍛�
- form.value.salesman = row.salesperson || "";
+ form.value.salesman = (row.salesperson || "").trim();
// 瀹㈡埛鍚嶇О -> customerId
- const customer = (customerOption.value || []).find((c) => c.customerName === row.customer);
+ const qCustomerName = String(row.customer || "").trim();
+ const customer = (customerOption.value || []).find((c) => {
+ const name = String(c.customerName || "").trim();
+ return name === qCustomerName || name.includes(qCustomerName) || qCustomerName.includes(name);
+ });
if (customer?.id) {
form.value.customerId = customer.id;
} else {
@@ -1098,7 +1300,9 @@
return {
// 鍙拌处瀛楁
productCategory: p.product || p.productName || "",
+ productModelId: p.productModelId || "",
specificationModel: p.specification || "",
+ uidNo: p.uidNo || "",
unit: p.unit || "",
quantity: quantity,
taxRate: taxRate,
@@ -1175,6 +1379,8 @@
}
});
};
+
+const batchNoOptions = ref([]);
// 鍏抽棴寮规
const closeDia = () => {
proxy.resetForm("formRef");
@@ -1184,6 +1390,12 @@
const productIndex = ref(0);
// 鎵撳紑浜у搧寮规
const openProductForm = async (type, row, index) => {
+ // 缂栬緫鏃舵鏌ヤ骇鍝佹槸鍚﹀凡鍙戣揣鎴栧鏍搁�氳繃
+ if (type === "edit" && isProductShipped(row)) {
+ proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳界紪杈�");
+ return;
+ }
+
productOperationType.value = type;
productForm.value = {};
proxy.resetForm("productFormRef");
@@ -1192,25 +1404,44 @@
productIndex.value = index;
// 缂栬緫鏃舵牴鎹骇鍝佸ぇ绫诲悕绉板弽鏌� tree 鑺傜偣 id锛屽苟鍔犺浇瑙勬牸鍨嬪彿鍒楄〃
try {
- const options = productOptions.value && productOptions.value.length > 0
- ? productOptions.value
- : await getProductOptions();
- const categoryId = findNodeIdByLabel(options, productForm.value.productCategory);
- if (categoryId) {
- const models = await modelList({ id: categoryId });
- modelOptions.value = models || [];
- // 鏍规嵁褰撳墠瑙勬牸鍨嬪彿鍚嶇О鍙嶆煡骞惰缃� productModelId锛屼究浜庝笅鎷夋鏄剧ず宸查�夊��
- const currentModel = (modelOptions.value || []).find(
- (m) => m.model === productForm.value.specificationModel
- );
+ if (!productOptions.value || productOptions.value.length === 0) {
+ await getProductOptions();
+ }
+
+ // 鍥炴樉锛氭牴鎹�滀骇鍝佸ぇ绫烩�濆弽鏌ヤ骇鍝佽妭鐐�
+ const categoryKey = findNodeIdByLabel(productOptions.value, productForm.value.productCategory);
+ if (categoryKey) {
+ const categoryNode = findNodeObjByValue(stockInventoryAllTree, categoryKey);
+ const models = (categoryNode?.children || [])
+ .filter((n) => n.nodeType === "model")
+ .map((m) => ({
+ id: m.value,
+ model: m.model ?? m.label ?? "",
+ unit: m.unit ?? "",
+ uidNo: m.uidNo ?? m.identifierCode ?? "",
+ }));
+ modelOptions.value = models;
+
+ // 鏍规嵁褰撳墠瑙勬牸鍨嬪彿鍥炴樉
+ const targetSpec = String(productForm.value.specificationModel ?? "").trim();
+ const currentModel =
+ (models || []).find((m) => String(m.model ?? "").trim() === targetSpec) ||
+ (models || []).find((m) => String(m.model ?? "").trim().includes(targetSpec)) ||
+ (models || []).find((m) => targetSpec.includes(String(m.model ?? "").trim()));
if (currentModel) {
+ productForm.value.customer = productForm.value.customer || row.customer || row.supplierName || "";
productForm.value.productModelId = currentModel.id;
+ getProductModel(currentModel.id);
}
}
} catch (e) {
// 鍔犺浇澶辫触鏃朵繚鎸佸彲缂栬緫锛屼笉涓柇寮圭獥
console.error("鍔犺浇浜у搧瑙勬牸鍨嬪彿澶辫触", e);
}
+ // 鏈�缁堝厹搴曪細濡傛灉涓�旇閲嶇疆娓呯┖锛岃嚦灏戝洖鏄捐鏁版嵁閲岀殑 UID
+ productForm.value.uidNo = row.uidNo ?? productForm.value.uidNo ?? "";
+ // 鏈�缁堝厹搴曪細鍚屾牱淇濊瘉鍗曚綅涓嶄細鍥犳爲鏁版嵁缂哄け鑰岃瑕嗙洊涓虹┖
+ productForm.value.unit = row.unit ?? productForm.value.unit ?? "";
} else {
getProductOptions()
}
@@ -1250,6 +1481,14 @@
proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
return;
}
+
+ // 妫�鏌ユ槸鍚︽湁宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝�
+ const shippedProducts = productSelectedRows.value.filter(row => isProductShipped(row));
+ if (shippedProducts.length > 0) {
+ proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳藉垹闄�");
+ return;
+ }
+
if (operationType.value === "add") {
productSelectedRows.value.forEach((selectedRow) => {
const index = productData.value.findIndex(
@@ -1324,15 +1563,55 @@
proxy.$modal.msg("宸插彇娑�");
});
};
+/** 鍒ゆ柇鍗曚釜浜у搧鏄惁宸插彂璐э紙鏍规嵁shippingStatus鍒ゆ柇锛屽凡鍙戣揣鎴栧鏍搁�氳繃涓嶅彲缂栬緫鍜屽垹闄わ級 */
+const isProductShipped = (product) => {
+ if (!product) return false;
+ const status = String(product.shippingStatus || "").trim();
+ // 濡傛灉鍙戣揣鐘舵�佹槸"宸插彂璐�"鎴�"瀹℃牳閫氳繃"锛屽垯涓嶅彲缂栬緫鍜屽垹闄�
+ return status === "宸插彂璐�" || status === "瀹℃牳閫氳繃";
+};
+
+/** 鍒ゆ柇閿�鍞鍗曚笅鏄惁瀛樺湪宸插彂璐�/鍙戣揣瀹屾垚鐨勪骇鍝侊紙涓嶅彲鍒犻櫎锛� */
+const hasShippedProducts = (products) => {
+ if (!products || !products.length) return false;
+ return products.some((p) => {
+ const status = String(p.shippingStatus || "").trim();
+ // 鏈夊彂璐ф棩鏈熸垨杞︾墝鍙疯涓哄凡鍙戣揣
+ if (p.shippingDate || p.shippingCarNumber) return true;
+ // 宸茶繘琛屽彂璐с�佸彂璐у畬鎴愩�佸凡鍙戣揣 鍧囦笉鍙垹闄�
+ return status === "宸茶繘琛屽彂璐�" || status === "鍙戣揣瀹屾垚" || status === "宸插彂璐�";
+ });
+};
+
// 鍒犻櫎
-const handleDelete = () => {
- let ids = [];
- if (selectedRows.value.length > 0) {
- ids = selectedRows.value.map((item) => item.id);
- } else {
+const handleDelete = async () => {
+ if (selectedRows.value.length === 0) {
proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
return;
}
+ const ids = selectedRows.value.map((item) => item.id);
+
+ // 妫�鏌ユ槸鍚︽湁宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曪紝鑻ユ湁鍒欎笉鍏佽鍒犻櫎
+ const cannotDeleteNames = [];
+ for (const row of selectedRows.value) {
+ let products = row.children && row.children.length > 0 ? row.children : null;
+ if (!products) {
+ try {
+ const res = await productList({ salesLedgerId: row.id, type: 1 });
+ products = res.data || [];
+ } catch {
+ products = [];
+ }
+ }
+ if (hasShippedProducts(products)) {
+ cannotDeleteNames.push(row.salesContractNo || `ID:${row.id}`);
+ }
+ }
+ if (cannotDeleteNames.length > 0) {
+ proxy.$modal.msgWarning("宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曚笉鑳藉垹闄わ細" + cannotDeleteNames.join("銆�"));
+ return;
+ }
+
ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
confirmButtonText: "纭",
cancelButtonText: "鍙栨秷",
@@ -1574,6 +1853,7 @@
<th>浜у搧鍚嶇О</th>
<th>瑙勬牸鍨嬪彿</th>
<th>鍗曚綅</th>
+ <th>UID鐮�</th>
<th>鍗曚环</th>
<th>闆跺敭鏁伴噺</th>
<th>闆跺敭閲戦</th>
@@ -1586,6 +1866,7 @@
<td>${product.productCategory || ''}</td>
<td>${product.specificationModel || ''}</td>
<td>${product.unit || ''}</td>
+ <td>${product.uidNo || ''}</td>
<td>${product.taxInclusiveUnitPrice || '0'}</td>
<td>${product.quantity || '0'}</td>
<td>${product.taxInclusiveTotalPrice || '0'}</td>
@@ -2004,13 +2285,6 @@
const submitDelivery = () => {
proxy.$refs["deliveryFormRef"].validate((valid) => {
if (valid) {
- // 瀹℃壒浜哄繀濉牎楠岋紙鎵�鏈夎妭鐐归兘瑕侀�変汉锛�
- const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
- if (hasEmptyApprover) {
- proxy.$modal.msgError("璇蜂负鎵�鏈夊鎵硅妭鐐归�夋嫨瀹℃壒浜猴紒");
- return;
- }
- const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
// 淇濆瓨褰撳墠灞曞紑鐨勮ID锛屼互渚垮彂璐у悗閲嶆柊鍔犺浇瀛愯〃鏍兼暟鎹�
const currentExpandedKeys = [...expandedRowKeys.value];
const salesLedgerId = currentDeliveryRow.value.salesLedgerId;
@@ -2018,7 +2292,6 @@
salesLedgerId: salesLedgerId,
salesLedgerProductId: currentDeliveryRow.value.id,
type: deliveryForm.value.type,
- approveUserIds,
})
.then(() => {
proxy.$modal.msgSuccess("鍙戣揣鎴愬姛");
@@ -2058,6 +2331,38 @@
let res = await userStore.getInfo();
currentFactoryName.value = res.user.currentFactoryName;
};
+
+const exportSaleOutbound = row => {
+ saleOutboundExport({id: row.id})
+ .then(res => {
+ // 鍒涘缓Blob瀵硅薄
+ const blob = new Blob([res], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ });
+ // 鍒涘缓涓嬭浇閾炬帴
+ const url = window.URL.createObjectURL(blob);
+ const link = document.createElement("a");
+ link.href = url;
+ link.download = `閿�鍞嚭搴撳崟.docx`;
+
+ // 妯℃嫙鐐瑰嚮涓嬭浇
+ document.body.appendChild(link);
+ link.click();
+
+ // 娓呯悊涓存椂瀵硅薄
+ setTimeout(() => {
+ document.body.removeChild(link);
+ window.URL.revokeObjectURL(url);
+ }, 100);
+
+ ElMessage.success("瀵煎嚭鎴愬姛");
+ })
+ .catch(err => {
+ console.error("瀵煎嚭澶辫触:", err);
+ ElMessage.error("瀵煎嚭澶辫触锛岃閲嶈瘯");
+ });
+};
+
onMounted(() => {
getList();
userListNoPage().then(res => {
@@ -2072,6 +2377,22 @@
margin-left: 10px;
}
+::v-deep .yellow {
+ background-color: #FAF0DE;
+}
+
+::v-deep .pink {
+ background-color: #FAE1DE;
+}
+
+::v-deep .red {
+ background-color: #FAE1DE;
+}
+
+::v-deep .purple{
+ background-color: #F4DEFA;
+}
+
.table_list {
margin-top: unset;
}
--
Gitblit v1.9.3