|
@@ -1,4 +1,5 @@
|
|
|
// @ts-check
|
|
|
+/* global BigInt */
|
|
|
|
|
|
/**
|
|
|
* @fileoverview 销售预测表单混入组件
|
|
@@ -58,7 +59,7 @@
|
|
|
|
|
|
// API接口导入
|
|
|
import { addForecast, updateForecast, getForecastDetail } from '@/api/forecast'
|
|
|
-import { batchSaveSalesForecastSummary } from '@/api/forecast/forecast-summary'
|
|
|
+import { addSalesForecastMain } from '@/api/forecast/forecast-summary'
|
|
|
import { getUserLinkGoods } from '@/api/order/sales-order'
|
|
|
|
|
|
// 常量和枚举导入
|
|
@@ -869,8 +870,9 @@ export default {
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
- * 提交表单数据(仅批量保存预测汇总)
|
|
|
+ * 提交表单数据(main-add:提交销售预测主表及子项明细)
|
|
|
* @returns {Promise<void>}
|
|
|
+ * @this {ForecastFormMixinComponent & Vue}
|
|
|
*/
|
|
|
async submitForm() {
|
|
|
try {
|
|
@@ -880,59 +882,89 @@ export default {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- // 组装批量保存载荷,仅保留预测数量>0的行
|
|
|
+ // 转换年份与月份
|
|
|
const year = typeof this.formData.year === 'string' ? parseInt(this.formData.year, 10) : this.formData.year
|
|
|
- const month = this.formData.month
|
|
|
+ const month = Number(this.formData.month)
|
|
|
+
|
|
|
+ // 安全的ID转换:优先使用 BigInt 校验范围,再决定以 number 还是 string 传输
|
|
|
+ const toIdOutput = (val) => {
|
|
|
+ if (val == null || val === '') return ''
|
|
|
+ try {
|
|
|
+ const bi = BigInt(String(val))
|
|
|
+ // 在 JS 中,超过 MAX_SAFE_INTEGER 的数字使用字符串传输,避免精度丢失
|
|
|
+ const absBi = bi >= 0n ? bi : -bi
|
|
|
+ const maxSafe = BigInt(Number.MAX_SAFE_INTEGER)
|
|
|
+ if (absBi <= maxSafe) {
|
|
|
+ // 安全范围内,返回 number
|
|
|
+ return Number(bi)
|
|
|
+ }
|
|
|
+ // 超出安全范围,返回字符串
|
|
|
+ return String(bi)
|
|
|
+ } catch (e) {
|
|
|
+ // 不是纯数字,兜底返回原字符串
|
|
|
+ return String(val)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- const payload = this.stockTableData
|
|
|
+ // 安全的数值转换(用于数量等非ID字段):若不可安全表示整数,仍以字符串传输
|
|
|
+ const toSafeNumberOrString = (val) => {
|
|
|
+ if (val == null || val === '') return 0
|
|
|
+ if (typeof val === 'number') {
|
|
|
+ return Number.isFinite(val) ? val : String(val)
|
|
|
+ }
|
|
|
+ const parsed = Number(val)
|
|
|
+ return Number.isFinite(parsed) ? parsed : String(val)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 组装子项明细,仅保留预测数量>0的行
|
|
|
+ const items = this.stockTableData
|
|
|
.filter(row => Number(row.forecastQuantity) > 0)
|
|
|
.map(row => {
|
|
|
const matchedBrand = this.brandDescList.find(b => b.cname === row.brandName)
|
|
|
+ const rawBrandId = row.brandId != null && row.brandId !== '' ? row.brandId : (matchedBrand ? matchedBrand.id : '')
|
|
|
+ const rawItemId = row.goodsId
|
|
|
|
|
|
- const brandIdRaw = row.brandId != null && row.brandId !== ''
|
|
|
- ? row.brandId
|
|
|
- : (matchedBrand ? matchedBrand.id : null)
|
|
|
- const itemIdRaw = row.goodsId
|
|
|
-
|
|
|
- const toSafeNumberOrString = (val) => {
|
|
|
- if (val == null || val === '') return 0
|
|
|
- if (typeof val === 'number') {
|
|
|
- return Number.isSafeInteger(val) ? val : String(val)
|
|
|
- }
|
|
|
- const parsed = Number(val)
|
|
|
- return Number.isSafeInteger(parsed) ? parsed : String(val)
|
|
|
- }
|
|
|
-
|
|
|
- const brandId = toSafeNumberOrString(brandIdRaw)
|
|
|
- const itemId = toSafeNumberOrString(itemIdRaw)
|
|
|
+ const brandId = toIdOutput(rawBrandId)
|
|
|
+ const itemId = toIdOutput(rawItemId)
|
|
|
|
|
|
return {
|
|
|
- year: year || new Date().getFullYear(),
|
|
|
- month: month || (new Date().getMonth() + 1),
|
|
|
+ // ID与编码/名称:缺失则置空
|
|
|
brandId: brandId,
|
|
|
- brandCode: '',
|
|
|
+ brandCode: row.brandCode || '',
|
|
|
brandName: row.brandName || (matchedBrand ? matchedBrand.cname : ''),
|
|
|
itemId: itemId,
|
|
|
itemCode: row.code || '',
|
|
|
itemName: row.cname || '',
|
|
|
+ // 规格与花纹:无则空
|
|
|
specs: row.typeNo || '',
|
|
|
pattern: row.productDescription || row.brandItem || '',
|
|
|
- forecastQuantity: Number(row.forecastQuantity) || 0,
|
|
|
- approvalStatus: this.formData.approvalStatus || 0
|
|
|
+ // 数量:保留为 number(有限数),否则以字符串兜底
|
|
|
+ forecastQuantity: toSafeNumberOrString(row.forecastQuantity),
|
|
|
+ // 子项审批状态:与顶层保持一致,缺省为待提交
|
|
|
+ approvalStatus: Number(this.formData.approvalStatus ?? 0)
|
|
|
}
|
|
|
})
|
|
|
|
|
|
- if (!payload.length) {
|
|
|
+ if (!items.length) {
|
|
|
this.$message && this.$message.warning('请至少填写一条有效的预测数量')
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- const res = await batchSaveSalesForecastSummary(payload)
|
|
|
+ // 组装 main-add 载荷
|
|
|
+ const payload = {
|
|
|
+ year: year || new Date().getFullYear(),
|
|
|
+ month: month || (new Date().getMonth() + 1),
|
|
|
+ approvalStatus: Number(this.formData.approvalStatus ?? 0),
|
|
|
+ pcBladeSalesForecastSummaryList: items
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = await addSalesForecastMain(payload)
|
|
|
if (res && res.data && res.data.success) {
|
|
|
- this.$message && this.$message.success('保存成功')
|
|
|
+ this.$message && this.$message.success('提交成功')
|
|
|
this.$emit && this.$emit(FORECAST_FORM_EVENTS.SUBMIT, res.data)
|
|
|
+ this.$emit && this.$emit(FORECAST_FORM_EVENTS.SUBMIT_SUCCESS, res.data)
|
|
|
} else {
|
|
|
- const msg = (res && res.data && (res.data.msg || res.data.message)) || '保存失败'
|
|
|
+ const msg = (res && res.data && (res.data.msg || res.data.message)) || '提交失败'
|
|
|
this.$message && this.$message.error(msg)
|
|
|
}
|
|
|
} catch (error) {
|