mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
core&ui: handle contest status display
This commit is contained in:
1 parent
069f420310
commit
78b1141a02
12 files changed
+29
-31
No files matched your search
@@ -108,7 +108,7 @@ export class ContestDetailHandler extends Handler {
|
||||
const psdict = {};
|
||||
let rdict = {};
|
||||
if (tsdoc) {
|
||||
if (tsdoc.attend && !tsdoc.startAt) {
|
||||
if (tsdoc.attend && !tsdoc.startAt && contest.isOngoing(tdoc)) {
|
||||
await contest.setStatus(domainId, tid, this.user._id, { startAt: new Date() });
|
||||
tsdoc.startAt = new Date();
|
||||
}
|
||||
@@ -240,13 +240,12 @@ export class ContestEditHandler extends Handler {
|
||||
for (const i in contest.RULES) rules[i] = contest.RULES[i].TEXT;
|
||||
let ts = Date.now();
|
||||
ts = ts - (ts % (15 * Time.minute)) + 15 * Time.minute;
|
||||
const dt = this.tdoc?.beginAt || new Date(ts);
|
||||
this.response.body = {
|
||||
rules,
|
||||
tdoc: this.tdoc,
|
||||
duration: tid ? (this.tdoc.endAt.getTime() - this.tdoc.beginAt.getTime()) / Time.hour : 2,
|
||||
pids: tid ? this.tdoc.pids.join(',') : '',
|
||||
startAt: dt,
|
||||
beginAt: this.tdoc?.beginAt || new Date(ts),
|
||||
page_name: tid ? 'contest_edit' : 'contest_create',
|
||||
};
|
||||
}
|
||||
@@ -261,13 +260,15 @@ export class ContestEditHandler extends Handler {
|
||||
@param('pids', Types.Content)
|
||||
@param('rated', Types.Boolean)
|
||||
@param('code', Types.String, true)
|
||||
@param('autoHide', Types.String, true)
|
||||
@param('autoHide', Types.Boolean, true)
|
||||
@param('assign', Types.CommaSeperatedArray, true)
|
||||
@param('lock', Types.UnsignedInt, true)
|
||||
@param('contestDuration', Types.Float, true)
|
||||
async post(
|
||||
domainId: string, tid: ObjectID, beginAtDate: string, beginAtTime: string, duration: number,
|
||||
title: string, content: string, rule: string, _pids: string, rated = false,
|
||||
_code = '', autoHide = false, assign: string[] = null, lock: number = null,
|
||||
contestDuration?: number,
|
||||
) {
|
||||
if (autoHide) this.checkPerm(PERM.PERM_EDIT_PROBLEM);
|
||||
const pids = _pids.replace(/,/g, ',').split(',').map((i) => +i).filter((i) => i);
|
||||
@@ -277,10 +278,11 @@ export class ContestEditHandler extends Handler {
|
||||
if (beginAtMoment.isSameOrAfter(endAt)) throw new ValidationError('duration');
|
||||
const beginAt = beginAtMoment.toDate();
|
||||
const lockAt = lock ? moment(endAt).add(-lock, 'minutes').toDate() : null;
|
||||
contestDuration ||= duration;
|
||||
await problem.getList(domainId, pids, this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN) || this.user._id, this.user.group, true);
|
||||
if (tid) {
|
||||
await contest.edit(domainId, tid, {
|
||||
title, content, rule, beginAt, endAt, pids, rated,
|
||||
title, content, rule, beginAt, endAt, pids, rated, duration: contestDuration,
|
||||
});
|
||||
if (this.tdoc.beginAt !== beginAt || this.tdoc.endAt !== endAt
|
||||
|| Array.isDiff(this.tdoc.pids, pids) || this.tdoc.rule !== rule
|
||||
@@ -288,7 +290,7 @@ export class ContestEditHandler extends Handler {
|
||||
await contest.recalcStatus(domainId, this.tdoc.docId);
|
||||
}
|
||||
} else {
|
||||
tid = await contest.add(domainId, title, content, this.user._id, rule, beginAt, endAt, pids, rated);
|
||||
tid = await contest.add(domainId, title, content, this.user._id, rule, beginAt, endAt, pids, rated, { duration: contestDuration });
|
||||
}
|
||||
const task = {
|
||||
type: 'schedule', subType: 'contest', domainId, tid,
|
||||
|
||||
@@ -452,7 +452,7 @@ export class ProblemDetailHandler extends ProblemHandler {
|
||||
export class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async prepare(domainId: string, tid?: ObjectID) {
|
||||
if (tid && !contest.isOngoing(this.tdoc)) throw new ContestNotLiveError(this.tdoc.docId);
|
||||
if (tid && !contest.isOngoing(this.tdoc, this.tsdoc)) throw new ContestNotLiveError(this.tdoc.docId);
|
||||
}
|
||||
|
||||
async get() {
|
||||
|
||||
@@ -546,23 +546,24 @@ export function isNew(tdoc: Tdoc, days = 1) {
|
||||
}
|
||||
|
||||
export function isUpcoming(tdoc: Tdoc, days = 7) {
|
||||
const now = new Date().getTime();
|
||||
const now = Date.now();
|
||||
const readyAt = tdoc.beginAt.getTime();
|
||||
return (now > readyAt - days * Time.day && now < tdoc.beginAt.getTime());
|
||||
return (now > readyAt - days * Time.day && now < readyAt);
|
||||
}
|
||||
|
||||
export function isNotStarted(tdoc: Tdoc) {
|
||||
return (new Date()) < tdoc.beginAt;
|
||||
}
|
||||
|
||||
export function isOngoing(tdoc: Tdoc) {
|
||||
export function isOngoing(tdoc: Tdoc, tsdoc?: any) {
|
||||
const now = new Date();
|
||||
if (tsdoc && tsdoc?.startAt <= new Date(Date.now() - Math.floor(tdoc.duration * Time.hour))) return false;
|
||||
return (tdoc.beginAt <= now && now < tdoc.endAt);
|
||||
}
|
||||
|
||||
export function isDone(tdoc: Tdoc, tsdoc?: any) {
|
||||
if (tdoc.endAt <= new Date()) return true;
|
||||
if (tsdoc?.startAt <= new Date(Date.now() + tdoc.duration * Time.hour)) return true;
|
||||
if (tsdoc && tsdoc?.startAt <= new Date(Date.now() - Math.floor(tdoc.duration * Time.hour))) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -658,22 +659,15 @@ export async function getScoreboard(
|
||||
return [tdoc, rows, udict, pdict, nPages];
|
||||
}
|
||||
|
||||
export const statusText = (tdoc: Tdoc) => (
|
||||
export const statusText = (tdoc: Tdoc, tsdoc?: any) => (
|
||||
isNew(tdoc)
|
||||
? 'New'
|
||||
: isUpcoming(tdoc)
|
||||
? 'Ready (☆▽☆)'
|
||||
: isOngoing(tdoc)
|
||||
: isOngoing(tdoc, tsdoc)
|
||||
? 'Live...'
|
||||
: 'Done');
|
||||
|
||||
export const getStatusText = (tdoc: Tdoc) => (
|
||||
isNotStarted(tdoc)
|
||||
? 'not_started'
|
||||
: isOngoing(tdoc)
|
||||
? 'ongoing'
|
||||
: 'finished');
|
||||
|
||||
global.Hydro.model.contest = {
|
||||
RULES,
|
||||
add,
|
||||
@@ -704,5 +698,4 @@ global.Hydro.model.contest = {
|
||||
isLocked,
|
||||
isExtended,
|
||||
statusText,
|
||||
getStatusText,
|
||||
};
|
||||
@@ -25,6 +25,7 @@
|
||||
"@types/json-schema": "^7.0.11",
|
||||
"@types/katex": "^0.14.0",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"@types/pickadate": "^3.5.32",
|
||||
"@types/qrcode": "^1.4.2",
|
||||
"@types/react-dom": "^18.0.4",
|
||||
"@types/redux-logger": "^3.0.9",
|
||||
|
||||
@@ -53,11 +53,13 @@
|
||||
{% set extra_attr = args.extra_attr %}
|
||||
{% set date = args.date or false %}
|
||||
{% set time = args.time or false %}
|
||||
{% set datetime = args.datetime or false %}
|
||||
class="{{ form_class }}{% if extra_class %} {{ extra_class }}{% endif %}"
|
||||
{% if disabled %}disabled{% endif %}
|
||||
{% if required %}required{% endif %}
|
||||
{% if autofocus %}autofocus data-autofocus{% endif %}
|
||||
{% if noAutocomplete %}autocomplete="off"{% endif %}
|
||||
{% if datetime %}data-pick-datetime{% endif %}
|
||||
{% if date %}data-pick-date{% endif %}
|
||||
{% if time %}data-pick-time{% endif %}
|
||||
{% if extra_attr %}{{ extra_attr }}{% endif %}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<h1 class="section__title">{{ tdoc.title }}</h1>
|
||||
</div>
|
||||
<div class="section__body">
|
||||
<span class="bp4-tag bp4-large bp4-minimal problem__tag-item">{{ _(model.contest.statusText(tdoc)) }}</span>
|
||||
<span class="bp4-tag bp4-large bp4-minimal problem__tag-item">{{ _(model.contest.statusText(tdoc, tsdoc)) }}</span>
|
||||
<span class="bp4-tag bp4-large bp4-minimal problem__tag-item icon icon-award">{{ _(model.contest.RULES[tdoc.rule].TEXT) }}</span>
|
||||
<span class="bp4-tag bp4-large bp4-minimal problem__tag-item">{{ _('Start at') }}: {{ contest.render_time(tdoc.beginAt) }}</span>
|
||||
<span class="bp4-tag bp4-large bp4-minimal problem__tag-item icon icon-schedule">{{ contest.render_duration(tdoc) }} {{ _('hour(s)') }}</span>
|
||||
@@ -25,14 +25,14 @@
|
||||
<div class="section">
|
||||
<div class="section__body typo">
|
||||
{{ tdoc['content']|markdown|safe }}
|
||||
{% if model.contest.isOngoing(tdoc) %}
|
||||
{% if model.contest.isOngoing(tdoc, tsdoc) %}
|
||||
<blockquote class="warn">
|
||||
<p>{{ _('We will check code similarity after this contest.') }}</p>
|
||||
</blockquote>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if model.contest.isOngoing(tdoc) or model.contest.isDone(tdoc, tsdoc) %}
|
||||
{% if model.contest.isOngoing(tdoc, tsdoc) or model.contest.isDone(tdoc, tsdoc) %}
|
||||
<div class="section">
|
||||
<div class="section__header">
|
||||
<h1 class="section__title">{{ _('Problem') }}</h1>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
label:'Begin Date',
|
||||
name:'beginAtDate',
|
||||
placeholder:'YYYY-mm-dd',
|
||||
value:date_text,
|
||||
value:beginAt.format('%Y-%m-%d'),
|
||||
date:true,
|
||||
row:false
|
||||
}) }}
|
||||
@@ -55,7 +55,7 @@
|
||||
label:'Begin Time',
|
||||
name:'beginAtTime',
|
||||
placeholder:'HH:MM',
|
||||
value:time_text,
|
||||
value:beginAt.format('%H:%M'),
|
||||
time:true,
|
||||
row:false
|
||||
}) }}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<div class="row">
|
||||
<div class="medium-9 columns">
|
||||
{%- for tdoc in tdocs -%}
|
||||
{% if model.contest.isOngoing(tdoc) %}
|
||||
{% if model.contest.isOngoing(tdoc, tsdoc) %}
|
||||
{{ render_important_contest('live', 'Live...', tdoc) }}
|
||||
{% elif model.contest.isUpcoming(tdoc) %}
|
||||
{{ render_important_contest('ready', 'Ready (☆▽☆)', tdoc) }}
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
<dl class="large horizontal">
|
||||
<dt>{{ _('Status') }}</dt>
|
||||
<dd>
|
||||
{{ _(model.contest.statusText(tdoc)) }}
|
||||
{{ _(model.contest.statusText(tdoc, tsdoc)) }}
|
||||
{% if tsdoc.attend %}
|
||||
({{ _('Attended') }})
|
||||
{% endif %}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</div>
|
||||
<ol class="section__list contest__list">
|
||||
{%- for tdoc in tdocs -%}
|
||||
<li class="section__list__item contest__item contest-type--{{ tdoc.rule }} {% if model.contest.isOngoing(tdoc) %}{{ 'live' }}{% elif model.contest.isUpcoming(tdoc) %}{{ 'ready' }}{% endif %}">
|
||||
<li class="section__list__item contest__item contest-type--{{ tdoc.rule }} {% if model.contest.isOngoing(tdoc, tsdoc) %}{{ 'live' }}{% elif model.contest.isUpcoming(tdoc) %}{{ 'ready' }}{% endif %}">
|
||||
<div class="media">
|
||||
<div class="media__left medium">
|
||||
<div class="contest__date numbox">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{% endif %}
|
||||
<div>
|
||||
<ol class="menu">
|
||||
{% if model.contest.isOngoing(tdoc) %}
|
||||
{% if model.contest.isOngoing(tdoc, tsdoc) %}
|
||||
{% if page_name == 'contest_detail_problem' %}
|
||||
<li class="menu__item scratchpad--hide"><a class="menu__link highlight" name="problem-sidebar__open-scratchpad" href="javascript:;" data-global-hotkey="alt+e">
|
||||
<span class="icon icon-enlarge"></span> {{ _('Open Scratchpad') }} (Alt+E)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{% endif %}
|
||||
<div>
|
||||
<ol class="menu">
|
||||
{% if model.contest.isOngoing(tdoc) or model.contest.isExtended(tdoc) %}
|
||||
{% if model.contest.isOngoing(tdoc, tsdoc) or model.contest.isExtended(tdoc, tsdoc) %}
|
||||
{% if page_name == 'homework_detail_problem' %}
|
||||
<li class="menu__item scratchpad--hide"><a class="menu__link highlight" name="problem-sidebar__open-scratchpad" href="javascript:;" data-global-hotkey="alt+e">
|
||||
<span class="icon icon-enlarge"></span> {{ _('Open Scratchpad') }} (Alt+E)
|
||||
|
||||
Reference in new issue
Block a user