feat: PhotoWall 毕业照存储系统初始版本
后端: Go(Gin+GORM+MySQL+Redis) - 17张业务表(yz_pw_前缀), 自动迁移 - JWT认证(3小时) + 盐+MD5密码 + 图形验证码 - 班级CRUD/加入(8人姓名验证/邀请码)/审核/30天自动清理 - 系统配置(16项)/菜单管理(动态路由)/数据统计 - 文件MD5去重/数据隔离/账号封禁/敏感词DFA检测 前端: Vue3+Vite+Element Plus+Less+ECharts+FontAwesome - 动态路由(数据库菜单驱动) - 蓝白配色, H5响应式 - 登录/注册/忘记密码/个人中心 - 班级创建向导/详情/加入/列表 - 管理后台: 审核/配置/菜单/统计/用户/敏感词 数据库: MySQL 10.31.100.3:3306/photowall 管理员: hero920103 / 920103
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"photowall/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type MenuService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewMenuService(db *gorm.DB) *MenuService {
|
||||
return &MenuService{db: db}
|
||||
}
|
||||
|
||||
// defaultMenus 默认菜单数据
|
||||
var defaultMenus = []model.Menu{
|
||||
// 首页
|
||||
{ID: 1, ParentID: 0, Name: "Home", Path: "/", Component: "home/index", Title: "首页", Icon: "fas fa-home", Sort: 1, Visible: true, RequireAuth: false, RequireAdmin: false},
|
||||
// 班级管理
|
||||
{ID: 2, ParentID: 0, Name: "Class", Path: "/class", Component: "", Title: "班级管理", Icon: "fas fa-users", Sort: 2, Visible: true, RequireAuth: false, RequireAdmin: false, Redirect: "/class/list"},
|
||||
{ID: 3, ParentID: 2, Name: "ClassList", Path: "/class/list", Component: "class/list/index", Title: "班级列表", Icon: "fas fa-list", Sort: 1, Visible: true, RequireAuth: false, RequireAdmin: false},
|
||||
{ID: 4, ParentID: 2, Name: "ClassEdit", Path: "/class/edit", Component: "class/edit/index", Title: "创建班级", Icon: "fas fa-plus", Sort: 2, Visible: true, RequireAuth: true, RequireAdmin: false},
|
||||
{ID: 5, ParentID: 2, Name: "ClassJoin", Path: "/class/join", Component: "class/join/index", Title: "加入班级", Icon: "fas fa-sign-in-alt", Sort: 3, Visible: true, RequireAuth: true, RequireAdmin: false},
|
||||
{ID: 6, ParentID: 2, Name: "ClassDetail", Path: "/class/detail/:id", Component: "class/detail/index", Title: "班级详情", Icon: "", Sort: 4, Visible: false, RequireAuth: false, RequireAdmin: false},
|
||||
// 个人中心
|
||||
{ID: 7, ParentID: 0, Name: "Profile", Path: "/profile", Component: "normalsettings/usersettings/detail/index", Title: "个人中心", Icon: "fas fa-user", Sort: 3, Visible: true, RequireAuth: true, RequireAdmin: false},
|
||||
// 系统管理(管理员)
|
||||
{ID: 8, ParentID: 0, Name: "Admin", Path: "/admin", Component: "", Title: "系统管理", Icon: "fas fa-cog", Sort: 4, Visible: true, RequireAuth: true, RequireAdmin: true, Redirect: "/admin/dashboard"},
|
||||
{ID: 18, ParentID: 8, Name: "Dashboard", Path: "/admin/dashboard", Component: "admin/dashboard/index", Title: "数据统计", Icon: "fas fa-chart-line", Sort: 1, Visible: true, RequireAuth: true, RequireAdmin: true},
|
||||
{ID: 9, ParentID: 8, Name: "AdminAudit", Path: "/admin/audit", Component: "admin/audit/list/index", Title: "审核管理", Icon: "fas fa-clipboard-check", Sort: 2, Visible: true, RequireAuth: true, RequireAdmin: true},
|
||||
{ID: 10, ParentID: 8, Name: "AdminAuditDetail", Path: "/admin/audit/detail/:id", Component: "admin/audit/detail/index", Title: "审核详情", Icon: "", Sort: 3, Visible: false, RequireAuth: true, RequireAdmin: true},
|
||||
{ID: 11, ParentID: 8, Name: "AdminConfig", Path: "/admin/config", Component: "admin/config/index", Title: "系统配置", Icon: "fas fa-sliders-h", Sort: 4, Visible: true, RequireAuth: true, RequireAdmin: true},
|
||||
{ID: 12, ParentID: 8, Name: "AdminMenu", Path: "/admin/menu", Component: "admin/menu/index", Title: "菜单管理", Icon: "fas fa-bars", Sort: 5, Visible: true, RequireAuth: true, RequireAdmin: true},
|
||||
{ID: 19, ParentID: 8, Name: "UserManage", Path: "/admin/users", Component: "admin/users/index", Title: "用户管理", Icon: "fas fa-user-shield", Sort: 6, Visible: true, RequireAuth: true, RequireAdmin: true},
|
||||
{ID: 20, ParentID: 8, Name: "SensitiveWord", Path: "/admin/sensitive", Component: "admin/sensitive/index", Title: "敏感词管理", Icon: "fas fa-shield-alt", Sort: 7, Visible: true, RequireAuth: true, RequireAdmin: true},
|
||||
// 基本设置(管理员)
|
||||
{ID: 13, ParentID: 0, Name: "NormalSettings", Path: "/normalsettings", Component: "", Title: "基本设置", Icon: "fas fa-wrench", Sort: 5, Visible: true, RequireAuth: true, RequireAdmin: true, Redirect: "/normalsettings/usersettings"},
|
||||
{ID: 14, ParentID: 13, Name: "UserSettings", Path: "/normalsettings/usersettings", Component: "normalsettings/usersettings/list/index", Title: "用户设置", Icon: "fas fa-user-cog", Sort: 1, Visible: true, RequireAuth: true, RequireAdmin: true},
|
||||
{ID: 15, ParentID: 13, Name: "RoleSettings", Path: "/normalsettings/rolesettings", Component: "normalsettings/rolesettings/list/index", Title: "角色设置", Icon: "fas fa-user-tag", Sort: 2, Visible: true, RequireAuth: true, RequireAdmin: true},
|
||||
{ID: 16, ParentID: 13, Name: "LogManagement", Path: "/normalsettings/logmanagement", Component: "normalsettings/logmanagement/list/index", Title: "日志管理", Icon: "fas fa-file-alt", Sort: 3, Visible: true, RequireAuth: true, RequireAdmin: true},
|
||||
// 登录页(不显示在菜单)
|
||||
{ID: 17, ParentID: 0, Name: "Login", Path: "/login", Component: "auth/login/index", Title: "登录", Icon: "", Sort: 99, Visible: false, RequireAuth: false, RequireAdmin: false},
|
||||
}
|
||||
|
||||
// InitDefaults 初始化默认菜单(不存在则创建)
|
||||
func (s *MenuService) InitDefaults() error {
|
||||
for _, m := range defaultMenus {
|
||||
var count int64
|
||||
s.db.Model(&model.Menu{}).Where("id = ? OR name = ?", m.ID, m.Name).Count(&count)
|
||||
if count == 0 {
|
||||
if err := s.db.Create(&m).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMenuTree 获取菜单树(isAdmin 过滤管理员菜单)
|
||||
func (s *MenuService) GetMenuTree(isAdmin bool) ([]*model.MenuTree, error) {
|
||||
var all []model.Menu
|
||||
query := s.db.Order("parent_id, sort")
|
||||
if !isAdmin {
|
||||
query = query.Where("require_admin = ?", false)
|
||||
}
|
||||
if err := query.Find(&all).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buildTree(all, 0), nil
|
||||
}
|
||||
|
||||
// GetAll 获取所有菜单(管理用,含隐藏)
|
||||
func (s *MenuService) GetAll() ([]model.Menu, error) {
|
||||
var list []model.Menu
|
||||
err := s.db.Order("parent_id, sort").Find(&list).Error
|
||||
return list, err
|
||||
}
|
||||
|
||||
// GetByID 获取单个菜单
|
||||
func (s *MenuService) GetByID(id uint) (*model.Menu, error) {
|
||||
var m model.Menu
|
||||
if err := s.db.First(&m, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// Create 创建菜单
|
||||
func (s *MenuService) Create(m *model.Menu) error {
|
||||
return s.db.Create(m).Error
|
||||
}
|
||||
|
||||
// Update 更新菜单
|
||||
func (s *MenuService) Update(m *model.Menu) error {
|
||||
return s.db.Save(m).Error
|
||||
}
|
||||
|
||||
// Delete 删除菜单(同时删除子菜单)
|
||||
func (s *MenuService) Delete(id uint) error {
|
||||
return s.db.Transaction(func(tx *gorm.DB) error {
|
||||
// 递归删除子菜单
|
||||
var children []model.Menu
|
||||
tx.Where("parent_id = ?", id).Find(&children)
|
||||
for _, child := range children {
|
||||
if err := tx.Delete(&child).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tx.Delete(&model.Menu{}, id).Error
|
||||
})
|
||||
}
|
||||
|
||||
// buildTree 构建菜单树
|
||||
func buildTree(list []model.Menu, parentID uint) []*model.MenuTree {
|
||||
var tree []*model.MenuTree
|
||||
for i := range list {
|
||||
if list[i].ParentID == parentID {
|
||||
node := &model.MenuTree{
|
||||
Menu: list[i],
|
||||
Children: buildTree(list, list[i].ID),
|
||||
}
|
||||
tree = append(tree, node)
|
||||
}
|
||||
}
|
||||
return tree
|
||||
}
|
||||
Reference in New Issue
Block a user