feat(web): 申请页改用中文姓名,前端转拼音提交
- ApplyView 的'姓名'字段(2~10 个汉字)替代自定义用户名
- 前端经 pinyin-pro(toneType:none + surname:head 处理姓氏多音字)转拼音作为用户名
- 提交前兜底校验拼音用户名长度(后端规则 [a-z][a-z0-9]{1,31})
- alert 文案改为实时预览 '通过后自动创建账号 ext_<username>'
- 新增依赖 pinyin-pro@3.29.3
This commit is contained in:
Generated
+7
@@ -12,6 +12,7 @@
|
|||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"element-plus": "^2.9.3",
|
"element-plus": "^2.9.3",
|
||||||
"pinia": "^2.3.1",
|
"pinia": "^2.3.1",
|
||||||
|
"pinyin-pro": "^3.29.3",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.5.0"
|
"vue-router": "^4.5.0"
|
||||||
},
|
},
|
||||||
@@ -1830,6 +1831,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pinyin-pro": {
|
||||||
|
"version": "3.29.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/pinyin-pro/-/pinyin-pro-3.29.3.tgz",
|
||||||
|
"integrity": "sha512-+UU9bx6vfDw8amOJGHm0TE0rdQl8VPylsDWviQ5OOQ3e+on1xRP4OqDbiDuMT5OISgvfl/Y6ez1BBRaIP80GLQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.26",
|
"version": "8.5.26",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"element-plus": "^2.9.3",
|
"element-plus": "^2.9.3",
|
||||||
"pinia": "^2.3.1",
|
"pinia": "^2.3.1",
|
||||||
|
"pinyin-pro": "^3.29.3",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.5.0"
|
"vue-router": "^4.5.0"
|
||||||
},
|
},
|
||||||
|
|||||||
+36
-15
@@ -1,26 +1,24 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue'
|
import { computed, reactive, ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { pinyin } from 'pinyin-pro'
|
||||||
import * as api from '@/api'
|
import * as api from '@/api'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
username: '',
|
realName: '', // 中文姓名,提交时转换为拼音作为用户名
|
||||||
email: '',
|
email: '',
|
||||||
supervisor: '',
|
supervisor: '',
|
||||||
purpose: '',
|
purpose: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 前端校验:中文姓名、邮箱、挂靠老师、用途均在前端完成
|
||||||
const rules = {
|
const rules = {
|
||||||
username: [
|
realName: [
|
||||||
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
{ required: true, message: '请输入中文姓名', trigger: 'blur' },
|
||||||
{
|
{ pattern: /^[\u4e00-\u9fa5]{2,10}$/, message: '请输入 2~10 个汉字', trigger: 'blur' },
|
||||||
pattern: /^[a-z][a-z0-9_]{1,30}$/,
|
|
||||||
message: '小写字母开头,仅小写字母/数字/下划线,2~31 位',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
email: [
|
email: [
|
||||||
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
||||||
@@ -32,21 +30,44 @@ const rules = {
|
|||||||
|
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
|
|
||||||
|
// 姓名 → 拼音(小写、无空格;首字按姓氏读音处理多音字)
|
||||||
|
function nameToPinyin(name: string): string {
|
||||||
|
const parts = pinyin(name, { toneType: 'none', type: 'array', surname: 'head' })
|
||||||
|
return parts.join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实时预览将创建的账号名;姓名非法或未输入时返回空
|
||||||
|
const accountPreview = computed(() => {
|
||||||
|
const n = form.realName.trim()
|
||||||
|
if (!/^[\u4e00-\u9fa5]{2,10}$/.test(n)) return ''
|
||||||
|
return `ext_${nameToPinyin(n)}`
|
||||||
|
})
|
||||||
|
|
||||||
|
// 提交前的前端校验(姓名→拼音合法性兜底,防止姓名过长)
|
||||||
|
function validUsername(uname: string): boolean {
|
||||||
|
return /^[a-z][a-z0-9]{1,31}$/.test(uname)
|
||||||
|
}
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
const valid = await formRef.value?.validate().catch(() => false)
|
const valid = await formRef.value?.validate().catch(() => false)
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
|
const uname = nameToPinyin(form.realName.trim())
|
||||||
|
if (!validUsername(uname)) {
|
||||||
|
ElMessage.warning('姓名拼音过长,无法生成可用账号,请联系管理员')
|
||||||
|
return
|
||||||
|
}
|
||||||
submitting.value = true
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
await api.submitApproval({
|
await api.submitApproval({
|
||||||
username: form.username.trim(),
|
username: uname,
|
||||||
email: form.email.trim(),
|
email: form.email.trim(),
|
||||||
supervisor: form.supervisor.trim(),
|
supervisor: form.supervisor.trim(),
|
||||||
purpose: form.purpose.trim(),
|
purpose: form.purpose.trim(),
|
||||||
})
|
})
|
||||||
ElMessage.success('申请已提交,等待管理员审批(结果将邮件通知)')
|
ElMessage.success('申请已提交,等待管理员审批(结果将邮件通知)')
|
||||||
Object.assign(form, { username: '', email: '', supervisor: '', purpose: '' })
|
Object.assign(form, { realName: '', email: '', supervisor: '', purpose: '' })
|
||||||
} catch {
|
} catch {
|
||||||
// 拦截器已提示(如用户名已被占用)
|
// 拦截器已提示(如拼音与已有申请重名)
|
||||||
} finally {
|
} finally {
|
||||||
submitting.value = false
|
submitting.value = false
|
||||||
}
|
}
|
||||||
@@ -65,14 +86,14 @@ async function onSubmit() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-alert type="info" :closable="false" show-icon class="apply-tip">
|
<el-alert type="info" :closable="false" show-icon class="apply-tip">
|
||||||
通过后自动创建账号(用户名将带 <code>ext_</code> 前缀)。
|
通过后自动创建账号 {{ accountPreview || 'ext_<username>' }}
|
||||||
</el-alert>
|
</el-alert>
|
||||||
|
|
||||||
<el-divider />
|
<el-divider />
|
||||||
|
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="90px" @submit.prevent="onSubmit">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="90px" @submit.prevent="onSubmit">
|
||||||
<el-form-item label="用户名" prop="username">
|
<el-form-item label="姓名" prop="realName">
|
||||||
<el-input v-model="form.username" placeholder="如 zhangsan(自动成为 ext_zhangsan)" maxlength="31" />
|
<el-input v-model="form.realName" placeholder="输入中文姓名,如 张三" maxlength="10" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="邮箱" prop="email">
|
<el-form-item label="邮箱" prop="email">
|
||||||
<el-input v-model="form.email" placeholder="接收通知与 OTP 验证码" />
|
<el-input v-model="form.email" placeholder="接收通知与 OTP 验证码" />
|
||||||
|
|||||||
Reference in New Issue
Block a user