feat: 添加完整的前端管理系统 (VbenAdmin)

- 添加基于 VbenAdmin + Vue3 + Element Plus 的前端管理系统
- 包含完整的 UI 组件库和工具链
- 支持多应用架构 (web-ele, backend-mock, playground)
- 包含完整的开发规范和配置
- 修复 admin 目录的子模块问题,确保正确提交
This commit is contained in:
万物街
2025-08-23 13:24:04 +08:00
parent 43626e5bf2
commit dc6e9baec0
1406 changed files with 133197 additions and 1 deletions

View File

@@ -0,0 +1,621 @@
<template>
<div class="p-4">
<VbenTabs v-model:active-key="activeTab" type="card">
<!-- 登录方式设置 -->
<VbenTabPane key="methods" tab="登录方式">
<VbenForm
ref="methodsFormRef"
:schema="methodsFormSchema"
:form-options="{
layout: 'vertical',
labelCol: { span: 24 },
wrapperCol: { span: 24 },
}"
@submit="handleSaveMethods"
>
<template #submitButton>
<div class="flex gap-2">
<VbenButton type="primary" :loading="saveLoading" @click="handleSaveMethods">
保存配置
</VbenButton>
<VbenButton @click="handleResetMethods">
重置配置
</VbenButton>
</div>
</template>
</VbenForm>
</VbenTabPane>
<!-- 安全设置 -->
<VbenTabPane key="security" tab="安全设置">
<VbenForm
ref="securityFormRef"
:schema="securityFormSchema"
:form-options="{
layout: 'vertical',
labelCol: { span: 24 },
wrapperCol: { span: 24 },
}"
@submit="handleSaveSecurity"
>
<template #submitButton>
<div class="flex gap-2">
<VbenButton type="primary" :loading="saveLoading" @click="handleSaveSecurity">
保存配置
</VbenButton>
<VbenButton @click="handleResetSecurity">
重置配置
</VbenButton>
</div>
</template>
</VbenForm>
</VbenTabPane>
<!-- 第三方登录 -->
<VbenTabPane key="oauth" tab="第三方登录">
<VbenForm
ref="oauthFormRef"
:schema="oauthFormSchema"
:form-options="{
layout: 'vertical',
labelCol: { span: 24 },
wrapperCol: { span: 24 },
}"
@submit="handleSaveOauth"
>
<template #submitButton>
<div class="flex gap-2">
<VbenButton type="primary" :loading="saveLoading" @click="handleSaveOauth">
保存配置
</VbenButton>
<VbenButton @click="handleResetOauth">
重置配置
</VbenButton>
</div>
</template>
</VbenForm>
</VbenTabPane>
<!-- 注册设置 -->
<VbenTabPane key="register" tab="注册设置">
<VbenForm
ref="registerFormRef"
:schema="registerFormSchema"
:form-options="{
layout: 'vertical',
labelCol: { span: 24 },
wrapperCol: { span: 24 },
}"
@submit="handleSaveRegister"
>
<template #submitButton>
<div class="flex gap-2">
<VbenButton type="primary" :loading="saveLoading" @click="handleSaveRegister">
保存配置
</VbenButton>
<VbenButton @click="handleResetRegister">
重置配置
</VbenButton>
</div>
</template>
</VbenForm>
</VbenTabPane>
</VbenTabs>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { VbenForm, VbenButton, VbenTabs, VbenTabPane } from '@vben/components'
import { message } from 'ant-design-vue'
import type { FormSchema } from '@vben/types'
import {
getLoginConfigApi,
updateLoginConfigApi,
resetLoginConfigApi,
type LoginConfig,
} from '@/api/common/login'
const methodsFormRef = ref()
const securityFormRef = ref()
const oauthFormRef = ref()
const registerFormRef = ref()
const saveLoading = ref(false)
const activeTab = ref('methods')
// 登录方式表单配置
const methodsFormSchema: FormSchema[] = [
{
field: 'username_enabled',
label: '用户名登录',
component: 'Switch',
defaultValue: true,
helpMessage: '允许用户使用用户名进行登录',
},
{
field: 'mobile_enabled',
label: '手机号登录',
component: 'Switch',
defaultValue: true,
helpMessage: '允许用户使用手机号进行登录',
},
{
field: 'email_enabled',
label: '邮箱登录',
component: 'Switch',
defaultValue: true,
helpMessage: '允许用户使用邮箱进行登录',
},
{
field: 'sms_enabled',
label: '短信验证码登录',
component: 'Switch',
defaultValue: false,
helpMessage: '允许用户使用短信验证码进行登录',
},
{
field: 'oauth_enabled',
label: '第三方登录',
component: 'Switch',
defaultValue: false,
helpMessage: '启用微信、QQ等第三方登录方式',
},
{
field: 'guest_enabled',
label: '游客模式',
component: 'Switch',
defaultValue: false,
helpMessage: '允许游客访问部分功能,无需注册登录',
},
]
// 安全设置表单配置
const securityFormSchema: FormSchema[] = [
{
field: 'captcha_enabled',
label: '登录验证码',
component: 'Switch',
defaultValue: true,
helpMessage: '登录时需要输入图形验证码',
},
{
field: 'captcha_type',
label: '验证码类型',
component: 'RadioGroup',
show: ({ values }) => values.captcha_enabled,
componentProps: {
options: [
{ label: '图形验证码', value: 'image' },
{ label: '滑动验证码', value: 'slide' },
{ label: '点击验证码', value: 'click' },
],
},
defaultValue: 'image',
},
{
field: 'max_fail_attempts',
label: '最大登录失败次数',
component: 'InputNumber',
required: true,
componentProps: {
min: 3,
max: 20,
addonAfter: '次',
},
defaultValue: 5,
helpMessage: '超过此次数将锁定账户',
},
{
field: 'lock_duration',
label: '账户锁定时间',
component: 'InputNumber',
required: true,
componentProps: {
min: 5,
max: 1440,
addonAfter: '分钟',
},
defaultValue: 30,
helpMessage: '账户被锁定后的解锁时间',
},
{
field: 'password_strength_enabled',
label: '密码强度检查',
component: 'Switch',
defaultValue: true,
helpMessage: '强制用户使用强密码',
},
{
field: 'password_min_length',
label: '密码最小长度',
component: 'InputNumber',
show: ({ values }) => values.password_strength_enabled,
componentProps: {
min: 6,
max: 20,
addonAfter: '位',
},
defaultValue: 8,
},
{
field: 'password_complexity',
label: '密码复杂度要求',
component: 'CheckboxGroup',
show: ({ values }) => values.password_strength_enabled,
componentProps: {
options: [
{ label: '包含大写字母', value: 'uppercase' },
{ label: '包含小写字母', value: 'lowercase' },
{ label: '包含数字', value: 'number' },
{ label: '包含特殊字符', value: 'special' },
],
},
defaultValue: ['lowercase', 'number'],
},
{
field: 'password_expire_enabled',
label: '强制定期修改密码',
component: 'Switch',
defaultValue: false,
helpMessage: '强制用户定期修改密码',
},
{
field: 'password_expire_days',
label: '密码有效期',
component: 'InputNumber',
show: ({ values }) => values.password_expire_enabled,
componentProps: {
min: 30,
max: 365,
addonAfter: '天',
},
defaultValue: 90,
},
{
field: 'single_sign_on_enabled',
label: '单点登录',
component: 'Switch',
defaultValue: false,
helpMessage: '同一账户只能在一个设备上登录',
},
]
// 第三方登录表单配置
const oauthFormSchema: FormSchema[] = [
{
field: 'wechat_enabled',
label: '启用微信登录',
component: 'Switch',
defaultValue: false,
},
{
field: 'wechat_app_id',
label: '微信应用ID',
component: 'Input',
show: ({ values }) => values.wechat_enabled,
required: true,
colProps: { span: 12 },
},
{
field: 'wechat_secret',
label: '微信应用密钥',
component: 'InputPassword',
show: ({ values }) => values.wechat_enabled,
required: true,
colProps: { span: 12 },
},
{
field: 'wechat_redirect_uri',
label: '微信回调地址',
component: 'Input',
show: ({ values }) => values.wechat_enabled,
helpMessage: '微信登录授权回调地址',
},
{
field: 'qq_enabled',
label: '启用QQ登录',
component: 'Switch',
defaultValue: false,
},
{
field: 'qq_app_id',
label: 'QQ应用ID',
component: 'Input',
show: ({ values }) => values.qq_enabled,
required: true,
colProps: { span: 12 },
},
{
field: 'qq_secret',
label: 'QQ应用密钥',
component: 'InputPassword',
show: ({ values }) => values.qq_enabled,
required: true,
colProps: { span: 12 },
},
{
field: 'qq_redirect_uri',
label: 'QQ回调地址',
component: 'Input',
show: ({ values }) => values.qq_enabled,
helpMessage: 'QQ登录授权回调地址',
},
{
field: 'github_enabled',
label: '启用GitHub登录',
component: 'Switch',
defaultValue: false,
},
{
field: 'github_client_id',
label: 'GitHub客户端ID',
component: 'Input',
show: ({ values }) => values.github_enabled,
required: true,
colProps: { span: 12 },
},
{
field: 'github_secret',
label: 'GitHub客户端密钥',
component: 'InputPassword',
show: ({ values }) => values.github_enabled,
required: true,
colProps: { span: 12 },
},
{
field: 'github_redirect_uri',
label: 'GitHub回调地址',
component: 'Input',
show: ({ values }) => values.github_enabled,
helpMessage: 'GitHub登录授权回调地址',
},
]
// 注册设置表单配置
const registerFormSchema: FormSchema[] = [
{
field: 'register_enabled',
label: '开放注册',
component: 'Switch',
defaultValue: true,
helpMessage: '是否允许用户注册新账户',
},
{
field: 'register_methods',
label: '注册方式',
component: 'CheckboxGroup',
show: ({ values }) => values.register_enabled,
componentProps: {
options: [
{ label: '用户名注册', value: 'username' },
{ label: '手机号注册', value: 'mobile' },
{ label: '邮箱注册', value: 'email' },
],
},
defaultValue: ['username', 'mobile'],
},
{
field: 'register_verification',
label: '注册验证方式',
component: 'RadioGroup',
show: ({ values }) => values.register_enabled,
componentProps: {
options: [
{ label: '无需验证', value: 'none' },
{ label: '邮箱验证', value: 'email' },
{ label: '短信验证', value: 'sms' },
{ label: '人工审核', value: 'manual' },
],
},
defaultValue: 'sms',
},
{
field: 'register_captcha_enabled',
label: '注册验证码',
component: 'Switch',
show: ({ values }) => values.register_enabled,
defaultValue: true,
helpMessage: '注册时需要输入验证码',
},
{
field: 'agreement_required',
label: '用户协议',
component: 'Switch',
show: ({ values }) => values.register_enabled,
defaultValue: true,
helpMessage: '用户注册时是否必须同意用户协议',
},
{
field: 'agreement_content',
label: '协议内容',
component: 'InputTextArea',
show: ({ values }) => values.register_enabled && values.agreement_required,
componentProps: {
rows: 6,
placeholder: '请输入用户协议内容',
},
},
{
field: 'default_role',
label: '默认用户组',
component: 'Select',
show: ({ values }) => values.register_enabled,
componentProps: {
options: [
{ label: '普通用户', value: 'user' },
{ label: 'VIP用户', value: 'vip' },
{ label: '会员', value: 'member' },
],
},
defaultValue: 'user',
},
{
field: 'reward_enabled',
label: '注册奖励',
component: 'Switch',
show: ({ values }) => values.register_enabled,
defaultValue: true,
helpMessage: '新用户注册时给予奖励',
},
{
field: 'reward_points',
label: '奖励积分',
component: 'InputNumber',
show: ({ values }) => values.register_enabled && values.reward_enabled,
componentProps: {
min: 0,
},
defaultValue: 100,
colProps: { span: 12 },
},
{
field: 'reward_balance',
label: '奖励余额',
component: 'InputNumber',
show: ({ values }) => values.register_enabled && values.reward_enabled,
componentProps: {
min: 0,
precision: 2,
addonAfter: '元',
},
defaultValue: 0,
colProps: { span: 12 },
},
]
// 加载配置
const loadConfig = async () => {
try {
const data = await getLoginConfigApi()
methodsFormRef.value?.setFieldsValue(data.methods || {})
securityFormRef.value?.setFieldsValue(data.security || {})
oauthFormRef.value?.setFieldsValue(data.oauth || {})
registerFormRef.value?.setFieldsValue(data.register || {})
} catch (error) {
message.error('加载配置失败')
}
}
// 保存登录方式配置
const handleSaveMethods = async () => {
try {
const values = await methodsFormRef.value?.validate()
if (!values) return
saveLoading.value = true
await updateLoginConfigApi({ type: 'methods', config: values })
message.success('登录方式配置保存成功')
} catch (error) {
message.error('保存失败')
} finally {
saveLoading.value = false
}
}
// 保存安全设置配置
const handleSaveSecurity = async () => {
try {
const values = await securityFormRef.value?.validate()
if (!values) return
saveLoading.value = true
await updateLoginConfigApi({ type: 'security', config: values })
message.success('安全设置配置保存成功')
} catch (error) {
message.error('保存失败')
} finally {
saveLoading.value = false
}
}
// 保存第三方登录配置
const handleSaveOauth = async () => {
try {
const values = await oauthFormRef.value?.validate()
if (!values) return
saveLoading.value = true
await updateLoginConfigApi({ type: 'oauth', config: values })
message.success('第三方登录配置保存成功')
} catch (error) {
message.error('保存失败')
} finally {
saveLoading.value = false
}
}
// 保存注册设置配置
const handleSaveRegister = async () => {
try {
const values = await registerFormRef.value?.validate()
if (!values) return
saveLoading.value = true
await updateLoginConfigApi({ type: 'register', config: values })
message.success('注册设置配置保存成功')
} catch (error) {
message.error('保存失败')
} finally {
saveLoading.value = false
}
}
// 重置配置
const handleResetMethods = async () => {
try {
await resetLoginConfigApi('methods')
await loadConfig()
message.success('登录方式配置已重置')
} catch (error) {
message.error('重置失败')
}
}
const handleResetSecurity = async () => {
try {
await resetLoginConfigApi('security')
await loadConfig()
message.success('安全设置配置已重置')
} catch (error) {
message.error('重置失败')
}
}
const handleResetOauth = async () => {
try {
await resetLoginConfigApi('oauth')
await loadConfig()
message.success('第三方登录配置已重置')
} catch (error) {
message.error('重置失败')
}
}
const handleResetRegister = async () => {
try {
await resetLoginConfigApi('register')
await loadConfig()
message.success('注册设置配置已重置')
} catch (error) {
message.error('重置失败')
}
}
onMounted(() => {
loadConfig()
})
</script>
<style scoped>
.p-4 {
padding: 16px;
}
.flex {
display: flex;
}
.gap-2 {
gap: 8px;
}
</style>