fix monaco.
This commit is contained in:
@@ -1,9 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import Md from "./step-1/index.md"
|
||||
import Monaco from "../shared/monaco/index.vue"
|
||||
|
||||
const route = useRoute()
|
||||
console.log(route.params.step)
|
||||
|
||||
const code = ref("")
|
||||
|
||||
function change(value: string) {
|
||||
code.value = value
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-row>
|
||||
<el-col :span="4"> </el-col>
|
||||
<el-col :span="12">
|
||||
<Md />
|
||||
{{ code }}
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<Monaco :value="code" @change="change" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -8,7 +8,7 @@ import App from "./App.vue"
|
||||
import storage from "./utils/storage"
|
||||
import routes from "./routes"
|
||||
import { STORAGE_KEY } from "./utils/constants"
|
||||
import { useLoginStore } from "./shared/stores/login"
|
||||
import { useLoginStore } from "./shared/store/login"
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { TabsPaneContext } from "element-plus"
|
||||
import { Ref } from "vue"
|
||||
import { Problem } from "../../../utils/types"
|
||||
import { submissionExists } from "../../api"
|
||||
import SubmitPanel from "./submit-panel.vue"
|
||||
import TestcasePanel from "./testcase-panel.vue"
|
||||
|
||||
const tab = ref("test")
|
||||
const submitPanelRef = ref<{ submit: Function }>()
|
||||
const problem = inject<Ref<Problem>>("problem")
|
||||
const [tried] = useToggle()
|
||||
|
||||
onMounted(() => {
|
||||
checkIfTried()
|
||||
})
|
||||
|
||||
async function checkIfTried() {
|
||||
const res = await submissionExists(problem!.value.id)
|
||||
tried.value = res.data
|
||||
}
|
||||
|
||||
function onTab(pane: TabsPaneContext) {
|
||||
if (pane.paneName === "submit") {
|
||||
submitPanelRef && submitPanelRef.value!.submit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-tabs type="border-card" @tab-click="onTab" v-model="tab">
|
||||
<TestcasePanel />
|
||||
<SubmitPanel ref="submitPanelRef" />
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,14 +1,13 @@
|
||||
<script lang="ts" setup>
|
||||
import loader, { Monaco } from "@monaco-editor/loader"
|
||||
import {
|
||||
LANGUAGE_LABEL,
|
||||
LANGUAGE_VALUE,
|
||||
SOURCES,
|
||||
} from "../../../utils/constants"
|
||||
import { isMobile } from "../../../utils/breakpoints"
|
||||
import { LANGUAGE_LABEL, SOURCES } from "../../../utils/constants"
|
||||
import { Problem } from "../../../utils/types"
|
||||
import EditorExec from "./editor-exec.vue"
|
||||
import { useCodeStore } from "../../stores/code"
|
||||
import { submissionExists } from "../../api"
|
||||
import { TabsPaneContext } from "element-plus"
|
||||
|
||||
import Monaco from "../../../shared/monaco/index.vue"
|
||||
import SubmitPanel from "../components/submit-panel.vue"
|
||||
import TestcasePanel from "../components/testcase-panel.vue"
|
||||
|
||||
interface Props {
|
||||
problem: Problem
|
||||
@@ -16,63 +15,38 @@ interface Props {
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const { code, setLanguage, setValue } = useCodeStore()
|
||||
setValue(SOURCES[props.problem.languages[0] || "C"])
|
||||
setLanguage(props.problem.languages[0] || "C")
|
||||
const { code } = useCodeStore()
|
||||
|
||||
const monacoEditorRef = ref()
|
||||
code.language = props.problem.languages[0] || "C"
|
||||
code.value = props.problem.template[code.language] || SOURCES[code.language]
|
||||
|
||||
let monaco: Monaco
|
||||
const tab = ref("test")
|
||||
const submitPanelRef = ref<{ submit: Function }>()
|
||||
const [tried] = useToggle()
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
monaco.editor.getModels().forEach((model) => model.dispose())
|
||||
})
|
||||
|
||||
watch(
|
||||
() => code.language,
|
||||
() => {
|
||||
if (monaco && monaco.editor) {
|
||||
monaco.editor.setModelLanguage(
|
||||
monaco.editor.getModels()[0],
|
||||
LANGUAGE_VALUE[code.language]
|
||||
)
|
||||
reset()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
function run() {}
|
||||
watch(() => code.language, reset)
|
||||
|
||||
function reset() {
|
||||
setValue(props.problem.template[code.language] || SOURCES[code.language])
|
||||
if (monaco && monaco.editor) {
|
||||
monaco.editor.getModels()[0].setValue(code.value)
|
||||
}
|
||||
code.value = props.problem.template[code.language] || SOURCES[code.language]
|
||||
}
|
||||
|
||||
async function init() {
|
||||
setValue(props.problem.template[code.language] || SOURCES[code.language])
|
||||
monaco = await loader.init()
|
||||
monaco.editor.create(monacoEditorRef.value, {
|
||||
value: code.value, // 编辑器初始显示文字
|
||||
language: LANGUAGE_VALUE[code.language],
|
||||
theme: "vs", // 官方自带三种主题vs, hc-black, or vs-dark
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
lineNumbersMinChars: 3,
|
||||
automaticLayout: true, // 自适应布局
|
||||
tabSize: 4,
|
||||
fontSize: isMobile.value ? 20 : 24, // 字体大小
|
||||
scrollBeyondLastLine: false, // 取消代码后面一大段空白
|
||||
})
|
||||
monaco.editor.getModels()[0].onDidChangeContent(() => {
|
||||
setValue(monaco.editor.getModels()[0].getValue())
|
||||
})
|
||||
function change(value: string) {
|
||||
code.value = value
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkIfTried()
|
||||
})
|
||||
|
||||
async function checkIfTried() {
|
||||
const res = await submissionExists(props.problem.id)
|
||||
tried.value = res.data
|
||||
}
|
||||
|
||||
function onTab(pane: TabsPaneContext) {
|
||||
if (pane.paneName === "submit") {
|
||||
submitPanelRef && submitPanelRef.value!.submit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -93,11 +67,17 @@ async function init() {
|
||||
<el-button @click="reset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<section
|
||||
ref="monacoEditorRef"
|
||||
:class="isMobile ? 'editorMobile' : 'editor'"
|
||||
></section>
|
||||
<EditorExec />
|
||||
<Monaco
|
||||
class="editor"
|
||||
:language="code.language"
|
||||
:value="code.value"
|
||||
height="calc(100vh - 621px)"
|
||||
@change="change"
|
||||
/>
|
||||
<el-tabs type="border-card" @tab-click="onTab" v-model="tab">
|
||||
<TestcasePanel />
|
||||
<SubmitPanel ref="submitPanelRef" />
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@@ -106,11 +86,6 @@ async function init() {
|
||||
}
|
||||
|
||||
.editor {
|
||||
/* 141px+400 */
|
||||
height: calc(100vh - 541px);
|
||||
}
|
||||
|
||||
.editorMobile {
|
||||
height: calc(100vh - 612px);
|
||||
min-height: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -61,5 +61,3 @@ defineProps<Props>()
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -230,7 +230,7 @@ defineExpose({ submit })
|
||||
</template>
|
||||
<style scoped>
|
||||
.panel {
|
||||
height: 320px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.result {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<el-tab-pane label="测试 & 运行" name="test">
|
||||
<el-tab-pane label="测试面板" name="test">
|
||||
<div class="panel"></div>
|
||||
</el-tab-pane>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.panel {
|
||||
height: 320px;
|
||||
height: 400px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { useUserStore } from "../../shared/stores/user"
|
||||
import { useUserStore } from "../../shared/store/user"
|
||||
import { filterEmptyValue, getTagColor } from "../../utils/functions"
|
||||
import { isDesktop } from "../../utils/breakpoints"
|
||||
import { getProblemList, getProblemTagList, getRandomProblemID } from "../api"
|
||||
@@ -77,7 +77,7 @@ function goProblem(row: any) {
|
||||
watch(() => query.page, routePush)
|
||||
|
||||
watch(
|
||||
() => query.tag || query.difficulty || query.limit,
|
||||
() => [query.tag, query.difficulty, query.limit],
|
||||
() => {
|
||||
query.page = 1
|
||||
routePush()
|
||||
|
||||
@@ -6,13 +6,5 @@ export const useCodeStore = defineStore("code", () => {
|
||||
language: "C",
|
||||
})
|
||||
|
||||
function setValue(value: string) {
|
||||
code.value = value
|
||||
}
|
||||
|
||||
function setLanguage(language: LANGUAGE) {
|
||||
code.language = language
|
||||
}
|
||||
|
||||
return { code, setLanguage, setValue }
|
||||
return { code }
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@ const routes = [
|
||||
component: Home,
|
||||
children: [
|
||||
{ path: "", component: Problems },
|
||||
{ path: "/learn", component: () => import("./learn/index.vue") },
|
||||
{ path: "/learn/:step*", component: () => import("./learn/index.vue") },
|
||||
{
|
||||
path: "problem/:problemID",
|
||||
component: () => import("./oj/problem/detail.vue"),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useLoginStore } from "../stores/login"
|
||||
import { useLoginStore } from "../store/login"
|
||||
import { useSignupStore } from "../../oj/stores/signup"
|
||||
import { useUserStore } from "../stores/user"
|
||||
import { useUserStore } from "../store/user"
|
||||
import { logout } from "../api"
|
||||
|
||||
const loginStore = useLoginStore()
|
||||
@@ -30,7 +30,7 @@ onMounted(userStore.getMyProfile)
|
||||
<el-menu router mode="horizontal" :default-active="$route.path">
|
||||
<el-menu-item index="/learn">自学</el-menu-item>
|
||||
<el-menu-item index="/">题库</el-menu-item>
|
||||
<el-menu-item index="/contest">竞赛</el-menu-item>
|
||||
<el-menu-item index="/contest">比赛</el-menu-item>
|
||||
<el-menu-item index="/status">提交</el-menu-item>
|
||||
<el-menu-item index="/rank">排名</el-menu-item>
|
||||
</el-menu>
|
||||
|
||||
107
src/shared/monaco/index.vue
Normal file
107
src/shared/monaco/index.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<script setup lang="ts">
|
||||
import type * as Monaco from "monaco-editor"
|
||||
import loader from "@monaco-editor/loader"
|
||||
import { LANGUAGE_VALUE } from "../../utils/constants"
|
||||
import { LANGUAGE } from "../../utils/types"
|
||||
import { isMobile } from "../../utils/breakpoints"
|
||||
|
||||
interface Props {
|
||||
value: string
|
||||
language?: LANGUAGE
|
||||
height?: string
|
||||
fontSize?: number
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
language: "C",
|
||||
height: "calc(100vh - 100px)",
|
||||
fontSize: 20,
|
||||
class: "",
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "change", value: string): void
|
||||
}>()
|
||||
|
||||
const monacoEditorRef = ref()
|
||||
let editor: Monaco.editor.IStandaloneCodeEditor | null
|
||||
|
||||
onMounted(async function () {
|
||||
const monaco = await loader.init()
|
||||
|
||||
const model = monaco.editor.createModel(
|
||||
props.value,
|
||||
LANGUAGE_VALUE[props.language],
|
||||
monaco.Uri.parse(`file:///root/${Date.now()}.${ext()}`)
|
||||
)
|
||||
|
||||
editor = monaco.editor.create(monacoEditorRef.value, {
|
||||
model,
|
||||
theme: "vs-dark", // 官方自带三种主题vs, hc-black, or vs-dark
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
lineNumbersMinChars: 3,
|
||||
automaticLayout: true, // 自适应布局
|
||||
tabSize: 4,
|
||||
fontSize: isMobile.value ? 20 : 24, // 字体大小
|
||||
})
|
||||
|
||||
model.onDidChangeContent(() => {
|
||||
const value = model.getValue().toString()
|
||||
emit("change", value)
|
||||
})
|
||||
|
||||
editor.onKeyDown((e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && e.code === "KeyS") {
|
||||
e.preventDefault()
|
||||
}
|
||||
if ((e.ctrlKey || e.metaKey) && e.code === "KeyR") {
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
monaco.editor.setModelLanguage(model, LANGUAGE_VALUE[props.language])
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.value !== model.getValue()) {
|
||||
console.log(666)
|
||||
model.setValue(props.value)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
editor && editor.dispose()
|
||||
})
|
||||
|
||||
function ext() {
|
||||
switch (props.language) {
|
||||
case "C":
|
||||
return "c"
|
||||
case "C++":
|
||||
return "cpp"
|
||||
case "Java":
|
||||
return "java"
|
||||
case "JavaScript":
|
||||
return "js"
|
||||
case "Python2":
|
||||
return "py"
|
||||
case "Python3":
|
||||
return "py"
|
||||
case "Golang":
|
||||
return "go"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
ref="monacoEditorRef"
|
||||
:class="props.class"
|
||||
:style="{ height: props.height }"
|
||||
></div>
|
||||
</template>
|
||||
<style scoped></style>
|
||||
@@ -2,8 +2,8 @@
|
||||
import { FormInstance } from "element-plus"
|
||||
import { useSignupStore } from "../../oj/stores/signup"
|
||||
import { login } from "../../shared/api"
|
||||
import { useLoginStore } from "../stores/login"
|
||||
import { useUserStore } from "../stores/user"
|
||||
import { useLoginStore } from "../store/login"
|
||||
import { useUserStore } from "../store/user"
|
||||
|
||||
const loginStore = useLoginStore()
|
||||
const signupStore = useSignupStore()
|
||||
|
||||
7
src/shims.d.ts
vendored
Normal file
7
src/shims.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
declare module "element-plus/dist/locale/zh-cn.mjs"
|
||||
|
||||
declare module "*.md" {
|
||||
import type { ComponentOptions } from "vue"
|
||||
const Component: ComponentOptions
|
||||
export default Component
|
||||
}
|
||||
@@ -189,6 +189,27 @@ export const DEAD_RESULTS = {
|
||||
output: "黄岩一职",
|
||||
},
|
||||
},
|
||||
Python2: {
|
||||
encoded: "",
|
||||
result: {
|
||||
status: 3,
|
||||
output: "黄岩一职",
|
||||
},
|
||||
},
|
||||
Golang: {
|
||||
encoded: "",
|
||||
result: {
|
||||
status: 3,
|
||||
output: "黄岩一职",
|
||||
},
|
||||
},
|
||||
JavaScript: {
|
||||
encoded: "",
|
||||
result: {
|
||||
status: 3,
|
||||
output: "黄岩一职",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const LANGUAGE_LABEL = {
|
||||
|
||||
@@ -49,3 +49,13 @@ export function submissionTimeFormat(time: number) {
|
||||
if (time === undefined) return "--"
|
||||
return time + "ms"
|
||||
}
|
||||
|
||||
export function debounce(fn: Function, n = 100) {
|
||||
let handle: any
|
||||
return (...args: any[]) => {
|
||||
if (handle) clearTimeout(handle)
|
||||
handle = setTimeout(() => {
|
||||
fn(...args)
|
||||
}, n)
|
||||
}
|
||||
}
|
||||
|
||||
59
src/utils/judge.ts
Normal file
59
src/utils/judge.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import axios from "axios"
|
||||
import { DEAD_RESULTS } from "./constants"
|
||||
import { Code } from "./types"
|
||||
|
||||
const http = axios.create({ baseURL: "https://judge0api.hyyz.izhai.net" })
|
||||
|
||||
function encode(str: string) {
|
||||
return btoa(unescape(encodeURIComponent(str || "")))
|
||||
}
|
||||
|
||||
function decode(bytes: string) {
|
||||
let escaped = escape(atob(bytes || ""))
|
||||
try {
|
||||
return decodeURIComponent(escaped)
|
||||
} catch (e) {
|
||||
return unescape(escaped)
|
||||
}
|
||||
}
|
||||
|
||||
export async function createTestSubmission(code: Code, input: string) {
|
||||
const encodedCode = encode(code.value)
|
||||
|
||||
if (encodedCode === DEAD_RESULTS[code.language].encoded) {
|
||||
return DEAD_RESULTS[code.language].result
|
||||
} else {
|
||||
const id = {
|
||||
C: 50,
|
||||
"C++": 54,
|
||||
Java: 62,
|
||||
Golang: 60,
|
||||
JavaScript: 63,
|
||||
Python2: 70,
|
||||
Python3: 71,
|
||||
}[code.language]
|
||||
let compilerOptions = ""
|
||||
if (id === 50) compilerOptions = "-lm" // 解决 GCC 的链接问题
|
||||
const payload = {
|
||||
source_code: encodedCode,
|
||||
language_id: id,
|
||||
stdin: encode(input),
|
||||
redirect_stderr_to_stdout: true,
|
||||
compiler_options: compilerOptions,
|
||||
}
|
||||
try {
|
||||
const response = await http.post("/submissions", payload, {
|
||||
params: { base64_encoded: true, wait: true },
|
||||
})
|
||||
const data = response.data
|
||||
return {
|
||||
status: data.status && data.status.id,
|
||||
output: [decode(data.compile_output), decode(data.stdout)]
|
||||
.join("\n")
|
||||
.trim(),
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
2
src/vite-env.d.ts
vendored
2
src/vite-env.d.ts
vendored
@@ -1,3 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
declare module "element-plus/dist/locale/zh-cn.mjs"
|
||||
declare module "*.md"
|
||||
|
||||
Reference in New Issue
Block a user