This commit is contained in:
2024-01-22 10:44:38 +08:00
parent d940c684ad
commit 230cf1bdeb
11 changed files with 369 additions and 370 deletions

View File

@@ -1,9 +1,9 @@
<script setup lang="ts">
import { zhCN, dateZhCN, darkTheme } from "naive-ui"
import { useDark } from "@vueuse/core"
import Desktop from "./desktop/index.vue"
import Mobile from "./mobile/index.vue"
import { isDesktop, isMobile } from "./composables/breakpoints"
import { useDark } from "@vueuse/core"
const isDark = useDark()
</script>
@@ -22,4 +22,3 @@ const isDark = useDark()
</n-message-provider>
</n-config-provider>
</template>
./themes/breakpoints

View File

@@ -1,56 +1,56 @@
import axios from "axios"
import { Code } from "./types"
import { deadResults, languageToId } from "./templates"
function getChromeVersion() {
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)
return raw ? parseInt(raw[2], 10) : 0
}
const isLowVersion = getChromeVersion() < 80
const protocol = isLowVersion ? "http" : "https"
function encode(string?: string) {
return btoa(String.fromCharCode(...new TextEncoder().encode(string ?? "")))
}
function decode(bytes?: string) {
const latin = atob(bytes ?? "")
return new TextDecoder("utf-8").decode(
Uint8Array.from({ length: latin.length }, (_, index) =>
latin.charCodeAt(index),
),
)
}
const http = axios.create({ baseURL: `${protocol}://judge0api.xuyue.cc` })
export async function submit(code: Code, input: string) {
const encodedCode = encode(code.value)
if (encodedCode === deadResults[code.language].encoded) {
return deadResults[code.language].result
} else {
const id = languageToId[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,
}
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(),
}
}
}
import axios from "axios"
import { Code } from "./types"
import { deadResults, languageToId } from "./templates"
function getChromeVersion() {
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)
return raw ? parseInt(raw[2], 10) : 0
}
const isLowVersion = getChromeVersion() < 80
const protocol = isLowVersion ? "http" : "https"
function encode(string?: string) {
return btoa(String.fromCharCode(...new TextEncoder().encode(string ?? "")))
}
function decode(bytes?: string) {
const latin = atob(bytes ?? "")
return new TextDecoder("utf-8").decode(
Uint8Array.from({ length: latin.length }, (_, index) =>
latin.charCodeAt(index),
),
)
}
const http = axios.create({ baseURL: `${protocol}://judge0api.xuyue.cc` })
export async function submit(code: Code, input: string) {
const encodedCode = encode(code.value)
if (encodedCode === deadResults[code.language].encoded) {
return deadResults[code.language].result
} else {
const id = languageToId[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,
}
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(),
}
}
}

View File

@@ -1,81 +1,81 @@
<script lang="ts" setup>
import { computed, ref, watch } from "vue"
import { useDark } from "@vueuse/core"
import { Codemirror } from "vue-codemirror"
import { cpp } from "@codemirror/lang-cpp"
import { python } from "@codemirror/lang-python"
import { EditorView } from "@codemirror/view"
import { LANGUAGE } from "../types"
import { oneDark } from "../themes/oneDark"
import { smoothy } from "../themes/smoothy"
interface Props {
label: string
modelValue: string
language?: LANGUAGE
fontSize?: number
readonly?: boolean
placeholder?: string
}
const props = withDefaults(defineProps<Props>(), {
language: "python",
fontSize: 24,
readonly: false,
placeholder: "",
})
const code = ref(props.modelValue)
const isDark = useDark()
const styleTheme = EditorView.baseTheme({
"& .cm-scroller": {
"font-family": "Consolas",
},
"&.cm-editor.cm-focused": {
outline: "none",
},
})
const emit = defineEmits(["update:modelValue"])
watch(
() => props.modelValue,
(v) => {
code.value = v
},
)
const lang = computed(() => {
if (props.language === "python") {
return python()
}
return cpp()
})
function onChange(v: string) {
emit("update:modelValue", v)
}
</script>
<template>
<div class="container">
<div class="title">{{ label }}</div>
<Codemirror
v-model="code"
indentWithTab
:extensions="[styleTheme, lang, isDark ? oneDark : smoothy]"
:disabled="props.readonly"
:tabSize="4"
:placeholder="props.placeholder"
:style="{ height: '100%', fontSize: props.fontSize + 'px' }"
@change="onChange"
/>
</div>
</template>
<style scoped>
.container {
height: 100%;
}
.title {
padding: 12px 20px;
font-size: 16px;
}
</style>
<script lang="ts" setup>
import { computed, ref, watch } from "vue"
import { useDark } from "@vueuse/core"
import { Codemirror } from "vue-codemirror"
import { cpp } from "@codemirror/lang-cpp"
import { python } from "@codemirror/lang-python"
import { EditorView } from "@codemirror/view"
import { LANGUAGE } from "../types"
import { oneDark } from "../themes/oneDark"
import { smoothy } from "../themes/smoothy"
interface Props {
label: string
modelValue: string
language?: LANGUAGE
fontSize?: number
readonly?: boolean
placeholder?: string
}
const props = withDefaults(defineProps<Props>(), {
language: "python",
fontSize: 24,
readonly: false,
placeholder: "",
})
const code = ref(props.modelValue)
const isDark = useDark()
const styleTheme = EditorView.baseTheme({
"& .cm-scroller": {
"font-family": "Consolas",
},
"&.cm-editor.cm-focused": {
outline: "none",
},
})
const emit = defineEmits(["update:modelValue"])
watch(
() => props.modelValue,
(v) => {
code.value = v
},
)
const lang = computed(() => {
if (props.language === "python") {
return python()
}
return cpp()
})
function onChange(v: string) {
emit("update:modelValue", v)
}
</script>
<template>
<div class="container">
<div class="title">{{ label }}</div>
<Codemirror
v-model="code"
indentWithTab
:extensions="[styleTheme, lang, isDark ? oneDark : smoothy]"
:disabled="props.readonly"
:tabSize="4"
:placeholder="props.placeholder"
:style="{ height: '100%', fontSize: props.fontSize + 'px' }"
@change="onChange"
/>
</div>
</template>
<style scoped>
.container {
height: 100%;
}
.title {
padding: 12px 20px;
font-size: 16px;
}
</style>

