diff --git a/.nvmrc b/.nvmrc
index 790e110..dc0bb0f 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-v20.10.0
+v22.12.0
diff --git a/.yarn/versions/7cefad94.yml b/.yarn/versions/7cefad94.yml
new file mode 100644
index 0000000..85ee0e5
--- /dev/null
+++ b/.yarn/versions/7cefad94.yml
@@ -0,0 +1,3 @@
+releases:
+ "@aoi-js/frontend": patch
+ "@aoi-js/server": patch
diff --git a/apps/frontend/src/components/user/UserAuthSms.vue b/apps/frontend/src/components/user/UserAuthSms.vue
index a020518..bc2886e 100644
--- a/apps/frontend/src/components/user/UserAuthSms.vue
+++ b/apps/frontend/src/components/user/UserAuthSms.vue
@@ -3,13 +3,23 @@
-
+
+
+ {{ t('action.send-otp') }}
+
diff --git a/apps/frontend/src/locales/en.yaml b/apps/frontend/src/locales/en.yaml
index 978422b..172c728 100644
--- a/apps/frontend/src/locales/en.yaml
+++ b/apps/frontend/src/locales/en.yaml
@@ -55,6 +55,7 @@ action:
fullscreen: Fullscreen
recommend-problem: Recommend Problem
select: Select
+ send-otp: Send OTP
term:
content: Content
diff --git a/apps/frontend/src/locales/zh-Hans.yml b/apps/frontend/src/locales/zh-Hans.yml
index 91cc2dd..24dc70d 100644
--- a/apps/frontend/src/locales/zh-Hans.yml
+++ b/apps/frontend/src/locales/zh-Hans.yml
@@ -55,6 +55,7 @@ action:
fullscreen: 全屏
recommend-problem: 推荐题目
select: 选择
+ send-otp: 发送验证码
term:
content: 内容
diff --git a/apps/frontend/src/utils/user/sms.ts b/apps/frontend/src/utils/user/sms.ts
index 9e309ba..d6ad7a6 100644
--- a/apps/frontend/src/utils/user/sms.ts
+++ b/apps/frontend/src/utils/user/sms.ts
@@ -1,7 +1,7 @@
-import { ref, type MaybeRef, toRef } from 'vue'
+import { ref, type MaybeRef, toRef, computed } from 'vue'
import { useI18n } from 'vue-i18n'
-import { useAsyncTask, withMessage } from '../async'
+import { noMessage, useAsyncTask, withMessage } from '../async'
import { http } from '../http'
import { useVaptcha } from '../vaptcha'
@@ -11,11 +11,21 @@ export function useChangePhone(userId: MaybeRef) {
const newPhone = ref('')
const code = ref('')
const userIdRef = toRef(userId)
+ const phoneRules = [
+ (value: string) => {
+ const re = /^1\d{10}$/
+ if (re.test(value)) return true
+ return t('hint.violate-phone-rule')
+ }
+ ]
+ const phoneValid = computed(() => phoneRules.every((rule) => rule(newPhone.value) === true))
const app = useAppState()
const { token } = useVaptcha({ onPass: (token) => sendTask.execute(token) })
const { t } = useI18n()
+ const codeSent = ref(false)
const sendTask = useAsyncTask(async (token: string) => {
+ if (!phoneValid.value) return noMessage()
await http.post(`user/${userIdRef.value}/preBind`, {
json: {
provider: 'sms',
@@ -26,6 +36,7 @@ export function useChangePhone(userId: MaybeRef) {
mfaToken: app.mfaToken
}
})
+ codeSent.value = true
return withMessage(t('msg.code-sent'))
})
const updateTask = useAsyncTask(async () => {
@@ -40,5 +51,5 @@ export function useChangePhone(userId: MaybeRef) {
}
})
})
- return { newPhone, code, token, sendTask, updateTask }
+ return { newPhone, code, token, sendTask, updateTask, phoneRules, phoneValid, codeSent }
}
diff --git a/apps/server/src/utils/package.ts b/apps/server/src/utils/package.ts
index cf63e0b..674d41d 100644
--- a/apps/server/src/utils/package.ts
+++ b/apps/server/src/utils/package.ts
@@ -1,3 +1,3 @@
-import packageJson from '../../package.json' assert { type: 'json' }
+import packageJson from '../../package.json' with { type: 'json' }
export { packageJson }
diff --git a/docker/dockerfiles/server.dockerfile b/docker/dockerfiles/server.dockerfile
index 092e224..eb0f418 100644
--- a/docker/dockerfiles/server.dockerfile
+++ b/docker/dockerfiles/server.dockerfile
@@ -1,4 +1,4 @@
-FROM node:20-alpine
+FROM node:22-alpine
ARG NODE_ENV=production
ENV NODE_ENV $NODE_ENV