restore new ui files
@ -10,10 +10,6 @@ WeChatBot = false
|
|||||||
SecretKey = "azyehq3ivunjhbntz78isj00i4hz2mt9xtddysfucxakadq4qbfrt0b7q3lnvg80" # 注意:这个是 JWT Token 授权密钥,生产环境请务必更换
|
SecretKey = "azyehq3ivunjhbntz78isj00i4hz2mt9xtddysfucxakadq4qbfrt0b7q3lnvg80" # 注意:这个是 JWT Token 授权密钥,生产环境请务必更换
|
||||||
MaxAge = 86400
|
MaxAge = 86400
|
||||||
|
|
||||||
[Manager]
|
|
||||||
Username = "admin"
|
|
||||||
Password = "admin123" # 如果是生产环境的话,这里管理员的密码记得修改
|
|
||||||
|
|
||||||
[Redis] # redis 配置信息
|
[Redis] # redis 配置信息
|
||||||
Host = "localhost"
|
Host = "localhost"
|
||||||
Port = 6379
|
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/sms/") ||
|
||||||
strings.HasPrefix(c.Request.URL.Path, "/api/captcha/") ||
|
strings.HasPrefix(c.Request.URL.Path, "/api/captcha/") ||
|
||||||
strings.HasPrefix(c.Request.URL.Path, "/api/payment/") ||
|
strings.HasPrefix(c.Request.URL.Path, "/api/payment/") ||
|
||||||
strings.HasPrefix(c.Request.URL.Path, "/static/") ||
|
strings.HasPrefix(c.Request.URL.Path, "/static/") {
|
||||||
c.Request.URL.Path == "/api/admin/config/get" {
|
|
||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ const (
|
|||||||
Success = BizCode(0)
|
Success = BizCode(0)
|
||||||
Failed = BizCode(1)
|
Failed = BizCode(1)
|
||||||
NotAuthorized = BizCode(400) // 未授权
|
NotAuthorized = BizCode(400) // 未授权
|
||||||
|
NotPermission = BizCode(403) // 没有权限
|
||||||
|
|
||||||
OkMsg = "Success"
|
OkMsg = "Success"
|
||||||
ErrorMsg = "系统开小差了"
|
ErrorMsg = "系统开小差了"
|
||||||
|
@ -95,7 +95,31 @@ func (h *ManagerHandler) Login(c *gin.Context) {
|
|||||||
manager.LastLoginAt = time.Now().Unix()
|
manager.LastLoginAt = time.Now().Unix()
|
||||||
h.db.Model(&manager).Updates(manager)
|
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 注销
|
// 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
|
return &h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type role struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
// List 用户列表
|
// List 用户列表
|
||||||
func (h *SysUserHandler) List(c *gin.Context) {
|
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)
|
page := h.GetInt(c, "page", 1)
|
||||||
pageSize := h.GetInt(c, "page_size", 20)
|
pageSize := h.GetInt(c, "page_size", 20)
|
||||||
username := h.GetTrim(c, "username")
|
username := h.GetTrim(c, "username")
|
||||||
@ -48,9 +58,16 @@ func (h *SysUserHandler) List(c *gin.Context) {
|
|||||||
var userVo vo.AdminUser
|
var userVo vo.AdminUser
|
||||||
err := utils.CopyObject(item, &userVo)
|
err := utils.CopyObject(item, &userVo)
|
||||||
if err == nil {
|
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.Id = item.Id
|
||||||
userVo.CreatedAt = item.CreatedAt.Unix()
|
userVo.CreatedAt = item.CreatedAt.Unix()
|
||||||
userVo.UpdatedAt = item.UpdatedAt.Unix()
|
userVo.UpdatedAt = item.UpdatedAt.Unix()
|
||||||
|
userVo.RoleIds = roles
|
||||||
users = append(users, userVo)
|
users = append(users, userVo)
|
||||||
} else {
|
} else {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
@ -68,6 +85,7 @@ func (h *SysUserHandler) Save(c *gin.Context) {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Status bool `json:"status"`
|
Status bool `json:"status"`
|
||||||
|
RoleIds []int `json:"role_ids"`
|
||||||
}
|
}
|
||||||
if err := c.ShouldBindJSON(&data); err != nil {
|
if err := c.ShouldBindJSON(&data); err != nil {
|
||||||
resp.ERROR(c, types.InvalidArgs)
|
resp.ERROR(c, types.InvalidArgs)
|
||||||
@ -83,31 +101,58 @@ func (h *SysUserHandler) Save(c *gin.Context) {
|
|||||||
var user = model.AdminUser{}
|
var user = model.AdminUser{}
|
||||||
var res *gorm.DB
|
var res *gorm.DB
|
||||||
var userVo vo.AdminUser
|
var userVo vo.AdminUser
|
||||||
|
|
||||||
|
tx := h.db.Begin()
|
||||||
|
|
||||||
if data.Id > 0 { // 更新
|
if data.Id > 0 { // 更新
|
||||||
user.Id = data.Id
|
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 值
|
// 此处需要用 map 更新,用结构体无法更新 0 值
|
||||||
res = h.db.Model(&user).Updates(map[string]interface{}{
|
res = tx.Model(&user).Updates(map[string]interface{}{
|
||||||
"username": data.Username,
|
"username": data.Username,
|
||||||
"status": data.Status,
|
"status": data.Status,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
salt := utils.RandString(8)
|
salt := utils.RandString(8)
|
||||||
u := model.AdminUser{
|
|
||||||
Username: data.Username,
|
user.Username = data.Username
|
||||||
Password: utils.GenPassword(data.Password, salt),
|
user.Password = utils.GenPassword(data.Password, salt)
|
||||||
Salt: salt,
|
user.Salt = salt
|
||||||
Status: true,
|
user.Status = true
|
||||||
}
|
|
||||||
res = h.db.Create(&u)
|
res = tx.Create(&user)
|
||||||
_ = utils.CopyObject(u, &userVo)
|
_ = utils.CopyObject(user, &userVo)
|
||||||
userVo.Id = u.Id
|
userVo.Id = user.Id
|
||||||
userVo.CreatedAt = u.CreatedAt.Unix()
|
userVo.CreatedAt = user.CreatedAt.Unix()
|
||||||
userVo.UpdatedAt = u.UpdatedAt.Unix()
|
userVo.UpdatedAt = user.UpdatedAt.Unix()
|
||||||
}
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
tx.Rollback()
|
||||||
resp.ERROR(c, "更新数据库失败")
|
resp.ERROR(c, "更新数据库失败")
|
||||||
return
|
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)
|
resp.SUCCESS(c, userVo)
|
||||||
}
|
}
|
||||||
@ -155,11 +200,20 @@ func (h *SysUserHandler) Remove(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if data.Id > 0 {
|
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 {
|
if res.Error != nil {
|
||||||
|
tx.Rollback()
|
||||||
resp.ERROR(c, "删除失败")
|
resp.ERROR(c, "删除失败")
|
||||||
return
|
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)
|
resp.SUCCESS(c)
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,11 @@ func (h *ApiKeyHandler) Save(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ApiKeyHandler) List(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 items []model.ApiKey
|
||||||
var keys = make([]vo.ApiKey, 0)
|
var keys = make([]vo.ApiKey, 0)
|
||||||
res := h.db.Find(&items)
|
res := h.db.Find(&items)
|
||||||
@ -109,10 +114,15 @@ func (h *ApiKeyHandler) Set(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ApiKeyHandler) Remove(c *gin.Context) {
|
func (h *ApiKeyHandler) Remove(c *gin.Context) {
|
||||||
id := h.GetInt(c, "id", 0)
|
var data struct {
|
||||||
|
Id uint
|
||||||
if id > 0 {
|
}
|
||||||
res := h.db.Where("id = ?", id).Delete(&model.ApiKey{})
|
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 {
|
if res.Error != nil {
|
||||||
resp.ERROR(c, "更新数据库失败!")
|
resp.ERROR(c, "更新数据库失败!")
|
||||||
return
|
return
|
||||||
|
@ -35,6 +35,11 @@ type chatItemVo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ChatHandler) List(c *gin.Context) {
|
func (h *ChatHandler) List(c *gin.Context) {
|
||||||
|
if err := utils.CheckPermission(c, h.db); err != nil {
|
||||||
|
resp.NotPermission(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
UserId uint `json:"user_id"`
|
UserId uint `json:"user_id"`
|
||||||
@ -212,9 +217,14 @@ func (h *ChatHandler) History(c *gin.Context) {
|
|||||||
// RemoveChat 删除对话
|
// RemoveChat 删除对话
|
||||||
func (h *ChatHandler) RemoveChat(c *gin.Context) {
|
func (h *ChatHandler) RemoveChat(c *gin.Context) {
|
||||||
chatId := h.GetTrim(c, "chat_id")
|
chatId := h.GetTrim(c, "chat_id")
|
||||||
|
if chatId == "" {
|
||||||
|
resp.ERROR(c, "请传入 ChatId")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
tx := h.db.Begin()
|
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 {
|
if res.Error != nil {
|
||||||
resp.ERROR(c, "failed to remove chat message")
|
resp.ERROR(c, "failed to remove chat message")
|
||||||
return
|
return
|
||||||
@ -235,7 +245,7 @@ func (h *ChatHandler) RemoveChat(c *gin.Context) {
|
|||||||
// RemoveMessage 删除聊天记录
|
// RemoveMessage 删除聊天记录
|
||||||
func (h *ChatHandler) RemoveMessage(c *gin.Context) {
|
func (h *ChatHandler) RemoveMessage(c *gin.Context) {
|
||||||
id := h.GetInt(c, "id", 0)
|
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 {
|
if tx.Error != nil {
|
||||||
resp.ERROR(c, "更新数据库失败!")
|
resp.ERROR(c, "更新数据库失败!")
|
||||||
return
|
return
|
||||||
|
@ -72,6 +72,11 @@ func (h *ChatModelHandler) Save(c *gin.Context) {
|
|||||||
|
|
||||||
// List 模型列表
|
// List 模型列表
|
||||||
func (h *ChatModelHandler) List(c *gin.Context) {
|
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{})
|
session := h.db.Session(&gorm.Session{})
|
||||||
enable := h.GetBool(c, "enable")
|
enable := h.GetBool(c, "enable")
|
||||||
if enable {
|
if enable {
|
||||||
@ -140,10 +145,15 @@ func (h *ChatModelHandler) Sort(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ChatModelHandler) Remove(c *gin.Context) {
|
func (h *ChatModelHandler) Remove(c *gin.Context) {
|
||||||
id := h.GetInt(c, "id", 0)
|
var data struct {
|
||||||
|
Id uint
|
||||||
if id > 0 {
|
}
|
||||||
res := h.db.Where("id = ?", id).Delete(&model.ChatModel{})
|
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 {
|
if res.Error != nil {
|
||||||
resp.ERROR(c, "更新数据库失败!")
|
resp.ERROR(c, "更新数据库失败!")
|
||||||
return
|
return
|
||||||
|
@ -53,6 +53,11 @@ func (h *ChatRoleHandler) Save(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ChatRoleHandler) List(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 items []model.ChatRole
|
||||||
var roles = make([]vo.ChatRole, 0)
|
var roles = make([]vo.ChatRole, 0)
|
||||||
res := h.db.Order("sort_num ASC").Find(&items)
|
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) {
|
func (h *ChatRoleHandler) Remove(c *gin.Context) {
|
||||||
id := h.GetInt(c, "id", 0)
|
var data struct {
|
||||||
if id <= 0 {
|
Id uint
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindJSON(&data); err != nil {
|
||||||
resp.ERROR(c, types.InvalidArgs)
|
resp.ERROR(c, types.InvalidArgs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if data.Id <= 0 {
|
||||||
res := h.db.Where("id = ?", id).Delete(&model.ChatRole{})
|
resp.ERROR(c, types.InvalidArgs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := h.db.Where("id = ?", data.Id).Delete(&model.ChatRole{})
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
resp.ERROR(c, "删除失败!")
|
resp.ERROR(c, "删除失败!")
|
||||||
return
|
return
|
||||||
|
@ -71,6 +71,11 @@ func (h *ConfigHandler) Update(c *gin.Context) {
|
|||||||
|
|
||||||
// Get 获取指定的系统配置
|
// Get 获取指定的系统配置
|
||||||
func (h *ConfigHandler) Get(c *gin.Context) {
|
func (h *ConfigHandler) Get(c *gin.Context) {
|
||||||
|
if err := utils.CheckPermission(c, h.db); err != nil {
|
||||||
|
resp.NotPermission(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
key := c.Query("key")
|
key := c.Query("key")
|
||||||
var config model.Config
|
var config model.Config
|
||||||
res := h.db.Where("marker", key).First(&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) {
|
func (h *FunctionHandler) List(c *gin.Context) {
|
||||||
|
if err := utils.CheckPermission(c, h.db); err != nil {
|
||||||
|
resp.NotPermission(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var items []model.Function
|
var items []model.Function
|
||||||
res := h.db.Find(&items)
|
res := h.db.Find(&items)
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
@ -25,6 +25,11 @@ func NewOrderHandler(app *core.AppServer, db *gorm.DB) *OrderHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *OrderHandler) List(c *gin.Context) {
|
func (h *OrderHandler) List(c *gin.Context) {
|
||||||
|
if err := utils.CheckPermission(c, h.db); err != nil {
|
||||||
|
resp.NotPermission(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
OrderNo string `json:"order_no"`
|
OrderNo string `json:"order_no"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
|
@ -70,6 +70,11 @@ func (h *ProductHandler) Save(c *gin.Context) {
|
|||||||
|
|
||||||
// List 模型列表
|
// List 模型列表
|
||||||
func (h *ProductHandler) List(c *gin.Context) {
|
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{})
|
session := h.db.Session(&gorm.Session{})
|
||||||
enable := h.GetBool(c, "enable")
|
enable := h.GetBool(c, "enable")
|
||||||
if enable {
|
if enable {
|
||||||
|
@ -2,6 +2,7 @@ package admin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"chatplus/core"
|
"chatplus/core"
|
||||||
|
"chatplus/core/types"
|
||||||
"chatplus/handler"
|
"chatplus/handler"
|
||||||
"chatplus/store/model"
|
"chatplus/store/model"
|
||||||
"chatplus/store/vo"
|
"chatplus/store/vo"
|
||||||
@ -23,6 +24,11 @@ func NewRewardHandler(app *core.AppServer, db *gorm.DB) *RewardHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *RewardHandler) List(c *gin.Context) {
|
func (h *RewardHandler) List(c *gin.Context) {
|
||||||
|
if err := utils.CheckPermission(c, h.db); err != nil {
|
||||||
|
resp.NotPermission(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var items []model.Reward
|
var items []model.Reward
|
||||||
res := h.db.Order("id DESC").Find(&items)
|
res := h.db.Order("id DESC").Find(&items)
|
||||||
var rewards = make([]vo.Reward, 0)
|
var rewards = make([]vo.Reward, 0)
|
||||||
@ -57,10 +63,15 @@ func (h *RewardHandler) List(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *RewardHandler) Remove(c *gin.Context) {
|
func (h *RewardHandler) Remove(c *gin.Context) {
|
||||||
id := h.GetInt(c, "id", 0)
|
var data struct {
|
||||||
|
Id uint
|
||||||
if id > 0 {
|
}
|
||||||
res := h.db.Where("id = ?", id).Delete(&model.Reward{})
|
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 {
|
if res.Error != nil {
|
||||||
resp.ERROR(c, "更新数据库失败!")
|
resp.ERROR(c, "更新数据库失败!")
|
||||||
return
|
return
|
||||||
|
@ -27,6 +27,11 @@ func NewUserHandler(app *core.AppServer, db *gorm.DB) *UserHandler {
|
|||||||
|
|
||||||
// List 用户列表
|
// List 用户列表
|
||||||
func (h *UserHandler) List(c *gin.Context) {
|
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)
|
page := h.GetInt(c, "page", 1)
|
||||||
pageSize := h.GetInt(c, "page_size", 20)
|
pageSize := h.GetInt(c, "page_size", 20)
|
||||||
username := h.GetTrim(c, "username")
|
username := h.GetTrim(c, "username")
|
||||||
@ -154,30 +159,36 @@ func (h *UserHandler) ResetPass(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *UserHandler) Remove(c *gin.Context) {
|
func (h *UserHandler) Remove(c *gin.Context) {
|
||||||
id := h.GetInt(c, "id", 0)
|
var data struct {
|
||||||
if id > 0 {
|
Id uint
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindJSON(&data); err != nil {
|
||||||
|
resp.ERROR(c, types.InvalidArgs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if data.Id > 0 {
|
||||||
tx := h.db.Begin()
|
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 {
|
if res.Error != nil {
|
||||||
resp.ERROR(c, "删除失败")
|
resp.ERROR(c, "删除失败")
|
||||||
return
|
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 {
|
if res.Error != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
resp.ERROR(c, "删除失败")
|
resp.ERROR(c, "删除失败")
|
||||||
return
|
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 {
|
if res.Error != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
resp.ERROR(c, "删除失败")
|
resp.ERROR(c, "删除失败")
|
||||||
return
|
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 {
|
if res.Error != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
resp.ERROR(c, "删除失败")
|
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.NewPaymentHandler),
|
||||||
fx.Provide(handler.NewOrderHandler),
|
fx.Provide(handler.NewOrderHandler),
|
||||||
fx.Provide(handler.NewProductHandler),
|
fx.Provide(handler.NewProductHandler),
|
||||||
|
fx.Provide(handler.NewConfigHandler),
|
||||||
|
|
||||||
fx.Provide(admin.NewConfigHandler),
|
fx.Provide(admin.NewConfigHandler),
|
||||||
fx.Provide(admin.NewAdminHandler),
|
fx.Provide(admin.NewAdminHandler),
|
||||||
@ -255,6 +256,10 @@ func main() {
|
|||||||
group.POST("remove", h.Remove)
|
group.POST("remove", h.Remove)
|
||||||
group.POST("publish", h.Publish)
|
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) {
|
fx.Invoke(func(s *core.AppServer, h *admin.ConfigHandler) {
|
||||||
@ -273,13 +278,13 @@ func main() {
|
|||||||
group.POST("save", h.Save)
|
group.POST("save", h.Save)
|
||||||
group.GET("list", h.List)
|
group.GET("list", h.List)
|
||||||
group.POST("set", h.Set)
|
group.POST("set", h.Set)
|
||||||
group.GET("remove", h.Remove)
|
group.POST("remove", h.Remove)
|
||||||
}),
|
}),
|
||||||
fx.Invoke(func(s *core.AppServer, h *admin.UserHandler) {
|
fx.Invoke(func(s *core.AppServer, h *admin.UserHandler) {
|
||||||
group := s.Engine.Group("/api/admin/user/")
|
group := s.Engine.Group("/api/admin/user/")
|
||||||
group.GET("list", h.List)
|
group.GET("list", h.List)
|
||||||
group.POST("save", h.Save)
|
group.POST("save", h.Save)
|
||||||
group.GET("remove", h.Remove)
|
group.POST("remove", h.Remove)
|
||||||
group.GET("loginLog", h.LoginLog)
|
group.GET("loginLog", h.LoginLog)
|
||||||
group.POST("resetPass", h.ResetPass)
|
group.POST("resetPass", h.ResetPass)
|
||||||
}),
|
}),
|
||||||
@ -289,12 +294,12 @@ func main() {
|
|||||||
group.POST("save", h.Save)
|
group.POST("save", h.Save)
|
||||||
group.POST("sort", h.Sort)
|
group.POST("sort", h.Sort)
|
||||||
group.POST("set", h.Set)
|
group.POST("set", h.Set)
|
||||||
group.GET("remove", h.Remove)
|
group.POST("remove", h.Remove)
|
||||||
}),
|
}),
|
||||||
fx.Invoke(func(s *core.AppServer, h *admin.RewardHandler) {
|
fx.Invoke(func(s *core.AppServer, h *admin.RewardHandler) {
|
||||||
group := s.Engine.Group("/api/admin/reward/")
|
group := s.Engine.Group("/api/admin/reward/")
|
||||||
group.GET("list", h.List)
|
group.GET("list", h.List)
|
||||||
group.GET("remove", h.Remove)
|
group.POST("remove", h.Remove)
|
||||||
}),
|
}),
|
||||||
fx.Invoke(func(s *core.AppServer, h *admin.DashboardHandler) {
|
fx.Invoke(func(s *core.AppServer, h *admin.DashboardHandler) {
|
||||||
group := s.Engine.Group("/api/admin/dashboard/")
|
group := s.Engine.Group("/api/admin/dashboard/")
|
||||||
@ -310,7 +315,7 @@ func main() {
|
|||||||
group.GET("list", h.List)
|
group.GET("list", h.List)
|
||||||
group.POST("set", h.Set)
|
group.POST("set", h.Set)
|
||||||
group.POST("sort", h.Sort)
|
group.POST("sort", h.Sort)
|
||||||
group.GET("remove", h.Remove)
|
group.POST("remove", h.Remove)
|
||||||
}),
|
}),
|
||||||
fx.Invoke(func(s *core.AppServer, h *handler.PaymentHandler) {
|
fx.Invoke(func(s *core.AppServer, h *handler.PaymentHandler) {
|
||||||
group := s.Engine.Group("/api/payment/")
|
group := s.Engine.Group("/api/payment/")
|
||||||
@ -392,6 +397,22 @@ func main() {
|
|||||||
group.POST("remove", h.Remove)
|
group.POST("remove", h.Remove)
|
||||||
group.POST("resetPass", h.ResetPass)
|
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.Provide(handler.NewFunctionHandler),
|
||||||
fx.Invoke(func(s *core.AppServer, h *handler.FunctionHandler) {
|
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"`
|
||||||
|
}
|
@ -6,4 +6,5 @@ type AdminUser struct {
|
|||||||
Status bool `json:"status"` // 当前状态
|
Status bool `json:"status"` // 当前状态
|
||||||
LastLoginAt int64 `json:"last_login_at"` // 最后登录时间
|
LastLoginAt int64 `json:"last_login_at"` // 最后登录时间
|
||||||
LastLoginIp string `json:"last_login_ip"` // 最后登录 IP
|
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"})
|
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"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -60,3 +60,73 @@ CREATE TABLE `chatgpt_admin_users` (
|
|||||||
) ENGINE = InnoDB AUTO_INCREMENT = 108 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '系统用户' ROW_FORMAT = Dynamic;
|
) 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 授权密钥,生产环境请务必更换
|
SecretKey = "azyehq3ivunjhbntz78isj00i4hz2mt9xtddysfucxakadq4qbfrt0b7q3lnvg80" # 注意:这个是 JWT Token 授权密钥,生产环境请务必更换
|
||||||
MaxAge = 86400
|
MaxAge = 86400
|
||||||
|
|
||||||
[Manager]
|
|
||||||
Username = "admin"
|
|
||||||
Password = "admin123" # 如果是生产环境的话,这里管理员的密码记得修改
|
|
||||||
|
|
||||||
[Redis] # redis 配置信息
|
[Redis] # redis 配置信息
|
||||||
Host = "localhost"
|
Host = "localhost"
|
||||||
Port = 6379
|
Port = 6379
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "gpt-vue",
|
"name": "chatgpt-plus",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clear": "rimraf node_modules projects/vue-admin/node_modules",
|
"clear": "rimraf node_modules rimraf -g */node_modules rimraf -g */*/node_modules",
|
||||||
"dev": "pnpm --filter=@gpt-vue-projects/* run dev",
|
"dev": "pnpm --filter=@chatgpt-plus-projects/* run dev",
|
||||||
"build": "pnpm --filter=@gpt-vue-projects/* run build"
|
"build": "pnpm --filter=@chatgpt-plus-projects/* run build"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@gpt-vue/packages",
|
"name": "@chatgpt-plus/packages",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" href="/favicon.ico">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<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",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@ -13,7 +13,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@arco-design/web-vue": "^2.54.6",
|
"@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",
|
"echarts": "^5.5.0",
|
||||||
"md-editor-v3": "^2.2.1",
|
"md-editor-v3": "^2.2.1",
|
||||||
"pinia": "^2.1.7",
|
"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>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { Message, type SwitchInstance } from "@arco-design/web-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"];
|
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,6 +38,7 @@ onActivated(handleSearch);
|
|||||||
<template>
|
<template>
|
||||||
<div class="search-table">
|
<div class="search-table">
|
||||||
<div class="search-table-header">
|
<div class="search-table-header">
|
||||||
|
<div class="search-table-header-option">
|
||||||
<div>
|
<div>
|
||||||
<slot name="header-title">{{ props.headerTitle }}</slot>
|
<slot name="header-title">{{ props.headerTitle }}</slot>
|
||||||
</div>
|
</div>
|
||||||
@ -55,13 +56,14 @@ onActivated(handleSearch);
|
|||||||
<slot :name="slot" v-bind="{ ...config, reload: handleSearch }" />
|
<slot :name="slot" v-bind="{ ...config, reload: handleSearch }" />
|
||||||
</template>
|
</template>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
</div>
|
||||||
<div ref="tableContainerRef" class="search-table-container">
|
<div ref="tableContainerRef" class="search-table-container">
|
||||||
<ATable
|
<ATable
|
||||||
v-bind="{
|
v-bind="{
|
||||||
...$attrs,
|
...$attrs,
|
||||||
...tableConfig,
|
...tableConfig,
|
||||||
...props,
|
...props,
|
||||||
scroll: useTableScroll(_columns, tableContainerRef as HTMLElement),
|
scroll: useTableScroll(_columns),
|
||||||
columns: _columns,
|
columns: _columns,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
@ -74,14 +76,18 @@ onActivated(handleSearch);
|
|||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.search-table {
|
.search-table {
|
||||||
display: flex;
|
position: relative;
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.search-table-container {
|
.search-table-container {
|
||||||
flex: 1;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
.search-table-header {
|
.search-table-header {
|
||||||
|
background: #fff;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.search-table-header-option {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
@ -1,6 +1,6 @@
|
|||||||
import { computed, onMounted, reactive, unref, type Ref } from "vue";
|
import { computed, onMounted, reactive, unref, type Ref } from "vue";
|
||||||
import type { TableInstance } from "@arco-design/web-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 TableOriginalProps = TableInstance["$props"];
|
||||||
export type TableRequest<T extends Record<string, unknown>> = (params?: any) => Promise<BaseResponse<ListResponse<T>>>
|
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";
|
import type { SearchTableColumns, SearchColumns } from "./type";
|
||||||
|
|
||||||
export function useTableXScroll(columns: TableColumnData[]) {
|
export function useTableScroll(columns: SearchTableColumns[]) {
|
||||||
return columns.reduce((prev, curr) => {
|
|
||||||
const width = curr.width ?? 150;
|
|
||||||
return prev + width;
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useTableScroll(columns: SearchTableColumns[], container?: HTMLElement) {
|
|
||||||
const x = columns.reduce((prev, curr) => {
|
const x = columns.reduce((prev, curr) => {
|
||||||
const width = curr.hideInTable ? 0 : curr.width ?? 150;
|
const width = curr.hideInTable ? 0 : curr.width ?? 150;
|
||||||
return prev + width;
|
return prev + width;
|
||||||
}, 0);
|
}, 0);
|
||||||
const y = container?.clientHeight ?? undefined;
|
return { x };
|
||||||
return { x, y };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDefaultFormData(columns: SearchTableColumns[]) {
|
export function getDefaultFormData(columns: SearchTableColumns[]) {
|
@ -1,6 +1,6 @@
|
|||||||
import { computed, onMounted, reactive, unref } from "vue";
|
import { computed, onMounted, reactive, unref } from "vue";
|
||||||
import type { TableInstance } from "@arco-design/web-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 TableOriginalProps = TableInstance["$props"];
|
||||||
export type TableRequest<T extends Record<string, unknown>> = (
|
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,7 +1,7 @@
|
|||||||
import usePopup, { type Config } from "./usePopup";
|
import usePopup, { type Config } from "./usePopup";
|
||||||
import { Message } from "@arco-design/web-vue";
|
import { Message } from "@arco-design/web-vue";
|
||||||
import type { Component } from "vue";
|
import type { Component } from "vue";
|
||||||
import type { BaseResponse } from "@gpt-vue/packages/type";
|
import type { BaseResponse } from "@chatgpt-plus/packages/type";
|
||||||
interface Arg {
|
interface Arg {
|
||||||
reload?: () => void;
|
reload?: () => void;
|
||||||
record?: Record<string, any>;
|
record?: Record<string, any>;
|
@ -1,6 +1,6 @@
|
|||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import type { 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>>
|
type Request<T> = (params?: any) => Promise<BaseResponse<T>>
|
||||||
function useRequest<T>(request: Request<T>) {
|
function useRequest<T>(request: Request<T>) {
|
@ -1,6 +1,5 @@
|
|||||||
import { ref, reactive, unref } from "vue";
|
import { ref, reactive, unref } from "vue";
|
||||||
import { Message } from "@arco-design/web-vue";
|
import type { BaseResponse } from "@chatgpt-plus/packages/type";
|
||||||
import type { BaseResponse } from "@gpt-vue/packages/type";
|
|
||||||
function useSubmit<T extends Record<string, any> = Record<string, any>, R = any>(defaultData?: T) {
|
function useSubmit<T extends Record<string, any> = Record<string, any>, R = any>(defaultData?: T) {
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const formData = reactive<T | Record<string, any>>({ ...defaultData ?? {} });
|
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;
|
submitting.value = true;
|
||||||
try {
|
try {
|
||||||
const hasError = await formRef.value?.validate();
|
const hasError = await formRef.value?.validate();
|
||||||
if (!hasError) {
|
if (hasError) {
|
||||||
const { data, message } = await api({ ...formData ?? {}, ...unref(params) });
|
return Promise.reject({ validateErrors: hasError });
|
||||||
message && Message.success(message);
|
|
||||||
return Promise.resolve({ formData, data });
|
|
||||||
}
|
}
|
||||||
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) {
|
} catch (err) {
|
||||||
return Promise.reject(err);
|
return Promise.reject({ errors: err });
|
||||||
} finally {
|
} finally {
|
||||||
submitting.value = false;
|
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 router from "@/router";
|
||||||
import { Notification } from "@arco-design/web-vue";
|
import { Notification } from "@arco-design/web-vue";
|
||||||
import createInstance from "@gpt-vue/packages/request"
|
import createInstance from "@chatgpt-plus/packages/request"
|
||||||
import type { BaseResponse } from "@gpt-vue/packages/type";
|
import type { BaseResponse } from "@chatgpt-plus/packages/type";
|
||||||
|
|
||||||
export const uploadUrl = import.meta.env.VITE_PROXY_BASE_URL + "/api/admin/upload";
|
export const uploadUrl = import.meta.env.VITE_PROXY_BASE_URL + "/api/admin/upload";
|
||||||
|
|
||||||
export const instance = createInstance(import.meta.env.VITE_PROXY_BASE_URL)
|
export const instance = createInstance(import.meta.env.VITE_PROXY_BASE_URL)
|
||||||
|
|
||||||
instance.interceptors.request.use((config) => {
|
instance.interceptors.request.use((config) => {
|
||||||
config.headers[__AUTH_KEY] = localStorage.getItem(__AUTH_KEY);
|
const TOKEN = JSON.parse(localStorage.getItem(__AUTH_KEY))?.token
|
||||||
config.headers["Authorization"] = localStorage.getItem(__AUTH_KEY);
|
config.headers[__AUTH_KEY] = TOKEN;
|
||||||
|
config.headers["Authorization"] = TOKEN;
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.interceptors.response.use(
|
instance.interceptors.response.use(
|
||||||
(response) => {
|
(response) => {
|
||||||
const { data }: { data: BaseResponse<unknown> } = response
|
const { data }: { data: BaseResponse<unknown> } = response
|
||||||
if (data && typeof data === "object" && data.code !== 0) {
|
if (data && typeof data === "object" && data.code > 0) {
|
||||||
if (data.code === 400) {
|
switch (data.code) {
|
||||||
|
case 400: {
|
||||||
localStorage.removeItem(__AUTH_KEY);
|
localStorage.removeItem(__AUTH_KEY);
|
||||||
router.push({ name: "Login" })
|
router.push({ name: "Login" })
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 403: {
|
||||||
|
router.replace({ name: "403" })
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Notification.error(data.message ?? '未知错误')
|
Notification.error(data.message ?? '未知错误')
|
||||||
}
|
}
|
@ -1,9 +1,6 @@
|
|||||||
import http from "@/http/config";
|
import http from "@/http/config";
|
||||||
|
|
||||||
export const userLogin = (data: {
|
export const userLogin = (data) => {
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
}) => {
|
|
||||||
return http({
|
return http({
|
||||||
url: "/api/admin/login",
|
url: "/api/admin/login",
|
||||||
method: "post",
|
method: "post",
|
||||||
@ -26,7 +23,7 @@ export const getSession = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const loginLog = (params?: Record<string, unknown>) => {
|
export const loginLog = (params) => {
|
||||||
return http({
|
return http({
|
||||||
url: "/api/admin/user/loginLog",
|
url: "/api/admin/user/loginLog",
|
||||||
method: "get",
|
method: "get",
|
@ -3,6 +3,8 @@ import { createPinia } from "pinia";
|
|||||||
import ArcoVue from "@arco-design/web-vue";
|
import ArcoVue from "@arco-design/web-vue";
|
||||||
import ArcoVueIcon from "@arco-design/web-vue/es/icon";
|
import ArcoVueIcon from "@arco-design/web-vue/es/icon";
|
||||||
import "@arco-design/web-vue/dist/arco.css";
|
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 App from "./App.vue";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
@ -14,6 +16,9 @@ app.use(router);
|
|||||||
app.use(ArcoVue);
|
app.use(ArcoVue);
|
||||||
app.use(ArcoVueIcon);
|
app.use(ArcoVueIcon);
|
||||||
|
|
||||||
|
app.component("PermissionRender", PermissionRender);
|
||||||
|
app.directive("permission", permission);
|
||||||
|
|
||||||
app.mount("#app");
|
app.mount("#app");
|
||||||
app.config.warnHandler = (msg, vm, trace) => {
|
app.config.warnHandler = (msg, vm, trace) => {
|
||||||
if (msg.includes('Invalid prop name: "key" is a reserved property.')) {
|
if (msg.includes('Invalid prop name: "key" is a reserved property.')) {
|