feat(home): implement workbench dashboard

This commit is contained in:
yelan
2026-08-27 17:08:51 +08:00
parent 4412a85adc
commit a61946b520
8 changed files with 1477 additions and 48 deletions
+252 -31
View File
@@ -1,42 +1,263 @@
import { request } from '@/utils/request'
import type { WorkbenchOverviewResponse } from './types'
import type {
HomeRankingPeriod,
WorkbenchCampus,
WorkbenchDocumentRanking,
WorkbenchOverviewQuery,
WorkbenchOverviewResponse,
WorkbenchTodoTask,
WorkbenchTrendPoint,
} from './types'
const useMockData = import.meta.env.VITE_USE_MOCK !== 'false'
const mockOverview: WorkbenchOverviewResponse = {
summary: {
pendingTasks: 18,
todaySigned: 36,
abnormalTasks: 2,
documentCount: 128,
},
recentTasks: [
{
id: 'task-001',
patientName: '李某某',
visitNo: 'ZY20260827001',
documentName: '住院患者知情同意书',
department: '消化内科',
status: 'pending',
updatedAt: '2026-08-27 09:30',
},
{
id: 'task-002',
patientName: '王某某',
visitNo: 'JZ20260827018',
documentName: '急诊留观知情同意书',
department: '儿科急诊',
status: 'signed',
updatedAt: '2026-08-27 09:12',
},
],
interface MockCampusOverview {
summary: WorkbenchOverviewResponse['summary']
trend: WorkbenchTrendPoint[]
todos: WorkbenchTodoTask[]
ranking: Array<Omit<WorkbenchDocumentRanking, 'signedCount'> & { baseCount: number }>
}
export function getWorkbenchOverview(): Promise<WorkbenchOverviewResponse> {
const mockCampusOverviews: Record<WorkbenchCampus, MockCampusOverview> = {
本部院区: {
summary: {
todaySigned: 36,
pendingPatientSigning: 18,
todayOverdue: 2,
availableTemplates: 128,
coveredDepartments: 9,
},
trend: [
{ label: '8/21', value: 24 },
{ label: '8/22', value: 31 },
{ label: '8/23', value: 28 },
{ label: '8/24', value: 35 },
{ label: '8/25', value: 32 },
{ label: '8/26', value: 39 },
{ label: '8/27', value: 36 },
],
todos: [
{
id: 'T0818003',
patientId: 'P202610005',
patientName: '陈志强',
documentName: '住院须知及告知书',
department: '消化内科',
status: 'pending',
method: 'pad',
updatedAt: '2026-08-27 11:20',
},
{
id: 'T0818002',
patientId: 'P202610002',
patientName: '李淑芬',
documentName: 'MRI 磁共振检查知情同意书',
department: '放射科',
status: 'pending',
method: 'sms',
updatedAt: '2026-08-27 10:05',
},
{
id: 'T0815001',
patientId: 'P202610001',
patientName: '王建国',
documentName: '心包穿刺知情同意书',
department: '心内科',
status: 'overdue',
method: 'sms',
updatedAt: '2026-08-27 09:40',
},
],
ranking: [
{ id: 'doc-001', documentName: '住院患者知情同意书', department: '全院通用', baseCount: 58 },
{ id: 'doc-002', documentName: '入院须知及告知书', department: '全院通用', baseCount: 51 },
{
id: 'doc-003',
documentName: 'MRI 磁共振检查知情同意书',
department: '放射科',
baseCount: 43,
},
{ id: 'doc-004', documentName: '手术知情同意书', department: '普外科', baseCount: 39 },
{ id: 'doc-005', documentName: '麻醉知情同意书', department: '麻醉科', baseCount: 35 },
{ id: 'doc-006', documentName: '患者授权委托书', department: '医务处', baseCount: 31 },
{ id: 'doc-007', documentName: '输血治疗知情同意书', department: '血液科', baseCount: 27 },
{ id: 'doc-008', documentName: '内镜检查知情同意书', department: '消化内科', baseCount: 24 },
{ id: 'doc-009', documentName: '介入治疗知情同意书', department: '心内科', baseCount: 21 },
{ id: 'doc-010', documentName: '特殊检查风险告知书', department: '影像科', baseCount: 18 },
],
},
东院区: {
summary: {
todaySigned: 22,
pendingPatientSigning: 11,
todayOverdue: 1,
availableTemplates: 76,
coveredDepartments: 6,
},
trend: [
{ label: '8/21', value: 15 },
{ label: '8/22', value: 18 },
{ label: '8/23', value: 17 },
{ label: '8/24', value: 23 },
{ label: '8/25', value: 20 },
{ label: '8/26', value: 25 },
{ label: '8/27', value: 22 },
],
todos: [
{
id: 'T0818001',
patientId: 'P202610004',
patientName: '赵美英',
documentName: '体检报告发放及知情同意书',
department: '健康管理中心',
status: 'pending',
method: 'pad',
updatedAt: '2026-08-27 09:12',
},
{
id: 'T0818011',
patientId: 'P202610011',
patientName: '周雅琴',
documentName: '检查前注意事项告知书',
department: '体检中心',
status: 'overdue',
method: 'sms',
updatedAt: '2026-08-27 08:30',
},
],
ranking: [
{
id: 'doc-011',
documentName: '体检报告发放及知情同意书',
department: '健康管理中心',
baseCount: 46,
},
{ id: 'doc-012', documentName: '检前告知书', department: '健康管理中心', baseCount: 39 },
{
id: 'doc-013',
documentName: '超声检查知情同意书',
department: '超声医学科',
baseCount: 32,
},
{
id: 'doc-014',
documentName: '胃肠镜检查知情同意书',
department: '消化内科',
baseCount: 28,
},
{ id: 'doc-015', documentName: '采血及检验告知书', department: '检验科', baseCount: 25 },
{ id: 'doc-016', documentName: '影像检查告知书', department: '影像科', baseCount: 21 },
{ id: 'doc-017', documentName: '健康体检知情同意书', department: '体检中心', baseCount: 19 },
{ id: 'doc-018', documentName: '隐私保护告知书', department: '健康管理中心', baseCount: 16 },
{ id: 'doc-019', documentName: '麻醉检查知情同意书', department: '麻醉科', baseCount: 14 },
{ id: 'doc-020', documentName: '报告领取授权书', department: '健康管理中心', baseCount: 12 },
],
},
西院区: {
summary: {
todaySigned: 17,
pendingPatientSigning: 9,
todayOverdue: 2,
availableTemplates: 54,
coveredDepartments: 5,
},
trend: [
{ label: '8/21', value: 11 },
{ label: '8/22', value: 14 },
{ label: '8/23', value: 13 },
{ label: '8/24', value: 16 },
{ label: '8/25', value: 15 },
{ label: '8/26', value: 19 },
{ label: '8/27', value: 17 },
],
todos: [
{
id: 'T0818021',
patientId: 'P202610021',
patientName: '孙浩然',
documentName: '心脏介入手术知情同意书',
department: '心内科',
status: 'pending',
method: 'pad',
updatedAt: '2026-08-27 10:15',
},
{
id: 'T0818022',
patientId: 'P202610022',
patientName: '刘晓琴',
documentName: '骨科手术知情同意书',
department: '骨科',
status: 'pending',
method: 'sms',
updatedAt: '2026-08-27 09:52',
},
{
id: 'T0818023',
patientId: 'P202610023',
patientName: '何文博',
documentName: '术前麻醉访视告知书',
department: '麻醉科',
status: 'overdue',
method: 'pad',
updatedAt: '2026-08-27 08:05',
},
],
ranking: [
{
id: 'doc-021',
documentName: '心脏介入手术知情同意书',
department: '心内科',
baseCount: 37,
},
{ id: 'doc-022', documentName: '骨科手术知情同意书', department: '骨科', baseCount: 33 },
{ id: 'doc-023', documentName: '术前麻醉访视告知书', department: '麻醉科', baseCount: 28 },
{ id: 'doc-024', documentName: '住院患者知情同意书', department: '全院通用', baseCount: 25 },
{ id: 'doc-025', documentName: '输血治疗知情同意书', department: '血液科', baseCount: 22 },
{ id: 'doc-026', documentName: '介入治疗知情同意书', department: '心内科', baseCount: 20 },
{ id: 'doc-027', documentName: '术后康复告知书', department: '骨科', baseCount: 18 },
{ id: 'doc-028', documentName: '特殊检查风险告知书', department: '影像科', baseCount: 16 },
{ id: 'doc-029', documentName: '患者授权委托书', department: '医务处', baseCount: 14 },
{ id: 'doc-030', documentName: '手术部位标识确认书', department: '手术部', baseCount: 12 },
],
},
}
function getPeriodFactor(period: HomeRankingPeriod) {
return period === 7 ? 1 : period === 14 ? 2 : 3.5
}
function createRanking(
rows: MockCampusOverview['ranking'],
period: HomeRankingPeriod,
): WorkbenchDocumentRanking[] {
const factor = getPeriodFactor(period)
return rows
.map((row, index) => ({
id: row.id,
documentName: row.documentName,
department: row.department,
signedCount: Math.round(row.baseCount * factor + (index % 3)),
}))
.sort((left, right) => right.signedCount - left.signedCount)
}
export function getWorkbenchOverview(
query: WorkbenchOverviewQuery,
): Promise<WorkbenchOverviewResponse> {
if (useMockData) {
return Promise.resolve(mockOverview)
const overview = mockCampusOverviews[query.campus] ?? mockCampusOverviews['本部院区']
return Promise.resolve({
summary: { ...overview.summary },
trend: overview.trend.map((point) => ({ ...point })),
todos: overview.todos.map((task) => ({ ...task })),
documentRanking: createRanking(overview.ranking, query.rankingPeriod),
})
}
return request.get<WorkbenchOverviewResponse>('/workbench/overview')
return request.get<WorkbenchOverviewResponse>('/workbench/overview', {
params: query,
})
}
+43 -4
View File
@@ -1,12 +1,22 @@
import type { PageQuery, PageResult } from '@/types/common'
export type WorkbenchCampus = '本部院区' | '东院区' | '西院区'
export type HomeRankingPeriod = 7 | 14 | 30
export interface WorkbenchOverviewQuery {
campus: WorkbenchCampus
rankingPeriod: HomeRankingPeriod
}
export type SigningTaskStatus = 'pending' | 'signing' | 'signed' | 'rejected' | 'expired'
export interface WorkbenchSummary {
pendingTasks: number
todaySigned: number
abnormalTasks: number
documentCount: number
pendingPatientSigning: number
todayOverdue: number
availableTemplates: number
coveredDepartments: number
}
export interface WorkbenchTask {
@@ -19,9 +29,38 @@ export interface WorkbenchTask {
updatedAt: string
}
export type WorkbenchTodoStatus = 'pending' | 'overdue'
export type SigningMethod = 'pad' | 'sms'
export interface WorkbenchTodoTask {
id: string
patientId: string
patientName: string
documentName: string
department: string
status: WorkbenchTodoStatus
method: SigningMethod
updatedAt: string
}
export interface WorkbenchTrendPoint {
label: string
value: number
}
export interface WorkbenchDocumentRanking {
id: string
documentName: string
department: string
signedCount: number
}
export interface WorkbenchOverviewResponse {
summary: WorkbenchSummary
recentTasks: WorkbenchTask[]
trend: WorkbenchTrendPoint[]
todos: WorkbenchTodoTask[]
documentRanking: WorkbenchDocumentRanking[]
}
export interface SigningTaskQuery extends PageQuery {