add editor.

This commit is contained in:
2023-01-06 20:09:26 +08:00
parent 2c7da88b06
commit c3746ad105
14 changed files with 298 additions and 169 deletions

View File

@@ -0,0 +1,148 @@
<script lang="ts" setup>
import loader, { Monaco } from "@monaco-editor/loader"
import { ref, onBeforeUnmount, onMounted, watch, reactive } from "vue"
import { onBeforeRouteLeave, useRoute } from "vue-router"
import {
buildProblemCodeKey,
LANGUAGE,
languageLabel,
languageValue,
} from "../../../utils/constants"
import storage from "../../../utils/storage"
const route = useRoute()
const { languages, template } = defineProps<{
languages: Array<LANGUAGE>
template: { [key in LANGUAGE]?: string }
}>()
const state = reactive({
value: "",
language: languages[0] || "C",
theme: "vs",
})
const monacoEditorRef = ref()
let monaco: Monaco
function reset() {
if (monaco && monaco.editor) {
monaco.editor.getModels()[0].setValue(template[state.language] || "")
}
}
onMounted(() => {
initValue()
initEditor()
})
onBeforeUnmount(() => {
monaco.editor.getModels().forEach((model) => model.dispose())
})
onBeforeRouteLeave(() => {
const key = buildProblemCodeKey(
route.params.problemID as string,
route.params.contestID as string
)
storage.set(key, {
code: state.value,
language: state.language,
theme: state.theme,
})
})
watch(
() => state.language,
() => {
if (monaco && monaco.editor) {
monaco.editor.setModelLanguage(
monaco.editor.getModels()[0],
languageValue[state.language]
)
}
}
)
function initValue() {
const key = buildProblemCodeKey(
route.params.problemID as string,
route.params.contestID as string
)
const problemCode = storage.get(key)
if (problemCode) {
state.value = problemCode.code
state.language = problemCode.language
state.theme = problemCode.theme
}
if (!state.value && template[state.language]) {
state.value = template[state.language] || ""
}
}
async function initEditor() {
monaco = await loader.init()
monaco.editor.create(monacoEditorRef.value, {
value: state.value, // 编辑器初始显示文字
language: languageValue[state.language],
automaticLayout: true, // 自适应布局
theme: state.theme, // 官方自带三种主题vs, hc-black, or vs-dark
minimap: {
enabled: false,
},
fontSize: 24, // 字体大小
scrollBeyondLastLine: false, // 取消代码后面一大段空白
overviewRulerBorder: false, // 不要滚动条的边框
})
// 监听值的变化
monaco.editor.getModels()[0].onDidChangeContent(() => {
console.log(1)
state.value = monaco.editor.getModels()[0].getValue()
})
}
</script>
<template>
<el-form :inline="true">
<el-form-item label="语言" label-width="60">
<el-select v-model="state.language" class="language">
<el-option
v-for="item in languages"
:key="item"
:value="item"
:label="languageLabel[item]"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-form>
<div ref="monacoEditorRef" class="editor"></div>
<el-tabs type="border-card">
<el-tab-pane label="测试用例"> 1 </el-tab-pane>
<el-tab-pane label="执行结果"> 2 </el-tab-pane>
</el-tabs>
<el-form class="actions">
<el-form-item>
<el-button>运行</el-button>
<el-button type="primary">提交</el-button>
</el-form-item>
</el-form>
</template>
<style scoped>
.language {
width: 100px;
}
.editor {
height: 500px;
}
.actions {
margin-top: 16px;
float: right;
}
</style>

View File

@@ -16,7 +16,7 @@ const { problem } = defineProps(["problem"])
<div v-if="problem.hint">
<p class="title">提示</p>
<el-card shadow="none">
<el-card shadow="never">
<div class="content" v-html="problem.hint"></div>
</el-card>
</div>

View File

@@ -1,7 +1,6 @@
<script setup lang="ts">
import { defineProps } from "vue"
import { DIFFICULTY, getTagColor } from "../../utils/constants"
import { getACRate } from "../../utils/functions"
import { DIFFICULTY, getTagColor } from "../../../utils/constants"
import { getACRate } from "../../../utils/functions"
const { problem } = defineProps(["problem"])
</script>

View File

