@xcpcio/board-app 0.6.4 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +6 -0
- package/LICENSE +1 -1
- package/README.md +13 -30
- package/cypress.config.ts +14 -0
- package/dist/_headers +3 -0
- package/dist/about.html +11 -0
- package/dist/assets/_...all_-27c7ae93.css +1 -0
- package/dist/assets/_...all_-d56798b5.js +3 -0
- package/dist/assets/_name_-8eab6137.js +1 -0
- package/dist/assets/about-a8cb8700.js +11 -0
- package/dist/assets/app-37f77a84.js +65 -0
- package/dist/assets/board-layout-deaedfc1.js +1 -0
- package/dist/assets/en-caedd340.js +1 -0
- package/dist/assets/home-49c336e5.js +1 -0
- package/dist/assets/index-a270cacd.css +5 -0
- package/dist/assets/index-layout-d65c80ea.js +1 -0
- package/dist/assets/test-0a3d6f7a.js +1 -0
- package/dist/assets/user-108782a1.js +1 -0
- package/dist/assets/virtual_pwa-register-1c1b9161.js +1 -0
- package/dist/assets/workbox-window.prod.es5-a7b12eab.js +2 -0
- package/dist/assets/zh-CN-86269804.js +1 -0
- package/dist/favicon-dark.svg +1 -0
- package/dist/favicon.svg +1 -0
- package/dist/index.html +1 -171
- package/dist/manifest.webmanifest +1 -0
- package/dist/pwa-192x192.png +0 -0
- package/dist/pwa-512x512.png +0 -0
- package/dist/robots.txt +4 -0
- package/dist/safari-pinned-tab.svg +41 -0
- package/dist/sitemap.xml +1 -0
- package/dist/ssr-manifest.json +486 -0
- package/dist/sw.js +1 -0
- package/dist/test.html +1 -0
- package/dist/workbox-b8d87ee1.js +1 -0
- package/package.json +94 -50
- package/public/_headers +3 -0
- package/public/favicon-dark.svg +1 -0
- package/public/favicon.svg +1 -0
- package/public/pwa-192x192.png +0 -0
- package/public/pwa-512x512.png +0 -0
- package/public/safari-pinned-tab.svg +41 -0
- package/src/App.vue +33 -0
- package/src/auto-imports.d.ts +909 -0
- package/src/components/ContestIndex.vue +227 -0
- package/src/components/Footer.vue +94 -0
- package/src/components/GoBack.vue +22 -0
- package/src/components/NavBar.vue +152 -0
- package/src/components/SearchInput.vue +50 -0
- package/src/components/TheCounter.vue +19 -0
- package/src/components/TheInput.vue +20 -0
- package/src/components/board/Balloon.vue +5 -0
- package/src/components/board/Board.vue +396 -0
- package/src/components/board/BottomStatistics.vue +159 -0
- package/src/components/board/ContestStateBadge.vue +41 -0
- package/src/components/board/Export.vue +75 -0
- package/src/components/board/Modal.vue +107 -0
- package/src/components/board/ModalMenu.vue +64 -0
- package/src/components/board/OptionsModal.vue +179 -0
- package/src/components/board/Progress.less +442 -0
- package/src/components/board/Progress.vue +229 -0
- package/src/components/board/SecondLevelMenu.vue +190 -0
- package/src/components/board/Standings.less +1162 -0
- package/src/components/board/Standings.vue +154 -0
- package/src/components/board/StandingsAnnotate.vue +38 -0
- package/src/components/board/Statistics.vue +77 -0
- package/src/components/board/SubmissionsTable.vue +312 -0
- package/src/components/board/SubmissionsTableModal.vue +52 -0
- package/src/components/board/TeamAwards.vue +93 -0
- package/src/components/board/TeamInfoModal.vue +128 -0
- package/src/components/board/TeamProblemBlock.vue +100 -0
- package/src/components/board/TeamUI.vue +161 -0
- package/src/components/board/Utility.vue +28 -0
- package/src/components/icon/GirlIcon.vue +80 -0
- package/src/components/icon/RightArrowIcon.vue +26 -0
- package/src/components/icon/StarIcon.vue +19 -0
- package/src/components/table/TablePagination.vue +108 -0
- package/src/components.d.ts +44 -0
- package/src/composables/dark.ts +4 -0
- package/src/composables/pagination.ts +81 -0
- package/src/composables/statistics.ts +280 -0
- package/src/composables/useLocalStorage.ts +29 -0
- package/src/composables/useQueryBoardData.ts +43 -0
- package/src/composables/utils.ts +11 -0
- package/src/layouts/board-layout.vue +14 -0
- package/src/layouts/default.vue +10 -0
- package/src/layouts/home.vue +12 -0
- package/src/layouts/index-layout.vue +15 -0
- package/src/main.ts +36 -0
- package/src/modules/README.md +11 -0
- package/src/modules/i18n.ts +52 -0
- package/src/modules/nprogress.ts +15 -0
- package/src/modules/pinia.ts +18 -0
- package/src/modules/pwa.ts +15 -0
- package/src/modules/toast.ts +10 -0
- package/src/pages/[...all].vue +34 -0
- package/src/pages/about.md +21 -0
- package/src/pages/hi/[name].vue +50 -0
- package/src/pages/index.vue +129 -0
- package/src/pages/test.vue +57 -0
- package/src/shims.d.ts +16 -0
- package/src/stores/user.ts +36 -0
- package/src/styles/color.css +51 -0
- package/src/styles/main.css +30 -0
- package/src/styles/markdown.css +28 -0
- package/src/styles/submission-status.css +123 -0
- package/src/types.ts +3 -0
- package/tsconfig.json +39 -0
- package/uno.config.ts +65 -0
- package/vite.config.ts +176 -0
- package/dist/favicon.ico +0 -0
- package/dist/umi.00ae29f6.js +0 -1
- package/dist/umi.bd64c248.css +0 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { Rank } from "@xcpcio/core";
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
rank: Rank,
|
|
6
|
+
}>();
|
|
7
|
+
|
|
8
|
+
const { t } = useI18n();
|
|
9
|
+
|
|
10
|
+
const rank = computed(() => props.rank);
|
|
11
|
+
const teams = computed(() => props.rank.teams);
|
|
12
|
+
|
|
13
|
+
const filterTeams = computed(() => {
|
|
14
|
+
const res = props.rank.teams.filter((t) => {
|
|
15
|
+
if (props.rank.organizations) {
|
|
16
|
+
if (props.rank.options.filterOrganizationMap.has(t.organization)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (props.rank.options.filterTeamMap.has(t.id)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return false;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return res;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const maxOrgLength = computed(() => {
|
|
32
|
+
let res = 0;
|
|
33
|
+
rank.value.teams.forEach((t) => {
|
|
34
|
+
res = Math.max(res, t.organization.length);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return res;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const maxTeamLength = computed(() => {
|
|
41
|
+
let res = 0;
|
|
42
|
+
rank.value.teams.forEach((t) => {
|
|
43
|
+
res = Math.max(res, t.name.length);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return res;
|
|
47
|
+
});
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<template>
|
|
51
|
+
<div>
|
|
52
|
+
<div>
|
|
53
|
+
<table
|
|
54
|
+
class="standings"
|
|
55
|
+
font-mono dark:text-gray-700
|
|
56
|
+
>
|
|
57
|
+
<thead
|
|
58
|
+
class="sticky top-0 z-99"
|
|
59
|
+
>
|
|
60
|
+
<tr>
|
|
61
|
+
<th
|
|
62
|
+
class="title"
|
|
63
|
+
style="width: 3rem;"
|
|
64
|
+
>
|
|
65
|
+
{{ t("standings.place") }}
|
|
66
|
+
</th>
|
|
67
|
+
<th
|
|
68
|
+
v-if="rank.contest.badge"
|
|
69
|
+
class="title"
|
|
70
|
+
style="width: 2rem;"
|
|
71
|
+
>
|
|
72
|
+
{{ rank.contest.badge }}
|
|
73
|
+
</th>
|
|
74
|
+
<th
|
|
75
|
+
v-if="rank.contest.organization"
|
|
76
|
+
class="title"
|
|
77
|
+
:style="{ width: `${Math.min(32, Math.ceil(maxOrgLength * 1.1))}rem` }"
|
|
78
|
+
>
|
|
79
|
+
{{ rank.contest.organization }}
|
|
80
|
+
</th>
|
|
81
|
+
<th
|
|
82
|
+
class="title"
|
|
83
|
+
:style="{ width: `${Math.min(32, Math.ceil(maxTeamLength * 1))}rem` }"
|
|
84
|
+
>
|
|
85
|
+
{{ t("standings.team") }}
|
|
86
|
+
</th>
|
|
87
|
+
<th
|
|
88
|
+
class="title"
|
|
89
|
+
style="width: 3rem;"
|
|
90
|
+
>
|
|
91
|
+
{{ t("standings.solved") }}
|
|
92
|
+
</th>
|
|
93
|
+
<th
|
|
94
|
+
class="title"
|
|
95
|
+
style="width: 4rem;"
|
|
96
|
+
>
|
|
97
|
+
{{ t("standings.penalty") }}
|
|
98
|
+
</th>
|
|
99
|
+
<th
|
|
100
|
+
v-for="p in rank.contest.problems"
|
|
101
|
+
:key="p.id"
|
|
102
|
+
class="success"
|
|
103
|
+
text-center
|
|
104
|
+
style="width: 3rem;"
|
|
105
|
+
:style="{
|
|
106
|
+
'background-color': p.balloonColor?.background_color,
|
|
107
|
+
'color': p.balloonColor?.color,
|
|
108
|
+
}"
|
|
109
|
+
>
|
|
110
|
+
{{ p.label }}
|
|
111
|
+
<br>
|
|
112
|
+
<s>{{ p.statistics.acceptedNum }}</s>
|
|
113
|
+
</th>
|
|
114
|
+
<th class="title" style="width: 2.5rem;">
|
|
115
|
+
{{ t("standings.dict") }}
|
|
116
|
+
</th>
|
|
117
|
+
</tr>
|
|
118
|
+
</thead>
|
|
119
|
+
<tbody>
|
|
120
|
+
<template
|
|
121
|
+
v-for="(team, ix) in filterTeams"
|
|
122
|
+
:key="`filter-${team.id}`"
|
|
123
|
+
>
|
|
124
|
+
<TeamUI
|
|
125
|
+
:ix="ix"
|
|
126
|
+
:rank="rank"
|
|
127
|
+
:team="team"
|
|
128
|
+
:is-filter="true"
|
|
129
|
+
/>
|
|
130
|
+
</template>
|
|
131
|
+
|
|
132
|
+
<template
|
|
133
|
+
v-for="(team, ix) in teams"
|
|
134
|
+
:key="team.id"
|
|
135
|
+
>
|
|
136
|
+
<TeamUI
|
|
137
|
+
:ix="ix"
|
|
138
|
+
:rank="rank"
|
|
139
|
+
:team="team"
|
|
140
|
+
/>
|
|
141
|
+
</template>
|
|
142
|
+
|
|
143
|
+
<BottomStatistics
|
|
144
|
+
:rank="rank"
|
|
145
|
+
/>
|
|
146
|
+
</tbody>
|
|
147
|
+
</table>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</template>
|
|
151
|
+
|
|
152
|
+
<style scoped lang="less">
|
|
153
|
+
@import "./Standings.less";
|
|
154
|
+
</style>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex items-center justify-center dark:text-black">
|
|
3
|
+
<table>
|
|
4
|
+
<tbody>
|
|
5
|
+
<tr>
|
|
6
|
+
<td class="gold">
|
|
7
|
+
Gold
|
|
8
|
+
</td>
|
|
9
|
+
<td class="silver">
|
|
10
|
+
Silver
|
|
11
|
+
</td>
|
|
12
|
+
<td class="bronze">
|
|
13
|
+
Bronze
|
|
14
|
+
</td>
|
|
15
|
+
<td class="honorable">
|
|
16
|
+
Honorable
|
|
17
|
+
</td>
|
|
18
|
+
<td class="first-solve">
|
|
19
|
+
First to solve problem
|
|
20
|
+
</td>
|
|
21
|
+
<td class="correct">
|
|
22
|
+
Solved problem
|
|
23
|
+
</td>
|
|
24
|
+
<td class="incorrect">
|
|
25
|
+
Attempted problem
|
|
26
|
+
</td>
|
|
27
|
+
<td class="pending">
|
|
28
|
+
Pending judgement
|
|
29
|
+
</td>
|
|
30
|
+
</tr>
|
|
31
|
+
</tbody>
|
|
32
|
+
</table>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<style scoped lang="less">
|
|
37
|
+
@import "./Standings.less";
|
|
38
|
+
</style>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { Chart } from "highcharts-vue";
|
|
3
|
+
|
|
4
|
+
import type { Rank } from "@xcpcio/core";
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
rank: Rank,
|
|
8
|
+
}>();
|
|
9
|
+
|
|
10
|
+
const { t } = useI18n();
|
|
11
|
+
|
|
12
|
+
const rank = computed(() => props.rank);
|
|
13
|
+
|
|
14
|
+
function getHeadData() {
|
|
15
|
+
const l = [];
|
|
16
|
+
|
|
17
|
+
l.push({
|
|
18
|
+
title: "standings.statistics.head_data.problems",
|
|
19
|
+
data: rank.value.contest.problems.length,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
l.push({
|
|
23
|
+
title: "standings.statistics.head_data.teams",
|
|
24
|
+
data: rank.value.teams.length,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
l.push({
|
|
28
|
+
title: "standings.statistics.head_data.submissions",
|
|
29
|
+
data: rank.value.getSubmissions().length,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return l;
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<div
|
|
38
|
+
class="w-88vw flex flex-col md:w-92vw"
|
|
39
|
+
>
|
|
40
|
+
<section>
|
|
41
|
+
<div class="mx-auto max-w-screen-xl px-4 py-4 lg:px-6 lg:py-6">
|
|
42
|
+
<div class="lg:grid lg:grid-cols-3 sm:gap-6 xl:gap-10 space-y-8 lg:space-y-0">
|
|
43
|
+
<div v-for="h in getHeadData()" :key="h.title">
|
|
44
|
+
<div class="mx-auto max-w-[16rem] flex flex-col border border-gray-100 rounded-lg bg-white p-6 text-center text-gray-900 shadow dark:border-gray-600 dark:bg-gray-800 xl:p-8 dark:text-white">
|
|
45
|
+
<h3 class="mb-4 text-2xl font-semibold">
|
|
46
|
+
{{ t(h.title) }}
|
|
47
|
+
</h3>
|
|
48
|
+
<div class="my-8 flex items-baseline justify-center">
|
|
49
|
+
<span class="mr-2 text-5xl font-extrabold">{{ h.data }}</span>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</section>
|
|
56
|
+
|
|
57
|
+
<div class="mt-8 flex flex-col gap-8">
|
|
58
|
+
<div>
|
|
59
|
+
<Chart
|
|
60
|
+
:options="getSubmitChart(rank)"
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div>
|
|
65
|
+
<Chart
|
|
66
|
+
:options="getProblemChart(rank)"
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div>
|
|
71
|
+
<Chart
|
|
72
|
+
:options="getTeamChart(rank)"
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { Rank, Submissions } from "@xcpcio/core";
|
|
3
|
+
import { Submission } from "@xcpcio/core";
|
|
4
|
+
import { SubmissionStatusToString } from "@xcpcio/types";
|
|
5
|
+
|
|
6
|
+
import { Pagination } from "~/composables/pagination";
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
rank: Rank,
|
|
10
|
+
submissions: Submissions,
|
|
11
|
+
pageSize?: number,
|
|
12
|
+
removeBorder?: boolean,
|
|
13
|
+
}>();
|
|
14
|
+
|
|
15
|
+
const rank = computed(() => props.rank);
|
|
16
|
+
const submissions = computed(() => {
|
|
17
|
+
const s = props.submissions;
|
|
18
|
+
return s.sort(Submission.compare).reverse();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const p = ref(new Pagination());
|
|
22
|
+
|
|
23
|
+
p.value.currentPage = 0;
|
|
24
|
+
p.value.pageSize = props.pageSize ?? 16;
|
|
25
|
+
p.value.totalSize = submissions.value.length;
|
|
26
|
+
|
|
27
|
+
watch(submissions, () => {
|
|
28
|
+
p.value.totalSize = submissions.value.length;
|
|
29
|
+
|
|
30
|
+
if (p.value.currentPage >= p.value.totalPage) {
|
|
31
|
+
p.value.currentPage = p.value.totalPage - 1;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const currentSubmissions = computed(() => {
|
|
36
|
+
return submissions.value.slice(p.value.currentLeft, p.value.currentRight);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const notShowing = ref(false);
|
|
40
|
+
|
|
41
|
+
function getSubmitTime(
|
|
42
|
+
timeDiff: number,
|
|
43
|
+
): string {
|
|
44
|
+
const h = Math.floor(timeDiff / 3600);
|
|
45
|
+
const m = Math.floor(timeDiff % 3600 / 60);
|
|
46
|
+
const s = timeDiff % 60;
|
|
47
|
+
|
|
48
|
+
const f = (x: number) => x.toString().padStart(2, "0");
|
|
49
|
+
|
|
50
|
+
return `${f(h)}:${f(m)}:${f(s)}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getProblemLabelColorClass(s: Submission) {
|
|
54
|
+
const defaultClass = "bg-primary-100 text-primary-800 dark:bg-primary-900 dark:text-primary-300";
|
|
55
|
+
|
|
56
|
+
const pId = s.problemId;
|
|
57
|
+
const p = rank.value.contest.problemsMap.get(pId);
|
|
58
|
+
|
|
59
|
+
if (p === null || p === undefined || !p.balloonColor) {
|
|
60
|
+
return defaultClass;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getProblemLabelColorStyle(s: Submission) {
|
|
65
|
+
const pId = s.problemId;
|
|
66
|
+
const p = rank.value.contest.problemsMap.get(pId);
|
|
67
|
+
|
|
68
|
+
if (p === null || p === undefined || !p.balloonColor) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const b = p.balloonColor;
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
backgroundColor: b.background_color as string,
|
|
76
|
+
color: b.color as string,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<template>
|
|
82
|
+
<section>
|
|
83
|
+
<div
|
|
84
|
+
class="mx-auto w-full"
|
|
85
|
+
px-4
|
|
86
|
+
>
|
|
87
|
+
<div
|
|
88
|
+
class="relative overflow-hidden bg-white dark:bg-gray-800"
|
|
89
|
+
:class="{
|
|
90
|
+
'shadow-md': props.removeBorder !== true,
|
|
91
|
+
'sm:rounded-sm': props.removeBorder !== true,
|
|
92
|
+
}"
|
|
93
|
+
>
|
|
94
|
+
<div
|
|
95
|
+
class="lg:flex-row lg:items-center lg:justify-between space-y-3 lg:space-x-4 lg:space-y-0"
|
|
96
|
+
flex flex-col
|
|
97
|
+
px-4 py-3
|
|
98
|
+
>
|
|
99
|
+
<div
|
|
100
|
+
class="flex flex-shrink-0 flex-col md:flex-row md:items-center lg:justify-end space-y-3 md:space-x-3 md:space-y-0"
|
|
101
|
+
>
|
|
102
|
+
<button
|
|
103
|
+
v-if="notShowing"
|
|
104
|
+
type="button"
|
|
105
|
+
class="flex items-center justify-center rounded-lg bg-primary-700 px-4 py-2 text-sm font-medium text-white dark:bg-primary-600 hover:bg-primary-800 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
|
|
106
|
+
>
|
|
107
|
+
<svg
|
|
108
|
+
class="mr-2 h-3.5 w-3.5"
|
|
109
|
+
fill="currentColor"
|
|
110
|
+
viewbox="0 0 20 20"
|
|
111
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
112
|
+
aria-hidden="true"
|
|
113
|
+
>
|
|
114
|
+
<path
|
|
115
|
+
clip-rule="evenodd"
|
|
116
|
+
fill-rule="evenodd"
|
|
117
|
+
d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z"
|
|
118
|
+
/>
|
|
119
|
+
</svg>
|
|
120
|
+
Add new product
|
|
121
|
+
</button>
|
|
122
|
+
|
|
123
|
+
<button
|
|
124
|
+
v-if="notShowing"
|
|
125
|
+
type="button"
|
|
126
|
+
class="flex flex-shrink-0 items-center justify-center border border-gray-200 rounded-lg bg-white px-3 py-2 text-sm font-medium text-gray-900 focus:z-10 dark:border-gray-600 dark:bg-gray-800 hover:bg-gray-100 dark:text-gray-400 hover:text-primary-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
|
|
127
|
+
>
|
|
128
|
+
<svg
|
|
129
|
+
class="mr-2 h-4 w-4"
|
|
130
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
131
|
+
aria-hidden="true"
|
|
132
|
+
fill="none"
|
|
133
|
+
viewbox="0 0 24 24"
|
|
134
|
+
stroke-width="1.5"
|
|
135
|
+
stroke="currentColor"
|
|
136
|
+
>
|
|
137
|
+
<path
|
|
138
|
+
stroke-linecap="round"
|
|
139
|
+
stroke-linejoin="round"
|
|
140
|
+
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
|
|
141
|
+
/>
|
|
142
|
+
</svg>
|
|
143
|
+
Update stocks 1/250
|
|
144
|
+
</button>
|
|
145
|
+
|
|
146
|
+
<button
|
|
147
|
+
v-if="notShowing"
|
|
148
|
+
type="button"
|
|
149
|
+
class="flex flex-shrink-0 items-center justify-center border border-gray-200 rounded-lg bg-white px-3 py-2 text-sm font-medium text-gray-900 focus:z-10 dark:border-gray-600 dark:bg-gray-800 hover:bg-gray-100 dark:text-gray-400 hover:text-primary-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
|
|
150
|
+
>
|
|
151
|
+
<div
|
|
152
|
+
i-pajamas-export
|
|
153
|
+
class="mr-2 h-4 w-4"
|
|
154
|
+
/>
|
|
155
|
+
Export
|
|
156
|
+
</button>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div
|
|
161
|
+
class="overflow-x-auto"
|
|
162
|
+
>
|
|
163
|
+
<table
|
|
164
|
+
class="w-full text-left text-sm text-gray-500 dark:text-gray-400"
|
|
165
|
+
font-medium font-mono
|
|
166
|
+
>
|
|
167
|
+
<thead class="bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-400">
|
|
168
|
+
<tr>
|
|
169
|
+
<th
|
|
170
|
+
scope="col"
|
|
171
|
+
class="px-4 py-3"
|
|
172
|
+
>
|
|
173
|
+
Problem
|
|
174
|
+
</th>
|
|
175
|
+
<th
|
|
176
|
+
v-if="rank.contest.organization"
|
|
177
|
+
scope="col"
|
|
178
|
+
class="px-4 py-3"
|
|
179
|
+
>
|
|
180
|
+
{{ rank.contest.organization }}
|
|
181
|
+
</th>
|
|
182
|
+
<th
|
|
183
|
+
scope="col"
|
|
184
|
+
class="px-4 py-3"
|
|
185
|
+
>
|
|
186
|
+
Team
|
|
187
|
+
</th>
|
|
188
|
+
<th
|
|
189
|
+
scope="col"
|
|
190
|
+
class="px-4 py-3"
|
|
191
|
+
>
|
|
192
|
+
Status
|
|
193
|
+
</th>
|
|
194
|
+
<th
|
|
195
|
+
v-if="notShowing"
|
|
196
|
+
scope="col"
|
|
197
|
+
class="px-4 py-3"
|
|
198
|
+
>
|
|
199
|
+
Time
|
|
200
|
+
</th>
|
|
201
|
+
<th
|
|
202
|
+
v-if="notShowing"
|
|
203
|
+
scope="col"
|
|
204
|
+
class="px-4 py-3"
|
|
205
|
+
>
|
|
206
|
+
Memory
|
|
207
|
+
</th>
|
|
208
|
+
<th
|
|
209
|
+
v-if="notShowing"
|
|
210
|
+
scope="col"
|
|
211
|
+
class="px-4 py-3"
|
|
212
|
+
>
|
|
213
|
+
Answer
|
|
214
|
+
</th>
|
|
215
|
+
<th
|
|
216
|
+
scope="col"
|
|
217
|
+
class="px-4 py-3"
|
|
218
|
+
>
|
|
219
|
+
Submit Time
|
|
220
|
+
</th>
|
|
221
|
+
</tr>
|
|
222
|
+
</thead>
|
|
223
|
+
|
|
224
|
+
<tbody>
|
|
225
|
+
<template
|
|
226
|
+
v-for="s in currentSubmissions"
|
|
227
|
+
:key="s.id"
|
|
228
|
+
>
|
|
229
|
+
<tr
|
|
230
|
+
class="border-b dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700"
|
|
231
|
+
>
|
|
232
|
+
<td
|
|
233
|
+
px-4 py-2
|
|
234
|
+
>
|
|
235
|
+
<span
|
|
236
|
+
class="rounded px-2 py-0.5 text-sm"
|
|
237
|
+
:class="[getProblemLabelColorClass(s)]"
|
|
238
|
+
:style="getProblemLabelColorStyle(s)"
|
|
239
|
+
>
|
|
240
|
+
{{ rank.contest.problemsMap.get(s.problemId)?.label }}
|
|
241
|
+
</span>
|
|
242
|
+
</td>
|
|
243
|
+
|
|
244
|
+
<td
|
|
245
|
+
v-if="rank.contest.organization"
|
|
246
|
+
class="whitespace-nowrap px-4 py-2 text-gray-900 dark:text-white"
|
|
247
|
+
>
|
|
248
|
+
{{ rank.teamsMap.get(s.teamId)?.organization }}
|
|
249
|
+
</td>
|
|
250
|
+
|
|
251
|
+
<td class="whitespace-nowrap px-4 py-2 text-gray-900 dark:text-white">
|
|
252
|
+
{{ rank.teamsMap.get(s.teamId)?.name }}
|
|
253
|
+
</td>
|
|
254
|
+
|
|
255
|
+
<td
|
|
256
|
+
scope="row"
|
|
257
|
+
:class="[s.status.toString()]"
|
|
258
|
+
whitespace-nowrap px-4 py-2
|
|
259
|
+
flex items-center
|
|
260
|
+
font-bold
|
|
261
|
+
>
|
|
262
|
+
{{ SubmissionStatusToString[s.status] }}
|
|
263
|
+
</td>
|
|
264
|
+
|
|
265
|
+
<td
|
|
266
|
+
v-if="notShowing"
|
|
267
|
+
class="whitespace-nowrap px-4 py-2 text-gray-900 dark:text-white"
|
|
268
|
+
>
|
|
269
|
+
<div class="flex items-center">
|
|
270
|
+
<div class="mr-2 inline-block h-4 w-4 rounded-full bg-red-700" />
|
|
271
|
+
95
|
|
272
|
+
</div>
|
|
273
|
+
</td>
|
|
274
|
+
|
|
275
|
+
<td
|
|
276
|
+
v-if="notShowing"
|
|
277
|
+
class="whitespace-nowrap px-4 py-2 text-gray-900 dark:text-white"
|
|
278
|
+
>
|
|
279
|
+
0.47
|
|
280
|
+
</td>
|
|
281
|
+
|
|
282
|
+
<td
|
|
283
|
+
v-if="notShowing"
|
|
284
|
+
class="whitespace-nowrap px-4 py-2 text-gray-900 dark:text-white"
|
|
285
|
+
>
|
|
286
|
+
<div class="flex items-center">
|
|
287
|
+
<span class="ml-1 text-gray-500 dark:text-gray-400">5.0</span>
|
|
288
|
+
</div>
|
|
289
|
+
</td>
|
|
290
|
+
|
|
291
|
+
<td class="whitespace-nowrap px-4 py-2 text-gray-900 dark:text-white">
|
|
292
|
+
<div class="flex items-center">
|
|
293
|
+
{{ getSubmitTime(s.timestamp) }}
|
|
294
|
+
</div>
|
|
295
|
+
</td>
|
|
296
|
+
</tr>
|
|
297
|
+
</template>
|
|
298
|
+
</tbody>
|
|
299
|
+
</table>
|
|
300
|
+
</div>
|
|
301
|
+
|
|
302
|
+
<TablePagination
|
|
303
|
+
v-model:pagination="p"
|
|
304
|
+
/>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
</section>
|
|
308
|
+
</template>
|
|
309
|
+
|
|
310
|
+
<style scoped lang="less">
|
|
311
|
+
@import "../../styles/submission-status.css";
|
|
312
|
+
</style>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { Rank, Team, TeamProblemStatistics } from "@xcpcio/core";
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
isHidden: boolean,
|
|
6
|
+
|
|
7
|
+
rank: Rank,
|
|
8
|
+
team: Team,
|
|
9
|
+
p: TeamProblemStatistics,
|
|
10
|
+
}>();
|
|
11
|
+
|
|
12
|
+
const emit = defineEmits(["update:isHidden"]);
|
|
13
|
+
|
|
14
|
+
const isHidden = computed({
|
|
15
|
+
get() {
|
|
16
|
+
return props.isHidden;
|
|
17
|
+
},
|
|
18
|
+
set(value) {
|
|
19
|
+
emit("update:isHidden", value);
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const rank = computed(() => props.rank);
|
|
24
|
+
const team = computed(() => props.team);
|
|
25
|
+
const p = computed(() => props.p);
|
|
26
|
+
|
|
27
|
+
const headerTitle = computed(() => {
|
|
28
|
+
return `${team.value.name} - ${p.value.problem.label}`;
|
|
29
|
+
});
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<Modal
|
|
34
|
+
v-model:isHidden="isHidden"
|
|
35
|
+
:title="headerTitle"
|
|
36
|
+
>
|
|
37
|
+
<div
|
|
38
|
+
w-full
|
|
39
|
+
font-bold font-mono
|
|
40
|
+
flex items-center justify-center
|
|
41
|
+
class="mt-[-12px]"
|
|
42
|
+
>
|
|
43
|
+
<SubmissionsTable
|
|
44
|
+
w-full
|
|
45
|
+
:rank="rank"
|
|
46
|
+
:submissions="p.submissions"
|
|
47
|
+
:page-size="8"
|
|
48
|
+
:remove-border="true"
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</Modal>
|
|
52
|
+
</template>
|