<template>
|
<div class="customer-detail-page">
|
<!-- 顶部导航栏 -->
|
<div class="page-header">
|
<div class="header-left">
|
<el-button @click="goBack" :icon="ArrowLeft" circle />
|
<div class="customer-info">
|
<span class="customer-name">{{ summary.customerName || '客户往来详情' }}</span>
|
<span class="customer-tag">客户往来统计</span>
|
</div>
|
</div>
|
</div>
|
|
<!-- 统计卡片区 -->
|
<div class="stats-section" v-loading="summaryLoading">
|
<div class="stats-grid">
|
<div class="stat-card primary">
|
<div class="stat-icon">
|
<el-icon><Document /></el-icon>
|
</div>
|
<div class="stat-content">
|
<div class="stat-label">合同总金额</div>
|
<div class="stat-value">
|
<span class="currency">¥</span>
|
<span class="number">{{ formatMoney(summary.contractAmounts) }}</span>
|
</div>
|
</div>
|
</div>
|
|
<div class="stat-card success">
|
<div class="stat-icon">
|
<el-icon><Tickets /></el-icon>
|
</div>
|
<div class="stat-content">
|
<div class="stat-label">合同数量</div>
|
<div class="stat-value">
|
<span class="number">{{ summary.contractCount || 0 }}</span>
|
<span class="unit">份</span>
|
</div>
|
</div>
|
</div>
|
|
<div class="stat-card info">
|
<div class="stat-icon">
|
<el-icon><Van /></el-icon>
|
</div>
|
<div class="stat-content">
|
<div class="stat-label">发货金额</div>
|
<div class="stat-value">
|
<span class="currency">¥</span>
|
<span class="number">{{ formatMoney(summary.shippedAmounts) }}</span>
|
</div>
|
</div>
|
</div>
|
|
<div class="stat-card danger">
|
<div class="stat-icon">
|
<el-icon><Clock /></el-icon>
|
</div>
|
<div class="stat-content">
|
<div class="stat-label">未发货金额</div>
|
<div class="stat-value">
|
<span class="currency">¥</span>
|
<span class="number">{{ formatMoney(summary.unshippedAmounts) }}</span>
|
</div>
|
</div>
|
</div>
|
|
<div class="stat-card progress-card">
|
<div class="stat-content-full">
|
<div class="progress-header">
|
<span class="stat-label">发货进度</span>
|
<span class="progress-value">{{ summary.shippedRate || 0 }}%</span>
|
</div>
|
<el-progress
|
:percentage="summary.shippedRate || 0"
|
:stroke-width="12"
|
:show-text="false"
|
:color="getProgressColor(summary.shippedRate)"
|
/>
|
<div class="progress-footer">
|
<span>已发货: ¥{{ formatMoney(summary.shippedAmounts) }}</span>
|
<span>总额: ¥{{ formatMoney(summary.contractAmounts) }}</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- Tab 切换 -->
|
<div class="table-section">
|
<el-tabs v-model="activeTab" class="custom-tabs">
|
<el-tab-pane label="产品明细" name="products">
|
<ProductTable :customerId="customerId" v-if="customerId && activeTab === 'products'" />
|
</el-tab-pane>
|
<!-- <el-tab-pane label="发货明细" name="shipments">
|
<ShipmentTable :customerId="customerId" v-if="customerId && activeTab === 'shipments'" />
|
</el-tab-pane> -->
|
</el-tabs>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, onMounted } from 'vue'
|
import { useRoute, useRouter } from 'vue-router'
|
import { ArrowLeft, Document, Tickets, Van, Clock } from '@element-plus/icons-vue'
|
import { customerTransactionsSummary } from '@/api/salesManagement/indicatorStats.js'
|
import ProductTable from './components/ProductTable.vue'
|
// import ShipmentTable from './components/ShipmentTable.vue'
|
|
const route = useRoute()
|
const router = useRouter()
|
|
const customerId = ref(null)
|
const summary = ref({})
|
const summaryLoading = ref(false)
|
const activeTab = ref('products')
|
|
const getSummary = () => {
|
if (!customerId.value) return
|
summaryLoading.value = true
|
customerTransactionsSummary({ customerId: customerId.value })
|
.then(res => {
|
if (res.code === 200) {
|
summary.value = res.data || {}
|
}
|
})
|
.finally(() => {
|
summaryLoading.value = false
|
})
|
}
|
|
const formatMoney = (value) => {
|
if (!value) return '0.00'
|
return Number(value).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
}
|
|
const getProgressColor = (rate) => {
|
if (!rate || rate < 30) return '#f56c6c'
|
if (rate < 60) return '#e6a23c'
|
if (rate < 80) return '#409eff'
|
return '#67c23a'
|
}
|
|
const goBack = () => {
|
router.push('/salesManagement/receiptPaymentLedger')
|
}
|
|
onMounted(() => {
|
customerId.value = route.query.customerId
|
if (customerId.value) {
|
getSummary()
|
}
|
})
|
</script>
|
|
<style scoped lang="scss">
|
.customer-detail-page {
|
background: #f5f7fa;
|
min-height: calc(100vh - 84px);
|
padding: 20px;
|
}
|
|
.page-header {
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
border-radius: 12px;
|
padding: 20px 24px;
|
margin-bottom: 20px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
|
|
.header-left {
|
display: flex;
|
align-items: center;
|
gap: 16px;
|
|
.el-button {
|
background: rgba(255, 255, 255, 0.2);
|
border: none;
|
color: white;
|
|
&:hover {
|
background: rgba(255, 255, 255, 0.3);
|
}
|
}
|
|
.customer-info {
|
display: flex;
|
flex-direction: column;
|
gap: 4px;
|
|
.customer-name {
|
font-size: 20px;
|
font-weight: 600;
|
color: white;
|
}
|
|
.customer-tag {
|
font-size: 12px;
|
color: rgba(255, 255, 255, 0.8);
|
background: rgba(255, 255, 255, 0.2);
|
padding: 2px 10px;
|
border-radius: 10px;
|
width: fit-content;
|
}
|
}
|
}
|
}
|
|
.stats-section {
|
margin-bottom: 20px;
|
}
|
|
.stats-grid {
|
display: grid;
|
grid-template-columns: repeat(5, 1fr);
|
gap: 16px;
|
|
@media (max-width: 1400px) {
|
grid-template-columns: repeat(3, 1fr);
|
}
|
|
@media (max-width: 1000px) {
|
grid-template-columns: repeat(2, 1fr);
|
}
|
}
|
|
.stat-card {
|
background: white;
|
border-radius: 12px;
|
padding: 20px;
|
display: flex;
|
align-items: center;
|
gap: 16px;
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
transition: all 0.3s ease;
|
position: relative;
|
overflow: hidden;
|
|
&::before {
|
content: '';
|
position: absolute;
|
top: 0;
|
left: 0;
|
width: 4px;
|
height: 100%;
|
}
|
|
&:hover {
|
transform: translateY(-2px);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
}
|
|
&.primary::before { background: linear-gradient(180deg, #667eea, #764ba2); }
|
&.success::before { background: linear-gradient(180deg, #67c23a, #4a9c2d); }
|
&.warning::before { background: linear-gradient(180deg, #e6a23c, #c78a2f); }
|
&.info::before { background: linear-gradient(180deg, #409eff, #2d7dd2); }
|
&.danger::before { background: linear-gradient(180deg, #f56c6c, #c45656); }
|
&.progress-card::before { background: linear-gradient(180deg, #909399, #606266); }
|
|
.stat-icon {
|
width: 52px;
|
height: 52px;
|
border-radius: 12px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
font-size: 24px;
|
flex-shrink: 0;
|
}
|
|
&.primary .stat-icon { background: linear-gradient(135deg, rgba(102, 126, 234, 0.15), rgba(118, 75, 162, 0.15)); color: #667eea; }
|
&.success .stat-icon { background: linear-gradient(135deg, rgba(103, 194, 58, 0.15), rgba(74, 156, 45, 0.15)); color: #67c23a; }
|
&.warning .stat-icon { background: linear-gradient(135deg, rgba(230, 162, 60, 0.15), rgba(199, 138, 47, 0.15)); color: #e6a23c; }
|
&.info .stat-icon { background: linear-gradient(135deg, rgba(64, 158, 255, 0.15), rgba(45, 125, 210, 0.15)); color: #409eff; }
|
&.danger .stat-icon { background: linear-gradient(135deg, rgba(245, 108, 108, 0.15), rgba(196, 86, 86, 0.15)); color: #f56c6c; }
|
&.progress-card .stat-icon { display: none; }
|
|
.stat-content {
|
flex: 1;
|
min-width: 0;
|
}
|
|
.stat-label {
|
font-size: 13px;
|
color: #909399;
|
margin-bottom: 6px;
|
}
|
|
.stat-value {
|
.currency {
|
font-size: 14px;
|
color: #606266;
|
margin-right: 2px;
|
}
|
|
.number {
|
font-size: 22px;
|
font-weight: 600;
|
color: #303133;
|
}
|
|
.unit {
|
font-size: 14px;
|
color: #909399;
|
margin-left: 4px;
|
}
|
}
|
|
&.progress-card {
|
grid-column: span 1;
|
|
@media (max-width: 1600px) {
|
grid-column: span 1;
|
}
|
|
.stat-content-full {
|
width: 100%;
|
}
|
|
.progress-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 10px;
|
|
.stat-label {
|
margin-bottom: 0;
|
}
|
|
.progress-value {
|
font-size: 18px;
|
font-weight: 600;
|
color: #303133;
|
}
|
}
|
|
.progress-footer {
|
display: flex;
|
justify-content: space-between;
|
margin-top: 10px;
|
font-size: 12px;
|
color: #909399;
|
}
|
}
|
}
|
|
.table-section {
|
background: white;
|
border-radius: 12px;
|
padding: 20px;
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
|
.custom-tabs {
|
:deep(.el-tabs__header) {
|
margin-bottom: 0;
|
|
.el-tabs__nav-wrap::after {
|
height: 1px;
|
}
|
|
.el-tabs__item {
|
font-size: 15px;
|
padding: 0 24px;
|
height: 44px;
|
line-height: 44px;
|
|
&.is-active {
|
font-weight: 600;
|
}
|
}
|
|
.el-tabs__active-bar {
|
height: 3px;
|
border-radius: 2px;
|
}
|
}
|
|
:deep(.el-tabs__content) {
|
padding-top: 20px;
|
}
|
}
|
}
|
</style>
|