mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-12-22 17:01:53 +00:00
refactor(web/list): list v2
This commit is contained in:
parent
bae26f1c16
commit
c5b3fbdd4a
@ -686,6 +686,7 @@ UNLOCK TABLES;
|
||||
CREATE TABLE `lists` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`title` text NOT NULL,
|
||||
`description` text NOT NULL DEFAULT '',
|
||||
`is_hidden` tinyint(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
|
@ -28,6 +28,10 @@
|
||||
|
||||
$group = queryGroup($assignment['group_id']);
|
||||
$list = queryProblemList($assignment['list_id']);
|
||||
|
||||
if (($group['is_hidden'] || $list['is_hidden']) && !isSuperUser($myUser)) {
|
||||
become403Page();
|
||||
}
|
||||
?>
|
||||
|
||||
<?php echoUOJPageHeader(UOJLocale::get('assignments')) ?>
|
||||
@ -40,7 +44,7 @@
|
||||
<small class="fs-4">作业:</small><?= $list['title'] ?>
|
||||
</h1>
|
||||
<ul class="mt-3">
|
||||
<li>对应题单:<a class="text-decoration-none" href="<?= HTML::url('/problem_list/'.$list['id']) ?>">#<?= $list['id'] ?></a></li>
|
||||
<li>对应题单:<a class="text-decoration-none" href="<?= HTML::url('/list/'.$list['id']) ?>">#<?= $list['id'] ?></a></li>
|
||||
<li>所属小组:<a class="text-decoration-none" href="<?= HTML::url('/group/'.$group['id']) ?>"><?= $group['title'] ?></a></li>
|
||||
<li>结束时间:<?= $assignment['end_time'] ?></li>
|
||||
</ul>
|
||||
|
@ -81,7 +81,7 @@
|
||||
$update_profile_form->handle = function($vdata) use ($group) {
|
||||
$esc_title = DB::escape($vdata['title']);
|
||||
$is_hidden = $_POST['is_hidden'];
|
||||
$esc_announcement = $vdata['announcement'];
|
||||
$esc_announcement = DB::escape($vdata['announcement']);
|
||||
|
||||
DB::update("UPDATE `groups` SET title = '$esc_title', is_hidden = '$is_hidden', announcement = '$esc_announcement' WHERE id = {$group['id']}");
|
||||
|
||||
@ -198,6 +198,10 @@ function(res) {
|
||||
}
|
||||
EOD);
|
||||
$add_new_assignment_form->runAtServer();
|
||||
|
||||
$now = new DateTime();
|
||||
$hidden_time = new DateTime();
|
||||
$hidden_time->sub(new DateInterval('P7D'));
|
||||
} elseif ($cur_tab == 'users') {
|
||||
if (isset($_POST['submit-remove_user']) && $_POST['submit-remove_user'] == 'remove_user') {
|
||||
$username = $_POST['remove_username'];
|
||||
@ -331,54 +335,56 @@ EOD);
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="assignments">
|
||||
<?php
|
||||
$now = new DateTime();
|
||||
$hidden_time = new DateTime();
|
||||
$hidden_time->sub(new DateInterval('P7D'));
|
||||
echoLongTable(
|
||||
['*'],
|
||||
'groups_assignments',
|
||||
"group_id = {$group['id']}",
|
||||
'order by end_time desc, list_id desc',
|
||||
<<<EOD
|
||||
echoLongTable(
|
||||
['*'],
|
||||
'groups_assignments',
|
||||
"group_id = {$group['id']}",
|
||||
'order by end_time desc, list_id desc',
|
||||
<<<EOD
|
||||
<tr>
|
||||
<th style="width:3em" class="text-center">ID</th>
|
||||
<th style="width:4em" class="text-center">题单 ID</th>
|
||||
<th style="width:12em">标题</th>
|
||||
<th style="width:4em">状态</th>
|
||||
<th style="width:8em">结束时间</th>
|
||||
<th style="width:8em">操作</th>
|
||||
</tr>
|
||||
EOD,
|
||||
function($row) use ($group, $now, $hidden_time) {
|
||||
$list = queryProblemList($row['list_id']);
|
||||
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']);
|
||||
function($row) use ($group, $now, $hidden_time) {
|
||||
$list = queryProblemList($row['list_id']);
|
||||
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']);
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td class="text-center">', $list['id'], '</td>';
|
||||
echo '<td>', '<a class="text-decoration-none" href="/group/', $group['id'], '/assignment/', $list['id'],'">', HTML::escape($list['title']), '</a>', '</td>';
|
||||
if ($end_time < $hidden_time) {
|
||||
echo '<td class="text-secondary">已隐藏</td>';
|
||||
} elseif ($end_time < $now) {
|
||||
echo '<td class="text-danger">已结束</td>';
|
||||
} else {
|
||||
echo '<td class="text-success">进行中</td>';
|
||||
}
|
||||
echo '<td>', $end_time->format('Y-m-d H:i:s'), '</td>';
|
||||
echo '<td>';
|
||||
echo '<a class="text-decoration-none d-inline-block align-middle" href="/problem_list/', $list['id'], '/manage">编辑</a> ';
|
||||
echo ' <form class="d-inline-block" method="POST" onsubmit=\'return confirm("你真的要移除这份作业吗?移除作业不会删除题单。")\'>'
|
||||
. '<input type="hidden" name="_token" value="' . crsf_token() . '">'
|
||||
. '<input type="hidden" name="list_id" value="' . $list['id'] . '">'
|
||||
. '<button class="btn btn-link text-danger text-decoration-none p-0" type="submit" name="submit-remove_assignment" value="remove_assignment">移除</button>'
|
||||
. '</form>';
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
},
|
||||
[
|
||||
'page_len' => 20,
|
||||
'div_classes' => ['table-responsive'],
|
||||
'table_classes' => ['table', 'align-middle'],
|
||||
]
|
||||
);
|
||||
echo '<tr>';
|
||||
echo '<td class="text-center">', $list['id'], '</td>';
|
||||
echo '<td>';
|
||||
echo '<a class="text-decoration-none" href="/group/', $group['id'], '/assignment/', $list['id'],'">', HTML::escape($list['title']), '</a>';
|
||||
if ($list['is_hidden']) {
|
||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||
}
|
||||
echo '</td>';
|
||||
if ($end_time < $hidden_time) {
|
||||
echo '<td class="text-secondary">已隐藏</td>';
|
||||
} elseif ($end_time < $now) {
|
||||
echo '<td class="text-danger">已结束</td>';
|
||||
} else {
|
||||
echo '<td class="text-success">进行中</td>';
|
||||
}
|
||||
echo '<td>', $end_time->format('Y-m-d H:i:s'), '</td>';
|
||||
echo '<td>';
|
||||
echo ' <a class="text-decoration-none d-inline-block align-middle" href="/list/', $list['id'], '/edit">编辑</a> ';
|
||||
echo ' <form class="d-inline-block" method="POST" onsubmit=\'return confirm("你真的要移除这份作业(题单 #', $row['id'], ')吗?移除作业不会删除题单。")\'>'
|
||||
. '<input type="hidden" name="_token" value="' . crsf_token() . '">'
|
||||
. '<input type="hidden" name="list_id" value="' . $list['id'] . '">'
|
||||
. '<button class="btn btn-link text-danger text-decoration-none p-0" type="submit" name="submit-remove_assignment" value="remove_assignment">移除</button>'
|
||||
. '</form>';
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
},
|
||||
[
|
||||
'page_len' => 20,
|
||||
'div_classes' => ['table-responsive'],
|
||||
'table_classes' => ['table', 'align-middle'],
|
||||
]
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<div class="tab-pane" id="add-assignment">
|
||||
|
@ -1,89 +1,57 @@
|
||||
<?php
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
requireLib('bootstrap5');
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
|
||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
||||
redirectToLogin();
|
||||
}
|
||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
||||
redirectToLogin();
|
||||
}
|
||||
|
||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
||||
become403Page();
|
||||
}
|
||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
||||
become403Page();
|
||||
}
|
||||
|
||||
if (!isset($_COOKIE['bootstrap4'])) {
|
||||
$REQUIRE_LIB['bootstrap5'] = '';
|
||||
}
|
||||
|
||||
if (isSuperUser($myUser)) {
|
||||
$new_group_form = new UOJForm('new_group');
|
||||
$new_group_form->handle = function() {
|
||||
DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)");
|
||||
};
|
||||
$new_group_form->submit_button_config['align'] = 'right';
|
||||
$new_group_form->submit_button_config['class_str'] = 'btn btn-primary';
|
||||
$new_group_form->submit_button_config['text'] = UOJLocale::get('add new group');
|
||||
$new_group_form->submit_button_config['smart_confirm'] = '';
|
||||
$new_group_form->runAtServer();
|
||||
}
|
||||
|
||||
function echoGroup($group) {
|
||||
global $myUser, $REQUIRE_LIB;
|
||||
|
||||
echo '<tr class="text-center">';
|
||||
echo '<td>';
|
||||
echo '#', $group['group_id'], '</td>';
|
||||
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo '<td class="text-start">';
|
||||
} else {
|
||||
echo '<td class="text-left">';
|
||||
}
|
||||
if ($group['is_hidden']) {
|
||||
echo ' <span class="text-danger">[隐藏]</span> ';
|
||||
}
|
||||
echo '<a ';
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo ' class="text-decoration-none" ';
|
||||
}
|
||||
echo ' href="/group/', $group['group_id'], '">', $group['title'], '</a>';
|
||||
echo '</td>';
|
||||
|
||||
echo "<td>{$group['user_count']}</td>";
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
?>
|
||||
if (isSuperUser($myUser)) {
|
||||
$new_group_form = new UOJForm('new_group');
|
||||
$new_group_form->handle = function() {
|
||||
DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)");
|
||||
};
|
||||
$new_group_form->submit_button_config['align'] = 'right';
|
||||
$new_group_form->submit_button_config['class_str'] = 'btn btn-primary';
|
||||
$new_group_form->submit_button_config['text'] = UOJLocale::get('add new group');
|
||||
$new_group_form->submit_button_config['smart_confirm'] = '';
|
||||
$new_group_form->runAtServer();
|
||||
}
|
||||
?>
|
||||
|
||||
<?php echoUOJPageHeader(UOJLocale::get('groups')) ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="row">
|
||||
|
||||
<!-- left col -->
|
||||
<div class="col-lg-9">
|
||||
|
||||
<!-- title container -->
|
||||
<div class="d-flex justify-content-between">
|
||||
<?php endif ?>
|
||||
|
||||
<h1 class="h2">
|
||||
<?= UOJLocale::get('groups') ?>
|
||||
</h1>
|
||||
|
||||
<?php if (isSuperUser($myUser)): ?>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="text-end mb-2">
|
||||
<?php endif ?>
|
||||
<?php $new_group_form->printHTML(); ?>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<?php if (isset($new_group_form)): ?>
|
||||
<div class="text-end mb-2">
|
||||
<?php $new_group_form->printHTML(); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
</div>
|
||||
<!-- end title container -->
|
||||
|
||||
<?php
|
||||
$groups_caption = UOJLocale::get('groups');
|
||||
$users_caption = UOJLocale::get('users count');
|
||||
$header = <<<EOD
|
||||
$groups_caption = UOJLocale::get('groups');
|
||||
$users_caption = UOJLocale::get('users count');
|
||||
$header = <<<EOD
|
||||
<tr>
|
||||
<th class="text-center" style="width:5em;">ID</th>
|
||||
<th>{$groups_caption}</th>
|
||||
@ -91,35 +59,44 @@
|
||||
</tr>
|
||||
EOD;
|
||||
|
||||
if (isSuperUser($myUser)) {
|
||||
$cond = "1";
|
||||
} else {
|
||||
$cond = 'is_hidden = 0';
|
||||
}
|
||||
if (isSuperUser($myUser)) {
|
||||
$cond = "1";
|
||||
} else {
|
||||
$cond = 'is_hidden = 0';
|
||||
}
|
||||
|
||||
$from = "`groups` a left join groups_users b on a.id = b.group_id";
|
||||
echoLongTable(
|
||||
['a.id as group_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.username) as user_count'],
|
||||
"`groups` a left join groups_users b on a.id = b.group_id",
|
||||
$cond,
|
||||
'group by a.id order by a.id asc',
|
||||
$header,
|
||||
function ($group) use ($myUser) {
|
||||
echo '<tr class="text-center">';
|
||||
echo '<td>';
|
||||
echo '#', $group['group_id'], '</td>';
|
||||
|
||||
echo '<td class="text-start">';
|
||||
echo '<a class="text-decoration-none" href="/group/', $group['group_id'], '">', $group['title'], '</a>';
|
||||
if ($group['is_hidden']) {
|
||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
echo "<td>{$group['user_count']}</td>";
|
||||
|
||||
echo '</tr>';
|
||||
},
|
||||
[
|
||||
'page_len' => 40,
|
||||
'div_classes' => ['card', 'my-3'],
|
||||
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
||||
'head_pagination' => true,
|
||||
'pagination_table' => "`groups`",
|
||||
]
|
||||
);
|
||||
?>
|
||||
|
||||
$table_config = array('page_len' => 40,
|
||||
'table_classes' => array('table', 'table-bordered', 'table-hover', 'table-striped'),
|
||||
'head_pagination' => true,
|
||||
'pagination_table' => "`groups`"
|
||||
);
|
||||
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
$table_config['div_classes'] = array('card', 'my-3');
|
||||
$table_config['table_classes'] = array('table', 'uoj-table', 'mb-0');
|
||||
}
|
||||
|
||||
echoLongTable(
|
||||
array('a.id as group_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.username) as user_count'),
|
||||
$from, $cond, 'group by a.id order by a.id asc',
|
||||
$header,
|
||||
'echoGroup',
|
||||
$table_config
|
||||
);
|
||||
?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<!-- end left col -->
|
||||
</div>
|
||||
|
||||
@ -129,6 +106,5 @@ EOD;
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
||||
|
251
web/app/controllers/list.php
Normal file
251
web/app/controllers/list.php
Normal file
@ -0,0 +1,251 @@
|
||||
<?php
|
||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
||||
redirectToLogin();
|
||||
}
|
||||
|
||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
||||
become403Page();
|
||||
}
|
||||
|
||||
requireLib('bootstrap5');
|
||||
requireLib('mathjax');
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
|
||||
$list_id = $_GET['id'];
|
||||
|
||||
if (!validateUInt($list_id) || !($list = queryProblemList($list_id))) {
|
||||
become404Page();
|
||||
}
|
||||
|
||||
if ($list['is_hidden'] && !isSuperUser($myUser)) {
|
||||
become403Page();
|
||||
}
|
||||
|
||||
function echoProblem($problem) {
|
||||
global $myUser;
|
||||
|
||||
if (isProblemVisibleToUser($problem, $myUser)) {
|
||||
echo '<tr class="text-center">';
|
||||
if ($problem['submission_id']) {
|
||||
echo '<td class="table-success">';
|
||||
} else {
|
||||
echo '<td>';
|
||||
}
|
||||
echo '#', $problem['id'], '</td>';
|
||||
echo '<td class="text-start">';
|
||||
echo '<a class="text-decoration-none" href="/problem/', $problem['id'], '">', $problem['title'], '</a>';
|
||||
|
||||
if ($problem['uploader'] == $myUser['username']) {
|
||||
echo ' <span class="badge text-white bg-info">', UOJLocale::get('problems::my problem') ,'</span> ';
|
||||
}
|
||||
|
||||
if ($problem['is_hidden']) {
|
||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||
}
|
||||
|
||||
if (isset($_COOKIE['show_tags_mode'])) {
|
||||
foreach (queryProblemTags($problem['id']) as $tag) {
|
||||
echo ' <a class="uoj-problem-tag my-1">';
|
||||
echo '<span class="badge bg-secondary">', HTML::escape($tag), '</span>';
|
||||
echo '</a> ';
|
||||
}
|
||||
}
|
||||
echo '</td>';
|
||||
if (isset($_COOKIE['show_submit_mode'])) {
|
||||
$perc = $problem['submit_num'] > 0 ? round(100 * $problem['ac_num'] / $problem['submit_num']) : 0;
|
||||
echo <<<EOD
|
||||
<td><a href="/submissions?problem_id={$problem['id']}&min_score=100&max_score=100">×{$problem['ac_num']}</a></td>
|
||||
<td><a href="/submissions?problem_id={$problem['id']}">×{$problem['submit_num']}</a></td>
|
||||
<td>
|
||||
<div class="progress bot-buffer-no">
|
||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="$perc" aria-valuemin="0" aria-valuemax="100" style="width: $perc%; min-width: 20px;">{$perc}%</div>
|
||||
</div>
|
||||
</td>
|
||||
EOD;
|
||||
}
|
||||
if (isset($_COOKIE['show_difficulty'])) {
|
||||
$extra_config = getProblemExtraConfig($problem);
|
||||
if ($extra_config['difficulty'] == 0) {
|
||||
echo "<td></td>";
|
||||
} else {
|
||||
echo "<td>{$extra_config['difficulty']}</td>";
|
||||
}
|
||||
}
|
||||
echo '<td class="text-start">', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
$header = '<tr>';
|
||||
$header .= '<th class="text-center" style="width:5em;">ID</th>';
|
||||
$header .= '<th>'.UOJLocale::get('problems::problem').'</th>';
|
||||
if (isset($_COOKIE['show_submit_mode'])) {
|
||||
$header .= '<th class="text-center" style="width:4em">'.UOJLocale::get('problems::ac').'</th>';
|
||||
$header .= '<th class="text-center" style="width:4em">'.UOJLocale::get('problems::submit').'</th>';
|
||||
$header .= '<th class="text-center" style="width:125px;">'.UOJLocale::get('problems::ac ratio').'</th>';
|
||||
}
|
||||
if (isset($_COOKIE['show_difficulty'])) {
|
||||
$header .= '<th class="text-center" style="width:3em;">'.UOJLocale::get('problems::difficulty').'</th>';
|
||||
}
|
||||
$header .= '<th class="text-center" style="width:100px;">'.UOJLocale::get('appraisal').'</th>';
|
||||
$header .= '</tr>';
|
||||
|
||||
$pag_config = [
|
||||
'page_len' => 40,
|
||||
'col_names' => [
|
||||
'best_ac_submissions.submission_id as submission_id',
|
||||
'problems.id as id',
|
||||
'problems.is_hidden as is_hidden',
|
||||
'problems.title as title',
|
||||
'problems.submit_num as submit_num',
|
||||
'problems.ac_num as ac_num',
|
||||
'problems.zan as zan',
|
||||
'problems.extra_config as extra_config',
|
||||
'problems.uploader as uploader',
|
||||
],
|
||||
'table_name' => "problems left join best_ac_submissions on best_ac_submissions.submitter = '{$myUser['username']}' and problems.id = best_ac_submissions.problem_id inner join lists_problems lp on lp.list_id = {$list_id} and lp.problem_id = problems.id",
|
||||
'cond' => '1',
|
||||
'tail' => 'ORDER BY `id` ASC',
|
||||
];
|
||||
$pag = new Paginator($pag_config);
|
||||
?>
|
||||
<?php echoUOJPageHeader(UOJLocale::get('problems lists')); ?>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<!-- left col -->
|
||||
<div class="col-lg-9">
|
||||
|
||||
<!-- title container -->
|
||||
<div class="d-flex justify-content-between">
|
||||
|
||||
<h1 class="h2">
|
||||
<?= $list['title'] ?>
|
||||
<span class="fs-5">(ID: #<?= $list['id'] ?>)</span>
|
||||
<?php if ($list['is_hidden']): ?>
|
||||
<span class="badge text-bg-danger fs-6">
|
||||
<i class="bi bi-eye-slash-fill"></i>
|
||||
<?= UOJLocale::get('hidden') ?>
|
||||
</span>
|
||||
<?php endif ?>
|
||||
</h1>
|
||||
|
||||
<?php if (isSuperUser($myUser)): ?>
|
||||
<div class="text-end">
|
||||
<a class="btn btn-primary" href="/list/<?= $list['id'] ?>/edit" role="button">
|
||||
<?= UOJLocale::get('problems::manage') ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
</div>
|
||||
<!-- end title container -->
|
||||
|
||||
<!-- description -->
|
||||
<div class="card my-2">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 mb-3">题单简介</h2>
|
||||
<?php $description = HTML::purifier()->purify(HTML::parsedown()->text($list['description'])) ?>
|
||||
<?php if ($description): ?>
|
||||
<?= $description ?>
|
||||
<?php else: ?>
|
||||
<p class="text-muted">暂无简介</p>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-12"></div>
|
||||
<div class="text-end p-2 col-12 col-sm-8">
|
||||
<div class="form-check d-inline-block me-2">
|
||||
<input type="checkbox" id="input-show_tags_mode" class="form-check-input"
|
||||
<?= isset($_COOKIE['show_tags_mode']) ? 'checked="checked" ': ''?>
|
||||
/>
|
||||
<label class="form-check-label" for="input-show_tags_mode">
|
||||
<?= UOJLocale::get('problems::show tags') ?>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check d-inline-block">
|
||||
<input type="checkbox" id="input-show_submit_mode" class="form-check-input"
|
||||
<?= isset($_COOKIE['show_submit_mode']) ? 'checked="checked" ': ''?>
|
||||
/>
|
||||
<label class="form-check-label" for="input-show_submit_mode">
|
||||
<?= UOJLocale::get('problems::show statistics') ?>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check d-inline-block">
|
||||
<input type="checkbox" id="input-show_difficulty" class="form-check-input"
|
||||
<?= isset($_COOKIE['show_difficulty']) ? 'checked="checked" ': ''?>
|
||||
/>
|
||||
<label class="form-check-label" for="input-show_difficulty">
|
||||
<?= UOJLocale::get('problems::show difficulty') ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('#input-show_tags_mode').click(function() {
|
||||
if (this.checked) {
|
||||
$.cookie('show_tags_mode', '', {path: '/'});
|
||||
} else {
|
||||
$.removeCookie('show_tags_mode', {path: '/'});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
$('#input-show_submit_mode').click(function() {
|
||||
if (this.checked) {
|
||||
$.cookie('show_submit_mode', '', {path: '/'});
|
||||
} else {
|
||||
$.removeCookie('show_submit_mode', {path: '/'});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
$('#input-show_difficulty').click(function() {
|
||||
if (this.checked) {
|
||||
$.cookie('show_difficulty', '', {path: '/'});
|
||||
} else {
|
||||
$.removeCookie('show_difficulty', {path: '/'});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
</script>
|
||||
|
||||
<?= $pag->pagination() ?>
|
||||
|
||||
<div class="card my-3 table-responsive">
|
||||
<table class="table uoj-table mb-0">
|
||||
<thead>
|
||||
<?= $header ?>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($pag->get() as $idx => $row): ?>
|
||||
<?php echoProblem($row) ?>
|
||||
<?php endforeach ?>
|
||||
<?php if ($pag->isEmpty()): ?>
|
||||
<tr>
|
||||
<td class="text-center" colspan="233">
|
||||
<?= UOJLocale::get('none') ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<?= $pag->pagination() ?>
|
||||
|
||||
</div>
|
||||
<!-- end left col -->
|
||||
|
||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||
<?php uojIncludeView('sidebar'); ?>
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
542
web/app/controllers/list_edit.php
Normal file
542
web/app/controllers/list_edit.php
Normal file
@ -0,0 +1,542 @@
|
||||
<?php
|
||||
if (!Auth::check()) {
|
||||
redirectToLogin();
|
||||
}
|
||||
|
||||
requireLib('bootstrap5');
|
||||
requirePHPLib('form');
|
||||
|
||||
$list_id = $_GET['id'];
|
||||
|
||||
if (!validateUInt($list_id) || !($list = queryProblemList($list_id))) {
|
||||
become404Page();
|
||||
}
|
||||
|
||||
if (!isSuperUser($myUser)) {
|
||||
become403Page();
|
||||
}
|
||||
|
||||
if (isset($_GET['tab'])) {
|
||||
$cur_tab = $_GET['tab'];
|
||||
} else {
|
||||
$cur_tab = 'profile';
|
||||
}
|
||||
|
||||
$tabs_info = [
|
||||
'profile' => [
|
||||
'name' => '基本信息',
|
||||
'url' => "/list/{$list['id']}/edit/profile",
|
||||
],
|
||||
'problems' => [
|
||||
'name' => '题目管理',
|
||||
'url' => "/list/{$list['id']}/edit/problems",
|
||||
],
|
||||
'assignments' => [
|
||||
'name' => '对应作业',
|
||||
'url' => "/list/{$list['id']}/edit/assignments",
|
||||
]
|
||||
];
|
||||
|
||||
if (!isset($tabs_info[$cur_tab])) {
|
||||
become404Page();
|
||||
}
|
||||
|
||||
if ($cur_tab == 'profile') {
|
||||
$list_tags = queryProblemListTags($list_id);
|
||||
|
||||
$update_profile_form = new UOJForm('update_profile');
|
||||
$update_profile_form->addVInput('name', 'text', '标题', $list['title'],
|
||||
function($title, &$vdata) {
|
||||
if ($title == '') {
|
||||
return '标题不能为空';
|
||||
}
|
||||
|
||||
if (strlen($title) > 100) {
|
||||
return '标题过长';
|
||||
}
|
||||
|
||||
if (HTML::escape($title) === '') {
|
||||
return '无效编码';
|
||||
}
|
||||
|
||||
$vdata['title'] = $title;
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$update_profile_form->addVCheckboxes('is_hidden', [
|
||||
'0' => '公开',
|
||||
'1' => '隐藏',
|
||||
], '可见性', $list['is_hidden']);
|
||||
$update_profile_form->addVInput('tags', 'text', '标签(多个标签用逗号隔开)', implode(', ', $list_tags),
|
||||
function($tags_str, &$vdata) {
|
||||
$tags_str = str_replace(',', ',', $tags_str);
|
||||
$tags_raw = explode(',', $tags_str);
|
||||
$tags = [];
|
||||
|
||||
if (count($tags_raw) > 10) {
|
||||
return '不能存在超过 10 个标签';
|
||||
}
|
||||
|
||||
foreach ($tags_raw as $tag) {
|
||||
$tag = trim($tag);
|
||||
|
||||
if (strlen($tag) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strlen($tag) > 30) {
|
||||
return '标签 “' . HTML::escape($tag) .'” 太长';
|
||||
}
|
||||
|
||||
if (in_array($tag, $tags, true)) {
|
||||
return '标签 “' . HTML::escape($tag) .'” 重复出现';
|
||||
}
|
||||
|
||||
$tags[] = $tag;
|
||||
}
|
||||
|
||||
$vdata['tags'] = $tags;
|
||||
|
||||
return '';
|
||||
},
|
||||
null);
|
||||
$update_profile_form->addVTextArea('description', '描述', $list['description'],
|
||||
function($description, &$vdata) {
|
||||
if (strlen($description) > 3000) {
|
||||
return '描述过长';
|
||||
}
|
||||
|
||||
$vdata['description'] = $description;
|
||||
|
||||
return '';
|
||||
}, null);
|
||||
$update_profile_form->handle = function($vdata) use ($list, $list_tags) {
|
||||
$esc_title = DB::escape($vdata['title']);
|
||||
$is_hidden = $_POST['is_hidden'];
|
||||
$esc_description = DB::escape($vdata['description']);
|
||||
|
||||
DB::update("UPDATE `lists` SET `title` = '$esc_title', `is_hidden` = '$is_hidden', `description` = '$esc_description' WHERE id = {$list['id']}");
|
||||
|
||||
if ($vdata['tags'] !== $list_tags) {
|
||||
DB::delete("DELETE FROM `lists_tags` WHERE `list_id` = {$list['id']}");
|
||||
|
||||
foreach ($vdata['tags'] as $tag) {
|
||||
$esc_tag = DB::escape($tag);
|
||||
|
||||
DB::insert("INSERT INTO `lists_tags` (list_id, tag) VALUES ({$list['id']}, '$esc_tag')");
|
||||
}
|
||||
}
|
||||
|
||||
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
||||
};
|
||||
$update_profile_form->setAjaxSubmit(<<<EOD
|
||||
function(res) {
|
||||
if (res.status === 'success') {
|
||||
$('#result-alert')
|
||||
.html('题单信息修改成功!')
|
||||
.addClass('alert-success')
|
||||
.removeClass('alert-danger')
|
||||
.show();
|
||||
} else {
|
||||
$('#result-alert')
|
||||
.html('题单信息修改失败。' + (res.message || ''))
|
||||
.removeClass('alert-success')
|
||||
.addClass('alert-danger')
|
||||
.show();
|
||||
}
|
||||
|
||||
$(window).scrollTop(0);
|
||||
}
|
||||
EOD);
|
||||
$update_profile_form->submit_button_config['margin_class'] = 'mt-3';
|
||||
$update_profile_form->submit_button_config['text'] = '更新';
|
||||
$update_profile_form->runAtServer();
|
||||
} elseif ($cur_tab == 'problems') {
|
||||
if (isset($_POST['submit-remove_problem']) && $_POST['submit-remove_problem'] == 'remove_problem') {
|
||||
crsf_defend();
|
||||
|
||||
$problem_id = $_POST['problem_id'];
|
||||
|
||||
if (!validateUInt($problem_id)) {
|
||||
dieWithAlert('题目 ID 不合法');
|
||||
}
|
||||
|
||||
if (!queryProblemBrief($problem_id)) {
|
||||
dieWithAlert('题目不存在');
|
||||
}
|
||||
|
||||
if (!queryProblemInList($list['id'], $problem_id)) {
|
||||
dieWithAlert('题目不在题单中');
|
||||
}
|
||||
|
||||
DB::delete("DELETE FROM lists_problems WHERE problem_id = {$problem_id} AND list_id = {$list['id']}");
|
||||
|
||||
dieWithAlert('移除成功!');
|
||||
}
|
||||
|
||||
$n_problems = DB::selectCount("SELECT count(*) FROM `lists_problems` WHERE `list_id` = {$list['id']}");
|
||||
|
||||
$add_new_problem_form = new UOJForm('add_new_problem');
|
||||
$add_new_problem_form->addVInput('problem_id', 'text', '题目 ID', '',
|
||||
function ($problem_id, &$vdata) use ($list) {
|
||||
if (!validateUInt($problem_id)) {
|
||||
return 'ID 不合法';
|
||||
}
|
||||
|
||||
if (!queryProblemBrief($problem_id)) {
|
||||
return '题目不存在';
|
||||
}
|
||||
|
||||
if (queryProblemInList($list['id'], $problem_id)) {
|
||||
return '该题目已经在题单中';
|
||||
}
|
||||
|
||||
$vdata['problem_id'] = $problem_id;
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$add_new_problem_form->submit_button_config['margin_class'] = 'mt-3';
|
||||
$add_new_problem_form->submit_button_config['text'] = '添加';
|
||||
$add_new_problem_form->handle = function($vdata) use ($list) {
|
||||
DB::insert("INSERT INTO `lists_problems` (`list_id`, `problem_id`) values ({$list['id']}, {$vdata['problem_id']})");
|
||||
|
||||
dieWithJsonData(['status' => 'success', 'message' => '已将题目 #' . $vdata['problem_id'] . ' 添加到题单 #' . $list['id'] .' 中']);
|
||||
};
|
||||
$add_new_problem_form->setAjaxSubmit(<<<EOD
|
||||
function(res) {
|
||||
if (res.status === 'success') {
|
||||
$('#result-alert')
|
||||
.html('题目添加成功!' + (res.message || ''))
|
||||
.addClass('alert-success')
|
||||
.removeClass('alert-danger')
|
||||
.show();
|
||||
} else {
|
||||
$('#result-alert')
|
||||
.html('题目添加失败。' + (res.message || ''))
|
||||
.removeClass('alert-success')
|
||||
.addClass('alert-danger')
|
||||
.show();
|
||||
}
|
||||
|
||||
$(window).scrollTop(0);
|
||||
}
|
||||
EOD);
|
||||
$add_new_problem_form->runAtServer();
|
||||
} elseif ($cur_tab == 'assignments') {
|
||||
if (isset($_POST['submit-remove_assignment']) && $_POST['submit-remove_assignment'] == 'remove_assignment') {
|
||||
crsf_defend();
|
||||
|
||||
$group_id = $_POST['group_id'];
|
||||
|
||||
if (!validateUInt($group_id)) {
|
||||
dieWithAlert('小组 ID 不合法。');
|
||||
}
|
||||
|
||||
if (!queryGroup($group_id)) {
|
||||
dieWithAlert('小组不存在。');
|
||||
}
|
||||
|
||||
if (!queryAssignmentByGroupListID($group_id, $list['id'])) {
|
||||
dieWithAlert('该小组并未将本题单布置为作业。');
|
||||
}
|
||||
|
||||
DB::delete("DELETE FROM groups_assignments WHERE group_id = {$group_id} AND list_id = {$list['id']}");
|
||||
|
||||
dieWithAlert('移除成功!');
|
||||
}
|
||||
|
||||
$add_new_assignment_form = new UOJForm('add_new_assignment');
|
||||
$add_new_assignment_form->addVInput('new_assignment_group_id', 'text', '小组 ID', '',
|
||||
function ($group_id, &$vdata) use ($list) {
|
||||
if (!validateUInt($group_id)) {
|
||||
return '小组 ID 不合法';
|
||||
}
|
||||
|
||||
if (!($list = queryGroup($group_id))) {
|
||||
return '小组不存在';
|
||||
}
|
||||
|
||||
if ($list['is_hidden'] != 0) {
|
||||
return '题单是隐藏的';
|
||||
}
|
||||
|
||||
if (queryAssignmentByGroupListID($group_id, $list['id'])) {
|
||||
return '该题单已经是这个小组的作业';
|
||||
}
|
||||
|
||||
$vdata['group_id'] = $group_id;
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$default_end_time = new DateTime();
|
||||
$default_end_time->setTime(22, 30, 0);
|
||||
$default_end_time->add(new DateInterval("P7D"));
|
||||
$add_new_assignment_form->addVInput('new_assignment_end_time', 'text', '截止时间', $default_end_time->format('Y-m-d H:i'),
|
||||
function ($end_time, &$vdata) {
|
||||
try {
|
||||
$vdata['end_time'] = new DateTime($end_time);
|
||||
} catch (Exception $e) {
|
||||
return '无效时间格式';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$add_new_assignment_form->handle = function(&$vdata) use ($list) {
|
||||
$esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s'));
|
||||
|
||||
DB::insert("insert into groups_assignments (group_id, list_id, end_time) values ({$vdata['group_id']}, '{$list['id']}', '{$esc_end_time}')");
|
||||
|
||||
dieWithJsonData([
|
||||
'status' => 'success',
|
||||
'message' => '题单 #' . $list['id'] . ' 已经被添加到小组 #' . $vdata['group_id'] . ' 的作业列表中,结束时间为 ' . $vdata['end_time']->format('Y-m-d H:i:s') . '。'
|
||||
]);
|
||||
};
|
||||
$add_new_assignment_form->submit_button_config['margin_class'] = 'mt-3';
|
||||
$add_new_assignment_form->submit_button_config['text'] = '添加';
|
||||
$add_new_assignment_form->setAjaxSubmit(<<<EOD
|
||||
function(res) {
|
||||
if (res.status === 'success') {
|
||||
$('#result-alert')
|
||||
.html('作业添加成功!' + (res.message || ''))
|
||||
.addClass('alert-success')
|
||||
.removeClass('alert-danger')
|
||||
.show();
|
||||
} else {
|
||||
$('#result-alert')
|
||||
.html('作业添加失败。' + (res.message || ''))
|
||||
.removeClass('alert-success')
|
||||
.addClass('alert-danger')
|
||||
.show();
|
||||
}
|
||||
|
||||
$(window).scrollTop(0);
|
||||
}
|
||||
EOD);
|
||||
$add_new_assignment_form->runAtServer();
|
||||
|
||||
$now = new DateTime();
|
||||
$hidden_time = new DateTime();
|
||||
$hidden_time->sub(new DateInterval('P7D'));
|
||||
}
|
||||
?>
|
||||
|
||||
<?php echoUOJPageHeader('管理 - ' . $list['title']) ?>
|
||||
|
||||
<h1 class="h2">
|
||||
<?= $list['title'] ?>
|
||||
<small class="fs-5">(ID: #<?= $list['id'] ?>)</small>
|
||||
管理
|
||||
</h1>
|
||||
|
||||
<div class="row mt-4">
|
||||
<!-- left col -->
|
||||
<div class="col-md-3">
|
||||
|
||||
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
||||
|
||||
<a
|
||||
class="btn btn-light d-block mt-2 w-100 text-start text-primary"
|
||||
style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;"
|
||||
href="<?= HTML::url("/list/{$list['id']}") ?>">
|
||||
<i class="bi bi-arrow-left"></i> 返回
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<!-- end left col -->
|
||||
|
||||
<!-- right col -->
|
||||
<div class="col-md-9">
|
||||
<?php if ($cur_tab == 'profile'): ?>
|
||||
<div class="card mt-3 mt-md-0">
|
||||
<div class="card-body">
|
||||
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
||||
<div class="row row-cols-1 row-cols-md-2">
|
||||
<div class="col">
|
||||
<?= $update_profile_form->printHTML() ?>
|
||||
</div>
|
||||
<div class="col mt-3 mt-md-0">
|
||||
<h5>注意事项</h5>
|
||||
<ul class="mb-0">
|
||||
<li>隐藏的题单无法被普通用户查看。</li>
|
||||
<li>题单描述支持 Markdown 语法。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php elseif ($cur_tab == 'problems'): ?>
|
||||
<div class="card mt-3 mt-md-0">
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#problems" data-bs-toggle="tab" data-bs-target="#problems">题目列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#add-problem" data-bs-toggle="tab" data-bs-target="#add-problem">添加题目</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body tab-content">
|
||||
<div class="tab-pane active" id="problems">
|
||||
<?php
|
||||
echoLongTable(
|
||||
[
|
||||
'problems.id as id',
|
||||
'problems.title as title',
|
||||
'problems.is_hidden as is_hidden',
|
||||
],
|
||||
"problems inner join lists_problems on lists_problems.list_id = {$list['id']} and lists_problems.problem_id = problems.id",
|
||||
"1",
|
||||
'ORDER BY `id` ASC',
|
||||
<<<EOD
|
||||
<tr>
|
||||
<th class="text-center" style="width:5em">ID</th>
|
||||
<th>标题</th>
|
||||
<th style="width:4em">操作</th>
|
||||
</tr>
|
||||
EOD,
|
||||
function ($row) {
|
||||
echo '<tr>';
|
||||
|
||||
echo '<td class="text-center">', $row['id'], '</td>';
|
||||
echo '<td>', '<a class="text-decoration-none" href="', HTML::url('/problem/' . $row['id']),'">', $row['title'], '</a>';
|
||||
if ($row['is_hidden']) {
|
||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||
}
|
||||
echo '</td>';
|
||||
echo '<td>';
|
||||
echo '<form target="_self" method="POST" class="d-inline-block" onsubmit=\'return confirm("你确定要将题目 #', $row['id'],' 从题单中移除吗?")\'>';
|
||||
echo '<input type="hidden" name="_token" value="', crsf_token(), '">';
|
||||
echo '<input type="hidden" name="problem_id" value="', $row['id'], '">';
|
||||
echo '<button class="btn btn-link text-danger text-decoration-none p-0" name="submit-remove_problem" value="remove_problem">移除</button>';
|
||||
echo '</form>';
|
||||
echo '</td>';
|
||||
|
||||
echo '</tr>';
|
||||
},
|
||||
[
|
||||
'page_len' => 20,
|
||||
'div_classes' => ['table-responsive'],
|
||||
'table_classes' => ['table', 'align-middle'],
|
||||
'print_after_table' => function() use ($n_problems) {
|
||||
echo '<div class="text-muted text-end">共 ', $n_problems,' 道题目</div>';
|
||||
},
|
||||
]
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<div class="tab-pane" id="add-problem">
|
||||
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
||||
<div class="row row-cols-1 row-cols-md-2">
|
||||
<div class="col">
|
||||
<?php $add_new_problem_form->printHTML() ?>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h5>注意事项</h5>
|
||||
<ul class="mt-0">
|
||||
<li>隐藏的题目添加进题单后无法被普通用户查看。</li>
|
||||
<li>如当前题单已经被设置为某个小组的作业,则作业也会一并更新。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php elseif ($cur_tab == 'assignments'): ?>
|
||||
<div class="card mt-3 mt-md-0">
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#assignments" data-bs-toggle="tab" data-bs-target="#assignments">作业列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#add-assignment" data-bs-toggle="tab" data-bs-target="#add-assignment">添加作业</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="assignments">
|
||||
<?php
|
||||
echoLongTable(
|
||||
['*'],
|
||||
'groups_assignments',
|
||||
"list_id = {$list['id']}",
|
||||
'order by end_time desc, group_id asc',
|
||||
<<<EOD
|
||||
<tr>
|
||||
<th style="width:4em" class="text-center">小组 ID</th>
|
||||
<th style="width:12em">名称</th>
|
||||
<th style="width:4em">状态</th>
|
||||
<th style="width:8em">结束时间</th>
|
||||
<th style="width:8em">操作</th>
|
||||
</tr>
|
||||
EOD,
|
||||
function($row) use ($list, $now, $hidden_time) {
|
||||
$group = queryGroup($row['group_id']);
|
||||
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']);
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td class="text-center">', $group['id'], '</td>';
|
||||
echo '<td>', '<a class="text-decoration-none" href="/group/', $group['id'], '">', HTML::escape($group['title']), '</a>', '</td>';
|
||||
if ($end_time < $hidden_time) {
|
||||
echo '<td class="text-secondary">已隐藏</td>';
|
||||
} elseif ($end_time < $now) {
|
||||
echo '<td class="text-danger">已结束</td>';
|
||||
} else {
|
||||
echo '<td class="text-success">进行中</td>';
|
||||
}
|
||||
echo '<td>', $end_time->format('Y-m-d H:i:s'), '</td>';
|
||||
echo '<td>';
|
||||
echo ' <a class="text-decoration-none d-inline-block align-middle" href="/group/', $group['id'], '/assignment/', $list['id'],'">排行榜</a> ';
|
||||
echo ' <form class="d-inline-block" method="POST" onsubmit=\'return confirm("你真的要为小组 #', $group['id'], ' 移除这份作业吗?移除作业不会删除题单。")\'>'
|
||||
. '<input type="hidden" name="_token" value="' . crsf_token() . '">'
|
||||
. '<input type="hidden" name="group_id" value="' . $group['id'] . '">'
|
||||
. '<button class="btn btn-link text-danger text-decoration-none p-0" type="submit" name="submit-remove_assignment" value="remove_assignment">移除</button>'
|
||||
. '</form>';
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
},
|
||||
[
|
||||
'page_len' => 20,
|
||||
'div_classes' => ['table-responsive'],
|
||||
'table_classes' => ['table', 'align-middle'],
|
||||
]
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<div class="tab-pane" id="add-assignment">
|
||||
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
||||
<div class="row row-cols-1 row-cols-md-2">
|
||||
<div class="col">
|
||||
<?php $add_new_assignment_form->printHTML() ?>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h5>注意事项</h5>
|
||||
<ul class="mt-0">
|
||||
<li>请为学生预留合理的完成作业的时间。</li>
|
||||
<li>排行榜将在作业结束后停止更新。</li>
|
||||
<li>如需延长结束时间请删除后再次添加,排行数据不会丢失。</li>
|
||||
<li>作业结束七天后将会自动在小组主页中隐藏,但仍可直接通过 URL 访问。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<!-- end right col -->
|
||||
|
||||
</div>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
165
web/app/controllers/lists.php
Normal file
165
web/app/controllers/lists.php
Normal file
@ -0,0 +1,165 @@
|
||||
<?php
|
||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
||||
redirectToLogin();
|
||||
}
|
||||
|
||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
||||
become403Page();
|
||||
}
|
||||
|
||||
requireLib('bootstrap5');
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
|
||||
if (isSuperUser($myUser)) {
|
||||
$new_list_form = new UOJForm('new_list');
|
||||
$new_list_form->handle = function() {
|
||||
DB::query("insert into lists (title, is_hidden) values ('未命名题单', 1)");
|
||||
};
|
||||
$new_list_form->submit_button_config['align'] = 'right';
|
||||
$new_list_form->submit_button_config['class_str'] = 'btn btn-primary';
|
||||
$new_list_form->submit_button_config['text'] = UOJLocale::get('problems::add new list');
|
||||
$new_list_form->submit_button_config['smart_confirm'] = '';
|
||||
|
||||
$new_list_form->runAtServer();
|
||||
}
|
||||
|
||||
function echoList($list) {
|
||||
global $myUser;
|
||||
|
||||
if (isListVisibleToUser($list, $myUser)) {
|
||||
echo '<tr class="text-center">';
|
||||
if ($list['problem_count'] == $list['accepted'] && $list['problem_count'] > 0) {
|
||||
echo '<td class="success">';
|
||||
} else {
|
||||
echo '<td>';
|
||||
}
|
||||
echo '#', $list['list_id'], '</td>';
|
||||
|
||||
echo '<td class="text-start">';
|
||||
echo '<a class="text-decoration-none" href="/list/', $list['list_id'], '">', $list['title'], '</a> ';
|
||||
|
||||
if ($list['is_hidden']) {
|
||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||
}
|
||||
|
||||
foreach (queryProblemListTags($list['list_id']) as $tag) {
|
||||
echo '<a class="uoj-list-tag my-1">', '<span class="badge bg-secondary">', HTML::escape($tag), '</span>', '</a> ';
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
echo "<td>{$list['accepted']}</td>";
|
||||
echo "<td>{$list['problem_count']}</td>";
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php echoUOJPageHeader(UOJLocale::get('problems lists')) ?>
|
||||
|
||||
<div class="row">
|
||||
<!-- left col -->
|
||||
<div class="col-lg-9">
|
||||
|
||||
<!-- title container -->
|
||||
<div class="d-flex justify-content-between">
|
||||
|
||||
<h1 class="h2">
|
||||
<?= UOJLocale::get('problems lists') ?>
|
||||
</h1>
|
||||
|
||||
<?php if (isset($new_list_form)): ?>
|
||||
<div class="text-end mb-2">
|
||||
<?php $new_list_form->printHTML(); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
</div>
|
||||
<!-- end title container -->
|
||||
|
||||
<?php
|
||||
$list_caption = UOJLocale::get('problems::problem list');
|
||||
$ac_caption = UOJLocale::get('problems::ac');
|
||||
$total_caption = UOJLocale::get('problems::total');
|
||||
$header = <<<EOD
|
||||
<tr>
|
||||
<th class="text-center" style="width:5em;">ID</th>
|
||||
<th>{$list_caption}</th>
|
||||
<th class="text-center" style="width:5em;">{$ac_caption}</th>
|
||||
<th class="text-center" style="width:5em;">{$total_caption}</th>
|
||||
</tr>
|
||||
EOD;
|
||||
|
||||
$cond = [];
|
||||
$search_tag = null;
|
||||
|
||||
if (isset($_GET['tag'])) {
|
||||
$search_tag = $_GET['tag'];
|
||||
}
|
||||
|
||||
if ($search_tag) {
|
||||
$cond[] = "'" . DB::escape($search_tag) . "' in (select tag from lists_tags where lists_tags.list_id = a.id)";
|
||||
}
|
||||
|
||||
if ($cond) {
|
||||
$cond = join($cond, ' and ');
|
||||
} else {
|
||||
$cond = '1';
|
||||
}
|
||||
|
||||
echoLongTable(
|
||||
array('a.id as list_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.problem_id) as problem_count', 'count(c.submitter) as accepted'),
|
||||
"lists a left join lists_problems b on a.id = b.list_id left join best_ac_submissions c on (b.problem_id = c.problem_id and c.submitter = '{$myUser['username']}')",
|
||||
$cond,
|
||||
'group by a.id order by a.id desc',
|
||||
$header,
|
||||
function($list) use ($myUser) {
|
||||
if (isListVisibleToUser($list, $myUser)) {
|
||||
echo '<tr class="text-center">';
|
||||
if ($list['problem_count'] == $list['accepted'] && $list['problem_count'] > 0) {
|
||||
echo '<td class="success">';
|
||||
} else {
|
||||
echo '<td>';
|
||||
}
|
||||
echo '#', $list['list_id'], '</td>';
|
||||
|
||||
echo '<td class="text-start">';
|
||||
echo '<a class="text-decoration-none" href="/list/', $list['list_id'], '">', $list['title'], '</a> ';
|
||||
|
||||
if ($list['is_hidden']) {
|
||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||
}
|
||||
|
||||
foreach (queryProblemListTags($list['list_id']) as $tag) {
|
||||
echo '<a class="uoj-list-tag my-1">', '<span class="badge bg-secondary">', HTML::escape($tag), '</span>', '</a> ';
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
echo "<td>{$list['accepted']}</td>";
|
||||
echo "<td>{$list['problem_count']}</td>";
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
},
|
||||
[
|
||||
'page_len' => 40,
|
||||
'table_classes' => ['table', 'table-bordered', 'table-hover', 'table-striped'],
|
||||
'head_pagination' => true,
|
||||
'pagination_table' => 'lists',
|
||||
'div_classes' => ['card', 'my-3'],
|
||||
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
||||
]
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<!-- end left col -->
|
||||
|
||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||
<?php uojIncludeView('sidebar') ?>
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
@ -1,315 +0,0 @@
|
||||
<?php
|
||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
||||
redirectToLogin();
|
||||
}
|
||||
|
||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
||||
become403Page();
|
||||
}
|
||||
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
|
||||
$list_id = $_GET['id'];
|
||||
|
||||
if (!validateUInt($list_id) || !($list = queryProblemList($list_id))) {
|
||||
become404Page();
|
||||
}
|
||||
|
||||
if (!isset($_COOKIE['bootstrap4'])) {
|
||||
$REQUIRE_LIB['bootstrap5'] = '';
|
||||
}
|
||||
|
||||
function echoProblem($problem) {
|
||||
global $myUser, $removeProblemForms, $REQUIRE_LIB;
|
||||
|
||||
if (isProblemVisibleToUser($problem, $myUser)) {
|
||||
echo '<tr class="text-center">';
|
||||
if ($problem['submission_id']) {
|
||||
echo '<td class="table-success">';
|
||||
} else {
|
||||
echo '<td>';
|
||||
}
|
||||
echo '#', $problem['id'], '</td>';
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo '<td class="text-start">';
|
||||
} else {
|
||||
echo '<td class="text-left">';
|
||||
}
|
||||
echo '<a ';
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo ' class="text-decoration-none" ';
|
||||
}
|
||||
echo ' href="/problem/', $problem['id'], '">', $problem['title'], '</a>';
|
||||
|
||||
if ($problem['uploader'] == $myUser['username']) {
|
||||
echo ' <span class="badge text-white bg-info">', UOJLocale::get('problems::my problem') ,'</span> ';
|
||||
}
|
||||
|
||||
if ($problem['is_hidden']) {
|
||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||
}
|
||||
|
||||
if (isset($_COOKIE['show_tags_mode'])) {
|
||||
foreach (queryProblemTags($problem['id']) as $tag) {
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo ' <a class="uoj-problem-tag my-1">';
|
||||
echo '<span class="badge bg-secondary">';
|
||||
} else {
|
||||
echo ' <a class="uoj-problem-tag">';
|
||||
echo '<span class="badge badge-pill badge-secondary">';
|
||||
}
|
||||
echo HTML::escape($tag), '</span>';
|
||||
echo '</a> ';
|
||||
}
|
||||
}
|
||||
echo '</td>';
|
||||
if (isset($_COOKIE['show_submit_mode'])) {
|
||||
$perc = $problem['submit_num'] > 0 ? round(100 * $problem['ac_num'] / $problem['submit_num']) : 0;
|
||||
echo <<<EOD
|
||||
<td><a href="/submissions?problem_id={$problem['id']}&min_score=100&max_score=100">×{$problem['ac_num']}</a></td>
|
||||
<td><a href="/submissions?problem_id={$problem['id']}">×{$problem['submit_num']}</a></td>
|
||||
<td>
|
||||
<div class="progress bot-buffer-no">
|
||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="$perc" aria-valuemin="0" aria-valuemax="100" style="width: $perc%; min-width: 20px;">{$perc}%</div>
|
||||
</div>
|
||||
</td>
|
||||
EOD;
|
||||
}
|
||||
if (isset($_COOKIE['show_difficulty'])) {
|
||||
$extra_config = getProblemExtraConfig($problem);
|
||||
if ($extra_config['difficulty'] == 0) {
|
||||
echo "<td></td>";
|
||||
} else {
|
||||
echo "<td>{$extra_config['difficulty']}</td>";
|
||||
}
|
||||
}
|
||||
echo '<td class="text-left">', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
$header = '<tr>';
|
||||
$header .= '<th class="text-center" style="width:5em;">ID</th>';
|
||||
$header .= '<th>'.UOJLocale::get('problems::problem').'</th>';
|
||||
if (isset($_COOKIE['show_submit_mode'])) {
|
||||
$header .= '<th class="text-center" style="width:' . (isset($REQUIRE_LIB['bootstrap5']) ? '4' : '5') . 'em;">'.UOJLocale::get('problems::ac').'</th>';
|
||||
$header .= '<th class="text-center" style="width:' . (isset($REQUIRE_LIB['bootstrap5']) ? '4' : '5') . 'em;">'.UOJLocale::get('problems::submit').'</th>';
|
||||
$header .= '<th class="text-center" style="width:' . (isset($REQUIRE_LIB['bootstrap5']) ? '125' : '150') . 'px;">'.UOJLocale::get('problems::ac ratio').'</th>';
|
||||
}
|
||||
if (isset($_COOKIE['show_difficulty'])) {
|
||||
$header .= '<th class="text-center" style="width:3em;">'.UOJLocale::get('problems::difficulty').'</th>';
|
||||
}
|
||||
$header .= '<th class="text-center" style="width:100px;">'.UOJLocale::get('appraisal').'</th>';
|
||||
$header .= '</tr>';
|
||||
|
||||
$pag_config = array('page_len' => 40);
|
||||
$pag_config['col_names'] = array('best_ac_submissions.submission_id as submission_id', 'problems.id as id', 'problems.is_hidden as is_hidden', 'problems.title as title', 'problems.submit_num as submit_num', 'problems.ac_num as ac_num', 'problems.zan as zan', 'problems.extra_config as extra_config', 'problems.uploader as uploader', 'problems.extra_config as extra_config');
|
||||
|
||||
$pag_config['table_name'] = "problems left join best_ac_submissions on best_ac_submissions.submitter = '{$myUser['username']}' and problems.id = best_ac_submissions.problem_id inner join lists_problems lp on lp.list_id = {$list_id} and lp.problem_id = problems.id";
|
||||
|
||||
$pag_config['cond'] = '1';
|
||||
$pag_config['tail'] = "order by id asc";
|
||||
$pag = new Paginator($pag_config);
|
||||
|
||||
$div_classes = isset($REQUIRE_LIB['bootstrap5'])
|
||||
? array('card', 'my-3', 'table-responsive')
|
||||
: array('table-responsive');
|
||||
$table_classes = isset($REQUIRE_LIB['bootstrap5'])
|
||||
? array('table', 'uoj-table', 'mb-0')
|
||||
: array('table', 'table-bordered', 'table-hover', 'table-striped');
|
||||
?>
|
||||
<?php echoUOJPageHeader(UOJLocale::get('problems lists')); ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-9">
|
||||
<div class="d-flex justify-content-between">
|
||||
<?php endif ?>
|
||||
<h1 class="h2">
|
||||
<?php if ($list['is_hidden']): ?>
|
||||
<span class="fs-5 text-danger">[隐藏]</span>
|
||||
<?php endif ?>
|
||||
<?= $list['title'] ?>
|
||||
<span class="fs-5">(ID: #<?= $list['id'] ?>)</span>
|
||||
</h1>
|
||||
|
||||
<?php if (isSuperUser($myUser)): ?>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="text-end">
|
||||
<a class="btn btn-primary" href="/problem_list/<?= $list['id'] ?>/manage" role="button">
|
||||
<?= UOJLocale::get('problems::manage') ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/problem_list/<?= $list['id'] ?>/manage" role="tab">
|
||||
<?= UOJLocale::get('problems::manage') ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-4
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
col-12
|
||||
<?php endif ?>
|
||||
"></div>
|
||||
<div class="
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
text-end p-2 col-12 col-sm-8
|
||||
<?php else: ?>
|
||||
text-right checkbox order-sm-5 col-sm-4
|
||||
<?php endif ?>
|
||||
">
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="form-check d-inline-block me-2">
|
||||
<?php else: ?>
|
||||
<label class="checkbox-inline" for="input-show_tags_mode">
|
||||
<?php endif ?>
|
||||
<input type="checkbox" id="input-show_tags_mode"
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
class="form-check-input"
|
||||
<?php endif ?>
|
||||
<?= isset($_COOKIE['show_tags_mode']) ? 'checked="checked" ': ''?>
|
||||
/>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<label class="form-check-label" for="input-show_tags_mode">
|
||||
<?php endif ?>
|
||||
<?= UOJLocale::get('problems::show tags') ?>
|
||||
|
||||
</label>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="form-check d-inline-block">
|
||||
<?php else: ?>
|
||||
<label class="checkbox-inline" for="input-show_submit_mode">
|
||||
<?php endif ?>
|
||||
<input type="checkbox" id="input-show_submit_mode"
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
class="form-check-input"
|
||||
<?php endif ?>
|
||||
<?= isset($_COOKIE['show_submit_mode']) ? 'checked="checked" ': ''?>
|
||||
/>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<label class="form-check-label" for="input-show_submit_mode">
|
||||
<?php endif ?>
|
||||
<?= UOJLocale::get('problems::show statistics') ?>
|
||||
</label>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="form-check d-inline-block">
|
||||
<?php else: ?>
|
||||
<label class="checkbox-inline" for="input-show_difficulty">
|
||||
<?php endif ?>
|
||||
<input type="checkbox" id="input-show_difficulty"
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
class="form-check-input"
|
||||
<?php endif ?>
|
||||
<?= isset($_COOKIE['show_difficulty']) ? 'checked="checked" ': ''?> />
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<label class="form-check-label" for="input-show_difficulty">
|
||||
<?php endif ?>
|
||||
<?= UOJLocale::get('problems::show difficulty') ?>
|
||||
</label>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<?php if (!isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="col-sm-4 order-sm-3">
|
||||
<?= $pag->pagination(); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="text-center">
|
||||
<?= $pag->pagination(); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (!isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="top-buffer-sm"></div>
|
||||
<?php endif ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('#input-show_tags_mode').click(function() {
|
||||
if (this.checked) {
|
||||
$.cookie('show_tags_mode', '', {path: '/'});
|
||||
} else {
|
||||
$.removeCookie('show_tags_mode', {path: '/'});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
$('#input-show_submit_mode').click(function() {
|
||||
if (this.checked) {
|
||||
$.cookie('show_submit_mode', '', {path: '/'});
|
||||
} else {
|
||||
$.removeCookie('show_submit_mode', {path: '/'});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
$('#input-show_difficulty').click(function() {
|
||||
if (this.checked) {
|
||||
$.cookie('show_difficulty', '', {path: '/'});
|
||||
} else {
|
||||
$.removeCookie('show_difficulty', {path: '/'});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="<?= join($div_classes, ' ') ?>">
|
||||
<table class="<?= join($table_classes, ' ') ?>">
|
||||
<thead>
|
||||
<?= $header ?>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ($pag->get() as $idx => $row) {
|
||||
echoProblem($row);
|
||||
echo "\n";
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if ($pag->isEmpty()): ?>
|
||||
<tr>
|
||||
<td class="text-center" colspan="233">
|
||||
<?= UOJLocale::get('none') ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif ?>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<?= $pag->pagination(); ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
|
||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||
<?php uojIncludeView('sidebar'); ?>
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
@ -1,194 +0,0 @@
|
||||
<?php
|
||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
||||
redirectToLogin();
|
||||
}
|
||||
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
|
||||
$list_id = $_GET['id'];
|
||||
|
||||
if (!validateUInt($list_id) || !($list = queryProblemList($list_id))) {
|
||||
become404Page();
|
||||
}
|
||||
|
||||
if (!isSuperUser($myUser)) {
|
||||
become403Page();
|
||||
}
|
||||
|
||||
$list_tags = queryProblemListTags($list_id);
|
||||
|
||||
$list_editor = new UOJBlogEditor();
|
||||
$list_editor->name = 'list';
|
||||
$list_editor->blog_url = null;
|
||||
$list_editor->cur_data = array(
|
||||
'title' => $list['title'],
|
||||
'tags' => $list_tags,
|
||||
'is_hidden' => $list['is_hidden']
|
||||
);
|
||||
$list_editor->label_text = array_merge($list_editor->label_text, array(
|
||||
'view blog' => '保存题单信息',
|
||||
'blog visibility' => '题单可见性'
|
||||
));
|
||||
$list_editor->show_editor = false;
|
||||
|
||||
$list_editor->save = function($data) {
|
||||
global $list_id, $list;
|
||||
DB::update("update lists set title = '" . DB::escape($data['title']) . "' where id = {$list_id}");
|
||||
|
||||
if ($data['tags'] !== $list_tags) {
|
||||
DB::delete("delete from lists_tags where list_id = {$list_id}");
|
||||
foreach ($data['tags'] as $tag) {
|
||||
DB::insert("insert into lists_tags (list_id, tag) values ({$list_id}, '" . DB::escape($tag) . "')");
|
||||
}
|
||||
}
|
||||
|
||||
if ($data['is_hidden'] != $list['is_hidden'] ) {
|
||||
DB::update("update lists set is_hidden = {$data['is_hidden']} where id = {$list_id}");
|
||||
}
|
||||
};
|
||||
|
||||
$list_editor->runAtServer();
|
||||
|
||||
$add_new_problem_form = new UOJForm('add_new_problem');
|
||||
$add_new_problem_form->addInput('problem_id', 'text', '题目 ID', '',
|
||||
function ($x) {
|
||||
global $myUser, $list_id;
|
||||
|
||||
if (!isSuperUser($myUser)) {
|
||||
return '只有超级用户可以编辑题单';
|
||||
}
|
||||
|
||||
if (!validateUInt($x)) {
|
||||
return 'ID 不合法';
|
||||
}
|
||||
$problem = queryProblemBrief($x);
|
||||
if (!$problem) {
|
||||
return '题目不存在';
|
||||
}
|
||||
|
||||
if (queryProblemInList($list_id, $x)) {
|
||||
return '该题目已经在题单中';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$add_new_problem_form->submit_button_config['align'] = 'compressed';
|
||||
$add_new_problem_form->submit_button_config['text'] = '添加到题单';
|
||||
$add_new_problem_form->handle = function() {
|
||||
global $list_id, $myUser;
|
||||
$problem_id = $_POST['problem_id'];
|
||||
|
||||
DB::insert("insert into lists_problems (list_id, problem_id) values ({$list_id}, {$problem_id})");
|
||||
};
|
||||
$add_new_problem_form->runAtServer();
|
||||
|
||||
function removeFromProblemListForm($problem_id) {
|
||||
$res_form = new UOJForm("remove_problem_{$problem_id}");
|
||||
$input_name = "problem_id_delete_{$problem_id}";
|
||||
$res_form->addHidden($input_name, $problem_id, function($problem_id) {
|
||||
global $myUser;
|
||||
if (!isSuperUser($myUser)) {
|
||||
return '只有超级用户可以编辑题单';
|
||||
}
|
||||
}, null);
|
||||
$res_form->handle = function() use ($input_name) {
|
||||
global $list_id;
|
||||
$problem_id = $_POST[$input_name];
|
||||
DB::query("delete from lists_problems where problem_id={$problem_id} and list_id={$list_id}");
|
||||
};
|
||||
$res_form->submit_button_config['class_str'] = 'btn btn-danger';
|
||||
$res_form->submit_button_config['text'] = '删除';
|
||||
$res_form->submit_button_config['align'] = 'inline';
|
||||
return $res_form;
|
||||
}
|
||||
|
||||
$removeProblemForms = array();
|
||||
$problem_ids = DB::query("select problem_id from lists_problems where list_id = {$list_id}");
|
||||
while ($row = DB::fetch($problem_ids)) {
|
||||
$problem_id = $row['problem_id'];
|
||||
$removeForm = removeFromProblemListForm($problem_id);
|
||||
$removeForm->runAtServer();
|
||||
$removeProblemForms[$problem_id] = $removeForm;
|
||||
}
|
||||
|
||||
function echoProblem($problem) {
|
||||
global $myUser, $removeProblemForms;
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td class="text-center">';
|
||||
echo '#', $problem['id'], '</td>';
|
||||
echo '<td class="text-left">';
|
||||
if ($problem['is_hidden']) {
|
||||
echo ' <span class="text-danger">[隐藏]</span> ';
|
||||
}
|
||||
if ($problem['uploader'] == $myUser['username']) {
|
||||
echo ' <span class="text-info">[我的题目]</span> ';
|
||||
}
|
||||
echo '<a href="/problem/', $problem['id'], '">', $problem['title'], '</a>';
|
||||
echo '</td>';
|
||||
echo '<td class="text-center">';
|
||||
$removeProblemForms[$problem['id']]->printHTML();
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
$pag_config = array('page_len' => 40);
|
||||
$pag_config['col_names'] = array('problems.id as id', 'problems.is_hidden as is_hidden', 'problems.title as title', 'problems.uploader as uploader');
|
||||
|
||||
$pag_config['table_name'] = "problems inner join lists_problems lp on lp.list_id = {$list_id} and lp.problem_id = problems.id";
|
||||
|
||||
$pag_config['cond'] = '1';
|
||||
$pag_config['tail'] = "order by id asc";
|
||||
$pag = new Paginator($pag_config);
|
||||
?>
|
||||
|
||||
<?php echoUOJPageHeader($list['title'] . ' 管理'); ?>
|
||||
|
||||
<h1 class="h2">
|
||||
<?= $list['title'] ?>(#<?= $list['id'] ?>)管理
|
||||
</h1>
|
||||
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item"><a class="nav-link" href="/problem_list/<?= $list['id'] ?>/manage" role="tab">管理</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/problem_list/<?= $list['id'] ?>" role="tab">返回</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="mb-4">
|
||||
<?php $list_editor->printHTML(); ?>
|
||||
</div>
|
||||
|
||||
<table class="table table-hover mb-4">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">ID</th>
|
||||
<th>题目名称</th>
|
||||
<th class="text-center">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ($pag->get() as $idx => $row) {
|
||||
echoProblem($row);
|
||||
echo "\n";
|
||||
}
|
||||
?>
|
||||
<?php if ($pag->isEmpty()): ?>
|
||||
<tr>
|
||||
<td class="text-center" colspan="233">
|
||||
<?= UOJLocale::get('none') ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="my-4">
|
||||
<?php $add_new_problem_form->printHTML() ?>
|
||||
</div>
|
||||
|
||||
<?= $pag->pagination(); ?>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
@ -1,165 +0,0 @@
|
||||
<?php
|
||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
||||
redirectToLogin();
|
||||
}
|
||||
|
||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
||||
become403Page();
|
||||
}
|
||||
|
||||
if (!isset($_COOKIE['bootstrap4'])) {
|
||||
$REQUIRE_LIB['bootstrap5'] = '';
|
||||
}
|
||||
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
|
||||
if (isSuperUser($myUser)) {
|
||||
$new_list_form = new UOJForm('new_list');
|
||||
$new_list_form->handle = function() {
|
||||
DB::query("insert into lists (title, is_hidden) values ('未命名题单', 1)");
|
||||
};
|
||||
$new_list_form->submit_button_config['align'] = 'right';
|
||||
$new_list_form->submit_button_config['class_str'] = 'btn btn-primary';
|
||||
$new_list_form->submit_button_config['text'] = UOJLocale::get('problems::add new list');
|
||||
$new_list_form->submit_button_config['smart_confirm'] = '';
|
||||
|
||||
$new_list_form->runAtServer();
|
||||
}
|
||||
|
||||
function echoList($list) {
|
||||
global $myUser, $REQUIRE_LIB;
|
||||
|
||||
echo '<tr class="text-center">';
|
||||
if ($list['problem_count'] == $list['accepted'] && $list['problem_count'] > 0) {
|
||||
echo '<td class="success">';
|
||||
} else {
|
||||
echo '<td>';
|
||||
}
|
||||
echo '#', $list['list_id'], '</td>';
|
||||
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo '<td class="text-start">';
|
||||
} else {
|
||||
echo '<td class="text-left">';
|
||||
}
|
||||
|
||||
if ($list['is_hidden']) {
|
||||
echo ' <span class="text-danger">[隐藏]</span> ';
|
||||
}
|
||||
echo '<a ';
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo ' class="text-decoration-none" ';
|
||||
}
|
||||
echo ' href="/problem_list/', $list['list_id'], '">', $list['title'], '</a> ';
|
||||
foreach (queryProblemListTags($list['list_id']) as $tag) {
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo '<a class="uoj-list-tag my-1">';
|
||||
echo '<span class="badge bg-secondary">';
|
||||
} else {
|
||||
echo '<a class="uoj-list-tag">';
|
||||
echo '<span class="badge badge-pill badge-secondary">';
|
||||
}
|
||||
|
||||
echo HTML::escape($tag), '</span>', '</a> ';
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
echo "<td>{$list['accepted']}</td>";
|
||||
echo "<td>{$list['problem_count']}</td>";
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
?>
|
||||
|
||||
<?php echoUOJPageHeader(UOJLocale::get('problems lists')) ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-9">
|
||||
<div class="d-flex justify-content-between">
|
||||
<?php endif ?>
|
||||
<h1 class="h2">
|
||||
<?= UOJLocale::get('problems lists') ?>
|
||||
</h1>
|
||||
|
||||
<?php if (isSuperUser($myUser)): ?>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="text-end mb-2">
|
||||
<?php endif ?>
|
||||
<?php $new_list_form->printHTML(); ?>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php
|
||||
$problem_list_caption = UOJLocale::get('problems::problem list');
|
||||
$ac_caption = UOJLocale::get('problems::ac');
|
||||
$total_caption = UOJLocale::get('problems::total');
|
||||
$header = <<<EOD
|
||||
<tr>
|
||||
<th class="text-center" style="width:5em;">ID</th>
|
||||
<th>{$problem_list_caption}</th>
|
||||
<th class="text-center" style="width:5em;">{$ac_caption}</th>
|
||||
<th class="text-center" style="width:5em;">{$total_caption}</th>
|
||||
</tr>
|
||||
EOD;
|
||||
|
||||
$cond = array();
|
||||
|
||||
$search_tag = null;
|
||||
if (isset($_GET['tag'])) {
|
||||
$search_tag = $_GET['tag'];
|
||||
}
|
||||
if ($search_tag) {
|
||||
$cond[] = "'" . DB::escape($search_tag) . "' in (select tag from lists_tags where lists_tags.list_id = a.id)";
|
||||
}
|
||||
if (!isSuperUser($myUser)) {
|
||||
$cond[] = "is_hidden = 0";
|
||||
}
|
||||
|
||||
if ($cond) {
|
||||
$cond = join($cond, ' and ');
|
||||
} else {
|
||||
$cond = '1';
|
||||
}
|
||||
|
||||
$from = "lists a left join lists_problems b on a.id = b.list_id left join best_ac_submissions c on (b.problem_id = c.problem_id and c.submitter = '{$myUser['username']}')";
|
||||
|
||||
$table_config = array(
|
||||
'page_len' => 40,
|
||||
'table_classes' => array('table', 'table-bordered', 'table-hover', 'table-striped'),
|
||||
'head_pagination' => true,
|
||||
'pagination_table' => 'lists'
|
||||
);
|
||||
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
$table_config['div_classes'] = array('card', 'my-3');
|
||||
$table_config['table_classes'] = array('table', 'uoj-table', 'mb-0');
|
||||
}
|
||||
|
||||
echoLongTable(
|
||||
array('a.id as list_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.problem_id) as problem_count', 'count(c.submitter) as accepted'),
|
||||
$from, $cond, 'group by a.id order by a.id desc',
|
||||
$header,
|
||||
'echoList',
|
||||
$table_config,
|
||||
);
|
||||
?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
|
||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||
<?php uojIncludeView('sidebar', array()) ?>
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
requireLib('bootstrap5');
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
@ -11,7 +12,6 @@
|
||||
become403Page();
|
||||
}
|
||||
|
||||
requireLib('bootstrap5');
|
||||
|
||||
if (isSuperUser($myUser) || isProblemManager($myUser) || isProblemUploader($myUser)) {
|
||||
$new_problem_form = new UOJForm('new_problem');
|
||||
@ -83,7 +83,7 @@ EOD;
|
||||
echo "<td>{$extra_config['difficulty']}</td>";
|
||||
}
|
||||
}
|
||||
echo '<td class="text-center">', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), '</td>';
|
||||
echo '<td class="text-start">', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
|
@ -207,6 +207,12 @@ function echoLongTable($col_names, $table_name, $cond, $tail, $header_row, $prin
|
||||
}
|
||||
|
||||
echo '<div class="', join($div_classes, ' '), '">';
|
||||
|
||||
if (isset($config['print_before_table'])) {
|
||||
$fun = $config['print_before_table'];
|
||||
$fun();
|
||||
}
|
||||
|
||||
echo '<table class="', join($table_classes, ' '), '">';
|
||||
echo '<thead>';
|
||||
echo $header_row;
|
||||
@ -226,12 +232,13 @@ function echoLongTable($col_names, $table_name, $cond, $tail, $header_row, $prin
|
||||
|
||||
echo '</tbody>';
|
||||
echo '</table>';
|
||||
echo '</div>';
|
||||
|
||||
|
||||
if (isset($config['print_after_table'])) {
|
||||
$fun = $config['print_after_table'];
|
||||
$fun();
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
echo $pag->pagination();
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ function queryProblemListTags($id) {
|
||||
return $tags;
|
||||
}
|
||||
function queryProblemInList($list_id, $problem_id) {
|
||||
return DB::selectFirst("select * from lists_problems where list_id='$blog_id' and problem_id='$problem_id'", MYSQLI_ASSOC);
|
||||
return DB::selectFirst("SELECT * FROM lists_problems WHERE list_id = '$list_id' AND problem_id = '$problem_id'", MYSQLI_ASSOC);
|
||||
}
|
||||
|
||||
function querySolution($problem_id, $blog_id) {
|
||||
@ -185,6 +185,9 @@ function queryBlogComment($id) {
|
||||
function isProblemVisibleToUser($problem, $user) {
|
||||
return !$problem['is_hidden'] || hasProblemPermission($user, $problem);
|
||||
}
|
||||
function isListVisibleToUser($list, $user) {
|
||||
return !$list['is_hidden'] || isSuperUser($user);
|
||||
}
|
||||
function isContestProblemVisibleToUser($problem, $contest, $user) {
|
||||
if (isProblemVisibleToUser($problem, $user)) {
|
||||
return true;
|
||||
|
@ -22,9 +22,9 @@ Route::group([
|
||||
Route::any('/problem/{id}/manage/managers', '/problem_managers_manage.php');
|
||||
Route::any('/problem/{id}/manage/data', '/problem_data_manage.php');
|
||||
|
||||
Route::any('/problem_lists', '/problem_lists.php');
|
||||
Route::any('/problem_list/{id}', '/problem_list.php');
|
||||
Route::any('/problem_list/{id}/manage', '/problem_list_manage.php');
|
||||
Route::any('/lists', '/lists.php');
|
||||
Route::any('/list/{id}', '/list.php');
|
||||
Route::any('/list/{id}/edit(?:/{tab})?', '/list_edit.php');
|
||||
|
||||
Route::any('/contests', '/contests.php');
|
||||
Route::any('/contest/new', '/add_contest.php');
|
||||
|
1
web/app/upgrade/9_list_v2/README.md
Normal file
1
web/app/upgrade/9_list_v2/README.md
Normal file
@ -0,0 +1 @@
|
||||
ref: https://github.com/renbaoshuo/S2OJ/pull/9
|
1
web/app/upgrade/9_list_v2/down.sql
Normal file
1
web/app/upgrade/9_list_v2/down.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE `lists` DROP COLUMN `description`;
|
1
web/app/upgrade/9_list_v2/up.sql
Normal file
1
web/app/upgrade/9_list_v2/up.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE `lists` ADD COLUMN `description` TEXT NOT NULL DEFAULT '' AFTER `title`;
|
@ -64,7 +64,7 @@ mb-4" role="navigation">
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?= HTML::url('/problem_lists') ?>">
|
||||
<a class="nav-link" href="<?= HTML::url('/lists') ?>">
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<i class="bi bi-card-list"></i>
|
||||
<?php else: ?>
|
||||
|
@ -249,7 +249,7 @@ $.fn.uoj_problem_tag = function() {
|
||||
}
|
||||
$.fn.uoj_list_tag = function() {
|
||||
return this.each(function() {
|
||||
$(this).attr('href', uojHome + '/problem_lists?tag=' + encodeURIComponent($(this).text()));
|
||||
$(this).attr('href', uojHome + '/lists?tag=' + encodeURIComponent($(this).text()));
|
||||
});
|
||||
}
|
||||
$.fn.uoj_blog_tag = function() {
|
||||
|
Loading…
Reference in New Issue
Block a user