mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
core&ui: optimize scoreboard nAccept and nSubmit calculation
This commit is contained in:
1 parent
d9fdcc9b7c
commit
6ddaa8cf0c
6 files changed
+63
-33
No files matched your search
@@ -236,11 +236,7 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
|
|||||||
await this.exportScoreboard(domainId, tid, ext);
|
await this.exportScoreboard(domainId, tid, ext);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const pdict = await problem.getList(domainId, this.tdoc.pids, true, undefined, false, [
|
const [, rows, udict, pdict] = await contest.getScoreboard.call(this, domainId, tid, false);
|
||||||
// Problem statistics display is allowed as we can view submission info in scoreboard.
|
|
||||||
...problem.PROJECTION_CONTEST_LIST, 'nSubmit', 'nAccept',
|
|
||||||
]);
|
|
||||||
const [, rows, udict] = await contest.getScoreboard.call(this, domainId, tid, false);
|
|
||||||
this.response.template = 'contest_scoreboard.html';
|
this.response.template = 'contest_scoreboard.html';
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
const page_name = this.tdoc.rule === 'homework'
|
const page_name = this.tdoc.rule === 'homework'
|
||||||
|
|||||||
@@ -352,8 +352,6 @@ export interface Tdoc<docType = document['TYPE_CONTEST'] | document['TYPE_TRAINI
|
|||||||
assign?: string[];
|
assign?: string[];
|
||||||
files?: FileInfo[];
|
files?: FileInfo[];
|
||||||
allowViewCode?: boolean;
|
allowViewCode?: boolean;
|
||||||
nSubmit?: Record<number, number>;
|
|
||||||
nAccept?: Record<number, number>;
|
|
||||||
|
|
||||||
// For contest
|
// For contest
|
||||||
lockAt?: Date;
|
lockAt?: Date;
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ const acm = buildContestRule({
|
|||||||
columns.push({ type: 'solved', value: `${_('Solved')}\n${_('Total Time')}` });
|
columns.push({ type: 'solved', value: `${_('Solved')}\n${_('Total Time')}` });
|
||||||
for (let i = 1; i <= tdoc.pids.length; i++) {
|
for (let i = 1; i <= tdoc.pids.length; i++) {
|
||||||
const pid = tdoc.pids[i - 1];
|
const pid = tdoc.pids[i - 1];
|
||||||
|
pdict[pid].nAccept = pdict[pid].nSubmit = 0;
|
||||||
if (isExport) {
|
if (isExport) {
|
||||||
columns.push(
|
columns.push(
|
||||||
{
|
{
|
||||||
@@ -134,6 +135,11 @@ const acm = buildContestRule({
|
|||||||
value: `${tsdoc.accept || 0}\n${formatSeconds(tsdoc.time || 0.0, false)}`,
|
value: `${tsdoc.accept || 0}\n${formatSeconds(tsdoc.time || 0.0, false)}`,
|
||||||
hover: formatSeconds(tsdoc.time || 0.0),
|
hover: formatSeconds(tsdoc.time || 0.0),
|
||||||
});
|
});
|
||||||
|
for (const s of tsdoc.journal || []) {
|
||||||
|
if (!pdict[s.pid]) continue;
|
||||||
|
pdict[s.pid].nSubmit++;
|
||||||
|
if (s.status === STATUS.STATUS_ACCEPTED) pdict[s.pid].nAccept++;
|
||||||
|
}
|
||||||
for (const pid of tdoc.pids) {
|
for (const pid of tdoc.pids) {
|
||||||
const doc = tsddict[pid] || {} as Partial<AcmDetail>;
|
const doc = tsddict[pid] || {} as Partial<AcmDetail>;
|
||||||
const accept = doc.status === STATUS.STATUS_ACCEPTED;
|
const accept = doc.status === STATUS.STATUS_ACCEPTED;
|
||||||
@@ -231,6 +237,8 @@ const oi = buildContestRule({
|
|||||||
}
|
}
|
||||||
columns.push({ type: 'total_score', value: _('Total Score') });
|
columns.push({ type: 'total_score', value: _('Total Score') });
|
||||||
for (let i = 1; i <= tdoc.pids.length; i++) {
|
for (let i = 1; i <= tdoc.pids.length; i++) {
|
||||||
|
const pid = tdoc.pids[i - 1];
|
||||||
|
pdict[pid].nAccept = pdict[pid].nSubmit = 0;
|
||||||
if (isExport) {
|
if (isExport) {
|
||||||
columns.push({
|
columns.push({
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@@ -259,6 +267,11 @@ const oi = buildContestRule({
|
|||||||
row.push({ type: 'string', value: udoc.studentId || '' });
|
row.push({ type: 'string', value: udoc.studentId || '' });
|
||||||
}
|
}
|
||||||
row.push({ type: 'total_score', value: tsdoc.score || 0 });
|
row.push({ type: 'total_score', value: tsdoc.score || 0 });
|
||||||
|
for (const s of tsdoc.journal || []) {
|
||||||
|
if (!pdict[s.pid]) continue;
|
||||||
|
pdict[s.pid].nSubmit++;
|
||||||
|
if (s.status === STATUS.STATUS_ACCEPTED) pdict[s.pid].nAccept++;
|
||||||
|
}
|
||||||
for (const pid of tdoc.pids) {
|
for (const pid of tdoc.pids) {
|
||||||
const index = `${tsdoc.uid}/${tdoc.domainId}/${pid}`;
|
const index = `${tsdoc.uid}/${tdoc.domainId}/${pid}`;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||||
@@ -395,6 +408,7 @@ const homework = buildContestRule({
|
|||||||
columns.push({ type: 'time', value: _('Total Time') });
|
columns.push({ type: 'time', value: _('Total Time') });
|
||||||
for (let i = 1; i <= tdoc.pids.length; i++) {
|
for (let i = 1; i <= tdoc.pids.length; i++) {
|
||||||
const pid = tdoc.pids[i - 1];
|
const pid = tdoc.pids[i - 1];
|
||||||
|
pdict[pid].nAccept = pdict[pid].nSubmit = 0;
|
||||||
if (isExport) {
|
if (isExport) {
|
||||||
columns.push(
|
columns.push(
|
||||||
{
|
{
|
||||||
@@ -438,6 +452,11 @@ const homework = buildContestRule({
|
|||||||
row.push({ type: 'string', value: tsdoc.score || 0 });
|
row.push({ type: 'string', value: tsdoc.score || 0 });
|
||||||
}
|
}
|
||||||
row.push({ type: 'time', value: formatSeconds(tsdoc.time || 0, false), raw: tsdoc.time });
|
row.push({ type: 'time', value: formatSeconds(tsdoc.time || 0, false), raw: tsdoc.time });
|
||||||
|
for (const s of tsdoc.journal || []) {
|
||||||
|
if (!pdict[s.pid]) continue;
|
||||||
|
pdict[s.pid].nSubmit++;
|
||||||
|
if (s.status === STATUS.STATUS_ACCEPTED) pdict[s.pid].nAccept++;
|
||||||
|
}
|
||||||
for (const pid of tdoc.pids) {
|
for (const pid of tdoc.pids) {
|
||||||
const rid = tsddict[pid]?.rid;
|
const rid = tsddict[pid]?.rid;
|
||||||
const colScore = tsddict[pid]?.penaltyScore ?? '';
|
const colScore = tsddict[pid]?.penaltyScore ?? '';
|
||||||
@@ -536,11 +555,7 @@ export async function getRelated(domainId: string, pid: number, rule?: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getStatus(domainId: string, tid: ObjectID, uid: number) {
|
export async function getStatus(domainId: string, tid: ObjectID, uid: number) {
|
||||||
const [tdoc, status] = await Promise.all([
|
return await document.getStatus(domainId, document.TYPE_CONTEST, tid, uid);
|
||||||
get(domainId, tid),
|
|
||||||
document.getStatus(domainId, document.TYPE_CONTEST, tid, uid),
|
|
||||||
]);
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _updateStatus(tdoc: Tdoc<30>, uid: number, rid: ObjectID, pid: number, status: STATUS, score: number) {
|
async function _updateStatus(tdoc: Tdoc<30>, uid: number, rid: ObjectID, pid: number, status: STATUS, score: number) {
|
||||||
@@ -702,7 +717,7 @@ export async function getScoreboard(
|
|||||||
const tdoc = await get(domainId, tid);
|
const tdoc = await get(domainId, tid);
|
||||||
if (!canShowScoreboard.call(this, tdoc)) throw new ContestScoreboardHiddenError(tid);
|
if (!canShowScoreboard.call(this, tdoc)) throw new ContestScoreboardHiddenError(tid);
|
||||||
const tsdocsCursor = getMultiStatus(domainId, { docId: tid }).sort(RULES[tdoc.rule].statusSort);
|
const tsdocsCursor = getMultiStatus(domainId, { docId: tid }).sort(RULES[tdoc.rule].statusSort);
|
||||||
const pdict = await problem.getList(domainId, tdoc.pids, true);
|
const pdict = await problem.getList(domainId, tdoc.pids, true, problem.PROJECTION_CONTEST_DETAIL);
|
||||||
const [rows, udict] = await RULES[tdoc.rule].scoreboard(
|
const [rows, udict] = await RULES[tdoc.rule].scoreboard(
|
||||||
isExport, this.translate.bind(this),
|
isExport, this.translate.bind(this),
|
||||||
tdoc, pdict, tsdocsCursor,
|
tdoc, pdict, tsdocsCursor,
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
.page--contest_scoreboard
|
.page--contest_scoreboard
|
||||||
|
.main
|
||||||
|
.row
|
||||||
|
max-width: 100vw !important;
|
||||||
|
|
||||||
.col--rank
|
.col--rank
|
||||||
width: rem(60px)
|
width: rem(60px)
|
||||||
text-align: center
|
text-align: center
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
.page--homework_scoreboard
|
.page--homework_scoreboard
|
||||||
|
.main
|
||||||
|
.row
|
||||||
|
max-width: 100vw !important;
|
||||||
|
|
||||||
.col--rank
|
.col--rank
|
||||||
width: rem(60px)
|
width: rem(60px)
|
||||||
text-align: center
|
text-align: center
|
||||||
|
|||||||
@@ -2,6 +2,18 @@
|
|||||||
{% extends "layout/basic.html" %}
|
{% extends "layout/basic.html" %}
|
||||||
{{ set(UiContext, 'tdoc', tdoc) }}
|
{{ set(UiContext, 'tdoc', tdoc) }}
|
||||||
{% set type = 'homework' if tdoc.rule == 'homework' else 'contest' %}
|
{% set type = 'homework' if tdoc.rule == 'homework' else 'contest' %}
|
||||||
|
|
||||||
|
{% macro renderRecord(cell, canView) %}
|
||||||
|
<a href="{{ url('record_detail', rid=cell.raw) if canView else '' }}"{% if cell.hover %} data-tooltip="{{ cell.hover }}"{% endif %}>
|
||||||
|
{%- if cell.status == status.STATUS_JUDGING -%}
|
||||||
|
<span style="font-weight:bold;color:yellow">?</span>
|
||||||
|
{%- else -%}
|
||||||
|
{%- set _color = utils.status.getScoreColor(cell.score|default(cell.value)) -%}
|
||||||
|
<span style="font-weight:bold;color:{{ _color }}">{{ cell.value|string|nl2br|safe }}</span>
|
||||||
|
{%- endif -%}
|
||||||
|
</a>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row"><div class="medium-12 columns scoreboard--{{ tdoc.rule }}">
|
<div class="row"><div class="medium-12 columns scoreboard--{{ tdoc.rule }}">
|
||||||
<div class="section visible">
|
<div class="section visible">
|
||||||
@@ -12,7 +24,7 @@
|
|||||||
<a class="button" href="{{ url(type + '_scoreboard_download', tid=tdoc.docId, ext='csv') }}">
|
<a class="button" href="{{ url(type + '_scoreboard_download', tid=tdoc.docId, ext='csv') }}">
|
||||||
<span class="icon icon-download"></span> {{ _('Export as CSV') }}
|
<span class="icon icon-download"></span> {{ _('Export as CSV') }}
|
||||||
</a>
|
</a>
|
||||||
{% if model.contest.isEnded(tdoc) and tdoc.lockAt and handler.user.own(tdoc) and not tdoc.unlocked %}
|
{% if model.contest.isDone(tdoc) and tdoc.lockAt and handler.user.own(tdoc) and not tdoc.unlocked %}
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input type="hidden" name="operation" value="unlock">
|
<input type="hidden" name="operation" value="unlock">
|
||||||
<button type="submit" class="button" href="{{ url(type + '_scoreboard_download', tid=tdoc.docId, ext='csv') }}">
|
<button type="submit" class="button" href="{{ url(type + '_scoreboard_download', tid=tdoc.docId, ext='csv') }}">
|
||||||
@@ -27,7 +39,7 @@
|
|||||||
{{ _('Scoreboard locked at {0}').format(datetimeSpan(tdoc.lockAt))|safe }}
|
{{ _('Scoreboard locked at {0}').format(datetimeSpan(tdoc.lockAt))|safe }}
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</div>
|
</div>
|
||||||
{% elif model.contest.isEnded(tdoc) and tdoc.lockAt and not tdoc.unlocked %}
|
{% elif model.contest.isDone(tdoc) and tdoc.lockAt and not tdoc.unlocked %}
|
||||||
<div class="section__body no-padding">
|
<div class="section__body no-padding">
|
||||||
<blockquote class="note">
|
<blockquote class="note">
|
||||||
{{ _('Please wait until contest host unlock the scoreboard.') }}
|
{{ _('Please wait until contest host unlock the scoreboard.') }}
|
||||||
@@ -45,48 +57,49 @@
|
|||||||
<tr>
|
<tr>
|
||||||
{%- for column in rows[0] -%}
|
{%- for column in rows[0] -%}
|
||||||
<th class="col--{{ column.type }}">
|
<th class="col--{{ column.type }}">
|
||||||
{% if column.type == 'problem' and column.raw %}
|
{%- if column.type == 'problem' and column.raw -%}
|
||||||
<a href="{{ url('problem_detail', pid=column.raw, query={tid:tdoc.docId}) }}" data-tooltip="{{ pdict[column.raw].title }}">
|
<a href="{{ url('problem_detail', pid=column.raw, query={tid:tdoc.docId}) }}" data-tooltip="{{ pdict[column.raw].title }}">
|
||||||
{{ column.value }}<br />{{ pdict[column.raw].nAccept }}/{{ pdict[column.raw].nSubmit }}
|
{{ column.value }}<br />{{ pdict[column.raw].nAccept|default(0) }}/{{ pdict[column.raw].nSubmit|default(0) }}
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{%- else -%}
|
||||||
{{ column.value|string|nl2br|safe }}
|
{{ column.value|string|nl2br|safe }}
|
||||||
{% endif %}
|
{%- endif -%}
|
||||||
</th>
|
</th>
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% set canViewAll = handler.user.own(tdoc) or model.contest.canShowRecord.call(handler, tdoc) %}
|
{%- set canViewAll = handler.user.own(tdoc) or model.contest.canShowRecord.call(handler, tdoc) -%}
|
||||||
{%- for row in rows -%}{% if loop.index0 > 0 %}
|
{%- for row in rows -%}{%- if loop.index0 > 0 -%}
|
||||||
<tr>
|
<tr>
|
||||||
{%- for column in row -%}
|
{%- for column in row -%}
|
||||||
<td class="col--{{ rows[0][loop.index0]['type'] }}"{% if column.style %} style="{{ column.style }}"{% endif %}>
|
<td class="col--{{ rows[0][loop.index0]['type'] }}"{% if column.style %} style="{{ column.style }}"{% endif %}>
|
||||||
{% if column.type == 'user' %}
|
{%- if column.type == 'user' -%}
|
||||||
{% set canView = canViewAll or handler.user._id == column.raw %}
|
{%- set canView = canViewAll or handler.user._id == column.raw -%}
|
||||||
{{ user.render_inline(udict[column.raw], badge=false) }}
|
{{ user.render_inline(udict[column.raw], badge=false) }}
|
||||||
{% elif column.type == 'record' and column.raw %}
|
{%- elif column.type == 'record' and column.raw -%}
|
||||||
<a href="{{ url('record_detail', rid=column.raw) if canView else '' }}" data-tooltip="{{ column.hover }}">
|
<a href="{{ url('record_detail', rid=column.raw) if canView else '' }}" data-tooltip="{{ column.hover }}">
|
||||||
<span style="font-weight:bold;color:{{ utils.status.getScoreColor(column.score|default(column.value)) }}">{{ column.value|string|nl2br|safe }}</span>
|
<span style="font-weight:bold;color:{{ utils.status.getScoreColor(column.score|default(column.value)) }}">{{ column.value|string|nl2br|safe }}</span>
|
||||||
</a>
|
</a>
|
||||||
{% elif column.type == 'records' %}
|
{%- elif column.type == 'records' -%}
|
||||||
{%- for record in column.raw -%}
|
{%- for record in column.raw -%}
|
||||||
{% if loop.index0 %}/{% endif %}
|
{%- if loop.index0 -%}/{%- endif -%}
|
||||||
{% if record.raw %}
|
{%- if record.raw -%}
|
||||||
<a href="{{ url('record_detail', rid=record.raw) if canView else '' }}">
|
<a href="{{ url('record_detail', rid=record.raw) if canView else '' }}">
|
||||||
<span style="font-weight:bold;color:{{ utils.status.getScoreColor(record.score|default(record.value)) }}">{{ record.value|string|nl2br|safe }}</span>
|
{%- set _color = utils.status.getScoreColor(record.score|default(record.value)) -%}
|
||||||
|
<span style="font-weight:bold;color:{{ _color }}">{{ record.value|string|nl2br|safe }}</span>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{%- else -%}
|
||||||
{{ record.value|string|nl2br|safe }}
|
{{ record.value|string|nl2br|safe }}
|
||||||
{% endif %}
|
{%- endif -%}
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{% else %}
|
{%- else -%}
|
||||||
{{ column.value|string|nl2br|safe }}
|
{{ column.value|string|nl2br|safe }}
|
||||||
{% endif %}
|
{%- endif -%}
|
||||||
</td>
|
</td>
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}{%- endfor -%}
|
{%- endif -%}{%- endfor -%}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user