新增功能
This commit is contained in:
@@ -122,7 +122,7 @@
|
||||
<div class="panel-heading panel-heading--table">
|
||||
<div>
|
||||
<h2>明细数据列表</h2>
|
||||
<p>部门层级汇总;开口率=开口/加粉,挂号率=付费挂号/加粉,接诊率=接诊诊单/加粉</p>
|
||||
<p>展开部门可查看人员明细;挂号=已支付且实收低于 10 元的订单,预约=有效预约记录;开口率=开口/加粉,挂号率=挂号/加粉,面诊率=面诊/预约,接诊率=接诊诊单/加粉</p>
|
||||
</div>
|
||||
<span>{{ dashboard.rows.length }} 个顶层节点</span>
|
||||
</div>
|
||||
@@ -133,16 +133,23 @@
|
||||
default-expand-all
|
||||
class="detail-table"
|
||||
>
|
||||
<el-table-column prop="name" label="部门" min-width="230" fixed="left">
|
||||
<el-table-column prop="name" label="部门 / 人员" min-width="250" fixed="left">
|
||||
<template #default="{ row }">
|
||||
<strong :class="{ 'is-parent': Array.isArray(row.children) && row.children.length }">
|
||||
<strong :class="{ 'is-parent': Array.isArray(row.children) && row.children.length, 'is-member': row.type === 'member' }">
|
||||
{{ row.name }}
|
||||
</strong>
|
||||
<el-tag v-if="row.type === 'member' && row.role" size="small" type="info" effect="plain" class="role-tag">
|
||||
{{ row.role }}{{ row.is_leader ? ' · 组长' : '' }}
|
||||
</el-tag>
|
||||
<el-tag v-else-if="row.type === 'unbound'" size="small" type="warning" effect="plain" class="role-tag">
|
||||
未绑定账号
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="add_fans_count" label="加粉" min-width="88" align="right" />
|
||||
<el-table-column prop="total_open_count" label="开口" min-width="88" align="right" />
|
||||
<el-table-column prop="paid_appointment_count" label="挂号" min-width="88" align="right" />
|
||||
<el-table-column prop="appointment_total_count" label="预约" min-width="88" align="right" />
|
||||
<el-table-column prop="interview_count" label="面诊" min-width="88" align="right" />
|
||||
<el-table-column prop="completed_order_count" label="接诊诊单" min-width="104" align="right" />
|
||||
<el-table-column label="接诊金额" min-width="120" align="right">
|
||||
@@ -154,6 +161,9 @@
|
||||
<el-table-column label="挂号率" min-width="96" align="right">
|
||||
<template #default="{ row }">{{ formatPercent(row.paid_appointment_rate) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="面诊率" min-width="96" align="right">
|
||||
<template #default="{ row }">{{ formatPercent(row.interview_rate) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="面诊接诊率" min-width="116" align="right">
|
||||
<template #default="{ row }">{{ formatPercent(row.interview_receive_rate) }}</template>
|
||||
</el-table-column>
|
||||
@@ -278,7 +288,7 @@ const timeOptions = [
|
||||
const metricCards: Array<{ key: string; label: string; type: MetricType; hint: string }> = [
|
||||
{ key: 'add_fans_count', label: '加粉数', type: 'count', hint: '企微新增客户' },
|
||||
{ key: 'total_open_count', label: '开口数', type: 'count', hint: '来源于个人业绩录入' },
|
||||
{ key: 'interview_count', label: '面诊', type: 'count', hint: '已完成挂号' },
|
||||
{ key: 'interview_count', label: '面诊', type: 'count', hint: '已完成预约' },
|
||||
{ key: 'completed_order_count', label: '接诊诊单', type: 'count', hint: '业务订单,按创建人归属并过滤无效单' },
|
||||
{ key: 'completed_order_amount', label: '诊单金额', type: 'money', hint: '排除取消、拒收、退款及已退款订单' },
|
||||
{ key: 'avg_unit_price', label: '平均客单价', type: 'money', hint: '诊单金额 / 接诊诊单' },
|
||||
@@ -475,6 +485,8 @@ onMounted(loadDashboard)
|
||||
:deep(td.el-table__cell) { color: #273347; font-size: 12px; }
|
||||
:deep(.el-table__row--level-0 > td.el-table__cell) { background: #edf7f5; font-weight: 650; }
|
||||
strong.is-parent { color: #172033; font-weight: 700; }
|
||||
strong.is-member { color: #314158; font-weight: 600; }
|
||||
.role-tag { margin-left: 7px; vertical-align: middle; }
|
||||
}
|
||||
|
||||
.target-panel { padding-bottom: 18px; }
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<span class="heading-mark"><el-icon><DataLine /></el-icon></span>
|
||||
<div>
|
||||
<h1>医生看板</h1>
|
||||
<p>从挂号、面诊到接诊成交,统一观察医生经营表现</p>
|
||||
<p>从挂号、预约、面诊到接诊成交,统一观察医生经营表现</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="heading-actions">
|
||||
@@ -70,8 +70,8 @@
|
||||
<div class="metric-icon"><el-icon><Calendar /></el-icon></div>
|
||||
<div>
|
||||
<span>总挂号</span>
|
||||
<strong>{{ formatNumber(dashboard.summary.appointment_total) }}</strong>
|
||||
<small>完成 {{ formatNumber(dashboard.summary.interview_count) }} · 完成率 {{ formatPercent(dashboard.summary.appointment_completion_rate) }}</small>
|
||||
<strong>{{ formatNumber(dashboard.summary.registration_total) }}</strong>
|
||||
<small>已支付且实收金额大于 0、低于 10 元的订单</small>
|
||||
</div>
|
||||
</article>
|
||||
<article class="metric-card metric-card--green">
|
||||
@@ -109,9 +109,9 @@
|
||||
<article class="metric-card metric-card--cyan">
|
||||
<div class="metric-icon"><el-icon><CircleCheck /></el-icon></div>
|
||||
<div>
|
||||
<span>挂号完成率</span>
|
||||
<span>预约完成率</span>
|
||||
<strong>{{ formatPercent(dashboard.summary.appointment_completion_rate) }}</strong>
|
||||
<small>{{ dashboard.meta.time_label }} · {{ dashboard.meta.doctor_count }} 位有数据医生</small>
|
||||
<small>总预约 {{ formatNumber(dashboard.summary.appointment_total) }} · {{ dashboard.meta.doctor_count }} 位有数据医生</small>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
@@ -212,7 +212,7 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="appointment_total" label="挂号" min-width="90" sortable />
|
||||
<el-table-column prop="appointment_total" label="预约" min-width="90" sortable />
|
||||
<el-table-column prop="interview_count" label="面诊" min-width="90" sortable />
|
||||
<el-table-column prop="order_count" label="接诊" min-width="90" sortable />
|
||||
<el-table-column prop="receive_conversion_rate" label="接诊率" min-width="110" sortable>
|
||||
@@ -248,7 +248,7 @@
|
||||
|
||||
<footer class="data-note">
|
||||
<el-icon><InfoFilled /></el-icon>
|
||||
<span>{{ dashboard.meta.appointment_rule }};{{ dashboard.meta.performance_rule }}。</span>
|
||||
<span>{{ dashboard.meta.registration_rule }};{{ dashboard.meta.appointment_rule }};{{ dashboard.meta.performance_rule }}。</span>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
@@ -279,14 +279,14 @@ const emptyDashboard = () => ({
|
||||
meta: {
|
||||
time_type: 'month', time_label: '本月', start_date: '', end_date: '', generated_at: '',
|
||||
scope_value: 4, scope_label: '', scope_kind: '', selected_dept_name: '', selected_doctor_name: '',
|
||||
doctor_count: 0, appointment_rule: '', performance_rule: ''
|
||||
doctor_count: 0, registration_rule: '', appointment_rule: '', performance_rule: ''
|
||||
},
|
||||
filters: {
|
||||
departments: [] as any[], doctors: [] as Array<{ id: number; name: string; disable: number }>,
|
||||
can_filter_department: true
|
||||
},
|
||||
summary: {
|
||||
appointment_total: 0, interview_count: 0, order_count: 0, deal_amount: 0,
|
||||
registration_total: 0, appointment_total: 0, interview_count: 0, order_count: 0, deal_amount: 0,
|
||||
avg_order_amount: null as number | null, appointment_completion_rate: null as number | null,
|
||||
receive_conversion_rate: null as number | null, missed_count: 0, cancelled_count: 0
|
||||
},
|
||||
@@ -453,7 +453,7 @@ function exportRows() {
|
||||
ElMessage.warning('当前范围暂无可导出的医生数据')
|
||||
return
|
||||
}
|
||||
const headers = ['医生', '状态', '挂号', '面诊', '接诊', '接诊率', '成交金额', '过号', '取消']
|
||||
const headers = ['医生', '状态', '预约', '面诊', '接诊', '接诊率', '成交金额', '过号', '取消']
|
||||
const lines = dashboard.rows.map((row: any) => [
|
||||
row.doctor_name, row.status === 'disabled' ? '停用' : '活跃', row.appointment_total,
|
||||
row.interview_count, row.order_count, formatPercent(row.receive_conversion_rate), row.deal_amount,
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<div class="summary-grid">
|
||||
<button class="summary-card summary-today" type="button" @click="selectDateType('today')">
|
||||
<span class="summary-icon"><el-icon><Calendar /></el-icon></span>
|
||||
<span class="summary-copy"><small>今日挂号</small><strong>{{ summary.today }}</strong><em>人</em></span>
|
||||
<span class="summary-copy"><small>今日预约</small><strong>{{ summary.today }}</strong><em>人</em></span>
|
||||
<span class="summary-date">{{ summaryDates.today || '—' }}</span>
|
||||
</button>
|
||||
<button class="summary-card summary-tomorrow" type="button" @click="selectDateType('tomorrow')">
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
<div
|
||||
class="registration-stats"
|
||||
v-loading="loading"
|
||||
element-loading-text="正在汇总权限范围内的挂号数据"
|
||||
element-loading-text="正在汇总权限范围内的挂号与预约数据"
|
||||
>
|
||||
<header class="page-heading">
|
||||
<div class="heading-copy">
|
||||
<span class="heading-mark"><el-icon><Histogram /></el-icon></span>
|
||||
<div>
|
||||
<h1>挂号统计</h1>
|
||||
<p>挂号、诊单与目标数据按当前角色和部门权限实时汇总</p>
|
||||
<p>挂号、预约、诊单与目标数据按当前角色和部门权限实时汇总</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="heading-actions">
|
||||
@@ -66,16 +66,26 @@
|
||||
|
||||
<section class="metric-grid" aria-label="挂号统计核心指标">
|
||||
<article class="metric-card metric-card--teal">
|
||||
<div class="metric-icon"><el-icon><Calendar /></el-icon></div>
|
||||
<div class="metric-icon"><el-icon><Wallet /></el-icon></div>
|
||||
<div>
|
||||
<span>{{ dashboard.meta.time_label || '今日' }}总挂号</span>
|
||||
<strong>{{ formatNumber(dashboard.summary.registration_count) }}</strong>
|
||||
<small :class="compareClass(dashboard.summary.registration_compare_rate)">
|
||||
{{ compareText(dashboard.summary.registration_compare_rate) }}
|
||||
</small>
|
||||
</div>
|
||||
</article>
|
||||
<article class="metric-card metric-card--blue">
|
||||
<div class="metric-icon"><el-icon><Calendar /></el-icon></div>
|
||||
<div>
|
||||
<span>{{ dashboard.meta.time_label || '今日' }}总预约</span>
|
||||
<strong>{{ formatNumber(dashboard.summary.appointment_count) }}</strong>
|
||||
<small :class="compareClass(dashboard.summary.appointment_compare_rate)">
|
||||
{{ compareText(dashboard.summary.appointment_compare_rate) }}
|
||||
</small>
|
||||
</div>
|
||||
</article>
|
||||
<article class="metric-card metric-card--blue">
|
||||
<article class="metric-card metric-card--violet">
|
||||
<div class="metric-icon"><el-icon><DocumentChecked /></el-icon></div>
|
||||
<div>
|
||||
<span>{{ dashboard.meta.time_label || '今日' }}总诊单</span>
|
||||
@@ -96,8 +106,8 @@
|
||||
<section class="panel employee-panel">
|
||||
<div class="panel-heading">
|
||||
<div>
|
||||
<h2>本组员工挂号统计</h2>
|
||||
<p>部门汇总可展开查看员工;明日、后日预约始终使用对应自然日</p>
|
||||
<h2>本组员工挂号与预约统计</h2>
|
||||
<p>挂号按已支付且实收低于 10 元的支付订单统计;预约按预约记录统计</p>
|
||||
</div>
|
||||
<span class="panel-badge">{{ dashboard.meta.time_label || '当前范围' }}</span>
|
||||
</div>
|
||||
@@ -118,14 +128,22 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="appointment_count" :label="`${dashboard.meta.time_label || '当前'}挂号`" min-width="118" align="right" sortable />
|
||||
<el-table-column prop="registration_count" :label="`${dashboard.meta.time_label || '当前'}挂号`" min-width="118" align="right" sortable />
|
||||
<el-table-column prop="appointment_count" :label="`${dashboard.meta.time_label || '当前'}预约`" min-width="118" align="right" sortable />
|
||||
<el-table-column prop="tomorrow_count" label="明日预约" min-width="105" align="right" sortable />
|
||||
<el-table-column prop="day_after_count" label="后日预约" min-width="105" align="right" sortable />
|
||||
<el-table-column prop="order_count" label="诊单" min-width="86" align="right" sortable />
|
||||
<el-table-column label="业绩" min-width="128" align="right" sortable :sort-method="sortAmount">
|
||||
<template #default="{ row }">{{ formatMoney(row.order_amount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="较上期" min-width="105" align="right">
|
||||
<el-table-column label="挂号较上期" min-width="112" align="right">
|
||||
<template #default="{ row }">
|
||||
<span :class="['rate-text', compareClass(row.registration_compare_rate)]">
|
||||
{{ compactCompare(row.registration_compare_rate) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="预约较上期" min-width="112" align="right">
|
||||
<template #default="{ row }">
|
||||
<span :class="['rate-text', compareClass(row.appointment_compare_rate)]">
|
||||
{{ compactCompare(row.appointment_compare_rate) }}
|
||||
@@ -190,9 +208,24 @@
|
||||
</article>
|
||||
<article class="panel ranking-panel">
|
||||
<div class="panel-heading">
|
||||
<div><h2>{{ dashboard.meta.time_label || '今日' }}挂号 TOP</h2><p>按有效挂号数量排序</p></div>
|
||||
<div><h2>{{ dashboard.meta.time_label || '今日' }}挂号 TOP</h2><p>按低于 10 元的已支付订单笔数排序</p></div>
|
||||
<span class="panel-badge">挂号</span>
|
||||
</div>
|
||||
<div v-if="dashboard.rankings.registrations.length" class="ranking-list ranking-list--blue">
|
||||
<div v-for="(item, index) in dashboard.rankings.registrations" :key="`registration-${item.admin_id}`" class="ranking-row">
|
||||
<b :class="{ 'is-top': index < 3 }">{{ index + 1 }}</b>
|
||||
<span>{{ item.name }}<small>已支付小额订单</small></span>
|
||||
<div class="rank-track"><i :style="{ width: rankWidth(item.value, maxRegistrations) }" /></div>
|
||||
<strong>{{ formatNumber(item.value) }} 笔</strong>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else :image-size="52" description="暂无挂号数据" />
|
||||
</article>
|
||||
<article class="panel ranking-panel">
|
||||
<div class="panel-heading">
|
||||
<div><h2>{{ dashboard.meta.time_label || '今日' }}预约 TOP</h2><p>按有效预约记录数量排序</p></div>
|
||||
<span class="panel-badge">预约</span>
|
||||
</div>
|
||||
<div v-if="dashboard.rankings.appointments.length" class="ranking-list ranking-list--blue">
|
||||
<div v-for="(item, index) in dashboard.rankings.appointments" :key="`appointment-${item.admin_id}`" class="ranking-row">
|
||||
<b :class="{ 'is-top': index < 3 }">{{ index + 1 }}</b>
|
||||
@@ -201,7 +234,7 @@
|
||||
<strong>{{ formatNumber(item.value) }} 个</strong>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else :image-size="52" description="暂无挂号数据" />
|
||||
<el-empty v-else :image-size="52" description="暂无预约数据" />
|
||||
</article>
|
||||
</section>
|
||||
|
||||
@@ -215,13 +248,21 @@
|
||||
<template #default="{ row }"><strong>{{ row.name }}</strong></template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="member_count" label="人数" min-width="90" align="right" sortable />
|
||||
<el-table-column prop="appointment_count" :label="`${dashboard.meta.time_label || '当前'}挂号`" min-width="118" align="right" sortable />
|
||||
<el-table-column prop="registration_count" :label="`${dashboard.meta.time_label || '当前'}挂号`" min-width="118" align="right" sortable />
|
||||
<el-table-column prop="appointment_count" :label="`${dashboard.meta.time_label || '当前'}预约`" min-width="118" align="right" sortable />
|
||||
<el-table-column prop="tomorrow_count" label="明日预约" min-width="105" align="right" sortable />
|
||||
<el-table-column prop="order_count" label="诊单" min-width="90" align="right" sortable />
|
||||
<el-table-column label="业绩" min-width="130" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.order_amount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="挂号环比" min-width="110" align="right">
|
||||
<template #default="{ row }">
|
||||
<span :class="['rate-text', compareClass(row.registration_compare_rate)]">
|
||||
{{ compactCompare(row.registration_compare_rate) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="预约环比" min-width="110" align="right">
|
||||
<template #default="{ row }">
|
||||
<span :class="['rate-text', compareClass(row.appointment_compare_rate)]">
|
||||
{{ compactCompare(row.appointment_compare_rate) }}
|
||||
@@ -234,7 +275,7 @@
|
||||
|
||||
<footer class="data-note">
|
||||
<el-icon><InfoFilled /></el-icon>
|
||||
<span>{{ dashboard.meta.appointment_rule }};{{ dashboard.meta.performance_rule }}。</span>
|
||||
<span>{{ dashboard.meta.registration_rule }};{{ dashboard.meta.appointment_rule }};{{ dashboard.meta.performance_rule }}。</span>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
@@ -261,15 +302,16 @@ const emptyDashboard = () => ({
|
||||
meta: {
|
||||
time_type: 'today', time_label: '今日', start_date: '', end_date: '', generated_at: '',
|
||||
scope_value: 4, scope_label: '', selected_dept_name: '', selected_assistant_name: '',
|
||||
member_count: 0, appointment_rule: '', performance_rule: ''
|
||||
member_count: 0, registration_rule: '', appointment_rule: '', performance_rule: ''
|
||||
},
|
||||
filters: { departments: [] as any[], assistants: [] as Array<{ id: number; name: string }> },
|
||||
summary: {
|
||||
registration_count: 0, registration_compare_count: 0, registration_compare_rate: null as number | null,
|
||||
appointment_count: 0, appointment_compare_count: 0, appointment_compare_rate: null as number | null,
|
||||
order_count: 0, order_amount: 0, range_label: '今日'
|
||||
},
|
||||
employee_rows: [] as any[],
|
||||
rankings: { performance: [] as any[], appointments: [] as any[] },
|
||||
rankings: { performance: [] as any[], registrations: [] as any[], appointments: [] as any[] },
|
||||
departments: [] as any[],
|
||||
target: {
|
||||
year: new Date().getFullYear(), target_amount: 0, actual_amount: 0,
|
||||
@@ -289,6 +331,7 @@ const timeOptions = [
|
||||
const deptTreeProps = { label: 'name', value: 'id', children: 'children' }
|
||||
|
||||
const maxPerformance = computed(() => Math.max(0, ...dashboard.rankings.performance.map((item: any) => Number(item.value) || 0)))
|
||||
const maxRegistrations = computed(() => Math.max(0, ...dashboard.rankings.registrations.map((item: any) => Number(item.value) || 0)))
|
||||
const maxAppointments = computed(() => Math.max(0, ...dashboard.rankings.appointments.map((item: any) => Number(item.value) || 0)))
|
||||
const targetChartOption = computed(() => ({
|
||||
animationDuration: 450,
|
||||
@@ -490,7 +533,7 @@ h2 { font-size: 15px; line-height: 1.4; }
|
||||
|
||||
.metric-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
@@ -513,6 +556,7 @@ h2 { font-size: 15px; line-height: 1.4; }
|
||||
}
|
||||
.metric-card--teal .metric-icon { color: #107f75; background: #e9f7f5; }
|
||||
.metric-card--blue .metric-icon { color: #416bd7; background: #edf1ff; }
|
||||
.metric-card--violet .metric-icon { color: #7257c7; background: #f2efff; }
|
||||
.metric-card--amber .metric-icon { color: #bc7428; background: #fff4e7; }
|
||||
.metric-card span { display: block; color: #748296; font-size: 13px; }
|
||||
.metric-card strong { display: block; margin: 4px 0 2px; font-size: 27px; line-height: 1.15; }
|
||||
@@ -565,10 +609,10 @@ h2 { font-size: 15px; line-height: 1.4; }
|
||||
.chart-legend .actual { background: var(--teal); }
|
||||
.chart-legend .target { background: repeating-linear-gradient(90deg, var(--blue) 0 5px, transparent 5px 8px); }
|
||||
|
||||
.ranking-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
|
||||
.ranking-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
|
||||
.ranking-panel { min-height: 286px; }
|
||||
.ranking-list { padding: 2px 16px 16px; }
|
||||
.ranking-row { display: grid; grid-template-columns: 30px minmax(110px, .8fr) minmax(100px, 1fr) 105px; align-items: center; gap: 10px; min-height: 43px; border-top: 1px solid #eff2f5; }
|
||||
.ranking-row { display: grid; grid-template-columns: 30px minmax(86px, .8fr) minmax(64px, 1fr) auto; align-items: center; gap: 10px; min-height: 43px; border-top: 1px solid #eff2f5; }
|
||||
.ranking-row > b { display: grid; width: 22px; height: 22px; place-items: center; border-radius: 7px; color: #8491a1; background: #f1f4f6; font-size: 11px; }
|
||||
.ranking-row > b.is-top { color: #fff; background: var(--teal); }
|
||||
.ranking-list--blue .ranking-row > b.is-top { background: var(--blue); }
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<div class="dashboard-title-row">
|
||||
<h1>数据驾驶舱</h1>
|
||||
<h1>我的首页</h1>
|
||||
<span class="scope-badge">
|
||||
<el-icon><Lock /></el-icon>
|
||||
{{ dashboard.scope.label || '数据范围' }}
|
||||
@@ -181,7 +181,7 @@
|
||||
<div class="ranking-main">
|
||||
<div class="ranking-copy">
|
||||
<strong>{{ item.name || '未命名成员' }}</strong>
|
||||
<span>{{ formatNumber(item.count) }} 个挂号</span>
|
||||
<span>{{ formatNumber(item.count) }} 笔挂号</span>
|
||||
</div>
|
||||
<div class="ranking-meter" aria-hidden="true">
|
||||
<span :style="{ width: rankingWidth(item.count, appointmentRankingMax) }" />
|
||||
@@ -328,7 +328,7 @@ import vCharts from 'vue-echarts'
|
||||
|
||||
import { performanceDashboardOverview } from '@/api/stats'
|
||||
|
||||
type TrendKey = 'appointments' | 'leads' | 'orders'
|
||||
type TrendKey = 'registrations' | 'appointments' | 'leads' | 'orders'
|
||||
|
||||
interface RankingItem {
|
||||
id: number
|
||||
@@ -417,6 +417,7 @@ const createInitialDashboard = () => ({
|
||||
trend: {
|
||||
date_range: [] as string[],
|
||||
dates: [] as string[],
|
||||
registrations: [] as number[],
|
||||
appointments: [] as number[],
|
||||
leads: [] as number[],
|
||||
orders: [] as number[],
|
||||
@@ -442,14 +443,15 @@ const dashboard = reactive(createInitialDashboard())
|
||||
const loading = ref(false)
|
||||
const loaded = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const activeTrend = ref<TrendKey>('appointments')
|
||||
const activeTrend = ref<TrendKey>('registrations')
|
||||
const rankingDeptId = ref<number | undefined>()
|
||||
const now = ref(new Date())
|
||||
let clockTimer: ReturnType<typeof setInterval> | undefined
|
||||
const departmentTreeProps = { value: 'id', label: 'name', children: 'children' }
|
||||
|
||||
const trendOptions = [
|
||||
{ label: '挂号', value: 'appointments' },
|
||||
{ label: '挂号', value: 'registrations' },
|
||||
{ label: '预约', value: 'appointments' },
|
||||
{ label: '进线', value: 'leads' },
|
||||
{ label: '诊单', value: 'orders' },
|
||||
]
|
||||
@@ -472,16 +474,16 @@ const todayMetrics = computed(() => [
|
||||
},
|
||||
{
|
||||
key: 'appointments',
|
||||
label: '今日挂号',
|
||||
label: '今日预约',
|
||||
value: formatNumber(dashboard.today.appointment_total_count),
|
||||
hint: '状态为已预约、已完成或改期,排除已取消',
|
||||
comparisons: [dashboard.today.comparisons.appointment_total_count],
|
||||
},
|
||||
{
|
||||
key: 'lowAmountPayments',
|
||||
label: '今日 10 元及以下收款',
|
||||
label: '今日挂号',
|
||||
value: `${formatNumber(dashboard.today.low_amount_payment_count)} 笔`,
|
||||
hint: '实收金额大于 0 且不超过 10 元的已支付订单',
|
||||
hint: '已支付且实收金额大于 0、低于 10 元的订单',
|
||||
comparisons: [dashboard.today.comparisons.low_amount_payment_count],
|
||||
},
|
||||
{
|
||||
@@ -496,9 +498,9 @@ const todayMetrics = computed(() => [
|
||||
},
|
||||
{
|
||||
key: 'appointmentRate',
|
||||
label: '付费挂号率',
|
||||
label: '挂号率',
|
||||
value: formatPercent(dashboard.today.paid_appointment_rate),
|
||||
hint: `付费挂号 ${formatNumber(dashboard.today.paid_appointment_count)} / 加粉数`,
|
||||
hint: `挂号 ${formatNumber(dashboard.today.paid_appointment_count)} / 加粉数`,
|
||||
comparisons: [dashboard.today.comparisons.paid_appointment_rate],
|
||||
},
|
||||
{
|
||||
@@ -512,7 +514,7 @@ const todayMetrics = computed(() => [
|
||||
key: 'interviews',
|
||||
label: '今日面诊',
|
||||
value: formatNumber(dashboard.today.interview_count),
|
||||
hint: '状态为已完成的挂号',
|
||||
hint: '状态为已完成的预约',
|
||||
comparisons: [dashboard.today.comparisons.interview_count],
|
||||
},
|
||||
])
|
||||
@@ -532,8 +534,8 @@ const currentDate = computed(() => new Intl.DateTimeFormat('zh-CN', {
|
||||
}).format(now.value))
|
||||
|
||||
const appointmentRankingSubtitle = computed(() => {
|
||||
const actor = dashboard.rankings.appointments.kind === 'doctor' ? '医生' : '医助'
|
||||
return `${dashboard.rankings.appointments.scope_label}内的${actor}有效挂号数(不含已取消)`
|
||||
const actor = dashboard.rankings.appointments.kind === 'doctor' ? '医生' : '成员'
|
||||
return `${dashboard.rankings.appointments.scope_label}内${actor}已支付且实收低于 10 元的订单笔数`
|
||||
})
|
||||
|
||||
const appointmentRankingMax = computed(() => Math.max(
|
||||
@@ -548,7 +550,8 @@ const performanceRankingMax = computed(() => Math.max(
|
||||
|
||||
const trendChartOption = computed(() => {
|
||||
const config: Record<TrendKey, { label: string; data: number[] }> = {
|
||||
appointments: { label: '挂号', data: dashboard.trend.appointments },
|
||||
registrations: { label: '挂号', data: dashboard.trend.registrations },
|
||||
appointments: { label: '预约', data: dashboard.trend.appointments },
|
||||
leads: { label: '进线', data: dashboard.trend.leads },
|
||||
orders: { label: '诊单', data: dashboard.trend.orders },
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user