mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 08:13:43 +08:00 
			
		
		
		
	Merge branch 'main' into husm_2024-09-02
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
			
		||||
# 更新日志
 | 
			
		||||
## v4.1.4
 | 
			
		||||
* 功能优化:用户文件列表组件增加分页功能支持
 | 
			
		||||
* Bug修复:修复用户注册失败Bug,注册操作只弹出一次行为验证码
 | 
			
		||||
 | 
			
		||||
## v4.1.3
 | 
			
		||||
* 功能优化:重构用户登录模块,给所有的登录组件增加行为验证码功能,支持用户绑定手机,邮箱和微信
 | 
			
		||||
 
 | 
			
		||||
@@ -204,7 +204,8 @@ func needLogin(c *gin.Context) bool {
 | 
			
		||||
		c.Request.URL.Path == "/api/chat/history" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/chat/detail" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/chat/list" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/role/list" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/app/list" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/app/list/user" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/model/list" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/mj/imgWall" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/mj/client" ||
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,6 @@ func (h *ApiKeyHandler) Save(c *gin.Context) {
 | 
			
		||||
func (h *ApiKeyHandler) List(c *gin.Context) {
 | 
			
		||||
	status := h.GetBool(c, "status")
 | 
			
		||||
	t := h.GetTrim(c, "type")
 | 
			
		||||
	platform := h.GetTrim(c, "platform")
 | 
			
		||||
 | 
			
		||||
	session := h.DB.Session(&gorm.Session{})
 | 
			
		||||
	if status {
 | 
			
		||||
@@ -83,9 +82,6 @@ func (h *ApiKeyHandler) List(c *gin.Context) {
 | 
			
		||||
	if t != "" {
 | 
			
		||||
		session = session.Where("type", t)
 | 
			
		||||
	}
 | 
			
		||||
	if platform != "" {
 | 
			
		||||
		session = session.Where("platform", platform)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var items []model.ApiKey
 | 
			
		||||
	var keys = make([]vo.ApiKey, 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -22,16 +22,16 @@ import (
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ChatRoleHandler struct {
 | 
			
		||||
type ChatAppHandler struct {
 | 
			
		||||
	handler.BaseHandler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewChatRoleHandler(app *core.AppServer, db *gorm.DB) *ChatRoleHandler {
 | 
			
		||||
	return &ChatRoleHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}}
 | 
			
		||||
func NewChatAppHandler(app *core.AppServer, db *gorm.DB) *ChatAppHandler {
 | 
			
		||||
	return &ChatAppHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Save 创建或者更新某个角色
 | 
			
		||||
func (h *ChatRoleHandler) Save(c *gin.Context) {
 | 
			
		||||
func (h *ChatAppHandler) Save(c *gin.Context) {
 | 
			
		||||
	var data vo.ChatRole
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
@@ -64,7 +64,7 @@ func (h *ChatRoleHandler) Save(c *gin.Context) {
 | 
			
		||||
	resp.SUCCESS(c, data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ChatRoleHandler) List(c *gin.Context) {
 | 
			
		||||
func (h *ChatAppHandler) List(c *gin.Context) {
 | 
			
		||||
	var items []model.ChatRole
 | 
			
		||||
	var roles = make([]vo.ChatRole, 0)
 | 
			
		||||
	res := h.DB.Order("sort_num ASC").Find(&items)
 | 
			
		||||
@@ -108,7 +108,7 @@ func (h *ChatRoleHandler) List(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sort 更新角色排序
 | 
			
		||||
func (h *ChatRoleHandler) Sort(c *gin.Context) {
 | 
			
		||||
func (h *ChatAppHandler) Sort(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Ids   []uint `json:"ids"`
 | 
			
		||||
		Sorts []int  `json:"sorts"`
 | 
			
		||||
@@ -130,7 +130,7 @@ func (h *ChatRoleHandler) Sort(c *gin.Context) {
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ChatRoleHandler) Set(c *gin.Context) {
 | 
			
		||||
func (h *ChatAppHandler) Set(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id    uint        `json:"id"`
 | 
			
		||||
		Filed string      `json:"filed"`
 | 
			
		||||
@@ -150,7 +150,7 @@ func (h *ChatRoleHandler) Set(c *gin.Context) {
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ChatRoleHandler) Remove(c *gin.Context) {
 | 
			
		||||
func (h *ChatAppHandler) Remove(c *gin.Context) {
 | 
			
		||||
	id := h.GetInt(c, "id", 0)
 | 
			
		||||
 | 
			
		||||
	if id <= 0 {
 | 
			
		||||
							
								
								
									
										148
									
								
								api/handler/admin/chat_app_type_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								api/handler/admin/chat_app_type_handler.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
package admin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"geekai/core"
 | 
			
		||||
	"geekai/core/types"
 | 
			
		||||
	"geekai/handler"
 | 
			
		||||
	"geekai/store/model"
 | 
			
		||||
	"geekai/store/vo"
 | 
			
		||||
	"geekai/utils"
 | 
			
		||||
	"geekai/utils/resp"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ChatAppTypeHandler struct {
 | 
			
		||||
	handler.BaseHandler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewChatAppTypeHandler(app *core.AppServer, db *gorm.DB) *ChatAppTypeHandler {
 | 
			
		||||
	return &ChatAppTypeHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Save 创建或更新App类型
 | 
			
		||||
func (h *ChatAppTypeHandler) Save(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id      uint   `json:"id"`
 | 
			
		||||
		Name    string `json:"name"`
 | 
			
		||||
		Enable  bool   `json:"enable"`
 | 
			
		||||
		Icon    string `json:"icon"`
 | 
			
		||||
		SortNum int    `json:"sort_num"`
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if data.Id == 0 { // for add
 | 
			
		||||
		err := h.DB.Where("name", data.Name).First(&model.AppType{}).Error
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			resp.ERROR(c, "当前分类已经存在")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		err = h.DB.Create(&model.AppType{
 | 
			
		||||
			Name:    data.Name,
 | 
			
		||||
			Icon:    data.Icon,
 | 
			
		||||
			Enabled: data.Enable,
 | 
			
		||||
			SortNum: data.SortNum,
 | 
			
		||||
		}).Error
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			resp.ERROR(c, err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	} else { // for update
 | 
			
		||||
		err := h.DB.Model(&model.AppType{}).Where("id", data.Id).Updates(map[string]interface{}{
 | 
			
		||||
			"name":    data.Name,
 | 
			
		||||
			"icon":    data.Icon,
 | 
			
		||||
			"enabled": data.Enable,
 | 
			
		||||
		}).Error
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			resp.ERROR(c, err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List 获取App类型列表
 | 
			
		||||
func (h *ChatAppTypeHandler) List(c *gin.Context) {
 | 
			
		||||
	var items []model.AppType
 | 
			
		||||
	var appTypes = make([]vo.AppType, 0)
 | 
			
		||||
	err := h.DB.Order("sort_num ASC").Find(&items).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp.ERROR(c, err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, v := range items {
 | 
			
		||||
		var appType vo.AppType
 | 
			
		||||
		err = utils.CopyObject(v, &appType)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		appType.Id = v.Id
 | 
			
		||||
		appType.CreatedAt = v.CreatedAt.Unix()
 | 
			
		||||
		appTypes = append(appTypes, appType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c, appTypes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove 删除App类型
 | 
			
		||||
func (h *ChatAppTypeHandler) Remove(c *gin.Context) {
 | 
			
		||||
	id := h.GetInt(c, "id", 0)
 | 
			
		||||
 | 
			
		||||
	if id <= 0 {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	err := h.DB.Where("id", id).Delete(&model.AppType{}).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp.ERROR(c, err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Enable 启用|禁用
 | 
			
		||||
func (h *ChatAppTypeHandler) Enable(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Id      uint `json:"id"`
 | 
			
		||||
		Enabled bool `json:"enabled"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := h.DB.Model(&model.AppType{}).Where("id", data.Id).UpdateColumn("enabled", data.Enabled).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp.ERROR(c, err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sort 更新排序
 | 
			
		||||
func (h *ChatAppTypeHandler) Sort(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Ids   []uint `json:"ids"`
 | 
			
		||||
		Sorts []int  `json:"sorts"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for index, id := range data.Ids {
 | 
			
		||||
		err := h.DB.Model(&model.AppType{}).Where("id", id).Update("sort_num", data.Sorts[index]).Error
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			resp.ERROR(c, err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
@@ -73,6 +73,8 @@ func (h *UserHandler) Save(c *gin.Context) {
 | 
			
		||||
		Id          uint     `json:"id"`
 | 
			
		||||
		Password    string   `json:"password"`
 | 
			
		||||
		Username    string   `json:"username"`
 | 
			
		||||
		Mobile      string   `json:"mobile"`
 | 
			
		||||
		Email       string   `json:"email"`
 | 
			
		||||
		ChatRoles   []string `json:"chat_roles"`
 | 
			
		||||
		ChatModels  []int    `json:"chat_models"`
 | 
			
		||||
		ExpiredTime string   `json:"expired_time"`
 | 
			
		||||
@@ -102,6 +104,8 @@ func (h *UserHandler) Save(c *gin.Context) {
 | 
			
		||||
		}
 | 
			
		||||
		var oldPower = user.Power
 | 
			
		||||
		user.Username = data.Username
 | 
			
		||||
		user.Email = data.Email
 | 
			
		||||
		user.Mobile = data.Mobile
 | 
			
		||||
		user.Status = data.Status
 | 
			
		||||
		user.Vip = data.Vip
 | 
			
		||||
		user.Power = data.Power
 | 
			
		||||
@@ -109,7 +113,8 @@ func (h *UserHandler) Save(c *gin.Context) {
 | 
			
		||||
		user.ChatModels = utils.JsonEncode(data.ChatModels)
 | 
			
		||||
		user.ExpiredTime = utils.Str2stamp(data.ExpiredTime)
 | 
			
		||||
 | 
			
		||||
		res = h.DB.Select("username", "status", "vip", "power", "chat_roles_json", "chat_models_json", "expired_time").Updates(&user)
 | 
			
		||||
		res = h.DB.Select("username", "mobile", "email", "status", "vip", "power", "chat_roles_json", "chat_models_json", "expired_time").Updates(&user)
 | 
			
		||||
 | 
			
		||||
		if res.Error != nil {
 | 
			
		||||
			logger.Error("error with update database:", res.Error)
 | 
			
		||||
			resp.ERROR(c, res.Error.Error())
 | 
			
		||||
@@ -147,6 +152,8 @@ func (h *UserHandler) Save(c *gin.Context) {
 | 
			
		||||
		u := model.User{
 | 
			
		||||
			Username:    data.Username,
 | 
			
		||||
			Password:    utils.GenPassword(data.Password, salt),
 | 
			
		||||
			Mobile:      data.Mobile,
 | 
			
		||||
			Email:       data.Email,
 | 
			
		||||
			Avatar:      "/images/avatar/user.png",
 | 
			
		||||
			Salt:        salt,
 | 
			
		||||
			Power:       data.Power,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								api/handler/chat_app_type_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								api/handler/chat_app_type_handler.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
package handler
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"geekai/core"
 | 
			
		||||
	"geekai/store/model"
 | 
			
		||||
	"geekai/store/vo"
 | 
			
		||||
	"geekai/utils"
 | 
			
		||||
	"geekai/utils/resp"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ChatAppTypeHandler struct {
 | 
			
		||||
	BaseHandler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewChatAppTypeHandler(app *core.AppServer, db *gorm.DB) *ChatAppTypeHandler {
 | 
			
		||||
	return &ChatAppTypeHandler{BaseHandler: BaseHandler{App: app, DB: db}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List 获取App类型列表
 | 
			
		||||
func (h *ChatAppTypeHandler) List(c *gin.Context) {
 | 
			
		||||
	var items []model.AppType
 | 
			
		||||
	var appTypes = make([]vo.AppType, 0)
 | 
			
		||||
	err := h.DB.Order("sort_num ASC").Find(&items).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp.ERROR(c, err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, v := range items {
 | 
			
		||||
		var appType vo.AppType
 | 
			
		||||
		err = utils.CopyObject(v, &appType)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		appType.Id = v.Id
 | 
			
		||||
		appType.CreatedAt = v.CreatedAt.Unix()
 | 
			
		||||
		appTypes = append(appTypes, appType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c, appTypes)
 | 
			
		||||
}
 | 
			
		||||
@@ -29,10 +29,37 @@ func NewChatRoleHandler(app *core.AppServer, db *gorm.DB) *ChatRoleHandler {
 | 
			
		||||
 | 
			
		||||
// List 获取用户聊天应用列表
 | 
			
		||||
func (h *ChatRoleHandler) List(c *gin.Context) {
 | 
			
		||||
	tid := h.GetInt(c, "tid", 0)
 | 
			
		||||
	var roles []model.ChatRole
 | 
			
		||||
	session := h.DB.Where("enable", true)
 | 
			
		||||
	if tid > 0 {
 | 
			
		||||
		session = session.Where("tid", tid)
 | 
			
		||||
	}
 | 
			
		||||
	err := session.Order("sort_num ASC").Find(&roles).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp.ERROR(c, err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var roleVos = make([]vo.ChatRole, 0)
 | 
			
		||||
	for _, r := range roles {
 | 
			
		||||
		var v vo.ChatRole
 | 
			
		||||
		err := utils.CopyObject(r, &v)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			v.Id = r.Id
 | 
			
		||||
			roleVos = append(roleVos, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	resp.SUCCESS(c, roleVos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListByUser 获取用户添加的角色列表
 | 
			
		||||
func (h *ChatRoleHandler) ListByUser(c *gin.Context) {
 | 
			
		||||
	id := h.GetInt(c, "id", 0)
 | 
			
		||||
	userId := h.GetLoginUserId(c)
 | 
			
		||||
	var roles []model.ChatRole
 | 
			
		||||
	query := h.DB.Where("enable", true)
 | 
			
		||||
	session := h.DB.Where("enable", true)
 | 
			
		||||
	// 如果用户没登录,则获取所有角色
 | 
			
		||||
	if userId > 0 {
 | 
			
		||||
		var user model.User
 | 
			
		||||
		h.DB.First(&user, userId)
 | 
			
		||||
@@ -42,12 +69,13 @@ func (h *ChatRoleHandler) List(c *gin.Context) {
 | 
			
		||||
			resp.ERROR(c, "角色解析失败!")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		query = query.Where("marker IN ?", roleKeys)
 | 
			
		||||
		session = session.Where("marker IN ?", roleKeys)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if id > 0 {
 | 
			
		||||
		query = query.Or("id", id)
 | 
			
		||||
		session = session.Or("id", id)
 | 
			
		||||
	}
 | 
			
		||||
	res := h.DB.Where("enable", true).Order("sort_num ASC").Find(&roles)
 | 
			
		||||
	res := session.Order("sort_num ASC").Find(&roles)
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		resp.ERROR(c, res.Error.Error())
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -74,6 +74,20 @@ func (h *UserHandler) Register(c *gin.Context) {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if h.App.SysConfig.EnabledVerify && data.RegWay == "username" {
 | 
			
		||||
		var check bool
 | 
			
		||||
		if data.X != 0 {
 | 
			
		||||
			check = h.captcha.SlideCheck(data)
 | 
			
		||||
		} else {
 | 
			
		||||
			check = h.captcha.Check(data)
 | 
			
		||||
		}
 | 
			
		||||
		if !check {
 | 
			
		||||
			resp.ERROR(c, "请先完人机验证")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data.Password = strings.TrimSpace(data.Password)
 | 
			
		||||
	if len(data.Password) < 8 {
 | 
			
		||||
		resp.ERROR(c, "密码长度不能少于8个字符")
 | 
			
		||||
@@ -587,7 +601,7 @@ func (h *UserHandler) ResetPass(c *gin.Context) {
 | 
			
		||||
		session = session.Where("email", data.Email)
 | 
			
		||||
		key = CodeStorePrefix + data.Email
 | 
			
		||||
	} else if data.Type == "mobile" {
 | 
			
		||||
		session = session.Where("mobile", data.Email)
 | 
			
		||||
		session = session.Where("mobile", data.Mobile)
 | 
			
		||||
		key = CodeStorePrefix + data.Mobile
 | 
			
		||||
	} else {
 | 
			
		||||
		resp.ERROR(c, "验证类别错误")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								api/main.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								api/main.go
									
									
									
									
									
								
							@@ -146,7 +146,7 @@ func main() {
 | 
			
		||||
		fx.Provide(admin.NewAdminHandler),
 | 
			
		||||
		fx.Provide(admin.NewApiKeyHandler),
 | 
			
		||||
		fx.Provide(admin.NewUserHandler),
 | 
			
		||||
		fx.Provide(admin.NewChatRoleHandler),
 | 
			
		||||
		fx.Provide(admin.NewChatAppHandler),
 | 
			
		||||
		fx.Provide(admin.NewRedeemHandler),
 | 
			
		||||
		fx.Provide(admin.NewDashboardHandler),
 | 
			
		||||
		fx.Provide(admin.NewChatModelHandler),
 | 
			
		||||
@@ -226,8 +226,9 @@ func main() {
 | 
			
		||||
 | 
			
		||||
		// 注册路由
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *handler.ChatRoleHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/role/")
 | 
			
		||||
			group := s.Engine.Group("/api/app/")
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
			group.GET("list/user", h.ListByUser)
 | 
			
		||||
			group.POST("update", h.UpdateRole)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *handler.UserHandler) {
 | 
			
		||||
@@ -338,7 +339,7 @@ func main() {
 | 
			
		||||
			group.GET("loginLog", h.LoginLog)
 | 
			
		||||
			group.POST("resetPass", h.ResetPass)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.ChatRoleHandler) {
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.ChatAppHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/role/")
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
			group.POST("save", h.Save)
 | 
			
		||||
@@ -502,6 +503,15 @@ func main() {
 | 
			
		||||
			group.GET("remove", h.Remove)
 | 
			
		||||
			group.GET("publish", h.Publish)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Provide(admin.NewChatAppTypeHandler),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.ChatAppTypeHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/app/type")
 | 
			
		||||
			group.POST("save", h.Save)
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
			group.GET("remove", h.Remove)
 | 
			
		||||
			group.POST("enable", h.Enable)
 | 
			
		||||
			group.POST("sort", h.Sort)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Provide(handler.NewTestHandler),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *handler.TestHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/test")
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ func NewSmtpService(appConfig *types.AppConfig) *SmtpService {
 | 
			
		||||
 | 
			
		||||
func (s *SmtpService) SendVerifyCode(to string, code int) error {
 | 
			
		||||
	subject := fmt.Sprintf("%s 注册验证码", s.config.AppName)
 | 
			
		||||
	body := fmt.Sprintf("您正在注册 %s 账户,注册验证码为 %d,请不要告诉他人。如非本人操作,请忽略此邮件。", s.config.AppName, code)
 | 
			
		||||
	body := fmt.Sprintf("【%s】:您的验证码为 %d,请不要告诉他人。如非本人操作,请忽略此邮件。", s.config.AppName, code)
 | 
			
		||||
 | 
			
		||||
	auth := smtp.PlainAuth("", s.config.From, s.config.Password, s.config.Host)
 | 
			
		||||
	if s.config.UseTls {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								api/store/model/app_type.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								api/store/model/app_type.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type AppType struct {
 | 
			
		||||
	Id        uint `gorm:"primarykey"`
 | 
			
		||||
	Name      string
 | 
			
		||||
	Icon      string
 | 
			
		||||
	Enabled   bool
 | 
			
		||||
	SortNum   int
 | 
			
		||||
	CreatedAt time.Time
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								api/store/vo/app_type.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								api/store/vo/app_type.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
package vo
 | 
			
		||||
 | 
			
		||||
type AppType struct {
 | 
			
		||||
	Id        uint   `json:"id"`
 | 
			
		||||
	Name      string `json:"name"`
 | 
			
		||||
	Icon      string `json:"icon"`
 | 
			
		||||
	SortNum   int    `json:"sort_num"`
 | 
			
		||||
	Enabled   bool   `json:"enabled"`
 | 
			
		||||
	CreatedAt int64  `json:"created_at"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								database/update-v4.1.4.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								database/update-v4.1.4.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
CREATE TABLE `chatgpt_app_types` (
 | 
			
		||||
                                      `id` int NOT NULL,
 | 
			
		||||
                                      `name` varchar(50) NOT NULL COMMENT '名称',
 | 
			
		||||
                                      `icon` varchar(255) NOT NULL COMMENT '图标URL',
 | 
			
		||||
                                      `sort_num` tinyint(3) NOT NULL COMMENT '排序',
 | 
			
		||||
                                      `enabled` tinyint(1) NOT NULL COMMENT '是否启用',
 | 
			
		||||
                                      `created_at` datetime NOT NULL
 | 
			
		||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='应用分类表';
 | 
			
		||||
 | 
			
		||||
ALTER TABLE `chatgpt_app_types`ADD PRIMARY KEY (`id`);
 | 
			
		||||
ALTER TABLE `chatgpt_app_types` MODIFY `id` int NOT NULL AUTO_INCREMENT;
 | 
			
		||||
ALTER TABLE `chatgpt_chat_roles` ADD `tid` INT NOT NULL COMMENT '分类ID' AFTER `name`;
 | 
			
		||||
@@ -384,7 +384,7 @@ const submitRegister = () => {
 | 
			
		||||
  if ((activeName.value === 'mobile' || activeName.value === 'email') && data.value.code === '') {
 | 
			
		||||
    return ElMessage.error('请输入验证码');
 | 
			
		||||
  }
 | 
			
		||||
  if (enableVerify.value) {
 | 
			
		||||
  if (enableVerify.value && activeName.value === 'username') {
 | 
			
		||||
    captchaRef.value.loadCaptcha()
 | 
			
		||||
    action.value = "register"
 | 
			
		||||
  } else {
 | 
			
		||||
 
 | 
			
		||||
@@ -90,12 +90,22 @@ const items = [
 | 
			
		||||
    index: '/admin/user',
 | 
			
		||||
    title: '用户管理',
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    icon: 'menu',
 | 
			
		||||
    index: '/admin/app',
 | 
			
		||||
    index: '1',
 | 
			
		||||
    title: '应用管理',
 | 
			
		||||
    subs: [
 | 
			
		||||
      {
 | 
			
		||||
        index: '/admin/app',
 | 
			
		||||
        title: '应用列表',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        index: '/admin/app/type',
 | 
			
		||||
        title: '应用分类',
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  
 | 
			
		||||
  {
 | 
			
		||||
    icon: 'api-key',
 | 
			
		||||
    index: '/admin/apikey',
 | 
			
		||||
 
 | 
			
		||||
@@ -173,6 +173,12 @@ const routes = [
 | 
			
		||||
                meta: {title: '应用管理'},
 | 
			
		||||
                component: () => import('@/views/admin/Apps.vue'),
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                path: '/admin/app/type',
 | 
			
		||||
                name: 'admin-app-type',
 | 
			
		||||
                meta: {title: '应用管理'},
 | 
			
		||||
                component: () => import('@/views/admin/AppType.vue'),
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                path: '/admin/apikey',
 | 
			
		||||
                name: 'admin-apikey',
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,6 @@ import {arrayContains, removeArrayItem, substr} from "@/utils/libs";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
import {useSharedStore} from "@/store/sharedata";
 | 
			
		||||
import ItemList from "@/components/ItemList.vue";
 | 
			
		||||
import {Plus} from "@element-plus/icons-vue";
 | 
			
		||||
 | 
			
		||||
const listBoxHeight = window.innerHeight - 87
 | 
			
		||||
const list = ref([])
 | 
			
		||||
@@ -72,7 +71,7 @@ const roles = ref([])
 | 
			
		||||
const store = useSharedStore();
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  httpGet("/api/role/list").then((res) => {
 | 
			
		||||
  httpGet("/api/app/list").then((res) => {
 | 
			
		||||
    const items = res.data
 | 
			
		||||
    // 处理 hello message
 | 
			
		||||
    for (let i = 0; i < items.length; i++) {
 | 
			
		||||
@@ -112,7 +111,7 @@ const updateRole = (row, opt) => {
 | 
			
		||||
      }
 | 
			
		||||
      roles.value = removeArrayItem(roles.value, row.key)
 | 
			
		||||
    }
 | 
			
		||||
    httpPost("/api/role/update", {keys: roles.value}).then(() => {
 | 
			
		||||
    httpPost("/api/app/update", {keys: roles.value}).then(() => {
 | 
			
		||||
      ElMessage.success({message: title.value + "成功!", duration: 1000})
 | 
			
		||||
    }).catch(e => {
 | 
			
		||||
      ElMessage.error(title.value + "失败:" + e.message)
 | 
			
		||||
 
 | 
			
		||||
@@ -364,7 +364,7 @@ const initData = () => {
 | 
			
		||||
      modelID.value = models.value[0].id
 | 
			
		||||
    }
 | 
			
		||||
    // 加载角色列表
 | 
			
		||||
    httpGet(`/api/role/list`,{id:roleId.value}).then((res) => {
 | 
			
		||||
    httpGet(`/api/app/list/user`,{id:roleId.value}).then((res) => {
 | 
			
		||||
      roles.value = res.data;
 | 
			
		||||
      if (!roleId.value) {
 | 
			
		||||
        roleId.value = roles.value[0]['id']
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
                  <div class="block">
 | 
			
		||||
                    <el-input placeholder="手机号码"
 | 
			
		||||
                              size="large"
 | 
			
		||||
                              v-model="data.username"
 | 
			
		||||
                              v-model="data.mobile"
 | 
			
		||||
                              maxlength="11"
 | 
			
		||||
                              autocomplete="off">
 | 
			
		||||
                      <template #prefix>
 | 
			
		||||
@@ -41,7 +41,7 @@
 | 
			
		||||
                        </el-input>
 | 
			
		||||
                      </el-col>
 | 
			
		||||
                      <el-col :span="12">
 | 
			
		||||
                        <send-msg size="large" :receiver="data.username" type="mobile"/>
 | 
			
		||||
                        <send-msg size="large" :receiver="data.mobile" type="mobile"/>
 | 
			
		||||
                      </el-col>
 | 
			
		||||
                    </el-row>
 | 
			
		||||
                  </div>
 | 
			
		||||
@@ -195,6 +195,8 @@ const title = ref('');
 | 
			
		||||
const logo = ref("")
 | 
			
		||||
const data = ref({
 | 
			
		||||
  username: '',
 | 
			
		||||
  mobile: '',
 | 
			
		||||
  email: '',
 | 
			
		||||
  password: '',
 | 
			
		||||
  code: '',
 | 
			
		||||
  repass: '',
 | 
			
		||||
@@ -250,15 +252,15 @@ getLicenseInfo().then(res => {
 | 
			
		||||
 | 
			
		||||
// 注册操作
 | 
			
		||||
const submitRegister = () => {
 | 
			
		||||
  if (data.value.username === '') {
 | 
			
		||||
  if (activeName.value === 'username' && data.value.username === '') {
 | 
			
		||||
    return showMessageError('请输入用户名');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (activeName.value === 'mobile' && !validateMobile(data.value.username)) {
 | 
			
		||||
  if (activeName.value === 'mobile' && !validateMobile(data.value.mobile)) {
 | 
			
		||||
    return showMessageError('请输入合法的手机号');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (activeName.value === 'email' && !validateEmail(data.value.username)) {
 | 
			
		||||
  if (activeName.value === 'email' && !validateEmail(data.value.email)) {
 | 
			
		||||
    return showMessageError('请输入合法的邮箱地址');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -273,7 +275,8 @@ const submitRegister = () => {
 | 
			
		||||
    return showMessageError('请输入验证码');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (enableVerify.value) {
 | 
			
		||||
  // 如果是用户名和密码登录,那么需要加载验证码
 | 
			
		||||
  if (enableVerify.value && activeName.value === 'username') {
 | 
			
		||||
    captchaRef.value.loadCaptcha()
 | 
			
		||||
  } else {
 | 
			
		||||
    doSubmitRegister({})
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								web/src/views/admin/AppType.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								web/src/views/admin/AppType.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="container app-type" >
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -18,6 +18,8 @@
 | 
			
		||||
            <el-image v-if="scope.row.vip" :src="vipImg" style="height: 20px;position: relative; top:5px; left: 5px"/>
 | 
			
		||||
          </template>
 | 
			
		||||
        </el-table-column>
 | 
			
		||||
        <el-table-column prop="mobile" label="手机"/>
 | 
			
		||||
        <el-table-column prop="email" label="邮箱"/>
 | 
			
		||||
        <el-table-column prop="nickname" label="昵称"/>
 | 
			
		||||
        <el-table-column prop="power" label="剩余算力"/>
 | 
			
		||||
        <el-table-column label="状态" width="80">
 | 
			
		||||
@@ -73,6 +75,12 @@
 | 
			
		||||
        <el-form-item label="账号:" prop="username">
 | 
			
		||||
          <el-input v-model="user.username" autocomplete="off"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="手机:" prop="mobile">
 | 
			
		||||
          <el-input v-model="user.mobile" autocomplete="off"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="邮箱:" prop="email">
 | 
			
		||||
          <el-input v-model="user.email" autocomplete="off"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item v-if="add" label="密码:" prop="password">
 | 
			
		||||
          <el-input v-model="user.password" autocomplete="off" placeholder="8-16位"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
 
 | 
			
		||||
@@ -105,7 +105,7 @@ checkSession().then((user) => {
 | 
			
		||||
  loginUser.value = user
 | 
			
		||||
  isLogin.value = true
 | 
			
		||||
  // 加载角色列表
 | 
			
		||||
  httpGet(`/api/role/list`).then((res) => {
 | 
			
		||||
  httpGet(`/api/app/list/user`).then((res) => {
 | 
			
		||||
    if (res.data) {
 | 
			
		||||
      const items = res.data
 | 
			
		||||
      for (let i = 0; i < items.length; i++) {
 | 
			
		||||
@@ -139,7 +139,7 @@ checkSession().then((user) => {
 | 
			
		||||
  finished.value = true
 | 
			
		||||
 | 
			
		||||
  // 加载角色列表
 | 
			
		||||
  httpGet('/api/role/list').then((res) => {
 | 
			
		||||
  httpGet('/api/app/list/user').then((res) => {
 | 
			
		||||
    if (res.data) {
 | 
			
		||||
      const items = res.data
 | 
			
		||||
      for (let i = 0; i < items.length; i++) {
 | 
			
		||||
 
 | 
			
		||||
@@ -186,7 +186,7 @@ httpGet('/api/model/list').then(res => {
 | 
			
		||||
  }
 | 
			
		||||
  modelValue.value = getModelName(modelId.value)
 | 
			
		||||
  // 加载角色列表
 | 
			
		||||
  httpGet(`/api/role/list`).then((res) => {
 | 
			
		||||
  httpGet(`/api/app/list/user`).then((res) => {
 | 
			
		||||
    roles.value = res.data;
 | 
			
		||||
    if (!roleId.value) {
 | 
			
		||||
      roleId.value = roles.value[0]['id']
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,7 @@ onMounted(() => {
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const fetchApps = () => {
 | 
			
		||||
  httpGet("/api/role/list").then((res) => {
 | 
			
		||||
  httpGet("/api/app/list/user").then((res) => {
 | 
			
		||||
    const items = res.data
 | 
			
		||||
    // 处理 hello message
 | 
			
		||||
    for (let i = 0; i < items.length; i++) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user