mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
feat::
core: buildContent: sv for samples core&ui: record_main: filter_by_status ui: scoreboard: colorize
This commit is contained in:
1 parent
b0cf638616
commit
7d7d3c1599
14 files changed
+69
-38
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.24.11",
|
"version": "2.24.12",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"main": "dist/loader.js",
|
"main": "dist/loader.js",
|
||||||
"typings": "dist/loader.d.ts",
|
"typings": "dist/loader.d.ts",
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ class RecordListHandler extends Handler {
|
|||||||
@param('pid', Types.Name, true)
|
@param('pid', Types.Name, true)
|
||||||
@param('tid', Types.ObjectID, true)
|
@param('tid', Types.ObjectID, true)
|
||||||
@param('uidOrName', Types.Name, true)
|
@param('uidOrName', Types.Name, true)
|
||||||
|
@param('status', Types.Int, true)
|
||||||
@param('allDomain', Types.Boolean, true)
|
@param('allDomain', Types.Boolean, true)
|
||||||
async get(domainId: string, page = 1, pid?: string, tid?: ObjectID, uidOrName?: string, all = false) {
|
async get(domainId: string, page = 1, pid?: string, tid?: ObjectID, uidOrName?: string, status?: number, all = false) {
|
||||||
this.response.template = 'record_main.html';
|
this.response.template = 'record_main.html';
|
||||||
const q: FilterQuery<Rdoc> = { 'contest.tid': tid, hidden: false };
|
const q: FilterQuery<Rdoc> = { 'contest.tid': tid, hidden: false };
|
||||||
if (tid) {
|
if (tid) {
|
||||||
@@ -42,6 +43,7 @@ class RecordListHandler extends Handler {
|
|||||||
if (pdoc) q.pid = pdoc.docId;
|
if (pdoc) q.pid = pdoc.docId;
|
||||||
else q.pid = null;
|
else q.pid = null;
|
||||||
}
|
}
|
||||||
|
if (status) q.status = status;
|
||||||
const [rdocs] = await paginate(
|
const [rdocs] = await paginate(
|
||||||
record.getMulti(domainId, q).sort('_id', -1),
|
record.getMulti(domainId, q).sort('_id', -1),
|
||||||
page,
|
page,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export interface ProblemSource {
|
|||||||
|
|
||||||
export function buildContent(source: ProblemSource | ContentNode[], type: 'markdown' | 'html' = 'markdown', translate?: Function) {
|
export function buildContent(source: ProblemSource | ContentNode[], type: 'markdown' | 'html' = 'markdown', translate?: Function) {
|
||||||
const _ = translate || ((s: string) => s);
|
const _ = translate || ((s: string) => s);
|
||||||
|
let cnt = 0;
|
||||||
if (source instanceof Array) {
|
if (source instanceof Array) {
|
||||||
return type === 'html'
|
return type === 'html'
|
||||||
? source.map((node) => [
|
? source.map((node) => [
|
||||||
@@ -25,11 +26,11 @@ export function buildContent(source: ProblemSource | ContentNode[], type: 'markd
|
|||||||
...node.type === 'Sample'
|
...node.type === 'Sample'
|
||||||
? [
|
? [
|
||||||
`## ${_('Sample Input')}`,
|
`## ${_('Sample Input')}`,
|
||||||
'```',
|
`\`\`\`input${++cnt}`,
|
||||||
node.payload[0],
|
node.payload[0],
|
||||||
'```',
|
'```',
|
||||||
`## ${_('Sample Output')}`,
|
`## ${_('Sample Output')}`,
|
||||||
'```',
|
`\`\`\`output${cnt}`,
|
||||||
node.payload[1],
|
node.payload[1],
|
||||||
'```',
|
'```',
|
||||||
]
|
]
|
||||||
@@ -43,11 +44,11 @@ export function buildContent(source: ProblemSource | ContentNode[], type: 'markd
|
|||||||
...source.input ? [`<h2>${_('Input Format')}</h2>`, source.input] : [],
|
...source.input ? [`<h2>${_('Input Format')}</h2>`, source.input] : [],
|
||||||
...source.output ? [`<h2>${_('Output Format')}</h2>`, source.output] : [],
|
...source.output ? [`<h2>${_('Output Format')}</h2>`, source.output] : [],
|
||||||
...(source.samples).map((sample, i) => [
|
...(source.samples).map((sample, i) => [
|
||||||
`<h2>${_('Sample Input')} ${i + 1}</h2><pre>`,
|
`<pre><code class="language-input${i + 1}">`,
|
||||||
sample[0],
|
sample[0],
|
||||||
`</pre><h2>${_('Sample Output')} ${i + 1}</h2><pre>`,
|
`</code></pre><pre><code class="language-output${i + 1}">`,
|
||||||
sample[1],
|
sample[1],
|
||||||
'</pre>',
|
'</code></pre>',
|
||||||
].join('\n')),
|
].join('\n')),
|
||||||
...source.hint ? [`<h2>${_('Hint')}</h2>`, source.hint] : [],
|
...source.hint ? [`<h2>${_('Hint')}</h2>`, source.hint] : [],
|
||||||
...source.source ? [`<h2>${_('Source')}</h2>`, source.source] : [],
|
...source.source ? [`<h2>${_('Source')}</h2>`, source.source] : [],
|
||||||
|
|||||||
@@ -462,7 +462,13 @@ export const CATEGORIES = {
|
|||||||
'Hashing',
|
'Hashing',
|
||||||
'函数式编程',
|
'函数式编程',
|
||||||
],
|
],
|
||||||
博弈论: [],
|
博弈论: [
|
||||||
|
'巴什博弈',
|
||||||
|
'尼姆博弈',
|
||||||
|
'威佐夫博弈',
|
||||||
|
'斐波那契博弈',
|
||||||
|
'SG定理',
|
||||||
|
],
|
||||||
字符串: [
|
字符串: [
|
||||||
'KMP',
|
'KMP',
|
||||||
'后缀数据结构',
|
'后缀数据结构',
|
||||||
@@ -506,6 +512,10 @@ export const CATEGORIES = {
|
|||||||
'数学',
|
'数学',
|
||||||
'排序',
|
'排序',
|
||||||
'构造',
|
'构造',
|
||||||
|
'打表',
|
||||||
|
'位运算',
|
||||||
|
'离散化',
|
||||||
|
'莫队',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const { filter } = require('lodash');
|
|||||||
const { argv } = require('yargs');
|
const { argv } = require('yargs');
|
||||||
const Xss = require('xss');
|
const Xss = require('xss');
|
||||||
const { findFileSync } = require('@hydrooj/utils/lib/utils');
|
const { findFileSync } = require('@hydrooj/utils/lib/utils');
|
||||||
|
const status = require('@hydrooj/utils/lib/status');
|
||||||
const markdown = require('./markdown');
|
const markdown = require('./markdown');
|
||||||
|
|
||||||
const { misc, buildContent, avatar } = global.Hydro.lib;
|
const { misc, buildContent, avatar } = global.Hydro.lib;
|
||||||
@@ -143,7 +144,7 @@ class Nunjucks extends nunjucks.Environment {
|
|||||||
}
|
}
|
||||||
if (typeof s === 'object' && !(s instanceof Array)) {
|
if (typeof s === 'object' && !(s instanceof Array)) {
|
||||||
const langs = Object.keys(s);
|
const langs = Object.keys(s);
|
||||||
const f = langs.filter(i => i.startsWith(language));
|
const f = langs.filter((i) => i.startsWith(language));
|
||||||
if (s[language]) s = s[language];
|
if (s[language]) s = s[language];
|
||||||
else if (f.length) s = s[f[0]];
|
else if (f.length) s = s[f[0]];
|
||||||
else s = s[langs[0]];
|
else s = s[langs[0]];
|
||||||
@@ -190,6 +191,7 @@ env.addGlobal('typeof', (o) => typeof o);
|
|||||||
env.addGlobal('datetimeSpan', misc.datetimeSpan);
|
env.addGlobal('datetimeSpan', misc.datetimeSpan);
|
||||||
env.addGlobal('paginate', misc.paginate);
|
env.addGlobal('paginate', misc.paginate);
|
||||||
env.addGlobal('size', misc.size);
|
env.addGlobal('size', misc.size);
|
||||||
|
env.addGlobal('utils', { status });
|
||||||
env.addGlobal('avatarUrl', avatar);
|
env.addGlobal('avatarUrl', avatar);
|
||||||
env.addGlobal('formatSeconds', misc.formatSeconds);
|
env.addGlobal('formatSeconds', misc.formatSeconds);
|
||||||
env.addGlobal('model', global.Hydro.model);
|
env.addGlobal('model', global.Hydro.model);
|
||||||
|
|||||||
@@ -95,9 +95,6 @@ const prismjsApiWrap = {
|
|||||||
const $code = $(code);
|
const $code = $(code);
|
||||||
const $pre = $code.parent();
|
const $pre = $code.parent();
|
||||||
$pre.addClass('syntax-hl');
|
$pre.addClass('syntax-hl');
|
||||||
if ($pre.closest('[data-syntax-hl-show-line-number]')) {
|
|
||||||
$pre.addClass('line-numbers');
|
|
||||||
}
|
|
||||||
const language = ($(code).attr('class') || '').trim();
|
const language = ($(code).attr('class') || '').trim();
|
||||||
const astyle = language.match(/astyle-([a-z]+)/);
|
const astyle = language.match(/astyle-([a-z]+)/);
|
||||||
if (format && astyle && astyle[1]) {
|
if (format && astyle && astyle[1]) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/ui-default",
|
"name": "@hydrooj/ui-default",
|
||||||
"version": "4.6.34",
|
"version": "4.7.0",
|
||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "hydro.js",
|
"main": "hydro.js",
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"@babel/preset-react": "^7.13.13",
|
"@babel/preset-react": "^7.13.13",
|
||||||
"@babel/register": "^7.13.14",
|
"@babel/register": "^7.13.14",
|
||||||
"@babel/runtime-corejs2": "^7.14.0",
|
"@babel/runtime-corejs2": "^7.14.0",
|
||||||
"@hydrooj/utils": "^1.0.7",
|
"@hydrooj/utils": "^1.0.10",
|
||||||
"ansi_up": "^5.0.1",
|
"ansi_up": "^5.0.1",
|
||||||
"autoprefixer": "^9.8.6",
|
"autoprefixer": "^9.8.6",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<td class="col--status record-status--border {{ class }} {{ model.builtin.STATUS_CODES[rdoc.status] }}">
|
<td class="col--status record-status--border {{ class }} {{ model.builtin.STATUS_CODES[rdoc.status] }}">
|
||||||
<div class="col--status__text">
|
<div class="col--status__text">
|
||||||
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[rdoc.status] }}"></span>
|
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[rdoc.status] }}"></span>
|
||||||
|
<span style="color: {{ utils.status.getScoreColor(rdoc.score|default(0)) }}">{{ rdoc.score|default(0) }}</span>
|
||||||
<a href="{{ url('record_detail', rid=rdoc[rid_key]) }}" class="record-status--text {{ model.builtin.STATUS_CODES[rdoc.status] }}">
|
<a href="{{ url('record_detail', rid=rdoc[rid_key]) }}" class="record-status--text {{ model.builtin.STATUS_CODES[rdoc.status] }}">
|
||||||
{{ model.builtin.STATUS_TEXTS[rdoc.status] }}
|
{{ model.builtin.STATUS_TEXTS[rdoc.status] }}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -40,7 +40,9 @@
|
|||||||
{% if column.type == 'user' %}
|
{% if column.type == 'user' %}
|
||||||
{{ 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) }}">{{ column.value }}</a>
|
<a href="{{ url('record_detail', rid=column.raw) }}">
|
||||||
|
<span style="font-weight:bold;color:{{ utils.status.getScoreColor(column.value) }}">{{ column.value }}</span>
|
||||||
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ column.value }}
|
{{ column.value }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -10,28 +10,11 @@
|
|||||||
<div class="section__header">
|
<div class="section__header">
|
||||||
<h1 class="section__title">{{ _('Code') }}</h1>
|
<h1 class="section__title">{{ _('Code') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="section__body" data-syntax-hl-show-line-number>
|
<div class="section__body">
|
||||||
<pre><code class="language-{{ (model.system.get('ui-default.lang_highlight_id')|parseYaml)[rdoc['lang']] }}">{{ rdoc['code'] }}</code></pre>
|
<pre><code class="line-numbers language-{{ (model.system.get('ui-default.lang_highlight_id')|parseYaml)[rdoc['lang']] }}">{{ rdoc['code'] }}</code></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if rdoc['stdout'] or rdoc['stderr'] %}
|
|
||||||
<div class="section">
|
|
||||||
<div class="section__header">
|
|
||||||
<h1 class="section__title">{{ _('Stdout') }}</h1>
|
|
||||||
</div>
|
|
||||||
{% if rdoc['stdout'] %}
|
|
||||||
<div class="section__body" data-syntax-hl-show-line-number>
|
|
||||||
<pre><code>{{ rdoc['stdout']|ansi|safe }}</code></pre>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if rdoc['stderr'] %}
|
|
||||||
<div class="section__body" data-syntax-hl-show-line-number>
|
|
||||||
<pre><code>{{ rdoc['stderr']|ansi|safe }}</code></pre>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="medium-3 columns">
|
<div class="medium-3 columns">
|
||||||
<div class="section side">
|
<div class="section side">
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<div class="section__header">
|
<div class="section__header">
|
||||||
<h1 class="section__title">
|
<h1 class="section__title">
|
||||||
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[rdoc['status']] }}"></span>
|
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[rdoc['status']] }}"></span>
|
||||||
|
<span style="color: {{ utils.status.getScoreColor(rdoc.score|default(0)) }}">{{ rdoc.score|default(0) }}</span>
|
||||||
<span class="record-status--text {{ model.builtin.STATUS_CODES[rdoc['status']] }}">
|
<span class="record-status--text {{ model.builtin.STATUS_CODES[rdoc['status']] }}">
|
||||||
{{ model.builtin.STATUS_TEXTS[rdoc['status']] }}
|
{{ model.builtin.STATUS_TEXTS[rdoc['status']] }}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -16,24 +16,40 @@
|
|||||||
<div class="section__body">
|
<div class="section__body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- TODO: replace with form_builder -->
|
<!-- TODO: replace with form_builder -->
|
||||||
<div class="medium-4 columns">
|
<div class="medium-3 columns">
|
||||||
<label class="filter-user">
|
<label class="filter-user">
|
||||||
{{ _('By Username / UID') }}
|
{{ _('By Username / UID') }}
|
||||||
<input name="uidOrName" type="text" class="textbox" value="{{ filterUidOrName }}" autocomplete="off" data-autofocus>
|
<input name="uidOrName" type="text" class="textbox" value="{{ filterUidOrName }}" autocomplete="off" data-autofocus>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="medium-4 columns">
|
<div class="medium-3 columns">
|
||||||
<label>
|
<label>
|
||||||
{{ _('By Problem') }}
|
{{ _('By Problem') }}
|
||||||
<input name="pid" type="text" class="textbox" value="{{ filterPid }}">
|
<input name="pid" type="text" class="textbox" value="{{ filterPid }}">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="medium-4 columns">
|
<div class="medium-3 columns">
|
||||||
<label>
|
<label>
|
||||||
{{ _('By Contest') }}
|
{{ _('By Contest') }}
|
||||||
<input name="tid" type="text" class="textbox" value="{{ filterTid }}">
|
<input name="tid" type="text" class="textbox" value="{{ filterTid }}">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="medium-3 columns">
|
||||||
|
<label>
|
||||||
|
{{ _('By Status') }}
|
||||||
|
</label>
|
||||||
|
<select class="inline compact select" name="status">
|
||||||
|
<option value="">{{ _('All Submissions') }}</option>
|
||||||
|
<option value="1">{{ _('Accepted') }}</option>
|
||||||
|
<option value="2">{{ _('Wrong Answer') }}</option>
|
||||||
|
<option value="3">{{ _('Time Limit Exceeded') }}</option>
|
||||||
|
<option value="4">{{ _('Memory Limit Exceeded') }}</option>
|
||||||
|
<option value="6">{{ _('Runtime Error') }}</option>
|
||||||
|
<option value="7">{{ _('Compile Error') }}</option>
|
||||||
|
<option value="8">{{ _('System Error') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -55,6 +55,22 @@ export const STATUS_CODES = {
|
|||||||
30: 'ignored',
|
30: 'ignored',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getScoreColor(score: number | string): string {
|
||||||
|
return [
|
||||||
|
'#ff4f4f',
|
||||||
|
'#ff694f',
|
||||||
|
'#f8603a',
|
||||||
|
'#fc8354',
|
||||||
|
'#fa9231',
|
||||||
|
'#f7bb3b',
|
||||||
|
'#ecdb44',
|
||||||
|
'#e2ec52',
|
||||||
|
'#b0d628',
|
||||||
|
'#93b127',
|
||||||
|
'#25ad40',
|
||||||
|
][Math.floor((Number(score) || 0) / 10)];
|
||||||
|
}
|
||||||
|
|
||||||
export const USER_GENDER_MALE = 0;
|
export const USER_GENDER_MALE = 0;
|
||||||
export const USER_GENDER_FEMALE = 1;
|
export const USER_GENDER_FEMALE = 1;
|
||||||
export const USER_GENDER_OTHER = 2;
|
export const USER_GENDER_OTHER = 2;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/utils",
|
"name": "@hydrooj/utils",
|
||||||
"version": "1.0.9",
|
"version": "1.0.10",
|
||||||
"description": "hydrooj utils",
|
"description": "hydrooj utils",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
|
|||||||
Reference in new issue
Block a user