batch update
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
2025-10-08 00:46:49 +08:00
parent b8c622dde1
commit b14316b919
48 changed files with 1236 additions and 735 deletions

View File

@@ -7,7 +7,6 @@ import type { Extension } from "@codemirror/state"
import { LANGUAGE } from "utils/types"
import { oneDark } from "../themes/oneDark"
import { smoothy } from "../themes/smoothy"
interface Props {
language?: LANGUAGE
fontSize?: number

View File

@@ -1,20 +1,27 @@
<script setup lang="ts">
import { Icon } from "@iconify/vue"
import { RouterLink } from "vue-router"
import { isDesktop, isMobile } from "shared/composables/breakpoints"
import { toggleLogin, toggleSignup } from "shared/composables/modal"
import { screenMode, switchScreenMode } from "shared/composables/switchScreen"
import { useBreakpoints } from "shared/composables/breakpoints"
import { useAuthModalStore } from "shared/store/authModal"
import { useScreenModeStore } from "shared/store/screenMode"
import { logout } from "../api"
import { useConfigStore } from "../store/config"
import { useUserStore } from "../store/user"
const isDark = useDark()
const toggleDark = useToggle(isDark)
const userStore = useUserStore()
const configStore = useConfigStore()
const authStore = useAuthModalStore()
const screenModeStore = useScreenModeStore()
const route = useRoute()
const router = useRouter()
const { isMobile, isDesktop } = useBreakpoints()
const isDark = useDark()
// 从 store 中获取屏幕模式状态
const { screenMode } = storeToRefs(screenModeStore)
const names = [
"man-with-chinese-cap-1",
"cat-face",
@@ -213,7 +220,7 @@ function goHome() {
isDesktop &&
(route.name === 'problem' || route.name === 'contest problem')
"
@click="() => switchScreenMode()"
@click="() => screenModeStore.switchScreenMode()"
>
{{ screenMode }}
</n-button>
@@ -227,19 +234,23 @@ function goHome() {
</n-button>
</n-dropdown>
<n-flex align="center" v-else>
<n-button secondary type="primary" @click="toggleLogin(true)">
<n-button
secondary
type="primary"
@click="authStore.openLoginModal()"
>
登录
</n-button>
<n-button
tertiary
v-if="configStore.config?.allow_register"
@click="toggleSignup(true)"
@click="authStore.openSignupModal()"
>
注册
</n-button>
</n-flex>
</div>
<n-button :bordered="false" circle @click="toggleDark()">
<n-button :bordered="false" circle @click="isDark = !isDark">
<template #icon>
<Icon v-if="isDark" icon="twemoji:sun-behind-small-cloud"></Icon>
<Icon v-else icon="twemoji:cloud-with-lightning-and-rain"></Icon>

View File

@@ -1,19 +1,21 @@
<script setup lang="ts">
import { login } from "../api"
import { loginModal, toggleLogin, toggleSignup } from "../composables/modal"
import { storeToRefs } from "pinia"
import { useAuthModalStore } from "../store/authModal"
import { useConfigStore } from "../store/config"
import { useUserStore } from "../store/user"
const userStore = useUserStore()
const configStore = useConfigStore()
const authStore = useAuthModalStore()
const {
loginModalOpen,
loginForm: form,
loginLoading: isLoading,
loginError: msg,
} = storeToRefs(authStore)
const loginRef = ref()
const [isLoading, toggleLoading] = useToggle()
const msg = ref("")
const form = reactive({
class: "",
username: "",
password: "",
})
const classList = computed<SelectOption[]>(() => {
const defaults = [{ label: "没有我所在的班级", value: "" }]
const configs =
@@ -35,29 +37,29 @@ async function submit() {
loginRef.value!.validate(async (errors: FormRules | undefined) => {
if (!errors) {
try {
msg.value = ""
toggleLoading(true)
authStore.clearLoginError()
authStore.setLoginLoading(true)
const merged = {
username: form.username,
password: form.password,
username: form.value.username,
password: form.value.password,
}
if (form.class) {
merged.username = form.class + form.username
if (form.value.class) {
merged.username = form.value.class + form.value.username
}
await login(merged)
} catch (err: any) {
if (err.data === "Your account has been disabled") {
msg.value = "此账号已被封禁"
authStore.setLoginError("此账号已被封禁")
} else if (err.data === "Invalid username or password") {
msg.value = "用户名或密码不正确"
authStore.setLoginError("用户名或密码不正确")
} else {
msg.value = "无法登录"
authStore.setLoginError("无法登录")
}
} finally {
toggleLoading(false)
authStore.setLoginLoading(false)
}
if (!msg.value) {
toggleLogin(false)
authStore.closeLoginModal()
userStore.getMyProfile()
}
}
@@ -65,19 +67,18 @@ async function submit() {
}
function goSignup() {
toggleLogin(false)
toggleSignup(true)
authStore.switchToSignup()
}
onMounted(() => {
msg.value = ""
authStore.clearLoginError()
})
</script>
<template>
<n-modal
:mask-closable="false"
v-model:show="loginModal"
v-model:show="loginModalOpen"
preset="card"
title="登录"
style="width: 400px"

View File

@@ -10,7 +10,6 @@
import { MdEditor } from "md-editor-v3"
import "md-editor-v3/lib/style.css"
import { uploadImage } from "../../admin/api"
const isDark = useDark()
const modelValue = defineModel<string>("value")

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { isDesktop } from "shared/composables/breakpoints"
import { useBreakpoints } from "shared/composables/breakpoints"
interface Props {
total: number
@@ -16,6 +16,8 @@ const emit = defineEmits(["update:limit", "update:page"])
const route = useRoute()
const { isDesktop } = useBreakpoints()
const limit = ref(props.limit)
const page = ref(props.page)
const sizes = computed(() => {

View File

@@ -1,19 +1,18 @@
<script setup lang="ts">
import { getCaptcha, signup } from "../api"
import { signupModal, toggleLogin, toggleSignup } from "../composables/modal"
import { useUserStore } from "../store/user"
import { storeToRefs } from "pinia"
import { useAuthModalStore } from "../store/authModal"
const userStore = useUserStore()
const authStore = useAuthModalStore()
const {
signupModalOpen,
signupForm: form,
signupLoading: isLoading,
signupError: msg,
captchaSrc,
} = storeToRefs(authStore)
const signupRef = ref()
const captchaSrc = ref("")
const form = reactive({
username: "",
email: "",
password: "",
passwordAgain: "",
captcha: "",
})
const rules: FormRules = {
username: [{ required: true, message: "用户名必填", trigger: "blur" }],
@@ -26,7 +25,8 @@ const rules: FormRules = {
{ required: true, message: "密码必填", trigger: "blur" },
{ min: 6, max: 20, message: "长度在 6 到 20 位之间", trigger: "input" },
{
validator: (_: FormItemRule, value: string) => value === form.password,
validator: (_: FormItemRule, value: string) =>
value === form.value.password,
message: "两次密码输入不一致",
trigger: "blur",
},
@@ -36,43 +36,39 @@ const rules: FormRules = {
],
}
const [isLoading, toggleLoading] = useToggle()
const msg = ref("")
function goLogin() {
toggleLogin(true)
toggleSignup(false)
authStore.switchToLogin()
}
function submit() {
signupRef.value!.validate(async (errors: FormRules | undefined) => {
if (!errors) {
try {
msg.value = ""
toggleLoading(true)
authStore.clearSignupError()
authStore.setSignupLoading(true)
await signup({
username: form.username,
email: form.email,
password: form.password,
captcha: form.captcha,
username: form.value.username,
email: form.value.email,
password: form.value.password,
captcha: form.value.captcha,
})
} catch (err: any) {
if (err.data === "Invalid captcha") {
msg.value = "验证码不正确"
authStore.setSignupError("验证码不正确")
} else if (err.data === "Username already exists") {
msg.value = "用户名已存在"
authStore.setSignupError("用户名已存在")
} else if (err.data === "Email already exists") {
msg.value = "邮箱已存在"
authStore.setSignupError("邮箱已存在")
} else {
msg.value = "无法注册"
authStore.setSignupError("无法注册")
}
getCaptchaSrc()
form.captcha = ""
form.value.captcha = ""
} finally {
toggleLoading(false)
authStore.setSignupLoading(false)
}
if (!msg.value) {
toggleSignup(false)
authStore.closeSignupModal()
}
}
})
@@ -80,10 +76,10 @@ function submit() {
async function getCaptchaSrc() {
const res = await getCaptcha()
captchaSrc.value = res.data
authStore.setCaptchaSrc(res.data)
}
watch(signupModal, (v) => {
watch(signupModalOpen, (v) => {
if (v) getCaptchaSrc()
})
</script>
@@ -91,7 +87,7 @@ watch(signupModal, (v) => {
<template>
<n-modal
:mask-closable="false"
v-model:show="signupModal"
v-model:show="signupModalOpen"
preset="card"
title="注册"
style="width: 400px"

View File

@@ -8,7 +8,8 @@ import { LANGUAGE } from "utils/types"
import { oneDark } from "../themes/oneDark"
import { smoothy } from "../themes/smoothy"
import { useCodeSync, SYNC_ERROR_CODES } from "../composables/sync"
import { isDesktop } from "../composables/breakpoints"
import { useBreakpoints } from "../composables/breakpoints"
const isDark = useDark()
interface EditorReadyPayload {
view: EditorView
@@ -44,7 +45,7 @@ const emit = defineEmits<{
]
}>()
const isDark = useDark()
const { isDesktop } = useBreakpoints()
const styleTheme = EditorView.baseTheme({
"& .cm-scroller": { "font-family": "Monaco" },