Browse Source

feat(srmPart): 优化零件信息管理功能

- 隐藏关联供应商标签页以简化界面
- 为SKU字段添加点击查询功能并增加必填验证
- 为属性模板字段增加必填验证规则
- 在基础数据查询中新增SKU类型支持
- 限制新增物料按钮仅在主表待提交状态下显示
- 移除报价表单的未税单价和税率必填验证
- 简化报价提交流程,仅验证阶梯价格表填写情况
- 将价格表查询整合到价格阶梯标签页中
- 移除独立的价格表查询对话框组件
- 添加价格阶梯数据展示和刷新功能
- 优化数值格式化和显示方法
master
qiankanghui 2 weeks ago
parent
commit
d4f5ce29ee
  1. 22
      src/views/modules/srmPart/partInfoList.vue
  2. 3
      src/views/modules/supplier/purHeaderList.vue
  3. 87
      src/views/modules/supplier/quoPurDetailList.vue
  4. 197
      src/views/modules/supplier/supPurReplyHistList.vue

22
src/views/modules/srmPart/partInfoList.vue

@ -119,9 +119,9 @@
<el-tab-pane label="规格参数" name="specParams" style=""> <el-tab-pane label="规格参数" name="specParams" style="">
<specParams ref="specParams"></specParams> <specParams ref="specParams"></specParams>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="关联供应商" name="suppliers" style="">
<suppliers ref="suppliers"></suppliers>
</el-tab-pane>
<!-- <el-tab-pane label="关联供应商" name="suppliers" style="">-->
<!-- <suppliers ref="suppliers"></suppliers>-->
<!-- </el-tab-pane>-->
<!-- <el-tab-pane label="审批与放行" name="approval" style="">--> <!-- <el-tab-pane label="审批与放行" name="approval" style="">-->
<!-- <approval ref="approval"></approval>--> <!-- <approval ref="approval"></approval>-->
<!-- </el-tab-pane>--> <!-- </el-tab-pane>-->
@ -184,8 +184,9 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="SKU">
<el-input v-model="currentpart.sku"></el-input>
<el-form-item>
<span style="cursor: pointer" slot="label" @click="getBaseList(508)"><a href="#">SKU</a></span>
<el-input v-model="currentpart.sku" ></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -246,7 +247,7 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item>
<el-form-item prop="codeNo">
<span style="cursor: pointer" slot="label" @click="getBaseList(527)"><a href="#">属性模板</a></span> <span style="cursor: pointer" slot="label" @click="getBaseList(527)"><a href="#">属性模板</a></span>
<el-input v-model="currentpart.codeNo" ></el-input> <el-input v-model="currentpart.codeNo" ></el-input>
</el-form-item> </el-form-item>
@ -917,6 +918,9 @@ export default {
], ],
partSpec: [ partSpec: [
{ required: true, message: ' ', trigger: 'blur' } { required: true, message: ' ', trigger: 'blur' }
],
codeNo: [
{ required: true, message: ' ', trigger: 'blur' }
] ]
}, },
copyDialogVisible: false, copyDialogVisible: false,
@ -1307,6 +1311,9 @@ export default {
if (this.tagNo === 510) { if (this.tagNo === 510) {
strVal = this.currentpart.unit strVal = this.currentpart.unit
} }
if (val === 508) {
strVal = this.currentpart.sku
}
if (val === 529) { if (val === 529) {
strVal = this.currentpart.buyerName strVal = this.currentpart.buyerName
} }
@ -1333,6 +1340,9 @@ export default {
if (this.tagNo === 510) { if (this.tagNo === 510) {
this.currentpart.unit = val.UMID this.currentpart.unit = val.UMID
} }
if (this.tagNo === 508) {
this.currentpart.sku = val.sku
}
if (this.tagNo === 529) { if (this.tagNo === 529) {
this.currentpart.buyerName = val.UserName this.currentpart.buyerName = val.UserName
} }

3
src/views/modules/supplier/purHeaderList.vue

@ -1018,8 +1018,9 @@ export default {
isMaterialEditable(row) { isMaterialEditable(row) {
return row && (row.status === '待提交' || row.status === '待报价') return row && (row.status === '待提交' || row.status === '待报价')
}, },
// 新增物料按钮只在主表状态为待提交时才显示
canAddMaterial() { canAddMaterial() {
return this.currentInquiry && (this.currentInquiry.status === '待提交' || this.currentInquiry.status === '待报价')
return this.currentInquiry && this.currentInquiry.status === '待提交'
}, },
openMaterialDialog(row) { openMaterialDialog(row) {
if (!this.currentInquiry) { if (!this.currentInquiry) {

87
src/views/modules/supplier/quoPurDetailList.vue

@ -454,22 +454,8 @@ export default {
site: this.$store.state.user.site, site: this.$store.state.user.site,
createdBy: this.$store.state.user.name createdBy: this.$store.state.user.name
}, },
quoteRules: {
price: [
{ required: true, message: '请输入未税单价', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value == null || Number(value) <= 0) {
callback(new Error('未税单价必须大于0'))
} else {
callback()
}
},
trigger: 'blur'
}
],
taxRate: [{ required: true, message: '请输入税率', trigger: 'blur' }]
},
// 报价弹窗取消必填字段校验,提交时仅校验阶梯价格表是否填写
quoteRules: {},
// 上次填写的报价信息(用于残留功能) // 上次填写的报价信息(用于残留功能)
lastQuoteData: null, lastQuoteData: null,
lastTierPriceData: null lastTierPriceData: null
@ -769,48 +755,39 @@ export default {
// 提交报价 // 提交报价
submitQuote() { submitQuote() {
this.calculatePrice() this.calculatePrice()
this.$refs.quoteForm.validate((valid) => {
if (valid) {
if (!this.quoteForm.price || Number(this.quoteForm.price) <= 0) {
this.$message.error('未税单价必须大于0')
return
}
if (!this.validateTierPriceList()) {
return
}
// 计算总成本(可选)
const totalCost = this.quoteForm.materialCost + this.quoteForm.produceFee +
this.quoteForm.surfaceFee + this.quoteForm.profit +
this.quoteForm.mouldFee + this.quoteForm.additionalCost +
this.quoteForm.freight + this.quoteForm.duty
const submitData = {
...this.quoteForm,
tierPriceList: this.buildTierPricePayload(),
totalCost: totalCost
}
// 取消必填字段校验,仅校验阶梯价格表是否填写
if (!this.validateTierPriceList()) {
return
}
// 计算总成本(可选)
const totalCost = this.quoteForm.materialCost + this.quoteForm.produceFee +
this.quoteForm.surfaceFee + this.quoteForm.profit +
this.quoteForm.mouldFee + this.quoteForm.additionalCost +
this.quoteForm.freight + this.quoteForm.duty
const submitData = {
...this.quoteForm,
tierPriceList: this.buildTierPricePayload(),
totalCost: totalCost
}
createPurReplyHist(submitData).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('报价提交成功')
// 提交成功后清除残留数据
this.lastQuoteData = null
this.lastTierPriceData = null
this.quoteDialogVisible = false
this.tierPriceDialogVisible = false
// 刷新报价记录列表
this.refreshCurrentTabTable()
// 刷新主列表状态
this.getMainData()
} else {
this.$message.error(data.msg || '报价提交失败')
}
}).catch(error => {
this.$message.error('报价提交失败: ' + error.message)
})
createPurReplyHist(submitData).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('报价提交成功')
// 提交成功后清除残留数据
this.lastQuoteData = null
this.lastTierPriceData = null
this.quoteDialogVisible = false
this.tierPriceDialogVisible = false
// 刷新报价记录列表
this.refreshCurrentTabTable()
// 刷新主列表状态
this.getMainData()
} else { } else {
this.$message.warning('请填写必填字段')
this.$message.error(data.msg || '报价提交失败')
} }
}).catch(error => {
this.$message.error('报价提交失败: ' + error.message)
}) })
}, },

