feat: 客户详情弹窗新增拜访/计划/商机/要客四个关联数据Tab
点击客户名 → 800px 弹窗,顶部显示基本信息,下方 el-tabs 切换: - 拜访记录 / 工作计划 / 商机跟单 / 要客拜访 - 各 Tab 并行加载对应 customer_id 筛选数据 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,12 @@ const feeCustomUnit = ref('')
|
||||
|
||||
const detailVisible = ref(false)
|
||||
const detailCustomer = ref<any>(null)
|
||||
const detailActiveTab = ref('visits')
|
||||
const detailVisits = ref<any[]>([])
|
||||
const detailPlans = ref<any[]>([])
|
||||
const detailMini = ref<any[]>([])
|
||||
const detailKeyVisits = ref<any[]>([])
|
||||
const detailLoading = ref(false)
|
||||
|
||||
const managers = ref<any[]>([])
|
||||
const selectedIds = ref<string[]>([])
|
||||
@@ -205,7 +211,30 @@ function mgrTextColor(name: string) {
|
||||
}
|
||||
|
||||
async function openDetail(customer: any) {
|
||||
try { const res = await customersApi.get(customer.id); detailCustomer.value = res.data; detailVisible.value = true } catch (_) {}
|
||||
try {
|
||||
const res = await customersApi.get(customer.id)
|
||||
detailCustomer.value = res.data
|
||||
detailActiveTab.value = 'visits'
|
||||
detailVisible.value = true
|
||||
loadDetailData(customer.id)
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
async function loadDetailData(customerId: string) {
|
||||
detailLoading.value = true
|
||||
try {
|
||||
const [visits, plans, mini, keyVisits] = await Promise.all([
|
||||
api.get('/visits/', { params: { customer_id: customerId } }),
|
||||
api.get('/work-plans/', { params: { customer_id: customerId } }),
|
||||
api.get('/mini-business/', { params: { customer_id: customerId } }),
|
||||
api.get('/key-visits/', { params: { customer_id: customerId } }),
|
||||
])
|
||||
detailVisits.value = Array.isArray(visits.data) ? visits.data : (visits.data.items || [])
|
||||
detailPlans.value = Array.isArray(plans.data) ? plans.data : (plans.data.items || [])
|
||||
detailMini.value = Array.isArray(mini.data) ? mini.data : (mini.data.items || [])
|
||||
detailKeyVisits.value = Array.isArray(keyVisits.data) ? keyVisits.data : (keyVisits.data.items || [])
|
||||
} catch (_) {}
|
||||
finally { detailLoading.value = false }
|
||||
}
|
||||
|
||||
async function handleDelete(customer: any) {
|
||||
@@ -403,25 +432,73 @@ async function handleImport() {
|
||||
</el-dialog>
|
||||
|
||||
<!-- Detail Dialog -->
|
||||
<el-dialog v-model="detailVisible" title="客户详情" width="500px">
|
||||
<template v-if="detailCustomer">
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="单位名称">{{ detailCustomer.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="行业">{{ detailCustomer.industry || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="地址">{{ detailCustomer.address || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="在用业务">{{ detailCustomer.in_use_services || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="收支费用">{{ detailCustomer.monthly_fee || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">{{ detailCustomer.remarks || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户经理">{{ detailCustomer.primary_manager_name || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<h4 style="margin-top:16px; font-family: var(--font-heading); color: var(--ink)">联系人</h4>
|
||||
<div v-if="detailCustomer.contacts?.length">
|
||||
<el-tag v-for="c in detailCustomer.contacts" :key="c.id" style="margin:4px">
|
||||
{{ c.name }}{{ c.phone ? ' · '+c.phone : '' }}{{ c.role_desc ? ' ('+c.role_desc+')' : '' }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div v-else style="color: var(--c-text-muted); text-align:center; padding:12px">暂无联系人</div>
|
||||
</template>
|
||||
<el-dialog v-model="detailVisible" :title="detailCustomer?.name || '客户详情'" width="800px" v-if="detailCustomer">
|
||||
<!-- Basic Info -->
|
||||
<div class="cust-info-bar">
|
||||
<span class="cust-info-item">行业:{{ detailCustomer.industry || '-' }}</span>
|
||||
<span class="cust-info-sep">|</span>
|
||||
<span class="cust-info-item">地址:{{ detailCustomer.address || '-' }}</span>
|
||||
<span class="cust-info-sep">|</span>
|
||||
<span class="cust-info-item">费用:{{ detailCustomer.monthly_fee || '-' }}</span>
|
||||
<span class="cust-info-sep">|</span>
|
||||
<span class="cust-info-item">客户经理:{{ detailCustomer.primary_manager_name || '-' }}</span>
|
||||
</div>
|
||||
<div v-if="detailCustomer.in_use_services" class="cust-info-bar" style="margin-top:4px">
|
||||
<span class="cust-info-item">在用业务:{{ detailCustomer.in_use_services }}</span>
|
||||
</div>
|
||||
<div v-if="detailCustomer.contacts?.length" class="cust-info-bar" style="margin-top:4px">
|
||||
<span class="cust-info-item">联系人:{{ detailCustomer.contacts.map((c:any) => c.name + (c.phone ? ' '+c.phone : '')).join('、') }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Tabs -->
|
||||
<el-tabs v-model="detailActiveTab" style="margin-top:16px">
|
||||
<el-tab-pane label="拜访记录" name="visits">
|
||||
<div v-loading="detailLoading">
|
||||
<el-table :data="detailVisits" size="small" max-height="300" v-if="detailVisits.length">
|
||||
<el-table-column prop="visit_date" label="日期" width="110" />
|
||||
<el-table-column prop="visit_method" label="方式" width="80" />
|
||||
<el-table-column prop="communication_content" label="沟通内容" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="manager_name" label="客户经理" width="90" />
|
||||
</el-table>
|
||||
<div v-else class="empty-tab">暂无拜访记录</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="工作计划" name="plans">
|
||||
<div v-loading="detailLoading">
|
||||
<el-table :data="detailPlans" size="small" max-height="300" v-if="detailPlans.length">
|
||||
<el-table-column prop="plan_date" label="计划时间" width="110" />
|
||||
<el-table-column prop="plan_content" label="工作计划" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="status" label="状态" width="90" />
|
||||
<el-table-column prop="manager_name" label="客户经理" width="90" />
|
||||
</el-table>
|
||||
<div v-else class="empty-tab">暂无工作计划</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="商机跟单" name="mini">
|
||||
<div v-loading="detailLoading">
|
||||
<el-table :data="detailMini" size="small" max-height="300" v-if="detailMini.length">
|
||||
<el-table-column prop="product_type" label="产品类型" width="110" />
|
||||
<el-table-column prop="amount" label="金额" width="100" />
|
||||
<el-table-column prop="status" label="状态" width="80" />
|
||||
<el-table-column prop="follow_up_detail" label="跟进内容" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="manager_name" label="客户经理" width="90" />
|
||||
</el-table>
|
||||
<div v-else class="empty-tab">暂无商机记录</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="要客拜访" name="keyVisits">
|
||||
<div v-loading="detailLoading">
|
||||
<el-table :data="detailKeyVisits" size="small" max-height="300" v-if="detailKeyVisits.length">
|
||||
<el-table-column prop="planned_date" label="计划时间" width="110" />
|
||||
<el-table-column prop="description" label="内容" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="urgency_level" label="紧急度" width="80" />
|
||||
<el-table-column prop="manager_name" label="客户经理" width="90" />
|
||||
</el-table>
|
||||
<div v-else class="empty-tab">暂不要客记录</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<template #footer>
|
||||
<el-button v-if="!auth.isLeader" type="primary" @click="detailVisible=false; openEdit(detailCustomer)">编辑</el-button>
|
||||
<el-button v-if="auth.isDirector" type="danger" @click="detailVisible=false; handleDelete(detailCustomer)">删除</el-button>
|
||||
@@ -499,4 +576,8 @@ async function handleImport() {
|
||||
}
|
||||
.page-rule { width: 32px; height: 3px; background: var(--gold); margin-top: 8px; }
|
||||
.header-btns { display: flex; gap: 8px; }
|
||||
.cust-info-bar { display: flex; align-items: center; gap: 4px; font-size: 13px; color: var(--warm-gray); }
|
||||
.cust-info-item { white-space: nowrap; }
|
||||
.cust-info-sep { color: var(--gold); margin: 0 4px; }
|
||||
.empty-tab { text-align: center; color: var(--c-text-muted); padding: 24px 0 12px; font-size: 13px; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user