feat: 联调对话功能
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { FASTAPI_BASE_URL, authHeaders, readError, type ApiEnvelope, type ScoreType } from './session'
|
||||
|
||||
export type DimensionScore = {
|
||||
dimension: string
|
||||
score: number
|
||||
max_score: number
|
||||
comment?: string
|
||||
evidence?: string[]
|
||||
deductions?: string[]
|
||||
improvement?: string
|
||||
}
|
||||
|
||||
export type ScoreDetail = {
|
||||
dimension: string
|
||||
score: number
|
||||
deducted_reason?: string
|
||||
ai_confidence?: number
|
||||
comment?: string
|
||||
}
|
||||
|
||||
export type EvaluationResult = {
|
||||
evaluation_id: number
|
||||
score_type: ScoreType
|
||||
total_score: number
|
||||
dimension_scores: DimensionScore[]
|
||||
score_details: ScoreDetail[]
|
||||
errors: string[]
|
||||
improvement_plan: string[]
|
||||
evidence_summary: string[]
|
||||
guideline_refs: string[]
|
||||
overall_comment: string
|
||||
}
|
||||
|
||||
export async function generateEvaluation(sessionId: number, scoreType: ScoreType = 'percentage') {
|
||||
const response = await fetch(`${FASTAPI_BASE_URL}/sessions/${sessionId}/evaluation`, {
|
||||
method: 'POST',
|
||||
headers: authHeaders(),
|
||||
body: JSON.stringify({
|
||||
score_type: scoreType
|
||||
})
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(await readError(response))
|
||||
}
|
||||
|
||||
const result = (await response.json()) as ApiEnvelope<EvaluationResult>
|
||||
if (result.code !== 'OK' || !result.data) {
|
||||
throw new Error(result.message || '评价生成失败')
|
||||
}
|
||||
|
||||
return result.data
|
||||
}
|
||||
+50
-4
@@ -58,15 +58,36 @@ function readErrorMessage(data: unknown, fallback: string) {
|
||||
return fallback
|
||||
}
|
||||
|
||||
function request<T>(url: string, data: unknown, method: 'POST' | 'GET' = 'POST'): Promise<T> {
|
||||
function readAccessToken() {
|
||||
try {
|
||||
return uni.getStorageSync('clinical-thinking-access-token') || ''
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
function createRequestHeaders(includeAuth = false) {
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
if (!includeAuth) return headers
|
||||
|
||||
const token = readAccessToken()
|
||||
if (token) {
|
||||
headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
function request<T>(url: string, data: unknown, method: 'POST' | 'GET' = 'POST', includeAuth = false): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: `${API_BASE_URL}${url}`,
|
||||
method,
|
||||
timeout: 10000,
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
header: createRequestHeaders(includeAuth),
|
||||
data,
|
||||
success: response => {
|
||||
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||
@@ -114,10 +135,35 @@ export type InstitutionRecord = {
|
||||
is_trial: boolean
|
||||
}
|
||||
|
||||
export type InstitutionInfo = {
|
||||
id: number
|
||||
code: string
|
||||
name: string
|
||||
type: string
|
||||
level: string
|
||||
province: string
|
||||
city: string
|
||||
banner_url: string
|
||||
}
|
||||
|
||||
export type DepartmentRecord = {
|
||||
id: number
|
||||
name: string
|
||||
category: string
|
||||
}
|
||||
|
||||
export function fetchInstitutions(): Promise<InstitutionRecord[]> {
|
||||
return request<InstitutionRecord[]>('/user/institution_list/', null, 'GET')
|
||||
}
|
||||
|
||||
export function fetchInstitutionInfo(): Promise<InstitutionInfo> {
|
||||
return request<InstitutionInfo>('/user/institution_info/', null, 'GET', true)
|
||||
}
|
||||
|
||||
export function fetchMyDepartments(): Promise<DepartmentRecord[]> {
|
||||
return request<DepartmentRecord[]>('/user/my_departments/', null, 'GET', true)
|
||||
}
|
||||
|
||||
export function loginWithCode(payload: LoginCodePayload): Promise<LoginResponse> {
|
||||
return request<LoginResponse>('/user/auth/login-code/', payload).then(response => {
|
||||
if (isLoginResponse(response)) return response
|
||||
|
||||
@@ -89,3 +89,9 @@ export function fetchCaseList(): Promise<ClinicalCase[]> {
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
export function readStoredClinicalCase() {
|
||||
const value = uni.getStorageSync('clinical-thinking-selected-case')
|
||||
if (value && typeof value === 'object') return value as ClinicalCase
|
||||
return null
|
||||
}
|
||||
|
||||
+52
-17
@@ -1,3 +1,5 @@
|
||||
import { API_BASE_URL, ApiRequestError } from './auth'
|
||||
|
||||
export type ConfigOption = {
|
||||
value: string
|
||||
label: string
|
||||
@@ -11,21 +13,12 @@ export type ConfigOptions = {
|
||||
}
|
||||
|
||||
export type ClinicalConfigPayload = {
|
||||
userId: string
|
||||
phone: string
|
||||
institutionId: string
|
||||
department: string
|
||||
title: string
|
||||
experience: string
|
||||
departmentName: string
|
||||
titleName: string
|
||||
experienceName: string
|
||||
department: number
|
||||
title_name: string
|
||||
practice_years: string
|
||||
}
|
||||
|
||||
export type ClinicalConfigResult = ClinicalConfigPayload & {
|
||||
id: string
|
||||
updatedAt: string
|
||||
}
|
||||
export type ClinicalConfigResult = Record<string, unknown>
|
||||
|
||||
export const MOCK_CONFIG_OPTIONS: ConfigOptions = {
|
||||
departments: [
|
||||
@@ -65,10 +58,52 @@ export function fetchConfigOptions() {
|
||||
})
|
||||
}
|
||||
|
||||
function readAccessToken() {
|
||||
try {
|
||||
return uni.getStorageSync('clinical-thinking-access-token') || ''
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
function readErrorMessage(data: unknown, fallback: string) {
|
||||
if (data && typeof data === 'object') {
|
||||
const payload = data as Record<string, unknown>
|
||||
const message = payload.message || payload.detail || payload.error
|
||||
if (typeof message === 'string' && message.trim()) return message
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
export function saveClinicalConfig(payload: ClinicalConfigPayload): Promise<ClinicalConfigResult> {
|
||||
return Promise.resolve({
|
||||
id: `mock-config-${Date.now()}`,
|
||||
...payload,
|
||||
updatedAt: new Date().toISOString()
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = readAccessToken()
|
||||
const header: Record<string, string> = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
if (token) {
|
||||
header.Authorization = `Bearer ${token}`
|
||||
}
|
||||
|
||||
uni.request({
|
||||
url: `${API_BASE_URL}/user/profile/config/`,
|
||||
method: 'POST',
|
||||
timeout: 10000,
|
||||
header,
|
||||
data: payload,
|
||||
success: response => {
|
||||
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||
resolve(response.data as ClinicalConfigResult)
|
||||
return
|
||||
}
|
||||
const data = response.data as Record<string, unknown> | undefined
|
||||
const code = typeof data?.code === 'string' ? data.code : undefined
|
||||
reject(new ApiRequestError(readErrorMessage(response.data, `保存失败(${response.statusCode})`), code, response.statusCode))
|
||||
},
|
||||
fail: error => {
|
||||
reject(new ApiRequestError(error.errMsg || '无法连接服务'))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
+29
-6
@@ -1,4 +1,5 @@
|
||||
import type { ClinicalCase } from './cases'
|
||||
import { FASTAPI_BASE_URL, authHeaders, readError, type ApiEnvelope } from './session'
|
||||
|
||||
export type DiagnosisDraft = {
|
||||
primaryDiagnosis: string
|
||||
@@ -6,6 +7,12 @@ export type DiagnosisDraft = {
|
||||
evidence: string
|
||||
}
|
||||
|
||||
export type DiagnosisPayload = {
|
||||
primary_diagnosis: string
|
||||
differential_diagnoses: string[]
|
||||
diagnosis_basis: string
|
||||
}
|
||||
|
||||
export type DiagnosisContext = {
|
||||
mentorAdvice: string
|
||||
defaultDraft: DiagnosisDraft
|
||||
@@ -26,11 +33,27 @@ export function fetchDiagnosisContext(caseItem?: ClinicalCase | null): Promise<D
|
||||
})
|
||||
}
|
||||
|
||||
export function submitDiagnosis(caseId: string, draft: DiagnosisDraft) {
|
||||
return Promise.resolve({
|
||||
id: `mock-diagnosis-${Date.now()}`,
|
||||
caseId,
|
||||
...draft,
|
||||
submittedAt: new Date().toISOString()
|
||||
export async function submitDiagnosis(sessionId: number, draft: DiagnosisDraft) {
|
||||
const payload: DiagnosisPayload = {
|
||||
primary_diagnosis: draft.primaryDiagnosis.trim(),
|
||||
differential_diagnoses: draft.differentialDiagnosis.map(item => item.trim()).filter(Boolean),
|
||||
diagnosis_basis: draft.evidence.trim()
|
||||
}
|
||||
|
||||
const response = await fetch(`${FASTAPI_BASE_URL}/sessions/${sessionId}/diagnosis`, {
|
||||
method: 'POST',
|
||||
headers: authHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(await readError(response))
|
||||
}
|
||||
|
||||
const result = (await response.json()) as ApiEnvelope<unknown>
|
||||
if (result.code !== 'OK') {
|
||||
throw new Error(result.message || '诊断提交失败')
|
||||
}
|
||||
|
||||
return result.data || payload
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { getCurrentInstance } from 'vue'
|
||||
|
||||
type OpenProfileEmit = (event: 'open-profile') => void
|
||||
type OpenSettingsEmit = (event: 'open-settings') => void
|
||||
type GoHomeEmit = (event: 'go-home') => void
|
||||
|
||||
export function createProfileOpener(emit: OpenProfileEmit) {
|
||||
const instance = getCurrentInstance()
|
||||
@@ -17,3 +19,35 @@ export function createProfileOpener(emit: OpenProfileEmit) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function createSettingsOpener(emit: OpenSettingsEmit) {
|
||||
const instance = getCurrentInstance()
|
||||
const hasOpenSettingsListener = Boolean(instance?.vnode.props?.onOpenSettings)
|
||||
|
||||
return function openSettings() {
|
||||
if (hasOpenSettingsListener) {
|
||||
emit('open-settings')
|
||||
return
|
||||
}
|
||||
|
||||
uni.navigateTo({
|
||||
url: '/pages/config/config'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function createHomeNavigator(emit: GoHomeEmit) {
|
||||
const instance = getCurrentInstance()
|
||||
const hasGoHomeListener = Boolean(instance?.vnode.props?.onGoHome)
|
||||
|
||||
return function goHome() {
|
||||
if (hasGoHomeListener) {
|
||||
emit('go-home')
|
||||
return
|
||||
}
|
||||
|
||||
uni.reLaunch({
|
||||
url: '/pages/home/home'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+129
-27
@@ -1,4 +1,11 @@
|
||||
import { createTrainingSession, type PatientConfigPayload, type TrainingMode } from './session'
|
||||
import {
|
||||
FASTAPI_BASE_URL,
|
||||
authHeaders,
|
||||
createTrainingSession,
|
||||
readError,
|
||||
type PatientConfigPayload,
|
||||
type TrainingMode
|
||||
} from './session'
|
||||
|
||||
export type ScenarioRecommendation = {
|
||||
id: string
|
||||
@@ -11,6 +18,7 @@ export type ScenarioRecommendation = {
|
||||
export type ScenarioOption = {
|
||||
value: string
|
||||
label: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type ScenarioForm = {
|
||||
@@ -27,6 +35,12 @@ export type ScenarioOptions = {
|
||||
personalities: ScenarioOption[]
|
||||
}
|
||||
|
||||
export type TrainingConfigRecommended = {
|
||||
recommended: ScenarioForm
|
||||
recommendedLabels: Record<ScenarioFormKey, string>
|
||||
options: ScenarioOptions
|
||||
}
|
||||
|
||||
export type ScenarioConfigPayload = ScenarioForm & {
|
||||
caseId: string
|
||||
caseNo: string
|
||||
@@ -34,6 +48,61 @@ export type ScenarioConfigPayload = ScenarioForm & {
|
||||
recommendationId?: string
|
||||
}
|
||||
|
||||
type TrainingConfigApiKey = 'visit_environment' | 'age_group' | 'education_level' | 'personality'
|
||||
|
||||
const DEFAULT_CASE_ID = 1
|
||||
|
||||
type ApiEnvelope<T> = {
|
||||
code: string
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
|
||||
type ScenarioFormKey = keyof ScenarioForm
|
||||
|
||||
type TrainingConfigRecommendedResponse = {
|
||||
case_id: number
|
||||
recommended: {
|
||||
visit_environment: string
|
||||
age_group: string
|
||||
education_level: string
|
||||
personality: string
|
||||
}
|
||||
recommended_labels: {
|
||||
visit_environment: string
|
||||
age_group: string
|
||||
education_level: string
|
||||
personality: string
|
||||
}
|
||||
options?: Partial<Record<TrainingConfigApiKey, ScenarioOption[] | Record<string, string>>>
|
||||
}
|
||||
|
||||
export const DEFAULT_SCENARIO_OPTIONS: ScenarioOptions = {
|
||||
environments: [
|
||||
{ value: 'outpatient', label: '门诊' },
|
||||
{ value: 'emergency', label: '急诊' },
|
||||
{ value: 'ward', label: '病房' }
|
||||
],
|
||||
ageGroups: [
|
||||
{ value: 'child', label: '儿童' },
|
||||
{ value: 'youth', label: '青年' },
|
||||
{ value: 'middle_aged', label: '中年' },
|
||||
{ value: 'elderly', label: '老年' }
|
||||
],
|
||||
educations: [
|
||||
{ value: 'primary_or_below', label: '小学及以下' },
|
||||
{ value: 'secondary', label: '中等教育' },
|
||||
{ value: 'higher', label: '高等教育' }
|
||||
],
|
||||
personalities: [
|
||||
{ value: 'calm', label: '平和' },
|
||||
{ value: 'anxious', label: '焦虑' },
|
||||
{ value: 'impatient', label: '急躁' },
|
||||
{ value: 'cooperative', label: '配合' },
|
||||
{ value: 'suspicious', label: '多疑' }
|
||||
]
|
||||
}
|
||||
|
||||
export function fetchScenarioOptions() {
|
||||
return Promise.resolve({
|
||||
recommendations: [
|
||||
@@ -62,37 +131,70 @@ export function fetchScenarioOptions() {
|
||||
}
|
||||
}
|
||||
] as ScenarioRecommendation[],
|
||||
options: {
|
||||
environments: [
|
||||
{ value: 'outpatient', label: '门诊' },
|
||||
{ value: 'emergency', label: '急诊' },
|
||||
{ value: 'ward', label: '病房' }
|
||||
],
|
||||
ageGroups: [
|
||||
{ value: 'child', label: '儿童' },
|
||||
{ value: 'youth', label: '青年' },
|
||||
{ value: 'middle_aged', label: '中年' },
|
||||
{ value: 'elderly', label: '老年' }
|
||||
],
|
||||
educations: [
|
||||
{ value: 'primary_or_below', label: '小学及以下' },
|
||||
{ value: 'secondary', label: '中等教育' },
|
||||
{ value: 'higher', label: '高等教育' }
|
||||
],
|
||||
personalities: [
|
||||
{ value: 'calm', label: '平和' },
|
||||
{ value: 'anxious', label: '焦虑' },
|
||||
{ value: 'impatient', label: '急躁' },
|
||||
{ value: 'cooperative', label: '配合' },
|
||||
{ value: 'suspicious', label: '多疑' }
|
||||
]
|
||||
} as ScenarioOptions
|
||||
options: DEFAULT_SCENARIO_OPTIONS
|
||||
})
|
||||
}
|
||||
|
||||
function normalizeApiOptions(
|
||||
source: TrainingConfigRecommendedResponse['options'] | undefined,
|
||||
key: keyof TrainingConfigRecommendedResponse['recommended'],
|
||||
fallback: ScenarioOption[]
|
||||
) {
|
||||
const value = source?.[key]
|
||||
if (Array.isArray(value)) return value
|
||||
if (value && typeof value === 'object') {
|
||||
return Object.entries(value).map(([optionValue, label]) => ({
|
||||
value: optionValue,
|
||||
label: String(label)
|
||||
}))
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
function normalizeTrainingConfig(payload: TrainingConfigRecommendedResponse): TrainingConfigRecommended {
|
||||
return {
|
||||
recommended: {
|
||||
environment: payload.recommended.visit_environment,
|
||||
ageGroup: payload.recommended.age_group,
|
||||
education: payload.recommended.education_level,
|
||||
personality: payload.recommended.personality
|
||||
},
|
||||
recommendedLabels: {
|
||||
environment: payload.recommended_labels.visit_environment,
|
||||
ageGroup: payload.recommended_labels.age_group,
|
||||
education: payload.recommended_labels.education_level,
|
||||
personality: payload.recommended_labels.personality
|
||||
},
|
||||
options: {
|
||||
environments: normalizeApiOptions(payload.options, 'visit_environment', DEFAULT_SCENARIO_OPTIONS.environments),
|
||||
ageGroups: normalizeApiOptions(payload.options, 'age_group', DEFAULT_SCENARIO_OPTIONS.ageGroups),
|
||||
educations: normalizeApiOptions(payload.options, 'education_level', DEFAULT_SCENARIO_OPTIONS.educations),
|
||||
personalities: normalizeApiOptions(payload.options, 'personality', DEFAULT_SCENARIO_OPTIONS.personalities)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchTrainingConfigOptions(caseId: number) {
|
||||
const response = await fetch(`${FASTAPI_BASE_URL}/training-config/options?case_id=${encodeURIComponent(caseId)}`, {
|
||||
method: 'GET',
|
||||
headers: authHeaders()
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(await readError(response))
|
||||
}
|
||||
|
||||
const result = (await response.json()) as ApiEnvelope<TrainingConfigRecommendedResponse>
|
||||
if (result.code !== 'OK' || !result.data?.recommended) {
|
||||
throw new Error(result.message || '推荐配置加载失败')
|
||||
}
|
||||
|
||||
return normalizeTrainingConfig(result.data)
|
||||
}
|
||||
|
||||
export function createScenarioConfig(payload: ScenarioConfigPayload) {
|
||||
return createTrainingSession({
|
||||
case_id: 1,
|
||||
case_id: DEFAULT_CASE_ID,
|
||||
training_type: 'diagnosis_treatment',
|
||||
mode: payload.mode,
|
||||
score_type: 'percentage',
|
||||
|
||||
+57
-3
@@ -32,7 +32,17 @@ export type TrainingSession = {
|
||||
patient_config: SessionPatientConfig
|
||||
}
|
||||
|
||||
type ApiEnvelope<T> = {
|
||||
export type CompleteInquiryResult = {
|
||||
session_id: number
|
||||
status: string
|
||||
}
|
||||
|
||||
export type StoredTrainingScenario = {
|
||||
session?: TrainingSession
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type ApiEnvelope<T> = {
|
||||
code: string
|
||||
message: string
|
||||
data: T
|
||||
@@ -56,7 +66,7 @@ function readAccessToken() {
|
||||
return token
|
||||
}
|
||||
|
||||
function authHeaders(accept = 'application/json') {
|
||||
export function authHeaders(accept = 'application/json') {
|
||||
return {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: accept,
|
||||
@@ -65,7 +75,7 @@ function authHeaders(accept = 'application/json') {
|
||||
}
|
||||
}
|
||||
|
||||
async function readError(response: Response) {
|
||||
export async function readError(response: Response) {
|
||||
const text = await response.text().catch(() => '')
|
||||
if (!text) return `请求失败(${response.status})`
|
||||
try {
|
||||
@@ -76,6 +86,32 @@ async function readError(response: Response) {
|
||||
return text
|
||||
}
|
||||
|
||||
export function readStoredTrainingScenario() {
|
||||
const value = uni.getStorageSync('clinical-thinking-scenario')
|
||||
if (value && typeof value === 'object') return value as StoredTrainingScenario
|
||||
return null
|
||||
}
|
||||
|
||||
export function readActiveSessionId() {
|
||||
const sessionId = readStoredTrainingScenario()?.session?.session_id
|
||||
if (typeof sessionId === 'number' && Number.isInteger(sessionId) && sessionId > 0) {
|
||||
return sessionId
|
||||
}
|
||||
throw new Error('未找到当前会话,请先生成模拟场景')
|
||||
}
|
||||
|
||||
export function updateStoredSessionStatus(status: string) {
|
||||
const scenario = readStoredTrainingScenario()
|
||||
if (!scenario?.session) return
|
||||
uni.setStorageSync('clinical-thinking-scenario', {
|
||||
...scenario,
|
||||
session: {
|
||||
...scenario.session,
|
||||
status
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function createTrainingSession(payload: CreateSessionPayload) {
|
||||
const response = await fetch(`${FASTAPI_BASE_URL}/sessions`, {
|
||||
method: 'POST',
|
||||
@@ -94,6 +130,24 @@ export async function createTrainingSession(payload: CreateSessionPayload) {
|
||||
return result.data
|
||||
}
|
||||
|
||||
export async function completeInquiry(sessionId: number) {
|
||||
const response = await fetch(`${FASTAPI_BASE_URL}/sessions/${sessionId}/complete-inquiry`, {
|
||||
method: 'POST',
|
||||
headers: authHeaders()
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(await readError(response))
|
||||
}
|
||||
|
||||
const result = (await response.json()) as ApiEnvelope<CompleteInquiryResult>
|
||||
if (result.code !== 'OK' || !result.data?.session_id) {
|
||||
throw new Error(result.message || '完成采集失败')
|
||||
}
|
||||
|
||||
return result.data
|
||||
}
|
||||
|
||||
export async function streamSessionChat(
|
||||
sessionId: number,
|
||||
message: string,
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { FASTAPI_BASE_URL, authHeaders, readError, type ApiEnvelope } from './session'
|
||||
|
||||
export type TreatmentDraft = {
|
||||
treatmentPrinciple: string
|
||||
treatmentMeasures: string
|
||||
riskPlan: string
|
||||
communication: string
|
||||
followUp: string
|
||||
}
|
||||
|
||||
export type TreatmentPayload = {
|
||||
treatment_principle: string
|
||||
treatment_measures: string
|
||||
risk_plan: string
|
||||
communication: string
|
||||
follow_up: string
|
||||
}
|
||||
|
||||
export async function submitTreatment(sessionId: number, draft: TreatmentDraft) {
|
||||
const payload: TreatmentPayload = {
|
||||
treatment_principle: draft.treatmentPrinciple.trim(),
|
||||
treatment_measures: draft.treatmentMeasures.trim(),
|
||||
risk_plan: draft.riskPlan.trim(),
|
||||
communication: draft.communication.trim(),
|
||||
follow_up: draft.followUp.trim()
|
||||
}
|
||||
|
||||
const response = await fetch(`${FASTAPI_BASE_URL}/sessions/${sessionId}/treatment`, {
|
||||
method: 'POST',
|
||||
headers: authHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(await readError(response))
|
||||
}
|
||||
|
||||
const result = (await response.json()) as ApiEnvelope<unknown>
|
||||
if (result.code !== 'OK') {
|
||||
throw new Error(result.message || '治疗方案提交失败')
|
||||
}
|
||||
|
||||
return result.data || payload
|
||||
}
|
||||
Reference in New Issue
Block a user