Skip to content

Commit 49b5fc3

Browse files
committed
feat: problem list order
1 parent 838e987 commit 49b5fc3

6 files changed

Lines changed: 149 additions & 6 deletions

File tree

db/app_uoj233.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,7 @@ UNLOCK TABLES;
814814
CREATE TABLE `lists_problems` (
815815
`list_id` int NOT NULL,
816816
`problem_id` int NOT NULL,
817+
`problem_order` int NOT NULL DEFAULT 0,
817818
PRIMARY KEY (`list_id`, `problem_id`),
818819
KEY `list_id` (`list_id`)
819820
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

web/app/controllers/list.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ function getProblemTR($info) {
9595
],
9696
],
9797
'cond' => '1',
98-
'tail' => "order by id asc",
98+
'tail' => "order by lists_problems.problem_order, problems.id asc",
9999
'page_len' => 50,
100100
'post_filter' => function ($problem) {
101101
return (new UOJProblem($problem))->userCanView(Auth::user());

web/app/controllers/list_manage.php

Lines changed: 115 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,15 @@ function ($problem_id) {
182182
},
183183
function ($type, $problem_id) {
184184
if ($type == '+') {
185+
$max_order = DB::selectFirst([
186+
"select max(problem_order) as max_order from lists_problems",
187+
"where", ["list_id" => UOJList::info('id')],
188+
]);
189+
$next_order = ($max_order['max_order'] ?? 0) + 1;
185190
DB::insert([
186191
"insert into lists_problems",
187-
DB::bracketed_fields(["list_id", "problem_id"]),
188-
"values", DB::tuple([UOJList::info('id'), $problem_id]),
192+
DB::bracketed_fields(["list_id", "problem_id", "problem_order"]),
193+
"values", DB::tuple([UOJList::info('id'), $problem_id, $next_order]),
189194
]);
190195
} else if ($type == '-') {
191196
DB::delete([
@@ -204,6 +209,92 @@ function ($type, $problem_id) {
204209
);
205210
$problems_form->runAtServer();
206211

212+
// Reorder form
213+
$current_order = DB::selectAll([
214+
"select problem_id from lists_problems",
215+
"where", ["list_id" => UOJList::info('id')],
216+
"order by problem_order asc, problem_id asc",
217+
]);
218+
$current_order_str = implode("\n", array_map(fn($x) => $x['problem_id'], $current_order));
219+
220+
$reorder_form = new UOJForm('reorder_problems');
221+
$reorder_form->addTextArea('problem_order', [
222+
'label' => '题目顺序',
223+
'input_class' => 'form-control font-monospace',
224+
'default_value' => $current_order_str,
225+
'validator_php' => function ($str, &$vdata) {
226+
$ids = [];
227+
foreach (explode("\n", $str) as $line) {
228+
$line = trim($line);
229+
if ($line === '') continue;
230+
if (!validateUInt($line)) {
231+
return "无效题号:{$line}";
232+
}
233+
$ids[] = intval($line);
234+
}
235+
236+
// Get all problem IDs in current list
237+
$current_ids = array_map(
238+
fn($x) => intval($x['problem_id']),
239+
DB::selectAll([
240+
"select problem_id from lists_problems",
241+
"where", ["list_id" => UOJList::info('id')],
242+
])
243+
);
244+
245+
sort($current_ids);
246+
$sorted_ids = $ids;
247+
sort($sorted_ids);
248+
249+
if ($sorted_ids !== $current_ids) {
250+
return '题目列表与当前题单中的题目不一致,请确保包含所有题目且无多余题目';
251+
}
252+
253+
if (count($ids) !== count(array_unique($ids))) {
254+
return '存在重复的题号';
255+
}
256+
257+
$vdata['order'] = $ids;
258+
return '';
259+
},
260+
'help' => '每行一个题号,按照从上到下的顺序排列。',
261+
]);
262+
$reorder_form->handle = function ($vdata) {
263+
$order = 1;
264+
foreach ($vdata['order'] as $problem_id) {
265+
DB::update([
266+
"update lists_problems",
267+
"set", ["problem_order" => $order],
268+
"where", [
269+
"list_id" => UOJList::info('id'),
270+
"problem_id" => $problem_id,
271+
],
272+
]);
273+
$order++;
274+
}
275+
dieWithJsonData(['status' => 'success', 'message' => '排序更新成功']);
276+
};
277+
$reorder_form->setAjaxSubmit(<<<EOD
278+
function(res) {
279+
if (res.status === 'success') {
280+
$('#reorder-result-alert')
281+
.html('排序更新成功!')
282+
.addClass('alert-success')
283+
.removeClass('alert-danger')
284+
.show();
285+
location.reload();
286+
} else {
287+
$('#reorder-result-alert')
288+
.html('排序更新失败。' + (res.message || ''))
289+
.removeClass('alert-success')
290+
.addClass('alert-danger')
291+
.show();
292+
}
293+
}
294+
EOD);
295+
$reorder_form->config['submit_button']['text'] = '更新排序';
296+
$reorder_form->runAtServer();
297+
207298
$n_problems = DB::selectCount([
208299
"select count(*)",
209300
"from lists_problems",
@@ -258,12 +349,13 @@ function ($type, $problem_id) {
258349
<div class="card-body">
259350
<?php
260351
echoLongTable(
261-
['problem_id'],
352+
['problem_id', 'problem_order'],
262353
"lists_problems",
263354
["list_id" => UOJList::info('id')],
264-
"order by problem_id asc",
355+
"order by problem_order asc, problem_id asc",
265356
<<<EOD
266357
<tr>
358+
<th class="text-center" style="width:3em">#</th>
267359
<th class="text-center" style="width:5em">ID</th>
268360
<th>标题</th>
269361
</tr>
@@ -272,6 +364,7 @@ function ($row) {
272364
$problem = UOJProblem::query($row['problem_id']);
273365

274366
echo HTML::tag_begin('tr');
367+
echo HTML::tag('td', ['class' => 'text-center text-muted'], $row['problem_order']);
275368
echo HTML::tag('td', ['class' => 'text-center'], $problem->info['id']);
276369
echo HTML::tag_begin('td');
277370
echo $problem->getLink(['with' => 'none']);
@@ -292,7 +385,25 @@ function ($row) {
292385
);
293386
?>
294387

388+
<hr>
389+
295390
<?php $problems_form->printHTML() ?>
391+
392+
<hr>
393+
394+
<div id="reorder-result-alert" class="alert" role="alert" style="display: none"></div>
395+
<div class="row">
396+
<div class="col-md-8">
397+
<?php $reorder_form->printHTML() ?>
398+
</div>
399+
<div class="col-md-4">
400+
<h5>排序说明</h5>
401+
<ul class="mb-0">
402+
<li>每行一个题号,按照期望的展示顺序排列。</li>
403+
<li>必须包含题单中所有题目,不能多也不能少。</li>
404+
</ul>
405+
</div>
406+
</div>
296407
</div>
297408
</div>
298409
<?php endif ?>

web/app/models/UOJList.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function getProblemIDs() {
5252
return array_map(fn ($x) => $x['problem_id'], DB::selectAll([
5353
DB::lc(), "select problem_id from lists_problems",
5454
"where", ['list_id' => $this->info['id']],
55-
"order by problem_id"
55+
"order by problem_order, problem_id"
5656
]));
5757
}
5858

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE `lists_problems` ADD COLUMN `problem_order` int NOT NULL DEFAULT 0 AFTER `problem_id`;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
return function (string $type) {
4+
if ($type == 'up') {
5+
DB::init();
6+
7+
$lists = DB::selectAll("select distinct list_id from lists_problems");
8+
9+
foreach ($lists as $list) {
10+
$problems = DB::selectAll([
11+
"select problem_id from lists_problems",
12+
"where", ["list_id" => $list['list_id']],
13+
"order by problem_id asc",
14+
]);
15+
16+
$order = 1;
17+
foreach ($problems as $problem) {
18+
DB::update([
19+
"update lists_problems",
20+
"set", ["problem_order" => $order],
21+
"where", [
22+
"list_id" => $list['list_id'],
23+
"problem_id" => $problem['problem_id'],
24+
],
25+
]);
26+
$order++;
27+
}
28+
}
29+
}
30+
};

0 commit comments

Comments
 (0)