core&ui: add clarification (#669)

This commit is contained in:
panda authored and GitHub committed 2023-11-05 06:49:51 +08:00
1 parent bc4f5115d2
commit c8c8063240
14 files changed
+373 -80

No files matched your search

@@ -2,13 +2,24 @@ import { nanoid } from 'nanoid';
import ReconnectingWebsocket from 'reconnecting-websocket';
import { InfoDialog } from 'vj/components/dialog';
import VjNotification from 'vj/components/notification/index';
import { FLAG_ALERT, FLAG_INFO, FLAG_RICHTEXT } from 'vj/constant/message';
import {
FLAG_ALERT, FLAG_I18N, FLAG_INFO, FLAG_RICHTEXT,
} from 'vj/constant/message';
import { AutoloadPage } from 'vj/misc/Page';
import { i18n, tpl } from 'vj/utils';
let previous: VjNotification;
const onmessage = (msg) => {
console.log('Received message', msg);
if (msg.mdoc.flag & FLAG_I18N) {
try {
msg.mdoc.content = JSON.parse(msg.mdoc.content);
if (msg.mdoc.content.url) msg.mdoc.url = msg.mdoc.content.url;
msg.mdoc.content = i18n(msg.mdoc.content.message, ...msg.mdoc.content.params);
} catch (e) {
msg.mdoc.content = i18n(msg.mdoc.content);
}
}
if (msg.mdoc.flag & FLAG_ALERT) {
// Is alert
new InfoDialog({
@@ -24,7 +35,7 @@ const onmessage = (msg) => {
if (msg.mdoc.flag & FLAG_INFO) {
if (previous) previous.hide();
previous = new VjNotification({
message: i18n(msg.mdoc.content),
message: msg.mdoc.content,
duration: 3000,
});
previous.show();
@@ -33,15 +44,17 @@ const onmessage = (msg) => {
if (document.hidden) return false;
// Is message
new VjNotification({
...(msg.udoc._id === 1 && msg.mdoc.flag & FLAG_RICHTEXT)
? { message: i18n('You received a system message, click here to view.') }
: {
...(msg.udoc._id === 1)
? {
type: 'info',
message: msg.mdoc.flag & FLAG_RICHTEXT ? i18n('You received a system message, click here to view.') : msg.mdoc.content,
} : {
title: msg.udoc.uname,
avatar: msg.udoc.avatarUrl,
message: msg.mdoc.content,
},
duration: 15000,
action: () => window.open(`/home/messages?uid=${msg.udoc._id}`, '_blank'),
action: () => window.open(msg.mdoc.url ? msg.mdoc.url : `/home/messages?uid=${msg.udoc._id}`, '_blank'),
}).show();
return true;
};
+1
View File
@@ -2,3 +2,4 @@ export const FLAG_UNREAD = 1;
export const FLAG_ALERT = 2;
export const FLAG_RICHTEXT = 4;
export const FLAG_INFO = 8;
export const FLAG_I18N = 16;
@@ -0,0 +1,24 @@
import $ from 'jquery';
import { NamedPage } from 'vj/misc/Page';
function handleReplyOrBroadcast(ev) {
const title = $(ev.currentTarget).data('title');
const did = $(ev.currentTarget).data('did');
$('#reply_or_broadcast .section_title').text(title);
$('#reply_or_broadcast [name="did"]').val(did ?? '');
const $item = $(`#clarification_${did} .media`);
if ($item.length) {
$('#reply_or_broadcast .form__item_subject').hide();
$('#reply_or_broadcast .clarification-container').empty().append($item.clone());
} else {
$('#reply_or_broadcast .form__item_subject').show();
$('#reply_or_broadcast .clarification-container').empty();
}
}
const page = new NamedPage('contest_manage', () => {
$(document).on('click', '[name="broadcast"]', handleReplyOrBroadcast);
$(document).on('click', '[name="reply"]', handleReplyOrBroadcast);
});
export default page;
@@ -6,3 +6,7 @@
{% macro render_duration(tdoc) %}
{{ tdoc.duration|round(1) if tdoc.duration else ((tdoc.endAt.getTime() - tdoc.beginAt.getTime()) /1000 / 3600)|round(1) }}
{% endmacro %}
{% macro render_clarification_subject(tdoc, pdict, subject) %}
{% if subject == 0 %}{{ _('General Issue') }}{% elif subject == -1 %}{{ _('Technical Issue') }}{% else %}{{ String.fromCharCode(65 + tdoc.pids.indexOf(subject)) + 1 }}. {{ pdict[subject].title }}{% endif %}
{% endmacro %}
+133 -59
View File
@@ -1,69 +1,143 @@
{% extends "layout/basic.html" %}
{% import "components/contest.html" as contest with context %}
{% block content %}
<div class="row">
<div class="medium-5 columns">
<div class="section">
<div class="section__body no-padding">
<table class="data-table">
<colgroup>
<col class="col--problem">
</colgroup>
<thead>
<tr>
<th class="col--problem">{{ _('Problem') }}</th>
</tr>
</thead>
<tbody>
{%- for pid in tdoc.pids -%}
<tr>
<td class="col--problem col--problem-name">
<a href="{{ url('problem_detail', pid=pid) }}">
<b>{{ String.fromCharCode(65+loop.index0) }}</b>&nbsp;&nbsp;{{ pdict[pid].title }}
</a>
</td>
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
</div>
</div>
<div class="medium-4 columns">
<div class="section">
<div class="section__header">
<h1 class="section__title">{{ _('Files') }}</h1>
<div class="section__tools">
<button class="primary rounded button" name="upload_file">{{ _('Upload File') }}</button>
<div class="medium-9 columns">
<div class="row">
<div class="medium-7 columns">
<div class="section">
<div class="section__body no-padding">
<table class="data-table">
<colgroup>
<col class="col--problem">
</colgroup>
<thead>
<tr>
<th class="col--problem">{{ _('Problem') }}</th>
</tr>
</thead>
<tbody>
{%- for pid in tdoc.pids -%}
<tr>
<td class="col--problem col--problem-name">
<a href="{{ url('problem_detail', pid=pid) }}">
<b>{{ String.fromCharCode(65+loop.index0) }}</b>&nbsp;&nbsp;{{ pdict[pid].title }}
</a>
</td>
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
</div>
</div>
{{ noscript_note.render() }}
{% include "partials/files.html" %}
<div class="section__body">
<button class="rounded button" name="remove_selected">{{ _('Remove Selected') }}</button>
<div class="medium-5 columns">
<div class="section">
<div class="section__header">
<h1 class="section__title">{{ _('Files') }}</h1>
<div class="section__tools">
<button class="primary rounded button" name="upload_file">{{ _('Upload File') }}</button>
</div>
</div>
{{ noscript_note.render() }}
{% include "partials/files.html" %}
<div class="section__body">
<button class="rounded button" name="remove_selected">{{ _('Remove Selected') }}</button>
</div>
</div>
</div>
<div class="medium-12 columns">
<div class="section">
<div class="section__header">
<h1 class="section__title">{{ _('Contest Clarifications') }}</h1>
<div class="section__tools">
<a href="#reply_or_broadcast" class="primary rounded button" name="broadcast" data-title="{{ _('Send Broadcast Message') }}" data-did="">{{ _('Send Broadcast Message') }}</a>
</div>
</div>
<div class="section__body">
{% if not tcdocs.length %}
{{ nothing.render('Oh, there is no clarification!') }}
{% else %}
<ul class="dczcomments__list">
{% for doc in tcdocs %}
<li class="dczcomments__item" id="clarification_{{ doc._id }}" data-did="{{ doc._id }}">
<div class="media">
<div class="media__body top" style="max-width:100%">
<div class="clearfix">
<div class="supplementary dczcomments__supplementary">
{{_('Subject') }}: {{ contest.render_clarification_subject(tdoc,pdict,doc.subject) }} | {% if doc.owner == 0 %}<b>{{ _('Jury') }}</b>{% else %}{{ user.render_inline(udict[doc.owner], badge=false) }}{% endif %} @ {{ datetimeSpan(doc._id)|safe }}
</div>
{% if doc.owner %}
<div class="dczcomments__operations nojs--hide">
<a href="#reply_or_broadcast" name="reply" data-title="{{ _('Reply') }}#{{ doc._id }}" data-did="{{ doc._id }}"
><span class="icon icon-reply"></span>{{ _('Reply') }}</a>
</div>
{% endif %}
</div>
<div class="typo" data-emoji-enabled>
{{ doc['content']|markdown|safe }}
</div>
</div>
</div>
<ul class="dczcomments__replies">
{%- for rdoc in doc['reply'] -%}
<li class="dczcomments__reply">
<div class="media">
<div class="media__left top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="media__body top">
<div class="clearfix">
<div class="supplementary dczcomments__supplementary">
<b>{{ _('Jury') }}</b>
</div>
</div>
<div class="typo" data-emoji-enabled>
{{ rdoc['content']|markdown|safe }}
</div>
</div>
</div>
</li>
{%- endfor -%}
</ul>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div id="reply_or_broadcast">
<div class="section__header">
<h1 class="section__title">{{ _('Send Broadcast Message') }}</h1>
</div>
<div class="section__body typo">
<form method="post">
<div class="clarification-container"></div>
<input type="hidden" name="operation" value="clarification">
<input type="hidden" name="did" value="">
<div class="row">
<div class="medium-12 columns form__item_subject">
<label>
{{ _('Subject') }}
<select name="subject" class="select">
<option value="0">{{ _('General Issue') }}</option>
<option value="-1">{{ _('Technical Issue') }}</option>
{% for pid in tdoc.pids %}
<option value="{{ pid }}">{{ String.fromCharCode(65+loop.index0) }}. {{ pdict[pid].title }}</option>
{% endfor %}
</select>
</label>
</div>
<div class="medium-12 columns form__item">
<label>
{{ _('Content') }}
<textarea name="content" class="textbox" data-markdown required></textarea>
</label>
</div>
</div>
<button type="submit" class="rounded primary button">{{ _('Submit') }}</button>
</div>
</div>
</div>
</div>
</div>
{% if model.contest.isOngoing(tdoc) %}
<div class="section">
<div class="section__header">
<h1 class="section__title">{{ _('Broadcast Message') }}</h1>
</div>
<div class="section__body">
<form method="post">
{{ form.form_textarea({
columns:null,
label:'Content',
name:'content',
value:''
}) }}
<div class="row"><div class="columns">
<button name="operation" value="broadcast" type="submit" class="rounded primary button">
{{ _('Send') }}
</button>
</div></div>
</form>
</div>
</div>
{% endif %}
</div>
<div class="medium-3 columns">
{% include 'partials/contest_sidebar_management.html' %}
@@ -5,7 +5,7 @@
{% block content %}
{{ set(UiContext, 'tdoc', tdoc) }}
{{ set(UiContext, 'tsdoc', tsdoc) }}
<div class="row">
<div class="row" data-sticky-parent>
<div class="medium-9 columns">
<div class="section">
<div class="section__header">
@@ -63,7 +63,7 @@
</div>
<div class="section__body no-padding">
{% if not canViewRecord %}
{{ nothing.render('According to the contest rules, you cannot view your submission details at current.') }}'
{{ nothing.render('According to the contest rules, you cannot view your submission details at current.') }}
{% elif not rdocs.length %}
{{ nothing.render('Oh, there is no submission!') }}
{% else %}
@@ -99,8 +99,86 @@
{% endif %}
</div>
</div>
<div class="section">
<div class="section__header">
<h1 class="section__title">{{ _('Contest Clarifications') }}</h1>
</div>
<div class="section__body">
{% if not tcdocs.length %}
{{ nothing.render('Oh, there is no clarification!') }}
{% else %}
<ul class="dczcomments__list">
{% for doc in tcdocs %}
<li class="dczcomments__item">
<div class="media">
<div class="media__body top">
<div class="clearfix">
<div class="supplementary dczcomments__supplementary">
{{_('Subject') }}: {{ contest.render_clarification_subject(tdoc,pdict,doc.subject) }} | {% if doc.owner == 0 %}<b>{{ _('Jury') }}</b>{% else %}{{ user.render_inline(udict[doc.owner], badge=false) }}{% endif %} @ {{ datetimeSpan(doc._id)|safe }}
</div>
</div>
<div class="typo" data-emoji-enabled>
{{ doc['content']|markdown|safe }}
</div>
</div>
</div>
<ul class="dczcomments__replies">
{%- for rdoc in doc['reply'] -%}
<li class="dczcomments__reply">
<div class="media">
<div class="media__left top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="media__body top">
<div class="clearfix">
<div class="supplementary dczcomments__supplementary">
<b>{{ _('Jury') }}</b> @ {{ datetimeSpan(rdoc['_id'])|safe }}
</div>
</div>
<div class="typo" data-emoji-enabled>
{{ rdoc['content']|markdown|safe }}
</div>
</div>
</div>
</li>
{%- endfor -%}
</ul>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% if tsdoc.attend %}
<div class="section__header">
<h1 class="section__title">{{ _('Send Clarification Request') }}</h1>
</div>
<div class="section__body typo">
<form method="post">
<input type="hidden" name="operation" value="clarification">
<div class="row">
<div class="medium-12 columns form__item">
<label>
{{ _('Subject') }}
<select name="subject" class="select">
<option value="0">{{ _('General Issue') }}</option>
<option value="-1">{{ _('Technical Issue') }}</option>
{% for pid in tdoc.pids %}
<option value="{{ pid }}">{{ String.fromCharCode(65+loop.index0) }}. {{ pdict[pid].title }}</option>
{% endfor %}
</select>
</label>
</div>
<div class="medium-12 columns form__item">
<label>
{{ _('Content') }}
<textarea name="content" class="textbox" data-markdown required></textarea>
</label>
</div>
</div>
<button type="submit" class="rounded primary button">{{ _('Submit') }}</button>
</div>
{% endif %}
</div>
</div>
<div class="medium-3 columns">
<div class="medium-3 columns" data-sticky="large">
{% set owner_udoc = udict[tdoc.owner] %}
{% include "partials/contest_sidebar.html" %}
</div>