197
src/views/modules/supplier/supPurReplyHistList.vue

@ -46,10 +46,9 @@
<!-- 列表 --> <!-- 列表 -->
<el-table :data="dataList" :height="height" border ref="mainTable" highlight-current-row v-loading="loading" style="width:100%" stripe> <el-table :data="dataList" :height="height" border ref="mainTable" highlight-current-row v-loading="loading" style="width:100%" stripe>
<el-table-column fixed="right" :label="'操作'" header-align="center" align="center" width="220">
<el-table-column fixed="right" :label="'操作'" header-align="center" align="center" width="120">
<template slot-scope="scope"> <template slot-scope="scope">
<el-link style="cursor: pointer" v-if="scope.row.status === '已报价'" @click="openDialog(scope.row)">审批 </el-link> <el-link style="cursor: pointer" v-if="scope.row.status === '已报价'" @click="openDialog(scope.row)">审批 </el-link>
<el-link style="cursor: pointer; margin-left: 8px;" v-if="scope.row.id" @click="openPriceSheet(scope.row)">价格表查询</el-link>
<!-- <el-link style="cursor: pointer" v-if="scope.row.status === '已接受'" @click="openPartDialog(scope.row)"> 可供物料</el-link>--> <!-- <el-link style="cursor: pointer" v-if="scope.row.status === '已接受'" @click="openPartDialog(scope.row)"> 可供物料</el-link>-->
<!-- <el-link style="cursor: pointer" @click="handleDelete(scope.row)">删除</el-link> --> <!-- <el-link style="cursor: pointer" @click="handleDelete(scope.row)">删除</el-link> -->
@ -163,6 +162,32 @@
<!-- 标签页 --> <!-- 标签页 -->
<el-tabs v-model="activeName" style="margin-top: 0px; width: 99%; padding: 0;" @tab-click="tabClick" class="customer-tab" type="border-card"> <el-tabs v-model="activeName" style="margin-top: 0px; width: 99%; padding: 0;" @tab-click="tabClick" class="customer-tab" type="border-card">
<el-tab-pane label="价格阶梯" name="tierPrice">
<el-table
:data="tierPriceList"
:height="tabHeight"
border
stripe
v-loading="tierPriceLoading"
style="width: 100%">
<el-table-column prop="qtyStart" label="开始数量" min-width="110" header-align="center" align="right">
<template slot-scope="scope">
{{ formatNumber(scope.row.qtyStart) }}
</template>
</el-table-column>
<el-table-column prop="qtyEnd" label="结束数量" min-width="110" header-align="center" align="right">
<template slot-scope="scope">
{{ formatNumber(scope.row.qtyEnd) }}
</template>
</el-table-column>
<el-table-column prop="unitPrice" label="价格" min-width="120" header-align="center" align="right">
<template slot-scope="scope">
{{ formatNumber(scope.row.unitPrice) }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="200" header-align="center" align="left" show-overflow-tooltip />
</el-table>
</el-tab-pane>
<el-tab-pane label="附件" name="attachments"> <el-tab-pane label="附件" name="attachments">
<attachments ref="attachments" :height="tabHeight"></attachments> <attachments ref="attachments" :height="tabHeight"></attachments>
</el-tab-pane> </el-tab-pane>
@ -558,64 +583,6 @@
</div> </div>
</el-dialog> </el-dialog>
<el-dialog
title="价格表查询"
:visible.sync="priceSheetDialogVisible"
width="700px"
:close-on-click-modal="false"
v-drag
append-to-body
>
<el-form :inline="true" label-position="top" class="price-sheet-header-form">
<el-form-item label="产品编码">
<el-input :value="displayText(priceSheetHeader.partNo)" disabled style="width: 140px" />
</el-form-item>
<el-form-item label="物料名称">
<el-input :value="displayText(priceSheetHeader.partDesc)" disabled style="width: 180px" />
</el-form-item>
<el-form-item label="价格日期">
<el-input :value="displayText(formatDateOnly(priceSheetHeader.priceDate))" disabled style="width: 120px" />
</el-form-item>
<el-form-item label="供应商编码">
<el-input :value="displayText(priceSheetHeader.supplierId)" disabled style="width: 120px" />
</el-form-item>
<el-form-item label="供应商名称">
<el-input :value="displayText(priceSheetHeader.supplierName)" disabled style="width: 160px" />
</el-form-item>
<el-form-item label="币种">
<el-input :value="displayText(priceSheetHeader.currency)" disabled style="width: 70px" />
</el-form-item>
</el-form>
<el-table
:data="priceSheetDetailList"
:height="320"
border
stripe
v-loading="priceSheetLoading"
style="width: 100%"
>
<el-table-column prop="qtyStart" label="开始数量" min-width="110" header-align="center" align="right">
<template slot-scope="scope">
{{ formatNumber(scope.row.qtyStart) }}
</template>
</el-table-column>
<el-table-column prop="qtyEnd" label="结束数量" min-width="110" header-align="center" align="right">
<template slot-scope="scope">
{{ formatNumber(scope.row.qtyEnd) }}
</template>
</el-table-column>
<el-table-column prop="unitPrice" label="价格" min-width="120" header-align="center" align="right">
<template slot-scope="scope">
{{ formatNumber(scope.row.unitPrice) }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="200" header-align="center" align="left" show-overflow-tooltip />
</el-table>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="priceSheetDialogVisible = false">关闭</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
@ -650,6 +617,7 @@ export default {
data() { data() {
return { return {
height: 200, height: 200,
tabHeight: 300,
loading: false, loading: false,
submitLoading: false, submitLoading: false,
dataList: [], dataList: [],
@ -657,7 +625,7 @@ export default {
pageSize: 20, pageSize: 20,
totalPage: 0, totalPage: 0,
currentRow: {}, currentRow: {},
activeName: 'attachments',
activeName: 'tierPrice',
searchData: { searchData: {
site: this.$store.state.user.site, site: this.$store.state.user.site,
createdBy: this.$store.state.user.name, createdBy: this.$store.state.user.name,
@ -747,18 +715,8 @@ export default {
overReceiveFlag: 'N', overReceiveFlag: 'N',
overReceiveTolerance: 0 overReceiveTolerance: 0
}, },
priceSheetDialogVisible: false,
priceSheetLoading: false,
priceSheetHeader: {
quotationReplyHistId: null,
partNo: '',
partDesc: '',
priceDate: '',
supplierId: '',
supplierName: '',
currency: ''
},
priceSheetDetailList: []
tierPriceList: [],
tierPriceLoading: false
} }
}, },
mounted() { mounted() {
@ -795,9 +753,35 @@ export default {
this.currentRow = {site: '', orderNo: ''} this.currentRow = {site: '', orderNo: ''}
} }
if (this.activeName === 'tierPrice') {
this.refreshTierPrice()
}
if (this.activeName === 'attachments') { if (this.activeName === 'attachments') {
this.refreshAttachments() this.refreshAttachments()
} }
},
// 价格阶梯页签:查询逻辑与报价记录的价格表查询一致
refreshTierPrice() {
if (!this.currentRow || !this.currentRow.id) {
this.tierPriceList = []
return
}
const params = {
site: this.$store.state.user.site,
quotationReplyHistId: this.currentRow.id
}
this.tierPriceLoading = true
getPurReplyPriceSheet(params).then(({ data }) => {
if (data && data.code === 0 && data.row) {
this.tierPriceList = data.row.tierPriceList || []
} else {
this.tierPriceList = []
}
this.tierPriceLoading = false
}).catch(() => {
this.tierPriceLoading = false
this.tierPriceList = []
})
}, },
refreshAttachments () { refreshAttachments () {
console.log('刷新附件组件,当前行数据:', this.currentRow) console.log('刷新附件组件,当前行数据:', this.currentRow)
@ -830,24 +814,6 @@ export default {
if (value === null || value === undefined) return '-' if (value === null || value === undefined) return '-'
return new Intl.NumberFormat('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(value) return new Intl.NumberFormat('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(value)
}, },
displayText(value) {
if (value === null || value === undefined || value === '') {
return '-'
}
return value
},
formatDateOnly(value) {
if (!value) return ''
if (typeof value === 'string') {
return value.length >= 10 ? value.slice(0, 10) : value
}
const date = new Date(value)
if (Number.isNaN(date.getTime())) {
return ''
}
const pad = num => String(num).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
},
formatNumber(value) { formatNumber(value) {
if (value === null || value === undefined || value === '') { if (value === null || value === undefined || value === '') {
return '0' return '0'
@ -858,51 +824,6 @@ export default {
} }
return String(Object.is(num, -0) ? 0 : num) return String(Object.is(num, -0) ? 0 : num)
}, },
openPriceSheet(row) {
if (!row || !row.id) {
this.$message.warning('当前报价记录缺少主键,无法查询价格表')
return
}
const params = {
site: this.$store.state.user.site,
quotationReplyHistId: row.id
}
this.priceSheetDialogVisible = true
this.priceSheetLoading = true
this.priceSheetHeader = {
quotationReplyHistId: row.id,
partNo: row.partNo || '',
partDesc: row.partDesc || '',
priceDate: row.createdDate || '',
supplierId: row.supplierId || '',
supplierName: row.supplierName || '',
currency: row.currency || ''
}
this.priceSheetDetailList = []
getPurReplyPriceSheet(params).then(({ data }) => {
if (data && data.code === 0 && data.row) {
const responseRow = data.row
this.priceSheetHeader = {
quotationReplyHistId: responseRow.quotationReplyHistId || row.id,
partNo: responseRow.partNo || row.partNo || '',
partDesc: responseRow.partDesc || row.partDesc || '',
priceDate: responseRow.priceDate || row.createdDate || '',
supplierId: responseRow.supplierId || row.supplierId || '',
supplierName: responseRow.supplierName || row.supplierName || '',
currency: responseRow.currency || row.currency || ''
}
this.priceSheetDetailList = responseRow.tierPriceList || []
} else {
this.priceSheetDetailList = []
this.$message.error((data && data.msg) || '获取价格表失败')
}
this.priceSheetLoading = false
}).catch(() => {
this.priceSheetLoading = false
this.priceSheetDetailList = []
this.$message.error('获取价格表失败')
})
},
getList() { getList() {
this.loading = true this.loading = true
const params = { const params = {
@ -1182,10 +1103,6 @@ export default {
margin-right: 10px; margin-right: 10px;
} }
.price-sheet-header-form {
margin-bottom: 8px;
}
/* 页签样式穿透 */ /* 页签样式穿透 */
/deep/ .customer-tab.el-tabs--border-card > .el-tabs__content { /deep/ .customer-tab.el-tabs--border-card > .el-tabs__content {
padding: 0; padding: 0;

Loading…
Cancel
Save