Browse Source

价格表

master
常熟吴彦祖 2 weeks ago
parent
commit
df2786021a
  1. 6
      src/api/initialImport.js
  2. 7
      src/views/modules/supplier/priceSheetReport.vue
  3. 98
      src/views/modules/supplier/supplierPartMoqPrice.vue
  4. 2
      src/views/modules/supplier/supplierPartTierPriceHistory.vue
  5. 146
      src/views/modules/sys/initialImport.vue

6
src/api/initialImport.js

@ -25,7 +25,8 @@ export const saveSupplierPrice = data => http({
url: http.adornUrl('/sys/initialImport/supplierPrice/save'), url: http.adornUrl('/sys/initialImport/supplierPrice/save'),
method: 'post', method: 'post',
data: http.adornData(data), data: http.adornData(data),
timeout: 600000
// 价格导入保存较慢,单独给 30 分钟,避免大批量写入被默认超时打断。
timeout: 30 * 60 * 1000
}) })
export const downloadPartSkuTemplate = () => http({ export const downloadPartSkuTemplate = () => http({
@ -86,5 +87,6 @@ export const savePoOrderBatch = data => http({
url: http.adornUrl('/pODetail/importCreatePoOrder/save'), url: http.adornUrl('/pODetail/importCreatePoOrder/save'),
method: 'post', method: 'post',
data: http.adornData(data), data: http.adornData(data),
timeout: 600000
// PO 导入保存较慢,单独给 30 分钟,避免大批量写入被默认超时打断。
timeout: 30 * 60 * 1000
}) })

7
src/views/modules/supplier/priceSheetReport.vue

@ -61,7 +61,7 @@
</el-form> </el-form>
<el-tabs v-model="activeTab" type="border-card" @tab-click="handleTabClick"> <el-tabs v-model="activeTab" type="border-card" @tab-click="handleTabClick">
<el-tab-pane label="price list" name="priceList">
<el-tab-pane label="Price List" name="priceList">
<el-table <el-table
ref="priceListTable" ref="priceListTable"
v-loading="tabState.priceList.loading" v-loading="tabState.priceList.loading"
@ -75,6 +75,7 @@
<el-table-column prop="supplier" label="SUPPLIER" min-width="130" header-align="center" align="left" show-overflow-tooltip /> <el-table-column prop="supplier" label="SUPPLIER" min-width="130" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="moqColor" label="MOQ/COLOR" min-width="120" header-align="center" align="right" :formatter="formatNumberCell" /> <el-table-column prop="moqColor" label="MOQ/COLOR" min-width="120" header-align="center" align="right" :formatter="formatNumberCell" />
<el-table-column prop="qtyPo" label="QTY/PO" min-width="110" header-align="center" align="right" :formatter="formatNumberCell" /> <el-table-column prop="qtyPo" label="QTY/PO" min-width="110" header-align="center" align="right" :formatter="formatNumberCell" />
<el-table-column prop="qtyCarton" label="QTY/CARTON" min-width="120" header-align="center" align="right" :formatter="formatNumberCell" />
<el-table-column prop="startDate" label="START DATE" min-width="120" header-align="center" align="center" /> <el-table-column prop="startDate" label="START DATE" min-width="120" header-align="center" align="center" />
<el-table-column prop="tierQty1" label="Tier_QTY_1" min-width="120" header-align="center" align="right" :formatter="formatNumberCell" /> <el-table-column prop="tierQty1" label="Tier_QTY_1" min-width="120" header-align="center" align="right" :formatter="formatNumberCell" />
<el-table-column prop="tierQty2" label="Tier_QTY_2" min-width="120" header-align="center" align="right" :formatter="formatNumberCell" /> <el-table-column prop="tierQty2" label="Tier_QTY_2" min-width="120" header-align="center" align="right" :formatter="formatNumberCell" />
@ -100,7 +101,7 @@
<report-pagination ref="priceListPagination" tab-name="priceList" :state="tabState.priceList" @size-change="handleSizeChange" @page-change="handlePageChange" /> <report-pagination ref="priceListPagination" tab-name="priceList" :state="tabState.priceList" @size-change="handleSizeChange" @page-change="handlePageChange" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="handling charge" name="handlingCharge">
<el-tab-pane label="Handling Charge" name="handlingCharge">
<el-table <el-table
ref="handlingChargeTable" ref="handlingChargeTable"
v-loading="tabState.handlingCharge.loading" v-loading="tabState.handlingCharge.loading"
@ -116,7 +117,7 @@
<report-pagination ref="handlingChargePagination" tab-name="handlingCharge" :state="tabState.handlingCharge" @size-change="handleSizeChange" @page-change="handlePageChange" /> <report-pagination ref="handlingChargePagination" tab-name="handlingCharge" :state="tabState.handlingCharge" @size-change="handleSizeChange" @page-change="handlePageChange" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="active payment terms" name="paymentTerms">
<el-tab-pane label="Active Payment Terms" name="paymentTerms">
<el-table <el-table
ref="paymentTermsTable" ref="paymentTermsTable"
v-loading="tabState.paymentTerms.loading" v-loading="tabState.paymentTerms.loading"

98
src/views/modules/supplier/supplierPartMoqPrice.vue

@ -86,12 +86,14 @@
<el-table-column prop="supplierCode" label="供应商编号" min-width="120" header-align="center" align="center" /> <el-table-column prop="supplierCode" label="供应商编号" min-width="120" header-align="center" align="center" />
<el-table-column prop="supplierName" label="供应商名称" min-width="180" header-align="center" align="left" show-overflow-tooltip /> <el-table-column prop="supplierName" label="供应商名称" min-width="180" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="currency" label="币种" min-width="90" header-align="center" align="center" /> <el-table-column prop="currency" label="币种" min-width="90" header-align="center" align="center" />
<el-table-column prop="currencyDesc" label="币种描述" min-width="110" header-align="center" align="center" show-overflow-tooltip />
<!-- <el-table-column prop="currencyDesc" label="币种描述" min-width="110" header-align="center" align="center" show-overflow-tooltip />-->
<el-table-column prop="partNo" label="产品编码" min-width="140" header-align="center" align="center" /> <el-table-column prop="partNo" label="产品编码" min-width="140" header-align="center" align="center" />
<el-table-column prop="item" label="Item" min-width="120" header-align="center" align="center" show-overflow-tooltip /> <el-table-column prop="item" label="Item" min-width="120" header-align="center" align="center" show-overflow-tooltip />
<el-table-column prop="sku" label="SKU" min-width="120" header-align="center" align="center" show-overflow-tooltip /> <el-table-column prop="sku" label="SKU" min-width="120" header-align="center" align="center" show-overflow-tooltip />
<el-table-column prop="partDesc" label="物料名称" min-width="200" header-align="center" align="left" show-overflow-tooltip /> <el-table-column prop="partDesc" label="物料名称" min-width="200" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="moq" label="MOQ" min-width="100" header-align="center" align="right" :formatter="formatNumberCell" />
<el-table-column prop="moqColor" label="MOQ/COLOR" min-width="120" header-align="center" align="right" :formatter="formatNumberCell" />
<el-table-column prop="moq" label="QTY/PO" min-width="110" header-align="center" align="right" :formatter="formatNumberCell" />
<el-table-column prop="qtyCarton" label="QTY/CARTON" min-width="120" header-align="center" align="right" :formatter="formatNumberCell" />
<el-table-column prop="active" label="在用" min-width="80" header-align="center" align="center"> <el-table-column prop="active" label="在用" min-width="80" header-align="center" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.active === 'Y' ? '是' : '否' }}</span> <span>{{ scope.row.active === 'Y' ? '是' : '否' }}</span>
@ -139,7 +141,7 @@
<el-dialog <el-dialog
title="维护MOQ" title="维护MOQ"
:visible.sync="moqDialogVisible" :visible.sync="moqDialogVisible"
width="420px"
width="640px"
:close-on-click-modal="false" :close-on-click-modal="false"
v-drag v-drag
> >
@ -157,12 +159,24 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="MOQ" required>
<el-col :span="8">
<el-form-item label="MOQ/COLOR" required>
<el-input-number v-model="moqForm.moqColor" :min="0" :controls="false" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="QTY/PO" required>
<el-input-number v-model="moqForm.moq" :min="0" :controls="false" style="width: 100%" /> <el-input-number v-model="moqForm.moq" :min="0" :controls="false" style="width: 100%" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-col :span="8">
<el-form-item label="QTY/CARTON" required>
<el-input-number v-model="moqForm.qtyCarton" :min="0" :controls="false" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="是否在用"> <el-form-item label="是否在用">
<el-select v-model="moqForm.active" style="width: 100%"> <el-select v-model="moqForm.active" style="width: 100%">
<el-option label="是" value="Y" /> <el-option label="是" value="Y" />
@ -183,7 +197,7 @@
<el-dialog <el-dialog
title="新增供应商物料" title="新增供应商物料"
:visible.sync="addDialogVisible" :visible.sync="addDialogVisible"
width="520px"
width="640px"
:close-on-click-modal="false" :close-on-click-modal="false"
v-drag v-drag
> >
@ -215,12 +229,24 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最小起订量(MOQ)">
<el-col :span="8">
<el-form-item label="MOQ/COLOR">
<el-input-number v-model="addForm.moqColor" :min="0" :controls="false" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="QTY/PO">
<el-input-number v-model="addForm.moq" :min="0" :controls="false" style="width: 100%" /> <el-input-number v-model="addForm.moq" :min="0" :controls="false" style="width: 100%" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-col :span="8">
<el-form-item label="QTY/CARTON">
<el-input-number v-model="addForm.qtyCarton" :min="0" :controls="false" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="是否在用"> <el-form-item label="是否在用">
<el-select v-model="addForm.active" style="width: 100%"> <el-select v-model="addForm.active" style="width: 100%">
<el-option label="是" value="Y" /> <el-option label="是" value="Y" />
@ -502,6 +528,8 @@ export default {
supplierCode: '', supplierCode: '',
partNo: '', partNo: '',
moq: 0, moq: 0,
moqColor: 0,
qtyCarton: 0,
active: 'Y' active: 'Y'
}, },
addDialogVisible: false, addDialogVisible: false,
@ -515,6 +543,8 @@ export default {
sku: '', sku: '',
partDesc: '', partDesc: '',
moq: 0, moq: 0,
moqColor: 0,
qtyCarton: 0,
active: 'Y' active: 'Y'
}, },
copyDialogVisible: false, copyDialogVisible: false,
@ -667,7 +697,9 @@ export default {
const rows = Array.isArray(pageData.list) ? pageData.list : (data.rows || []) const rows = Array.isArray(pageData.list) ? pageData.list : (data.rows || [])
this.supplierPartList = rows.map(item => ({ this.supplierPartList = rows.map(item => ({
...item, ...item,
moq: this.normalizeNumberValue(item.moq, 0)
moq: this.normalizeNumberValue(item.moq, 0),
moqColor: this.normalizeNumberValue(item.moqColor, 0),
qtyCarton: this.normalizeNumberValue(item.qtyCarton, 0)
})) }))
this.pageIndex = Number(pageData.currPage || this.pageIndex || 1) this.pageIndex = Number(pageData.currPage || this.pageIndex || 1)
this.pageSize = Number(pageData.pageSize || this.pageSize || 50) this.pageSize = Number(pageData.pageSize || this.pageSize || 50)
@ -732,19 +764,26 @@ export default {
this.bottomLoading = false this.bottomLoading = false
}) })
}, },
/**
* 打开维护弹窗。三个数量顺序为 MOQ/COLOR、QTY/PO、QTY/CARTON,空值按 0。
*/
openMoqDialog (row) { openMoqDialog (row) {
this.moqForm = { this.moqForm = {
site: this.$store.state.user.site, site: this.$store.state.user.site,
supplierCode: row.supplierCode, supplierCode: row.supplierCode,
partNo: row.partNo, partNo: row.partNo,
moq: this.normalizeNumberValue(row.moq, 0), moq: this.normalizeNumberValue(row.moq, 0),
moqColor: this.normalizeNumberValue(row.moqColor, 0),
qtyCarton: this.normalizeNumberValue(row.qtyCarton, 0),
active: row.active || 'Y' active: row.active || 'Y'
} }
this.moqDialogVisible = true this.moqDialogVisible = true
}, },
/**
* 保存维护弹窗。三个数量都不能为空且不能小于 0,site 取当前登录站点。
*/
saveMoq () { saveMoq () {
if (this.moqForm.moq === null || this.moqForm.moq === undefined) {
this.$message.warning('MOQ不能为空')
if (!this.validateQtyFields(this.moqForm)) {
return return
} }
this.moqSaveLoading = true this.moqSaveLoading = true
@ -753,6 +792,8 @@ export default {
supplierCode: this.moqForm.supplierCode, supplierCode: this.moqForm.supplierCode,
partNo: this.moqForm.partNo, partNo: this.moqForm.partNo,
moq: this.moqForm.moq, moq: this.moqForm.moq,
moqColor: this.moqForm.moqColor,
qtyCarton: this.moqForm.qtyCarton,
active: this.moqForm.active active: this.moqForm.active
} }
saveSupplierPartMoq(inData).then(({ data }) => { saveSupplierPartMoq(inData).then(({ data }) => {
@ -779,6 +820,8 @@ export default {
sku: '', sku: '',
partDesc: '', partDesc: '',
moq: 0, moq: 0,
moqColor: 0,
qtyCarton: 0,
active: 'Y' active: 'Y'
} }
this.addDialogVisible = true this.addDialogVisible = true
@ -792,8 +835,7 @@ export default {
this.$message.warning('产品编码不能为空') this.$message.warning('产品编码不能为空')
return return
} }
if (this.addForm.moq === null || this.addForm.moq === undefined || this.addForm.moq < 0) {
this.$message.warning('MOQ不能小于0')
if (!this.validateQtyFields(this.addForm)) {
return return
} }
this.addSaveLoading = true this.addSaveLoading = true
@ -802,6 +844,8 @@ export default {
supplierCode: this.addForm.supplierCode.trim(), supplierCode: this.addForm.supplierCode.trim(),
partNo: this.addForm.partNo.trim(), partNo: this.addForm.partNo.trim(),
moq: this.addForm.moq, moq: this.addForm.moq,
moqColor: this.addForm.moqColor,
qtyCarton: this.addForm.qtyCarton,
active: this.addForm.active || 'Y' active: this.addForm.active || 'Y'
} }
addSupplierPartMoq(inData).then(({ data }) => { addSupplierPartMoq(inData).then(({ data }) => {
@ -944,6 +988,30 @@ export default {
remark: '' remark: ''
} }
}, },
/**
* 校验三个起订量:空值不允许,且不能小于 0。
* 入参 form 为新增或维护表单;失败时弹出对应列名提示。
*/
validateQtyFields (form) {
const fields = [
{ key: 'moqColor', label: 'MOQ/COLOR' },
{ key: 'moq', label: 'QTY/PO' },
{ key: 'qtyCarton', label: 'QTY/CARTON' }
]
for (let i = 0; i < fields.length; i++) {
const field = fields[i]
const value = form[field.key]
if (value === null || value === undefined || value === '') {
this.$message.warning(field.label + '不能为空')
return false
}
if (Number(value) < 0) {
this.$message.warning(field.label + '不能小于0')
return false
}
}
return true
},
normalizeNumberValue (value, defaultValue = 0) { normalizeNumberValue (value, defaultValue = 0) {
if (value === null || value === undefined || value === '') return defaultValue if (value === null || value === undefined || value === '') return defaultValue
const num = Number(value) const num = Number(value)

2
src/views/modules/supplier/supplierPartTierPriceHistory.vue

@ -74,7 +74,7 @@
</el-table-column> </el-table-column>
<el-table-column prop="supplierCode" label="供应商编号" min-width="120" header-align="center" align="center" /> <el-table-column prop="supplierCode" label="供应商编号" min-width="120" header-align="center" align="center" />
<el-table-column prop="supplierName" label="供应商名称" min-width="180" header-align="center" align="left" show-overflow-tooltip /> <el-table-column prop="supplierName" label="供应商名称" min-width="180" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="currencyDesc" label="币种描述" min-width="120" header-align="center" align="center" :formatter="formatCurrencyDesc" />
<!-- <el-table-column prop="currencyDesc" label="币种描述" min-width="120" header-align="center" align="center" :formatter="formatCurrencyDesc" />-->
<el-table-column prop="partNo" label="产品编码" min-width="140" header-align="center" align="center" /> <el-table-column prop="partNo" label="产品编码" min-width="140" header-align="center" align="center" />
<el-table-column prop="item" label="Item" min-width="120" header-align="center" align="center" show-overflow-tooltip /> <el-table-column prop="item" label="Item" min-width="120" header-align="center" align="center" show-overflow-tooltip />
<el-table-column prop="sku" label="SKU" min-width="120" header-align="center" align="center" show-overflow-tooltip /> <el-table-column prop="sku" label="SKU" min-width="120" header-align="center" align="center" show-overflow-tooltip />

146
src/views/modules/sys/initialImport.vue

@ -32,7 +32,7 @@
:close-on-click-modal="false" :close-on-click-modal="false"
:close-on-press-escape="!saving" :close-on-press-escape="!saving"
:before-close="handleDialogClose" :before-close="handleDialogClose"
@closed="resetDialog">
@closed="handleDialogClosed">
<div class="dialog-toolbar"> <div class="dialog-toolbar">
<com-po-order-customer-picker <com-po-order-customer-picker
v-if="isPoOrderImport" v-if="isPoOrderImport"
@ -90,6 +90,13 @@
empty-text="请选择Excel文件进行预览" empty-text="请选择Excel文件进行预览"
:row-class-name="previewRowClassName" :row-class-name="previewRowClassName"
class="initial-import-preview"> class="initial-import-preview">
<el-table-column
prop="validationMessage"
label="错误信息"
min-width="280"
fixed="left"
align="left"
show-overflow-tooltip />
<el-table-column <el-table-column
v-if="isPoOrderImport" v-if="isPoOrderImport"
prop="excelRowNo" prop="excelRowNo"
@ -154,13 +161,13 @@ export default {
{ {
type: 'supplierPrice', type: 'supplierPrice',
name: '供应商价格期初导入', name: '供应商价格期初导入',
description: '导入供应商物料的MOQ、阶梯数量和阶梯价格。'
},
{
type: 'partSku',
name: '物料SKU导入',
description: '按Item更新物料SKU,不存在的SKU会自动新增。'
description: '导入供应商物料的QTY/PO、MOQ/COLOR、QTY/CARTON、阶梯数量和阶梯价格。'
}, },
// {
// type: 'partSku',
// name: '物料SKU导入',
// description: '按Item更新物料SKU,不存在的SKU会自动新增。'
// },
{ {
type: 'poOrder', type: 'poOrder',
name: 'PO订单导入', name: 'PO订单导入',
@ -180,12 +187,16 @@ export default {
previewDisplayLimit: 500, previewDisplayLimit: 500,
poOrderColumns: [], poOrderColumns: [],
saveProgressText: '', saveProgressText: '',
// 保存成功后先关弹框,等关闭动画结束再弹出绿色提示,避免提示被弹框盖住或一起消失。
pendingSuccessMessage: '',
missingItems: [], missingItems: [],
missingSuppliers: [], missingSuppliers: [],
supplierPriceColumns: [ supplierPriceColumns: [
{ prop: 'rawCode', label: 'RAW CODE', width: 120, align: 'center' }, { prop: 'rawCode', label: 'RAW CODE', width: 120, align: 'center' },
{ prop: 'supplier', label: 'Short_NPC', width: 100, align: 'center' }, { prop: 'supplier', label: 'Short_NPC', width: 100, align: 'center' },
{ prop: 'moqColor', label: 'MOQ/COLOR', width: 80, align: 'center' }, { prop: 'moqColor', label: 'MOQ/COLOR', width: 80, align: 'center' },
{ prop: 'qtyPo', label: 'QTY/PO', width: 80, align: 'center' },
{ prop: 'qtyCarton', label: 'QTY/CARTON', width: 90, align: 'center' },
{ prop: 'startDate', label: 'START DATE', width: 100, align: 'center' }, { prop: 'startDate', label: 'START DATE', width: 100, align: 'center' },
{ prop: 'tierQty1', label: 'Tier_QTY_1', width: 80, align: 'center' }, { prop: 'tierQty1', label: 'Tier_QTY_1', width: 80, align: 'center' },
{ prop: 'tierQty2', label: 'Tier_QTY_2', width: 80, align: 'center' }, { prop: 'tierQty2', label: 'Tier_QTY_2', width: 80, align: 'center' },
@ -226,14 +237,8 @@ export default {
} else { } else {
columns = this.supplierPriceColumns columns = this.supplierPriceColumns
} }
// 三个导入预览都把错误信息放在最后一列,和导出文件保持一致。
const withoutError = (columns || []).filter(column => column.prop !== 'validationMessage')
return withoutError.concat([{
prop: 'validationMessage',
label: '错误信息',
width: 280,
align: 'left'
}])
// 预览业务列不含错误信息;弹框里错误信息单独固定在最左侧。
return (columns || []).filter(column => column.prop !== 'validationMessage')
}, },
invalidPreviewCount () { invalidPreviewCount () {
return this.previewRows.filter(row => this.isPreviewRowInvalid(row)).length return this.previewRows.filter(row => this.isPreviewRowInvalid(row)).length
@ -365,7 +370,7 @@ export default {
: previewSupplierPrice(rawFile, site) : previewSupplierPrice(rawFile, site)
}, },
buildPoOrderColumns (columnMapping) { buildPoOrderColumns (columnMapping) {
// 预览表按模板字段展示;物料编码、供应商编码分别由 Item、Vendor Name 解析得到。
// 预览表按模板字段展示;物料编码等于 Item,供应商编码仍由 Vendor Name 解析。
const columns = Object.keys(columnMapping).map(prop => ({ const columns = Object.keys(columnMapping).map(prop => ({
prop, prop,
label: columnMapping[prop], label: columnMapping[prop],
@ -478,19 +483,12 @@ export default {
rows: this.previewRows rows: this.previewRows
}).then(({ data }) => { }).then(({ data }) => {
if (data && data.code === 0) { if (data && data.code === 0) {
const savedCount = data.savedCount == null ? this.previewRows.length : data.savedCount
const skippedCount = data.skippedCount || 0
const skippedText = skippedCount > 0 ? `,跳过${skippedCount}行` : ''
this.$message.success(`保存完成,成功${savedCount}行${skippedText}`)
this.dialogVisible = false
this.closeImportDialogAfterSuccess()
} else { } else {
this.$message.error((data && data.msg) || '保存失败')
this.showImportSaveError((data && data.msg) || '保存失败')
} }
}).catch(error => { }).catch(error => {
const message = error && error.response && error.response.data && error.response.data.msg
? error.response.data.msg
: '保存失败,请稍后重试'
this.$message.error(message)
this.showImportSaveError(this.resolveImportSaveErrorMessage(error, '保存失败,请稍后重试'))
}).finally(() => { }).finally(() => {
this.saving = false this.saving = false
}) })
@ -530,26 +528,63 @@ export default {
this.previewRows.splice(0, rows.length) this.previewRows.splice(0, rows.length)
this.saveProgressText = `正在分批保存:${savedCount}/${totalCount}` this.saveProgressText = `正在分批保存:${savedCount}/${totalCount}`
} }
this.$message.success(`保存完成,共成功${savedCount}行`)
this.dialogVisible = false
this.closeImportDialogAfterSuccess()
} catch (error) { } catch (error) {
const responseMessage = error && error.response && error.response.data && error.response.data.msg
const message = responseMessage || error.message || '保存失败,请稍后重试'
this.$message.error(`已保存${savedCount}行,后续批次停止:${message}`)
const message = this.resolveImportSaveErrorMessage(error, '保存失败,请稍后重试')
this.showImportSaveError(`已保存${savedCount}行,后续批次停止:${message}`)
} finally { } finally {
this.saving = false this.saving = false
} }
}, },
/**
* 从保存接口失败结果中取出用户可读错误。
* HTTP 200 + code=500 时错误在 data.msg;网络/超时时走 axios error。
*/
resolveImportSaveErrorMessage (error, fallback) {
if (!error) {
return fallback
}
const responseData = error.response && error.response.data
if (responseData && responseData.msg) {
return responseData.msg
}
if (error.message && /timeout/i.test(error.message)) {
return '保存超时,请缩小导入行数后重试'
}
return error.message || fallback
},
/**
* 导入保存失败必须弹确认框,点确定后才关闭,避免 $message 几秒后消失看不清。
*/
showImportSaveError (message) {
const text = message || '保存失败'
const content = this.$createElement(
'div',
{ style: { maxHeight: '360px', overflowY: 'auto', whiteSpace: 'pre-wrap', wordBreak: 'break-all', lineHeight: '1.6', textAlign: 'left' } },
text
)
this.$alert(content, '导入保存失败', {
confirmButtonText: '确定',
type: 'error',
customClass: 'initial-import-error-alert'
}).catch(() => {})
},
/**
* 预览后弹出缺失主数据提示。
* PO 订单导入不再校验 Item 是否存在,因此不展示 Item 缺失清单。
*/
showMissingDataAlert () { showMissingDataAlert () {
if (!this.missingItems.length && !this.missingSuppliers.length) {
const showMissingItems = this.missingItems.length && !this.isPoOrderImport
const showMissingSuppliers = (this.activeImportType === 'supplierPrice' || this.isPoOrderImport)
&& this.missingSuppliers.length
if (!showMissingItems && !showMissingSuppliers) {
return return
} }
const messages = [] const messages = []
if (this.missingItems.length) {
if (showMissingItems) {
messages.push(`以下Item不存在:${this.missingItems.join('、')}`) messages.push(`以下Item不存在:${this.missingItems.join('、')}`)
} }
// PO 导入按 Vendor Name 查供应商;价格期初仍按 ShortNPC 提示。
if ((this.activeImportType === 'supplierPrice' || this.isPoOrderImport) && this.missingSuppliers.length) {
if (showMissingSuppliers) {
const supplierLabel = this.isPoOrderImport ? 'Vendor Name' : 'ShortNPC' const supplierLabel = this.isPoOrderImport ? 'Vendor Name' : 'ShortNPC'
messages.push(`以下${supplierLabel}不存在:${this.missingSuppliers.join('、')}`) messages.push(`以下${supplierLabel}不存在:${this.missingSuppliers.join('、')}`)
} }
@ -603,10 +638,15 @@ export default {
} }
}, },
/** /**
* 导出列与预览表一致:PO 额外带 Excel 行号,最后一列固定为错误信息。
* 导出列与弹框预览一致:错误信息放在最左侧,PO 额外带 Excel 行号。
*/ */
buildPreviewExportColumns () { buildPreviewExportColumns () {
const columns = []
const columns = [{
prop: 'validationMessage',
label: '错误信息',
width: 280,
align: 'left'
}]
if (this.isPoOrderImport) { if (this.isPoOrderImport) {
columns.push({ prop: 'excelRowNo', label: 'Excel行号' }) columns.push({ prop: 'excelRowNo', label: 'Excel行号' })
} }
@ -687,6 +727,26 @@ export default {
.replace(/>/g, '&gt;') .replace(/>/g, '&gt;')
.replace(/"/g, '&quot;') .replace(/"/g, '&quot;')
}, },
/**
* 导入保存成功:先关弹框,提示文案等 closed 后再弹出。
*/
closeImportDialogAfterSuccess () {
this.saving = false
this.pendingSuccessMessage = '导入成功'
this.dialogVisible = false
},
/**
* 弹框关闭动画结束后再清理状态。
* 若本次是保存成功关闭,再弹出绿色“导入成功”,避免和弹框一起消失。
*/
handleDialogClosed () {
const successMessage = this.pendingSuccessMessage
this.pendingSuccessMessage = ''
this.resetDialog()
if (successMessage) {
this.$message.success(successMessage)
}
},
handleDialogClose (done) { handleDialogClose (done) {
if (!this.saving) { if (!this.saving) {
done() done()
@ -825,3 +885,15 @@ export default {
text-align: right; text-align: right;
} }
</style> </style>
<style>
/* MessageBox 挂到 body,不能写 scoped,否则超长 SQL 错误会撑破弹框。 */
.initial-import-error-alert .el-message-box__message {
max-height: 360px;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-all;
line-height: 1.6;
text-align: left;
}
</style>
Loading…
Cancel
Save