Files
OCS_service/app/components/dashboard/QaRecordsTable.vue
T
2026-05-23 01:49:15 +08:00

216 lines
5.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- app/components/dashboard/QaRecordsTable.vue - 最近问答记录表格基于已准备好的 TableCom -->
<script lang="ts" setup>
import { Eye } from "lucide-vue-next";
import { storeToRefs } from "pinia";
import TableCom from "@/components/Table/TableCom.vue";
import type { TableColumn } from "@/components/Table/type";
import TooltipCom from "@/components/TooltipCom.vue";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from "@/components/ui/card";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue
} from "@/components/ui/select";
import {
DASHBOARD_PAGE_SIZE_OPTIONS,
QUESTION_TYPE_LABELS,
useAnswerStore
} from "@/stores/answer";
import { getOptionLines } from "@/utils";
const answerStore = useAnswerStore();
const {
pagedRecords,
recordCount,
recordsLoading,
recordsPage,
recordsPageSize
} = storeToRefs(answerStore);
/** TableCom 列配置集中在组件顶部,便于和其他项目的表格风格保持一致 */
const columns = computed<TableColumn[]>(() => [
{
label: "时间",
slot: "time",
width: 170
},
{
label: "题型",
slot: "type",
width: 100,
cellAlign: "center",
headerAlign: "center"
},
{
label: "题目",
slot: "question",
minWidth: 280
},
{
label: "选项",
slot: "options",
minWidth: 220
},
{
label: "答案",
slot: "answer",
minWidth: 160
},
{
label: "操作",
slot: "action",
width: 90,
cellAlign: "center",
headerAlign: "center"
}
]);
/** 题型英文值兜底展示原值,避免未来 OCS 扩展题型时表格为空 */
const getQuestionTypeLabel = (type: string) => {
return QUESTION_TYPE_LABELS[type] || type || "自动判断";
};
</script>
<template>
<Card>
<CardHeader>
<div class="flex items-center justify-between gap-4">
<div>
<CardTitle>最近问答记录</CardTitle>
<CardDescription>分页展示按创建时间倒序</CardDescription>
</div>
<Select
:model-value="String(recordsPageSize)"
@update:model-value="(v) => answerStore.setRecordsPageSize(Number(v))"
>
<SelectTrigger class="w-28">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem
v-for="size in DASHBOARD_PAGE_SIZE_OPTIONS"
:key="size"
:value="String(size)"
>
{{ size }} 条/页
</SelectItem>
</SelectContent>
</Select>
</div>
</CardHeader>
<CardContent>
<TableCom
:data="pagedRecords"
:columns="columns"
:load="recordsLoading"
:buffer="true"
:pagination="{
currentPage: recordsPage,
total: recordCount,
pageSize: recordsPageSize,
align: 'end'
}"
cell-align="left"
header-align="start"
cell-class-name="align-top"
@page:change="answerStore.setRecordsPage"
>
<template #time="{ value }">
<span class="whitespace-nowrap text-foreground">{{ value }}</span>
</template>
<template #type="{ value }">
<Badge variant="secondary" class="text-center">
{{ getQuestionTypeLabel(value) }}
</Badge>
</template>
<template #question="{ value }">
<div class="max-w-136 truncate text-foreground" :title="value">
{{ value }}
</div>
</template>
<template #options="{ row }">
<TooltipCom side="top" align="start">
<template #trigger>
<div class="max-w-md cursor-default truncate">
<template v-if="row.options">
<template
v-for="(line, i) in getOptionLines(
row.options,
row.answer ?? ''
)"
:key="i"
>
<span v-if="i > 0" class="text-muted-foreground"
>&nbsp;</span
>
<span
:class="
line.isCorrect
? 'text-green-500 font-medium'
: 'text-muted-foreground'
"
>{{ line.text }}</span
>
</template>
</template>
<span v-else class="text-muted-foreground">-</span>
</div>
</template>
<div
v-if="row.options"
class="max-w-sm whitespace-pre-wrap px-3 py-1 text-xs leading-5"
>
<div
v-for="(line, i) in getOptionLines(
row.options,
row.answer ?? ''
)"
:key="i"
:class="line.isCorrect ? 'text-green-500 font-medium' : ''"
>
{{ line.text }}
</div>
</div>
</TooltipCom>
</template>
<template #answer="{ value }">
<div
class="max-w-[20rem] truncate font-medium text-foreground"
:title="value"
>
{{ value }}
</div>
</template>
<template #action="{ row }">
<Button
type="button"
variant="outline"
size="icon-sm"
title="查看详情"
@click.stop="answerStore.selectRecord(row)"
>
<Eye class="size-4" />
</Button>
</template>
</TableCom>
</CardContent>
</Card>
</template>