From e479cb94ea4154fb88393f41903fae265f254f4c Mon Sep 17 00:00:00 2001 From: undefined Date: Mon, 30 Jun 2025 16:46:33 +0800 Subject: [PATCH] core&ui: contest correction mode --- README.md | 4 ++-- packages/hydrooj/src/handler/contest.ts | 11 +++++++++- packages/hydrooj/src/handler/problem.ts | 6 ++++- packages/ui-default/locales/zh.yaml | 2 ++ packages/ui-default/pages/contest.page.styl | 4 ++-- .../templates/contest_problemlist.html | 22 ++++++++++++++++--- .../partials/problem_description.html | 8 ++++++- .../partials/problem_sidebar_contest.html | 7 +++--- .../partials/problem_sidebar_normal.html | 2 +- .../ui-default/templates/problem_detail.html | 6 +++-- 10 files changed, 56 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3fca1a046..85479b219 100644 --- a/README.md +++ b/README.md @@ -143,11 +143,11 @@ Hydro 用户群:1085853538 - framework: 添加 Subscription API - core: 添加 fixStorage 脚本 - core: websocket: 重构 Subscription API -- ui: 允许跨页选择题目 +- ui: 允许跨页选择题目,支持批量选择题目 - judge: 重构 config.detail 设置 - core: 自动清理多余的静态文件 - ui: 优化比赛题目列表显示 - +- core: 添加补题模式 ### Bug Fixes diff --git a/packages/hydrooj/src/handler/contest.ts b/packages/hydrooj/src/handler/contest.ts index f3182713a..e3a274eda 100644 --- a/packages/hydrooj/src/handler/contest.ts +++ b/packages/hydrooj/src/handler/contest.ts @@ -207,9 +207,18 @@ export class ContestProblemListHandler extends ContestDetailBaseHandler { const psdocs: any[] = Object.values(this.response.body.psdict); const canViewRecord = contest.canShowSelfRecord.call(this, this.tdoc); this.response.body.canViewRecord = canViewRecord; + const rids = psdocs.map((i) => i.rid); + if (contest.isDone(this.tdoc) && canViewRecord) { + const correction = await problem.getListStatus(domainId, this.user._id, this.tdoc.pids); + for (const pid in correction) { + if (this.tsdoc.detail[pid]?.rid === correction[pid].rid) delete correction[pid]; + } + rids.push(...Object.values(correction).map((i) => i.rid)); + this.response.body.correction = correction; + } [this.response.body.rdict, this.response.body.rdocs] = canViewRecord ? await Promise.all([ - record.getList(domainId, psdocs.map((i: any) => i.rid)), + record.getList(domainId, rids), record.getMulti(domainId, { contest: tid, uid: this.user._id }) .sort({ _id: -1 }).toArray(), ]) diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index fc38ef699..c7ee4bb66 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -334,6 +334,10 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler { discussionCount: dcnt, tdoc: this.tdoc, owner_udoc: (tid && this.tdoc.owner !== this.pdoc.owner) ? await user.getById(domainId, this.tdoc.owner) : null, + mode: !tid ? 'normal' + : !this.tsdoc?.attend ? 'view' + : !contest.isDone(this.tdoc) ? 'contest' + : problem.canViewBy(this.pdoc, this.user) ? 'correction' : 'none', }; if (this.tdoc && this.tsdoc) { const fields = ['attend', 'startAt']; @@ -802,7 +806,7 @@ export class ProblemFileDownloadHandler extends ProblemDetailHandler { @param('filename', Types.Filename) @param('noDisposition', Types.Boolean) @query('tid', Types.ObjectId, true) - async get(domainId: string, type = 'additional_file', filename: string, noDisposition = false, tid: ObjectId) { + async get({ }, type = 'additional_file', filename: string, noDisposition = false, tid: ObjectId) { if (!tid) this.checkPerm(PERM.PERM_VIEW_PROBLEM); if (this.pdoc.reference) { if (type === 'testdata') throw new ProblemIsReferencedError('download testdata'); diff --git a/packages/ui-default/locales/zh.yaml b/packages/ui-default/locales/zh.yaml index 5c24d912f..dfe0e7e17 100644 --- a/packages/ui-default/locales/zh.yaml +++ b/packages/ui-default/locales/zh.yaml @@ -223,6 +223,7 @@ Copy Selected: 复制选中 Copy WeChat Account: 复制微信号 Copy: 复制 Copyright Complaint: 版权申诉 +Correction: 补题 CPU Info: CPU信息 Create a contest: 创建一个比赛 Create a Discussion: 创建一个讨论 @@ -914,6 +915,7 @@ Testdata: 测试数据 Text: 文本 The 'default' role applies to ALL REGISTERED USER.: default 角色作用于所有已注册用户 The contest is a flexible time contest. You need to complete the contest within a specified time after you attended.: 本场比赛采用灵活时间模式,你需要在参加后的指定时间内完成比赛。 +The contest is ended. New submissions will be treated as correction submissions and will not be counted in the contest.: 比赛已经结束。新提交将被视为补题提交,不计入比赛成绩。 The group to join when user joining the domain.: 加入域时自动加入的小组。 The homework's deadline is due but in extension. You can still submit for this problem but your score will be penalized.: 作业已超过截止时间,但仍在延期时间内。您递交题目将无法获得全部分数。 The invitation code to enter to successfully join the domain. You can only use letters and numbers in the code and it should not be longer than 64 characters.: 加入此域的邀请码。您只能使用字母和数字,并且不能长于 64 个字符。 diff --git a/packages/ui-default/pages/contest.page.styl b/packages/ui-default/pages/contest.page.styl index 28f355df6..b61b85aa9 100644 --- a/packages/ui-default/pages/contest.page.styl +++ b/packages/ui-default/pages/contest.page.styl @@ -110,7 +110,7 @@ $highlight-button-color = #F6DF45 width: auto .page--contest_problemlist - .col--status + .col--status, .col--correction width: rem(150px) .col--submit-at @@ -128,7 +128,7 @@ $highlight-button-color = #F6DF45 border-left: 1px solid $table-border-color +mobile() - .col--submit-at + .col--submit-at, .col--correction display: none +tablet() diff --git a/packages/ui-default/templates/contest_problemlist.html b/packages/ui-default/templates/contest_problemlist.html index d50f07838..cf90d0ece 100644 --- a/packages/ui-default/templates/contest_problemlist.html +++ b/packages/ui-default/templates/contest_problemlist.html @@ -5,6 +5,7 @@ {% block content %} {{ set(UiContext, 'tdoc', tdoc) }} {{ set(UiContext, 'tsdoc', tsdoc) }} +{% set hasCorrection = correction and Object.keys(correction).length %}
@@ -27,7 +28,11 @@ {% if handler.user.hasPriv(PRIV.PRIV_USER_PROFILE) %} {{ _('Status') }} - {{ _('Last Submit At') }} + {% if hasCorrection %} + {{ _('Correction') }} + {% else %} + {{ _('Last Submit At') }} + {% endif %} {% endif %} {% if showScore %} {{ _('Score') }} @@ -47,10 +52,21 @@ {% else %} {{ _('Submitted') }} {% endif %} - {{ datetimeSpan(rdoc._id)|safe }} + {% if not hasCorrection %} + {{ datetimeSpan(rdoc._id)|safe }} + {% endif %} {% else %} {{ _('No Submissions') }} - - + {% if not hasCorrection %} + - + {% endif %} + {% endif %} + {% if hasCorrection %} + {% if correction[pid] %} + {{ record.render_status_td(rdict[correction[pid].rid], class="col--correction") }} + {% else %} + - + {% endif %} {% endif %} {% endif %} {% if showScore %} diff --git a/packages/ui-default/templates/partials/problem_description.html b/packages/ui-default/templates/partials/problem_description.html index 9fd8c50f9..b56d4e189 100644 --- a/packages/ui-default/templates/partials/problem_description.html +++ b/packages/ui-default/templates/partials/problem_description.html @@ -14,10 +14,16 @@

{{ _('No submission language available for this problem.') }}

{% endif %} - {% if tdoc and tdoc.docType == model.document.TYPE_CONTEST and model.contest.isDone(tdoc) %} + {% if tdoc and tdoc.docType == model.document.TYPE_CONTEST %} + {% if mode == 'view' %}

{{ _('You cannot submit for this problem because the contest is ended. You can click "Open in Problem Set" to view this problem in normal mode.') }}

+ {% elif mode == 'correction' %} +
+

{{ _('The contest is ended. New submissions will be treated as correction submissions and will not be counted in the contest.') }}

+
+ {% endif %} {% endif %} {% if not renderredContent %} {% set preferredLang = handler.request.query.lang or handler.user.viewLang or handler.session.viewLang %} diff --git a/packages/ui-default/templates/partials/problem_sidebar_contest.html b/packages/ui-default/templates/partials/problem_sidebar_contest.html index d93a5e5be..1200aa2d8 100644 --- a/packages/ui-default/templates/partials/problem_sidebar_contest.html +++ b/packages/ui-default/templates/partials/problem_sidebar_contest.html @@ -7,7 +7,7 @@ {% endif %}