View File

@@ -1,40 +1,40 @@
import { ref } from "vue"
import copyTextToClipboard from "copy-text-to-clipboard"
import { Code, LANGUAGE } from "../types"
import { sources } from "../templates"
import { submit } from "../api"
export const code = ref<Code>({
value: sources["python"],
language: "python",
})
export const input = ref("")
export const output = ref("")
export const loading = ref(false)
export function copy() {
copyTextToClipboard(code.value.value)
}
export function reset() {
code.value.value = sources["python"]
output.value = ""
}
export function changeLanguage(language: LANGUAGE) {
code.value.value = sources[language]
output.value = ""
}
export async function run() {
loading.value = true
const cleanCode = code.value.value.trim()
if (!cleanCode) return
output.value = ""
const result = await submit(
{ value: cleanCode, language: code.value.language },
input.value.trim(),
)
output.value = result.output || ""
loading.value = false
}
import { ref } from "vue"
import copyTextToClipboard from "copy-text-to-clipboard"
import { Code, LANGUAGE } from "../types"
import { sources } from "../templates"
import { submit } from "../api"
export const code = ref<Code>({
value: sources["python"],
language: "python",
})
export const input = ref("")
export const output = ref("")
export const loading = ref(false)
export function copy() {
copyTextToClipboard(code.value.value)
}
export function reset() {
code.value.value = sources["python"]
output.value = ""
}
export function changeLanguage(language: LANGUAGE) {
code.value.value = sources[language]
output.value = ""
}
export async function run() {
loading.value = true
const cleanCode = code.value.value.trim()
if (!cleanCode) return
output.value = ""
const result = await submit(
{ value: cleanCode, language: code.value.language },
input.value.trim(),
)
output.value = result.output || ""
loading.value = false
}

View File

@@ -1,37 +1,37 @@
<template>
<n-layout-content class="container">
<n-split direction="horizontal" :min="1 / 3" :max="4 / 5">
<template #1>
<CodeEditor
label="代码区"
v-model="code.value"
:language="code.language"
/>
</template>
<template #2>
<n-split
direction="vertical"
:default-size="1 / 3"
:min="1 / 5"
:max="3 / 5"
>
<template #1>
<CodeEditor label="输入框" v-model="input" />
</template>
<template #2>
<CodeEditor label="输出框" v-model="output" readonly />
</template>
</n-split>
</template>
</n-split>
</n-layout-content>
</template>
<script lang="ts" setup>
import { code, input, output } from "../composables/code"
import CodeEditor from "../components/CodeEditor.vue"
</script>
<style scoped>
.container {
height: calc(100vh - 60px);
}
</style>
<template>
<n-layout-content class="container">
<n-split direction="horizontal" :min="1 / 3" :max="4 / 5">
<template #1>
<CodeEditor
label="代码区"
v-model="code.value"
:language="code.language"
/>
</template>
<template #2>
<n-split
direction="vertical"
:default-size="1 / 3"
:min="1 / 5"
:max="3 / 5"
>
<template #1>
<CodeEditor label="输入框" v-model="input" />
</template>
<template #2>
<CodeEditor label="输出框" v-model="output" readonly />
</template>
</n-split>
</template>
</n-split>
</n-layout-content>
</template>
<script lang="ts" setup>
import { code, input, output } from "../composables/code"
import CodeEditor from "../components/CodeEditor.vue"
</script>
<style scoped>
.container {
height: calc(100vh - 60px);
}
</style>

