use default props
Some checks failed
Deploy / deploy (build, debian, 22, /root/OJDeploy/data/clientnext) (push) Has been cancelled
Deploy / deploy (build:staging, school, 8822, /root/OJ/data/dist) (push) Has been cancelled

This commit is contained in:
2026-06-06 05:49:02 -06:00
parent 31d7f4d274
commit 4b05086ba1
13 changed files with 63 additions and 80 deletions

View File

@@ -60,7 +60,7 @@ import { useAIStore } from "oj/store/ai"
import { parseTime } from "utils/functions" import { parseTime } from "utils/functions"
const aiStore = useAIStore() const aiStore = useAIStore()
const containerRef = ref<HTMLElement>() const containerRef = useTemplateRef<HTMLElement>("containerRef")
const CELL_SIZE = 12 const CELL_SIZE = 12
const CELL_GAP = 3 const CELL_GAP = 3

View File

@@ -31,9 +31,7 @@ interface Props {
isConnected?: boolean // WebSocket 实际的连接状态(已建立/未建立) isConnected?: boolean // WebSocket 实际的连接状态(已建立/未建立)
} }
const props = withDefaults(defineProps<Props>(), { const { storageKey, isConnected = false } = defineProps<Props>()
isConnected: false,
})
// 注入同步状态 // 注入同步状态
const syncStatus = injectSyncStatus() const syncStatus = injectSyncStatus()
@@ -102,7 +100,7 @@ const reset = () => {
problem.value!.template[codeStore.code.language] || problem.value!.template[codeStore.code.language] ||
SOURCES[codeStore.code.language], SOURCES[codeStore.code.language],
) )
storage.remove(props.storageKey) storage.remove(storageKey)
message.success("代码重置成功") message.success("代码重置成功")
} }
@@ -228,7 +226,7 @@ onMounted(() => {
/> />
<!-- 同步状态标签 --> <!-- 同步状态标签 -->
<template v-if="props.isConnected"> <template v-if="isConnected">
<n-tag v-if="syncStatus.otherUser.value" type="info"> <n-tag v-if="syncStatus.otherUser.value" type="info">
{{ SYNC_MESSAGES.SYNCING_WITH(syncStatus.otherUser.value.name) }} {{ SYNC_MESSAGES.SYNCING_WITH(syncStatus.otherUser.value.name) }}
</n-tag> </n-tag>

View File

@@ -67,7 +67,7 @@
{{ content }} {{ content }}
</n-form-item> </n-form-item>
<n-button <n-button
v-if="hasCommented && props.showStatistics" v-if="hasCommented && showStatistics"
type="primary" type="primary"
@click="getComments" @click="getComments"
> >
@@ -77,7 +77,7 @@
提交 提交
</n-button> </n-button>
</n-form> </n-form>
<div v-if="props.showStatistics"> <div v-if="showStatistics">
<n-descriptions <n-descriptions
class="list" class="list"
v-if="count" v-if="count"
@@ -117,9 +117,7 @@ interface Props {
showStatistics?: boolean showStatistics?: boolean
} }
const props = withDefaults(defineProps<Props>(), { const { showStatistics = true } = defineProps<Props>()
showStatistics: true,
})
const userStore = useUserStore() const userStore = useUserStore()
const problemStore = useProblemStore() const problemStore = useProblemStore()

View File

@@ -40,10 +40,7 @@ interface Props {
problemSetId?: string problemSetId?: string
} }
const props = withDefaults(defineProps<Props>(), { const { problemID, contestID = "", problemSetId = "" } = defineProps<Props>()
contestID: "",
problemSetId: "",
})
const errMsg = ref("无数据") const errMsg = ref("无数据")
const route = useRoute() const route = useRoute()
@@ -67,7 +64,7 @@ const tabOptions = computed(() => {
options.push("editor") options.push("editor")
} }
options.push("info") options.push("info")
if (!props.contestID) { if (!contestID) {
options.push("comment") options.push("comment")
} }
if (myFlowchartStore.showing) { if (myFlowchartStore.showing) {
@@ -110,7 +107,7 @@ watch(
async function init() { async function init() {
screenModeStore.resetScreenMode() screenModeStore.resetScreenMode()
try { try {
const res = await getProblem(props.problemID, props.contestID) const res = await getProblem(problemID, contestID)
problem.value = res.data problem.value = res.data
} catch (err: any) { } catch (err: any) {
problem.value = null problem.value = null
@@ -120,7 +117,7 @@ async function init() {
} }
} }
onMounted(init) onMounted(init)
watch(() => props.problemID, init) watch(() => problemID, init)
onBeforeUnmount(() => { onBeforeUnmount(() => {
problem.value = null problem.value = null
errMsg.value = "无数据" errMsg.value = "无数据"
@@ -159,15 +156,15 @@ watch(isMobile, (value) => {
<n-tab-pane <n-tab-pane
name="info" name="info"
tab="题目统计" tab="题目统计"
:disabled="!!props.problemSetId" :disabled="!!problemSetId"
> >
<ProblemInfo /> <ProblemInfo />
</n-tab-pane> </n-tab-pane>
<n-tab-pane <n-tab-pane
v-if="!props.contestID" v-if="!contestID"
name="comment" name="comment"
tab="题目点评" tab="题目点评"
:disabled="!!props.problemSetId" :disabled="!!problemSetId"
> >
<ProblemComment /> <ProblemComment />
</n-tab-pane> </n-tab-pane>
@@ -181,7 +178,7 @@ watch(isMobile, (value) => {
<n-tab-pane <n-tab-pane
name="submission" name="submission"
tab="我的提交" tab="我的提交"
:disabled="!!props.problemSetId" :disabled="!!problemSetId"
> >
<ProblemSubmission /> <ProblemSubmission />
</n-tab-pane> </n-tab-pane>
@@ -215,15 +212,15 @@ watch(isMobile, (value) => {
<n-tab-pane <n-tab-pane
name="info" name="info"
tab="题目统计" tab="题目统计"
:disabled="!!props.problemSetId" :disabled="!!problemSetId"
> >
<ProblemInfo /> <ProblemInfo />
</n-tab-pane> </n-tab-pane>
<n-tab-pane <n-tab-pane
v-if="!props.contestID" v-if="!contestID"
name="comment" name="comment"
tab="题目点评" tab="题目点评"
:disabled="!!props.problemSetId" :disabled="!!problemSetId"
> >
<ProblemComment /> <ProblemComment />
</n-tab-pane> </n-tab-pane>
@@ -237,7 +234,7 @@ watch(isMobile, (value) => {
<n-tab-pane <n-tab-pane
name="submission" name="submission"
tab="我的提交" tab="我的提交"
:disabled="!!props.problemSetId" :disabled="!!problemSetId"
> >
<ProblemSubmission /> <ProblemSubmission />
</n-tab-pane> </n-tab-pane>
@@ -256,14 +253,14 @@ watch(isMobile, (value) => {
<n-tab-pane name="editor" tab="代码"> <n-tab-pane name="editor" tab="代码">
<component :is="inProblem ? ProblemEditor : ContestEditor" /> <component :is="inProblem ? ProblemEditor : ContestEditor" />
</n-tab-pane> </n-tab-pane>
<n-tab-pane name="info" tab="统计" :disabled="!!props.problemSetId"> <n-tab-pane name="info" tab="统计" :disabled="!!problemSetId">
<ProblemInfo /> <ProblemInfo />
</n-tab-pane> </n-tab-pane>
<n-tab-pane <n-tab-pane
v-if="!props.contestID" v-if="!contestID"
name="comment" name="comment"
tab="点评" tab="点评"
:disabled="!!props.problemSetId" :disabled="!!problemSetId"
> >
<ProblemComment /> <ProblemComment />
</n-tab-pane> </n-tab-pane>
@@ -274,7 +271,7 @@ watch(isMobile, (value) => {
> >
<MyFlowchartTab /> <MyFlowchartTab />
</n-tab-pane> </n-tab-pane>
<n-tab-pane name="submission" tab="提交" :disabled="!!props.problemSetId"> <n-tab-pane name="submission" tab="提交" :disabled="!!problemSetId">
<ProblemSubmission /> <ProblemSubmission />
</n-tab-pane> </n-tab-pane>
</n-tabs> </n-tabs>

View File

@@ -28,7 +28,7 @@ const isDefaultAvatar = computed(
() => profile.value?.avatar.endsWith("default.png") ?? true, () => profile.value?.avatar.endsWith("default.png") ?? true,
) )
const problemsFlexRef = ref<HTMLElement | null>(null) const problemsFlexRef = useTemplateRef<HTMLElement>("problemsFlexRef")
const itemsPerRow = ref(8) const itemsPerRow = ref(8)
function updateItemsPerRow() { function updateItemsPerRow() {

View File

@@ -22,21 +22,19 @@ interface Props {
placeholder?: string placeholder?: string
} }
const props = withDefaults(defineProps<Props>(), { const {
language: "Python3", language = "Python3",
fontSize: 20, fontSize = 20,
height: "100%", height = "100%",
readonly: false, readonly = false,
placeholder: "", placeholder = "",
}) } = defineProps<Props>()
const { readonly, placeholder, height, fontSize } = toRefs(props)
const code = defineModel<string>("value") const code = defineModel<string>("value")
const isDark = useDark() const isDark = useDark()
const langExtension = computed(() => { const langExtension = computed(() => {
return ["Python2", "Python3"].includes(props.language) ? python() : cpp() return ["Python2", "Python3"].includes(language) ? python() : cpp()
}) })
const extensions = computed(() => [ const extensions = computed(() => [
@@ -45,7 +43,7 @@ const extensions = computed(() => [
bracketMatching(), bracketMatching(),
closeBrackets(), closeBrackets(),
autocompletion({ autocompletion({
override: [enhanceCompletion(props.language), completeAnyWord], override: [enhanceCompletion(language), completeAnyWord],
}), }),
isDark.value ? oneDark : smoothy, isDark.value ? oneDark : smoothy,
]) ])

View File

@@ -78,7 +78,7 @@ const emit = defineEmits<Emits>()
const isHovered = ref(false) const isHovered = ref(false)
const isEditing = ref(false) const isEditing = ref(false)
const editText = ref("") const editText = ref("")
const editInput = ref<HTMLInputElement>() const editInput = useTemplateRef<HTMLInputElement>("editInput")
// 定时器和事件处理器 // 定时器和事件处理器
let hideTimeout: ReturnType<typeof setTimeout> | null = null let hideTimeout: ReturnType<typeof setTimeout> | null = null

View File

@@ -26,9 +26,7 @@ interface Props {
height?: string height?: string
} }
withDefaults(defineProps<Props>(), { const { height = "calc(100vh - 133px)" } = defineProps<Props>()
height: "calc(100vh - 133px)",
})
// Vue Flow 实例 // Vue Flow 实例
const { addEdges, removeNodes, removeEdges } = useVueFlow() const { addEdges, removeNodes, removeEdges } = useVueFlow()

View File

@@ -17,7 +17,7 @@ const {
loginLoading: isLoading, loginLoading: isLoading,
loginError: msg, loginError: msg,
} = storeToRefs(authStore) } = storeToRefs(authStore)
const loginRef = ref() const loginRef = useTemplateRef("loginRef")
const classUserOptions = ref<SelectOption[]>([]) const classUserOptions = ref<SelectOption[]>([])
const classUserLoading = ref(false) const classUserLoading = ref(false)
const isClassLogin = computed(() => Boolean(form.value.class)) const isClassLogin = computed(() => Boolean(form.value.class))

View File

@@ -7,17 +7,14 @@ interface Props {
page: number page: number
} }
const props = withDefaults(defineProps<Props>(), { const { total, limit: initialLimit = 10, page: initialPage = 1 } = defineProps<Props>()
limit: 10,
page: 1,
})
const emit = defineEmits(["update:limit", "update:page"]) const emit = defineEmits(["update:limit", "update:page"])
const { isDesktop } = useBreakpoints() const { isDesktop } = useBreakpoints()
const limit = ref(props.limit) const limit = ref(initialLimit)
const page = ref(props.page) const page = ref(initialPage)
const sizes = [10, 30, 50] const sizes = [10, 30, 50]
watch(limit, () => emit("update:limit", limit)) watch(limit, () => emit("update:limit", limit))
@@ -26,9 +23,9 @@ watch(page, () => emit("update:page", page))
<template> <template>
<n-pagination <n-pagination
v-if="props.total" v-if="total"
class="right margin" class="right margin"
:item-count="props.total" :item-count="total"
v-model:page="page" v-model:page="page"
v-model:page-size="limit" v-model:page-size="limit"
:page-sizes="sizes" :page-sizes="sizes"

View File

@@ -12,7 +12,7 @@ const {
signupError: msg, signupError: msg,
captchaSrc, captchaSrc,
} = storeToRefs(authStore) } = storeToRefs(authStore)
const signupRef = ref() const signupRef = useTemplateRef("signupRef")
const rules: FormRules = { const rules: FormRules = {
username: [{ required: true, message: "用户名必填", trigger: "blur" }], username: [{ required: true, message: "用户名必填", trigger: "blur" }],

View File

@@ -36,15 +36,15 @@ interface Props {
placeholder?: string placeholder?: string
} }
const props = withDefaults(defineProps<Props>(), { const {
language: "Python3", sync,
fontSize: 20, problem,
height: "100%", language = "Python3",
readonly: false, fontSize = 20,
placeholder: "", height = "100%",
}) readonly = false,
placeholder = "",
const { readonly, placeholder, height, fontSize } = toRefs(props) } = defineProps<Props>()
const code = defineModel<string>("value") const code = defineModel<string>("value")
const emit = defineEmits<{ const emit = defineEmits<{
@@ -57,7 +57,7 @@ const emit = defineEmits<{
const { isDesktop } = useBreakpoints() const { isDesktop } = useBreakpoints()
const langExtension = computed((): Extension => { const langExtension = computed((): Extension => {
return ["Python2", "Python3"].includes(props.language) ? python() : cpp() return ["Python2", "Python3"].includes(language) ? python() : cpp()
}) })
const extensions = computed(() => [ const extensions = computed(() => [
@@ -67,7 +67,7 @@ const extensions = computed(() => [
closeBrackets(), closeBrackets(),
isDark.value ? oneDark : smoothy, isDark.value ? oneDark : smoothy,
autocompletion({ autocompletion({
override: [enhanceCompletion(props.language), completeAnyWord], override: [enhanceCompletion(language), completeAnyWord],
}), }),
getInitialExtension(), getInitialExtension(),
]) ])
@@ -85,12 +85,12 @@ const cleanupSyncResources = () => {
} }
const initSync = async () => { const initSync = async () => {
if (!editorView.value || !props.problem || !isDesktop.value) return if (!editorView.value || !problem || !isDesktop.value) return
cleanupSyncResources() cleanupSyncResources()
cleanupSync = await startSync({ cleanupSync = await startSync({
problemId: props.problem, problemId: problem,
editorView: editorView.value as EditorView, editorView: editorView.value as EditorView,
onStatusChange: (status) => { onStatusChange: (status) => {
// 处理需要断开同步的情况 // 处理需要断开同步的情况
@@ -108,13 +108,13 @@ const initSync = async () => {
const handleEditorReady = (payload: EditorReadyPayload) => { const handleEditorReady = (payload: EditorReadyPayload) => {
editorView.value = payload.view as EditorView editorView.value = payload.view as EditorView
if (props.sync) { if (sync) {
initSync() initSync()
} }
} }
watch( watch(
() => props.sync, () => sync,
(shouldSync) => { (shouldSync) => {
if (shouldSync) { if (shouldSync) {
initSync() initSync()
@@ -125,9 +125,9 @@ watch(
) )
watch( watch(
() => props.problem, () => problem,
(newProblem, oldProblem) => { (newProblem, oldProblem) => {
if (newProblem !== oldProblem && props.sync) { if (newProblem !== oldProblem && sync) {
initSync() initSync()
} }
}, },

View File

@@ -17,10 +17,7 @@ interface Props {
const rawHtml = defineModel<string>("value") const rawHtml = defineModel<string>("value")
type InsertFnType = (url: string, alt: string, href: string) => void type InsertFnType = (url: string, alt: string, href: string) => void
const props = withDefaults(defineProps<Props>(), { const { title, minHeight = 0, simple = false } = defineProps<Props>()
minHeight: 0,
simple: false,
})
const message = useMessage() const message = useMessage()
@@ -112,17 +109,17 @@ async function customUpload(file: File, insertFn: InsertFnType) {
</script> </script>
<template> <template>
<div class="title" v-if="props.title">{{ props.title }}</div> <div class="title" v-if="title">{{ title }}</div>
<div class="editorWrapper"> <div class="editorWrapper">
<Toolbar <Toolbar
class="toolbar" class="toolbar"
:editor="toolbarEditorRef" :editor="toolbarEditorRef"
:defaultConfig="props.simple ? toolbarConfigSimple : toolbarConfig" :defaultConfig="simple ? toolbarConfigSimple : toolbarConfig"
mode="simple" mode="simple"
/> />
<Editor <Editor
@click="onClick" @click="onClick"
:style="{ minHeight: props.minHeight + 'px' }" :style="{ minHeight: minHeight + 'px' }"
v-model="rawHtml" v-model="rawHtml"
:defaultConfig="editorConfig" :defaultConfig="editorConfig"
mode="simple" mode="simple"