feat(admin): 新增邀请码生成及注册校验功能

- 在管理员页面新增邀请码生成面板,支持限制使用次数和有效期
- 新增后端接口支持创建邀请码,邀请码存储在Redis并设置过期时间
- 用户注册接口新增邀请码参数,校验邀请码有效性和剩余使用次数
- 注册时成功使用邀请码后,Redis中对应邀请码的使用次数减1
- 登录接口及相关服务层逻辑新增邀请码字段支持
- 后端权限配置增加/admin路径的root角色校验
- 优化角色权限同步时Redis存储格式为列表类型
- 调整SaToken相关接口实现以支持角色ID转换逻辑
This commit is contained in:
lbw
2025-12-29 15:44:05 +08:00
parent bddf6c0936
commit 5858bf2ecc
14 changed files with 163 additions and 24 deletions

View File

@@ -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>