提交详情
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
2025-09-25 23:05:09 +08:00
parent 25117b454d
commit d7bc25d086
8 changed files with 197 additions and 85 deletions

2
.env
View File

@@ -1,5 +1,5 @@
PUBLIC_ENV=dev
PUBLIC_MAXKB_URL=https://maxkb.xuyue.cc/chat/api/embed?protocol=https&host=maxkb.xuyue.cc&token=2e801f7d6efdcc99
PUBLIC_OJ_URL=http://localhost:8000
PUBLIC_CODE_URL=https://code.xuyue.cc
PUBLIC_CODE_URL=http://localhost:3000
PUBLIC_JUDGE0_URL=https://judge0api.xuyue.cc

102
package-lock.json generated
View File

@@ -19,11 +19,13 @@
"codemirror": "^6.0.2",
"copy-text-to-clipboard": "^3.2.1",
"date-fns": "^4.1.0",
"fflate": "^0.8.2",
"highlight.js": "^11.11.1",
"md-editor-v3": "^6.0.1",
"naive-ui": "^2.43.1",
"normalize.css": "^8.0.1",
"pinia": "^3.0.3",
"query-string": "^9.3.1",
"vue": "^3.5.21",
"vue-chartjs": "^5.3.2",
"vue-codemirror": "^6.1.1",
@@ -884,6 +886,7 @@
"integrity": "sha512-mj0MxorF0uTppKdYS2uFpx7xYBwBP1WnOzwPm9Szd8WZDun7vmrDe8xfc6c5kK9hScHHA7zlfj8IVJFccQmpbA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@rspack/core": "1.5.5",
"@rspack/lite-tapable": "~1.0.1",
@@ -1110,6 +1113,7 @@
"integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"tslib": "^2.8.0"
}
@@ -1251,6 +1255,7 @@
"resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz",
"integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@transloadit/prettier-bytes": "0.0.7",
"@uppy/store-default": "^2.1.1",
@@ -1300,6 +1305,7 @@
"resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
"integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@uppy/companion-client": "^2.2.2",
"@uppy/utils": "^4.1.2",
@@ -1492,6 +1498,7 @@
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.9.0.tgz",
"integrity": "sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
"@vueuse/metadata": "13.9.0",
@@ -1530,6 +1537,7 @@
"resolved": "https://registry.npmjs.org/@wangeditor-next/basic-modules/-/basic-modules-1.5.45.tgz",
"integrity": "sha512-XMaUf+uvuqBSUs8rvOI1Pkdjzg+xSIrqvvl6v8F4ZOvwRK922ZuWlJR1+dtzn98z/BkZ9F+36wS6GsUu9IXsGg==",
"license": "MIT",
"peer": true,
"dependencies": {
"is-url": "^1.2.4"
},
@@ -1562,6 +1570,7 @@
"resolved": "https://registry.npmjs.org/@wangeditor-next/core/-/core-1.7.45.tgz",
"integrity": "sha512-5Pt8JCmdzJWk4q18zUZse+zM+mBW6jYt3npXVkLswYysx01krC3bBQq1J9JeZe4Ci+rQAs0tQj3t1imjpsmRgg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/event-emitter": "^0.3.3",
"event-emitter": "^0.3.5",
@@ -1591,6 +1600,7 @@
"resolved": "https://registry.npmjs.org/@wangeditor-next/editor/-/editor-5.6.45.tgz",
"integrity": "sha512-IgbKJ+F5kFK7X0YLroSW+N8tmnPVfMJNboi8OfbEGmvCKlouOmcY3M2X8zrh3Haz5MZ6jyGrDzzDUqCBYhuOFw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@uppy/core": "^2.1.1",
"@uppy/xhr-upload": "^2.0.3",
@@ -1863,6 +1873,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -1889,6 +1900,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -2032,6 +2044,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001737",
"electron-to-chromium": "^1.5.211",
@@ -2117,6 +2130,7 @@
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz",
"integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@kurkle/color": "^0.3.0"
},
@@ -2163,6 +2177,7 @@
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/commands": "^6.0.0",
@@ -2273,6 +2288,7 @@
"resolved": "https://registry.npmmirror.com/css-render/-/css-render-0.15.14.tgz",
"integrity": "sha512-9nF4PdUle+5ta4W5SyZdLCCmFd37uVimSjg1evcTqKJCyvCEEj12WKzOSBNak6r4im4J4iYXKH1OWpUV5LBYFg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@emotion/hash": "~0.8.0",
"csstype": "~3.0.5"
@@ -2308,6 +2324,7 @@
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
@@ -2340,6 +2357,15 @@
}
}
},
"node_modules/decode-uri-component": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz",
"integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==",
"license": "MIT",
"engines": {
"node": ">=14.16"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -2354,6 +2380,7 @@
"resolved": "https://registry.npmjs.org/dom7/-/dom7-4.0.6.tgz",
"integrity": "sha512-emjdpPLhpNubapLFdjNL9tP06Sr+GZkrIHEXLWvOGsytACUrkbeIdjO5g77m00BrHTznnlcNqgmn7pCN192TBA==",
"license": "MIT",
"peer": true,
"dependencies": {
"ssr-window": "^4.0.0"
}
@@ -2657,6 +2684,12 @@
],
"license": "BSD-3-Clause"
},
"node_modules/fflate": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
"license": "MIT"
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -2669,6 +2702,18 @@
"node": ">=8"
}
},
"node_modules/filter-obj": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz",
"integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==",
"license": "MIT",
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
@@ -2952,7 +2997,8 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz",
"integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/is-number": {
"version": "7.0.0",
@@ -3102,37 +3148,43 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash.foreach": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
"integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash.toarray": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
"integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lru-cache": {
"version": "11.2.1",
@@ -3395,6 +3447,7 @@
}
],
"license": "MIT",
"peer": true,
"bin": {
"nanoid": "bin/nanoid.js"
},
@@ -3623,6 +3676,23 @@
],
"license": "MIT"
},
"node_modules/query-string": {
"version": "9.3.1",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-9.3.1.tgz",
"integrity": "sha512-5fBfMOcDi5SA9qj5jZhWAcTtDfKF5WFdd2uD9nVNlbxVv1baq65aALy6qofpNEGELHvisjjasxQp7BlM9gvMzw==",
"license": "MIT",
"dependencies": {
"decode-uri-component": "^0.4.1",
"filter-obj": "^5.1.0",
"split-on-first": "^3.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -3739,6 +3809,7 @@
"resolved": "https://registry.npmjs.org/slate/-/slate-0.82.1.tgz",
"integrity": "sha512-3mdRdq7U3jSEoyFrGvbeb28hgrvrr4NdFCtJX+IjaNvSFozY0VZd/CGHF0zf/JDx7aEov864xd5uj0HQxxEWTQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"immer": "^9.0.6",
"is-plain-object": "^5.0.0",
@@ -3762,6 +3833,7 @@
"resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.6.2.tgz",
"integrity": "sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12.17.0"
}
@@ -3805,6 +3877,18 @@
"node": ">=0.10.0"
}
},
"node_modules/split-on-first": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-3.0.0.tgz",
"integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ssr-window": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz",
@@ -3967,6 +4051,7 @@
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -4010,6 +4095,7 @@
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -4294,6 +4380,7 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz",
"integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.21",
"@vue/compiler-sfc": "3.5.21",
@@ -4416,6 +4503,7 @@
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.8",

