From 57e75ea91e7210d058627e7930efc75526dab622 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期五, 22 五月 2026 09:43:09 +0800
Subject: [PATCH] feat(product): 添加产品规格型号向下复制功能 - 在产品树形结构中添加向下复制按钮,仅在层级大于1时显示 - 实现handleDownCopy方法,支持将当前节点规格型号复制到同层级下一个节点 - 添加downCopyProductModel API接口,用于处理向下复制请求 - 添加相应的警告和成功消息提示
---
src/views/salesManagement/salesLedger/index.vue | 228 ++++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 152 insertions(+), 76 deletions(-)
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index 740371d..3e9c0b2 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -34,6 +34,7 @@
<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="handleExport">瀵煎嚭閫佽揣鍗�</el-button>
</div>
</div>
<el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
@@ -103,18 +104,21 @@
</template>
</el-table-column>
<el-table-column align="center" label="搴忓彿" type="index" width="60" />
- <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="model" width="100" show-overflow-tooltip />
+ <el-table-column label="鐢靛帇" prop="voltage" width="100" show-overflow-tooltip />
+ <el-table-column label="qty" prop="qty" 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="contractAmount" width="220" show-overflow-tooltip
- :formatter="formattedNumber" />
+ <el-table-column label="鍚堝悓閲戦(鍏�)" prop="contractAmount" width="220" show-overflow-tooltip
+ :formatter="formattedNumber" />
+ <el-table-column label="浠樻鏂瑰紡" prop="paymentMethod" show-overflow-tooltip />
<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 label="涓氬姟鍛�" prop="salesman" width="100" show-overflow-tooltip />
+ <el-table-column label="澶囨敞" prop="remarks" width="200" show-overflow-tooltip />
+ <el-table-column label="閿�鍞悎鍚屽彿" prop="salesContractNo" width="180" 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)"
@@ -217,7 +221,7 @@
</el-col>
<el-col :span="12">
<el-form-item label="鏄惁鐢熶骇锛�" prop="produce">
- <el-radio-group v-model="form.produce">
+ <el-radio-group v-model="form.produce" :disabled="operationType !== 'add'">
<el-radio :label="true">鏄�</el-radio>
<el-radio :label="false">鍚�</el-radio>
</el-radio-group>
@@ -340,10 +344,10 @@
</el-row>
<el-row :gutter="30">
<el-col :span="24">
- <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="productModelId">
- <el-select v-model="productForm.productModelId" placeholder="璇烽�夋嫨" clearable
+ <el-form-item label="鐢靛帇锛�" prop="stockId">
+ <el-select v-model="productForm.stockId" placeholder="璇烽�夋嫨" clearable
@change="getProductModel" filterable>
- <el-option v-for="item in modelOptions" :key="item.id" :label="item.model"
+ <el-option v-for="item in modelOptions" :key="item.id" :label="item.label"
:value="item.id" />
</el-select>
</el-form-item>
@@ -446,7 +450,7 @@
鏆傛棤鎵撳嵃鏁版嵁
</div>
<div v-else
- style="text-align: center; padding: 10px; color: #666; font-size: 16px; background: #e8f4fd; margin-bottom: 10px;">
+ style="text-align: center; padding: 10px; color: #666; font-size: 18px; background: #e8f4fd; margin-bottom: 10px;">
鍏� {{ printData.length }} 鏉℃暟鎹緟鎵撳嵃
</div>
<div v-for="(item, index) in printData" :key="index" class="print-page">
@@ -503,7 +507,7 @@
</div>
</div>
- <span style="font-size: 20px; margin-top: 5px;">璐х墿璇︾粏淇℃伅锛�</span>
+ <span style="font-size: 18px; margin-top: 5px;">璐х墿璇︾粏淇℃伅锛�</span>
<div class="table-section">
<table class="product-table">
<thead>
@@ -528,14 +532,14 @@
<td>{{ item.salesContractNo || '' }}</td>
</tr>
<!-- 娣诲姞绌虹櫧琛屼互纭繚鑷冲皯5琛� -->
- <tr v-for="n in Math.max(0, 5 - (item.products ? item.products.length : 0))" :key="'empty-' + n" style="height: 25px;">
- <td style="height: 35px;"></td>
- <td style="height: 35px;"></td>
- <td style="height: 35px;"></td>
- <td style="height: 35px;"></td>
- <td style="height: 35px;"></td>
- <td style="height: 35px;"></td>
- <td style="height: 35px;"></td>
+ <tr v-for="n in Math.max(0, 5 - (item.products ? item.products.length : 0))" :key="'empty-' + n">
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
</tr>
</tbody>
<tfoot>
@@ -548,14 +552,14 @@
</table>
<div style="width: 80px; display: flex; flex-direction: column;">
- <div style="height: 35px; border-bottom: 1px dashed #000; text-align: center; display: flex; align-items: center; justify-content: center;">鍏卞洓鑱�</div>
- <div style="height: 35px; border-bottom: 1px dashed #000; text-align: center; display: flex; align-items: center; justify-content: center;">瀛樻牴</div>
- <div style="height: 35px; border-bottom: 1px dashed #000; text-align: center; display: flex; align-items: center; justify-content: center;">瀹㈡埛</div>
- <div style="height: 35px; border-bottom: 1px dashed #000; text-align: center; display: flex; align-items: center; justify-content: center;">璁拌处</div>
- <div style="height: 35px; text-align: center; display: flex; align-items: center; justify-content: center;">浠撳簱</div>
+ <div style="height: 33px; border-bottom: 1px dashed #000; text-align: center; display: flex; align-items: center; justify-content: center;">鍏卞洓鑱�</div>
+ <div style="height: 28px; border-bottom: 1px dashed #000; text-align: center; display: flex; align-items: center; justify-content: center;">瀛樻牴</div>
+ <div style="height: 29px; border-bottom: 1px dashed #000; text-align: center; display: flex; align-items: center; justify-content: center;">瀹㈡埛</div>
+ <div style="height: 29px; border-bottom: 1px dashed #000; text-align: center; display: flex; align-items: center; justify-content: center;">璁拌处</div>
+ <div style="height: 28px; text-align: center; display: flex; align-items: center; justify-content: center;">浠撳簱</div>
</div>
</div>
- <div style="margin: 10px 0; font-size: 20px;">
+ <div style="margin: 10px 0; font-size: 16px;">
<span>澶囨敞锛� 璐靛叕鍙稿湪鏀惰揣鍚庤鍗冲埢鏍稿疄鏁伴噺鍙婂搧璐紝鑻ユ湁寮傝锛岃鍦�3鏃ュ唴鎻愬嚭锛屽惁鍒欒涓烘敹濡ャ��</span>
</div>
<div class="footer">
@@ -658,17 +662,17 @@
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,
} from "@/api/salesManagement/salesLedger.js";
-import { modelList, productTreeList } from "@/api/basicData/product.js";
+import { finishedProductList } from "@/api/basicData/product.js";
import useFormData from "@/hooks/useFormData.js";
import dayjs from "dayjs";
import { getCurrentDate } from "@/utils/index.js";
@@ -682,6 +686,7 @@
const userList = ref([]);
const customerOption = ref([]);
const productOptions = ref([]);
+const productOptionsRaw = ref([]); // 淇濆瓨鍘熷鏁版嵁锛堝寘鍚� children锛�
const modelOptions = ref([]);
const tableLoading = ref(false);
const page = reactive({
@@ -916,31 +921,71 @@
// 鑾峰彇浜у搧澶х被tree鏁版嵁
const getProductOptions = () => {
// 杩斿洖 Promise锛屼究浜庡湪缂栬緫浜у搧鏃剁瓑寰呭姞杞藉畬鎴�
- return productTreeList().then((res) => {
- productOptions.value = convertIdToValue(res);
+ return finishedProductList({}).then((res) => {
+ // 淇濆瓨鍘熷鏁版嵁锛堝寘鍚� children锛夌敤浜庡悗缁彁鍙栫數鍘嬪垪琛�
+ productOptionsRaw.value = res || [];
+ // 浜у搧澶х被涓嬫媺閫夐」
+ productOptions.value = (res || []).map(item => ({
+ ...item,
+ value: item.productId, // 鐢� productId 浣滀负 value
+ children: undefined // 鍘绘帀涓嬫媺绠ご
+ }));
return productOptions.value;
});
};
const formattedNumber = (row, column, cellValue) => {
return parseFloat(cellValue).toFixed(2);
};
-// 鑾峰彇tree瀛愭暟鎹�
+// 鑾峰彇tree瀛愭暟鎹紙浠� children 涓彁鍙栫數鍘嬪垪琛級
const getModels = (value) => {
productForm.value.productCategory = findNodeById(productOptions.value, value);
- modelList({ id: value }).then((res) => {
- modelOptions.value = res;
- });
+ // 浠庡師濮嬫暟鎹腑鎵惧埌閫変腑鐨勮妭鐐癸紙鍖呭惈 children锛�
+ const selectedNode = productOptionsRaw.value.find(item => item.productId === value);
+ if (selectedNode && selectedNode.children && selectedNode.children.length > 0) {
+ // 鎻愬彇 children 涓殑鍨嬪彿鏁版嵁锛屾嫾鎺ユ樉绀烘枃鏈�
+ modelOptions.value = selectedNode.children
+ .map(item => {
+ // 鎷兼帴鏄剧ず鏂囨湰锛歮odel - processCategory - voltage锛堣繃婊ょ┖瀛楃涓诧級
+ const parts = [];
+ if (item.model && item.model.trim()) parts.push(item.model);
+ if (item.processCategory && item.processCategory.trim()) parts.push(item.processCategory);
+ if (item.voltage && item.voltage.trim()) parts.push(item.voltage);
+ return {
+ ...item,
+ id: item.stockId, // 鐢� stockId 浣滀负鍞竴鏍囪瘑
+ productModelId: item.productModelId, // 淇濆瓨 productModelId 鐢ㄤ簬鎻愪氦
+ label: parts.join('-')
+ };
+ })
+ .filter(item => item.label); // 杩囨护鎺� label 涓虹┖鐨勯�夐」
+ } else {
+ modelOptions.value = [];
+ }
};
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;
- productForm.value.materialCode = modelOptions.value[index].materialCode;
+ const selectedItem = modelOptions.value[index];
+ // 瑙勬牸鍨嬪彿瀛樺偍鎷兼帴鍊硷紝鐢ㄤ簬琛ㄦ牸鏄剧ず
+ productForm.value.specificationModel = selectedItem.label;
+ productForm.value.unit = selectedItem.unit;
+ productForm.value.materialCode = selectedItem.materialCode;
+ // 淇濆瓨鐢靛帇淇℃伅
+ productForm.value.voltage = selectedItem.voltage;
+ // 淇濆瓨宸ュ簭绫诲埆
+ productForm.value.processCategory = selectedItem.processCategory;
+ // 淇濆瓨 productModelId 鐢ㄤ簬鎻愪氦
+ productForm.value.productModelId = selectedItem.productModelId;
+ // 淇濆瓨 stockId 鐢ㄤ簬鎻愪氦
+ productForm.value.stockId = selectedItem.stockId;
} else {
productForm.value.specificationModel = null;
productForm.value.unit = null;
productForm.value.materialCode = null;
+ productForm.value.voltage = null;
+ productForm.value.processCategory = null;
+ productForm.value.productModelId = null;
+ productForm.value.stockId = null;
}
};
const findNodeById = (nodes, productId) => {
@@ -959,13 +1004,13 @@
};
function convertIdToValue(data) {
return data.map((item) => {
- const { id, children, ...rest } = item;
+ const { productId, children, ...rest } = item;
const newItem = {
...rest,
- value: id, // 灏� id 鏀逛负 value
+ value: productId, // 浜у搧澶х被鐢� productId 浣滀负 value
};
if (children && children.length > 0) {
- newItem.children = convertIdToValue(children);
+ newItem.children = children; // children 淇濇寔鍘熸牱
}
return newItem;
@@ -1264,22 +1309,36 @@
if (type === "edit") {
productForm.value = { ...row };
productIndex.value = index;
- // 缂栬緫鏃舵牴鎹骇鍝佸ぇ绫诲悕绉板弽鏌� tree 鑺傜偣 id锛屽苟鍔犺浇瑙勬牸鍨嬪彿鍒楄〃
+ // 缂栬緫鏃舵牴鎹骇鍝佸ぇ绫诲悕绉板弽鏌� 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 (currentModel) {
- productForm.value.productModelId = currentModel.id;
+ // 浠庡師濮嬫暟鎹腑鎵惧埌閫変腑鐨勮妭鐐癸紝鎻愬彇 children
+ const selectedNode = productOptionsRaw.value.find(item => item.productId === categoryId);
+ if (selectedNode && selectedNode.children && selectedNode.children.length > 0) {
+ modelOptions.value = selectedNode.children
+ .map(item => {
+ // 鎷兼帴鏄剧ず鏂囨湰锛歮odel - processCategory - voltage锛堣繃婊ょ┖瀛楃涓诧級
+ const parts = [];
+ if (item.model && item.model.trim()) parts.push(item.model);
+ if (item.processCategory && item.processCategory.trim()) parts.push(item.processCategory);
+ if (item.voltage && item.voltage.trim()) parts.push(item.voltage);
+ return {
+ ...item,
+ id: item.stockId, // 鐢� stockId 浣滀负鍞竴鏍囪瘑
+ productModelId: item.productModelId,
+ label: parts.join('-')
+ };
+ })
+ .filter(item => item.label); // 杩囨护鎺� label 涓虹┖鐨勯�夐」
}
+ // 鏍规嵁褰撳墠 stockId 璁剧疆閫変腑鍊硷紙鐢ㄤ簬涓嬫媺妗嗗洖鏄撅級
+ productForm.value.stockId = row.stockId;
+ // 鍚屾椂淇濆瓨 productModelId
+ productForm.value.productModelId = row.productModelId;
}
} catch (e) {
// 鍔犺浇澶辫触鏃朵繚鎸佸彲缂栬緫锛屼笉涓柇寮圭獥
@@ -1471,6 +1530,25 @@
});
};
+const handleExport = () => {
+ if (selectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇烽�夋嫨瑕佸鍑洪�佽揣鍗曠殑鏁版嵁");
+ return;
+ }
+
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ proxy.download("/sales/ledger/exportShippingNote", {ids: selectedRows.value.map((item) => item.id).join(",")}, "閫佽揣鍗�.xlsx");
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+}
+
// 鎵撳嵃鍔熻兘
const handlePrint = async () => {
if (selectedRows.value.length === 0) {
@@ -1562,22 +1640,20 @@
width: 100%;
height: 100%;
font-size: 18px;
- line-height: 1.5;
+ line-height: 1;
display: flex;
flex-direction: column;
color: #000;
}
.header {
text-align: center;
- margin-bottom: 8px;
}
.company-name {
- font-size: 32px;
+ font-size: 30px;
font-weight: bold;
- margin-bottom: 4px;
}
.document-title {
- font-size: 28px;
+ font-size: 25px;
font-weight: bold;
letter-spacing: 10px;
}
@@ -1587,17 +1663,17 @@
align-items: center;
}
.info-row {
- line-height: 26px;
+ line-height: 20px;
}
.label {
font-weight: bold;
min-width: 60px;
- font-size: 20px;
+ font-size: 18px;
}
.value {
margin-right: 20px;
min-width: 80px;
- font-size: 20px;
+ font-size: 18px;
}
.table-section {
margin-bottom: 4px;
@@ -1611,13 +1687,13 @@
}
.product-table th, .product-table td {
border: 1px solid #000;
- padding: 6px;
+ padding: 3px;
text-align: center;
- font-size: 20px;
- line-height: 1.4;
+ font-size: 18px;
+ line-height: 1.2;
}
.product-table th {
- font-size: 20px;
+ font-size: 19px;
font-weight: bold;
}
.total-value {
@@ -1627,7 +1703,7 @@
margin: 10px 0;
}
.sign-section {
- margin-top: 15px;
+ margin-top: 10px;
}
.footer {
display: flex;
@@ -1638,17 +1714,17 @@
width: 50%;
}
.info-row {
- line-height: 26px;
+ line-height: 20px;
}
.label {
font-weight: bold;
min-width: 60px;
- font-size: 20px;
+ font-size: 18px;
}
.value {
margin-right: 20px;
min-width: 80px;
- font-size: 20px;
+ font-size: 18px;
}
}
@media print {
@@ -1662,7 +1738,7 @@
padding-right: 10mm;
page-break-inside: avoid;
page-break-after: always;
- font-size: 20px;
+ font-size: 18px;
}
.print-page:last-child {
page-break-after: avoid;
@@ -2231,7 +2307,7 @@
th,
td {
border: 1px solid #000;
- padding: 6px;
+ padding: 3px;
text-align: center;
font-size: 16px;
line-height: 1.4;
@@ -2327,4 +2403,4 @@
page-break-after: avoid;
}
}
-</style>
\ No newline at end of file
+</style>
--
Gitblit v1.9.3