feat: 初始化项目

This commit is contained in:
王天骄
2026-05-29 17:40:10 +08:00
parent 185ccb260e
commit 873c3e98fb
21 changed files with 7801 additions and 67 deletions
+82
View File
@@ -0,0 +1,82 @@
export type ClinicalCase = {
id: string
title: string
patientName: string
gender: '男' | '女'
age: number
department: string
scene: string
caseNo: string
tone: 'blue' | 'teal' | 'pink' | 'orange' | 'purple' | 'green'
}
export function fetchCaseList(): Promise<ClinicalCase[]> {
return Promise.resolve([
{
id: 'case-31190016',
title: '间断四肢多关节肿痛5年,加重1个月',
patientName: '郭爱和',
gender: '男',
age: 43,
department: '风湿免疫科',
scene: '门诊部',
caseNo: '31190016',
tone: 'blue'
},
{
id: 'case-31180002',
title: '右膝关节疼痛8年,腰背部疼痛2年',
patientName: '索航',
gender: '男',
age: 51,
department: '风湿免疫科',
scene: '住院部',
caseNo: '31180002',
tone: 'teal'
},
{
id: 'case-2238015',
title: '阴道不规则流血4月。',
patientName: '韩爱利',
gender: '女',
age: 52,
department: '妇科',
scene: '住院部',
caseNo: '2238015',
tone: 'pink'
},
{
id: 'case-1006004',
title: '持续胸痛3小时',
patientName: '毕波涛',
gender: '男',
age: 60,
department: '心血管内科',
scene: '住院部',
caseNo: '1006004',
tone: 'orange'
},
{
id: 'case-31190042',
title: '咳嗽、咳痰10余年,加重1周',
patientName: '厉明',
gender: '男',
age: 52,
department: '呼吸内科',
scene: '普通门诊',
caseNo: '31190042',
tone: 'purple'
},
{
id: 'case-2238019',
title: '尿频、尿急、尿痛3天',
patientName: '刘晓元',
gender: '女',
age: 25,
department: '泌尿外科',
scene: '急诊留观',
caseNo: '2238019',
tone: 'green'
}
])
}
+106
View File
@@ -0,0 +1,106 @@
import type { ClinicalCase } from './cases'
export type ChatRole = 'patient' | 'mentor' | 'doctor'
export type ChatMessage = {
id: string
role: ChatRole
content: string
label: string
}
export type ChatSession = {
patient: {
name: string
gender: string
age: number
department: string
chiefComplaint: string
}
stages: Array<{
key: string
label: string
active: boolean
}>
messages: ChatMessage[]
}
const defaultCase: ClinicalCase = {
id: 'case-1006004',
title: '持续胸痛3小时',
patientName: '陈先生',
gender: '男',
age: 60,
department: '心血管内科',
scene: '住院部',
caseNo: '1006004',
tone: 'orange'
}
export function createMockChatSession(caseItem?: ClinicalCase | null): Promise<ChatSession> {
const currentCase = caseItem || defaultCase
const patientName = currentCase.patientName === '毕波涛' ? '陈先生' : currentCase.patientName
return Promise.resolve({
patient: {
name: patientName,
gender: currentCase.gender,
age: currentCase.age,
department: currentCase.department,
chiefComplaint: currentCase.title
},
stages: [
{ key: 'history', label: '病史采集', active: true },
{ key: 'diagnosis', label: '初步诊断', active: false },
{ key: 'treatment', label: '治疗方案', active: false }
],
messages: [
{
id: 'patient-initial',
role: 'patient',
content: currentCase.department === '心血管内科'
? '医生,我心口这儿针扎一样疼了两个小时了,现在感觉喘气都费劲。'
: `医生,我这次主要是${currentCase.title},有点担心。`,
label: '患者'
},
{
id: 'mentor-initial',
role: 'mentor',
content: '观察患者的面部表情和生命体征。你的第一个问题应该如何询问,以明确疼痛的性质?',
label: '王主任'
}
]
})
}
export function sendMockChatMessage(content: string): Promise<ChatMessage[]> {
const normalized = content.trim()
const patientReply = normalized.includes('出冷汗') || normalized.includes('恶心')
? '有,刚才疼得厉害的时候出了一身冷汗,还有点恶心,但没有吐。'
: normalized.includes('体格检查')
? '患者面色苍白,额部出汗,心率偏快,血压较入院时略低。'
: normalized.includes('辅助检查')
? '心电图提示下壁导联 ST 段抬高,肌钙蛋白待回报。'
: '疼痛主要在胸骨后,像压榨一样,休息后也没有明显缓解。'
return Promise.resolve([
{
id: `doctor-${Date.now()}`,
role: 'doctor',
content: normalized,
label: '我'
},
{
id: `patient-${Date.now() + 1}`,
role: 'patient',
content: patientReply,
label: '患者'
},
{
id: `mentor-${Date.now() + 2}`,
role: 'mentor',
content: '很好,继续围绕 OPQRST 思路追问疼痛诱因、部位、性质、放射、持续时间和缓解因素,同时关注危险信号。',
label: '王主任'
}
])
}
+74
View File
@@ -0,0 +1,74 @@
export type ConfigOption = {
value: string
label: string
desc?: string
}
export type ConfigOptions = {
departments: ConfigOption[]
titles: ConfigOption[]
experiences: ConfigOption[]
}
export type ClinicalConfigPayload = {
userId: string
phone: string
institutionId: string
department: string
title: string
experience: string
departmentName: string
titleName: string
experienceName: string
}
export type ClinicalConfigResult = ClinicalConfigPayload & {
id: string
updatedAt: string
}
export const MOCK_CONFIG_OPTIONS: ConfigOptions = {
departments: [
{ value: 'im', label: '内科', desc: '心内、呼吸、消化、肾内等临床场景' },
{ value: 'sur', label: '外科', desc: '普外、骨科、神外、胸外等临床场景' },
{ value: 'ped', label: '儿科', desc: '儿童常见病、急重症与沟通训练' },
{ value: 'obg', label: '妇产科', desc: '围产、妇科、产科急症训练' },
{ value: 'er', label: '急诊科', desc: '分诊、抢救、危急值处置训练' },
{ value: 'icu', label: '重症医学科', desc: '危重症评估与多学科决策训练' }
],
titles: [
{ value: 'resident', label: '住院医师', desc: '强化基础诊疗路径与病历思维' },
{ value: 'attending', label: '主治医师', desc: '提升独立诊疗和带教表达' },
{ value: 'associate_chief', label: '副主任医师', desc: '复杂病例决策与团队协作' },
{ value: 'chief', label: '主任医师', desc: '疑难病例、质控和教学管理' }
],
experiences: [
{ value: '1-3', label: '1-3年', desc: '基础病例训练优先' },
{ value: '3-5', label: '3-5年', desc: '进阶诊疗路径优先' },
{ value: '5-10', label: '5-10年', desc: '复杂病例推演优先' },
{ value: '10+', label: '10年以上', desc: '疑难病例与带教模拟优先' }
]
}
export function fetchConfigOptions() {
return Promise.resolve({
options: MOCK_CONFIG_OPTIONS,
defaults: {
department: 'im',
title: 'resident',
experience: '1-3'
},
mentor: {
name: '王主任',
message: '欢迎回来!请配置执业信息,开始精准带教模拟。'
}
})
}
export function saveClinicalConfig(payload: ClinicalConfigPayload): Promise<ClinicalConfigResult> {
return Promise.resolve({
id: `mock-config-${Date.now()}`,
...payload,
updatedAt: new Date().toISOString()
})
}
+36
View File
@@ -0,0 +1,36 @@
import type { ClinicalCase } from './cases'
export type DiagnosisDraft = {
primaryDiagnosis: string
differentialDiagnosis: string[]
evidence: string
}
export type DiagnosisContext = {
mentorAdvice: string
defaultDraft: DiagnosisDraft
}
export function fetchDiagnosisContext(caseItem?: ClinicalCase | null): Promise<DiagnosisContext> {
const isChestPain = caseItem?.title.includes('胸痛') || caseItem?.department === '心血管内科'
return Promise.resolve({
mentorAdvice: isChestPain
? '王主任建议:请结合患者既往高血压史及突发性胸痛的性质,进行准确诊断。注意鉴别心梗与主动脉夹层。'
: '王主任建议:请基于主诉、阳性症状和危险信号提出主要诊断,并列出需要排除的鉴别诊断。',
defaultDraft: {
primaryDiagnosis: '',
differentialDiagnosis: ['', ''],
evidence: ''
}
})
}
export function submitDiagnosis(caseId: string, draft: DiagnosisDraft) {
return Promise.resolve({
id: `mock-diagnosis-${Date.now()}`,
caseId,
...draft,
submittedAt: new Date().toISOString()
})
}
+22
View File
@@ -0,0 +1,22 @@
export type HomeSummary = {
greeting: string
highlight: string
remainingModules: number
doctorName: string
}
export function fetchHomeSummary(): Promise<HomeSummary> {
return Promise.resolve({
greeting: '下午好,医生。',
highlight: '让我们继续提升您的临床思维能力吧。',
remainingModules: 3,
doctorName: '王主任'
})
}
export function startTrainingSession() {
return Promise.resolve({
sessionId: `mock-session-${Date.now()}`,
startedAt: new Date().toISOString()
})
}
+23
View File
@@ -0,0 +1,23 @@
export type MatchingProfile = {
message: string
subtitle: string
progressTarget: number
tags: Array<{
label: string
tone: 'secondary' | 'primary' | 'tertiary' | 'neutral'
}>
}
export function fetchMatchingProfile(): Promise<MatchingProfile> {
return Promise.resolve({
message: '王主任正在为您智能匹配病例',
subtitle: '正在通过大模型计算最适合您的临床案例库...',
progressTarget: 92,
tags: [
{ label: '薄弱环节', tone: 'secondary' },
{ label: '主治医级别', tone: 'primary' },
{ label: '高匹配度', tone: 'tertiary' },
{ label: '基于历史偏好', tone: 'neutral' }
]
})
}
+96
View File
@@ -0,0 +1,96 @@
export type ScenarioRecommendation = {
id: string
title: string
desc: string
tags: string[]
defaults: ScenarioForm
}
export type ScenarioOption = {
value: string
label: string
}
export type ScenarioForm = {
environment: string
ageGroup: string
education: string
personality: string
}
export type ScenarioOptions = {
environments: ScenarioOption[]
ageGroups: ScenarioOption[]
educations: ScenarioOption[]
personalities: ScenarioOption[]
}
export type ScenarioConfigPayload = ScenarioForm & {
caseId: string
caseNo: string
recommendationId?: string
}
export function fetchScenarioOptions() {
return Promise.resolve({
recommendations: [
{
id: 'typical-outpatient',
title: '典型门诊病例',
desc: '门诊常规病例:针对初学者设计的标准化沟通流程。',
tags: ['中年', '配合'],
defaults: {
environment: 'outpatient',
ageGroup: 'middle',
education: 'higher',
personality: 'calm'
}
},
{
id: 'emergency-crisis',
title: '急诊重症危机',
desc: '急诊危重:急性心梗紧急入院。',
tags: ['老年', '急躁'],
defaults: {
environment: 'emergency',
ageGroup: 'elderly',
education: 'secondary',
personality: 'irritable'
}
}
] as ScenarioRecommendation[],
options: {
environments: [
{ value: 'outpatient', label: '门诊' },
{ value: 'emergency', label: '急诊' },
{ value: 'ward', label: '病房' }
],
ageGroups: [
{ value: 'child', label: '儿童' },
{ value: 'young', label: '青年' },
{ value: 'middle', label: '中年' },
{ value: 'elderly', label: '老年' }
],
educations: [
{ value: 'primary', label: '小学及以下' },
{ value: 'secondary', label: '中等教育' },
{ value: 'higher', label: '高等教育' }
],
personalities: [
{ value: 'calm', label: '平和' },
{ value: 'anxious', label: '焦虑' },
{ value: 'irritable', label: '急躁' },
{ value: 'cooperative', label: '配合' },
{ value: 'suspicious', label: '多疑' }
]
} as ScenarioOptions
})
}
export function createScenarioConfig(payload: ScenarioConfigPayload) {
return Promise.resolve({
id: `mock-scenario-${Date.now()}`,
...payload,
createdAt: new Date().toISOString()
})
}