mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
judge: support generate testdata (#695)
Co-authored-by: panda <panda_dtdyy@outlook.com>
This commit is contained in:
1 parent
b83b2e792e
commit
55b4e1aaf0
27 files changed
+454
-68
No files matched your search
@@ -0,0 +1,63 @@
|
||||
import { assign } from 'lodash';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import DOMAttachedObject from 'vj/components/DOMAttachedObject';
|
||||
import AutoComplete, { AutoCompleteOptions } from '.';
|
||||
import FileSelectAutoCompleteFC from './components/FileSelectAutoComplete';
|
||||
|
||||
interface FileSelectOptions {
|
||||
data: {
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
const Component = React.forwardRef<any, any>((props, ref) => {
|
||||
const [value, setValue] = React.useState(props.value);
|
||||
return (
|
||||
<FileSelectAutoCompleteFC
|
||||
ref={ref as any}
|
||||
height="auto"
|
||||
selectedKeys={value.split(',').map((i) => i.trim()).filter((i) => i)}
|
||||
onChange={(v) => {
|
||||
setValue(v);
|
||||
props.onChange(v);
|
||||
}}
|
||||
data={props.data}
|
||||
multi={props.multi}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default class FileSelectAutoComplete<Multi extends boolean> extends AutoComplete {
|
||||
static DOMAttachKey = 'ucwFileSelectAutoCompleteInstance';
|
||||
options: FileSelectOptions & AutoCompleteOptions;
|
||||
|
||||
constructor($dom, options: FileSelectOptions & AutoCompleteOptions<Multi>) {
|
||||
super($dom, {
|
||||
classes: 'custom-select',
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
value(): Multi extends true ? number[] : string {
|
||||
if (this.options.multi) return this.ref?.getSelectedItemKeys().map((i) => +i) ?? this.$dom.val();
|
||||
return this.ref?.getSelectedItems()[0] ?? null;
|
||||
}
|
||||
|
||||
attach() {
|
||||
const value = this.$dom.val();
|
||||
ReactDOM.createRoot(this.container).render(
|
||||
<Component
|
||||
ref={(ref) => { this.ref = ref; }}
|
||||
data={this.options.data}
|
||||
value={value}
|
||||
multi={this.options.multi}
|
||||
onChange={this.onChange}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
assign(FileSelectAutoComplete, DOMAttachedObject);
|
||||
window.Hydro.components.FileSelectAutoComplete = FileSelectAutoComplete;
|
||||
@@ -100,7 +100,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class ScratchpadTool
|
||||
}
|
||||
|
||||
render() {
|
||||
let canUsePretest = ['default', 'fileio'].includes(UiContext.pdoc.config?.type);
|
||||
let canUsePretest = UiContext.pdoc.config?.type === 'default';
|
||||
const langInfo = availableLangs[this.props.editorLang];
|
||||
if (UiContext.pdoc.config?.type === 'remote_judge' && langInfo) {
|
||||
if (langInfo.pretest) canUsePretest = true;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { i18n } from 'vj/utils';
|
||||
|
||||
export default function reducer(state = {
|
||||
pretest: {
|
||||
visible: ['default', 'fileio'].includes(UiContext.pdoc.config?.type)
|
||||
visible: UiContext.pdoc.config?.type === 'default'
|
||||
? localStorage.getItem('scratchpad/pretest') === 'true'
|
||||
: false,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
__langname: English
|
||||
'File IO: {0}': 'File IO: {0}'
|
||||
Can be Extended For: Extension
|
||||
Current Status: Status
|
||||
Handled Requests: Req
|
||||
@@ -27,7 +28,6 @@ problem_main: Problem Set
|
||||
problem_solution: Problem Solution
|
||||
problem_submit: Problem Submit
|
||||
problem_type.default: 'Type: Default'
|
||||
problem_type.fileio: 'Type: FileIO ({0})'
|
||||
problem_type.interactive: 'Type: Interactive'
|
||||
problem_type.objective: 'Type: Objective'
|
||||
problem_type.remote_judge: 'Type: RemoteJudge'
|
||||
|
||||
@@ -27,7 +27,9 @@ __langname: 简体中文
|
||||
'Current dataset: {0}': '当前测试数据: {0}'
|
||||
'Discussion: Terms Of Service': 讨论区服务条款
|
||||
'Drag and drop testcases here:': '拖拽测试点到此处:'
|
||||
'Enter a new name for the file: ': 请输入新的文件名:
|
||||
'Failed to get credential: {0}': '获取认证数据失败: {0}'
|
||||
'File IO: {0}': 文件IO:{0}
|
||||
'File upload failed: {0}': 文件上传失败:{0}
|
||||
'Format: category 1, category 2, ..., category n': 格式:分类1, 分类2, ..., 分类n
|
||||
'Hello, {0}! You can click following link to active your new email of your {1} account:': 您好,{0}!您可以点击以下链接来激活您 {1} 账户的新电子邮件地址:
|
||||
@@ -50,6 +52,8 @@ __langname: 简体中文
|
||||
(None): (无)
|
||||
(Not changed): 未更改
|
||||
6-Digit Code: 6位代码
|
||||
A data generator is a program that generates testdata. It should output result to stdout.: 数据生成器是一个生成测试数据的程序。它应该将结果输出到标准输出。
|
||||
A standard program is a program that solves the problem. It should output answer to stdout.: 标准程序是一个解决问题的程序。它应该将答案输出到标准输出。
|
||||
Aborted: 已放弃
|
||||
About {0}: 关于 {0}
|
||||
About Markdown: 关于 Markdown
|
||||
@@ -245,6 +249,7 @@ Current Status: 当前状态
|
||||
currently offline: 目前离线
|
||||
Daily update check: 每日自动检查更新
|
||||
Dark: 暗色
|
||||
Data Generator: 数据生成器
|
||||
Data of Problem {0} not found.: 题目 {0} 的数据缺失。
|
||||
Data of problem {1} not found.: 题目 {1} 的数据未找到。
|
||||
Data of record {0} not found.: 记录 {0} 的数据未找到。
|
||||
@@ -358,7 +363,6 @@ End Time: 结束时间
|
||||
Enroll Training: 参加训练
|
||||
Enrolled: 已参加
|
||||
Enrollees: 参加人数
|
||||
'Enter a new name for the file: ': 请输入新的文件名:
|
||||
error: 错误
|
||||
Errors detected in the config. Confirm save?: 配置中存在错误。确认保存?
|
||||
Evaluated difficulty: 估计的难度
|
||||
@@ -398,6 +402,9 @@ Freeze scoreboard with N minutes remaining: 在赛事剩余N分钟时封榜
|
||||
fs_upload: 上传文件
|
||||
Gender Visibility: 性别可见性
|
||||
Gender: 性别
|
||||
Generate testdata is not supported for this problem type.: 此题目类型不支持生成测试数据。
|
||||
Generate Testdata: 生成测试数据
|
||||
Generate: 生成
|
||||
Gravatar URL Prefix: Gravatar地址前缀
|
||||
Group / UID: 小组或 UID
|
||||
Group Name: 名称
|
||||
@@ -686,7 +693,6 @@ problem_main: 题库
|
||||
problem_solution: 题解
|
||||
problem_submit: 递交代码
|
||||
problem_type.default: 传统题
|
||||
problem_type.fileio: '文件IO ({0})'
|
||||
problem_type.interactive: 交互题
|
||||
problem_type.objective: 客观题
|
||||
problem_type.remote_judge: 远端评测题
|
||||
@@ -845,6 +851,7 @@ Sorry: 对不起
|
||||
Sort by: 排序
|
||||
Source type: 来源类型
|
||||
Standard mode: 标准模式
|
||||
Standard Program: 标准程序
|
||||
Star Topic: 收藏讨论
|
||||
Star: 收藏
|
||||
Starred Users: 关注用户
|
||||
|
||||
@@ -2,7 +2,8 @@ import $ from 'jquery';
|
||||
import { map } from 'lodash';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { ActionDialog, ConfirmDialog } from 'vj/components/dialog/index';
|
||||
import FileSelectAutoComplete from 'vj/components/autocomplete/FileSelectAutoComplete';
|
||||
import { ActionDialog, ConfirmDialog, InfoDialog } from 'vj/components/dialog/index';
|
||||
import createHint from 'vj/components/hint';
|
||||
import Notification from 'vj/components/notification';
|
||||
import { previewFile } from 'vj/components/preview/preview.page';
|
||||
@@ -318,6 +319,48 @@ const page = new NamedPage('problem_files', () => {
|
||||
handleClickUpload(type, files);
|
||||
}
|
||||
|
||||
async function handleGenerateTestdata(ev) {
|
||||
ev.preventDefault();
|
||||
const gen = $('[name=gen]').val();
|
||||
const std = $('[name=std]').val();
|
||||
if (!gen) {
|
||||
Notification.error(i18n('Please input the generator.'));
|
||||
return;
|
||||
}
|
||||
if (!std) {
|
||||
Notification.error(i18n('Please input the standard program.'));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await request.post('', {
|
||||
operation: 'generate_testdata',
|
||||
gen,
|
||||
std,
|
||||
});
|
||||
if (res.error) Notification.error(res.error);
|
||||
else {
|
||||
Notification.success(i18n('Generating...'));
|
||||
await new InfoDialog({
|
||||
$body: tpl`
|
||||
<div class="typo">
|
||||
<iframe src="${res.url}"
|
||||
scrolling="yes" border="0" frameborder="no" framespacing="0" width="100%" style="height: 70vh;"></iframe>
|
||||
</div>`,
|
||||
width: `${window.innerWidth - 200}px`,
|
||||
height: `${window.innerHeight - 100}px`,
|
||||
}).open();
|
||||
}
|
||||
} catch (error) {
|
||||
Notification.error([error.message, ...error.params].join(' '));
|
||||
}
|
||||
}
|
||||
|
||||
if (UiContext.pdoc) {
|
||||
FileSelectAutoComplete.getOrConstruct($('[name=gen]'), { data: UiContext.pdoc.data });
|
||||
FileSelectAutoComplete.getOrConstruct($('[name=std]'), { data: UiContext.pdoc.data });
|
||||
$('[name="generate_testdata"]').on('click', handleGenerateTestdata);
|
||||
}
|
||||
|
||||
if ($('[name="upload_testdata"]').length) {
|
||||
$(document).on('click', '[name="upload_testdata"]', () => handleClickUpload('testdata'));
|
||||
$(document).on('click', '[name="upload_file"]', () => handleClickUpload('additional_file'));
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
<span class="bp5-tag bp5-large bp5-minimal problem__tag-item">{{ _('ID') }}: {{ pdoc.docId }}</span>
|
||||
{% endif %}
|
||||
<span class="bp5-tag bp5-large bp5-minimal problem__tag-item icon icon-book">{{ _('problem_type.' + pdoc.config.type).format(pdoc.config.subType) }}</span>
|
||||
{% if pdoc.config.type == 'default' and pdoc.config.subType %}
|
||||
<span class="bp5-tag bp5-large bp5-minimal problem__tag-item icon icon-book">{{ _('File IO: {0}').format(pdoc.config.subType) }}</span>
|
||||
{% endif %}
|
||||
{% if pdoc.config.type != 'objective' and pdoc.config.type != 'submit_answer' %}
|
||||
<span class="bp5-tag bp5-large bp5-minimal problem__tag-item icon icon-stopwatch">{{ pdoc.config.timeMax if pdoc.config.timeMax == pdoc.config.timeMin else pdoc.config.timeMin+'~'+pdoc.config.timeMax }}ms</span>
|
||||
<span class="bp5-tag bp5-large bp5-minimal problem__tag-item icon icon-comparison">{{ pdoc.config.memoryMax if pdoc.config.memoryMax == pdoc.config.memoryMin else pdoc.config.memoryMin+'~'+pdoc.config.memoryMax }}MiB</span>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% import "components/nothing.html" as nothing with context %}
|
||||
{% extends "layout/basic.html" %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
@@ -27,6 +28,36 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if not reference and (handler.user.own(pdoc, perm.PERM_EDIT_PROBLEM_SELF) or handler.user.hasPerm(perm.PERM_EDIT_PROBLEM)) %}
|
||||
{{ set(UiContext, {
|
||||
pdoc: pdoc
|
||||
}) }}
|
||||
<div class="section">
|
||||
<div class="section__header">
|
||||
<h1 class="section__title">{{ _('Generate Testdata') }}(Beta)</h1>
|
||||
</div>
|
||||
{{ noscript_note.render() }}
|
||||
<div class="section__body generate">
|
||||
{% if pdoc.config.type === 'default' %}
|
||||
{{ form.form_text({
|
||||
columns: 12,
|
||||
label:'Data Generator',
|
||||
name:'gen',
|
||||
help_text:'A data generator is a program that generates testdata. It should output result to stdout.'
|
||||
}) }}
|
||||
{{ form.form_text({
|
||||
columns: 12,
|
||||
label:'Standard Program',
|
||||
name:'std',
|
||||
help_text:'A standard program is a program that solves the problem. It should output answer to stdout.'
|
||||
}) }}
|
||||
<button class="rounded button" name="generate_testdata">{{ _('Generate') }}</button>
|
||||
{% else %}
|
||||
{{ nothing.render('Generate testdata is not supported for this problem type.') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="medium-4 columns">
|
||||
<div class="section">
|
||||
|
||||
Reference in new issue
Block a user