restore new ui files
@@ -10,10 +10,6 @@ WeChatBot = false
 | 
			
		||||
  SecretKey = "azyehq3ivunjhbntz78isj00i4hz2mt9xtddysfucxakadq4qbfrt0b7q3lnvg80" # 注意:这个是 JWT Token 授权密钥,生产环境请务必更换
 | 
			
		||||
  MaxAge = 86400
 | 
			
		||||
 | 
			
		||||
[Manager]
 | 
			
		||||
  Username = "admin"
 | 
			
		||||
  Password = "admin123" # 如果是生产环境的话,这里管理员的密码记得修改
 | 
			
		||||
 | 
			
		||||
[Redis] # redis 配置信息
 | 
			
		||||
  Host = "localhost"
 | 
			
		||||
  Port = 6379
 | 
			
		||||
 
 | 
			
		||||
@@ -162,8 +162,7 @@ func authorizeMiddleware(s *AppServer, client *redis.Client) gin.HandlerFunc {
 | 
			
		||||
			strings.HasPrefix(c.Request.URL.Path, "/api/sms/") ||
 | 
			
		||||
			strings.HasPrefix(c.Request.URL.Path, "/api/captcha/") ||
 | 
			
		||||
			strings.HasPrefix(c.Request.URL.Path, "/api/payment/") ||
 | 
			
		||||
			strings.HasPrefix(c.Request.URL.Path, "/static/") ||
 | 
			
		||||
			c.Request.URL.Path == "/api/admin/config/get" {
 | 
			
		||||
			strings.HasPrefix(c.Request.URL.Path, "/static/") {
 | 
			
		||||
			c.Next()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ const (
 | 
			
		||||
	Success       = BizCode(0)
 | 
			
		||||
	Failed        = BizCode(1)
 | 
			
		||||
	NotAuthorized = BizCode(400) // 未授权
 | 
			
		||||
	NotPermission = BizCode(403) // 没有权限
 | 
			
		||||
 | 
			
		||||
	OkMsg       = "Success"
 | 
			
		||||
	ErrorMsg    = "系统开小差了"
 | 
			
		||||
 
 | 
			
		||||
@@ -95,7 +95,31 @@ func (h *ManagerHandler) Login(c *gin.Context) {
 | 
			
		||||
	manager.LastLoginAt = time.Now().Unix()
 | 
			
		||||
	h.db.Model(&manager).Updates(manager)
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c, tokenString)
 | 
			
		||||
	permissions := h.GetAdminSlugs(manager.Id)
 | 
			
		||||
	var result = struct {
 | 
			
		||||
		IsSuperAdmin bool     `json:"is_super_admin"`
 | 
			
		||||
		Token        string   `json:"token"`
 | 
			
		||||
		Permissions  []string `json:"permissions"`
 | 
			
		||||
	}{
 | 
			
		||||
		IsSuperAdmin: manager.Id == 1,
 | 
			
		||||
		Token:        tokenString,
 | 
			
		||||
		Permissions:  permissions,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ManagerHandler) GetAdminSlugs(userId uint) []string {
 | 
			
		||||
	var permissions []string
 | 
			
		||||
	err := h.db.Raw("SELECT distinct p.slug "+
 | 
			
		||||
		"FROM chatgpt_admin_user_roles as ur "+
 | 
			
		||||
		"LEFT JOIN chatgpt_admin_role_permissions as rp ON ur.role_id = rp.role_id "+
 | 
			
		||||
		"LEFT JOIN chatgpt_admin_permissions as p ON rp.permission_id = p.id "+
 | 
			
		||||
		"WHERE ur.admin_id = ?", userId).Scan(&permissions)
 | 
			
		||||
	if err.Error == nil {
 | 
			
		||||
		return []string{}
 | 
			
		||||
	}
 | 
			
		||||
	return permissions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Logout 注销
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										132
									
								
								api/handler/admin/admin_permission_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,132 @@
 | 
			
		||||
package admin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"chatplus/core"
 | 
			
		||||
	"chatplus/core/types"
 | 
			
		||||
	"chatplus/handler"
 | 
			
		||||
	"chatplus/store/model"
 | 
			
		||||
	"chatplus/store/vo"
 | 
			
		||||
	"chatplus/utils"
 | 
			
		||||
	"chatplus/utils/resp"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SysPermissionHandler struct {
 | 
			
		||||
	handler.BaseHandler
 | 
			
		||||
	db *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewSysPermissionHandler(app *core.AppServer, db *gorm.DB) *SysPermissionHandler {
 | 
			
		||||
	h := SysPermissionHandler{db: db}
 | 
			
		||||
	h.App = app
 | 
			
		||||
	return &h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SysPermissionHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var items []model.AdminPermission
 | 
			
		||||
	var data = make([]vo.AdminPermission, 0)
 | 
			
		||||
	res := h.db.Find(&items)
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		resp.ERROR(c, "暂无数据")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		adminPermissionVo := vo.AdminPermission{}
 | 
			
		||||
		_ = utils.CopyObject(item, &adminPermissionVo)
 | 
			
		||||
		data = append(data, adminPermissionVo)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data = ArrayToTree(data)
 | 
			
		||||
	resp.SUCCESS(c, data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ArrayToTree(dates []vo.AdminPermission) []vo.AdminPermission {
 | 
			
		||||
	group := make(map[int][]vo.AdminPermission, 0)
 | 
			
		||||
	for _, node := range dates {
 | 
			
		||||
		group[node.Pid] = append(group[node.Pid], node)
 | 
			
		||||
	}
 | 
			
		||||
	// 初始化递归,从根节点开始构建树
 | 
			
		||||
	result := FindSiblings(group[0], group)
 | 
			
		||||
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FindSiblings(siblings []vo.AdminPermission, group map[int][]vo.AdminPermission) []vo.AdminPermission {
 | 
			
		||||
	result := make([]vo.AdminPermission, 0)
 | 
			
		||||
	for _, sibling := range siblings {
 | 
			
		||||
		children, ok := group[sibling.Id]
 | 
			
		||||
		if ok {
 | 
			
		||||
			sibling.Children = FindSiblings(children, group)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		result = append(result, sibling)
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SysPermissionHandler) Save(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id   int    `json:"id"`
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
		Slug string `json:"slug"`
 | 
			
		||||
		Sort int    `json:"sort"`
 | 
			
		||||
		Pid  int    `json:"pid"`
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var permission = model.AdminPermission{}
 | 
			
		||||
	var res *gorm.DB
 | 
			
		||||
	if data.Id > 0 { // 更新
 | 
			
		||||
		permission.Id = data.Id
 | 
			
		||||
		// 此处需要用 map 更新,用结构体无法更新 0 值
 | 
			
		||||
		res = h.db.Model(&permission).Updates(map[string]interface{}{
 | 
			
		||||
			"name": data.Name,
 | 
			
		||||
			"slug": data.Slug,
 | 
			
		||||
			"sort": data.Sort,
 | 
			
		||||
			"pid":  data.Pid,
 | 
			
		||||
		})
 | 
			
		||||
	} else {
 | 
			
		||||
		p := model.AdminPermission{
 | 
			
		||||
			Name: data.Name,
 | 
			
		||||
			Slug: data.Slug,
 | 
			
		||||
			Sort: data.Sort,
 | 
			
		||||
			Pid:  data.Pid,
 | 
			
		||||
		}
 | 
			
		||||
		res = h.db.Create(&p)
 | 
			
		||||
	}
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		fmt.Println(res.Error)
 | 
			
		||||
		resp.ERROR(c, "更新数据库失败")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SysPermissionHandler) Remove(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id int
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if data.Id > 0 {
 | 
			
		||||
		res := h.db.Where("id = ?", data.Id).Delete(&model.AdminPermission{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			resp.ERROR(c, "删除失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										166
									
								
								api/handler/admin/admin_role_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,166 @@
 | 
			
		||||
package admin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"chatplus/core"
 | 
			
		||||
	"chatplus/core/types"
 | 
			
		||||
	"chatplus/handler"
 | 
			
		||||
	"chatplus/store/model"
 | 
			
		||||
	"chatplus/store/vo"
 | 
			
		||||
	"chatplus/utils"
 | 
			
		||||
	"chatplus/utils/resp"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SysRoleHandler struct {
 | 
			
		||||
	handler.BaseHandler
 | 
			
		||||
	db *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewSysRoleHandler(app *core.AppServer, db *gorm.DB) *SysRoleHandler {
 | 
			
		||||
	h := SysRoleHandler{db: db}
 | 
			
		||||
	h.App = app
 | 
			
		||||
	return &h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type permission struct {
 | 
			
		||||
	Id   int    `json:"id"`
 | 
			
		||||
	Name string `json:"name"`
 | 
			
		||||
	Slug string `json:"slug"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SysRoleHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	page := h.GetInt(c, "page", 1)
 | 
			
		||||
	pageSize := h.GetInt(c, "page_size", 20)
 | 
			
		||||
	name := h.GetTrim(c, "name")
 | 
			
		||||
 | 
			
		||||
	offset := (page - 1) * pageSize
 | 
			
		||||
	var items []model.AdminRole
 | 
			
		||||
	var data = make([]vo.AdminRole, 0)
 | 
			
		||||
	var total int64
 | 
			
		||||
 | 
			
		||||
	session := h.db.Session(&gorm.Session{})
 | 
			
		||||
	if name != "" {
 | 
			
		||||
		session = session.Where("name LIKE ?", "%"+name+"%")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session.Model(&model.AdminRole{}).Count(&total)
 | 
			
		||||
	res := session.Offset(offset).Limit(pageSize).Find(&items)
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		resp.ERROR(c, "暂无数据")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for _, item := range items {
 | 
			
		||||
		adminRoleVo := vo.AdminRole{}
 | 
			
		||||
		err := utils.CopyObject(item, &adminRoleVo)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			var permissions []permission
 | 
			
		||||
			h.db.Raw("SELECT p.id,p.name,p.slug "+
 | 
			
		||||
				"FROM chatgpt_admin_role_permissions as rp "+
 | 
			
		||||
				"LEFT JOIN chatgpt_admin_permissions as p ON rp.permission_id = p.id "+
 | 
			
		||||
				"WHERE rp.role_id = ?", item.Id).Scan(&permissions)
 | 
			
		||||
 | 
			
		||||
			adminRoleVo.Permissions = permissions
 | 
			
		||||
			adminRoleVo.CreatedAt = item.CreatedAt.Format("2006-01-02 15:04:05")
 | 
			
		||||
			data = append(data, adminRoleVo)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	pageVo := vo.NewPage(total, page, pageSize, data)
 | 
			
		||||
	resp.SUCCESS(c, pageVo)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SysRoleHandler) Save(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id          int
 | 
			
		||||
		Name        string
 | 
			
		||||
		Description string
 | 
			
		||||
		Permissions []int
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var role = model.AdminRole{}
 | 
			
		||||
	var res *gorm.DB
 | 
			
		||||
	tx := h.db.Begin()
 | 
			
		||||
	if data.Id > 0 { // 更新
 | 
			
		||||
		role.Id = data.Id
 | 
			
		||||
		//删除角色对应的权限
 | 
			
		||||
		err := tx.Where("role_id = ?", role.Id).Delete(model.AdminRolePermission{})
 | 
			
		||||
		if err.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "更新数据库失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		//更新角色名
 | 
			
		||||
		res = tx.Model(&role).Updates(map[string]interface{}{
 | 
			
		||||
			"name":        data.Name,
 | 
			
		||||
			"description": data.Description,
 | 
			
		||||
		})
 | 
			
		||||
	} else {
 | 
			
		||||
		//新建角色
 | 
			
		||||
		role.Name = data.Name
 | 
			
		||||
		role.Description = data.Description
 | 
			
		||||
		res = tx.Create(&role)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		tx.Rollback()
 | 
			
		||||
		resp.ERROR(c, "更新数据库失败")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rp := make([]model.AdminRolePermission, 0)
 | 
			
		||||
	if len(data.Permissions) > 0 {
 | 
			
		||||
		for _, per := range data.Permissions {
 | 
			
		||||
			rp = append(rp, model.AdminRolePermission{
 | 
			
		||||
				RoleId:       role.Id,
 | 
			
		||||
				PermissionId: per,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		res2 := tx.CreateInBatches(rp, len(rp))
 | 
			
		||||
		if res2.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "更新数据库失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tx.Commit()
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SysRoleHandler) Remove(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id int
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if data.Id > 0 {
 | 
			
		||||
		tx := h.db.Begin()
 | 
			
		||||
		res := tx.Where("id = ?", data.Id).Delete(&model.AdminRole{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "删除失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		res = tx.Where("role_id = ?", data.Id).Delete(&model.AdminRolePermission{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "删除失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		tx.Commit()
 | 
			
		||||
	}
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
@@ -23,8 +23,18 @@ func NewSysUserHandler(app *core.AppServer, db *gorm.DB) *SysUserHandler {
 | 
			
		||||
	return &h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type role struct {
 | 
			
		||||
	Id   int    `json:"id"`
 | 
			
		||||
	Name string `json:"name"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List 用户列表
 | 
			
		||||
func (h *SysUserHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	page := h.GetInt(c, "page", 1)
 | 
			
		||||
	pageSize := h.GetInt(c, "page_size", 20)
 | 
			
		||||
	username := h.GetTrim(c, "username")
 | 
			
		||||
@@ -48,9 +58,16 @@ func (h *SysUserHandler) List(c *gin.Context) {
 | 
			
		||||
			var userVo vo.AdminUser
 | 
			
		||||
			err := utils.CopyObject(item, &userVo)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				var roles []role
 | 
			
		||||
				h.db.Raw("SELECT r.id,r.name "+
 | 
			
		||||
					"FROM chatgpt_admin_user_roles as ur "+
 | 
			
		||||
					"LEFT JOIN chatgpt_admin_roles as r ON ur.role_id = r.id "+
 | 
			
		||||
					"WHERE ur.admin_id = ?", item.Id).Scan(&roles)
 | 
			
		||||
 | 
			
		||||
				userVo.Id = item.Id
 | 
			
		||||
				userVo.CreatedAt = item.CreatedAt.Unix()
 | 
			
		||||
				userVo.UpdatedAt = item.UpdatedAt.Unix()
 | 
			
		||||
				userVo.RoleIds = roles
 | 
			
		||||
				users = append(users, userVo)
 | 
			
		||||
			} else {
 | 
			
		||||
				logger.Error(err)
 | 
			
		||||
@@ -68,6 +85,7 @@ func (h *SysUserHandler) Save(c *gin.Context) {
 | 
			
		||||
		Password string `json:"password"`
 | 
			
		||||
		Username string `json:"username"`
 | 
			
		||||
		Status   bool   `json:"status"`
 | 
			
		||||
		RoleIds  []int  `json:"role_ids"`
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
@@ -83,31 +101,58 @@ func (h *SysUserHandler) Save(c *gin.Context) {
 | 
			
		||||
	var user = model.AdminUser{}
 | 
			
		||||
	var res *gorm.DB
 | 
			
		||||
	var userVo vo.AdminUser
 | 
			
		||||
 | 
			
		||||
	tx := h.db.Begin()
 | 
			
		||||
 | 
			
		||||
	if data.Id > 0 { // 更新
 | 
			
		||||
		user.Id = data.Id
 | 
			
		||||
		err := tx.Where("admin_id = ?", user.Id).Delete(&model.AdminUserRole{})
 | 
			
		||||
		if err.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "更新数据库失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// 此处需要用 map 更新,用结构体无法更新 0 值
 | 
			
		||||
		res = h.db.Model(&user).Updates(map[string]interface{}{
 | 
			
		||||
		res = tx.Model(&user).Updates(map[string]interface{}{
 | 
			
		||||
			"username": data.Username,
 | 
			
		||||
			"status":   data.Status,
 | 
			
		||||
		})
 | 
			
		||||
	} else {
 | 
			
		||||
		salt := utils.RandString(8)
 | 
			
		||||
		u := model.AdminUser{
 | 
			
		||||
			Username: data.Username,
 | 
			
		||||
			Password: utils.GenPassword(data.Password, salt),
 | 
			
		||||
			Salt:     salt,
 | 
			
		||||
			Status:   true,
 | 
			
		||||
		}
 | 
			
		||||
		res = h.db.Create(&u)
 | 
			
		||||
		_ = utils.CopyObject(u, &userVo)
 | 
			
		||||
		userVo.Id = u.Id
 | 
			
		||||
		userVo.CreatedAt = u.CreatedAt.Unix()
 | 
			
		||||
		userVo.UpdatedAt = u.UpdatedAt.Unix()
 | 
			
		||||
 | 
			
		||||
		user.Username = data.Username
 | 
			
		||||
		user.Password = utils.GenPassword(data.Password, salt)
 | 
			
		||||
		user.Salt = salt
 | 
			
		||||
		user.Status = true
 | 
			
		||||
 | 
			
		||||
		res = tx.Create(&user)
 | 
			
		||||
		_ = utils.CopyObject(user, &userVo)
 | 
			
		||||
		userVo.Id = user.Id
 | 
			
		||||
		userVo.CreatedAt = user.CreatedAt.Unix()
 | 
			
		||||
		userVo.UpdatedAt = user.UpdatedAt.Unix()
 | 
			
		||||
	}
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		tx.Rollback()
 | 
			
		||||
		resp.ERROR(c, "更新数据库失败")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// 添加角色
 | 
			
		||||
	userRole := make([]model.AdminUserRole, 0)
 | 
			
		||||
	if len(data.RoleIds) > 0 {
 | 
			
		||||
		for _, roleId := range data.RoleIds {
 | 
			
		||||
			userRole = append(userRole, model.AdminUserRole{
 | 
			
		||||
				AdminId: user.Id,
 | 
			
		||||
				RoleId:  roleId,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		err := tx.CreateInBatches(userRole, len(userRole))
 | 
			
		||||
		if err.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "更新数据库失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	tx.Commit()
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c, userVo)
 | 
			
		||||
}
 | 
			
		||||
@@ -155,11 +200,20 @@ func (h *SysUserHandler) Remove(c *gin.Context) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if data.Id > 0 {
 | 
			
		||||
		res := h.db.Where("id = ?", data.Id).Delete(&model.AdminUser{})
 | 
			
		||||
		tx := h.db.Begin()
 | 
			
		||||
		res := tx.Where("id = ?", data.Id).Delete(&model.AdminUser{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "删除失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		res2 := tx.Where("admin_id = ?", data.Id).Delete(&model.AdminUserRole{})
 | 
			
		||||
		if res2.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "删除失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		tx.Commit()
 | 
			
		||||
	}
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -68,6 +68,11 @@ func (h *ApiKeyHandler) Save(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ApiKeyHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var items []model.ApiKey
 | 
			
		||||
	var keys = make([]vo.ApiKey, 0)
 | 
			
		||||
	res := h.db.Find(&items)
 | 
			
		||||
@@ -109,10 +114,15 @@ func (h *ApiKeyHandler) Set(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ApiKeyHandler) Remove(c *gin.Context) {
 | 
			
		||||
	id := h.GetInt(c, "id", 0)
 | 
			
		||||
 | 
			
		||||
	if id > 0 {
 | 
			
		||||
		res := h.db.Where("id = ?", id).Delete(&model.ApiKey{})
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id uint
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if data.Id > 0 {
 | 
			
		||||
		res := h.db.Where("id = ?", data.Id).Delete(&model.ApiKey{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			resp.ERROR(c, "更新数据库失败!")
 | 
			
		||||
			return
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,11 @@ type chatItemVo struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ChatHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Title    string   `json:"title"`
 | 
			
		||||
		UserId   uint     `json:"user_id"`
 | 
			
		||||
@@ -212,9 +217,14 @@ func (h *ChatHandler) History(c *gin.Context) {
 | 
			
		||||
// RemoveChat 删除对话
 | 
			
		||||
func (h *ChatHandler) RemoveChat(c *gin.Context) {
 | 
			
		||||
	chatId := h.GetTrim(c, "chat_id")
 | 
			
		||||
	if chatId == "" {
 | 
			
		||||
		resp.ERROR(c, "请传入 ChatId")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tx := h.db.Begin()
 | 
			
		||||
	// 删除聊天记录
 | 
			
		||||
	res := tx.Unscoped().Where("chat_id = ?", chatId).Delete(&model.ChatMessage{})
 | 
			
		||||
	res := tx.Unscoped().Debug().Where("chat_id = ?", chatId).Delete(&model.ChatMessage{})
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		resp.ERROR(c, "failed to remove chat message")
 | 
			
		||||
		return
 | 
			
		||||
@@ -235,7 +245,7 @@ func (h *ChatHandler) RemoveChat(c *gin.Context) {
 | 
			
		||||
// RemoveMessage 删除聊天记录
 | 
			
		||||
func (h *ChatHandler) RemoveMessage(c *gin.Context) {
 | 
			
		||||
	id := h.GetInt(c, "id", 0)
 | 
			
		||||
	tx := h.db.Unscoped().Delete(&model.ChatMessage{}, id)
 | 
			
		||||
	tx := h.db.Unscoped().Where("id = ?", id).Delete(&model.ChatMessage{})
 | 
			
		||||
	if tx.Error != nil {
 | 
			
		||||
		resp.ERROR(c, "更新数据库失败!")
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,11 @@ func (h *ChatModelHandler) Save(c *gin.Context) {
 | 
			
		||||
 | 
			
		||||
// List 模型列表
 | 
			
		||||
func (h *ChatModelHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session := h.db.Session(&gorm.Session{})
 | 
			
		||||
	enable := h.GetBool(c, "enable")
 | 
			
		||||
	if enable {
 | 
			
		||||
@@ -140,10 +145,15 @@ func (h *ChatModelHandler) Sort(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ChatModelHandler) Remove(c *gin.Context) {
 | 
			
		||||
	id := h.GetInt(c, "id", 0)
 | 
			
		||||
 | 
			
		||||
	if id > 0 {
 | 
			
		||||
		res := h.db.Where("id = ?", id).Delete(&model.ChatModel{})
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id uint
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if data.Id > 0 {
 | 
			
		||||
		res := h.db.Where("id = ?", data.Id).Delete(&model.ChatModel{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			resp.ERROR(c, "更新数据库失败!")
 | 
			
		||||
			return
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,11 @@ func (h *ChatRoleHandler) Save(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ChatRoleHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var items []model.ChatRole
 | 
			
		||||
	var roles = make([]vo.ChatRole, 0)
 | 
			
		||||
	res := h.db.Order("sort_num ASC").Find(&items)
 | 
			
		||||
@@ -119,13 +124,18 @@ func (h *ChatRoleHandler) Set(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ChatRoleHandler) Remove(c *gin.Context) {
 | 
			
		||||
	id := h.GetInt(c, "id", 0)
 | 
			
		||||
	if id <= 0 {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id uint
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res := h.db.Where("id = ?", id).Delete(&model.ChatRole{})
 | 
			
		||||
	if data.Id <= 0 {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	res := h.db.Where("id = ?", data.Id).Delete(&model.ChatRole{})
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		resp.ERROR(c, "删除失败!")
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -71,6 +71,11 @@ func (h *ConfigHandler) Update(c *gin.Context) {
 | 
			
		||||
 | 
			
		||||
// Get 获取指定的系统配置
 | 
			
		||||
func (h *ConfigHandler) Get(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key := c.Query("key")
 | 
			
		||||
	var config model.Config
 | 
			
		||||
	res := h.db.Where("marker", key).First(&config)
 | 
			
		||||
 
 | 
			
		||||
@@ -74,6 +74,11 @@ func (h *FunctionHandler) Set(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *FunctionHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var items []model.Function
 | 
			
		||||
	res := h.db.Find(&items)
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,11 @@ func NewOrderHandler(app *core.AppServer, db *gorm.DB) *OrderHandler {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *OrderHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var data struct {
 | 
			
		||||
		OrderNo  string   `json:"order_no"`
 | 
			
		||||
		Status   int      `json:"status"`
 | 
			
		||||
 
 | 
			
		||||
@@ -70,6 +70,11 @@ func (h *ProductHandler) Save(c *gin.Context) {
 | 
			
		||||
 | 
			
		||||
// List 模型列表
 | 
			
		||||
func (h *ProductHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session := h.db.Session(&gorm.Session{})
 | 
			
		||||
	enable := h.GetBool(c, "enable")
 | 
			
		||||
	if enable {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package admin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"chatplus/core"
 | 
			
		||||
	"chatplus/core/types"
 | 
			
		||||
	"chatplus/handler"
 | 
			
		||||
	"chatplus/store/model"
 | 
			
		||||
	"chatplus/store/vo"
 | 
			
		||||
@@ -23,6 +24,11 @@ func NewRewardHandler(app *core.AppServer, db *gorm.DB) *RewardHandler {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *RewardHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var items []model.Reward
 | 
			
		||||
	res := h.db.Order("id DESC").Find(&items)
 | 
			
		||||
	var rewards = make([]vo.Reward, 0)
 | 
			
		||||
@@ -57,10 +63,15 @@ func (h *RewardHandler) List(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *RewardHandler) Remove(c *gin.Context) {
 | 
			
		||||
	id := h.GetInt(c, "id", 0)
 | 
			
		||||
 | 
			
		||||
	if id > 0 {
 | 
			
		||||
		res := h.db.Where("id = ?", id).Delete(&model.Reward{})
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id uint
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if data.Id > 0 {
 | 
			
		||||
		res := h.db.Where("id = ?", data.Id).Delete(&model.Reward{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			resp.ERROR(c, "更新数据库失败!")
 | 
			
		||||
			return
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,11 @@ func NewUserHandler(app *core.AppServer, db *gorm.DB) *UserHandler {
 | 
			
		||||
 | 
			
		||||
// List 用户列表
 | 
			
		||||
func (h *UserHandler) List(c *gin.Context) {
 | 
			
		||||
	if err := utils.CheckPermission(c, h.db); err != nil {
 | 
			
		||||
		resp.NotPermission(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	page := h.GetInt(c, "page", 1)
 | 
			
		||||
	pageSize := h.GetInt(c, "page_size", 20)
 | 
			
		||||
	username := h.GetTrim(c, "username")
 | 
			
		||||
@@ -154,30 +159,36 @@ func (h *UserHandler) ResetPass(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *UserHandler) Remove(c *gin.Context) {
 | 
			
		||||
	id := h.GetInt(c, "id", 0)
 | 
			
		||||
	if id > 0 {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id uint
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if data.Id > 0 {
 | 
			
		||||
		tx := h.db.Begin()
 | 
			
		||||
		res := h.db.Where("id = ?", id).Delete(&model.User{})
 | 
			
		||||
		res := h.db.Where("id = ?", data.Id).Delete(&model.User{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			resp.ERROR(c, "删除失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// 删除聊天记录
 | 
			
		||||
		res = h.db.Where("user_id = ?", id).Delete(&model.ChatItem{})
 | 
			
		||||
		res = h.db.Where("user_id = ?", data.Id).Delete(&model.ChatItem{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "删除失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// 删除聊天历史记录
 | 
			
		||||
		res = h.db.Where("user_id = ?", id).Delete(&model.ChatMessage{})
 | 
			
		||||
		res = h.db.Where("user_id = ?", data.Id).Delete(&model.ChatMessage{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "删除失败")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// 删除登录日志
 | 
			
		||||
		res = h.db.Where("user_id = ?", id).Delete(&model.UserLoginLog{})
 | 
			
		||||
		res = h.db.Where("user_id = ?", data.Id).Delete(&model.UserLoginLog{})
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			tx.Rollback()
 | 
			
		||||
			resp.ERROR(c, "删除失败")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										42
									
								
								api/handler/config_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,42 @@
 | 
			
		||||
package handler
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"chatplus/core"
 | 
			
		||||
	"chatplus/store/model"
 | 
			
		||||
	"chatplus/utils"
 | 
			
		||||
	"chatplus/utils/resp"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ConfigHandler struct {
 | 
			
		||||
	BaseHandler
 | 
			
		||||
	db *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewConfigHandler(app *core.AppServer, db *gorm.DB) *ConfigHandler {
 | 
			
		||||
	h := ConfigHandler{db: db}
 | 
			
		||||
	h.App = app
 | 
			
		||||
	return &h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get 获取指定的系统配置
 | 
			
		||||
func (h *ConfigHandler) Get(c *gin.Context) {
 | 
			
		||||
	key := c.Query("key")
 | 
			
		||||
	var config model.Config
 | 
			
		||||
	res := h.db.Where("marker", key).First(&config)
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		resp.ERROR(c, res.Error.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var value map[string]interface{}
 | 
			
		||||
	err := utils.JsonDecode(config.Config, &value)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp.ERROR(c, err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c, value)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								api/main.go
									
									
									
									
									
								
							
							
						
						@@ -125,6 +125,7 @@ func main() {
 | 
			
		||||
		fx.Provide(handler.NewPaymentHandler),
 | 
			
		||||
		fx.Provide(handler.NewOrderHandler),
 | 
			
		||||
		fx.Provide(handler.NewProductHandler),
 | 
			
		||||
		fx.Provide(handler.NewConfigHandler),
 | 
			
		||||
 | 
			
		||||
		fx.Provide(admin.NewConfigHandler),
 | 
			
		||||
		fx.Provide(admin.NewAdminHandler),
 | 
			
		||||
@@ -255,6 +256,10 @@ func main() {
 | 
			
		||||
			group.POST("remove", h.Remove)
 | 
			
		||||
			group.POST("publish", h.Publish)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *handler.ConfigHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/config/")
 | 
			
		||||
			group.GET("get", h.Get)
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
		// 管理后台控制器
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.ConfigHandler) {
 | 
			
		||||
@@ -273,13 +278,13 @@ func main() {
 | 
			
		||||
			group.POST("save", h.Save)
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
			group.POST("set", h.Set)
 | 
			
		||||
			group.GET("remove", h.Remove)
 | 
			
		||||
			group.POST("remove", h.Remove)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.UserHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/user/")
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
			group.POST("save", h.Save)
 | 
			
		||||
			group.GET("remove", h.Remove)
 | 
			
		||||
			group.POST("remove", h.Remove)
 | 
			
		||||
			group.GET("loginLog", h.LoginLog)
 | 
			
		||||
			group.POST("resetPass", h.ResetPass)
 | 
			
		||||
		}),
 | 
			
		||||
@@ -289,12 +294,12 @@ func main() {
 | 
			
		||||
			group.POST("save", h.Save)
 | 
			
		||||
			group.POST("sort", h.Sort)
 | 
			
		||||
			group.POST("set", h.Set)
 | 
			
		||||
			group.GET("remove", h.Remove)
 | 
			
		||||
			group.POST("remove", h.Remove)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.RewardHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/reward/")
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
			group.GET("remove", h.Remove)
 | 
			
		||||
			group.POST("remove", h.Remove)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.DashboardHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/dashboard/")
 | 
			
		||||
@@ -310,7 +315,7 @@ func main() {
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
			group.POST("set", h.Set)
 | 
			
		||||
			group.POST("sort", h.Sort)
 | 
			
		||||
			group.GET("remove", h.Remove)
 | 
			
		||||
			group.POST("remove", h.Remove)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *handler.PaymentHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/payment/")
 | 
			
		||||
@@ -392,6 +397,22 @@ func main() {
 | 
			
		||||
			group.POST("remove", h.Remove)
 | 
			
		||||
			group.POST("resetPass", h.ResetPass)
 | 
			
		||||
		}),
 | 
			
		||||
		// 权限
 | 
			
		||||
		fx.Provide(admin.NewSysPermissionHandler),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.SysPermissionHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/sysPermission/")
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
			group.POST("save", h.Save)
 | 
			
		||||
			group.POST("remove", h.Remove)
 | 
			
		||||
		}),
 | 
			
		||||
		// 角色
 | 
			
		||||
		fx.Provide(admin.NewSysRoleHandler),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.SysRoleHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/sysRole/")
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
			group.POST("save", h.Save)
 | 
			
		||||
			group.POST("remove", h.Remove)
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
		fx.Provide(handler.NewFunctionHandler),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *handler.FunctionHandler) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								api/store/model/admin_permission.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,13 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type AdminPermission struct {
 | 
			
		||||
	Id        int `gorm:"primarykey;column:id"`
 | 
			
		||||
	Name      string
 | 
			
		||||
	Slug      string
 | 
			
		||||
	Sort      int
 | 
			
		||||
	Pid       int
 | 
			
		||||
	CreatedAt time.Time
 | 
			
		||||
	UpdatedAt time.Time
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								api/store/model/admin_role.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,11 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type AdminRole struct {
 | 
			
		||||
	Id          int `gorm:"primarykey;column:id"`
 | 
			
		||||
	Name        string
 | 
			
		||||
	Description string
 | 
			
		||||
	CreatedAt   time.Time
 | 
			
		||||
	UpdatedAt   time.Time
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								api/store/model/admin_role_permission.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,11 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type AdminRolePermission struct {
 | 
			
		||||
	Id           int `gorm:"primarykey;column:id"`
 | 
			
		||||
	RoleId       int
 | 
			
		||||
	PermissionId int
 | 
			
		||||
	CreatedAt    time.Time
 | 
			
		||||
	UpdatedAt    time.Time
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								api/store/model/admin_user_role.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,11 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type AdminUserRole struct {
 | 
			
		||||
	Id        int `gorm:"primarykey;column:id"`
 | 
			
		||||
	AdminId   uint
 | 
			
		||||
	RoleId    int
 | 
			
		||||
	CreatedAt time.Time
 | 
			
		||||
	UpdatedAt time.Time
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								api/store/vo/admin_permission.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,10 @@
 | 
			
		||||
package vo
 | 
			
		||||
 | 
			
		||||
type AdminPermission struct {
 | 
			
		||||
	Id       int               `json:"id"`
 | 
			
		||||
	Name     string            `json:"name"`
 | 
			
		||||
	Slug     string            `json:"slug"`
 | 
			
		||||
	Sort     int               `json:"sort"`
 | 
			
		||||
	Pid      int               `json:"pid"`
 | 
			
		||||
	Children []AdminPermission `json:"children"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								api/store/vo/admin_role.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,9 @@
 | 
			
		||||
package vo
 | 
			
		||||
 | 
			
		||||
type AdminRole struct {
 | 
			
		||||
	Id          int         `json:"id"`
 | 
			
		||||
	Name        string      `json:"name"`
 | 
			
		||||
	Description string      `json:"description"`
 | 
			
		||||
	Permissions interface{} `json:"permissions"`
 | 
			
		||||
	CreatedAt   string      `json:"created_at"`
 | 
			
		||||
}
 | 
			
		||||
@@ -2,8 +2,9 @@ package vo
 | 
			
		||||
 | 
			
		||||
type AdminUser struct {
 | 
			
		||||
	BaseVo
 | 
			
		||||
	Username    string `json:"username"`
 | 
			
		||||
	Status      bool   `json:"status"`        // 当前状态
 | 
			
		||||
	LastLoginAt int64  `json:"last_login_at"` // 最后登录时间
 | 
			
		||||
	LastLoginIp string `json:"last_login_ip"` // 最后登录 IP
 | 
			
		||||
	Username    string      `json:"username"`
 | 
			
		||||
	Status      bool        `json:"status"`        // 当前状态
 | 
			
		||||
	LastLoginAt int64       `json:"last_login_at"` // 最后登录时间
 | 
			
		||||
	LastLoginIp string      `json:"last_login_ip"` // 最后登录 IP
 | 
			
		||||
	RoleIds     interface{} `json:"role_ids"`      //角色ids
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								api/utils/permission.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,36 @@
 | 
			
		||||
package utils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CheckPermission Todo: 放在缓存
 | 
			
		||||
// CheckPermission 检查权限
 | 
			
		||||
func CheckPermission(c *gin.Context, db *gorm.DB) error {
 | 
			
		||||
	return nil
 | 
			
		||||
	//u, err := url.Parse(c.Request.RequestURI)
 | 
			
		||||
	//if err != nil {
 | 
			
		||||
	//	panic(err)
 | 
			
		||||
	//}
 | 
			
		||||
	//slug := strings.Replace(u.Path, "/", "_", -1)[1:]
 | 
			
		||||
	//
 | 
			
		||||
	//// 用户名
 | 
			
		||||
	//userName, _ := c.Get(types.LoginUserID)
 | 
			
		||||
	//
 | 
			
		||||
	//var manager model.AdminUser
 | 
			
		||||
	//db.Table("chatgpt_admin_users").Select("chatgpt_admin_users.id").Where("username = ?", userName).First(&manager)
 | 
			
		||||
	//
 | 
			
		||||
	//// 超级管理员不判断
 | 
			
		||||
	//if manager.Id == 1 {
 | 
			
		||||
	//	return nil
 | 
			
		||||
	//}
 | 
			
		||||
	//var roleIds []int
 | 
			
		||||
	//var count int64
 | 
			
		||||
	//db.Raw("SELECT `chatgpt_admin_user_roles`.role_id FROM `chatgpt_admin_users` LEFT JOIN `chatgpt_admin_user_roles` ON ( `chatgpt_admin_users`.id = `chatgpt_admin_user_roles`.admin_id ) WHERE `chatgpt_admin_users`.id = ?", manager.Id).Find(&roleIds)
 | 
			
		||||
	//db.Raw("SELECT `chatgpt_admin_permissions`.slug FROM `chatgpt_admin_permissions` LEFT JOIN `chatgpt_admin_role_permissions` ON (`chatgpt_admin_permissions`.id = `chatgpt_admin_role_permissions`.permission_id) WHERE `chatgpt_admin_role_permissions`.role_id IN ? and `chatgpt_admin_permissions`.slug = ? ", roleIds, slug).Count(&count)
 | 
			
		||||
	//if count > 0 {
 | 
			
		||||
	//	return nil
 | 
			
		||||
	//}
 | 
			
		||||
	//return fmt.Errorf("没有权限")
 | 
			
		||||
}
 | 
			
		||||
@@ -34,3 +34,11 @@ func NotAuth(c *gin.Context, messages ...string) {
 | 
			
		||||
		c.JSON(http.StatusOK, types.BizVo{Code: types.NotAuthorized, Message: "Not Authorized"})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NotPermission(c *gin.Context, messages ...string) {
 | 
			
		||||
	if messages != nil {
 | 
			
		||||
		c.JSON(http.StatusOK, types.BizVo{Code: types.NotPermission, Message: messages[0]})
 | 
			
		||||
	} else {
 | 
			
		||||
		c.JSON(http.StatusOK, types.BizVo{Code: types.NotPermission, Message: "Not Permission"})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -59,4 +59,74 @@ CREATE TABLE `chatgpt_admin_users`  (
 | 
			
		||||
                                        UNIQUE INDEX `username`(`username`) USING BTREE
 | 
			
		||||
) ENGINE = InnoDB AUTO_INCREMENT = 108 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '系统用户' ROW_FORMAT = Dynamic;
 | 
			
		||||
 | 
			
		||||
INSERT INTO `chatgpt_admin_users` VALUES (1, 'admin', '6d17e80c87d209efb84ca4b2e0824f549d09fac8b2e1cc698de5bb5e1d75dfd0', 'mmrql75o', 1, 1710238055, '172.22.11.29', '2024-03-11 16:30:20', '2024-03-12 18:07:35');
 | 
			
		||||
INSERT INTO `chatgpt_admin_users` VALUES (1, 'admin', '6d17e80c87d209efb84ca4b2e0824f549d09fac8b2e1cc698de5bb5e1d75dfd0', 'mmrql75o', 1, 1710238055, '172.22.11.29', '2024-03-11 16:30:20', '2024-03-12 18:07:35');
 | 
			
		||||
 | 
			
		||||
CREATE TABLE `chatgpt_admin_user_roles` (
 | 
			
		||||
                                            `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
 | 
			
		||||
                                            `admin_id` int NOT NULL COMMENT '用户ID',
 | 
			
		||||
                                            `role_id` int NOT NULL COMMENT '角色ID',
 | 
			
		||||
                                            `created_at` datetime NOT NULL,
 | 
			
		||||
                                            `updated_at` datetime NOT NULL,
 | 
			
		||||
                                            PRIMARY KEY (`id`) USING BTREE,
 | 
			
		||||
                                            KEY `idx_admin_id` (`admin_id`),
 | 
			
		||||
                                            KEY `idx_role_id` (`role_id`) USING BTREE
 | 
			
		||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户角色表';
 | 
			
		||||
 | 
			
		||||
CREATE TABLE `chatgpt_admin_roles` (
 | 
			
		||||
                                       `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
 | 
			
		||||
                                       `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '角色名称',
 | 
			
		||||
                                       `description` varchar(255) DEFAULT '' COMMENT '描述',
 | 
			
		||||
                                       `created_at` datetime NOT NULL,
 | 
			
		||||
                                       `updated_at` datetime NOT NULL,
 | 
			
		||||
                                       PRIMARY KEY (`id`) USING BTREE
 | 
			
		||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='角色表';
 | 
			
		||||
 | 
			
		||||
CREATE TABLE `chatgpt_admin_role_permissions` (
 | 
			
		||||
                                                  `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
 | 
			
		||||
                                                  `role_id` int NOT NULL COMMENT '角色ID',
 | 
			
		||||
                                                  `permission_id` int NOT NULL COMMENT '权限ID',
 | 
			
		||||
                                                  `created_at` datetime NOT NULL,
 | 
			
		||||
                                                  `updated_at` datetime NOT NULL,
 | 
			
		||||
                                                  PRIMARY KEY (`id`) USING BTREE,
 | 
			
		||||
                                                  KEY `idx_role_id` (`role_id`),
 | 
			
		||||
                                                  KEY `idx_permission_id` (`permission_id`) USING BTREE
 | 
			
		||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户角色表';
 | 
			
		||||
 | 
			
		||||
CREATE TABLE `chatgpt_admin_permissions` (
 | 
			
		||||
                                             `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
 | 
			
		||||
                                             `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '权限名称(模块@菜单名称@方法)',
 | 
			
		||||
                                             `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '前端权限模块',
 | 
			
		||||
                                             `sort` int NOT NULL DEFAULT '1' COMMENT '排序(越大排越靠前)',
 | 
			
		||||
                                             `pid` int NOT NULL DEFAULT '0' COMMENT '父节点',
 | 
			
		||||
                                             `created_at` datetime DEFAULT NULL,
 | 
			
		||||
                                             `updated_at` datetime DEFAULT NULL,
 | 
			
		||||
                                             PRIMARY KEY (`id`),
 | 
			
		||||
                                             KEY `idx_slug` (`slug`) USING BTREE
 | 
			
		||||
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='权限表';
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (6, '用户管理', '', 2, 0, '2024-03-14 10:47:41', '2024-03-14 10:48:41');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (7, '列表', 'api_admin_user_list', 1, 6, '2024-03-14 10:53:36', '2024-03-14 10:53:36');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (10, '角色模型', '', 3, 0, '2024-03-14 11:02:45', '2024-03-14 11:02:45');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (11, '列表', 'api_admin_role_list', 1, 10, '2024-03-14 11:03:43', '2024-03-14 11:03:45');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (12, '语言模型', '', 4, 0, '2024-03-14 11:05:00', '2024-03-14 11:05:00');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (13, '列表', 'api_admin_model_list', 1, 12, '2024-03-14 11:05:36', '2024-03-14 11:05:36');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (14, '充值产品', '', 5, 0, '2024-03-14 11:16:37', '2024-03-14 11:16:37');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (15, '列表', 'api_admin_product_list', 1, 14, '2024-03-14 11:17:05', '2024-03-14 11:17:05');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (16, 'APIKEY', '', 6, 0, '2024-03-14 11:17:16', '2024-03-14 11:17:16');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (17, '列表', 'api_admin_apikey_list', 1, 16, '2024-03-14 11:17:53', '2024-03-14 11:18:02');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (18, '充值订单', '', 7, 0, '2024-03-14 11:18:20', '2024-03-14 11:18:20');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (19, '列表', 'api_admin_order_list', 1, 18, '2024-03-14 11:18:44', '2024-03-14 11:18:44');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (20, '众筹管理', '', 8, 0, '2024-03-14 11:18:59', '2024-03-14 11:18:59');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (21, '列表', 'api_admin_reward_list', 1, 20, '2024-03-14 11:19:28', '2024-03-14 11:19:28');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (22, '函数管理', '', 9, 0, '2024-03-14 11:19:42', '2024-03-14 11:19:42');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (23, '列表', 'api_admin_function_list', 1, 22, '2024-03-14 11:20:07', '2024-03-14 11:20:07');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (24, '对话管理', '', 10, 0, '2024-03-14 11:20:30', '2024-03-14 11:20:30');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (25, '列表', 'api_admin_chat_list', 1, 24, '2024-03-14 11:20:51', '2024-03-14 11:20:51');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (26, '网站设置', '', 11, 0, '2024-03-14 11:21:05', '2024-03-14 11:21:05');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (27, '配置列表', 'api_admin_config_get', 1, 26, '2024-03-14 11:21:53', '2024-03-14 11:21:53');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (28, '系统配置', '', 12, 0, '2024-03-14 11:22:07', '2024-03-14 15:28:22');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (29, '列表', 'api_admin_sysUser_list', 1, 30, '2024-03-14 11:22:36', '2024-03-14 15:28:52');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (30, '系统管理员', '', 1, 28, '2024-03-14 15:28:43', '2024-03-14 15:28:43');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (31, '权限配置', '', 2, 28, '2024-03-14 15:29:05', '2024-03-14 15:29:05');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (32, '角色配置', '', 3, 28, '2024-03-14 15:29:15', '2024-03-14 15:29:15');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (33, '列表', 'api_admin_sysPermission_list', 1, 31, '2024-03-14 15:29:52', '2024-03-14 15:29:52');
 | 
			
		||||
INSERT INTO `chatgpt_admin_permissions` VALUES (34, '列表', 'api_admin_sysRole_list', 1, 32, '2024-03-14 15:30:21', '2024-03-14 15:30:21');
 | 
			
		||||
 
 | 
			
		||||
@@ -10,10 +10,6 @@ WeChatBot = false
 | 
			
		||||
  SecretKey = "azyehq3ivunjhbntz78isj00i4hz2mt9xtddysfucxakadq4qbfrt0b7q3lnvg80" # 注意:这个是 JWT Token 授权密钥,生产环境请务必更换
 | 
			
		||||
  MaxAge = 86400
 | 
			
		||||
 | 
			
		||||
[Manager]
 | 
			
		||||
  Username = "admin"
 | 
			
		||||
  Password = "admin123" # 如果是生产环境的话,这里管理员的密码记得修改
 | 
			
		||||
 | 
			
		||||
[Redis] # redis 配置信息
 | 
			
		||||
  Host = "localhost"
 | 
			
		||||
  Port = 6379
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "gpt-vue",
 | 
			
		||||
  "name": "chatgpt-plus",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "description": "",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "clear": "rimraf node_modules projects/vue-admin/node_modules",
 | 
			
		||||
    "dev": "pnpm --filter=@gpt-vue-projects/* run dev",
 | 
			
		||||
    "build": "pnpm --filter=@gpt-vue-projects/* run build"
 | 
			
		||||
    "clear": "rimraf node_modules rimraf -g */node_modules rimraf -g */*/node_modules",
 | 
			
		||||
    "dev": "pnpm --filter=@chatgpt-plus-projects/* run dev",
 | 
			
		||||
    "build": "pnpm --filter=@chatgpt-plus-projects/* run build"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [],
 | 
			
		||||
  "author": "",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@gpt-vue/packages",
 | 
			
		||||
  "name": "@chatgpt-plus/packages",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "description": "",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6458
									
								
								new-ui/pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						@@ -6,4 +6,4 @@ declare module "*.vue" {
 | 
			
		||||
  export default component;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
declare const __AUTH_KEY: string;
 | 
			
		||||
declare const __AUTH_KEY: string;
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <link rel="icon" href="/favicon.ico">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@gpt-vue-projects/vue-admin",
 | 
			
		||||
  "name": "@chatgpt-plus-projects/admin",
 | 
			
		||||
  "version": "0.0.0",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "type": "module",
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@arco-design/web-vue": "^2.54.6",
 | 
			
		||||
    "@gpt-vue/packages": "workspace:^1.0.0",
 | 
			
		||||
    "@chatgpt-plus/packages": "workspace:^1.0.0",
 | 
			
		||||
    "echarts": "^5.5.0",
 | 
			
		||||
    "md-editor-v3": "^2.2.1",
 | 
			
		||||
    "pinia": "^2.1.7",
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB  | 
| 
		 Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB  | 
| 
		 Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB  | 
| 
		 Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB  | 
| 
		 Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB  | 
| 
		 Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB  | 
| 
		 Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB  | 
| 
		 Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB  | 
| 
		 Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB  | 
| 
		 Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB  | 
| 
		 Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB  | 
| 
		 Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB  | 
| 
		 Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB  | 
| 
		 Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB  | 
| 
		 Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB  | 
| 
		 Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB  | 
| 
		 Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB  | 
| 
		 Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB  | 
| 
		 Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB  | 
| 
		 Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB  | 
| 
		 Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB  | 
| 
		 Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB  | 
| 
		 Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB  | 
| 
		 Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB  | 
| 
		 Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB  | 
| 
		 Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB  | 
| 
		 Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB  | 
| 
		 Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB  | 
| 
		 Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB  | 
| 
		 Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB  | 
| 
		 Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB  | 
| 
		 Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB  | 
| 
		 Before Width: | Height: | Size: 276 B After Width: | Height: | Size: 276 B  | 
@@ -1,7 +1,7 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { computed } from "vue";
 | 
			
		||||
import { Message, type SwitchInstance } from "@arco-design/web-vue";
 | 
			
		||||
import type { BaseResponse } from "@gpt-vue/packages/type";
 | 
			
		||||
import type { BaseResponse } from "@chatgpt-plus/packages/type";
 | 
			
		||||
 | 
			
		||||
type OriginProps = SwitchInstance["$props"];
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								new-ui/projects/admin/src/components/PermissionRender.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,10 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { hasPermission } from "@/directives/permission";
 | 
			
		||||
defineProps<{
 | 
			
		||||
  permission: string | string[] | true;
 | 
			
		||||
}>();
 | 
			
		||||
</script>
 | 
			
		||||
<template>
 | 
			
		||||
  <slot v-if="hasPermission(permission)" />
 | 
			
		||||
  <slot v-else name="none" />
 | 
			
		||||
</template>
 | 
			
		||||
@@ -38,30 +38,32 @@ onActivated(handleSearch);
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="search-table">
 | 
			
		||||
    <div class="search-table-header">
 | 
			
		||||
      <div>
 | 
			
		||||
        <slot name="header-title">{{ props.headerTitle }}</slot>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="header-option">
 | 
			
		||||
        <slot name="header-option" :formData="formData" :reload="handleSearch" />
 | 
			
		||||
      <div class="search-table-header-option">
 | 
			
		||||
        <div>
 | 
			
		||||
          <slot name="header-title">{{ props.headerTitle }}</slot>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="header-option">
 | 
			
		||||
          <slot name="header-option" :formData="formData" :reload="handleSearch" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <FormSection
 | 
			
		||||
          v-model="formData"
 | 
			
		||||
          :columns="columns"
 | 
			
		||||
          :submitting="tableConfig.loading as boolean"
 | 
			
		||||
          @request="handleSearch"
 | 
			
		||||
      >
 | 
			
		||||
        <template v-for="slot in Object.keys($slots)" #[slot]="config">
 | 
			
		||||
          <slot :name="slot" v-bind="{ ...config, reload: handleSearch }" />
 | 
			
		||||
        </template>
 | 
			
		||||
      </FormSection>
 | 
			
		||||
    </div>
 | 
			
		||||
    <FormSection
 | 
			
		||||
      v-model="formData"
 | 
			
		||||
      :columns="columns"
 | 
			
		||||
      :submitting="tableConfig.loading as boolean"
 | 
			
		||||
      @request="handleSearch"
 | 
			
		||||
    >
 | 
			
		||||
      <template v-for="slot in Object.keys($slots)" #[slot]="config">
 | 
			
		||||
        <slot :name="slot" v-bind="{ ...config, reload: handleSearch }" />
 | 
			
		||||
      </template>
 | 
			
		||||
    </FormSection>
 | 
			
		||||
    <div ref="tableContainerRef" class="search-table-container">
 | 
			
		||||
      <ATable
 | 
			
		||||
        v-bind="{
 | 
			
		||||
          ...$attrs,
 | 
			
		||||
          ...tableConfig,
 | 
			
		||||
          ...props,
 | 
			
		||||
          scroll: useTableScroll(_columns, tableContainerRef as HTMLElement),
 | 
			
		||||
          scroll: useTableScroll(_columns),
 | 
			
		||||
          columns: _columns,
 | 
			
		||||
        }"
 | 
			
		||||
      >
 | 
			
		||||
@@ -74,14 +76,18 @@ onActivated(handleSearch);
 | 
			
		||||
</template>
 | 
			
		||||
<style scoped>
 | 
			
		||||
.search-table {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.search-table-container {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
}
 | 
			
		||||
.search-table-header {
 | 
			
		||||
  background: #fff;
 | 
			
		||||
  z-index: 2;
 | 
			
		||||
}
 | 
			
		||||
.search-table-header-option {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { computed, onMounted, reactive, unref, type Ref } from "vue";
 | 
			
		||||
import type { TableInstance } from "@arco-design/web-vue";
 | 
			
		||||
import type { BaseResponse, ListResponse } from "@gpt-vue/packages/type";
 | 
			
		||||
import type { BaseResponse, ListResponse } from "@chatgpt-plus/packages/type";
 | 
			
		||||
 | 
			
		||||
export type TableOriginalProps = TableInstance["$props"];
 | 
			
		||||
export type TableRequest<T extends Record<string, unknown>> = (params?: any) => Promise<BaseResponse<ListResponse<T>>>
 | 
			
		||||
@@ -1,20 +1,11 @@
 | 
			
		||||
import type { TableColumnData } from "@arco-design/web-vue";
 | 
			
		||||
import type { SearchTableColumns, SearchColumns } from "./type";
 | 
			
		||||
 | 
			
		||||
export function useTableXScroll(columns: TableColumnData[]) {
 | 
			
		||||
  return columns.reduce((prev, curr) => {
 | 
			
		||||
    const width = curr.width ?? 150;
 | 
			
		||||
    return prev + width;
 | 
			
		||||
  }, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useTableScroll(columns: SearchTableColumns[], container?: HTMLElement) {
 | 
			
		||||
export function useTableScroll(columns: SearchTableColumns[]) {
 | 
			
		||||
  const x = columns.reduce((prev, curr) => {
 | 
			
		||||
    const width = curr.hideInTable ? 0 : curr.width ?? 150;
 | 
			
		||||
    return prev + width;
 | 
			
		||||
  }, 0);
 | 
			
		||||
  const y = container?.clientHeight ?? undefined;
 | 
			
		||||
  return { x, y };
 | 
			
		||||
  return { x };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getDefaultFormData(columns: SearchTableColumns[]) {
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { computed, onMounted, reactive, unref } from "vue";
 | 
			
		||||
import type { TableInstance } from "@arco-design/web-vue";
 | 
			
		||||
import type { BaseResponse } from "@gpt-vue/packages/type";
 | 
			
		||||
import type { BaseResponse } from "@chatgpt-plus/packages/type";
 | 
			
		||||
 | 
			
		||||
export type TableOriginalProps = TableInstance["$props"];
 | 
			
		||||
export type TableRequest<T extends Record<string, unknown>> = (
 | 
			
		||||
							
								
								
									
										64
									
								
								new-ui/projects/admin/src/components/SystemMenu.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,64 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent, h } from "vue";
 | 
			
		||||
import type { Component, PropType } from "vue";
 | 
			
		||||
import type { RouteRecordRaw } from "vue-router";
 | 
			
		||||
import { SubMenu, MenuItem } from "@arco-design/web-vue";
 | 
			
		||||
const CustomMenuItem: Component = defineComponent({
 | 
			
		||||
  props: {
 | 
			
		||||
    tree: {
 | 
			
		||||
      type: Array as PropType<RouteRecordRaw[]>,
 | 
			
		||||
      default: () => [],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  setup: (props) => {
 | 
			
		||||
    return () =>
 | 
			
		||||
      props.tree?.map((item) => {
 | 
			
		||||
        const _icon = item.meta?.icon ? h(item.meta.icon) : undefined;
 | 
			
		||||
        const hasChildren = Array.isArray(item.children) && item.children.length;
 | 
			
		||||
        if (hasChildren) {
 | 
			
		||||
          return h(
 | 
			
		||||
            SubMenu,
 | 
			
		||||
            { title: item.meta.title, key: item.name },
 | 
			
		||||
            {
 | 
			
		||||
              default: () => h(CustomMenuItem, { tree: item.children }),
 | 
			
		||||
              icon: () => _icon,
 | 
			
		||||
            }
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
        return h(
 | 
			
		||||
          MenuItem,
 | 
			
		||||
          { key: item.name },
 | 
			
		||||
          { default: () => item.meta.title, icon: () => _icon }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { computed } from "vue";
 | 
			
		||||
import { useRoute } from "vue-router";
 | 
			
		||||
import router from "@/router";
 | 
			
		||||
import menu from "@/router/menu";
 | 
			
		||||
import { hasPermission } from "@/directives/permission";
 | 
			
		||||
defineProps({
 | 
			
		||||
  width: {
 | 
			
		||||
    type: [Number, String],
 | 
			
		||||
    default: 200,
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const goto = (name: string) => router.push({ name });
 | 
			
		||||
 | 
			
		||||
const selectedKeys = computed(() => [route.name]);
 | 
			
		||||
 | 
			
		||||
const showMenu = computed(() => menu.filter((item: any) => hasPermission(item.meta?.permission)));
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <ALayoutSider :style="{ width, height: '100%' }">
 | 
			
		||||
    <AMenu :selectedKeys="selectedKeys" auto-open-selected @menu-item-click="goto">
 | 
			
		||||
      <CustomMenuItem :tree="showMenu" />
 | 
			
		||||
    </AMenu>
 | 
			
		||||
  </ALayoutSider>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -1,44 +1,44 @@
 | 
			
		||||
import usePopup, { type Config } from "./usePopup";
 | 
			
		||||
import { Message } from "@arco-design/web-vue";
 | 
			
		||||
import type { Component } from "vue";
 | 
			
		||||
import type { BaseResponse } from "@gpt-vue/packages/type";
 | 
			
		||||
interface Arg {
 | 
			
		||||
  reload?: () => void;
 | 
			
		||||
  record?: Record<string, any>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function (
 | 
			
		||||
  node: Component,
 | 
			
		||||
  api: (params?: any) => Promise<BaseResponse<any>>,
 | 
			
		||||
  config?: Config
 | 
			
		||||
): (arg: Arg) => void {
 | 
			
		||||
  const nodeProps = (arg: Arg[]) => {
 | 
			
		||||
    return {
 | 
			
		||||
      data: arg[0].record || {},
 | 
			
		||||
      ...config.nodeProps?.(arg),
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const popupProps = (arg: Arg[], getExposed) => {
 | 
			
		||||
    return {
 | 
			
		||||
      width: 750,
 | 
			
		||||
      maskClosable: false,
 | 
			
		||||
      onBeforeOk: async () => {
 | 
			
		||||
        const exposed = getExposed();
 | 
			
		||||
        const validateRes = await exposed?.formRef.value.validate();
 | 
			
		||||
        if (validateRes) {
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        const { code } = await api(exposed?.form.value);
 | 
			
		||||
        if (code === 0) {
 | 
			
		||||
          Message.success("操作成功");
 | 
			
		||||
        }
 | 
			
		||||
        arg[0]?.reload?.();
 | 
			
		||||
        return code === 0;
 | 
			
		||||
      },
 | 
			
		||||
      ...config.popupProps?.(arg, getExposed),
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return usePopup(node, { nodeProps, popupProps });
 | 
			
		||||
}
 | 
			
		||||
import usePopup, { type Config } from "./usePopup";
 | 
			
		||||
import { Message } from "@arco-design/web-vue";
 | 
			
		||||
import type { Component } from "vue";
 | 
			
		||||
import type { BaseResponse } from "@chatgpt-plus/packages/type";
 | 
			
		||||
interface Arg {
 | 
			
		||||
  reload?: () => void;
 | 
			
		||||
  record?: Record<string, any>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function (
 | 
			
		||||
  node: Component,
 | 
			
		||||
  api: (params?: any) => Promise<BaseResponse<any>>,
 | 
			
		||||
  config?: Config
 | 
			
		||||
): (arg: Arg) => void {
 | 
			
		||||
  const nodeProps = (arg: Arg[]) => {
 | 
			
		||||
    return {
 | 
			
		||||
      data: arg[0].record || {},
 | 
			
		||||
      ...config.nodeProps?.(arg),
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const popupProps = (arg: Arg[], getExposed) => {
 | 
			
		||||
    return {
 | 
			
		||||
      width: 750,
 | 
			
		||||
      maskClosable: false,
 | 
			
		||||
      onBeforeOk: async () => {
 | 
			
		||||
        const exposed = getExposed();
 | 
			
		||||
        const validateRes = await exposed?.formRef.value.validate();
 | 
			
		||||
        if (validateRes) {
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        const { code } = await api(exposed?.form.value);
 | 
			
		||||
        if (code === 0) {
 | 
			
		||||
          Message.success("操作成功");
 | 
			
		||||
        }
 | 
			
		||||
        arg[0]?.reload?.();
 | 
			
		||||
        return code === 0;
 | 
			
		||||
      },
 | 
			
		||||
      ...config.popupProps?.(arg, getExposed),
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return usePopup(node, { nodeProps, popupProps });
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import type { Ref } from "vue";
 | 
			
		||||
import type { BaseResponse } from "@gpt-vue/packages/type";
 | 
			
		||||
import type { BaseResponse } from "@chatgpt-plus/packages/type";
 | 
			
		||||
 | 
			
		||||
type Request<T> = (params?: any) => Promise<BaseResponse<T>>
 | 
			
		||||
function useRequest<T>(request: Request<T>) {
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
import { ref, reactive, unref } from "vue";
 | 
			
		||||
import { Message } from "@arco-design/web-vue";
 | 
			
		||||
import type { BaseResponse } from "@gpt-vue/packages/type";
 | 
			
		||||
import type { BaseResponse } from "@chatgpt-plus/packages/type";
 | 
			
		||||
function useSubmit<T extends Record<string, any> = Record<string, any>, R = any>(defaultData?: T) {
 | 
			
		||||
  const formRef = ref();
 | 
			
		||||
  const formData = reactive<T | Record<string, any>>({ ...defaultData ?? {} });
 | 
			
		||||
@@ -10,14 +9,18 @@ function useSubmit<T extends Record<string, any> = Record<string, any>, R = any>
 | 
			
		||||
    submitting.value = true;
 | 
			
		||||
    try {
 | 
			
		||||
      const hasError = await formRef.value?.validate();
 | 
			
		||||
      if (!hasError) {
 | 
			
		||||
        const { data, message } = await api({ ...formData ?? {}, ...unref(params) });
 | 
			
		||||
        message && Message.success(message);
 | 
			
		||||
        return Promise.resolve({ formData, data });
 | 
			
		||||
      if (hasError) {
 | 
			
		||||
        return Promise.reject({ validateErrors: hasError });
 | 
			
		||||
      }
 | 
			
		||||
      return Promise.reject(false);
 | 
			
		||||
 | 
			
		||||
      const { data, code, message } = await api({ ...formData ?? {}, ...unref(params) });
 | 
			
		||||
      if (code) {
 | 
			
		||||
        return Promise.reject({ requestErrors: message })
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return Promise.resolve({ formData, data });
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      return Promise.reject(err);
 | 
			
		||||
      return Promise.reject({ errors: err });
 | 
			
		||||
    } finally {
 | 
			
		||||
      submitting.value = false;
 | 
			
		||||
    }
 | 
			
		||||
							
								
								
									
										32
									
								
								new-ui/projects/admin/src/directives/permission.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,32 @@
 | 
			
		||||
import { useAuthStore } from "@/stores/auth";
 | 
			
		||||
 | 
			
		||||
// 判断操作权限
 | 
			
		||||
export function hasPermission(permissionTag: string | string[] | boolean) {
 | 
			
		||||
  const authStore = useAuthStore();
 | 
			
		||||
  const { is_super_admin, permissions = [] } = authStore;
 | 
			
		||||
  if (is_super_admin) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  if (Array.isArray(permissionTag)) {
 | 
			
		||||
    return permissionTag.every((tag) => permissions.includes(tag));
 | 
			
		||||
  }
 | 
			
		||||
  if (typeof permissionTag === "string") {
 | 
			
		||||
    return permissions.includes(permissionTag);
 | 
			
		||||
  }
 | 
			
		||||
  return permissionTag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function checkPermission(el, binding) {
 | 
			
		||||
  if (!hasPermission(binding.value)) {
 | 
			
		||||
    el.parentNode && el.parentNode.removeChild(el);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const permission = {
 | 
			
		||||
  mounted(el, binding) {
 | 
			
		||||
    checkPermission(el, binding);
 | 
			
		||||
  },
 | 
			
		||||
  updated(el, binding) {
 | 
			
		||||
    checkPermission(el, binding);
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@@ -1,25 +1,33 @@
 | 
			
		||||
import router from "@/router";
 | 
			
		||||
import { Notification } from "@arco-design/web-vue";
 | 
			
		||||
import createInstance from "@gpt-vue/packages/request"
 | 
			
		||||
import type { BaseResponse } from "@gpt-vue/packages/type";
 | 
			
		||||
import createInstance from "@chatgpt-plus/packages/request"
 | 
			
		||||
import type { BaseResponse } from "@chatgpt-plus/packages/type";
 | 
			
		||||
 | 
			
		||||
export const uploadUrl = import.meta.env.VITE_PROXY_BASE_URL + "/api/admin/upload";
 | 
			
		||||
 | 
			
		||||
export const instance = createInstance(import.meta.env.VITE_PROXY_BASE_URL)
 | 
			
		||||
 | 
			
		||||
instance.interceptors.request.use((config) => {
 | 
			
		||||
  config.headers[__AUTH_KEY] = localStorage.getItem(__AUTH_KEY);
 | 
			
		||||
  config.headers["Authorization"] = localStorage.getItem(__AUTH_KEY);
 | 
			
		||||
  const TOKEN = JSON.parse(localStorage.getItem(__AUTH_KEY))?.token
 | 
			
		||||
  config.headers[__AUTH_KEY] = TOKEN;
 | 
			
		||||
  config.headers["Authorization"] = TOKEN;
 | 
			
		||||
  return config;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
instance.interceptors.response.use(
 | 
			
		||||
  (response) => {
 | 
			
		||||
    const { data }: { data: BaseResponse<unknown> } = response
 | 
			
		||||
    if (data && typeof data === "object" && data.code !== 0) {
 | 
			
		||||
      if (data.code === 400) {
 | 
			
		||||
        localStorage.removeItem(__AUTH_KEY);
 | 
			
		||||
        router.push({ name: "Login" })
 | 
			
		||||
    if (data && typeof data === "object" && data.code > 0) {
 | 
			
		||||
      switch (data.code) {
 | 
			
		||||
        case 400: {
 | 
			
		||||
          localStorage.removeItem(__AUTH_KEY);
 | 
			
		||||
          router.push({ name: "Login" })
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 403: {
 | 
			
		||||
          router.replace({ name: "403" })
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      Notification.error(data.message ?? '未知错误')
 | 
			
		||||
    }
 | 
			
		||||
@@ -1,9 +1,6 @@
 | 
			
		||||
import http from "@/http/config";
 | 
			
		||||
 | 
			
		||||
export const userLogin = (data: {
 | 
			
		||||
  username: string;
 | 
			
		||||
  password: string;
 | 
			
		||||
}) => {
 | 
			
		||||
export const userLogin = (data) => {
 | 
			
		||||
  return http({
 | 
			
		||||
    url: "/api/admin/login",
 | 
			
		||||
    method: "post",
 | 
			
		||||
@@ -26,7 +23,7 @@ export const getSession = () => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export const loginLog = (params?: Record<string, unknown>) => {
 | 
			
		||||
export const loginLog = (params) => {
 | 
			
		||||
  return http({
 | 
			
		||||
    url: "/api/admin/user/loginLog",
 | 
			
		||||
    method: "get",
 | 
			
		||||
@@ -3,6 +3,8 @@ import { createPinia } from "pinia";
 | 
			
		||||
import ArcoVue from "@arco-design/web-vue";
 | 
			
		||||
import ArcoVueIcon from "@arco-design/web-vue/es/icon";
 | 
			
		||||
import "@arco-design/web-vue/dist/arco.css";
 | 
			
		||||
import PermissionRender from "@/components/PermissionRender.vue";
 | 
			
		||||
import { permission } from "@/directives/permission";
 | 
			
		||||
 | 
			
		||||
import App from "./App.vue";
 | 
			
		||||
import router from "./router";
 | 
			
		||||
@@ -14,6 +16,9 @@ app.use(router);
 | 
			
		||||
app.use(ArcoVue);
 | 
			
		||||
app.use(ArcoVueIcon);
 | 
			
		||||
 | 
			
		||||
app.component("PermissionRender", PermissionRender);
 | 
			
		||||
app.directive("permission", permission);
 | 
			
		||||
 | 
			
		||||
app.mount("#app");
 | 
			
		||||
app.config.warnHandler = (msg, vm, trace) => {
 | 
			
		||||
  if (msg.includes('Invalid prop name: "key" is a reserved property.')) {
 | 
			
		||||