View File

@@ -1,69 +1,69 @@
<script setup lang="ts">
import { useMessage, type SelectOption } from "naive-ui"
import { useDark, useToggle } from "@vueuse/core"
import Play from "../icons/Play.vue"
import {
code,
copy,
reset,
run,
loading,
changeLanguage,
} from "../composables/code"
const message = useMessage()
const isDark = useDark()
const toggleDark = useToggle(isDark)
const languages: SelectOption[] = [
{ value: "python", label: "Python" },
{ value: "c", label: "C" },
]
function copyAndNotify() {
copy()
message.success("已经复制好了")
}
</script>
<template>
<n-layout-header bordered class="header">
<n-flex justify="space-between" align="center">
<div class="title">徐越的自测猫</div>
<n-flex>
<n-button @click="toggleDark()">
{{ isDark ? "浅色" : "深色" }}
</n-button>
<n-button @click="reset">重置</n-button>
<n-button @click="copyAndNotify">复制</n-button>
<n-select
class="select"
:options="languages"
v-model:value="code.language"
@update:value="changeLanguage"
/>
<n-button type="primary" @click="run" :loading="loading">
<template #icon>
<n-icon>
<Play />
</n-icon>
</template>
运行 (F5)
</n-button>
</n-flex>
</n-flex>
</n-layout-header>
</template>
<style scoped>
.header {
height: 60px;
padding: 12px;
}
.title {
font-size: 20px;
}
.select {
width: 100px;
}
</style>
<script setup lang="ts">
import { useMessage, type SelectOption } from "naive-ui"
import { useDark, useToggle } from "@vueuse/core"
import Play from "../icons/Play.vue"
import {
code,
copy,
reset,
run,
loading,
changeLanguage,
} from "../composables/code"
const message = useMessage()
const isDark = useDark()
const toggleDark = useToggle(isDark)
const languages: SelectOption[] = [
{ value: "python", label: "Python" },
{ value: "c", label: "C" },
]
function copyAndNotify() {
copy()
message.success("已经复制好了")
}
</script>
<template>
<n-layout-header bordered class="header">
<n-flex justify="space-between" align="center">
<div class="title">徐越的自测猫</div>
<n-flex>
<n-button @click="toggleDark()">
{{ isDark ? "浅色" : "深色" }}
</n-button>
<n-button @click="reset">重置</n-button>
<n-button @click="copyAndNotify">复制</n-button>
<n-select
class="select"
:options="languages"
v-model:value="code.language"
@update:value="changeLanguage"
/>
<n-button type="primary" @click="run" :loading="loading">
<template #icon>
<n-icon>
<Play />
</n-icon>
</template>
运行 (F5)
</n-button>
</n-flex>
</n-flex>
</n-layout-header>
</template>
<style scoped>
.header {
height: 60px;
padding: 12px;
}
.title {
font-size: 20px;
}
.select {
width: 100px;
}
</style>

View File

@@ -1,8 +1,8 @@
<template>
<Header />
<Content />
</template>
<script lang="ts" setup>
import Header from "./Header.vue"
import Content from "./Content.vue"
</script>
<template>
<Header />
<Content />
</template>
<script lang="ts" setup>
import Header from "./Header.vue"
import Content from "./Content.vue"
</script>

View File

@@ -1,15 +1,15 @@
<template>
<svg
viewBox="0 0 1024 1024"
focusable="false"
data-icon="caret-right"
width="18px"
height="18px"
fill="currentColor"
aria-hidden="true"
>
<path
d="M715.8 493.5L335 165.1c-14.2-12.2-35-1.2-35 18.5v656.8c0 19.7 20.8 30.7 35 18.5l380.8-328.4c10.9-9.4 10.9-27.6 0-37z"
></path>
</svg>
</template>
<template>
<svg
viewBox="0 0 1024 1024"
focusable="false"
data-icon="caret-right"
width="18px"
height="18px"
fill="currentColor"
aria-hidden="true"
>
<path
d="M715.8 493.5L335 165.1c-14.2-12.2-35-1.2-35 18.5v656.8c0 19.7 20.8 30.7 35 18.5l380.8-328.4c10.9-9.4 10.9-27.6 0-37z"
></path>
</svg>
</template>

