From ac8777c3df1de48c4e69a60829c0238af99a12f3 Mon Sep 17 00:00:00 2001
From: zss <zss@example.com>
Date: 星期四, 23 七月 2026 09:46:19 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_pro_河南鹤壁' into dev_pro_河南鹤壁
---
src/views/basicData/product/ProductSelectDialog.vue | 11
src/views/collaborativeApproval/rulesRegulationsManagement/index.vue | 2
multiple/assets/favicon/TDDQfavicon.ico | 0
multiple/config.json | 18
src/views/basicData/product/index.vue | 2
src/utils/documentPrint.js | 331 ++++++++++
src/api/procurementManagement/procurementLedger.js | 7
src/views/salesManagement/receiptPaymentLedger/index.vue | 27
src/views/salesManagement/salesLedger/index.vue | 598 +++++-------------
src/views/qualityManagement/metricBinding/index.vue | 179 ++++-
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue | 35
src/views/inventoryManagement/dispatchLog/Record.vue | 9
multiple/assets/favicon/JHJMfavicon.ico | 0
src/views/procurementManagement/procurementLedger/detail.vue | 8
src/views/inventoryManagement/stockManagement/Record.vue | 4
src/views/inventoryManagement/receiptManagement/Record.vue | 9
src/utils/summarizeTable.js | 21
src/views/basicData/supplierManage/components/HomeTab.vue | 43
src/views/qualityManagement/processInspection/components/formDia.vue | 46 +
src/views/salesManagement/deliveryLedger/index.vue | 23
multiple/assets/logo/JHJMLogo.png | 0
src/views/equipmentManagement/spareParts/index.vue | 27
src/views/procurementManagement/procurementReport/index.vue | 7
src/utils/numberFormat.js | 47 +
src/views/qualityManagement/finalInspection/components/formDia.vue | 47 +
multiple/assets/logo/TDDQLogo.png | 0
src/components/PIMTable/PIMTable.vue | 5
src/views/salesManagement/salesQuotation/index.vue | 16
src/views/procurementManagement/paymentLedger/index.vue | 43
src/views/procurementManagement/procurementLedger/index.vue | 199 ++++-
src/api/salesManagement/salesLedger.js | 7
src/views/reportAnalysis/reportManagement/index.vue | 54
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue | 38 +
package.json | 1
src/views/basicData/supplierManage/components/BlacklistTab.vue | 44
35 files changed, 1,234 insertions(+), 674 deletions(-)
diff --git a/multiple/assets/favicon/JHJMfavicon.ico b/multiple/assets/favicon/JHJMfavicon.ico
new file mode 100644
index 0000000..ed59d69
--- /dev/null
+++ b/multiple/assets/favicon/JHJMfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/TDDQfavicon.ico b/multiple/assets/favicon/TDDQfavicon.ico
new file mode 100644
index 0000000..78a6cf8
--- /dev/null
+++ b/multiple/assets/favicon/TDDQfavicon.ico
Binary files differ
diff --git a/multiple/assets/logo/JHJMLogo.png b/multiple/assets/logo/JHJMLogo.png
new file mode 100644
index 0000000..3b95956
--- /dev/null
+++ b/multiple/assets/logo/JHJMLogo.png
Binary files differ
diff --git a/multiple/assets/logo/TDDQLogo.png b/multiple/assets/logo/TDDQLogo.png
new file mode 100644
index 0000000..b34689f
--- /dev/null
+++ b/multiple/assets/logo/TDDQLogo.png
Binary files differ
diff --git a/multiple/config.json b/multiple/config.json
index 9cdff0b..94d369a 100644
--- a/multiple/config.json
+++ b/multiple/config.json
@@ -132,6 +132,24 @@
"logo": "logo/XSWHLogo.png",
"favicon": "favicon/XSWHfavicon.ico"
},
+ "TDDQ": {
+ "env": {
+ "VITE_APP_TITLE": "娌冲崡鍚屽痉鐢靛櫒鏈夐檺鍏徃",
+ "VITE_BASE_API": "http://localhost:9001",
+ "VITE_JAVA_API": "http://localhost:9002"
+ },
+ "logo": "logo/TDDQLogo.png",
+ "favicon": "favicon/TDDQfavicon.ico"
+ },
+ "JHJM": {
+ "env": {
+ "VITE_APP_TITLE": "楣ゅ甯傞敠姹囩簿瀵嗘満姊版湁闄愬叕鍙�",
+ "VITE_BASE_API": "http://103.189.141.42:9001",
+ "VITE_JAVA_API": "http://103.189.141.42:9002"
+ },
+ "logo": "logo/JHJMLogo.png",
+ "favicon": "favicon/JHJMfavicon.ico"
+ },
"logo": "/src/assets/logo/logo.png",
"favicon": "/public/favicon.ico"
}
\ No newline at end of file
diff --git a/package.json b/package.json
index 11fa01d..4e2b8d8 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,7 @@
"element-plus": "2.7.7",
"file-saver": "2.0.5",
"fuse.js": "6.6.2",
+ "html2canvas": "^1.4.1",
"js-beautify": "1.14.11",
"js-cookie": "3.0.5",
"jsencrypt": "3.3.2",
diff --git a/src/api/procurementManagement/procurementLedger.js b/src/api/procurementManagement/procurementLedger.js
index 5f9df05..3bdee66 100644
--- a/src/api/procurementManagement/procurementLedger.js
+++ b/src/api/procurementManagement/procurementLedger.js
@@ -122,4 +122,11 @@
method: "get",
params: id,
});
+}
+// 鑾峰彇閲囪喘鍗曟墦鍗版暟鎹�
+export function getPrintData(id) {
+ return request({
+ url: '/purchase/ledger/printData/' + id,
+ method: 'get',
+ });
}
\ No newline at end of file
diff --git a/src/api/salesManagement/salesLedger.js b/src/api/salesManagement/salesLedger.js
index 6548927..841a8a1 100644
--- a/src/api/salesManagement/salesLedger.js
+++ b/src/api/salesManagement/salesLedger.js
@@ -116,4 +116,11 @@
method: "get",
params: query,
});
+}
+// 鑾峰彇閿�鍞崟鎵撳嵃鏁版嵁
+export function getPrintData(id) {
+ return request({
+ url: '/sales/ledger/printData/' + id,
+ method: 'get',
+ });
}
\ No newline at end of file
diff --git a/src/components/PIMTable/PIMTable.vue b/src/components/PIMTable/PIMTable.vue
index 631d956..aad24fa 100644
--- a/src/components/PIMTable/PIMTable.vue
+++ b/src/components/PIMTable/PIMTable.vue
@@ -8,6 +8,7 @@
:highlight-current-row="highlightCurrentRow"
:row-class-name="rowClassName"
:row-style="rowStyle"
+ :cell-style="cellStyle"
:row-key="rowKey"
:style="tableStyle"
tooltip-effect="dark"
@@ -293,6 +294,10 @@
type: [Object, Function],
default: () => ({}),
},
+ cellStyle: {
+ type: [Object, Function],
+ default: () => ({}),
+ },
tableData: {
type: Array,
default: () => [],
diff --git a/src/utils/documentPrint.js b/src/utils/documentPrint.js
new file mode 100644
index 0000000..2db84f3
--- /dev/null
+++ b/src/utils/documentPrint.js
@@ -0,0 +1,331 @@
+import html2canvas from 'html2canvas'
+
+function esc(s) {
+ if (!s) return ''
+ return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"')
+}
+
+function fmtDate(v) {
+ if (!v) return ''
+ const d = new Date(v)
+ const y = d.getFullYear()
+ const m = String(d.getMonth() + 1).padStart(2, '0')
+ const day = String(d.getDate()).padStart(2, '0')
+ return y + '-' + m + '-' + day
+}
+
+function fmtMoney(v) {
+ if (v == null) return '0.00'
+ return Number(v).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
+}
+
+function digitUppercase(n) {
+ const digits = ['闆�', '澹�', '璐�', '鍙�', '鑲�', '浼�', '闄�', '鏌�', '鎹�', '鐜�']
+ const radices = ['', '鎷�', '浣�', '浠�', '涓�', '鎷�', '浣�', '浠�', '浜�']
+ let num = Math.abs(n)
+ let result = ''
+ const intPart = Math.floor(num)
+ const intStr = String(intPart)
+ const len = intStr.length
+ if (intPart === 0) {
+ result = '闆�'
+ } else {
+ let zeroFlag = false
+ for (let i = 0; i < len; i++) {
+ const d = parseInt(intStr[i])
+ const pos = len - 1 - i
+ if (d === 0) {
+ zeroFlag = true
+ if (pos % 4 === 0) {
+ result += radices[pos]
+ zeroFlag = false
+ }
+ } else {
+ if (zeroFlag) {
+ result += '闆�'
+ zeroFlag = false
+ }
+ result += digits[d] + radices[pos]
+ }
+ }
+ if (result.endsWith('闆�')) result = result.slice(0, -1)
+ }
+ result += '鍏�'
+ const decPart = Math.round((num - intPart) * 100)
+ if (decPart === 0) {
+ result += '鏁�'
+ } else {
+ const jiao = Math.floor(decPart / 10)
+ const fen = decPart % 10
+ if (jiao > 0) result += digits[jiao] + '瑙�'
+ if (fen > 0) result += digits[fen] + '鍒�'
+ }
+ return result
+}
+
+function coreCss() {
+ return `*{margin:0;padding:0;box-sizing:border-box}body{font-family:"Microsoft YaHei","SimSun",sans-serif;padding:30px 36px;color:#333;background:#fff}.title{text-align:center;font-size:18px;font-weight:bold;letter-spacing:6px;margin-bottom:4px}.sub{text-align:center;font-size:12px;color:#999;margin-bottom:18px}.info-top{display:flex;justify-content:space-between;font-size:13px;margin-bottom:14px;padding-bottom:10px;border-bottom:1px dashed #ccc}.info-top .left,.info-top .right{line-height:2}.info-grid{display:grid;grid-template-columns:1fr 1fr;gap:4px 36px;font-size:13px;margin-bottom:14px;padding-bottom:8px;border-bottom:1px solid #ccc}.info-grid .l{color:#666}.info-grid .v{font-weight:500}table{width:100%;border-collapse:collapse;font-size:13px;margin-bottom:14px}th,td{border:1px solid #333;padding:5px 6px;text-align:center}th{background:#eee;font-weight:500}td.r{text-align:right}.summary{text-align:right;font-size:13px;margin-bottom:16px;line-height:2.2}.summary .cn{font-weight:bold;color:#cf1322}`
+}
+
+function productRows(products) {
+ if (!products || !products.length) return ''
+ let html = ''
+ products.forEach((p, i) => {
+ const name = p.productCategory || ''
+ const spec = p.specificationModel || ''
+ html += '<tr>'
+ html += '<td>' + (i + 1) + '</td>'
+ html += '<td style="text-align:left">' + esc(name)
+ if (spec) html += '<br><span style="color:#888;font-size:12px">' + esc(spec) + '</span>'
+ html += '</td>'
+ html += '<td>' + esc(p.unit || '') + '</td>'
+ html += '<td class="r">' + (p.quantity != null ? Number(p.quantity).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : '') + '</td>'
+ html += '<td class="r">' + fmtMoney(p.taxInclusiveUnitPrice) + '</td>'
+ html += '<td class="r">' + fmtMoney(p.taxInclusiveTotalPrice) + '</td>'
+ html += '<td>' + (p.taxRate != null ? p.taxRate + '%' : '') + '</td>'
+ html += '<td>' + esc(p.invoiceType || '') + '</td>'
+ html += '</tr>'
+ })
+ return html
+}
+
+function calcTotals(products) {
+ let total = 0, totalNoTax = 0
+ if (products) {
+ products.forEach(p => {
+ if (p.taxInclusiveTotalPrice != null) total += Number(p.taxInclusiveTotalPrice)
+ if (p.taxExclusiveTotalPrice != null) totalNoTax += Number(p.taxExclusiveTotalPrice)
+ })
+ }
+ return { total, totalNoTax }
+}
+
+function buildSalesHtml(companyName, ledger, forPrint) {
+ const products = ledger.productData || []
+ const { total, totalNoTax } = calcTotals(products)
+ const toolbar = forPrint ? '<div class="toolbar"><button onclick="window.print()">鎵撳嵃 / 鍙﹀瓨涓� PDF</button></div>' : ''
+ const printCss = forPrint ? '@media print{body{padding:15px 24px}.toolbar{display:none}}' : ''
+ const printScript = forPrint ? '<script>window.onload=function(){setTimeout(function(){window.print();},300);};<\/script>' : ''
+
+ return `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8">
+<title>閿�鍞崟 - ${esc(ledger.salesContractNo)} - ${esc(companyName)}</title>
+<style>.toolbar{text-align:center;margin-bottom:16px}.toolbar button{padding:6px 20px;font-size:14px;cursor:pointer;background:#1890ff;color:#fff;border:none;border-radius:4px}.toolbar button:hover{background:#40a9ff}${coreCss()}${printCss}</style></head><body>
+${toolbar}
+<div class="title">${esc(companyName)}</div>
+<div class="sub">閿�鍞悎鍚� / 閿�鍞崟</div>
+<div class="info-top">
+ <div class="left"><div><strong>閿�鏂瑰悕绉帮細</strong>${esc(companyName)}</div></div>
+ <div class="right"><div><strong>鍚堝悓缂栧彿锛�</strong>${esc(ledger.salesContractNo)}</div><div><strong>绛捐鏃ユ湡锛�</strong>${fmtDate(ledger.executionDate)}</div></div>
+</div>
+<div class="info-grid">
+ <div><span class="l">瀹㈡埛鍚嶇О锛�</span><span class="v">${esc(ledger.customerName)}</span></div>
+ <div><span class="l">椤圭洰鍚嶇О锛�</span><span class="v">${esc(ledger.projectName)}</span></div>
+ <div><span class="l">涓氬姟鍛橈細</span><span class="v">${esc(ledger.salesman)}</span></div>
+ <div><span class="l">浠樻鏂瑰紡锛�</span><span class="v">${esc(ledger.paymentMethod)}</span></div>
+ <div><span class="l">褰曞叆鏃ユ湡锛�</span><span class="v">${fmtDate(ledger.entryDate)}</span></div>
+ <div><span class="l">浜よ揣鏃ユ湡锛�</span><span class="v">${fmtDate(ledger.deliveryDate)}</span></div>
+ ${ledger.remarks ? `<div style="grid-column:1/-1"><span class="l">澶囨敞锛�</span><span class="v">${esc(ledger.remarks)}</span></div>` : ''}
+</div>
+<table><thead><tr><th>搴忓彿</th><th>浜у搧鍚嶇О / 瑙勬牸鍨嬪彿</th><th>鍗曚綅</th><th>鏁伴噺</th><th>鍚◣鍗曚环</th><th>鍚◣鎬讳环</th><th>绋庣巼</th><th>鍙戠エ绫诲瀷</th></tr></thead><tbody>
+${productRows(products)}
+</tbody></table>
+<div class="summary">
+ <div>涓嶅惈绋庡悎璁★細<strong>${fmtMoney(totalNoTax)}</strong></div>
+ <div>鍚◣鍚堣锛堝ぇ鍐欙級锛�<span class="cn">${digitUppercase(total)}</span></div>
+ <div>鍚◣鍚堣锛堝皬鍐欙級锛�<strong>楼${fmtMoney(total)}</strong></div>
+</div>
+${printScript}
+</body></html>`
+}
+
+function buildPurchaseHtml(companyName, ledger, products, forPrint) {
+ const { total, totalNoTax } = calcTotals(products)
+ const contractAmount = ledger.contractAmount != null ? Number(ledger.contractAmount) : total
+ const toolbar = forPrint ? '<div class="toolbar"><button onclick="window.print()">鎵撳嵃 / 鍙﹀瓨涓� PDF</button></div>' : ''
+ const printCss = forPrint ? '@media print{body{padding:15px 24px}.toolbar{display:none}}' : ''
+ const printScript = forPrint ? '<script>window.onload=function(){setTimeout(function(){window.print();},300);};<\/script>' : ''
+
+ return `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8">
+<title>閲囪喘鍗� - ${esc(ledger.purchaseContractNumber)} - ${esc(companyName)}</title>
+<style>.toolbar{text-align:center;margin-bottom:16px}.toolbar button{padding:6px 20px;font-size:14px;cursor:pointer;background:#1890ff;color:#fff;border:none;border-radius:4px}.toolbar button:hover{background:#40a9ff}${coreCss()}${printCss}</style></head><body>
+${toolbar}
+<div class="title">${esc(companyName)}</div>
+<div class="info-top">
+ <div class="left"><div><strong>璐柟鍚嶇О锛�</strong>${esc(companyName)}</div></div>
+ <div class="right"><div><strong>鍚堝悓缂栧彿锛�</strong>${esc(ledger.purchaseContractNumber)}</div><div><strong>绛捐鏃ユ湡锛�</strong>${fmtDate(ledger.executionDate)}</div></div>
+</div>
+<div class="info-grid">
+ <div><span class="l">渚涘簲鍟嗗悕绉帮細</span><span class="v">${esc(ledger.supplierName)}</span></div>
+ <div><span class="l">椤圭洰鍚嶇О锛�</span><span class="v">${esc(ledger.projectName)}</span></div>
+ <div><span class="l">褰曞叆浜猴細</span><span class="v">${esc(ledger.recorderName)}</span></div>
+ <div><span class="l">浠樻鏂瑰紡锛�</span><span class="v">${esc(ledger.paymentMethod)}</span></div>
+ <div><span class="l">褰曞叆鏃ユ湡锛�</span><span class="v">${fmtDate(ledger.entryDate)}</span></div>
+ ${ledger.salesContractNo ? `<div><span class="l">鍏宠仈閿�鍞悎鍚屽彿锛�</span><span class="v">${esc(ledger.salesContractNo)}</span></div>` : ''}
+ ${ledger.remarks ? `<div style="grid-column:1/-1"><span class="l">澶囨敞锛�</span><span class="v">${esc(ledger.remarks)}</span></div>` : ''}
+</div>
+<table><thead><tr><th>搴忓彿</th><th>浜у搧鍚嶇О / 瑙勬牸鍨嬪彿</th><th>鍗曚綅</th><th>鏁伴噺</th><th>鍚◣鍗曚环</th><th>鍚◣鎬讳环</th><th>绋庣巼</th><th>鍙戠エ绫诲瀷</th></tr></thead><tbody>
+${productRows(products)}
+</tbody></table>
+<div class="summary">
+ <div>涓嶅惈绋庡悎璁★細<strong>${fmtMoney(totalNoTax)}</strong></div>
+ <div>鍚◣鍚堣锛堝ぇ鍐欙級锛�<span class="cn">${digitUppercase(total)}</span></div>
+ <div>鍚◣鍚堣锛堝皬鍐欙級锛�<strong>楼${fmtMoney(total)}</strong></div>
+ <div>鍚堝悓閲戦锛堝ぇ鍐欙級锛�<span class="cn">${digitUppercase(contractAmount)}</span></div>
+ <div>鍚堝悓閲戦锛堝皬鍐欙級锛�<strong>楼${fmtMoney(contractAmount)}</strong></div>
+</div>
+${printScript}
+</body></html>`
+}
+
+export function buildSalesDocument(companyName, ledger) {
+ return buildSalesHtml(companyName, ledger, false)
+}
+
+export function buildPurchaseDocument(companyName, ledger, products) {
+ return buildPurchaseHtml(companyName, ledger, products, false)
+}
+
+function buildSalesPrintHtml(companyName, ledger) {
+ return buildSalesHtml(companyName, ledger, true)
+}
+
+function buildPurchasePrintHtml(companyName, ledger, products) {
+ return buildPurchaseHtml(companyName, ledger, products, true)
+}
+
+export function openPrintWindow(html) {
+ const w = window.open('', '_blank', 'width=900,height=700')
+ if (!w) return
+ w.document.write(html)
+ w.document.close()
+}
+
+export async function downloadAsJpg(html, filename) {
+ const iframe = document.createElement('iframe')
+ iframe.style.position = 'fixed'
+ iframe.style.left = '0'
+ iframe.style.top = '0'
+ iframe.style.width = '900px'
+ iframe.style.height = '600px'
+ iframe.style.opacity = '0'
+ iframe.style.pointerEvents = 'none'
+ iframe.style.zIndex = '99999'
+ document.body.appendChild(iframe)
+
+ return new Promise((resolve, reject) => {
+ const iframeDoc = iframe.contentDocument || iframe.contentWindow.document
+ iframeDoc.open()
+ iframeDoc.write(html)
+ iframeDoc.close()
+
+ const doCapture = async () => {
+ try {
+ const body = iframeDoc.body
+ iframe.style.height = Math.max(body.scrollHeight, 600) + 'px'
+ await new Promise(r => setTimeout(r, 100))
+ const canvas = await html2canvas(body, {
+ scale: 2,
+ useCORS: true,
+ backgroundColor: '#ffffff',
+ windowWidth: 900
+ })
+ document.body.removeChild(iframe)
+ canvas.toBlob(blob => {
+ const url = URL.createObjectURL(blob)
+ const a = document.createElement('a')
+ a.href = url
+ a.download = filename
+ a.click()
+ URL.revokeObjectURL(url)
+ resolve()
+ }, 'image/jpeg', 0.95)
+ } catch (e) {
+ document.body.removeChild(iframe)
+ reject(e)
+ }
+ }
+
+ iframe.onload = () => setTimeout(doCapture, 300)
+ setTimeout(doCapture, 1000)
+ })
+}
+
+export function downloadSalesJpg(companyName, ledger, filename) {
+ const html = buildSalesHtml(companyName, ledger, false)
+ return downloadAsJpg(html, filename)
+}
+
+export function downloadPurchaseJpg(companyName, ledger, products, filename) {
+ const html = buildPurchaseHtml(companyName, ledger, products, false)
+ return downloadAsJpg(html, filename)
+}
+
+export function printSales(companyName, ledger) {
+ const html = buildSalesPrintHtml(companyName, ledger)
+ openPrintWindow(html)
+}
+
+export function printPurchase(companyName, ledger, products) {
+ const html = buildPurchasePrintHtml(companyName, ledger, products)
+ openPrintWindow(html)
+}
+
+export function printSalesMulti(companyName, orders) {
+ let bodies = ''
+ orders.forEach((ledger, i) => {
+ const html = buildSalesHtml(companyName, ledger, true)
+ const bodyMatch = html.match(/<body>([\s\S]*)<\/body>/)
+ if (bodyMatch) {
+ const body = bodyMatch[1].replace(/<script>[\s\S]*?<\/script>/g, '')
+ bodies += '<div class="print-page' + (i < orders.length - 1 ? ' page-break' : '') + '">' + body + '</div>'
+ }
+ })
+ const combined = `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8">
+<title>閿�鍞崟 - ${esc(companyName)}</title>
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:"Microsoft YaHei","SimSun",sans-serif;padding:20px 36px;color:#333;background:#fff}
+.toolbar{text-align:center;margin-bottom:20px}
+.toolbar button{padding:6px 24px;font-size:14px;cursor:pointer;background:#1890ff;color:#fff;border:none;border-radius:4px}
+.toolbar button:hover{background:#40a9ff}
+${coreCss()}
+.print-page{page-break-inside:avoid}
+.page-break{page-break-after:always}
+@media print{body{padding:15px 24px}.toolbar{display:none}}
+</style></head><body>
+<div class="toolbar"><button onclick="window.print()">鎵撳嵃鍏ㄩ儴 (鍏�${orders.length}浠�)</button></div>
+${bodies}
+<script>window.onload=function(){setTimeout(function(){window.print();},300);};<\/script>
+</body></html>`
+ openPrintWindow(combined)
+}
+
+export function printPurchaseMulti(companyName, orders) {
+ let bodies = ''
+ orders.forEach((item, i) => {
+ const html = buildPurchaseHtml(companyName, item.ledger, item.products, true)
+ const bodyMatch = html.match(/<body>([\s\S]*)<\/body>/)
+ if (bodyMatch) {
+ const body = bodyMatch[1].replace(/<script>[\s\S]*?<\/script>/g, '')
+ bodies += '<div class="print-page' + (i < orders.length - 1 ? ' page-break' : '') + '">' + body + '</div>'
+ }
+ })
+ const combined = `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8">
+<title>閲囪喘鍗� - ${esc(companyName)}</title>
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:"Microsoft YaHei","SimSun",sans-serif;padding:20px 36px;color:#333;background:#fff}
+.toolbar{text-align:center;margin-bottom:20px}
+.toolbar button{padding:6px 24px;font-size:14px;cursor:pointer;background:#1890ff;color:#fff;border:none;border-radius:4px}
+.toolbar button:hover{background:#40a9ff}
+${coreCss()}
+.print-page{page-break-inside:avoid}
+.page-break{page-break-after:always}
+@media print{body{padding:15px 24px}.toolbar{display:none}}
+</style></head><body>
+<div class="toolbar"><button onclick="window.print()">鎵撳嵃鍏ㄩ儴 (鍏�${orders.length}浠�)</button></div>
+${bodies}
+<script>window.onload=function(){setTimeout(function(){window.print();},300);};<\/script>
+</body></html>`
+ openPrintWindow(combined)
+}
diff --git a/src/utils/numberFormat.js b/src/utils/numberFormat.js
new file mode 100644
index 0000000..50175f0
--- /dev/null
+++ b/src/utils/numberFormat.js
@@ -0,0 +1,47 @@
+/** 閲戦绫诲瓧娈甸粯璁ゆ渶澶у皬鏁颁綅鏁� */
+export const AMOUNT_DECIMAL_SCALE = 6
+
+/**
+ * 鏍煎紡鍖栨暟瀛楋細鏈�澶氫繚鐣� scale 浣嶅皬鏁帮紝骞跺幓闄ゆ湯灏惧浣欑殑 0
+ */
+export function formatDecimal(value, scale = AMOUNT_DECIMAL_SCALE, fallback = '0') {
+ if (value === null || value === undefined || value === '') {
+ return fallback
+ }
+ const num = Number(value)
+ if (Number.isNaN(num)) {
+ return fallback
+ }
+ return parseFloat(num.toFixed(scale)).toString()
+}
+
+/** 甯﹁揣甯佺鍙风殑閲戦灞曠ず */
+export function formatCurrency(value, scale = AMOUNT_DECIMAL_SCALE) {
+ return `楼${formatDecimal(value, scale)}`
+}
+
+/** el-table-column formatter */
+export function tableAmountFormatter(row, column, cellValue) {
+ return formatDecimal(cellValue)
+}
+
+/** 璁$畻鍚庝繚鐣欐寚瀹氫綅灏忔暟 */
+export function roundAmount(value, scale = AMOUNT_DECIMAL_SCALE) {
+ if (value === null || value === undefined || value === '') {
+ return 0
+ }
+ const num = Number(value)
+ if (Number.isNaN(num)) {
+ return 0
+ }
+ return parseFloat(num.toFixed(scale))
+}
+
+/** 鏋勫缓 summarizeTable 閲戦鍒楁牸寮忛厤缃� */
+export function buildAmountSummaryFormat(fields, extraFormat = {}) {
+ const format = { ...extraFormat }
+ fields.forEach(field => {
+ format[field] = { decimalPlaces: AMOUNT_DECIMAL_SCALE }
+ })
+ return format
+}
diff --git a/src/utils/summarizeTable.js b/src/utils/summarizeTable.js
index 1ad480d..3602523 100644
--- a/src/utils/summarizeTable.js
+++ b/src/utils/summarizeTable.js
@@ -1,3 +1,5 @@
+import { formatDecimal, AMOUNT_DECIMAL_SCALE } from './numberFormat'
+
/**
* 閫氱敤鐨勮〃鏍煎悎璁℃柟娉�
* @param {Object} param - 鍖呭惈琛ㄦ牸鍒楅厤缃拰鏁版嵁婧愮殑瀵硅薄
@@ -26,28 +28,35 @@
// 濡傛灉鎸囧畾浜嗕笉闇�瑕佷繚鐣欏皬鏁帮紝鍒欑洿鎺ヨ浆鎹负鏁存暟
sums[index] = Math.round(sum).toString();
} else {
- // 榛樿淇濈暀涓や綅灏忔暟
- sums[index] = parseFloat(sum).toFixed(
+ sums[index] = formatDecimal(
+ sum,
specialFormat[prop]?.decimalPlaces ?? 2
);
}
} else {
- sums[index] = "";
+ sums[index] = '';
}
} else {
- sums[index] = "";
+ sums[index] = '';
}
});
return sums;
};
+
// 涓嶅惈绋庢�讳环璁$畻
const calculateTaxExclusiveTotalPrice = (taxInclusiveTotalPrice, taxRate) => {
const taxRateDecimal = taxRate / 100;
- return (taxInclusiveTotalPrice / (1 + taxRateDecimal)).toFixed(2);
+ return formatDecimal(
+ Number(taxInclusiveTotalPrice) / (1 + taxRateDecimal),
+ AMOUNT_DECIMAL_SCALE
+ );
};
// 鍚◣鎬讳环璁$畻
const calculateTaxIncludeTotalPrice = (taxInclusiveUnitPrice, quantity) => {
- return (taxInclusiveUnitPrice * quantity).toFixed(2);
+ return formatDecimal(
+ Number(taxInclusiveUnitPrice) * Number(quantity),
+ AMOUNT_DECIMAL_SCALE
+ );
};
// 瀵煎嚭鍑芥暟渚涘叾浠栨枃浠朵娇鐢�
export {
diff --git a/src/views/basicData/product/ProductSelectDialog.vue b/src/views/basicData/product/ProductSelectDialog.vue
index ad27baa..590f8ca 100644
--- a/src/views/basicData/product/ProductSelectDialog.vue
+++ b/src/views/basicData/product/ProductSelectDialog.vue
@@ -2,11 +2,11 @@
<el-dialog v-model="visible" title="閫夋嫨浜у搧" width="900px" destroy-on-close :close-on-click-modal="false">
<el-form :inline="true" :model="query" class="mb-2">
<el-form-item label="浜у搧鍚嶇О">
- <el-input v-model="query.productName" placeholder="杈撳叆浜у搧鍚嶇О" clearable @keyup.enter="onSearch" />
+ <el-input v-model="query.productName" placeholder="杈撳叆浜у搧鍚嶇О" clearable @keyup.enter="onSearch" style="width: 200px" />
</el-form-item>
<el-form-item label="浜у搧鍨嬪彿">
- <el-input v-model="query.model" placeholder="杈撳叆浜у搧鍨嬪彿" clearable @keyup.enter="onSearch" />
+ <el-input v-model="query.model" placeholder="杈撳叆浜у搧鍨嬪彿" clearable @keyup.enter="onSearch" style="width: 200px" />
</el-form-item>
<el-form-item>
@@ -20,9 +20,10 @@
@selection-change="handleSelectionChange" @select="handleSelect">
<el-table-column type="selection" width="55" />
<el-table-column type="index" label="搴忓彿" width="60" />
- <el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="160" />
- <el-table-column prop="model" label="浜у搧鍨嬪彿" min-width="200" />
- <el-table-column prop="unit" label="鍗曚綅" min-width="160" />
+ <el-table-column prop="topProductName" label="浜у搧澶х被" min-width="120" />
+ <el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="140" />
+ <el-table-column prop="model" label="浜у搧鍨嬪彿" min-width="180" />
+ <el-table-column prop="unit" label="鍗曚綅" min-width="100" />
</el-table>
<div class="mt-3 flex justify-end">
diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
index cdc8265..15f817d 100644
--- a/src/views/basicData/product/index.vue
+++ b/src/views/basicData/product/index.vue
@@ -335,7 +335,7 @@
rules: {
productName: [
{ required: true, message: "璇疯緭鍏�", trigger: "blur" },
- { max: 20, message: "浜у搧鍚嶇О涓嶈兘瓒呰繃20涓瓧绗�", trigger: "blur" },
+ { max: 50, message: "浜у搧鍚嶇О涓嶈兘瓒呰繃50涓瓧绗�", trigger: "blur" },
],
},
modelForm: {
diff --git a/src/views/basicData/supplierManage/components/BlacklistTab.vue b/src/views/basicData/supplierManage/components/BlacklistTab.vue
index 952d9b7..9e5a75f 100644
--- a/src/views/basicData/supplierManage/components/BlacklistTab.vue
+++ b/src/views/basicData/supplierManage/components/BlacklistTab.vue
@@ -96,7 +96,7 @@
</el-col>
</el-row>
<el-row :gutter="30">
- <el-col :span="12">
+ <!-- <el-col :span="12">
<el-form-item label="渚涘簲鍟嗙被鍨嬶細"
prop="supplierType">
<el-select v-model="form.supplierType"
@@ -112,7 +112,7 @@
value="涓�" />
</el-select>
</el-form-item>
- </el-col>
+ </el-col> -->
<el-col :span="12">
<el-form-item label="鏄惁鐧藉悕鍗曪細"
prop="isWhite">
@@ -203,22 +203,22 @@
{
label: "渚涘簲鍟嗗悕绉�",
prop: "supplierName",
- width: 250,
+ // width: 250,
},
- {
- label: "渚涘簲鍟嗙被鍨�",
- prop: "supplierType",
- width: 120,
- },
+ // {
+ // label: "渚涘簲鍟嗙被鍨�",
+ // prop: "supplierType",
+ // width: 120,
+ // },
{
label: "绾崇◣浜鸿瘑鍒彿",
prop: "taxpayerIdentificationNum",
- width: 230,
+ // width: 230,
},
{
label: "鍏徃鍦板潃",
prop: "companyAddress",
- width: 220,
+ // width: 300,
},
{
label: "缁存姢浜�",
@@ -228,7 +228,7 @@
{
label: "缁存姢鏃堕棿",
prop: "maintainTime",
- width: 100,
+ // width: 100,
},
{
dataType: "action",
@@ -244,14 +244,14 @@
openForm("edit", row);
},
},
- {
- //璧勮川闄勪欢
- name: "璧勮川鏂囦欢",
- type: "text",
- clickFun: row => {
- openFileDialog(row);
- },
- },
+ // {
+ // //璧勮川闄勪欢
+ // name: "璧勮川鏂囦欢",
+ // type: "text",
+ // clickFun: row => {
+ // openFileDialog(row);
+ // },
+ // },
],
},
]);
@@ -290,9 +290,9 @@
companyAddress: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
maintainUserId: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
maintainTime: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
- supplierType: [
- { required: true, message: "璇烽�夋嫨渚涘簲鍟嗙被鍨�", trigger: "change" },
- ],
+ // supplierType: [
+ // { required: true, message: "璇烽�夋嫨渚涘簲鍟嗙被鍨�", trigger: "change" },
+ // ],
},
});
const { searchForm, form, rules } = toRefs(data);
diff --git a/src/views/basicData/supplierManage/components/HomeTab.vue b/src/views/basicData/supplierManage/components/HomeTab.vue
index 7edf87b..2c78f95 100644
--- a/src/views/basicData/supplierManage/components/HomeTab.vue
+++ b/src/views/basicData/supplierManage/components/HomeTab.vue
@@ -102,7 +102,7 @@
</el-col>
</el-row>
<el-row :gutter="30">
- <el-col :span="12">
+ <!-- <el-col :span="12">
<el-form-item label="渚涘簲鍟嗙被鍨嬶細"
prop="supplierType">
<el-select v-model="form.supplierType"
@@ -118,7 +118,7 @@
value="涓�" />
</el-select>
</el-form-item>
- </el-col>
+ </el-col> -->
<el-col :span="12">
<el-form-item label="鏄惁鐧藉悕鍗曪細"
prop="isWhite">
@@ -209,26 +209,27 @@
{
label: "渚涘簲鍟嗗悕绉�",
prop: "supplierName",
- width: 250,
+ // width: 250,
},
- {
- label: "渚涘簲鍟嗙被鍨�",
- prop: "supplierType",
- width: 120,
- },
+ // {
+ // label: "渚涘簲鍟嗙被鍨�",
+ // prop: "supplierType",
+ // width: 120,
+ // },
{
label: "绾崇◣浜鸿瘑鍒彿",
prop: "taxpayerIdentificationNum",
- width: 230,
+ // width: 230,
},
{
label: "鍏徃鍦板潃",
prop: "companyAddress",
- width: 220,
+ // width: 220,
},
{
label: "缁存姢浜�",
prop: "maintainUserName",
+ // width: 220,
},
{
@@ -250,14 +251,14 @@
openForm("edit", row);
},
},
- {
- //璧勮川闄勪欢
- name: "璧勮川鏂囦欢",
- type: "text",
- clickFun: row => {
- openFileDialog(row);
- },
- },
+ // {
+ // //璧勮川闄勪欢
+ // name: "璧勮川鏂囦欢",
+ // type: "text",
+ // clickFun: row => {
+ // openFileDialog(row);
+ // },
+ // },
],
},
]);
@@ -296,9 +297,9 @@
companyAddress: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
maintainUserId: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
maintainTime: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
- supplierType: [
- { required: true, message: "璇烽�夋嫨渚涘簲鍟嗙被鍨�", trigger: "change" },
- ],
+ // supplierType: [
+ // { required: true, message: "璇烽�夋嫨渚涘簲鍟嗙被鍨�", trigger: "change" },
+ // ],
},
});
const { searchForm, form, rules } = toRefs(data);
diff --git a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
index 7c7524f..e4cc4c0 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
@@ -22,14 +22,10 @@
<el-row>
<el-col :span="24">
<el-form-item label="鐢宠閮ㄩ棬锛�">
- <el-select disabled
- v-model="form.approveDeptId"
- placeholder="閫夋嫨閮ㄩ棬">
- <el-option v-for="user in productOptions"
- :key="user.deptId"
- :label="user.deptName"
- :value="user.deptId" />
- </el-select>
+ <el-input v-model="form.approveDeptName"
+ placeholder=""
+ clearable
+ disabled />
</el-form-item>
</el-col>
</el-row>
@@ -42,6 +38,18 @@
clearable
type="textarea"
disabled />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row v-if="Number(props.approveType) === 4">
+ <el-col :span="24">
+ <el-form-item label="鎶ラ攢閲戦锛�">
+ <el-input-number v-model="form.price"
+ disabled
+ :min="0"
+ :precision="2"
+ style="width: 100%"
+ placeholder="" />
</el-form-item>
</el-col>
</el-row>
@@ -75,7 +83,7 @@
<el-descriptions-item label="鎶ヤ环鎬婚"
:span="2">
<span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
- 楼{{ Number(currentQuotation.totalAmount ?? 0).toFixed(2) }}
+ {{ formatCurrency(currentQuotation.totalAmount) }}
</span>
</el-descriptions-item>
</el-descriptions>
@@ -92,7 +100,7 @@
label="鍗曚綅" />
<el-table-column prop="unitPrice"
label="鍗曚环">
- <template #default="scope">楼{{ Number(scope.row.unitPrice ?? 0).toFixed(2) }}</template>
+ <template #default="scope">{{ formatCurrency(scope.row.unitPrice) }}</template>
</el-table-column>
</el-table>
</div>
@@ -135,7 +143,7 @@
<el-descriptions-item label="鍚堝悓閲戦"
:span="2">
<span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
- 楼{{ Number(currentPurchase.contractAmount ?? 0).toFixed(2) }}
+ {{ formatCurrency(currentPurchase.contractAmount) }}
</span>
</el-descriptions-item>
</el-descriptions>
@@ -154,11 +162,11 @@
label="鏁伴噺" />
<el-table-column prop="taxInclusiveUnitPrice"
label="鍚◣鍗曚环">
- <template #default="scope">楼{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template>
+ <template #default="scope">{{ formatCurrency(scope.row.taxInclusiveUnitPrice) }}</template>
</el-table-column>
<el-table-column prop="taxInclusiveTotalPrice"
label="鍚◣鎬讳环">
- <template #default="scope">楼{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template>
+ <template #default="scope">{{ formatCurrency(scope.row.taxInclusiveTotalPrice) }}</template>
</el-table-column>
</el-table>
</div>
@@ -332,6 +340,7 @@
import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js";
import { getDeliveryDetailByShippingNo } from "@/api/salesManagement/deliveryLedger.js";
import ImagePreview from "@/components/AttachmentPreview/image/index.vue";
+ import { formatCurrency } from "@/utils/numberFormat";
const emit = defineEmits(["close"]);
const { proxy } = getCurrentInstance();
diff --git a/src/views/collaborativeApproval/rulesRegulationsManagement/index.vue b/src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
index f7ba9d9..edf045c 100644
--- a/src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
+++ b/src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
@@ -318,7 +318,7 @@
formatData: (v) => (v === "active" ? "鐢熸晥涓�" : "宸插簾姝�"),
formatType: (v) => (v === "active" ? "success" : "info"),
},
- { label: "宸茶浜烘暟", prop: "readCount", width: 100 },
+ // { label: "宸茶浜烘暟", prop: "readCount", width: 100 },
{
dataType: "action",
label: "鎿嶄綔",
diff --git a/src/views/equipmentManagement/spareParts/index.vue b/src/views/equipmentManagement/spareParts/index.vue
index 8abe35d..a1a4026 100644
--- a/src/views/equipmentManagement/spareParts/index.vue
+++ b/src/views/equipmentManagement/spareParts/index.vue
@@ -29,6 +29,7 @@
:tableLoading="loading"
:page="pagination"
:isShowPagination="true"
+ :row-class-name="rowClassName"
@pagination="handleSizeChange"
>
<template #status="{ row }">
@@ -95,7 +96,7 @@
</el-dialog>
</el-tab-pane>
- <el-tab-pane label="澶囦欢棰嗙敤璁板綍" name="usage">
+ <el-tab-pane label="澶囦欢浣跨敤璁板綍" name="usage">
<div class="search_form">
<el-form :inline="true" :model="usageQuery" class="search-form">
<el-form-item label="澶囦欢鍚嶇О">
@@ -521,9 +522,17 @@
onMounted(() => {
fetchListData();
});
+
+// 鏍规嵁鏁伴噺杩涜鍒ゆ柇鑳屾櫙棰滆壊
+const rowClassName = ({ row }) => {
+ const num = Number(row.quantity);
+ if (num <= 1) return 'row-qty-low';
+ if (num >= 8) return 'row-qty-high';
+ return 'row-qty-mid';
+};
</script>
-<style scoped>
+<style>
.spare-part-category {
padding: 20px;
}
@@ -547,8 +556,17 @@
font-weight: 600;
}
-.el-table__row:hover > td {
- background-color: #fafafa;
+.el-table .row-qty-low td.el-table__cell,
+.el-table .row-qty-low:hover > td.el-table__cell {
+ background-color: #fde8e8 !important;
+}
+.el-table .row-qty-mid td.el-table__cell,
+.el-table .row-qty-mid:hover > td.el-table__cell {
+ background-color: #f0f4f8 !important;
+}
+.el-table .row-qty-high td.el-table__cell,
+.el-table .row-qty-high:hover > td.el-table__cell {
+ background-color: #e8f5e9 !important;
}
/* 鎸夐挳缁勬牱寮� */
@@ -567,4 +585,5 @@
font-size: 12px;
margin-right: 4px;
}
+
</style>
\ No newline at end of file
diff --git a/src/views/inventoryManagement/dispatchLog/Record.vue b/src/views/inventoryManagement/dispatchLog/Record.vue
index bb5c5c1..c7d53ab 100644
--- a/src/views/inventoryManagement/dispatchLog/Record.vue
+++ b/src/views/inventoryManagement/dispatchLog/Record.vue
@@ -102,9 +102,13 @@
<el-table-column
label="鍑哄簱鏃ユ湡"
prop="createTime"
- width="180"
+ width="120"
show-overflow-tooltip
- />
+ >
+ <template #default="scope">
+ <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
<el-table-column
label="浜у搧澶х被"
prop="productName"
@@ -167,6 +171,7 @@
findAllQualifiedStockOutRecordTypeOptions,
findAllUnQualifiedStockOutRecordTypeOptions,
} from "@/api/basicData/enum.js";
+import { parseTime } from "@/utils/ruoyi";
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
diff --git a/src/views/inventoryManagement/receiptManagement/Record.vue b/src/views/inventoryManagement/receiptManagement/Record.vue
index f66d970..2fe86a2 100644
--- a/src/views/inventoryManagement/receiptManagement/Record.vue
+++ b/src/views/inventoryManagement/receiptManagement/Record.vue
@@ -106,8 +106,12 @@
show-overflow-tooltip/>
<el-table-column label="鍏ュ簱鏃堕棿"
prop="createTime"
- width="160"
- show-overflow-tooltip/>
+ width="120"
+ show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
<el-table-column label="浜у搧澶х被"
prop="productName"
show-overflow-tooltip/>
@@ -185,6 +189,7 @@
findAllQualifiedStockInRecordTypeOptions,
// findAllUnQualifiedStockInRecordTypeOptions,
} from "@/api/basicData/enum.js";
+import { parseTime } from "@/utils/ruoyi";
const {proxy} = getCurrentInstance();
diff --git a/src/views/inventoryManagement/stockManagement/Record.vue b/src/views/inventoryManagement/stockManagement/Record.vue
index d871952..0f3c79c 100644
--- a/src/views/inventoryManagement/stockManagement/Record.vue
+++ b/src/views/inventoryManagement/stockManagement/Record.vue
@@ -104,11 +104,11 @@
prop="unQualifiedLockedQuantity"
show-overflow-tooltip
/> -->
- <el-table-column
+<!-- <el-table-column
label="搴撳瓨棰勮鏁伴噺"
prop="warnNum"
show-overflow-tooltip
- />
+ />-->
<el-table-column label="澶囨敞" prop="remark" show-overflow-tooltip />
<el-table-column
label="鏈�杩戞洿鏂版椂闂�"
diff --git a/src/views/procurementManagement/paymentLedger/index.vue b/src/views/procurementManagement/paymentLedger/index.vue
index ae2c30b..b913032 100644
--- a/src/views/procurementManagement/paymentLedger/index.vue
+++ b/src/views/procurementManagement/paymentLedger/index.vue
@@ -79,7 +79,7 @@
@pagination="sonPaginationSearch">
<template #payableAmountSlot="{ row }">
<el-text type="danger">
- {{ parseFloat(row.unshippedAmount).toFixed(2) }}
+ {{ formatDecimal(row.unshippedAmount) }}
</el-text>
</template>
</PIMTable>
@@ -90,13 +90,14 @@
</template>
<script setup>
- import { ref, toRefs } from "vue";
+ import { ref, toRefs, reactive, getCurrentInstance } from "vue";
import { Search } from "@element-plus/icons-vue";
import {
paymentLedgerList,
paymentRecordList,
} from "@/api/procurementManagement/paymentLedger.js";
import Pagination from "../../../components/PIMTable/Pagination.vue";
+ import { tableAmountFormatter, formatDecimal, buildAmountSummaryFormat } from "@/utils/numberFormat";
const tableData = ref([]);
const tableLoading = ref(false);
@@ -140,17 +141,13 @@
label: "鍚堝悓閲戦(鍏�)",
prop: "contractAmount",
width: 200,
- formatData: params => {
- return params ? parseFloat(params).toFixed(2) : 0;
- },
+ formatData: params => formatDecimal(params),
},
{
label: "宸插叆搴撻噾棰�(鍏�)",
prop: "shippedAmount",
width: 200,
- formatData: params => {
- return params ? parseFloat(params).toFixed(2) : 0;
- },
+ formatData: params => formatDecimal(params),
},
{
label: "鏈叆搴撻噾棰�(鍏�)",
@@ -171,10 +168,13 @@
return proxy.summarizeTable(
param,
["contractAmounts", "shippedAmount", "unshippedAmount"],
- {
- ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- }
+ buildAmountSummaryFormat(
+ ["contractAmounts", "shippedAmount", "unshippedAmount"],
+ {
+ ticketsNum: { noDecimal: true },
+ futureTickets: { noDecimal: true },
+ }
+ )
);
};
// 瀛愯〃鍚堣鏂规硶
@@ -182,10 +182,13 @@
let summarizeTable = proxy.summarizeTable(
param,
["contractAmount", "shippedAmount", "unshippedAmount"],
- {
- ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- }
+ buildAmountSummaryFormat(
+ ["contractAmount", "shippedAmount", "unshippedAmount"],
+ {
+ ticketsNum: { noDecimal: true },
+ futureTickets: { noDecimal: true },
+ }
+ )
);
return summarizeTable;
};
@@ -257,13 +260,7 @@
sonPage.size = pagination.limit;
getPaymenRecordtList(currentSupplierId.value);
};
- const formattedNumber = (row, column, cellValue) => {
- if (column.property !== "supplierName") {
- return parseFloat(cellValue).toFixed(2);
- } else {
- return cellValue;
- }
- };
+ const formattedNumber = tableAmountFormatter;
getList();
</script>
diff --git a/src/views/procurementManagement/procurementLedger/detail.vue b/src/views/procurementManagement/procurementLedger/detail.vue
index 37b7fdb..80aa42b 100644
--- a/src/views/procurementManagement/procurementLedger/detail.vue
+++ b/src/views/procurementManagement/procurementLedger/detail.vue
@@ -127,6 +127,7 @@
import FormDialog from "@/components/Dialog/FormDialog.vue"
import filePreview from '@/components/filePreview/index.vue'
import { getPurchaseById } from "@/api/procurementManagement/procurementLedger"
+import { tableAmountFormatter } from '@/utils/numberFormat'
const visible = ref(false)
// 鏄惁鏄剧ず閿�鍞悎鍚屽彿缁戝畾
@@ -157,12 +158,7 @@
fileList.value = []
}
-const formattedNumber = (row, column, cellValue) => {
- if (cellValue != null && !isNaN(cellValue)) {
- return Number(cellValue).toFixed(2)
- }
- return cellValue
-}
+const formattedNumber = tableAmountFormatter
const sumTaxInclusiveUnitPrice = computed(() => {
return productData.value.reduce((sum, item) => {
diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue
index e512edb..e2d340b 100644
--- a/src/views/procurementManagement/procurementLedger/index.vue
+++ b/src/views/procurementManagement/procurementLedger/index.vue
@@ -45,6 +45,7 @@
<el-button @click="handleOut">瀵煎嚭</el-button>
<el-button type="danger" plain @click="handleDelete">鍒犻櫎
</el-button>
+ <el-button type="warning" plain @click="handlePrint">鎵撳嵃鍗曟嵁</el-button>
</div>
<el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
:expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary :summary-method="summarizeMainTable"
@@ -100,14 +101,14 @@
<el-table-column label="褰曞叆浜�" prop="recorderName" width="120" show-overflow-tooltip />
<el-table-column label="褰曞叆鏃ユ湡" prop="entryDate" width="100" show-overflow-tooltip />
<el-table-column label="澶囨敞" prop="remarks" width="200" show-overflow-tooltip />
- <el-table-column fixed="right" label="鎿嶄綔" width="180" align="center">
+ <el-table-column fixed="right" label="鎿嶄綔" width="220" align="center">
<template #default="scope">
<el-button link type="primary" @click="openForm('detail', scope.row)">璇︽儏
</el-button>
<el-button link type="primary" @click="openForm('edit', scope.row)"
:disabled="scope.row.stockInStatus === '瀹屽叏鍏ュ簱'">缂栬緫
</el-button>
- <el-button link type="primary" @click="openFileDialog(scope.row)">闄勪欢</el-button>
+ <el-button link type="primary" @click="downloadOrder(scope.row.id)">涓嬭浇</el-button>
</template>
</el-table-column>
</el-table>
@@ -161,7 +162,7 @@
<el-row :gutter="30">
<el-col :span="12">
<el-form-item label="褰曞叆浜猴細" prop="recorderId">
- <el-select v-model="form.recorderId" placeholder="璇烽�夋嫨" clearable filterable>
+ <el-select v-model="form.recorderId" placeholder="璇烽�夋嫨" clearable filterable disabled>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
@@ -208,7 +209,7 @@
<el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
<el-table-column label="鍗曚綅" prop="unit" width="70" />
<el-table-column label="鏁伴噺" prop="quantity" width="70" />
- <el-table-column label="搴撳瓨棰勮鏁伴噺" prop="warnNum" width="120" show-overflow-tooltip />
+<!-- <el-table-column label="搴撳瓨棰勮鏁伴噺" prop="warnNum" width="120" show-overflow-tooltip />-->
<el-table-column label="绋庣巼(%)" prop="taxRate" width="80" />
<el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" width="150" />
<el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="150" />
@@ -276,20 +277,22 @@
@cancel="closeProductDia">
<el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef">
<el-row :gutter="30">
- <el-col :span="24">
- <el-form-item label="浜у搧澶х被锛�" prop="productId">
- <el-tree-select v-model="productForm.productId" placeholder="璇烽�夋嫨" clearable filterable check-strictly
- @change="getModels" :data="productOptions" :render-after-expand="false" style="width: 100%" />
+ <el-col :span="12">
+ <el-form-item label="浜у搧澶х被锛�" prop="productCategory">
+ <el-input v-model="productForm.productCategory"
+ placeholder="鐐瑰嚮閫夋嫨"
+ readonly
+ @click="showProductSelectDialog = true"
+ style="cursor:pointer" />
</el-form-item>
</el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="24">
+ <el-col :span="12">
<el-form-item label="瑙勬牸鍨嬪彿锛�" prop="productModelId">
- <el-select v-model="productForm.productModelId" placeholder="璇烽�夋嫨" filterable clearable
- @change="getProductModel">
- <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
- </el-select>
+ <el-input v-model="productForm.specificationModel"
+ placeholder="鐐瑰嚮閫夋嫨"
+ readonly
+ @click="showProductSelectDialog = true"
+ style="cursor:pointer" />
</el-form-item>
</el-col>
</el-row>
@@ -310,7 +313,7 @@
<el-row :gutter="30">
<el-col :span="12">
<el-form-item label="鍚◣鍗曚环(鍏�)锛�" prop="taxInclusiveUnitPrice">
- <el-input-number v-model="productForm.taxInclusiveUnitPrice" :precision="2" :step="0.1" :min="0" clearable
+ <el-input-number v-model="productForm.taxInclusiveUnitPrice" :precision="6" :step="0.000001" :min="0" clearable
style="width: 100%" @change="mathNum" />
</el-form-item>
</el-col>
@@ -324,13 +327,13 @@
<el-row :gutter="30">
<el-col :span="12">
<el-form-item label="鍚◣鎬讳环(鍏�)锛�" prop="taxInclusiveTotalPrice">
- <el-input-number v-model="productForm.taxInclusiveTotalPrice" :precision="2" :step="0.1" :min="0"
+ <el-input-number v-model="productForm.taxInclusiveTotalPrice" :precision="6" :step="0.000001" :min="0"
clearable style="width: 100%" @change="reverseMathNum('taxInclusiveTotalPrice')" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="涓嶅惈绋庢�讳环(鍏�)锛�" prop="taxExclusiveTotalPrice">
- <el-input-number v-model="productForm.taxExclusiveTotalPrice" :precision="2" :step="0.1" :min="0"
+ <el-input-number v-model="productForm.taxExclusiveTotalPrice" :precision="6" :step="0.000001" :min="0"
clearable style="width: 100%" @change="reverseMathNum('taxExclusiveTotalPrice')" />
</el-form-item>
</el-col>
@@ -344,14 +347,12 @@
</el-select>
</el-form-item>
</el-col>
- <el-col :span="12">
- <el-form-item label="搴撳瓨棰勮鏁伴噺锛�" prop="warnNum">
- <el-input-number v-model="productForm.warnNum" :precision="2" :step="0.1" :min="0" clearable
- style="width: 100%" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
+<!-- <el-col :span="12">-->
+<!-- <el-form-item label="搴撳瓨棰勮鏁伴噺锛�" prop="warnNum">-->
+<!-- <el-input-number v-model="productForm.warnNum" :precision="2" :step="0.1" :min="0" clearable-->
+<!-- style="width: 100%" />-->
+<!-- </el-form-item>-->
+<!-- </el-col>-->
<el-col :span="12">
<el-form-item label="鏄惁璐ㄦ锛�" prop="isChecked">
<el-radio-group v-model="productForm.isChecked">
@@ -361,8 +362,21 @@
</el-form-item>
</el-col>
</el-row>
+<!-- <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鏄惁璐ㄦ锛�" prop="isChecked">
+ <el-radio-group v-model="productForm.isChecked">
+ <el-radio label="鏄�" :value="true" />
+ <el-radio label="鍚�" :value="false" />
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>-->
</el-form>
</FormDialog>
+ <ProductSelectDialog v-model="showProductSelectDialog"
+ @confirm="handleProductSelect"
+ single />
<FileList v-if="fileListDialogVisible" v-model:visible="fileListDialogVisible" record-type="purchase_ledger"
:record-id="recordId" />
<Detail ref="detailRef" />
@@ -403,6 +417,7 @@
productList,
getPurchaseById,
getOptions,
+ getPrintData,
getPurchaseTemplateList,
delPurchaseTemplate,
} from "@/api/procurementManagement/procurementLedger.js";
@@ -435,8 +450,11 @@
const fileList = ref([]);
import useUserStore from "@/store/modules/user";
import { modelList, productTreeList } from "@/api/basicData/product.js";
+import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import dayjs from "dayjs";
import FileUpload from "@/components/AttachmentUpload/file/index.vue";
+import { tableAmountFormatter, formatDecimal, buildAmountSummaryFormat } from '@/utils/numberFormat';
+import { downloadPurchaseJpg, printPurchaseMulti } from "@/utils/documentPrint.js";
const userStore = useUserStore();
@@ -636,6 +654,7 @@
// 浜у搧琛ㄥ崟寮规鏁版嵁
const productFormVisible = ref(false);
+const showProductSelectDialog = ref(false);
const productOperationType = ref("");
const productOperationIndex = ref("");
const currentId = ref("");
@@ -656,15 +675,15 @@
isChecked: false,
},
productRules: {
- productId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ productCategory: [{ required: true, message: "璇烽�夋嫨浜у搧澶х被", trigger: "change" }],
+ productModelId: [{ required: true, message: "璇烽�夋嫨瑙勬牸鍨嬪彿", trigger: "change" }],
unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
taxInclusiveUnitPrice: [
{ required: true, message: "璇疯緭鍏�", trigger: "blur" },
],
taxRate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- warnNum: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ // warnNum: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
taxInclusiveTotalPrice: [
{ required: true, message: "璇疯緭鍏�", trigger: "blur" },
],
@@ -763,9 +782,7 @@
handleQuery();
};
-const formattedNumber = (row, column, cellValue) => {
- return parseFloat(cellValue).toFixed(2);
-};
+const formattedNumber = tableAmountFormatter;
// 鏌ヨ鍒楄〃
/** 鎼滅储鎸夐挳鎿嶄綔 */
const handleQuery = () => {
@@ -883,10 +900,19 @@
"futureTickets",
"futureTicketsAmount",
],
- {
- ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- }
+ buildAmountSummaryFormat(
+ [
+ "taxInclusiveUnitPrice",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ "ticketsAmount",
+ "futureTicketsAmount",
+ ],
+ {
+ ticketsNum: { noDecimal: true },
+ futureTickets: { noDecimal: true },
+ }
+ )
);
};
const paginationChange = obj => {
@@ -949,15 +975,27 @@
};
// 涓昏〃鍚堣鏂规硶
const summarizeMainTable = param => {
- return proxy.summarizeTable(param, ["contractAmount"]);
+ return proxy.summarizeTable(
+ param,
+ ["contractAmount"],
+ buildAmountSummaryFormat(["contractAmount"])
+ );
};
// 瀛愯〃鍚堣鏂规硶
const summarizeProTable = param => {
- return proxy.summarizeTable(param, [
- "taxInclusiveUnitPrice",
- "taxInclusiveTotalPrice",
- "taxExclusiveTotalPrice",
- ]);
+ return proxy.summarizeTable(
+ param,
+ [
+ "taxInclusiveUnitPrice",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ ],
+ buildAmountSummaryFormat([
+ "taxInclusiveUnitPrice",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ ])
+ );
};
// 鎵撳紑寮规
const openForm = async (type, row) => {
@@ -998,6 +1036,7 @@
);
form.value.entryDate = getCurrentDate();
+ form.value.recorderId = userStore.id;
if (type === "add") {
// 鏂板鏃剁敓鎴愰噰璐悎鍚屽彿
@@ -1225,6 +1264,19 @@
await nextTick();
}
};
+
+// ProductSelectDialog 閫変腑鍥炶皟
+const handleProductSelect = (products) => {
+ if (!products || !products.length) return;
+ const p = products[0];
+ productForm.value.productId = p.productId;
+ productForm.value.productCategory = p.productName || '';
+ productForm.value.productModelId = p.id;
+ productForm.value.specificationModel = p.model || '';
+ productForm.value.unit = p.unit || '';
+ showProductSelectDialog.value = false;
+};
+
const getProductOptions = () => {
return productTreeList().then(res => {
productOptions.value = convertIdToValue(res);
@@ -1407,6 +1459,31 @@
});
};
+// 鎵归噺鎵撳嵃閲囪喘鍗� - 澶氶�夊悎骞堕瑙�
+const handlePrint = async () => {
+ if (selectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇烽�夋嫨瑕佹墦鍗扮殑鏁版嵁");
+ return;
+ }
+ proxy.$modal.loading("姝e湪鍔犺浇鎵撳嵃鏁版嵁...");
+ try {
+ const orders = [];
+ let companyName = '';
+ for (const row of selectedRows.value) {
+ const res = await getPrintData(row.id);
+ const data = res.data || res;
+ companyName = data.companyName || companyName;
+ orders.push({ ledger: data.ledger, products: data.products });
+ }
+ printPurchaseMulti(companyName, orders);
+ } catch (e) {
+ console.error('鎵撳嵃澶辫触:', e);
+ proxy.$modal.msgError("鎵撳嵃澶辫触");
+ } finally {
+ proxy.$modal.closeLoading();
+ }
+};
+
// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
function getCurrentDate() {
const today = new Date();
@@ -1466,10 +1543,10 @@
if (field === "taxInclusiveTotalPrice") {
// 宸茬煡鍚◣鎬讳环鍜屾暟閲忥紝鍙嶇畻鍚◣鍗曚环
if (productForm.value.quantity) {
- productForm.value.taxInclusiveUnitPrice = (
+ productForm.value.taxInclusiveUnitPrice = formatDecimal(
Number(productForm.value.taxInclusiveTotalPrice) /
Number(productForm.value.quantity)
- ).toFixed(2);
+ );
// 纭繚缁撴灉涓嶄负璐熸暟
if (Number(productForm.value.taxInclusiveUnitPrice) < 0) {
productForm.value.taxInclusiveUnitPrice = "0";
@@ -1487,30 +1564,30 @@
}
}
// 鍙嶇畻涓嶅惈绋庢�讳环
- productForm.value.taxExclusiveTotalPrice = (
+ productForm.value.taxExclusiveTotalPrice = formatDecimal(
Number(productForm.value.taxInclusiveTotalPrice) /
(1 + taxRate / 100)
- ).toFixed(2);
+ );
// 纭繚缁撴灉涓嶄负璐熸暟
if (Number(productForm.value.taxExclusiveTotalPrice) < 0) {
productForm.value.taxExclusiveTotalPrice = "0";
}
} else if (field === "taxExclusiveTotalPrice") {
// 鍙嶇畻鍚◣鎬讳环
- productForm.value.taxInclusiveTotalPrice = (
+ productForm.value.taxInclusiveTotalPrice = formatDecimal(
Number(productForm.value.taxExclusiveTotalPrice) *
(1 + taxRate / 100)
- ).toFixed(2);
+ );
// 纭繚缁撴灉涓嶄负璐熸暟
if (Number(productForm.value.taxInclusiveTotalPrice) < 0) {
productForm.value.taxInclusiveTotalPrice = "0";
}
// 宸茬煡鏁伴噺锛屽弽绠楀惈绋庡崟浠�
if (productForm.value.quantity) {
- productForm.value.taxInclusiveUnitPrice = (
+ productForm.value.taxInclusiveUnitPrice = formatDecimal(
Number(productForm.value.taxInclusiveTotalPrice) /
Number(productForm.value.quantity)
- ).toFixed(2);
+ );
// 纭繚缁撴灉涓嶄负璐熸暟
if (Number(productForm.value.taxInclusiveUnitPrice) < 0) {
productForm.value.taxInclusiveUnitPrice = "0";
@@ -1560,6 +1637,28 @@
fileListDialogVisible.value = true;
};
+// 涓嬭浇閲囪喘鍗�
+const downloadOrder = async (id) => {
+ try {
+ const res = await getPrintData(id);
+ const data = res.data || res;
+ downloadPurchaseJpg(data.companyName, data.ledger, data.products, '閲囪喘鍗昣' + (data.ledger.purchaseContractNumber || id) + '.jpg');
+ } catch (e) {
+ console.error('涓嬭浇澶辫触:', e);
+ }
+};
+
+// 鎵撳嵃閲囪喘鍗�
+const printOrder = async (id) => {
+ try {
+ const res = await getPrintData(id);
+ const data = res.data || res;
+ printPurchase(data.companyName, data.ledger, data.products);
+ } catch (e) {
+ console.error('鎵撳嵃澶辫触:', e);
+ }
+};
+
// 鍒犻櫎妯℃澘
const handleDeleteTemplate = async item => {
if (!item.id) {
diff --git a/src/views/procurementManagement/procurementReport/index.vue b/src/views/procurementManagement/procurementReport/index.vue
index 26e682d..e891868 100644
--- a/src/views/procurementManagement/procurementReport/index.vue
+++ b/src/views/procurementManagement/procurementReport/index.vue
@@ -83,6 +83,7 @@
import PIMTable from '@/components/PIMTable/PIMTable.vue'
import { procurementBusinessSummaryListPage } from '@/api/procurementManagement/procurementReport'
import { productTreeList } from '@/api/basicData/product'
+import { formatDecimal, formatCurrency } from '@/utils/numberFormat'
const { proxy } = getCurrentInstance()
@@ -135,14 +136,14 @@
prop: 'returnAmount',
width: 120,
formatData: (val) => {
- return val ? `楼${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : '楼0.00'
+ return val ? formatCurrency(val) : '楼0'
}
},
{
label: '閫�娆惧偍閲�',
prop: 'purchaseAmount',
formatData: (val) => {
- return val ? `楼${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : '楼0.00'
+ return val ? formatCurrency(val) : '楼0'
}
},
{
@@ -155,7 +156,7 @@
prop: 'averagePrice',
width: 120,
formatData: (val) => {
- return val ? `楼${parseFloat(val).toFixed(2)}` : '楼0.00'
+ return val ? formatCurrency(val) : '楼0'
}
},
{
diff --git a/src/views/qualityManagement/finalInspection/components/formDia.vue b/src/views/qualityManagement/finalInspection/components/formDia.vue
index 31ba755..e5cd36e 100644
--- a/src/views/qualityManagement/finalInspection/components/formDia.vue
+++ b/src/views/qualityManagement/finalInspection/components/formDia.vue
@@ -97,6 +97,34 @@
</el-row>
<el-row :gutter="30">
<el-col :span="12">
+ <el-form-item label="鏄惁鎶芥锛�"
+ prop="isSampling">
+ <el-radio-group v-model="form.isSampling"
+ class="sampling-radio-group"
+ :disabled="isViewMode"
+ @change="handleSamplingChange">
+ <el-radio-button :label="1">鏄�</el-radio-button>
+ <el-radio-button :label="0">鍚�</el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12"
+ v-if="form.isSampling === 1">
+ <el-form-item label="鎶芥鏁伴噺锛�"
+ prop="samplingQuantity">
+ <el-input-number :step="0.01"
+ :min="0"
+ style="width: 100%"
+ v-model="form.samplingQuantity"
+ placeholder="璇疯緭鍏�"
+ clearable
+ :precision="2"
+ :disabled="isViewMode" />
+ </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 :disabled="isViewMode"/>
</el-form-item>
@@ -184,6 +212,8 @@
qualifiedQuantity: "",
unqualifiedQuantity: "",
checkCompany: "",
+ isSampling: 0,
+ samplingQuantity: "",
},
rules: {
checkTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
@@ -197,6 +227,8 @@
qualifiedQuantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
unqualifiedQuantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
checkCompany: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ isSampling: [{ required: true, message: "璇烽�夋嫨鏄惁鎶芥", trigger: "change" }],
+ samplingQuantity: [{ required: true, message: "璇疯緭鍏ユ娊妫�鏁伴噺", trigger: "blur" }],
},
});
const { form, rules } = toRefs(data);
@@ -289,7 +321,7 @@
]);
userList.value = userListsRes.data;
- form.value = {}
+ form.value = { isSampling: 0, samplingQuantity: "" }
testStandardOptions.value = [];
tableData.value = [];
@@ -502,6 +534,15 @@
tableData.value = res.data;
});
}
+// 鏄惁鎶芥鍒囨崲
+const handleSamplingChange = (value) => {
+ if (value !== 1) {
+ form.value.samplingQuantity = "";
+ nextTick(() => {
+ proxy.$refs?.formRef?.clearValidate?.("samplingQuantity");
+ });
+ }
+}
// 鍏抽棴寮规
const closeDia = () => {
proxy.resetForm("formRef");
@@ -517,5 +558,7 @@
</script>
<style scoped>
-
+.sampling-radio-group {
+ height: 32px;
+}
</style>
diff --git a/src/views/qualityManagement/metricBinding/index.vue b/src/views/qualityManagement/metricBinding/index.vue
index 1ac268a..ba989ea 100644
--- a/src/views/qualityManagement/metricBinding/index.vue
+++ b/src/views/qualityManagement/metricBinding/index.vue
@@ -120,25 +120,45 @@
<el-dialog
v-model="bindingDialogVisible"
title="娣诲姞缁戝畾"
- width="520px"
+ width="640px"
@close="closeBindingDialog"
>
- <el-form label-width="100px">
- <el-form-item label="浜у搧">
- <el-tree-select
- v-model="selectedProductIds"
- multiple
- collapse-tags
- collapse-tags-tooltip
- placeholder="璇烽�夋嫨浜у搧锛堝彲澶氶�夛級"
- clearable
- check-strictly
- :data="productOptions"
- :render-after-expand="false"
- style="width: 100%"
- />
- </el-form-item>
- </el-form>
+ <div class="binding-dialog">
+ <el-input
+ v-model="productSearchKeyword"
+ placeholder="鎼滅储浜у搧"
+ clearable
+ prefix-icon="Search"
+ class="binding-search"
+ />
+ <el-tree
+ ref="productTreeRef"
+ :key="productTreeKey"
+ v-loading="productTreeLoading"
+ :data="productTreeData"
+ show-checkbox
+ check-strictly
+ node-key="id"
+ :props="{ label: 'label', children: 'children', disabled: 'disabled' }"
+ :filter-node-method="filterProductNode"
+ class="product-binding-tree"
+ @check="handleProductTreeCheck"
+ />
+ <div v-if="selectedProductLabels.length" class="selected-products">
+ <div class="selected-title">宸查�夋嫨锛坽{ selectedProductLabels.length }}锛�</div>
+ <div class="selected-tags">
+ <el-tag
+ v-for="item in selectedProductLabels"
+ :key="item.id"
+ closable
+ type="info"
+ @close="removeSelectedProduct(item.id)"
+ >
+ {{ item.label }}
+ </el-tag>
+ </div>
+ </div>
+ </div>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeBindingDialog">鍙栨秷</el-button>
@@ -150,8 +170,7 @@
</template>
<script setup>
-import { Search } from '@element-plus/icons-vue'
-import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue'
+import { ref, reactive, toRefs, computed, watch, nextTick, onMounted, getCurrentInstance } from 'vue'
import { ElMessageBox } from 'element-plus'
import PIMTable from '@/components/PIMTable/PIMTable.vue'
import { productTreeList } from '@/api/basicData/product.js'
@@ -261,28 +280,74 @@
const bindingDialogVisible = ref(false)
// 浜у搧鏍戯紙鐢ㄤ簬缁戝畾閫夋嫨锛�
-const productOptions = ref([])
+const productTreeData = ref([])
+const productTreeLoading = ref(false)
+const productTreeRef = ref(null)
+const productTreeKey = ref(0)
+const productSearchKeyword = ref('')
const selectedProductIds = ref([])
-const getProductOptions = async () => {
- // 閬垮厤閲嶅璇锋眰
- if (productOptions.value?.length) return
- const res = await productTreeList()
- productOptions.value = convertIdToValue(Array.isArray(res) ? res : [])
+const markParentNodesDisabled = (nodes) => {
+ return (nodes || []).map((node) => {
+ const children = node.children?.length ? markParentNodesDisabled(node.children) : []
+ return {
+ ...node,
+ children,
+ disabled: children.length > 0
+ }
+ })
}
-function convertIdToValue(data) {
- return (data || []).map((item) => {
- const { id, children, ...rest } = item
- const newItem = {
- ...rest,
- value: id
+const buildProductLabelMap = (nodes, map = {}) => {
+ ;(nodes || []).forEach((node) => {
+ if (node.id != null) {
+ map[node.id] = node.label
}
- if (children && children.length > 0) {
- newItem.children = convertIdToValue(children)
+ if (node.children?.length) {
+ buildProductLabelMap(node.children, map)
}
- return newItem
})
+ return map
+}
+
+const productLabelMap = computed(() => buildProductLabelMap(productTreeData.value))
+
+const selectedProductLabels = computed(() =>
+ selectedProductIds.value.map((id) => ({
+ id,
+ label: productLabelMap.value[id] || id
+ }))
+)
+
+const filterProductNode = (value, data) => {
+ if (!value) return true
+ return String(data.label || '').includes(value)
+}
+
+watch(productSearchKeyword, (val) => {
+ productTreeRef.value?.filter(val)
+})
+
+const getProductTreeData = async () => {
+ if (productTreeData.value?.length) return
+ productTreeLoading.value = true
+ try {
+ const res = await productTreeList()
+ productTreeData.value = markParentNodesDisabled(Array.isArray(res) ? res : [])
+ } catch (error) {
+ console.error('鑾峰彇浜у搧鏍戝け璐�:', error)
+ } finally {
+ productTreeLoading.value = false
+ }
+}
+
+const handleProductTreeCheck = () => {
+ selectedProductIds.value = productTreeRef.value?.getCheckedKeys(true) || []
+}
+
+const removeSelectedProduct = (id) => {
+ selectedProductIds.value = selectedProductIds.value.filter((item) => item !== id)
+ productTreeRef.value?.setChecked(id, false, false)
}
const handleQuery = () => {
@@ -354,12 +419,20 @@
const openBindingDialog = () => {
if (!currentStandard.value?.id) return
selectedProductIds.value = []
- getProductOptions()
+ productSearchKeyword.value = ''
+ productTreeKey.value += 1
bindingDialogVisible.value = true
+ nextTick(() => {
+ productTreeRef.value?.setCheckedKeys([])
+ productTreeRef.value?.filter('')
+ })
}
const closeBindingDialog = () => {
bindingDialogVisible.value = false
+ selectedProductIds.value = []
+ productSearchKeyword.value = ''
+ productTreeRef.value?.setCheckedKeys([])
}
const submitBinding = async () => {
@@ -428,6 +501,7 @@
onMounted(() => {
getStandardList()
getProcessList()
+ getProductTreeData()
})
</script>
@@ -533,4 +607,39 @@
width: 100%;
margin-top: 4px;
}
+
+.binding-dialog {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.binding-search {
+ width: 100%;
+}
+
+.product-binding-tree {
+ max-height: 360px;
+ overflow-y: auto;
+ border: 1px solid #ebeef5;
+ border-radius: 4px;
+ padding: 8px;
+}
+
+.selected-products {
+ border-top: 1px solid #ebeef5;
+ padding-top: 12px;
+}
+
+.selected-title {
+ font-size: 13px;
+ color: #606266;
+ margin-bottom: 8px;
+}
+
+.selected-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
</style>
diff --git a/src/views/qualityManagement/processInspection/components/formDia.vue b/src/views/qualityManagement/processInspection/components/formDia.vue
index f28cec2..a02976e 100644
--- a/src/views/qualityManagement/processInspection/components/formDia.vue
+++ b/src/views/qualityManagement/processInspection/components/formDia.vue
@@ -130,6 +130,34 @@
</el-row>
<el-row :gutter="30">
<el-col :span="12">
+ <el-form-item label="鏄惁鎶芥锛�"
+ prop="isSampling">
+ <el-radio-group v-model="form.isSampling"
+ class="sampling-radio-group"
+ :disabled="isViewMode"
+ @change="handleSamplingChange">
+ <el-radio-button :label="1">鏄�</el-radio-button>
+ <el-radio-button :label="0">鍚�</el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12"
+ v-if="form.isSampling === 1">
+ <el-form-item label="鎶芥鏁伴噺锛�"
+ prop="samplingQuantity">
+ <el-input-number :step="0.01"
+ :min="0"
+ style="width: 100%"
+ v-model="form.samplingQuantity"
+ placeholder="璇疯緭鍏�"
+ clearable
+ :precision="2"
+ :disabled="isViewMode" />
+ </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"
@@ -242,6 +270,8 @@
qualifiedQuantity: "",
unqualifiedQuantity: "",
checkCompany: "",
+ isSampling: 0,
+ samplingQuantity: "",
},
rules: {
checkTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
@@ -255,6 +285,8 @@
qualifiedQuantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
unqualifiedQuantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
checkCompany: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ isSampling: [{ required: true, message: "璇烽�夋嫨鏄惁鎶芥", trigger: "change" }],
+ samplingQuantity: [{ required: true, message: "璇疯緭鍏ユ娊妫�鏁伴噺", trigger: "blur" }],
},
});
const userList = ref([]);
@@ -359,6 +391,8 @@
unit: "",
quantity: "",
checkCompany: "",
+ isSampling: 0,
+ samplingQuantity: "",
};
testStandardOptions.value = [];
tableData.value = [];
@@ -607,6 +641,15 @@
tableData.value = res.data;
});
};
+ // 鏄惁鎶芥鍒囨崲
+ const handleSamplingChange = (value) => {
+ if (value !== 1) {
+ form.value.samplingQuantity = "";
+ nextTick(() => {
+ proxy.$refs?.formRef?.clearValidate?.("samplingQuantity");
+ });
+ }
+ };
// 鍏抽棴寮规
const closeDia = () => {
proxy.resetForm("formRef");
@@ -622,4 +665,7 @@
</script>
<style scoped>
+.sampling-radio-group {
+ height: 32px;
+}
</style>
diff --git a/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue b/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
index b745e9d..d3f9fc0 100644
--- a/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
+++ b/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
@@ -14,6 +14,7 @@
v-model="form.supplier"
placeholder="璇烽�夋嫨"
clearable
+ filterable
:disabled="isViewMode || supplierQuantityDisabled"
>
<el-option
@@ -96,6 +97,23 @@
<el-input-number :step="0.01" :min="0" :max="form.quantity || 0" style="width: 100%"
v-model="form.unqualifiedQuantity" placeholder="璇疯緭鍏�" :precision="2"
@change="onUnqualifiedChange" :disabled="isViewMode"/>
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鏄惁鎶芥锛�" prop="isSampling">
+ <el-radio-group v-model="form.isSampling" class="sampling-radio-group" :disabled="isViewMode" @change="handleSamplingChange">
+ <el-radio-button :label="1">鏄�</el-radio-button>
+ <el-radio-button :label="0">鍚�</el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12" v-if="form.isSampling === 1">
+ <el-form-item label="鎶芥鏁伴噺锛�" prop="samplingQuantity">
+ <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.samplingQuantity"
+ placeholder="璇疯緭鍏�" clearable :precision="2" :disabled="isViewMode"/>
</el-form-item>
</el-col>
</el-row>
@@ -190,6 +208,8 @@
unit: "",
quantity: "",
checkCompany: "",
+ isSampling: 0,
+ samplingQuantity: "",
},
rules: {
checkTime: [{required: true, message: "璇疯緭鍏�", trigger: "blur"},],
@@ -203,6 +223,8 @@
qualifiedQuantity: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
unqualifiedQuantity: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
checkCompany: [{required: false, message: "璇疯緭鍏�", trigger: "blur"}],
+ isSampling: [{required: true, message: "璇烽�夋嫨鏄惁鎶芥", trigger: "change"}],
+ samplingQuantity: [{required: true, message: "璇疯緭鍏ユ娊妫�鏁伴噺", trigger: "blur"}],
},
});
const tableColumn = ref([
@@ -307,6 +329,8 @@
unit: "",
quantity: "",
checkCompany: "",
+ isSampling: 0,
+ samplingQuantity: "",
}
testStandardOptions.value = [];
tableData.value = [];
@@ -531,6 +555,16 @@
}
};
+// 鏄惁鎶芥鍒囨崲
+const handleSamplingChange = (value) => {
+ if (value !== 1) {
+ form.value.samplingQuantity = "";
+ nextTick(() => {
+ proxy.$refs?.formRef?.clearValidate?.("samplingQuantity");
+ });
+ }
+};
+
// 鍏抽棴寮规
const closeDia = () => {
proxy.resetForm("formRef");
@@ -546,5 +580,7 @@
</script>
<style scoped>
-
+.sampling-radio-group {
+ height: 32px;
+}
</style>
diff --git a/src/views/reportAnalysis/reportManagement/index.vue b/src/views/reportAnalysis/reportManagement/index.vue
index 3bcb8ae..4c9e1ea 100644
--- a/src/views/reportAnalysis/reportManagement/index.vue
+++ b/src/views/reportAnalysis/reportManagement/index.vue
@@ -37,7 +37,7 @@
</div>
</div>
</div>
- <div class="typeNum">
+ <div class="typeNum" v-if="showSemiFinished">
<div class="typeNum-left">
<img src="~@/assets/images/chartCard2.svg" alt="鍥捐〃"
style="width: 40px; height: 40px; object-fit: contain;">
@@ -123,7 +123,7 @@
</div>
</div>
</div>
- <div class="quality-card green-card">
+ <div class="quality-card green-card" v-if="showSemiFinished">
<div class="quality-card-title">
<img src="~@/assets/images/chartCard2.svg" alt="鍗婃垚鍝�"
style="width: 24px; height: 24px; margin-right: 8px;">
@@ -202,7 +202,7 @@
<div class="chart-box-title">鍘熸潗鏂欐�绘暟</div>
<div class="chart-box-num">{{ getYearlyStatValue(0, 'totalCount') }}</div>
</div>
- <div class="inspection-chart-box">
+ <div class="inspection-chart-box" v-if="showSemiFinished">
<div class="chart-box-title">鍗婃垚鍝佹�绘暟</div>
<div class="chart-box-num">{{ getYearlyStatValue(1, 'totalCount') }}</div>
</div>
@@ -266,7 +266,7 @@
<!-- Tab 閫夋嫨鍣� -->
<div class="tab-selector">
<div class="tab-item" :class="{ active: activeTab === 'raw' }" @click="activeTab = 'raw'">鍘熸潗鏂�</div>
- <div class="tab-item" :class="{ active: activeTab === 'semi' }" @click="activeTab = 'semi'">鍗婃垚鍝�</div>
+ <div v-if="showSemiFinished" class="tab-item" :class="{ active: activeTab === 'semi' }" @click="activeTab = 'semi'">鍗婃垚鍝�</div>
<div class="tab-item" :class="{ active: activeTab === 'final' }" @click="activeTab = 'final'">鎴愬搧</div>
</div>
</el-card>
@@ -295,6 +295,9 @@
const monthlyCompletionDetailsData = ref([]);
const topParametersData = ref({ totalCount: 0, list: [] });
const activeTab = ref("raw");
+
+// 鏄惁鏄剧ず鍗婃垚鍝佺浉鍏冲唴瀹广�傛湁鐨勪紒涓氭病鏈夊崐鎴愬搧锛岃涓� false 鍗冲彲闅愯棌鎵�鏈夊崐鎴愬搧鐩稿叧灞曠ず
+const showSemiFinished = ref(false);
const getParameterColor = (index) => {
const colors = ['#165DFF', '#14C9C9', '#F7BA1E', '#722ED1', '#3491FA', '#FF7D00', '#F53F3F'];
@@ -526,7 +529,7 @@
containLabel: true,
},
legend: {
- data: ["鍘熸潗鏂�", "鍗婃垚鍝�", "鎴愬搧"], // 鍥句緥鏁版嵁
+ data: showSemiFinished.value ? ["鍘熸潗鏂�", "鍗婃垚鍝�", "鎴愬搧"] : ["鍘熸潗鏂�", "鎴愬搧"], // 鍥句緥鏁版嵁
icon: ["circle", "circle", "circle"],
itemWidth: 10, // 璁剧疆鍥炬爣瀹藉害
itemHeight: 10,
@@ -564,7 +567,7 @@
color: "#409EFF",
},
},
- {
+ ...(showSemiFinished.value ? [{
name: "鍗婃垚鍝�",
type: "bar",
barWidth: "15%",
@@ -573,7 +576,7 @@
itemStyle: {
color: "#67C23A",
},
- },
+ }] : []),
{
name: "鎴愬搧",
type: "bar",
@@ -607,7 +610,7 @@
radius: "70%",
data: [
{ value: getYearlyStatValue(0, 'totalCount'), name: "鍘熸潗鏂�", itemStyle: { color: "#1890FF" } },
- { value: getYearlyStatValue(1, 'totalCount'), name: "鍗婃垚鍝�", itemStyle: { color: "#F7BA1E" } },
+ ...(showSemiFinished.value ? [{ value: getYearlyStatValue(1, 'totalCount'), name: "鍗婃垚鍝�", itemStyle: { color: "#F7BA1E" } }] : []),
{ value: getYearlyStatValue(2, 'totalCount'), name: "鎴愬搧", itemStyle: { color: "#14C9C9" } },
],
label: {
@@ -655,7 +658,7 @@
},
// 鍥句緥閰嶇疆
legend: {
- data: ["鍘熸潗鏂�", "鍗婃垚鍝�", "鎴愬搧"], // 鍥句緥鏁版嵁
+ data: showSemiFinished.value ? ["鍘熸潗鏂�", "鍗婃垚鍝�", "鎴愬搧"] : ["鍘熸潗鏂�", "鎴愬搧"], // 鍥句緥鏁版嵁
icon: ["circle", "circle", "circle"],
itemWidth: 10, // 璁剧疆鍥炬爣瀹藉害
itemHeight: 10,
@@ -697,7 +700,7 @@
},
data: monthlyPassRateData.value.map(item => item.rawMaterial.passRate),
},
- {
+ ...(showSemiFinished.value ? [{
name: "鍗婃垚鍝�", // 绯诲垪鍚嶇О
type: "line", // 鍥捐〃绫诲瀷涓烘姌绾垮浘
// stack: "Total", // 鍫嗗彔鍚嶇О
@@ -706,7 +709,7 @@
color: "#F7BA1E", // 璁剧疆杩欐潯绾跨殑棰滆壊
},
data: monthlyPassRateData.value.map(item => item.process.passRate),
- },
+ }] : []),
{
name: "鎴愬搧", // 绯诲垪鍚嶇О
type: "line", // 鍥捐〃绫诲瀷涓烘姌绾垮浘
@@ -769,16 +772,18 @@
"#52c41a",
getPassRateStatValue(0, 'passRate')
);
- semiCompletionChartInstance = initQualityChart(
- semiCompletionChart,
- "#1890ff",
- getPassRateStatValue(1, 'completionRate')
- );
- semiQualityChartInstance = initQualityChart(
- semiQualityChart,
- "#52c41a",
- getPassRateStatValue(1, 'passRate')
- );
+ if (showSemiFinished.value) {
+ semiCompletionChartInstance = initQualityChart(
+ semiCompletionChart,
+ "#1890ff",
+ getPassRateStatValue(1, 'completionRate')
+ );
+ semiQualityChartInstance = initQualityChart(
+ semiQualityChart,
+ "#52c41a",
+ getPassRateStatValue(1, 'passRate')
+ );
+ }
finalCompletionChartInstance = initQualityChart(
finalCompletionChart,
"#1890ff",
@@ -1161,7 +1166,7 @@
.typeNum {
height: 100%;
- width: 33.33%;
+ flex: 1;
display: flex;
align-items: center;
justify-content: center;
@@ -1297,11 +1302,12 @@
.flex-center {
justify-content: space-evenly;
+ gap: 15px;
}
.quality-card {
- /* flex: 1; */
- width: 32%;
+ flex: 1;
+ min-width: 0;
/* height: 100px; */
border-radius: 8px;
padding: 12px;
diff --git a/src/views/salesManagement/deliveryLedger/index.vue b/src/views/salesManagement/deliveryLedger/index.vue
index 9907cf6..68ad099 100644
--- a/src/views/salesManagement/deliveryLedger/index.vue
+++ b/src/views/salesManagement/deliveryLedger/index.vue
@@ -22,7 +22,7 @@
@change="handleQuery"
/>
</el-form-item>
- <el-form-item label="蹇�掑崟鍙凤細" v-if="false">
+ <el-form-item label="蹇�掑崟鍙凤細" >
<el-input
v-model="searchForm.expressNumber"
placeholder="璇疯緭鍏�"
@@ -95,17 +95,16 @@
label="鍙戣揣杞︾墝鍙�"
prop="shippingCarNumber"
show-overflow-tooltip
+ v-if="false"
/>
<el-table-column
label="蹇�掑叕鍙�"
prop="expressCompany"
- v-if="false"
show-overflow-tooltip
/>
<el-table-column
label="蹇�掑崟鍙�"
prop="expressNumber"
- v-if="false"
show-overflow-tooltip
/>
<el-table-column
@@ -182,8 +181,8 @@
style="width: 100%"
@change="handleShippingTypeChange"
>
- <el-option label="璐ц溅" value="璐ц溅" />
- <el-option label="蹇��" value="蹇��" v-if="false" />
+ <el-option label="蹇��" value="蹇��" />
+ <el-option label="璐ц溅" value="璐ц溅" v-if="false"/>
</el-select>
</el-form-item>
</el-col>
@@ -205,7 +204,7 @@
</el-row>
<el-row :gutter="30">
<el-col :span="24" v-if="form.type === '璐ц溅'">
- <el-form-item label="鍙戣揣杞︾墝鍙凤細" prop="shippingCarNumber">
+ <el-form-item label="鍙戣揣杞︾墝鍙凤細" prop="shippingCarNumber" v-if="false">
<el-input
v-model="form.shippingCarNumber"
placeholder="璇疯緭鍏ュ彂璐ц溅鐗屽彿"
@@ -223,7 +222,7 @@
</el-form-item>
</el-col>
</el-row>
- <el-row :gutter="30" v-if="false">
+ <el-row :gutter="30" >
<el-col :span="24">
<el-form-item label="蹇�掑崟鍙凤細" prop="expressNumber">
<el-input
@@ -283,13 +282,13 @@
<el-descriptions-item label="瀹℃牳鐘舵��">{{
getApprovalStatusText(detailRow.status)
}}</el-descriptions-item>
- <el-descriptions-item label="鍙戣揣杞︾墝鍙�">{{
+ <el-descriptions-item label="鍙戣揣杞︾墝鍙�" v-if="false">{{
detailRow.shippingCarNumber || "--"
}}</el-descriptions-item>
- <el-descriptions-item label="蹇�掑叕鍙�" v-if="false">{{
+ <el-descriptions-item label="蹇�掑叕鍙�" >{{
detailRow.expressCompany || "--"
}}</el-descriptions-item>
- <el-descriptions-item label="蹇�掑崟鍙�" :span="2" v-if="false">{{
+ <el-descriptions-item label="蹇�掑崟鍙�" :span="2" >{{
detailRow.expressNumber || "--"
}}</el-descriptions-item>
<el-descriptions-item label="鍑哄簱鍗曞彿" :span="2">{{
@@ -385,7 +384,7 @@
customerName: "",
specificationModel: "",
productName: "",
- type: "璐ц溅", // 璐ц溅, 蹇��
+ type: "蹇��", // 璐ц溅, 蹇��
shippingDate: "",
shippingCarNumber: "",
expressCompany: "",
@@ -476,7 +475,7 @@
id: row.id ?? null,
salesContractNo: row.salesContractNo ?? "",
customerName: row.customerName ?? "",
- type: row.type || "璐ц溅",
+ type: row.type || "蹇��",
shippingDate: row.shippingDate || getCurrentDate(),
shippingCarNumber: row.shippingCarNumber ?? "",
expressCompany: row.expressCompany ?? "",
diff --git a/src/views/salesManagement/receiptPaymentLedger/index.vue b/src/views/salesManagement/receiptPaymentLedger/index.vue
index 715cb9e..0bc5de3 100644
--- a/src/views/salesManagement/receiptPaymentLedger/index.vue
+++ b/src/views/salesManagement/receiptPaymentLedger/index.vue
@@ -126,6 +126,7 @@
customewTransactionsDetails,
} from "@/api/salesManagement/indicatorStats.js";
import Pagination from "../../../components/PIMTable/Pagination.vue";
+ import { tableAmountFormatter, buildAmountSummaryFormat } from "@/utils/numberFormat";
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const receiptRecord = ref([]);
@@ -173,18 +174,19 @@
}
});
};
- const formattedNumber = (row, column, cellValue) => {
- return cellValue ? parseFloat(cellValue).toFixed(2) : "0.00";
- };
+ const formattedNumber = tableAmountFormatter;
// 涓昏〃鍚堣鏂规硶
const summarizeMainTable = param => {
return proxy.summarizeTable(
param,
["contractAmounts", "shippedAmount", "unshippedAmount"],
- {
- ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- }
+ buildAmountSummaryFormat(
+ ["contractAmounts", "shippedAmount", "unshippedAmount"],
+ {
+ ticketsNum: { noDecimal: true },
+ futureTickets: { noDecimal: true },
+ }
+ )
);
};
// 瀛愯〃鍚堣鏂规硶
@@ -192,10 +194,13 @@
var summarizeTable = proxy.summarizeTable(
param,
["contractAmount", "shippedAmount", "unshippedAmount"],
- {
- ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
- }
+ buildAmountSummaryFormat(
+ ["contractAmount", "shippedAmount", "unshippedAmount"],
+ {
+ ticketsNum: { noDecimal: true },
+ futureTickets: { noDecimal: true },
+ }
+ )
);
return summarizeTable;
};
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index a82f141..23c7438 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -123,15 +123,14 @@
</el-table-column>
<el-table-column label="蹇�掑叕鍙�"
prop="expressCompany"
- v-if="false"
show-overflow-tooltip />
<el-table-column label="蹇�掑崟鍙�"
prop="expressNumber"
- v-if="false"
show-overflow-tooltip />
<el-table-column label="鍙戣揣杞︾墝"
minWidth="100px"
- align="center">
+ align="center"
+ v-if="false">
<template #default="scope">
<div>
<el-tag type="success"
@@ -250,7 +249,7 @@
</el-button>
<el-button link
type="primary"
- @click="openFileDialog(scope.row)">闄勪欢
+ @click="downloadOrder(scope.row.id)">涓嬭浇
</el-button>
</template>
</el-table-column>
@@ -380,7 +379,7 @@
:reserve-keyword="false"
placeholder="璇烽�夋嫨"
clearable
- :disabled="operationType === 'view'"
+ disabled
@change="changs">
<el-option v-for="item in userList"
:key="item.userId"
@@ -568,7 +567,7 @@
width="160"
align="right">
<template #default="scope">
- {{ Number(scope.row.totalAmount ?? 0).toFixed(2) }}
+ {{ formatDecimal(scope.row.totalAmount) }}
</template>
</el-table-column>
<el-table-column fixed="right"
@@ -606,35 +605,22 @@
:rules="productRules"
ref="productFormRef">
<el-row :gutter="30">
- <el-col :span="24">
- <el-form-item label="浜у搧澶х被锛�"
- prop="productCategory">
- <el-tree-select v-model="productForm.productCategory"
- placeholder="璇烽�夋嫨"
- clearable
- filterable
- check-strictly
- @change="getModels"
- :data="productOptions"
- :render-after-expand="false"
- style="width: 100%" />
+ <el-col :span="12">
+ <el-form-item label="浜у搧澶х被锛�" prop="productCategory">
+ <el-input v-model="productForm.productCategory"
+ placeholder="鐐瑰嚮閫夋嫨"
+ readonly
+ @click="showProductSelectDialog = true"
+ style="cursor:pointer" />
</el-form-item>
</el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="24">
- <el-form-item label="瑙勬牸鍨嬪彿锛�"
- prop="productModelId">
- <el-select v-model="productForm.productModelId"
- placeholder="璇烽�夋嫨"
- clearable
- @change="getProductModel"
- filterable>
- <el-option v-for="item in modelOptions"
- :key="item.id"
- :label="item.model"
- :value="item.id" />
- </el-select>
+ <el-col :span="12">
+ <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="productModelId">
+ <el-input v-model="productForm.specificationModel"
+ placeholder="鐐瑰嚮閫夋嫨"
+ readonly
+ @click="showProductSelectDialog = true"
+ style="cursor:pointer" />
</el-form-item>
</el-col>
</el-row>
@@ -666,11 +652,11 @@
<el-col :span="12">
<el-form-item label="鍚◣鍗曚环(鍏�)锛�"
prop="taxInclusiveUnitPrice">
- <el-input-number :step="0.01"
+ <el-input-number :step="0.000001"
:min="0"
v-model="productForm.taxInclusiveUnitPrice"
style="width: 100%"
- :precision="2"
+ :precision="6"
placeholder="璇疯緭鍏�"
clearable
@change="calculateFromUnitPrice" />
@@ -724,20 +710,44 @@
</el-select>
</el-form-item>
</el-col>
-<!-- <el-col :span="12">
+ <el-col :span="12">
<el-form-item label="鏄惁鐢熶骇锛�"
prop="isProduction">
- <el-radio-group v-model="productForm.isProduction">
- <el-radio label="鏄�"
- :value="true" />
- <el-radio label="鍚�"
- :value="false" />
- </el-radio-group>
+ <div style="display: flex; align-items: center; width: 100%;">
+ <el-radio-group v-model="productForm.isProduction">
+ <el-radio label="鏄�"
+ :value="true" />
+ <el-radio label="鍚�"
+ :value="false" />
+ </el-radio-group>
+ <div
+ v-if="currentStock !== null"
+ :style="{
+ marginLeft: '20px',
+ padding: '0 12px',
+ height: '28px',
+ lineHeight: '28px',
+ borderRadius: '4px',
+ fontSize: '13px',
+ fontWeight: '500',
+ display: 'inline-block',
+ whiteSpace: 'nowrap',
+ backgroundColor: (productForm.quantity || 0) > currentStock ? '#fff0f0' : '#f0f9eb',
+ border: (productForm.quantity || 0) > currentStock ? '1px solid #ffcccc' : '1px solid #e1f3d8',
+ color: (productForm.quantity || 0) > currentStock ? '#f56c6c' : '#67c23a'
+ }"
+ >
+ <span>褰撳墠搴撳瓨锛歿{ currentStock }} {{ productForm.unit || '' }}</span>
+ </div>
+ </div>
</el-form-item>
- </el-col>-->
+ </el-col>
</el-row>
</el-form>
</FormDialog>
+ <ProductSelectDialog v-model="showProductSelectDialog"
+ @confirm="handleProductSelect"
+ single />
<!-- 瀵煎叆寮圭獥 -->
<FormDialog v-model="importUpload.open"
:title="importUpload.title"
@@ -813,7 +823,7 @@
<span class="label">鍙戣揣鏃ユ湡锛�</span>
<span class="value">{{ formatDate(item.createTime) }}</span>
</div>
- <div>
+ <div v-if="false">
<span class="label">鍙戣揣杞︾墝鍙凤細</span>
<span class="value">{{ item.shippingCarNumber }}</span>
</div>
@@ -916,11 +926,11 @@
placeholder="璇烽�夋嫨鍙戣揣绫诲瀷"
style="width: 100%"
@change="handleDeliveryTypeChange">
- <el-option label="璐ц溅"
- value="璐ц溅" />
<el-option label="蹇��"
- v-if="false"
value="蹇��" />
+ <el-option v-if="false"
+ label="璐ц溅"
+ value="璐ц溅" />
</el-select>
</el-form-item>
</el-col>
@@ -952,7 +962,7 @@
</el-col>
</el-row>
<el-row :gutter="30"
- v-if="false">
+ >
<el-col :span="24">
<el-form-item label="蹇�掑崟鍙凤細"
prop="expressNumber">
@@ -1051,13 +1061,21 @@
delProduct,
delLedgerFile,
getProductInventory,
+ getPrintData,
} from "@/api/salesManagement/salesLedger.js";
+ import { downloadSalesJpg, printSalesMulti } from "@/utils/documentPrint.js";
import { getStockInventoryByModelId } from "@/api/inventoryManagement/stockInventory.js";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import useFormData from "@/hooks/useFormData.js";
import dayjs from "dayjs";
import FileUpload from "@/components/AttachmentUpload/file/index.vue";
+ import {
+ tableAmountFormatter,
+ formatDecimal,
+ buildAmountSummaryFormat,
+ } from "@/utils/numberFormat";
import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
+ import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import { getCurrentDate } from "@/utils/index.js";
import { listCustomer } from "@/api/basicData/customer.js";
@@ -1086,6 +1104,7 @@
const total = ref(0);
const fileList = ref([]);
const deliveryFileList = ref([]);
+ const showProductSelectDialog = ref(false);
// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
const operationType = ref("");
@@ -1128,7 +1147,9 @@
const currentId = ref("");
const productFormData = reactive({
productForm: {
+ productId: "",
productCategory: "",
+ productModelId: "",
specificationModel: "",
unit: "",
quantity: "",
@@ -1140,11 +1161,8 @@
isProduction: false,
},
productRules: {
- productCategory: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- specificationModel: [
- { required: true, message: "璇烽�夋嫨", trigger: "change" },
- ],
+ productCategory: [{ required: true, message: "璇烽�夋嫨浜у搧澶х被", trigger: "change" }],
+ productModelId: [{ required: true, message: "璇烽�夋嫨瑙勬牸鍨嬪彿", trigger: "change" }],
unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
taxInclusiveUnitPrice: [
@@ -1197,6 +1215,27 @@
item?.qualifiedQuantity ??
item?.stockQuantity;
return quantity ?? 0;
+ };
+ const currentStock = ref(null);
+ const fetchCurrentStock = async (productModelId) => {
+ if (!productModelId) {
+ currentStock.value = null;
+ return;
+ }
+ try {
+ const res = await getStockInventoryByModelId(productModelId);
+ const rawList = Array.isArray(res?.data)
+ ? res.data
+ : res?.data?.records || res?.data?.rows || [];
+ let total = 0;
+ rawList.forEach(item => {
+ total += Number(getDeliveryBatchQuantity(item) || 0);
+ });
+ currentStock.value = total;
+ } catch (e) {
+ console.error(e);
+ currentStock.value = 0;
+ }
};
const getCurrentDeliveryRowQuantity = () => {
return Number(currentDeliveryRow.value?.noQuantity || 0);
@@ -1283,7 +1322,7 @@
shippingCarNumber: "",
expressCompany: "",
expressNumber: "",
- type: "璐ц溅", // 璐ц溅, 蹇��
+ type: "蹇��", // 璐ц溅, 蹇��
},
deliveryRules: {
shippingCarNumber: [
@@ -1401,12 +1440,7 @@
return productOptions.value;
});
};
- const formattedNumber = (row, column, cellValue) => {
- if (cellValue === undefined || cellValue === null || cellValue === "") {
- return "0.00";
- }
- return parseFloat(cellValue).toFixed(2);
- };
+ const formattedNumber = tableAmountFormatter;
const findLedgerRecordByRow = row => {
if (!row) return null;
if (
@@ -1460,9 +1494,21 @@
}
return formattedNumber(row, column, cellValue);
};
+ // ProductSelectDialog 閫変腑鍥炶皟
+ const handleProductSelect = (products) => {
+ if (!products || !products.length) return;
+ const p = products[0];
+ productForm.value.productId = p.productId;
+ productForm.value.productCategory = p.productName || '';
+ productForm.value.productModelId = p.id;
+ productForm.value.specificationModel = p.model || '';
+ productForm.value.unit = p.unit || '';
+ showProductSelectDialog.value = false;
+ };
// 鑾峰彇tree瀛愭暟鎹�
const getModels = value => {
productForm.value.productCategory = findNodeById(productOptions.value, value);
+ currentStock.value = null;
modelList({ id: value }).then(res => {
modelOptions.value = res;
});
@@ -1472,9 +1518,11 @@
if (index !== -1) {
productForm.value.specificationModel = modelOptions.value[index].model;
productForm.value.unit = modelOptions.value[index].unit;
+ fetchCurrentStock(value);
} else {
productForm.value.specificationModel = null;
productForm.value.unit = null;
+ currentStock.value = null;
}
};
const findNodeById = (nodes, productId) => {
@@ -1569,11 +1617,15 @@
};
// 涓昏〃鍚堣鏂规硶
const summarizeMainTable = param => {
- return proxy.summarizeTable(param, [
- "contractAmount",
- "taxInclusiveTotalPrice",
- "taxExclusiveTotalPrice",
- ]);
+ return proxy.summarizeTable(
+ param,
+ ["contractAmount", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice"],
+ buildAmountSummaryFormat([
+ "contractAmount",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ ])
+ );
};
// 瀛愯〃鍚堣鏂规硶
const summarizeChildrenTable = (param, parentRow) => {
@@ -1595,11 +1647,19 @@
return "";
});
}
- return proxy.summarizeTable(param, [
- "taxInclusiveUnitPrice",
- "taxInclusiveTotalPrice",
- "taxExclusiveTotalPrice",
- ]);
+ return proxy.summarizeTable(
+ param,
+ [
+ "taxInclusiveUnitPrice",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ ],
+ buildAmountSummaryFormat([
+ "taxInclusiveUnitPrice",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ ])
+ );
};
// 鎵撳紑寮规
const openForm = async (type, row) => {
@@ -1727,7 +1787,7 @@
const quantity = Number(p.quantity ?? 0) || 0;
const unitPrice = Number(p.unitPrice ?? 0) || 0;
const taxRate = "13"; // 榛樿 13%锛屼究浜庣洿鎺ユ彁浜わ紙濡傞渶鍙湪浜у搧涓嚜琛屼慨鏀癸級
- const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
+ const taxInclusiveTotalPrice = formatDecimal(unitPrice * quantity);
const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(
taxInclusiveTotalPrice,
taxRate
@@ -1739,7 +1799,7 @@
unit: p.unit || "",
quantity: quantity,
taxRate: taxRate,
- taxInclusiveUnitPrice: unitPrice.toFixed(2),
+ taxInclusiveUnitPrice: formatDecimal(unitPrice),
taxInclusiveTotalPrice: taxInclusiveTotalPrice,
taxExclusiveTotalPrice: taxExclusiveTotalPrice,
invoiceType: "澧炴櫘绁�",
@@ -1798,6 +1858,7 @@
productOperationType.value = type;
productForm.value = {};
+ currentStock.value = null;
if (type === "add") {
productForm.value.isProduction = true;
}
@@ -1824,6 +1885,7 @@
);
if (currentModel) {
productForm.value.productModelId = currentModel.id;
+ fetchCurrentStock(currentModel.id);
}
}
} catch (e) {
@@ -2026,359 +2088,31 @@
});
};
- // 鎵撳嵃鍔熻兘
+ // 鎵撳嵃鍔熻兘 - 澶氶�夊悎骞堕瑙�
const handlePrint = async () => {
if (selectedRows.value.length === 0) {
proxy.$modal.msgWarning("璇烽�夋嫨瑕佹墦鍗扮殑鏁版嵁");
return;
}
-
- // 鏄剧ず鍔犺浇鐘舵��
- proxy.$modal.loading("姝e湪鑾峰彇浜у搧鏁版嵁锛岃绋嶅��...");
-
+ proxy.$modal.loading("姝e湪鍔犺浇鎵撳嵃鏁版嵁...");
try {
- // 涓烘瘡涓�変腑鐨勯攢鍞彴璐﹁褰曟煡璇㈠搴旂殑浜у搧鏁版嵁
- const printDataWithProducts = [];
-
+ const orders = [];
+ let companyName = '';
for (const row of selectedRows.value) {
- try {
- // 璋冪敤productList鎺ュ彛鏌ヨ浜у搧鏁版嵁
- const productRes = await productList({
- salesLedgerId: row.id,
- type: 1,
- });
-
- // 灏嗕骇鍝佹暟鎹暣鍚堝埌閿�鍞彴璐﹁褰曚腑
- const rowWithProducts = {
- ...row,
- products: productRes.data || [],
- };
-
- printDataWithProducts.push(rowWithProducts);
- } catch (error) {
- console.error(`鑾峰彇閿�鍞彴璐� ${row.id} 鐨勪骇鍝佹暟鎹け璐�:`, error);
- // 鍗充娇鏌愪釜璁板綍鐨勪骇鍝佹暟鎹幏鍙栧け璐ワ紝涔熻鍖呭惈璇ヨ褰�
- printDataWithProducts.push({
- ...row,
- products: [],
- });
- }
+ const res = await getPrintData(row.id);
+ const data = res.data || res;
+ companyName = data.companyName || companyName;
+ orders.push(data.ledger);
}
-
- printData.value = printDataWithProducts;
- console.log("鎵撳嵃鏁版嵁锛堝寘鍚骇鍝侊級:", printData.value);
- printPreviewVisible.value = true;
- } catch (error) {
- console.error("鑾峰彇浜у搧鏁版嵁澶辫触:", error);
- proxy.$modal.msgError("鑾峰彇浜у搧鏁版嵁澶辫触锛岃閲嶈瘯");
+ printSalesMulti(companyName, orders);
+ } catch (e) {
+ console.error('鎵撳嵃澶辫触:', e);
+ proxy.$modal.msgError("鎵撳嵃澶辫触");
} finally {
proxy.$modal.closeLoading();
}
};
- // 鎵ц鎵撳嵃
- const executePrint = () => {
- console.log("寮�濮嬫墽琛屾墦鍗帮紝鏁版嵁鏉℃暟:", printData.value.length);
- console.log("鎵撳嵃鏁版嵁:", printData.value);
- // 鍒涘缓涓�涓柊鐨勬墦鍗扮獥鍙�
- const printWindow = window.open("", "_blank", "width=800,height=600");
-
- // 鏋勫缓鎵撳嵃鍐呭
- let printContent = `
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>鎵撳嵃棰勮</title>
- <style>
- body {
- margin: 0;
- padding: 0;
- font-family: "SimSun", serif;
- background: white;
- }
- .print-page {
- width: 200mm;
- height: 75mm;
- padding: 10mm;
- padding-left: 20mm;
- background: white;
- box-sizing: border-box;
- page-break-after: always;
- page-break-inside: avoid;
- }
- .print-page:last-child {
- page-break-after: avoid;
- }
- .delivery-note {
- width: 100%;
- height: 100%;
- font-size: 12px;
- line-height: 1.2;
- display: flex;
- flex-direction: column;
- color: #000;
- }
- .header {
- text-align: center;
- margin-bottom: 8px;
- }
- .company-name {
- font-size: 18px;
- font-weight: bold;
- margin-bottom: 4px;
- }
- .document-title {
- font-size: 16px;
- font-weight: bold;
- }
- .info-section {
- margin-bottom: 8px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .info-row {
- line-height: 20px;
- }
- .label {
- font-weight: bold;
- width: 60px;
- font-size: 12px;
- }
- .value {
- margin-right: 20px;
- min-width: 80px;
- font-size: 12px;
- }
- .table-section {
- margin-bottom: 40px;
- // flex: 0.6;
- }
- .product-table {
- width: 100%;
- border-collapse: collapse;
- border: 1px solid #000;
- }
- .product-table th, .product-table td {
- border: 1px solid #000;
- padding: 6px;
- text-align: center;
- font-size: 12px;
- line-height: 1.4;
- }
- .product-table th {
- font-weight: bold;
- }
- .total-value {
- font-weight: bold;
- }
- .footer-section {
- margin-top: auto;
- }
- .footer-row {
- display: flex;
- margin-bottom: 3px;
- line-height: 22px;
- justify-content: space-between;
- }
- .footer-item {
- display: flex;
- margin-right: 20px;
- }
- .footer-item .label {
- font-weight: bold;
- width: 80px;
- font-size: 12px;
- }
- .footer-item .value {
- min-width: 80px;
- font-size: 12px;
- }
- .address-item .address-value {
- min-width: 200px;
- }
- @media print {
- body {
- margin: 0;
- padding: 0;
- }
- .print-page {
- margin: 0;
- padding: 10mm;
- /* padding-left: 20mm; */
- page-break-inside: avoid;
- page-break-after: always;
- }
- .print-page:last-child {
- page-break-after: avoid;
- }
- }
- </style>
- </head>
- <body>
- `;
-
- // 涓烘瘡鏉℃暟鎹敓鎴愭墦鍗伴〉闈�
- printData.value.forEach((item, index) => {
- printContent += `
- <div class="print-page">
- <div class="delivery-note">
- <div class="header">
- <div class="document-title">闆跺敭鍙戣揣鍗�</div>
- </div>
-
- <div class="info-section">
- <div class="info-row">
- <div>
- <span class="label">鍙戣揣鏃ユ湡锛�</span>
- <span class="value">${formatDate(
- item.createTime
- )}</span>
- </div>
- <div>
- <span class="label">瀹㈡埛鍚嶇О锛�</span>
- <span class="value">${
- item.customerName
- }</span>
- </div>
- </div>
- <div class="info-row">
- <span class="label">鍗曞彿锛�</span>
- <span class="value">${
- item.salesContractNo ||
- ""
- }</span>
- </div>
- </div>
-
- <div class="table-section">
- <table class="product-table">
- <thead>
- <tr>
- <th>浜у搧鍚嶇О</th>
- <th>瑙勬牸鍨嬪彿</th>
- <th>鍗曚綅</th>
- <th>鍗曚环</th>
- <th>闆跺敭鏁伴噺</th>
- <th>闆跺敭閲戦</th>
- </tr>
- </thead>
- <tbody>
- ${
- item.products &&
- item
- .products
- .length >
- 0
- ? item.products
- .map(
- product => `
- <tr>
- <td>${
- product.productCategory ||
- ""
- }</td>
- <td>${
- product.specificationModel ||
- ""
- }</td>
- <td>${
- product.unit ||
- ""
- }</td>
- <td>${
- product.taxInclusiveUnitPrice ||
- "0"
- }</td>
- <td>${
- product.quantity ||
- "0"
- }</td>
- <td>${
- product.taxInclusiveTotalPrice ||
- "0"
- }</td>
- </tr>
- `
- )
- .join(
- ""
- )
- : '<tr><td colspan="6" style="text-align: center; color: #999;">鏆傛棤浜у搧鏁版嵁</td></tr>'
- }
- </tbody>
- <tfoot>
- <tr>
- <td class="label">鍚堣</td>
- <td class="total-value"></td>
- <td class="total-value"></td>
- <td class="total-value"></td>
- <td class="total-value">${getTotalQuantityForPrint(
- item.products
- )}</td>
- <td class="total-value">${getTotalAmountForPrint(
- item.products
- )}</td>
- </tr>
- </tfoot>
- </table>
- </div>
-
- <div class="footer-section">
- <div class="footer-row">
- <div class="footer-item">
- <span class="label">鏀惰揣鐢佃瘽锛�</span>
- <span class="value"></span>
- </div>
- <div class="footer-item">
- <span class="label">鏀惰揣浜猴細</span>
- <span class="value"></span>
- </div>
- <div class="footer-item address-item">
- <span class="label">鏀惰揣鍦板潃锛�</span>
- <span class="value address-value"></span>
- </div>
- </div>
- <div class="footer-row">
- <div class="footer-item">
- <span class="label">鎿嶄綔鍛橈細</span>
- <span class="value">${
- userStore.nickName ||
- "鎾曞紑鍓�"
- }</span>
- </div>
- <div class="footer-item">
- <span class="label">鎵撳嵃鏃ユ湡锛�</span>
- <span class="value">${formatDateTime(
- new Date()
- )}</span>
- </div>
- </div>
- </div>
- </div>
- </div>
- `;
- });
-
- printContent += `
- </body>
- </html>
- `;
-
- // 鍐欏叆鍐呭鍒版柊绐楀彛
- printWindow.document.write(printContent);
- printWindow.document.close();
-
- // 绛夊緟鍐呭鍔犺浇瀹屾垚鍚庢墦鍗�
- printWindow.onload = () => {
- setTimeout(() => {
- printWindow.print();
- printWindow.close();
- printPreviewVisible.value = false;
- }, 500);
- };
- };
// 鏍煎紡鍖栨棩鏈�
const formatDate = dateString => {
if (!dateString) return getCurrentDate();
@@ -2413,7 +2147,7 @@
const total = products.reduce((sum, product) => {
return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
}, 0);
- return total.toFixed(2);
+ return formatDecimal(total);
};
// 鐢ㄤ簬鎵撳嵃鐨勮绠楀嚱鏁�
@@ -2430,7 +2164,7 @@
const total = products.reduce((sum, product) => {
return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
}, 0);
- return total.toFixed(2);
+ return formatDecimal(total);
};
const mathNum = () => {
@@ -2471,7 +2205,7 @@
isCalculating.value = true;
// 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
- productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
+ productForm.value.taxInclusiveUnitPrice = formatDecimal(totalPrice / quantity);
// 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
if (productForm.value.taxRate) {
@@ -2508,12 +2242,12 @@
// 鍏堣绠楀惈绋庢�讳环 = 涓嶅惈绋庢�讳环 / (1 - 绋庣巼/100)
const taxRateDecimal = taxRate / 100;
const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
- productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
+ productForm.value.taxInclusiveTotalPrice = formatDecimal(inclusiveTotalPrice);
// 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
- productForm.value.taxInclusiveUnitPrice = (
+ productForm.value.taxInclusiveUnitPrice = formatDecimal(
inclusiveTotalPrice / quantity
- ).toFixed(2);
+ );
isCalculating.value = false;
};
@@ -2536,7 +2270,7 @@
isCalculating.value = true;
// 璁$畻鍚◣鎬讳环
- productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
+ productForm.value.taxInclusiveTotalPrice = formatDecimal(unitPrice * quantity);
// 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
if (productForm.value.taxRate) {
@@ -2568,7 +2302,7 @@
isCalculating.value = true;
// 璁$畻鍚◣鎬讳环
- productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
+ productForm.value.taxInclusiveTotalPrice = formatDecimal(unitPrice * quantity);
// 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
if (productForm.value.taxRate) {
@@ -2709,6 +2443,28 @@
fileDialogVisible.value = true;
};
+ // 涓嬭浇閿�鍞崟
+ const downloadOrder = async (id) => {
+ try {
+ const res = await getPrintData(id);
+ const data = res.data || res;
+ downloadSalesJpg(data.companyName, data.ledger, '閿�鍞崟_' + (data.ledger.salesContractNo || id) + '.jpg');
+ } catch (e) {
+ console.error('涓嬭浇澶辫触:', e);
+ }
+ };
+
+ // 鎵撳嵃閿�鍞崟
+ const printOrder = async (id) => {
+ try {
+ const res = await getPrintData(id);
+ const data = res.data || res;
+ printSales(data.companyName, data.ledger);
+ } catch (e) {
+ console.error('鎵撳嵃澶辫触:', e);
+ }
+ };
+
// 鎵撳紑鍙戣揣寮规
const openDeliveryForm = async row => {
// 妫�鏌ユ槸鍚﹀彲浠ュ彂璐�
@@ -2727,7 +2483,7 @@
shippingCarNumber: "",
expressCompany: "",
expressNumber: "",
- type: "璐ц溅",
+ type: "蹇��",
batchNo: [],
batchNoList,
};
diff --git a/src/views/salesManagement/salesQuotation/index.vue b/src/views/salesManagement/salesQuotation/index.vue
index fce764f..455f686 100644
--- a/src/views/salesManagement/salesQuotation/index.vue
+++ b/src/views/salesManagement/salesQuotation/index.vue
@@ -65,7 +65,7 @@
</el-table-column>
<el-table-column prop="totalAmount" label="鎶ヤ环閲戦" width="120">
<template #default="scope">
- 楼{{ scope.row.totalAmount.toFixed(2) }}
+ 楼{{ formatDecimal(scope.row.totalAmount) }}
</template>
</el-table-column>
<el-table-column label="鎿嶄綔" width="200" fixed="right" align="center">
@@ -215,7 +215,7 @@
<el-table-column prop="unitPrice" label="鍗曚环">
<template #default="scope">
<el-form-item :prop="`products.${scope.$index}.unitPrice`" class="product-table-form-item">
- <el-input-number v-model="scope.row.unitPrice" :min="0" :precision="2" style="width: 100%" />
+ <el-input-number v-model="scope.row.unitPrice" :min="0" :precision="6" :step="0.000001" style="width: 100%" />
</el-form-item>
</template>
</el-table-column>
@@ -267,7 +267,7 @@
<!-- <el-tag :type="getStatusType(currentQuotation.status)">{{ currentQuotation.status }}</el-tag>-->
<!-- </el-descriptions-item>-->
<el-descriptions-item label="鎶ヤ环鎬婚" :span="2">
- <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">楼{{ currentQuotation.totalAmount?.toFixed(2) }}</span>
+ <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">楼{{ formatDecimal(currentQuotation.totalAmount) }}</span>
</el-descriptions-item>
</el-descriptions>
@@ -279,7 +279,7 @@
<el-table-column prop="unit" label="鍗曚綅" />
<el-table-column prop="unitPrice" label="鍗曚环">
<template #default="scope">
- 楼{{ scope.row.unitPrice.toFixed(2) }}
+ 楼{{ formatDecimal(scope.row.unitPrice) }}
</template>
</el-table-column>
</el-table>
@@ -303,6 +303,7 @@
import {modelList, productTreeList} from "@/api/basicData/product.js";
import {listCustomer} from "@/api/basicData/customer.js";
import { userListNoPage } from "@/api/system/user.js";
+import { formatDecimal, roundAmount } from '@/utils/numberFormat';
// 鍝嶅簲寮忔暟鎹�
const loading = ref(false)
@@ -346,6 +347,7 @@
const baseRules = {
customer: [{ required: true, message: '璇烽�夋嫨瀹㈡埛', trigger: 'change' }],
+ customerId: [{ required: true, message: '璇烽�夋嫨瀹㈡埛', trigger: 'change' }],
salesperson: [{ required: true, message: '璇烽�夋嫨涓氬姟鍛�', trigger: 'change' }],
quotationDate: [{ required: true, message: '璇烽�夋嫨鎶ヤ环鏃ユ湡', trigger: 'change' }],
validDate: [{ required: true, message: '璇烽�夋嫨鏈夋晥鏈�', trigger: 'change' }],
@@ -686,11 +688,11 @@
return
}
- // 璁$畻鎵�鏈変骇鍝佺殑鍗曚环鎬诲拰
- form.totalAmount = form.products.reduce((sum, product) => {
+ // 璁$畻鎵�鏈変骇鍝佺殑鍗曚环鎬诲拰锛屼繚鐣欏叚浣嶅皬鏁�
+ form.totalAmount = roundAmount(form.products.reduce((sum, product) => {
const price = Number(product.unitPrice) || 0
return sum + price
- }, 0)
+ }, 0))
form.customer = customerOption.value.find(item => item.id === form.customerId)?.customerName || ''
if (isEdit.value) {
--
Gitblit v1.9.3