diff --git a/web/app/libs/uoj-contest-lib.php b/web/app/libs/uoj-contest-lib.php
index a88f28e..5ebc4bd 100644
--- a/web/app/libs/uoj-contest-lib.php
+++ b/web/app/libs/uoj-contest-lib.php
@@ -48,9 +48,9 @@ function updateContestPlayerNum($contest) {
// problems: pos => id
//
// for individual competition:
-// people : username, realname
+// people : username, realname, null, username_color
// for team competition:
-// people : username, null, ['team_name' => team_name, 'members' => members]
+// people : username, null, ['team_name' => team_name, 'members' => members], null
//
// for OI/IOI contest:
// data : id, submit_time, submitter, problem_pos, score
@@ -437,7 +437,7 @@ function calcStandings($contest, $contest_data, &$score, &$standings, $cfg = [])
function calcACMScoreAndPenaltyForOneProblem($contest, $problem_id, $sub, $n_failures) {
if (isset($contest['extra_config']['bonus']["problem_{$problem_id}"])) {
- if ($sub[4] === 100) {
+ if ($sub[4] == 100) {
return [0, -60 * 20];
} else {
return [0, 0];
diff --git a/web/app/views/contest-reviews.php b/web/app/views/contest-reviews.php
index 035e17e..89d4fb0 100644
--- a/web/app/views/contest-reviews.php
+++ b/web/app/views/contest-reviews.php
@@ -39,6 +39,12 @@ foreach ($contest_data['people'] as $person) {
}
?>
+
+
diff --git a/web/app/views/contest-standings.php b/web/app/views/contest-standings.php
index b5240f8..84d52c2 100644
--- a/web/app/views/contest-standings.php
+++ b/web/app/views/contest-standings.php
@@ -1,75 +1,22 @@
+
+
+ 封榜于 = $contest['frozen_time']->format(UOJTime::FORMAT) ?>
+
+
+
diff --git a/web/js/uoj.js b/web/js/uoj.js
index cfbadc4..2984664 100644
--- a/web/js/uoj.js
+++ b/web/js/uoj.js
@@ -524,14 +524,16 @@ $.fn.long_table = function(data, cur_page, header_row, get_row_str, config) {
}
$(table_div).append(
- $('
').append(
- (typeof config.print_before_table === 'function' ? config.print_before_table() : ''),
- $('
').append(
- $('
' + header_row + '')
- ).append(
- tbody
- ),
- (typeof config.print_after_table === 'function' ? config.print_after_table() : '')
+ typeof config.print_before_table === 'function' ? config.print_before_table() : ''
+ ).append(
+ $('
').append(
+ $('
').append(
+ $('
').append(header_row)
+ ).append(
+ tbody
+ )
+ ).append(
+ typeof config.print_after_table === 'function' ? config.print_after_table() : ''
)
);
@@ -554,8 +556,7 @@ $.fn.long_table = function(data, cur_page, header_row, get_row_str, config) {
);
return li;
};
-
- if (n_pages > 1) {
+ var get_pagination = function() {
var pagination = $('');
if (cur_page > 1) {
pagination.append(get_page_li(1, '
'));
@@ -575,7 +576,14 @@ $.fn.long_table = function(data, cur_page, header_row, get_row_str, config) {
pagination.append(get_page_li(-1, '
'));
pagination.append(get_page_li(-1, '
'));
}
- $(table_div).append($('
').append(pagination));
+ return pagination;
+ }
+
+ if (n_pages > 1) {
+ $(table_div).append($('
').append(get_pagination()));
+ if (config.top_pagination) {
+ $(table_div).prepend($('
').append(get_pagination()));
+ }
}
});
};
@@ -1663,6 +1671,293 @@ function showCommentReplies(id, replies) {
);
}
+function getACMStandingsMeta() {
+ var stat = {};
+ var full_score = 0;
+
+ for (var k = 0; k < problems.length; k++) {
+ var pid = problems[k];
+ stat[pid] = {};
+ stat[pid].cnt = 0;
+ stat[pid].ac_cnt = 0;
+ stat[pid].earliest = null;
+ if (("problem_" + pid) in bonus) {
+ for (var j in score) {
+ if (score[j][k] != undefined) {
+ stat[pid].cnt += score[j][k][3];
+ if (score[j][k][1] === -1200) {
+ stat[pid].ac_cnt++;
+ }
+ }
+ }
+ } else {
+ full_score += 100;
+ for (var j in score) {
+ if (score[j][k] != undefined) {
+ stat[pid].cnt += score[j][k][3];
+ if (score[j][k][0] === 100) {
+ stat[pid].ac_cnt++;
+ if (stat[pid].earliest === null || score[j][k][2] < stat[pid].earliest) {
+ stat[pid].earliest = score[j][k][2];
+ }
+ }
+ }
+ }
+ }
+ }
+ return { stat, full_score };
+}
+
+function setACMStandingsTH(th, i, meta) {
+ if (i == -3) {
+ return $(th).css('width', '34px').text('#');
+ } else if (i == -2) {
+ if (problems.length <= 10) {
+ $(th).css('width', '114px');
+ }
+ return $(th).text(uojLocale('username'));
+ } else if (i == -1) {
+ return $(th).css('width', '57px').text(uojLocale('contests::total score'));
+ }
+
+ var pid = problems[i];
+
+ $(th).css('width', '57px');
+ if (("problem_" + pid) in bonus) {
+ $(th).attr('title', '附加题,通过后减免 20 分钟罚时');
+ }
+ var th_str = '
';
+ if (meta && pid in meta.stat) {
+ th_str += '
' + meta.stat[pid].ac_cnt + '/' + meta.stat[pid].cnt + '
';
+ }
+ return $(th).html(th_str);
+}
+
+function setACMStandingsTD(td, row, i, meta) {
+ if (i == -3) {
+ return $(td).attr('class', '').html(row[3]);
+ } else if (i == -2) {
+ if (2 in row[2] && row[2][2]) {
+ let td_title = row[2][2]['team_name'] + "\n";
+ for (var i = 0; i < row[2][2]['members'].length; i++) {
+ td_title += row[2][2]['members'][i]['name'];
+ td_title += " (";
+ td_title += row[2][2]['members'][i]['organization'];
+ td_title += ")";
+ if (i < row[2][2]['members'].length - 1) {
+ td_title += "\n";
+ }
+ }
+ return $(td).attr('class', '').attr('title', td_title).html(
+ '
' +
+ '' + htmlspecialchars(row[2][2]['team_name']) + '' +
+ '
' +
+ '
' +
+ '' + getUserLink(row[2][0], row[2][1], row[2][3]) + '' +
+ '
'
+ );
+ } else {
+ return $(td).attr('class', '').html(getUserLink(row[2][0], row[2][1], row[2][3]));
+ }
+ } else if (i == -1) {
+ let td_title = "总分:" + row[0] + "\n";
+ td_title += "罚时:" + row[1] + ",即 " + getPenaltyTimeStr(row[1]);
+ return $(td).attr('class', 'standings-score-td').attr('title', td_title).html(
+ '
' +
+ '' +
+ row[0] +
+ '' +
+ '
' +
+ '
' +
+ '' + getPenaltyTimeStr(row[1]) + '' +
+ '
'
+ );
+ }
+
+ var col = score[row[2][0]][i];
+
+ $(td).attr('class', 'standings-score-td');
+
+ if (col === undefined) {
+ return $(td).html('');
+ }
+
+ var td_title = String.fromCharCode('A'.charCodeAt(0) + i) + "题\n";
+ var td_content = '';
+
+ if (("problem_" + problems[i]) in bonus) {
+ td_content += '
';
+ if (col[0] !== null) {
+ if (col[1] == -1200) {
+ td_content += '
';
+ td_content += '+';
+ td_content += '';
+
+ td_title += col[3] + " 次有效提交后通过,减免罚时 20 分钟";
+ } else {
+ td_content += '
';
+ td_content += 0;
+ td_content += '';
+
+ td_title += "尚未通过,未减免罚时";
+ td_title += "\n" + col[3] + " 次有效提交";
+ }
+ if (col[5] > 0) {
+ td_content += ' + ';
+ td_title += "\n" + "因封榜有 " + col[5] + " 次提交结果未知";
+ }
+ } else {
+ td_title += "封榜后提交了 " + col[5] + " 次,结果未知";
+ }
+
+ if (col[5] > 0) {
+ td_content += '
?';
+ }
+ td_content += '
';
+
+ if (col[4] > 0) {
+ td_content += '
';
+ td_content += '(+' + col[4] + ')';
+ td_content += '
';
+ }
+ } else {
+ td_content += '
';
+ if (col[0] !== null) {
+ td_content += '
';
+ td_content += col[0];
+ td_content += '';
+
+ td_title += "得分:" + col[0] + " 分";
+ td_title += "\n" + col[3] + " 次有效提交";
+
+ if (col[5] > 0) {
+ td_content += ' + ';
+ td_title += "\n" + "因封榜有 " + col[5] + " 次提交结果未知";
+ }
+ } else {
+ td_title += "封榜后提交了 " + col[5] + " 次,结果未知";
+ }
+ if (col[5] > 0) {
+ td_content += '
?';
+ }
+ td_content += '
';
+
+ if (col[0] > 0) {
+ let orig_penalty = col[1] - col[4] * 60 * 20;
+ td_content += '
' + getPenaltyTimeStr(orig_penalty) + '
';
+
+ if (col[4] > 0) {
+ td_title += "\n" + col[4] + " 次提交计入罚时";
+ }
+ td_title += "\n" + "罚时:" + orig_penalty;
+ if (col[4] > 0) {
+ td_title += " + " + col[4] + " × 1200 = " + col[1];
+ }
+ td_title += ",即 " + getPenaltyTimeStr(orig_penalty);
+ }
+
+ if (col[4] > 0) {
+ td_content += '
';
+ td_content += '(+' + col[4] + ')';
+ td_content += '
';
+ }
+ }
+
+ if (meta.stat[problems[i]].earliest === col[2]) {
+ $(td).addClass('first-blood table-success');
+ }
+
+ return $(td).attr('title', td_title).html(td_content);
+}
+
+// standings
+function showStandings() {
+ if (contest_rule == 'OI' || contest_rule == 'IOI') {
+ $("#standings").long_table(
+ standings,
+ 1,
+ '
' +
+ '# | ' +
+ ''+uojLocale('username')+' | ' +
+ ''+uojLocale('contests::total score')+' | ' +
+ $.map(problems, function(col, idx) {
+ return '' + '' + String.fromCharCode('A'.charCodeAt(0) + idx) + '' + ' | ';
+ }).join('') +
+ '
',
+ function(row) {
+ var col_tr = '';
+ if (myname != row[2][0]) {
+ col_tr += '
';
+ } else {
+ col_tr += '
';
+ }
+ col_tr += '' + row[3] + ' | ';
+ col_tr += '' + getUserLink(row[2][0], row[2][1], row[2][3]) + ' | ';
+ col_tr += '' + ' ' + row[0] + ' ' + '' + getPenaltyTimeStr(row[1]) + ' | ';
+ for (var i = 0; i < problems.length; i++) {
+ col_tr += '';
+ col = score[row[2][0]][i];
+ if (col != undefined) {
+ col_tr += '';
+ if (standings_version < 2) {
+ col_tr += ' ' + getPenaltyTimeStr(col[1]) + ' ';
+ } else {
+ if (col[0] > 0) {
+ col_tr += '' + getPenaltyTimeStr(col[1]) + ' ';
+ }
+ }
+ }
+ col_tr += ' | ';
+ }
+ col_tr += '
';
+ return col_tr;
+ }, {
+ div_classes: standings_config.div_classes ? standings_config.div_classes : ['table-responsive', 'card', 'my-3'],
+ table_classes: standings_config.table_classes ? standings_config.table_classes : ['table', 'table-bordered', 'text-center', 'align-middle', 'uoj-table', 'uoj-standings-table', 'mb-0'],
+ page_len: standings_config.page_len ? standings_config.page_len : 50,
+ top_pagination: true,
+ print_after_table: function() {
+ return '';
+ }
+ }
+ );
+ } else if (contest_rule == 'ACM') {
+ var meta = getACMStandingsMeta();
+ var header = $('
|
');
+ for (let i = -3; i < problems.length; i++) {
+ header.append(setACMStandingsTH(document.createElement('th'), i, meta));
+ }
+
+ $("#standings").long_table(
+ standings,
+ 1,
+ header,
+ function(row) {
+ var tr = $('
|
'); // .css('height', '57px');
+ if (myname == row[2][0]) {
+ tr.addClass('table-warning');
+ }
+ for (let i = -3; i < problems.length; i++) {
+ tr.append(setACMStandingsTD(document.createElement('td'), row, i, meta));
+ }
+ return tr;
+ }, {
+ div_classes: standings_config.div_classes ? standings_config.div_classes : ['table-responsive', 'card', 'my-3'],
+ table_classes: standings_config.table_classes ? standings_config.table_classes : ['table', 'table-bordered', 'text-center', 'align-middle', 'uoj-table', 'uoj-standings-table', 'mb-0'],
+ page_len: standings_config.page_len ? standings_config.page_len : 50,
+ top_pagination: true,
+ print_after_table: function() {
+ return '';
+ }
+ }
+ );
+ }
+}
+
// PDF
$(document).ready(function() {
$('div[data-pdf]').each(function() {