View File

@@ -1 +1 @@
<template></template>
<template></template>

View File

@@ -1,55 +1,55 @@
const cSource =
'#include<stdio.h>\r\n\r\nint main()\r\n{\r\n printf("黄岩一职");\r\n return 0;\r\n}'
const cppSource =
'#include<iostream>\r\n\r\nusing namespace std;\r\n\r\nint main()\r\n{\r\n cout<<"黄岩一职"<<endl;\r\n return 0;\r\n}'
const pythonSource = 'print("黄岩一职")'
const javaSource =
'public class Main {\r\n public static void main(String[] args) {\r\n System.out.println("黄岩一职");\r\n }\r\n}'
export const languageToId = {
c: 50,
cpp: 54,
java: 62,
python: 71,
}
export const sources = {
c: cSource,
cpp: cppSource,
java: javaSource,
python: pythonSource,
}
export const deadResults = {
c: {
encoded:
"I2luY2x1ZGU8c3RkaW8uaD4NCg0KaW50IG1haW4oKQ0Kew0KICAgIHByaW50Zigi6buE5bKp5LiA6IGMIik7DQogICAgcmV0dXJuIDA7DQp9",
result: {
status: 3,
output: "黄岩一职",
},
},
cpp: {
encoded:
"I2luY2x1ZGU8aW9zdHJlYW0+DQoNCnVzaW5nIG5hbWVzcGFjZSBzdGQ7DQoNCmludCBtYWluKCkNCnsNCiAgICBjb3V0PDwi6buE5bKp5LiA6IGMIjw8ZW5kbDsNCiAgICByZXR1cm4gMDsNCn0=",
result: {
status: 3,
output: "黄岩一职",
},
},
python: {
encoded: "cHJpbnQoIum7hOWyqeS4gOiBjCIp",
result: {
status: 3,
output: "黄岩一职",
},
},
java: {
encoded:
"cHVibGljIGNsYXNzIE1haW4gew0KICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHsNCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCLpu4TlsqnkuIDogYwiKTsNCiAgICB9DQp9",
result: {
status: 3,
output: "黄岩一职",
},
},
}
const cSource =
'#include<stdio.h>\r\n\r\nint main()\r\n{\r\n printf("黄岩一职");\r\n return 0;\r\n}'
const cppSource =
'#include<iostream>\r\n\r\nusing namespace std;\r\n\r\nint main()\r\n{\r\n cout<<"黄岩一职"<<endl;\r\n return 0;\r\n}'
const pythonSource = 'print("黄岩一职")'
const javaSource =
'public class Main {\r\n public static void main(String[] args) {\r\n System.out.println("黄岩一职");\r\n }\r\n}'
export const languageToId = {
c: 50,
cpp: 54,
java: 62,
python: 71,
}
export const sources = {
c: cSource,
cpp: cppSource,
java: javaSource,
python: pythonSource,
}
export const deadResults = {
c: {
encoded:
"I2luY2x1ZGU8c3RkaW8uaD4NCg0KaW50IG1haW4oKQ0Kew0KICAgIHByaW50Zigi6buE5bKp5LiA6IGMIik7DQogICAgcmV0dXJuIDA7DQp9",
result: {
status: 3,
output: "黄岩一职",
},
},
cpp: {
encoded:
"I2luY2x1ZGU8aW9zdHJlYW0+DQoNCnVzaW5nIG5hbWVzcGFjZSBzdGQ7DQoNCmludCBtYWluKCkNCnsNCiAgICBjb3V0PDwi6buE5bKp5LiA6IGMIjw8ZW5kbDsNCiAgICByZXR1cm4gMDsNCn0=",
result: {
status: 3,
output: "黄岩一职",
},
},
java: {
encoded:
"cHVibGljIGNsYXNzIE1haW4gew0KICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHsNCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCLpu4TlsqnkuIDogYwiKTsNCiAgICB9DQp9",
result: {
status: 3,
output: "黄岩一职",
},
},
python: {
encoded: "cHJpbnQoIum7hOWyqeS4gOiBjCIp",
result: {
status: 3,
output: "黄岩一职",
},
},
}

View File

@@ -1,6 +1,6 @@
export type LANGUAGE = "c" | "cpp" | "python" | "java"
export interface Code {
value: string
language: LANGUAGE
}
export type LANGUAGE = "c" | "cpp" | "python" | "java"
export interface Code {
value: string
language: LANGUAGE
}