Files
OCS_service/app/stores/answer.ts
T
2026-05-23 13:45:58 +08:00

249 lines
7.1 KiB
TypeScript

// 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<string, string> = {
"": "自动判断",
single: "单选题",
multiple: "多选题",
judgement: "判断题",
completion: "填空题"
};
/** OCS AI 答题服务前端状态管理 */
export const useAnswerStore = defineStore("answer", () => {
// ---- 答题表单状态 ----
/** 当前问题内容 */
const question = ref("");
/** 当前问题类型 */
const questionType = ref<QuestionType>("");
/** 当前问题选项 */
const options = ref("");
/** 答题请求加载状态 */
const searchLoading = ref(false);
/** 答题结果 */
const answerResult = ref<ISearchSuccessResponse>();
/** 答题错误文案 */
const searchErrorMessage = ref("");
// ---- Dashboard 状态 ----
/** 健康检查信息 */
const health = ref<IHealthResponse>();
/** 运行统计信息 */
const stats = ref<IStatsResponse>();
/** 最近问答记录 */
const records = ref<IQaRecord[]>([]);
/** 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<IQaRecord>();
/** 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
};
});