refactor editor and panel.

This commit is contained in:
2023-01-31 22:16:41 +08:00
parent 7b0163885a
commit 17aa4afc04
8 changed files with 115 additions and 74 deletions

4
src/components.d.ts vendored
View File

@@ -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']

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -49,6 +49,7 @@ export const useContestStore = defineStore("contest", () => {
}
async function _getProblems(contestID: string) {
problems.value = []
try {
problems.value = await getContestProblem(contestID)
} catch (err) {

View File

@@ -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"

View File

@@ -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>

View File

@@ -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>