diff --git a/backend/submission/serializers.py b/backend/submission/serializers.py index 74ab7d24..aebc978e 100644 --- a/backend/submission/serializers.py +++ b/backend/submission/serializers.py @@ -34,6 +34,7 @@ class Meta: class SubmissionListSerializer(serializers.ModelSerializer): problem = serializers.SlugRelatedField(read_only=True, slug_field="_id") + problem_id = serializers.SerializerMethodField() show_link = serializers.SerializerMethodField() user_avatar = serializers.SerializerMethodField() @@ -53,3 +54,6 @@ def get_show_link(self, obj): def get_user_avatar(self, obj): return obj.user_avatar + + def get_problem_id(self, obj): + return obj.problem._id diff --git a/backend/submission/tests.py b/backend/submission/tests.py index d32cf37b..5978e5bb 100644 --- a/backend/submission/tests.py +++ b/backend/submission/tests.py @@ -232,6 +232,10 @@ def test_get_submissions_general(self): resp = self.client.get(f"{self.url}?limit=10") self.assertSuccess(resp) self.assertTrue("results" in resp.data["data"]) + result = next( + sub for sub in resp.data["data"]["results"] if sub["id"] == submission.id + ) + self.assertEqual(result["problem_id"], self.problem._id) def test_get_submissions_filtered_by_problem(self): # 문제 필터링 테스트 (일반 문제만) @@ -281,10 +285,18 @@ def test_get_submissions_contest_admin_access(self): def test_get_submissions_contest_myself(self): # contest_id 지정, myself=1일때는 조회 성공 - sub = self.create_submission(self.user, self.contest_problem, contest_id=self.contest["id"]) + sub = self.create_submission( + self.user, + self.contest_problem, + contest_id=self.contest["id"], + result=JudgeStatus.ACCEPTED, + ) resp = self.client.get(f"{self.url}?limit=10&contest_id={self.contest['id']}&myself=1") self.assertSuccess(resp) - self.assertTrue(any(s["id"] == sub.id for s in resp.data["data"]["results"])) + result = next( + s for s in resp.data["data"]["results"] if s["id"] == sub.id + ) + self.assertEqual(result["problem_id"], self.contest_problem._id) def test_get_submissions_with_problem_not_exist(self): # problem_id 지정했으나 존재하지 않는 경우 에러 발생 diff --git a/frontend/src/i18n/oj/en-US.js b/frontend/src/i18n/oj/en-US.js index 8c0c0096..4fa83e0c 100644 --- a/frontend/src/i18n/oj/en-US.js +++ b/frontend/src/i18n/oj/en-US.js @@ -30,9 +30,9 @@ export const m = { Tags: "태그", Show: "Show", Submit: "제출", - Submitting: "처리중", - Judging: "Judging", - Wrong_Answer: "Wrong Answer", + Submitting: "제출 중", + Judging: "채점 중", + Wrong_Answer: "오답", Statistic: "Statistic", Close: "Close", View_Contest: "View Contest", @@ -380,21 +380,24 @@ export const m = { // SubmissionList.vue When: "제출시각", ID: "ID", - Time: "Time", + Time: "시간", Memory: "메모리", Author: "작성자", + Problem_ID: "문제 번호", Option: "옵션", Check: "확인", - Mine: "사용자", + Mine: "내 제출만", Submission_Table_Author: "제출자", - Accepted: "Accepted", - Time_Limit_Exceeded: "Time Limit Exceeded", - Memory_Limit_Exceeded: "Memory Limit Exceeded", - Runtime_Error: "Runtime Error", - System_Error: "System Error", - Pending: "Pending", - Partial_Accepted: "Partial Accepted", - Compile_Error: "Compile Error", + Search_Submitter: "제출자 검색", + Accepted: "정답", + Time_Limit_Exceeded: "시간 초과", + Memory_Limit_Exceeded: "메모리 초과", + Runtime_Error: "런타임 에러", + System_Error: "시스템 에러", + Pending: "대기 중", + Partial_Accepted: "부분 정답", + Compile_Error: "컴파일 에러", + Loading: "불러오는 중...", Rejudge: "재채점", Rejudging: "채점중...", diff --git a/frontend/src/i18n/oj/zh-CN.js b/frontend/src/i18n/oj/zh-CN.js index 7220c4b7..15b9fecb 100644 --- a/frontend/src/i18n/oj/zh-CN.js +++ b/frontend/src/i18n/oj/zh-CN.js @@ -254,6 +254,7 @@ export const m = { Option: "选项", Mine: "我的", Search_Author: "搜索作者", + Search_Submitter: "搜索提交者", Accepted: "答案正确", Time_Limit_Exceeded: "运行超时", Memory_Limit_Exceeded: "内存超限", diff --git a/frontend/src/i18n/oj/zh-TW.js b/frontend/src/i18n/oj/zh-TW.js index 38318a58..53847eda 100644 --- a/frontend/src/i18n/oj/zh-TW.js +++ b/frontend/src/i18n/oj/zh-TW.js @@ -255,6 +255,7 @@ export const m = { Option: "選項", Mine: "我的", Search_Author: "搜尋作者", + Search_Submitter: "搜尋提交者", Accepted: "答案正確", Time_Limit_Exceeded: "超出時間限制", Memory_Limit_Exceeded: "超出記憶體空間限制", diff --git a/frontend/src/pages/oj/App.vue b/frontend/src/pages/oj/App.vue index 21fa849f..ba3c1596 100644 --- a/frontend/src/pages/oj/App.vue +++ b/frontend/src/pages/oj/App.vue @@ -6,13 +6,19 @@ -
+
@@ -41,20 +47,47 @@ export default { }, mounted() { this.getWebsiteConfig() + this.syncSubmissionListChrome() + }, + updated() { + this.syncSubmissionListChrome() + }, + beforeDestroy() { + this.syncSubmissionListChrome(false) }, methods: { ...mapActions(["getWebsiteConfig", "changeDomTitle"]), + syncSubmissionListChrome(force) { + const enabled = + typeof force === "boolean" ? force : this.isSubmissionList + document.documentElement.classList.toggle( + "submission-list-page", + enabled, + ) + document.body.classList.toggle("submission-list-page", enabled) + }, }, computed: { ...mapState(["website"]), ...mapGetters(["isProblemSolving", "removedPopupId"]), + isSubmissionList() { + return ( + this.$route.name === "submission-list" || this.$route.path === "/status" + ) + }, }, watch: { website() { this.changeDomTitle() }, - $route() { - this.changeDomTitle() + $route: { + immediate: true, + handler() { + this.changeDomTitle() + this.$nextTick(() => { + this.syncSubmissionListChrome() + }) + }, }, }, } @@ -253,6 +286,46 @@ a { background-color: var(--site-background-color); } +.submission-list-app, +.submission-list-footer-dummy { + background-color: #ffffff; +} + +.submission-list-app { + margin-top: calc(var(--header-height) + 28px); +} + +html.submission-list-page, +body.submission-list-page, +html.submission-list-page #app, +html.submission-list-page #wrapper { + background-color: #ffffff; +} + +html:has(.content-app.submission-list-app), +body:has(.content-app.submission-list-app) { + background-color: #ffffff; +} + +html.submission-list-page { + --header-glass-bg: #ffffff; + --header-glass-border-color: #eef1f5; + --header-glass-shadow: none; +} + +html.submission-list-page #header .header-menu { + padding-right: 32px; + padding-left: 32px; +} + +html.submission-list-page #header .logo { + margin-left: 0; +} + +html.submission-list-page #header .header-menu > .drop-menu { + padding-right: 0 !important; +} + .ps { margin-top: 50px; background-color: var(--bg-color); diff --git a/frontend/src/pages/oj/views/submission/SubmissionList.vue b/frontend/src/pages/oj/views/submission/SubmissionList.vue index ef9a749d..e120c7c9 100644 --- a/frontend/src/pages/oj/views/submission/SubmissionList.vue +++ b/frontend/src/pages/oj/views/submission/SubmissionList.vue @@ -1,91 +1,135 @@ diff --git a/frontend/src/pages/oj/views/submission/SubmissionListItem.vue b/frontend/src/pages/oj/views/submission/SubmissionListItem.vue index 6c6340d1..7909877e 100644 --- a/frontend/src/pages/oj/views/submission/SubmissionListItem.vue +++ b/frontend/src/pages/oj/views/submission/SubmissionListItem.vue @@ -1,25 +1,56 @@ diff --git a/frontend/src/pages/oj/views/submission/SubmissionTable.vue b/frontend/src/pages/oj/views/submission/SubmissionTable.vue index 8bf1975a..af5aee6d 100644 --- a/frontend/src/pages/oj/views/submission/SubmissionTable.vue +++ b/frontend/src/pages/oj/views/submission/SubmissionTable.vue @@ -5,6 +5,10 @@ export default { name: "SubmissionTable", components: { SubmissionListItem }, props: { + contestID: { + type: [String, Number], + default: "", + }, data: { type: Array, default: () => [], @@ -14,54 +18,210 @@ export default { default: false, }, }, + computed: { + skeletonRows() { + return Array.from({ length: 18 }, (_, index) => index) + }, + }, }