mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-22 14:08:42 +00:00
refactor(web/group): group v2 (#8)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
commit
b6b8efd5fb
@ -366,7 +366,7 @@ UNLOCK TABLES;
|
||||
CREATE TABLE `countdowns` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`title` text NOT NULL,
|
||||
`endtime` datetime NOT NULL,
|
||||
`end_time` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
@ -448,6 +448,21 @@ CREATE TABLE `groups` (
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `groups_assignments`
|
||||
--
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `groups_assignments` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`list_id` int(11) NOT NULL,
|
||||
`group_id` int(11) NOT NULL,
|
||||
`end_time` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `groups_users`
|
||||
--
|
||||
@ -461,22 +476,6 @@ CREATE TABLE `groups_users` (
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `assignments`
|
||||
--
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `assignments` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`list_id` int(11) NOT NULL,
|
||||
`group_id` int(11) NOT NULL,
|
||||
`create_time` datetime NOT NULL,
|
||||
`deadline` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `hacks`
|
||||
--
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
requireLib('bootstrap5');
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
@ -16,20 +17,19 @@
|
||||
become404Page();
|
||||
}
|
||||
|
||||
if (!isset($_COOKIE['bootstrap4'])) {
|
||||
$REQUIRE_LIB['bootstrap5'] = '';
|
||||
if (!isSuperUser($myUser) && $group['is_hidden']) {
|
||||
become403Page();
|
||||
}
|
||||
?>
|
||||
|
||||
<?php echoUOJPageHeader(UOJLocale::get('groups')) ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="row">
|
||||
<!-- left col -->
|
||||
<div class="col-lg-9">
|
||||
<div class="d-flex justify-content-between">
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<!-- title -->
|
||||
<div class="d-flex justify-content-between">
|
||||
<h1 class="h2">
|
||||
<?php if ($group['is_hidden']): ?>
|
||||
<span class="fs-5 text-danger">[隐藏]</span>
|
||||
@ -37,57 +37,48 @@
|
||||
<?= $group['title'] ?>
|
||||
<span class="fs-5">(ID: #<?= $group['id'] ?>)</span>
|
||||
</h1>
|
||||
<?php else: ?>
|
||||
<h2 style="margin-top: 24px"><?= $group['title'] ?></h2>
|
||||
<p>(<b>小组 ID</b>: <?= $group['id'] ?>)</p>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isSuperUser($myUser)): ?>
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="text-end">
|
||||
<a class="btn btn-primary" href="/group/<?= $group['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="/group/<?= $group['id'] ?>/manage" role="tab">管理</a></li>
|
||||
</ul>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<!-- end title -->
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="card card-default mb-3">
|
||||
<!-- main content -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h2 class="h4">
|
||||
<?= UOJLocale::get('group announcement') ?>
|
||||
</h2>
|
||||
<?php if ($group['announcement']): ?>
|
||||
<div class="text-break">
|
||||
<?= HTML::purifier_inline()->purify(HTML::parsedown()->line($group['announcement'])) ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="text-muted">
|
||||
<?= UOJLocale::get('none') ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title h4">
|
||||
<?php else: ?>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 mt-4">
|
||||
<h5>
|
||||
<?php endif ?>
|
||||
<?= UOJLocale::get('news') ?>
|
||||
</h5>
|
||||
<ul
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
class="mb-0"
|
||||
<?php endif ?>
|
||||
>
|
||||
<ul class="mb-0">
|
||||
<?php
|
||||
$current_ac = queryGroupCurrentAC($group['id']);
|
||||
foreach ($current_ac as $ac) {
|
||||
echo '<li>';
|
||||
echo getUserLink($ac['submitter']);
|
||||
echo ' 解决了问题 ';
|
||||
echo '<a ';
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo ' class="text-decoration-none" ';
|
||||
}
|
||||
echo ' href="/problem/', $ac['problem_id'], '">', $ac['problem_title'], '</a> ';
|
||||
echo '<a class="text-decoration-none" href="/problem/', $ac['problem_id'], '">', $ac['problem_title'], '</a> ';
|
||||
echo '<time class="time">(', $ac['submit_time'], ')</time>';
|
||||
echo '</li>';
|
||||
}
|
||||
@ -99,94 +90,72 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="card card-default mb-3">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title h4">
|
||||
<?php else: ?>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 mt-4">
|
||||
<h5>
|
||||
<?php endif ?>
|
||||
<?= UOJLocale::get('assignments') ?>
|
||||
</h5>
|
||||
<ul
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
class="mb-0"
|
||||
<?php endif ?>
|
||||
>
|
||||
<?php
|
||||
$assignments = queryGroupActiveAssignments($group['id']);
|
||||
foreach ($assignments as $ass) {
|
||||
$ddl = DateTime::createFromFormat('Y-m-d H:i:s', $ass['deadline']);
|
||||
$create_time = DateTime::createFromFormat('Y-m-d H:i:s', $ass['create_time']);
|
||||
$now = new DateTime();
|
||||
<?php
|
||||
$now = new DateTime();
|
||||
echoLongTable(
|
||||
['groups_assignments.list_id as list_id', 'lists.title as title', 'groups_assignments.end_time as end_time'],
|
||||
'groups_assignments left join lists on lists.id = groups_assignments.list_id',
|
||||
"groups_assignments.group_id = {$group['id']} and groups_assignments.end_time > addtime(now(), '-168:00:00')",
|
||||
'order by end_time desc, list_id desc',
|
||||
<<<EOD
|
||||
<tr>
|
||||
<th style="width:3em" class="text-center">ID</th>
|
||||
<th style="width:12em">标题</th>
|
||||
<th style="width:4em">状态</th>
|
||||
<th style="width:8em">结束时间</th>
|
||||
</tr>
|
||||
EOD,
|
||||
function($row) use ($group, $now) {
|
||||
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']);
|
||||
|
||||
echo '<li>';
|
||||
echo '<a ';
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo ' class="text-decoration-none" ';
|
||||
}
|
||||
echo ' href="/problem_list/', $ass['list_id'], '">', $ass['title'], ' (题单 #', $ass['list_id'], ')</a>';
|
||||
|
||||
if ($ddl < $now) {
|
||||
echo '<sup style="color:red"> overdue</sup>';
|
||||
} elseif ($ddl->getTimestamp() - $now->getTimestamp() < 86400) { // 1d
|
||||
echo '<sup style="color:red"> soon</sup>';
|
||||
} elseif ($now->getTimestamp() - $create_time->getTimestamp() < 86400) { // 1d
|
||||
echo '<sup style="color:red"> new</sup>';
|
||||
}
|
||||
|
||||
$ddl_str = $ddl->format('Y-m-d H:i');
|
||||
echo ' (截止时间: ', $ddl_str, ',<a ';
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo ' class="text-decoration-none" ';
|
||||
}
|
||||
echo ' href="/group/',$group['id'],'/assignment/', $ass['list_id'], '">查看完成情况</a>)';
|
||||
echo '</li>';
|
||||
}
|
||||
|
||||
if (count($assignments) == 0) {
|
||||
echo '<p>暂无作业</p>';
|
||||
}
|
||||
echo '<tr>';
|
||||
echo '<td class="text-center">', $row['list_id'], '</td>';
|
||||
echo '<td>', '<a class="text-decoration-none" href="/group/', $group['id'], '/assignment/', $row['list_id'],'">', HTML::escape($row['title']), '</a>', '</td>';
|
||||
if ($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 '</tr>';
|
||||
},
|
||||
[
|
||||
'echo_full' => true,
|
||||
'div_classes' => ['table-responsive'],
|
||||
'table_classes' => ['table', 'align-middle', 'mb-0'],
|
||||
]
|
||||
);
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<div class="card card-default mb-3">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title h4">
|
||||
<?php else: ?>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 mt-4">
|
||||
<h5>
|
||||
<?php endif ?>
|
||||
<?= UOJLocale::get('top solver') ?>
|
||||
</h5>
|
||||
<?php echoRanklist(array(
|
||||
'echo_full' => true,
|
||||
<?php echoRanklist([
|
||||
'page_len' => 50,
|
||||
'group_id' => $group_id,
|
||||
'by_accepted' => true,
|
||||
'table_classes' => isset($REQUIRE_LIB['bootstrap5'])
|
||||
? array('table', 'text-center', 'mb-0')
|
||||
: array('table', 'table-bordered', 'table-hover', 'table-striped', 'table-text-center')
|
||||
)) ?>
|
||||
'table_classes' => ['table', 'text-center', 'mb-0'],
|
||||
]) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
|
||||
<!-- end left col -->
|
||||
</div>
|
||||
|
||||
<!-- right col -->
|
||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||
<?php uojIncludeView('sidebar', array()); ?>
|
||||
<?php uojIncludeView('sidebar'); ?>
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
||||
|
@ -40,85 +40,140 @@
|
||||
<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('/group/'.$group['id']) ?>"><?= $group['title'] ?></a></li>
|
||||
<li>开始时间:<?= $assignment['create_time'] ?></li>
|
||||
<li>结束时间:<?= $assignment['deadline'] ?></li>
|
||||
<li>结束时间:<?= $assignment['end_time'] ?></li>
|
||||
</ul>
|
||||
|
||||
<?php
|
||||
$query = DB::query("select problem_id from lists_problems where list_id = {$list['id']}");
|
||||
$problems = DB::selectAll("select problem_id from lists_problems where list_id = {$list['id']}");
|
||||
$users = queryGroupUsers($group['id']);
|
||||
$problem_ids = [];
|
||||
while ($row = DB::fetch($query)) {
|
||||
$problem_ids[] = $row['problem_id'];
|
||||
$usernames = [];
|
||||
$n_users = count($users);
|
||||
$n_problems = count($problems);
|
||||
$submission_end_time = min(new DateTime(), DateTime::createFromFormat('Y-m-d H:i:s', $assignment['end_time']))->format('Y-m-d H:i:s');
|
||||
|
||||
foreach ($problems as $problem) {
|
||||
$problem_ids[] = $problem['problem_id'];
|
||||
}
|
||||
|
||||
$header_row = '';
|
||||
$header_row .= '<tr>';
|
||||
$header_row .= '<th style="width: 10em;">'.UOJLocale::get('username').'</th>';
|
||||
$header_row .= '<th style="width: 2em;">'.UOJLocale::get('contests::total score').'</th>';
|
||||
foreach ($problem_ids as $problem_id) {
|
||||
$header_row .= '<th style="width: 2em;">' . '<a class="text-decoration-none" href="'.HTML::url('/problem/'.$problem_id).'">#'.$problem_id.'</a>' . '</th>';
|
||||
sort($problem_ids);
|
||||
|
||||
foreach ($users as $user) {
|
||||
$usernames[] = $user['username'];
|
||||
}
|
||||
$header_row .= '</tr>';
|
||||
|
||||
$print_row = function($row) use ($problem_ids) {
|
||||
$username = $row['username'];
|
||||
// standings: rank => [user => [username, realname], scores[], rank]
|
||||
$standings = [];
|
||||
|
||||
$scores = [];
|
||||
$sum = 0;
|
||||
$total_score = count($problem_ids) * 100;
|
||||
$query = DB::query("SELECT MAX(id), problem_id, MAX(score) FROM submissions WHERE (problem_id, score) IN (SELECT problem_id, MAX(score) FROM submissions WHERE submitter = '{$username}' AND problem_id IN (".implode(',', $problem_ids).") GROUP BY problem_id) AND submitter = '{$username}' GROUP BY problem_id");
|
||||
foreach ($usernames as $username) {
|
||||
$user = queryUser($username);
|
||||
$row = ['total_score' => 0];
|
||||
|
||||
while ($row = DB::fetch($query)) {
|
||||
$scores[$row['problem_id']] = [
|
||||
'submission_id' => $row['MAX(id)'],
|
||||
'score' => $row['MAX(score)'],
|
||||
];
|
||||
|
||||
$sum += $row['MAX(score)'];
|
||||
}
|
||||
|
||||
if ($sum == $total_score) {
|
||||
echo '<tr class="table-success">';
|
||||
} else {
|
||||
echo '<tr>';
|
||||
}
|
||||
echo '<td>' . getUserLink($username) . '</td>';
|
||||
echo '<td>';
|
||||
echo '<span class="uoj-score" data-max="', $total_score, '">', $sum, '</span>';
|
||||
echo '</td>';
|
||||
$row['user'] = [
|
||||
'username' => $user['username'],
|
||||
'realname' => $user['realname'],
|
||||
];
|
||||
|
||||
foreach ($problem_ids as $problem_id) {
|
||||
if (!isset($scores[$problem_id])) {
|
||||
echo '<td>';
|
||||
$cond = "submitter = '{$user['username']}' AND problem_id = $problem_id AND submit_time <= '$submission_end_time'";
|
||||
$submission = DB::selectFirst("SELECT id, score FROM submissions INNER JOIN (SELECT MAX(score) AS score FROM submissions WHERE $cond) AS max USING (score) WHERE $cond ORDER BY submit_time DESC");
|
||||
|
||||
if ($submission) {
|
||||
$row['scores'][] = [
|
||||
'submission_id' => $submission['id'],
|
||||
'score' => intval($submission['score']),
|
||||
];
|
||||
$row['total_score'] += $submission['score'];
|
||||
} else {
|
||||
if ($scores[$problem_id]['score'] == 100) {
|
||||
echo '<td class="table-success">';
|
||||
} else {
|
||||
echo '<td>';
|
||||
}
|
||||
echo '<a class="text-decoration-none uoj-score" href="'.HTML::url('/submission/'.$scores[$problem_id]['submission_id']).'">'.$scores[$problem_id]['score'].'</a>';
|
||||
$row['scores'][] = null;
|
||||
}
|
||||
echo '</td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
};
|
||||
|
||||
$from = "user_info a inner join groups_users b on (b.group_id = {$group['id']} and a.username = b.username)";
|
||||
$col_names = array('a.username as username');
|
||||
$cond = "1";
|
||||
$tail = "order by a.username asc";
|
||||
$config = [
|
||||
'page_len' => 50,
|
||||
'div_classes' => ['card', 'my-3', 'table-responsive', 'text-center'],
|
||||
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
||||
];
|
||||
$standings[] = $row;
|
||||
}
|
||||
|
||||
echoLongTable($col_names, $from, $cond, $tail, $header_row, $print_row, $config);
|
||||
usort($standings, function($lhs, $rhs) {
|
||||
if ($lhs['total_score'] != $rhs['total_score']) {
|
||||
return $rhs['total_score'] - $lhs['total_score'];
|
||||
}
|
||||
|
||||
return strcmp($lhs['user']['username'], $rhs['user']['username']);
|
||||
});
|
||||
?>
|
||||
|
||||
<!-- end left col -->
|
||||
<div id="standings"></div>
|
||||
|
||||
<script>
|
||||
var n_problems = <?= $n_problems ?>;
|
||||
var max_total_score = <?= $n_problems * 100 ?>;
|
||||
var standings = <?= json_encode($standings) ?>;
|
||||
|
||||
$('#standings').long_table(
|
||||
standings,
|
||||
1,
|
||||
'<tr>' +
|
||||
'<th style="width:10em"><?= UOJLocale::get('username') ?></th>' +
|
||||
'<th style="width:2em"><?= UOJLocale::get('contests::total score') ?></th>' +
|
||||
<?php foreach ($problem_ids as $problem_id): ?>
|
||||
'<th style="width:2em">' +
|
||||
'<a class="text-decoration-none" href="<?= HTML::url('/problem/' . $problem_id) ?>">#<?= $problem_id ?></a>' +
|
||||
'</th>' +
|
||||
<?php endforeach ?>
|
||||
'</tr>',
|
||||
function(row) {
|
||||
var col_tr = '';
|
||||
|
||||
if (row['total_score'] == max_total_score) {
|
||||
col_tr += '<tr class="table-success">';
|
||||
} else {
|
||||
col_tr += '<tr>';
|
||||
}
|
||||
|
||||
col_tr += '<td>' + getUserLink(row['user']['username'], row['user']['realname']) + '</td>';
|
||||
col_tr += '<td>' +
|
||||
'<span class="uoj-score" data-max="' + max_total_score + '" style="color:' + getColOfScore(row['total_score'] / n_problems) + '">' + row['total_score'] + '</span>' +
|
||||
'</td>';
|
||||
for (var i = 0; i < row['scores'].length; i++) {
|
||||
var col = row['scores'][i];
|
||||
|
||||
if (col) {
|
||||
if (col['score'] == 100) {
|
||||
col_tr += '<td class="table-success">';
|
||||
} else {
|
||||
col_tr += '<td>';
|
||||
}
|
||||
col_tr += '<a class="text-decoration-none uoj-score" href="/submission/' + col['submission_id'] + '" style="color:' + getColOfScore(col['score']) + '">' + col['score'] + '</a>';
|
||||
col_tr += '</td>';
|
||||
} else {
|
||||
col_tr += '<td></td>';
|
||||
}
|
||||
}
|
||||
|
||||
col_tr += '</tr>';
|
||||
|
||||
return col_tr;
|
||||
},
|
||||
{
|
||||
div_classes: ['card', 'my-3', 'table-responsive', 'text-center'],
|
||||
table_classes: ['table', 'uoj-table', 'table-bordered', 'mb-0'],
|
||||
page_len: 50,
|
||||
print_before_table: function() {
|
||||
var html = '';
|
||||
|
||||
html += '<div class="card-header bg-transparent text-muted text-start small">' +
|
||||
'成绩统计截止时间:<?= $submission_end_time ?>' +
|
||||
'</div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
</div>
|
||||
<!-- end left col -->
|
||||
|
||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||
<!-- right col -->
|
||||
|
@ -3,6 +3,7 @@
|
||||
redirectToLogin();
|
||||
}
|
||||
|
||||
requireLib('bootstrap5');
|
||||
requirePHPLib('form');
|
||||
requirePHPLib('judger');
|
||||
requirePHPLib('data');
|
||||
@ -16,258 +17,458 @@
|
||||
become403Page();
|
||||
}
|
||||
|
||||
$group_editor = new UOJBlogEditor();
|
||||
$group_editor->name = 'group';
|
||||
$group_editor->blog_url = null;
|
||||
$group_editor->cur_data = array(
|
||||
'title' => $group['title'],
|
||||
'tags' => array(),
|
||||
'is_hidden' => $group['is_hidden']
|
||||
);
|
||||
$group_editor->label_text = array_merge($group_editor->label_text, array(
|
||||
'view blog' => '保存小组信息',
|
||||
'blog visibility' => '小组可见性'
|
||||
));
|
||||
$group_editor->show_editor = false;
|
||||
$group_editor->show_tags = false;
|
||||
if (isset($_GET['tab'])) {
|
||||
$cur_tab = $_GET['tab'];
|
||||
} else {
|
||||
$cur_tab = 'profile';
|
||||
}
|
||||
|
||||
$group_editor->save = function($data) {
|
||||
global $group_id, $group;
|
||||
DB::update("update `groups` set title = '".DB::escape($data['title'])."' where id = {$group_id}");
|
||||
$tabs_info = [
|
||||
'profile' => [
|
||||
'name' => '基本信息',
|
||||
'url' => "/group/{$group['id']}/manage/profile",
|
||||
],
|
||||
'assignments' => [
|
||||
'name' => '作业管理',
|
||||
'url' => "/group/{$group['id']}/manage/assignments",
|
||||
],
|
||||
'users' => [
|
||||
'name' => '用户管理',
|
||||
'url' => "/group/{$group['id']}/manage/users",
|
||||
]
|
||||
];
|
||||
|
||||
if ($data['is_hidden'] != $group['is_hidden'] ) {
|
||||
DB::update("update `groups` set is_hidden = {$data['is_hidden']} where id = {$group_id}");
|
||||
if (!isset($tabs_info[$cur_tab])) {
|
||||
become404Page();
|
||||
}
|
||||
|
||||
if ($cur_tab == 'profile') {
|
||||
$update_profile_form = new UOJForm('update_profile');
|
||||
$update_profile_form->addVInput('name', 'text', '名称', $group['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' => '隐藏',
|
||||
], '可见性', $group['is_hidden']);
|
||||
$update_profile_form->addVTextArea('announcement', '公告', $group['announcement'],
|
||||
function($announcement, &$vdata) {
|
||||
if (strlen($announcement) > 3000) {
|
||||
return '公告过长';
|
||||
}
|
||||
|
||||
$vdata['announcement'] = $announcement;
|
||||
|
||||
return '';
|
||||
}, null);
|
||||
$update_profile_form->handle = function($vdata) use ($group) {
|
||||
$esc_title = DB::escape($vdata['title']);
|
||||
$is_hidden = $_POST['is_hidden'];
|
||||
$esc_announcement = $vdata['announcement'];
|
||||
|
||||
DB::update("UPDATE `groups` SET title = '$esc_title', is_hidden = '$is_hidden', announcement = '$esc_announcement' WHERE id = {$group['id']}");
|
||||
|
||||
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 == 'assignments') {
|
||||
if (isset($_POST['submit-remove_assignment']) && $_POST['submit-remove_assignment'] == 'remove_assignment') {
|
||||
$list_id = $_POST['list_id'];
|
||||
|
||||
if (!validateUInt($list_id)) {
|
||||
dieWithAlert('题单 ID 不合法。');
|
||||
}
|
||||
|
||||
if (!queryAssignmentByGroupListID($group['id'], $list_id)) {
|
||||
dieWithAlert('该题单不在作业中。');
|
||||
}
|
||||
|
||||
DB::delete("DELETE FROM `groups_assignments` WHERE `list_id` = $list_id AND `group_id` = {$group['id']}");
|
||||
|
||||
dieWithAlert('移除成功!');
|
||||
}
|
||||
};
|
||||
$group_editor->runAtServer();
|
||||
|
||||
$add_new_user_form = new UOJForm('add_new_user');
|
||||
$add_new_user_form->addInput('new_username', 'text', '用户名', '',
|
||||
function ($x) {
|
||||
global $group_id;
|
||||
$add_new_assignment_form = new UOJForm('add_new_assignment');
|
||||
$add_new_assignment_form->addVInput('new_assignment_list_id', 'text', '题单 ID', '',
|
||||
function ($list_id, &$vdata) use ($group) {
|
||||
if (!validateUInt($list_id)) {
|
||||
return '题单 ID 不合法';
|
||||
}
|
||||
|
||||
if (!validateUsername($x)) {
|
||||
return '用户名不合法';
|
||||
}
|
||||
$user = queryUser($x);
|
||||
if (!$user) {
|
||||
return '用户不存在';
|
||||
if (!($list = queryProblemList($list_id))) {
|
||||
return '题单不存在';
|
||||
}
|
||||
|
||||
if ($list['is_hidden'] != 0) {
|
||||
return '题单是隐藏的';
|
||||
}
|
||||
|
||||
if (queryAssignmentByGroupListID($group['id'], $list_id)) {
|
||||
return '该题单已经在作业中';
|
||||
}
|
||||
|
||||
$vdata['list_id'] = $list_id;
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$default_end_time = new DateTime();
|
||||
$default_end_time->setTime(17, 0, 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 ($group) {
|
||||
$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 ({$group['id']}, '{$vdata['list_id']}', '{$esc_end_time}')");
|
||||
|
||||
dieWithJsonData([
|
||||
'status' => 'success',
|
||||
'message' => '题单 #' . $vdata['list_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();
|
||||
} elseif ($cur_tab == 'users') {
|
||||
if (isset($_POST['submit-remove_user']) && $_POST['submit-remove_user'] == 'remove_user') {
|
||||
$username = $_POST['remove_username'];
|
||||
|
||||
if (!validateUsername($username)) {
|
||||
dieWithAlert('用户名不合法。');
|
||||
}
|
||||
|
||||
if (queryUserInGroup($group_id, $x)) {
|
||||
return '该用户已经在小组中';
|
||||
if (!queryUser($username)) {
|
||||
dieWithAlert('用户不存在。');
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$add_new_user_form->submit_button_config['align'] = 'compressed';
|
||||
$add_new_user_form->submit_button_config['text'] = '添加到小组';
|
||||
$add_new_user_form->handle = function() {
|
||||
global $group_id, $myUser;
|
||||
$username = $_POST['new_username'];
|
||||
|
||||
DB::insert("insert into groups_users (group_id, username) values ({$group_id}, '{$username}')");
|
||||
};
|
||||
$add_new_user_form->runAtServer();
|
||||
|
||||
|
||||
$delete_user_form = new UOJForm('delete_user');
|
||||
$delete_user_form->addInput('del_username', 'text', '用户名', '',
|
||||
function ($x) {
|
||||
global $group_id;
|
||||
|
||||
if (!validateUsername($x)) {
|
||||
return '用户名不合法';
|
||||
}
|
||||
if (!queryUserInGroup($group_id, $x)) {
|
||||
return '该用户不在小组中';
|
||||
if (!queryUserInGroup($group['id'], $username)) {
|
||||
dieWithAlert('该用户不在小组中。');
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$delete_user_form->submit_button_config['align'] = 'compressed';
|
||||
$delete_user_form->submit_button_config['text'] = '从小组中删除';
|
||||
$delete_user_form->handle = function() {
|
||||
global $group_id, $myUser;
|
||||
$username = $_POST['del_username'];
|
||||
DB::delete("DELETE FROM `groups_users` WHERE `username` = '$username' AND `group_id` = {$group['id']}");
|
||||
|
||||
DB::query("delete from groups_users where username='{$username}' and group_id={$group_id}");
|
||||
};
|
||||
$delete_user_form->runAtServer();
|
||||
dieWithAlert('移除成功!');
|
||||
}
|
||||
|
||||
$add_new_assignment_form = new UOJForm('add_new_assignment');
|
||||
$add_new_assignment_form->addInput('new_assignment_list_id', 'text', '题单 ID', '',
|
||||
function ($x) {
|
||||
global $group_id;
|
||||
$add_new_user_form = new UOJForm('add_new_user');
|
||||
$add_new_user_form->addVInput('new_username', 'text', '用户名', '',
|
||||
function ($username, &$vdata) {
|
||||
global $group_id;
|
||||
|
||||
if (!validateUInt($x)) {
|
||||
return '题单 ID 不合法';
|
||||
}
|
||||
$list = queryProblemList($x);
|
||||
if (!$list) {
|
||||
return '题单不存在';
|
||||
}
|
||||
if ($list['is_hidden'] != 0) {
|
||||
return '题单是隐藏的';
|
||||
}
|
||||
if (!validateUsername($username)) {
|
||||
return '用户名不合法';
|
||||
}
|
||||
|
||||
if (queryAssignmentByGroupListID($group_id, $x)) {
|
||||
return '该题单已经在作业中';
|
||||
}
|
||||
if (!queryUser($username)) {
|
||||
return '用户不存在';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$default_ddl = new DateTime();
|
||||
$default_ddl->setTime(17, 0, 0);
|
||||
$default_ddl->add(new DateInterval("P7D"));
|
||||
$add_new_assignment_form->addInput('new_assignment_deadline', 'text', '截止时间', $default_ddl->format('Y-m-d H:i'),
|
||||
function ($x) {
|
||||
$ddl = DateTime::createFromFormat('Y-m-d H:i', $x);
|
||||
if (!$ddl) {
|
||||
return '截止时间格式不正确,请以类似 "2020-10-1 17:00" 的格式输入';
|
||||
}
|
||||
if (queryUserInGroup($group_id, $username)) {
|
||||
return '该用户已经在小组中';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$add_new_assignment_form->submit_button_config['align'] = 'compressed';
|
||||
$add_new_assignment_form->submit_button_config['text'] = '添加作业';
|
||||
$add_new_assignment_form->handle = function() {
|
||||
global $group_id, $myUser;
|
||||
$list_id = $_POST['new_assignment_list_id'];
|
||||
$ddl = DateTime::createFromFormat('Y-m-d H:i', $_POST['new_assignment_deadline']);
|
||||
$ddl_str = $ddl->format('Y-m-d H:i:s');
|
||||
$vdata['username'] = $username;
|
||||
|
||||
DB::insert("insert into assignments (group_id, list_id, create_time, deadline) values ({$group_id}, '{$list_id}', now(), '{$ddl_str}')");
|
||||
};
|
||||
$add_new_assignment_form->runAtServer();
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$add_new_user_form->submit_button_config['margin_class'] = 'mt-3';
|
||||
$add_new_user_form->submit_button_config['text'] = '添加';
|
||||
$add_new_user_form->handle = function(&$vdata) use ($group) {
|
||||
DB::insert("insert into groups_users (group_id, username) values ({$group['id']}, '{$vdata['username']}')");
|
||||
|
||||
$remove_assignment_form = new UOJForm('remove_assignment');
|
||||
$remove_assignment_form->addInput('remove_assignment_list_id', 'text', '题单 ID', '',
|
||||
function ($x) {
|
||||
global $group_id;
|
||||
dieWithJsonData(['status' => 'success', 'message' => '已将用户名为 ' . $vdata['username'] . ' 的用户添加到本小组。']);
|
||||
};
|
||||
$add_new_user_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();
|
||||
}
|
||||
|
||||
if (!validateUInt($x)) {
|
||||
return '题单 ID 不合法';
|
||||
}
|
||||
if (!queryAssignmentByGroupListID($group_id, $x)) {
|
||||
return '该题单不在作业中';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
$remove_assignment_form->submit_button_config['align'] = 'compressed';
|
||||
$remove_assignment_form->submit_button_config['text'] = '删除作业';
|
||||
$remove_assignment_form->handle = function() {
|
||||
global $group_id, $myUser;
|
||||
$list_id = $_POST['remove_assignment_list_id'];
|
||||
|
||||
DB::query("delete from assignments where list_id='{$list_id}' and group_id={$group_id}");
|
||||
};
|
||||
$remove_assignment_form->runAtServer();
|
||||
|
||||
$announcement_form = new UOJForm('announcement_form');
|
||||
$announcement_form->addVTextArea('announcement_content', '公告', $group['announcement'],
|
||||
function ($x) {
|
||||
return '';
|
||||
},
|
||||
null
|
||||
);
|
||||
$announcement_form->submit_button_config['text'] = '更新公告';
|
||||
$announcement_form->handle = function() {
|
||||
global $group_id, $myUser;
|
||||
|
||||
$content = $_POST['announcement_content'];
|
||||
$esc_content = DB::escape($content);
|
||||
DB::query("update groups set announcement = '{$esc_content}' where id = {$group_id}");
|
||||
};
|
||||
$announcement_form->runAtServer();
|
||||
$(window).scrollTop(0);
|
||||
}
|
||||
EOD);
|
||||
$add_new_user_form->runAtServer();
|
||||
}
|
||||
?>
|
||||
<?php echoUOJPageHeader('管理 - ' . $group['title']); ?>
|
||||
|
||||
<?php echoUOJPageHeader($group['title'] . ' 管理'); ?>
|
||||
|
||||
<h1 class="h2">
|
||||
<?= $group['title'] ?>(#<?= $group['id'] ?>)管理
|
||||
<h1 class="h2 d-block d-md-inline-block">
|
||||
<?= $group['title'] ?>
|
||||
<small class="fs-5">(ID: #<?= $group['id'] ?>)</small>
|
||||
管理
|
||||
</h1>
|
||||
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item"><a class="nav-link" href="/group/<?= $group['id'] ?>/manage" role="tab">管理</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/group/<?= $group['id'] ?>" role="tab">返回</a></li>
|
||||
</ul>
|
||||
<div class="row mt-4">
|
||||
<!-- left col -->
|
||||
<div class="col-md-3">
|
||||
|
||||
<div class="top-buffer-md"></div>
|
||||
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
||||
|
||||
<h5>编辑小组信息</h5>
|
||||
<div class="mb-4">
|
||||
<?php $group_editor->printHTML(); ?>
|
||||
<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("/group/{$group['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">
|
||||
<h5>注意事项</h5>
|
||||
<ul class="mb-0">
|
||||
<li>隐藏的小组无法被普通用户查看,即使该用户属于本小组。</li>
|
||||
<li>公告支持 Markdown 语法,但不支持添加数学公式。</li>
|
||||
</ul>
|
||||
</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
|
||||
$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
|
||||
<tr>
|
||||
<th style="width:3em" 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']);
|
||||
|
||||
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'],
|
||||
]
|
||||
);
|
||||
?>
|
||||
</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>如需延长结束时间请删除后再次添加,排行数据不会丢失。</li>
|
||||
<li>作业结束七天后将会自动在小组主页中隐藏,但仍可直接通过 URL 访问。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php elseif ($cur_tab == 'users'): ?>
|
||||
<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="#users" data-bs-toggle="tab" data-bs-target="#users">用户列表</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#add-user" data-bs-toggle="tab" data-bs-target="#add-user">添加用户</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="users">
|
||||
<?php
|
||||
echoLongTable(
|
||||
['*'],
|
||||
'groups_users',
|
||||
"group_id = {$group['id']}",
|
||||
'order by username asc',
|
||||
<<<EOD
|
||||
<tr>
|
||||
<th>用户名</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
EOD,
|
||||
function($row) use ($group) {
|
||||
echo '<tr>';
|
||||
echo '<td>', getUserLink($row['username']), '</td>';
|
||||
echo '<td>';
|
||||
echo '<form class="d-inline-block" method="POST" onsubmit=\'return confirm("你真的要从小组中移除这个用户吗?")\'>'
|
||||
. '<input type="hidden" name="_token" value="' . crsf_token() . '">'
|
||||
. '<input type="hidden" name="remove_username" value="' . $row['username'] . '">'
|
||||
. '<button class="btn btn-link text-danger text-decoration-none p-0" type="submit" name="submit-remove_user" value="remove_user">移除</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-user">
|
||||
<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_user_form->printHTML() ?>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h5>注意事项</h5>
|
||||
<ul class="mb-0">
|
||||
<li>添加用户前请确认用户名是否正确以免带来不必要的麻烦。</li>
|
||||
<li>用户被添加到小组后将自动被加入组内的所有作业排行中。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5>编辑小组公告</h5>
|
||||
<?php $announcement_form->printHTML(); ?>
|
||||
|
||||
<h5>添加用户到小组</h5>
|
||||
<?php $add_new_user_form->printHTML(); ?>
|
||||
|
||||
<h5>从小组中删除用户</h5>
|
||||
<?php $delete_user_form->printHTML(); ?>
|
||||
|
||||
<h5>为小组添加作业</h5>
|
||||
<?php $add_new_assignment_form->printHTML(); ?>
|
||||
|
||||
<h5>删除小组的作业</h5>
|
||||
<?php $remove_assignment_form->printHTML(); ?>
|
||||
|
||||
<h5>已被自动隐藏的作业</h5>
|
||||
<ul>
|
||||
<?php
|
||||
$assignments = queryGroupAssignments($group['id']);
|
||||
foreach ($assignments as $ass) {
|
||||
$ddl = DateTime::createFromFormat('Y-m-d H:i:s', $ass['deadline']);
|
||||
$create_time = DateTime::createFromFormat('Y-m-d H:i:s', $ass['create_time']);
|
||||
$now = new DateTime();
|
||||
|
||||
if ($now->getTimestamp() - $ddl->getTimestamp() <= 604800) {
|
||||
continue;
|
||||
} // 7d
|
||||
|
||||
echo '<li>';
|
||||
echo '<a ';
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo ' class="text-decoration-none" ';
|
||||
}
|
||||
echo ' href="/problem_list/', $ass['list_id'], '">', $ass['title'], ' (题单 #', $ass['list_id'], ')</a>';
|
||||
|
||||
if ($ddl < $now) {
|
||||
echo '<sup style="color:red"> overdue</sup>';
|
||||
} elseif ($ddl->getTimestamp() - $now->getTimestamp() < 86400) { // 1d
|
||||
echo '<sup style="color:red"> soon</sup>';
|
||||
} elseif ($now->getTimestamp() - $create_time->getTimestamp() < 86400) { // 1d
|
||||
echo '<sup style="color:red"> new</sup>';
|
||||
}
|
||||
|
||||
$ddl_str = $ddl->format('Y-m-d H:i');
|
||||
echo ' (截止时间: ', $ddl_str, ',<a ';
|
||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
||||
echo ' class="text-decoration-none" ';
|
||||
}
|
||||
echo ' href="/group/',$group['id'],'/assignment/', $ass['list_id'], '">查看完成情况</a>)';
|
||||
echo '</li>';
|
||||
}
|
||||
|
||||
if (count($assignments) == 0) {
|
||||
echo '<p>暂无作业</p>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
||||
|
@ -19,7 +19,7 @@
|
||||
$count = $_result["count(*)"];
|
||||
|
||||
function throwError($msg) {
|
||||
returnJSONData(['status' => 'error', 'message' => $msg]);
|
||||
dieWithJsonData(['status' => 'error', 'message' => $msg]);
|
||||
}
|
||||
|
||||
$allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG];
|
||||
@ -66,7 +66,7 @@
|
||||
$existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'");
|
||||
|
||||
if ($existing_image) {
|
||||
returnJSONData(['status' => 'success', 'path' => $existing_image['path']]);
|
||||
dieWithJsonData(['status' => 'success', 'path' => $existing_image['path']]);
|
||||
}
|
||||
|
||||
$image = new Imagick($_FILES["image_upload_file"]["tmp_name"]);
|
||||
@ -92,7 +92,7 @@
|
||||
|
||||
DB::insert("INSERT INTO users_images (`path`, uploader, width, height, upload_time, size, `hash`) VALUES ('$filename', '{$myUser['username']}', $width, $height, now(), {$_FILES["image_upload_file"]["size"]}, '$hash')");
|
||||
|
||||
returnJSONData(['status' => 'success', 'path' => $filename]);
|
||||
dieWithJsonData(['status' => 'success', 'path' => $filename]);
|
||||
} elseif ($_POST['image_delete_submit'] == 'submit') {
|
||||
crsf_defend();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
$blogs = DB::selectAll("select blogs.id, title, poster, post_time from important_blogs, blogs where is_hidden = 0 and important_blogs.blog_id = blogs.id order by level desc, important_blogs.blog_id desc limit 5");
|
||||
$countdowns = DB::selectAll("select * from countdowns order by endtime asc");
|
||||
$countdowns = DB::selectAll("select * from countdowns order by end_time asc");
|
||||
$friend_links = DB::selectAll("select * from friend_links order by level desc, id asc");
|
||||
|
||||
if (!isset($_COOKIE['bootstrap4'])) {
|
||||
@ -134,7 +134,7 @@
|
||||
<?php endif ?> mb-0">
|
||||
<?php foreach ($countdowns as $countdown): ?>
|
||||
<?php
|
||||
$enddate = strtotime($countdown['endtime']);
|
||||
$enddate = strtotime($countdown['end_time']);
|
||||
$nowdate = time();
|
||||
$diff = floor(($enddate - $nowdate) / (24 * 60 * 60));
|
||||
?>
|
||||
|
@ -56,12 +56,12 @@
|
||||
$blog_id = $_POST['blog_id'];
|
||||
|
||||
if (!validateUInt($blog_id)) {
|
||||
die('<script>alert("移除失败:博客 ID 无效");</script>' . SCRIPT_REFRESH_AS_GET);
|
||||
dieWithAlert('移除失败:博客 ID 无效');
|
||||
}
|
||||
|
||||
DB::delete("DELETE FROM important_blogs WHERE blog_id = {$blog_id}");
|
||||
|
||||
die('<script>alert("移除成功!");</script>' . SCRIPT_REFRESH_AS_GET);
|
||||
dieWithAlert('移除成功!');
|
||||
}
|
||||
|
||||
$announcements = DB::selectAll("SELECT blogs.id as id, blogs.title as title, blogs.poster as poster, user_info.realname as realname, blogs.post_time as post_time, important_blogs.level as level, blogs.is_hidden as is_hidden FROM important_blogs INNER JOIN blogs ON important_blogs.blog_id = blogs.id INNER JOIN user_info ON blogs.poster = user_info.username ORDER BY level DESC, important_blogs.blog_id DESC");
|
||||
@ -121,15 +121,15 @@
|
||||
$countdown_id = $_POST['countdown_id'];
|
||||
|
||||
if (!validateUInt($countdown_id)) {
|
||||
die('<script>alert("删除失败:倒计时 ID 无效");</script>' . SCRIPT_REFRESH_AS_GET);
|
||||
dieWithAlert('删除失败:倒计时 ID 无效');
|
||||
}
|
||||
|
||||
DB::delete("DELETE FROM countdowns WHERE id = {$countdown_id}");
|
||||
|
||||
die('<script>alert("删除成功!");</script>' . SCRIPT_REFRESH_AS_GET);
|
||||
dieWithAlert('删除成功!');
|
||||
}
|
||||
|
||||
$countdowns = DB::selectAll("SELECT id, title, endtime FROM countdowns ORDER BY endtime ASC");
|
||||
$countdowns = DB::selectAll("SELECT id, title, end_time FROM countdowns ORDER BY end_time ASC");
|
||||
|
||||
$add_countdown_form = new UOJForm('add_countdown');
|
||||
$add_countdown_form->addInput('countdown_title', 'text', '标题', '',
|
||||
@ -144,10 +144,10 @@
|
||||
},
|
||||
null
|
||||
);
|
||||
$add_countdown_form->addInput('countdown_endtime', 'text', '结束时间', date("Y-m-d H:i:s"),
|
||||
function($endtime, &$vdata) {
|
||||
$add_countdown_form->addInput('countdown_end_time', 'text', '结束时间', date("Y-m-d H:i:s"),
|
||||
function($end_time, &$vdata) {
|
||||
try {
|
||||
$vdata['endtime'] = new DateTime($endtime);
|
||||
$vdata['end_time'] = new DateTime($end_time);
|
||||
} catch (Exception $e) {
|
||||
return '无效时间格式';
|
||||
}
|
||||
@ -158,9 +158,9 @@
|
||||
);
|
||||
$add_countdown_form->handle = function(&$vdata) {
|
||||
$esc_title = DB::escape($vdata['title']);
|
||||
$esc_endtime = DB::escape($vdata['endtime']->format('Y-m-d H:i:s'));
|
||||
$esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s'));
|
||||
|
||||
DB::insert("INSERT INTO countdowns (title, endtime) VALUES ('{$esc_title}', '{$esc_endtime}')");
|
||||
DB::insert("INSERT INTO countdowns (title, end_time) VALUES ('{$esc_title}', '{$esc_end_time}')");
|
||||
};
|
||||
$add_countdown_form->submit_button_config['align'] = 'compressed';
|
||||
$add_countdown_form->submit_button_config['text'] = '添加';
|
||||
@ -174,12 +174,12 @@
|
||||
$item_id = $_POST['item_id'];
|
||||
|
||||
if (!validateUInt($item_id)) {
|
||||
die('<script>alert("删除失败:ID 无效");</script>' . SCRIPT_REFRESH_AS_GET);
|
||||
dieWithAlert('删除失败:ID 无效');
|
||||
}
|
||||
|
||||
DB::delete("DELETE FROM links WHERE id = {$item_id}");
|
||||
|
||||
die('<script>alert("删除成功!");</script>' . SCRIPT_REFRESH_AS_GET);
|
||||
dieWithAlert('删除成功!');
|
||||
}
|
||||
|
||||
$links = DB::selectAll("SELECT `id`, `title`, `url`, `level` FROM `friend_links` ORDER BY `level` DESC, `id` ASC");
|
||||
@ -315,7 +315,7 @@
|
||||
|
||||
DB::query("insert into user_info (username, realname, email, school, password, svn_password, register_time, usergroup) values ('$username', '$realname', '$email', '$school', '$password', '$svn_password', now(), 'U')");
|
||||
|
||||
returnJSONData(['status' => 'success', 'message' => '']);
|
||||
dieWithJsonData(['status' => 'success', 'message' => '']);
|
||||
};
|
||||
$register_form->setAjaxSubmit(<<<EOD
|
||||
function(res) {
|
||||
@ -370,7 +370,7 @@ EOD);
|
||||
|
||||
DB::query("update user_info set password = '$esc_password' where username = '$esc_username'");
|
||||
|
||||
returnJSONData(['status' => 'success', 'message' => '用户 ' . $vdata['username'] . ' 的密码已经被成功重置。']);
|
||||
dieWithJsonData(['status' => 'success', 'message' => '用户 ' . $vdata['username'] . ' 的密码已经被成功重置。']);
|
||||
};
|
||||
$change_password_form->submit_button_config['margin_class'] = 'mt-3';
|
||||
$change_password_form->submit_button_config['text'] = '重置';
|
||||
@ -436,7 +436,7 @@ EOD);
|
||||
break;
|
||||
}
|
||||
|
||||
returnJSONData(['status' => 'success', 'message' => '用户 ' . $username . ' 现在是 ' . $usergroup . '。']);
|
||||
dieWithJsonData(['status' => 'success', 'message' => '用户 ' . $username . ' 现在是 ' . $usergroup . '。']);
|
||||
};
|
||||
$change_usergroup_form->setAjaxSubmit(<<<EOD
|
||||
function(res) {
|
||||
@ -539,17 +539,17 @@ EOD);
|
||||
$image_id = $_POST['image_id'];
|
||||
|
||||
if (!validateUInt($image_id)) {
|
||||
die('<script>alert("删除失败:图片 ID 无效");</script>' . SCRIPT_REFRESH_AS_GET);
|
||||
dieWithAlert('删除失败:图片 ID 无效');
|
||||
}
|
||||
|
||||
if (!($image = DB::selectFirst("SELECT * from users_images where id = $image_id"))) {
|
||||
die('<script>alert("删除失败:图片不存在");</script>' . SCRIPT_REFRESH_AS_GET);
|
||||
dieWithAlert('删除失败:图片不存在');
|
||||
}
|
||||
|
||||
unlink(UOJContext::storagePath().$result['path']);
|
||||
DB::delete("DELETE FROM users_images WHERE id = $image_id");
|
||||
|
||||
die('<script>alert("删除成功!");</script>' . SCRIPT_REFRESH_AS_GET);
|
||||
dieWithAlert('删除成功!');
|
||||
}
|
||||
|
||||
|
||||
@ -710,7 +710,7 @@ EOD);
|
||||
col_tr += '<tr>';
|
||||
|
||||
col_tr += '<td>' + row['title'] + '</td>';
|
||||
col_tr += '<td>' + row['endtime'] + '</td>';
|
||||
col_tr += '<td>' + row['end_time'] + '</td>';
|
||||
col_tr += '<td>' +
|
||||
'<form method="POST" onsubmit=\'return confirm("你真的要删除这个倒计时吗?")\'>' +
|
||||
'<input type="hidden" name="_token" value="<?= crsf_token() ?>">' +
|
||||
|
@ -179,7 +179,7 @@ EOD);
|
||||
|
||||
DB::update("UPDATE user_info SET email = '$esc_email', qq = '$esc_qq', sex = '$esc_sex', motto = '$esc_motto', codeforces_handle = '$esc_codeforces_handle', github = '$esc_github', website = '$esc_website', avatar_source = '$esc_avatar_source' WHERE username = '{$user['username']}'");
|
||||
|
||||
returnJSONData(['status' => 'success']);
|
||||
dieWithJsonData(['status' => 'success']);
|
||||
};
|
||||
$update_profile_form->submit_button_config['margin_class'] = 'mt-3';
|
||||
$update_profile_form->submit_button_config['text'] = '更新';
|
||||
@ -209,21 +209,21 @@ EOD);
|
||||
$new_password = $_POST['new_password'];
|
||||
|
||||
if (!validatePassword($old_password) || !checkPassword($user, $old_password)) {
|
||||
returnJSONData(['status' => 'error', 'message' => '旧密码错误']);
|
||||
dieWithJsonData(['status' => 'error', 'message' => '旧密码错误']);
|
||||
}
|
||||
|
||||
if (!validatePassword($new_password)) {
|
||||
returnJSONData(['status' => 'error', 'message' => '新密码不合法']);
|
||||
dieWithJsonData(['status' => 'error', 'message' => '新密码不合法']);
|
||||
}
|
||||
|
||||
if ($old_password == $new_password) {
|
||||
returnJSONData(['status' => 'error', 'message' => '新密码不能与旧密码相同']);
|
||||
dieWithJsonData(['status' => 'error', 'message' => '新密码不能与旧密码相同']);
|
||||
}
|
||||
|
||||
$password = getPasswordToStore($new_password, $user['username']);
|
||||
DB::update("UPDATE `user_info` SET `password` = '$password' where `username` = '{$user['username']}'");
|
||||
|
||||
returnJSONData(['status' => 'success', 'message' => '密码修改成功']);
|
||||
dieWithJsonData(['status' => 'success', 'message' => '密码修改成功']);
|
||||
}
|
||||
} elseif ($cur_tab == 'privilege') {
|
||||
if (isset($_POST['submit-privilege']) && $_POST['submit-privilege'] == 'privilege' && isSuperUser($myUser)) {
|
||||
@ -254,7 +254,7 @@ EOD);
|
||||
|
||||
DB::update("UPDATE `user_info` SET `usertype` = '{$user['usertype']}' where `username` = '{$user['username']}'");
|
||||
|
||||
returnJSONData(['status' => 'success', 'message' => '权限修改成功']);
|
||||
dieWithJsonData(['status' => 'success', 'message' => '权限修改成功']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
<?php
|
||||
define('SCRIPT_REFRESH_AS_GET', '<script>;window.location = window.location.origin + window.location.pathname + (window.location.search.length ? window.location.search + "&" : "?") + "_refresh_" + (+new Date()) + "=" + (+new Date()) + window.location.hash;</script>');
|
||||
|
||||
class UOJForm {
|
||||
public $form_name;
|
||||
public $succ_href;
|
||||
@ -862,8 +864,12 @@ EOD;
|
||||
return $form;
|
||||
}
|
||||
|
||||
function returnJSONData($data) {
|
||||
function dieWithJsonData($data) {
|
||||
header('Content-Type: application/json');
|
||||
die(json_encode($data));
|
||||
}
|
||||
|
||||
function dieWithAlert($str) {
|
||||
die('<script>alert(decodeURIComponent("'.rawurlencode($str).'"));</script>'.SCRIPT_REFRESH_AS_GET);
|
||||
}
|
||||
?>
|
||||
|
@ -130,6 +130,9 @@ function queryContestProblems($id) {
|
||||
function queryGroup($id) {
|
||||
return DB::selectFirst("select * from groups where id = $id", MYSQLI_ASSOC);
|
||||
}
|
||||
function queryGroupUsers($id) {
|
||||
return DB::selectAll("SELECT * FROM groups_users WHERE group_id = $id");
|
||||
}
|
||||
function queryUserInGroup($group_id, $username) {
|
||||
return DB::selectFirst("select * from groups_users where username='$username' and group_id='$group_id'", MYSQLI_ASSOC);
|
||||
}
|
||||
@ -143,17 +146,13 @@ function queryGroupCurrentAC($group_id) {
|
||||
return DB::selectAll("select a.problem_id as problem_id, a.submitter as submitter, a.submission_id as submission_id, b.submit_time as submit_time, d.title as problem_title, b.submit_time as submit_time, e.realname as realname from best_ac_submissions a inner join submissions b on (a.submission_id = b.id) inner join groups_users c on (a.submitter = c.username and c.group_id = $group_id) inner join problems d on (a.problem_id = d.id and d.is_hidden = 0) inner join user_info e on (a.submitter = e.username) where b.submit_time > addtime(now(), '-360:00:00') order by b.submit_time desc limit 10", MYSQLI_ASSOC);
|
||||
}
|
||||
function queryGroupAssignments($group_id) {
|
||||
return DB::selectAll("select a.id as id, a.list_id as list_id, a.create_time as create_time, a.deadline as deadline, b.title from assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id order by a.deadline asc", MYSQLI_ASSOC);
|
||||
return DB::selectAll("select a.id as id, a.list_id as list_id, a.end_time as end_time, b.title from groups_assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id order by a.end_time asc", MYSQLI_ASSOC);
|
||||
}
|
||||
function queryGroupActiveAssignments($group_id) {
|
||||
return DB::selectAll("select a.id as id, a.group_id as group_id, a.list_id as list_id, a.create_time as create_time, a.deadline as deadline, b.title from assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id and a.deadline > addtime(now(), '-168:00:00') order by a.deadline asc", MYSQLI_ASSOC);
|
||||
}
|
||||
|
||||
function queryAssignment($id) {
|
||||
return DB::selectFirst("select * from assignments where id = $id", MYSQLI_ASSOC);
|
||||
return DB::selectAll("select a.id as id, a.group_id as group_id, a.list_id as list_id, a.end_time as end_time, b.title from groups_assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id and a.end_time >= addtime(now(), '-168:00:00') order by a.end_time asc", MYSQLI_ASSOC);
|
||||
}
|
||||
function queryAssignmentByGroupListID($group_id, $list_id) {
|
||||
return DB::selectFirst("select * from assignments where list_id='$list_id' and group_id='$group_id'", MYSQLI_ASSOC);
|
||||
return DB::selectFirst("select * from groups_assignments where list_id='$list_id' and group_id='$group_id'", MYSQLI_ASSOC);
|
||||
}
|
||||
|
||||
function queryZanVal($id, $type, $user) {
|
||||
|
@ -15,6 +15,7 @@ return [
|
||||
'problems lists' => 'Problems Lists',
|
||||
'groups' => 'Groups',
|
||||
'add new group' => 'Add new group',
|
||||
'group announcement' => 'Group Announcement',
|
||||
'group announcements' => 'Group Announcements',
|
||||
'users count' => 'Users',
|
||||
'submissions' => 'Submissions',
|
||||
|
@ -15,6 +15,7 @@ return [
|
||||
'problems lists' => '题单',
|
||||
'groups' => '小组',
|
||||
'add new group' => '添加新小组',
|
||||
'group announcement' => '小组公告',
|
||||
'group announcements' => '小组公告',
|
||||
'users count' => '用户数量',
|
||||
'submissions' => '提交记录',
|
||||
|
@ -49,7 +49,7 @@ Route::group([
|
||||
|
||||
Route::any('/groups', '/groups.php');
|
||||
Route::any('/group/{id}', '/group.php');
|
||||
Route::any('/group/{id}/manage', '/group_manage.php');
|
||||
Route::any('/group/{id}/manage(?:/{tab})?', '/group_manage.php');
|
||||
Route::any('/group/{id}/assignment/{list_id}', '/group_assignment.php');
|
||||
|
||||
Route::any('/blogs', '/blogs.php');
|
||||
|
1
web/app/upgrade/8_group_v2/README.md
Normal file
1
web/app/upgrade/8_group_v2/README.md
Normal file
@ -0,0 +1 @@
|
||||
ref: https://github.com/renbaoshuo/S2OJ/pull/8
|
4
web/app/upgrade/8_group_v2/down.sql
Normal file
4
web/app/upgrade/8_group_v2/down.sql
Normal file
@ -0,0 +1,4 @@
|
||||
RENAME TABLE groups_assignments TO assignments;
|
||||
ALTER TABLE `assignments` ADD COLUMN `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
ALTER TABLE `assignments` CHANGE COLUMN `end_time` `deadline` datetime NOT NULL;
|
||||
ALTER TABLE `countdowns` CHANGE COLUMN `end_time` `endtime` datetime NOT NULL;
|
4
web/app/upgrade/8_group_v2/up.sql
Normal file
4
web/app/upgrade/8_group_v2/up.sql
Normal file
@ -0,0 +1,4 @@
|
||||
RENAME TABLE assignments TO groups_assignments;
|
||||
ALTER TABLE `groups_assignments` DROP COLUMN `create_time`;
|
||||
ALTER TABLE `groups_assignments` CHANGE COLUMN `deadline` `end_time` datetime NOT NULL;
|
||||
ALTER TABLE `countdowns` CHANGE COLUMN `endtime` `end_time` datetime NOT NULL;
|
@ -21,8 +21,16 @@
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php if ($standings_data): ?>
|
||||
<div class="tab-pane card-body" id="tab-standings">
|
||||
<?php uojIncludeView('contest-standings', array_merge($standings_data, ['no_bs5_card' => ''])) ?>
|
||||
<div class="tab-pane" id="tab-standings">
|
||||
<?php
|
||||
uojIncludeView('contest-standings', array_merge(
|
||||
$standings_data,
|
||||
[
|
||||
'standings_config' => [
|
||||
'div_classes' => ['table-responsive', 'mb-3']
|
||||
]
|
||||
]
|
||||
)); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
@ -1,14 +1,13 @@
|
||||
<div id="standings" class="
|
||||
<?php if (!isset($no_bs5_card)): ?>
|
||||
card card-default
|
||||
<?php endif ?>"></div>
|
||||
<div id="standings"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
standings_version=<?=$contest['extra_config']['standings_version']?>;
|
||||
show_self_reviews=<?=isset($show_self_reviews) && $show_self_reviews ? 'true' : 'false' ?>;
|
||||
contest_id=<?=$contest['id']?>;
|
||||
standings=<?=json_encode($standings)?>;
|
||||
score=<?=json_encode($score)?>;
|
||||
problems=<?=json_encode($contest_data['problems'])?>;
|
||||
$(document).ready(showStandings());
|
||||
var standings_version=<?=$contest['extra_config']['standings_version']?>;
|
||||
var show_self_reviews=<?=isset($show_self_reviews) && $show_self_reviews ? 'true' : 'false' ?>;
|
||||
var contest_id=<?=$contest['id']?>;
|
||||
var standings=<?=json_encode($standings)?>;
|
||||
var score=<?=json_encode($score)?>;
|
||||
var problems=<?=json_encode($contest_data['problems'])?>;
|
||||
var standings_config = <?=json_encode(isset($standings_config) ? $standings_config : ['_config' => true])?>;
|
||||
|
||||
$(document).ready(showStandings(standings_config));
|
||||
</script>
|
||||
|
@ -11,6 +11,8 @@
|
||||
<?php
|
||||
$group_detail = DB::selectFirst("select * from groups where id = {$group['id']}");
|
||||
$group_announcement = $group_detail['announcement'];
|
||||
$purifier = HTML::purifier_inline();
|
||||
$parsedown = HTML::parsedown();
|
||||
?>
|
||||
<li class="list-group-item">
|
||||
<a class="fw-bold text-decoration-none" href="<?= HTML::url('/group/'.$group['id']) ?>">
|
||||
@ -18,7 +20,7 @@
|
||||
</a>
|
||||
<?php if ($group_announcement): ?>
|
||||
<div class="text-break">
|
||||
<?= HTML::purifier_inline()->purify($group_announcement) ?>
|
||||
<?= $purifier->purify($parsedown->line($group_announcement)) ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="text-muted">
|
||||
@ -38,11 +40,13 @@
|
||||
}
|
||||
|
||||
usort($assignments, function($a, $b) {
|
||||
$deadline_a = DateTime::createFromFormat('Y-m-d H:i:s', $a['deadline']);
|
||||
$deadline_b = DateTime::createFromFormat('Y-m-d H:i:s', $b['deadline']);
|
||||
$end_time_a = DateTime::createFromFormat('Y-m-d H:i:s', $a['end_time']);
|
||||
$end_time_b = DateTime::createFromFormat('Y-m-d H:i:s', $b['end_time']);
|
||||
|
||||
return $deadline_b->getTimestamp() - $deadline_a->getTimestamp();
|
||||
return $end_time_b->getTimestamp() - $end_time_a->getTimestamp();
|
||||
});
|
||||
|
||||
$assignments = array_slice($assignments, 0, 5);
|
||||
?>
|
||||
<?php if (count($assignments)): ?>
|
||||
<div class="card card-default mb-2" id="group-assignments">
|
||||
@ -53,22 +57,19 @@
|
||||
<?php foreach ($assignments as $assignment): ?>
|
||||
<li class="list-group-item">
|
||||
<?php
|
||||
$deadline = DateTime::createFromFormat('Y-m-d H:i:s', $assignment['deadline']);
|
||||
$create_time = DateTime::createFromFormat('Y-m-d H:i:s', $assignment['create_time']);
|
||||
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $assignment['end_time']);
|
||||
$now = new DateTime();
|
||||
?>
|
||||
<a href="<?= HTML::url('/group/'.$assignment['group_id'].'/assignment/'.$assignment['list_id']) ?>" class="fw-bold text-decoration-none">
|
||||
<?= $assignment['title'] ?>
|
||||
<?php if ($deadline < $now): ?>
|
||||
<?php if ($end_time < $now): ?>
|
||||
<sup class="fw-normal text-danger">overdue</sup>
|
||||
<?php elseif ($deadline->getTimestamp() - $now->getTimestamp() < 86400): ?>
|
||||
<?php elseif ($end_time->getTimestamp() - $now->getTimestamp() < 86400): ?>
|
||||
<sup class="fw-normal text-danger">soon</sup>
|
||||
<?php elseif ($now->getTimestamp() - $create_time->getTimestamp() < 86400): ?>
|
||||
<sup class="fw-normal text-danger">new</sup>
|
||||
<?php endif ?>
|
||||
</a>
|
||||
<div class="text-end small text-muted">
|
||||
截止时间: <?= $deadline->format('Y-m-d H:i') ?>
|
||||
截止时间: <?= $end_time->format('Y-m-d H:i') ?>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
|
@ -51,11 +51,13 @@ label {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.uoj-table > tbody > tr:last-child {
|
||||
.uoj-table > tbody > tr:last-child,
|
||||
.uoj-table > tbody > tr:last-child > td {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
.uoj-table > thead > tr:first-child {
|
||||
.uoj-table > thead > tr:first-child,
|
||||
.uoj-table > thead > tr:first-child > td {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
|
@ -541,18 +541,16 @@ $.fn.long_table = function(data, cur_page, header_row, get_row_str, config) {
|
||||
|
||||
$(table_div).append(
|
||||
$('<div class="' + div_classes.join(' ') + '" />').append(
|
||||
(typeof config.print_before_table === 'function' ? config.print_before_table() : ''),
|
||||
$('<table class="' + table_classes.join(' ') + '" />').append(
|
||||
$('<thead>' + header_row + '</thead>')
|
||||
).append(
|
||||
tbody
|
||||
)
|
||||
),
|
||||
(typeof config.print_after_table === 'function' ? config.print_after_table() : '')
|
||||
)
|
||||
);
|
||||
|
||||
if (config.print_after_table != undefined) {
|
||||
$(table_div).append(config.print_after_table());
|
||||
}
|
||||
|
||||
var get_page_li = function(p, h) {
|
||||
if (p == -1) {
|
||||
return $('<li class="page-item"></li>').addClass('disabled').append($('<a class="page-link"></a>').append(h));
|
||||
@ -1129,7 +1127,7 @@ function showCommentReplies(id, replies) {
|
||||
}
|
||||
|
||||
// standings
|
||||
function showStandings() {
|
||||
function showStandings(config) {
|
||||
$("#standings").long_table(
|
||||
standings,
|
||||
1,
|
||||
@ -1178,9 +1176,9 @@ function showStandings() {
|
||||
col_tr += '</tr>';
|
||||
return col_tr;
|
||||
}, {
|
||||
div_classes: ['table-responsive'],
|
||||
table_classes: ['table', 'table-bordered', 'text-center', 'align-middle', 'uoj-table', 'uoj-standings-table', 'mb-0'],
|
||||
page_len: 100,
|
||||
div_classes: config.div_classes ? config.div_classes : ['table-responsive', 'card', 'my-3'],
|
||||
table_classes: config.table_classes ? config.table_classes : ['table', 'table-bordered', 'text-center', 'align-middle', 'uoj-table', 'uoj-standings-table', 'mb-0'],
|
||||
page_len: config.page_len ? config.page_len : 50,
|
||||
print_after_table: function() {
|
||||
return '<div class="card-footer bg-transparent text-end text-muted">' + uojLocale("contests::n participants", standings.length) + '</div><script>if (window.MathJax) window.MathJax.typeset();</scr' + 'ipt>';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user