249 lines
7.1 KiB
TypeScript
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
|
|
};
|
|
});
|