From 2f8d0ee7be402db4d4620b0e6e6173dd9efcc858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B8=B8=E7=86=9F=E5=90=B4=E5=BD=A6=E7=A5=96?= Date: Tue, 8 Sep 2026 15:26:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=B7=E6=A0=BC=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/initialImport.js | 28 ++ src/api/supplier/priceSheetReport.js | 14 + .../modules/srmSupplier/supplierList.vue | 62 ++- .../modules/supplier/priceSheetReport.vue | 364 ++++++++++++++++++ src/views/modules/sys/initialImport.vue | 71 +++- 5 files changed, 516 insertions(+), 23 deletions(-) create mode 100644 src/api/supplier/priceSheetReport.js create mode 100644 src/views/modules/supplier/priceSheetReport.vue diff --git a/src/api/initialImport.js b/src/api/initialImport.js index 2986924..42e0e5d 100644 --- a/src/api/initialImport.js +++ b/src/api/initialImport.js @@ -27,3 +27,31 @@ export const saveSupplierPrice = data => http({ data: http.adornData(data), timeout: 600000 }) + +export const downloadPartSkuTemplate = () => http({ + url: http.adornUrl('/sys/initialImport/partSku/template'), + method: 'get', + responseType: 'blob' +}) + +export const previewPartSku = (file, site) => { + const formData = new FormData() + formData.append('file', file) + formData.append('site', site) + return http({ + url: http.adornUrl('/sys/initialImport/partSku/preview'), + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + }, + timeout: 120000 + }) +} + +export const savePartSku = data => http({ + url: http.adornUrl('/sys/initialImport/partSku/save'), + method: 'post', + data: http.adornData(data), + timeout: 600000 +}) diff --git a/src/api/supplier/priceSheetReport.js b/src/api/supplier/priceSheetReport.js new file mode 100644 index 0000000..7419bce --- /dev/null +++ b/src/api/supplier/priceSheetReport.js @@ -0,0 +1,14 @@ +import { createAPI } from '@/utils/httpRequest.js' + +export const getPriceListPage = data => createAPI('/supplier/priceSheetReport/priceListPage', 'post', data) + +export const getHandlingChargePage = data => createAPI('/supplier/priceSheetReport/handlingChargePage', 'post', data) + +export const getPaymentTermsPage = data => createAPI('/supplier/priceSheetReport/paymentTermsPage', 'post', data) + +export const exportPriceSheetReport = data => createAPI( + '/supplier/priceSheetReport/export', + 'post', + data, + { responseType: 'blob', timeout: 600000 } +) diff --git a/src/views/modules/srmSupplier/supplierList.vue b/src/views/modules/srmSupplier/supplierList.vue index f0a09ff..f0376fb 100644 --- a/src/views/modules/srmSupplier/supplierList.vue +++ b/src/views/modules/srmSupplier/supplierList.vue @@ -67,6 +67,9 @@ {{ scope.row.status }} + + {{ formatSupplierNumberDisplay(scope.row[item.columnProp]) }} + {{ scope.row[item.columnProp] }} - +
+ + + + + + - + @@ -713,7 +722,25 @@ export default { { userId: this.$store.state.user.name, functionId: this.functionId, - serialNumber: '811001Table1DeliveryTerm', + serialNumber: '811001Table1MinShipAccount', + tableId: '811001Table1', + tableName: '供应商信息', + columnProp: 'minShipAccount', + headerAlign: 'center', + align: 'center', + columnLabel: '最低出货金额', + columnWidth: '120', + columnHidden: false, + columnImage: false, + columnSortable: false, + sortLv: 0, + status: true, + fixed: false + }, + { + userId: this.$store.state.user.name, + functionId: this.functionId, + serialNumber: '811001Table1HandlingCharge', tableId: '811001Table1', tableName: '供应商信息', columnProp: 'handlingCharge', @@ -1253,7 +1280,8 @@ export default { taxCode:'', paymentTerm:'', deliveryTerm:'', - handlingCharge:'', + minShipAccount: 0, + handlingCharge: 0, contract:'', phoneNo: '', phoneNo2:'', @@ -1324,6 +1352,21 @@ export default { 'status-inactive': status === 'Inactive' } }, + /** + * 查询列表数值去尾零。 + * 业务意图:最低出货金额/手续费按“去尾零”展示,整数显示为 1 而不是 1.000。 + * 边界:空值显示空;非数字原样返回。 + */ + formatSupplierNumberDisplay (value) { + if (value === null || value === undefined || value === '') { + return '' + } + const num = Number(value) + if (!Number.isFinite(num)) { + return String(value) + } + return String(num) + }, loadMainOrReminder () { const raw = this.$route.query.docExpireSupplierIds if (raw !== undefined && raw !== null && String(raw).trim() !== '') { @@ -1651,6 +1694,8 @@ export default { taxCode:'', paymentTerm:'', deliveryTerm:'', + minShipAccount: 0, + handlingCharge: 0, contract:'', phoneNo: '', phoneNo2:'', @@ -1687,7 +1732,14 @@ export default { // 列表展示使用 user_display,编辑回填需恢复为账号 buyer: this.currentRow.buyerAccount || this.currentRow.buyer || '', sourcingStaff: this.currentRow.sourcingStaffAccount || this.currentRow.sourcingStaff || '', - planner: this.currentRow.plannerAccount || this.currentRow.planner || '' + planner: this.currentRow.plannerAccount || this.currentRow.planner || '', + // 价格字段空值按 0 回填,避免编辑框出现 null - rqrq + minShipAccount: this.currentRow.minShipAccount === null || this.currentRow.minShipAccount === undefined || this.currentRow.minShipAccount === '' + ? 0 + : this.currentRow.minShipAccount, + handlingCharge: this.currentRow.handlingCharge === null || this.currentRow.handlingCharge === undefined || this.currentRow.handlingCharge === '' + ? 0 + : this.currentRow.handlingCharge } this.loadSupplierDocTypeOptions() this.supplierDialogVisible = true diff --git a/src/views/modules/supplier/priceSheetReport.vue b/src/views/modules/supplier/priceSheetReport.vue new file mode 100644 index 0000000..6246ed0 --- /dev/null +++ b/src/views/modules/supplier/priceSheetReport.vue @@ -0,0 +1,364 @@ + + + + + diff --git a/src/views/modules/sys/initialImport.vue b/src/views/modules/sys/initialImport.vue index e37bf28..84fddf6 100644 --- a/src/views/modules/sys/initialImport.vue +++ b/src/views/modules/sys/initialImport.vue @@ -23,10 +23,10 @@
+ class="initial-import-preview"> import { + downloadPartSkuTemplate, downloadSupplierPriceTemplate, + previewPartSku, previewSupplierPrice, + savePartSku, saveSupplierPrice } from '@/api/initialImport' @@ -113,8 +116,14 @@ export default { type: 'supplierPrice', name: '供应商价格期初导入', description: '导入供应商物料的MOQ、阶梯数量和阶梯价格。' + }, + { + type: 'partSku', + name: '物料SKU导入', + description: '按Item更新物料SKU,不存在的SKU会自动新增。' } ], + activeImportType: '', dialogVisible: false, previewLoading: false, saving: false, @@ -123,7 +132,7 @@ export default { previewRows: [], missingItems: [], missingSuppliers: [], - columns: [ + supplierPriceColumns: [ { prop: 'rawCode', label: 'RAW CODE', width: 120, align: 'center' }, { prop: 'supplier', label: 'Short_NPC', width: 100, align: 'center' }, { prop: 'moqColor', label: 'MOQ/COLOR', width: 80, align: 'center' }, @@ -144,14 +153,31 @@ export default { { prop: 'priceTier6', label: 'Price_Tier_6', width: 90, align: 'center' }, { prop: 'priceTier7', label: 'Price_Tier_7', width: 90, align: 'center' }, { prop: 'priceTier8', label: 'Price_Tier_8', width: 90, align: 'center' } + ], + partSkuColumns: [ + { prop: 'item', label: 'ITEM', width: 220, align: 'left' }, + { prop: 'sku', label: 'SKU', width: 220, align: 'left' } ] } }, + computed: { + activeColumns () { + return this.activeImportType === 'partSku' ? this.partSkuColumns : this.supplierPriceColumns + }, + dialogTitle () { + return this.activeImportType === 'partSku' ? '物料SKU导入' : '供应商价格期初导入' + }, + dialogWidth () { + return this.activeImportType === 'partSku' ? '680px' : '94%' + } + }, methods: { openImportDialog (type) { - if (type !== 'supplierPrice') { + if (type !== 'supplierPrice' && type !== 'partSku') { return } + this.resetDialog() + this.activeImportType = type this.dialogVisible = true }, handleFileChange (file) { @@ -170,7 +196,8 @@ export default { this.missingItems = [] this.missingSuppliers = [] this.previewLoading = true - previewSupplierPrice(rawFile, site).then(({ data }) => { + const previewRequest = this.activeImportType === 'partSku' ? previewPartSku : previewSupplierPrice + previewRequest(rawFile, site).then(({ data }) => { if (data && data.code === 0) { this.previewRows = data.data || [] this.missingItems = data.missingItems || [] @@ -200,14 +227,20 @@ export default { }, handleDownloadTemplate () { this.templateDownloading = true - downloadSupplierPriceTemplate().then(response => { + const downloadRequest = this.activeImportType === 'partSku' + ? downloadPartSkuTemplate + : downloadSupplierPriceTemplate + const downloadFileName = this.activeImportType === 'partSku' + ? '物料SKU期初导入模板.xlsx' + : '供应商价格期初导入模板.xlsx' + downloadRequest().then(response => { const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }) const url = window.URL.createObjectURL(blob) const link = document.createElement('a') link.href = url - link.download = '供应商价格期初导入模板.xlsx' + link.download = downloadFileName document.body.appendChild(link) link.click() document.body.removeChild(link) @@ -231,7 +264,7 @@ export default { const invalidCount = this.previewRows.filter(row => row && row.valid === false).length if (invalidCount > 0) { this.$confirm( - `存在${invalidCount}行淡黄色数据。如果继续保存,不存在的数据行将跳过,是否继续?`, + `存在${invalidCount}行淡黄色数据。如果继续保存,无效数据行将跳过,是否继续?`, '数据校验提示', { confirmButtonText: '继续保存', @@ -247,7 +280,8 @@ export default { }, performSave (site) { this.saving = true - saveSupplierPrice({ + const saveRequest = this.activeImportType === 'partSku' ? savePartSku : saveSupplierPrice + saveRequest({ site, rows: this.previewRows }).then(({ data }) => { @@ -277,7 +311,7 @@ export default { if (this.missingItems.length) { messages.push(`以下Item不存在:${this.missingItems.join('、')}`) } - if (this.missingSuppliers.length) { + if (this.activeImportType === 'supplierPrice' && this.missingSuppliers.length) { messages.push(`以下供应商简称不存在:${this.missingSuppliers.join('、')}`) } const content = this.$createElement( @@ -300,11 +334,12 @@ export default { }, clearSelectedFile () { this.fileName = '' - if (this.$refs.supplierPriceUpload) { - this.$refs.supplierPriceUpload.clearFiles() + if (this.$refs.initialImportUpload) { + this.$refs.initialImportUpload.clearFiles() } }, resetDialog () { + this.activeImportType = '' this.previewLoading = false this.saving = false this.templateDownloading = false @@ -364,15 +399,15 @@ export default { font-variant-numeric: tabular-nums; } -.supplier-price-preview { +.initial-import-preview { width: 100%; } -.supplier-price-preview /deep/ .initial-import-warning-row > td { +.initial-import-preview /deep/ .initial-import-warning-row > td { background-color: #fff7d6 !important; } -.supplier-price-preview /deep/ .initial-import-warning-row:hover > td { +.initial-import-preview /deep/ .initial-import-warning-row:hover > td { background-color: #fff0b3 !important; }