@@ -1,15 +1,17 @@
<script setup lang="ts">
import { onMounted, ref } from "vue"
import { useRoute } from "vue-router"
import Editor from "./editor.vue"
import Editor from "./components/editor.vue"
import { getProblem } from "../api"
import ProblemContent from "./problem-content.vue"
import ProblemInfo from "./problem-info.vue"
import ProblemContent from "./components/problem-content.vue"
import ProblemInfo from "./components/problem-info.vue"
const route = useRoute()
const code = ref("print('hello world')")
const language = ref("C")
const contestID = route.params.contestID as string
const problemID = route.params.problemID as string
const problem = ref({
_id: 0,
created_by: {},
io_mode: {},
languages: [],
@@ -20,8 +22,7 @@ const problem = ref({
})
async function init() {
const id = route.params.id as string
const res = await getProblem(id)
const res = await getProblem(problemID)
problem.value = res.data
}
@@ -31,21 +32,21 @@ onMounted(() => {
</script>
<template>
<el-row>
<el-row v-if="problem._id">
<el-col :span="14">
<el-tabs type="border-card">
<el-tab-pane label="题目描述">
<ProblemContent :problem="problem" />
</el-tab-pane>
<el-tab-pane label="比赛信息"></el-tab-pane>
<el-tab-pane label="比赛信息" v-if="contestID"></el-tab-pane>
<el-tab-pane label="题目信息">
<ProblemInfo :problem="problem" />
</el-tab-pane>
<el-tab-pane label="提交信息">3</el-tab-pane>
<el-tab-pane label="提交情况">3</el-tab-pane>
</el-tabs>
</el-col>
<el-col :span="10">
<Editor :value="code" :language="language" />
<Editor :languages="problem.languages" :template="problem.template" />
</el-col>
</el-row>
</template>

View File

@@ -1,134 +0,0 @@
<script lang="ts" setup>
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker"
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker"
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker"
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker"
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker"
import * as monaco from "monaco-editor"
import {
nextTick,
ref,
onBeforeUnmount,
onMounted,
watch,
defineProps,
} from "vue"
const props = defineProps(["value", "language"])
const value = ref(props.value || "")
const language = ref(props.language || "C")
const monacoEditorRef = ref()
// @ts-ignore
self.MonacoEnvironment = {
getWorker(workerId: string, label: string) {
if (label === "json") {
return new jsonWorker()
}
if (label === "css" || label === "scss" || label === "less") {
return new cssWorker()
}
if (label === "html" || label === "handlebars" || label === "razor") {
return new htmlWorker()
}
if (label === "typescript" || label === "javascript") {
return new tsWorker()
}
return new editorWorker()
},
}
function reset() {
if (editor) {
editor.getModel()!.setValue(props.value || "")
}
}
onBeforeUnmount(() => {
editor && editor.dispose()
})
onMounted(() => {
editorInit()
})
watch(language, () => {
if (editor) {
monaco.editor.setModelLanguage(
editor.getModel()!,
language.value.toLowerCase()
)
}
})
let editor: monaco.editor.IStandaloneCodeEditor
function editorInit() {
nextTick(() => {
if (editor) {
editor.setValue("")
} else {
editor = monaco.editor.create(monacoEditorRef.value, {
value: value.value, // 编辑器初始显示文字
language: language.value.toLowerCase(),
automaticLayout: true, // 自适应布局
theme: "vs", // 官方自带三种主题vs, hc-black, or vs-dark
minimap: {
enabled: false,
},
fontSize: 24, // 字体大小
scrollBeyondLastLine: false, // 取消代码后面一大段空白
overviewRulerBorder: false, // 不要滚动条的边框
})
}
// 监听值的变化
editor.onDidChangeModelContent(() => {
value.value = editor.getValue()
})
})
}
</script>
<template>
<el-form :inline="true">
<el-form-item label="语言" label-width="60">
<el-select class="language" v-model="language">
<el-option value="C">C</el-option>
<el-option value="Python">Python</el-option>
<el-option value="CPP">C++</el-option>
<el-option value="Java">Java</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-form>
<div ref="monacoEditorRef" class="editor"></div>
<el-tabs type="border-card">
<el-tab-pane label="测试用例"> 1 </el-tab-pane>
<el-tab-pane label="执行结果"> 2 </el-tab-pane>
</el-tabs>
<el-form class="actions">
<el-form-item>
<el-button>运行</el-button>
<el-button type="primary">提交</el-button>
</el-form-item>
</el-form>
</template>
<style scoped>
.language {
width: 100px;
}
.editor {
height: 500px;
}
.actions {
margin-top: 16px;
float: right;
}
</style>