feat: 初始化项目
This commit is contained in:
@@ -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
@@ -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: '王主任'
|
||||
}
|
||||
])
|
||||
}
|
||||
@@ -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()
|
||||
})
|
||||
}
|
||||
@@ -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
@@ -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()
|
||||
})
|
||||
}
|
||||
@@ -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' }
|
||||
]
|
||||
})
|
||||
}
|
||||
@@ -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()
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user