diff --git a/Antis.Erp.Plat/antis-ncc-admin/src/views/douyinLogistics/CreateWaybill.vue b/Antis.Erp.Plat/antis-ncc-admin/src/views/douyinLogistics/CreateWaybill.vue index 90e4f12..a9d0fa2 100644 --- a/Antis.Erp.Plat/antis-ncc-admin/src/views/douyinLogistics/CreateWaybill.vue +++ b/Antis.Erp.Plat/antis-ncc-admin/src/views/douyinLogistics/CreateWaybill.vue @@ -144,20 +144,11 @@ 优惠金额 {{ formatDiscountFen(form.orderAmountFen, form.payAmountFen) }} -
+
商家实际收入 -
- -
+ + {{ form.merchantIncome !== null && form.merchantIncome !== undefined ? `¥${Number(form.merchantIncome).toFixed(2)}` : '' }} +
@@ -184,6 +175,9 @@
暂无图片
{{ item.product_name }}
+
+ ERP:{{ item.erp_spmc || '-' }} +
SKUID:{{ getSkuCode(item) }} ({{ formatSpec(item.spec) }}) @@ -318,8 +312,8 @@ @@ -1185,6 +1179,7 @@ const loadOrderDetail = async () => { selectedSerialNumbers: item.selectedSerialNumbers || [], // 序列号列表 spxlhLoaded: false, // 序列号类型是否已加载 spxlhType: item.spxlhType || '', // 序列号类型 + erp_spmc: item.erp_spmc || item.ErpSpmc || item.erpProductName || item.spmc || item.Spmc || '', // ERP 商品名称 erpSpbh: '' // ERP 商品主键 Id,用于 UpdateSerialNumberStatus 手动录入序列号 } @@ -1275,6 +1270,7 @@ const addProduct = async (product) => { // 添加商品到清单 const newProduct = { product_name: product.spmc || '', + erp_spmc: product.spmc || '', product_pic: resolveProductPicUrl(productPic || product.imageUrl || ''), // ERP 添加的商品没有抖音图,ERP 图直接填 erp_pic,用于"商品清单"展示 douyin_pic: '', @@ -1850,7 +1846,6 @@ const handleSubmit = async () => { remark: form.value.remark, douyinOrderIds: form.value.orderId_Douyin || '', mergedOrderInternalIds: mergedInternalIds.value.length > 1 ? mergedInternalIds.value : undefined, - merchantIncome: form.value.merchantIncome, fhr: form.value.fhr }) @@ -2430,6 +2425,10 @@ onMounted(() => { color: #e6a23c; } +.amount-readonly { + color: #606266; +} + /* ── 商品明细(订单信息右列):多件时纵向滚动,避免把整页撑过长 ── */ .order-product-list { max-height: min(380px, 42vh); diff --git a/Antis.Erp.Plat/antis-ncc-admin/src/views/douyinLogistics/OrderList.vue b/Antis.Erp.Plat/antis-ncc-admin/src/views/douyinLogistics/OrderList.vue index b2f6a17..3b83c87 100644 --- a/Antis.Erp.Plat/antis-ncc-admin/src/views/douyinLogistics/OrderList.vue +++ b/Antis.Erp.Plat/antis-ncc-admin/src/views/douyinLogistics/OrderList.vue @@ -89,6 +89,7 @@ + @@ -109,6 +110,9 @@ + + + 卖家:{{ row.sellerWords }}
+
+ 编辑并回传抖音 +
-
@@ -474,13 +481,38 @@ 确认发货
+ + + + + {{ remarkForm.orderDisplay }} + + + + + + + + +
+ 取消 + 保存并回传抖音 +
+
diff --git a/Antis.Erp.Plat/antis-ncc-admin/src/views/wtBsd/Form.vue b/Antis.Erp.Plat/antis-ncc-admin/src/views/wtBsd/Form.vue index 41254b6..be151ad 100644 --- a/Antis.Erp.Plat/antis-ncc-admin/src/views/wtBsd/Form.vue +++ b/Antis.Erp.Plat/antis-ncc-admin/src/views/wtBsd/Form.vue @@ -513,12 +513,12 @@ getcjckOptions(){ - previewDataInterface('681758216954053893').then(res => { + return previewDataInterface('681758216954053893').then(res => { this.cjckOptions = res.data }); }, getrkckOptions(){ - previewDataInterface('681758216954053893').then(res => { + return previewDataInterface('681758216954053893').then(res => { this.rkckOptions = res.data }); }, @@ -543,10 +543,35 @@ // }); // }, getckckOptions(){ - previewDataInterface('681758216954053893').then(res => { + return previewDataInterface('681758216954053893').then(res => { this.ckckOptions = res.data }); }, + /** + * 详情接口返回时后端已把 ckck/rkck/cjck/rkck 替换为展示名称(门店名称), + * 但编辑页的 el-select 绑定的是 ID;这里把名称反查回 ID,避免: + * 1) 仓库下拉显示空 + * 2) 按名称查询库存失败 → 账面库存为 0 不显示 + */ + resolveIdByName(val, options) { + if (val == null || val === '') return val; + const v = String(val).trim(); + if (!options || !options.length) return val; + // 若已经是合法 ID(命中选项 F_Id),直接返回 + if (options.some(o => o && String(o.F_Id) === v)) return val; + // 否则尝试按名称反查 + const hit = options.find(o => o && (o.F_mdmc === v || o.F_ckmc === v || o.F_name === v)); + return hit ? hit.F_Id : val; + }, + async ensureWarehouseOptionsReady() { + const tasks = []; + if (!this.cjckOptions || !this.cjckOptions.length) tasks.push(this.getcjckOptions()); + if (!this.rkckOptions || !this.rkckOptions.length) tasks.push(this.getrkckOptions()); + if (!this.ckckOptions || !this.ckckOptions.length) tasks.push(this.getckckOptions()); + if (tasks.length > 0) { + try { await Promise.all(tasks); } catch (e) { /* 选项加载失败时降级继续 */ } + } + }, // getspbhOptions(){ // previewDataInterface('675937572047815941').then(res => { // this.spbhOptions = res.data @@ -612,26 +637,86 @@ request({ url: '/api/Extend/WtXsckd/' +id, method: 'get' - }).then(res =>{ + }).then(async res =>{ _this.dataForm = res.data; console.log('编辑时加载的数据:', _this.dataForm); console.log('明细数据:', _this.dataForm.wtXsckdMxList); - // 为每个明细项添加productQuery字段 + // 后端详情接口会把 cjck / 明细 ckck 等字段由 ID 替换为展示名称; + // 编辑页 el-select 绑的是 ID,且 getStockQuantity 也需要 ID, + // 这里等仓库选项加载好后做一次「名称 → ID」反查,解决账面库存不显示问题 + await _this.ensureWarehouseOptionsReady(); + _this.dataForm.cjck = _this.resolveIdByName(_this.dataForm.cjck, _this.cjckOptions); + _this.dataForm.rkck = _this.resolveIdByName(_this.dataForm.rkck, _this.rkckOptions); + if (_this.dataForm.wtXsckdMxList) { _this.dataForm.wtXsckdMxList.forEach(item => { if (!item.hasOwnProperty('productQuery')) { _this.$set(item, 'productQuery', ''); } + if (!item.hasOwnProperty('loadingStock')) { + _this.$set(item, 'loadingStock', false); + } + // kucun 后端未落库,这里先显式声明为响应式属性, + // 后续 getStockQuantity 在 catch/else 分支中直接赋值才能触发视图更新 + if (!item.hasOwnProperty('kucun')) { + _this.$set(item, 'kucun', undefined); + } + // 明细仓库字段同样做名称→ID 反查 + _this.$set(item, 'ckck', _this.resolveIdByName(item.ckck, _this.ckckOptions)); + if (item.rkck) { + _this.$set(item, 'rkck', _this.resolveIdByName(item.rkck, _this.rkckOptions)); + } + // 金额回显:若后端 je 为 0 但 sl/dj 有值,则按 sl*dj 重算;否则回退使用 cbje + const slNum = parseFloat(item.sl) || 0; + const djNum = parseFloat(item.dj) || 0; + const jeNum = parseFloat(item.je) || 0; + const cbjeNum = parseFloat(item.cbje) || 0; + if (jeNum === 0) { + if (slNum > 0 && djNum > 0) { + _this.$set(item, 'je', (slNum * djNum).toFixed(2)); + } else if (cbjeNum > 0) { + _this.$set(item, 'je', cbjeNum.toFixed(2)); + if (djNum === 0) { + const cbdjNum = parseFloat(item.cbdj) || 0; + if (cbdjNum > 0) _this.$set(item, 'dj', cbdjNum.toFixed(4)); + } + } + } }); } - // 初始化时计算总金额 _this.calculateTotalAmount(); - // 同步明细表出库仓库 _this.syncDetailWarehouses(); - // 恢复序列号信息 _this.restoreSerialNumbers(); + // 序列号类型(spxlhType)只缓存在 productCache 中,且 row.spxlhLoaded + // 仅在 handleProductChange 里被置 true;打开已有单据需要主动拉一次, + // 否则「序列号类型」列会一直显示「加载中...」 + if (_this.dataForm.wtXsckdMxList && _this.dataForm.wtXsckdMxList.length > 0) { + _this.dataForm.wtXsckdMxList.forEach(item => { + if (!item.hasOwnProperty('spxlhLoaded')) { + _this.$set(item, 'spxlhLoaded', false); + } + }); + _this.getAllProductSerialNumberTypes().then(() => { + _this.dataForm.wtXsckdMxList.forEach(item => { + if (item.spbh) { + _this.$set(item, 'spxlhLoaded', true); + } + }); + _this.$forceUpdate(); + }).catch(err => { + console.error('批量获取序列号类型失败:', err); + }); + } + // 账面库存不落库,重新点开必须按商品+仓库查询刷新(此时 ckck 已是 ID) + if (_this.dataForm.wtXsckdMxList) { + _this.dataForm.wtXsckdMxList.forEach(item => { + if (item.spbh && item.ckck) { + _this.getStockQuantity(item); + } + }); + } }) } else{ @@ -639,10 +724,26 @@ } }) }, + // 校验所有明细的报损数量不超过账面库存 + validateBsdSlNotExceedKucun() { + const list = this.dataForm.wtXsckdMxList || []; + for (let i = 0; i < list.length; i++) { + const row = list[i]; + if (!row || !row.spbh) continue; + const sl = parseFloat(row.sl); + const kucun = parseFloat(row.kucun); + if (!isNaN(kucun) && !isNaN(sl) && sl > kucun) { + this.$message.error(`第${i + 1}行商品"${row.spmc || ''}"报损数量(${sl})超过账面库存(${kucun}),请先修正`); + return false; + } + } + return true; + }, // 保存草稿:只做基础表单校验,不做序列号强校验,保存时带isDraft:true字段 async saveDraft() { // 确保单据类型字段赋值 this.dataForm.djlx = '报损单'; + if (!this.validateBsdSlNotExceedKucun()) return; this.$refs['elForm'].validate(async (valid) => { if (valid) { try { @@ -685,6 +786,7 @@ this.$message.warning(`第 ${mxCheck.emptyLineNos.join('、')} 行未选择商品,请先删除空白行后再提交`) return } + if (!this.validateBsdSlNotExceedKucun()) return; // 1. 明细校验:序列号数量与销售数量一致性 let validationErrors = []; for (let i = 0; i < this.dataForm.wtXsckdMxList.length; i++) { @@ -1032,8 +1134,15 @@ } }, handleAmountChange(row) { - const sl = parseFloat(row.sl) || 0; + let sl = parseFloat(row.sl) || 0; const dj = parseFloat(row.dj) || 0; + // 报损数量不能超过账面库存 + const kucun = parseFloat(row.kucun); + if (!isNaN(kucun) && sl > kucun) { + this.$message.warning(`商品"${row.spmc || ''}"报损数量(${sl})不能超过账面库存(${kucun})`); + sl = kucun; + row.sl = kucun.toString(); + } row.je = (sl * dj).toFixed(2); // 自动计算总收款金额 this.calculateTotalAmount(); diff --git a/Antis.Erp.Plat/antis-ncc-admin/src/views/wtByd/Form.vue b/Antis.Erp.Plat/antis-ncc-admin/src/views/wtByd/Form.vue index 5f0fdba..db3189e 100644 --- a/Antis.Erp.Plat/antis-ncc-admin/src/views/wtByd/Form.vue +++ b/Antis.Erp.Plat/antis-ncc-admin/src/views/wtByd/Form.vue @@ -513,12 +513,12 @@ getcjckOptions(){ - previewDataInterface('681758216954053893').then(res => { + return previewDataInterface('681758216954053893').then(res => { this.cjckOptions = res.data }); }, getrkckOptions(){ - previewDataInterface('681758216954053893').then(res => { + return previewDataInterface('681758216954053893').then(res => { this.rkckOptions = res.data }); }, @@ -543,10 +543,31 @@ // }); // }, getckckOptions(){ - previewDataInterface('681758216954053893').then(res => { + return previewDataInterface('681758216954053893').then(res => { this.ckckOptions = res.data }); }, + /** + * 后端详情接口会把仓库字段由 ID 替换成展示名称,编辑页绑定 ID, + * 这里做名称→ID 反查,确保下拉能回显、按 ID 查账面库存生效 + */ + resolveIdByName(val, options) { + if (val == null || val === '') return val; + const v = String(val).trim(); + if (!options || !options.length) return val; + if (options.some(o => o && String(o.F_Id) === v)) return val; + const hit = options.find(o => o && (o.F_mdmc === v || o.F_ckmc === v || o.F_name === v)); + return hit ? hit.F_Id : val; + }, + async ensureWarehouseOptionsReady() { + const tasks = []; + if (!this.cjckOptions || !this.cjckOptions.length) tasks.push(this.getcjckOptions()); + if (!this.rkckOptions || !this.rkckOptions.length) tasks.push(this.getrkckOptions()); + if (!this.ckckOptions || !this.ckckOptions.length) tasks.push(this.getckckOptions()); + if (tasks.length > 0) { + try { await Promise.all(tasks); } catch (e) { /* 选项加载失败时降级继续 */ } + } + }, // getspbhOptions(){ // previewDataInterface('675937572047815941').then(res => { // this.spbhOptions = res.data @@ -612,26 +633,86 @@ request({ url: '/api/Extend/WtXsckd/' +id, method: 'get' - }).then(res =>{ + }).then(async res =>{ _this.dataForm = res.data; console.log('编辑时加载的数据:', _this.dataForm); console.log('明细数据:', _this.dataForm.wtXsckdMxList); - // 为每个明细项添加productQuery字段 + // 后端详情接口会把 cjck / 明细 ckck 字段由 ID 替换为展示名称; + // 编辑页 el-select 绑的是 ID,且 getStockQuantity 也需要 ID, + // 这里等仓库选项加载好后做一次「名称 → ID」反查 + await _this.ensureWarehouseOptionsReady(); + _this.dataForm.cjck = _this.resolveIdByName(_this.dataForm.cjck, _this.cjckOptions); + _this.dataForm.rkck = _this.resolveIdByName(_this.dataForm.rkck, _this.rkckOptions); + if (_this.dataForm.wtXsckdMxList) { _this.dataForm.wtXsckdMxList.forEach(item => { if (!item.hasOwnProperty('productQuery')) { _this.$set(item, 'productQuery', ''); } + if (!item.hasOwnProperty('loadingStock')) { + _this.$set(item, 'loadingStock', false); + } + // kucun 后端未落库,这里先显式声明为响应式属性, + // 后续 getStockQuantity 在 catch/else 分支中直接赋值才能触发视图更新 + if (!item.hasOwnProperty('kucun')) { + _this.$set(item, 'kucun', undefined); + } + // 明细仓库字段同样做名称→ID 反查 + _this.$set(item, 'ckck', _this.resolveIdByName(item.ckck, _this.ckckOptions)); + if (item.rkck) { + _this.$set(item, 'rkck', _this.resolveIdByName(item.rkck, _this.rkckOptions)); + } + // 金额回显:若后端 je 为 0 但 sl/dj 有值,则按 sl*dj 重算;否则回退使用 cbje + const slNum = parseFloat(item.sl) || 0; + const djNum = parseFloat(item.dj) || 0; + const jeNum = parseFloat(item.je) || 0; + const cbjeNum = parseFloat(item.cbje) || 0; + if (jeNum === 0) { + if (slNum > 0 && djNum > 0) { + _this.$set(item, 'je', (slNum * djNum).toFixed(2)); + } else if (cbjeNum > 0) { + _this.$set(item, 'je', cbjeNum.toFixed(2)); + if (djNum === 0) { + const cbdjNum = parseFloat(item.cbdj) || 0; + if (cbdjNum > 0) _this.$set(item, 'dj', cbdjNum.toFixed(4)); + } + } + } }); } - // 初始化时计算总金额 _this.calculateTotalAmount(); - // 同步明细表出库仓库 _this.syncDetailWarehouses(); - // 恢复序列号信息 _this.restoreSerialNumbers(); + // 序列号类型(spxlhType)只缓存在 productCache 中,且 row.spxlhLoaded + // 仅在 handleProductChange 里被置 true;打开已有单据需要主动拉一次, + // 否则「序列号类型」列会一直显示「加载中...」 + if (_this.dataForm.wtXsckdMxList && _this.dataForm.wtXsckdMxList.length > 0) { + _this.dataForm.wtXsckdMxList.forEach(item => { + if (!item.hasOwnProperty('spxlhLoaded')) { + _this.$set(item, 'spxlhLoaded', false); + } + }); + _this.getAllProductSerialNumberTypes().then(() => { + _this.dataForm.wtXsckdMxList.forEach(item => { + if (item.spbh) { + _this.$set(item, 'spxlhLoaded', true); + } + }); + _this.$forceUpdate(); + }).catch(err => { + console.error('批量获取序列号类型失败:', err); + }); + } + // 账面库存不落库,重新点开必须按商品+仓库查询刷新(此时 ckck 已是 ID) + if (_this.dataForm.wtXsckdMxList) { + _this.dataForm.wtXsckdMxList.forEach(item => { + if (item.spbh && item.ckck) { + _this.getStockQuantity(item); + } + }); + } }) } else{ diff --git a/Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgrkd/Form.vue b/Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgrkd/Form.vue index ef4f317..38030a4 100644 --- a/Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgrkd/Form.vue +++ b/Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgrkd/Form.vue @@ -1,7 +1,7 @@