449 lines
21 KiB
Vue
449 lines
21 KiB
Vue
<script setup lang="ts">
|
||
/**
|
||
* F006 询价详情 (W5.x.x+5 整改) - 完整版
|
||
*
|
||
* 沿用老 vue supplier/inquiry/inquiry-detail.vue 491 行完整功能:
|
||
* - 询价基本信息 (产品/品牌/规格/单位/数量/收货地址/备注/交货日期/价格有效)
|
||
* - 报价列表 (供应商/报价状态/报价时间/报价次数/来源)
|
||
* - 操作: 导出价格分析表 / 查看报价详情
|
||
* - 文件下载
|
||
*/
|
||
import { ref, onMounted, watch, computed } from 'vue'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import { ElMessage } from 'element-plus'
|
||
import { httpGet, httpPost } from '@/utils/request'
|
||
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
||
|
||
interface Inquiry {
|
||
id: string
|
||
title: string
|
||
productName: string
|
||
productBrand: string
|
||
specification: string
|
||
unit: string
|
||
quantity: number
|
||
shippingAddress: string
|
||
detailNote: string
|
||
deliveryDate: string
|
||
priceValidDate: string
|
||
status: number
|
||
enterpriseName: string
|
||
createDate: string
|
||
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
|
||
}
|
||
|
||
interface Quotation {
|
||
id: string
|
||
quotationEnterpriseName: string
|
||
quotationStatus: number
|
||
quotationDate: string
|
||
quotationCountStr: string
|
||
source: string
|
||
totalPrice: number
|
||
raw: any
|
||
}
|
||
|
||
const QUOTATION_STATUS_MAP: Record<number, { label: string; type: string }> = {
|
||
0: { label: '待报价', type: 'warning' },
|
||
1: { label: '已报价', type: 'success' },
|
||
2: { label: '已成交', type: 'primary' },
|
||
3: { label: '已拒绝', type: 'danger' }
|
||
}
|
||
|
||
const INQUIRY_STATUS_MAP: Record<number, { label: string; type: string }> = {
|
||
0: { label: '待报价', type: 'warning' },
|
||
1: { label: '报价中', type: 'primary' },
|
||
2: { label: '已成交', type: 'success' },
|
||
3: { label: '已取消', type: 'info' }
|
||
}
|
||
|
||
const FALLBACK: Inquiry = {
|
||
id: 'RFQ20260705001',
|
||
title: '工业传感器 X100 高精度采购',
|
||
productName: '工业传感器 X100',
|
||
productBrand: '西门子',
|
||
specification: 'X100 0.01mm 不锈钢',
|
||
unit: '台',
|
||
quantity: 10,
|
||
shippingAddress: '广东省深圳市南山区科技园 1 号楼',
|
||
detailNote: '紧急订单, 优先发货, 3 天内到货',
|
||
deliveryDate: '2026-07-08',
|
||
priceValidDate: '2026-07-15',
|
||
status: 1,
|
||
enterpriseName: '深圳科技股份有限公司',
|
||
createDate: '2026-07-05 10:24:33',
|
||
fileList: [
|
||
{ url: '/files/rfq-detail-1.pdf', imagesName: '采购清单.pdf' },
|
||
{ url: '/files/rfq-detail-2.pdf', imagesName: '技术规格书.pdf' }
|
||
],
|
||
quotationList: [
|
||
{ id: 'q1', quotationEnterpriseName: '上海制造企业', quotationStatus: 1, quotationDate: '2026-07-05 11:30', quotationCountStr: '1次', source: '平台报价', totalPrice: 23000, raw: {} },
|
||
{ id: 'q2', quotationEnterpriseName: '北京电子有限公司', quotationStatus: 0, quotationDate: '', quotationCountStr: '0次', source: '邀请报价', totalPrice: 0, raw: {} },
|
||
{ id: 'q3', quotationEnterpriseName: '广州工厂', quotationStatus: 1, quotationDate: '2026-07-05 14:20', quotationCountStr: '2次', source: '平台报价', totalPrice: 22000, raw: {} }
|
||
],
|
||
raw: {}
|
||
}
|
||
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
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: 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 || '',
|
||
detailNote: '', // 清除 FALLBACK 占位文案,备注一律取真实数据
|
||
enterpriseName: resp.inquiryParty || resp.inquiryEnterpriseName || FALLBACK.enterpriseName,
|
||
detailList: resp.inquiryDetailList || [],
|
||
fileList: resetFiles(resp),
|
||
raw: resp,
|
||
}
|
||
// 报价回复:受邀供应商 + 已报价企业商品清单
|
||
await Promise.all([loadInvited(resp.orderId || resp.id), loadQuotes(resp.orderId || resp.id)])
|
||
} else {
|
||
detail.value = { ...FALLBACK, id: inquiryId.value }
|
||
}
|
||
} catch {
|
||
detail.value = { ...FALLBACK, id: inquiryId.value }
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 附件:发布时 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)
|
||
|
||
// 供应商维度报价列表:受邀供应商(含报价状态)+ 主动报价供应商补充
|
||
const supplierRows = computed(() => {
|
||
const groups = quoteGroups.value
|
||
const rows: any[] = []
|
||
const seen = new Set<number>()
|
||
// 已报价企业先入(getQuotationById 分组,企业名非空)
|
||
for (const g of groups) {
|
||
if (!g.name || g.name === '未报价') continue
|
||
const entName = g.name
|
||
const row = {
|
||
name: entName,
|
||
status: 1, // 1=已报价
|
||
date: g.rows.find((r: any) => r.quotationDate)?.quotationDate || '',
|
||
count: g.count,
|
||
total: g.total,
|
||
rows: g.rows,
|
||
invited: false,
|
||
}
|
||
rows.push(row)
|
||
}
|
||
// 受邀供应商:合并状态(邀请表报价状态 0=未报价 1=已报价 2=邀请再次报价)
|
||
for (const inv of invitedSuppliers.value) {
|
||
const id = Number(inv.invitedEnterpriseId)
|
||
const name = inv.enterpriseName || ('企业#' + id)
|
||
const existing = rows.find(r => r.name === name)
|
||
const quoted = Number(inv.quotationStatus) === 1
|
||
if (existing) {
|
||
existing.invited = true
|
||
if (!quoted) existing.status = 0
|
||
continue
|
||
}
|
||
rows.push({
|
||
name,
|
||
status: quoted ? 1 : 0,
|
||
date: '',
|
||
count: 0,
|
||
total: 0,
|
||
rows: [],
|
||
invited: true,
|
||
})
|
||
}
|
||
return rows
|
||
})
|
||
const invitedSuppliers = ref<any[]>([])
|
||
async function loadInvited(orderId: any) {
|
||
try {
|
||
const res: any = await httpGet('/supplier/quotationinvited/listByOrder', { orderId: String(orderId) })
|
||
if (res && Array.isArray(res)) invitedSuppliers.value = res
|
||
else if (res && Array.isArray(res?.list)) invitedSuppliers.value = res.list
|
||
else invitedSuppliers.value = []
|
||
} catch { invitedSuppliers.value = [] }
|
||
}
|
||
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) {
|
||
const note = status === 3 ? prompt('请输入驳回原因:') : ''
|
||
if (status === 3 && note === null) return
|
||
auditLoading.value = true
|
||
try {
|
||
const res: any = await httpPost('/supplier/inquiry/saveInquiryAudit', {
|
||
id: detail.value?.id,
|
||
apprStatus: status,
|
||
...(status === 3 && note ? { auditNote: note } : {}),
|
||
})
|
||
// httpPost 已解包到 data: saveInquiryAudit 返回 data=true(布尔), 兼容 code===0
|
||
if (res === true || res?.code === 0) {
|
||
ElMessage.success(status === 2 ? '审核通过,询价已发布' : '已驳回')
|
||
load()
|
||
} else {
|
||
ElMessage.error(res?.msg || '操作失败')
|
||
}
|
||
} catch (e: any) {
|
||
ElMessage.error(e?.msg || e?.message || '操作失败')
|
||
} finally {
|
||
auditLoading.value = false
|
||
}
|
||
}
|
||
|
||
function fmtDate(s: any): string {
|
||
if (!s) return '--'
|
||
return String(s).substring(0, 19).replace('T', ' ')
|
||
}
|
||
function fmtMoney(n: any): string { return `¥ ${Number(n || 0).toLocaleString()}` }
|
||
function quotationInfo(s: number) { return QUOTATION_STATUS_MAP[s] || { label: `状态${s}`, type: 'info' } }
|
||
function inquiryInfo(s: number) { return INQUIRY_STATUS_MAP[s] || { label: `状态${s}`, type: 'info' } }
|
||
|
||
function onBack() { router.push('/inquiry') }
|
||
function onDownloadFile(url: string, name: string) { if (url) ElMessage.info(`下载: ${name || url}`) }
|
||
function onExportPriceComparison() { ElMessage.info('导出功能开发中') }
|
||
function onViewQuotation(row: Quotation) { ElMessage.info(`查看报价: ${row.quotationEnterpriseName} (请前往询价管理)`) }
|
||
function onQuote(row: Quotation) { ElMessage.info('请前往前台发起报价') }
|
||
|
||
onMounted(load)
|
||
watch(inquiryId, load)
|
||
</script>
|
||
|
||
<template>
|
||
<div class="rr-page">
|
||
<PageHeader title="询价详情" :sub="`询价单号: ${detail?.id || ''} · 发布时间: ${detail ? fmtDate(detail.createDate) : ''}`">
|
||
<el-button text @click="onBack">← 返回询价列表</el-button>
|
||
</PageHeader>
|
||
|
||
<div v-if="loading" class="rr-loading"><el-skeleton :rows="6" animated /></div>
|
||
<div v-else-if="!detail" class="rr-empty"><el-empty description="询价不存在" /></div>
|
||
<div v-else>
|
||
<!-- 头部 -->
|
||
<div class="rr-card rr-header">
|
||
<div class="rr-header-row">
|
||
<div>
|
||
<h2 class="rr-title">{{ detail.title }}</h2>
|
||
<p class="rr-sub">询价单号: {{ detail.id }} · 发布时间: {{ fmtDate(detail.createDate) }}</p>
|
||
</div>
|
||
<el-tag :type="(inquiryInfo(detail.status).type as any)" size="large" effect="light">
|
||
{{ inquiryInfo(detail.status).label }}
|
||
</el-tag>
|
||
</div>
|
||
<div class="rr-header-actions">
|
||
<template v-if="detail.raw?.apprStatus === 1">
|
||
<el-button type="success" :loading="auditLoading" @click="onAudit(2)">审核通过</el-button>
|
||
<el-button type="danger" :loading="auditLoading" @click="onAudit(3)">驳回</el-button>
|
||
</template>
|
||
<el-button @click="onExportPriceComparison">导出基础价格分析表</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 询价基本信息 -->
|
||
<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="询价主体(采购方)" :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.createDate || detail.publishDate || '--' }}</el-descriptions-item>
|
||
<el-descriptions-item label="收货地址" :span="2">{{ detail.shippingAddress || '--' }}</el-descriptions-item>
|
||
<el-descriptions-item label="询价备注" :span="2">{{ detail.note || '--' }}</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>
|
||
<div class="rr-files">
|
||
<div v-for="(f, i) in detail.fileList" :key="i" class="rr-file-item">
|
||
<el-icon><Document /></el-icon>
|
||
<span class="rr-file-name">{{ f.imagesName }}</span>
|
||
<el-button text type="primary" size="small" @click="onDownloadFile(f.url, f.imagesName)">下载</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 报价列表(供应商维度:受邀未报价 / 已报价,展开查看商品清单) -->
|
||
<div class="rr-card">
|
||
<div class="rr-card-header"><h3 class="rr-card-title">报价列表 ({{ supplierRows.length }} 家供应商)</h3></div>
|
||
<div v-if="quoteLoading" class="rr-empty">加载报价中...</div>
|
||
<div v-else-if="!supplierRows.length" class="rr-empty">暂无受邀供应商与报价</div>
|
||
<el-table v-else :data="supplierRows" border size="small" row-key="name">
|
||
<el-table-column type="expand">
|
||
<template #default="{ row }">
|
||
<div v-if="row.rows.length" class="rr-expand">
|
||
<el-table :data="row.rows" border size="small" class="rr-expand-table">
|
||
<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: r }">{{ r.specification || '--' }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="报价单价(含税)" width="130" align="right">
|
||
<template #default="{ row: r }">¥ {{ Number(r.unitPriceTaxIncluded || r.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: r }">{{ r.unit || '件' }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="生产周期" min-width="110">
|
||
<template #default="{ row: r }">{{ r.productionCycle || '--' }}</template>
|
||
</el-table-column>
|
||
<el-table-column prop="quotationNote" label="备注" min-width="130">
|
||
<template #default="{ row: r }">{{ r.quotationNote || '--' }}</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
<div v-else class="rr-tip">该供应商尚未提交报价</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="name" label="供应商" min-width="200" show-overflow-tooltip />
|
||
<el-table-column label="报价状态" width="120" align="center">
|
||
<template #default="{ row }">
|
||
<span v-if="Number(row.status) === 1" class="rr-tag rr-tag-green">已报价</span>
|
||
<span v-else class="rr-tag rr-tag-amber">{{ row.invited ? '受邀未报价' : '未报价' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="报价时间" width="180">
|
||
<template #default="{ row }">{{ row.date || '--' }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="商品项数" width="100" align="center">
|
||
<template #default="{ row }">{{ row.count || '--' }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="报价合计" width="140" align="right">
|
||
<template #default="{ row }">
|
||
<span v-if="row.total > 0">¥ {{ Number(row.total).toLocaleString() }}</span>
|
||
<span v-else>--</span>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<div class="rr-tip mt10">受邀未报价的供应商将不展示报价清单,点击行展开可查看已报价企业的逐商品报价详情</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped lang="scss">
|
||
.rr-page { max-width: 1400px; }
|
||
.rr-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; margin-bottom: 16px; }
|
||
.rr-card-header { padding: 16px 20px; border-bottom: 1px solid var(--border); }
|
||
.rr-card-title { font-size: 15px; font-weight: 600; color: var(--ink); margin: 0; }
|
||
.rr-loading { padding: 40px 20px; }
|
||
.rr-empty { padding: 60px 20px; text-align: center; }
|
||
.rr-header { padding: 24px 28px; }
|
||
.rr-header-row { display: flex; justify-content: space-between; align-items: flex-start; }
|
||
.rr-title { font-size: 20px; font-weight: 600; color: var(--ink); margin: 0 0 4px 0; }
|
||
.rr-sub { color: var(--ink-3); font-size: 13px; margin: 0; }
|
||
.rr-header-actions { display: flex; gap: 8px; padding-top: 16px; margin-top: 16px; border-top: 1px solid var(--border); }
|
||
.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; }
|
||
.rr-expand { padding: 10px 24px; }
|
||
.rr-expand-table { max-width: 960px; }
|
||
.rr-tag-amber { background: #fdf6ec; color: #e6a23c; }
|
||
</style>
|