feat(admin): 新增邀请码生成及注册校验功能
- 在管理员页面新增邀请码生成面板,支持限制使用次数和有效期 - 新增后端接口支持创建邀请码,邀请码存储在Redis并设置过期时间 - 用户注册接口新增邀请码参数,校验邀请码有效性和剩余使用次数 - 注册时成功使用邀请码后,Redis中对应邀请码的使用次数减1 - 登录接口及相关服务层逻辑新增邀请码字段支持 - 后端权限配置增加/admin路径的root角色校验 - 优化角色权限同步时Redis存储格式为列表类型 - 调整SaToken相关接口实现以支持角色ID转换逻辑
This commit is contained in:
@@ -8,3 +8,6 @@ export function createUser(data) {
|
||||
return axios.post('/admin/user/create', data)
|
||||
}
|
||||
|
||||
export function createInvitationCode(data) {
|
||||
return axios.post('/admin/user/create/invitation/code', data)
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
<el-form-item prop="password_repeat">
|
||||
<el-input v-model="form.password_repeat" type="password" maxlength="20" placeholder="重复密码" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="invitationCode">
|
||||
<el-input v-model="form.invitationCode" maxlength="6" placeholder="邀请码" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<div class="flex items-center gap-2 w-full">
|
||||
<el-input v-model="form.code" maxlength="6" placeholder="验证码" />
|
||||
@@ -86,6 +89,7 @@ const form = reactive({
|
||||
password: '',
|
||||
password_repeat: '',
|
||||
code: '',
|
||||
invitationCode: '',
|
||||
})
|
||||
|
||||
const rules = {
|
||||
@@ -143,6 +147,7 @@ async function userLogin() {
|
||||
name: form.name.trim(),
|
||||
password: form.password.trim(),
|
||||
code: form.code.trim(),
|
||||
invitationCode: form.invitationCode.trim()
|
||||
}
|
||||
const res = await login(payload)
|
||||
const data = res.data
|
||||
|
||||
@@ -31,6 +31,29 @@
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt-4">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<span>生成邀请码</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="inviteForm" :rules="inviteRules" ref="inviteFormRef" label-width="120px">
|
||||
<el-form-item label="使用次数限制" prop="limit">
|
||||
<el-input-number v-model="inviteForm.limit" :min="1" :max="9999" />
|
||||
</el-form-item>
|
||||
<el-form-item label="有效期(天)" prop="expire">
|
||||
<el-input-number v-model="inviteForm.expire" :min="1" :max="3650" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="inviteLoading" @click="submitInvite">生成邀请码</el-button>
|
||||
<el-button class="ml-2" @click="resetInvite">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div v-if="inviteCode" class="mt-2">
|
||||
<el-alert type="success" :closable="false" :title="`邀请码:${inviteCode}`" show-icon />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="createVisible" title="新增用户" width="420px">
|
||||
<el-form :model="createForm" :rules="rules" ref="createFormRef" label-width="80px">
|
||||
<el-form-item label="姓名" prop="name">
|
||||
@@ -57,7 +80,7 @@
|
||||
<script setup>
|
||||
import Header from '@/layouts/components/Header.vue'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { getUserList, createUser } from '@/api/admin'
|
||||
import { getUserList, createUser, createInvitationCode } from '@/api/admin'
|
||||
import { showMessage } from '@/composables/util.js'
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -144,4 +167,42 @@ onMounted(() => {
|
||||
fetchList()
|
||||
})
|
||||
|
||||
const inviteForm = reactive({ limit: 10, expire: 3 })
|
||||
const inviteFormRef = ref()
|
||||
const inviteLoading = ref(false)
|
||||
const inviteCode = ref('')
|
||||
const inviteRules = {
|
||||
limit: [{ required: true, message: '请输入使用次数限制', trigger: 'change' }],
|
||||
expire: [{ required: true, message: '请输入有效期', trigger: 'change' }],
|
||||
}
|
||||
|
||||
function resetInvite() {
|
||||
inviteForm.limit = 10
|
||||
inviteForm.expire = 3
|
||||
inviteCode.value = ''
|
||||
}
|
||||
|
||||
function submitInvite() {
|
||||
inviteFormRef.value?.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
inviteLoading.value = true
|
||||
try {
|
||||
const r = await createInvitationCode({ limit: inviteForm.limit, expire: inviteForm.expire })
|
||||
const d = r?.data
|
||||
if (d?.success) {
|
||||
inviteCode.value = d?.data?.invitationCode || ''
|
||||
if (inviteCode.value) {
|
||||
showMessage('邀请码生成成功', 'success')
|
||||
} else {
|
||||
showMessage('生成成功,但未返回邀请码', 'warning')
|
||||
}
|
||||
} else {
|
||||
showMessage(d?.message || '邀请码生成失败', 'error')
|
||||
}
|
||||
} finally {
|
||||
inviteLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user