From 0dadd48fa23109f8bb4087654d8e2dad0cbd8f20 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期三, 15 四月 2026 13:28:00 +0800
Subject: [PATCH] 新增入库功能至销售台账页面,支持选择入库状态并执行入库操作,提升用户交互体验
---
src/views/salesManagement/salesLedger/index.vue | 397 ++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 322 insertions(+), 75 deletions(-)
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index 1222b2b..0965cf1 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -41,6 +41,12 @@
<el-option label="宸插彂璐�" :value="4" />
</el-select>
</el-form-item>
+ <el-form-item label="鍏ュ簱鐘舵�侊細">
+ <el-select v-model="searchForm.stockStatus" placeholder="璇烽�夋嫨" clearable style="width: 140px">
+ <el-option label="鏈叆搴�" :value="0" />
+ <el-option label="宸插叆搴�" :value="1" />
+ </el-select>
+ </el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery"> 鎼滅储 </el-button>
</el-form-item>
@@ -59,6 +65,7 @@
@confirm="handleProcessFlowSelectConfirm"
/>
<el-space wrap>
+ <el-button type="primary" @click="handleSalesStock">鍏ュ簱</el-button>
<el-button type="primary" @click="openForm('add')">鏂板鍙拌处</el-button>
<el-button type="primary" @click="handleBulkDelivery">鍙戣揣</el-button>
<el-button type="primary" plain @click="handleImport">瀵煎叆</el-button>
@@ -204,6 +211,13 @@
<el-tag v-else type="info">-</el-tag>
</template>
</el-table-column>
+ <el-table-column label="鍏ュ簱鐘舵��" width="120" align="center">
+ <template #default="scope">
+ <el-tag v-if="Number(scope.row.stockStatus) === 0" type="info">鏈叆搴�</el-tag>
+ <el-tag v-else-if="Number(scope.row.stockStatus) === 1" type="success">宸插叆搴�</el-tag>
+ <el-tag v-else type="info">-</el-tag>
+ </template>
+ </el-table-column>
<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 />
@@ -298,7 +312,14 @@
</el-row>
<el-row>
<el-form-item label="浜у搧淇℃伅锛�" prop="entryDate">
- <el-button v-if="operationType !== 'view'" type="primary" @click="addProductInline">娣诲姞</el-button>
+ <el-button
+ v-if="operationType !== 'view'"
+ type="primary"
+ :disabled="hasEditingProductRow()"
+ @click="addProductInline"
+ >
+ 娣诲姞
+ </el-button>
<el-button v-if="operationType !== 'view'" plain type="danger" @click="deleteProduct" >鍒犻櫎</el-button>
</el-form-item>
</el-row>
@@ -325,7 +346,7 @@
<span v-else>{{ scope.row.productCategory ?? "" }}</span>
</template>
</el-table-column>
- <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" min-width="140">
+ <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" min-width="160">
<template #default="scope">
<el-select
v-if="scope.row.__editing"
@@ -333,7 +354,7 @@
placeholder="璇烽�夋嫨"
clearable
filterable
- style="width: 140px"
+ style="width: 100%"
@change="(val) => handleInlineProductModelChange(scope.row, val)"
>
<el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
@@ -341,7 +362,7 @@
<span v-else>{{ scope.row.specificationModel ?? "" }}</span>
</template>
</el-table-column>
- <el-table-column label="鍘氬害" prop="thickness" min-width="90">
+ <el-table-column label="鍘氬害(mm)" prop="thickness" min-width="160">
<template #default="scope">
<el-input-number
v-if="scope.row.__editing"
@@ -349,14 +370,14 @@
:min="0"
:step="0.000000000000001"
:precision="15"
- style="width: 110px"
+ style="width: 100%"
placeholder="璇疯緭鍏�"
clearable
/>
<span v-else>{{ scope.row.thickness ?? "" }}</span>
</template>
</el-table-column>
- <el-table-column label="瀹�(mm)" prop="width" min-width="80">
+ <el-table-column label="瀹�(mm)" prop="width" min-width="160">
<template #default="scope">
<el-input-number
v-if="scope.row.__editing"
@@ -364,15 +385,16 @@
:min="0"
:step="1"
:precision="2"
- style="width: 110px"
+ style="width:100%"
placeholder="璇疯緭鍏�"
clearable
@change="() => handleInlineSizeChange(scope.row)"
+ @input="() => handleInlineSizeChange(scope.row)"
/>
<span v-else>{{ scope.row.width ?? "" }}</span>
</template>
</el-table-column>
- <el-table-column label="楂�(mm)" prop="height" min-width="80">
+ <el-table-column label="楂�(mm)" prop="height" min-width="160">
<template #default="scope">
<el-input-number
v-if="scope.row.__editing"
@@ -380,30 +402,32 @@
:min="0"
:step="1"
:precision="2"
- style="width: 110px"
+ style="width: 100%"
placeholder="璇疯緭鍏�"
clearable
@change="() => handleInlineSizeChange(scope.row)"
+ @input="() => handleInlineSizeChange(scope.row)"
/>
<span v-else>{{ scope.row.height ?? "" }}</span>
</template>
</el-table-column>
- <el-table-column label="闈㈢Н(m虏)" prop="actualTotalArea" min-width="100">
+ <el-table-column label="缁撶畻鍗曠墖闈㈢Н(銕�)" prop="settlePieceArea" min-width="160">
<template #default="scope">
<el-input-number
v-if="scope.row.__editing"
- v-model="scope.row.actualTotalArea"
+ v-model="scope.row.settlePieceArea"
:min="0"
:step="0.00001"
:precision="5"
- style="width: 120px"
- placeholder="鑷姩璁$畻"
- :disabled="true"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="() => handleInlineSettleAreaChange(scope.row)"
/>
- <span v-else>{{ scope.row.actualTotalArea ?? "" }}</span>
+ <span v-else>{{ scope.row.settlePieceArea ?? "" }}</span>
</template>
</el-table-column>
- <el-table-column label="鏁伴噺" prop="quantity" min-width="90">
+ <el-table-column label="鏁伴噺" prop="quantity" min-width="150">
<template #default="scope">
<el-input-number
v-if="scope.row.__editing"
@@ -411,12 +435,27 @@
:step="0.1"
:min="0"
:precision="2"
- style="width: 110px"
+ style="width: 100%"
placeholder="璇疯緭鍏�"
clearable
@change="() => handleInlineQuantityChange(scope.row)"
+ @input="() => handleInlineQuantityChange(scope.row)"
/>
<span v-else>{{ scope.row.quantity ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="闈㈢Н(m虏)" prop="actualTotalArea" min-width="160">
+ <template #default="scope">
+ <el-input-number
+ v-if="scope.row.__editing"
+ v-model="scope.row.actualTotalArea"
+ :min="0"
+ :step="0.00001"
+ :precision="5"
+ style="width: 100%"
+ placeholder="鑷姩璁$畻"
+ />
+ <span v-else>{{ scope.row.actualTotalArea ?? "" }}</span>
</template>
</el-table-column>
<el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" min-width="140">
@@ -426,23 +465,24 @@
:step="0.01"
:min="0"
:precision="2"
- style="width: 120px"
+ style="width: 100%"
v-model="scope.row.taxInclusiveUnitPrice"
placeholder="璇疯緭鍏�"
clearable
@change="() => handleInlineUnitPriceChange(scope.row)"
+ @input="() => handleInlineUnitPriceChange(scope.row)"
/>
<span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveUnitPrice ?? 0) }}</span>
</template>
</el-table-column>
- <el-table-column label="绋庣巼(%)" prop="taxRate" min-width="90">
+ <el-table-column label="绋庣巼(%)" prop="taxRate" min-width="120">
<template #default="scope">
<el-select
v-if="scope.row.__editing"
v-model="scope.row.taxRate"
placeholder="璇烽�夋嫨"
clearable
- style="width: 90px"
+ style="width: 100%"
@change="() => handleInlineTaxRateChange(scope.row)"
>
<el-option label="1" value="1" />
@@ -454,8 +494,8 @@
<span v-else>{{ scope.row.taxRate ?? "" }}</span>
</template>
</el-table-column>
- <el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
- <el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
+ <el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" min-width="120"/>
+ <el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" min-width="120"/>
<el-table-column label="鍙戠エ绫诲瀷" prop="invoiceType" min-width="120">
<template #default="scope">
<el-select
@@ -463,7 +503,7 @@
v-model="scope.row.invoiceType"
placeholder="璇烽�夋嫨"
clearable
- style="width: 120px"
+ style="width: 100%"
>
<el-option label="澧炴櫘绁�" value="澧炴櫘绁�" />
<el-option label="澧炰笓绁�" value="澧炰笓绁�" />
@@ -471,22 +511,7 @@
<span v-else>{{ scope.row.invoiceType ?? "" }}</span>
</template>
</el-table-column>
- <el-table-column label="缁撶畻鍗曠墖闈㈢Н(銕�)" prop="settlePieceArea" min-width="140">
- <template #default="scope">
- <el-input-number
- v-if="scope.row.__editing"
- v-model="scope.row.settlePieceArea"
- :min="0"
- :step="0.00001"
- :precision="5"
- style="width: 140px"
- placeholder="璇疯緭鍏�"
- clearable
- @change="() => handleInlineSettleAreaChange(scope.row)"
- />
- <span v-else>{{ scope.row.settlePieceArea ?? "" }}</span>
- </template>
- </el-table-column>
+
<el-table-column label="鍔犲伐瑕佹眰" prop="processRequirement" min-width="160" show-overflow-tooltip>
<template #default="scope">
<el-input
@@ -494,7 +519,7 @@
v-model="scope.row.processRequirement"
placeholder="璇疯緭鍏�"
clearable
- style="width: 160px"
+ style="width: 100%"
/>
<span v-else>{{ scope.row.processRequirement ?? "" }}</span>
</template>
@@ -506,7 +531,7 @@
v-model="scope.row.remark"
placeholder="璇疯緭鍏�"
clearable
- style="width: 140px"
+ style="width: 100%"
/>
<span v-else>{{ scope.row.remark ?? "" }}</span>
</template>
@@ -518,7 +543,7 @@
v-model="scope.row.floorCode"
placeholder="璇疯緭鍏�"
clearable
- style="width: 140px"
+ style="width: 100%"
/>
<span v-else>{{ scope.row.floorCode ?? "" }}</span>
</template>
@@ -530,7 +555,7 @@
v-model="scope.row.heavyBox"
placeholder="璇疯緭鍏�"
clearable
- style="width: 110px"
+ style="width: 100%"
/>
<span v-else>{{ scope.row.heavyBox ?? "" }}</span>
</template>
@@ -541,10 +566,11 @@
<el-button link type="primary" size="small" @click="saveProductInline(scope.row, scope.$index)">淇濆瓨</el-button>
<el-button link type="danger" size="small" @click="cancelProductInline(scope.row, scope.$index)">鍙栨秷</el-button>
<el-popover
- :width="420"
+ :width="560"
trigger="click"
:hide-after="0"
- v-model:visible="scope.row.__otherAmountPopoverVisible"
+ :visible="scope.row.__otherAmountPopoverVisible"
+ @update:visible="(val) => handleOtherAmountPopoverVisibleChange(scope.row, val)"
>
<template #reference>
<el-button
@@ -565,14 +591,50 @@
鏂板
</el-button>
</div>
+ <div
+ v-if="scope.row.__inlineOtherAmountAdding"
+ style="display:flex; flex-direction:column; gap: 8px; margin-bottom: 10px;"
+ @click.stop
+ >
+ <el-select
+ v-model="scope.row.__inlineOtherAmountAddId"
+ filterable
+ clearable
+ placeholder="璇烽�夋嫨鍏朵粬閲戦椤圭洰"
+ style="width: 100%;"
+ >
+ <el-option
+ v-for="item in otherAmountSelectOptions"
+ :key="item.id"
+ :label="item.processName"
+ :value="item.id"
+ />
+ </el-select>
+ <div style="display:flex; justify-content:flex-end; gap: 8px;">
+ <el-button
+ size="small"
+ @click="scope.row.__inlineOtherAmountAdding = false; scope.row.__inlineOtherAmountAddId = null"
+ >
+ 鍙栨秷
+ </el-button>
+ <el-button
+ type="primary"
+ size="small"
+ :disabled="scope.row.__inlineOtherAmountAddId === null || scope.row.__inlineOtherAmountAddId === undefined || scope.row.__inlineOtherAmountAddId === ''"
+ @click="confirmAddOtherAmountForRow(scope.row)"
+ >
+ 纭娣诲姞
+ </el-button>
+ </div>
+ </div>
<div v-if="Array.isArray(scope.row.salesProductProcessList) && scope.row.salesProductProcessList.length > 0"
- style="display:flex; flex-direction:column; gap: 8px;"
+ style="display:flex; flex-wrap:wrap; gap: 8px;"
>
<div
v-for="(item, idx) in scope.row.salesProductProcessList"
:key="String(item.id) + '_' + idx"
- style="display:flex; align-items:center; gap: 8px;"
+ style="display:flex; align-items:center; gap: 8px; flex: 0 0 calc(50% - 4px); max-width: calc(50% - 4px);"
>
<el-tag type="info" style="max-width: 170px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
{{ item.processName }}
@@ -608,10 +670,11 @@
缂栬緫
</el-button>
<el-popover
- :width="420"
+ :width="560"
trigger="click"
:hide-after="0"
- v-model:visible="scope.row.__otherAmountPopoverVisible"
+ :visible="scope.row.__otherAmountPopoverVisible"
+ @update:visible="(val) => handleOtherAmountPopoverVisibleChange(scope.row, val)"
>
<template #reference>
<el-button
@@ -639,14 +702,52 @@
鏂板
</el-button>
</div>
+ <div
+ v-if="scope.row.__inlineOtherAmountAdding"
+ style="display:flex; flex-direction:column; gap: 8px; margin-bottom: 10px;"
+ @click.stop
+ >
+ <el-select
+ v-model="scope.row.__inlineOtherAmountAddId"
+ filterable
+ clearable
+ placeholder="璇烽�夋嫨鍏朵粬閲戦椤圭洰"
+ style="width: 100%;"
+ :disabled="isProductShipped(scope.row)"
+ >
+ <el-option
+ v-for="item in otherAmountSelectOptions"
+ :key="item.id"
+ :label="item.processName"
+ :value="item.id"
+ />
+ </el-select>
+ <div style="display:flex; justify-content:flex-end; gap: 8px;">
+ <el-button
+ size="small"
+ :disabled="isProductShipped(scope.row)"
+ @click="scope.row.__inlineOtherAmountAdding = false; scope.row.__inlineOtherAmountAddId = null"
+ >
+ 鍙栨秷
+ </el-button>
+ <el-button
+ type="primary"
+ size="small"
+ :disabled="isProductShipped(scope.row) || scope.row.__inlineOtherAmountAddId === null || scope.row.__inlineOtherAmountAddId === undefined || scope.row.__inlineOtherAmountAddId === ''"
+ @click="confirmAddOtherAmountForRow(scope.row)"
+ >
+ 纭娣诲姞
+ </el-button>
+ </div>
+ </div>
<div v-if="Array.isArray(scope.row.salesProductProcessList) && scope.row.salesProductProcessList.length > 0"
- style="display:flex; flex-direction:column; gap: 8px;"
+ style="display:flex; flex-wrap:wrap; gap: 8px;"
>
<div
v-for="(item, idx) in scope.row.salesProductProcessList"
:key="String(item.id) + '_' + idx"
- style="display:flex; align-items:center; gap: 8px;"
+ style="display:flex; align-items:center; gap: 8px; flex: 0 0 calc(50% - 4px); max-width: calc(50% - 4px);"
>
<el-tag type="info" style="max-width: 170px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
{{ item.processName }}
@@ -1278,7 +1379,7 @@
<script setup>
import { getToken } from "@/utils/auth";
import pagination from "@/components/PIMTable/Pagination.vue";
-import {onMounted, ref, getCurrentInstance, watch} from "vue";
+import {onMounted, ref, getCurrentInstance, watch, nextTick} from "vue";
import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
import { ElMessageBox, ElMessage } from "element-plus";
import { ArrowDown } from "@element-plus/icons-vue";
@@ -1308,6 +1409,7 @@
getSalesOrder,
getSalesInvoices,
getSalesLabel,
+ salesStock,
} from "@/api/salesManagement/salesLedger.js";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import useFormData from "@/hooks/useFormData.js";
@@ -1356,6 +1458,7 @@
entryDateStart: undefined,
entryDateEnd: undefined,
deliveryStatus: undefined, // 鍙戣揣鐘舵�侊細1鏈彂璐� 2瀹℃壒涓� 3瀹℃壒澶辫触 4宸插彂璐�
+ stockStatus: undefined, // 鍏ュ簱鐘舵�侊細0鏈叆搴� 1宸插叆搴�
},
form: {
salesContractNo: "",
@@ -1436,6 +1539,8 @@
if (!row || typeof row !== "object") return;
if (!Array.isArray(row.salesProductProcessList)) row.salesProductProcessList = [];
if (row.__otherAmountPopoverVisible === undefined || row.__otherAmountPopoverVisible === null) row.__otherAmountPopoverVisible = false;
+ if (row.__inlineOtherAmountAdding === undefined || row.__inlineOtherAmountAdding === null) row.__inlineOtherAmountAdding = false;
+ if (row.__inlineOtherAmountAddId === undefined) row.__inlineOtherAmountAddId = null;
if (row.width === undefined || row.width === null) row.width = 0;
if (row.height === undefined || row.height === null) row.height = 0;
if (row.perimeter === undefined || row.perimeter === null) row.perimeter = 0;
@@ -1461,10 +1566,16 @@
editingProductRow.value = null;
};
+const hasEditingProductRow = () => {
+ return (productData.value || []).some((r) => r && r.__editing);
+};
+
const addProductInline = async () => {
if (operationType.value === "view") return;
- // 宸叉湁琛屽湪缂栬緫鏃讹紝鍏堝彇娑堝叾缂栬緫鐘舵�侊紝閬垮厤娣蜂贡
- stopOtherEditingRows();
+ if (hasEditingProductRow()) {
+ proxy.$modal.msgWarning("璇峰厛淇濆瓨鎴栧彇娑堝綋鍓嶇紪杈戣");
+ return;
+ }
await getProductOptions();
await fetchOtherAmountSelectOptions(true);
const row = {
@@ -1591,6 +1702,9 @@
// 鎻愪氦鍓嶅厹搴曡绠椾竴娆★紙娌跨敤鍘熼�昏緫锛�
recalcAreaTotals();
+ // 鎻愪氦鍏滃簳锛氱◣鐜�/鏁伴噺鏈~鏃舵寜鏁板瓧 0 浼犻��
+ row.taxRate = Number(row.taxRate ?? 0) || 0;
+ row.quantity = Number(row.quantity ?? 0) || 0;
// 瑙勮寖鍖栧叾浠栭噾棰濇彁浜ょ粨鏋�
row.salesProductProcessList = (Array.isArray(row.salesProductProcessList) ? row.salesProductProcessList : [])
@@ -1655,11 +1769,43 @@
}
ensureProductRowDefaults(row);
productForm.value = row;
+ otherAmountAddTargetRow.value = row;
await fetchOtherAmountSelectOptions(true);
mergeOtherAmountOptionsBySelection(row.salesProductProcessList);
row.salesProductProcessList = fillOtherAmountProcessName(row.salesProductProcessList);
// 鍙仛鏁版嵁鍑嗗涓庢墦寮�娴眰锛堟柊澧炵敱娴眰鍐呮寜閽Е鍙戯級
row.__otherAmountPopoverVisible = true;
+};
+
+const keepOtherAmountPopoverOpenKey = ref(null);
+const keepOtherAmountPopoverOpenUntil = ref(0);
+
+const getOtherAmountRowKey = (row) => String(row?.__tempKey ?? row?.id ?? "");
+
+const lockOtherAmountPopoverOpen = (row, durationMs = 1200) => {
+ const key = getOtherAmountRowKey(row);
+ if (!key) return;
+ keepOtherAmountPopoverOpenKey.value = key;
+ keepOtherAmountPopoverOpenUntil.value = Date.now() + durationMs;
+};
+
+const handleOtherAmountPopoverVisibleChange = (row, visible) => {
+ if (!row) return;
+ if (visible) {
+ row.__otherAmountPopoverVisible = true;
+ return;
+ }
+ if (row.__inlineOtherAmountAdding) {
+ row.__otherAmountPopoverVisible = true;
+ return;
+ }
+ const key = getOtherAmountRowKey(row);
+ const shouldKeepOpen = Boolean(
+ key &&
+ keepOtherAmountPopoverOpenKey.value === key &&
+ Date.now() < keepOtherAmountPopoverOpenUntil.value
+ );
+ row.__otherAmountPopoverVisible = shouldKeepOpen;
};
const startAddOtherAmountForRow = async (row) => {
@@ -1674,7 +1820,36 @@
await fetchOtherAmountSelectOptions(true);
mergeOtherAmountOptionsBySelection(row.salesProductProcessList);
row.salesProductProcessList = fillOtherAmountProcessName(row.salesProductProcessList);
- startAddOtherAmount();
+ row.__inlineOtherAmountAddId = null;
+ row.__inlineOtherAmountAdding = true;
+ row.__otherAmountPopoverVisible = true;
+};
+
+const confirmAddOtherAmountForRow = (row) => {
+ if (!row) return;
+ ensureProductRowDefaults(row);
+ productForm.value = row;
+ const selectedId = row.__inlineOtherAmountAddId;
+ if (selectedId === null || selectedId === undefined || selectedId === "") return;
+ const opt = otherAmountSelectOptions.value.find((o) => String(o.id) === String(selectedId));
+ if (!opt) return;
+ const exists = (row.salesProductProcessList ?? []).some(
+ (it) => String(it?.id) === String(opt.id)
+ );
+ if (exists) {
+ proxy.$modal.msgWarning("璇ュ叾浠栭噾棰濋」鐩凡娣诲姞");
+ return;
+ }
+ row.salesProductProcessList.push({
+ id: opt.id,
+ processName: opt.processName,
+ unitPrice: opt.unitPrice ?? 0,
+ quantity: 0,
+ });
+ row.__inlineOtherAmountAddId = null;
+ row.__inlineOtherAmountAdding = false;
+ row.__otherAmountPopoverVisible = true;
+ calculateFromUnitPrice(true);
};
const removeOtherAmountAtForRow = (row, index) => {
@@ -1892,6 +2067,8 @@
// 鍏朵粬閲戦锛氱偣鍑烩�滄柊澧炩�濆悗鍦ㄥ脊绐楅噷閫夋嫨涓�涓」鐩�
const otherAmountAddDialogVisible = ref(false);
const otherAmountAddId = ref(null);
+const otherAmountAddTargetRow = ref(null);
+const otherAmountAddTargetRowKey = ref(null);
const startAddOtherAmount = () => {
if (operationType.value === "view") return;
@@ -1906,6 +2083,10 @@
const cancelAddOtherAmount = () => {
otherAmountAddDialogVisible.value = false;
otherAmountAddId.value = null;
+ otherAmountAddTargetRow.value = null;
+ otherAmountAddTargetRowKey.value = null;
+ keepOtherAmountPopoverOpenKey.value = null;
+ keepOtherAmountPopoverOpenUntil.value = 0;
};
const handleOtherAmountSelected = (id) => {
@@ -1930,9 +2111,30 @@
});
calculateFromUnitPrice(true);
- // 閫夋嫨瀹屾垚鍚庡叧闂脊绐楋紝涓嬩竴娆″彲鍐嶆鐐瑰嚮鈥滄柊澧炩�濈户缁坊鍔�
+ // 閫夋嫨瀹屾垚鍚庡叧闂�滄柊澧炲叾浠栭噾棰濃�濆脊绐楋紝骞朵繚鎸佽鍐呪�滃叾浠栭噾棰濃�濆脊灞傚紑鍚紝渚夸簬鐩存帴濉啓鏁伴噺
otherAmountAddDialogVisible.value = false;
otherAmountAddId.value = null;
+ const reopenOtherAmountPopover = () => {
+ let targetRow = otherAmountAddTargetRow.value;
+ const rowKey = otherAmountAddTargetRowKey.value;
+ if (rowKey) {
+ const matchedRow = (productData.value || []).find(
+ (it) => String(it?.__tempKey ?? it?.id ?? "") === rowKey
+ );
+ if (matchedRow) targetRow = matchedRow;
+ }
+ if (targetRow && typeof targetRow === "object") {
+ lockOtherAmountPopoverOpen(targetRow, 1500);
+ targetRow.__otherAmountPopoverVisible = true;
+ }
+ };
+ nextTick(() => {
+ reopenOtherAmountPopover();
+ setTimeout(reopenOtherAmountPopover, 0);
+ setTimeout(reopenOtherAmountPopover, 80);
+ });
+ otherAmountAddTargetRow.value = null;
+ otherAmountAddTargetRowKey.value = null;
};
const confirmAddOtherAmount = () => {
@@ -2066,6 +2268,43 @@
.catch(() => {
tableLoading.value = false;
});
+};
+
+// 鍏ュ簱锛堥攢鍞彴璐� -> 鍏ュ簱鐘舵�侊級
+const handleSalesStock = async () => {
+ if (selectedRows.value.length !== 1) {
+ ElMessage.warning("璇峰嬀閫変竴鏉″彴璐︽暟鎹繘琛屽叆搴�");
+ return;
+ }
+ const row = selectedRows.value[0] || {};
+ const id = row?.id;
+ if (!id) {
+ ElMessage.warning("鎵�閫夋暟鎹己灏慽d锛屾棤娉曞叆搴�");
+ return;
+ }
+ if (Number(row.stockStatus) === 1) {
+ ElMessage.info("璇ュ彴璐﹀凡鍏ュ簱锛屾棤闇�閲嶅鎿嶄綔");
+ return;
+ }
+ try {
+ await ElMessageBox.confirm("纭瀵规墍閫夊彴璐︽墽琛屽叆搴擄紵", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ });
+ } catch {
+ return;
+ }
+ proxy?.$modal?.loading?.("姝e湪鍏ュ簱锛岃绋嶅��...");
+ try {
+ await salesStock({ id });
+ proxy?.$modal?.msgSuccess?.("鍏ュ簱鎴愬姛");
+ await getList();
+ } catch (e) {
+ proxy?.$modal?.msgError?.("鍏ュ簱澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ proxy?.$modal?.closeLoading?.();
+ }
};
// 鎵撳紑鈥滃伐鑹鸿矾绾块厤缃�濋�夋嫨寮圭獥锛堝繀椤绘樉寮忛�夋嫨锛�
@@ -2213,15 +2452,18 @@
}
return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
};
-function convertIdToValue(data) {
+function convertIdToValue(data, level = 0) {
return data.map((item) => {
const { id, children, ...rest } = item;
+ const hasChildren = Array.isArray(children) && children.length > 0;
const newItem = {
...rest,
value: id, // 灏� id 鏀逛负 value
+ // 浠呭厑璁稿彾瀛愯妭鐐硅閫夋嫨锛堟湁瀛愯妭鐐圭殑鍒嗙被鑺傜偣缁熶竴绂佺敤锛�
+ disabled: Boolean(rest?.disabled) || hasChildren,
};
- if (children && children.length > 0) {
- newItem.children = convertIdToValue(children);
+ if (hasChildren) {
+ newItem.children = convertIdToValue(children, level + 1);
}
return newItem;
@@ -2505,6 +2747,8 @@
const cleanedProducts = (productData.value || []).map((p) => {
if (!p || typeof p !== "object") return p;
const { __editing, __isNew, __backup, __productCategoryId, __tempKey, __otherAmountPopoverVisible, ...rest } = p;
+ rest.taxRate = Number(rest.taxRate ?? 0) || 0;
+ rest.quantity = Number(rest.quantity ?? 0) || 0;
return rest;
});
form.value.productData = proxy.HaveJson(cleanedProducts);
@@ -2625,6 +2869,9 @@
// 闈㈢Н/鎬昏瀛楁鍦ㄦ彁浜ゅ墠鍏滃簳璁$畻涓�娆�
recalcAreaTotals();
+ // 鎻愪氦鍏滃簳锛氱◣鐜�/鏁伴噺鏈~鏃舵寜鏁板瓧 0 浼犻��
+ productForm.value.taxRate = Number(productForm.value.taxRate ?? 0) || 0;
+ productForm.value.quantity = Number(productForm.value.quantity ?? 0) || 0;
// 鍏朵粬閲戦鍙彁浜� {id, processName, quantity}锛堝悗绔瓧娈碉細salesProductProcessList锛�
productForm.value.salesProductProcessList = (Array.isArray(productForm.value.salesProductProcessList)
? productForm.value.salesProductProcessList
@@ -3060,10 +3307,10 @@
// 鏍规嵁涓嶅惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
const calculateFromExclusiveTotalPrice = () => {
- if (!productForm.value.taxRate) {
- proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
- return;
- }
+ // if (!productForm.value.taxRate) {
+ // proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ // return;
+ // }
if (isCalculating.value) return;
const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice);
@@ -3093,10 +3340,10 @@
// 鏍规嵁鏁伴噺鍙樺寲璁$畻鎬讳环
const calculateFromQuantity = () => {
- if (!productForm.value.taxRate) {
- proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
- return;
- }
+ // if (!productForm.value.taxRate) {
+ // proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ // return;
+ // }
if (isCalculating.value) return;
const quantity = parseFloat(productForm.value.quantity);
@@ -3130,10 +3377,10 @@
// 鏍规嵁鍚◣鍗曚环鍙樺寲璁$畻鎬讳环
const calculateFromUnitPrice = (silent = false) => {
- if (!productForm.value.taxRate) {
- if (!silent) proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
- return;
- }
+ // if (!productForm.value.taxRate) {
+ // if (!silent) proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ // return;
+ // }
if (isCalculating.value) return;
const quantity = parseFloat(productForm.value.quantity);
@@ -3167,10 +3414,10 @@
// 鏍规嵁绋庣巼鍙樺寲璁$畻涓嶅惈绋庢�讳环
const calculateFromTaxRate = () => {
- if (!productForm.value.taxRate) {
- proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
- return;
- }
+ // if (!productForm.value.taxRate) {
+ // proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ // return;
+ // }
if (isCalculating.value) return;
const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
--
Gitblit v1.9.3