更新
This commit is contained in:
@@ -68,6 +68,21 @@ export function yejiStatsLeadLines(params: {
|
||||
return request.get({ url: '/stats.yejiStats/leadLines', params })
|
||||
}
|
||||
|
||||
/** 医助排行榜「预约诊单」逐条挂号明细;业绩主表部门行传 dept_id(可与 assistant_id 二选一) */
|
||||
export function yejiStatsAppointmentLines(params: {
|
||||
start_date: string
|
||||
end_date: string
|
||||
assistant_id?: number
|
||||
dept_id?: number
|
||||
dept_ids?: string
|
||||
channel_code?: string
|
||||
tag_id?: string
|
||||
page?: number
|
||||
page_size?: number
|
||||
}) {
|
||||
return request.get({ url: '/stats.yejiStats/appointmentLines', params })
|
||||
}
|
||||
|
||||
/** 二中心复诊:部门行下钻医助 × 业务订单笔数 */
|
||||
export function yejiStatsRevisitBreakdown(params: {
|
||||
start_date: string
|
||||
|
||||
@@ -221,6 +221,7 @@
|
||||
<th class="col-consult">接诊单数</th>
|
||||
<th class="col-deal">接诊诊单</th>
|
||||
<th class="col-assign">被指派数</th>
|
||||
<th class="col-appointment">预约诊单</th>
|
||||
<template v-if="lb.er_center_subtree">
|
||||
<th class="col-revisit">复诊合计</th>
|
||||
<th
|
||||
@@ -248,6 +249,15 @@
|
||||
<td class="col-consult">{{ formatLeaderboardInt(r.consult_count) }}</td>
|
||||
<td class="col-deal">{{ formatLeaderboardInt(r.deal_order_count) }}</td>
|
||||
<td class="col-assign">{{ formatLeaderboardInt(r.assign_count ?? 0) }}</td>
|
||||
<td class="col-appointment" @click.stop="onLeaderboardAppointmentCellClick(r)">
|
||||
<span
|
||||
v-if="Number(r.appointment_count ?? 0) > 0"
|
||||
class="yeji-lead-cell--link"
|
||||
>{{ formatLeaderboardInt(r.appointment_count ?? 0) }}</span>
|
||||
<template v-else>{{
|
||||
formatLeaderboardInt(r.appointment_count ?? 0)
|
||||
}}</template>
|
||||
</td>
|
||||
<template v-if="lb.er_center_subtree">
|
||||
<td class="col-revisit" @click.stop="onLeaderboardRevisitTotalClick(r)">
|
||||
<span
|
||||
@@ -284,6 +294,9 @@
|
||||
<span v-if="lb.er_center_subtree">
|
||||
· 复诊列为二中心口径(同一诊单业务单序列第 2 笔起),点击数字查看对应业务订单
|
||||
</span>
|
||||
<span>
|
||||
· 预约诊单:预约日期在统计区间内,状态含已预约/已完成/已过号(不含已取消),医助归属与接诊单数一致;各科组展示全部医助。
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -305,7 +318,7 @@
|
||||
|
||||
<el-tab-pane label="甄养堂互联网医院诊金" name="zyyt" lazy>
|
||||
<p class="yeji-zyyt-intro">
|
||||
各中心部门诊金、业绩、进线与 ROI 等,与顶部渠道、展示部门、日期筛选联动。
|
||||
各中心部门诊金、业绩、进线与 ROI 等,与顶部渠道、展示部门、日期筛选联动。本月 / 本周 / 今日等多张业绩表中「预约诊单」列数字可点开查看每条挂号记录。
|
||||
</p>
|
||||
|
||||
<!-- <el-alert
|
||||
@@ -475,8 +488,19 @@
|
||||
<el-tooltip placement="top" effect="dark" :show-after="200">
|
||||
<template #content>
|
||||
<div style="max-width: 320px; line-height: 1.7; font-size: 12px">
|
||||
已完成挂号条数,与「医生预约 / 已完成」列表同口径。<br />
|
||||
部门按医助→接诊医生归属。
|
||||
已预约 / 已完成 / 已过号(不含已取消),按<b>预约日期</b>落在区间内统计;部门归属医助优先,否则接诊医生;与<b>医助排行榜 · 预约诊单</b>及明细弹窗同口径。<br />
|
||||
点击数字可查看每条挂号记录。
|
||||
</div>
|
||||
</template>
|
||||
<el-icon class="col-info"><InfoFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</th>
|
||||
<th>
|
||||
<span>已完成挂号</span>
|
||||
<el-tooltip placement="top" effect="dark" :show-after="200">
|
||||
<template #content>
|
||||
<div style="max-width: 320px; line-height: 1.7; font-size: 12px">
|
||||
仅<b>已完成</b>(status=3),与 admin「医生预约 / 已完成」列表计数条件一致(appointment_date、诊单未软删);归属规则同「接诊诊单」列数据源说明。
|
||||
</div>
|
||||
</template>
|
||||
<el-icon class="col-info"><InfoFilled /></el-icon>
|
||||
@@ -588,6 +612,16 @@
|
||||
</td>
|
||||
<td>{{ formatMoney(r.performance_amount) }}</td>
|
||||
<td v-if="tb.channel_name" class="col-completed">{{ formatMoney(r.completed_performance_amount) }}</td>
|
||||
<td @click.stop="onYejiDeptAppointmentBookedClick(tb, r)">
|
||||
<span
|
||||
v-if="
|
||||
yejiAppointmentBookedCellClickable(r) &&
|
||||
Number(r.appointment_booked_count ?? 0) > 0
|
||||
"
|
||||
class="yeji-lead-cell--link"
|
||||
>{{ formatInt(r.appointment_booked_count ?? 0) }}</span>
|
||||
<template v-else>{{ formatInt(r.appointment_booked_count ?? 0) }}</template>
|
||||
</td>
|
||||
<td>{{ formatInt(r.consult_count) }}</td>
|
||||
<td>{{ formatInt(r.deal_order_count) }}</td>
|
||||
<td v-if="tb.channel_name" class="col-completed">{{ formatInt(r.channel_consult_count) }}</td>
|
||||
@@ -606,6 +640,7 @@
|
||||
>{{ formatInt(yejiRevisitSlotAt(tb.total, slot)) }}</td>
|
||||
<td>{{ formatMoney(tb.total.performance_amount) }}</td>
|
||||
<td v-if="tb.channel_name" class="col-completed">{{ formatMoney(tb.total.completed_performance_amount) }}</td>
|
||||
<td>{{ formatInt(tb.total.appointment_booked_count ?? 0) }}</td>
|
||||
<td>{{ formatInt(tb.total.consult_count) }}</td>
|
||||
<td>{{ formatInt(tb.total.deal_order_count) }}</td>
|
||||
<td v-if="tb.channel_name" class="col-completed">{{ formatInt(tb.total.channel_consult_count) }}</td>
|
||||
@@ -1106,6 +1141,70 @@
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="appointmentLinesDialogVisible"
|
||||
width="min(960px, 96vw)"
|
||||
destroy-on-close
|
||||
class="yeji-leadlines-dialog"
|
||||
>
|
||||
<template #header>
|
||||
<div class="yeji-unassigned-dialog__head">
|
||||
<span class="yeji-unassigned-dialog__title">预约诊单 · 挂号明细</span>
|
||||
<p class="yeji-unassigned-dialog__sub">{{ appointmentLinesSubtitle }}</p>
|
||||
</div>
|
||||
</template>
|
||||
<p v-if="appointmentLinesApiNote" class="yeji-unassigned-dialog__note">{{ appointmentLinesApiNote }}</p>
|
||||
<div v-loading="appointmentLinesLoading" class="yeji-unassigned-dialog__body">
|
||||
<el-table
|
||||
v-if="appointmentLinesRows.length > 0 || appointmentLinesLoading"
|
||||
:data="appointmentLinesRows"
|
||||
size="small"
|
||||
stripe
|
||||
border
|
||||
max-height="440"
|
||||
class="yeji-unassigned-dialog__table"
|
||||
:empty-text="appointmentLinesLoading ? '加载中…' : '暂无数据'"
|
||||
>
|
||||
<el-table-column type="index" label="#" width="46" :index="appointmentLinesIndexMethod" />
|
||||
<el-table-column prop="appointment_date" label="预约日期" width="108" />
|
||||
<el-table-column prop="appointment_time" label="时段" min-width="96" show-overflow-tooltip />
|
||||
<el-table-column prop="status_desc" label="状态" width="84" />
|
||||
<el-table-column prop="appointment_type_desc" label="类型" width="92" />
|
||||
<el-table-column prop="patient_name" label="患者" min-width="92" show-overflow-tooltip />
|
||||
<el-table-column prop="patient_phone" label="手机" min-width="116" show-overflow-tooltip />
|
||||
<el-table-column prop="doctor_name" label="接诊医生" width="92" show-overflow-tooltip />
|
||||
<el-table-column label="诊单ID" width="84" align="right">
|
||||
<template #default="{ row }">{{ formatInt(row.diagnosis_id ?? 0) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="appointmentLinesShowChannelColumn"
|
||||
prop="channel_source"
|
||||
label="渠道来源"
|
||||
width="96"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
</el-table>
|
||||
<el-empty
|
||||
v-if="!appointmentLinesLoading && appointmentLinesRows.length === 0"
|
||||
description="暂无挂号记录"
|
||||
/>
|
||||
<div v-if="appointmentLinesCount > 0" class="yeji-leadlines-dialog__pager">
|
||||
<el-pagination
|
||||
:current-page="appointmentLinesPage"
|
||||
:page-size="appointmentLinesPageSize"
|
||||
background
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="appointmentLinesCount"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:disabled="appointmentLinesLoading"
|
||||
:hide-on-single-page="false"
|
||||
@current-change="onAppointmentLinesPageChange"
|
||||
@size-change="onAppointmentLinesPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="revisitBreakdownVisible"
|
||||
width="min(560px, 94vw)"
|
||||
@@ -1168,6 +1267,7 @@ import {
|
||||
yejiStatsOverview,
|
||||
yejiStatsUnassignedBreakdown,
|
||||
yejiStatsLeadLines,
|
||||
yejiStatsAppointmentLines,
|
||||
yejiStatsRevisitBreakdown,
|
||||
} from '@/api/stats'
|
||||
import { deptPerformanceTargetMonthMatrix } from '@/api/finance'
|
||||
@@ -1284,6 +1384,8 @@ interface YejiRow {
|
||||
assign_count: number
|
||||
revisit_count?: number
|
||||
revisit_slots?: Record<string, number>
|
||||
/** 预约诊单(status 1/3/4),与医助排行榜「预约诊单」一致 */
|
||||
appointment_booked_count?: number
|
||||
consult_count: number
|
||||
deal_order_count: number
|
||||
channel_consult_count: number
|
||||
@@ -1308,6 +1410,7 @@ interface YejiTable {
|
||||
assign_count: number
|
||||
revisit_count?: number
|
||||
revisit_slots?: Record<string, number>
|
||||
appointment_booked_count?: number
|
||||
consult_count: number
|
||||
deal_order_count: number
|
||||
channel_consult_count: number
|
||||
@@ -1342,6 +1445,7 @@ interface LeaderboardPack {
|
||||
assign_count?: number
|
||||
consult_count: number
|
||||
deal_order_count: number
|
||||
appointment_count?: number
|
||||
consult_rate: number
|
||||
revisit_count?: number
|
||||
revisit_slots?: Record<string, number>
|
||||
@@ -1465,6 +1569,35 @@ const leadLinesPage = ref(1)
|
||||
const leadLinesPageSize = ref(20)
|
||||
const leadLinesContext = ref<{ tb: YejiTable; row: YejiRow } | null>(null)
|
||||
|
||||
const appointmentLinesDialogVisible = ref(false)
|
||||
const appointmentLinesLoading = ref(false)
|
||||
const appointmentLinesSubtitle = ref('')
|
||||
const appointmentLinesApiNote = ref('')
|
||||
const appointmentLinesRows = ref<Array<Record<string, unknown>>>([])
|
||||
const appointmentLinesCount = ref(0)
|
||||
const appointmentLinesPage = ref(1)
|
||||
const appointmentLinesPageSize = ref(20)
|
||||
type AppointmentLinesCtx =
|
||||
| {
|
||||
mode: 'assistant'
|
||||
assistant_id: number
|
||||
name: string
|
||||
start_date: string
|
||||
end_date: string
|
||||
}
|
||||
| {
|
||||
mode: 'dept'
|
||||
dept_id: number
|
||||
dept_name: string
|
||||
start_date: string
|
||||
end_date: string
|
||||
}
|
||||
const appointmentLinesContext = ref<AppointmentLinesCtx | null>(null)
|
||||
|
||||
const appointmentLinesShowChannelColumn = computed(() =>
|
||||
appointmentLinesRows.value.some(r => String(r.channel_source ?? '') !== '')
|
||||
)
|
||||
|
||||
/** 图表 / 数据表切换 */
|
||||
const yejiDisplayTab = ref<'doctor' | 'leaderboard' | 'zyyt'>('zyyt')
|
||||
|
||||
@@ -2752,6 +2885,113 @@ function onLeadLinesPageSizeChange(size: number) {
|
||||
void fetchLeadLinesPage()
|
||||
}
|
||||
|
||||
function appointmentLinesIndexMethod(index: number) {
|
||||
return (appointmentLinesPage.value - 1) * appointmentLinesPageSize.value + index + 1
|
||||
}
|
||||
|
||||
/** 业绩主表中「预约诊单」列是否可点开明细(含未归属中心行 dept_id=0) */
|
||||
function yejiAppointmentBookedCellClickable(r: YejiRow): boolean {
|
||||
if (isUnassignedYejiRow(r)) {
|
||||
return true
|
||||
}
|
||||
return r.dept_id > 0
|
||||
}
|
||||
|
||||
async function fetchAppointmentLinesPage() {
|
||||
const ctx = appointmentLinesContext.value
|
||||
if (!ctx) {
|
||||
return
|
||||
}
|
||||
appointmentLinesLoading.value = true
|
||||
try {
|
||||
const p: Record<string, string | number> = {
|
||||
start_date: ctx.start_date,
|
||||
end_date: ctx.end_date,
|
||||
page: appointmentLinesPage.value,
|
||||
page_size: appointmentLinesPageSize.value,
|
||||
}
|
||||
if (ctx.mode === 'dept') {
|
||||
p.dept_id = ctx.dept_id
|
||||
} else {
|
||||
p.assistant_id = ctx.assistant_id
|
||||
}
|
||||
if (selectedDeptIds.value.length > 0) {
|
||||
p.dept_ids = selectedDeptIds.value.join(',')
|
||||
}
|
||||
if (selectedChannel.value) {
|
||||
p.channel_code = selectedChannel.value
|
||||
}
|
||||
const res: any = await yejiStatsAppointmentLines(p as any)
|
||||
appointmentLinesRows.value = Array.isArray(res?.lists) ? res.lists : []
|
||||
appointmentLinesCount.value = Number(res?.count ?? 0)
|
||||
appointmentLinesApiNote.value = typeof res?.note === 'string' ? res.note : ''
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.msg || e?.message || '加载挂号明细失败')
|
||||
appointmentLinesRows.value = []
|
||||
appointmentLinesCount.value = 0
|
||||
appointmentLinesApiNote.value = ''
|
||||
} finally {
|
||||
appointmentLinesLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onLeaderboardAppointmentCellClick(r: LeaderboardPack['leaderboards'][0]['rows'][0]) {
|
||||
if (!r || r.admin_id <= 0 || !leaderboardBlock.value) {
|
||||
return
|
||||
}
|
||||
if (Number(r.appointment_count ?? 0) <= 0) {
|
||||
return
|
||||
}
|
||||
const lb = leaderboardBlock.value
|
||||
appointmentLinesContext.value = {
|
||||
mode: 'assistant',
|
||||
assistant_id: r.admin_id,
|
||||
name: r.name,
|
||||
start_date: lb.start_date,
|
||||
end_date: lb.end_date,
|
||||
}
|
||||
appointmentLinesSubtitle.value = `${r.name} · 医助 · ${lb.start_date} ~ ${lb.end_date}`
|
||||
appointmentLinesApiNote.value = ''
|
||||
appointmentLinesRows.value = []
|
||||
appointmentLinesCount.value = 0
|
||||
appointmentLinesPage.value = 1
|
||||
appointmentLinesPageSize.value = 20
|
||||
appointmentLinesDialogVisible.value = true
|
||||
void fetchAppointmentLinesPage()
|
||||
}
|
||||
|
||||
function onYejiDeptAppointmentBookedClick(tb: YejiTable, r: YejiRow) {
|
||||
if (!yejiAppointmentBookedCellClickable(r) || Number(r.appointment_booked_count ?? 0) <= 0) {
|
||||
return
|
||||
}
|
||||
appointmentLinesContext.value = {
|
||||
mode: 'dept',
|
||||
dept_id: r.dept_id,
|
||||
dept_name: r.dept_name,
|
||||
start_date: tb.start_date,
|
||||
end_date: tb.end_date,
|
||||
}
|
||||
appointmentLinesSubtitle.value = `${r.dept_name} · ${tb.start_date} ~ ${tb.end_date}`
|
||||
appointmentLinesApiNote.value = ''
|
||||
appointmentLinesRows.value = []
|
||||
appointmentLinesCount.value = 0
|
||||
appointmentLinesPage.value = 1
|
||||
appointmentLinesPageSize.value = 20
|
||||
appointmentLinesDialogVisible.value = true
|
||||
void fetchAppointmentLinesPage()
|
||||
}
|
||||
|
||||
function onAppointmentLinesPageChange(p: number) {
|
||||
appointmentLinesPage.value = p
|
||||
void fetchAppointmentLinesPage()
|
||||
}
|
||||
|
||||
function onAppointmentLinesPageSizeChange(size: number) {
|
||||
appointmentLinesPageSize.value = size
|
||||
appointmentLinesPage.value = 1
|
||||
void fetchAppointmentLinesPage()
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门业绩行:有子部门 → 仅筛选该节点(后端展开子行);末级 → 侧栏业务订单;「未归属中心」→ 按诊单医助拆解弹窗
|
||||
*/
|
||||
@@ -3831,6 +4071,12 @@ onMounted(async () => {
|
||||
text-align: right;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.col-appointment {
|
||||
width: 88px;
|
||||
text-align: right;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
}
|
||||
|
||||
.leaderboard-empty {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user