View File

@@ -21,11 +21,13 @@
"codemirror": "^6.0.2",
"copy-text-to-clipboard": "^3.2.1",
"date-fns": "^4.1.0",
"fflate": "^0.8.2",
"highlight.js": "^11.11.1",
"md-editor-v3": "^6.0.1",
"naive-ui": "^2.43.1",
"normalize.css": "^8.0.1",
"pinia": "^3.0.3",
"query-string": "^9.3.1",
"vue": "^3.5.21",
"vue-chartjs": "^5.3.2",
"vue-codemirror": "^6.1.1",

View File

@@ -16,12 +16,11 @@
<script setup lang="ts">
import { Icon } from "@iconify/vue"
import { Submission } from "~/utils/types"
import { SubmissionListItem } from "~/utils/types"
interface Props {
submission: Submission
submission: SubmissionListItem
}
const router = useRouter()
const props = defineProps<Props>()
defineEmits(["showCode"])

View File

@@ -1,38 +1,26 @@
<script setup lang="ts">
import copy from "copy-text-to-clipboard"
import { createMessage, getSubmission } from "oj/api"
import qs from "query-string"
import { getSubmission } from "oj/api"
import { JUDGE_STATUS, LANGUAGE_FORMAT_VALUE } from "utils/constants"
import {
parseTime,
submissionMemoryFormat,
submissionTimeFormat,
utoa,
} from "utils/functions"
import { Submission } from "utils/types"
import SubmissionResultTag from "~/shared/components/SubmissionResultTag.vue"
import { useUserStore } from "~/shared/store/user"
const TextEditor = defineAsyncComponent(
() => import("~/shared/components/TextEditor.vue"),
)
const props = defineProps<{
submissionID: string
problemID?: string
submission?: Submission
hideList?: boolean
}>()
const userStore = useUserStore()
const systemMessage = useMessage()
const submission = ref<Submission>()
const message = ref<string>("")
const [copied, toggle] = useToggle()
const [showBox, toggleBox] = useToggle()
const { start } = useTimeoutFn(() => toggle(false), 1000, { immediate: false })
const router = useRouter()
const canWriteMessage = computed(
() =>
userStore.isSuperAdmin && userStore.user!.id !== submission.value?.user_id,
)
const submission = ref<Submission>()
async function init() {
submission.value = props.submission
@@ -41,24 +29,6 @@ async function init() {
submission.value = res.data
}
function handleCopy(v: string) {
copy(v)
toggle(true)
start()
}
async function sendMessage() {
if (!message.value || message.value === "<p><br></p>") return
const data = {
message: message.value,
recipient: submission.value!.user_id,
submission: submission.value!.id,
}
await createMessage(data)
systemMessage.success("消息发送成功")
message.value = ""
}
const columns: DataTableColumn<Submission["info"]["data"][number]>[] = [
{ title: "测试用例", key: "test_case" },
{
@@ -78,21 +48,55 @@ const columns: DataTableColumn<Submission["info"]["data"][number]>[] = [
},
]
function copyToCat() {
const lang = LANGUAGE_FORMAT_VALUE[submission.value!.language]
const data = {
lang,
code: submission.value!.code,
input: "",
}
const base64 = utoa(JSON.stringify(data))
const url = qs.stringifyUrl({
url: import.meta.env.PUBLIC_CODE_URL,
query: {
share: base64,
},
})
window.open(url, "_blank")
}
function copyToProblem() {
router.push({
name: "problem",
params: {
contestID: submission.value!.contest,
problemID: props.problemID,
},
})
}
onMounted(init)
</script>
<template>
<n-flex vertical v-if="submission" :size="24">
<n-alert
:type="JUDGE_STATUS[submission.result]['type']"
:title="JUDGE_STATUS[submission.result]['name']"
>
<n-flex>
<span>提交时间{{ parseTime(submission.create_time) }}</span>
<span>编程语言{{ submission.language }}</span>
<span>用户{{ submission.username }}</span>
<n-flex justify="space-between">
<n-alert
style="flex: 1"
:type="JUDGE_STATUS[submission.result]['type']"
:title="JUDGE_STATUS[submission.result]['name']"
>
<n-flex>
<span>提交时间{{ parseTime(submission.create_time) }}</span>
<span>编程语言{{ submission.language }}</span>
<span>用户{{ submission.username }}</span>
</n-flex>
</n-alert>
<n-flex vertical>
<n-button secondary @click="copyToCat">复制到自测猫</n-button>
<n-button secondary @click="copyToProblem">回到题目</n-button>
</n-flex>
</n-alert>
</n-flex>
<n-card embedded>
<n-code
class="code"
@@ -101,24 +105,6 @@ onMounted(init)
show-line-numbers
/>
</n-card>
<n-flex>
<n-button v-if="!hideList" @click="handleCopy(submission!.code)">
{{ copied ? "成功复制" : "复制代码" }}
</n-button>
<n-button v-if="canWriteMessage" @click="toggleBox(!showBox)">
{{ showBox ? "关闭" : "打开" }}文本框
</n-button>
<n-button v-if="canWriteMessage && showBox" @click="sendMessage">
发送消息
</n-button>
</n-flex>
<TextEditor
title=""
simple
v-if="showBox && canWriteMessage"
v-model:value="message"
:min-height="200"
/>
<n-data-table
v-if="!hideList && submission.info && submission.info.data"
:columns="columns"

View File

@@ -2,7 +2,7 @@
import { NButton, NH2, NText } from "naive-ui"
import { adminRejudge, getSubmissions, getTodaySubmissionCount } from "oj/api"
import { filterEmptyValue, parseTime } from "utils/functions"
import { LANGUAGE, Submission } from "utils/types"
import { LANGUAGE, SubmissionListItem } from "utils/types"
import Pagination from "~/shared/components/Pagination.vue"
import SubmissionResultTag from "~/shared/components/SubmissionResultTag.vue"
import { isDesktop } from "~/shared/composables/breakpoints"
@@ -29,7 +29,7 @@ const router = useRouter()
const userStore = useUserStore()
const message = useMessage()
const submissions = ref([])
const submissions = ref<SubmissionListItem[]>([])
const total = ref(0)
const todayCount = ref(0)
const query = reactive<Query>({
@@ -42,6 +42,7 @@ const query = reactive<Query>({
language: <LANGUAGE | "">route.query.language ?? "",
})
const submissionID = ref("")
const problemDisplayID = ref("")
const [statisticPanel, toggleStatisticPanel] = useToggle(false)
const [codePanel, toggleCodePanel] = useToggle(false)
@@ -130,7 +131,7 @@ async function rejudge(submissionID: string) {
listSubmissions()
}
function problemClicked(row: Submission) {
function problemClicked(row: SubmissionListItem) {
if (route.name === "contest submissions") {
const path = router.resolve({
name: "contest problem",
@@ -144,9 +145,10 @@ function problemClicked(row: Submission) {
}
}
function showCodePanel(id: string) {
function showCodePanel(id: string, problem: string) {
toggleCodePanel(true)
submissionID.value = id
problemDisplayID.value = problem
}
watch(() => query.page, routerPush)
@@ -178,7 +180,7 @@ watch(
)
const columns = computed(() => {
const res: DataTableColumn<Submission>[] = [
const res: DataTableColumn<SubmissionListItem>[] = [
{
title: renderTableTitle("提交时间", "noto:seven-oclock"),
key: "create_time",
@@ -192,7 +194,7 @@ const columns = computed(() => {
render: (row) =>
h(SubmissionLink, {
submission: row,
onShowCode: () => showCodePanel(row.id),
onShowCode: () => showCodePanel(row.id, row.problem),
}),
},
{
@@ -347,7 +349,11 @@ const columns = computed(() => {
:content-style="{ overflow: 'auto' }"
title="代码详情"
>
<SubmissionDetail :submissionID="submissionID" hideList />
<SubmissionDetail
:problemID="problemDisplayID"
:submissionID="submissionID"
hideList
/>
</n-modal>
</template>
<style scoped>

View File

@@ -1,6 +1,7 @@
import { getTime, intervalToDuration, parseISO, type Duration } from "date-fns"
import { User } from "./types"
import { USER_TYPE } from "./constants"
import { strFromU8, strToU8, unzlibSync, zlibSync } from "fflate"
function calculateACRate(acCount: number, totalCount: number): string {
if (totalCount === 0) return "0.00"
@@ -184,6 +185,20 @@ export function getCSRFToken(): string {
return match ? decodeURIComponent(match[1]) : ""
}
export function utoa(data: string): string {
const buffer = strToU8(data)
const zipped = zlibSync(buffer, { level: 9 })
const binary = strFromU8(zipped, true)
return btoa(binary)
}
export function atou(base64: string): string {
const binary = atob(base64)
const buffer = strToU8(binary, true)
const unzipped = unzlibSync(buffer)
return strFromU8(unzipped)
}
// function getChromeVersion() {
// var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)
// return raw ? parseInt(raw[2], 10) : 0

View File

@@ -120,9 +120,9 @@ export interface Problem {
total_score: number
submission_number: number
accepted_number: number
statistic_info: { [key in string]: number }
statistic_info: { time_cost: number; memory_cost: number }
share_submission: boolean
contest: null
contest: number
my_status: number
visible: boolean
}
@@ -220,11 +220,27 @@ export interface Submission {
memory_cost?: number
}
ip: string
contest: null
problem: string
contest: number
problem: number // 不是 display_id
can_unshare: boolean
}
export interface SubmissionListItem {
id: string
problem: string
show_link: boolean
create_time: string
user_id: number
username: string
result: SUBMISSION_RESULT
language: LANGUAGE
shared: boolean
statistic_info: {
time_cost: number
memory_cost: number
}
}
export interface SubmissionListPayload {
myself?: "1" | "0"
result?: string