feat(problem/manage/data): subtasks configure

This commit is contained in:
Baoshuo Ren 2023-02-05 18:19:45 +08:00
parent b3113238a2
commit 6c24bd9bf6
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
2 changed files with 231 additions and 10 deletions

View File

@ -37,7 +37,7 @@ class UOJProblemConfigure {
private static function getCardHeader($title, $body_class = 'vstack gap-3') {
return <<<EOD
<div class="col-12 col-md-6">
<div class="card">
<div class="card h-100 overflow-hidden">
<div class="card-header fw-bold">
{$title}
</div>
@ -99,10 +99,11 @@ class UOJProblemConfigure {
$this->simple_form->appendHTML(static::getCardHeader('测试点分值', ''));
$this->simple_form->appendHTML(<<<EOD
<details>
<details id="div-point-score-container-outer">
<summary>展开/收起全部</summary>
<div id="div-point-score-container" class="row g-3 mt-0"></div>
</details>
<div id="div-point-score-unavailable" style="display: none;">在启用 Subtask 时「测试点分值」不可用。</div>
EOD);
$this->simple_form->appendHTML(static::getCardFooter());
$this->simple_form->appendHTML(<<<EOD
@ -123,6 +124,58 @@ class UOJProblemConfigure {
</script>
EOD);
$this->simple_form->appendHTML(static::getCardHeader('Subtask 配置', 'p-0'));
$this->simple_form->appendHTML(<<<EOD
<div class="form-check form-switch m-3">
<input class="form-check-input" type="checkbox" role="switch" id="input-enable_subtasks">
<label class="form-check-label" for="input-enable_subtasks">启用 Subtask</label>
</div>
<div id="div-subtasks-container"></div>
EOD);
$this->simple_form->appendHTML(static::getCardFooter());
$this->simple_form->appendHTML(<<<EOD
<script>
$(document).ready(function() {
$('#input-enable_subtasks').change(function() {
if (this.checked) {
$('#div-point-score-container-outer').hide();
$('#div-point-score-unavailable').show();
$('#div-subtasks-container').problem_configure_subtasks(problem_conf);
} else {
$('#div-point-score-container-outer').show();
$('#div-point-score-unavailable').hide();
$('#div-subtasks-container').empty();
$('.uoj-problem-configure-point-score-input').val('');
var subtask_keys = Object.keys(problem_conf).filter(function(key) {
return /^subtask_/.test(key);
});
for (var i = 0; i < subtask_keys.length; ++i) {
problem_conf[subtask_keys[i]] = '';
}
problem_conf['n_subtasks'] = '';
}
$('#problem-conf-preview').problem_conf_preview(problem_conf);
});
if (problem_conf['n_subtasks']) {
$('#input-enable_subtasks').prop('checked', true).trigger('change');
}
});
</script>
EOD);
$this->simple_form->appendHTML(<<<EOD
<script>
$(document).on("keydown", "form", function(event) {
return event.key != "Enter";
});
</script>
EOD);
$this->simple_form->succ_href = $this->href;
$this->simple_form->config['form']['class'] = 'row gy-3';
$this->simple_form->config['submit_container']['class'] = 'col-12 text-center mt-3';
@ -137,7 +190,7 @@ class UOJProblemConfigure {
$form->addSelect($key, [
'options' => $options,
'label' => $label,
'div_class' => 'row',
'div_class' => 'row gx-2',
'label_class' => 'col-form-label col-4',
'select_div_class' => 'col-8',
'default_value' => $this->problem_conf->getVal($key, $default_val),
@ -157,7 +210,7 @@ class UOJProblemConfigure {
$form->addInput($key, [
'type' => 'number',
'label' => $label,
'div_class' => 'row',
'div_class' => 'row gx-2',
'label_class' => 'col-form-label col-4',
'input_div_class' => 'col-8',
'default_value' => $this->problem_conf->getVal($key, $default_val),
@ -181,7 +234,7 @@ class UOJProblemConfigure {
'type' => 'number',
'label' => $label,
'input_attrs' => ['step' => 0.001],
'div_class' => 'row',
'div_class' => 'row gx-2',
'label_class' => 'col-form-label col-4',
'input_div_class' => 'col-8',
'default_value' => $this->problem_conf->getVal($key, $default_val),
@ -209,7 +262,7 @@ class UOJProblemConfigure {
$this->conf_keys[$key] = true;
$form->addInput($key, [
'label' => $label,
'div_class' => 'row',
'div_class' => 'row gx-2',
'label_class' => 'col-form-label col-4',
'input_div_class' => 'col-8',
'default_value' => $this->problem_conf->getVal($key, $default_val),
@ -235,11 +288,33 @@ class UOJProblemConfigure {
$conf = $this->problem_conf->conf;
$conf_keys = $this->conf_keys;
$n_tests = intval(UOJRequest::post('n_tests', 'validateUInt', $this->problem_conf->getVal('n_tests', 10)));
$n_subtasks = intval(UOJRequest::post('n_subtasks', 'validateUInt', $this->problem_conf->getVal('n_subtasks', 0)));
for ($i = 1; $i <= $n_tests; $i++) {
$conf_keys["point_score_$i"] = true;
}
$conf_keys['n_subtasks'] = true;
for ($i = 1; $i <= $n_subtasks; $i++) {
$conf_keys["subtask_type_$i"] = true;
$conf_keys["subtask_score_$i"] = true;
$conf_keys["subtask_end_$i"] = true;
$conf_keys["subtask_used_time_type_$i"] = true;
// $conf_keys["subtask_dependence_$i"] = true;
// $subtask_dependence_str = UOJRequest::post("subtask_dependence_$i", 'is_string', '');
// if ($subtask_dependence_str == 'many') {
// $subtask_dependence_cnt = 0;
// while (UOJRequest::post("subtask_dependence_{$i}_{$subtask_dependence_cnt}", 'is_string', '') != '') {
// $subtask_dependence_cnt++;
// $conf_keys["subtask_dependence_{$i}_{$subtask_dependence_cnt}"] = true;
// }
// }
}
foreach (array_keys($conf_keys) as $key) {
$val = UOJRequest::post($key, 'is_string', '');
if ($key === 'use_builtin_judger') {

View File

@ -1212,10 +1212,12 @@ $.fn.problem_configure_point_scores = function(problem_conf) {
var _this = this;
var n_tests = parseInt(problem_conf['n_tests']);
$(this).html('');
$(this).empty();
if (isNaN(n_tests) || n_tests <= 0) {
$(this).html('不可用。');
return;
}
for (var i = 1; i <= n_tests; i++) {
@ -1275,6 +1277,150 @@ $.fn.problem_configure_point_scores = function(problem_conf) {
});
};
// problem_configure: subtasks
$.fn.problem_configure_subtasks = function(problem_conf) {
return $(this).each(function() {
var _this = this;
var n_subtasks = parseInt(problem_conf['n_subtasks'] || '0');
$(this).empty();
if (isNaN(n_subtasks)) {
$(this).html('不可用。');
return;
}
var input_n_subtasks = $('<input class="form-control" type="number" name="n_subtasks" id="input-n_subtasks" />');
var div_subtasks = $('<div class="list-group list-group-flush border-top" />');
if (n_subtasks) {
input_n_subtasks.val(n_subtasks);
}
$(this).append(
$('<div class="m-3" />').append(
$('<div class="row" />').append(
$('<div class="col-4" />').append('<label for="input-n_subtasks" class="col-form-label">子任务数</label>')
).append(
$('<div class="col-8" />').append(input_n_subtasks)
)
)
).append(div_subtasks);
input_n_subtasks.change(function() {
div_subtasks.empty();
var n_subtasks = parseInt(input_n_subtasks.val() || '0');
problem_conf['n_subtasks'] = input_n_subtasks.val();
for (var i = 1; i <= n_subtasks; i++) {
var input_subtask_type = $('<select class="form-select form-select-sm" name="subtask_type_' + i + '" id="input-subtask_type_' + i + '" />');
var input_subtask_end = $('<input class="form-control form-control-sm uoj-problem-configure-subtask-end-input" type="number" name="subtask_end_' + i + '" id="input-subtask_end_' + i + '" />');
var input_subtask_score = $('<input class="form-control form-control-sm uoj-problem-configure-subtask-score-input" type="number" name="subtask_score_' + i + '" id="input-subtask_score_' + i + '" />');
var input_subtask_used_time_type = $('<select class="form-select form-select-sm" name="subtask_used_time_type_' + i + '" id="input-subtask_used_time_type_' + i + '" />');
input_subtask_type
.append($('<option value="packed" />').text('错一个就零分'))
.append($('<option value="min" />').text('得分取所有测试点中的最小值'));
input_subtask_used_time_type
.append($('<option value="sum" />').text('全部相加'))
.append($('<option value="max" />').text('取所有测试点中的最大值'));
(function(i) {
input_subtask_type.change(function() {
problem_conf['subtask_type_' + i] = $(this).val();
$('#problem-conf-preview').problem_conf_preview(problem_conf);
});
input_subtask_end.change(function() {
problem_conf['subtask_end_' + i] = $(this).val();
$('#problem-conf-preview').problem_conf_preview(problem_conf);
})
input_subtask_score.change(function() {
problem_conf['subtask_score_' + i] = $(this).val();
$('#problem-conf-preview').problem_conf_preview(problem_conf);
});
input_subtask_used_time_type.change(function() {
problem_conf['subtask_used_time_type_' + i] = $(this).val();
$('#problem-conf-preview').problem_conf_preview(problem_conf);
});
})(i);
div_subtasks.append(
$('<div class="list-group-item" />').append(
$('<div class="fw-bold" />').text('Subtask #' + i)
).append(
$('<div />').append(
$('<div class="row mt-2" />').append(
$('<div class="col-sm-6" />').append('<label for="input-subtask_type_' + i + '" class="col-form-label col-form-label-sm">评分类型</label>')
).append(
$('<div class="col-sm-6" />').append(input_subtask_type)
)
).append(
$('<div class="row mt-2" />').append(
$('<div class="col-sm-6" />').append('<label for="input-subtask_end_' + i + '" class="col-form-label col-form-label-sm">最后一个测试点的编号</label>')
).append(
$('<div class="col-sm-6" />').append(input_subtask_end)
)
).append(
$('<div class="row mt-2" />').append(
$('<div class="col-sm-6" />').append('<label for="input-subtask_score_' + i + '" class="col-form-label col-form-label-sm">分数</label>')
).append(
$('<div class="col-sm-6" />').append(input_subtask_score)
)
).append(
$('<div class="row mt-2" />').append(
$('<div class="col-sm-6" />').append('<label for="input-subtask_used_time_type_' + i + '" class="col-form-label col-form-label-sm">程序用时统计方式</label>')
).append(
$('<div class="col-sm-6" />').append(input_subtask_used_time_type)
)
)
)
);
}
$('.uoj-problem-configure-subtask-score-input', _this).change(function() {
var full_score = 100;
var rest_subtasks = parseInt(problem_conf['n_subtasks'] || '10');
var score_type = problem_conf['score_type'] || 'int';
$('.uoj-problem-configure-subtask-score-input', _this).each(function() {
var subtask_score = parseInt($(this).val());
if (!isNaN(subtask_score)) {
full_score -= subtask_score;
rest_subtasks--;
}
});
$('.uoj-problem-configure-subtask-score-input', _this).each(function() {
if ($(this).val() == '') {
var val = full_score / rest_subtasks;
if (score_type == 'int') {
val = Math.floor(val);
} else {
var decimal_places = parseInt(score_type.substring(5));
val = val.toFixed(decimal_places);
}
$(this).attr('placeholder', val);
}
});
});
$('.uoj-problem-configure-subtask-score-input', _this).first().trigger('change');
$('#problem-conf-preview').problem_conf_preview(problem_conf);
});
input_n_subtasks.trigger('change');
});
};
// custom test
function custom_test_onsubmit(response_text, div_result, url) {
if (response_text != '') {