Browse Source

更新

master
常熟吴彦祖 4 weeks ago
parent
commit
5e4595e5f8
  1. 4
      src/api/supplier/purReplyHist.js
  2. 170
      src/views/modules/supplier/com_inquiry_QuotationList.vue
  3. 216
      src/views/modules/supplier/partPriceAnalysis.vue
  4. 179
      src/views/modules/supplier/quoPurDetailList.vue
  5. 156
      src/views/modules/supplier/supPurReplyHistList.vue

4
src/api/supplier/purReplyHist.js

@ -8,3 +8,7 @@ export const updatePurReplyHist = (data) => createAPI(`/purQuotationReplyHist/sa
export const deletePurReplyHist = (data) => createAPI(`/purQuotationReplyHist/delete`, 'post', data) export const deletePurReplyHist = (data) => createAPI(`/purQuotationReplyHist/delete`, 'post', data)
//更新状态 //更新状态
export const updatePurReplyHistStatus = (data) => createAPI(`/purQuotationReplyHist/updatePurReplyHistStatus`, 'post', data) export const updatePurReplyHistStatus = (data) => createAPI(`/purQuotationReplyHist/updatePurReplyHistStatus`, 'post', data)
// 报价阶梯价
export const listPurReplyTierPrice = (data) => createAPI(`/purQuotationReplyHist/listTierPrice`, 'post', data)
export const getPurReplyPriceSheet = (data) => createAPI(`/purQuotationReplyHist/getPriceSheet`, 'post', data)

170
src/views/modules/supplier/com_inquiry_QuotationList.vue

@ -37,17 +37,16 @@
<span v-if="!item.columnHidden">{{ formatColumn(scope.row, item) }}</span> <span v-if="!item.columnHidden">{{ formatColumn(scope.row, item) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column-->
<!-- header-align="center"-->
<!-- align="center"-->
<!-- width="180"-->
<!-- fixed="right"-->
<!-- label="Actions">-->
<!-- <template slot-scope="scope">-->
<!-- &lt;!&ndash; <a type="text" size="small" @click="editModel(scope.row)">Edit |</a>-->
<!-- <a type="text" size="small" @click="deleteData(scope.row)"> Delete</a> &ndash;&gt;-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column
fixed="right"
header-align="center"
align="center"
width="100"
label="操作">
<template slot-scope="scope">
<el-link style="cursor: pointer" @click="openPriceSheet(scope.row)">价格表查询</el-link>
</template>
</el-table-column>
</el-table> </el-table>
<!-- 新增/编辑弹窗 --> <!-- 新增/编辑弹窗 -->
@ -175,12 +174,72 @@
<el-button @click="dialogVisible = false">取消</el-button> <el-button @click="dialogVisible = false">取消</el-button>
</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>
<script> <script>
// API // API
import { import {
getPurReplyPriceSheet,
searchPurReplyHistList searchPurReplyHistList
} from '@/api/supplier/purReplyHist.js' } from '@/api/supplier/purReplyHist.js'
import { formatPartColumn } from '@/utils/purQuotationPartDisplay.js' import { formatPartColumn } from '@/utils/purQuotationPartDisplay.js'
@ -228,6 +287,18 @@ export default {
formRules: { formRules: {
partNo: [{ required: true, message: '请输入产品编码', trigger: 'blur' }] partNo: [{ required: true, message: '请输入产品编码', trigger: 'blur' }]
}, },
priceSheetDialogVisible: false,
priceSheetLoading: false,
priceSheetHeader: {
quotationReplyHistId: null,
partNo: '',
partDesc: '',
priceDate: '',
supplierId: '',
supplierName: '',
currency: ''
},
priceSheetDetailList: [],
columnList: [ columnList: [
{ columnProp: 'partNo', headerAlign: 'center', align: 'left', columnLabel: '产品编码', columnWidth: 120, fixed: '', columnHidden: false, columnSortable: false }, { columnProp: 'partNo', headerAlign: 'center', align: 'left', columnLabel: '产品编码', columnWidth: 120, fixed: '', columnHidden: false, columnSortable: false },
{ columnProp: 'partDesc', headerAlign: 'center', align: 'left', columnLabel: '物料名称', columnWidth: 150, fixed: '', columnHidden: false, columnSortable: false }, { columnProp: 'partDesc', headerAlign: 'center', align: 'left', columnLabel: '物料名称', columnWidth: 150, fixed: '', columnHidden: false, columnSortable: false },
@ -264,6 +335,79 @@ export default {
formatColumn(row, item) { formatColumn(row, item) {
return formatPartColumn(row, item.columnProp) return formatPartColumn(row, item.columnProp)
}, },
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) {
if (value === null || value === undefined || value === '') {
return '0'
}
const num = Number(value)
if (Number.isNaN(num)) {
return '0'
}
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: '',
supplierName: '',
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 || '',
supplierName: responseRow.supplierName || '',
currency: responseRow.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('获取价格表失败')
})
},
// //
init(inData) { init(inData) {
if (inData) { if (inData) {
@ -387,4 +531,8 @@ export default {
.customer-css { .customer-css {
padding: 10px; padding: 10px;
} }
.price-sheet-header-form {
margin-bottom: 8px;
}
</style> </style>

216
src/views/modules/supplier/partPriceAnalysis.vue

@ -37,7 +37,7 @@
<span style="cursor: pointer" slot="label" @click="getBaseList(520)"><a href="javascript:void(0)">供应商编码</a></span> <span style="cursor: pointer" slot="label" @click="getBaseList(520)"><a href="javascript:void(0)">供应商编码</a></span>
<el-input <el-input
v-model="searchData.supplierId" v-model="searchData.supplierId"
placeholder="不填则按物料查询"
placeholder="不填则按产品查询"
style="width: 160px" style="width: 160px"
clearable clearable
@keyup.enter.native="handleSearch" @keyup.enter.native="handleSearch"
@ -49,6 +49,27 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-form v-if="showProductInfo" :inline="true" label-position="top" class="pi-product-form">
<el-form-item label="产品编码">
<el-input :value="displayText(productInfo.partNo || searchData.partNo)" disabled style="width: 160px" />
</el-form-item>
<el-form-item label="产品名称">
<el-input :value="displayText(productInfo.partDesc)" disabled style="width: 220px" />
</el-form-item>
<el-form-item label="Item">
<el-input :value="displayText(productInfo.item)" disabled style="width: 120px" />
</el-form-item>
<el-form-item label="SKU">
<el-input :value="displayText(productInfo.sku)" disabled style="width: 120px" />
</el-form-item>
<el-form-item label="物料分类">
<el-input :value="displayText(productInfo.categoryName)" disabled style="width: 160px" />
</el-form-item>
<el-form-item label="物料二级分类">
<el-input :value="displayText(productInfo.categoryLevel2Name)" disabled style="width: 160px" />
</el-form-item>
</el-form>
<el-table <el-table
:data="dataList" :data="dataList"
:height="tableHeight" :height="tableHeight"
@ -58,9 +79,12 @@
style="width: 100%" style="width: 100%"
empty-text="请填写查询条件后点击查询" empty-text="请填写查询条件后点击查询"
> >
<el-table-column prop="partNo" label="产品编码" min-width="80" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="partDesc" label="物料名称" min-width="250" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="price" label="报价" min-width="80" header-align="center" align="right">
<el-table-column fixed="left" label="操作" width="90" header-align="center" align="center">
<template slot-scope="scope">
<el-link style="cursor: pointer" @click="openPriceSheet(scope.row)">价格表</el-link>
</template>
</el-table-column>
<el-table-column prop="price" label="价格" min-width="80" header-align="center" align="right">
<template slot-scope="scope"> <template slot-scope="scope">
{{ formatMoney(scope.row.price) }} {{ formatMoney(scope.row.price) }}
</template> </template>
@ -72,21 +96,78 @@
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="createdDate" label="报价时间" min-width="160" header-align="center" align="center" />
<el-table-column prop="supplierId" label="报价供应商编码" min-width="120" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="supplierName" label="报价供应商名称" min-width="200" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="categoryName" label="物料分类" min-width="100" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="categoryLevel2Name" label="物料二级分类" min-width="100" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="categoryLevel3Name" label="物料三级分类" min-width="100" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="priceDate" label="价格日期" min-width="160" header-align="center" align="center">
<template slot-scope="scope">
{{ formatDateOnly(scope.row.priceDate) }}
</template>
</el-table-column>
<el-table-column prop="supplierId" label="供应商编码" min-width="120" header-align="center" align="left" show-overflow-tooltip />
<el-table-column prop="supplierName" label="供应商名称" min-width="200" header-align="center" align="left" show-overflow-tooltip />
</el-table> </el-table>
<el-card shadow="never" class="chart-card"> <el-card shadow="never" class="chart-card">
<div slot="header" class="chart-card__header"> <div slot="header" class="chart-card__header">
<span>价格趋势已接受报价</span>
<span>价格趋势供应商历史价格</span>
</div> </div>
<div id="partPriceChart" class="chart-box" :style="{ height: chartHeight + 'px' }"></div> <div id="partPriceChart" class="chart-box" :style="{ height: chartHeight + 'px' }"></div>
</el-card> </el-card>
<el-dialog
title="价格表"
:visible.sync="priceSheetDialogVisible"
width="600px"
:close-on-click-modal="false"
v-drag
append-to-body
>
<el-form :inline="true" label-position="top" class="pi-price-sheet-form">
<el-form-item label="产品">
<el-input :value="displayText(priceSheetHeader.productText)" disabled style="width: 190px" />
</el-form-item>
<el-form-item label="价格日期">
<el-input :value="displayText(formatDateOnly(priceSheetHeader.priceDate))" disabled style="width: 80px" />
</el-form-item>
<!-- <el-form-item label="供应商编码">-->
<!-- <el-input :value="displayText(priceSheetHeader.supplierId)" disabled style="width: 100px" />-->
<!-- </el-form-item>-->
<el-form-item label="供应商名称">
<el-input :value="displayText(priceSheetHeader.supplierName)" disabled style="width: 180px" />
</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="300"
border
stripe
v-loading="priceSheetLoading"
style="width: 100%"
>
<el-table-column prop="qtyStart" label="开始数量" min-width="80" 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="80" 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="80" 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="150" 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>
<Chooselist <Chooselist
ref="baseList" ref="baseList"
@getBaseData="getBaseData"> @getBaseData="getBaseData">
@ -97,6 +178,7 @@
<script> <script>
import echarts from 'echarts' import echarts from 'echarts'
import { searchPartPriceAnalysis } from '@/api/supplier/partPriceAnalysis' import { searchPartPriceAnalysis } from '@/api/supplier/partPriceAnalysis'
import { listTierPriceHistoryDetail } from '@/api/supplier/supplierPartMoqPrice'
import Chooselist from '@/views/modules/common/Chooselist_eam' import Chooselist from '@/views/modules/common/Chooselist_eam'
function getDefaultStartDate () { function getDefaultStartDate () {
@ -106,6 +188,17 @@ function getDefaultStartDate () {
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
} }
function createEmptyProductInfo () {
return {
partNo: '',
partDesc: '',
item: '',
sku: '',
categoryName: '',
categoryLevel2Name: ''
}
}
export default { export default {
name: 'PartPriceAnalysis', name: 'PartPriceAnalysis',
components: { components: {
@ -123,6 +216,19 @@ export default {
partNo: '', partNo: '',
supplierId: '' supplierId: ''
}, },
showProductInfo: false,
productInfo: createEmptyProductInfo(),
priceSheetDialogVisible: false,
priceSheetLoading: false,
priceSheetHeader: {
productText: '',
priceDate: '',
supplierId: '',
supplierName: '',
currency: '',
historyMainId: null
},
priceSheetDetailList: [],
tableHeight: 280, tableHeight: 280,
chartHeight: 320, chartHeight: 320,
chartInstance: null chartInstance: null
@ -178,6 +284,8 @@ export default {
partNo: '', partNo: '',
supplierId: '' supplierId: ''
} }
this.showProductInfo = false
this.productInfo = createEmptyProductInfo()
this.dataList = [] this.dataList = []
this.renderChart([]) this.renderChart([])
}, },
@ -232,10 +340,14 @@ export default {
} }
searchPartPriceAnalysis(params).then(({ data }) => { searchPartPriceAnalysis(params).then(({ data }) => {
if (data && data.code === 0) { if (data && data.code === 0) {
this.showProductInfo = true
this.productInfo = Object.assign(createEmptyProductInfo(), data.productInfo || {}, {
partNo: (data.productInfo && data.productInfo.partNo) || params.partNo
})
this.dataList = data.list || [] this.dataList = data.list || []
this.renderChart(this.dataList) this.renderChart(this.dataList)
if (this.dataList.length === 0) { if (this.dataList.length === 0) {
this.$message.info('未查询到已接受报价记录')
this.$message.info('未查询到历史价格记录')
} }
} else { } else {
this.$message.error((data && data.msg) || '查询失败') this.$message.error((data && data.msg) || '查询失败')
@ -246,14 +358,49 @@ export default {
this.$message.error('请求失败') this.$message.error('请求失败')
}) })
}, },
openPriceSheet (row) {
if (!row || !row.historyMainId) {
this.$message.warning('当前记录未找到关联价格表')
return
}
const productText = [row.partNo, row.partDesc].filter(Boolean).join(' / ')
this.priceSheetHeader = {
productText,
priceDate: row.priceDate || '',
supplierId: row.supplierId || '',
supplierName: row.supplierName || '',
currency: row.currency || '',
historyMainId: row.historyMainId
}
this.priceSheetDetailList = []
this.priceSheetDialogVisible = true
this.priceSheetLoading = true
const params = {
site: this.$store.state.user.site,
historyMainId: row.historyMainId
}
listTierPriceHistoryDetail(params).then(({ data }) => {
if (data && data.code === 0) {
this.priceSheetDetailList = data.rows || []
} else {
this.priceSheetDetailList = []
this.$message.error((data && data.msg) || '获取价格表明细失败')
}
this.priceSheetLoading = false
}).catch(() => {
this.priceSheetLoading = false
this.priceSheetDetailList = []
this.$message.error('获取价格表明细失败')
})
},
renderChart (list) { renderChart (list) {
if (!this.chartInstance) { if (!this.chartInstance) {
this.initChart() this.initChart()
} }
const chartData = [...list].sort((a, b) => { const chartData = [...list].sort((a, b) => {
return new Date(a.createdDate).getTime() - new Date(b.createdDate).getTime()
return new Date(a.priceDate).getTime() - new Date(b.priceDate).getTime()
}) })
const xAxisData = chartData.map(item => this.formatChartDate(item.createdDate))
const xAxisData = chartData.map(item => this.formatChartDate(item.priceDate))
const seriesData = chartData.map(item => item.price) const seriesData = chartData.map(item => item.price)
const titleSuffix = this.searchData.supplierId const titleSuffix = this.searchData.supplierId
? `${this.searchData.partNo} / ${this.searchData.supplierId}` ? `${this.searchData.partNo} / ${this.searchData.supplierId}`
@ -261,7 +408,7 @@ export default {
const option = { const option = {
title: { title: {
text: chartData.length ? `物料价格趋势 - ${titleSuffix}` : '暂无数据',
text: chartData.length ? `产品价格趋势 - ${titleSuffix}` : '暂无数据',
left: 'center', left: 'center',
textStyle: { textStyle: {
fontSize: 14, fontSize: 14,
@ -277,8 +424,8 @@ export default {
const index = params[0].dataIndex const index = params[0].dataIndex
const row = chartData[index] || {} const row = chartData[index] || {}
return [ return [
`报价时间${this.formatDateTime(row.createdDate)}`,
`价:${this.formatMoney(row.price)}`,
`价格日期${this.formatDateOnly(row.priceDate)}`,
`${this.formatMoney(row.price)}`,
`供应商:${row.supplierId || '-'} ${row.supplierName || ''}` `供应商:${row.supplierId || '-'} ${row.supplierName || ''}`
].join('<br/>') ].join('<br/>')
} }
@ -303,7 +450,7 @@ export default {
scale: true scale: true
}, },
series: [{ series: [{
name: '价',
name: '价',
type: 'line', type: 'line',
smooth: true, smooth: true,
symbol: 'circle', symbol: 'circle',
@ -328,6 +475,19 @@ export default {
maximumFractionDigits: 2 maximumFractionDigits: 2
}).format(value) }).format(value)
}, },
displayText (value) {
return value === null || value === undefined || value === '' ? '-' : value
},
formatNumber (value) {
if (value === null || value === undefined || value === '') {
return '-'
}
const num = Number(value)
if (Number.isNaN(num)) {
return value
}
return String(Object.is(num, -0) ? 0 : num)
},
getPriceChangeClass (value) { getPriceChangeClass (value) {
if (!value || value === '-') { if (!value || value === '-') {
return '' return ''
@ -362,6 +522,17 @@ export default {
} }
const pad = num => String(num).padStart(2, '0') const pad = num => String(num).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}` return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
},
formatDateOnly (value) {
if (!value) {
return ''
}
const date = new Date(value)
if (Number.isNaN(date.getTime())) {
return value
}
const pad = num => String(num).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
} }
} }
} }
@ -372,6 +543,15 @@ export default {
margin-top: 12px; margin-top: 12px;
} }
.part-price-analysis .pi-product-form {
margin-top: 2px;
margin-bottom: 10px;
}
.part-price-analysis .pi-price-sheet-form {
margin-top: 2px;
}
.part-price-analysis .chart-card__header { .part-price-analysis .chart-card__header {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;

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

@ -273,10 +273,62 @@
</el-form> </el-form>
</div> </div>
<div slot="footer" class="dialog-footer" style="margin-top: 20px; text-align: center;"> <div slot="footer" class="dialog-footer" style="margin-top: 20px; text-align: center;">
<div style="margin-bottom: 8px;">
<el-button @click="openTierPriceDialog">阶梯表</el-button>
</div>
<el-button type="primary" @click="submitQuote">提交报价</el-button> <el-button type="primary" @click="submitQuote">提交报价</el-button>
<el-button @click="cancelQuote">取消</el-button> <el-button @click="cancelQuote">取消</el-button>
</div> </div>
</el-dialog> </el-dialog>
<el-dialog
title="阶梯表维护"
:visible.sync="tierPriceDialogVisible"
width="760px"
top="6vh"
:close-on-click-modal="false"
append-to-body
v-drag
class="part-dialog"
>
<div class="rq">
<div class="tier-price-header">
<span class="tier-price-title">阶梯价格表</span>
<el-button type="primary" size="mini" @click="addTierPriceRow">新增阶梯</el-button>
</div>
<el-table :data="quoteForm.tierPriceList" border stripe size="mini" style="width: 100%">
<el-table-column label="开始数量" min-width="120" header-align="center" align="right">
<template slot-scope="scope">
<el-input-number v-model="scope.row.qtyStart" :min="0" controls-position="right" style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="结束数量" min-width="120" header-align="center" align="right">
<template slot-scope="scope">
<el-input-number v-model="scope.row.qtyEnd" :min="0" controls-position="right" style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="价格" min-width="140" header-align="center" align="right">
<template slot-scope="scope">
<el-input-number v-model="scope.row.unitPrice" :min="0" controls-position="right" style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="备注" min-width="180" header-align="center" align="left">
<template slot-scope="scope">
<el-input v-model="scope.row.remark" placeholder="备注" />
</template>
</el-table-column>
<el-table-column label="操作" width="90" header-align="center" align="center" fixed="right">
<template slot-scope="scope">
<el-link style="cursor: pointer" :disabled="quoteForm.tierPriceList.length <= 1" @click="removeTierPriceRow(scope.$index)">删除</el-link>
</template>
</el-table-column>
</el-table>
</div>
<div slot="footer" class="dialog-footer" style="text-align: center;">
<el-button type="primary" @click="tierPriceDialogVisible = false">确认</el-button>
<el-button @click="tierPriceDialogVisible = false">取消</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
@ -367,6 +419,7 @@ export default {
], ],
// //
quoteDialogVisible: false, quoteDialogVisible: false,
tierPriceDialogVisible: false,
quoteForm: { quoteForm: {
// //
partNo: '', partNo: '',
@ -392,6 +445,7 @@ export default {
// //
remark2: '', remark2: '',
remark: '', remark: '',
tierPriceList: [],
// //
orderNo: '', orderNo: '',
itemNo: '', itemNo: '',
@ -417,7 +471,8 @@ export default {
taxRate: [{ required: true, message: '请输入税率', trigger: 'blur' }] taxRate: [{ required: true, message: '请输入税率', trigger: 'blur' }]
}, },
// //
lastQuoteData: null
lastQuoteData: null,
lastTierPriceData: null
} }
}, },
created() { created() {
@ -449,6 +504,96 @@ export default {
tempPartDesc(row) { tempPartDesc(row) {
return formatTempPartDesc(row) return formatTempPartDesc(row)
}, },
createTierPriceRow(row = {}) {
return {
qtyStart: row.qtyStart != null ? Number(row.qtyStart) : 0,
qtyEnd: row.qtyEnd != null ? Number(row.qtyEnd) : 0,
unitPrice: row.unitPrice != null ? Number(row.unitPrice) : 0,
remark: row.remark || ''
}
},
addTierPriceRow() {
if (!Array.isArray(this.quoteForm.tierPriceList)) {
this.$set(this.quoteForm, 'tierPriceList', [])
}
this.quoteForm.tierPriceList.push(this.createTierPriceRow())
},
openTierPriceDialog() {
if (!Array.isArray(this.quoteForm.tierPriceList) || !this.quoteForm.tierPriceList.length) {
this.$set(this.quoteForm, 'tierPriceList', [this.createTierPriceRow()])
}
this.tierPriceDialogVisible = true
},
removeTierPriceRow(index) {
if (!Array.isArray(this.quoteForm.tierPriceList)) {
return
}
if (this.quoteForm.tierPriceList.length <= 1) {
this.$message.warning('至少保留一条阶梯价格')
return
}
this.quoteForm.tierPriceList.splice(index, 1)
},
validateTierPriceList() {
const rows = this.quoteForm.tierPriceList || []
if (!rows.length) {
this.$message.error('请至少维护一条阶梯价格')
return false
}
const normalizedRows = rows.map((row, index) => {
const qtyStart = Number(row.qtyStart)
const qtyEnd = Number(row.qtyEnd)
const unitPrice = Number(row.unitPrice)
if (Number.isNaN(qtyStart) || qtyStart < 0) {
this.$message.error(`${index + 1}行开始数量必须大于等于0`)
return null
}
if (Number.isNaN(qtyEnd) || qtyEnd < 0) {
this.$message.error(`${index + 1}行结束数量必须大于等于0`)
return null
}
if (qtyStart > qtyEnd) {
this.$message.error(`${index + 1}行开始数量不能大于结束数量`)
return null
}
if (Number.isNaN(unitPrice) || unitPrice < 0) {
this.$message.error(`${index + 1}行价格必须大于等于0`)
return null
}
return {
qtyStart,
qtyEnd,
unitPrice,
remark: row.remark ? String(row.remark).trim() : ''
}
})
if (normalizedRows.some(item => !item)) {
return false
}
const sortedRows = [...normalizedRows].sort((a, b) => {
if (a.qtyStart === b.qtyStart) {
return a.qtyEnd - b.qtyEnd
}
return a.qtyStart - b.qtyStart
})
for (let i = 1; i < sortedRows.length; i++) {
const prev = sortedRows[i - 1]
const curr = sortedRows[i]
if (curr.qtyStart <= prev.qtyEnd) {
this.$message.error('阶梯价格数量区间存在重叠,请检查')
return false
}
}
return true
},
buildTierPricePayload() {
return (this.quoteForm.tierPriceList || []).map(row => ({
qtyStart: Number(row.qtyStart || 0),
qtyEnd: Number(row.qtyEnd || 0),
unitPrice: Number(row.unitPrice || 0),
remark: row.remark ? String(row.remark).trim() : ''
}))
},
handleResize() { handleResize() {
this.height = (window.innerHeight - 280) / 2 this.height = (window.innerHeight - 280) / 2
this.tabHeight = this.height - 50 this.tabHeight = this.height - 50
@ -554,6 +699,11 @@ export default {
const hasLastData = this.lastQuoteData && const hasLastData = this.lastQuoteData &&
this.lastQuoteData.orderNo === row.orderNo && this.lastQuoteData.orderNo === row.orderNo &&
this.lastQuoteData.itemNo === row.itemNo this.lastQuoteData.itemNo === row.itemNo
const hasLastTierData = this.lastTierPriceData &&
this.lastTierPriceData.orderNo === row.orderNo &&
this.lastTierPriceData.itemNo === row.itemNo &&
Array.isArray(this.lastTierPriceData.tierPriceList) &&
this.lastTierPriceData.tierPriceList.length > 0
// //
this.quoteForm = { this.quoteForm = {
@ -584,6 +734,9 @@ export default {
// //
remark2: row.remark2 || '', remark2: row.remark2 || '',
remark: hasLastData ? this.lastQuoteData.remark : (row.remark || ''), remark: hasLastData ? this.lastQuoteData.remark : (row.remark || ''),
tierPriceList: hasLastTierData
? this.lastTierPriceData.tierPriceList.map(item => this.createTierPriceRow(item))
: [this.createTierPriceRow()],
// //
orderNo: row.orderNo, orderNo: row.orderNo,
itemNo: row.itemNo, itemNo: row.itemNo,
@ -622,6 +775,9 @@ export default {
this.$message.error('未税单价必须大于0') this.$message.error('未税单价必须大于0')
return return
} }
if (!this.validateTierPriceList()) {
return
}
// //
const totalCost = this.quoteForm.materialCost + this.quoteForm.produceFee + const totalCost = this.quoteForm.materialCost + this.quoteForm.produceFee +
this.quoteForm.surfaceFee + this.quoteForm.profit + this.quoteForm.surfaceFee + this.quoteForm.profit +
@ -630,6 +786,7 @@ export default {
const submitData = { const submitData = {
...this.quoteForm, ...this.quoteForm,
tierPriceList: this.buildTierPricePayload(),
totalCost: totalCost totalCost: totalCost
} }
@ -638,7 +795,9 @@ export default {
this.$message.success('报价提交成功') this.$message.success('报价提交成功')
// //
this.lastQuoteData = null this.lastQuoteData = null
this.lastTierPriceData = null
this.quoteDialogVisible = false this.quoteDialogVisible = false
this.tierPriceDialogVisible = false
// //
this.refreshCurrentTabTable() this.refreshCurrentTabTable()
// //
@ -678,7 +837,13 @@ export default {
// //
remark: this.quoteForm.remark remark: this.quoteForm.remark
} }
this.lastTierPriceData = {
orderNo: this.quoteForm.orderNo,
itemNo: this.quoteForm.itemNo,
tierPriceList: this.buildTierPricePayload()
}
this.quoteDialogVisible = false this.quoteDialogVisible = false
this.tierPriceDialogVisible = false
} }
} }
} }
@ -758,6 +923,18 @@ export default {
line-height: 1.5; line-height: 1.5;
} }
.tier-price-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.tier-price-title {
font-weight: 500;
color: #303133;
}
/* 对话框底部按钮居中 */ /* 对话框底部按钮居中 */
.dialog-footer-center { .dialog-footer-center {
text-align: center; text-align: center;

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

@ -46,9 +46,10 @@
<!-- 列表 --> <!-- 列表 -->
<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="160">
<el-table-column fixed="right" :label="'操作'" header-align="center" align="center" width="220">
<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> -->
@ -556,6 +557,65 @@
<el-button @click="partDialogVisible = false">取消</el-button> <el-button @click="partDialogVisible = false">取消</el-button>
</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>
@ -566,7 +626,8 @@ import {
createPurReplyHist, createPurReplyHist,
updatePurReplyHist, updatePurReplyHist,
deletePurReplyHist, deletePurReplyHist,
updatePurReplyHistStatus
updatePurReplyHistStatus,
getPurReplyPriceSheet
} from '@/api/supplier/purReplyHist.js' } from '@/api/supplier/purReplyHist.js'
import { import {
@ -685,7 +746,19 @@ export default {
closeTolerance: 0, closeTolerance: 0,
overReceiveFlag: 'N', overReceiveFlag: 'N',
overReceiveTolerance: 0 overReceiveTolerance: 0
}
},
priceSheetDialogVisible: false,
priceSheetLoading: false,
priceSheetHeader: {
quotationReplyHistId: null,
partNo: '',
partDesc: '',
priceDate: '',
supplierId: '',
supplierName: '',
currency: ''
},
priceSheetDetailList: []
} }
}, },
mounted() { mounted() {
@ -757,6 +830,79 @@ 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) {
if (value === null || value === undefined || value === '') {
return '0'
}
const num = Number(value)
if (Number.isNaN(num)) {
return '0'
}
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 = {
@ -1036,6 +1182,10 @@ 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