refactor editor and panel.
This commit is contained in:
4
src/components.d.ts
vendored
4
src/components.d.ts
vendored
@@ -11,6 +11,9 @@ declare module '@vue/runtime-core' {
|
||||
IEpCaretRight: typeof import('~icons/ep/caret-right')['default']
|
||||
IEpLoading: typeof import('~icons/ep/loading')['default']
|
||||
IEpLock: typeof import('~icons/ep/lock')['default']
|
||||
IEpMenu: typeof import('~icons/ep/menu')['default']
|
||||
IEpMore: typeof import('~icons/ep/more')['default']
|
||||
IEpMoreFilled: typeof import('~icons/ep/more-filled')['default']
|
||||
NAlert: typeof import('naive-ui')['NAlert']
|
||||
NButton: typeof import('naive-ui')['NButton']
|
||||
NButtonGroup: typeof import('naive-ui')['NButtonGroup']
|
||||
@@ -36,6 +39,7 @@ declare module '@vue/runtime-core' {
|
||||
NModal: typeof import('naive-ui')['NModal']
|
||||
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
||||
NPagination: typeof import('naive-ui')['NPagination']
|
||||
NPopover: typeof import('naive-ui')['NPopover']
|
||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||
NSelect: typeof import('naive-ui')['NSelect']
|
||||
NSpace: typeof import('naive-ui')['NSpace']
|
||||
|
||||
@@ -3,12 +3,17 @@ import { SOURCES } from "utils/constants"
|
||||
import { Problem } from "utils/types"
|
||||
import Monaco from "~/shared/Monaco.vue"
|
||||
import { code } from "oj/composables/code"
|
||||
import { isDesktop, isMobile } from "~/shared/composables/breakpoints"
|
||||
import { DropdownOption } from "naive-ui"
|
||||
|
||||
const Submit = defineAsyncComponent(() => import("./Submit.vue"))
|
||||
|
||||
interface Props {
|
||||
problem: Problem
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const router = useRouter()
|
||||
|
||||
code.language = props.problem.languages[0] || "C"
|
||||
code.value = props.problem.template[code.language] || SOURCES[code.language]
|
||||
@@ -22,8 +27,10 @@ function reset() {
|
||||
function change(value: string) {
|
||||
code.value = value
|
||||
}
|
||||
|
||||
const options = props.problem.languages.map((it) => ({
|
||||
function goSubmissions() {
|
||||
router.push(`/submission?problem=${props.problem._id}`)
|
||||
}
|
||||
const options: DropdownOption[] = props.problem.languages.map((it) => ({
|
||||
label: () => [
|
||||
h("img", {
|
||||
src: `/${it}.svg`,
|
||||
@@ -38,11 +45,27 @@ const options = props.problem.languages.map((it) => ({
|
||||
],
|
||||
value: it,
|
||||
}))
|
||||
|
||||
const menu: DropdownOption[] = [
|
||||
{ label: "重置", key: "reset" },
|
||||
{ label: "提交信息", key: "submissions" },
|
||||
]
|
||||
|
||||
function select(key: string) {
|
||||
switch (key) {
|
||||
case "reset":
|
||||
reset()
|
||||
break
|
||||
case "submissions":
|
||||
goSubmissions()
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-form inline label-placement="left">
|
||||
<n-form-item label="语言">
|
||||
<n-form-item :label="isDesktop ? '语言' : ''">
|
||||
<n-select
|
||||
class="language"
|
||||
v-model:value="code.language"
|
||||
@@ -50,11 +73,26 @@ const options = props.problem.languages.map((it) => ({
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<Submit />
|
||||
</n-form-item>
|
||||
<n-dropdown
|
||||
v-if="isMobile"
|
||||
trigger="click"
|
||||
:options="menu"
|
||||
@select="select"
|
||||
>
|
||||
<n-button>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<i-ep-more-filled />
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
<n-form-item v-if="isDesktop">
|
||||
<n-space>
|
||||
<n-button @click="reset">重置</n-button>
|
||||
<n-button @click="$router.push(`/submission?problem=${problem._id}`)">
|
||||
提交信息
|
||||
</n-button>
|
||||
<n-button @click="goSubmissions">提交信息</n-button>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
@@ -63,7 +101,7 @@ const options = props.problem.languages.map((it) => ({
|
||||
:language="code.language"
|
||||
:value="code.value"
|
||||
@change="change"
|
||||
height="calc(100vh - 594px)"
|
||||
height="calc(100vh - 200px)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { createTestSubmission } from "utils/judge"
|
||||
import { code } from "oj/composables/code"
|
||||
import party from "party-js"
|
||||
import { Ref } from "vue"
|
||||
@@ -7,7 +6,7 @@ import { SOURCES, JUDGE_STATUS, SubmissionStatus } from "utils/constants"
|
||||
import { submissionMemoryFormat, submissionTimeFormat } from "utils/functions"
|
||||
import { Problem, Submission, SubmitCodePayload } from "utils/types"
|
||||
import { getSubmission, submitCode } from "oj/api"
|
||||
import SubmissionResultTag from "../../../shared/SubmissionResultTag.vue"
|
||||
import SubmissionResultTag from "~/shared/SubmissionResultTag.vue"
|
||||
import type { DataTableColumn } from "naive-ui"
|
||||
|
||||
const problem = inject<Ref<Problem>>("problem")
|
||||
@@ -16,9 +15,7 @@ const route = useRoute()
|
||||
const contestID = <string>route.params.contestID ?? ""
|
||||
|
||||
const submissionId = ref("")
|
||||
const submission = ref<Submission | null>(null)
|
||||
const input = ref("")
|
||||
const result = ref("")
|
||||
const submission = ref<Submission>()
|
||||
const [submitted] = useToggle()
|
||||
|
||||
const { start: submitPending, isPending } = useTimeout(5000, {
|
||||
@@ -186,69 +183,51 @@ watch(
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
async function testcaseSubmit() {
|
||||
const res = await createTestSubmission(code, input.value)
|
||||
result.value = res.output
|
||||
}
|
||||
|
||||
const tabProps = {
|
||||
onClick() {
|
||||
if (!submitDisabled.value) {
|
||||
submit()
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-tabs default-value="testcase">
|
||||
<n-tab-pane name="testcase" tab="测试面板">
|
||||
<n-scrollbar style="height: 400px">
|
||||
<n-form inline label-placement="left">
|
||||
<n-form-item label="输入">
|
||||
<n-input type="textarea" v-model:value="input" />
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<n-button @click="testcaseSubmit">运行</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<div class="msg">{{ result }}</div>
|
||||
</n-scrollbar>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="submit" :disabled="submitDisabled" :tab-props="tabProps">
|
||||
<template #tab>
|
||||
<n-icon>
|
||||
<i-ep-loading v-if="judging || pending || submitting" />
|
||||
<i-ep-bell v-else-if="isPending" />
|
||||
<i-ep-caret-right v-else />
|
||||
</n-icon>
|
||||
<span>{{ submitLabel }}</span>
|
||||
</template>
|
||||
<n-scrollbar style="height: 400px">
|
||||
<n-alert
|
||||
v-if="submission"
|
||||
:type="JUDGE_STATUS[submission.result]['type']"
|
||||
:title="JUDGE_STATUS[submission.result]['name']"
|
||||
/>
|
||||
<div v-if="msg" class="msg result">{{ msg }}</div>
|
||||
<n-data-table
|
||||
v-if="infoTable.length"
|
||||
size="small"
|
||||
striped
|
||||
:data="infoTable"
|
||||
:columns="columns"
|
||||
/>
|
||||
</n-scrollbar>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
<n-popover
|
||||
trigger="click"
|
||||
placement="bottom-end"
|
||||
scrollable
|
||||
:show-arrow="false"
|
||||
style="max-height: 600px"
|
||||
>
|
||||
<template #trigger>
|
||||
<n-button type="primary" :disabled="submitDisabled" @click="submit">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<i-ep-loading v-if="judging || pending || submitting" />
|
||||
<i-ep-bell v-else-if="isPending" />
|
||||
<i-ep-caret-right v-else />
|
||||
</n-icon>
|
||||
</template>
|
||||
{{ submitLabel }}
|
||||
</n-button>
|
||||
</template>
|
||||
<template #header>
|
||||
<n-alert
|
||||
v-if="submission"
|
||||
:type="JUDGE_STATUS[submission.result]['type']"
|
||||
:title="JUDGE_STATUS[submission.result]['name']"
|
||||
/>
|
||||
</template>
|
||||
<n-space vertical v-if="msg || infoTable.length">
|
||||
<n-card v-if="msg" embedded class="msg">{{ msg }}</n-card>
|
||||
<n-data-table
|
||||
v-if="infoTable.length"
|
||||
size="small"
|
||||
striped
|
||||
:data="infoTable"
|
||||
:columns="columns"
|
||||
/>
|
||||
</n-space>
|
||||
</n-popover>
|
||||
</template>
|
||||
<style scoped>
|
||||
.msg {
|
||||
white-space: pre;
|
||||
word-break: break-all;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.result {
|
||||
margin-top: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,6 @@ import { isDesktop, isMobile } from "~/shared/composables/breakpoints"
|
||||
import { Problem } from "utils/types"
|
||||
|
||||
const Editor = defineAsyncComponent(() => import("./components/Editor.vue"))
|
||||
const Panel = defineAsyncComponent(() => import("./components/Panel.vue"))
|
||||
const ProblemContent = defineAsyncComponent(
|
||||
() => import("./components/ProblemContent.vue")
|
||||
)
|
||||
@@ -42,7 +41,6 @@ provide("problem", readonly(problem))
|
||||
</n-tab-pane>
|
||||
<n-tab-pane v-if="isMobile" name="editor" tab="代码编辑">
|
||||
<Editor :problem="problem" />
|
||||
<Panel />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane
|
||||
name="contest"
|
||||
@@ -56,7 +54,6 @@ provide("problem", readonly(problem))
|
||||
</n-gi>
|
||||
<n-gi v-if="isDesktop">
|
||||
<Editor :problem="problem" />
|
||||
<Panel />
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
@@ -49,6 +49,7 @@ export const useContestStore = defineStore("contest", () => {
|
||||
}
|
||||
|
||||
async function _getProblems(contestID: string) {
|
||||
problems.value = []
|
||||
try {
|
||||
problems.value = await getContestProblem(contestID)
|
||||
} catch (err) {
|
||||
|
||||
@@ -16,12 +16,20 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const submission = ref<Submission>()
|
||||
const [copied, toggle] = useToggle()
|
||||
const { start } = useTimeoutFn(() => toggle(false), 1000, { immediate: false })
|
||||
|
||||
async function init() {
|
||||
const res = await getSubmission(props.submissionID)
|
||||
submission.value = res.data
|
||||
}
|
||||
|
||||
function handleCopy(v: string) {
|
||||
copy(v)
|
||||
toggle(true)
|
||||
start()
|
||||
}
|
||||
|
||||
const columns: DataTableColumn<Submission["info"]["data"][number]>[] = [
|
||||
{ title: "测试用例", key: "test_case" },
|
||||
{
|
||||
@@ -59,7 +67,9 @@ onMounted(init)
|
||||
</n-alert>
|
||||
<n-card embedded>
|
||||
<n-space justify="end">
|
||||
<n-button @click="copy(submission!.code)">复制代码</n-button>
|
||||
<n-button @click="handleCopy(submission!.code)">
|
||||
{{ copied ? "已复制" : "复制代码" }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
<n-code
|
||||
class="code"
|
||||
|
||||
@@ -15,10 +15,16 @@ function handleClick(value: string) {
|
||||
<template>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon @click="handleClick(value)">
|
||||
<n-icon class="icon" @click="handleClick(value)">
|
||||
<component :is="copied ? Select : DocumentCopy"></component>
|
||||
</n-icon>
|
||||
</template>
|
||||
{{ copied ? "已复制" : "复制" }}
|
||||
</n-tooltip>
|
||||
</template>
|
||||
<style scoped>
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
transform: translateY(2px);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -107,7 +107,13 @@ const options = computed<Array<DropdownOption | DropdownDividerOption>>(() => [
|
||||
<n-button @click="toggleSignup(true)">注册</n-button>
|
||||
</n-space>
|
||||
<n-dropdown :options="menus">
|
||||
<n-button>菜单</n-button>
|
||||
<n-button>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<i-ep-menu />
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user