feat(bid): 优化供应商报价和甲方报价页面展示
1. 重构SupplierQuoteTab移除冗余空状态样式 2. 为CompareSection添加交期最快标识样式和逻辑 3. 全新重构ClientQuoteTab页面,优化表格布局与样式
This commit is contained in:
@@ -1,30 +1,69 @@
|
||||
<template>
|
||||
<div>
|
||||
<div style="margin-bottom:10px; text-align:right">
|
||||
<div class="client-quote-tab">
|
||||
<!-- 操作栏 -->
|
||||
<div class="tab-toolbar">
|
||||
<span class="tab-title">甲方报价记录</span>
|
||||
<el-button size="mini" icon="el-icon-download" @click="exportExcel">导出Excel</el-button>
|
||||
</div>
|
||||
<el-table :data="list" v-loading="loading" border size="small">
|
||||
<el-table-column label="报价日期" prop="create_time" width="160" />
|
||||
<el-table-column label="甲方名称" prop="client_name" width="160" />
|
||||
<el-table-column label="成本价(元)" prop="cost_price" width="120">
|
||||
<template slot-scope="scope">¥{{ scope.row.cost_price }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单价(元)" prop="unit_price" width="120">
|
||||
<template slot-scope="scope">¥{{ scope.row.unit_price }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成交价(元)" prop="total_price" width="120">
|
||||
<template slot-scope="scope">¥{{ scope.row.total_price }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="报价单号" prop="quote_no" width="150" />
|
||||
<el-table-column label="状态" prop="quote_status" width="100">
|
||||
|
||||
<!-- 报价表格 -->
|
||||
<el-table
|
||||
:data="list"
|
||||
v-loading="loading"
|
||||
border
|
||||
size="small"
|
||||
class="quote-table"
|
||||
:header-cell-style="headerStyle">
|
||||
<el-table-column label="报价日期" width="120" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.quote_status === 'accepted' ? 'success' : 'danger'" size="small">
|
||||
{{ scope.row.quote_status === 'accepted' ? '已接受' : '已拒绝' }}
|
||||
<span class="date-cell">{{ formatDate(scope.row.create_time) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="甲方信息" min-width="200">
|
||||
<template slot-scope="scope">
|
||||
<div class="client-info">
|
||||
<div class="client-name">{{ scope.row.client_name }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="成本价(元)" width="120" align="right">
|
||||
<template slot-scope="scope">
|
||||
<span class="price-cell cost-price">¥{{ formatPrice(scope.row.cost_price) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="单价(元)" width="120" align="right">
|
||||
<template slot-scope="scope">
|
||||
<span class="price-cell">¥{{ formatPrice(scope.row.unit_price) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="成交价(元)" width="120" align="right">
|
||||
<template slot-scope="scope">
|
||||
<span class="price-cell total-price">¥{{ formatPrice(scope.row.total_price) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="报价单号" width="150" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span class="quote-no">{{ scope.row.quote_no }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag
|
||||
:type="getStatusType(scope.row.quote_status)"
|
||||
size="small"
|
||||
effect="dark"
|
||||
class="status-tag">
|
||||
{{ getStatusText(scope.row.quote_status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-if="!loading && !list.length" description="暂无甲方报价" :image-size="80" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -45,9 +84,124 @@ export default {
|
||||
this.loading = false;
|
||||
}).catch(() => { this.loading = false; });
|
||||
},
|
||||
formatDate(dateStr) {
|
||||
if (!dateStr) return '-';
|
||||
const date = new Date(dateStr);
|
||||
return date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' });
|
||||
},
|
||||
formatPrice(price) {
|
||||
if (!price && price !== 0) return '-';
|
||||
return Number(price).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
},
|
||||
getStatusType(status) {
|
||||
const map = { 'accepted': 'success', 'rejected': 'danger', 'pending': 'warning', 'draft': 'info' };
|
||||
return map[status] || 'info';
|
||||
},
|
||||
getStatusText(status) {
|
||||
const map = { 'accepted': '已接受', 'rejected': '已拒绝', 'pending': '待处理', 'draft': '草稿' };
|
||||
return map[status] || status;
|
||||
},
|
||||
headerStyle() {
|
||||
return {
|
||||
background: '#f5f7fa',
|
||||
color: '#606266',
|
||||
fontWeight: 600,
|
||||
fontSize: '13px'
|
||||
};
|
||||
},
|
||||
exportExcel() {
|
||||
this.$message.info('导出功能开发中');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.client-quote-tab {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* 工具栏 */
|
||||
.tab-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 16px;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #e4e7ed 100%);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.tab-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
/* 表格样式 */
|
||||
.quote-table {
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
>>> .el-table__header-wrapper {
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
/* 日期单元格 */
|
||||
.date-cell {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 甲方信息 */
|
||||
.client-info {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.client-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 价格单元格 */
|
||||
.price-cell {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.price-cell.cost-price {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.price-cell.total-price {
|
||||
color: #67c23a;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* 报价单号 */
|
||||
.quote-no {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
font-family: 'Courier New', monospace;
|
||||
background: #f5f7fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* 状态标签 */
|
||||
.status-tag {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 行悬停效果 */
|
||||
>>> .el-table__row:hover {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -107,7 +107,10 @@
|
||||
v-for="(quote, qIdx) in quoteMap[mat.materialId]"
|
||||
:key="qIdx"
|
||||
class="quote-row"
|
||||
:class="{ 'is-lowest': isLowestPrice(mat.materialId, qIdx) }">
|
||||
:class="{
|
||||
'is-lowest': isLowestPrice(mat.materialId, qIdx),
|
||||
'is-fastest': isFastestDelivery(mat.materialId, qIdx)
|
||||
}">
|
||||
<div class="qr-col supplier-col">
|
||||
<span class="supplier-name" :title="quote.supplier_name">{{ quote.supplier_name }}</span>
|
||||
<span v-if="quote.supplier_contact || quote.supplier_phone" class="supplier-contact">
|
||||
@@ -115,10 +118,11 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="qr-col price-col">
|
||||
<span class="price-value">¥{{ formatPrice(quote.unit_price) }}</span>
|
||||
<span v-if="isLowestPrice(mat.materialId, qIdx)" class="lowest-tag">最低</span>
|
||||
<span class="price-value" :class="{ 'is-lowest-price': isLowestPrice(mat.materialId, qIdx) }">¥{{ formatPrice(quote.unit_price) }}</span>
|
||||
</div>
|
||||
<div class="qr-col delivery-col">
|
||||
<span class="delivery-value" :class="{ 'is-fastest-delivery': isFastestDelivery(mat.materialId, qIdx) }">{{ quote.delivery_days || '—' }}</span>
|
||||
</div>
|
||||
<div class="qr-col delivery-col">{{ quote.delivery_days || '—' }}</div>
|
||||
<div class="qr-col quote-no-col" :title="quote.quote_no">{{ quote.quote_no }}</div>
|
||||
<div class="qr-col date-col">{{ formatDate(quote.submit_time) }}</div>
|
||||
</div>
|
||||
@@ -320,6 +324,17 @@ export default {
|
||||
const quotes = this.quoteMap[materialId];
|
||||
if (!quotes || !quotes.length) return false;
|
||||
return quoteIndex === 0;
|
||||
},
|
||||
|
||||
isFastestDelivery(materialId, quoteIndex) {
|
||||
const quotes = this.quoteMap[materialId];
|
||||
if (!quotes || !quotes.length) return false;
|
||||
// 找出最小交期
|
||||
const minDays = Math.min(...quotes.map(q => Number(q.delivery_days) || Infinity));
|
||||
if (minDays === Infinity) return false;
|
||||
// 检查当前报价的交期是否等于最小交期
|
||||
const currentDays = Number(quotes[quoteIndex].delivery_days);
|
||||
return currentDays === minDays;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -569,6 +584,14 @@ export default {
|
||||
background: linear-gradient(90deg, #f0f9eb 0%, #e8f5e0 100%);
|
||||
border-left: 3px solid #67c23a;
|
||||
}
|
||||
.quote-row.is-fastest {
|
||||
background: linear-gradient(90deg, #ecf5ff 0%, #d9ecff 100%);
|
||||
border-left: 3px solid #409eff;
|
||||
}
|
||||
.quote-row.is-lowest.is-fastest {
|
||||
background: linear-gradient(90deg, #f0f9eb 0%, #e8f5e0 50%, #ecf5ff 100%);
|
||||
border-left: 3px solid #67c23a;
|
||||
}
|
||||
|
||||
.qr-col {
|
||||
text-align: center;
|
||||
@@ -597,19 +620,24 @@ export default {
|
||||
|
||||
.price-value {
|
||||
font-weight: 700;
|
||||
color: #f56c6c;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
.lowest-tag {
|
||||
display: inline-block;
|
||||
background: #67c23a;
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
padding: 1px 5px;
|
||||
border-radius: 3px;
|
||||
margin-left: 4px;
|
||||
vertical-align: middle;
|
||||
font-weight: 500;
|
||||
.price-value.is-lowest-price {
|
||||
color: #67c23a;
|
||||
border-bottom: 2px solid #67c23a;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.delivery-value {
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
.delivery-value.is-fastest-delivery {
|
||||
color: #e6a23c;
|
||||
border-bottom: 2px solid #e6a23c;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.qr-col.delivery-col,
|
||||
|
||||
@@ -69,13 +69,6 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<el-empty v-if="!loading && !list.length" description="暂无供应商报价" :image-size="80">
|
||||
<template #description>
|
||||
<span class="empty-text">暂无供应商报价记录</span>
|
||||
</template>
|
||||
</el-empty>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -222,12 +215,6 @@ export default {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-text {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 行悬停效果 */
|
||||
>>> .el-table__row:hover {
|
||||
background-color: #f5f7fa !important;
|
||||
|
||||
Reference in New Issue
Block a user