From e3e6db2d9974588f91ac1567a58fa4846655ce1b Mon Sep 17 00:00:00 2001
From: yearning <10538594+wangweifeng1999@user.noreply.gitee.com>
Date: 星期三, 30 九月 2026 12:54:55 +0800
Subject: [PATCH] 1.判断题优化;2.新增考评员是否能查看考生隐私开关
---
frontend/src/pages/AttemptReviewPage.tsx | 61 +++++++++++++++++++++++++-----
1 files changed, 50 insertions(+), 11 deletions(-)
diff --git a/frontend/src/pages/AttemptReviewPage.tsx b/frontend/src/pages/AttemptReviewPage.tsx
index 7e503ff..23e6503 100644
--- a/frontend/src/pages/AttemptReviewPage.tsx
+++ b/frontend/src/pages/AttemptReviewPage.tsx
@@ -20,6 +20,8 @@
readScoreListQuery,
type ScoreListQuery,
} from "../scoreQueryParams";
+import { useSystemSettings } from "../systemSettings";
+import type { UserMe } from "../App";
import "./AttemptReviewPage.css";
const { useBreakpoint } = Grid;
@@ -30,6 +32,7 @@
type Q = {
external_item_id: string;
part_name?: string;
+ item_type?: number;
item_order?: number;
title_html?: string;
detail_json?: string;
@@ -44,6 +47,7 @@
type Attempt = {
attempt_id: string;
+ student_no?: string;
examinee_name?: string;
id_card?: string;
score: number;
@@ -61,6 +65,17 @@
function stripHtml(html: string) {
return html.replace(/<[^>]+>/g, "");
+}
+
+/** 鍒ゆ柇棰樼瓟妗堟牸寮忓寲锛歍鈫掓纭紙A锛夛紝F鈫掗敊璇紙B锛� */
+function formatAnswer(raw: string | undefined, itemType?: number): string {
+ if (!raw) return "鈥�";
+ if (itemType === 320) {
+ const s = raw.trim().toUpperCase();
+ if (s === "T" || s === "A") return "姝g‘锛圓锛�";
+ if (s === "F" || s === "B") return "閿欒锛圔锛�";
+ }
+ return raw;
}
function isAnswered(q: Q) {
@@ -197,6 +212,7 @@
attempt_id: string;
name: string;
id_card: string;
+ student_no: string;
subject_name: string;
score: number;
};
@@ -206,11 +222,13 @@
function AttemptRoster({
activeAttemptId,
listQuery,
+ hidePrivacy,
onSelectAttempt,
onSearch,
}: {
activeAttemptId: string;
listQuery: ScoreListQuery;
+ hidePrivacy: boolean;
onSelectAttempt: (attemptId: string) => void;
onSearch: (filters: Pick<ScoreListQuery, "name" | "id_card" | "subject">) => void;
}) {
@@ -303,12 +321,16 @@
wrapperCol={{ flex: "1 1 0" }}
onFinish={(v) => onSearch(v)}
>
- <Form.Item name="name" label="濮撳悕" className="attempt-review__roster-field">
- <Input allowClear />
- </Form.Item>
- <Form.Item name="id_card" label="璇佷欢鍙�" className="attempt-review__roster-field">
- <Input allowClear />
- </Form.Item>
+ {!hidePrivacy && (
+ <>
+ <Form.Item name="name" label="濮撳悕" className="attempt-review__roster-field">
+ <Input allowClear />
+ </Form.Item>
+ <Form.Item name="id_card" label="璇佷欢鍙�" className="attempt-review__roster-field">
+ <Input allowClear />
+ </Form.Item>
+ </>
+ )}
<Form.Item name="subject" label="绉戠洰" className="attempt-review__roster-field">
<Select allowClear options={subjects.map((s) => ({ value: s, label: s }))} />
</Form.Item>
@@ -330,7 +352,7 @@
if (row.attempt_id !== activeAttemptId) onSelectAttempt(row.attempt_id);
}}
>
- <div className="attempt-review__roster-name">{row.name || "鈥�"}</div>
+ <div className="attempt-review__roster-name">{hidePrivacy ? row.student_no : (row.name || "鈥�")}</div>
<div className="attempt-review__roster-meta">
<span>{row.score} 鍒�</span>
<span className="attempt-review__roster-subject">{row.subject_name}</span>
@@ -359,6 +381,17 @@
const detailScrollRef = useRef<HTMLDivElement>(null);
const screens = useBreakpoint();
const isWide = !!screens.lg;
+ const { settings } = useSystemSettings();
+ const [user, setUser] = useState<UserMe | null>(null);
+
+ const hidePrivacy = user?.role === "grader" && !settings.grader_can_see_privacy;
+
+ useEffect(() => {
+ api
+ .get<UserMe>("/api/auth/me")
+ .then((r) => setUser(r.data))
+ .catch(() => setUser(null));
+ }, []);
const selectAttempt = useCallback(
(id: string) => {
@@ -491,8 +524,8 @@
<li key={opt.identifier}>{opt.identifier}. {stripHtml(opt.text)}</li>
))}
</ul>
- <p>鑰冪敓绛旀锛歿q.user_answer || "鈥�"}</p>
- <p>鍙傝�冪瓟妗堬細{q.reference_answer || "鈥�"}</p>
+ <p>鑰冪敓绛旀锛歿formatAnswer(q.user_answer, q.item_type)}</p>
+ <p>鍙傝�冪瓟妗堬細{formatAnswer(q.reference_answer, q.item_type)}</p>
<p>
{q.is_correct ? <Tag color="success">姝g‘</Tag> : <Tag color="error">閿欒</Tag>}
寰楀垎锛歿q.score} / {q.max_score ?? 1}
@@ -515,8 +548,13 @@
{data && (
<Card className="attempt-review__header" size="small">
<Descriptions column={{ xs: 1, sm: 2 }} size="small">
- <Descriptions.Item label="濮撳悕">{data.examinee_name}</Descriptions.Item>
- <Descriptions.Item label="璇佷欢鍙�">{data.id_card}</Descriptions.Item>
+ <Descriptions.Item label="鑰冪敓缂栧彿">{data.student_no}</Descriptions.Item>
+ {!hidePrivacy && (
+ <>
+ <Descriptions.Item label="濮撳悕">{data.examinee_name}</Descriptions.Item>
+ <Descriptions.Item label="璇佷欢鍙�">{data.id_card}</Descriptions.Item>
+ </>
+ )}
<Descriptions.Item label="绉戠洰">{data.subject_name}</Descriptions.Item>
<Descriptions.Item label="鎬诲垎">{data.score} / {data.paper_total_score}</Descriptions.Item>
<Descriptions.Item label="璇曞嵎">{data.paper_name}</Descriptions.Item>
@@ -562,6 +600,7 @@
<AttemptRoster
activeAttemptId={attemptId}
listQuery={listQuery}
+ hidePrivacy={hidePrivacy}
onSelectAttempt={selectAttempt}
onSearch={searchRoster}
/>
--
Gitblit v1.8.0