// app/stores/answer.ts - 答题页和 Dashboard 的统一状态管理 import { defineStore } from "pinia"; import type { IHealthResponse, IQaRecord, ISearchSuccessResponse, IStatsResponse, QuestionType } from "@/interfaces"; import { AnswerService } from "@/services"; import { formatUptime, getClientErrorMessage } from "~/utils"; /** Dashboard 最近记录表格每页数量,组件直接复用,避免多个地方写死 */ export const DASHBOARD_RECORD_PAGE_SIZE = 10; /** 分页大小可选列表,与后端白名单保持一致 */ export const DASHBOARD_PAGE_SIZE_OPTIONS = [10, 50, 100] as const; /** 题型下拉选项,value 保持 OCS / 旧 Python 服务使用的英文值 */ export const QUESTION_TYPE_OPTIONS: Array<{ label: string; value: QuestionType; }> = [ { label: "自动判断", value: "" }, { label: "单选题", value: "single" }, { label: "多选题", value: "multiple" }, { label: "判断题", value: "judgement" }, { label: "填空题", value: "completion" } ]; /** 题型展示文案,Dashboard 表格用它把英文值转成本地业务表达 */ export const QUESTION_TYPE_LABELS: Record = { "": "自动判断", single: "单选题", multiple: "多选题", judgement: "判断题", completion: "填空题" }; /** OCS AI 答题服务前端状态管理 */ export const useAnswerStore = defineStore("answer", () => { // ---- 答题表单状态 ---- /** 当前问题内容 */ const question = ref(""); /** 当前问题类型 */ const questionType = ref(""); /** 当前问题选项 */ const options = ref(""); /** 答题请求加载状态 */ const searchLoading = ref(false); /** 答题结果 */ const answerResult = ref(); /** 答题错误文案 */ const searchErrorMessage = ref(""); // ---- Dashboard 状态 ---- /** 健康检查信息 */ const health = ref(); /** 运行统计信息 */ const stats = ref(); /** 最近问答记录 */ const records = ref([]); /** Dashboard 错误文案 */ const dashboardErrorMessage = ref(""); /** 统计信息加载状态 */ const statsLoading = ref(false); /** 最近问答记录加载状态 */ const recordsLoading = ref(false); /** 缓存清理状态 */ const cacheClearing = ref(false); /** 最近问答记录当前页码 */ const recordsPage = ref(1); /** 最近问答记录每页数量 */ const recordsPageSize = ref(DASHBOARD_RECORD_PAGE_SIZE); /** 最近问答记录总数 */ const recordCount = ref(0); /** 当前选中的问答记录 */ const selectedRecord = ref(); /** Dashboard 表格当前页数据,页码切换会重新请求服务端分页接口 */ const pagedRecords = computed(() => records.value); /** Dashboard 顶部运行时长展示 */ const uptimeText = computed(() => { return stats.value ? formatUptime(stats.value.uptime) : "-"; }); /** 选择表格记录,交给详情弹窗展示完整题目、选项和答案 */ const selectRecord = (record?: IQaRecord) => { selectedRecord.value = record; }; /** 切换最近记录表格页码,并请求对应页数据 */ const setRecordsPage = async (page: number) => { if (recordsLoading.value || page === recordsPage.value) return; await getRecords(page); }; /** 切换分页大小,重置到第 1 页后重新请求 */ const setRecordsPageSize = async (size: number) => { if (recordsLoading.value || size === recordsPageSize.value) return; recordsPageSize.value = size; await getRecords(1); }; /** 调用答题 API,返回 OCS 兼容结构但只在 store 中维护 UI 状态 */ const searchAnswer = async () => { const title = question.value.trim(); const requestOptions = options.value.trim(); answerResult.value = undefined; searchErrorMessage.value = ""; if (!title) { searchErrorMessage.value = "未提供问题内容"; return; } searchLoading.value = true; try { const res = await AnswerService.search({ title, type: questionType.value, options: requestOptions }); if (res.data.code === 1) { answerResult.value = res.data; recordsPage.value = 1; await Promise.allSettled([getStats(), getRecords()]); return; } searchErrorMessage.value = res.data.msg || "答题失败"; } catch (error) { searchErrorMessage.value = getClientErrorMessage(error, "服务器内部错误"); } finally { searchLoading.value = false; } }; /** 读取健康检查,失败时只写本地错误文案 */ const getHealth = async () => { try { const res = await AnswerService.getHealth(); health.value = res.data.data; } catch (error) { dashboardErrorMessage.value = getClientErrorMessage( error, "健康检查失败" ); } }; /** 读取运行统计 */ const getStats = async () => { statsLoading.value = true; try { const res = await AnswerService.getStats(); stats.value = res.data.data; } catch (error) { dashboardErrorMessage.value = getClientErrorMessage( error, "统计信息读取失败" ); } finally { statsLoading.value = false; } }; /** 读取最近问答记录;服务端按 page/size 返回当前页数据 */ const getRecords = async (page = recordsPage.value) => { recordsLoading.value = true; try { const res = await AnswerService.getRecords({ page, size: recordsPageSize.value }); records.value = res.data.data.records; recordsPage.value = res.data.data.page; recordsPageSize.value = res.data.data.size; recordCount.value = res.data.data.total; } catch (error) { dashboardErrorMessage.value = getClientErrorMessage( error, "问答记录读取失败" ); } finally { recordsLoading.value = false; } }; /** Dashboard 首次加载时并行拉取运行状态、统计和最近记录 */ const loadDashboard = async () => { dashboardErrorMessage.value = ""; await Promise.allSettled([getHealth(), getStats(), getRecords()]); }; /** 清空缓存后刷新统计与表格;$fetch 非 2xx 时会抛出,错误由 catch 处理 */ const clearCache = async () => { cacheClearing.value = true; dashboardErrorMessage.value = ""; try { await AnswerService.clearCache(); await Promise.allSettled([getStats(), getRecords(1)]); } catch (error) { dashboardErrorMessage.value = getClientErrorMessage( error, "缓存清理失败" ); } finally { cacheClearing.value = false; } }; return { question, questionType, options, searchLoading, answerResult, searchErrorMessage, health, stats, records, dashboardErrorMessage, statsLoading, recordsLoading, cacheClearing, recordsPage, recordsPageSize, selectedRecord, pagedRecords, recordCount, uptimeText, searchAnswer, getHealth, getStats, getRecords, loadDashboard, clearCache, selectRecord, setRecordsPage, setRecordsPageSize }; });