// app/stores/answer.ts - 答题页和 Dashboard 的统一状态管理 import { defineStore } from "pinia"; import { toast } from "vue-sonner"; import type { IQaRecord, ISearchSuccessResponse, QuestionType } from "@/interfaces"; import { AnswerService } from "@/services"; import { 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 records = ref([]); /** Dashboard 错误文案 */ const dashboardErrorMessage = ref(""); /** 最近问答记录加载状态 */ 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); /** 选择表格记录,交给详情弹窗展示完整题目、选项和答案 */ 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 getRecords(); return; } searchErrorMessage.value = res.data.msg || "答题失败"; toast.error(searchErrorMessage.value); } catch (error) { searchErrorMessage.value = getClientErrorMessage(error, "服务器内部错误"); toast.error(searchErrorMessage.value); } finally { searchLoading.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, "问答记录读取失败" ); toast.error(dashboardErrorMessage.value); } finally { recordsLoading.value = false; } }; /** Dashboard 首次加载时拉取最近记录 */ const loadDashboard = async () => { dashboardErrorMessage.value = ""; await getRecords(); }; /** 清空缓存后刷新统计与表格;$fetch 非 2xx 时会抛出,错误由 catch 处理 */ const clearCache = async () => { cacheClearing.value = true; dashboardErrorMessage.value = ""; try { await AnswerService.clearCache(); toast.success("缓存已清空"); await getRecords(1); } catch (error) { dashboardErrorMessage.value = getClientErrorMessage( error, "缓存清理失败" ); toast.error(dashboardErrorMessage.value); } finally { cacheClearing.value = false; } }; return { question, questionType, options, searchLoading, answerResult, searchErrorMessage, records, dashboardErrorMessage, recordsLoading, cacheClearing, recordsPage, recordsPageSize, selectedRecord, pagedRecords, recordCount, searchAnswer, getRecords, loadDashboard, clearCache, selectRecord, setRecordsPage, setRecordsPageSize }; });