Files
vueapp/api/assessment.ts
2026-06-11 12:12:55 +08:00

145 lines
3.6 KiB
TypeScript

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 type EvaluationDetail = {
evaluation_id: number
session_id: number
case_id: number
case_title: string
score_type: ScoreType
total_score: number
dimension_scores: DimensionScore[]
score_details: ScoreDetail[]
overall_comment: string
pdf_file_path?: string
created_at?: string
}
export type EvaluationPdfExport = {
export_id: number
file_path: string
}
export type EvaluationPdfDownload = {
blob?: Blob
filePath?: string
fileName: 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
}
export async function fetchEvaluationDetail(evaluationId: number) {
const response = await fetch(`${FASTAPI_BASE_URL}/evaluations/${evaluationId}`, {
method: 'GET',
headers: authHeaders()
})
if (!response.ok) {
throw new Error(await readError(response))
}
const result = (await response.json()) as ApiEnvelope<EvaluationDetail>
if (result.code !== 'OK' || !result.data) {
throw new Error(result.message || '评价详情加载失败')
}
return result.data
}
export async function downloadEvaluationPdf(evaluationId: number): Promise<EvaluationPdfDownload> {
const response = await fetch(`${FASTAPI_BASE_URL}/evaluations/${evaluationId}/download-pdf`, {
method: 'GET',
headers: authHeaders('application/pdf')
})
if (!response.ok) {
throw new Error(await readError(response))
}
const contentType = response.headers.get('Content-Type') || ''
const disposition = response.headers.get('Content-Disposition') || ''
const fileName = readDownloadFileName(disposition, evaluationId)
if (contentType.includes('application/json')) {
const result = (await response.json()) as ApiEnvelope<EvaluationPdfExport>
if (result.code !== 'OK' || !result.data?.file_path) {
throw new Error(result.message || 'PDF 下载失败')
}
return {
filePath: result.data.file_path,
fileName: readFileNameFromPath(result.data.file_path, fileName)
}
}
return {
blob: await response.blob(),
fileName
}
}
function readDownloadFileName(disposition: string, evaluationId: number) {
const utf8Name = disposition.match(/filename\*=UTF-8''([^;]+)/i)?.[1]
if (utf8Name) return decodeURIComponent(utf8Name)
const quotedName = disposition.match(/filename="?([^"]+)"?/i)?.[1]
if (quotedName) return quotedName
return `training_record_${evaluationId}.pdf`
}
function readFileNameFromPath(filePath: string, fallback: string) {
const cleanPath = filePath.split('?')[0].split('#')[0]
const name = cleanPath.split('/').filter(Boolean).pop()
return name || fallback
}