From 5a520798abc9bef73c308edaa5d606ecdd7ce72a Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期四, 14 五月 2026 09:11:41 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' of http://114.132.189.42:9002/r/product-inventory-management into dev_西宁_青铝绿行
---
src/views/index.vue | 2
src/views/financialManagement/receivable/salesOut.vue | 272 -
multiple/config.json | 40
src/views/basicData/product/index.vue | 38
src/api/financialManagement/voucher.js | 54
src/views/financialManagement/generalLedger/index.vue | 172 +
src/views/salesManagement/returnOrder/components/detailDia.vue | 260 ++
src/api/procurementManagement/purchase_return_order.js | 9
src/views/financialManagement/voucher/index.vue | 439 +++-
src/views/salesManagement/salesLedger/index.vue | 2
src/api/financialManagement/ledger.js | 19
src/views/salesManagement/returnOrder/index.vue | 24
multiple/assets/favicon/KYHGfavicon.ico | 0
src/views/basicData/customerFile/index.vue | 35
src/views/salesManagement/returnOrder/components/formDia.vue | 228 ++
src/views/procurementManagement/purchaseReturnOrder/index.vue | 487 +++-
src/views/financialManagement/assets/intangibleAssets.vue | 190 +
public/favicon.ico | 0
src/views/procurementManagement/purchaseReturnOrder/ProductList.vue | 91
src/views/financialManagement/voucher/detailLedger.vue | 434 ++--
src/api/financialManagement/accountPurchase.js | 19
src/views/financialManagement/voucher/generalLedger.vue | 382 ++-
src/views/inventoryManagement/receiptManagement/Record.vue | 11
src/views/qualityManagement/processInspection/components/formDia.vue | 844 ++++----
src/views/salesManagement/deliveryLedger/index.vue | 16
multiple/assets/logo/HYZCLogo.png | 0
src/api/financialManagement/fixedAsset.js | 50
FINANCIAL_MANAGEMENT_BACKEND_SPEC.md | 233 ++
src/assets/logo/logo.png | 0
multiple/assets/favicon/WTXCfavicon.ico | 0
src/api/basicData/customer.js | 8
src/router/index.js | 7
src/views/financialManagement/assets/fixedAssets.vue | 182 +
src/views/financialManagement/receivable/salesReturn.vue | 308 --
multiple/assets/logo/DYKJLogo.png | 0
multiple/assets/logo/WTXCLogo.png | 0
src/views/financialManagement/payable/purchaseIn.vue | 326 --
src/api/financialManagement/intangibleAsset.js | 50
multiple/assets/favicon/DYKJfavicon.ico | 0
src/views/procurementManagement/purchaseReturnOrder/New.vue | 92
multiple/assets/logo/KYHGLogo.png | 0
src/api/financialManagement/accountSales.js | 19
src/views/inventoryManagement/stockReport/index.vue | 14
src/views/financialManagement/payable/purchaseReturn.vue | 239 ++
multiple/assets/favicon/HYZCfavicon.ico | 0
45 files changed, 3,566 insertions(+), 2,030 deletions(-)
diff --git a/FINANCIAL_MANAGEMENT_BACKEND_SPEC.md b/FINANCIAL_MANAGEMENT_BACKEND_SPEC.md
new file mode 100644
index 0000000..ee7e5b7
--- /dev/null
+++ b/FINANCIAL_MANAGEMENT_BACKEND_SPEC.md
@@ -0,0 +1,233 @@
+# 璐㈠姟绠$悊鍚庣鏂囨。锛堜粎璐熻矗妯″潡锛�
+
+鏇存柊鏃堕棿锛�2026-05-12
+閫傜敤鑼冨洿锛堜粎浠ヤ笅 6 涓ā鍧楋級锛�
+1. 鍥哄畾璧勪骇锛坄/financial/fixed-assets`锛�
+2. 鏃犲舰璧勪骇锛坄/financial/intangible-assets`锛�
+3. 鎬昏处绉戠洰锛坄/financial/general-ledger`锛�
+4. 鍑瘉锛坄/financial/voucher`锛�
+5. 绉戠洰鎬昏处锛坄/financial/voucher-general-ledger`锛�
+6. 绉戠洰鏄庣粏璐︼紙`/financial/voucher-detail-ledger`锛�
+
+---
+
+## 1. 缁熶竴绾﹀畾
+
+### 1.1 鍝嶅簲缁撴瀯
+```json
+{
+ "code": 200,
+ "msg": "success",
+ "data": {}
+}
+```
+
+### 1.2 鍒嗛〉缁撴瀯锛堝鏋滄槸鍒嗛〉鎺ュ彛锛�
+璇锋眰鍙傛暟寤鸿锛�
+- `current`锛堥〉鐮侊級
+- `size`锛堟瘡椤垫潯鏁帮級
+
+鍝嶅簲寤鸿锛�
+```json
+{
+ "code": 200,
+ "data": {
+ "records": [],
+ "total": 0
+ }
+}
+```
+
+### 1.3 閲戦涓庣簿搴�
+- 閲戦瀛楁寤鸿 `decimal(18,2)`銆�
+- 鍓嶅悗绔粺涓�淇濈暀涓や綅灏忔暟銆�
+
+---
+
+## 2. 妯″潡涓�锛氭�昏处绉戠洰锛堝凡鎺ョ湡瀹� API锛�
+
+鍓嶇鏂囦欢锛歚src/views/financialManagement/generalLedger/index.vue`
+API 鏂囦欢锛歚src/api/financialManagement/accountSubject.js`
+
+### 2.1 鎺ュ彛鐜扮姸
+- `GET /accountSubject/list`
+- `POST /accountSubject/add`
+- `PUT /accountSubject/edit`
+- `DELETE /accountSubject/remove/{ids}`
+- `POST /accountSubject/export`
+
+### 2.2 瀛楁妯″瀷
+- `id`
+- `subjectCode`锛堢鐩紪鐮侊級
+- `subjectName`锛堢鐩悕绉帮級
+- `subjectType`锛堢鐩被鍨嬶級
+- `balanceDirection`锛堜綑棰濇柟鍚戯細鍊熸柟/璐锋柟锛�
+- `status`锛�0 鍚敤锛�1 绂佺敤锛�
+- `remark`
+
+### 2.3 涓氬姟瑙勫垯
+- `subjectCode`銆乣subjectName`銆乣subjectType` 蹇呭~銆�
+- 鍒犻櫎闇�瑕佸仛寮曠敤鏍¢獙锛堣嫢宸茶鍑瘉鍒嗗綍寮曠敤锛屼笉鍏佽鍒犻櫎锛夈��
+
+---
+
+## 3. 妯″潡浜岋細鍥哄畾璧勪骇锛堝綋鍓嶅墠绔负 mock锛屽緟鍚庣瀹炵幇锛�
+
+鍓嶇鏂囦欢锛歚src/views/financialManagement/assets/fixedAssets.vue`
+
+### 3.1 寤鸿鎺ュ彛
+- `GET /financial/fixedAsset/page`
+- `POST /financial/fixedAsset/add`
+- `PUT /financial/fixedAsset/update`
+- `DELETE /financial/fixedAsset/delete`
+- `POST /financial/fixedAsset/depreciate`锛堟寜鏈堣鎻愶級
+
+### 3.2 瀛楁妯″瀷
+- `id, assetCode, assetName, category, specification`
+- `purchaseDate, originalValue, usefulLife, residualRate`
+- `accumulatedDepreciation, netValue`
+- `location, department, keeper, status, remark`
+
+### 3.3 鏍稿績鍏紡锛堝繀椤讳竴鑷达級
+- `monthlyDepreciation = originalValue * (1 - residualRate/100) / (usefulLife*12)`
+- `accumulatedDepreciation += monthlyDepreciation`
+- `netValue = originalValue - accumulatedDepreciation`
+
+### 3.4 鐘舵�佸缓璁�
+- `in_use`锛堝湪鐢級
+- `idle`锛堥棽缃級
+- `repair`锛堢淮淇腑锛�
+- `scrapped`锛堟姤搴燂級
+
+---
+
+## 4. 妯″潡涓夛細鏃犲舰璧勪骇锛堝綋鍓嶅墠绔负 mock锛屽緟鍚庣瀹炵幇锛�
+
+鍓嶇鏂囦欢锛歚src/views/financialManagement/assets/intangibleAssets.vue`
+
+### 4.1 寤鸿鎺ュ彛
+- `GET /financial/intangibleAsset/page`
+- `POST /financial/intangibleAsset/add`
+- `PUT /financial/intangibleAsset/update`
+- `DELETE /financial/intangibleAsset/delete`
+- `POST /financial/intangibleAsset/amortize`锛堟寜鏈堟憡閿�锛�
+
+### 4.2 瀛楁妯″瀷
+- `id, assetCode, assetName, category, certificateNo`
+- `acquisitionDate, originalValue, amortizationPeriod, residualRate`
+- `accumulatedAmortization, netValue`
+- `validityDate, status, description, remark`
+
+### 4.3 鏍稿績鍏紡锛堝繀椤讳竴鑷达級
+- `monthlyAmortization = originalValue * (1 - residualRate/100) / (amortizationPeriod*12)`
+- `accumulatedAmortization += monthlyAmortization`
+- `netValue = originalValue - accumulatedAmortization`
+- 褰� `netValue <= 0`锛�
+ - `netValue = 0`
+ - `status = amortized`
+
+### 4.4 鐘舵�佸缓璁�
+- `in_use`锛堝湪鐢級
+- `expired`锛堝埌鏈燂級
+- `amortized`锛堝凡鎽婇攢瀹岋級
+
+---
+
+## 5. 妯″潡鍥涳細鍑瘉锛堝綋鍓嶅墠绔负 mock锛屽緟鍚庣瀹炵幇锛�
+
+鍓嶇鏂囦欢锛歚src/views/financialManagement/voucher/index.vue`
+
+### 5.1 寤鸿鎺ュ彛
+- `GET /financial/voucher/page`
+- `POST /financial/voucher/add`
+- `PUT /financial/voucher/update`
+- `POST /financial/voucher/post`锛堣繃璐︼級
+- `POST /financial/voucher/cancel`锛堜綔搴燂級
+- `GET /financial/voucher/detail/{id}`
+
+### 5.2 涓昏〃瀛楁
+- `id, voucherNo, voucherDate, summary`
+- `debit, credit, creator, status, attachmentCount, remark`
+
+### 5.3 鍒嗗綍瀛楁
+- `subjectCode, subjectName, summary, debit, credit`
+
+### 5.4 鍏抽敭鏍¢獙
+- 鍒嗗綍鑷冲皯涓�鏉℃湁鏁堣锛堢鐩笉绌猴紝涓斿�熸柟鎴栬捶鏂� > 0锛夈��
+- 鍊熻捶骞宠 锛歚sum(debit) == sum(credit)` 涓� > 0锛屼笉婊¤冻绂佹淇濆瓨銆�
+
+### 5.5 鐘舵�佹祦杞�
+- `unposted -> posted`
+- `unposted -> cancelled`
+
+---
+
+## 6. 妯″潡浜旓細绉戠洰鎬昏处锛堝綋鍓嶅墠绔负 mock锛屽緟鍚庣瀹炵幇锛�
+
+鍓嶇鏂囦欢锛歚src/views/financialManagement/voucher/generalLedger.vue`
+
+### 6.1 寤鸿鎺ュ彛
+- `GET /financial/ledger/general`
+
+### 6.2 璇锋眰鍙傛暟
+- `subjectCode`锛堟湯绾ф垨鎸囧畾绉戠洰锛�
+- `startMonth`锛圷YYY-MM锛�
+- `endMonth`锛圷YYY-MM锛�
+
+### 6.3 鍝嶅簲瀛楁
+- `date, voucherNo, summary`
+- `debit, credit, direction, balance`
+
+### 6.4 瑙勫垯
+- 浠呭湪閫夋嫨绉戠洰鍚庤繑鍥炴暟鎹��
+- 鏀寔鈥滄湡鍒濅綑棰� / 鏈湀鍚堣 / 鏈勾绱鈥濊锛堝彲閫氳繃 `rowType` 瀛楁鍖哄垎锛夈��
+
+---
+
+## 7. 妯″潡鍏細绉戠洰鏄庣粏璐︼紙褰撳墠鍓嶇涓� mock锛屽緟鍚庣瀹炵幇锛�
+
+鍓嶇鏂囦欢锛歚src/views/financialManagement/voucher/detailLedger.vue`
+
+### 7.1 寤鸿鎺ュ彛
+- `GET /financial/ledger/detail`
+
+### 7.2 璇锋眰鍙傛暟
+- `subjectCode`
+- `auxiliaryType`锛坈ustomer/supplier/department/employee/project锛�
+- `auxiliaryId`
+- `startMonth`锛圷YYY-MM锛�
+- `endMonth`锛圷YYY-MM锛�
+
+### 7.3 鍝嶅簲瀛楁
+- `date, voucherNo, summary`
+- `debit, credit, direction, balance`
+
+### 7.4 瑙勫垯
+- 鍏堥�夌鐩紝鍐嶆煡鏄庣粏銆�
+- 杈呭姪鏍哥畻鏉′欢涓哄彲閫夛紝浣嗗缓璁悗绔敮鎸佺淮搴﹁繃婊ゃ��
+
+---
+
+## 8. 鎺ㄨ崘鏈�灏忚〃璁捐锛堜粎鏈寖鍥达級
+
+- `fin_account_subject`
+- `fin_fixed_asset`
+- `fin_intangible_asset`
+- `fin_voucher`
+- `fin_voucher_entry`
+- `fin_ledger_snapshot_general`锛堝彲閫夛紝鍋氭�ц兘浼樺寲锛�
+- `fin_ledger_snapshot_detail`锛堝彲閫夛紝鍋氭�ц兘浼樺寲锛�
+
+---
+
+## 9. AI 鐢熸垚鍚庣浠诲姟椤哄簭锛堝缓璁級
+
+1. 鍏堝畬鎴� **鎬昏处绉戠洰**锛堝凡鏈� API锛屾渶绋冲畾锛夈��
+2. 瀹屾垚 **鍑瘉 + 鍒嗗綍 + 鍊熻捶骞宠 鏍¢獙 + 鐘舵�佹祦杞�**銆�
+3. 瀹炵幇 **绉戠洰鎬昏处 / 绉戠洰鏄庣粏璐�** 鏌ヨ銆�
+4. 瀹炵幇 **鍥哄畾璧勪骇鎶樻棫** 涓� **鏃犲舰璧勪骇鎽婇攢**銆�
+5. 琛ユ祴璇曪細
+ - 鍊熻捶骞宠 鏍¢獙
+ - 鎶樻棫/鎽婇攢鍏紡
+ - 绉戠洰琚紩鐢ㄧ姝㈠垹闄�
+
diff --git a/multiple/assets/favicon/DYKJfavicon.ico b/multiple/assets/favicon/DYKJfavicon.ico
new file mode 100644
index 0000000..8437010
--- /dev/null
+++ b/multiple/assets/favicon/DYKJfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/HYZCfavicon.ico b/multiple/assets/favicon/HYZCfavicon.ico
new file mode 100644
index 0000000..996ab43
--- /dev/null
+++ b/multiple/assets/favicon/HYZCfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/KYHGfavicon.ico b/multiple/assets/favicon/KYHGfavicon.ico
new file mode 100644
index 0000000..8178896
--- /dev/null
+++ b/multiple/assets/favicon/KYHGfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/WTXCfavicon.ico b/multiple/assets/favicon/WTXCfavicon.ico
new file mode 100644
index 0000000..ce783dc
--- /dev/null
+++ b/multiple/assets/favicon/WTXCfavicon.ico
Binary files differ
diff --git a/multiple/assets/logo/DYKJLogo.png b/multiple/assets/logo/DYKJLogo.png
new file mode 100644
index 0000000..b96b61c
--- /dev/null
+++ b/multiple/assets/logo/DYKJLogo.png
Binary files differ
diff --git a/multiple/assets/logo/HYZCLogo.png b/multiple/assets/logo/HYZCLogo.png
new file mode 100644
index 0000000..e8e4cad
--- /dev/null
+++ b/multiple/assets/logo/HYZCLogo.png
Binary files differ
diff --git a/multiple/assets/logo/KYHGLogo.png b/multiple/assets/logo/KYHGLogo.png
new file mode 100644
index 0000000..0186c87
--- /dev/null
+++ b/multiple/assets/logo/KYHGLogo.png
Binary files differ
diff --git a/multiple/assets/logo/WTXCLogo.png b/multiple/assets/logo/WTXCLogo.png
new file mode 100644
index 0000000..0a486cd
--- /dev/null
+++ b/multiple/assets/logo/WTXCLogo.png
Binary files differ
diff --git a/multiple/config.json b/multiple/config.json
index e6d47ef..802ef67 100644
--- a/multiple/config.json
+++ b/multiple/config.json
@@ -45,8 +45,8 @@
"BTYX": {
"env": {
"VITE_APP_TITLE": "娌冲崡甯お浼橀�夎繘鍑哄彛鏈夐檺鍏徃",
- "VITE_BASE_API": "http://127.0.0.1:9001",
- "VITE_JAVA_API": "http://127.0.0.1:9000"
+ "VITE_BASE_API": "http://1.15.17.182:9056",
+ "VITE_JAVA_API": "http://1.15.17.182:9057"
},
"logo": "logo/BTYXLogo.png",
"favicon": "favicon/BTYXfavicon.ico"
@@ -60,6 +60,42 @@
"logo": "logo/ZXZNLogo.png",
"favicon": "favicon/ZXZNfavicon.ico"
},
+ "HYZC": {
+ "env": {
+ "VITE_APP_TITLE": "灞辫タ鍗庝嚎浼楁垚寤烘潗鏈夐檺鍏徃",
+ "VITE_BASE_API": "http://36.137.13.103:9001",
+ "VITE_JAVA_API": "http://36.137.13.103:9000"
+ },
+ "logo": "logo/HYZCLogo.png",
+ "favicon": "favicon/HYZCfavicon.ico"
+ },
+ "WTXC": {
+ "env": {
+ "VITE_APP_TITLE": "瀹佸涓囬�氭柊鏉�",
+ "VITE_BASE_API": "http://42.63.71.140:9001",
+ "VITE_JAVA_API": "http://42.63.71.140:9000"
+ },
+ "logo": "logo/WTXCLogo.png",
+ "favicon": "favicon/WTXCfavicon.ico"
+ },
+ "KYHG": {
+ "env": {
+ "VITE_APP_TITLE": "灞辫タ鍧ゆ簮鍖栧伐鏈夐檺鍏徃",
+ "VITE_BASE_API": "http://36.137.13.29:9001",
+ "VITE_JAVA_API": "http://36.137.13.29:9000"
+ },
+ "logo": "logo/KYHGLogo.png",
+ "favicon": "favicon/KYHGfavicon.ico"
+ },
+ "DYKJ": {
+ "env": {
+ "VITE_APP_TITLE": "灞辫タ寰风泭绉戞妧鏈夐檺鍏徃",
+ "VITE_BASE_API": "http://36.137.12.37:9001",
+ "VITE_JAVA_API": "http://36.137.12.37:9000"
+ },
+ "logo": "logo/DYKJLogo.png",
+ "favicon": "favicon/DYKJfavicon.ico"
+ },
"logo": "/src/assets/logo/logo.png",
"favicon": "/public/favicon.ico"
}
diff --git a/public/favicon.ico b/public/favicon.ico
index 2fa05d5..ce783dc 100644
--- a/public/favicon.ico
+++ b/public/favicon.ico
Binary files differ
diff --git a/src/api/basicData/customer.js b/src/api/basicData/customer.js
index 28f2eab..0934193 100644
--- a/src/api/basicData/customer.js
+++ b/src/api/basicData/customer.js
@@ -26,6 +26,14 @@
})
}
+// 娴佸叆鍏捣
+export function backCustomer(id) {
+ return request({
+ url: '/basic/customer/back/' + id,
+ method: 'post'
+ })
+}
+
export function shareCustomer(data) {
return request({
url: '/basic/customer/together',
diff --git a/src/api/financialManagement/accountPurchase.js b/src/api/financialManagement/accountPurchase.js
new file mode 100644
index 0000000..9e2d508
--- /dev/null
+++ b/src/api/financialManagement/accountPurchase.js
@@ -0,0 +1,19 @@
+import request from "@/utils/request";
+
+/** 閲囪喘鍏ュ簱鍒嗛〉鍒楄〃 */
+export const listPageAccountPurchase = (params) => {
+ return request({
+ url: "/accountPurchase/listPageAccountPurchase",
+ method: "get",
+ params,
+ });
+};
+
+/** 閲囪喘閫�璐у垎椤靛垪琛� */
+export const listPageAccountPurchaseReturn = (params) => {
+ return request({
+ url: "/accountPurchase/listPageAccountPurchaseReturn",
+ method: "get",
+ params,
+ });
+};
diff --git a/src/api/financialManagement/accountSales.js b/src/api/financialManagement/accountSales.js
new file mode 100644
index 0000000..e56d50f
--- /dev/null
+++ b/src/api/financialManagement/accountSales.js
@@ -0,0 +1,19 @@
+import request from "@/utils/request";
+
+/** 閿�鍞嚭搴撳垎椤靛垪琛� */
+export const listPageAccountSales = (params) => {
+ return request({
+ url: "/accountSales/listPageAccountSales",
+ method: "get",
+ params,
+ });
+};
+
+/** 閿�鍞��璐у垎椤靛垪琛� */
+export const listPageAccountSalesReturn = (params) => {
+ return request({
+ url: "/accountSales/listPageAccountSalesReturn",
+ method: "get",
+ params,
+ });
+};
diff --git a/src/api/financialManagement/fixedAsset.js b/src/api/financialManagement/fixedAsset.js
new file mode 100644
index 0000000..5c28db4
--- /dev/null
+++ b/src/api/financialManagement/fixedAsset.js
@@ -0,0 +1,50 @@
+import request from "@/utils/request";
+
+// 鍥哄畾璧勪骇鍒嗛〉鏌ヨ锛坈urrent/size锛�
+export function listFixedAssetPage(params) {
+ return request({
+ url: "/financial/fixedAsset/page",
+ method: "get",
+ params,
+ });
+}
+
+// 鏂板鍥哄畾璧勪骇
+export function addFixedAsset(data) {
+ return request({
+ url: "/financial/fixedAsset/add",
+ method: "post",
+ data,
+ });
+}
+
+// 淇敼鍥哄畾璧勪骇
+export function updateFixedAsset(data) {
+ return request({
+ url: "/financial/fixedAsset/update",
+ method: "put",
+ data,
+ });
+}
+
+// 鍒犻櫎鍥哄畾璧勪骇锛堝悗绔姹� ids=1&ids=2 褰㈠紡锛�
+export function deleteFixedAsset(ids) {
+ const idList = Array.isArray(ids) ? ids : [ids];
+ const query = idList
+ .filter(id => id !== undefined && id !== null && id !== "")
+ .map(id => `ids=${encodeURIComponent(id)}`)
+ .join("&");
+ return request({
+ url: `/financial/fixedAsset/delete?${query}`,
+ method: "delete",
+ });
+}
+
+// 鎶樻棫璁℃彁锛坽} 琛ㄧず鍏ㄩ儴鍦ㄧ敤璧勪骇锛�
+export function depreciateFixedAsset(data = {}) {
+ return request({
+ url: "/financial/fixedAsset/depreciate",
+ method: "post",
+ data,
+ });
+}
diff --git a/src/api/financialManagement/intangibleAsset.js b/src/api/financialManagement/intangibleAsset.js
new file mode 100644
index 0000000..802e649
--- /dev/null
+++ b/src/api/financialManagement/intangibleAsset.js
@@ -0,0 +1,50 @@
+import request from "@/utils/request";
+
+// 鏃犲舰璧勪骇鍒嗛〉鏌ヨ锛坈urrent/size锛�
+export function listIntangibleAssetPage(params) {
+ return request({
+ url: "/financial/intangibleAsset/page",
+ method: "get",
+ params,
+ });
+}
+
+// 鏂板鏃犲舰璧勪骇
+export function addIntangibleAsset(data) {
+ return request({
+ url: "/financial/intangibleAsset/add",
+ method: "post",
+ data,
+ });
+}
+
+// 淇敼鏃犲舰璧勪骇
+export function updateIntangibleAsset(data) {
+ return request({
+ url: "/financial/intangibleAsset/update",
+ method: "put",
+ data,
+ });
+}
+
+// 鍒犻櫎鏃犲舰璧勪骇锛堝悗绔姹� ids=1&ids=2 褰㈠紡锛�
+export function deleteIntangibleAsset(ids) {
+ const idList = Array.isArray(ids) ? ids : [ids];
+ const query = idList
+ .filter(id => id !== undefined && id !== null && id !== "")
+ .map(id => `ids=${encodeURIComponent(id)}`)
+ .join("&");
+ return request({
+ url: `/financial/intangibleAsset/delete?${query}`,
+ method: "delete",
+ });
+}
+
+// 鎽婇攢璁℃彁锛坽} 琛ㄧず鍏ㄩ儴鍦ㄧ敤璧勪骇锛�
+export function amortizeIntangibleAsset(data = {}) {
+ return request({
+ url: "/financial/intangibleAsset/amortize",
+ method: "post",
+ data,
+ });
+}
diff --git a/src/api/financialManagement/ledger.js b/src/api/financialManagement/ledger.js
new file mode 100644
index 0000000..17e62fc
--- /dev/null
+++ b/src/api/financialManagement/ledger.js
@@ -0,0 +1,19 @@
+import request from "@/utils/request";
+
+// 绉戠洰鎬昏处
+export function getGeneralLedger(params) {
+ return request({
+ url: "/financial/ledger/general",
+ method: "get",
+ params,
+ });
+}
+
+// 绉戠洰鏄庣粏璐�
+export function getDetailLedger(params) {
+ return request({
+ url: "/financial/ledger/detail",
+ method: "get",
+ params,
+ });
+}
diff --git a/src/api/financialManagement/voucher.js b/src/api/financialManagement/voucher.js
new file mode 100644
index 0000000..ccb0908
--- /dev/null
+++ b/src/api/financialManagement/voucher.js
@@ -0,0 +1,54 @@
+import request from "@/utils/request";
+
+// 鍑瘉鍒嗛〉鏌ヨ锛坈urrent/size + 杩囨护鏉′欢锛�
+export function listVoucherPage(params) {
+ return request({
+ url: "/financial/voucher/page",
+ method: "get",
+ params,
+ });
+}
+
+// 鏂板鍑瘉
+export function addVoucher(data) {
+ return request({
+ url: "/financial/voucher/add",
+ method: "post",
+ data,
+ });
+}
+
+// 淇敼鍑瘉锛堜粎鏈繃璐︼級
+export function updateVoucher(data) {
+ return request({
+ url: "/financial/voucher/update",
+ method: "put",
+ data,
+ });
+}
+
+// 杩囪处
+export function postVoucher(data) {
+ return request({
+ url: "/financial/voucher/post",
+ method: "post",
+ data,
+ });
+}
+
+// 浣滃簾
+export function cancelVoucher(data) {
+ return request({
+ url: "/financial/voucher/cancel",
+ method: "post",
+ data,
+ });
+}
+
+// 璇︽儏
+export function getVoucherDetail(id) {
+ return request({
+ url: `/financial/voucher/detail/${id}`,
+ method: "get",
+ });
+}
diff --git a/src/api/procurementManagement/purchase_return_order.js b/src/api/procurementManagement/purchase_return_order.js
index aeb380d..2705dde 100644
--- a/src/api/procurementManagement/purchase_return_order.js
+++ b/src/api/procurementManagement/purchase_return_order.js
@@ -19,6 +19,15 @@
});
}
+// 鏍规嵁閲囪喘鍙拌处 ID 鏌ヨ鍙��浜у搧绛変俊鎭�
+export function getPurchaseReturnOrderByPurchaseLedgerId(query) {
+ return request({
+ url: "/purchaseReturnOrders/getByPurchaseLedgerId",
+ method: "get",
+ params: query,
+ });
+}
+
// 鏌ョ湅璇︽儏
// purchaseReturnOrders/selectById/xxx
export function getPurchaseReturnOrderDetail(id) {
diff --git a/src/assets/logo/logo.png b/src/assets/logo/logo.png
index a5831b8..0a486cd 100644
--- a/src/assets/logo/logo.png
+++ b/src/assets/logo/logo.png
Binary files differ
diff --git a/src/router/index.js b/src/router/index.js
index aea22ca..d809a63 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -183,7 +183,12 @@
name: "PurchaseIn",
meta: { title: "閲囪喘鍏ュ簱" },
},
-
+ {
+ path: "purchase-return",
+ component: () => import("@/views/financialManagement/payable/purchaseReturn.vue"),
+ name: "PurchaseReturn",
+ meta: { title: "閲囪喘閫�璐�" },
+ },
{
path: "input-invoice",
component: () => import("@/views/financialManagement/payable/input-invoice.vue"),
diff --git a/src/views/basicData/customerFile/index.vue b/src/views/basicData/customerFile/index.vue
index 97ea3e6..7091a02 100644
--- a/src/views/basicData/customerFile/index.vue
+++ b/src/views/basicData/customerFile/index.vue
@@ -27,6 +27,9 @@
<div>
<el-button type="primary"
@click="openForm('add')">鏂板瀹㈡埛</el-button>
+ <el-button type="primary"
+ plain
+ @click="back">娴佸叆鍏捣</el-button>
<el-button @click="handleOut">瀵煎嚭</el-button>
<el-button type="info"
plain
@@ -619,7 +622,7 @@
addReturnVisit,
getReturnVisit,
} from "@/api/basicData/customerFile.js";
- import {listCustomer, getCustomer, addCustomer, updateCustomer, delCustomer} from "@/api/basicData/customer.js";
+ import {listCustomer, getCustomer, addCustomer, updateCustomer, delCustomer, backCustomer} from "@/api/basicData/customer.js";
import { ElMessageBox } from "element-plus";
import { userListNoPage } from "@/api/system/user.js";
import useUserStore from "@/store/modules/user";
@@ -1126,6 +1129,36 @@
});
};
+ const back = () => {
+ if (selectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+ const ids = selectedRows.value.map(item => item.id);
+ ElMessageBox.confirm("閫変腑鐨勫鎴峰皢娴佸叆鍏捣锛屾槸鍚︾‘璁わ紵", "娴佸叆鍏捣鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ tableLoading.value = true;
+ return Promise.all(ids.map(id => backCustomer(id)))
+ .then(() => {
+ proxy.$modal.msgSuccess("娴佸叆鍏捣鎴愬姛");
+ selectedRows.value = [];
+ getList();
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+ })
+ .catch(error => {
+ if (error === "cancel" || error === "close") {
+ proxy.$modal.msg("宸插彇娑�");
+ }
+ });
+ };
+
// 鎵撳紑鍥炶鎻愰啋寮圭獥
const openReminderDialog = row => {
currentCustomerId.value = row.id;
diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
index 99ab028..07da49b 100644
--- a/src/views/basicData/product/index.vue
+++ b/src/views/basicData/product/index.vue
@@ -43,12 +43,12 @@
<el-button type="primary"
link
:disabled="isTopLevelNode(data, node)"
- @click="openProDia('edit', data)">
+ @click="openProDia('edit', data, node)">
缂栬緫
</el-button>
<el-button type="primary"
link
- @click="openProDia('add', data)">
+ @click="openProDia('add', data, node)">
娣诲姞浜у搧
</el-button>
<el-button v-if="!node.childNodes.length"
@@ -285,6 +285,8 @@
const search = ref("");
const currentId = ref("");
const currentParentId = ref("");
+ /** 浜у搧寮圭獥锛歛dd 瀛樼埗鑺傜偣 id锛沞dit 瀛樺綋鍓嶈妭鐐� id 涓� parentId锛堜笉渚濊禆鏍戦�変腑椤癸級 */
+ const productDialogTarget = ref(null);
const operationType = ref("");
const treeLoad = ref(false);
const list = ref([]);
@@ -388,17 +390,28 @@
return [null, undefined, "", 0, "0"].includes(data?.parentId);
};
// 鎵撳紑浜у搧寮规
- const openProDia = (type, data) => {
- if (data && type === "edit" && isTopLevelNode(data)) {
+ const openProDia = (type, data, node) => {
+ if (data && type === "edit" && isTopLevelNode(data, node)) {
proxy.$modal.msgWarning("涓�绾ц妭鐐逛笉鑳界紪杈戞垨鍒犻櫎");
return;
}
operationType.value = type;
- productDia.value = true;
- form.value.productName = "";
- if (type === "edit") {
- form.value.productName = data.productName;
+ productDialogTarget.value = null;
+ if (type === "add" && data) {
+ productDialogTarget.value = { parentId: data.id };
+ } else if (type === "edit" && data) {
+ let parentId = data.parentId;
+ if (
+ [null, undefined, ""].includes(parentId) &&
+ node?.parent?.data?.id != null
+ ) {
+ parentId = node.parent.data.id;
+ }
+ productDialogTarget.value = { id: data.id, parentId };
}
+ productDia.value = true;
+ form.value.productName =
+ type === "edit" && data ? data.productName : "";
};
// 鎵撳紑瑙勬牸鍨嬪彿寮规
const openModelDia = (type, data) => {
@@ -417,14 +430,16 @@
proxy.$refs.formRef.validate(valid => {
if (valid) {
if (operationType.value === "add") {
- form.value.parentId = currentId.value;
+ form.value.parentId =
+ productDialogTarget.value?.parentId ?? currentId.value;
form.value.id = "";
} else if (operationType.value === "addOne") {
form.value.id = "";
form.value.parentId = "";
} else {
- form.value.id = currentId.value;
- form.value.parentId = "";
+ form.value.id =
+ productDialogTarget.value?.id ?? currentId.value;
+ form.value.parentId = productDialogTarget.value?.parentId ?? "";
}
addOrEditProduct(form.value).then(res => {
proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
@@ -437,6 +452,7 @@
// 鍏抽棴浜у搧寮规
const closeProDia = () => {
proxy.$refs.formRef.resetFields();
+ productDialogTarget.value = null;
productDia.value = false;
};
diff --git a/src/views/financialManagement/assets/fixedAssets.vue b/src/views/financialManagement/assets/fixedAssets.vue
index 61eb245..c6241c8 100644
--- a/src/views/financialManagement/assets/fixedAssets.vue
+++ b/src/views/financialManagement/assets/fixedAssets.vue
@@ -43,6 +43,7 @@
</div>
<PIMTable
rowKey="id"
+ isSelection
:column="columns"
:tableData="dataList"
:page="{
@@ -50,6 +51,7 @@
size: pagination.pageSize,
total: pagination.total,
}"
+ @selection-change="handleSelectionChange"
@pagination="changePage"
>
<template #originalValue="{ row }">
@@ -76,7 +78,7 @@
</div>
<FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
- <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
+ <el-form :model="form" :rules="rules" :disabled="isView" ref="formRef" label-width="120px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="璧勪骇缂栧彿" prop="assetCode">
@@ -178,7 +180,7 @@
</el-form-item>
</el-form>
<template #footer>
- <el-button type="primary" @click="submitForm">纭畾</el-button>
+ <el-button v-if="!isView" type="primary" @click="submitForm">纭畾</el-button>
<el-button @click="dialogVisible = false">鍙栨秷</el-button>
</template>
</FormDialog>
@@ -189,6 +191,13 @@
import { ref, reactive, onMounted, computed } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import FormDialog from "@/components/Dialog/FormDialog.vue";
+import {
+ listFixedAssetPage,
+ addFixedAsset,
+ updateFixedAsset,
+ deleteFixedAsset,
+ depreciateFixedAsset,
+} from "@/api/financialManagement/fixedAsset";
defineOptions({
name: "鍥哄畾璧勪骇",
@@ -210,23 +219,30 @@
const columns = [
{ label: "璧勪骇缂栧彿", prop: "assetCode", width: "130" },
{ label: "璧勪骇鍚嶇О", prop: "assetName", width: "150" },
- { label: "璧勪骇绫诲埆", prop: "category", slot: "category" },
+ { label: "璧勪骇绫诲埆", prop: "category", dataType: "slot", slot: "category" },
{ label: "瑙勬牸鍨嬪彿", prop: "specification", width: "120" },
- { label: "璧勪骇鍘熷��", prop: "originalValue", slot: "originalValue" },
- { label: "绱鎶樻棫", prop: "accumulatedDepreciation", slot: "accumulatedDepreciation" },
- { label: "璧勪骇鍑�鍊�", prop: "netValue", slot: "netValue" },
- { label: "鐘舵��", prop: "status", slot: "status" },
- { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "180", fixed: "right" },
+ { label: "璧勪骇鍘熷��", prop: "originalValue", dataType: "slot", slot: "originalValue" },
+ { label: "绱鎶樻棫", prop: "accumulatedDepreciation", dataType: "slot", slot: "accumulatedDepreciation" },
+ { label: "璧勪骇鍑�鍊�", prop: "netValue", dataType: "slot", slot: "netValue" },
+ { label: "鐘舵��", prop: "status", dataType: "slot", slot: "status" },
+ { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "180", fixed: "right" },
];
const dataList = ref([]);
+const multipleList = ref([]);
const dialogVisible = ref(false);
const dialogTitle = ref("");
const formRef = ref(null);
const isEdit = ref(false);
+const isView = ref(false);
const currentId = ref(null);
+const selectedIds = computed(() =>
+ multipleList.value
+ .map(item => item?.id)
+ .filter(id => id !== undefined && id !== null && id !== "")
+);
-const form = reactive({
+const createDefaultForm = () => ({
assetCode: "",
assetName: "",
category: "",
@@ -244,6 +260,10 @@
remark: "",
});
+const form = reactive({
+ ...createDefaultForm(),
+});
+
const rules = {
assetName: [{ required: true, message: "璇疯緭鍏ヨ祫浜у悕绉�", trigger: "blur" }],
category: [{ required: true, message: "璇烽�夋嫨璧勪骇绫诲埆", trigger: "change" }],
@@ -251,13 +271,6 @@
originalValue: [{ required: true, message: "璇疯緭鍏ヨ祫浜у師鍊�", trigger: "blur" }],
usefulLife: [{ required: true, message: "璇疯緭鍏ヤ娇鐢ㄥ勾闄�", trigger: "blur" }],
};
-
-const mockData = [
- { id: 1, assetCode: "GD2024001", assetName: "鍔炲叕鐢佃剳", category: "electronic", specification: "鑱旀兂ThinkPad X1", purchaseDate: "2023-01-15", originalValue: 8000, usefulLife: 5, residualRate: 5, accumulatedDepreciation: 1520, netValue: 6480, location: "鍔炲叕瀹�", department: "璐㈠姟閮�", keeper: "寮犱笁", status: "in_use", remark: "" },
- { id: 2, assetCode: "GD2024002", assetName: "鎵撳嵃鏈�", category: "electronic", specification: "鎯犳櫘M479fdw", purchaseDate: "2023-03-20", originalValue: 3500, usefulLife: 5, residualRate: 5, accumulatedDepreciation: 532, netValue: 2968, location: "鏂囧嵃瀹�", department: "琛屾斂閮�", keeper: "鏉庡洓", status: "in_use", remark: "" },
- { id: 3, assetCode: "GD2024003", assetName: "鍔炲叕妗屾", category: "furniture", specification: "瀹炴湪鍔炲叕妗�", purchaseDate: "2023-06-10", originalValue: 2500, usefulLife: 10, residualRate: 5, accumulatedDepreciation: 118.75, netValue: 2381.25, location: "鍔炲叕瀹�", department: "閿�鍞儴", keeper: "鐜嬩簲", status: "in_use", remark: "" },
- { id: 4, assetCode: "GD2024004", assetName: "鍟嗗姟杞�", category: "vehicle", specification: "鍒厠GL8", purchaseDate: "2022-08-01", originalValue: 280000, usefulLife: 10, residualRate: 5, accumulatedDepreciation: 53200, netValue: 226800, location: "鍋滆溅鍦�", department: "琛屾斂閮�", keeper: "璧靛叚", status: "in_use", remark: "" },
-];
const totalOriginalValue = computed(() => {
return dataList.value.reduce((sum, item) => sum + Number(item.originalValue), 0);
@@ -288,35 +301,44 @@
};
const getStatusLabel = (status) => {
- const map = { in_use: "鍦ㄧ敤", idle: "闂茬疆", scrapped: "鎶ュ簾" };
- return map[status] || status;
+ const key = String(status || "").toLowerCase();
+ const map = { in_use: "鍦ㄧ敤", idle: "闂茬疆", repair: "缁翠慨涓�", scrapped: "鎶ュ簾" };
+ return map[key] || status;
};
const getStatusType = (status) => {
- const map = { in_use: "success", idle: "warning", scrapped: "info" };
- return map[status] || "";
+ const key = String(status || "").toLowerCase();
+ const map = { in_use: "success", idle: "warning", repair: "warning", scrapped: "info" };
+ return map[key] || "";
};
const calculateNetValue = () => {
- form.netValue = Number((form.originalValue - form.accumulatedDepreciation).toFixed(2));
+ const originalValue = Number(form.originalValue || 0);
+ const accumulatedDepreciation = Number(form.accumulatedDepreciation || 0);
+ form.netValue = Number((originalValue - accumulatedDepreciation).toFixed(2));
};
-const getTableData = () => {
- let result = [...mockData];
- if (filters.assetCode) {
- result = result.filter(item => item.assetCode.includes(filters.assetCode));
+// 鑱旇皟绾﹀畾锛氬垎椤靛弬鏁板浐瀹氫负 current/size锛岃繑鍥� data.records/data.total
+const getTableData = async () => {
+ try {
+ const { data } = await listFixedAssetPage({
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ assetCode: filters.assetCode,
+ assetName: filters.assetName,
+ category: filters.category,
+ status: filters.status,
+ });
+ dataList.value = data?.records || [];
+ multipleList.value = [];
+ pagination.total = Number(data?.total || 0);
+ } catch (error) {
+ // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
}
- if (filters.assetName) {
- result = result.filter(item => item.assetName.includes(filters.assetName));
- }
- if (filters.category) {
- result = result.filter(item => item.category === filters.category);
- }
- if (filters.status) {
- result = result.filter(item => item.status === filters.status);
- }
- pagination.total = result.length;
- dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+};
+
+const handleSelectionChange = (selectionList) => {
+ multipleList.value = selectionList;
};
const resetFilters = () => {
@@ -334,39 +356,32 @@
getTableData();
};
+const buildAssetCode = () => `GD${Date.now().toString().slice(-10)}`;
+
const add = () => {
isEdit.value = false;
+ isView.value = false;
+ currentId.value = null;
dialogTitle.value = "鏂板鍥哄畾璧勪骇";
- Object.assign(form, {
- assetCode: "GD" + Date.now().toString().slice(-8),
- assetName: "",
- category: "",
- specification: "",
+ Object.assign(form, createDefaultForm(), {
+ assetCode: buildAssetCode(),
purchaseDate: new Date().toISOString().split('T')[0],
- originalValue: 0,
- usefulLife: 5,
- residualRate: 5,
- accumulatedDepreciation: 0,
- netValue: 0,
- location: "",
- department: "",
- keeper: "",
- status: "in_use",
- remark: "",
});
dialogVisible.value = true;
};
const edit = (row) => {
isEdit.value = true;
+ isView.value = false;
currentId.value = row.id;
dialogTitle.value = "缂栬緫鍥哄畾璧勪骇";
- Object.assign(form, row);
+ Object.assign(form, createDefaultForm(), row);
dialogVisible.value = true;
};
const view = (row) => {
- ElMessage.info(`鏌ョ湅璧勪骇: ${row.assetName}`);
+ edit(row);
+ isView.value = true;
};
const handleDelete = (row) => {
@@ -374,31 +389,30 @@
confirmButtonText: "纭畾",
cancelButtonText: "鍙栨秷",
type: "warning",
- }).then(() => {
- const index = mockData.findIndex(item => item.id === row.id);
- if (index !== -1) {
- mockData.splice(index, 1);
+ }).then(async () => {
+ // 鑱旇皟绾﹀畾锛氬垹闄ゆ帴鍙d娇鐢� ids=1&ids=2
+ await deleteFixedAsset([row.id]);
+ if (dataList.value.length === 1 && pagination.currentPage > 1) {
+ pagination.currentPage -= 1;
}
ElMessage.success("鍒犻櫎鎴愬姛");
- getTableData();
+ await getTableData();
});
};
const handleDepreciation = () => {
- ElMessageBox.confirm("纭杩涜鏈湀鎶樻棫璁℃彁鍚楋紵", "鎻愮ず", {
+ const ids = selectedIds.value;
+ const confirmText = ids.length
+ ? `纭瀵归�変腑鐨� ${ids.length} 鏉¤祫浜ц繘琛屾湰鏈堟姌鏃ц鎻愬悧锛焋
+ : "纭杩涜鏈湀鎶樻棫璁℃彁鍚楋紵";
+ ElMessageBox.confirm(confirmText, "鎻愮ず", {
confirmButtonText: "纭",
cancelButtonText: "鍙栨秷",
type: "info",
- }).then(() => {
- mockData.forEach(item => {
- if (item.status === "in_use") {
- const monthlyDepreciation = (item.originalValue * (1 - item.residualRate / 100)) / (item.usefulLife * 12);
- item.accumulatedDepreciation = Number((item.accumulatedDepreciation + monthlyDepreciation).toFixed(2));
- item.netValue = Number((item.originalValue - item.accumulatedDepreciation).toFixed(2));
- }
- });
+ }).then(async () => {
+ await depreciateFixedAsset({ ids });
ElMessage.success("鎶樻棫璁℃彁瀹屾垚");
- getTableData();
+ await getTableData();
});
};
@@ -407,22 +421,28 @@
};
const submitForm = () => {
- formRef.value.validate((valid) => {
+ if (isView.value) {
+ dialogVisible.value = false;
+ return;
+ }
+ formRef.value.validate(async valid => {
if (valid) {
- calculateNetValue();
- if (isEdit.value) {
- const index = mockData.findIndex(item => item.id === currentId.value);
- if (index !== -1) {
- mockData[index] = { ...mockData[index], ...form };
+ try {
+ calculateNetValue();
+ const payload = { ...form };
+ if (isEdit.value) {
+ payload.id = currentId.value;
+ await updateFixedAsset(payload);
+ ElMessage.success("缂栬緫鎴愬姛");
+ } else {
+ await addFixedAsset(payload);
+ ElMessage.success("鏂板鎴愬姛");
}
- ElMessage.success("缂栬緫鎴愬姛");
- } else {
- const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
- mockData.push({ id: newId, ...form });
- ElMessage.success("鏂板鎴愬姛");
+ dialogVisible.value = false;
+ await getTableData();
+ } catch (error) {
+ // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
}
- dialogVisible.value = false;
- getTableData();
}
});
};
diff --git a/src/views/financialManagement/assets/intangibleAssets.vue b/src/views/financialManagement/assets/intangibleAssets.vue
index 14dae55..47820c2 100644
--- a/src/views/financialManagement/assets/intangibleAssets.vue
+++ b/src/views/financialManagement/assets/intangibleAssets.vue
@@ -44,6 +44,7 @@
</div>
<PIMTable
rowKey="id"
+ isSelection
:column="columns"
:tableData="dataList"
:page="{
@@ -51,6 +52,7 @@
size: pagination.pageSize,
total: pagination.total,
}"
+ @selection-change="handleSelectionChange"
@pagination="changePage"
>
<template #originalValue="{ row }">
@@ -77,7 +79,7 @@
</div>
<FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
- <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
+ <el-form :model="form" :rules="rules" :disabled="isView" ref="formRef" label-width="120px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="璧勪骇缂栧彿" prop="assetCode">
@@ -171,7 +173,7 @@
</el-form-item>
</el-form>
<template #footer>
- <el-button type="primary" @click="submitForm">纭畾</el-button>
+ <el-button v-if="!isView" type="primary" @click="submitForm">纭畾</el-button>
<el-button @click="dialogVisible = false">鍙栨秷</el-button>
</template>
</FormDialog>
@@ -182,6 +184,13 @@
import { ref, reactive, onMounted, computed } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import FormDialog from "@/components/Dialog/FormDialog.vue";
+import {
+ listIntangibleAssetPage,
+ addIntangibleAsset,
+ updateIntangibleAsset,
+ deleteIntangibleAsset,
+ amortizeIntangibleAsset,
+} from "@/api/financialManagement/intangibleAsset";
defineOptions({
name: "鏃犲舰璧勪骇",
@@ -203,23 +212,30 @@
const columns = [
{ label: "璧勪骇缂栧彿", prop: "assetCode", width: "130" },
{ label: "璧勪骇鍚嶇О", prop: "assetName", width: "150" },
- { label: "璧勪骇绫诲埆", prop: "category", slot: "category" },
+ { label: "璧勪骇绫诲埆", prop: "category", dataType: "slot", slot: "category" },
{ label: "璇佷功缂栧彿", prop: "certificateNo", width: "150" },
- { label: "璧勪骇鍘熷��", prop: "originalValue", slot: "originalValue" },
- { label: "绱鎽婇攢", prop: "accumulatedAmortization", slot: "accumulatedAmortization" },
- { label: "璧勪骇鍑�鍊�", prop: "netValue", slot: "netValue" },
- { label: "鐘舵��", prop: "status", slot: "status" },
- { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "180", fixed: "right" },
+ { label: "璧勪骇鍘熷��", prop: "originalValue", dataType: "slot", slot: "originalValue" },
+ { label: "绱鎽婇攢", prop: "accumulatedAmortization", dataType: "slot", slot: "accumulatedAmortization" },
+ { label: "璧勪骇鍑�鍊�", prop: "netValue", dataType: "slot", slot: "netValue" },
+ { label: "鐘舵��", prop: "status", dataType: "slot", slot: "status" },
+ { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "180", fixed: "right" },
];
const dataList = ref([]);
+const multipleList = ref([]);
const dialogVisible = ref(false);
const dialogTitle = ref("");
const formRef = ref(null);
const isEdit = ref(false);
+const isView = ref(false);
const currentId = ref(null);
+const selectedIds = computed(() =>
+ multipleList.value
+ .map(item => item?.id)
+ .filter(id => id !== undefined && id !== null && id !== "")
+);
-const form = reactive({
+const createDefaultForm = () => ({
assetCode: "",
assetName: "",
category: "",
@@ -236,6 +252,10 @@
remark: "",
});
+const form = reactive({
+ ...createDefaultForm(),
+});
+
const rules = {
assetName: [{ required: true, message: "璇疯緭鍏ヨ祫浜у悕绉�", trigger: "blur" }],
category: [{ required: true, message: "璇烽�夋嫨璧勪骇绫诲埆", trigger: "change" }],
@@ -243,13 +263,6 @@
originalValue: [{ required: true, message: "璇疯緭鍏ヨ祫浜у師鍊�", trigger: "blur" }],
amortizationPeriod: [{ required: true, message: "璇疯緭鍏ユ憡閿�骞撮檺", trigger: "blur" }],
};
-
-const mockData = [
- { id: 1, assetCode: "WX2024001", assetName: "ERP杞欢璁稿彲", category: "software", certificateNo: "SW-2023-001", acquisitionDate: "2023-01-01", originalValue: 50000, amortizationPeriod: 10, residualRate: 0, accumulatedAmortization: 5000, netValue: 45000, validityDate: "2033-01-01", status: "in_use", description: "浼佷笟璧勬簮璁″垝绠$悊绯荤粺", remark: "" },
- { id: 2, assetCode: "WX2024002", assetName: "鍙戞槑涓撳埄", category: "patent", certificateNo: "ZL202210123456.7", acquisitionDate: "2022-06-15", originalValue: 100000, amortizationPeriod: 20, residualRate: 0, accumulatedAmortization: 3750, netValue: 96250, validityDate: "2042-06-15", status: "in_use", description: "涓�绉嶆柊鍨嬬敓浜у伐鑹�", remark: "" },
- { id: 3, assetCode: "WX2024003", assetName: "鍟嗘爣鏉�", category: "trademark", certificateNo: "TM-2023-008", acquisitionDate: "2023-03-10", originalValue: 20000, amortizationPeriod: 10, residualRate: 0, accumulatedAmortization: 1500, netValue: 18500, validityDate: "2033-03-10", status: "in_use", description: "鍏徃鍝佺墝鍟嗘爣", remark: "" },
- { id: 4, assetCode: "WX2024004", assetName: "鍦熷湴浣跨敤鏉�", category: "land", certificateNo: "鍦熷浗鐢�(2023)绗�001鍙�", acquisitionDate: "2023-07-01", originalValue: 500000, amortizationPeriod: 50, residualRate: 0, accumulatedAmortization: 5000, netValue: 495000, validityDate: "2073-07-01", status: "in_use", description: "宸ヤ笟鐢ㄥ湴浣跨敤鏉�", remark: "" },
-];
const totalOriginalValue = computed(() => {
return dataList.value.reduce((sum, item) => sum + Number(item.originalValue), 0);
@@ -281,35 +294,49 @@
};
const getStatusLabel = (status) => {
- const map = { in_use: "鍦ㄧ敤", idle: "闂茬疆", amortized: "宸叉憡閿�瀹屾瘯" };
- return map[status] || status;
+ const key = String(status || "").toLowerCase();
+ const map = {
+ in_use: "鍦ㄧ敤",
+ idle: "闂茬疆",
+ expired: "宸插埌鏈�",
+ amortized: "宸叉憡閿�瀹屾瘯",
+ };
+ return map[key] || status;
};
const getStatusType = (status) => {
- const map = { in_use: "success", idle: "warning", amortized: "info" };
- return map[status] || "";
+ const key = String(status || "").toLowerCase();
+ const map = { in_use: "success", idle: "warning", expired: "warning", amortized: "info" };
+ return map[key] || "";
};
const calculateNetValue = () => {
- form.netValue = Number((form.originalValue - form.accumulatedAmortization).toFixed(2));
+ const originalValue = Number(form.originalValue || 0);
+ const accumulatedAmortization = Number(form.accumulatedAmortization || 0);
+ form.netValue = Number((originalValue - accumulatedAmortization).toFixed(2));
};
-const getTableData = () => {
- let result = [...mockData];
- if (filters.assetCode) {
- result = result.filter(item => item.assetCode.includes(filters.assetCode));
+// 鑱旇皟绾﹀畾锛氬垎椤靛弬鏁板浐瀹氫负 current/size锛岃繑鍥� data.records/data.total
+const getTableData = async () => {
+ try {
+ const { data } = await listIntangibleAssetPage({
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ assetCode: filters.assetCode,
+ assetName: filters.assetName,
+ category: filters.category,
+ status: filters.status,
+ });
+ dataList.value = data?.records || [];
+ multipleList.value = [];
+ pagination.total = Number(data?.total || 0);
+ } catch (error) {
+ // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
}
- if (filters.assetName) {
- result = result.filter(item => item.assetName.includes(filters.assetName));
- }
- if (filters.category) {
- result = result.filter(item => item.category === filters.category);
- }
- if (filters.status) {
- result = result.filter(item => item.status === filters.status);
- }
- pagination.total = result.length;
- dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+};
+
+const handleSelectionChange = (selectionList) => {
+ multipleList.value = selectionList;
};
const resetFilters = () => {
@@ -327,38 +354,32 @@
getTableData();
};
+const buildAssetCode = () => `WX${Date.now().toString().slice(-10)}`;
+
const add = () => {
isEdit.value = false;
+ isView.value = false;
+ currentId.value = null;
dialogTitle.value = "鏂板鏃犲舰璧勪骇";
- Object.assign(form, {
- assetCode: "WX" + Date.now().toString().slice(-8),
- assetName: "",
- category: "",
- certificateNo: "",
+ Object.assign(form, createDefaultForm(), {
+ assetCode: buildAssetCode(),
acquisitionDate: new Date().toISOString().split('T')[0],
- originalValue: 0,
- amortizationPeriod: 10,
- residualRate: 0,
- accumulatedAmortization: 0,
- netValue: 0,
- validityDate: "",
- status: "in_use",
- description: "",
- remark: "",
});
dialogVisible.value = true;
};
const edit = (row) => {
isEdit.value = true;
+ isView.value = false;
currentId.value = row.id;
dialogTitle.value = "缂栬緫鏃犲舰璧勪骇";
- Object.assign(form, row);
+ Object.assign(form, createDefaultForm(), row);
dialogVisible.value = true;
};
const view = (row) => {
- ElMessage.info(`鏌ョ湅璧勪骇: ${row.assetName}`);
+ edit(row);
+ isView.value = true;
};
const handleDelete = (row) => {
@@ -366,35 +387,30 @@
confirmButtonText: "纭畾",
cancelButtonText: "鍙栨秷",
type: "warning",
- }).then(() => {
- const index = mockData.findIndex(item => item.id === row.id);
- if (index !== -1) {
- mockData.splice(index, 1);
+ }).then(async () => {
+ // 鑱旇皟绾﹀畾锛氬垹闄ゆ帴鍙d娇鐢� ids=1&ids=2
+ await deleteIntangibleAsset([row.id]);
+ if (dataList.value.length === 1 && pagination.currentPage > 1) {
+ pagination.currentPage -= 1;
}
ElMessage.success("鍒犻櫎鎴愬姛");
- getTableData();
+ await getTableData();
});
};
const handleAmortization = () => {
- ElMessageBox.confirm("纭杩涜鏈湀鎽婇攢璁℃彁鍚楋紵", "鎻愮ず", {
+ const ids = selectedIds.value;
+ const confirmText = ids.length
+ ? `纭瀵归�変腑鐨� ${ids.length} 鏉¤祫浜ц繘琛屾湰鏈堟憡閿�璁℃彁鍚楋紵`
+ : "纭杩涜鏈湀鎽婇攢璁℃彁鍚楋紵";
+ ElMessageBox.confirm(confirmText, "鎻愮ず", {
confirmButtonText: "纭",
cancelButtonText: "鍙栨秷",
type: "info",
- }).then(() => {
- mockData.forEach(item => {
- if (item.status === "in_use") {
- const monthlyAmortization = (item.originalValue * (1 - item.residualRate / 100)) / (item.amortizationPeriod * 12);
- item.accumulatedAmortization = Number((item.accumulatedAmortization + monthlyAmortization).toFixed(2));
- item.netValue = Number((item.originalValue - item.accumulatedAmortization).toFixed(2));
- if (item.netValue <= 0) {
- item.status = "amortized";
- item.netValue = 0;
- }
- }
- });
+ }).then(async () => {
+ await amortizeIntangibleAsset({ ids });
ElMessage.success("鎽婇攢璁℃彁瀹屾垚");
- getTableData();
+ await getTableData();
});
};
@@ -403,22 +419,28 @@
};
const submitForm = () => {
- formRef.value.validate((valid) => {
+ if (isView.value) {
+ dialogVisible.value = false;
+ return;
+ }
+ formRef.value.validate(async valid => {
if (valid) {
- calculateNetValue();
- if (isEdit.value) {
- const index = mockData.findIndex(item => item.id === currentId.value);
- if (index !== -1) {
- mockData[index] = { ...mockData[index], ...form };
+ try {
+ calculateNetValue();
+ const payload = { ...form };
+ if (isEdit.value) {
+ payload.id = currentId.value;
+ await updateIntangibleAsset(payload);
+ ElMessage.success("缂栬緫鎴愬姛");
+ } else {
+ await addIntangibleAsset(payload);
+ ElMessage.success("鏂板鎴愬姛");
}
- ElMessage.success("缂栬緫鎴愬姛");
- } else {
- const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
- mockData.push({ id: newId, ...form });
- ElMessage.success("鏂板鎴愬姛");
+ dialogVisible.value = false;
+ await getTableData();
+ } catch (error) {
+ // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
}
- dialogVisible.value = false;
- getTableData();
}
});
};
diff --git a/src/views/financialManagement/generalLedger/index.vue b/src/views/financialManagement/generalLedger/index.vue
index fbe2210..556567b 100644
--- a/src/views/financialManagement/generalLedger/index.vue
+++ b/src/views/financialManagement/generalLedger/index.vue
@@ -48,16 +48,58 @@
icon="Download">瀵煎嚭</el-button>
</div>
</div>
- <PIMTable rowKey="id"
- :column="columns"
- :tableData="dataList"
- :page="{
- current: pagination.currentPage,
- size: pagination.pageSize,
- total: pagination.total,
- }"
- @pagination="changePage">
- </PIMTable>
+ <el-table ref="tableRef"
+ v-loading="loading"
+ :data="dataList"
+ row-key="id"
+ :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+ height="calc(100vh - 280px)"
+ border
+ stripe
+ highlight-current-row
+ class="subject-table">
+ <el-table-column label="绉戠洰缂栫爜" prop="subjectCode" width="140">
+ <template #default="scope">
+ <span class="subject-code">{{ scope.row.subjectCode }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="绉戠洰鍚嶇О" prop="subjectName" min-width="180">
+ <template #default="scope">
+ <span class="subject-name" :class="{ 'is-parent': scope.row.children?.length > 0 }">
+ {{ scope.row.subjectName }}
+ </span>
+ </template>
+ </el-table-column>
+ <el-table-column label="绉戠洰绫诲瀷" prop="subjectType" width="100" align="center">
+ <template #default="scope">
+ <el-tag size="small" :type="getSubjectTypeType(scope.row.subjectType)">
+ {{ scope.row.subjectType }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="浣欓鏂瑰悜" prop="balanceDirection" width="100" align="center">
+ <template #default="scope">
+ <el-tag size="small" :type="scope.row.balanceDirection === '鍊熸柟' ? 'primary' : 'danger'">
+ {{ scope.row.balanceDirection }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="鐘舵��" prop="status" width="80" align="center">
+ <template #default="scope">
+ <el-tag size="small" :type="scope.row.status === 0 || scope.row.status === '0' ? 'success' : 'info'">
+ {{ scope.row.status === 0 || scope.row.status === '0' ? '鍚敤' : '绂佺敤' }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="澶囨敞" prop="remark" show-overflow-tooltip min-width="150" />
+ <el-table-column label="鎿嶄綔" align="center" fixed="right" width="240">
+ <template #default="scope">
+ <el-button link type="primary" icon="Plus" @click="addChild(scope.row)">鏂板</el-button>
+ <el-button link type="primary" icon="Edit" @click="edit(scope.row)">缂栬緫</el-button>
+ <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)">鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
</div>
<FormDialog :title="dialogTitle"
v-model="dialogVisible"
@@ -68,6 +110,10 @@
:rules="rules"
ref="formRef"
label-width="100px">
+ <el-form-item label="鐖剁骇绉戠洰">
+ <el-input :model-value="parentSubjectLabel"
+ disabled />
+ </el-form-item>
<el-form-item label="绉戠洰缂栫爜"
prop="subjectCode">
<el-input v-model="form.subjectCode"
@@ -127,7 +173,7 @@
</template>
<script setup>
- import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+ import { ref, reactive, onMounted, getCurrentInstance, nextTick } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import FormDialog from "@/components/Dialog/FormDialog.vue";
import {
@@ -201,8 +247,15 @@
label: "鎿嶄綔",
align: "center",
fixed: "right",
- width: "150",
+ width: "220",
operation: [
+ {
+ name: "鏂板",
+ type: "primary",
+ clickFun: row => {
+ addChild(row);
+ },
+ },
{
name: "缂栬緫",
type: "primary",
@@ -224,11 +277,15 @@
const dataList = ref([]);
const dialogVisible = ref(false);
const dialogTitle = ref("");
+ const parentSubjectLabel = ref("椤剁骇绉戠洰");
const formRef = ref(null);
+ const tableRef = ref(null);
const isEdit = ref(false);
+ const loading = ref(false);
const form = reactive({
id: undefined,
+ parentId: null,
subjectCode: "",
subjectName: "",
subjectType: "",
@@ -257,14 +314,17 @@
};
const getTableData = () => {
+ loading.value = true;
const query = {
- pageNum: pagination.currentPage,
- pageSize: pagination.pageSize,
+ current: pagination.currentPage,
+ size: pagination.pageSize,
...filters,
};
listAccountSubject(query).then(response => {
- dataList.value = response.data.records;
- pagination.total = response.data.total;
+ dataList.value = response.data.records || [];
+ loading.value = false;
+ }).catch(() => {
+ loading.value = false;
});
};
@@ -282,11 +342,19 @@
getTableData();
};
- const add = () => {
- isEdit.value = false;
- dialogTitle.value = "鏂板绉戠洰";
+ const buildParentSubjectLabel = parentRow => {
+ if (!parentRow) {
+ return "椤剁骇绉戠洰";
+ }
+ const code = parentRow.subjectCode || "";
+ const name = parentRow.subjectName || "";
+ return `${code} ${name}`.trim();
+ };
+
+ const resetForm = ({ parentId = null, parentRow = null } = {}) => {
Object.assign(form, {
id: undefined,
+ parentId,
subjectCode: "",
subjectName: "",
subjectType: "",
@@ -294,13 +362,54 @@
status: 0,
remark: "",
});
+ parentSubjectLabel.value = buildParentSubjectLabel(parentRow);
+ };
+
+ const add = () => {
+ isEdit.value = false;
+ dialogTitle.value = "鏂板绉戠洰";
+ resetForm({ parentId: null, parentRow: null });
dialogVisible.value = true;
+ };
+
+ const addChild = row => {
+ isEdit.value = false;
+ dialogTitle.value = "鏂板瀛愮鐩�";
+ resetForm({ parentId: row.id, parentRow: row });
+ form.subjectType = row.subjectType || "";
+ form.balanceDirection = row.balanceDirection || "鍊熸柟";
+ dialogVisible.value = true;
+ };
+
+ const findSubjectById = (nodes, id) => {
+ for (const item of nodes || []) {
+ if (item.id === id) {
+ return item;
+ }
+ if (item.children && item.children.length > 0) {
+ const found = findSubjectById(item.children, id);
+ if (found) {
+ return found;
+ }
+ }
+ }
+ return null;
};
const edit = row => {
isEdit.value = true;
dialogTitle.value = "缂栬緫绉戠洰";
Object.assign(form, row);
+ form.parentId = row.parentId ?? null;
+ const parentRow =
+ row.parentId === null || row.parentId === undefined
+ ? null
+ : findSubjectById(dataList.value, row.parentId);
+ parentSubjectLabel.value = parentRow
+ ? buildParentSubjectLabel(parentRow)
+ : row.parentId
+ ? `涓婄骇ID: ${row.parentId}`
+ : buildParentSubjectLabel(null);
dialogVisible.value = true;
};
@@ -361,4 +470,29 @@
justify-content: space-between;
margin-bottom: 15px;
}
+
+ .subject-table {
+ border-radius: 8px;
+ overflow: hidden;
+
+ :deep(.el-table__row) {
+ transition: background-color 0.3s;
+ }
+
+ :deep(.el-table__row:hover) {
+ background-color: #f5f7fa;
+ }
+
+ .subject-code {
+ color: #606266;
+ }
+
+ .subject-name {
+ font-weight: 500;
+
+ &.is-parent {
+ color: #409eff;
+ }
+ }
+ }
</style>
diff --git a/src/views/financialManagement/payable/purchaseIn.vue b/src/views/financialManagement/payable/purchaseIn.vue
index 4813159..4fadcbb 100644
--- a/src/views/financialManagement/payable/purchaseIn.vue
+++ b/src/views/financialManagement/payable/purchaseIn.vue
@@ -1,19 +1,27 @@
<template>
+ <!-- 閲囪喘鍏ュ簱 -->
<div class="app-container">
<el-form :model="filters" :inline="true">
<el-form-item label="鍏ュ簱鍗曞彿:">
- <el-input v-model="filters.inCode" placeholder="璇疯緭鍏ュ叆搴撳崟鍙�" clearable style="width: 200px;" />
+ <el-input v-model="filters.inboundBatches" placeholder="璇疯緭鍏ュ叆搴撳崟鍙�" clearable style="width: 200px;" />
</el-form-item>
<el-form-item label="渚涘簲鍟�:">
- <el-select v-model="filters.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" clearable style="width: 200px;">
- <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
+ <el-input v-model="filters.supplierName" placeholder="璇疯緭鍏ヤ緵搴斿晢" clearable style="width: 200px;" />
</el-form-item>
<el-form-item label="鍏ュ簱鏃ユ湡:">
- <el-date-picker v-model="filters.dateRange" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" range-separator="鑷�" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" clearable />
+ <el-date-picker
+ v-model="filters.dateRange"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ clearable
+ />
</el-form-item>
<el-form-item>
- <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+ <el-button type="primary" @click="onSearch">鎼滅储</el-button>
<el-button @click="resetFilters">閲嶇疆</el-button>
</el-form-item>
</el-form>
@@ -28,6 +36,7 @@
rowKey="id"
:column="columns"
:tableData="dataList"
+ :tableLoading="tableLoading"
:page="{
current: pagination.currentPage,
size: pagination.pageSize,
@@ -35,107 +44,28 @@
}"
@pagination="changePage"
>
- <template #amount="{ row }">
- <span class="text-primary">楼{{ formatMoney(row.amount) }}</span>
- </template>
- <template #status="{ row }">
- <el-tag :type="getStatusType(row.status)">{{ getStatusLabel(row.status) }}</el-tag>
- </template>
- <template #operation="{ row }">
- <el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
- <el-button type="primary" link @click="edit(row)" v-if="row.status === 'pending'">缂栬緫</el-button>
- <el-button type="danger" link @click="handleDelete(row)" v-if="row.status === 'pending'">鍒犻櫎</el-button>
+ <template #inboundDate="{ row }">
+ {{ row.InboundDate || row.inboundDate || "" }}
</template>
</PIMTable>
</div>
-
- <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
- <el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="鍏ュ簱鍗曞彿" prop="inCode">
- <el-input v-model="form.inCode" placeholder="璇疯緭鍏ュ叆搴撳崟鍙�" :disabled="isEdit" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="渚涘簲鍟�" prop="supplierId">
- <el-select v-model="form.supplierId" placeholder="璇烽�夋嫨渚涘簲鍟�" style="width: 100%;" :disabled="isEdit">
- <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="鍏ュ簱鏃ユ湡" prop="inDate">
- <el-date-picker v-model="form.inDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鍏ュ簱閲戦" prop="amount">
- <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="鍏ュ簱鏄庣粏" prop="details">
- <el-table :data="form.details" border style="width: 100%">
- <el-table-column prop="materialName" label="鐗╂枡鍚嶇О" width="150">
- <template #default="{ $index }">
- <el-input v-model="form.details[$index].materialName" placeholder="鐗╂枡鍚嶇О" />
- </template>
- </el-table-column>
- <el-table-column prop="spec" label="瑙勬牸" width="120">
- <template #default="{ $index }">
- <el-input v-model="form.details[$index].spec" placeholder="瑙勬牸" />
- </template>
- </el-table-column>
- <el-table-column prop="quantity" label="鏁伴噺" width="100">
- <template #default="{ $index }">
- <el-input-number v-model="form.details[$index].quantity" :min="0" style="width: 100%;" />
- </template>
- </el-table-column>
- <el-table-column prop="unitPrice" label="鍗曚环" width="120">
- <template #default="{ $index }">
- <el-input-number v-model="form.details[$index].unitPrice" :min="0" :precision="2" style="width: 100%;" />
- </template>
- </el-table-column>
- <el-table-column prop="total" label="閲戦" width="120">
- <template #default="{ row }">
- <span>楼{{ formatMoney(row.quantity * row.unitPrice) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="鎿嶄綔" width="80">
- <template #default="{ $index }">
- <el-button type="danger" link @click="removeDetail($index)">鍒犻櫎</el-button>
- </template>
- </el-table-column>
- </el-table>
- <el-button type="primary" link @click="addDetail" style="margin-top: 10px;">+ 娣诲姞鏄庣粏</el-button>
- </el-form-item>
- <el-form-item label="澶囨敞" prop="remark">
- <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button type="primary" @click="submitForm">纭畾</el-button>
- <el-button @click="dialogVisible = false">鍙栨秷</el-button>
- </template>
- </FormDialog>
</div>
</template>
<script setup>
-import { ref, reactive, onMounted } from "vue";
-import { ElMessage, ElMessageBox } from "element-plus";
-import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ElMessage } from "element-plus";
+import { listPageAccountPurchase } from "@/api/financialManagement/accountPurchase";
defineOptions({
name: "閲囪喘鍏ュ簱",
});
+const { proxy } = getCurrentInstance();
+
const filters = reactive({
- inCode: "",
- supplierId: "",
+ inboundBatches: "",
+ supplierName: "",
dateRange: [],
});
@@ -146,170 +76,85 @@
});
const columns = [
- { label: "鍏ュ簱鍗曞彿", prop: "inCode", width: "150" },
- { label: "渚涘簲鍟�", prop: "supplierName", width: "180" },
- { label: "鍏ュ簱鏃ユ湡", prop: "inDate", width: "120" },
- { label: "鍏ュ簱閲戦", prop: "amount", slot: "amount" },
- { label: "鐘舵��", prop: "status", slot: "status" },
- { label: "澶囨敞", prop: "remark", showOverflowTooltip: true },
- { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "200", fixed: "right" },
+ { label: "鍏ュ簱鍗曞彿", prop: "inboundBatches", minWidth: "150" },
+ { label: "渚涘簲鍟�", prop: "supplierName", minWidth: "180" },
+ {
+ label: "鍏ュ簱鏃ユ湡",
+ prop: "InboundDate",
+ minWidth: "170",
+ dataType: "slot",
+ slot: "inboundDate",
+ },
+ { label: "浜у搧鍚嶇О", prop: "productName", minWidth: "140" },
+ { label: "浜у搧瑙勬牸", prop: "specificationModel", minWidth: "140" },
+ { label: "閲囪喘璁㈠崟鍙�", prop: "purchaseContractNumber", minWidth: "150" },
];
const dataList = ref([]);
-const dialogVisible = ref(false);
-const dialogTitle = ref("");
-const formRef = ref(null);
-const isEdit = ref(false);
-const currentId = ref(null);
+const tableLoading = ref(false);
-const supplierList = [
- { id: 1, name: "鍖椾含鍘熸潗鏂欎緵搴斿晢" },
- { id: 2, name: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�" },
- { id: 3, name: "骞垮窞鍖呰鏉愭枡鍘�" },
- { id: 4, name: "娣卞湷浜旈噾閰嶄欢鍏徃" },
-];
+function buildFilterParams() {
+ const params = {
+ inboundBatches: filters.inboundBatches || undefined,
+ supplierName: filters.supplierName || undefined,
+ };
+ if (filters.dateRange && filters.dateRange.length === 2) {
+ params.startDate = filters.dateRange[0];
+ params.endDate = filters.dateRange[1];
+ }
+ return params;
+}
-const form = reactive({
- inCode: "",
- supplierId: "",
- inDate: "",
- amount: 0,
- details: [],
- remark: "",
-});
-
-const rules = {
- inCode: [{ required: true, message: "璇疯緭鍏ュ叆搴撳崟鍙�", trigger: "blur" }],
- supplierId: [{ required: true, message: "璇烽�夋嫨渚涘簲鍟�", trigger: "change" }],
- inDate: [{ required: true, message: "璇烽�夋嫨鍏ュ簱鏃ユ湡", trigger: "change" }],
- amount: [{ required: true, message: "璇疯緭鍏ュ叆搴撻噾棰�", trigger: "blur" }],
-};
-
-const mockData = [
- { id: 1, inCode: "RK2024001", supplierId: 1, supplierName: "鍖椾含鍘熸潗鏂欎緵搴斿晢", inDate: "2024-01-10", amount: 8000, status: "approved", details: [{ materialName: "閽㈡潗", spec: "Q235", quantity: 10, unitPrice: 500 }], remark: "" },
- { id: 2, inCode: "RK2024002", supplierId: 2, supplierName: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�", inDate: "2024-01-12", amount: 12000, status: "pending", details: [{ materialName: "鑺墖", spec: "STM32", quantity: 100, unitPrice: 80 }], remark: "" },
- { id: 3, inCode: "RK2024003", supplierId: 3, supplierName: "骞垮窞鍖呰鏉愭枡鍘�", inDate: "2024-01-15", amount: 3500, status: "approved", details: [{ materialName: "绾哥", spec: "50*40*30", quantity: 500, unitPrice: 5 }], remark: "" },
-];
-
-const formatMoney = (value) => {
- if (value === undefined || value === null) return "0.00";
- return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
-};
-
-const getStatusLabel = (status) => {
- const map = { pending: "寰呭鏍�", approved: "宸插鏍�", rejected: "宸查┏鍥�" };
- return map[status] || status;
-};
-
-const getStatusType = (status) => {
- const map = { pending: "warning", approved: "success", rejected: "danger" };
- return map[status] || "";
+const onSearch = () => {
+ pagination.currentPage = 1;
+ getTableData();
};
const getTableData = () => {
- let result = [...mockData];
- if (filters.inCode) {
- result = result.filter(item => item.inCode.includes(filters.inCode));
- }
- if (filters.supplierId) {
- result = result.filter(item => item.supplierId === filters.supplierId);
- }
- if (filters.dateRange && filters.dateRange.length === 2) {
- result = result.filter(item => item.inDate >= filters.dateRange[0] && item.inDate <= filters.dateRange[1]);
- }
- pagination.total = result.length;
- dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+ tableLoading.value = true;
+ listPageAccountPurchase({
+ ...buildFilterParams(),
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ })
+ .then((res) => {
+ const ok = res.code === 200 || res.code === 0;
+ if (ok && res.data) {
+ pagination.total = res.data.total ?? 0;
+ dataList.value = res.data.records ?? [];
+ } else {
+ ElMessage.error(res.msg || "鏌ヨ澶辫触");
+ dataList.value = [];
+ }
+ })
+ .catch(() => {
+ dataList.value = [];
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
};
const resetFilters = () => {
- filters.inCode = "";
- filters.supplierId = "";
+ filters.inboundBatches = "";
+ filters.supplierName = "";
filters.dateRange = [];
pagination.currentPage = 1;
getTableData();
};
-const changePage = ({ current, size }) => {
- pagination.currentPage = current;
- pagination.pageSize = size;
+const changePage = ({ page, limit }) => {
+ pagination.currentPage = page;
+ pagination.pageSize = limit;
getTableData();
};
-const addDetail = () => {
- form.details.push({ materialName: "", spec: "", quantity: 0, unitPrice: 0 });
-};
-
-const removeDetail = (index) => {
- form.details.splice(index, 1);
-};
-
-const add = () => {
- isEdit.value = false;
- dialogTitle.value = "鏂板鍏ュ簱";
- Object.assign(form, {
- inCode: "RK" + Date.now().toString().slice(-8),
- supplierId: "",
- inDate: new Date().toISOString().split('T')[0],
- amount: 0,
- details: [{ materialName: "", spec: "", quantity: 0, unitPrice: 0 }],
- remark: "",
- });
- dialogVisible.value = true;
-};
-
-const edit = (row) => {
- isEdit.value = true;
- currentId.value = row.id;
- dialogTitle.value = "缂栬緫鍏ュ簱";
- Object.assign(form, row);
- if (!form.details || form.details.length === 0) {
- form.details = [{ materialName: "", spec: "", quantity: 0, unitPrice: 0 }];
- }
- dialogVisible.value = true;
-};
-
-const view = (row) => {
- ElMessage.info(`鏌ョ湅鍏ュ簱鍗�: ${row.inCode}`);
-};
-
-const handleDelete = (row) => {
- ElMessageBox.confirm("纭鍒犻櫎璇ュ叆搴撳崟鍚楋紵", "鎻愮ず", {
- confirmButtonText: "纭畾",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- }).then(() => {
- const index = mockData.findIndex(item => item.id === row.id);
- if (index !== -1) {
- mockData.splice(index, 1);
- }
- ElMessage.success("鍒犻櫎鎴愬姛");
- getTableData();
- });
-};
-
const handleOut = () => {
- ElMessage.success("瀵煎嚭鎴愬姛");
-};
-
-const submitForm = () => {
- formRef.value.validate((valid) => {
- if (valid) {
- const supplier = supplierList.find(item => item.id === form.supplierId);
- if (isEdit.value) {
- const index = mockData.findIndex(item => item.id === currentId.value);
- if (index !== -1) {
- mockData[index] = { ...mockData[index], ...form, supplierName: supplier?.name };
- }
- ElMessage.success("缂栬緫鎴愬姛");
- } else {
- const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
- mockData.push({ id: newId, ...form, supplierName: supplier?.name, status: "pending" });
- ElMessage.success("鏂板鎴愬姛");
- }
- dialogVisible.value = false;
- getTableData();
- }
- });
+ proxy.download(
+ "/accountPurchase/exportAccountPurchaseInbound",
+ buildFilterParams(),
+ `閲囪喘鍏ュ簱_${new Date().getTime()}.xlsx`
+ );
};
onMounted(() => {
@@ -322,10 +167,5 @@
display: flex;
justify-content: space-between;
margin-bottom: 15px;
-}
-
-.text-primary {
- color: #409eff;
- font-weight: bold;
}
</style>
diff --git a/src/views/financialManagement/payable/purchaseReturn.vue b/src/views/financialManagement/payable/purchaseReturn.vue
new file mode 100644
index 0000000..e7ca665
--- /dev/null
+++ b/src/views/financialManagement/payable/purchaseReturn.vue
@@ -0,0 +1,239 @@
+<template>
+ <!-- 閲囪喘閫�璐� -->
+
+ <div class="app-container">
+ <el-form :model="filters" :inline="true">
+ <el-form-item label="閫�璐у崟鍙�:">
+ <el-input
+ v-model="filters.returnNo"
+ placeholder="璇疯緭鍏ラ��璐у崟鍙�"
+ clearable
+ style="width: 200px"
+ />
+ </el-form-item>
+
+ <el-form-item label="渚涘簲鍟�:">
+ <el-input
+ v-model="filters.supplierName"
+ placeholder="璇疯緭鍏ヤ緵搴斿晢"
+ clearable
+ style="width: 200px"
+ />
+ </el-form-item>
+
+ <el-form-item label="閫�璐ф棩鏈�:">
+ <el-date-picker
+ v-model="filters.dateRange"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ clearable
+ />
+ </el-form-item>
+
+ <el-form-item>
+ <el-button type="primary" @click="onSearch">鎼滅储</el-button>
+
+ <el-button @click="resetFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <div class="table_list">
+ <div class="actions">
+ <div></div>
+
+ <div>
+ <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+ </div>
+ </div>
+
+ <PIMTable
+ rowKey="id"
+ :column="columns"
+ :tableData="dataList"
+ :tableLoading="tableLoading"
+ :page="{
+ current: pagination.currentPage,
+
+ size: pagination.pageSize,
+
+ total: pagination.total,
+ }"
+ @pagination="changePage"
+ />
+ </div>
+ </div>
+</template>
+
+
+
+<script setup>
+import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+
+import { ElMessage } from "element-plus";
+
+import { listPageAccountPurchaseReturn } from "@/api/financialManagement/accountPurchase";
+
+defineOptions({
+ name: "閲囪喘閫�璐�",
+});
+
+const { proxy } = getCurrentInstance();
+
+const filters = reactive({
+ returnNo: "",
+
+ supplierName: "",
+
+ dateRange: [],
+});
+
+const pagination = reactive({
+ currentPage: 1,
+
+ pageSize: 10,
+
+ total: 0,
+});
+
+const columns = [
+ { label: "閫�璐у崟鍙�", prop: "returnNo", minWidth: "150" },
+
+ { label: "渚涘簲鍟�", prop: "supplierName", minWidth: "180" },
+
+ { label: "鍏宠仈鍏ュ簱鍗曞彿", prop: "inboundBatches", minWidth: "150" },
+
+ { label: "閫�璐ф棩鏈�", prop: "preparedAt", minWidth: "170" },
+
+ {
+ label: "閫�娆炬�婚",
+
+ prop: "totalAmount",
+
+ minWidth: "150",
+
+ align: "right",
+
+ formatData: (val) =>
+ val === null || val === undefined || val === ""
+ ? ""
+ : Number(val).toLocaleString("zh-CN", {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ }),
+ },
+
+ { label: "閫�璐ф柟寮�", prop: "returnType", minWidth: "150" },
+
+ { label: "閲囪喘璁㈠崟鍙�", prop: "purchaseContractNumber", minWidth: "150" },
+];
+
+const dataList = ref([]);
+
+const tableLoading = ref(false);
+
+function buildFilterParams() {
+ const params = {
+ returnNo: filters.returnNo || undefined,
+
+ supplierName: filters.supplierName || undefined,
+ };
+
+ if (filters.dateRange && filters.dateRange.length === 2) {
+ params.startDate = filters.dateRange[0];
+
+ params.endDate = filters.dateRange[1];
+ }
+
+ return params;
+}
+
+const onSearch = () => {
+ pagination.currentPage = 1;
+
+ getTableData();
+};
+
+const getTableData = () => {
+ tableLoading.value = true;
+
+ listPageAccountPurchaseReturn({
+ ...buildFilterParams(),
+
+ current: pagination.currentPage,
+
+ size: pagination.pageSize,
+ })
+ .then((res) => {
+ const ok = res.code === 200 || res.code === 0;
+
+ if (ok && res.data) {
+ pagination.total = res.data.total ?? 0;
+
+ dataList.value = res.data.records ?? [];
+ } else {
+ ElMessage.error(res.msg || "鏌ヨ澶辫触");
+
+ dataList.value = [];
+ }
+ })
+
+ .catch(() => {
+ dataList.value = [];
+ })
+
+ .finally(() => {
+ tableLoading.value = false;
+ });
+};
+
+const resetFilters = () => {
+ filters.returnNo = "";
+
+ filters.supplierName = "";
+
+ filters.dateRange = [];
+
+ pagination.currentPage = 1;
+
+ getTableData();
+};
+
+const changePage = ({ page, limit }) => {
+ pagination.currentPage = page;
+
+ pagination.pageSize = limit;
+
+ getTableData();
+};
+
+const handleOut = () => {
+ proxy.download(
+ "/accountPurchase/exportAccountPurchaseReturn",
+
+ buildFilterParams(),
+
+ `閲囪喘閫�璐${new Date().getTime()}.xlsx`
+ );
+};
+
+onMounted(() => {
+ getTableData();
+});
+</script>
+
+
+
+<style lang="scss" scoped>
+.actions {
+ display: flex;
+
+ justify-content: space-between;
+
+ margin-bottom: 15px;
+}
+</style>
+
diff --git a/src/views/financialManagement/receivable/salesOut.vue b/src/views/financialManagement/receivable/salesOut.vue
index fce0c20..297a82c 100644
--- a/src/views/financialManagement/receivable/salesOut.vue
+++ b/src/views/financialManagement/receivable/salesOut.vue
@@ -1,19 +1,27 @@
<template>
+<!-- 閿�鍞嚭搴� -->
<div class="app-container">
<el-form :model="filters" :inline="true">
<el-form-item label="鍑哄簱鍗曞彿:">
- <el-input v-model="filters.outCode" placeholder="璇疯緭鍏ュ嚭搴撳崟鍙�" clearable style="width: 200px;" />
+ <el-input v-model="filters.outboundBatches" placeholder="璇疯緭鍏ュ嚭搴撳崟鍙�" clearable style="width: 200px;" />
</el-form-item>
- <el-form-item label="瀹㈡埛:">
- <el-select v-model="filters.customerId" placeholder="璇烽�夋嫨瀹㈡埛" clearable style="width: 200px;">
- <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
+ <el-form-item label="瀹㈡埛鍚嶇О:">
+ <el-input v-model="filters.customerName" placeholder="璇疯緭鍏ュ鎴峰悕绉�" clearable style="width: 200px;" />
</el-form-item>
<el-form-item label="鍑哄簱鏃ユ湡:">
- <el-date-picker v-model="filters.dateRange" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" range-separator="鑷�" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" clearable />
+ <el-date-picker
+ v-model="filters.dateRange"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ clearable
+ />
</el-form-item>
<el-form-item>
- <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+ <el-button type="primary" @click="onSearch">鎼滅储</el-button>
<el-button @click="resetFilters">閲嶇疆</el-button>
</el-form-item>
</el-form>
@@ -28,76 +36,32 @@
rowKey="id"
:column="columns"
:tableData="dataList"
+ :tableLoading="tableLoading"
:page="{
current: pagination.currentPage,
size: pagination.pageSize,
total: pagination.total,
}"
@pagination="changePage"
- >
- <template #status="{ row }">
- <el-tag :type="getStatusType(row.status)">{{ getStatusLabel(row.status) }}</el-tag>
- </template>
- <template #operation="{ row }">
- <el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
- <el-button type="primary" link @click="edit(row)" v-if="row.status === 'pending'">缂栬緫</el-button>
- <el-button type="danger" link @click="handleDelete(row)" v-if="row.status === 'pending'">鍒犻櫎</el-button>
- </template>
- </PIMTable>
+ />
</div>
-
- <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
- <el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="鍑哄簱鍗曞彿" prop="outCode">
- <el-input v-model="form.outCode" placeholder="璇疯緭鍏ュ嚭搴撳崟鍙�" :disabled="isEdit" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="瀹㈡埛" prop="customerId">
- <el-select v-model="form.customerId" placeholder="璇烽�夋嫨瀹㈡埛" style="width: 100%;" :disabled="isEdit">
- <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="鍑哄簱鏃ユ湡" prop="outDate">
- <el-date-picker v-model="form.outDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="閲戦" prop="amount">
- <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="澶囨敞" prop="remark">
- <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button type="primary" @click="submitForm">纭畾</el-button>
- <el-button @click="dialogVisible = false">鍙栨秷</el-button>
- </template>
- </FormDialog>
</div>
</template>
<script setup>
-import { ref, reactive, onMounted } from "vue";
-import { ElMessage, ElMessageBox } from "element-plus";
-import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ElMessage } from "element-plus";
+import { listPageAccountSales } from "@/api/financialManagement/accountSales";
defineOptions({
name: "閿�鍞嚭搴�",
});
+const { proxy } = getCurrentInstance();
+
const filters = reactive({
- outCode: "",
- customerId: "",
+ outboundBatches: "",
+ customerName: "",
dateRange: [],
});
@@ -108,153 +72,87 @@
});
const columns = [
- { label: "鍑哄簱鍗曞彿", prop: "outCode", width: "150" },
- { label: "瀹㈡埛鍚嶇О", prop: "customerName", width: "180" },
- { label: "鍑哄簱鏃ユ湡", prop: "outDate", width: "120" },
- { label: "閲戦", prop: "amount", width: "120" },
- { label: "鐘舵��", prop: "status", slot: "status" },
- { label: "澶囨敞", prop: "remark", showOverflowTooltip: true },
- { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "200", fixed: "right" },
+ { label: "鍑哄簱鍗曞彿", prop: "outboundBatches", minWidth: "150" },
+ { label: "瀹㈡埛鍚嶇О", prop: "customerName", minWidth: "180" },
+ { label: "鍑哄簱鏃ユ湡", prop: "shippingDate", width: "170" },
+ { label: "浜у搧鍚嶇О", prop: "productName", minWidth: "140" },
+ { label: "浜у搧瑙勬牸", prop: "specificationModel", minWidth: "140" },
+ {
+ label: "閲戦",
+ prop: "outboundAmount",
+ minWidth: "120",
+ align: "right",
+ formatData: (val) => (val === null || val === undefined || val === "" ? "" : Number(val).toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })),
+ },
+ { label: "鍙戣揣缂栧彿", prop: "shippingNo", minWidth: "140" },
+ { label: "閿�鍞鍗曞彿", prop: "salesContractNo", minWidth: "150" },
];
const dataList = ref([]);
-const dialogVisible = ref(false);
-const dialogTitle = ref("");
-const formRef = ref(null);
-const isEdit = ref(false);
-const currentId = ref(null);
+const tableLoading = ref(false);
-const customerList = [
- { id: 1, name: "鍖椾含绉戞妧鏈夐檺鍏徃" },
- { id: 2, name: "涓婃捣璐告槗鍏徃" },
- { id: 3, name: "骞垮窞瀹炰笟鏈夐檺鍏徃" },
- { id: 4, name: "娣卞湷鐢靛瓙鍏徃" },
-];
+function buildFilterParams() {
+ const params = {
+ outboundBatches: filters.outboundBatches || undefined,
+ customerName: filters.customerName || undefined,
+ };
+ if (filters.dateRange && filters.dateRange.length === 2) {
+ params.startDate = filters.dateRange[0];
+ params.endDate = filters.dateRange[1];
+ }
+ return params;
+}
-const form = reactive({
- outCode: "",
- customerId: "",
- outDate: "",
- amount: 0,
- remark: "",
-});
-
-const rules = {
- outCode: [{ required: true, message: "璇疯緭鍏ュ嚭搴撳崟鍙�", trigger: "blur" }],
- customerId: [{ required: true, message: "璇烽�夋嫨瀹㈡埛", trigger: "change" }],
- outDate: [{ required: true, message: "璇烽�夋嫨鍑哄簱鏃ユ湡", trigger: "change" }],
- amount: [{ required: true, message: "璇疯緭鍏ラ噾棰�", trigger: "blur" }],
-};
-
-const mockData = [
- { id: 1, outCode: "CK2024001", customerId: 1, customerName: "鍖椾含绉戞妧鏈夐檺鍏徃", outDate: "2024-01-15", amount: 5000, status: "approved", remark: "" },
- { id: 2, outCode: "CK2024002", customerId: 2, customerName: "涓婃捣璐告槗鍏徃", outDate: "2024-01-16", amount: 8000, status: "pending", remark: "" },
- { id: 3, outCode: "CK2024003", customerId: 3, customerName: "骞垮窞瀹炰笟鏈夐檺鍏徃", outDate: "2024-01-18", amount: 12000, status: "approved", remark: "" },
- { id: 4, outCode: "CK2024004", customerId: 4, customerName: "娣卞湷鐢靛瓙鍏徃", outDate: "2024-01-20", amount: 3500, status: "pending", remark: "" },
-];
-
-const getStatusLabel = (status) => {
- const map = { pending: "寰呭鏍�", approved: "宸插鏍�", rejected: "宸查┏鍥�" };
- return map[status] || status;
-};
-
-const getStatusType = (status) => {
- const map = { pending: "warning", approved: "success", rejected: "danger" };
- return map[status] || "";
+const onSearch = () => {
+ pagination.currentPage = 1;
+ getTableData();
};
const getTableData = () => {
- let result = [...mockData];
- if (filters.outCode) {
- result = result.filter(item => item.outCode.includes(filters.outCode));
- }
- if (filters.customerId) {
- result = result.filter(item => item.customerId === filters.customerId);
- }
- if (filters.dateRange && filters.dateRange.length === 2) {
- result = result.filter(item => item.outDate >= filters.dateRange[0] && item.outDate <= filters.dateRange[1]);
- }
- pagination.total = result.length;
- dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+ tableLoading.value = true;
+ listPageAccountSales({
+ ...buildFilterParams(),
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ })
+ .then((res) => {
+ const ok = res.code === 200 || res.code === 0;
+ if (ok && res.data) {
+ pagination.total = res.data.total ?? 0;
+ dataList.value = res.data.records ?? [];
+ } else {
+ ElMessage.error(res.msg || "鏌ヨ澶辫触");
+ dataList.value = [];
+ }
+ })
+ .catch(() => {
+ dataList.value = [];
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
};
const resetFilters = () => {
- filters.outCode = "";
- filters.customerId = "";
+ filters.outboundBatches = "";
+ filters.customerName = "";
filters.dateRange = [];
pagination.currentPage = 1;
getTableData();
};
-const changePage = ({ current, size }) => {
- pagination.currentPage = current;
- pagination.pageSize = size;
+const changePage = ({ page, limit }) => {
+ pagination.currentPage = page;
+ pagination.pageSize = limit;
getTableData();
};
-const add = () => {
- isEdit.value = false;
- dialogTitle.value = "鏂板鍑哄簱";
- Object.assign(form, {
- outCode: "CK" + Date.now(),
- customerId: "",
- outDate: "",
- amount: 0,
- remark: "",
- });
- dialogVisible.value = true;
-};
-
-const edit = (row) => {
- isEdit.value = true;
- currentId.value = row.id;
- dialogTitle.value = "缂栬緫鍑哄簱";
- Object.assign(form, row);
- dialogVisible.value = true;
-};
-
-const view = (row) => {
- ElMessage.info(`鏌ョ湅鍑哄簱鍗�: ${row.outCode}`);
-};
-
-const submitForm = () => {
- formRef.value.validate((valid) => {
- if (valid) {
- const customer = customerList.find(item => item.id === form.customerId);
- if (isEdit.value) {
- const index = mockData.findIndex(item => item.id === currentId.value);
- if (index !== -1) {
- mockData[index] = { ...mockData[index], ...form, customerName: customer?.name };
- }
- ElMessage.success("缂栬緫鎴愬姛");
- } else {
- const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
- mockData.push({ id: newId, ...form, customerName: customer?.name, status: "pending" });
- ElMessage.success("鏂板鎴愬姛");
- }
- dialogVisible.value = false;
- getTableData();
- }
- });
-};
-
-const handleDelete = (row) => {
- ElMessageBox.confirm("纭鍒犻櫎璇ュ嚭搴撳崟鍚楋紵", "鎻愮ず", {
- confirmButtonText: "纭畾",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- }).then(() => {
- const index = mockData.findIndex(item => item.id === row.id);
- if (index !== -1) {
- mockData.splice(index, 1);
- }
- ElMessage.success("鍒犻櫎鎴愬姛");
- getTableData();
- });
-};
-
const handleOut = () => {
- ElMessage.success("瀵煎嚭鎴愬姛");
+ proxy.download(
+ "/accountSales/exportAccountSalesOutbound",
+ buildFilterParams(),
+ `閿�鍞嚭搴揰${new Date().getTime()}.xlsx`
+ );
};
onMounted(() => {
diff --git a/src/views/financialManagement/receivable/salesReturn.vue b/src/views/financialManagement/receivable/salesReturn.vue
index 4cf54d6..c58d330 100644
--- a/src/views/financialManagement/receivable/salesReturn.vue
+++ b/src/views/financialManagement/receivable/salesReturn.vue
@@ -1,19 +1,27 @@
<template>
+ <!-- 閿�鍞��璐� -->
<div class="app-container">
<el-form :model="filters" :inline="true">
<el-form-item label="閫�璐у崟鍙�:">
- <el-input v-model="filters.returnCode" placeholder="璇疯緭鍏ラ��璐у崟鍙�" clearable style="width: 200px;" />
+ <el-input v-model="filters.returnNo" placeholder="璇疯緭鍏ラ��璐у崟鍙�" clearable style="width: 200px;" />
</el-form-item>
- <el-form-item label="瀹㈡埛:">
- <el-select v-model="filters.customerId" placeholder="璇烽�夋嫨瀹㈡埛" clearable style="width: 200px;">
- <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
+ <el-form-item label="瀹㈡埛鍚嶇О:">
+ <el-input v-model="filters.customerName" placeholder="璇疯緭鍏ュ鎴峰悕绉�" clearable style="width: 200px;" />
</el-form-item>
<el-form-item label="閫�璐ф棩鏈�:">
- <el-date-picker v-model="filters.dateRange" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" range-separator="鑷�" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" clearable />
+ <el-date-picker
+ v-model="filters.dateRange"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ clearable
+ />
</el-form-item>
<el-form-item>
- <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+ <el-button type="primary" @click="onSearch">鎼滅储</el-button>
<el-button @click="resetFilters">閲嶇疆</el-button>
</el-form-item>
</el-form>
@@ -28,90 +36,32 @@
rowKey="id"
:column="columns"
:tableData="dataList"
+ :tableLoading="tableLoading"
:page="{
current: pagination.currentPage,
size: pagination.pageSize,
total: pagination.total,
}"
@pagination="changePage"
- >
- <template #status="{ row }">
- <el-tag :type="getStatusType(row.status)">{{ getStatusLabel(row.status) }}</el-tag>
- </template>
- <template #operation="{ row }">
- <el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
- <el-button type="primary" link @click="edit(row)" v-if="row.status === 'pending'">缂栬緫</el-button>
- <el-button type="success" link @click="handleAudit(row)" v-if="row.status === 'pending'">瀹℃牳</el-button>
- </template>
- </PIMTable>
+ />
</div>
-
- <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
- <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="閫�璐у崟鍙�" prop="returnCode">
- <el-input v-model="form.returnCode" placeholder="璇疯緭鍏ラ��璐у崟鍙�" :disabled="isEdit" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鍏宠仈鍑哄簱鍗�" prop="outCode">
- <el-select v-model="form.outCode" placeholder="璇烽�夋嫨鍑哄簱鍗�" style="width: 100%;" :disabled="isEdit">
- <el-option v-for="item in outList" :key="item.outCode" :label="item.outCode" :value="item.outCode" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="瀹㈡埛" prop="customerId">
- <el-select v-model="form.customerId" placeholder="璇烽�夋嫨瀹㈡埛" style="width: 100%;" :disabled="isEdit">
- <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="閫�璐ф棩鏈�" prop="returnDate">
- <el-date-picker v-model="form.returnDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="閫�璐ч噾棰�" prop="amount">
- <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="閫�璐у師鍥�" prop="reason">
- <el-input v-model="form.reason" placeholder="璇疯緭鍏ラ��璐у師鍥�" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="澶囨敞" prop="remark">
- <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button type="primary" @click="submitForm">纭畾</el-button>
- <el-button @click="dialogVisible = false">鍙栨秷</el-button>
- </template>
- </FormDialog>
</div>
</template>
<script setup>
-import { ref, reactive, onMounted } from "vue";
-import { ElMessage, ElMessageBox } from "element-plus";
-import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ElMessage } from "element-plus";
+import { listPageAccountSalesReturn } from "@/api/financialManagement/accountSales";
defineOptions({
name: "閿�鍞��璐�",
});
+const { proxy } = getCurrentInstance();
+
const filters = reactive({
- returnCode: "",
- customerId: "",
+ returnNo: "",
+ customerName: "",
dateRange: [],
});
@@ -122,173 +72,89 @@
});
const columns = [
- { label: "閫�璐у崟鍙�", prop: "returnCode", width: "150" },
- { label: "瀹㈡埛鍚嶇О", prop: "customerName", width: "180" },
- { label: "鍏宠仈鍑哄簱鍗�", prop: "outCode", width: "150" },
- { label: "閫�璐ф棩鏈�", prop: "returnDate", width: "120" },
- { label: "閫�璐ч噾棰�", prop: "amount", width: "120" },
- { label: "閫�璐у師鍥�", prop: "reason", width: "150", showOverflowTooltip: true },
- { label: "鐘舵��", prop: "status", slot: "status" },
- { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "200", fixed: "right" },
+ { label: "閫�璐у崟鍙�", prop: "returnNo", minWidth: "150" },
+ { label: "瀹㈡埛鍚嶇О", prop: "customerName", minWidth: "180" },
+ { label: "鍏宠仈鍙戣揣鍗曞彿", prop: "shippingNo", minWidth: "150" },
+ { label: "閫�璐ф棩鏈�", prop: "makeTime", minWidth: "170" },
+ {
+ label: "閫�娆炬�婚",
+ prop: "refundAmount",
+ minWidth: "120",
+ align: "right",
+ formatData: (val) =>
+ val === null || val === undefined || val === ""
+ ? ""
+ : Number(val).toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 }),
+ },
+ { label: "閫�璐у師鍥�", prop: "returnReason", minWidth: "150", showOverflowTooltip: true },
+ { label: "閿�鍞鍗曞彿", prop: "salesContractNo", minWidth: "150" },
];
const dataList = ref([]);
-const dialogVisible = ref(false);
-const dialogTitle = ref("");
-const formRef = ref(null);
-const isEdit = ref(false);
-const currentId = ref(null);
+const tableLoading = ref(false);
-const customerList = [
- { id: 1, name: "鍖椾含绉戞妧鏈夐檺鍏徃" },
- { id: 2, name: "涓婃捣璐告槗鍏徃" },
- { id: 3, name: "骞垮窞瀹炰笟鏈夐檺鍏徃" },
- { id: 4, name: "娣卞湷鐢靛瓙鍏徃" },
-];
+function buildFilterParams() {
+ const params = {
+ returnNo: filters.returnNo || undefined,
+ customerName: filters.customerName || undefined,
+ };
+ if (filters.dateRange && filters.dateRange.length === 2) {
+ params.startDate = filters.dateRange[0];
+ params.endDate = filters.dateRange[1];
+ }
+ return params;
+}
-const outList = [
- { outCode: "CK2024001", customerId: 1 },
- { outCode: "CK2024002", customerId: 2 },
- { outCode: "CK2024003", customerId: 3 },
-];
-
-const form = reactive({
- returnCode: "",
- outCode: "",
- customerId: "",
- returnDate: "",
- amount: 0,
- reason: "",
- remark: "",
-});
-
-const rules = {
- returnCode: [{ required: true, message: "璇疯緭鍏ラ��璐у崟鍙�", trigger: "blur" }],
- outCode: [{ required: true, message: "璇烽�夋嫨鍏宠仈鍑哄簱鍗�", trigger: "change" }],
- customerId: [{ required: true, message: "璇烽�夋嫨瀹㈡埛", trigger: "change" }],
- returnDate: [{ required: true, message: "璇烽�夋嫨閫�璐ф棩鏈�", trigger: "change" }],
- amount: [{ required: true, message: "璇疯緭鍏ラ��璐ч噾棰�", trigger: "blur" }],
-};
-
-const mockData = [
- { id: 1, returnCode: "TH2024001", outCode: "CK2024001", customerId: 1, customerName: "鍖椾含绉戞妧鏈夐檺鍏徃", returnDate: "2024-01-20", amount: 1000, reason: "璐ㄩ噺闂", status: "approved", remark: "" },
- { id: 2, returnCode: "TH2024002", outCode: "CK2024002", customerId: 2, customerName: "涓婃捣璐告槗鍏徃", returnDate: "2024-01-22", amount: 500, reason: "瑙勬牸涓嶇", status: "pending", remark: "" },
-];
-
-const getStatusLabel = (status) => {
- const map = { pending: "寰呭鏍�", approved: "宸插鏍�", rejected: "宸查┏鍥�" };
- return map[status] || status;
-};
-
-const getStatusType = (status) => {
- const map = { pending: "warning", approved: "success", rejected: "danger" };
- return map[status] || "";
+const onSearch = () => {
+ pagination.currentPage = 1;
+ getTableData();
};
const getTableData = () => {
- let result = [...mockData];
- if (filters.returnCode) {
- result = result.filter(item => item.returnCode.includes(filters.returnCode));
- }
- if (filters.customerId) {
- result = result.filter(item => item.customerId === filters.customerId);
- }
- if (filters.dateRange && filters.dateRange.length === 2) {
- result = result.filter(item => item.returnDate >= filters.dateRange[0] && item.returnDate <= filters.dateRange[1]);
- }
- pagination.total = result.length;
- dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
+ tableLoading.value = true;
+ listPageAccountSalesReturn({
+ ...buildFilterParams(),
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ })
+ .then((res) => {
+ const ok = res.code === 200 || res.code === 0;
+ if (ok && res.data) {
+ pagination.total = res.data.total ?? 0;
+ dataList.value = res.data.records ?? [];
+ } else {
+ ElMessage.error(res.msg || "鏌ヨ澶辫触");
+ dataList.value = [];
+ }
+ })
+ .catch(() => {
+ dataList.value = [];
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
};
const resetFilters = () => {
- filters.returnCode = "";
- filters.customerId = "";
+ filters.returnNo = "";
+ filters.customerName = "";
filters.dateRange = [];
pagination.currentPage = 1;
getTableData();
};
-const changePage = ({ current, size }) => {
- pagination.currentPage = current;
- pagination.pageSize = size;
+const changePage = ({ page, limit }) => {
+ pagination.currentPage = page;
+ pagination.pageSize = limit;
getTableData();
};
-const add = () => {
- isEdit.value = false;
- dialogTitle.value = "鏂板閫�璐�";
- Object.assign(form, {
- returnCode: "TH" + Date.now(),
- outCode: "",
- customerId: "",
- returnDate: "",
- amount: 0,
- reason: "",
- remark: "",
- });
- dialogVisible.value = true;
-};
-
-const edit = (row) => {
- isEdit.value = true;
- currentId.value = row.id;
- dialogTitle.value = "缂栬緫閫�璐�";
- Object.assign(form, row);
- dialogVisible.value = true;
-};
-
-const view = (row) => {
- ElMessage.info(`鏌ョ湅閫�璐у崟: ${row.returnCode}`);
-};
-
-const handleAudit = (row) => {
- ElMessageBox.confirm("纭瀹℃牳閫氳繃璇ラ��璐у崟鍚楋紵", "鎻愮ず", {
- confirmButtonText: "閫氳繃",
- cancelButtonText: "椹冲洖",
- distinguishCancelAndClose: true,
- type: "warning",
- }).then(() => {
- const index = mockData.findIndex(item => item.id === row.id);
- if (index !== -1) {
- mockData[index].status = "approved";
- }
- ElMessage.success("瀹℃牳閫氳繃");
- getTableData();
- }).catch((action) => {
- if (action === "cancel") {
- const index = mockData.findIndex(item => item.id === row.id);
- if (index !== -1) {
- mockData[index].status = "rejected";
- }
- ElMessage.warning("宸查┏鍥�");
- getTableData();
- }
- });
-};
-
-const submitForm = () => {
- formRef.value.validate((valid) => {
- if (valid) {
- const customer = customerList.find(item => item.id === form.customerId);
- if (isEdit.value) {
- const index = mockData.findIndex(item => item.id === currentId.value);
- if (index !== -1) {
- mockData[index] = { ...mockData[index], ...form, customerName: customer?.name };
- }
- ElMessage.success("缂栬緫鎴愬姛");
- } else {
- const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
- mockData.push({ id: newId, ...form, customerName: customer?.name, status: "pending" });
- ElMessage.success("鏂板鎴愬姛");
- }
- dialogVisible.value = false;
- getTableData();
- }
- });
-};
-
const handleOut = () => {
- ElMessage.success("瀵煎嚭鎴愬姛");
+ proxy.download(
+ "/accountSales/exportAccountSalesReturn",
+ buildFilterParams(),
+ `閿�鍞��璐${new Date().getTime()}.xlsx`
+ );
};
onMounted(() => {
diff --git a/src/views/financialManagement/voucher/detailLedger.vue b/src/views/financialManagement/voucher/detailLedger.vue
index 7f85790..1909d0e 100644
--- a/src/views/financialManagement/voucher/detailLedger.vue
+++ b/src/views/financialManagement/voucher/detailLedger.vue
@@ -1,165 +1,126 @@
<template>
- <div class="app-container">
- <el-form :model="filters" :inline="true">
- <el-form-item label="浼氳绉戠洰:">
- <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code' }" placeholder="璇烽�夋嫨浼氳绉戠洰" clearable style="width: 250px;" filterable />
- </el-form-item>
- <el-form-item label="杈呭姪鏍哥畻:">
- <el-select v-model="filters.auxiliary" placeholder="璇烽�夋嫨杈呭姪鏍哥畻" clearable style="width: 180px;">
- <el-option label="瀹㈡埛" value="customer" />
- <el-option label="渚涘簲鍟�" value="supplier" />
- <el-option label="閮ㄩ棬" value="department" />
- <el-option label="鍛樺伐" value="employee" />
- <el-option label="椤圭洰" value="project" />
- </el-select>
- </el-form-item>
- <el-form-item label="鏍哥畻瀵硅薄:">
- <el-select v-model="filters.auxiliaryItem" placeholder="璇烽�夋嫨鏍哥畻瀵硅薄" clearable style="width: 200px;" :disabled="!filters.auxiliary">
- <el-option v-for="item in auxiliaryItems" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- <el-form-item label="鏈熼棿:">
- <el-date-picker v-model="filters.startMonth" type="month" placeholder="寮�濮嬫湀浠�" value-format="YYYY-MM" style="width: 140px;" />
- <span style="margin: 0 10px;">鑷�</span>
- <el-date-picker v-model="filters.endMonth" type="month" placeholder="缁撴潫鏈堜唤" value-format="YYYY-MM" style="width: 140px;" />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
- <el-button @click="resetFilters">閲嶇疆</el-button>
- <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>
- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
- </el-form-item>
- </el-form>
+ <div class="app-container ledger-page">
+ <div class="ledger-layout">
+ <aside class="subject-panel">
+ <el-input v-model="subjectKeyword" placeholder="璇疯緭鍏ョ鐩悕绉�/缂栧彿" clearable prefix-icon="Search" />
+ <el-scrollbar class="subject-tree-scroll">
+ <el-tree
+ ref="subjectTreeRef"
+ :data="subjectOptions"
+ node-key="code"
+ :props="{ label: 'name', children: 'children' }"
+ highlight-current
+ default-expand-all
+ :expand-on-click-node="false"
+ :filter-node-method="filterSubjectNode"
+ @node-click="handleSubjectClick"
+ >
+ <template #default="{ data }">
+ <span class="subject-node">{{ data.code }} {{ data.name }}</span>
+ </template>
+ </el-tree>
+ </el-scrollbar>
+ </aside>
- <div class="ledger-header" v-if="currentSubject">
- <h2>绉戠洰鏄庣粏璐�</h2>
- <p>绉戠洰: {{ currentSubject.code }} {{ currentSubject.name }}</p>
- <p v-if="filters.auxiliary && filters.auxiliaryItem">杈呭姪鏍哥畻: {{ getAuxiliaryLabel() }}</p>
- <p>鏈熼棿: {{ filters.startMonth }} 鑷� {{ filters.endMonth }}</p>
+ <section class="ledger-content">
+ <el-form :model="filters" :inline="true" class="filter-form">
+ <el-form-item label="鏈熼棿:">
+ <el-date-picker v-model="filters.startMonth" type="month" placeholder="寮�濮嬫湀浠�" value-format="YYYY-MM" style="width: 140px;" />
+ <span style="margin: 0 10px;">鑷�</span>
+ <el-date-picker v-model="filters.endMonth" type="month" placeholder="缁撴潫鏈堜唤" value-format="YYYY-MM" style="width: 140px;" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
+ <el-button @click="resetFilters">閲嶇疆</el-button>
+ <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>
+ <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+ </el-form-item>
+ </el-form>
+
+ <div class="table_list">
+ <el-table :data="dataList" border style="width: 100%">
+ <el-table-column prop="date" label="鏃ユ湡" width="120" />
+ <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" />
+ <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip />
+ <el-table-column prop="debit" label="鍊熸柟" width="150">
+ <template #default="{ row }">
+ <span v-if="row.debit > 0" class="text-danger">楼{{ formatMoney(row.debit) }}</span>
+ <span v-else>-</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="credit" label="璐锋柟" width="150">
+ <template #default="{ row }">
+ <span v-if="row.credit > 0" class="text-success">楼{{ formatMoney(row.credit) }}</span>
+ <span v-else>-</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏂瑰悜" width="80">
+ <template #default="{ row }">
+ <el-tag :type="row.direction === '鍊�' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="浣欓" width="150">
+ <template #default="{ row }">
+ <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+
+ <el-empty v-if="!currentSubject" description="璇烽�夋嫨浼氳绉戠洰鏌ヨ" style="margin-top: 50px;" />
+ </section>
</div>
-
- <div class="table_list">
- <el-table :data="dataList" border style="width: 100%" show-summary :summary-method="getSummaries">
- <el-table-column prop="date" label="鏃ユ湡" width="120" />
- <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" />
- <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip />
- <el-table-column label="鍊熸柟" width="150">
- <template #default="{ row }">
- <span v-if="row.debit > 0" class="text-danger">楼{{ formatMoney(row.debit) }}</span>
- <span v-else>-</span>
- </template>
- </el-table-column>
- <el-table-column label="璐锋柟" width="150">
- <template #default="{ row }">
- <span v-if="row.credit > 0" class="text-success">楼{{ formatMoney(row.credit) }}</span>
- <span v-else>-</span>
- </template>
- </el-table-column>
- <el-table-column label="鏂瑰悜" width="80">
- <template #default="{ row }">
- <el-tag :type="row.direction === '鍊�' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="浣欓" width="150">
- <template #default="{ row }">
- <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
- </template>
- </el-table-column>
- </el-table>
- </div>
-
- <el-empty v-if="!currentSubject" description="璇烽�夋嫨浼氳绉戠洰鏌ヨ" style="margin-top: 50px;" />
</div>
</template>
<script setup>
-import { ref, reactive, onMounted, computed, watch } from "vue";
+import { ref, reactive, onMounted, computed, watch, nextTick } from "vue";
import { ElMessage } from "element-plus";
+import { listAccountSubject } from "@/api/financialManagement/accountSubject";
+import { getDetailLedger } from "@/api/financialManagement/ledger";
defineOptions({
name: "绉戠洰鏄庣粏璐�",
});
const filters = reactive({
- subject: [],
- auxiliary: "",
- auxiliaryItem: "",
- startMonth: "2024-01",
- endMonth: "2024-03",
+ subject: "",
+ startMonth: "",
+ endMonth: "",
});
const dataList = ref([]);
+const subjectOptions = ref([]);
+const subjectKeyword = ref("");
+const subjectTreeRef = ref();
-const subjectOptions = [
- {
- code: "1122",
- name: "搴旀敹璐︽",
- children: [
- { code: "112201", name: "鍖椾含绉戞妧鏈夐檺鍏徃" },
- { code: "112202", name: "涓婃捣璐告槗鍏徃" },
- { code: "112203", name: "骞垮窞瀹炰笟鏈夐檺鍏徃" },
- ],
- },
- {
- code: "2202",
- name: "搴斾粯璐︽",
- children: [
- { code: "220201", name: "鍖椾含鍘熸潗鏂欎緵搴斿晢" },
- { code: "220202", name: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�" },
- { code: "220203", name: "骞垮窞鍖呰鏉愭枡鍘�" },
- ],
- },
- {
- code: "6602",
- name: "绠$悊璐圭敤",
- children: [
- { code: "660201", name: "鍔炲叕璐�" },
- { code: "660202", name: "宸梾璐�" },
- { code: "660203", name: "涓氬姟鎷涘緟璐�" },
- ],
- },
+const getPreviousMonth = () => {
+ const date = new Date();
+ date.setDate(1);
+ date.setMonth(date.getMonth() - 1);
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ return `${year}-${month}`;
+};
+
+const defaultMonth = getPreviousMonth();
+filters.startMonth = defaultMonth;
+filters.endMonth = defaultMonth;
+
+const fallbackSubjects = [
+ { code: "1122", name: "搴旀敹璐︽" },
+ { code: "2202", name: "搴斾粯璐︽" },
+ { code: "6602", name: "绠$悊璐圭敤" },
];
-const auxiliaryItems = computed(() => {
- const map = {
- customer: [
- { value: "1", label: "鍖椾含绉戞妧鏈夐檺鍏徃" },
- { value: "2", label: "涓婃捣璐告槗鍏徃" },
- { value: "3", label: "骞垮窞瀹炰笟鏈夐檺鍏徃" },
- ],
- supplier: [
- { value: "1", label: "鍖椾含鍘熸潗鏂欎緵搴斿晢" },
- { value: "2", label: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�" },
- { value: "3", label: "骞垮窞鍖呰鏉愭枡鍘�" },
- ],
- department: [
- { value: "1", label: "璐㈠姟閮�" },
- { value: "2", label: "閿�鍞儴" },
- { value: "3", label: "閲囪喘閮�" },
- ],
- employee: [
- { value: "1", label: "寮犱笁" },
- { value: "2", label: "鏉庡洓" },
- { value: "3", label: "鐜嬩簲" },
- ],
- project: [
- { value: "1", label: "椤圭洰A" },
- { value: "2", label: "椤圭洰B" },
- { value: "3", label: "椤圭洰C" },
- ],
- };
- return map[filters.auxiliary] || [];
-});
-
-watch(() => filters.auxiliary, () => {
- filters.auxiliaryItem = "";
-});
-
-const currentSubject = computed(() => {
- if (!filters.subject || filters.subject.length === 0) return null;
- const code = filters.subject[filters.subject.length - 1];
- return findSubject(subjectOptions, code);
-});
+const toTree = (nodes = []) =>
+ nodes
+ .filter(item => item.subjectCode && item.subjectName)
+ .map(item => ({
+ code: item.subjectCode,
+ name: item.subjectName,
+ children: toTree(item.children || []),
+ }));
const findSubject = (options, code) => {
for (const item of options) {
@@ -172,9 +133,68 @@
return null;
};
-const getAuxiliaryLabel = () => {
- const item = auxiliaryItems.value.find(i => i.value === filters.auxiliaryItem);
- return item ? item.label : "";
+const currentSubject = computed(() => {
+ if (!filters.subject) return null;
+ return findSubject(subjectOptions.value, filters.subject);
+});
+
+const getFirstSubjectCode = (nodes = []) => {
+ for (const item of nodes) {
+ if (item.code) return item.code;
+ if (item.children && item.children.length > 0) {
+ const childCode = getFirstSubjectCode(item.children);
+ if (childCode) return childCode;
+ }
+ }
+ return "";
+};
+
+const setDefaultSubjectSelection = async () => {
+ const firstCode = getFirstSubjectCode(subjectOptions.value);
+ if (!firstCode) {
+ filters.subject = "";
+ subjectTreeRef.value?.setCurrentKey(null);
+ return;
+ }
+ filters.subject = firstCode;
+ await nextTick();
+ subjectTreeRef.value?.setCurrentKey(firstCode);
+};
+
+const filterSubjectNode = (value, data) => {
+ const keyword = value?.trim();
+ if (!keyword) return true;
+ return `${data.code}${data.name}`.includes(keyword);
+};
+
+watch(subjectKeyword, (value) => {
+ subjectTreeRef.value?.filter(value || "");
+});
+
+const handleSubjectClick = async (data) => {
+ filters.subject = data.code;
+ await getTableData();
+};
+
+const loadSubjectOptions = async () => {
+ let options = [];
+ try {
+ const { data } = await listAccountSubject({
+ current: 1,
+ size: 1000,
+ });
+ options = toTree(data?.records || []);
+ } catch (error) {
+ // 鍏ㄥ眬鎷︽埅鍣ㄥ凡鎻愮ず锛屼笅闈㈣蛋鍏滃簳绉戠洰
+ }
+ if (options.length === 0) {
+ options = fallbackSubjects.map(item => ({ ...item, children: [] }));
+ }
+ subjectOptions.value = options;
+ await setDefaultSubjectSelection();
+ if (filters.subject) {
+ await getTableData();
+ }
};
const formatMoney = (value) => {
@@ -182,63 +202,34 @@
return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};
-const mockData = [
- { date: "2024-01-01", voucherNo: "-", summary: "鏈熷垵浣欓", debit: 0, credit: 0, direction: "鍊�", balance: 10000 },
- { date: "2024-01-05", voucherNo: "璁�-0001", summary: "閿�鍞嚭搴�", debit: 5000, credit: 0, direction: "鍊�", balance: 15000 },
- { date: "2024-01-10", voucherNo: "璁�-0002", summary: "鏀跺埌璐ф", debit: 0, credit: 3000, direction: "鍊�", balance: 12000 },
- { date: "2024-01-15", voucherNo: "璁�-0003", summary: "閿�鍞嚭搴�", debit: 8000, credit: 0, direction: "鍊�", balance: 20000 },
- { date: "2024-01-20", voucherNo: "璁�-0004", summary: "閿�鍞��璐�", debit: 0, credit: 2000, direction: "鍊�", balance: 18000 },
- { date: "2024-01-25", voucherNo: "璁�-0005", summary: "鏀跺埌璐ф", debit: 0, credit: 5000, direction: "鍊�", balance: 13000 },
- { date: "2024-01-31", voucherNo: "-", summary: "鏈湀鍚堣", debit: 13000, credit: 10000, direction: "鍊�", balance: 13000 },
- { date: "2024-02-01", voucherNo: "-", summary: "鏈熷垵浣欓", debit: 0, credit: 0, direction: "鍊�", balance: 13000 },
- { date: "2024-02-10", voucherNo: "璁�-0006", summary: "閿�鍞嚭搴�", debit: 6000, credit: 0, direction: "鍊�", balance: 19000 },
- { date: "2024-02-15", voucherNo: "璁�-0007", summary: "鏀跺埌璐ф", debit: 0, credit: 4000, direction: "鍊�", balance: 15000 },
- { date: "2024-02-28", voucherNo: "-", summary: "鏈湀鍚堣", debit: 6000, credit: 4000, direction: "鍊�", balance: 15000 },
- { date: "2024-03-01", voucherNo: "-", summary: "鏈熷垵浣欓", debit: 0, credit: 0, direction: "鍊�", balance: 15000 },
- { date: "2024-03-05", voucherNo: "璁�-0008", summary: "閿�鍞嚭搴�", debit: 7000, credit: 0, direction: "鍊�", balance: 22000 },
- { date: "2024-03-10", voucherNo: "璁�-0009", summary: "鏀跺埌璐ф", debit: 0, credit: 6000, direction: "鍊�", balance: 16000 },
- { date: "2024-03-31", voucherNo: "-", summary: "鏈湀鍚堣", debit: 7000, credit: 6000, direction: "鍊�", balance: 16000 },
- { date: "2024-03-31", voucherNo: "-", summary: "鏈勾绱", debit: 26000, credit: 20000, direction: "鍊�", balance: 16000 },
-];
-
-const getTableData = () => {
+// 鑱旇皟绾﹀畾锛氭槑缁嗚处鎸夌鐩笌鏈熼棿杩囨护
+const getTableData = async () => {
if (!currentSubject.value) {
dataList.value = [];
return;
}
- dataList.value = [...mockData];
+ try {
+ const { data } = await getDetailLedger({
+ subjectCode: currentSubject.value.code,
+ startMonth: filters.startMonth,
+ endMonth: filters.endMonth,
+ });
+ dataList.value = Array.isArray(data) ? data : data?.records || [];
+ } catch (error) {
+ // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
+ }
};
-const resetFilters = () => {
- filters.subject = [];
- filters.auxiliary = "";
- filters.auxiliaryItem = "";
- filters.startMonth = "2024-01";
- filters.endMonth = "2024-03";
+const resetFilters = async () => {
+ filters.startMonth = defaultMonth;
+ filters.endMonth = defaultMonth;
dataList.value = [];
-};
-
-const getSummaries = (param) => {
- const { columns, data } = param;
- const sums = [];
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = "鍚堣";
- return;
- }
- if (column.property === "debit") {
- const values = data.map(item => Number(item.debit));
- const sum = values.reduce((prev, curr) => prev + curr, 0);
- sums[index] = "楼" + formatMoney(sum);
- } else if (column.property === "credit") {
- const values = data.map(item => Number(item.credit));
- const sum = values.reduce((prev, curr) => prev + curr, 0);
- sums[index] = "楼" + formatMoney(sum);
- } else {
- sums[index] = "";
- }
- });
- return sums;
+ subjectKeyword.value = "";
+ subjectTreeRef.value?.filter("");
+ await setDefaultSubjectSelection();
+ if (filters.subject) {
+ await getTableData();
+ }
};
const handlePrint = () => {
@@ -249,22 +240,43 @@
ElMessage.success("瀵煎嚭鎴愬姛");
};
-onMounted(() => {
- // 榛樿涓嶅姞杞芥暟鎹紝闇�瑕侀�夋嫨绉戠洰
+onMounted(async () => {
+ await loadSubjectOptions();
});
</script>
<style lang="scss" scoped>
-.ledger-header {
- text-align: center;
- margin-bottom: 20px;
- h2 {
- margin: 0 0 10px 0;
- }
- p {
- color: #606266;
- margin: 5px 0;
- }
+.ledger-layout {
+ display: flex;
+ gap: 16px;
+}
+
+.subject-panel {
+ width: 260px;
+ flex-shrink: 0;
+ padding: 12px;
+ border: 1px solid #e4e7ed;
+ border-radius: 8px;
+ background-color: #fff;
+}
+
+.subject-tree-scroll {
+ height: 600px;
+ margin-top: 12px;
+}
+
+.subject-node {
+ display: inline-flex;
+ align-items: center;
+}
+
+.ledger-content {
+ flex: 1;
+ min-width: 0;
+}
+
+.filter-form {
+ margin-bottom: 12px;
}
.text-primary {
@@ -286,4 +298,12 @@
color: #e6a23c;
font-weight: bold;
}
+
+.subject-panel :deep(.el-tree-node__content) {
+ height: 34px;
+}
+
+.subject-panel :deep(.el-tree-node.is-current > .el-tree-node__content) {
+ background-color: #f0f7ff;
+}
</style>
diff --git a/src/views/financialManagement/voucher/generalLedger.vue b/src/views/financialManagement/voucher/generalLedger.vue
index 5da2d70..9683487 100644
--- a/src/views/financialManagement/voucher/generalLedger.vue
+++ b/src/views/financialManagement/voucher/generalLedger.vue
@@ -1,114 +1,128 @@
<template>
- <div class="app-container">
- <el-form :model="filters" :inline="true">
- <el-form-item label="浼氳绉戠洰:">
- <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code' }" placeholder="璇烽�夋嫨浼氳绉戠洰" clearable style="width: 250px;" filterable />
- </el-form-item>
- <el-form-item label="鏈熼棿:">
- <el-date-picker v-model="filters.startMonth" type="month" placeholder="寮�濮嬫湀浠�" value-format="YYYY-MM" style="width: 140px;" />
- <span style="margin: 0 10px;">鑷�</span>
- <el-date-picker v-model="filters.endMonth" type="month" placeholder="缁撴潫鏈堜唤" value-format="YYYY-MM" style="width: 140px;" />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
- <el-button @click="resetFilters">閲嶇疆</el-button>
- <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>
- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
- </el-form-item>
- </el-form>
+ <div class="app-container ledger-page">
+ <div class="ledger-layout">
+ <aside class="subject-panel">
+ <el-input v-model="subjectKeyword" placeholder="璇疯緭鍏ョ鐩悕绉�/缂栧彿" clearable prefix-icon="Search" />
+ <el-scrollbar class="subject-tree-scroll">
+ <el-tree
+ ref="subjectTreeRef"
+ :data="subjectOptions"
+ node-key="code"
+ :props="{ label: 'name', children: 'children' }"
+ highlight-current
+ default-expand-all
+ :expand-on-click-node="false"
+ :filter-node-method="filterSubjectNode"
+ @node-click="handleSubjectClick"
+ >
+ <template #default="{ data }">
+ <span class="subject-node">{{ data.code }} {{ data.name }}</span>
+ </template>
+ </el-tree>
+ </el-scrollbar>
+ </aside>
- <div class="ledger-header" v-if="currentSubject">
- <h2>绉戠洰鎬昏处</h2>
- <p>绉戠洰: {{ currentSubject.code }} {{ currentSubject.name }}</p>
- <p>鏈熼棿: {{ filters.startMonth }} 鑷� {{ filters.endMonth }}</p>
+ <section class="ledger-content">
+ <el-form :model="filters" :inline="true" class="filter-form">
+ <el-form-item label="鏈熼棿:">
+ <el-date-picker v-model="filters.startMonth" type="month" placeholder="寮�濮嬫湀浠�" value-format="YYYY-MM" style="width: 140px;" />
+ <span style="margin: 0 10px;">鑷�</span>
+ <el-date-picker v-model="filters.endMonth" type="month" placeholder="缁撴潫鏈堜唤" value-format="YYYY-MM" style="width: 140px;" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
+ <el-button @click="resetFilters">閲嶇疆</el-button>
+ <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>
+ <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+ </el-form-item>
+ </el-form>
+
+ <div class="table_list">
+ <el-table :data="dataList" border style="width: 100%">
+ <el-table-column prop="date" label="鏃ユ湡" width="120" />
+ <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" />
+ <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip />
+ <el-table-column prop="debit" label="鍊熸柟" width="150">
+ <template #default="{ row }">
+ <span v-if="row.debit > 0" class="text-danger">楼{{ formatMoney(row.debit) }}</span>
+ <span v-else>-</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="credit" label="璐锋柟" width="150">
+ <template #default="{ row }">
+ <span v-if="row.credit > 0" class="text-success">楼{{ formatMoney(row.credit) }}</span>
+ <span v-else>-</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏂瑰悜" width="80">
+ <template #default="{ row }">
+ <el-tag :type="row.direction === '鍊�' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="浣欓" width="150">
+ <template #default="{ row }">
+ <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+
+ <el-empty v-if="!currentSubject" description="璇烽�夋嫨浼氳绉戠洰鏌ヨ" style="margin-top: 50px;" />
+ </section>
</div>
-
- <div class="table_list">
- <el-table :data="dataList" border style="width: 100%" show-summary :summary-method="getSummaries">
- <el-table-column prop="date" label="鏃ユ湡" width="120" />
- <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" />
- <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip />
- <el-table-column label="鍊熸柟" width="150">
- <template #default="{ row }">
- <span v-if="row.debit > 0" class="text-danger">楼{{ formatMoney(row.debit) }}</span>
- <span v-else>-</span>
- </template>
- </el-table-column>
- <el-table-column label="璐锋柟" width="150">
- <template #default="{ row }">
- <span v-if="row.credit > 0" class="text-success">楼{{ formatMoney(row.credit) }}</span>
- <span v-else>-</span>
- </template>
- </el-table-column>
- <el-table-column label="鏂瑰悜" width="80">
- <template #default="{ row }">
- <el-tag :type="row.direction === '鍊�' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="浣欓" width="150">
- <template #default="{ row }">
- <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
- </template>
- </el-table-column>
- </el-table>
- </div>
-
- <el-empty v-if="!currentSubject" description="璇烽�夋嫨浼氳绉戠洰鏌ヨ" style="margin-top: 50px;" />
</div>
</template>
<script setup>
-import { ref, reactive, onMounted, computed } from "vue";
+import { ref, reactive, onMounted, computed, watch, nextTick } from "vue";
import { ElMessage } from "element-plus";
+import { listAccountSubject } from "@/api/financialManagement/accountSubject";
+import { getGeneralLedger } from "@/api/financialManagement/ledger";
defineOptions({
name: "绉戠洰鎬昏处",
});
const filters = reactive({
- subject: [],
- startMonth: "2024-01",
- endMonth: "2024-03",
+ subject: "",
+ startMonth: "",
+ endMonth: "",
});
const dataList = ref([]);
+const subjectOptions = ref([]);
+const subjectKeyword = ref("");
+const subjectTreeRef = ref();
-const subjectOptions = [
- {
- code: "1001",
- name: "搴撳瓨鐜伴噾",
- children: [],
- },
- {
- code: "1002",
- name: "閾惰瀛樻",
- children: [
- { code: "100201", name: "宸ュ晢閾惰" },
- { code: "100202", name: "寤鸿閾惰" },
- ],
- },
- {
- code: "1122",
- name: "搴旀敹璐︽",
- children: [],
- },
- {
- code: "2202",
- name: "搴斾粯璐︽",
- children: [],
- },
- {
- code: "6001",
- name: "涓昏惀涓氬姟鏀跺叆",
- children: [],
- },
+const getPreviousMonth = () => {
+ const date = new Date();
+ date.setDate(1);
+ date.setMonth(date.getMonth() - 1);
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ return `${year}-${month}`;
+};
+
+const defaultMonth = getPreviousMonth();
+filters.startMonth = defaultMonth;
+filters.endMonth = defaultMonth;
+
+const fallbackSubjects = [
+ { code: "1001", name: "搴撳瓨鐜伴噾" },
+ { code: "1002", name: "閾惰瀛樻" },
+ { code: "1122", name: "搴旀敹璐︽" },
+ { code: "2202", name: "搴斾粯璐︽" },
+ { code: "6001", name: "涓昏惀涓氬姟鏀跺叆" },
];
-const currentSubject = computed(() => {
- if (!filters.subject || filters.subject.length === 0) return null;
- const code = filters.subject[filters.subject.length - 1];
- return findSubject(subjectOptions, code);
-});
+const toTree = (nodes = []) =>
+ nodes
+ .filter(item => item.subjectCode && item.subjectName)
+ .map(item => ({
+ code: item.subjectCode,
+ name: item.subjectName,
+ children: toTree(item.children || []),
+ }));
const findSubject = (options, code) => {
for (const item of options) {
@@ -121,65 +135,104 @@
return null;
};
+const currentSubject = computed(() => {
+ if (!filters.subject) return null;
+ return findSubject(subjectOptions.value, filters.subject);
+});
+
+const getFirstSubjectCode = (nodes = []) => {
+ for (const item of nodes) {
+ if (item.code) return item.code;
+ if (item.children && item.children.length > 0) {
+ const childCode = getFirstSubjectCode(item.children);
+ if (childCode) return childCode;
+ }
+ }
+ return "";
+};
+
+const setDefaultSubjectSelection = async () => {
+ const firstCode = getFirstSubjectCode(subjectOptions.value);
+ if (!firstCode) {
+ filters.subject = "";
+ subjectTreeRef.value?.setCurrentKey(null);
+ return;
+ }
+ filters.subject = firstCode;
+ await nextTick();
+ subjectTreeRef.value?.setCurrentKey(firstCode);
+};
+
+const filterSubjectNode = (value, data) => {
+ const keyword = value?.trim();
+ if (!keyword) return true;
+ return `${data.code}${data.name}`.includes(keyword);
+};
+
+watch(subjectKeyword, (value) => {
+ subjectTreeRef.value?.filter(value || "");
+});
+
+const handleSubjectClick = async (data) => {
+ filters.subject = data.code;
+ await getTableData();
+};
+
+const loadSubjectOptions = async () => {
+ let options = [];
+ try {
+ const { data } = await listAccountSubject({
+ current: 1,
+ size: 1000,
+ status: 0,
+ });
+ options = toTree(data?.records || []);
+ } catch (error) {
+ // 鍏ㄥ眬鎷︽埅鍣ㄥ凡鎻愮ず锛屼笅闈㈣蛋鍏滃簳绉戠洰
+ }
+ if (options.length === 0) {
+ options = fallbackSubjects.map(item => ({ ...item, children: [] }));
+ }
+ subjectOptions.value = options;
+ await setDefaultSubjectSelection();
+ if (filters.subject) {
+ await getTableData();
+ }
+};
+
const formatMoney = (value) => {
if (value === undefined || value === null) return "0.00";
return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};
-const mockData = [
- { date: "2024-01-01", voucherNo: "-", summary: "鏈熷垵浣欓", debit: 0, credit: 0, direction: "鍊�", balance: 100000 },
- { date: "2024-01-05", voucherNo: "璁�-0001", summary: "閿�鍞敹鍏�", debit: 5650, credit: 0, direction: "鍊�", balance: 105650 },
- { date: "2024-01-10", voucherNo: "璁�-0002", summary: "閲囪喘鏀嚭", debit: 0, credit: 8000, direction: "鍊�", balance: 97650 },
- { date: "2024-01-15", voucherNo: "璁�-0003", summary: "鏀跺埌璐ф", debit: 10000, credit: 0, direction: "鍊�", balance: 107650 },
- { date: "2024-01-20", voucherNo: "璁�-0004", summary: "鏀粯璐圭敤", debit: 0, credit: 5000, direction: "鍊�", balance: 102650 },
- { date: "2024-01-31", voucherNo: "-", summary: "鏈湀鍚堣", debit: 15650, credit: 13000, direction: "鍊�", balance: 102650 },
- { date: "2024-02-01", voucherNo: "-", summary: "鏈熷垵浣欓", debit: 0, credit: 0, direction: "鍊�", balance: 102650 },
- { date: "2024-02-10", voucherNo: "璁�-0005", summary: "閿�鍞敹鍏�", debit: 8000, credit: 0, direction: "鍊�", balance: 110650 },
- { date: "2024-02-15", voucherNo: "璁�-0006", summary: "閲囪喘鏀嚭", debit: 0, credit: 12000, direction: "鍊�", balance: 98650 },
- { date: "2024-02-28", voucherNo: "-", summary: "鏈湀鍚堣", debit: 8000, credit: 12000, direction: "鍊�", balance: 98650 },
- { date: "2024-03-01", voucherNo: "-", summary: "鏈熷垵浣欓", debit: 0, credit: 0, direction: "鍊�", balance: 98650 },
- { date: "2024-03-05", voucherNo: "璁�-0007", summary: "閿�鍞敹鍏�", debit: 12000, credit: 0, direction: "鍊�", balance: 110650 },
- { date: "2024-03-10", voucherNo: "璁�-0008", summary: "鏀粯宸ヨ祫", debit: 0, credit: 15000, direction: "鍊�", balance: 95650 },
- { date: "2024-03-31", voucherNo: "-", summary: "鏈湀鍚堣", debit: 12000, credit: 15000, direction: "鍊�", balance: 95650 },
- { date: "2024-03-31", voucherNo: "-", summary: "鏈勾绱", debit: 35650, credit: 40000, direction: "鍊�", balance: 95650 },
-];
-
-const getTableData = () => {
+// 鑱旇皟绾﹀畾锛氭�昏处鎺ュ彛杩斿洖琛屾暟缁勶紙rowType/date/voucherNo/summary/debit/credit/direction/balance锛�
+const getTableData = async () => {
if (!currentSubject.value) {
dataList.value = [];
return;
}
- dataList.value = [...mockData];
+ try {
+ const { data } = await getGeneralLedger({
+ subjectCode: currentSubject.value.code,
+ startMonth: filters.startMonth,
+ endMonth: filters.endMonth,
+ });
+ dataList.value = Array.isArray(data) ? data : data?.records || [];
+ } catch (error) {
+ // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
+ }
};
-const resetFilters = () => {
- filters.subject = [];
- filters.startMonth = "2024-01";
- filters.endMonth = "2024-03";
+const resetFilters = async () => {
+ filters.startMonth = defaultMonth;
+ filters.endMonth = defaultMonth;
dataList.value = [];
-};
-
-const getSummaries = (param) => {
- const { columns, data } = param;
- const sums = [];
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = "鍚堣";
- return;
- }
- if (column.property === "debit") {
- const values = data.map(item => Number(item.debit));
- const sum = values.reduce((prev, curr) => prev + curr, 0);
- sums[index] = "楼" + formatMoney(sum);
- } else if (column.property === "credit") {
- const values = data.map(item => Number(item.credit));
- const sum = values.reduce((prev, curr) => prev + curr, 0);
- sums[index] = "楼" + formatMoney(sum);
- } else {
- sums[index] = "";
- }
- });
- return sums;
+ subjectKeyword.value = "";
+ subjectTreeRef.value?.filter("");
+ await setDefaultSubjectSelection();
+ if (filters.subject) {
+ await getTableData();
+ }
};
const handlePrint = () => {
@@ -190,22 +243,43 @@
ElMessage.success("瀵煎嚭鎴愬姛");
};
-onMounted(() => {
- // 榛樿涓嶅姞杞芥暟鎹紝闇�瑕侀�夋嫨绉戠洰
+onMounted(async () => {
+ await loadSubjectOptions();
});
</script>
<style lang="scss" scoped>
-.ledger-header {
- text-align: center;
- margin-bottom: 20px;
- h2 {
- margin: 0 0 10px 0;
- }
- p {
- color: #606266;
- margin: 5px 0;
- }
+.ledger-layout {
+ display: flex;
+ gap: 16px;
+}
+
+.subject-panel {
+ width: 260px;
+ flex-shrink: 0;
+ padding: 12px;
+ border: 1px solid #e4e7ed;
+ border-radius: 8px;
+ background-color: #fff;
+}
+
+.subject-tree-scroll {
+ height: 600px;
+ margin-top: 12px;
+}
+
+.subject-node {
+ display: inline-flex;
+ align-items: center;
+}
+
+.ledger-content {
+ flex: 1;
+ min-width: 0;
+}
+
+.filter-form {
+ margin-bottom: 12px;
}
.text-primary {
@@ -227,4 +301,12 @@
color: #e6a23c;
font-weight: bold;
}
+
+.subject-panel :deep(.el-tree-node__content) {
+ height: 34px;
+}
+
+.subject-panel :deep(.el-tree-node.is-current > .el-tree-node__content) {
+ background-color: #f0f7ff;
+}
</style>
diff --git a/src/views/financialManagement/voucher/index.vue b/src/views/financialManagement/voucher/index.vue
index 817185c..03c0856 100644
--- a/src/views/financialManagement/voucher/index.vue
+++ b/src/views/financialManagement/voucher/index.vue
@@ -9,9 +9,12 @@
</el-form-item>
<el-form-item label="鍒跺崟浜�:">
<el-select v-model="filters.creator" placeholder="璇烽�夋嫨鍒跺崟浜�" clearable style="width: 150px;">
- <el-option label="寮犱笁" value="寮犱笁" />
- <el-option label="鏉庡洓" value="鏉庡洓" />
- <el-option label="鐜嬩簲" value="鐜嬩簲" />
+ <el-option
+ v-for="item in creatorOptions"
+ :key="item"
+ :label="item"
+ :value="item"
+ />
</el-select>
</el-form-item>
<el-form-item label="鐘舵��:">
@@ -62,9 +65,9 @@
</template>
<template #operation="{ row }">
<el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
- <el-button type="primary" link @click="edit(row)" v-if="row.status === 'unposted'">缂栬緫</el-button>
- <el-button type="success" link @click="handlePost(row)" v-if="row.status === 'unposted'">杩囪处</el-button>
- <el-button type="danger" link @click="handleCancel(row)" v-if="row.status === 'unposted'">浣滃簾</el-button>
+ <el-button type="primary" link @click="edit(row)" v-if="canEditVoucher(row.status)">缂栬緫</el-button>
+ <el-button type="success" link @click="handlePost(row)" v-if="canEditVoucher(row.status)">杩囪处</el-button>
+ <el-button type="danger" link @click="handleCancel(row)" v-if="canEditVoucher(row.status)">浣滃簾</el-button>
</template>
</PIMTable>
</div>
@@ -75,25 +78,25 @@
<h2 class="voucher-title">璁拌处鍑瘉</h2>
<div class="voucher-period">{{ form.voucherDate ? form.voucherDate.substring(0, 7) + '鏈�' : '' }}</div>
</div>
- <el-form :model="form" :rules="rules" ref="formRef" label-width="0">
+ <el-form :model="form" :rules="rules" :disabled="isViewMode" ref="formRef" label-width="0">
<div class="voucher-info">
<div class="voucher-no-section">
<span class="label">鍑瘉瀛楋細</span>
- <el-select v-model="form.voucherPrefix" style="width: 70px;">
+ <el-select v-model="form.voucherPrefix" :disabled="isViewMode" style="width: 70px;">
<el-option label="璁�" value="璁�" />
</el-select>
- <el-input v-model="form.voucherNum" style="width: 60px;" />
+ <el-input v-model="form.voucherNum" :disabled="isViewMode" style="width: 60px;" />
<span class="label" style="margin-left: 5px;">鍙�</span>
</div>
<div class="voucher-date-section">
<span class="label">鏃ユ湡锛�</span>
- <el-date-picker v-model="form.voucherDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 140px;" />
+ <el-date-picker v-model="form.voucherDate" :disabled="isViewMode" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 140px;" />
</div>
<div class="voucher-attachment-section">
<span class="label">闄勪欢锛�</span>
- <el-input-number v-model="form.attachmentCount" :min="0" :controls="false" style="width: 60px;" />
+ <el-input-number v-model="form.attachmentCount" :disabled="isViewMode" :min="0" :controls="false" style="width: 60px;" />
<span class="label" style="margin-left: 5px;">寮�</span>
- <el-button type="primary" link style="margin-left: 10px;">涓婁紶鏂囦欢</el-button>
+ <el-button type="primary" link :disabled="isViewMode" style="margin-left: 10px;">涓婁紶鏂囦欢</el-button>
</div>
</div>
<div class="voucher-table">
@@ -134,18 +137,28 @@
<tbody>
<tr v-for="(entry, rowIndex) in form.entries" :key="rowIndex" @click="selectRow(rowIndex)" :class="{ 'selected-row': selectedRowIndex === rowIndex }">
<td class="col-summary">
- <el-input v-model="entry.summary" placeholder="璇疯緭鍏ユ憳瑕�" @focus="selectRow(rowIndex)" />
+ <el-input v-model="entry.summary" :disabled="isViewMode" placeholder="璇疯緭鍏ユ憳瑕�" @focus="selectRow(rowIndex)" />
</td>
<td class="col-subject">
- <el-select v-model="entry.subjectCode" placeholder="閫夋嫨绉戠洰" filterable @change="(val) => handleSubjectChange(val, rowIndex)" @focus="selectRow(rowIndex)">
- <el-option v-for="item in subjectList" :key="item.code" :label="item.code + item.name" :value="item.code" />
- </el-select>
+ <el-tree-select
+ v-model="entry.subjectCode"
+ :data="subjectTreeOptions"
+ :props="subjectTreeSelectProps"
+ :disabled="isViewMode"
+ placeholder="閫夋嫨绉戠洰"
+ filterable
+ check-strictly
+ clearable
+ :render-after-expand="false"
+ @change="(val) => handleSubjectChange(val, rowIndex)"
+ @focus="selectRow(rowIndex)"
+ />
<div class="subject-name">{{ entry.subjectName }}</div>
</td>
<!-- 鍊熸柟11鍒� -->
<template v-if="editingCell.row === rowIndex && editingCell.type === 'debit'">
<td colspan="11" class="debit-input-cell">
- <el-input-number ref="amountInputRef" v-model="entry.debit" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
+ <el-input-number ref="amountInputRef" v-model="entry.debit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
</td>
</template>
<template v-else>
@@ -156,7 +169,7 @@
<!-- 璐锋柟11鍒� -->
<template v-if="editingCell.row === rowIndex && editingCell.type === 'credit'">
<td colspan="11" class="credit-input-cell">
- <el-input-number ref="amountInputRef" v-model="entry.credit" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
+ <el-input-number ref="amountInputRef" v-model="entry.credit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
</td>
</template>
<template v-else>
@@ -165,7 +178,7 @@
</td>
</template>
<td class="col-action">
- <el-button type="danger" link size="small" @click="removeEntry(rowIndex)" icon="Delete" :disabled="form.entries.length <= 2">鍒犻櫎</el-button>
+ <el-button type="danger" link size="small" @click="removeEntry(rowIndex)" icon="Delete" :disabled="isViewMode || form.entries.length <= 2">鍒犻櫎</el-button>
</td>
</tr>
<tr class="total-row">
@@ -182,19 +195,34 @@
</table>
</div>
<div class="voucher-toolbar">
- <el-button type="primary" link @click="addEntry" icon="Plus">鏂板琛�</el-button>
+ <el-button type="primary" link @click="addEntry" icon="Plus" :disabled="isViewMode">鏂板琛�</el-button>
</div>
<div class="voucher-footer">
<div class="creator-section">
- <span class="label">鍒跺崟浜猴細{{ form.creator }}</span>
+ <span class="label">鍒跺崟浜猴細</span>
+ <el-select
+ v-model="form.creator"
+ :disabled="isViewMode"
+ placeholder="璇烽�夋嫨鍒跺崟浜�"
+ filterable
+ clearable
+ style="width: 200px;"
+ >
+ <el-option
+ v-for="item in creatorOptions"
+ :key="item"
+ :label="item"
+ :value="item"
+ />
+ </el-select>
</div>
</div>
</el-form>
</div>
<template #footer>
<div>
- <el-button type="primary" @click="submitForm" :disabled="!isBalanced">淇濆瓨</el-button>
- <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button v-if="!isViewMode" type="primary" @click="submitForm" :disabled="!isBalanced">淇濆瓨</el-button>
+ <el-button @click="dialogVisible = false">{{ isViewMode ? '鍏抽棴' : '鍙栨秷' }}</el-button>
</div>
</template>
</FormDialog>
@@ -205,10 +233,24 @@
import { ref, reactive, onMounted, computed, nextTick } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import FormDialog from "@/components/Dialog/FormDialog.vue";
+import useUserStore from "@/store/modules/user";
+import { userListNoPageByTenantId } from "@/api/system/user";
+import { listAccountSubject } from "@/api/financialManagement/accountSubject";
+import {
+ listVoucherPage,
+ addVoucher,
+ updateVoucher,
+ postVoucher,
+ cancelVoucher,
+ getVoucherDetail,
+} from "@/api/financialManagement/voucher";
defineOptions({
name: "鍑瘉绠$悊",
});
+
+const userStore = useUserStore();
+const getDefaultCreator = () => userStore.nickName || userStore.name || "寮犱笁";
const filters = reactive({
voucherNo: "",
@@ -227,39 +269,92 @@
{ label: "鍑瘉瀛楀彿", prop: "voucherNo", width: "120" },
{ label: "鍑瘉鏃ユ湡", prop: "voucherDate", width: "120" },
{ label: "鎽樿", prop: "summary", showOverflowTooltip: true },
- { label: "鍊熸柟閲戦", prop: "debit", slot: "debit" },
- { label: "璐锋柟閲戦", prop: "credit", slot: "credit" },
+ { label: "鍊熸柟閲戦", prop: "debit", dataType: "slot", slot: "debit" },
+ { label: "璐锋柟閲戦", prop: "credit", dataType: "slot", slot: "credit" },
{ label: "鍒跺崟浜�", prop: "creator", width: "100" },
- { label: "鐘舵��", prop: "status", slot: "status" },
- { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "220", fixed: "right" },
+ { label: "鐘舵��", prop: "status", dataType: "slot", slot: "status" },
+ { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "220", fixed: "right" },
];
const dataList = ref([]);
const dialogVisible = ref(false);
const dialogTitle = ref("");
const formRef = ref(null);
+const dialogMode = ref("add");
const isEdit = ref(false);
const currentId = ref(null);
+const isViewMode = computed(() => dialogMode.value === "view");
-const subjectList = [
- { code: "1001", name: "搴撳瓨鐜伴噾" },
- { code: "1002", name: "閾惰瀛樻" },
- { code: "1122", name: "搴旀敹璐︽" },
- { code: "2202", name: "搴斾粯璐︽" },
- { code: "5001", name: "鐢熶骇鎴愭湰" },
- { code: "6001", name: "涓昏惀涓氬姟鏀跺叆" },
- { code: "6401", name: "涓昏惀涓氬姟鎴愭湰" },
+const fallbackSubjectTree = [
+ { subjectCode: "1001", subjectName: "搴撳瓨鐜伴噾", balanceDirection: "鍊熸柟", children: [] },
+ { subjectCode: "1002", subjectName: "閾惰瀛樻", balanceDirection: "鍊熸柟", children: [] },
+ { subjectCode: "1122", subjectName: "搴旀敹璐︽", balanceDirection: "鍊熸柟", children: [] },
+ { subjectCode: "2202", subjectName: "搴斾粯璐︽", balanceDirection: "璐锋柟", children: [] },
+ { subjectCode: "5001", subjectName: "鐢熶骇鎴愭湰", balanceDirection: "鍊熸柟", children: [] },
+ { subjectCode: "6001", subjectName: "涓昏惀涓氬姟鏀跺叆", balanceDirection: "璐锋柟", children: [] },
+ { subjectCode: "6401", subjectName: "涓昏惀涓氬姟鎴愭湰", balanceDirection: "鍊熸柟", children: [] },
];
-const form = reactive({
+const subjectTreeOptions = ref([]);
+const subjectList = ref([]);
+const subjectTreeSelectProps = {
+ children: "children",
+ label: "label",
+ value: "value",
+};
+
+const buildSubjectTreeOptions = (nodes = [], flatList = []) =>
+ (nodes || [])
+ .filter(item => item.subjectCode && item.subjectName)
+ .map(item => {
+ const balanceDirection = item.balanceDirection || "";
+ const flatItem = {
+ code: item.subjectCode,
+ name: item.subjectName,
+ balanceDirection,
+ };
+ flatList.push(flatItem);
+ return {
+ value: flatItem.code,
+ label: `${flatItem.code} ${flatItem.name}${balanceDirection ? ` [${balanceDirection}]` : ""}`,
+ children: buildSubjectTreeOptions(item.children || [], flatList),
+ };
+ });
+
+const createEmptyEntry = () => ({
+ subjectCode: "",
+ subjectName: "",
+ balanceDirection: "",
+ summary: "",
+ debit: 0,
+ credit: 0,
+});
+
+const createDefaultForm = () => ({
voucherNo: "",
voucherPrefix: "璁�",
voucherNum: "",
voucherDate: "",
attachmentCount: 0,
- entries: [],
- creator: "寮犱笁",
+ entries: [createEmptyEntry(), createEmptyEntry()],
+ creator: getDefaultCreator(),
remark: "",
+});
+
+const form = reactive({
+ ...createDefaultForm(),
+});
+
+const userOptions = ref([]);
+
+const creatorOptions = computed(() => {
+ const source = [
+ ...userOptions.value.map(item => item.nickName || item.userName || item.name),
+ getDefaultCreator(),
+ form.creator,
+ filters.creator,
+ ];
+ return [...new Set(source.filter(Boolean))];
});
const selectedRowIndex = ref(-1);
@@ -276,12 +371,6 @@
const rules = {
voucherDate: [{ required: true, message: "璇烽�夋嫨鍑瘉鏃ユ湡", trigger: "change" }],
};
-
-const mockData = [
- { id: 1, voucherNo: "璁�-0001", voucherDate: "2024-01-15", summary: "閿�鍞敹鍏�", debit: 5650, credit: 5650, creator: "寮犱笁", status: "posted", entries: [{ subjectCode: "1002", subjectName: "閾惰瀛樻", summary: "閿�鍞敹鍏�", debit: 5650, credit: 0 }, { subjectCode: "6001", subjectName: "涓昏惀涓氬姟鏀跺叆", summary: "閿�鍞敹鍏�", debit: 0, credit: 5000 }, { subjectCode: "2221", subjectName: "搴斾氦绋庤垂", summary: "閿�椤圭◣棰�", debit: 0, credit: 650 }] },
- { id: 2, voucherNo: "璁�-0002", voucherDate: "2024-01-16", summary: "閲囪喘鍘熸潗鏂�", debit: 9040, credit: 9040, creator: "鏉庡洓", status: "unposted", entries: [{ subjectCode: "5001", subjectName: "鐢熶骇鎴愭湰", summary: "閲囪喘鍘熸潗鏂�", debit: 8000, credit: 0 }, { subjectCode: "2221", subjectName: "搴斾氦绋庤垂", summary: "杩涢」绋庨", debit: 1040, credit: 0 }, { subjectCode: "2202", subjectName: "搴斾粯璐︽", summary: "閲囪喘鍘熸潗鏂�", debit: 0, credit: 9040 }] },
- { id: 3, voucherNo: "璁�-0003", voucherDate: "2024-01-18", summary: "鏀粯璐ф", debit: 5000, credit: 5000, creator: "寮犱笁", status: "posted", entries: [{ subjectCode: "2202", subjectName: "搴斾粯璐︽", summary: "鏀粯璐ф", debit: 5000, credit: 0 }, { subjectCode: "1002", subjectName: "閾惰瀛樻", summary: "鏀粯璐ф", debit: 0, credit: 5000 }] },
-];
const totalDebit = computed(() => {
return dataList.value.reduce((sum, item) => sum + Number(item.debit), 0);
@@ -304,32 +393,79 @@
return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};
+const normalizeVoucherStatus = status => String(status || "").toLowerCase();
+
+const canEditVoucher = status => {
+ const key = normalizeVoucherStatus(status);
+ return key === "unposted" || status === "鏈繃璐�";
+};
+
const getStatusLabel = (status) => {
+ const key = normalizeVoucherStatus(status);
const map = { unposted: "鏈繃璐�", posted: "宸茶繃璐�", cancelled: "宸蹭綔搴�" };
- return map[status] || status;
+ return map[key] || status;
};
const getStatusType = (status) => {
+ const key = normalizeVoucherStatus(status);
const map = { unposted: "warning", posted: "success", cancelled: "info" };
- return map[status] || "";
+ return map[key] || "";
};
-const getTableData = () => {
- let result = [...mockData];
- if (filters.voucherNo) {
- result = result.filter(item => item.voucherNo.includes(filters.voucherNo));
+// 鑱旇皟绾﹀畾锛氬垎椤靛弬鏁颁娇鐢� current/size锛屾棩鏈熻寖鍥存媶鍒嗕负 startDate/endDate
+const getTableData = async () => {
+ try {
+ const [startDate, endDate] =
+ filters.dateRange && filters.dateRange.length === 2 ? filters.dateRange : ["", ""];
+ const { data } = await listVoucherPage({
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ voucherNo: filters.voucherNo,
+ creator: filters.creator,
+ status: filters.status,
+ startDate,
+ endDate,
+ });
+ dataList.value = data?.records || [];
+ pagination.total = Number(data?.total || 0);
+ } catch (error) {
+ // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
}
- if (filters.dateRange && filters.dateRange.length === 2) {
- result = result.filter(item => item.voucherDate >= filters.dateRange[0] && item.voucherDate <= filters.dateRange[1]);
+};
+
+// 鍑瘉鍒嗗綍閲岀殑绉戠洰涓嬫媺涓庢�昏处绉戠洰淇濇寔涓�鑷达紝閬垮厤鎻愪氦涓嶅瓨鍦ㄧ鐩�
+const loadSubjectList = async () => {
+ try {
+ const { data } = await listAccountSubject({
+ current: 1,
+ size: 1000,
+ status: 0
+ });
+ const flatList = [];
+ const treeOptions = buildSubjectTreeOptions(data?.records || [], flatList);
+ if (treeOptions.length > 0) {
+ subjectTreeOptions.value = treeOptions;
+ subjectList.value = flatList;
+ return;
+ }
+ const fallbackFlatList = [];
+ subjectTreeOptions.value = buildSubjectTreeOptions(fallbackSubjectTree, fallbackFlatList);
+ subjectList.value = fallbackFlatList;
+ } catch (error) {
+ // 鍏ㄥ眬鎷︽埅鍣ㄥ凡鎻愮ず閿欒锛岃繖閲屼繚鐣欓粯璁ょ鐩綔涓哄厹搴�
+ const fallbackFlatList = [];
+ subjectTreeOptions.value = buildSubjectTreeOptions(fallbackSubjectTree, fallbackFlatList);
+ subjectList.value = fallbackFlatList;
}
- if (filters.creator) {
- result = result.filter(item => item.creator === filters.creator);
+};
+
+const loadUserOptions = async () => {
+ try {
+ const { data } = await userListNoPageByTenantId();
+ userOptions.value = Array.isArray(data) ? data : [];
+ } catch (error) {
+ userOptions.value = [];
}
- if (filters.status) {
- result = result.filter(item => item.status === filters.status);
- }
- pagination.total = result.length;
- dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
};
const resetFilters = () => {
@@ -348,7 +484,10 @@
};
const addEntry = () => {
- form.entries.push({ subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 });
+ if (isViewMode.value) {
+ return;
+ }
+ form.entries.push(createEmptyEntry());
};
const selectRow = (index) => {
@@ -356,6 +495,9 @@
};
const openAmountInput = (index, type) => {
+ if (isViewMode.value) {
+ return;
+ }
editingCell.row = index;
editingCell.type = type;
nextTick(() => {
@@ -402,65 +544,83 @@
};
const removeEntry = (index) => {
+ if (isViewMode.value) {
+ return;
+ }
+ if (form.entries.length <= 2) {
+ return;
+ }
form.entries.splice(index, 1);
- calculateTotal();
};
const handleSubjectChange = (val, index) => {
- const subject = subjectList.find(item => item.code === val);
+ const subject = subjectList.value.find(item => item.code === val);
if (subject) {
form.entries[index].subjectName = subject.name;
+ form.entries[index].balanceDirection = subject.balanceDirection || "";
+ } else {
+ form.entries[index].subjectName = "";
+ form.entries[index].balanceDirection = "";
}
-};
-
-const calculateTotal = () => {
- // 鑷姩璁$畻锛岀敱computed灞炴�у鐞�
};
const add = () => {
+ dialogMode.value = "add";
isEdit.value = false;
+ currentId.value = null;
dialogTitle.value = "鏂板鍑瘉";
- const nextNum = String(mockData.length + 1).padStart(2, "0");
- Object.assign(form, {
- voucherNo: "璁�-" + nextNum,
+ const nextNum = String((pagination.total || 0) + 1).padStart(4, "0");
+ Object.assign(form, createDefaultForm(), {
voucherPrefix: "璁�",
voucherNum: nextNum,
+ voucherNo: `璁�-${nextNum}`,
voucherDate: new Date().toISOString().split('T')[0],
- attachmentCount: 0,
- entries: [
- { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 },
- { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 },
- { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 },
- { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 },
- ],
- creator: "寮犱笁",
- remark: "",
});
selectedRowIndex.value = 0;
dialogVisible.value = true;
};
-const edit = (row) => {
- isEdit.value = true;
- currentId.value = row.id;
- dialogTitle.value = "缂栬緫鍑瘉";
- const parts = row.voucherNo.split('-');
- Object.assign(form, {
- ...row,
- voucherPrefix: parts[0] || '璁�',
- voucherNum: parts[1] || '',
- });
- if (form.entries.length < 4) {
- while (form.entries.length < 4) {
- form.entries.push({ subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 });
+const openVoucherDialog = async (row, mode = "edit") => {
+ try {
+ dialogMode.value = mode;
+ isEdit.value = mode === "edit";
+ currentId.value = row.id;
+ dialogTitle.value = mode === "view" ? "鏌ョ湅鍑瘉" : "缂栬緫鍑瘉";
+ const { data } = await getVoucherDetail(row.id);
+ const detail = data || row;
+ const parts = (detail.voucherNo || "").split("-");
+ Object.assign(form, createDefaultForm(), detail, {
+ voucherPrefix: parts[0] || "璁�",
+ voucherNum: parts[1] || "",
+ creator: detail.creator || getDefaultCreator(),
+ entries:
+ detail.entries?.map(item => ({
+ subjectCode: item.subjectCode || "",
+ subjectName: item.subjectName || "",
+ balanceDirection: item.balanceDirection || "",
+ summary: item.summary || "",
+ debit: Number(item.debit || 0),
+ credit: Number(item.credit || 0),
+ })) || [],
+ });
+ if (form.entries.length < 2) {
+ while (form.entries.length < 2) {
+ form.entries.push(createEmptyEntry());
+ }
}
+ selectedRowIndex.value = 0;
+ dialogVisible.value = true;
+ } catch (error) {
+ // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
}
- selectedRowIndex.value = 0;
- dialogVisible.value = true;
};
-const view = (row) => {
- ElMessage.info(`鏌ョ湅鍑瘉: ${row.voucherNo}`);
+const edit = async row => {
+ await openVoucherDialog(row, "edit");
+};
+
+const view = async row => {
+ await openVoucherDialog(row, "view");
};
const handlePost = (row) => {
@@ -468,13 +628,10 @@
confirmButtonText: "纭",
cancelButtonText: "鍙栨秷",
type: "info",
- }).then(() => {
- const index = mockData.findIndex(item => item.id === row.id);
- if (index !== -1) {
- mockData[index].status = "posted";
- }
+ }).then(async () => {
+ await postVoucher({ id: row.id });
ElMessage.success("杩囪处鎴愬姛");
- getTableData();
+ await getTableData();
});
};
@@ -483,13 +640,10 @@
confirmButtonText: "纭",
cancelButtonText: "鍙栨秷",
type: "warning",
- }).then(() => {
- const index = mockData.findIndex(item => item.id === row.id);
- if (index !== -1) {
- mockData[index].status = "cancelled";
- }
+ }).then(async () => {
+ await cancelVoucher({ id: row.id });
ElMessage.success("浣滃簾鎴愬姛");
- getTableData();
+ await getTableData();
});
};
@@ -502,45 +656,79 @@
};
const submitForm = () => {
- formRef.value.validate((valid) => {
+ if (isViewMode.value) {
+ dialogVisible.value = false;
+ return;
+ }
+ formRef.value.validate(async valid => {
if (valid) {
+ // 鍓嶇疆鏍¢獙锛氫笌鍚庣瑙勫垯瀵归綈锛屽噺灏戞棤鏁堣姹�
if (!isBalanced.value) {
ElMessage.error("鍊熻捶涓嶅钩琛★紝璇锋鏌ュ垎褰�");
return;
}
- const validEntries = form.entries.filter(e => e.subjectCode && (e.debit > 0 || e.credit > 0));
+ const validEntries = form.entries.filter(
+ entry => entry.subjectCode && (Number(entry.debit) > 0 || Number(entry.credit) > 0)
+ );
+ if (validEntries.length === 0) {
+ ElMessage.error("璇疯嚦灏戝~鍐欎竴鏉℃湁鏁堝垎褰�");
+ return;
+ }
+
+ const invalidEntry = validEntries.find(
+ entry => Number(entry.debit) > 0 && Number(entry.credit) > 0
+ );
+ if (invalidEntry) {
+ ElMessage.error("鍚屼竴鍒嗗綍涓嶈兘鍚屾椂濉啓鍊熸柟鍜岃捶鏂�");
+ return;
+ }
+
const summary = validEntries.find(e => e.debit > 0)?.summary || "";
const voucherNo = `${form.voucherPrefix}-${form.voucherNum}`;
const dataToSave = {
- ...form,
voucherNo,
+ voucherDate: form.voucherDate,
summary,
+ creator: form.creator,
+ attachmentCount: Number(form.attachmentCount || 0),
+ remark: form.remark,
debit: totalDebitEntry.value,
credit: totalCreditEntry.value,
- entries: validEntries,
+ entries: validEntries.map(entry => ({
+ subjectCode: entry.subjectCode,
+ subjectName: entry.subjectName,
+ summary: entry.summary,
+ debit: Number(entry.debit || 0),
+ credit: Number(entry.credit || 0),
+ })),
};
- if (isEdit.value) {
- const index = mockData.findIndex(item => item.id === currentId.value);
- if (index !== -1) {
- mockData[index] = { ...mockData[index], ...dataToSave };
+ try {
+ if (isEdit.value) {
+ await updateVoucher({
+ id: currentId.value,
+ ...dataToSave,
+ });
+ ElMessage.success("缂栬緫鎴愬姛");
+ } else {
+ await addVoucher(dataToSave);
+ ElMessage.success("鏂板鎴愬姛");
}
- ElMessage.success("缂栬緫鎴愬姛");
- } else {
- const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
- mockData.push({ id: newId, ...dataToSave, status: "unposted" });
- ElMessage.success("鏂板鎴愬姛");
+ dialogVisible.value = false;
+ await getTableData();
+ } catch (error) {
+ // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
}
- dialogVisible.value = false;
- getTableData();
}
});
};
-onMounted(() => {
- getTableData();
+onMounted(async () => {
+ await loadUserOptions();
+ await loadSubjectList();
+ await getTableData();
});
</script>
@@ -780,7 +968,8 @@
.col-subject {
position: relative;
- .el-select {
+ .el-select,
+ .el-tree-select {
.el-input input {
font-size: 12px;
}
diff --git a/src/views/index.vue b/src/views/index.vue
index 00d4312..6c0b729 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -479,7 +479,7 @@
// 鑾峰彇宸ュ簭鍒楄〃
const getProcessList = () => {
list().then(res => {
- processOptions.value = res.data
+ processOptions.value = res.data.records
})
}
diff --git a/src/views/inventoryManagement/receiptManagement/Record.vue b/src/views/inventoryManagement/receiptManagement/Record.vue
index 78ba5bb..9485188 100644
--- a/src/views/inventoryManagement/receiptManagement/Record.vue
+++ b/src/views/inventoryManagement/receiptManagement/Record.vue
@@ -124,7 +124,8 @@
batchApproveStockInRecords,
} from "@/api/inventoryManagement/stockInRecord.js";
import {
- findAllQualifiedStockInRecordTypeOptions, findAllUnQualifiedStockInRecordTypeOptions,
+ findAllQualifiedStockInRecordTypeOptions,
+ // findAllUnQualifiedStockInRecordTypeOptions,
} from "@/api/basicData/enum.js";
const {proxy} = getCurrentInstance();
@@ -236,10 +237,10 @@
})
return
}
- findAllUnQualifiedStockInRecordTypeOptions()
- .then(res => {
- stockRecordTypeOptions.value = res.data;
- })
+ // findAllUnQualifiedStockInRecordTypeOptions()
+ // .then(res => {
+ // stockRecordTypeOptions.value = res.data;
+ // })
}
// 琛ㄦ牸閫夋嫨鏁版嵁
diff --git a/src/views/inventoryManagement/stockReport/index.vue b/src/views/inventoryManagement/stockReport/index.vue
index 8139508..26bc8a0 100644
--- a/src/views/inventoryManagement/stockReport/index.vue
+++ b/src/views/inventoryManagement/stockReport/index.vue
@@ -223,7 +223,7 @@
} from "@/api/inventoryManagement/stockInventory.js";
import {
findAllQualifiedStockInRecordTypeOptions,
- findAllUnQualifiedStockInRecordTypeOptions,
+ // findAllUnQualifiedStockInRecordTypeOptions,
} from "@/api/basicData/enum.js";
const { proxy } = getCurrentInstance();
@@ -265,12 +265,12 @@
const fetchStockRecordTypeOptions = () => {
findAllQualifiedStockInRecordTypeOptions().then(res => {
stockRecordTypeOptions.value = res.data;
- findAllUnQualifiedStockInRecordTypeOptions().then(res => {
- stockRecordTypeOptions.value = [
- ...stockRecordTypeOptions.value,
- ...res.data,
- ];
- });
+ // findAllUnQualifiedStockInRecordTypeOptions().then(res => {
+ // stockRecordTypeOptions.value = [
+ // ...stockRecordTypeOptions.value,
+ // ...res.data,
+ // ];
+ // });
});
};
diff --git a/src/views/procurementManagement/purchaseReturnOrder/New.vue b/src/views/procurementManagement/purchaseReturnOrder/New.vue
index dffdeea..2c6801d 100644
--- a/src/views/procurementManagement/purchaseReturnOrder/New.vue
+++ b/src/views/procurementManagement/purchaseReturnOrder/New.vue
@@ -227,10 +227,11 @@
<span class="title-text">浜у搧鍒楄〃</span>
</div>
<el-button type="primary" size="small" style="margin-bottom: 20px" @click="isShowProductsModal = true" :disabled="!formState.purchaseLedgerId">娣诲姞浜у搧</el-button>
- <el-table :data="formState.purchaseReturnOrderProductsDtos"
+ <div class="product-table-scroll">
+ <el-table class="product-table-inner"
+ :data="formState.purchaseReturnOrderProductsDtos"
border
max-height="400"
- :scroll-y="true"
show-summary
:summary-method="summarizeChildrenTable">
<el-table-column align="center"
@@ -240,6 +241,12 @@
label="搴忓彿"
type="index"
width="60" />
+ <el-table-column label="鍏ュ簱鍗曞彿"
+ prop="inboundBatches"
+ width="150" />
+ <el-table-column label="鎵规鍙�"
+ prop="batchNo"
+ width="150" />
<el-table-column label="浜у搧澶х被"
prop="productCategory" />
<el-table-column label="瑙勬牸鍨嬪彿"
@@ -248,11 +255,17 @@
prop="unit"
width="70" />
<el-table-column label="鏁伴噺"
- prop="quantity"
+ prop="stockInNum"
width="100" />
<el-table-column label="鍙��璐ф暟閲�"
- prop="availableQuality"
+ prop="unQuantity"
width="130" />
+ <el-table-column label="宸查��璐ф暟閲�"
+ width="130">
+ <template #default="scope">
+ {{ calcAlreadyReturned(scope.row) }}
+ </template>
+ </el-table-column>
<el-table-column label="閫�璐ф暟閲�"
prop="returnQuantity"
width="180">
@@ -268,27 +281,27 @@
placeholder="璇疯緭鍏ラ��璐ф暟閲�" />
</template>
</el-table-column>
- <el-table-column label="搴撳瓨棰勮鏁伴噺"
+ <!-- <el-table-column label="搴撳瓨棰勮鏁伴噺"
prop="warnNum"
width="120"
show-overflow-tooltip />
<el-table-column label="绋庣巼(%)"
prop="taxRate"
- width="80" />
+ width="80" /> -->
<el-table-column label="鍚◣鍗曚环(鍏�)"
prop="taxInclusiveUnitPrice"
:formatter="formattedNumber"
- width="150" />
+ width="120" />
<el-table-column label="閫�璐ф�讳环(鍏�)"
prop="taxInclusiveTotalPrice"
- width="180">
+ width="120">
<template #default="scope">
{{ formatAmount(getReturnTotal(scope.row)) || '--' }}
</template>
</el-table-column>
<el-table-column label="鏄惁璐ㄦ"
prop="isChecked"
- width="150">
+ width="100">
<template #default="scope">
<el-tag :type="scope.row.isChecked ? 'success' : 'info'">
{{ scope.row.isChecked ? '鏄�' : '鍚�' }}
@@ -311,6 +324,7 @@
</template>
</el-table-column>
</el-table>
+ </div>
</div>
<div class="section-title">
@@ -408,9 +422,6 @@
import {getOptions, purchaseList} from "@/api/procurementManagement/procurementLedger.js";
import {userListNoPageByTenantId} from "@/api/system/user.js";
const ProductList = defineAsyncComponent(() => import("@/views/procurementManagement/purchaseReturnOrder/ProductList.vue"));
- import {
- productList,
- } from "@/api/procurementManagement/procurementLedger.js";
const props = defineProps({
visible: {
type: Boolean,
@@ -518,6 +529,14 @@
return Number.isNaN(num) ? 0 : num
}
+/** 宸查��璐ф暟閲� = 鍏ュ簱琛屾�绘暟閲� 鈭� 褰撳墠鍙��璐ф暟閲忥紙鍓╀綑锛� */
+const calcAlreadyReturned = (row) => {
+ const total = Number(row?.stockInNum ?? row?.totalQuantity ?? row?.quantity ?? 0)
+ const un = Number(row?.unQuantity ?? 0)
+ if (!Number.isFinite(total) || !Number.isFinite(un)) return 0
+ return Math.max(total - un, 0)
+}
+
const getReturnTotal = (row) => {
const qty = toNumber(row?.returnQuantity)
const unitPrice = toNumber(row?.taxInclusiveUnitPrice)
@@ -553,7 +572,7 @@
}
const getReturnQtyMax = (row) => {
- const max = Number(row?.availableQuality)
+ const max = Number(row?.unQuantity)
if (Number.isNaN(max) || max < 0) {
return 0
}
@@ -568,17 +587,17 @@
return proxy.summarizeTable(
param,
[
- "quantity",
- "availableQuality",
+ "stockInNum",
+ "unQuantity",
"returnQuantity",
"taxInclusiveUnitPrice",
"taxInclusiveTotalPrice",
"taxExclusiveTotalPrice",
],
{
- quantity: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
+ stockInNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
returnQuantity: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- availableQuality: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
+ unQuantity: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
}
);
};
@@ -660,20 +679,10 @@
}
}
-// 澶勭悊鏀瑰彉閲囪喘鍙拌处鏁版嵁
-const handleChangePurchaseLedgerId = async () => {
+// 澶勭悊鏀瑰彉閲囪喘鍙拌处鏁版嵁锛堜笉璇锋眰鎺ュ彛鍥炴樉浜у搧锛屼骇鍝佷粎鍦ㄣ�屾坊鍔犱骇鍝併�嶅脊绐楀嬀閫夊悗鍐欏叆锛�
+const handleChangePurchaseLedgerId = () => {
resetFeeInfo()
- if (!formState.value.purchaseLedgerId) {
- formState.value.purchaseReturnOrderProductsDtos = []
- return
- }
- const res = await productList({ salesLedgerId: formState.value.purchaseLedgerId, type: 2 });
- formState.value.purchaseReturnOrderProductsDtos = res.data.map(item => ({
- ...item,
- returnQuantity: undefined,
- taxInclusiveTotalPrice: 0,
- salesLedgerProductId: item.id,
- }))
+ formState.value.purchaseReturnOrderProductsDtos = []
syncTotalAmount()
}
@@ -691,7 +700,7 @@
...item,
returnQuantity: undefined,
taxInclusiveTotalPrice: 0,
- salesLedgerProductId: item.id,
+ // salesLedgerProductId: item.salesLedgerProductId,
}));
formState.value.purchaseReturnOrderProductsDtos.push(...newProducts);
syncTotalAmount()
@@ -717,7 +726,7 @@
// 閫愯鏍¢獙閫�璐ф暟閲忥細浠绘剰涓�琛屾湭濉�/闈炴硶/瓒呴檺閮戒笉鍏佽鎻愪氦
const invalidRowIndex = productList.findIndex((item) => {
const qty = Number(item.returnQuantity)
- const maxQty = Number(item.availableQuality)
+ const maxQty = Number(item.unQuantity)
if (item.returnQuantity === null || item.returnQuantity === undefined || item.returnQuantity === "") {
return true
@@ -738,7 +747,15 @@
proxy.$refs["formRef"].validate(valid => {
if (valid) {
- createPurchaseReturnOrder(formState.value).then(res => {
+ console.log(productList)
+ const submitPayload = {
+ ...formState.value,
+ purchaseReturnOrderProductsDtos: productList.map((row) => ({
+ ...row,
+ stockInRecordId: row.id,
+ })),
+ }
+ createPurchaseReturnOrder(submitPayload).then(res => {
// 鍏抽棴妯℃�佹
isShow.value = false;
// 鍛婄煡鐖剁粍浠跺凡瀹屾垚
@@ -785,4 +802,13 @@
border-radius: 50%;
margin-right: 8px;
}
+
+.product-table-scroll {
+ width: 100%;
+ overflow-x: auto;
+}
+
+.product-table-inner {
+ min-width: 1280px;
+}
</style>
\ No newline at end of file
diff --git a/src/views/procurementManagement/purchaseReturnOrder/ProductList.vue b/src/views/procurementManagement/purchaseReturnOrder/ProductList.vue
index 3eeb167..27fae4a 100644
--- a/src/views/procurementManagement/purchaseReturnOrder/ProductList.vue
+++ b/src/views/procurementManagement/purchaseReturnOrder/ProductList.vue
@@ -6,9 +6,10 @@
width="1200"
@close="closeModal"
>
- <div class="table_list">
+ <div class="table_list" v-loading="tableLoading">
<el-table :data="tableData"
border
+ row-key="id"
@selection-change="handleChangeSelection">
<el-table-column align="center"
type="selection"
@@ -17,6 +18,12 @@
label="搴忓彿"
type="index"
width="60" />
+ <el-table-column label="鍏ュ簱鍗曞彿"
+ prop="inboundBatches"
+ width="150" />
+ <el-table-column label="鎵规鍙�"
+ prop="batchNo"
+ width="150" />
<el-table-column label="浜у搧澶х被"
prop="productCategory" />
<el-table-column label="瑙勬牸鍨嬪彿"
@@ -25,27 +32,36 @@
prop="unit"
width="70" />
<el-table-column label="鏁伴噺"
- prop="quantity"
+ prop="stockInNum"
width="70" />
- <el-table-column label="搴撳瓨棰勮鏁伴噺"
+ <el-table-column label="鍙��璐ф暟閲�"
+ prop="unQuantity"
+ width="130" />
+ <el-table-column label="宸查��璐ф暟閲�"
+ width="130">
+ <template #default="scope">
+ {{ calcAlreadyReturned(scope.row) }}
+ </template>
+ </el-table-column>
+ <!-- <el-table-column label="搴撳瓨棰勮鏁伴噺"
prop="warnNum"
width="120"
show-overflow-tooltip />
<el-table-column label="绋庣巼(%)"
prop="taxRate"
- width="80" />
+ width="80" /> -->
<el-table-column label="鍚◣鍗曚环(鍏�)"
prop="taxInclusiveUnitPrice"
:formatter="formattedNumber"
width="150" />
- <el-table-column label="鍚◣鎬讳环(鍏�)"
+ <!-- <el-table-column label="鍚◣鎬讳环(鍏�)"
prop="taxInclusiveTotalPrice"
:formatter="formattedNumber"
width="150" />
<el-table-column label="涓嶅惈绋庢�讳环(鍏�)"
prop="taxExclusiveTotalPrice"
:formatter="formattedNumber"
- width="150" />
+ width="150" /> -->
<el-table-column label="鏄惁璐ㄦ"
prop="isChecked"
width="150">
@@ -56,8 +72,6 @@
</template>
</el-table-column>
</el-table>
- <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper"
- :page="page.current" :limit="page.size" @pagination="paginationChange" />
</div>
<template #footer>
@@ -71,8 +85,8 @@
</template>
<script setup>
-import {computed, reactive, ref, onMounted} from "vue";
-import {productList} from "@/api/procurementManagement/procurementLedger.js";
+import {computed, ref, onMounted} from "vue";
+import {getPurchaseReturnOrderByPurchaseLedgerId} from "@/api/procurementManagement/purchase_return_order.js";
import {ElMessage} from "element-plus";
const props = defineProps({
@@ -82,7 +96,7 @@
},
purchaseLedgerId: {
- type: Number,
+ type: [Number, String],
required: true,
}
});
@@ -101,32 +115,59 @@
const tableData = ref([])
const selectedRows = ref([])
const tableLoading = ref(false)
-const page = reactive({
- current: 1,
- size: 100,
-})
-const total = ref(0)
const formattedNumber = (row, column, cellValue) => {
return parseFloat(cellValue).toFixed(2);
};
-const paginationChange = (obj) => {
- page.current = obj.page;
- page.size = obj.limit;
- getList()
+/** 宸查��璐ф暟閲� = 鍏ュ簱琛屾�绘暟閲� 鈭� 褰撳墠鍙��璐ф暟閲忥紙鍓╀綑锛� */
+const calcAlreadyReturned = (row) => {
+ const total = Number(row?.stockInNum ?? row?.totalQuantity ?? row?.quantity ?? 0)
+ const un = Number(row?.unQuantity ?? 0)
+ if (!Number.isFinite(total) || !Number.isFinite(un)) return 0
+ return Math.max(total - un, 0)
}
const handleChangeSelection = (val) => {
selectedRows.value = val;
}
+/** 涓� New.vue 涓噰璐彴璐﹀彉鏇存椂瑙f瀽 getByPurchaseLedgerId 鐨勮鍒欎竴鑷� */
+const parseProductRowsFromLedgerResponse = (res) => {
+ const payload = res?.data
+ let list = []
+ if (Array.isArray(payload)) {
+ list = payload
+ } else if (payload && typeof payload === 'object') {
+ const nested =
+ payload.purchaseReturnOrderProductsDtos ||
+ payload.purchaseReturnOrderProductsDetailVoList
+ list = Array.isArray(nested) ? nested : []
+ if (list.length && list[0]?.salesLedgerProduct) {
+ list = list.map((item) => ({ ...item, ...item.salesLedgerProduct }))
+ }
+ }
+ return list
+}
+
const fetchData = () => {
- tableLoading.value = true;
- productList({salesLedgerId: props.purchaseLedgerId, type: 2}).then((res) => {
- tableData.value = res.data;
- }).finally(() => {
- tableLoading.value = false;
+ if (props.purchaseLedgerId === undefined || props.purchaseLedgerId === null || props.purchaseLedgerId === '') {
+ tableData.value = []
+ return
+ }
+ tableLoading.value = true
+ getPurchaseReturnOrderByPurchaseLedgerId({
+ purchaseLedgerId: props.purchaseLedgerId,
})
+ .then((res) => {
+ const list = parseProductRowsFromLedgerResponse(res)
+ tableData.value = list
+ })
+ .catch(() => {
+ tableData.value = []
+ })
+ .finally(() => {
+ tableLoading.value = false
+ })
}
const handleSubmit = () => {
diff --git a/src/views/procurementManagement/purchaseReturnOrder/index.vue b/src/views/procurementManagement/purchaseReturnOrder/index.vue
index 942b4dc..f8866e1 100644
--- a/src/views/procurementManagement/purchaseReturnOrder/index.vue
+++ b/src/views/procurementManagement/purchaseReturnOrder/index.vue
@@ -1,24 +1,26 @@
<template>
<div class="app-container">
<div class="search_form">
- <el-form :model="searchForm"
- :inline="true">
+ <el-form :model="searchForm" :inline="true">
<el-form-item label="閫�鏂欏崟鍙凤細">
- <el-input v-model="searchForm.no"
- placeholder="璇疯緭鍏�"
- clearable
- prefix-icon="Search"
- @change="handleQuery" />
+ <el-input
+ v-model="searchForm.no"
+ placeholder="璇疯緭鍏�"
+ clearable
+ prefix-icon="Search"
+ @change="handleQuery"
+ />
</el-form-item>
<el-form-item>
- <el-button type="primary"
- @click="handleQuery"> 鎼滅储 </el-button>
+ <el-button type="primary" @click="handleQuery"> 鎼滅储 </el-button>
</el-form-item>
</el-form>
<div>
- <el-button type="primary" @click="isShowNewModal = true">鏂板</el-button>
+ <el-button type="primary" @click="isShowNewModal = true"
+ >鏂板</el-button
+ >
</div>
</div>
@@ -35,14 +37,25 @@
@pagination="paginationChange"
>
<template #operation="{ row }">
- <el-button link type="primary" size="small" style="color: #67C23A" @click="handleDetail(row)">璇︽儏</el-button>
- <el-button link size="small" @click="handleDelete(row)">鍒犻櫎</el-button>
+ <el-button
+ link
+ type="primary"
+ size="small"
+ style="color: #67c23a"
+ @click="handleDetail(row)"
+ >璇︽儏</el-button
+ >
+ <el-button link size="small" @click="handleDelete(row)"
+ >鍒犻櫎</el-button
+ >
</template>
</PIMTable>
</div>
- <new v-if="isShowNewModal"
- v-model:visible="isShowNewModal"
- @completed="handleQuery" />
+ <new
+ v-if="isShowNewModal"
+ v-model:visible="isShowNewModal"
+ @completed="handleQuery"
+ />
<el-dialog
v-model="detailVisible"
@@ -52,21 +65,51 @@
>
<div v-loading="detailLoading">
<el-descriptions :column="3" border>
- <el-descriptions-item label="閫�鏂欏崟鍙�">{{ detailData.no || '--' }}</el-descriptions-item>
- <el-descriptions-item label="閫�璐ф柟寮�">{{ getReturnTypeLabel(detailData.returnType) }}</el-descriptions-item>
- <el-descriptions-item label="渚涘簲鍟嗗悕绉�">{{ detailData.supplierName || '--' }}</el-descriptions-item>
- <el-descriptions-item label="椤圭洰闃舵">{{ getProjectPhaseLabel(detailData.projectPhase) }}</el-descriptions-item>
- <el-descriptions-item label="鍏宠仈鍗曞彿">{{ detailData.purchaseContractNumber || '--' }}</el-descriptions-item>
- <el-descriptions-item label="鍒朵綔鏃ユ湡">{{ detailData.preparedAt || '--' }}</el-descriptions-item>
- <el-descriptions-item label="鍒跺崟浜�">{{ detailData.preparedUserName || '--' }}</el-descriptions-item>
- <el-descriptions-item label="閫�鏂欎汉">{{ detailData.returnUserName || '--' }}</el-descriptions-item>
- <el-descriptions-item label="鏁村崟鎶樻墸棰�">{{ formatAmount(detailData.totalDiscountAmount) }}</el-descriptions-item>
- <el-descriptions-item label="鏁村崟鎶樻墸鐜�">{{ detailData.totalDiscountRate ?? '--' }}</el-descriptions-item>
- <el-descriptions-item label="鎴愪氦閲戦">{{ formatAmount(detailData.totalAmount) }}</el-descriptions-item>
- <el-descriptions-item label="鍒涘缓浜�">{{ detailData.createUserName || '--' }}</el-descriptions-item>
- <el-descriptions-item label="鍒涘缓鏃堕棿">{{ detailData.createTime || '--' }}</el-descriptions-item>
- <el-descriptions-item label="鏈�杩戞洿鏂版椂闂�">{{ detailData.updateTime || '--' }}</el-descriptions-item>
- <el-descriptions-item label="澶囨敞" :span="3">{{ detailData.remark || '--' }}</el-descriptions-item>
+ <el-descriptions-item label="閫�鏂欏崟鍙�">{{
+ detailData.no || "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="閫�璐ф柟寮�">{{
+ getReturnTypeLabel(detailData.returnType)
+ }}</el-descriptions-item>
+ <el-descriptions-item label="渚涘簲鍟嗗悕绉�">{{
+ detailData.supplierName || "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="椤圭洰闃舵">{{
+ getProjectPhaseLabel(detailData.projectPhase)
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鍏宠仈鐨勯噰璐鍗曞彿">{{
+ detailData.purchaseContractNumber || "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鍒朵綔鏃ユ湡">{{
+ detailData.preparedAt || "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鍒跺崟浜�">{{
+ detailData.preparedUserName || "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="閫�鏂欎汉">{{
+ detailData.returnUserName || "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鏁村崟鎶樻墸棰�">{{
+ formatAmount(detailData.totalDiscountAmount)
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鏁村崟鎶樻墸鐜�">{{
+ detailData.totalDiscountRate ?? "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鎴愪氦閲戦">{{
+ formatAmount(detailData.totalAmount)
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鍒涘缓浜�">{{
+ detailData.createUserName || "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鍒涘缓鏃堕棿">{{
+ detailData.createTime || "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鏈�杩戞洿鏂版椂闂�">{{
+ detailData.updateTime || "--"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="澶囨敞" :span="3">{{
+ detailData.remark || "--"
+ }}</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">浜у搧鍒楄〃</el-divider>
@@ -77,27 +120,75 @@
max-height="420"
style="width: 100%"
>
- <el-table-column align="center" label="搴忓彿" type="index" width="60" />
- <el-table-column label="浜у搧澶х被" prop="productCategory" min-width="120" show-overflow-tooltip />
- <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" min-width="140" show-overflow-tooltip />
+ <el-table-column
+ align="center"
+ label="搴忓彿"
+ type="index"
+ width="60"
+ />
+ <el-table-column label="鍏ュ簱鍗曞彿" prop="inboundBatches" width="150" />
+ <el-table-column label="鎵规鍙�" prop="batchNo" width="150" />
+ <el-table-column
+ label="浜у搧澶х被"
+ prop="productCategory"
+ min-width="120"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="瑙勬牸鍨嬪彿"
+ prop="specificationModel"
+ min-width="140"
+ show-overflow-tooltip
+ />
<el-table-column label="鍗曚綅" prop="unit" width="80" />
- <el-table-column label="鏁伴噺" prop="quantity" width="80" />
- <el-table-column label="閫�璐ф暟閲�" prop="returnQuantity" width="100" />
- <el-table-column label="搴撳瓨棰勮鏁伴噺" prop="warnNum" width="120" />
- <el-table-column label="绋庣巼(%)" prop="taxRate" width="90" />
- <el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" width="130">
- <template #default="scope">{{ formatAmount(scope.row.taxInclusiveUnitPrice) }}</template>
+ <el-table-column label="鏁伴噺" prop="stockInNum" width="80" />
+ <el-table-column label="鍙��璐ф暟閲�"
+ prop="unQuantity"
+ width="100" />
+ <el-table-column label="宸查��璐ф暟閲�"
+ width="100">
+ <template #default="scope">
+ {{ calcAlreadyReturned(scope.row) }}
+ </template>
</el-table-column>
- <el-table-column label="閫�璐ф�讳环(鍏�)" prop="taxInclusiveTotalPrice" width="130">
- <template #default="scope">{{ formatAmount(scope.row.taxInclusiveTotalPrice) }}</template>
+ <!-- <el-table-column label="搴撳瓨棰勮鏁伴噺" prop="warnNum" width="120" /> -->
+ <!-- <el-table-column label="绋庣巼(%)" prop="taxRate" width="90" /> -->
+ <el-table-column
+ label="鍚◣鍗曚环(鍏�)"
+ prop="taxInclusiveUnitPrice"
+ width="130"
+ >
+ <template #default="scope">{{
+ formatAmount(scope.row.taxInclusiveUnitPrice)
+ }}</template>
</el-table-column>
- <el-table-column label="涓嶉��璐ф�讳环(鍏�)" prop="taxExclusiveTotalPrice" width="140">
- <template #default="scope">{{ formatAmount(scope.row.taxExclusiveTotalPrice) }}</template>
+ <!-- <el-table-column
+ label="閫�璐ф�讳环(鍏�)"
+ prop="taxInclusiveTotalPrice"
+ width="130"
+ >
+ <template #default="scope">{{
+ formatAmount(scope.row.taxInclusiveTotalPrice)
+ }}</template>
</el-table-column>
- <el-table-column label="鏄惁璐ㄦ" prop="isChecked" width="100" align="center">
+ <el-table-column
+ label="涓嶉��璐ф�讳环(鍏�)"
+ prop="taxExclusiveTotalPrice"
+ width="140"
+ >
+ <template #default="scope">{{
+ formatAmount(scope.row.taxExclusiveTotalPrice)
+ }}</template>
+ </el-table-column> -->
+ <el-table-column
+ label="鏄惁璐ㄦ"
+ prop="isChecked"
+ width="100"
+ align="center"
+ >
<template #default="scope">
<el-tag :type="scope.row.isChecked ? 'success' : 'info'">
- {{ scope.row.isChecked ? '鏄�' : '鍚�' }}
+ {{ scope.row.isChecked ? "鏄�" : "鍚�" }}
</el-tag>
</template>
</el-table-column>
@@ -111,238 +202,280 @@
</template>
<script setup>
-import PIMTable from '@/components/PIMTable/PIMTable.vue'
-import { ref, reactive, toRefs, onMounted, defineAsyncComponent, getCurrentInstance } from 'vue'
-const { proxy } = getCurrentInstance()
-import {findPurchaseReturnOrderListPage, getPurchaseReturnOrderDetail, deletePurchaseReturnOrder} from "@/api/procurementManagement/purchase_return_order.js";
-const New = defineAsyncComponent(() => import("@/views/procurementManagement/purchaseReturnOrder/New.vue"));
-const tableData = ref([])
-const selectedRows = ref([])
-const tableLoading = ref(false)
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+import {
+ ref,
+ reactive,
+ toRefs,
+ onMounted,
+ defineAsyncComponent,
+ getCurrentInstance,
+} from "vue";
+const { proxy } = getCurrentInstance();
+import {
+ findPurchaseReturnOrderListPage,
+ getPurchaseReturnOrderDetail,
+ deletePurchaseReturnOrder,
+} from "@/api/procurementManagement/purchase_return_order.js";
+const New = defineAsyncComponent(() =>
+ import("@/views/procurementManagement/purchaseReturnOrder/New.vue")
+);
+const tableData = ref([]);
+const selectedRows = ref([]);
+const tableLoading = ref(false);
const page = reactive({
current: 1,
size: 100,
total: 0,
-})
-const detailVisible = ref(false)
-const detailLoading = ref(false)
-const detailData = ref({})
-const detailProducts = ref([])
+});
+const detailVisible = ref(false);
+const detailLoading = ref(false);
+const detailData = ref({});
+const detailProducts = ref([]);
// 鏄惁鏄剧ず鏂板寮规
-const isShowNewModal = ref(false)
+const isShowNewModal = ref(false);
const returnTypeOptions = [
- { label: '閫�璐ч��娆�', value: 0 },
- { label: '鎷掓敹', value: 1 },
-]
+ { label: "閫�璐ч��娆�", value: 0 },
+ { label: "鎷掓敹", value: 1 },
+];
const projectPhaseOptions = [
- { label: '绔嬮」', value: 0 },
- { label: '璁捐', value: 1 },
- { label: '閲囪喘', value: 2 },
- { label: '鐢熶骇', value: 3 },
- { label: '鍑鸿揣', value: 4 },
-]
+ { label: "绔嬮」", value: 0 },
+ { label: "璁捐", value: 1 },
+ { label: "閲囪喘", value: 2 },
+ { label: "鐢熶骇", value: 3 },
+ { label: "鍑鸿揣", value: 4 },
+];
const tableColumn = ref([
{
- label: '閫�鏂欏崟鍙�',
- prop: 'no',
+ label: "閫�鏂欏崟鍙�",
+ prop: "no",
},
{
- label: '閫�璐ф柟寮�',
- prop: 'returnType',
- formatData: (val) => returnTypeOptions.find(item => item.value === val)?.label || '--',
+ label: "閫�璐ф柟寮�",
+ prop: "returnType",
+ formatData: (val) =>
+ returnTypeOptions.find((item) => item.value === val)?.label || "--",
},
{
- label: '渚涘簲鍟嗗悕绉�',
- prop: 'supplierName',
+ label: "渚涘簲鍟嗗悕绉�",
+ prop: "supplierName",
width: 180,
},
{
- label: '椤圭洰闃舵',
- prop: 'projectPhase',
+ label: "椤圭洰闃舵",
+ prop: "projectPhase",
width: 100,
- formatData: (val) => projectPhaseOptions.find(item => String(item.value) === String(val))?.label || '--',
+ formatData: (val) =>
+ projectPhaseOptions.find((item) => String(item.value) === String(val))
+ ?.label || "--",
},
{
- label: '鍏宠仈鍗曞彿',
- prop: 'purchaseContractNumber',
+ label: "鍏宠仈鐨勯噰璐鍗曞彿",
+ prop: "purchaseContractNumber",
width: 160,
},
{
- label: '鍒朵綔鏃ユ湡',
- prop: 'preparedAt',
+ label: "鍒朵綔鏃ユ湡",
+ prop: "preparedAt",
width: 130,
},
{
- label: '鍒跺崟浜�',
- prop: 'preparedUserName',
+ label: "鍒跺崟浜�",
+ prop: "preparedUserName",
width: 110,
},
{
- label: '閫�鏂欎汉',
- prop: 'returnUserName',
+ label: "閫�鏂欎汉",
+ prop: "returnUserName",
width: 110,
},
{
- label: '鏁村崟鎶樻墸棰�',
- prop: 'totalDiscountAmount',
+ label: "鏁村崟鎶樻墸棰�",
+ prop: "totalDiscountAmount",
width: 120,
},
{
- label: '鏁村崟鎶樻墸鐜�',
- prop: 'totalDiscountRate',
+ label: "鏁村崟鎶樻墸鐜�",
+ prop: "totalDiscountRate",
width: 120,
},
{
- label: '鎴愪氦閲戦',
- prop: 'totalAmount',
+ label: "鎴愪氦閲戦",
+ prop: "totalAmount",
width: 120,
},
{
- label: '鍒涘缓浜�',
- prop: 'createUserName',
+ label: "鍒涘缓浜�",
+ prop: "createUserName",
width: 110,
},
{
- label: '鍒涘缓鏃堕棿',
- prop: 'createTime',
+ label: "鍒涘缓鏃堕棿",
+ prop: "createTime",
width: 170,
},
{
- label: '鏈�杩戞洿鏂版椂闂�',
- prop: 'updateTime',
+ label: "鏈�杩戞洿鏂版椂闂�",
+ prop: "updateTime",
width: 170,
},
{
- label: '澶囨敞',
- prop: 'remark',
+ label: "澶囨敞",
+ prop: "remark",
width: 180,
},
{
dataType: "action",
width: 120,
- label: "鎿嶄綔",
- align: "center",
- fixed: "right",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: "right",
operation: [
{
- name: "璇︽儏",
- type: "text",
- clickFun: row => {handleDetail(row);},
- },
+ name: "璇︽儏",
+ type: "text",
+ clickFun: (row) => {
+ handleDetail(row);
+ },
+ },
{
name: "鍒犻櫎",
- clickFun: row => {handleDelete(row)},
+ clickFun: (row) => {
+ handleDelete(row);
+ },
},
- ],
+ ],
},
-
-])
+]);
const data = reactive({
searchForm: {
- no: '',
- }
-})
-const { searchForm } = toRefs(data)
+ no: "",
+ },
+});
+const { searchForm } = toRefs(data);
// 鏌ヨ鍒楄〃
/** 鎼滅储鎸夐挳鎿嶄綔 */
const handleQuery = () => {
- page.current = 1
- getList()
-}
+ page.current = 1;
+ getList();
+};
// 鍒犻櫎鎿嶄綔
const handleDelete = (row) => {
- console.log('鍒犻櫎琛屾暟鎹細', row)
- proxy?.$modal?.confirm('纭畾瑕佸垹闄ゅ悧锛熷垹闄ゅ皢鏃犳硶鎭㈠').then(() => {
- // 杩欓噷璋冪敤鍒犻櫎鎺ュ彛锛屼紶鍏� row.id
- deletePurchaseReturnOrder(row.id).then(() => {
- proxy?.$modal?.msgSuccess?.("鍒犻櫎鎴愬姛");
- getList()
- }).catch(() => {
- proxy?.$modal?.msgError?.('鍒犻櫎澶辫触')
+ console.log("鍒犻櫎琛屾暟鎹細", row);
+ proxy?.$modal
+ ?.confirm("纭畾瑕佸垹闄ゅ悧锛熷垹闄ゅ皢鏃犳硶鎭㈠")
+ .then(() => {
+ // 杩欓噷璋冪敤鍒犻櫎鎺ュ彛锛屼紶鍏� row.id
+ deletePurchaseReturnOrder(row.id)
+ .then(() => {
+ proxy?.$modal?.msgSuccess?.("鍒犻櫎鎴愬姛");
+ getList();
+ })
+ .catch(() => {
+ proxy?.$modal?.msgError?.("鍒犻櫎澶辫触");
+ });
})
- }).catch(() => {
- // 鍙栨秷鍒犻櫎
- proxy?.$modal?.msgInfo?.('宸插彇娑堝垹闄�')
-
- })
-}
+ .catch(() => {
+ // 鍙栨秷鍒犻櫎
+ proxy?.$modal?.msgInfo?.("宸插彇娑堝垹闄�");
+ });
+};
// 鏌ョ湅璇︽儏
const handleDetail = (row) => {
if (!row?.id) {
- proxy?.$modal?.msgWarning?.('鏈幏鍙栧埌鍗曟嵁ID')
- return
+ proxy?.$modal?.msgWarning?.("鏈幏鍙栧埌鍗曟嵁ID");
+ return;
}
- detailVisible.value = true
- detailLoading.value = true
- getPurchaseReturnOrderDetail(row.id).then(res => {
- const payload = res?.data || {}
- detailData.value = payload
- // 鎷兼帴杩炰釜瀵硅薄鎴愪竴涓璞★紝鏂逛究灞曠ず item 鍜� item.salesLedgerProduct 閲岀殑瀛楁
+ detailVisible.value = true;
+ detailLoading.value = true;
+ getPurchaseReturnOrderDetail(row.id)
+ .then((res) => {
+ const payload = res?.data || {};
+ detailData.value = payload;
+ // 鎷兼帴杩炰釜瀵硅薄鎴愪竴涓璞★紝鏂逛究灞曠ず item 鍜� item.salesLedgerProduct 閲岀殑瀛楁
-
- detailProducts.value =
- payload.purchaseReturnOrderProductsDetailVoList.map(item => ({ ...item, ...item.salesLedgerProduct })) ||
- []
- }).catch(() => {
- proxy?.$modal?.msgError?.('鑾峰彇璇︽儏澶辫触')
- }).finally(() => {
- detailLoading.value = false
- })
-}
-
+ detailProducts.value =
+ payload.purchaseReturnOrderProductsDetailVoList.map((item) => ({
+ ...item,
+ ...item.salesLedgerProduct,
+ })) || [];
+ })
+ .catch(() => {
+ proxy?.$modal?.msgError?.("鑾峰彇璇︽儏澶辫触");
+ })
+ .finally(() => {
+ detailLoading.value = false;
+ });
+};
const paginationChange = (obj) => {
page.current = obj.page;
page.size = obj.limit;
- getList()
-}
+ getList();
+};
const getList = () => {
- tableLoading.value = true
- findPurchaseReturnOrderListPage({ ...searchForm.value, ...page }).then(res => {
- tableLoading.value = false
- tableData.value = res.data.records
- page.total = res.data.total
- }).catch(() => {
- tableLoading.value = false
- })
-}
+ tableLoading.value = true;
+ findPurchaseReturnOrderListPage({ ...searchForm.value, ...page })
+ .then((res) => {
+ tableLoading.value = false;
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ })
+ .catch(() => {
+ tableLoading.value = false;
+ });
+};
// 琛ㄦ牸閫夋嫨鏁版嵁
const handleSelectionChange = (selection) => {
// 杩囨护鎺夊瓙鏁版嵁
- selectedRows.value = selection.filter(item => item.id);
-}
+ selectedRows.value = selection.filter((item) => item.id);
+};
const getReturnTypeLabel = (value) => {
- return returnTypeOptions.find(item => String(item.value) === String(value))?.label || '--'
-}
+ return (
+ returnTypeOptions.find((item) => String(item.value) === String(value))
+ ?.label || "--"
+ );
+};
const getProjectPhaseLabel = (value) => {
- return projectPhaseOptions.find(item => String(item.value) === String(value))?.label || '--'
-}
+ return (
+ projectPhaseOptions.find((item) => String(item.value) === String(value))
+ ?.label || "--"
+ );
+};
const formatAmount = (value) => {
- if (value === null || value === undefined || value === '') {
- return '--'
+ if (value === null || value === undefined || value === "") {
+ return "--";
}
- const num = Number(value)
+ const num = Number(value);
if (Number.isNaN(num)) {
- return value
+ return value;
}
- return num.toFixed(2)
-}
+ return num.toFixed(2);
+};
+
+/** 宸查��璐ф暟閲� = 鍏ュ簱琛屾�绘暟閲� 鈭� 褰撳墠鍙��璐ф暟閲忥紙鍓╀綑锛� */
+const calcAlreadyReturned = (row) => {
+ const total = Number(row?.stockInNum ?? row?.totalQuantity ?? row?.quantity ?? 0);
+ const un = Number(row?.unQuantity ?? 0);
+ if (!Number.isFinite(total) || !Number.isFinite(un)) return 0;
+ return Math.max(total - un, 0);
+};
onMounted(() => {
- getList()
-})
+ getList();
+});
</script>
<style scoped>
.table_list {
- margin-top: unset;
+ margin-top: unset;
}
</style>
diff --git a/src/views/qualityManagement/processInspection/components/formDia.vue b/src/views/qualityManagement/processInspection/components/formDia.vue
index c1185d2..88c1e20 100644
--- a/src/views/qualityManagement/processInspection/components/formDia.vue
+++ b/src/views/qualityManagement/processInspection/components/formDia.vue
@@ -1,129 +1,165 @@
<template>
<div>
- <el-dialog
- v-model="dialogFormVisible"
- :title="operationType === 'add' ? '鏂板杩囩▼妫�楠�' : '缂栬緫杩囩▼妫�楠�'"
- width="70%"
- @close="closeDia"
- >
- <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
+ <el-dialog v-model="dialogFormVisible"
+ :title="operationType === 'add' ? '鏂板杩囩▼妫�楠�' : '缂栬緫杩囩▼妫�楠�'"
+ width="70%"
+ @close="closeDia">
+ <el-form :model="form"
+ label-width="140px"
+ label-position="top"
+ :rules="rules"
+ ref="formRef">
<el-row :gutter="30">
<el-col :span="12">
- <el-form-item label="宸ュ簭锛�" prop="process">
- <el-select v-model="form.process" placeholder="璇烽�夋嫨宸ュ簭" clearable :disabled="processQuantityDisabled" style="width: 100%">
- <el-option v-for="item in processList" :key="item.name" :label="item.name" :value="item.name"/>
+ <el-form-item label="宸ュ簭锛�"
+ prop="process">
+ <el-select v-model="form.process"
+ placeholder="璇烽�夋嫨宸ュ簭"
+ clearable
+ :disabled="processQuantityDisabled"
+ style="width: 100%">
+ <el-option v-for="item in processList"
+ :key="item.name"
+ :label="item.name"
+ :value="item.name" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="浜у搧鍚嶇О锛�" prop="productId">
- <el-tree-select
- v-model="form.productId"
- placeholder="璇烽�夋嫨"
- clearable
- check-strictly
- @change="getModels"
- :data="productOptions"
- :render-after-expand="false"
- :disabled="operationType === 'edit'"
- style="width: 100%"
- />
+ <el-form-item label="浜у搧鍚嶇О锛�"
+ prop="productId">
+ <el-tree-select v-model="form.productId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ check-strictly
+ @change="getModels"
+ :data="productOptions"
+ :render-after-expand="false"
+ :disabled="operationType === 'edit'"
+ style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="30">
<el-col :span="12">
- <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="productModelId">
- <el-select v-model="form.productModelId" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'edit'"
- filterable readonly @change="handleChangeModel">
- <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
+ <el-form-item label="瑙勬牸鍨嬪彿锛�"
+ prop="productModelId">
+ <el-select v-model="form.productModelId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ :disabled="operationType === 'edit'"
+ filterable
+ readonly
+ @change="handleChangeModel">
+ <el-option v-for="item in modelOptions"
+ :key="item.id"
+ :label="item.model"
+ :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="鎸囨爣閫夋嫨锛�" prop="testStandardId">
- <el-select
- v-model="form.testStandardId"
- placeholder="璇烽�夋嫨鎸囨爣"
- clearable
- @change="handleTestStandardChange"
- style="width: 100%"
- >
- <el-option
- v-for="item in testStandardOptions"
- :key="item.id"
- :label="item.standardName || item.standardNo"
- :value="item.id"
- />
+ <el-form-item label="鎸囨爣閫夋嫨锛�"
+ prop="testStandardId">
+ <el-select v-model="form.testStandardId"
+ placeholder="璇烽�夋嫨鎸囨爣"
+ clearable
+ @change="handleTestStandardChange"
+ style="width: 100%">
+ <el-option v-for="item in testStandardOptions"
+ :key="item.id"
+ :label="item.standardName || item.standardNo"
+ :value="item.id" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="30">
<el-col :span="12">
- <el-form-item label="鍗曚綅锛�" prop="unit">
- <el-input v-model="form.unit" placeholder="璇疯緭鍏�" disabled/>
+ <el-form-item label="鍗曚綅锛�"
+ prop="unit">
+ <el-input v-model="form.unit"
+ placeholder="璇疯緭鍏�"
+ disabled />
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="鏁伴噺锛�" prop="quantity">
- <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="璇疯緭鍏�" clearable :precision="2" :disabled="processQuantityDisabled"/>
+ <el-form-item label="鏁伴噺锛�"
+ prop="quantity">
+ <el-input-number :step="0.01"
+ :min="0"
+ style="width: 100%"
+ v-model="form.quantity"
+ placeholder="璇疯緭鍏�"
+ clearable
+ :precision="2"
+ :disabled="processQuantityDisabled" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="30">
<el-col :span="12">
- <el-form-item label="妫�娴嬪崟浣嶏細" prop="checkCompany">
- <el-input v-model="form.checkCompany" placeholder="璇疯緭鍏�" clearable/>
+ <el-form-item label="妫�娴嬪崟浣嶏細"
+ prop="checkCompany">
+ <el-input v-model="form.checkCompany"
+ placeholder="璇疯緭鍏�"
+ clearable />
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="妫�娴嬬粨鏋滐細" prop="checkResult">
+ <el-form-item label="妫�娴嬬粨鏋滐細"
+ prop="checkResult">
<el-select v-model="form.checkResult">
- <el-option label="鍚堟牸" value="鍚堟牸" />
- <el-option label="涓嶅悎鏍�" value="涓嶅悎鏍�" />
+ <el-option label="鍚堟牸"
+ value="鍚堟牸" />
+ <el-option label="涓嶅悎鏍�"
+ value="涓嶅悎鏍�" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="30">
<el-col :span="12">
- <el-form-item label="妫�楠屽憳锛�" prop="checkName">
- <el-select v-model="form.checkName" placeholder="璇烽�夋嫨" clearable>
- <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
- :value="item.nickName"/>
- </el-select>
+ <el-form-item label="妫�楠屽憳锛�"
+ prop="checkName">
+ <el-select v-model="form.checkName"
+ placeholder="璇烽�夋嫨"
+ clearable>
+ <el-option v-for="item in userList"
+ :key="item.nickName"
+ :label="item.nickName"
+ :value="item.nickName" />
+ </el-select>
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="妫�娴嬫棩鏈燂細" prop="checkTime">
- <el-date-picker
- v-model="form.checkTime"
- type="date"
- placeholder="璇烽�夋嫨鏃ユ湡"
- value-format="YYYY-MM-DD"
- format="YYYY-MM-DD"
- clearable
- style="width: 100%"
- />
+ <el-form-item label="妫�娴嬫棩鏈燂細"
+ prop="checkTime">
+ <el-date-picker v-model="form.checkTime"
+ type="date"
+ placeholder="璇烽�夋嫨鏃ユ湡"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ clearable
+ style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
</el-form>
- <PIMTable
- rowKey="id"
- :column="tableColumn"
- :tableData="tableData"
- :tableLoading="tableLoading"
- height="400"
- >
- <template #slot="{ row }">
- <el-input v-model="row.testValue" clearable/>
- </template>
- </PIMTable>
+ <PIMTable rowKey="id"
+ :column="tableColumn"
+ :tableData="tableData"
+ :tableLoading="tableLoading"
+ height="400">
+ <template #slot="{ row }">
+ <el-input v-model="row.testValue"
+ clearable />
+ </template>
+ </PIMTable>
<template #footer>
<div class="dialog-footer">
- <el-button type="primary" @click="submitForm">纭</el-button>
+ <el-button type="primary"
+ @click="submitForm">纭</el-button>
<el-button @click="closeDia">鍙栨秷</el-button>
</div>
</template>
@@ -132,332 +168,356 @@
</template>
<script setup>
-import {ref, reactive, toRefs, computed, getCurrentInstance, nextTick} from "vue";
-import {getOptions} from "@/api/procurementManagement/procurementLedger.js";
-import {modelList, productTreeList} from "@/api/basicData/product.js";
-import {qualityInspectAdd, qualityInspectUpdate} from "@/api/qualityManagement/rawMaterialInspection.js";
-import {qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId} from "@/api/qualityManagement/metricMaintenance.js";
-import {userListNoPage} from "@/api/system/user.js";
-import {qualityInspectParamInfo} from "@/api/qualityManagement/qualityInspectParam.js";
-import { list } from "@/api/productionManagement/productionProcess";
-const { proxy } = getCurrentInstance()
-const emit = defineEmits(['close'])
+ import {
+ ref,
+ reactive,
+ toRefs,
+ computed,
+ getCurrentInstance,
+ nextTick,
+ } from "vue";
+ import { getOptions } from "@/api/procurementManagement/procurementLedger.js";
+ import { modelList, productTreeList } from "@/api/basicData/product.js";
+ import {
+ qualityInspectAdd,
+ qualityInspectUpdate,
+ } from "@/api/qualityManagement/rawMaterialInspection.js";
+ import {
+ qualityInspectDetailByProductId,
+ getQualityTestStandardParamByTestStandardId,
+ } from "@/api/qualityManagement/metricMaintenance.js";
+ import { userListNoPage } from "@/api/system/user.js";
+ import { qualityInspectParamInfo } from "@/api/qualityManagement/qualityInspectParam.js";
+ import { list } from "@/api/productionManagement/productionProcess";
+ const { proxy } = getCurrentInstance();
+ const emit = defineEmits(["close"]);
-
-
-const dialogFormVisible = ref(false);
-const operationType = ref('')
-const data = reactive({
- form: {
- checkTime: "",
- process: "",
- checkName: "",
- productName: "",
- productId: "",
- productModelId: "",
- model: "",
- testStandardId: "",
- unit: "",
- quantity: "",
- checkCompany: "",
- checkResult: "",
- },
- rules: {
- checkTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" },],
- process: [{ required: true, message: "璇烽�夋嫨宸ュ簭", trigger: "change" }],
- checkName: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
- productId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- testStandardId: [{required: false, message: "璇烽�夋嫨鎸囨爣", trigger: "change"}],
- unit: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
- quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- checkCompany: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
- checkResult: [{ required: true, message: "璇疯緭鍏�", trigger: "change" }],
- },
-});
-const userList = ref([]);
-const { form, rules } = toRefs(data);
-// 缂栬緫鏃讹細productMainId 鎴� purchaseLedgerId 浠讳竴鏈夊�煎垯宸ュ簭銆佹暟閲忕疆鐏�
-const processQuantityDisabled = computed(() => {
- const v = form.value || {};
- return !!(v.productMainId != null || v.purchaseLedgerId != null);
-});
-const processList = ref([]); // 宸ュ簭涓嬫媺鍒楄〃锛堝伐搴忓悕绉� name锛�
-const supplierList = ref([]);
-const productOptions = ref([]);
-const tableColumn = ref([
- {
- label: "鎸囨爣",
- prop: "parameterItem",
- },
- {
- label: "鍗曚綅",
- prop: "unit",
- },
- {
- label: "鏍囧噯鍊�",
- prop: "standardValue",
- },
- {
- label: "鍐呮帶鍊�",
- prop: "controlValue",
- },
- {
- label: "妫�楠屽��",
- prop: "testValue",
- dataType: 'slot',
- slot: 'slot',
- },
-]);
-const tableData = ref([]);
-const tableLoading = ref(false);
-const currentProductId = ref(0);
-const testStandardOptions = ref([]); // 鎸囨爣閫夋嫨涓嬫媺妗嗘暟鎹�
-const modelOptions = ref([]);
-
-// 鎵撳紑寮规
-const openDialog = async (type, row) => {
- operationType.value = type;
- getOptions().then((res) => {
- supplierList.value = res.data;
- });
- // 鍔犺浇宸ュ簭涓嬫媺鍒楄〃
- try {
- const res = await list();
- processList.value = res.data || [];
- } catch (e) {
- console.error("鍔犺浇宸ュ簭鍒楄〃澶辫触", e);
- processList.value = [];
- }
- let userLists = await userListNoPage();
- userList.value = userLists.data;
- // 鍏堥噸缃〃鍗曟暟鎹紙淇濇寔瀛楁瀹屾暣锛岄伩鍏嶅脊绐楅娆℃覆鏌撴椂瑙﹀彂蹇呭~绾㈡鈥滈棯涓�涓嬧�濓級
- form.value = {
- checkTime: "",
- process: "",
- checkName: "",
- productName: "",
- productId: "",
- productModelId: "",
- model: "",
- testStandardId: "",
- unit: "",
- quantity: "",
- checkCompany: "",
- checkResult: "",
- }
- testStandardOptions.value = [];
- tableData.value = [];
- // 鍏堢‘淇濅骇鍝佹爲宸插姞杞斤紝鍚﹀垯缂栬緫鏃朵骇鍝�/瑙勬牸鍨嬪彿鏃犳硶鍙嶆樉
- await getProductOptions();
- if (operationType.value === 'edit') {
- // 鍏堜繚瀛� testStandardId锛岄伩鍏嶈娓呯┖
- const savedTestStandardId = row.testStandardId;
- // 鍏堣缃〃鍗曟暟鎹紝浣嗘殏鏃舵竻绌� testStandardId锛岀瓑閫夐」鍔犺浇瀹屾垚鍚庡啀璁剧疆
- form.value = {...row, testStandardId: ''}
- currentProductId.value = row.productId || 0
- // 鍏抽敭锛氱紪杈戞椂鍔犺浇瑙勬牸鍨嬪彿涓嬫媺閫夐」锛屾墠鑳藉弽鏄� productModelId
- if (currentProductId.value) {
- try {
- const res = await modelList({ id: currentProductId.value });
- modelOptions.value = res || [];
- // 鍚屾鍥炲~ model / unit锛堟湁浜涙帴鍙h繑鍥炵殑 row 閲屽彲鑳芥病甯﹀叏锛�
- if (form.value.productModelId) {
- handleChangeModel(form.value.productModelId);
- }
- } catch (e) {
- console.error("鍔犺浇瑙勬牸鍨嬪彿澶辫触", e);
- modelOptions.value = [];
- }
- }
- // 缂栬緫妯″紡涓嬶紝鍏堝姞杞芥寚鏍囬�夐」锛岀劧鍚庡姞杞藉弬鏁板垪琛�
- if (currentProductId.value) {
- // 鍏堝姞杞芥寚鏍囬�夐」
- let params = {
- productId: currentProductId.value,
- inspectType: 1,
- process: form.value.process || ''
- }
- qualityInspectDetailByProductId(params).then(res => {
- testStandardOptions.value = res.data || [];
- // 浣跨敤 nextTick 鍜� setTimeout 纭繚閫夐」宸茬粡娓叉煋鍒� DOM
- nextTick(() => {
- setTimeout(() => {
- // 濡傛灉缂栬緫鏁版嵁涓湁 testStandardId锛屽垯璁剧疆骞跺姞杞藉搴旂殑鍙傛暟
- if (savedTestStandardId) {
- // 纭繚绫诲瀷鍖归厤锛坕tem.id 鍙兘鏄暟瀛楁垨瀛楃涓诧級
- const matchedOption = testStandardOptions.value.find(item =>
- item.id == savedTestStandardId || String(item.id) === String(savedTestStandardId)
- );
- if (matchedOption) {
- // 纭繚浣跨敤鍖归厤椤圭殑 id锛堜繚鎸佺被鍨嬩竴鑷达級
- form.value.testStandardId = matchedOption.id;
- // 缂栬緫淇濈暀鍘熸楠屽�硷紝鐩存帴鎷夊彇鍘熷弬鏁版暟鎹�
- getQualityInspectParamList(row.id);
- } else {
- // 濡傛灉鎵句笉鍒板尮閰嶉」锛屽皾璇曠洿鎺ヤ娇鐢ㄥ師鍊�
- console.warn('鏈壘鍒板尮閰嶇殑鎸囨爣閫夐」锛宼estStandardId:', savedTestStandardId, '鍙敤閫夐」:', testStandardOptions.value);
- form.value.testStandardId = savedTestStandardId;
- getQualityInspectParamList(row.id);
- }
- } else {
- // 鍚﹀垯浣跨敤鏃х殑閫昏緫
- getQualityInspectParamList(row.id);
- }
- }, 100);
- });
- });
- } else {
- getQualityInspectParamList(row.id);
- }
- }
- // 鏈�鍚庡啀鎵撳紑寮圭獥锛屽苟娓呯悊鏍¢獙鎬侊紝閬垮厤蹇呭~鎻愮ず闂儊
- dialogFormVisible.value = true;
- nextTick(() => {
- proxy.$refs?.formRef?.clearValidate?.();
- });
-}
-const getProductOptions = () => {
- return productTreeList().then((res) => {
- productOptions.value = convertIdToValue(res);
- return productOptions.value;
+ const dialogFormVisible = ref(false);
+ const operationType = ref("");
+ const data = reactive({
+ form: {
+ checkTime: "",
+ process: "",
+ checkName: "",
+ productName: "",
+ productId: "",
+ productModelId: "",
+ model: "",
+ testStandardId: "",
+ unit: "",
+ quantity: "",
+ checkCompany: "",
+ checkResult: "",
+ },
+ rules: {
+ checkTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ process: [{ required: true, message: "璇烽�夋嫨宸ュ簭", trigger: "change" }],
+ checkName: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ productId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ testStandardId: [
+ { required: false, message: "璇烽�夋嫨鎸囨爣", trigger: "change" },
+ ],
+ unit: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ checkCompany: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ checkResult: [{ required: true, message: "璇疯緭鍏�", trigger: "change" }],
+ },
});
-};
-const getModels = (value) => {
- form.value.productModelId = undefined;
- form.value.unit = undefined;
- modelOptions.value = [];
- currentProductId.value = value
- form.value.productName = findNodeById(productOptions.value, value);
- modelList({ id: value }).then((res) => {
- modelOptions.value = res;
- })
- if (currentProductId.value) {
- getList();
- }
-};
+ const userList = ref([]);
+ const { form, rules } = toRefs(data);
+ // 缂栬緫鏃讹細productMainId 鎴� purchaseLedgerId 浠讳竴鏈夊�煎垯宸ュ簭銆佹暟閲忕疆鐏�
+ const processQuantityDisabled = computed(() => {
+ const v = form.value || {};
+ return !!(v.productMainId != null || v.purchaseLedgerId != null);
+ });
+ const processList = ref([]); // 宸ュ簭涓嬫媺鍒楄〃锛堝伐搴忓悕绉� name锛�
+ const supplierList = ref([]);
+ const productOptions = ref([]);
+ const tableColumn = ref([
+ {
+ label: "鎸囨爣",
+ prop: "parameterItem",
+ },
+ {
+ label: "鍗曚綅",
+ prop: "unit",
+ },
+ {
+ label: "鏍囧噯鍊�",
+ prop: "standardValue",
+ },
+ {
+ label: "鍐呮帶鍊�",
+ prop: "controlValue",
+ },
+ {
+ label: "妫�楠屽��",
+ prop: "testValue",
+ dataType: "slot",
+ slot: "slot",
+ },
+ ]);
+ const tableData = ref([]);
+ const tableLoading = ref(false);
+ const currentProductId = ref(0);
+ const testStandardOptions = ref([]); // 鎸囨爣閫夋嫨涓嬫媺妗嗘暟鎹�
+ const modelOptions = ref([]);
-const handleChangeModel = (value) => {
- form.value.model = modelOptions.value.find(item => item.id == value)?.model || '';
- form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || '';
-}
-
-const findNodeById = (nodes, productId) => {
- for (let i = 0; i < nodes.length; i++) {
- if (nodes[i].value === productId) {
- return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣
+ // 鎵撳紑寮规
+ const openDialog = async (type, row) => {
+ operationType.value = type;
+ getOptions().then(res => {
+ supplierList.value = res.data;
+ });
+ // 鍔犺浇宸ュ簭涓嬫媺鍒楄〃
+ try {
+ const res = await list({ size: -1, current: -1 });
+ processList.value = res.data.records || [];
+ } catch (e) {
+ console.error("鍔犺浇宸ュ簭鍒楄〃澶辫触", e);
+ processList.value = [];
}
- 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
+ let userLists = await userListNoPage();
+ userList.value = userLists.data;
+ // 鍏堥噸缃〃鍗曟暟鎹紙淇濇寔瀛楁瀹屾暣锛岄伩鍏嶅脊绐楅娆℃覆鏌撴椂瑙﹀彂蹇呭~绾㈡鈥滈棯涓�涓嬧�濓級
+ form.value = {
+ checkTime: "",
+ process: "",
+ checkName: "",
+ productName: "",
+ productId: "",
+ productModelId: "",
+ model: "",
+ testStandardId: "",
+ unit: "",
+ quantity: "",
+ checkCompany: "",
+ checkResult: "",
};
- if (children && children.length > 0) {
- newItem.children = convertIdToValue(children);
- }
-
- return newItem;
- });
-}
-// 宸ュ簭鍙樺寲澶勭悊
-// 鎻愪氦浜у搧琛ㄥ崟
-const submitForm = () => {
- proxy.$refs.formRef.validate(valid => {
- if (valid) {
- form.value.inspectType = 1
- const processName = form.value.process || '';
- if (operationType.value === "add") {
- tableData.value.forEach((item) => {
- delete item.id
- })
- }
- const data = {
- ...form.value,
- process: processName, // 淇濈暀 process 瀛楁浠ュ吋瀹瑰悗绔�
- qualityInspectParams: tableData.value
- }
- if (operationType.value === "add") {
- qualityInspectAdd(data).then(res => {
- proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
- closeDia();
- })
+ testStandardOptions.value = [];
+ tableData.value = [];
+ // 鍏堢‘淇濅骇鍝佹爲宸插姞杞斤紝鍚﹀垯缂栬緫鏃朵骇鍝�/瑙勬牸鍨嬪彿鏃犳硶鍙嶆樉
+ await getProductOptions();
+ if (operationType.value === "edit") {
+ // 鍏堜繚瀛� testStandardId锛岄伩鍏嶈娓呯┖
+ const savedTestStandardId = row.testStandardId;
+ // 鍏堣缃〃鍗曟暟鎹紝浣嗘殏鏃舵竻绌� testStandardId锛岀瓑閫夐」鍔犺浇瀹屾垚鍚庡啀璁剧疆
+ form.value = { ...row, testStandardId: "" };
+ currentProductId.value = row.productId || 0;
+ // 鍏抽敭锛氱紪杈戞椂鍔犺浇瑙勬牸鍨嬪彿涓嬫媺閫夐」锛屾墠鑳藉弽鏄� productModelId
+ if (currentProductId.value) {
+ try {
+ const res = await modelList({ id: currentProductId.value });
+ modelOptions.value = res || [];
+ // 鍚屾鍥炲~ model / unit锛堟湁浜涙帴鍙h繑鍥炵殑 row 閲屽彲鑳芥病甯﹀叏锛�
+ if (form.value.productModelId) {
+ handleChangeModel(form.value.productModelId);
+ }
+ } catch (e) {
+ console.error("鍔犺浇瑙勬牸鍨嬪彿澶辫触", e);
+ modelOptions.value = [];
+ }
+ }
+ // 缂栬緫妯″紡涓嬶紝鍏堝姞杞芥寚鏍囬�夐」锛岀劧鍚庡姞杞藉弬鏁板垪琛�
+ if (currentProductId.value) {
+ // 鍏堝姞杞芥寚鏍囬�夐」
+ let params = {
+ productId: currentProductId.value,
+ inspectType: 1,
+ process: form.value.process || "",
+ };
+ qualityInspectDetailByProductId(params).then(res => {
+ testStandardOptions.value = res.data || [];
+ // 浣跨敤 nextTick 鍜� setTimeout 纭繚閫夐」宸茬粡娓叉煋鍒� DOM
+ nextTick(() => {
+ setTimeout(() => {
+ // 濡傛灉缂栬緫鏁版嵁涓湁 testStandardId锛屽垯璁剧疆骞跺姞杞藉搴旂殑鍙傛暟
+ if (savedTestStandardId) {
+ // 纭繚绫诲瀷鍖归厤锛坕tem.id 鍙兘鏄暟瀛楁垨瀛楃涓诧級
+ const matchedOption = testStandardOptions.value.find(
+ item =>
+ item.id == savedTestStandardId ||
+ String(item.id) === String(savedTestStandardId)
+ );
+ if (matchedOption) {
+ // 纭繚浣跨敤鍖归厤椤圭殑 id锛堜繚鎸佺被鍨嬩竴鑷达級
+ form.value.testStandardId = matchedOption.id;
+ // 缂栬緫淇濈暀鍘熸楠屽�硷紝鐩存帴鎷夊彇鍘熷弬鏁版暟鎹�
+ getQualityInspectParamList(row.id);
+ } else {
+ // 濡傛灉鎵句笉鍒板尮閰嶉」锛屽皾璇曠洿鎺ヤ娇鐢ㄥ師鍊�
+ console.warn(
+ "鏈壘鍒板尮閰嶇殑鎸囨爣閫夐」锛宼estStandardId:",
+ savedTestStandardId,
+ "鍙敤閫夐」:",
+ testStandardOptions.value
+ );
+ form.value.testStandardId = savedTestStandardId;
+ getQualityInspectParamList(row.id);
+ }
+ } else {
+ // 鍚﹀垯浣跨敤鏃х殑閫昏緫
+ getQualityInspectParamList(row.id);
+ }
+ }, 100);
+ });
+ });
} else {
- qualityInspectUpdate(data).then(res => {
- proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
- closeDia();
- })
+ getQualityInspectParamList(row.id);
}
}
- })
-}
-const getList = () => {
- if (!currentProductId.value) {
- testStandardOptions.value = [];
- tableData.value = [];
- return;
- }
- const processName = form.value.process || '';
- let params = {
- productId: currentProductId.value,
- inspectType: 1,
- process: processName
- }
- qualityInspectDetailByProductId(params).then(res => {
- // 淇濆瓨涓嬫媺妗嗛�夐」鏁版嵁
- testStandardOptions.value = res.data || [];
- // 娓呯┖琛ㄦ牸鏁版嵁锛岀瓑寰呯敤鎴烽�夋嫨鎸囨爣
- tableData.value = [];
- // 娓呯┖鎸囨爣閫夋嫨
- form.value.testStandardId = '';
- })
-}
+ // 鏈�鍚庡啀鎵撳紑寮圭獥锛屽苟娓呯悊鏍¢獙鎬侊紝閬垮厤蹇呭~鎻愮ず闂儊
+ dialogFormVisible.value = true;
+ nextTick(() => {
+ proxy.$refs?.formRef?.clearValidate?.();
+ });
+ };
+ const getProductOptions = () => {
+ return productTreeList().then(res => {
+ productOptions.value = convertIdToValue(res);
+ return productOptions.value;
+ });
+ };
+ const getModels = value => {
+ form.value.productModelId = undefined;
+ form.value.unit = undefined;
+ modelOptions.value = [];
+ currentProductId.value = value;
+ form.value.productName = findNodeById(productOptions.value, value);
+ modelList({ id: value }).then(res => {
+ modelOptions.value = res;
+ });
+ if (currentProductId.value) {
+ getList();
+ }
+ };
-// 鎸囨爣閫夋嫨鍙樺寲澶勭悊
-const handleTestStandardChange = (testStandardId) => {
- if (!testStandardId) {
- tableData.value = [];
- return;
- }
- tableLoading.value = true;
- getQualityTestStandardParamByTestStandardId(testStandardId).then(res => {
- tableData.value = res.data || [];
- }).catch(error => {
- console.error('鑾峰彇鏍囧噯鍙傛暟澶辫触:', error);
- tableData.value = [];
- }).finally(() => {
- tableLoading.value = false;
- })
-}
-const getQualityInspectParamList = (id) => {
- qualityInspectParamInfo(id).then(res => {
- tableData.value = res.data;
- })
-}
-// 鍏抽棴寮规
-const closeDia = () => {
- proxy.resetForm("formRef");
- tableData.value = [];
- testStandardOptions.value = [];
- form.value.testStandardId = '';
- dialogFormVisible.value = false;
- emit('close')
-};
-defineExpose({
- openDialog,
-});
+ const handleChangeModel = value => {
+ form.value.model =
+ modelOptions.value.find(item => item.id == value)?.model || "";
+ form.value.unit =
+ modelOptions.value.find(item => item.id == value)?.unit || "";
+ };
+
+ 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;
+ });
+ }
+ // 宸ュ簭鍙樺寲澶勭悊
+ // 鎻愪氦浜у搧琛ㄥ崟
+ const submitForm = () => {
+ proxy.$refs.formRef.validate(valid => {
+ if (valid) {
+ form.value.inspectType = 1;
+ const processName = form.value.process || "";
+ if (operationType.value === "add") {
+ tableData.value.forEach(item => {
+ delete item.id;
+ });
+ }
+ const data = {
+ ...form.value,
+ process: processName, // 淇濈暀 process 瀛楁浠ュ吋瀹瑰悗绔�
+ qualityInspectParams: tableData.value,
+ };
+ if (operationType.value === "add") {
+ qualityInspectAdd(data).then(res => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeDia();
+ });
+ } else {
+ qualityInspectUpdate(data).then(res => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeDia();
+ });
+ }
+ }
+ });
+ };
+ const getList = () => {
+ if (!currentProductId.value) {
+ testStandardOptions.value = [];
+ tableData.value = [];
+ return;
+ }
+ const processName = form.value.process || "";
+ let params = {
+ productId: currentProductId.value,
+ inspectType: 1,
+ process: processName,
+ };
+ qualityInspectDetailByProductId(params).then(res => {
+ // 淇濆瓨涓嬫媺妗嗛�夐」鏁版嵁
+ testStandardOptions.value = res.data || [];
+ // 娓呯┖琛ㄦ牸鏁版嵁锛岀瓑寰呯敤鎴烽�夋嫨鎸囨爣
+ tableData.value = [];
+ // 娓呯┖鎸囨爣閫夋嫨
+ form.value.testStandardId = "";
+ });
+ };
+
+ // 鎸囨爣閫夋嫨鍙樺寲澶勭悊
+ const handleTestStandardChange = testStandardId => {
+ if (!testStandardId) {
+ tableData.value = [];
+ return;
+ }
+ tableLoading.value = true;
+ getQualityTestStandardParamByTestStandardId(testStandardId)
+ .then(res => {
+ tableData.value = res.data || [];
+ })
+ .catch(error => {
+ console.error("鑾峰彇鏍囧噯鍙傛暟澶辫触:", error);
+ tableData.value = [];
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+ };
+ const getQualityInspectParamList = id => {
+ qualityInspectParamInfo(id).then(res => {
+ tableData.value = res.data;
+ });
+ };
+ // 鍏抽棴寮规
+ const closeDia = () => {
+ proxy.resetForm("formRef");
+ tableData.value = [];
+ testStandardOptions.value = [];
+ form.value.testStandardId = "";
+ dialogFormVisible.value = false;
+ emit("close");
+ };
+ defineExpose({
+ openDialog,
+ });
</script>
<style scoped>
-
</style>
\ No newline at end of file
diff --git a/src/views/salesManagement/deliveryLedger/index.vue b/src/views/salesManagement/deliveryLedger/index.vue
index d65727d..c8890cc 100644
--- a/src/views/salesManagement/deliveryLedger/index.vue
+++ b/src/views/salesManagement/deliveryLedger/index.vue
@@ -87,6 +87,11 @@
show-overflow-tooltip
/>
<el-table-column
+ label="鍙戣揣鏁伴噺"
+ prop="totalQuantity"
+ show-overflow-tooltip
+ />
+ <el-table-column
label="鍙戣揣杞︾墝鍙�"
prop="shippingCarNumber"
show-overflow-tooltip
@@ -105,7 +110,7 @@
label="瀹℃牳鐘舵��"
prop="status"
align="center"
- width="120"
+ width="100"
>
<template #default="scope">
<el-tag :type="getApprovalStatusType(scope.row.status)">
@@ -113,6 +118,12 @@
</el-tag>
</template>
</el-table-column>
+ <el-table-column
+ label="鍑哄簱鍗曞彿"
+ prop="outboundBatches"
+ show-overflow-tooltip
+ width="130"
+ />
<el-table-column fixed="right" label="鎿嶄綔" width="220" align="center">
<template #default="scope">
<!-- <el-button-->
@@ -279,6 +290,9 @@
<el-descriptions-item label="蹇�掑崟鍙�" :span="2">{{
detailRow.expressNumber || "--"
}}</el-descriptions-item>
+ <el-descriptions-item label="鍑哄簱鍗曞彿" :span="2">{{
+ detailRow.outboundBatches || "--"
+ }}</el-descriptions-item>
</el-descriptions>
<el-table
:data="getDeliveryProductInfoList()"
diff --git a/src/views/salesManagement/returnOrder/components/detailDia.vue b/src/views/salesManagement/returnOrder/components/detailDia.vue
index 9ff4e89..ecc663f 100644
--- a/src/views/salesManagement/returnOrder/components/detailDia.vue
+++ b/src/views/salesManagement/returnOrder/components/detailDia.vue
@@ -10,8 +10,8 @@
<el-descriptions-item label="瀹㈡埛鍚嶇О">{{ detail.customerName }}</el-descriptions-item>
<el-descriptions-item label="閿�鍞崟鍙�">{{ detail.salesContractNo }}</el-descriptions-item>
<el-descriptions-item label="涓氬姟鍛�">{{ detail.salesman }}</el-descriptions-item>
- <el-descriptions-item label="鍏宠仈鍑哄簱鍗曞彿">{{ detail.shippingNo }}</el-descriptions-item>
- <el-descriptions-item label="椤圭洰鍚嶇О">{{ detail.projectName }}</el-descriptions-item>
+ <el-descriptions-item label="鍏宠仈鍙戣揣鍗曞彿">{{ detail.shippingNo }}</el-descriptions-item>
+ <!-- <el-descriptions-item label="椤圭洰鍚嶇О">{{ detail.projectName }}</el-descriptions-item> -->
<el-descriptions-item label="鍒跺崟浜�">{{ detail.maker }}</el-descriptions-item>
<el-descriptions-item label="鍒跺崟鏃堕棿">{{ detail.makeTime }}</el-descriptions-item>
<el-descriptions-item label="閫�璐у師鍥�">{{ detail.returnReason }}</el-descriptions-item>
@@ -20,7 +20,11 @@
<div style="padding-top: 20px">
<span class="descriptions">浜у搧鍒楄〃</span>
- <PIMTable :isShowPagination="false" rowKey="id" :column="tableColumn" :tableData="tableData" />
+ <PIMTable :isShowPagination="false" rowKey="id" :column="tableColumn" :tableData="tableData">
+ <template #totalReturnNum="{ row }">
+ {{ calcAlreadyReturned(row) }}
+ </template>
+ </PIMTable>
</div>
</div>
<template #footer>
@@ -41,12 +45,214 @@
const tableData = ref([]);
const availableProducts = ref([]);
+const sameKey = (a, b) => a != null && b != null && String(a) === String(b);
+
+/** 涓� formDia 涓�鑷达細涓や唤鍒楄〃鎸� id 鍚堝苟锛岄伩鍏嶅彧鍙� productDtoData 鏃剁己鍑哄簱鍗曞彿/鎵规/鏁伴噺 */
+const mergeShippingProductLists = (data) => {
+ const lists = [data?.shippingProductVoList, data?.productDtoData].filter(Array.isArray);
+ if (!lists.length) return [];
+ const map = new Map();
+ for (const list of lists) {
+ for (const p of list) {
+ if (p == null) continue;
+ const key = p.id != null ? String(p.id) : null;
+ if (!key) continue;
+ const prev = map.get(key);
+ map.set(key, prev ? { ...prev, ...p } : { ...p });
+ }
+ }
+ return Array.from(map.values());
+};
+
+const pickShippingLine = (normalized) => {
+ const pid = normalized?.returnSaleLedgerProductId ?? normalized?.id;
+ const sid = normalized?.stockOutRecordId ?? normalized?.shippingProductId;
+ const direct = availableProducts.value.find(
+ (p) =>
+ sameKey(p?.id, pid) ||
+ sameKey(p?.stockOutRecordId, pid) ||
+ sameKey(p?.id, sid) ||
+ sameKey(p?.stockOutRecordId, sid)
+ );
+ if (direct) return direct;
+ const pmid = normalized?.productModelId;
+ if (pmid == null || pmid === "") return undefined;
+ const candidates = availableProducts.value.filter((p) => sameKey(p?.productModelId, pmid));
+ if (!candidates.length) return undefined;
+ if (candidates.length === 1) return candidates[0];
+ const spec = String(normalized?.specificationModel ?? normalized?.model ?? "");
+ if (spec) {
+ const hit = candidates.find((p) => {
+ const ps = String(p?.specificationModel ?? p?.model ?? "");
+ return ps && ps === spec;
+ });
+ if (hit) return hit;
+ }
+ return candidates[0];
+};
+
+const isEmptyText = (v) => v === "" || v == null || v === undefined;
+
+const firstFiniteNumber = (...vals) => {
+ for (const v of vals) {
+ if (v === "" || v == null || v === undefined) continue;
+ const n = Number(v);
+ if (Number.isFinite(n)) return n;
+ }
+ return undefined;
+};
+
+const firstNonEmptyText = (...vals) => {
+ const hit = vals.find((v) => !isEmptyText(v));
+ return hit === undefined ? "" : hit;
+};
+
+const calcAlreadyReturned = (row) => {
+ const total = Number(row?.stockOutNum ?? row?.totalQuantity ?? row?.totalReturnNum ?? 0);
+ const un = Number(row?.unQuantity ?? 0);
+ if (!Number.isFinite(total) || !Number.isFinite(un)) return 0;
+ return Math.max(total - un, 0);
+};
+
+/** 璇︽儏琛ㄧ敤 productName / model锛涘悎骞舵椂鍕胯绌轰覆鐩栨帀鍑哄簱琛屽瓧娈� */
+const mergeDetailProductRow = (product, normalized) => {
+ const row = { ...product, ...normalized };
+ row.outboundBatches = firstNonEmptyText(
+ row.outboundBatches,
+ product?.outboundBatches,
+ product?.shippingNo,
+ product?.outboundNo,
+ normalized?.outboundBatches,
+ normalized?.outboundNo,
+ normalized?.shippingNo
+ );
+ row.batchNo = firstNonEmptyText(
+ row.batchNo,
+ product?.batchNo,
+ product?.batchNumber,
+ product?.lotNo,
+ product?.batchCode,
+ product?.shippingBatchNo,
+ normalized?.batchNo,
+ normalized?.batchNumber,
+ normalized?.lotNo,
+ normalized?.shippingBatchNo
+ );
+ const stock = firstFiniteNumber(
+ row.stockOutNum,
+ product?.stockOutNum,
+ product?.totalQuantity,
+ product?.shippingQuantity,
+ product?.deliveryQuantity,
+ product?.quantity,
+ product?.outQuantity,
+ normalized?.stockOutNum,
+ normalized?.totalQuantity,
+ normalized?.shippingQuantity,
+ normalized?.deliveryQuantity
+ );
+ if (stock !== undefined) row.stockOutNum = stock;
+ const un = firstFiniteNumber(
+ row.unQuantity,
+ product?.unQuantity,
+ product?.remainingQuantity,
+ product?.noReturnQuantity,
+ product?.canReturnQuantity,
+ product?.availableReturnNum,
+ normalized?.unQuantity,
+ normalized?.remainingQuantity,
+ normalized?.noReturnQuantity,
+ normalized?.canReturnQuantity
+ );
+ if (un !== undefined) row.unQuantity = un;
+ else {
+ const s = Number(row.stockOutNum);
+ const ret = Number(row.totalReturnNum ?? 0);
+ if (Number.isFinite(s) && s >= 0 && Number.isFinite(ret) && ret >= 0) {
+ row.unQuantity = Math.max(0, s - ret);
+ }
+ }
+ const returned = firstFiniteNumber(
+ row.totalReturnNum,
+ product?.totalReturnNum,
+ product?.totalReturnedNum,
+ normalized?.totalReturnNum,
+ normalized?.totalReturnedNum
+ );
+ if (returned !== undefined) row.totalReturnNum = returned;
+ else if (isEmptyText(row.totalReturnNum)) row.totalReturnNum = 0;
+ if (isEmptyText(row.unit)) {
+ row.unit = firstNonEmptyText(product?.unit, normalized?.unit);
+ }
+ row.productName = firstNonEmptyText(
+ row.productName,
+ normalized?.productName,
+ normalized?.productCategory,
+ product?.productName,
+ product?.productCategory
+ );
+ row.model = firstNonEmptyText(
+ row.model,
+ normalized?.model,
+ normalized?.specificationModel,
+ product?.model,
+ product?.specificationModel
+ );
+ return row;
+};
+
+const normalizeDetailRow = (raw) => {
+ const ledgerId =
+ raw?.returnSaleLedgerProductId ??
+ raw?.saleLedgerProductId ??
+ raw?.stockOutRecordId ??
+ raw?.shippingProductId;
+ const productId = ledgerId ?? raw?.id;
+ const num = Number(raw?.num ?? raw?.returnQuantity ?? 0);
+ return {
+ ...raw,
+ id: productId,
+ returnSaleLedgerProductId: productId,
+ productModelId: raw?.productModelId,
+ stockOutRecordId: raw?.stockOutRecordId,
+ shippingProductId: raw?.shippingProductId,
+ productName: raw?.productName ?? raw?.productCategory ?? raw?.productTypeName ?? "",
+ model: raw?.model ?? raw?.specificationModel ?? raw?.specModel ?? "",
+ outboundBatches: raw?.outboundBatches ?? raw?.outboundNo ?? raw?.shippingNo,
+ batchNo:
+ raw?.batchNo ??
+ raw?.batchNumber ??
+ raw?.lotNo ??
+ raw?.batchCode ??
+ raw?.shippingBatchNo,
+ stockOutNum:
+ raw?.stockOutNum ??
+ raw?.totalQuantity ??
+ raw?.shippingQuantity ??
+ raw?.deliveryQuantity ??
+ raw?.quantity,
+ totalReturnNum: raw?.totalReturnNum ?? raw?.totalReturnedNum,
+ unQuantity:
+ raw?.unQuantity ??
+ raw?.remainingQuantity ??
+ raw?.noReturnQuantity ??
+ raw?.canReturnQuantity,
+ returnQuantity: Number.isFinite(num) ? num : 0,
+ price: Number(raw?.taxInclusiveUnitPrice ?? raw?.price ?? 0),
+ amount: Number(raw?.amount ?? 0).toFixed(2),
+ isQuality: raw?.isQuality ?? 2,
+ remark: raw?.remark ?? "",
+ };
+};
+
const tableColumn = [
- {align: "center", label: "浜у搧澶х被", prop: "productCategory"},
- {align: "center", label: "瑙勬牸鍨嬪彿", prop: "specificationModel"},
+ {align: "center", label: "鍑哄簱鍗曞彿", prop: "outboundBatches"},
+ {align: "center", label: "鎵规鍙�", prop: "batchNo"},
+ {align: "center", label: "浜у搧澶х被", prop: "productName"},
+ {align: "center", label: "瑙勬牸鍨嬪彿", prop: "model"},
{align: "center", label: "鍗曚綅", prop: "unit", width: 80},
- {align: "center", label: "鎬绘暟閲�", prop: "quantity", width: 120},
- {align: "center", label: "宸查��璐ф暟閲�", prop: "totalReturnNum", width: 120},
+ {align: "center", label: "鎬绘暟閲�", prop: "stockOutNum", width: 120},
+ {align: "center", label: "宸查��璐ф暟閲�", prop: "totalReturnNum", width: 120, dataType: "slot", slot: "totalReturnNum"},
{align: "center", label: "鏈��璐ф暟閲�", prop: "unQuantity", width: 120},
{align: "center", label: "閫�璐ф暟閲�", prop: "returnQuantity", width: 120},
{align: "center", label: "閫�璐т骇鍝佸崟浠�", prop: "price", width: 120},
@@ -82,30 +288,30 @@
if (detail.value.shippingId) {
const productRes = await returnManagementGetByShippingId({ shippingId: detail.value.shippingId });
if (productRes.code === 200) {
- availableProducts.value = productRes.data.productDtoData || [];
+ availableProducts.value = mergeShippingProductLists(productRes.data);
}
}
-
+
const list =
detail.value?.returnSaleProducts ||
- detail.value?.returnSaleProductList ||
- detail.value?.returnSaleProductDtoData ||
- [];
-
- tableData.value = Array.isArray(list) ? list.map(raw => {
- const productId = raw?.returnSaleLedgerProductId ?? raw?.saleLedgerProductId ?? raw?.id;
- const product = availableProducts.value.find((p) => p.id === productId);
- const normalized = {
- ...raw,
- id: productId,
- returnQuantity: Number(raw?.num ?? raw?.returnQuantity ?? 0),
- price: Number(raw?.taxInclusiveUnitPrice ?? raw?.price ?? 0),
- amount: Number(raw?.amount ?? 0).toFixed(2),
- isQuality: raw?.isQuality ?? 2,
- remark: raw?.remark ?? "",
- };
- return product ? { ...product, ...normalized } : normalized;
- }) : [];
+ detail.value?.returnSaleProductList ||
+ detail.value?.returnSaleProductDtoData ||
+ [];
+
+ tableData.value = Array.isArray(list)
+ ? list.map((raw) => {
+ const normalized = normalizeDetailRow(raw);
+ const product = pickShippingLine(normalized);
+ return product ? mergeDetailProductRow(product, normalized) : normalized;
+ })
+ : [];
+
+ const headerShipNo = detail.value?.shippingNo;
+ if (headerShipNo && Array.isArray(tableData.value) && tableData.value.length) {
+ tableData.value = tableData.value.map((r) =>
+ isEmptyText(r.outboundBatches) ? { ...r, outboundBatches: headerShipNo } : r
+ );
+ }
} catch (e) {
console.error("Failed to load detail", e);
} finally {
diff --git a/src/views/salesManagement/returnOrder/components/formDia.vue b/src/views/salesManagement/returnOrder/components/formDia.vue
index 0f27e98..6a6d756 100644
--- a/src/views/salesManagement/returnOrder/components/formDia.vue
+++ b/src/views/salesManagement/returnOrder/components/formDia.vue
@@ -32,7 +32,7 @@
</el-form-item>
</el-col>
<el-col :span="4">
- <el-form-item label="鍏宠仈鍑哄簱鍗曞彿锛�" prop="shippingId">
+ <el-form-item label="鍏宠仈鍙戣揣鍗曞彿锛�" prop="shippingId">
<el-select v-model="form.shippingId" filterable placeholder="璇烽�夋嫨鍑哄簱鍗曞彿" @change="outboundNoChange">
<el-option
v-for="item in outboundOptions"
@@ -82,6 +82,9 @@
<el-button type="primary" @click="openProductSelection" :disabled="!form.shippingId">娣诲姞浜у搧</el-button>
</div>
<PIMTable :isShowPagination="false" rowKey="id" :column="tableColumn" :tableData="tableData">
+ <template #totalReturnNum="{ row }">
+ {{ calcAlreadyReturned(row) }}
+ </template>
<template #returnQuantity="{ row }">
<el-input
v-model="row.returnQuantity"
@@ -122,7 +125,7 @@
placeholder="璇疯緭鍏�"
/>
</template>
- <template #action="{ row, index }">
+ <template #action="{ index }">
<el-button type="danger" link @click="deleteRow(index)">鍒犻櫎</el-button>
</template>
</PIMTable>
@@ -145,10 +148,12 @@
row-key="id"
>
<el-table-column align="center" type="selection" width="55" />
+ <el-table-column align="center" prop="outboundBatches" label="鍑哄簱鍗曞彿" />
+ <el-table-column align="center" prop="batchNo" label="鎵规鍙�" />
<el-table-column align="center" prop="productCategory" label="浜у搧澶х被" />
<el-table-column align="center" prop="specificationModel" label="瑙勬牸鍨嬪彿" />
<el-table-column align="center" prop="unit" label="鍗曚綅" />
- <el-table-column align="center" prop="quantity" label="鎬绘暟閲�" />
+ <el-table-column align="center" prop="stockOutNum" label="鎬绘暟閲�" />
<el-table-column align="center" prop="unQuantity" label="鏈��璐ф暟閲�" />
<el-table-column align="center" label="宸查��璐ф暟閲�">
<template #default="{ row }">{{ calcAlreadyReturned(row) }}</template>
@@ -208,18 +213,20 @@
const { form, rules } = toRefs(data);
const calcAlreadyReturned = (row) => {
- const total = Number(row?.quantity ?? row?.totalQuantity ?? row?.totalReturnNum ?? 0);
+ const total = Number(row?.stockOutNum ?? row?.totalQuantity ?? row?.totalReturnNum ?? 0);
const un = Number(row?.unQuantity ?? 0);
if (!Number.isFinite(total) || !Number.isFinite(un)) return 0;
return Math.max(total - un, 0);
};
const tableColumn = ref([
+ {align: "center", label: "鍑哄簱鍗曞彿", prop: "outboundBatches" },
+ {align: "center", label: "鎵规鍙�", prop: "batchNo" },
{align: "center", label: "浜у搧澶х被", prop: "productCategory" },
{align: "center", label: "瑙勬牸鍨嬪彿", prop: "specificationModel" },
{align: "center", label: "鍗曚綅", prop: "unit", width: 80 },
- {align: "center", label: "鎬绘暟閲�", prop: "quantity", width: 120 },
- {align: "center", label: "宸查��璐ф暟閲�", prop: "totalReturnNum", width: 120 },
+ {align: "center", label: "鎬绘暟閲�", prop: "stockOutNum", width: 120 },
+ {align: "center", label: "宸查��璐ф暟閲�", prop: "totalReturnNum", width: 120, dataType: "slot", slot: "totalReturnNum" },
{align: "center", label: "鏈��璐ф暟閲�", prop: "unQuantity", width: 120 },
{align: "center", label: "閫�璐ф暟閲�", prop: "returnQuantity", dataType: "slot", slot: "returnQuantity", width: 120 },
{align: "center", label: "閫�璐т骇鍝佸崟浠�", prop: "price", dataType: "slot", slot: "price", width: 120 },
@@ -238,8 +245,164 @@
tableData.value.splice(index, 1);
};
+const sameKey = (a, b) => a != null && b != null && String(a) === String(b);
+
+/** 鎺ュ彛鍙兘鎷嗘垚 shippingProductVoList / productDtoData 涓や唤锛屽彧鍙栧叾涓�浼氱己鎵规銆佹暟閲忕瓑瀛楁 */
+const mergeShippingProductLists = (data) => {
+ const lists = [data?.shippingProductVoList, data?.productDtoData].filter(Array.isArray);
+ if (!lists.length) return [];
+ const map = new Map();
+ for (const list of lists) {
+ for (const p of list) {
+ if (p == null) continue;
+ const key = p.id != null ? String(p.id) : null;
+ if (!key) continue;
+ const prev = map.get(key);
+ map.set(key, prev ? { ...prev, ...p } : { ...p });
+ }
+ }
+ return Array.from(map.values());
+};
+
+const pickShippingLine = (normalized) => {
+ const pid = normalized?.returnSaleLedgerProductId ?? normalized?.id;
+ const sid = normalized?.stockOutRecordId ?? normalized?.shippingProductId;
+ const direct = availableProducts.value.find(
+ (p) =>
+ sameKey(p?.id, pid) ||
+ sameKey(p?.stockOutRecordId, pid) ||
+ sameKey(p?.id, sid) ||
+ sameKey(p?.stockOutRecordId, sid)
+ );
+ if (direct) return direct;
+ const pmid = normalized?.productModelId;
+ if (pmid == null || pmid === "") return undefined;
+ const candidates = availableProducts.value.filter((p) => sameKey(p?.productModelId, pmid));
+ if (!candidates.length) return undefined;
+ if (candidates.length === 1) return candidates[0];
+ const spec = String(normalized?.specificationModel ?? normalized?.model ?? "");
+ if (spec) {
+ const hit = candidates.find((p) => {
+ const ps = String(p?.specificationModel ?? p?.model ?? "");
+ return ps && ps === spec;
+ });
+ if (hit) return hit;
+ }
+ return candidates[0];
+};
+
+const isEmptyText = (v) => v === "" || v == null || v === undefined;
+
+const firstFiniteNumber = (...vals) => {
+ for (const v of vals) {
+ if (v === "" || v == null || v === undefined) continue;
+ const n = Number(v);
+ if (Number.isFinite(n)) return n;
+ }
+ return undefined;
+};
+
+const firstNonEmptyText = (...vals) => {
+ const hit = vals.find((v) => !isEmptyText(v));
+ return hit === undefined ? "" : hit;
+};
+
+/** 璇︽儏鎺ュ彛瀛楁甯镐笉鍏紱{...product,...normalized} 浼氳 normalized 閲岀殑绌轰覆鐩栨帀鍑哄簱琛屼笂鐨勫睍绀哄瓧娈� */
+const mergeShippingLineWithDetail = (product, normalized) => {
+ const row = { ...product, ...normalized };
+ row.outboundBatches = firstNonEmptyText(
+ row.outboundBatches,
+ product?.outboundBatches,
+ product?.shippingNo,
+ product?.outboundNo,
+ normalized?.outboundBatches,
+ normalized?.outboundNo,
+ normalized?.shippingNo
+ );
+ row.batchNo = firstNonEmptyText(
+ row.batchNo,
+ product?.batchNo,
+ product?.batchNumber,
+ product?.lotNo,
+ product?.batchCode,
+ product?.shippingBatchNo,
+ normalized?.batchNo,
+ normalized?.batchNumber,
+ normalized?.lotNo,
+ normalized?.shippingBatchNo
+ );
+ const stock = firstFiniteNumber(
+ row.stockOutNum,
+ product?.stockOutNum,
+ product?.totalQuantity,
+ product?.shippingQuantity,
+ product?.deliveryQuantity,
+ product?.quantity,
+ product?.outQuantity,
+ normalized?.stockOutNum,
+ normalized?.totalQuantity,
+ normalized?.shippingQuantity,
+ normalized?.deliveryQuantity
+ );
+ if (stock !== undefined) row.stockOutNum = stock;
+ const un = firstFiniteNumber(
+ row.unQuantity,
+ product?.unQuantity,
+ product?.remainingQuantity,
+ product?.noReturnQuantity,
+ product?.canReturnQuantity,
+ product?.availableReturnNum,
+ normalized?.unQuantity,
+ normalized?.remainingQuantity,
+ normalized?.noReturnQuantity,
+ normalized?.canReturnQuantity
+ );
+ if (un !== undefined) row.unQuantity = un;
+ else {
+ const s = Number(row.stockOutNum);
+ const ret = Number(row.totalReturnNum ?? 0);
+ if (Number.isFinite(s) && s >= 0 && Number.isFinite(ret) && ret >= 0) {
+ row.unQuantity = Math.max(0, s - ret);
+ }
+ }
+ const returned = firstFiniteNumber(
+ row.totalReturnNum,
+ product?.totalReturnNum,
+ product?.totalReturnedNum,
+ normalized?.totalReturnNum,
+ normalized?.totalReturnedNum
+ );
+ if (returned !== undefined) row.totalReturnNum = returned;
+ else if (isEmptyText(row.totalReturnNum)) row.totalReturnNum = 0;
+ if (isEmptyText(row.unit)) {
+ row.unit = firstNonEmptyText(product?.unit, normalized?.unit);
+ }
+ if (isEmptyText(row.productCategory)) {
+ row.productCategory = firstNonEmptyText(
+ normalized?.productCategory,
+ normalized?.productName,
+ product?.productCategory,
+ product?.productName
+ );
+ }
+ if (isEmptyText(row.specificationModel)) {
+ row.specificationModel = firstNonEmptyText(
+ normalized?.specificationModel,
+ normalized?.model,
+ product?.specificationModel,
+ product?.model
+ );
+ }
+ return row;
+};
+
const normalizeDetailRow = (raw) => {
- const productId = raw?.returnSaleLedgerProductId ?? raw?.saleLedgerProductId ?? raw?.id;
+ const ledgerId =
+ raw?.returnSaleLedgerProductId ??
+ raw?.saleLedgerProductId ??
+ raw?.stockOutRecordId ??
+ raw?.shippingProductId;
+ const productId = ledgerId ?? raw?.id;
const returnSaleProductId = raw?.returnSaleProductId ?? raw?.id;
const num = Number(raw?.num ?? raw?.returnQuantity ?? 0);
return {
@@ -248,6 +411,29 @@
returnSaleProductId,
returnSaleLedgerProductId: productId,
productModelId: raw?.productModelId,
+ stockOutRecordId: raw?.stockOutRecordId,
+ shippingProductId: raw?.shippingProductId,
+ productCategory: raw?.productCategory ?? raw?.productName ?? raw?.productTypeName ?? "",
+ specificationModel: raw?.specificationModel ?? raw?.model ?? raw?.specModel ?? "",
+ outboundBatches: raw?.outboundBatches ?? raw?.outboundNo ?? raw?.shippingNo,
+ batchNo:
+ raw?.batchNo ??
+ raw?.batchNumber ??
+ raw?.lotNo ??
+ raw?.batchCode ??
+ raw?.shippingBatchNo,
+ stockOutNum:
+ raw?.stockOutNum ??
+ raw?.totalQuantity ??
+ raw?.shippingQuantity ??
+ raw?.deliveryQuantity ??
+ raw?.quantity,
+ totalReturnNum: raw?.totalReturnNum ?? raw?.totalReturnedNum,
+ unQuantity:
+ raw?.unQuantity ??
+ raw?.remainingQuantity ??
+ raw?.noReturnQuantity ??
+ raw?.canReturnQuantity,
num,
returnQuantity: Number.isFinite(num) ? num : 0,
price: Number(raw?.taxInclusiveUnitPrice ?? raw?.price ?? 0),
@@ -259,7 +445,6 @@
const setFormForEdit = async (row) => {
const res = await returnManagementGetById({ returnManagementId: row?.id });
- console.log("res", res);
const detail = res?.data ?? res ?? {};
Object.assign(form.value, detail);
@@ -281,11 +466,18 @@
tableData.value = Array.isArray(list)
? list.map((raw) => {
const normalized = normalizeDetailRow(raw);
- const product = availableProducts.value.find((p) => p.id === normalized.id);
- return product ? { ...product, ...normalized } : normalized;
+ const product = pickShippingLine(normalized);
+ return product ? mergeShippingLineWithDetail(product, normalized) : normalized;
})
: [];
-
+
+ const headerShipNo = detail?.shippingNo ?? form.value?.shippingNo;
+ if (headerShipNo && Array.isArray(tableData.value) && tableData.value.length) {
+ tableData.value = tableData.value.map((r) =>
+ isEmptyText(r.outboundBatches) ? { ...r, outboundBatches: headerShipNo } : r
+ );
+ }
+
calculateTotalRefund();
};
@@ -320,7 +512,7 @@
proxy.$refs["formRef"].validate(valid => {
if (!valid) return;
const returnSaleProducts = (tableData.value || []).map(el => ({
- returnSaleLedgerProductId: el.returnSaleLedgerProductId ?? el.id,
+ stockOutRecordId: el.returnSaleLedgerProductId ?? el.id,
productModelId: el.productModelId,
unit: el.unit,
num: Number(el.num ?? el.returnQuantity ?? 0),
@@ -419,8 +611,7 @@
// If backend returns project info, set it
if (res.data.projectId) form.value.projectId = res.data.projectId;
- // Store available products for selection
- availableProducts.value = res.data.productDtoData || [];
+ availableProducts.value = mergeShippingProductLists(res.data);
if (clearTable) tableData.value = [];
}
};
@@ -457,9 +648,9 @@
};
const calculateRowAmount = (row) => {
- const quantity = Number(row.returnQuantity || 0);
+ const stockOutNum = Number(row.returnQuantity || 0);
const price = Number(row.price || 0);
- row.amount = (quantity * price).toFixed(2);
+ row.amount = (stockOutNum * price).toFixed(2);
};
const calculateTotalRefund = () => {
@@ -511,10 +702,11 @@
amount: "0.00",
isQuality: 2,
remark: "",
+ productCategory: product.productCategory ?? product.productName ?? "",
productName: product.productName,
- specificationModel: product.specificationModel,
+ specificationModel: product.specificationModel ?? product.model ?? "",
unit: product.unit,
- quantity: product.quantity,
+ stockOutNum: product.stockOutNum,
totalReturnNum: product.totalReturnNum,
unQuantity: product.unQuantity
});
diff --git a/src/views/salesManagement/returnOrder/index.vue b/src/views/salesManagement/returnOrder/index.vue
index d41d4bf..0a8257b 100644
--- a/src/views/salesManagement/returnOrder/index.vue
+++ b/src/views/salesManagement/returnOrder/index.vue
@@ -11,8 +11,8 @@
<el-form-item label="閿�鍞崟鍙�">
<el-input v-model="searchForm.salesContractNo" placeholder="閿�鍞崟鍙�" clearable />
</el-form-item>
- <el-form-item label="鍏宠仈鍑哄簱鍗曞彿">
- <el-input v-model="searchForm.shippingNo" placeholder="鍏宠仈鍑哄簱鍗曞彿" clearable />
+ <el-form-item label="鍏宠仈鍙戣揣鍗曞彿">
+ <el-input v-model="searchForm.shippingNo" placeholder="鍏宠仈鍙戣揣鍗曞彿" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">鎼滅储</el-button>
@@ -112,22 +112,22 @@
]);
const defaultColumns = [
- { label: "閫�璐у崟鍙�", prop: "returnNo", width: 160 },
- { label: "鍗曟嵁鐘舵��", prop: "status", width: 90, dataType: "slot", slot: "status" },
- { label: "鍒跺崟鏃堕棿", prop: "makeTime", width: 170 },
- { label: "瀹㈡埛鍚嶇О", prop: "customerName", width: 220 },
- { label: "閿�鍞崟鍙�", prop: "salesContractNo", width: 160 },
- { label: "涓氬姟鍛�", prop: "salesman", width: 120 },
- { label: "鍏宠仈鍑哄簱鍗曞彿", prop: "shippingNo", width: 170 },
- { label: "椤圭洰鍚嶇О", prop: "projectName", width: 180 },
- { label: "鍒跺崟浜�", prop: "maker", width: 120 },
+ { label: "閫�璐у崟鍙�", prop: "returnNo", minWidth: 160 },
+ { label: "鍗曟嵁鐘舵��", prop: "status", minWidth: 90, dataType: "slot", slot: "status" },
+ { label: "鍒跺崟鏃堕棿", prop: "makeTime", minWidth: 170 },
+ { label: "瀹㈡埛鍚嶇О", prop: "customerName", minWidth: 220 },
+ { label: "閿�鍞崟鍙�", prop: "salesContractNo", minWidth: 160 },
+ { label: "涓氬姟鍛�", prop: "salesman", minWidth: 120 },
+ { label: "鍏宠仈鍙戣揣鍗曞彿", prop: "shippingNo", minWidth: 170 },
+ { label: "椤圭洰鍚嶇О", prop: "projectName", minWidth: 180 },
+ { label: "鍒跺崟浜�", prop: "maker", minWidth: 120 },
{
label: "鎿嶄綔",
prop: "operation",
dataType: "action",
align: "center",
fixed: "right",
- width: 240,
+ minWidth: 240,
operation: [
{ name: "缂栬緫", disabled: (row) => row.status !== 0, type: "text", clickFun: (row) => openForm("edit", row) },
{ name: "閫�娆惧鐞�", disabled: (row) => row.status !== 0, type: "text", clickFun: (row) => handleRowHandle(row) },
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index 4e2d84e..fc2851f 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -2594,6 +2594,7 @@
瀹℃牳鎷掔粷: "瀹℃牳鎷掔粷",
瀹℃牳閫氳繃: "瀹℃牳閫氳繃",
宸插彂璐�: "宸插彂璐�",
+ 閮ㄥ垎鍙戣揣: "閮ㄥ垎鍙戣揣",
};
return statusTextMap[statusStr] || "寰呭彂璐�";
};
@@ -2625,6 +2626,7 @@
瀹℃牳鎷掔粷: "danger",
瀹℃牳閫氳繃: "success",
宸插彂璐�: "success",
+ 閮ㄥ垎鍙戣揣: "warning",
};
return typeTextMap[statusStr] || "info";
};
--
Gitblit v1.9.3