fix(inquiry): 后台询价详情对齐新结构——询价主体=inquiryParty、采购类型/报价方式/报价要求/付款/发票/截止全字段、商品明细表、报价按企业分组(getQuotationById)
This commit is contained in:
parent
5103eb269f
commit
241c269e37
@ -32,6 +32,16 @@ interface Inquiry {
|
||||
fileList: { url: string; imagesName: string }[]
|
||||
// 报价列表
|
||||
quotationList: Quotation[]
|
||||
// 新结构(与发布询价信息一致)
|
||||
procurementTypeName?: string
|
||||
quotationTypeName?: string
|
||||
quotationDemandName?: string
|
||||
paymentMethodName?: string
|
||||
invoiceTypeName?: string
|
||||
inquiryValidDate?: string
|
||||
publishDate?: string
|
||||
note?: string
|
||||
detailList?: any[]
|
||||
raw: any
|
||||
}
|
||||
|
||||
@ -93,29 +103,44 @@ const detail = ref<Inquiry | null>(null)
|
||||
const loading = ref(true)
|
||||
const inquiryId = computed(() => String(route.params.id || ''))
|
||||
|
||||
const PROC_TYPE: Record<number, string> = { 1: '定量采购', 2: '框架采购' }
|
||||
const DEMAND: Record<number, string> = { 1: '不允许部分报价', 2: '允许部分报价' }
|
||||
const INVOICE: Record<number, string> = { 1: '普通发票', 2: '增值税专用发票', 3: '无' }
|
||||
const QUOTE_TYPE: Record<number, string> = { 1: '公开报价', 2: '邀请报价' }
|
||||
const mapLabel = (m: Record<number, string>, v: any) => (v == null ? '--' : m[Number(v)] || String(v))
|
||||
const mapLabel1 = (m: Record<number, string>, v: any) => (v == null ? '--' : m[Number(v)] || String(v))
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
const resp: any = await httpGet('/supplier/inquiry/getById', { id: inquiryId.value })
|
||||
if (resp && resp.id) {
|
||||
const first = resp.inquiryDetailList?.[0] || {}
|
||||
detail.value = {
|
||||
...FALLBACK,
|
||||
...resp,
|
||||
id: String(resp.id || inquiryId.value),
|
||||
title: resp.title || FALLBACK.title,
|
||||
productName: resp.productName || resp.product || FALLBACK.productName,
|
||||
productBrand: resp.brand || resp.productBrand || FALLBACK.productBrand,
|
||||
specification: resp.specification || resp.spec || FALLBACK.specification,
|
||||
unit: resp.unit || FALLBACK.unit,
|
||||
quantity: resp.purchaseQuantity || resp.quantity || FALLBACK.quantity,
|
||||
shippingAddress: resp.shippingAddress || resp.address || FALLBACK.shippingAddress,
|
||||
deliveryDate: resp.deliveryDate || FALLBACK.deliveryDate,
|
||||
priceValidDate: resp.priceValidDate || FALLBACK.priceValidDate,
|
||||
enterpriseName: resp.inquiryEnterpriseName || resp.enterpriseName || FALLBACK.enterpriseName,
|
||||
fileList: resp.fileList || FALLBACK.fileList,
|
||||
quotationList: resp.quotationList || FALLBACK.quotationList,
|
||||
productName: first.productName || '--',
|
||||
productBrand: first.productBrand || '--',
|
||||
specification: first.specification || '--',
|
||||
unit: first.unit || '--',
|
||||
quantity: resp.purchaseQuantity ?? '--',
|
||||
// 新结构字段:与发布询价信息一致
|
||||
procurementTypeName: mapLabel(PROC_TYPE, resp.procurementType),
|
||||
quotationTypeName: mapLabel(QUOTE_TYPE, resp.quotationType),
|
||||
quotationDemandName: mapLabel(DEMAND, resp.quotationDemand),
|
||||
paymentMethodName: resp.paymentMethodName || '--',
|
||||
invoiceTypeName: mapLabel(INVOICE, resp.invoiceType),
|
||||
inquiryValidDate: resp.inquiryValidDate || '--',
|
||||
note: resp.note || '',
|
||||
enterpriseName: resp.inquiryParty || resp.inquiryEnterpriseName || FALLBACK.enterpriseName,
|
||||
detailList: resp.inquiryDetailList || [],
|
||||
fileList: resetFiles(resp),
|
||||
raw: resp,
|
||||
}
|
||||
// 报价回复:按企业分组(getQuotationById 返回逐商品报价行)
|
||||
await loadQuotes(resp.orderId || resp.id)
|
||||
} else {
|
||||
detail.value = { ...FALLBACK, id: inquiryId.value }
|
||||
}
|
||||
@ -126,6 +151,34 @@ async function load() {
|
||||
}
|
||||
}
|
||||
|
||||
// 附件:发布时 images 为 URL 数组 + imageNames 名称数组
|
||||
function resetFiles(resp: any): any[] {
|
||||
const urls: string[] = resp.images || []
|
||||
const names: string[] = resp.imageNames || []
|
||||
return urls.map((u: string, i: number) => ({ url: u, imagesName: names[i] || ('附件' + (i + 1)) }))
|
||||
}
|
||||
|
||||
const quoteGroups = ref<any[]>([])
|
||||
const quoteLoading = ref(false)
|
||||
async function loadQuotes(orderId: any) {
|
||||
quoteLoading.value = true
|
||||
try {
|
||||
const res: any = await httpPost('/supplier/inquiry/getQuotationById', { orderId: String(orderId) })
|
||||
const rows = (res && (Array.isArray(res) ? res : [])) || []
|
||||
const groups: any[] = []
|
||||
for (const q of rows) {
|
||||
const name = q.quotationEnterpriseName || '未报价'
|
||||
let g = groups.find(x => x.name === name)
|
||||
if (!g) { g = { name, rows: [], count: 0, total: 0, date: '', list: [] }; groups.push(g) }
|
||||
g.rows.push(q)
|
||||
g.count++
|
||||
g.total += Number(q.unitPriceTaxIncluded || q.unitPrice || 0) * Number(q.quantity || 0)
|
||||
if (q.quotationDate && !g.date) g.date = q.quotationDate
|
||||
}
|
||||
quoteGroups.value = groups
|
||||
} catch { quoteGroups.value = [] } finally { quoteLoading.value = false }
|
||||
}
|
||||
|
||||
// === 审核操作: apprStatus 2=通过 3=驳回 ===
|
||||
const auditLoading = ref(false)
|
||||
async function onAudit(status: number) {
|
||||
@ -203,19 +256,41 @@ watch(inquiryId, load)
|
||||
<div class="rr-card">
|
||||
<div class="rr-card-header"><h3 class="rr-card-title">询价信息</h3></div>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="产品名称">{{ detail.productName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="品牌">{{ detail.productBrand || '--' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="规格型号">{{ detail.specification || '--' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="单位">{{ detail.unit }}</el-descriptions-item>
|
||||
<el-descriptions-item label="数量">{{ detail.quantity }}</el-descriptions-item>
|
||||
<el-descriptions-item label="询价主体(采购方)" :span="2">{{ detail.enterpriseName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="采购类型">{{ detail.procurementTypeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报价方式">{{ detail.quotationTypeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="采购数量">{{ detail.quantity }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报价要求">{{ detail.quotationDemandName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="付款方式">{{ detail.paymentMethodName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="发票要求">{{ detail.invoiceTypeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="询价截止">{{ detail.inquiryValidDate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="要求交货日期">{{ detail.deliveryDate || '--' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="价格有效截止" :span="2">{{ detail.priceValidDate || '--' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="发布时间" :span="2">{{ detail.createDate || detail.publishDate || '--' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="收货地址" :span="2">{{ detail.shippingAddress || '--' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="询价备注" :span="2">{{ detail.detailNote || '--' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="采购方" :span="2">{{ detail.enterpriseName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="询价备注" :span="2">{{ detail.note || detail.detailNote || '--' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<!-- 商品明细 -->
|
||||
<div class="rr-card" v-if="(detail.detailList || []).length">
|
||||
<div class="rr-card-header"><h3 class="rr-card-title">商品明细 ({{ (detail.detailList || []).length }})</h3></div>
|
||||
<el-table :data="(detail.detailList || [])" border size="small">
|
||||
<el-table-column type="index" label="#" width="50" align="center" />
|
||||
<el-table-column prop="productName" label="商品名称" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="productBrand" label="品牌" min-width="120">
|
||||
<template #default="{ row }">{{ row.productBrand || '--' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="specification" label="规格" min-width="140">
|
||||
<template #default="{ row }">{{ row.specification || '--' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="quantity" label="数量" width="90" align="center" />
|
||||
<el-table-column prop="unit" label="单位" width="80" align="center" />
|
||||
<el-table-column prop="detailNote" label="备注" min-width="140">
|
||||
<template #default="{ row }">{{ row.detailNote || '--' }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 询价附件 -->
|
||||
<div class="rr-card" v-if="detail.fileList.length > 0">
|
||||
<div class="rr-card-header"><h3 class="rr-card-title">询价附件</h3></div>
|
||||
@ -228,39 +303,46 @@ watch(inquiryId, load)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 报价列表 -->
|
||||
<!-- 报价列表(按企业分组) -->
|
||||
<div class="rr-card">
|
||||
<div class="rr-card-header"><h3 class="rr-card-title">报价列表 ({{ detail.quotationList.length }})</h3></div>
|
||||
<el-table :data="detail.quotationList" border style="width: 100%">
|
||||
<el-table-column type="index" label="#" width="50" align="center" />
|
||||
<el-table-column prop="quotationEnterpriseName" label="供应商名称" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="报价状态" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="(quotationInfo(row.quotationStatus).type as any)" size="small" effect="light">
|
||||
{{ quotationInfo(row.quotationStatus).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="报价金额" width="140" align="right">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.totalPrice > 0">{{ fmtMoney(row.totalPrice) }}</span>
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="报价时间" width="170">
|
||||
<template #default="{ row }">{{ row.quotationDate || '--' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="quotationCountStr" label="报价次数" width="100" align="center" />
|
||||
<el-table-column prop="source" label="来源" width="120" align="center" />
|
||||
<el-table-column label="操作" width="160" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.quotationStatus === 1" text type="primary" size="small" @click="onViewQuotation(row)">查看报价</el-button>
|
||||
<el-button v-else text type="primary" size="small" @click="onQuote(row)">邀请报价</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="rr-card-header"><h3 class="rr-card-title">报价列表 ({{ quoteGroups.reduce((a, g) => a + g.count, 0) }})</h3></div>
|
||||
<div v-if="quoteLoading" class="rr-empty">加载报价中...</div>
|
||||
<div v-else-if="!quoteGroups.length" class="rr-empty">暂无报价回复</div>
|
||||
<div v-else class="rr-quote-groups">
|
||||
<div v-for="(g, gi) in quoteGroups" :key="gi" class="rr-quote-group">
|
||||
<div class="rr-quote-group-head">
|
||||
<b>{{ g.name }}</b>
|
||||
<span v-if="g.name !== '未报价'" class="rr-tag rr-tag-green">已报价</span>
|
||||
<span v-else class="rr-tag">待报价</span>
|
||||
<span class="rr-quote-meta">{{ g.count }} 项{{ g.date ? ' · ' + g.date : '' }}</span>
|
||||
</div>
|
||||
<el-table :data="g.rows" border size="small">
|
||||
<el-table-column type="index" label="#" width="46" align="center" />
|
||||
<el-table-column prop="productName" label="商品" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="specification" label="规格" min-width="120">
|
||||
<template #default="{ row }">{{ row.specification || '--' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="报价单价(含税)" width="130" align="right">
|
||||
<template #default="{ row }">¥ {{ Number(row.unitPriceTaxIncluded || row.unitPrice || 0).toLocaleString() }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="quantity" label="数量" width="80" align="center" />
|
||||
<el-table-column prop="unit" label="单位" width="70" align="center">
|
||||
<template #default="{ row }">{{ row.unit || '件' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="生产周期" min-width="110">
|
||||
<template #default="{ row }">{{ row.productionCycle || '--' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="quotationNote" label="备注" min-width="130">
|
||||
<template #default="{ row }">{{ row.quotationNote || '--' }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 旧操作列说明 -->
|
||||
<div class="rr-tip mt10">报价详情可在前台「我的询价-询价详情-企业报价回复」查看</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -279,4 +361,14 @@ watch(inquiryId, load)
|
||||
.rr-files { padding: 16px 20px; display: flex; flex-direction: column; gap: 8px; }
|
||||
.rr-file-item { display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: var(--bg-soft); border-radius: var(--radius); }
|
||||
.rr-file-name { flex: 1; color: var(--ink); font-size: 13px; }
|
||||
|
||||
.rr-quote-groups { display: flex; flex-direction: column; gap: 12px; }
|
||||
.rr-quote-group { border: 1px solid var(--el-border-color); border-radius: 8px; overflow: hidden; }
|
||||
.rr-quote-group-head { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: var(--el-fill-color-light); font-size: 13px; flex-wrap: wrap; }
|
||||
.rr-quote-meta { margin-left: auto; color: var(--el-text-color-secondary); font-size: 12px; }
|
||||
.rr-tag { font-size: 11px; padding: 1px 8px; border-radius: 10px; background: var(--el-color-info-light-9); color: var(--el-text-color-secondary); }
|
||||
.rr-tag-green { background: #f0f9eb; color: #67c23a; }
|
||||
.rr-empty { padding: 24px; text-align: center; color: var(--el-text-color-secondary); font-size: 13px; }
|
||||
.rr-tip { font-size: 12px; color: var(--el-text-color-secondary); }
|
||||
.mt10 { margin-top: 10px; }
|
||||
</style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user