refactor: 重构系统权限与设置管理,新增多类型配置能力
1. 重构权限码规范,将系统权限前缀从perm:system改为system: 2. 扩展系统设置模型,支持string/image/select/boolean四种配置类型 3. 新增设置项选项配置、图片上传功能 4. 重构初始化权限数据,拆分权限与系统设置权限结构 5. 重写前端系统设置页面,支持按类型渲染不同配置表单 6. 添加python-multipart依赖支持文件上传 遗留问题: 1.系统设置页面的添加设置按钮无法使用
This commit is contained in:
parent
01bda3d0cc
commit
82cf0192e8
@ -1,7 +1,11 @@
|
|||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException, File, UploadFile
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy import select, and_
|
from sqlalchemy import select, and_
|
||||||
from fastcrud import FastCRUD
|
from fastcrud import FastCRUD
|
||||||
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from database import get_db
|
from database import get_db
|
||||||
from models import SystemSetting, User
|
from models import SystemSetting, User
|
||||||
@ -18,6 +22,10 @@ router = APIRouter(prefix="/settings", tags=["settings"])
|
|||||||
# 创建FastCRUD实例
|
# 创建FastCRUD实例
|
||||||
setting_crud = FastCRUD(SystemSetting, SystemSettingResponse)
|
setting_crud = FastCRUD(SystemSetting, SystemSettingResponse)
|
||||||
|
|
||||||
|
# 图片存储目录
|
||||||
|
UPLOAD_DIR = Path(__file__).parent.parent.parent / "uploads"
|
||||||
|
UPLOAD_DIR.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/", response_model=SystemSettingResponse)
|
@router.post("/", response_model=SystemSettingResponse)
|
||||||
async def create_setting(
|
async def create_setting(
|
||||||
@ -36,6 +44,8 @@ async def create_setting(
|
|||||||
db_setting = SystemSetting(
|
db_setting = SystemSetting(
|
||||||
key=setting_data.key,
|
key=setting_data.key,
|
||||||
value=setting_data.value,
|
value=setting_data.value,
|
||||||
|
type=setting_data.type or "string",
|
||||||
|
options=setting_data.options,
|
||||||
description=setting_data.description,
|
description=setting_data.description,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -129,3 +139,39 @@ async def delete_setting(
|
|||||||
# 使用FastCRUD删除设置
|
# 使用FastCRUD删除设置
|
||||||
deleted = await setting_crud.delete(db, id=setting_id)
|
deleted = await setting_crud.delete(db, id=setting_id)
|
||||||
return {"message": "设置项删除成功"}
|
return {"message": "设置项删除成功"}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/upload")
|
||||||
|
async def upload_image(
|
||||||
|
file: UploadFile = File(...),
|
||||||
|
current_user: User = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
"""上传图片"""
|
||||||
|
# 检查文件类型
|
||||||
|
if not file.filename or not file.filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp')):
|
||||||
|
raise HTTPException(status_code=400, detail="只支持图片格式(png, jpg, jpeg, gif, webp)")
|
||||||
|
|
||||||
|
# 检查文件大小(2MB)
|
||||||
|
file_size = 0
|
||||||
|
chunk = await file.read(1024)
|
||||||
|
while chunk:
|
||||||
|
file_size += len(chunk)
|
||||||
|
if file_size > 2 * 1024 * 1024:
|
||||||
|
raise HTTPException(status_code=400, detail="文件大小不能超过2MB")
|
||||||
|
chunk = await file.read(1024)
|
||||||
|
|
||||||
|
# 重置文件指针
|
||||||
|
await file.seek(0)
|
||||||
|
|
||||||
|
# 生成文件名
|
||||||
|
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||||
|
ext = file.filename.split('.')[-1]
|
||||||
|
filename = f"setting_{timestamp}.{ext}"
|
||||||
|
file_path = UPLOAD_DIR / filename
|
||||||
|
|
||||||
|
# 保存文件
|
||||||
|
with open(file_path, "wb") as buffer:
|
||||||
|
shutil.copyfileobj(file.file, buffer)
|
||||||
|
|
||||||
|
# 返回文件路径
|
||||||
|
return {"url": f"/uploads/{filename}"}
|
||||||
|
|||||||
@ -50,49 +50,71 @@ async def init_permissions(db: AsyncSession):
|
|||||||
# 定义需要初始化的权限(树形结构)
|
# 定义需要初始化的权限(树形结构)
|
||||||
# parentid: 0 = 顶级模块, >0 = 子权限
|
# parentid: 0 = 顶级模块, >0 = 子权限
|
||||||
permission_tree = [
|
permission_tree = [
|
||||||
|
# ========================================
|
||||||
# 顶级模块
|
# 顶级模块
|
||||||
|
# ========================================
|
||||||
{"name": "权限管理", "code": "perm", "parentid": 0, "description": "权限管理模块"},
|
{"name": "权限管理", "code": "perm", "parentid": 0, "description": "权限管理模块"},
|
||||||
|
{"name": "系统设置", "code": "system", "parentid": 0, "description": "系统设置模块"},
|
||||||
|
|
||||||
# 二级子模块
|
# ========================================
|
||||||
|
# 权限管理 -> 二级子模块
|
||||||
|
# ========================================
|
||||||
{"name": "用户管理", "code": "perm:user", "parentid": 1, "description": "用户管理子模块"},
|
{"name": "用户管理", "code": "perm:user", "parentid": 1, "description": "用户管理子模块"},
|
||||||
{"name": "角色管理", "code": "perm:role", "parentid": 1, "description": "角色管理子模块"},
|
{"name": "角色管理", "code": "perm:role", "parentid": 1, "description": "角色管理子模块"},
|
||||||
{"name": "权限配置", "code": "perm:config", "parentid": 1, "description": "权限配置子模块"},
|
{"name": "权限配置", "code": "perm:config", "parentid": 1, "description": "权限配置子模块"},
|
||||||
{"name": "系统设置", "code": "perm:system", "parentid": 1, "description": "系统设置子模块"},
|
|
||||||
|
|
||||||
# 用户管理操作
|
# ========================================
|
||||||
{"name": "查看列表", "code": "perm:user:list", "parentid": 2, "description": "查看用户列表"},
|
# 系统设置 -> 二级子模块
|
||||||
{"name": "查看详情", "code": "perm:user:detail", "parentid": 2, "description": "查看用户详情"},
|
# ========================================
|
||||||
{"name": "搜索", "code": "perm:user:search", "parentid": 2, "description": "搜索用户"},
|
{"name": "基础配置", "code": "system:basic", "parentid": 2, "description": "系统基础配置"},
|
||||||
{"name": "创建", "code": "perm:user:create", "parentid": 2, "description": "创建新用户"},
|
{"name": "高级配置", "code": "system:advanced", "parentid": 2, "description": "系统高级配置"},
|
||||||
{"name": "编辑", "code": "perm:user:edit", "parentid": 2, "description": "编辑用户信息"},
|
|
||||||
{"name": "删除", "code": "perm:user:delete", "parentid": 2, "description": "删除用户"},
|
|
||||||
{"name": "导出", "code": "perm:user:export", "parentid": 2, "description": "导出用户数据"},
|
|
||||||
|
|
||||||
# 角色管理操作
|
# ========================================
|
||||||
{"name": "查看列表", "code": "perm:role:list", "parentid": 3, "description": "查看角色列表"},
|
# 用户管理操作(parentid=3)
|
||||||
{"name": "查看详情", "code": "perm:role:detail", "parentid": 3, "description": "查看角色详情"},
|
# ========================================
|
||||||
{"name": "搜索", "code": "perm:role:search", "parentid": 3, "description": "搜索角色"},
|
{"name": "查看列表", "code": "perm:user:list", "parentid": 3, "description": "查看用户列表"},
|
||||||
{"name": "创建", "code": "perm:role:create", "parentid": 3, "description": "创建新角色"},
|
{"name": "查看详情", "code": "perm:user:detail", "parentid": 3, "description": "查看用户详情"},
|
||||||
{"name": "编辑", "code": "perm:role:edit", "parentid": 3, "description": "编辑角色信息"},
|
{"name": "搜索", "code": "perm:user:search", "parentid": 3, "description": "搜索用户"},
|
||||||
{"name": "删除", "code": "perm:role:delete", "parentid": 3, "description": "删除角色"},
|
{"name": "创建", "code": "perm:user:create", "parentid": 3, "description": "创建新用户"},
|
||||||
{"name": "导出", "code": "perm:role:export", "parentid": 3, "description": "导出角色数据"},
|
{"name": "编辑", "code": "perm:user:edit", "parentid": 3, "description": "编辑用户信息"},
|
||||||
{"name": "分配权限", "code": "perm:role:assign", "parentid": 3, "description": "为角色分配权限"},
|
{"name": "删除", "code": "perm:user:delete", "parentid": 3, "description": "删除用户"},
|
||||||
|
{"name": "导出", "code": "perm:user:export", "parentid": 3, "description": "导出用户数据"},
|
||||||
|
{"name": "批量操作", "code": "perm:user:batch", "parentid": 3, "description": "批量操作用户"},
|
||||||
|
|
||||||
# 权限配置操作
|
# ========================================
|
||||||
{"name": "查看列表", "code": "perm:config:list", "parentid": 4, "description": "查看权限列表"},
|
# 角色管理操作(parentid=4)
|
||||||
{"name": "查看详情", "code": "perm:config:detail", "parentid": 4, "description": "查看权限详情"},
|
# ========================================
|
||||||
{"name": "搜索", "code": "perm:config:search", "parentid": 4, "description": "搜索权限"},
|
{"name": "查看列表", "code": "perm:role:list", "parentid": 4, "description": "查看角色列表"},
|
||||||
{"name": "创建", "code": "perm:config:create", "parentid": 4, "description": "创建新权限"},
|
{"name": "查看详情", "code": "perm:role:detail", "parentid": 4, "description": "查看角色详情"},
|
||||||
{"name": "编辑", "code": "perm:config:edit", "parentid": 4, "description": "编辑权限信息"},
|
{"name": "搜索", "code": "perm:role:search", "parentid": 4, "description": "搜索角色"},
|
||||||
{"name": "删除", "code": "perm:config:delete", "parentid": 4, "description": "删除权限"},
|
{"name": "创建", "code": "perm:role:create", "parentid": 4, "description": "创建新角色"},
|
||||||
{"name": "导出", "code": "perm:config:export", "parentid": 4, "description": "导岀权限数据"},
|
{"name": "编辑", "code": "perm:role:edit", "parentid": 4, "description": "编辑角色信息"},
|
||||||
|
{"name": "删除", "code": "perm:role:delete", "parentid": 4, "description": "删除角色"},
|
||||||
|
{"name": "导出", "code": "perm:role:export", "parentid": 4, "description": "导出角色数据"},
|
||||||
|
{"name": "分配权限", "code": "perm:role:assign", "parentid": 4, "description": "为角色分配权限"},
|
||||||
|
|
||||||
# 系统设置操作(parentid 为 5,对应系统设置子模块)
|
# ========================================
|
||||||
{"name": "查看列表", "code": "perm:system:list", "parentid": 5, "description": "查看系统设置列表"},
|
# 权限配置操作(parentid=5)
|
||||||
{"name": "查看详情", "code": "perm:system:detail", "parentid": 5, "description": "查看系统设置详情"},
|
# ========================================
|
||||||
{"name": "创建", "code": "perm:system:create", "parentid": 5, "description": "创建设置项"},
|
{"name": "查看列表", "code": "perm:config:list", "parentid": 5, "description": "查看权限列表"},
|
||||||
{"name": "编辑", "code": "perm:system:edit", "parentid": 5, "description": "编辑设置项"},
|
{"name": "查看详情", "code": "perm:config:detail", "parentid": 5, "description": "查看权限详情"},
|
||||||
{"name": "删除", "code": "perm:system:delete", "parentid": 5, "description": "删除设置项"},
|
{"name": "搜索", "code": "perm:config:search", "parentid": 5, "description": "搜索权限"},
|
||||||
|
{"name": "创建", "code": "perm:config:create", "parentid": 5, "description": "创建新权限"},
|
||||||
|
{"name": "编辑", "code": "perm:config:edit", "parentid": 5, "description": "编辑权限信息"},
|
||||||
|
{"name": "删除", "code": "perm:config:delete", "parentid": 5, "description": "删除权限"},
|
||||||
|
{"name": "导出", "code": "perm:config:export", "parentid": 5, "description": "导岀权限数据"},
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 系统设置 -> 基础配置操作(parentid=6)
|
||||||
|
# ========================================
|
||||||
|
{"name": "查看配置", "code": "system:basic:view", "parentid": 6, "description": "查看基础配置"},
|
||||||
|
{"name": "修改配置", "code": "system:basic:edit", "parentid": 6, "description": "修改基础配置"},
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# 系统设置 -> 高级配置操作(parentid=7)
|
||||||
|
# ========================================
|
||||||
|
{"name": "查看配置", "code": "system:advanced:view", "parentid": 7, "description": "查看高级配置"},
|
||||||
|
{"name": "修改配置", "code": "system:advanced:edit", "parentid": 7, "description": "修改高级配置"},
|
||||||
]
|
]
|
||||||
|
|
||||||
# 检查现有权限
|
# 检查现有权限
|
||||||
|
|||||||
@ -88,7 +88,9 @@ class SystemSetting(Base):
|
|||||||
__tablename__ = "system_setting"
|
__tablename__ = "system_setting"
|
||||||
id = Column(Integer, primary_key=True, index=True, comment="设置ID")
|
id = Column(Integer, primary_key=True, index=True, comment="设置ID")
|
||||||
key = Column(String(100), nullable=False, unique=True, comment="设置键名")
|
key = Column(String(100), nullable=False, unique=True, comment="设置键名")
|
||||||
value = Column(String(1000), nullable=False, comment="设置值")
|
value = Column(String(2000), nullable=False, comment="设置值")
|
||||||
|
type = Column(String(20), default="string", comment="类型:string/image/select/boolean")
|
||||||
|
options = Column(String(500), nullable=True, comment="下拉选项(用|分隔)")
|
||||||
description = Column(String(255), nullable=True, comment="设置描述")
|
description = Column(String(255), nullable=True, comment="设置描述")
|
||||||
createtime = Column(DateTime, default=datetime.utcnow, comment="创建时间")
|
createtime = Column(DateTime, default=datetime.utcnow, comment="创建时间")
|
||||||
updatetime = Column(
|
updatetime = Column(
|
||||||
|
|||||||
@ -28,4 +28,7 @@ asyncpg>=0.31.0
|
|||||||
redis>=7.2.0
|
redis>=7.2.0
|
||||||
|
|
||||||
# 验证码生成
|
# 验证码生成
|
||||||
captcha>=0.7.1
|
captcha>=0.7.1
|
||||||
|
|
||||||
|
# 文件上传
|
||||||
|
python-multipart>=0.0.9
|
||||||
@ -190,7 +190,9 @@ class SystemSettingBase(BaseModel):
|
|||||||
"""系统设置基础模型"""
|
"""系统设置基础模型"""
|
||||||
|
|
||||||
key: str = Field(..., max_length=100, description="设置键名")
|
key: str = Field(..., max_length=100, description="设置键名")
|
||||||
value: str = Field(..., max_length=1000, description="设置值")
|
value: str = Field(..., max_length=2000, description="设置值")
|
||||||
|
type: Optional[str] = Field("string", max_length=20, description="类型:string/image/select/boolean")
|
||||||
|
options: Optional[str] = Field(None, max_length=500, description="下拉选项(用|分隔)")
|
||||||
description: Optional[str] = Field(None, max_length=255, description="设置描述")
|
description: Optional[str] = Field(None, max_length=255, description="设置描述")
|
||||||
|
|
||||||
model_config = {"extra": "ignore"}
|
model_config = {"extra": "ignore"}
|
||||||
@ -212,6 +214,8 @@ class SystemSettingResponse(BaseModel):
|
|||||||
id: int = Field(..., description="设置ID")
|
id: int = Field(..., description="设置ID")
|
||||||
key: str = Field(..., description="设置键名")
|
key: str = Field(..., description="设置键名")
|
||||||
value: str = Field(..., description="设置值")
|
value: str = Field(..., description="设置值")
|
||||||
|
type: str = Field(..., description="类型")
|
||||||
|
options: Optional[str] = Field(None, description="下拉选项")
|
||||||
description: Optional[str] = Field(None, description="设置描述")
|
description: Optional[str] = Field(None, description="设置描述")
|
||||||
createtime: datetime = Field(..., description="创建时间")
|
createtime: datetime = Field(..., description="创建时间")
|
||||||
updatetime: datetime = Field(..., description="更新时间")
|
updatetime: datetime = Field(..., description="更新时间")
|
||||||
|
|||||||
@ -98,7 +98,7 @@ const hasPermissionPermission = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const hasSystemPermission = computed(() => {
|
const hasSystemPermission = computed(() => {
|
||||||
return auth.permissions.some(p => p.code.startsWith("perm:system"));
|
return auth.permissions.some(p => p.code.startsWith("system:"));
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasAnyPermission = computed(() => {
|
const hasAnyPermission = computed(() => {
|
||||||
|
|||||||
@ -1,25 +1,245 @@
|
|||||||
<template>
|
<template>
|
||||||
<fs-page>
|
<fs-page>
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding" />
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>系统设置管理</span>
|
||||||
|
<el-button type="primary" @click="openAddModal">添加设置</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table :data="settings" border style="width: 100%">
|
||||||
|
<el-table-column prop="id" label="ID" width="80" />
|
||||||
|
<el-table-column prop="key" label="设置键名" />
|
||||||
|
<el-table-column prop="value" label="设置值" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column prop="type" label="类型" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ getTypeLabel(scope.row.type) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="description" label="描述" />
|
||||||
|
<el-table-column prop="createtime" label="创建时间" width="180" />
|
||||||
|
<el-table-column label="操作" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button size="small" @click="openEditModal(scope.row)">编辑</el-button>
|
||||||
|
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 添加/编辑弹窗 -->
|
||||||
|
<el-dialog :title="isEdit ? '编辑设置' : '添加设置'" :visible.sync="showModal" width="600px">
|
||||||
|
<el-form :model="form" label-width="120px">
|
||||||
|
<el-form-item label="设置键名" prop="key">
|
||||||
|
<el-input v-model="form.key" placeholder="请输入设置键名" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="类型" prop="type">
|
||||||
|
<el-select v-model="form.type" placeholder="请选择类型">
|
||||||
|
<el-option label="字符串" value="string" />
|
||||||
|
<el-option label="图片" value="image" />
|
||||||
|
<el-option label="下拉列表" value="select" />
|
||||||
|
<el-option label="布尔值" value="boolean" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 字符串类型 -->
|
||||||
|
<el-form-item v-if="form.type === 'string'" label="设置值" prop="value">
|
||||||
|
<el-input v-model="form.value" type="textarea" :rows="3" placeholder="请输入值" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 图片类型 -->
|
||||||
|
<el-form-item v-if="form.type === 'image'" label="设置值" prop="value">
|
||||||
|
<el-upload
|
||||||
|
action="#"
|
||||||
|
accept="image/*"
|
||||||
|
list-type="picture-card"
|
||||||
|
:show-file-list="false"
|
||||||
|
:before-upload="handleImageUpload"
|
||||||
|
:on-remove="handleImageRemove"
|
||||||
|
>
|
||||||
|
<div v-if="!form.value">
|
||||||
|
<el-icon><UploadIcon /></el-icon>
|
||||||
|
<div>上传图片</div>
|
||||||
|
</div>
|
||||||
|
<img v-else :src="form.value" style="width: 100%; height: 100%" />
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 下拉列表类型 -->
|
||||||
|
<template v-if="form.type === 'select'">
|
||||||
|
<el-form-item label="选项配置" prop="options">
|
||||||
|
<el-input v-model="form.options" type="textarea" :rows="2" placeholder="多个选项用 | 分隔,如:选项1|选项2|选项3" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="设置值" prop="value">
|
||||||
|
<el-select v-model="form.value" placeholder="请选择">
|
||||||
|
<el-option v-for="opt in optionsList" :key="opt" :label="opt" :value="opt" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 布尔值类型 -->
|
||||||
|
<el-form-item v-if="form.type === 'boolean'" label="设置值" prop="value">
|
||||||
|
<el-switch v-model="form.booleanValue" active-text="开启" inactive-text="关闭" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="描述" prop="description">
|
||||||
|
<el-input v-model="form.description" type="textarea" :rows="2" placeholder="请输入描述" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showModal = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted } from "vue";
|
import { ref, computed, watch } from "vue";
|
||||||
import { useFs } from "@fast-crud/fast-crud";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import { createSettingCrudOptions } from "./setting-crud";
|
import { http } from "@/modules/admin/api/http";
|
||||||
|
import type { SettingRow } from "./setting-crud";
|
||||||
|
|
||||||
const { crudBinding, crudRef, crudExpose } = useFs({
|
const settings = ref<SettingRow[]>([]);
|
||||||
createCrudOptions: createSettingCrudOptions,
|
const showModal = ref(false);
|
||||||
|
const isEdit = ref(false);
|
||||||
|
|
||||||
|
const form = ref({
|
||||||
|
id: 0,
|
||||||
|
key: "",
|
||||||
|
value: "",
|
||||||
|
type: "string",
|
||||||
|
options: "",
|
||||||
|
description: "",
|
||||||
|
booleanValue: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
const optionsList = computed(() => {
|
||||||
crudExpose.doRefresh();
|
if (!form.value.options) return [];
|
||||||
|
return form.value.options.split("|").filter(Boolean).map((o) => o.trim());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(() => form.value.type, (newType) => {
|
||||||
|
if (newType === "boolean") {
|
||||||
|
form.value.booleanValue = form.value.value === "true";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTypeLabel = (type: string) => {
|
||||||
|
const types: Record<string, string> = {
|
||||||
|
string: "字符串",
|
||||||
|
image: "图片",
|
||||||
|
select: "下拉列表",
|
||||||
|
boolean: "布尔值",
|
||||||
|
};
|
||||||
|
return types[type] || type;
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await http.get<SettingRow[]>("/settings/");
|
||||||
|
settings.value = data;
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error("加载失败");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const openAddModal = () => {
|
||||||
|
isEdit.value = false;
|
||||||
|
form.value = {
|
||||||
|
id: 0,
|
||||||
|
key: "",
|
||||||
|
value: "",
|
||||||
|
type: "string",
|
||||||
|
options: "",
|
||||||
|
description: "",
|
||||||
|
booleanValue: false,
|
||||||
|
};
|
||||||
|
showModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const openEditModal = (row: SettingRow) => {
|
||||||
|
isEdit.value = true;
|
||||||
|
form.value = {
|
||||||
|
id: row.id,
|
||||||
|
key: row.key,
|
||||||
|
value: row.value,
|
||||||
|
type: row.type,
|
||||||
|
options: row.options || "",
|
||||||
|
description: row.description || "",
|
||||||
|
booleanValue: row.value === "true",
|
||||||
|
};
|
||||||
|
showModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleImageUpload = async (file: any) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file.raw);
|
||||||
|
try {
|
||||||
|
const response = await http.post("/settings/upload", formData, {
|
||||||
|
headers: { "Content-Type": "multipart/form-data" },
|
||||||
|
});
|
||||||
|
form.value.value = response.data.url;
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error("上传失败");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleImageRemove = () => {
|
||||||
|
form.value.value = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!form.value.key) {
|
||||||
|
ElMessage.error("请输入设置键名");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (form.value.type === "boolean") {
|
||||||
|
form.value.value = form.value.booleanValue ? "true" : "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (isEdit.value) {
|
||||||
|
await http.put(`/settings/${form.value.id}`, form.value);
|
||||||
|
ElMessage.success("修改成功");
|
||||||
|
} else {
|
||||||
|
await http.post("/settings/", form.value);
|
||||||
|
ElMessage.success("添加成功");
|
||||||
|
}
|
||||||
|
showModal.value = false;
|
||||||
|
await loadData();
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error.response?.data?.detail || "操作失败");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = async (row: SettingRow) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm("确定要删除吗?");
|
||||||
|
await http.delete(`/settings/${row.id}`);
|
||||||
|
ElMessage.success("删除成功");
|
||||||
|
await loadData();
|
||||||
|
} catch {
|
||||||
|
// 用户取消
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadData();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.setting-manage {
|
.flex {
|
||||||
height: 100%;
|
display: flex;
|
||||||
|
}
|
||||||
|
.items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.justify-between {
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import type { CreateCrudOptions } from "@fast-crud/fast-crud";
|
import type { CreateCrudOptions } from "@fast-crud/fast-crud";
|
||||||
|
import { dict } from "@fast-crud/fast-crud";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { http } from "@/modules/admin/api/http";
|
import { http } from "@/modules/admin/api/http";
|
||||||
|
|
||||||
@ -6,6 +7,8 @@ export type SettingRow = {
|
|||||||
id: number;
|
id: number;
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
type: string;
|
||||||
|
options?: string | null;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
createtime: string;
|
createtime: string;
|
||||||
updatetime: string;
|
updatetime: string;
|
||||||
@ -71,12 +74,42 @@ export const createSettingCrudOptions: CreateCrudOptions<SettingRow> = () => {
|
|||||||
rules: [{ required: true, message: "请输入设置键名", trigger: "blur" }],
|
rules: [{ required: true, message: "请输入设置键名", trigger: "blur" }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
type: {
|
||||||
|
title: "类型",
|
||||||
|
key: "type",
|
||||||
|
type: "dict-select",
|
||||||
|
column: { width: 120 },
|
||||||
|
dict: dict({
|
||||||
|
data: [
|
||||||
|
{ value: "string", label: "字符串" },
|
||||||
|
{ value: "image", label: "图片" },
|
||||||
|
{ value: "select", label: "下拉列表" },
|
||||||
|
{ value: "boolean", label: "布尔值" },
|
||||||
|
],
|
||||||
|
value: "value",
|
||||||
|
label: "label",
|
||||||
|
}),
|
||||||
|
form: {
|
||||||
|
value: "string",
|
||||||
|
rules: [{ required: true, message: "请选择类型", trigger: "change" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
value: {
|
value: {
|
||||||
title: "设置值",
|
title: "设置值",
|
||||||
key: "value",
|
key: "value",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
|
column: { width: 200 },
|
||||||
form: {
|
form: {
|
||||||
rules: [{ required: true, message: "请输入设置值", trigger: "blur" }],
|
rules: [{ required: true, message: "请输入值", trigger: "blur" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
title: "选项配置",
|
||||||
|
key: "options",
|
||||||
|
type: "textarea",
|
||||||
|
column: { show: false },
|
||||||
|
form: {
|
||||||
|
placeholder: "多个选项用 | 分隔,如:选项1|选项2|选项3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
|
|||||||
@ -48,7 +48,7 @@ const router = createRouter({
|
|||||||
{
|
{
|
||||||
path: "settings",
|
path: "settings",
|
||||||
name: "admin-settings",
|
name: "admin-settings",
|
||||||
meta: { title: "系统设置", permission: "perm:system" },
|
meta: { title: "系统设置", permission: "system:" },
|
||||||
component: () =>
|
component: () =>
|
||||||
import("@/modules/admin/views/settings/SettingManage.vue"),
|
import("@/modules/admin/views/settings/SettingManage.vue"),
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user