✨ Init
This commit is contained in:
		
							
								
								
									
										38
									
								
								service/system/article.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								service/system/article.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/common"
 | 
			
		||||
	"miniapp/model/common/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ArticleService struct{}
 | 
			
		||||
 | 
			
		||||
// GetArticleList 获取文章列表
 | 
			
		||||
func (a ArticleService) GetArticleList(p request.PageInfo) (list []common.Article, total int64, err error) {
 | 
			
		||||
	err = global.GVA_DB.Scopes(Page(p.Page, p.PageSize)).Find(&list).Offset(-1).Limit(-1).Count(&total).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateArticle 创建文章
 | 
			
		||||
func (a ArticleService) CreateArticle(article *common.Article) (err error) {
 | 
			
		||||
	return global.GVA_DB.Create(&article).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateArticle 更新文章
 | 
			
		||||
func (a ArticleService) UpdateArticle(article *common.Article) (err error) {
 | 
			
		||||
	return global.GVA_DB.Updates(&article).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteArticle 删除文章
 | 
			
		||||
func (a ArticleService) DeleteArticle(article *common.Article) (err error) {
 | 
			
		||||
	return global.GVA_DB.Delete(&article).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetArticleById 根据id获取文章
 | 
			
		||||
func (a ArticleService) GetArticleById(id string) (article *common.Article, err error) {
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", id).First(&article).Error
 | 
			
		||||
	err = global.GVA_DB.Table("articles").Where("id = ?", id).Update("reading_num", gorm.Expr("reading_num + ?", 1)).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								service/system/banner.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								service/system/banner.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/common"
 | 
			
		||||
	"miniapp/model/common/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type BannerService struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetBannerList 获取轮播图列表
 | 
			
		||||
func (b BannerService) GetBannerList(p request.PageInfo) (list []common.Banner, total int64, err error) {
 | 
			
		||||
	err = global.GVA_DB.Scopes(Page(p.Page, p.PageSize)).Find(&list).Limit(-1).Offset(-1).Count(&total).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateBanner 创建轮播图
 | 
			
		||||
func (b BannerService) CreateBanner(banner *common.Banner) (err error) {
 | 
			
		||||
	return global.GVA_DB.Create(&banner).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateBanner 更新轮播图
 | 
			
		||||
func (b BannerService) UpdateBanner(banner *common.Banner) (err error) {
 | 
			
		||||
	return global.GVA_DB.Updates(&banner).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteBanner 删除轮播图
 | 
			
		||||
func (b BannerService) DeleteBanner(banner *common.Banner) (err error) {
 | 
			
		||||
	return global.GVA_DB.Delete(&banner).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetBannerById 根据id获取轮播图
 | 
			
		||||
func (b BannerService) GetBannerById(id string) (banner *common.Banner, err error) {
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", id).First(&banner).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								service/system/base.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								service/system/base.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"go.uber.org/zap"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 分页组件
 | 
			
		||||
func Page(current, size int) func(db *gorm.DB) *gorm.DB {
 | 
			
		||||
	return func(db *gorm.DB) *gorm.DB {
 | 
			
		||||
		if current == 0 {
 | 
			
		||||
			current = 1
 | 
			
		||||
		}
 | 
			
		||||
		if size < 1 {
 | 
			
		||||
			size = 10
 | 
			
		||||
		}
 | 
			
		||||
		// 计算偏移量
 | 
			
		||||
		offset := (current - 1) * size
 | 
			
		||||
		// 返回组装结果
 | 
			
		||||
		return db.Offset(offset).Limit(size)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @title updateSortBefore
 | 
			
		||||
// @description 更新之前处理序号
 | 
			
		||||
// @param tx *gorm.DB "已开启的事务对象"
 | 
			
		||||
// @param model any "模型对象"
 | 
			
		||||
// @return error "错误信息"
 | 
			
		||||
func updateSortBefore(tx *gorm.DB, tableName, id string, sort int, param string) (err error) {
 | 
			
		||||
	// 查出原来的排序号
 | 
			
		||||
	var oldSort int
 | 
			
		||||
	err = tx.Table(tableName).Select("sort").Where("id = ?", id).Scan(&oldSort).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		global.GVA_LOG.Error("查询老数据失败: %v", zap.Error(err))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// 如果相等,啥都不干
 | 
			
		||||
	if oldSort == sort {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	// 处理排序
 | 
			
		||||
	// 如果老的排序号小于新的,(老, 新]之间的排序号都要-1
 | 
			
		||||
	// 如果老的大于新的,[老, 新)排序号-1
 | 
			
		||||
	if oldSort < sort {
 | 
			
		||||
		// 老的小于新的,[老, 新) + 1
 | 
			
		||||
		sel := tx.Table(tableName).
 | 
			
		||||
			Where("sort <= ? AND sort > ?", sort, oldSort).
 | 
			
		||||
			Where("deleted_at IS NULL")
 | 
			
		||||
		if param != "" {
 | 
			
		||||
			sel.Where(param) // 自定义条件
 | 
			
		||||
		}
 | 
			
		||||
		err = sel.Update("sort", gorm.Expr("sort - 1")).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		// 老的大于新的,[新, 老) + 1
 | 
			
		||||
		sel := tx.Table(tableName).
 | 
			
		||||
			Where("sort >= ? AND sort < ?", sort, oldSort).
 | 
			
		||||
			Where("deleted_at IS NULL")
 | 
			
		||||
		if param != "" {
 | 
			
		||||
			sel.Where(param) // 自定义条件
 | 
			
		||||
		}
 | 
			
		||||
		err = sel.Update("sort", gorm.Expr("sort + 1")).Error
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @title createSortBefore
 | 
			
		||||
// @description 新建之前处理序号
 | 
			
		||||
// @param tx *gorm.DB "已开启的事务对象"
 | 
			
		||||
// @param model any "模型对象"
 | 
			
		||||
// @return error "错误信息"
 | 
			
		||||
func createSortBefore(tx *gorm.DB, tableName string, sort int, param string) (err error) {
 | 
			
		||||
	// 处理排序,如果没有传,就会是在最前面
 | 
			
		||||
	sel := tx.Table(tableName).Where("sort >= ?", sort).
 | 
			
		||||
		Where("deleted_at IS NULL")
 | 
			
		||||
	if param != "" {
 | 
			
		||||
		sel.Where(param)
 | 
			
		||||
	}
 | 
			
		||||
	err = sel.Update("sort", gorm.Expr("sort + 1")).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		global.GVA_LOG.Error("处理前置排序失败:%v", zap.Error(err))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @title dealSortAfter
 | 
			
		||||
// @description 处理序号之后
 | 
			
		||||
// @param tx *gorm.DB "已开启的事务对象"
 | 
			
		||||
// @param modelName string "表名"
 | 
			
		||||
// @return error "错误信息"
 | 
			
		||||
func dealSortAfter(tx *gorm.DB, modelName, param string) (err error) {
 | 
			
		||||
	// 保存成功,刷新排序
 | 
			
		||||
	if param != "" {
 | 
			
		||||
		param += " AND "
 | 
			
		||||
	}
 | 
			
		||||
	sql := fmt.Sprintf("UPDATE %s a, (SELECT (@i := @i + 1) i, id FROM %s WHERE %s deleted_at IS NULL order by sort ASC) i, "+
 | 
			
		||||
		"(SELECT @i := 0) ir SET a.sort = i.i, updated_at=now() WHERE a.id = i.id", modelName, modelName, param)
 | 
			
		||||
	err = tx.Exec(sql).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		global.GVA_LOG.Error("刷新排序失败: %v", zap.Error(err))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								service/system/enter.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								service/system/enter.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
type ServiceGroup struct {
 | 
			
		||||
	JwtService
 | 
			
		||||
	ApiService
 | 
			
		||||
	MenuService
 | 
			
		||||
	UserService
 | 
			
		||||
	CasbinService
 | 
			
		||||
	InitDBService
 | 
			
		||||
	AutoCodeService
 | 
			
		||||
	BaseMenuService
 | 
			
		||||
	AuthorityService
 | 
			
		||||
	DictionaryService
 | 
			
		||||
	SystemConfigService
 | 
			
		||||
	AutoCodeHistoryService
 | 
			
		||||
	OperationRecordService
 | 
			
		||||
	DictionaryDetailService
 | 
			
		||||
	AuthorityBtnService
 | 
			
		||||
	ChatGptService
 | 
			
		||||
	HospitalService
 | 
			
		||||
	BannerService
 | 
			
		||||
	ArticleService
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								service/system/hospital.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								service/system/hospital.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/common"
 | 
			
		||||
	"miniapp/model/common/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type HospitalService struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetHospitalList 获取医院列表
 | 
			
		||||
func (h HospitalService) GetHospitalList(p request.PageInfo) (list []common.Hospital, total int64, err error) {
 | 
			
		||||
	err = global.GVA_DB.Scopes(Page(p.Page, p.PageSize)).Preload("Notes").Preload("Todos").Find(&list).Offset(-1).Limit(-1).Count(&total).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateHospital 创建医院
 | 
			
		||||
func (h HospitalService) CreateHospital(hospital *common.Hospital) (err error) {
 | 
			
		||||
	return global.GVA_DB.Create(&hospital).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateHospital 更新医院
 | 
			
		||||
func (h HospitalService) UpdateHospital(hospital *common.Hospital) (err error) {
 | 
			
		||||
	return global.GVA_DB.Updates(&hospital).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteHospital 删除医院
 | 
			
		||||
func (h HospitalService) DeleteHospital(hospital *common.Hospital) (err error) {
 | 
			
		||||
	return global.GVA_DB.Select("Notes").Delete(&hospital).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetHospitalById 根据id获取医院
 | 
			
		||||
func (h HospitalService) GetHospitalById(id uint) (hospital *common.Hospital, err error) {
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", id).Preload("Notes").Preload("Todos").First(&hospital).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								service/system/jwt_black_list.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								service/system/jwt_black_list.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"go.uber.org/zap"
 | 
			
		||||
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/utils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type JwtService struct{}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: JsonInBlacklist
 | 
			
		||||
//@description: 拉黑jwt
 | 
			
		||||
//@param: jwtList model.JwtBlacklist
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (jwtService *JwtService) JsonInBlacklist(jwtList system.JwtBlacklist) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Create(&jwtList).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	global.BlackCache.SetDefault(jwtList.Jwt, struct{}{})
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: IsBlacklist
 | 
			
		||||
//@description: 判断JWT是否在黑名单内部
 | 
			
		||||
//@param: jwt string
 | 
			
		||||
//@return: bool
 | 
			
		||||
 | 
			
		||||
func (jwtService *JwtService) IsBlacklist(jwt string) bool {
 | 
			
		||||
	_, ok := global.BlackCache.Get(jwt)
 | 
			
		||||
	return ok
 | 
			
		||||
	// err := global.GVA_DB.Where("jwt = ?", jwt).First(&system.JwtBlacklist{}).Error
 | 
			
		||||
	// isNotFound := errors.Is(err, gorm.ErrRecordNotFound)
 | 
			
		||||
	// return !isNotFound
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetRedisJWT
 | 
			
		||||
//@description: 从redis取jwt
 | 
			
		||||
//@param: userName string
 | 
			
		||||
//@return: redisJWT string, err error
 | 
			
		||||
 | 
			
		||||
func (jwtService *JwtService) GetRedisJWT(userName string) (redisJWT string, err error) {
 | 
			
		||||
	redisJWT, err = global.GVA_REDIS.Get(context.Background(), userName).Result()
 | 
			
		||||
	return redisJWT, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: SetRedisJWT
 | 
			
		||||
//@description: jwt存入redis并设置过期时间
 | 
			
		||||
//@param: jwt string, userName string
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (jwtService *JwtService) SetRedisJWT(jwt string, userName string) (err error) {
 | 
			
		||||
	// 此处过期时间等于jwt过期时间
 | 
			
		||||
	dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	timer := dr
 | 
			
		||||
	err = global.GVA_REDIS.Set(context.Background(), userName, jwt, timer).Err()
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LoadAll() {
 | 
			
		||||
	var data []string
 | 
			
		||||
	err := global.GVA_DB.Model(&system.JwtBlacklist{}).Select("jwt").Find(&data).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		global.GVA_LOG.Error("加载数据库jwt黑名单失败!", zap.Error(err))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < len(data); i++ {
 | 
			
		||||
		global.BlackCache.SetDefault(data[i], struct{}{})
 | 
			
		||||
	} // jwt黑名单 加入 BlackCache 中
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										196
									
								
								service/system/sys_api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								service/system/sys_api.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,196 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/common/request"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: CreateApi
 | 
			
		||||
//@description: 新增基础api
 | 
			
		||||
//@param: api model.SysApi
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
type ApiService struct{}
 | 
			
		||||
 | 
			
		||||
var ApiServiceApp = new(ApiService)
 | 
			
		||||
 | 
			
		||||
func (apiService *ApiService) CreateApi(api system.SysApi) (err error) {
 | 
			
		||||
	if !errors.Is(global.GVA_DB.Where("path = ? AND method = ?", api.Path, api.Method).First(&system.SysApi{}).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return errors.New("存在相同api")
 | 
			
		||||
	}
 | 
			
		||||
	return global.GVA_DB.Create(&api).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteApi
 | 
			
		||||
//@description: 删除基础api
 | 
			
		||||
//@param: api model.SysApi
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (apiService *ApiService) DeleteApi(api system.SysApi) (err error) {
 | 
			
		||||
	var entity system.SysApi
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", api.ID).First(&entity).Error // 根据id查询api记录
 | 
			
		||||
	if errors.Is(err, gorm.ErrRecordNotFound) {                      // api记录不存在
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Delete(&entity).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	CasbinServiceApp.ClearCasbin(1, entity.Path, entity.Method)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetAPIInfoList
 | 
			
		||||
//@description: 分页获取数据,
 | 
			
		||||
//@param: api model.SysApi, info request.PageInfo, order string, desc bool
 | 
			
		||||
//@return: list interface{}, total int64, err error
 | 
			
		||||
 | 
			
		||||
func (apiService *ApiService) GetAPIInfoList(api system.SysApi, info request.PageInfo, order string, desc bool) (list interface{}, total int64, err error) {
 | 
			
		||||
	limit := info.PageSize
 | 
			
		||||
	offset := info.PageSize * (info.Page - 1)
 | 
			
		||||
	db := global.GVA_DB.Model(&system.SysApi{})
 | 
			
		||||
	var apiList []system.SysApi
 | 
			
		||||
 | 
			
		||||
	if api.Path != "" {
 | 
			
		||||
		db = db.Where("path LIKE ?", "%"+api.Path+"%")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if api.Description != "" {
 | 
			
		||||
		db = db.Where("description LIKE ?", "%"+api.Description+"%")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if api.Method != "" {
 | 
			
		||||
		db = db.Where("method = ?", api.Method)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if api.ApiGroup != "" {
 | 
			
		||||
		db = db.Where("api_group = ?", api.ApiGroup)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = db.Count(&total).Error
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return apiList, total, err
 | 
			
		||||
	} else {
 | 
			
		||||
		db = db.Limit(limit).Offset(offset)
 | 
			
		||||
		if order != "" {
 | 
			
		||||
			var OrderStr string
 | 
			
		||||
			// 设置有效排序key 防止sql注入
 | 
			
		||||
			// 感谢 Tom4t0 提交漏洞信息
 | 
			
		||||
			orderMap := make(map[string]bool, 5)
 | 
			
		||||
			orderMap["id"] = true
 | 
			
		||||
			orderMap["path"] = true
 | 
			
		||||
			orderMap["api_group"] = true
 | 
			
		||||
			orderMap["description"] = true
 | 
			
		||||
			orderMap["method"] = true
 | 
			
		||||
			if orderMap[order] {
 | 
			
		||||
				if desc {
 | 
			
		||||
					OrderStr = order + " desc"
 | 
			
		||||
				} else {
 | 
			
		||||
					OrderStr = order
 | 
			
		||||
				}
 | 
			
		||||
			} else { // didn't match any order key in `orderMap`
 | 
			
		||||
				err = fmt.Errorf("非法的排序字段: %v", order)
 | 
			
		||||
				return apiList, total, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err = db.Order(OrderStr).Find(&apiList).Error
 | 
			
		||||
		} else {
 | 
			
		||||
			err = db.Order("api_group").Find(&apiList).Error
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return apiList, total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetAllApis
 | 
			
		||||
//@description: 获取所有的api
 | 
			
		||||
//@return:  apis []model.SysApi, err error
 | 
			
		||||
 | 
			
		||||
func (apiService *ApiService) GetAllApis() (apis []system.SysApi, err error) {
 | 
			
		||||
	err = global.GVA_DB.Find(&apis).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetApiById
 | 
			
		||||
//@description: 根据id获取api
 | 
			
		||||
//@param: id float64
 | 
			
		||||
//@return: api model.SysApi, err error
 | 
			
		||||
 | 
			
		||||
func (apiService *ApiService) GetApiById(id int) (api system.SysApi, err error) {
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", id).First(&api).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: UpdateApi
 | 
			
		||||
//@description: 根据id更新api
 | 
			
		||||
//@param: api model.SysApi
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (apiService *ApiService) UpdateApi(api system.SysApi) (err error) {
 | 
			
		||||
	var oldA system.SysApi
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", api.ID).First(&oldA).Error
 | 
			
		||||
	if oldA.Path != api.Path || oldA.Method != api.Method {
 | 
			
		||||
		if !errors.Is(global.GVA_DB.Where("path = ? AND method = ?", api.Path, api.Method).First(&system.SysApi{}).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
			return errors.New("存在相同api路径")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else {
 | 
			
		||||
		err = CasbinServiceApp.UpdateCasbinApi(oldA.Path, api.Path, oldA.Method, api.Method)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		} else {
 | 
			
		||||
			err = global.GVA_DB.Save(&api).Error
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteApis
 | 
			
		||||
//@description: 删除选中API
 | 
			
		||||
//@param: apis []model.SysApi
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (apiService *ApiService) DeleteApisByIds(ids request.IdsReq) (err error) {
 | 
			
		||||
	var apis []system.SysApi
 | 
			
		||||
	err = global.GVA_DB.Find(&apis, "id in ?", ids.Ids).Delete(&apis).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else {
 | 
			
		||||
		for _, sysApi := range apis {
 | 
			
		||||
			CasbinServiceApp.ClearCasbin(1, sysApi.Path, sysApi.Method)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteApis
 | 
			
		||||
//@description: 删除选中API
 | 
			
		||||
//@param: apis []model.SysApi
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (apiService *ApiService) FreshCasbin() (err error) {
 | 
			
		||||
	e := CasbinServiceApp.Casbin()
 | 
			
		||||
	err = e.LoadPolicy()
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								service/system/sys_authority.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								service/system/sys_authority.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/common/request"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/model/system/response"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var ErrRoleExistence = errors.New("存在相同角色id")
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: CreateAuthority
 | 
			
		||||
//@description: 创建一个角色
 | 
			
		||||
//@param: auth model.SysAuthority
 | 
			
		||||
//@return: authority system.SysAuthority, err error
 | 
			
		||||
 | 
			
		||||
type AuthorityService struct{}
 | 
			
		||||
 | 
			
		||||
var AuthorityServiceApp = new(AuthorityService)
 | 
			
		||||
 | 
			
		||||
func (authorityService *AuthorityService) CreateAuthority(auth system.SysAuthority) (authority system.SysAuthority, err error) {
 | 
			
		||||
	var authorityBox system.SysAuthority
 | 
			
		||||
	if !errors.Is(global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&authorityBox).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return auth, ErrRoleExistence
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Create(&auth).Error
 | 
			
		||||
	return auth, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: CopyAuthority
 | 
			
		||||
//@description: 复制一个角色
 | 
			
		||||
//@param: copyInfo response.SysAuthorityCopyResponse
 | 
			
		||||
//@return: authority system.SysAuthority, err error
 | 
			
		||||
 | 
			
		||||
func (authorityService *AuthorityService) CopyAuthority(copyInfo response.SysAuthorityCopyResponse) (authority system.SysAuthority, err error) {
 | 
			
		||||
	var authorityBox system.SysAuthority
 | 
			
		||||
	if !errors.Is(global.GVA_DB.Where("authority_id = ?", copyInfo.Authority.AuthorityId).First(&authorityBox).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return authority, ErrRoleExistence
 | 
			
		||||
	}
 | 
			
		||||
	copyInfo.Authority.Children = []system.SysAuthority{}
 | 
			
		||||
	menus, err := MenuServiceApp.GetMenuAuthority(&request.GetAuthorityId{AuthorityId: int(copyInfo.OldAuthorityId)})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var baseMenu []system.SysBaseMenu
 | 
			
		||||
	for _, v := range menus {
 | 
			
		||||
		intNum, _ := strconv.Atoi(v.MenuId)
 | 
			
		||||
		v.SysBaseMenu.ID = uint(intNum)
 | 
			
		||||
		baseMenu = append(baseMenu, v.SysBaseMenu)
 | 
			
		||||
	}
 | 
			
		||||
	copyInfo.Authority.SysBaseMenus = baseMenu
 | 
			
		||||
	err = global.GVA_DB.Create(©Info.Authority).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var btns []system.SysAuthorityBtn
 | 
			
		||||
 | 
			
		||||
	err = global.GVA_DB.Find(&btns, "authority_id = ?", copyInfo.OldAuthorityId).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if len(btns) > 0 {
 | 
			
		||||
		for i := range btns {
 | 
			
		||||
			btns[i].AuthorityId = copyInfo.Authority.AuthorityId
 | 
			
		||||
		}
 | 
			
		||||
		err = global.GVA_DB.Create(&btns).Error
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	paths := CasbinServiceApp.GetPolicyPathByAuthorityId(copyInfo.OldAuthorityId)
 | 
			
		||||
	err = CasbinServiceApp.UpdateCasbin(copyInfo.Authority.AuthorityId, paths)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		_ = authorityService.DeleteAuthority(©Info.Authority)
 | 
			
		||||
	}
 | 
			
		||||
	return copyInfo.Authority, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: UpdateAuthority
 | 
			
		||||
//@description: 更改一个角色
 | 
			
		||||
//@param: auth model.SysAuthority
 | 
			
		||||
//@return: authority system.SysAuthority, err error
 | 
			
		||||
 | 
			
		||||
func (authorityService *AuthorityService) UpdateAuthority(auth system.SysAuthority) (authority system.SysAuthority, err error) {
 | 
			
		||||
	err = global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&system.SysAuthority{}).Updates(&auth).Error
 | 
			
		||||
	return auth, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteAuthority
 | 
			
		||||
//@description: 删除角色
 | 
			
		||||
//@param: auth *model.SysAuthority
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (authorityService *AuthorityService) DeleteAuthority(auth *system.SysAuthority) (err error) {
 | 
			
		||||
	if errors.Is(global.GVA_DB.Debug().Preload("Users").First(&auth).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return errors.New("该角色不存在")
 | 
			
		||||
	}
 | 
			
		||||
	if len(auth.Users) != 0 {
 | 
			
		||||
		return errors.New("此角色有用户正在使用禁止删除")
 | 
			
		||||
	}
 | 
			
		||||
	if !errors.Is(global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&system.SysUser{}).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return errors.New("此角色有用户正在使用禁止删除")
 | 
			
		||||
	}
 | 
			
		||||
	if !errors.Is(global.GVA_DB.Where("parent_id = ?", auth.AuthorityId).First(&system.SysAuthority{}).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return errors.New("此角色存在子角色不允许删除")
 | 
			
		||||
	}
 | 
			
		||||
	db := global.GVA_DB.Preload("SysBaseMenus").Preload("DataAuthorityId").Where("authority_id = ?", auth.AuthorityId).First(auth)
 | 
			
		||||
	err = db.Unscoped().Delete(auth).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if len(auth.SysBaseMenus) > 0 {
 | 
			
		||||
		err = global.GVA_DB.Model(auth).Association("SysBaseMenus").Delete(auth.SysBaseMenus)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// err = db.Association("SysBaseMenus").Delete(&auth)
 | 
			
		||||
	}
 | 
			
		||||
	if len(auth.DataAuthorityId) > 0 {
 | 
			
		||||
		err = global.GVA_DB.Model(auth).Association("DataAuthorityId").Delete(auth.DataAuthorityId)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Delete(&[]system.SysUserAuthority{}, "sys_authority_authority_id = ?", auth.AuthorityId).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Delete(&[]system.SysAuthorityBtn{}, "authority_id = ?", auth.AuthorityId).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	authorityId := strconv.Itoa(int(auth.AuthorityId))
 | 
			
		||||
	CasbinServiceApp.ClearCasbin(0, authorityId)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetAuthorityInfoList
 | 
			
		||||
//@description: 分页获取数据
 | 
			
		||||
//@param: info request.PageInfo
 | 
			
		||||
//@return: list interface{}, total int64, err error
 | 
			
		||||
 | 
			
		||||
func (authorityService *AuthorityService) GetAuthorityInfoList(info request.PageInfo) (list interface{}, total int64, err error) {
 | 
			
		||||
	limit := info.PageSize
 | 
			
		||||
	offset := info.PageSize * (info.Page - 1)
 | 
			
		||||
	db := global.GVA_DB.Model(&system.SysAuthority{})
 | 
			
		||||
	if err = db.Where("parent_id = ?", "0").Count(&total).Error; total == 0 || err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var authority []system.SysAuthority
 | 
			
		||||
	err = db.Limit(limit).Offset(offset).Preload("DataAuthorityId").Where("parent_id = ?", "0").Find(&authority).Error
 | 
			
		||||
	for k := range authority {
 | 
			
		||||
		err = authorityService.findChildrenAuthority(&authority[k])
 | 
			
		||||
	}
 | 
			
		||||
	return authority, total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetAuthorityInfo
 | 
			
		||||
//@description: 获取所有角色信息
 | 
			
		||||
//@param: auth model.SysAuthority
 | 
			
		||||
//@return: sa system.SysAuthority, err error
 | 
			
		||||
 | 
			
		||||
func (authorityService *AuthorityService) GetAuthorityInfo(auth system.SysAuthority) (sa system.SysAuthority, err error) {
 | 
			
		||||
	err = global.GVA_DB.Preload("DataAuthorityId").Where("authority_id = ?", auth.AuthorityId).First(&sa).Error
 | 
			
		||||
	return sa, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: SetDataAuthority
 | 
			
		||||
//@description: 设置角色资源权限
 | 
			
		||||
//@param: auth model.SysAuthority
 | 
			
		||||
//@return: error
 | 
			
		||||
 | 
			
		||||
func (authorityService *AuthorityService) SetDataAuthority(auth system.SysAuthority) error {
 | 
			
		||||
	var s system.SysAuthority
 | 
			
		||||
	global.GVA_DB.Preload("DataAuthorityId").First(&s, "authority_id = ?", auth.AuthorityId)
 | 
			
		||||
	err := global.GVA_DB.Model(&s).Association("DataAuthorityId").Replace(&auth.DataAuthorityId)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: SetMenuAuthority
 | 
			
		||||
//@description: 菜单与角色绑定
 | 
			
		||||
//@param: auth *model.SysAuthority
 | 
			
		||||
//@return: error
 | 
			
		||||
 | 
			
		||||
func (authorityService *AuthorityService) SetMenuAuthority(auth *system.SysAuthority) error {
 | 
			
		||||
	var s system.SysAuthority
 | 
			
		||||
	global.GVA_DB.Preload("SysBaseMenus").First(&s, "authority_id = ?", auth.AuthorityId)
 | 
			
		||||
	err := global.GVA_DB.Model(&s).Association("SysBaseMenus").Replace(&auth.SysBaseMenus)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: findChildrenAuthority
 | 
			
		||||
//@description: 查询子角色
 | 
			
		||||
//@param: authority *model.SysAuthority
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (authorityService *AuthorityService) findChildrenAuthority(authority *system.SysAuthority) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Preload("DataAuthorityId").Where("parent_id = ?", authority.AuthorityId).Find(&authority.Children).Error
 | 
			
		||||
	if len(authority.Children) > 0 {
 | 
			
		||||
		for k := range authority.Children {
 | 
			
		||||
			err = authorityService.findChildrenAuthority(&authority.Children[k])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								service/system/sys_authority_btn.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								service/system/sys_authority_btn.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/model/system/request"
 | 
			
		||||
	"miniapp/model/system/response"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AuthorityBtnService struct{}
 | 
			
		||||
 | 
			
		||||
func (a *AuthorityBtnService) GetAuthorityBtn(req request.SysAuthorityBtnReq) (res response.SysAuthorityBtnRes, err error) {
 | 
			
		||||
	var authorityBtn []system.SysAuthorityBtn
 | 
			
		||||
	err = global.GVA_DB.Find(&authorityBtn, "authority_id = ? and sys_menu_id = ?", req.AuthorityId, req.MenuID).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var selected []uint
 | 
			
		||||
	for _, v := range authorityBtn {
 | 
			
		||||
		selected = append(selected, v.SysBaseMenuBtnID)
 | 
			
		||||
	}
 | 
			
		||||
	res.Selected = selected
 | 
			
		||||
	return res, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AuthorityBtnService) SetAuthorityBtn(req request.SysAuthorityBtnReq) (err error) {
 | 
			
		||||
	return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
 | 
			
		||||
		var authorityBtn []system.SysAuthorityBtn
 | 
			
		||||
		err = tx.Delete(&[]system.SysAuthorityBtn{}, "authority_id = ? and sys_menu_id = ?", req.AuthorityId, req.MenuID).Error
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		for _, v := range req.Selected {
 | 
			
		||||
			authorityBtn = append(authorityBtn, system.SysAuthorityBtn{
 | 
			
		||||
				AuthorityId:      req.AuthorityId,
 | 
			
		||||
				SysMenuID:        req.MenuID,
 | 
			
		||||
				SysBaseMenuBtnID: v,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		if len(authorityBtn) > 0 {
 | 
			
		||||
			err = tx.Create(&authorityBtn).Error
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AuthorityBtnService) CanRemoveAuthorityBtn(ID string) (err error) {
 | 
			
		||||
	fErr := global.GVA_DB.First(&system.SysAuthorityBtn{}, "sys_base_menu_btn_id = ?", ID).Error
 | 
			
		||||
	if errors.Is(fErr, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return errors.New("此按钮正在被使用无法删除")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										958
									
								
								service/system/sys_auto_code.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										958
									
								
								service/system/sys_auto_code.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,958 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"archive/zip"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"mime/multipart"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"text/template"
 | 
			
		||||
 | 
			
		||||
	ast2 "miniapp/utils/ast"
 | 
			
		||||
 | 
			
		||||
	cp "github.com/otiai10/copy"
 | 
			
		||||
	"go.uber.org/zap"
 | 
			
		||||
	"miniapp/resource/autocode_template/subcontract"
 | 
			
		||||
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/utils"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	autoPath           = "autocode_template/"
 | 
			
		||||
	autocodePath       = "resource/autocode_template"
 | 
			
		||||
	plugPath           = "resource/plug_template"
 | 
			
		||||
	packageService     = "service/%s/enter.go"
 | 
			
		||||
	packageServiceName = "service"
 | 
			
		||||
	packageRouter      = "router/%s/enter.go"
 | 
			
		||||
	packageRouterName  = "router"
 | 
			
		||||
	packageAPI         = "api/v1/%s/enter.go"
 | 
			
		||||
	packageAPIName     = "api/v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type autoPackage struct {
 | 
			
		||||
	path string
 | 
			
		||||
	temp string
 | 
			
		||||
	name string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	packageInjectionMap map[string]astInjectionMeta
 | 
			
		||||
	injectionPaths      []injectionMeta
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Init(Package string) {
 | 
			
		||||
	injectionPaths = []injectionMeta{
 | 
			
		||||
		{
 | 
			
		||||
			path: filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SApi, Package), "enter.go"),
 | 
			
		||||
			funcName:    "ApiGroup",
 | 
			
		||||
			structNameF: "%sApi",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			path: filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SRouter, Package), "enter.go"),
 | 
			
		||||
			funcName:    "RouterGroup",
 | 
			
		||||
			structNameF: "%sRouter",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			path: filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SService, Package), "enter.go"),
 | 
			
		||||
			funcName:    "ServiceGroup",
 | 
			
		||||
			structNameF: "%sService",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	packageInjectionMap = map[string]astInjectionMeta{
 | 
			
		||||
		packageServiceName: {
 | 
			
		||||
			path: filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, "service", "enter.go"),
 | 
			
		||||
			importCodeF:  "miniapp/%s/%s",
 | 
			
		||||
			packageNameF: "%s",
 | 
			
		||||
			groupName:    "ServiceGroup",
 | 
			
		||||
			structNameF:  "%sServiceGroup",
 | 
			
		||||
		},
 | 
			
		||||
		packageRouterName: {
 | 
			
		||||
			path: filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, "router", "enter.go"),
 | 
			
		||||
			importCodeF:  "miniapp/%s/%s",
 | 
			
		||||
			packageNameF: "%s",
 | 
			
		||||
			groupName:    "RouterGroup",
 | 
			
		||||
			structNameF:  "%s",
 | 
			
		||||
		},
 | 
			
		||||
		packageAPIName: {
 | 
			
		||||
			path: filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, "api/v1", "enter.go"),
 | 
			
		||||
			importCodeF:  "miniapp/%s/%s",
 | 
			
		||||
			packageNameF: "%s",
 | 
			
		||||
			groupName:    "ApiGroup",
 | 
			
		||||
			structNameF:  "%sApiGroup",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type injectionMeta struct {
 | 
			
		||||
	path        string
 | 
			
		||||
	funcName    string
 | 
			
		||||
	structNameF string // 带格式化的
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type astInjectionMeta struct {
 | 
			
		||||
	path         string
 | 
			
		||||
	importCodeF  string
 | 
			
		||||
	structNameF  string
 | 
			
		||||
	packageNameF string
 | 
			
		||||
	groupName    string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type tplData struct {
 | 
			
		||||
	template         *template.Template
 | 
			
		||||
	autoPackage      string
 | 
			
		||||
	locationPath     string
 | 
			
		||||
	autoCodePath     string
 | 
			
		||||
	autoMoveFilePath string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AutoCodeService struct{}
 | 
			
		||||
 | 
			
		||||
var AutoCodeServiceApp = new(AutoCodeService)
 | 
			
		||||
 | 
			
		||||
// @author: [songzhibin97](https://github.com/songzhibin97)
 | 
			
		||||
// @function: PreviewTemp
 | 
			
		||||
// @description: 预览创建代码
 | 
			
		||||
// @param: model.AutoCodeStruct
 | 
			
		||||
// @return: map[string]string, error
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) PreviewTemp(autoCode system.AutoCodeStruct) (map[string]string, error) {
 | 
			
		||||
	makeDictTypes(&autoCode)
 | 
			
		||||
	for i := range autoCode.Fields {
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "time.Time" {
 | 
			
		||||
			autoCode.HasTimer = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].Require {
 | 
			
		||||
			autoCode.NeedValid = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].Sort {
 | 
			
		||||
			autoCode.NeedSort = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "picture" {
 | 
			
		||||
			autoCode.HasPic = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "video" {
 | 
			
		||||
			autoCode.HasPic = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "richtext" {
 | 
			
		||||
			autoCode.HasRichText = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "pictures" {
 | 
			
		||||
			autoCode.HasPic = true
 | 
			
		||||
			autoCode.NeedJSON = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "file" {
 | 
			
		||||
			autoCode.HasFile = true
 | 
			
		||||
			autoCode.NeedJSON = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	dataList, _, needMkdir, err := autoCodeService.getNeedList(&autoCode)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 写入文件前,先创建文件夹
 | 
			
		||||
	if err = utils.CreateDir(needMkdir...); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 创建map
 | 
			
		||||
	ret := make(map[string]string)
 | 
			
		||||
 | 
			
		||||
	// 生成map
 | 
			
		||||
	for _, value := range dataList {
 | 
			
		||||
		ext := ""
 | 
			
		||||
		if ext = filepath.Ext(value.autoCodePath); ext == ".txt" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		f, err := os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_WRONLY, 0o755)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err = value.template.Execute(f, autoCode); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		_ = f.Close()
 | 
			
		||||
		f, err = os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_RDONLY, 0o755)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		builder := strings.Builder{}
 | 
			
		||||
		builder.WriteString("```")
 | 
			
		||||
 | 
			
		||||
		if ext != "" && strings.Contains(ext, ".") {
 | 
			
		||||
			builder.WriteString(strings.Replace(ext, ".", "", -1))
 | 
			
		||||
		}
 | 
			
		||||
		builder.WriteString("\n\n")
 | 
			
		||||
		data, err := io.ReadAll(f)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		builder.Write(data)
 | 
			
		||||
		builder.WriteString("\n\n```")
 | 
			
		||||
 | 
			
		||||
		pathArr := strings.Split(value.autoCodePath, string(os.PathSeparator))
 | 
			
		||||
		ret[pathArr[1]+"-"+pathArr[3]] = builder.String()
 | 
			
		||||
		_ = f.Close()
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	defer func() { // 移除中间文件
 | 
			
		||||
		if err := os.RemoveAll(autoPath); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	return ret, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeDictTypes(autoCode *system.AutoCodeStruct) {
 | 
			
		||||
	DictTypeM := make(map[string]string)
 | 
			
		||||
	for _, v := range autoCode.Fields {
 | 
			
		||||
		if v.DictType != "" {
 | 
			
		||||
			DictTypeM[v.DictType] = ""
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for k := range DictTypeM {
 | 
			
		||||
		autoCode.DictTypes = append(autoCode.DictTypes, k)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// @function: CreateTemp
 | 
			
		||||
// @description: 创建代码
 | 
			
		||||
// @param: model.AutoCodeStruct
 | 
			
		||||
// @return: err error
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) CreateTemp(autoCode system.AutoCodeStruct, ids ...uint) (err error) {
 | 
			
		||||
	makeDictTypes(&autoCode)
 | 
			
		||||
	for i := range autoCode.Fields {
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "time.Time" {
 | 
			
		||||
			autoCode.HasTimer = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].Require {
 | 
			
		||||
			autoCode.NeedValid = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].Sort {
 | 
			
		||||
			autoCode.NeedSort = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "picture" {
 | 
			
		||||
			autoCode.HasPic = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "video" {
 | 
			
		||||
			autoCode.HasPic = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "richtext" {
 | 
			
		||||
			autoCode.HasRichText = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "pictures" {
 | 
			
		||||
			autoCode.NeedJSON = true
 | 
			
		||||
			autoCode.HasPic = true
 | 
			
		||||
		}
 | 
			
		||||
		if autoCode.Fields[i].FieldType == "file" {
 | 
			
		||||
			autoCode.NeedJSON = true
 | 
			
		||||
			autoCode.HasFile = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// 增加判断: 重复创建struct
 | 
			
		||||
	if autoCode.AutoMoveFile && AutoCodeHistoryServiceApp.Repeat(autoCode.BusinessDB, autoCode.StructName, autoCode.Package) {
 | 
			
		||||
		return RepeatErr
 | 
			
		||||
	}
 | 
			
		||||
	dataList, fileList, needMkdir, err := autoCodeService.getNeedList(&autoCode)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	meta, _ := json.Marshal(autoCode)
 | 
			
		||||
	// 写入文件前,先创建文件夹
 | 
			
		||||
	if err = utils.CreateDir(needMkdir...); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 生成文件
 | 
			
		||||
	for _, value := range dataList {
 | 
			
		||||
		f, err := os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_WRONLY, 0o755)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if err = value.template.Execute(f, autoCode); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		_ = f.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer func() { // 移除中间文件
 | 
			
		||||
		if err := os.RemoveAll(autoPath); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	bf := strings.Builder{}
 | 
			
		||||
	idBf := strings.Builder{}
 | 
			
		||||
	injectionCodeMeta := strings.Builder{}
 | 
			
		||||
	for _, id := range ids {
 | 
			
		||||
		idBf.WriteString(strconv.Itoa(int(id)))
 | 
			
		||||
		idBf.WriteString(";")
 | 
			
		||||
	}
 | 
			
		||||
	if autoCode.AutoMoveFile { // 判断是否需要自动转移
 | 
			
		||||
		Init(autoCode.Package)
 | 
			
		||||
		for index := range dataList {
 | 
			
		||||
			autoCodeService.addAutoMoveFile(&dataList[index])
 | 
			
		||||
		}
 | 
			
		||||
		// 判断目标文件是否都可以移动
 | 
			
		||||
		for _, value := range dataList {
 | 
			
		||||
			if utils.FileExist(value.autoMoveFilePath) {
 | 
			
		||||
				return errors.New(fmt.Sprintf("目标文件已存在:%s\n", value.autoMoveFilePath))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for _, value := range dataList { // 移动文件
 | 
			
		||||
			if err := utils.FileMove(value.autoCodePath, value.autoMoveFilePath); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			// 在gorm.go 注入 自动迁移
 | 
			
		||||
			path := filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "gorm.go")
 | 
			
		||||
			varDB := utils.MaheHump(autoCode.BusinessDB)
 | 
			
		||||
			ast2.AddRegisterTablesAst(path, "RegisterTables", autoCode.Package, varDB, autoCode.BusinessDB, autoCode.StructName)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			// router.go 注入 自动迁移
 | 
			
		||||
			path := filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "router.go")
 | 
			
		||||
			ast2.AddRouterCode(path, "Routers", autoCode.Package, autoCode.StructName)
 | 
			
		||||
		}
 | 
			
		||||
		// 给各个enter进行注入
 | 
			
		||||
		err = injectionCode(autoCode.StructName, &injectionCodeMeta)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// 保存生成信息
 | 
			
		||||
		for _, data := range dataList {
 | 
			
		||||
			if len(data.autoMoveFilePath) != 0 {
 | 
			
		||||
				bf.WriteString(data.autoMoveFilePath)
 | 
			
		||||
				bf.WriteString(";")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else { // 打包
 | 
			
		||||
		if err = utils.ZipFiles("./ginvueadmin.zip", fileList, ".", "."); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if autoCode.AutoMoveFile || autoCode.AutoCreateApiToSql {
 | 
			
		||||
		if autoCode.TableName != "" {
 | 
			
		||||
			err = AutoCodeHistoryServiceApp.CreateAutoCodeHistory(
 | 
			
		||||
				string(meta),
 | 
			
		||||
				autoCode.StructName,
 | 
			
		||||
				autoCode.Description,
 | 
			
		||||
				bf.String(),
 | 
			
		||||
				injectionCodeMeta.String(),
 | 
			
		||||
				autoCode.TableName,
 | 
			
		||||
				idBf.String(),
 | 
			
		||||
				autoCode.Package,
 | 
			
		||||
				autoCode.BusinessDB,
 | 
			
		||||
			)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = AutoCodeHistoryServiceApp.CreateAutoCodeHistory(
 | 
			
		||||
				string(meta),
 | 
			
		||||
				autoCode.StructName,
 | 
			
		||||
				autoCode.Description,
 | 
			
		||||
				bf.String(),
 | 
			
		||||
				injectionCodeMeta.String(),
 | 
			
		||||
				autoCode.StructName,
 | 
			
		||||
				idBf.String(),
 | 
			
		||||
				autoCode.Package,
 | 
			
		||||
				autoCode.BusinessDB,
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if autoCode.AutoMoveFile {
 | 
			
		||||
		return system.ErrAutoMove
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// @function: GetAllTplFile
 | 
			
		||||
// @description: 获取 pathName 文件夹下所有 tpl 文件
 | 
			
		||||
// @param: pathName string, fileList []string
 | 
			
		||||
// @return: []string, error
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) GetAllTplFile(pathName string, fileList []string) ([]string, error) {
 | 
			
		||||
	files, err := os.ReadDir(pathName)
 | 
			
		||||
	for _, fi := range files {
 | 
			
		||||
		if fi.IsDir() {
 | 
			
		||||
			fileList, err = autoCodeService.GetAllTplFile(pathName+"/"+fi.Name(), fileList)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if strings.HasSuffix(fi.Name(), ".tpl") {
 | 
			
		||||
				fileList = append(fileList, pathName+"/"+fi.Name())
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return fileList, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// @function: GetDB
 | 
			
		||||
// @description: 获取指定数据库和指定数据表的所有字段名,类型值等
 | 
			
		||||
// @param: tableName string, dbName string
 | 
			
		||||
// @return: err error, Columns []request.ColumnReq
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) DropTable(BusinessDb, tableName string) error {
 | 
			
		||||
	if BusinessDb != "" {
 | 
			
		||||
		return global.MustGetGlobalDBByDBName(BusinessDb).Exec("DROP TABLE " + tableName).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		return global.GVA_DB.Exec("DROP TABLE " + tableName).Error
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @author: [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
// @author: [songzhibin97](https://github.com/songzhibin97)
 | 
			
		||||
// @function: addAutoMoveFile
 | 
			
		||||
// @description: 生成对应的迁移文件路径
 | 
			
		||||
// @param: *tplData
 | 
			
		||||
// @return: null
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) addAutoMoveFile(data *tplData) {
 | 
			
		||||
	base := filepath.Base(data.autoCodePath)
 | 
			
		||||
	fileSlice := strings.Split(data.autoCodePath, string(os.PathSeparator))
 | 
			
		||||
	n := len(fileSlice)
 | 
			
		||||
	if n <= 2 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if strings.Contains(fileSlice[1], "server.exe.exe") {
 | 
			
		||||
		if strings.Contains(fileSlice[n-2], "router") {
 | 
			
		||||
			data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server,
 | 
			
		||||
				fmt.Sprintf(global.GVA_CONFIG.AutoCode.SRouter, data.autoPackage), base)
 | 
			
		||||
		} else if strings.Contains(fileSlice[n-2], "api") {
 | 
			
		||||
			data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SApi, data.autoPackage), base)
 | 
			
		||||
		} else if strings.Contains(fileSlice[n-2], "service") {
 | 
			
		||||
			data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SService, data.autoPackage), base)
 | 
			
		||||
		} else if strings.Contains(fileSlice[n-2], "model") {
 | 
			
		||||
			data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SModel, data.autoPackage), base)
 | 
			
		||||
		} else if strings.Contains(fileSlice[n-2], "request") {
 | 
			
		||||
			data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SRequest, data.autoPackage), base)
 | 
			
		||||
		}
 | 
			
		||||
	} else if strings.Contains(fileSlice[1], "web") {
 | 
			
		||||
		if strings.Contains(fileSlice[n-1], "js") {
 | 
			
		||||
			data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Web, global.GVA_CONFIG.AutoCode.WApi, base)
 | 
			
		||||
		} else if strings.Contains(fileSlice[n-2], "form") {
 | 
			
		||||
			data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Web, global.GVA_CONFIG.AutoCode.WForm, filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), strings.TrimSuffix(base, filepath.Ext(base))+"Form.vue")
 | 
			
		||||
		} else if strings.Contains(fileSlice[n-2], "table") {
 | 
			
		||||
			data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
				global.GVA_CONFIG.AutoCode.Web, global.GVA_CONFIG.AutoCode.WTable, filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), base)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// @author: [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
// @function: CreateApi
 | 
			
		||||
// @description: 自动创建api数据,
 | 
			
		||||
// @param: a *model.AutoCodeStruct
 | 
			
		||||
// @return: err error
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) AutoCreateApi(a *system.AutoCodeStruct) (ids []uint, err error) {
 | 
			
		||||
	apiList := []system.SysApi{
 | 
			
		||||
		{
 | 
			
		||||
			Path:        "/" + a.Abbreviation + "/" + "create" + a.StructName,
 | 
			
		||||
			Description: "新增" + a.Description,
 | 
			
		||||
			ApiGroup:    a.Description,
 | 
			
		||||
			Method:      "POST",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Path:        "/" + a.Abbreviation + "/" + "delete" + a.StructName,
 | 
			
		||||
			Description: "删除" + a.Description,
 | 
			
		||||
			ApiGroup:    a.Description,
 | 
			
		||||
			Method:      "DELETE",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Path:        "/" + a.Abbreviation + "/" + "delete" + a.StructName + "ByIds",
 | 
			
		||||
			Description: "批量删除" + a.Description,
 | 
			
		||||
			ApiGroup:    a.Description,
 | 
			
		||||
			Method:      "DELETE",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Path:        "/" + a.Abbreviation + "/" + "update" + a.StructName,
 | 
			
		||||
			Description: "更新" + a.Description,
 | 
			
		||||
			ApiGroup:    a.Description,
 | 
			
		||||
			Method:      "PUT",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Path:        "/" + a.Abbreviation + "/" + "find" + a.StructName,
 | 
			
		||||
			Description: "根据ID获取" + a.Description,
 | 
			
		||||
			ApiGroup:    a.Description,
 | 
			
		||||
			Method:      "GET",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Path:        "/" + a.Abbreviation + "/" + "get" + a.StructName + "List",
 | 
			
		||||
			Description: "获取" + a.Description + "列表",
 | 
			
		||||
			ApiGroup:    a.Description,
 | 
			
		||||
			Method:      "GET",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
 | 
			
		||||
		for _, v := range apiList {
 | 
			
		||||
			var api system.SysApi
 | 
			
		||||
			if errors.Is(tx.Where("path = ? AND method = ?", v.Path, v.Method).First(&api).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
				if err = tx.Create(&v).Error; err != nil { // 遇到错误时回滚事务
 | 
			
		||||
					return err
 | 
			
		||||
				} else {
 | 
			
		||||
					ids = append(ids, v.ID)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
	return ids, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) getNeedList(autoCode *system.AutoCodeStruct) (dataList []tplData, fileList []string, needMkdir []string, err error) {
 | 
			
		||||
	// 去除所有空格
 | 
			
		||||
	utils.TrimSpace(autoCode)
 | 
			
		||||
	for _, field := range autoCode.Fields {
 | 
			
		||||
		utils.TrimSpace(field)
 | 
			
		||||
	}
 | 
			
		||||
	// 获取 basePath 文件夹下所有tpl文件
 | 
			
		||||
	tplFileList, err := autoCodeService.GetAllTplFile(autocodePath, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	dataList = make([]tplData, 0, len(tplFileList))
 | 
			
		||||
	fileList = make([]string, 0, len(tplFileList))
 | 
			
		||||
	needMkdir = make([]string, 0, len(tplFileList)) // 当文件夹下存在多个tpl文件时,改为map更合理
 | 
			
		||||
	// 根据文件路径生成 tplData 结构体,待填充数据
 | 
			
		||||
	for _, value := range tplFileList {
 | 
			
		||||
		dataList = append(dataList, tplData{locationPath: value, autoPackage: autoCode.Package})
 | 
			
		||||
	}
 | 
			
		||||
	// 生成 *Template, 填充 template 字段
 | 
			
		||||
	for index, value := range dataList {
 | 
			
		||||
		dataList[index].template, err = template.ParseFiles(value.locationPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// 生成文件路径,填充 autoCodePath 字段,readme.txt.tpl不符合规则,需要特殊处理
 | 
			
		||||
	// resource/template/web/api.js.tpl -> autoCode/web/autoCode.PackageName/api/autoCode.PackageName.js
 | 
			
		||||
	// resource/template/readme.txt.tpl -> autoCode/readme.txt
 | 
			
		||||
	for index, value := range dataList {
 | 
			
		||||
		trimBase := strings.TrimPrefix(value.locationPath, autocodePath+"/")
 | 
			
		||||
		if trimBase == "readme.txt.tpl" {
 | 
			
		||||
			dataList[index].autoCodePath = autoPath + "readme.txt"
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if lastSeparator := strings.LastIndex(trimBase, "/"); lastSeparator != -1 {
 | 
			
		||||
			origFileName := strings.TrimSuffix(trimBase[lastSeparator+1:], ".tpl")
 | 
			
		||||
			firstDot := strings.Index(origFileName, ".")
 | 
			
		||||
			if firstDot != -1 {
 | 
			
		||||
				var fileName string
 | 
			
		||||
				if origFileName[firstDot:] != ".go" {
 | 
			
		||||
					fileName = autoCode.PackageName + origFileName[firstDot:]
 | 
			
		||||
				} else {
 | 
			
		||||
					fileName = autoCode.HumpPackageName + origFileName[firstDot:]
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				dataList[index].autoCodePath = filepath.Join(autoPath, trimBase[:lastSeparator], autoCode.PackageName,
 | 
			
		||||
					origFileName[:firstDot], fileName)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if lastSeparator := strings.LastIndex(dataList[index].autoCodePath, string(os.PathSeparator)); lastSeparator != -1 {
 | 
			
		||||
			needMkdir = append(needMkdir, dataList[index].autoCodePath[:lastSeparator])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, value := range dataList {
 | 
			
		||||
		fileList = append(fileList, value.autoCodePath)
 | 
			
		||||
	}
 | 
			
		||||
	return dataList, fileList, needMkdir, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// injectionCode 封装代码注入
 | 
			
		||||
func injectionCode(structName string, bf *strings.Builder) error {
 | 
			
		||||
	for _, meta := range injectionPaths {
 | 
			
		||||
		code := fmt.Sprintf(meta.structNameF, structName)
 | 
			
		||||
		ast2.ImportForAutoEnter(meta.path, meta.funcName, code)
 | 
			
		||||
		bf.WriteString(fmt.Sprintf("%s@%s@%s;", meta.path, meta.funcName, code))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) CreateAutoCode(s *system.SysAutoCode) error {
 | 
			
		||||
	if s.PackageName == "autocode" || s.PackageName == "system" || s.PackageName == "example" || s.PackageName == "" {
 | 
			
		||||
		return errors.New("不能使用已保留的package name")
 | 
			
		||||
	}
 | 
			
		||||
	if !errors.Is(global.GVA_DB.Where("package_name = ?", s.PackageName).First(&system.SysAutoCode{}).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return errors.New("存在相同PackageName")
 | 
			
		||||
	}
 | 
			
		||||
	if e := autoCodeService.CreatePackageTemp(s.PackageName); e != nil {
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	return global.GVA_DB.Create(&s).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) GetPackage() (pkgList []system.SysAutoCode, err error) {
 | 
			
		||||
	err = global.GVA_DB.Find(&pkgList).Error
 | 
			
		||||
	return pkgList, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) DelPackage(a system.SysAutoCode) error {
 | 
			
		||||
	return global.GVA_DB.Delete(&a).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) CreatePackageTemp(packageName string) error {
 | 
			
		||||
	Init(packageName)
 | 
			
		||||
	pendingTemp := []autoPackage{{
 | 
			
		||||
		path: packageService,
 | 
			
		||||
		name: packageServiceName,
 | 
			
		||||
		temp: string(subcontract.Server),
 | 
			
		||||
	}, {
 | 
			
		||||
		path: packageRouter,
 | 
			
		||||
		name: packageRouterName,
 | 
			
		||||
		temp: string(subcontract.Router),
 | 
			
		||||
	}, {
 | 
			
		||||
		path: packageAPI,
 | 
			
		||||
		name: packageAPIName,
 | 
			
		||||
		temp: string(subcontract.API),
 | 
			
		||||
	}}
 | 
			
		||||
	for i, s := range pendingTemp {
 | 
			
		||||
		pendingTemp[i].path = filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, filepath.Clean(fmt.Sprintf(s.path, packageName)))
 | 
			
		||||
	}
 | 
			
		||||
	// 选择模板
 | 
			
		||||
	for _, s := range pendingTemp {
 | 
			
		||||
		err := os.MkdirAll(filepath.Dir(s.path), 0755)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		f, err := os.Create(s.path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		defer f.Close()
 | 
			
		||||
 | 
			
		||||
		temp, err := template.New("").Parse(s.temp)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		err = temp.Execute(f, struct {
 | 
			
		||||
			PackageName string `json:"package_name"`
 | 
			
		||||
		}{packageName})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// 创建完成后在对应的位置插入结构代码
 | 
			
		||||
	for _, v := range pendingTemp {
 | 
			
		||||
		meta := packageInjectionMap[v.name]
 | 
			
		||||
		if err := ast2.ImportReference(meta.path, fmt.Sprintf(meta.importCodeF, v.name, packageName), fmt.Sprintf(meta.structNameF, utils.FirstUpper(packageName)), fmt.Sprintf(meta.packageNameF, packageName), meta.groupName); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreatePlug 自动创建插件模板
 | 
			
		||||
func (autoCodeService *AutoCodeService) CreatePlug(plug system.AutoPlugReq) error {
 | 
			
		||||
	// 检查列表参数是否有效
 | 
			
		||||
	plug.CheckList()
 | 
			
		||||
	tplFileList, _ := autoCodeService.GetAllTplFile(plugPath, nil)
 | 
			
		||||
	for _, tpl := range tplFileList {
 | 
			
		||||
		temp, err := template.ParseFiles(tpl)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			zap.L().Error("parse err", zap.String("tpl", tpl), zap.Error(err))
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		pathArr := strings.SplitAfter(tpl, "/")
 | 
			
		||||
		if strings.Index(pathArr[2], "tpl") < 0 {
 | 
			
		||||
			dirPath := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SPlug, plug.Snake+"/"+pathArr[2]))
 | 
			
		||||
			os.MkdirAll(dirPath, 0755)
 | 
			
		||||
		}
 | 
			
		||||
		file := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SPlug, plug.Snake+"/"+tpl[len(plugPath):len(tpl)-4]))
 | 
			
		||||
		f, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE, 0666)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			zap.L().Error("open file", zap.String("tpl", tpl), zap.Error(err), zap.Any("plug", plug))
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		defer f.Close()
 | 
			
		||||
 | 
			
		||||
		err = temp.Execute(f, plug)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			zap.L().Error("exec err", zap.String("tpl", tpl), zap.Error(err), zap.Any("plug", plug))
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) InstallPlugin(file *multipart.FileHeader) (web, server int, err error) {
 | 
			
		||||
	const GVAPLUGPINATH = "./gva-plug-temp/"
 | 
			
		||||
	defer os.RemoveAll(GVAPLUGPINATH)
 | 
			
		||||
	_, err = os.Stat(GVAPLUGPINATH)
 | 
			
		||||
	if os.IsNotExist(err) {
 | 
			
		||||
		os.Mkdir(GVAPLUGPINATH, os.ModePerm)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	src, err := file.Open()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, -1, err
 | 
			
		||||
	}
 | 
			
		||||
	defer src.Close()
 | 
			
		||||
 | 
			
		||||
	out, err := os.Create(GVAPLUGPINATH + file.Filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, -1, err
 | 
			
		||||
	}
 | 
			
		||||
	defer out.Close()
 | 
			
		||||
 | 
			
		||||
	_, err = io.Copy(out, src)
 | 
			
		||||
 | 
			
		||||
	paths, err := utils.Unzip(GVAPLUGPINATH+file.Filename, GVAPLUGPINATH)
 | 
			
		||||
	paths = filterFile(paths)
 | 
			
		||||
	var webIndex = -1
 | 
			
		||||
	var serverIndex = -1
 | 
			
		||||
	for i := range paths {
 | 
			
		||||
		paths[i] = filepath.ToSlash(paths[i])
 | 
			
		||||
		pathArr := strings.Split(paths[i], "/")
 | 
			
		||||
		ln := len(pathArr)
 | 
			
		||||
		if ln < 2 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if pathArr[ln-2] == "server.exe.exe" && pathArr[ln-1] == "plugin" {
 | 
			
		||||
			serverIndex = i
 | 
			
		||||
		}
 | 
			
		||||
		if pathArr[ln-2] == "web" && pathArr[ln-1] == "plugin" {
 | 
			
		||||
			webIndex = i
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if webIndex == -1 && serverIndex == -1 {
 | 
			
		||||
		zap.L().Error("非标准插件,请按照文档自动迁移使用")
 | 
			
		||||
		return webIndex, serverIndex, errors.New("非标准插件,请按照文档自动迁移使用")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if webIndex != -1 {
 | 
			
		||||
		err = installation(paths[webIndex], global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.Web)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return webIndex, serverIndex, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if serverIndex != -1 {
 | 
			
		||||
		err = installation(paths[serverIndex], global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.Server)
 | 
			
		||||
	}
 | 
			
		||||
	return webIndex, serverIndex, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func installation(path string, formPath string, toPath string) error {
 | 
			
		||||
	arr := strings.Split(filepath.ToSlash(path), "/")
 | 
			
		||||
	ln := len(arr)
 | 
			
		||||
	if ln < 3 {
 | 
			
		||||
		return errors.New("arr")
 | 
			
		||||
	}
 | 
			
		||||
	name := arr[ln-3]
 | 
			
		||||
 | 
			
		||||
	var form = filepath.ToSlash(global.GVA_CONFIG.AutoCode.Root + formPath + "/" + path)
 | 
			
		||||
	var to = filepath.ToSlash(global.GVA_CONFIG.AutoCode.Root + toPath + "/plugin/")
 | 
			
		||||
	_, err := os.Stat(to + name)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		zap.L().Error("autoPath 已存在同名插件,请自行手动安装", zap.String("to", to))
 | 
			
		||||
		return errors.New(toPath + "已存在同名插件,请自行手动安装")
 | 
			
		||||
	}
 | 
			
		||||
	return cp.Copy(form, to, cp.Options{Skip: skipMacSpecialDocument})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func filterFile(paths []string) []string {
 | 
			
		||||
	np := make([]string, 0, len(paths))
 | 
			
		||||
	for _, path := range paths {
 | 
			
		||||
		if ok, _ := skipMacSpecialDocument(path); ok {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		np = append(np, path)
 | 
			
		||||
	}
 | 
			
		||||
	return np
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func skipMacSpecialDocument(src string) (bool, error) {
 | 
			
		||||
	if strings.Contains(src, ".DS_Store") || strings.Contains(src, "__MACOSX") {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) PubPlug(plugName string) (zipPath string, err error) {
 | 
			
		||||
	if plugName == "" {
 | 
			
		||||
		return "", errors.New("插件名称不能为空")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 防止路径穿越
 | 
			
		||||
	plugName = filepath.Clean(plugName)
 | 
			
		||||
 | 
			
		||||
	webPath := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Web, "plugin", plugName)
 | 
			
		||||
	serverPath := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, "plugin", plugName)
 | 
			
		||||
	// 创建一个新的zip文件
 | 
			
		||||
 | 
			
		||||
	// 判断目录是否存在
 | 
			
		||||
	webInfo, err := os.Stat(webPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", errors.New("web路径不存在")
 | 
			
		||||
	}
 | 
			
		||||
	serverInfo, err := os.Stat(serverPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", errors.New("server路径不存在")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fileName := plugName + ".zip"
 | 
			
		||||
	// 创建一个新的zip文件
 | 
			
		||||
	zipFile, err := os.Create(fileName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer zipFile.Close()
 | 
			
		||||
 | 
			
		||||
	// 创建一个zip写入器
 | 
			
		||||
	zipWriter := zip.NewWriter(zipFile)
 | 
			
		||||
	defer zipWriter.Close()
 | 
			
		||||
 | 
			
		||||
	// 创建一个新的文件头
 | 
			
		||||
	webHeader, err := zip.FileInfoHeader(webInfo)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 创建一个新的文件头
 | 
			
		||||
	serverHeader, err := zip.FileInfoHeader(serverInfo)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	webHeader.Name = filepath.Join(plugName, "web", "plugin")
 | 
			
		||||
	serverHeader.Name = filepath.Join(plugName, "server.exe.exe", "plugin")
 | 
			
		||||
 | 
			
		||||
	// 将文件添加到zip归档中
 | 
			
		||||
	_, err = zipWriter.CreateHeader(serverHeader)
 | 
			
		||||
	_, err = zipWriter.CreateHeader(webHeader)
 | 
			
		||||
 | 
			
		||||
	// 遍历webPath目录并将所有非隐藏文件添加到zip归档中
 | 
			
		||||
	err = filepath.Walk(webPath, func(path string, info os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 跳过隐藏文件
 | 
			
		||||
		if strings.HasPrefix(info.Name(), ".") {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 创建一个新的文件头
 | 
			
		||||
		header, err := zip.FileInfoHeader(info)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 将文件头的名称设置为文件的相对路径
 | 
			
		||||
		rel, _ := filepath.Rel(webPath, path)
 | 
			
		||||
		header.Name = filepath.Join(plugName, "web", "plugin", plugName, rel)
 | 
			
		||||
 | 
			
		||||
		// 将文件添加到zip归档中
 | 
			
		||||
		writer, err := zipWriter.CreateHeader(header)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if info.IsDir() {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 打开文件并将其内容复制到zip归档中
 | 
			
		||||
		file, err := os.Open(path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		defer file.Close()
 | 
			
		||||
		_, err = io.Copy(writer, file)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 遍历serverPath目录并将所有非隐藏文件添加到zip归档中
 | 
			
		||||
	err = filepath.Walk(serverPath, func(path string, info os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 跳过隐藏文件和目录
 | 
			
		||||
		if strings.HasPrefix(info.Name(), ".") {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 创建一个新的文件头
 | 
			
		||||
		header, err := zip.FileInfoHeader(info)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 将文件头的名称设置为文件的相对路径
 | 
			
		||||
		rel, _ := filepath.Rel(serverPath, path)
 | 
			
		||||
		header.Name = filepath.Join(plugName, "server.exe.exe", "plugin", plugName, rel)
 | 
			
		||||
		// 将文件添加到zip归档中
 | 
			
		||||
		writer, err := zipWriter.CreateHeader(header)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if info.IsDir() {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 打开文件并将其内容复制到zip归档中
 | 
			
		||||
		file, err := os.Open(path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		defer file.Close()
 | 
			
		||||
		_, err = io.Copy(writer, file)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, fileName), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								service/system/sys_auto_code_interface.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								service/system/sys_auto_code_interface.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/response"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Database interface {
 | 
			
		||||
	GetDB(businessDB string) (data []response.Db, err error)
 | 
			
		||||
	GetTables(businessDB string, dbName string) (data []response.Table, err error)
 | 
			
		||||
	GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (autoCodeService *AutoCodeService) Database(businessDB string) Database {
 | 
			
		||||
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		switch global.GVA_CONFIG.System.DbType {
 | 
			
		||||
		case "mysql":
 | 
			
		||||
			return AutoCodeMysql
 | 
			
		||||
		case "pgsql":
 | 
			
		||||
			return AutoCodePgsql
 | 
			
		||||
		case "sqlite":
 | 
			
		||||
			return AutoCodeSqlite
 | 
			
		||||
		default:
 | 
			
		||||
			return AutoCodeMysql
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for _, info := range global.GVA_CONFIG.DBList {
 | 
			
		||||
			if info.AliasName == businessDB {
 | 
			
		||||
				switch info.Type {
 | 
			
		||||
				case "mysql":
 | 
			
		||||
					return AutoCodeMysql
 | 
			
		||||
				case "mssql":
 | 
			
		||||
					return AutoCodeMssql
 | 
			
		||||
				case "pgsql":
 | 
			
		||||
					return AutoCodePgsql
 | 
			
		||||
				case "oracle":
 | 
			
		||||
					return AutoCodeOracle
 | 
			
		||||
				case "sqlite":
 | 
			
		||||
					return AutoCodeSqlite
 | 
			
		||||
				default:
 | 
			
		||||
					return AutoCodeMysql
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return AutoCodeMysql
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								service/system/sys_auto_code_mssql.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								service/system/sys_auto_code_mssql.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/response"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var AutoCodeMssql = new(autoCodeMssql)
 | 
			
		||||
 | 
			
		||||
type autoCodeMssql struct{}
 | 
			
		||||
 | 
			
		||||
// GetDB 获取数据库的所有数据库名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (s *autoCodeMssql) GetDB(businessDB string) (data []response.Db, err error) {
 | 
			
		||||
	var entities []response.Db
 | 
			
		||||
	sql := "select name AS 'database' from sysdatabases;"
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql).Scan(&entities).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error
 | 
			
		||||
	}
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTables 获取数据库的所有表名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (s *autoCodeMssql) GetTables(businessDB string, dbName string) (data []response.Table, err error) {
 | 
			
		||||
	var entities []response.Table
 | 
			
		||||
 | 
			
		||||
	sql := fmt.Sprintf(`select name as 'table_name' from %s.DBO.sysobjects where xtype='U'`, dbName)
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql).Scan(&entities).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetColumn 获取指定数据库和指定数据表的所有字段名,类型值等
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (s *autoCodeMssql) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) {
 | 
			
		||||
	var entities []response.Column
 | 
			
		||||
	sql := fmt.Sprintf(`select sc.name as column_name,st.name as data_type, sc.length as data_type_long
 | 
			
		||||
	 from %s.DBO.syscolumns sc,systypes st where sc.xtype=st.xtype and st.usertype=0 and sc.id in (select id from %s.DBO.sysobjects where xtype='U' and name='%s');`, dbName, dbName, tableName)
 | 
			
		||||
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql).Scan(&entities).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										69
									
								
								service/system/sys_auto_code_mysql.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								service/system/sys_auto_code_mysql.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/response"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var AutoCodeMysql = new(autoCodeMysql)
 | 
			
		||||
 | 
			
		||||
type autoCodeMysql struct{}
 | 
			
		||||
 | 
			
		||||
// GetDB 获取数据库的所有数据库名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (s *autoCodeMysql) GetDB(businessDB string) (data []response.Db, err error) {
 | 
			
		||||
	var entities []response.Db
 | 
			
		||||
	sql := "SELECT SCHEMA_NAME AS `database` FROM INFORMATION_SCHEMA.SCHEMATA;"
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql).Scan(&entities).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error
 | 
			
		||||
	}
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTables 获取数据库的所有表名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (s *autoCodeMysql) GetTables(businessDB string, dbName string) (data []response.Table, err error) {
 | 
			
		||||
	var entities []response.Table
 | 
			
		||||
	sql := `select table_name as table_name from information_schema.tables where table_schema = ?`
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql, dbName).Scan(&entities).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql, dbName).Scan(&entities).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetColumn 获取指定数据库和指定数据表的所有字段名,类型值等
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (s *autoCodeMysql) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) {
 | 
			
		||||
	var entities []response.Column
 | 
			
		||||
	sql := `
 | 
			
		||||
	SELECT COLUMN_NAME        column_name,
 | 
			
		||||
       DATA_TYPE          data_type,
 | 
			
		||||
       CASE DATA_TYPE
 | 
			
		||||
           WHEN 'longtext' THEN c.CHARACTER_MAXIMUM_LENGTH
 | 
			
		||||
           WHEN 'varchar' THEN c.CHARACTER_MAXIMUM_LENGTH
 | 
			
		||||
           WHEN 'double' THEN CONCAT_WS(',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE)
 | 
			
		||||
           WHEN 'decimal' THEN CONCAT_WS(',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE)
 | 
			
		||||
           WHEN 'int' THEN c.NUMERIC_PRECISION
 | 
			
		||||
           WHEN 'bigint' THEN c.NUMERIC_PRECISION
 | 
			
		||||
           ELSE '' END AS data_type_long,
 | 
			
		||||
       COLUMN_COMMENT     column_comment
 | 
			
		||||
	FROM INFORMATION_SCHEMA.COLUMNS c
 | 
			
		||||
	WHERE table_name = ?
 | 
			
		||||
	  AND table_schema = ?
 | 
			
		||||
	`
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql, tableName, dbName).Scan(&entities).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql, tableName, dbName).Scan(&entities).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								service/system/sys_auto_code_oracle.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								service/system/sys_auto_code_oracle.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/response"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var AutoCodeOracle = new(autoCodeOracle)
 | 
			
		||||
 | 
			
		||||
type autoCodeOracle struct{}
 | 
			
		||||
 | 
			
		||||
// GetDB 获取数据库的所有数据库名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (s *autoCodeOracle) GetDB(businessDB string) (data []response.Db, err error) {
 | 
			
		||||
	var entities []response.Db
 | 
			
		||||
	sql := `SELECT lower(username) AS "database" FROM all_users`
 | 
			
		||||
	err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTables 获取数据库的所有表名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (s *autoCodeOracle) GetTables(businessDB string, dbName string) (data []response.Table, err error) {
 | 
			
		||||
	var entities []response.Table
 | 
			
		||||
	sql := `select lower(table_name) as "table_name" from all_tables where lower(owner) = ?`
 | 
			
		||||
 | 
			
		||||
	err = global.GVA_DBList[businessDB].Raw(sql, dbName).Scan(&entities).Error
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetColumn 获取指定数据库和指定数据表的所有字段名,类型值等
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (s *autoCodeOracle) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) {
 | 
			
		||||
	var entities []response.Column
 | 
			
		||||
	sql := `
 | 
			
		||||
		select lower(a.COLUMN_NAME) as "column_name",
 | 
			
		||||
			   (CASE WHEN a.DATA_TYPE = 'NUMBER' AND a.DATA_SCALE=0 THEN 'int' else lower(a.DATA_TYPE) end)  as "data_type", 
 | 
			
		||||
			   (CASE WHEN a.DATA_TYPE = 'NUMBER' THEN a.DATA_PRECISION else a.DATA_LENGTH end) as "data_type_long",
 | 
			
		||||
			   b.COMMENTS as "column_comment"
 | 
			
		||||
		from all_tab_columns a , all_col_comments b
 | 
			
		||||
		 where a.OWNER = b.OWNER
 | 
			
		||||
		 and a.TABLE_NAME = b.TABLE_NAME
 | 
			
		||||
		 and a.COLUMN_NAME = b.COLUMN_NAME
 | 
			
		||||
		and lower(a.table_name) = ?
 | 
			
		||||
		 and lower(a.OWNER) = ?		 
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
	err = global.GVA_DBList[businessDB].Raw(sql, tableName, dbName).Scan(&entities).Error
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								service/system/sys_auto_code_pgsql.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								service/system/sys_auto_code_pgsql.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"gorm.io/driver/postgres"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"gorm.io/gorm/logger"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/response"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var AutoCodePgsql = new(autoCodePgsql)
 | 
			
		||||
 | 
			
		||||
type autoCodePgsql struct{}
 | 
			
		||||
 | 
			
		||||
// GetDB 获取数据库的所有数据库名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (a *autoCodePgsql) GetDB(businessDB string) (data []response.Db, err error) {
 | 
			
		||||
	var entities []response.Db
 | 
			
		||||
	sql := `SELECT datname as database FROM pg_database WHERE datistemplate = false`
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql).Scan(&entities).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTables 获取数据库的所有表名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (a *autoCodePgsql) GetTables(businessDB string, dbName string) (data []response.Table, err error) {
 | 
			
		||||
	var entities []response.Table
 | 
			
		||||
	sql := `select table_name as table_name from information_schema.tables where table_catalog = ? and table_schema = ?`
 | 
			
		||||
	db, _err := gorm.Open(postgres.Open(global.GVA_CONFIG.Pgsql.LinkDsn(dbName)), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)})
 | 
			
		||||
	if _err != nil {
 | 
			
		||||
		return nil, errors.Wrapf(err, "[pgsql] 连接 数据库(%s)的表失败!", dbName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = db.Raw(sql, dbName, "public").Scan(&entities).Error
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetColumn 获取指定数据库和指定数据表的所有字段名,类型值等
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (a *autoCodePgsql) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) {
 | 
			
		||||
	// todo 数据获取不全, 待完善sql
 | 
			
		||||
	sql := `
 | 
			
		||||
		SELECT psc.COLUMN_NAME AS COLUMN_NAME,
 | 
			
		||||
 psc.udt_name AS data_type,
 | 
			
		||||
CASE
 | 
			
		||||
  psc.udt_name 
 | 
			
		||||
  WHEN 'text' THEN
 | 
			
		||||
   concat_ws ( '', '', psc.CHARACTER_MAXIMUM_LENGTH ) 
 | 
			
		||||
  WHEN 'varchar' THEN
 | 
			
		||||
   concat_ws ( '', '', psc.CHARACTER_MAXIMUM_LENGTH ) 
 | 
			
		||||
  WHEN 'smallint' THEN
 | 
			
		||||
   concat_ws ( ',', psc.NUMERIC_PRECISION, psc.NUMERIC_SCALE ) 
 | 
			
		||||
  WHEN 'decimal' THEN
 | 
			
		||||
   concat_ws ( ',', psc.NUMERIC_PRECISION, psc.NUMERIC_SCALE ) 
 | 
			
		||||
  WHEN 'integer' THEN
 | 
			
		||||
   concat_ws ( '', '', psc.NUMERIC_PRECISION ) 
 | 
			
		||||
  WHEN 'int4' THEN
 | 
			
		||||
   concat_ws ( '', '', psc.NUMERIC_PRECISION ) 
 | 
			
		||||
  WHEN 'int8' THEN
 | 
			
		||||
   concat_ws ( '', '', psc.NUMERIC_PRECISION ) 
 | 
			
		||||
  WHEN 'bigint' THEN
 | 
			
		||||
   concat_ws ( '', '', psc.NUMERIC_PRECISION ) 
 | 
			
		||||
  WHEN 'timestamp' THEN
 | 
			
		||||
   concat_ws ( '', '', psc.datetime_precision ) 
 | 
			
		||||
  ELSE '' 
 | 
			
		||||
 END AS data_type_long,
 | 
			
		||||
 (
 | 
			
		||||
   SELECT
 | 
			
		||||
    pd.description 
 | 
			
		||||
   FROM
 | 
			
		||||
    pg_description pd 
 | 
			
		||||
   WHERE
 | 
			
		||||
    (pd.objoid,pd.objsubid) in (
 | 
			
		||||
       SELECT pa.attrelid,pa.attnum
 | 
			
		||||
       FROM
 | 
			
		||||
        pg_attribute pa 
 | 
			
		||||
      WHERE pa.attrelid = ( SELECT oid FROM pg_class pc WHERE 
 | 
			
		||||
      pc.relname = psc.table_name
 | 
			
		||||
      ) 
 | 
			
		||||
      and attname = psc.column_name
 | 
			
		||||
    ) 
 | 
			
		||||
 ) AS column_comment 
 | 
			
		||||
FROM
 | 
			
		||||
 INFORMATION_SCHEMA.COLUMNS psc 
 | 
			
		||||
WHERE
 | 
			
		||||
 table_catalog = ?
 | 
			
		||||
 AND table_schema = 'public' 
 | 
			
		||||
 AND TABLE_NAME = ?;
 | 
			
		||||
	`
 | 
			
		||||
	var entities []response.Column
 | 
			
		||||
	db, _err := gorm.Open(postgres.Open(global.GVA_CONFIG.Pgsql.LinkDsn(dbName)), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)})
 | 
			
		||||
	if _err != nil {
 | 
			
		||||
		return nil, errors.Wrapf(err, "[pgsql] 连接 数据库(%s)的表(%s)失败!", dbName, tableName)
 | 
			
		||||
	}
 | 
			
		||||
	//sql = strings.ReplaceAll(sql, "@table_catalog", dbName)
 | 
			
		||||
	//sql = strings.ReplaceAll(sql, "@table_name", tableName)
 | 
			
		||||
	err = db.Raw(sql, dbName, tableName).Scan(&entities).Error
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								service/system/sys_auto_code_sqlite.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								service/system/sys_auto_code_sqlite.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/response"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var AutoCodeSqlite = new(autoCodeSqlite)
 | 
			
		||||
 | 
			
		||||
type autoCodeSqlite struct{}
 | 
			
		||||
 | 
			
		||||
// GetDB 获取数据库的所有数据库名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (a *autoCodeSqlite) GetDB(businessDB string) (data []response.Db, err error) {
 | 
			
		||||
	var entities []response.Db
 | 
			
		||||
	sql := "PRAGMA database_list;"
 | 
			
		||||
	var databaseList []struct {
 | 
			
		||||
		File string `gorm:"column:file"`
 | 
			
		||||
	}
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql).Find(&databaseList).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql).Find(&databaseList).Error
 | 
			
		||||
	}
 | 
			
		||||
	for _, database := range databaseList {
 | 
			
		||||
		if database.File != "" {
 | 
			
		||||
			fileName := filepath.Base(database.File)
 | 
			
		||||
			fileExt := filepath.Ext(fileName)
 | 
			
		||||
			fileNameWithoutExt := strings.TrimSuffix(fileName, fileExt)
 | 
			
		||||
 | 
			
		||||
			entities = append(entities, response.Db{fileNameWithoutExt})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// entities = append(entities, response.Db{global.GVA_CONFIG.Sqlite.Dbname})
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTables 获取数据库的所有表名
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (a *autoCodeSqlite) GetTables(businessDB string, dbName string) (data []response.Table, err error) {
 | 
			
		||||
	var entities []response.Table
 | 
			
		||||
	sql := `SELECT name FROM sqlite_master WHERE type='table'`
 | 
			
		||||
	tabelNames := []string{}
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql).Find(&tabelNames).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql).Find(&tabelNames).Error
 | 
			
		||||
	}
 | 
			
		||||
	for _, tabelName := range tabelNames {
 | 
			
		||||
		entities = append(entities, response.Table{tabelName})
 | 
			
		||||
	}
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetColumn 获取指定数据表的所有字段名,类型值等
 | 
			
		||||
// Author [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (a *autoCodeSqlite) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) {
 | 
			
		||||
	var entities []response.Column
 | 
			
		||||
	sql := fmt.Sprintf("PRAGMA table_info(%s);", tableName)
 | 
			
		||||
	var columnInfos []struct {
 | 
			
		||||
		Name string `gorm:"column:name"`
 | 
			
		||||
		Type string `gorm:"column:type"`
 | 
			
		||||
	}
 | 
			
		||||
	if businessDB == "" {
 | 
			
		||||
		err = global.GVA_DB.Raw(sql).Scan(&columnInfos).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = global.GVA_DBList[businessDB].Raw(sql).Scan(&columnInfos).Error
 | 
			
		||||
	}
 | 
			
		||||
	for _, columnInfo := range columnInfos {
 | 
			
		||||
		entities = append(entities, response.Column{
 | 
			
		||||
			ColumnName: columnInfo.Name,
 | 
			
		||||
			DataType:   columnInfo.Type,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return entities, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										153
									
								
								service/system/sys_autocode_history.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								service/system/sys_autocode_history.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	systemReq "miniapp/model/system/request"
 | 
			
		||||
	"miniapp/utils/ast"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"miniapp/model/system/response"
 | 
			
		||||
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/common/request"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/utils"
 | 
			
		||||
 | 
			
		||||
	"go.uber.org/zap"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var RepeatErr = errors.New("重复创建")
 | 
			
		||||
 | 
			
		||||
type AutoCodeHistoryService struct{}
 | 
			
		||||
 | 
			
		||||
var AutoCodeHistoryServiceApp = new(AutoCodeHistoryService)
 | 
			
		||||
 | 
			
		||||
// CreateAutoCodeHistory 创建代码生成器历史记录
 | 
			
		||||
// RouterPath : RouterPath@RouterString;RouterPath2@RouterString2
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
// Author [songzhibin97](https://github.com/songzhibin97)
 | 
			
		||||
func (autoCodeHistoryService *AutoCodeHistoryService) CreateAutoCodeHistory(meta, structName, structCNName, autoCodePath string, injectionMeta string, tableName string, apiIds string, Package string, BusinessDB string) error {
 | 
			
		||||
	return global.GVA_DB.Create(&system.SysAutoCodeHistory{
 | 
			
		||||
		Package:       Package,
 | 
			
		||||
		RequestMeta:   meta,
 | 
			
		||||
		AutoCodePath:  autoCodePath,
 | 
			
		||||
		InjectionMeta: injectionMeta,
 | 
			
		||||
		StructName:    structName,
 | 
			
		||||
		StructCNName:  structCNName,
 | 
			
		||||
		TableName:     tableName,
 | 
			
		||||
		ApiIDs:        apiIds,
 | 
			
		||||
		BusinessDB:    BusinessDB,
 | 
			
		||||
	}).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// First 根据id获取代码生成器历史的数据
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
// Author [songzhibin97](https://github.com/songzhibin97)
 | 
			
		||||
func (autoCodeHistoryService *AutoCodeHistoryService) First(info *request.GetById) (string, error) {
 | 
			
		||||
	var meta string
 | 
			
		||||
	return meta, global.GVA_DB.Model(system.SysAutoCodeHistory{}).Select("request_meta").Where("id = ?", info.Uint()).First(&meta).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Repeat 检测重复
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
// Author [songzhibin97](https://github.com/songzhibin97)
 | 
			
		||||
func (autoCodeHistoryService *AutoCodeHistoryService) Repeat(businessDB, structName, Package string) bool {
 | 
			
		||||
	var count int64
 | 
			
		||||
	global.GVA_DB.Model(&system.SysAutoCodeHistory{}).Where("business_db = ? and struct_name = ? and package = ? and flag = 0", businessDB, structName, Package).Count(&count)
 | 
			
		||||
	return count > 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RollBack 回滚
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
// Author [songzhibin97](https://github.com/songzhibin97)
 | 
			
		||||
func (autoCodeHistoryService *AutoCodeHistoryService) RollBack(info *systemReq.RollBack) error {
 | 
			
		||||
	md := system.SysAutoCodeHistory{}
 | 
			
		||||
	if err := global.GVA_DB.Where("id = ?", info.ID).First(&md).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// 清除API表
 | 
			
		||||
 | 
			
		||||
	ids := request.IdsReq{}
 | 
			
		||||
	idsStr := strings.Split(md.ApiIDs, ";")
 | 
			
		||||
	for i := range idsStr[0 : len(idsStr)-1] {
 | 
			
		||||
		id, err := strconv.Atoi(idsStr[i])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		ids.Ids = append(ids.Ids, id)
 | 
			
		||||
	}
 | 
			
		||||
	err := ApiServiceApp.DeleteApisByIds(ids)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		global.GVA_LOG.Error("ClearTag DeleteApiByIds:", zap.Error(err))
 | 
			
		||||
	}
 | 
			
		||||
	// 删除表
 | 
			
		||||
	if info.DeleteTable {
 | 
			
		||||
		if err = AutoCodeServiceApp.DropTable(md.BusinessDB, md.TableName); err != nil {
 | 
			
		||||
			global.GVA_LOG.Error("ClearTag DropTable:", zap.Error(err))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// 删除文件
 | 
			
		||||
 | 
			
		||||
	for _, path := range strings.Split(md.AutoCodePath, ";") {
 | 
			
		||||
 | 
			
		||||
		// 增加安全判断补丁:
 | 
			
		||||
		_path, err := filepath.Abs(path)
 | 
			
		||||
		if err != nil || _path != path {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 迁移
 | 
			
		||||
		nPath := filepath.Join(global.GVA_CONFIG.AutoCode.Root,
 | 
			
		||||
			"rm_file", time.Now().Format("20060102"), filepath.Base(filepath.Dir(filepath.Dir(path))), filepath.Base(filepath.Dir(path)), filepath.Base(path))
 | 
			
		||||
		// 判断目标文件是否存在
 | 
			
		||||
		for utils.FileExist(nPath) {
 | 
			
		||||
			fmt.Println("文件已存在:", nPath)
 | 
			
		||||
			nPath += fmt.Sprintf("_%d", time.Now().Nanosecond())
 | 
			
		||||
		}
 | 
			
		||||
		err = utils.FileMove(path, nPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			global.GVA_LOG.Error("file move err ", zap.Error(err))
 | 
			
		||||
		}
 | 
			
		||||
		//_ = utils.DeLFile(path)
 | 
			
		||||
	}
 | 
			
		||||
	// 清除注入
 | 
			
		||||
	for _, v := range strings.Split(md.InjectionMeta, ";") {
 | 
			
		||||
		// RouterPath@functionName@RouterString
 | 
			
		||||
		meta := strings.Split(v, "@")
 | 
			
		||||
		if len(meta) == 3 {
 | 
			
		||||
			_ = utils.AutoClearCode(meta[0], meta[2])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ast.RollBackAst(md.Package, md.StructName)
 | 
			
		||||
 | 
			
		||||
	md.Flag = 1
 | 
			
		||||
	return global.GVA_DB.Save(&md).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Delete 删除历史数据
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
// Author [songzhibin97](https://github.com/songzhibin97)
 | 
			
		||||
func (autoCodeHistoryService *AutoCodeHistoryService) Delete(info *request.GetById) error {
 | 
			
		||||
	return global.GVA_DB.Where("id = ?", info.Uint()).Delete(&system.SysAutoCodeHistory{}).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetList 获取系统历史数据
 | 
			
		||||
// Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
// Author [songzhibin97](https://github.com/songzhibin97)
 | 
			
		||||
func (autoCodeHistoryService *AutoCodeHistoryService) GetList(info request.PageInfo) (list []response.AutoCodeHistory, total int64, err error) {
 | 
			
		||||
	limit := info.PageSize
 | 
			
		||||
	offset := info.PageSize * (info.Page - 1)
 | 
			
		||||
	db := global.GVA_DB.Model(&system.SysAutoCodeHistory{})
 | 
			
		||||
	var entities []response.AutoCodeHistory
 | 
			
		||||
	err = db.Count(&total).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, total, err
 | 
			
		||||
	}
 | 
			
		||||
	err = db.Limit(limit).Offset(offset).Order("updated_at desc").Find(&entities).Error
 | 
			
		||||
	return entities, total, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										125
									
								
								service/system/sys_base_menu.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								service/system/sys_base_menu.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,125 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type BaseMenuService struct{}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteBaseMenu
 | 
			
		||||
//@description: 删除基础路由
 | 
			
		||||
//@param: id float64
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (baseMenuService *BaseMenuService) DeleteBaseMenu(id int) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Preload("MenuBtn").Preload("Parameters").Where("parent_id = ?", id).First(&system.SysBaseMenu{}).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		var menu system.SysBaseMenu
 | 
			
		||||
		db := global.GVA_DB.Preload("SysAuthoritys").Where("id = ?", id).First(&menu).Delete(&menu)
 | 
			
		||||
		err = global.GVA_DB.Delete(&system.SysBaseMenuParameter{}, "sys_base_menu_id = ?", id).Error
 | 
			
		||||
		err = global.GVA_DB.Delete(&system.SysBaseMenuBtn{}, "sys_base_menu_id = ?", id).Error
 | 
			
		||||
		err = global.GVA_DB.Delete(&system.SysAuthorityBtn{}, "sys_menu_id = ?", id).Error
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if len(menu.SysAuthoritys) > 0 {
 | 
			
		||||
			err = global.GVA_DB.Model(&menu).Association("SysAuthoritys").Delete(&menu.SysAuthoritys)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = db.Error
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		return errors.New("此菜单存在子菜单不可删除")
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: UpdateBaseMenu
 | 
			
		||||
//@description: 更新路由
 | 
			
		||||
//@param: menu model.SysBaseMenu
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (baseMenuService *BaseMenuService) UpdateBaseMenu(menu system.SysBaseMenu) (err error) {
 | 
			
		||||
	var oldMenu system.SysBaseMenu
 | 
			
		||||
	upDateMap := make(map[string]interface{})
 | 
			
		||||
	upDateMap["keep_alive"] = menu.KeepAlive
 | 
			
		||||
	upDateMap["close_tab"] = menu.CloseTab
 | 
			
		||||
	upDateMap["default_menu"] = menu.DefaultMenu
 | 
			
		||||
	upDateMap["parent_id"] = menu.ParentId
 | 
			
		||||
	upDateMap["path"] = menu.Path
 | 
			
		||||
	upDateMap["name"] = menu.Name
 | 
			
		||||
	upDateMap["hidden"] = menu.Hidden
 | 
			
		||||
	upDateMap["component"] = menu.Component
 | 
			
		||||
	upDateMap["title"] = menu.Title
 | 
			
		||||
	upDateMap["active_name"] = menu.ActiveName
 | 
			
		||||
	upDateMap["icon"] = menu.Icon
 | 
			
		||||
	upDateMap["sort"] = menu.Sort
 | 
			
		||||
 | 
			
		||||
	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
 | 
			
		||||
		db := tx.Where("id = ?", menu.ID).Find(&oldMenu)
 | 
			
		||||
		if oldMenu.Name != menu.Name {
 | 
			
		||||
			if !errors.Is(tx.Where("id <> ? AND name = ?", menu.ID, menu.Name).First(&system.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
				global.GVA_LOG.Debug("存在相同name修改失败")
 | 
			
		||||
				return errors.New("存在相同name修改失败")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		txErr := tx.Unscoped().Delete(&system.SysBaseMenuParameter{}, "sys_base_menu_id = ?", menu.ID).Error
 | 
			
		||||
		if txErr != nil {
 | 
			
		||||
			global.GVA_LOG.Debug(txErr.Error())
 | 
			
		||||
			return txErr
 | 
			
		||||
		}
 | 
			
		||||
		txErr = tx.Unscoped().Delete(&system.SysBaseMenuBtn{}, "sys_base_menu_id = ?", menu.ID).Error
 | 
			
		||||
		if txErr != nil {
 | 
			
		||||
			global.GVA_LOG.Debug(txErr.Error())
 | 
			
		||||
			return txErr
 | 
			
		||||
		}
 | 
			
		||||
		if len(menu.Parameters) > 0 {
 | 
			
		||||
			for k := range menu.Parameters {
 | 
			
		||||
				menu.Parameters[k].SysBaseMenuID = menu.ID
 | 
			
		||||
			}
 | 
			
		||||
			txErr = tx.Create(&menu.Parameters).Error
 | 
			
		||||
			if txErr != nil {
 | 
			
		||||
				global.GVA_LOG.Debug(txErr.Error())
 | 
			
		||||
				return txErr
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(menu.MenuBtn) > 0 {
 | 
			
		||||
			for k := range menu.MenuBtn {
 | 
			
		||||
				menu.MenuBtn[k].SysBaseMenuID = menu.ID
 | 
			
		||||
			}
 | 
			
		||||
			txErr = tx.Create(&menu.MenuBtn).Error
 | 
			
		||||
			if txErr != nil {
 | 
			
		||||
				global.GVA_LOG.Debug(txErr.Error())
 | 
			
		||||
				return txErr
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		txErr = db.Updates(upDateMap).Error
 | 
			
		||||
		if txErr != nil {
 | 
			
		||||
			global.GVA_LOG.Debug(txErr.Error())
 | 
			
		||||
			return txErr
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetBaseMenuById
 | 
			
		||||
//@description: 返回当前选中menu
 | 
			
		||||
//@param: id float64
 | 
			
		||||
//@return: menu system.SysBaseMenu, err error
 | 
			
		||||
 | 
			
		||||
func (baseMenuService *BaseMenuService) GetBaseMenuById(id int) (menu system.SysBaseMenu, err error) {
 | 
			
		||||
	err = global.GVA_DB.Preload("MenuBtn").Preload("Parameters").Where("id = ?", id).First(&menu).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										141
									
								
								service/system/sys_casbin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								service/system/sys_casbin.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/casbin/casbin/v2"
 | 
			
		||||
	"github.com/casbin/casbin/v2/model"
 | 
			
		||||
	gormadapter "github.com/casbin/gorm-adapter/v3"
 | 
			
		||||
	_ "github.com/go-sql-driver/mysql"
 | 
			
		||||
	"go.uber.org/zap"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: UpdateCasbin
 | 
			
		||||
//@description: 更新casbin权限
 | 
			
		||||
//@param: authorityId string, casbinInfos []request.CasbinInfo
 | 
			
		||||
//@return: error
 | 
			
		||||
 | 
			
		||||
type CasbinService struct{}
 | 
			
		||||
 | 
			
		||||
var CasbinServiceApp = new(CasbinService)
 | 
			
		||||
 | 
			
		||||
func (casbinService *CasbinService) UpdateCasbin(AuthorityID uint, casbinInfos []request.CasbinInfo) error {
 | 
			
		||||
	authorityId := strconv.Itoa(int(AuthorityID))
 | 
			
		||||
	casbinService.ClearCasbin(0, authorityId)
 | 
			
		||||
	rules := [][]string{}
 | 
			
		||||
	//做权限去重处理
 | 
			
		||||
	deduplicateMap := make(map[string]bool)
 | 
			
		||||
	for _, v := range casbinInfos {
 | 
			
		||||
		key := authorityId + v.Path + v.Method
 | 
			
		||||
		if _, ok := deduplicateMap[key]; !ok {
 | 
			
		||||
			deduplicateMap[key] = true
 | 
			
		||||
			rules = append(rules, []string{authorityId, v.Path, v.Method})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	e := casbinService.Casbin()
 | 
			
		||||
	success, _ := e.AddPolicies(rules)
 | 
			
		||||
	if !success {
 | 
			
		||||
		return errors.New("存在相同api,添加失败,请联系管理员")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: UpdateCasbinApi
 | 
			
		||||
//@description: API更新随动
 | 
			
		||||
//@param: oldPath string, newPath string, oldMethod string, newMethod string
 | 
			
		||||
//@return: error
 | 
			
		||||
 | 
			
		||||
func (casbinService *CasbinService) UpdateCasbinApi(oldPath string, newPath string, oldMethod string, newMethod string) error {
 | 
			
		||||
	err := global.GVA_DB.Model(&gormadapter.CasbinRule{}).Where("v1 = ? AND v2 = ?", oldPath, oldMethod).Updates(map[string]interface{}{
 | 
			
		||||
		"v1": newPath,
 | 
			
		||||
		"v2": newMethod,
 | 
			
		||||
	}).Error
 | 
			
		||||
	e := casbinService.Casbin()
 | 
			
		||||
	err = e.LoadPolicy()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetPolicyPathByAuthorityId
 | 
			
		||||
//@description: 获取权限列表
 | 
			
		||||
//@param: authorityId string
 | 
			
		||||
//@return: pathMaps []request.CasbinInfo
 | 
			
		||||
 | 
			
		||||
func (casbinService *CasbinService) GetPolicyPathByAuthorityId(AuthorityID uint) (pathMaps []request.CasbinInfo) {
 | 
			
		||||
	e := casbinService.Casbin()
 | 
			
		||||
	authorityId := strconv.Itoa(int(AuthorityID))
 | 
			
		||||
	list := e.GetFilteredPolicy(0, authorityId)
 | 
			
		||||
	for _, v := range list {
 | 
			
		||||
		pathMaps = append(pathMaps, request.CasbinInfo{
 | 
			
		||||
			Path:   v[1],
 | 
			
		||||
			Method: v[2],
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return pathMaps
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: ClearCasbin
 | 
			
		||||
//@description: 清除匹配的权限
 | 
			
		||||
//@param: v int, p ...string
 | 
			
		||||
//@return: bool
 | 
			
		||||
 | 
			
		||||
func (casbinService *CasbinService) ClearCasbin(v int, p ...string) bool {
 | 
			
		||||
	e := casbinService.Casbin()
 | 
			
		||||
	success, _ := e.RemoveFilteredPolicy(v, p...)
 | 
			
		||||
	return success
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: Casbin
 | 
			
		||||
//@description: 持久化到数据库  引入自定义规则
 | 
			
		||||
//@return: *casbin.Enforcer
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	syncedCachedEnforcer *casbin.SyncedCachedEnforcer
 | 
			
		||||
	once                 sync.Once
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (casbinService *CasbinService) Casbin() *casbin.SyncedCachedEnforcer {
 | 
			
		||||
	once.Do(func() {
 | 
			
		||||
		a, err := gormadapter.NewAdapterByDB(global.GVA_DB)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			zap.L().Error("适配数据库失败请检查casbin表是否为InnoDB引擎!", zap.Error(err))
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		text := `
 | 
			
		||||
		[request_definition]
 | 
			
		||||
		r = sub, obj, act
 | 
			
		||||
		
 | 
			
		||||
		[policy_definition]
 | 
			
		||||
		p = sub, obj, act
 | 
			
		||||
		
 | 
			
		||||
		[role_definition]
 | 
			
		||||
		g = _, _
 | 
			
		||||
		
 | 
			
		||||
		[policy_effect]
 | 
			
		||||
		e = some(where (p.eft == allow))
 | 
			
		||||
		
 | 
			
		||||
		[matchers]
 | 
			
		||||
		m = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act
 | 
			
		||||
		`
 | 
			
		||||
		m, err := model.NewModelFromString(text)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			zap.L().Error("字符串加载模型失败!", zap.Error(err))
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		syncedCachedEnforcer, _ = casbin.NewSyncedCachedEnforcer(m, a)
 | 
			
		||||
		syncedCachedEnforcer.SetExpireTime(60 * 60)
 | 
			
		||||
		_ = syncedCachedEnforcer.LoadPolicy()
 | 
			
		||||
	})
 | 
			
		||||
	return syncedCachedEnforcer
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										167
									
								
								service/system/sys_chatgpt.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								service/system/sys_chatgpt.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,167 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/sashabaranov/go-openai"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/model/system/request"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ChatGptService struct{}
 | 
			
		||||
 | 
			
		||||
func (chat *ChatGptService) CreateSK(option system.SysChatGptOption) error {
 | 
			
		||||
	_, err := chat.GetSK()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if errors.Is(err, gorm.ErrRecordNotFound) {
 | 
			
		||||
			return global.GVA_DB.Create(option).Error
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return errors.New("已经存在sk")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (chat *ChatGptService) GetSK() (option system.SysChatGptOption, err error) {
 | 
			
		||||
	err = global.GVA_DB.First(&option).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (chat *ChatGptService) DeleteSK() error {
 | 
			
		||||
	option, err := chat.GetSK()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return global.GVA_DB.Delete(option, "sk = ?", option.SK).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (chat *ChatGptService) GetTable(req request.ChatGptRequest) (sql string, results []map[string]interface{}, err error) {
 | 
			
		||||
	if req.DBName == "" {
 | 
			
		||||
		return "", nil, errors.New("未选择db")
 | 
			
		||||
	}
 | 
			
		||||
	var tablesInfo []system.ChatField
 | 
			
		||||
	var tableName string
 | 
			
		||||
	global.GVA_DB.Table("information_schema.columns").Where("TABLE_SCHEMA = ?", req.DBName).Scan(&tablesInfo)
 | 
			
		||||
 | 
			
		||||
	var tablesMap = make(map[string]bool)
 | 
			
		||||
	for i := range tablesInfo {
 | 
			
		||||
		tablesMap[tablesInfo[i].TABLE_NAME] = true
 | 
			
		||||
	}
 | 
			
		||||
	for i := range tablesMap {
 | 
			
		||||
		tableName += i + ","
 | 
			
		||||
	}
 | 
			
		||||
	option, err := chat.GetSK()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", nil, err
 | 
			
		||||
	}
 | 
			
		||||
	client := openai.NewClient(option.SK)
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
 | 
			
		||||
	tables, err := getTables(ctx, client, tableName, req.Chat)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", nil, err
 | 
			
		||||
	}
 | 
			
		||||
	tableArr := strings.Split(tables, ",")
 | 
			
		||||
	if len(tableArr) != 0 {
 | 
			
		||||
		firstKeyArr := strings.Split(tableArr[0], ":")
 | 
			
		||||
		tableArr[0] = strings.Trim(firstKeyArr[len(firstKeyArr)-1], "\n")
 | 
			
		||||
	}
 | 
			
		||||
	sql, err = getSql(ctx, client, tableArr, tablesInfo, req.Chat)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", nil, err
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Raw(sql).Scan(&results).Error
 | 
			
		||||
	return sql, results, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTables(ctx context.Context, client *openai.Client, tables string, chat string) (string, error) {
 | 
			
		||||
	var tablePrompt = `You are a database administrator
 | 
			
		||||
 | 
			
		||||
Filter out the table names you might need from the tables I provided formatted as:
 | 
			
		||||
 | 
			
		||||
Table1,Table2,Table3
 | 
			
		||||
 | 
			
		||||
I will provide you with the following table configuration information:
 | 
			
		||||
 | 
			
		||||
Table1,Table2,Table3
 | 
			
		||||
 | 
			
		||||
Do not return information other than the table
 | 
			
		||||
 | 
			
		||||
Configured as:
 | 
			
		||||
%s
 | 
			
		||||
 | 
			
		||||
The problem is:
 | 
			
		||||
%s
 | 
			
		||||
`
 | 
			
		||||
	content := fmt.Sprintf(tablePrompt, tables, chat)
 | 
			
		||||
	chatReq := openai.ChatCompletionRequest{
 | 
			
		||||
		Model: openai.GPT3Dot5Turbo,
 | 
			
		||||
		Messages: []openai.ChatCompletionMessage{
 | 
			
		||||
			{
 | 
			
		||||
				Role:    openai.ChatMessageRoleUser,
 | 
			
		||||
				Content: content,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := client.CreateChatCompletion(ctx, chatReq)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Printf("Completion error: %v\n", err)
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return resp.Choices[0].Message.Content, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getSql(ctx context.Context, client *openai.Client, tables []string, ChatField []system.ChatField, chat string) (string, error) {
 | 
			
		||||
	var sqlPrompt = `You are a database administrator
 | 
			
		||||
 | 
			
		||||
Give me an SQL statement based on my question
 | 
			
		||||
 | 
			
		||||
I will provide you with my current database table configuration information in the form below
 | 
			
		||||
 | 
			
		||||
Table Name | Column Name | Column Description
 | 
			
		||||
 | 
			
		||||
Do not return information other than SQL
 | 
			
		||||
 | 
			
		||||
Configured as:
 | 
			
		||||
 | 
			
		||||
%s
 | 
			
		||||
 | 
			
		||||
The problem is:
 | 
			
		||||
 | 
			
		||||
%s`
 | 
			
		||||
	var configured string
 | 
			
		||||
	for ii := range ChatField {
 | 
			
		||||
		for i := range tables {
 | 
			
		||||
			if strings.Index(tables[i], ChatField[ii].TABLE_NAME) > -1 {
 | 
			
		||||
				configured += fmt.Sprintf("%s | %s | %s \n", ChatField[ii].TABLE_NAME, ChatField[ii].COLUMN_NAME, ChatField[ii].COLUMN_COMMENT)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if configured == "" {
 | 
			
		||||
		return "", errors.New("未找到表")
 | 
			
		||||
	}
 | 
			
		||||
	chatReq := openai.ChatCompletionRequest{
 | 
			
		||||
		Model: openai.GPT3Dot5Turbo,
 | 
			
		||||
		Messages: []openai.ChatCompletionMessage{
 | 
			
		||||
			{
 | 
			
		||||
				Role:    openai.ChatMessageRoleUser,
 | 
			
		||||
				Content: fmt.Sprintf(sqlPrompt, configured, chat),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := client.CreateChatCompletion(ctx, chatReq)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Printf("Completion error: %v\n", err)
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	sql := resp.Choices[0].Message.Content
 | 
			
		||||
	sqlArr := strings.Split(sql, ":")
 | 
			
		||||
	sql = sqlArr[len(sqlArr)-1]
 | 
			
		||||
	return sql, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										128
									
								
								service/system/sys_dictionary.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								service/system/sys_dictionary.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/model/system/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteSysDictionary
 | 
			
		||||
//@description: 创建字典数据
 | 
			
		||||
//@param: sysDictionary model.SysDictionary
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
type DictionaryService struct{}
 | 
			
		||||
 | 
			
		||||
func (dictionaryService *DictionaryService) CreateSysDictionary(sysDictionary system.SysDictionary) (err error) {
 | 
			
		||||
	if (!errors.Is(global.GVA_DB.First(&system.SysDictionary{}, "type = ?", sysDictionary.Type).Error, gorm.ErrRecordNotFound)) {
 | 
			
		||||
		return errors.New("存在相同的type,不允许创建")
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Create(&sysDictionary).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteSysDictionary
 | 
			
		||||
//@description: 删除字典数据
 | 
			
		||||
//@param: sysDictionary model.SysDictionary
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (dictionaryService *DictionaryService) DeleteSysDictionary(sysDictionary system.SysDictionary) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", sysDictionary.ID).Preload("SysDictionaryDetails").First(&sysDictionary).Error
 | 
			
		||||
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return errors.New("请不要搞事")
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Delete(&sysDictionary).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sysDictionary.SysDictionaryDetails != nil {
 | 
			
		||||
		return global.GVA_DB.Where("sys_dictionary_id=?", sysDictionary.ID).Delete(sysDictionary.SysDictionaryDetails).Error
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: UpdateSysDictionary
 | 
			
		||||
//@description: 更新字典数据
 | 
			
		||||
//@param: sysDictionary *model.SysDictionary
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (dictionaryService *DictionaryService) UpdateSysDictionary(sysDictionary *system.SysDictionary) (err error) {
 | 
			
		||||
	var dict system.SysDictionary
 | 
			
		||||
	sysDictionaryMap := map[string]interface{}{
 | 
			
		||||
		"Name":   sysDictionary.Name,
 | 
			
		||||
		"Type":   sysDictionary.Type,
 | 
			
		||||
		"Status": sysDictionary.Status,
 | 
			
		||||
		"Desc":   sysDictionary.Desc,
 | 
			
		||||
	}
 | 
			
		||||
	db := global.GVA_DB.Where("id = ?", sysDictionary.ID).First(&dict)
 | 
			
		||||
	if dict.Type != sysDictionary.Type {
 | 
			
		||||
		if !errors.Is(global.GVA_DB.First(&system.SysDictionary{}, "type = ?", sysDictionary.Type).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
			return errors.New("存在相同的type,不允许创建")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	err = db.Updates(sysDictionaryMap).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetSysDictionary
 | 
			
		||||
//@description: 根据id或者type获取字典单条数据
 | 
			
		||||
//@param: Type string, Id uint
 | 
			
		||||
//@return: err error, sysDictionary model.SysDictionary
 | 
			
		||||
 | 
			
		||||
func (dictionaryService *DictionaryService) GetSysDictionary(Type string, Id uint, status *bool) (sysDictionary system.SysDictionary, err error) {
 | 
			
		||||
	var flag = false
 | 
			
		||||
	if status == nil {
 | 
			
		||||
		flag = true
 | 
			
		||||
	} else {
 | 
			
		||||
		flag = *status
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Where("(type = ? OR id = ?) and status = ?", Type, Id, flag).Preload("SysDictionaryDetails", func(db *gorm.DB) *gorm.DB {
 | 
			
		||||
		return db.Where("status = ?", true).Order("sort")
 | 
			
		||||
	}).First(&sysDictionary).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@author: [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
//@function: GetSysDictionaryInfoList
 | 
			
		||||
//@description: 分页获取字典列表
 | 
			
		||||
//@param: info request.SysDictionarySearch
 | 
			
		||||
//@return: err error, list interface{}, total int64
 | 
			
		||||
 | 
			
		||||
func (dictionaryService *DictionaryService) GetSysDictionaryInfoList(info request.SysDictionarySearch) (list interface{}, total int64, err error) {
 | 
			
		||||
	limit := info.PageSize
 | 
			
		||||
	offset := info.PageSize * (info.Page - 1)
 | 
			
		||||
	// 创建db
 | 
			
		||||
	db := global.GVA_DB.Model(&system.SysDictionary{})
 | 
			
		||||
	var sysDictionarys []system.SysDictionary
 | 
			
		||||
	// 如果有条件搜索 下方会自动创建搜索语句
 | 
			
		||||
	if info.Name != "" {
 | 
			
		||||
		db = db.Where("`name` LIKE ?", "%"+info.Name+"%")
 | 
			
		||||
	}
 | 
			
		||||
	if info.Type != "" {
 | 
			
		||||
		db = db.Where("`type` LIKE ?", "%"+info.Type+"%")
 | 
			
		||||
	}
 | 
			
		||||
	if info.Status != nil {
 | 
			
		||||
		db = db.Where("`status` = ?", info.Status)
 | 
			
		||||
	}
 | 
			
		||||
	if info.Desc != "" {
 | 
			
		||||
		db = db.Where("`desc` LIKE ?", "%"+info.Desc+"%")
 | 
			
		||||
	}
 | 
			
		||||
	err = db.Count(&total).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	err = db.Limit(limit).Offset(offset).Find(&sysDictionarys).Error
 | 
			
		||||
	return sysDictionarys, total, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								service/system/sys_dictionary_detail.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								service/system/sys_dictionary_detail.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/model/system/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: CreateSysDictionaryDetail
 | 
			
		||||
//@description: 创建字典详情数据
 | 
			
		||||
//@param: sysDictionaryDetail model.SysDictionaryDetail
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
type DictionaryDetailService struct{}
 | 
			
		||||
 | 
			
		||||
func (dictionaryDetailService *DictionaryDetailService) CreateSysDictionaryDetail(sysDictionaryDetail system.SysDictionaryDetail) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Create(&sysDictionaryDetail).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteSysDictionaryDetail
 | 
			
		||||
//@description: 删除字典详情数据
 | 
			
		||||
//@param: sysDictionaryDetail model.SysDictionaryDetail
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (dictionaryDetailService *DictionaryDetailService) DeleteSysDictionaryDetail(sysDictionaryDetail system.SysDictionaryDetail) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Delete(&sysDictionaryDetail).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: UpdateSysDictionaryDetail
 | 
			
		||||
//@description: 更新字典详情数据
 | 
			
		||||
//@param: sysDictionaryDetail *model.SysDictionaryDetail
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (dictionaryDetailService *DictionaryDetailService) UpdateSysDictionaryDetail(sysDictionaryDetail *system.SysDictionaryDetail) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Save(sysDictionaryDetail).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetSysDictionaryDetail
 | 
			
		||||
//@description: 根据id获取字典详情单条数据
 | 
			
		||||
//@param: id uint
 | 
			
		||||
//@return: sysDictionaryDetail system.SysDictionaryDetail, err error
 | 
			
		||||
 | 
			
		||||
func (dictionaryDetailService *DictionaryDetailService) GetSysDictionaryDetail(id uint) (sysDictionaryDetail system.SysDictionaryDetail, err error) {
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", id).First(&sysDictionaryDetail).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetSysDictionaryDetailInfoList
 | 
			
		||||
//@description: 分页获取字典详情列表
 | 
			
		||||
//@param: info request.SysDictionaryDetailSearch
 | 
			
		||||
//@return: list interface{}, total int64, err error
 | 
			
		||||
 | 
			
		||||
func (dictionaryDetailService *DictionaryDetailService) GetSysDictionaryDetailInfoList(info request.SysDictionaryDetailSearch) (list interface{}, total int64, err error) {
 | 
			
		||||
	limit := info.PageSize
 | 
			
		||||
	offset := info.PageSize * (info.Page - 1)
 | 
			
		||||
	// 创建db
 | 
			
		||||
	db := global.GVA_DB.Model(&system.SysDictionaryDetail{})
 | 
			
		||||
	var sysDictionaryDetails []system.SysDictionaryDetail
 | 
			
		||||
	// 如果有条件搜索 下方会自动创建搜索语句
 | 
			
		||||
	if info.Label != "" {
 | 
			
		||||
		db = db.Where("label LIKE ?", "%"+info.Label+"%")
 | 
			
		||||
	}
 | 
			
		||||
	if info.Value != 0 {
 | 
			
		||||
		db = db.Where("value = ?", info.Value)
 | 
			
		||||
	}
 | 
			
		||||
	if info.Status != nil {
 | 
			
		||||
		db = db.Where("status = ?", info.Status)
 | 
			
		||||
	}
 | 
			
		||||
	if info.SysDictionaryID != 0 {
 | 
			
		||||
		db = db.Where("sys_dictionary_id = ?", info.SysDictionaryID)
 | 
			
		||||
	}
 | 
			
		||||
	err = db.Count(&total).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	err = db.Limit(limit).Offset(offset).Order("sort").Find(&sysDictionaryDetails).Error
 | 
			
		||||
	return sysDictionaryDetails, total, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										184
									
								
								service/system/sys_initdb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								service/system/sys_initdb.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,184 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/request"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Mysql           = "mysql"
 | 
			
		||||
	Pgsql           = "pgsql"
 | 
			
		||||
	Sqlite          = "sqlite"
 | 
			
		||||
	InitSuccess     = "\n[%v] --> 初始数据成功!\n"
 | 
			
		||||
	InitDataExist   = "\n[%v] --> %v 的初始数据已存在!\n"
 | 
			
		||||
	InitDataFailed  = "\n[%v] --> %v 初始数据失败! \nerr: %+v\n"
 | 
			
		||||
	InitDataSuccess = "\n[%v] --> %v 初始数据成功!\n"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	InitOrderSystem   = 10
 | 
			
		||||
	InitOrderInternal = 1000
 | 
			
		||||
	InitOrderExternal = 100000
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrMissingDBContext        = errors.New("missing db in context")
 | 
			
		||||
	ErrMissingDependentContext = errors.New("missing dependent value in context")
 | 
			
		||||
	ErrDBTypeMismatch          = errors.New("db type mismatch")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SubInitializer 提供 source/*/init() 使用的接口,每个 initializer 完成一个初始化过程
 | 
			
		||||
type SubInitializer interface {
 | 
			
		||||
	InitializerName() string // 不一定代表单独一个表,所以改成了更宽泛的语义
 | 
			
		||||
	MigrateTable(ctx context.Context) (next context.Context, err error)
 | 
			
		||||
	InitializeData(ctx context.Context) (next context.Context, err error)
 | 
			
		||||
	TableCreated(ctx context.Context) bool
 | 
			
		||||
	DataInserted(ctx context.Context) bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TypedDBInitHandler 执行传入的 initializer
 | 
			
		||||
type TypedDBInitHandler interface {
 | 
			
		||||
	EnsureDB(ctx context.Context, conf *request.InitDB) (context.Context, error) // 建库,失败属于 fatal error,因此让它 panic
 | 
			
		||||
	WriteConfig(ctx context.Context) error                                       // 回写配置
 | 
			
		||||
	InitTables(ctx context.Context, inits initSlice) error                       // 建表 handler
 | 
			
		||||
	InitData(ctx context.Context, inits initSlice) error                         // 建数据 handler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// orderedInitializer 组合一个顺序字段,以供排序
 | 
			
		||||
type orderedInitializer struct {
 | 
			
		||||
	order int
 | 
			
		||||
	SubInitializer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// initSlice 供 initializer 排序依赖时使用
 | 
			
		||||
type initSlice []*orderedInitializer
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	initializers initSlice
 | 
			
		||||
	cache        map[string]*orderedInitializer
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RegisterInit 注册要执行的初始化过程,会在 InitDB() 时调用
 | 
			
		||||
func RegisterInit(order int, i SubInitializer) {
 | 
			
		||||
	if initializers == nil {
 | 
			
		||||
		initializers = initSlice{}
 | 
			
		||||
	}
 | 
			
		||||
	if cache == nil {
 | 
			
		||||
		cache = map[string]*orderedInitializer{}
 | 
			
		||||
	}
 | 
			
		||||
	name := i.InitializerName()
 | 
			
		||||
	if _, existed := cache[name]; existed {
 | 
			
		||||
		panic(fmt.Sprintf("Name conflict on %s", name))
 | 
			
		||||
	}
 | 
			
		||||
	ni := orderedInitializer{order, i}
 | 
			
		||||
	initializers = append(initializers, &ni)
 | 
			
		||||
	cache[name] = &ni
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ---- * service * ---- */
 | 
			
		||||
 | 
			
		||||
type InitDBService struct{}
 | 
			
		||||
 | 
			
		||||
// InitDB 创建数据库并初始化 总入口
 | 
			
		||||
func (initDBService *InitDBService) InitDB(conf request.InitDB) (err error) {
 | 
			
		||||
	ctx := context.TODO()
 | 
			
		||||
	if len(initializers) == 0 {
 | 
			
		||||
		return errors.New("无可用初始化过程,请检查初始化是否已执行完成")
 | 
			
		||||
	}
 | 
			
		||||
	sort.Sort(&initializers) // 保证有依赖的 initializer 排在后面执行
 | 
			
		||||
	// Note: 若 initializer 只有单一依赖,可以写为 B=A+1, C=A+1; 由于 BC 之间没有依赖关系,所以谁先谁后并不影响初始化
 | 
			
		||||
	// 若存在多个依赖,可以写为 C=A+B, D=A+B+C, E=A+1;
 | 
			
		||||
	// C必然>A|B,因此在AB之后执行,D必然>A|B|C,因此在ABC后执行,而E只依赖A,顺序与CD无关,因此E与CD哪个先执行并不影响
 | 
			
		||||
	var initHandler TypedDBInitHandler
 | 
			
		||||
	switch conf.DBType {
 | 
			
		||||
	case "mysql":
 | 
			
		||||
		initHandler = NewMysqlInitHandler()
 | 
			
		||||
		ctx = context.WithValue(ctx, "dbtype", "mysql")
 | 
			
		||||
	case "pgsql":
 | 
			
		||||
		initHandler = NewPgsqlInitHandler()
 | 
			
		||||
		ctx = context.WithValue(ctx, "dbtype", "pgsql")
 | 
			
		||||
	case "sqlite":
 | 
			
		||||
		initHandler = NewSqliteInitHandler()
 | 
			
		||||
		ctx = context.WithValue(ctx, "dbtype", "sqlite")
 | 
			
		||||
	default:
 | 
			
		||||
		initHandler = NewMysqlInitHandler()
 | 
			
		||||
		ctx = context.WithValue(ctx, "dbtype", "mysql")
 | 
			
		||||
	}
 | 
			
		||||
	ctx, err = initHandler.EnsureDB(ctx, &conf)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	db := ctx.Value("db").(*gorm.DB)
 | 
			
		||||
	global.GVA_DB = db
 | 
			
		||||
 | 
			
		||||
	if err = initHandler.InitTables(ctx, initializers); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err = initHandler.InitData(ctx, initializers); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = initHandler.WriteConfig(ctx); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	initializers = initSlice{}
 | 
			
		||||
	cache = map[string]*orderedInitializer{}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// createDatabase 创建数据库( EnsureDB() 中调用 )
 | 
			
		||||
func createDatabase(dsn string, driver string, createSql string) error {
 | 
			
		||||
	db, err := sql.Open(driver, dsn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer func(db *sql.DB) {
 | 
			
		||||
		err = db.Close()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println(err)
 | 
			
		||||
		}
 | 
			
		||||
	}(db)
 | 
			
		||||
	if err = db.Ping(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = db.Exec(createSql)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// createTables 创建表(默认 dbInitHandler.initTables 行为)
 | 
			
		||||
func createTables(ctx context.Context, inits initSlice) error {
 | 
			
		||||
	next, cancel := context.WithCancel(ctx)
 | 
			
		||||
	defer func(c func()) { c() }(cancel)
 | 
			
		||||
	for _, init := range inits {
 | 
			
		||||
		if init.TableCreated(next) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if n, err := init.MigrateTable(next); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		} else {
 | 
			
		||||
			next = n
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* -- sortable interface -- */
 | 
			
		||||
 | 
			
		||||
func (a initSlice) Len() int {
 | 
			
		||||
	return len(a)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a initSlice) Less(i, j int) bool {
 | 
			
		||||
	return a[i].order < a[j].order
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a initSlice) Swap(i, j int) {
 | 
			
		||||
	a[i], a[j] = a[j], a[i]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								service/system/sys_initdb_mysql.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								service/system/sys_initdb_mysql.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/gookit/color"
 | 
			
		||||
	"miniapp/config"
 | 
			
		||||
 | 
			
		||||
	"miniapp/utils"
 | 
			
		||||
 | 
			
		||||
	"github.com/gofrs/uuid/v5"
 | 
			
		||||
	"gorm.io/driver/mysql"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MysqlInitHandler struct{}
 | 
			
		||||
 | 
			
		||||
func NewMysqlInitHandler() *MysqlInitHandler {
 | 
			
		||||
	return &MysqlInitHandler{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteConfig mysql回写配置
 | 
			
		||||
func (h MysqlInitHandler) WriteConfig(ctx context.Context) error {
 | 
			
		||||
	c, ok := ctx.Value("config").(config.Mysql)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("mysql config invalid")
 | 
			
		||||
	}
 | 
			
		||||
	global.GVA_CONFIG.System.DbType = "mysql"
 | 
			
		||||
	global.GVA_CONFIG.Mysql = c
 | 
			
		||||
	global.GVA_CONFIG.JWT.SigningKey = uuid.Must(uuid.NewV4()).String()
 | 
			
		||||
	cs := utils.StructToMap(global.GVA_CONFIG)
 | 
			
		||||
	for k, v := range cs {
 | 
			
		||||
		global.GVA_VP.Set(k, v)
 | 
			
		||||
	}
 | 
			
		||||
	return global.GVA_VP.WriteConfig()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EnsureDB 创建数据库并初始化 mysql
 | 
			
		||||
func (h MysqlInitHandler) EnsureDB(ctx context.Context, conf *request.InitDB) (next context.Context, err error) {
 | 
			
		||||
	if s, ok := ctx.Value("dbtype").(string); !ok || s != "mysql" {
 | 
			
		||||
		return ctx, ErrDBTypeMismatch
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c := conf.ToMysqlConfig()
 | 
			
		||||
	next = context.WithValue(ctx, "config", c)
 | 
			
		||||
	if c.Dbname == "" {
 | 
			
		||||
		return ctx, nil
 | 
			
		||||
	} // 如果没有数据库名, 则跳出初始化数据
 | 
			
		||||
 | 
			
		||||
	dsn := conf.MysqlEmptyDsn()
 | 
			
		||||
	createSql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;", c.Dbname)
 | 
			
		||||
	if err = createDatabase(dsn, "mysql", createSql); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} // 创建数据库
 | 
			
		||||
 | 
			
		||||
	var db *gorm.DB
 | 
			
		||||
	if db, err = gorm.Open(mysql.New(mysql.Config{
 | 
			
		||||
		DSN:                       c.Dsn(), // DSN data source name
 | 
			
		||||
		DefaultStringSize:         191,     // string 类型字段的默认长度
 | 
			
		||||
		SkipInitializeWithVersion: true,    // 根据版本自动配置
 | 
			
		||||
	}), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}); err != nil {
 | 
			
		||||
		return ctx, err
 | 
			
		||||
	}
 | 
			
		||||
	global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..")
 | 
			
		||||
	next = context.WithValue(next, "db", db)
 | 
			
		||||
	return next, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h MysqlInitHandler) InitTables(ctx context.Context, inits initSlice) error {
 | 
			
		||||
	return createTables(ctx, inits)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h MysqlInitHandler) InitData(ctx context.Context, inits initSlice) error {
 | 
			
		||||
	next, cancel := context.WithCancel(ctx)
 | 
			
		||||
	defer func(c func()) { c() }(cancel)
 | 
			
		||||
	for _, init := range inits {
 | 
			
		||||
		if init.DataInserted(next) {
 | 
			
		||||
			color.Info.Printf(InitDataExist, Mysql, init.InitializerName())
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if n, err := init.InitializeData(next); err != nil {
 | 
			
		||||
			color.Info.Printf(InitDataFailed, Mysql, init.InitializerName(), err)
 | 
			
		||||
			return err
 | 
			
		||||
		} else {
 | 
			
		||||
			next = n
 | 
			
		||||
			color.Info.Printf(InitDataSuccess, Mysql, init.InitializerName())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	color.Info.Printf(InitSuccess, Mysql)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								service/system/sys_initdb_pgsql.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								service/system/sys_initdb_pgsql.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/gookit/color"
 | 
			
		||||
	"miniapp/config"
 | 
			
		||||
 | 
			
		||||
	"miniapp/utils"
 | 
			
		||||
 | 
			
		||||
	"github.com/gofrs/uuid/v5"
 | 
			
		||||
	"gorm.io/driver/postgres"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type PgsqlInitHandler struct{}
 | 
			
		||||
 | 
			
		||||
func NewPgsqlInitHandler() *PgsqlInitHandler {
 | 
			
		||||
	return &PgsqlInitHandler{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteConfig pgsql 回写配置
 | 
			
		||||
func (h PgsqlInitHandler) WriteConfig(ctx context.Context) error {
 | 
			
		||||
	c, ok := ctx.Value("config").(config.Pgsql)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("postgresql config invalid")
 | 
			
		||||
	}
 | 
			
		||||
	global.GVA_CONFIG.System.DbType = "pgsql"
 | 
			
		||||
	global.GVA_CONFIG.Pgsql = c
 | 
			
		||||
	global.GVA_CONFIG.JWT.SigningKey = uuid.Must(uuid.NewV4()).String()
 | 
			
		||||
	cs := utils.StructToMap(global.GVA_CONFIG)
 | 
			
		||||
	for k, v := range cs {
 | 
			
		||||
		global.GVA_VP.Set(k, v)
 | 
			
		||||
	}
 | 
			
		||||
	return global.GVA_VP.WriteConfig()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EnsureDB 创建数据库并初始化 pg
 | 
			
		||||
func (h PgsqlInitHandler) EnsureDB(ctx context.Context, conf *request.InitDB) (next context.Context, err error) {
 | 
			
		||||
	if s, ok := ctx.Value("dbtype").(string); !ok || s != "pgsql" {
 | 
			
		||||
		return ctx, ErrDBTypeMismatch
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c := conf.ToPgsqlConfig()
 | 
			
		||||
	next = context.WithValue(ctx, "config", c)
 | 
			
		||||
	if c.Dbname == "" {
 | 
			
		||||
		return ctx, nil
 | 
			
		||||
	} // 如果没有数据库名, 则跳出初始化数据
 | 
			
		||||
 | 
			
		||||
	dsn := conf.PgsqlEmptyDsn()
 | 
			
		||||
	createSql := fmt.Sprintf("CREATE DATABASE %s;", c.Dbname)
 | 
			
		||||
	if err = createDatabase(dsn, "pgx", createSql); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} // 创建数据库
 | 
			
		||||
 | 
			
		||||
	var db *gorm.DB
 | 
			
		||||
	if db, err = gorm.Open(postgres.New(postgres.Config{
 | 
			
		||||
		DSN:                  c.Dsn(), // DSN data source name
 | 
			
		||||
		PreferSimpleProtocol: false,
 | 
			
		||||
	}), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}); err != nil {
 | 
			
		||||
		return ctx, err
 | 
			
		||||
	}
 | 
			
		||||
	global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..")
 | 
			
		||||
	next = context.WithValue(next, "db", db)
 | 
			
		||||
	return next, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h PgsqlInitHandler) InitTables(ctx context.Context, inits initSlice) error {
 | 
			
		||||
	return createTables(ctx, inits)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h PgsqlInitHandler) InitData(ctx context.Context, inits initSlice) error {
 | 
			
		||||
	next, cancel := context.WithCancel(ctx)
 | 
			
		||||
	defer func(c func()) { c() }(cancel)
 | 
			
		||||
	for i := 0; i < len(inits); i++ {
 | 
			
		||||
		if inits[i].DataInserted(next) {
 | 
			
		||||
			color.Info.Printf(InitDataExist, Pgsql, inits[i].InitializerName())
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if n, err := inits[i].InitializeData(next); err != nil {
 | 
			
		||||
			color.Info.Printf(InitDataFailed, Pgsql, inits[i].InitializerName(), err)
 | 
			
		||||
			return err
 | 
			
		||||
		} else {
 | 
			
		||||
			next = n
 | 
			
		||||
			color.Info.Printf(InitDataSuccess, Pgsql, inits[i].InitializerName())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	color.Info.Printf(InitSuccess, Pgsql)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								service/system/sys_initdb_sqlite.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								service/system/sys_initdb_sqlite.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/glebarez/sqlite"
 | 
			
		||||
	"github.com/gofrs/uuid/v5"
 | 
			
		||||
	"github.com/gookit/color"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/config"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system/request"
 | 
			
		||||
	"miniapp/utils"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SqliteInitHandler struct{}
 | 
			
		||||
 | 
			
		||||
func NewSqliteInitHandler() *SqliteInitHandler {
 | 
			
		||||
	return &SqliteInitHandler{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteConfig mysql回写配置
 | 
			
		||||
func (h SqliteInitHandler) WriteConfig(ctx context.Context) error {
 | 
			
		||||
	c, ok := ctx.Value("config").(config.Sqlite)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("mysql config invalid")
 | 
			
		||||
	}
 | 
			
		||||
	global.GVA_CONFIG.System.DbType = "sqlite"
 | 
			
		||||
	global.GVA_CONFIG.Sqlite = c
 | 
			
		||||
	global.GVA_CONFIG.JWT.SigningKey = uuid.Must(uuid.NewV4()).String()
 | 
			
		||||
	cs := utils.StructToMap(global.GVA_CONFIG)
 | 
			
		||||
	for k, v := range cs {
 | 
			
		||||
		global.GVA_VP.Set(k, v)
 | 
			
		||||
	}
 | 
			
		||||
	return global.GVA_VP.WriteConfig()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EnsureDB 创建数据库并初始化 sqlite
 | 
			
		||||
func (h SqliteInitHandler) EnsureDB(ctx context.Context, conf *request.InitDB) (next context.Context, err error) {
 | 
			
		||||
	if s, ok := ctx.Value("dbtype").(string); !ok || s != "sqlite" {
 | 
			
		||||
		return ctx, ErrDBTypeMismatch
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c := conf.ToSqliteConfig()
 | 
			
		||||
	next = context.WithValue(ctx, "config", c)
 | 
			
		||||
	if c.Dbname == "" {
 | 
			
		||||
		return ctx, nil
 | 
			
		||||
	} // 如果没有数据库名, 则跳出初始化数据
 | 
			
		||||
 | 
			
		||||
	dsn := conf.SqliteEmptyDsn()
 | 
			
		||||
 | 
			
		||||
	var db *gorm.DB
 | 
			
		||||
	if db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{
 | 
			
		||||
		DisableForeignKeyConstraintWhenMigrating: true,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return ctx, err
 | 
			
		||||
	}
 | 
			
		||||
	global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..")
 | 
			
		||||
	next = context.WithValue(next, "db", db)
 | 
			
		||||
	return next, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h SqliteInitHandler) InitTables(ctx context.Context, inits initSlice) error {
 | 
			
		||||
	return createTables(ctx, inits)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h SqliteInitHandler) InitData(ctx context.Context, inits initSlice) error {
 | 
			
		||||
	next, cancel := context.WithCancel(ctx)
 | 
			
		||||
	defer func(c func()) { c() }(cancel)
 | 
			
		||||
	for _, init := range inits {
 | 
			
		||||
		if init.DataInserted(next) {
 | 
			
		||||
			color.Info.Printf(InitDataExist, Sqlite, init.InitializerName())
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if n, err := init.InitializeData(next); err != nil {
 | 
			
		||||
			color.Info.Printf(InitDataFailed, Sqlite, init.InitializerName(), err)
 | 
			
		||||
			return err
 | 
			
		||||
		} else {
 | 
			
		||||
			next = n
 | 
			
		||||
			color.Info.Printf(InitDataSuccess, Sqlite, init.InitializerName())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	color.Info.Printf(InitSuccess, Sqlite)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										236
									
								
								service/system/sys_menu.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								service/system/sys_menu.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,236 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/common/request"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: getMenuTreeMap
 | 
			
		||||
//@description: 获取路由总树map
 | 
			
		||||
//@param: authorityId string
 | 
			
		||||
//@return: treeMap map[string][]system.SysMenu, err error
 | 
			
		||||
 | 
			
		||||
type MenuService struct{}
 | 
			
		||||
 | 
			
		||||
var MenuServiceApp = new(MenuService)
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) getMenuTreeMap(authorityId uint) (treeMap map[string][]system.SysMenu, err error) {
 | 
			
		||||
	var allMenus []system.SysMenu
 | 
			
		||||
	var baseMenu []system.SysBaseMenu
 | 
			
		||||
	var btns []system.SysAuthorityBtn
 | 
			
		||||
	treeMap = make(map[string][]system.SysMenu)
 | 
			
		||||
 | 
			
		||||
	var SysAuthorityMenus []system.SysAuthorityMenu
 | 
			
		||||
	err = global.GVA_DB.Where("sys_authority_authority_id = ?", authorityId).Find(&SysAuthorityMenus).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var MenuIds []string
 | 
			
		||||
 | 
			
		||||
	for i := range SysAuthorityMenus {
 | 
			
		||||
		MenuIds = append(MenuIds, SysAuthorityMenus[i].MenuId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = global.GVA_DB.Where("id in (?)", MenuIds).Order("sort").Preload("Parameters").Find(&baseMenu).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := range baseMenu {
 | 
			
		||||
		allMenus = append(allMenus, system.SysMenu{
 | 
			
		||||
			SysBaseMenu: baseMenu[i],
 | 
			
		||||
			AuthorityId: authorityId,
 | 
			
		||||
			MenuId:      strconv.Itoa(int(baseMenu[i].ID)),
 | 
			
		||||
			Parameters:  baseMenu[i].Parameters,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = global.GVA_DB.Where("authority_id = ?", authorityId).Preload("SysBaseMenuBtn").Find(&btns).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var btnMap = make(map[uint]map[string]uint)
 | 
			
		||||
	for _, v := range btns {
 | 
			
		||||
		if btnMap[v.SysMenuID] == nil {
 | 
			
		||||
			btnMap[v.SysMenuID] = make(map[string]uint)
 | 
			
		||||
		}
 | 
			
		||||
		btnMap[v.SysMenuID][v.SysBaseMenuBtn.Name] = authorityId
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range allMenus {
 | 
			
		||||
		v.Btns = btnMap[v.ID]
 | 
			
		||||
		treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
 | 
			
		||||
	}
 | 
			
		||||
	return treeMap, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetMenuTree
 | 
			
		||||
//@description: 获取动态菜单树
 | 
			
		||||
//@param: authorityId string
 | 
			
		||||
//@return: menus []system.SysMenu, err error
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) GetMenuTree(authorityId uint) (menus []system.SysMenu, err error) {
 | 
			
		||||
	menuTree, err := menuService.getMenuTreeMap(authorityId)
 | 
			
		||||
	menus = menuTree["0"]
 | 
			
		||||
	for i := 0; i < len(menus); i++ {
 | 
			
		||||
		err = menuService.getChildrenList(&menus[i], menuTree)
 | 
			
		||||
	}
 | 
			
		||||
	return menus, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: getChildrenList
 | 
			
		||||
//@description: 获取子菜单
 | 
			
		||||
//@param: menu *model.SysMenu, treeMap map[string][]model.SysMenu
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) getChildrenList(menu *system.SysMenu, treeMap map[string][]system.SysMenu) (err error) {
 | 
			
		||||
	menu.Children = treeMap[menu.MenuId]
 | 
			
		||||
	for i := 0; i < len(menu.Children); i++ {
 | 
			
		||||
		err = menuService.getChildrenList(&menu.Children[i], treeMap)
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetInfoList
 | 
			
		||||
//@description: 获取路由分页
 | 
			
		||||
//@return: list interface{}, total int64,err error
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) GetInfoList() (list interface{}, total int64, err error) {
 | 
			
		||||
	var menuList []system.SysBaseMenu
 | 
			
		||||
	treeMap, err := menuService.getBaseMenuTreeMap()
 | 
			
		||||
	menuList = treeMap["0"]
 | 
			
		||||
	for i := 0; i < len(menuList); i++ {
 | 
			
		||||
		err = menuService.getBaseChildrenList(&menuList[i], treeMap)
 | 
			
		||||
	}
 | 
			
		||||
	return menuList, total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: getBaseChildrenList
 | 
			
		||||
//@description: 获取菜单的子菜单
 | 
			
		||||
//@param: menu *model.SysBaseMenu, treeMap map[string][]model.SysBaseMenu
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) getBaseChildrenList(menu *system.SysBaseMenu, treeMap map[string][]system.SysBaseMenu) (err error) {
 | 
			
		||||
	menu.Children = treeMap[strconv.Itoa(int(menu.ID))]
 | 
			
		||||
	for i := 0; i < len(menu.Children); i++ {
 | 
			
		||||
		err = menuService.getBaseChildrenList(&menu.Children[i], treeMap)
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: AddBaseMenu
 | 
			
		||||
//@description: 添加基础路由
 | 
			
		||||
//@param: menu model.SysBaseMenu
 | 
			
		||||
//@return: error
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) AddBaseMenu(menu system.SysBaseMenu) error {
 | 
			
		||||
	if !errors.Is(global.GVA_DB.Where("name = ?", menu.Name).First(&system.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return errors.New("存在重复name,请修改name")
 | 
			
		||||
	}
 | 
			
		||||
	return global.GVA_DB.Create(&menu).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: getBaseMenuTreeMap
 | 
			
		||||
//@description: 获取路由总树map
 | 
			
		||||
//@return: treeMap map[string][]system.SysBaseMenu, err error
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) getBaseMenuTreeMap() (treeMap map[string][]system.SysBaseMenu, err error) {
 | 
			
		||||
	var allMenus []system.SysBaseMenu
 | 
			
		||||
	treeMap = make(map[string][]system.SysBaseMenu)
 | 
			
		||||
	err = global.GVA_DB.Order("sort").Preload("MenuBtn").Preload("Parameters").Find(&allMenus).Error
 | 
			
		||||
	for _, v := range allMenus {
 | 
			
		||||
		treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
 | 
			
		||||
	}
 | 
			
		||||
	return treeMap, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetBaseMenuTree
 | 
			
		||||
//@description: 获取基础路由树
 | 
			
		||||
//@return: menus []system.SysBaseMenu, err error
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) GetBaseMenuTree() (menus []system.SysBaseMenu, err error) {
 | 
			
		||||
	treeMap, err := menuService.getBaseMenuTreeMap()
 | 
			
		||||
	menus = treeMap["0"]
 | 
			
		||||
	for i := 0; i < len(menus); i++ {
 | 
			
		||||
		err = menuService.getBaseChildrenList(&menus[i], treeMap)
 | 
			
		||||
	}
 | 
			
		||||
	return menus, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: AddMenuAuthority
 | 
			
		||||
//@description: 为角色增加menu树
 | 
			
		||||
//@param: menus []model.SysBaseMenu, authorityId string
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) AddMenuAuthority(menus []system.SysBaseMenu, authorityId uint) (err error) {
 | 
			
		||||
	var auth system.SysAuthority
 | 
			
		||||
	auth.AuthorityId = authorityId
 | 
			
		||||
	auth.SysBaseMenus = menus
 | 
			
		||||
	err = AuthorityServiceApp.SetMenuAuthority(&auth)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetMenuAuthority
 | 
			
		||||
//@description: 查看当前角色树
 | 
			
		||||
//@param: info *request.GetAuthorityId
 | 
			
		||||
//@return: menus []system.SysMenu, err error
 | 
			
		||||
 | 
			
		||||
func (menuService *MenuService) GetMenuAuthority(info *request.GetAuthorityId) (menus []system.SysMenu, err error) {
 | 
			
		||||
	var baseMenu []system.SysBaseMenu
 | 
			
		||||
	var SysAuthorityMenus []system.SysAuthorityMenu
 | 
			
		||||
	err = global.GVA_DB.Where("sys_authority_authority_id = ?", info.AuthorityId).Find(&SysAuthorityMenus).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var MenuIds []string
 | 
			
		||||
 | 
			
		||||
	for i := range SysAuthorityMenus {
 | 
			
		||||
		MenuIds = append(MenuIds, SysAuthorityMenus[i].MenuId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = global.GVA_DB.Where("id in (?) ", MenuIds).Order("sort").Find(&baseMenu).Error
 | 
			
		||||
 | 
			
		||||
	for i := range baseMenu {
 | 
			
		||||
		menus = append(menus, system.SysMenu{
 | 
			
		||||
			SysBaseMenu: baseMenu[i],
 | 
			
		||||
			AuthorityId: uint(info.AuthorityId),
 | 
			
		||||
			MenuId:      strconv.Itoa(int(baseMenu[i].ID)),
 | 
			
		||||
			Parameters:  baseMenu[i].Parameters,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	// sql := "SELECT authority_menu.keep_alive,authority_menu.default_menu,authority_menu.created_at,authority_menu.updated_at,authority_menu.deleted_at,authority_menu.menu_level,authority_menu.parent_id,authority_menu.path,authority_menu.`name`,authority_menu.hidden,authority_menu.component,authority_menu.title,authority_menu.icon,authority_menu.sort,authority_menu.menu_id,authority_menu.authority_id FROM authority_menu WHERE authority_menu.authority_id = ? ORDER BY authority_menu.sort ASC"
 | 
			
		||||
	// err = global.GVA_DB.Raw(sql, authorityId).Scan(&menus).Error
 | 
			
		||||
	return menus, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UserAuthorityDefaultRouter 用户角色默认路由检查
 | 
			
		||||
//
 | 
			
		||||
//	Author [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
func (menuService *MenuService) UserAuthorityDefaultRouter(user *system.SysUser) {
 | 
			
		||||
	var menuIds []string
 | 
			
		||||
	err := global.GVA_DB.Model(&system.SysAuthorityMenu{}).Where("sys_authority_authority_id = ?", user.AuthorityId).Pluck("sys_base_menu_id", &menuIds).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var am system.SysBaseMenu
 | 
			
		||||
	err = global.GVA_DB.First(&am, "name = ? and id in (?)", user.Authority.DefaultRouter, menuIds).Error
 | 
			
		||||
	if errors.Is(err, gorm.ErrRecordNotFound) {
 | 
			
		||||
		user.Authority.DefaultRouter = "404"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								service/system/sys_operation_record.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								service/system/sys_operation_record.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/common/request"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	systemReq "miniapp/model/system/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//@author: [granty1](https://github.com/granty1)
 | 
			
		||||
//@function: CreateSysOperationRecord
 | 
			
		||||
//@description: 创建记录
 | 
			
		||||
//@param: sysOperationRecord model.SysOperationRecord
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
type OperationRecordService struct{}
 | 
			
		||||
 | 
			
		||||
func (operationRecordService *OperationRecordService) CreateSysOperationRecord(sysOperationRecord system.SysOperationRecord) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Create(&sysOperationRecord).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [granty1](https://github.com/granty1)
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteSysOperationRecordByIds
 | 
			
		||||
//@description: 批量删除记录
 | 
			
		||||
//@param: ids request.IdsReq
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (operationRecordService *OperationRecordService) DeleteSysOperationRecordByIds(ids request.IdsReq) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Delete(&[]system.SysOperationRecord{}, "id in (?)", ids.Ids).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [granty1](https://github.com/granty1)
 | 
			
		||||
//@function: DeleteSysOperationRecord
 | 
			
		||||
//@description: 删除操作记录
 | 
			
		||||
//@param: sysOperationRecord model.SysOperationRecord
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (operationRecordService *OperationRecordService) DeleteSysOperationRecord(sysOperationRecord system.SysOperationRecord) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Delete(&sysOperationRecord).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [granty1](https://github.com/granty1)
 | 
			
		||||
//@function: DeleteSysOperationRecord
 | 
			
		||||
//@description: 根据id获取单条操作记录
 | 
			
		||||
//@param: id uint
 | 
			
		||||
//@return: sysOperationRecord system.SysOperationRecord, err error
 | 
			
		||||
 | 
			
		||||
func (operationRecordService *OperationRecordService) GetSysOperationRecord(id uint) (sysOperationRecord system.SysOperationRecord, err error) {
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", id).First(&sysOperationRecord).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [granty1](https://github.com/granty1)
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetSysOperationRecordInfoList
 | 
			
		||||
//@description: 分页获取操作记录列表
 | 
			
		||||
//@param: info systemReq.SysOperationRecordSearch
 | 
			
		||||
//@return: list interface{}, total int64, err error
 | 
			
		||||
 | 
			
		||||
func (operationRecordService *OperationRecordService) GetSysOperationRecordInfoList(info systemReq.SysOperationRecordSearch) (list interface{}, total int64, err error) {
 | 
			
		||||
	limit := info.PageSize
 | 
			
		||||
	offset := info.PageSize * (info.Page - 1)
 | 
			
		||||
	// 创建db
 | 
			
		||||
	db := global.GVA_DB.Model(&system.SysOperationRecord{})
 | 
			
		||||
	var sysOperationRecords []system.SysOperationRecord
 | 
			
		||||
	// 如果有条件搜索 下方会自动创建搜索语句
 | 
			
		||||
	if info.Method != "" {
 | 
			
		||||
		db = db.Where("method = ?", info.Method)
 | 
			
		||||
	}
 | 
			
		||||
	if info.Path != "" {
 | 
			
		||||
		db = db.Where("path LIKE ?", "%"+info.Path+"%")
 | 
			
		||||
	}
 | 
			
		||||
	if info.Status != 0 {
 | 
			
		||||
		db = db.Where("status = ?", info.Status)
 | 
			
		||||
	}
 | 
			
		||||
	err = db.Count(&total).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	err = db.Order("id desc").Limit(limit).Offset(offset).Preload("User").Find(&sysOperationRecords).Error
 | 
			
		||||
	return sysOperationRecords, total, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								service/system/sys_system.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								service/system/sys_system.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"go.uber.org/zap"
 | 
			
		||||
	"miniapp/config"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/utils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetSystemConfig
 | 
			
		||||
//@description: 读取配置文件
 | 
			
		||||
//@return: conf config.Server, err error
 | 
			
		||||
 | 
			
		||||
type SystemConfigService struct{}
 | 
			
		||||
 | 
			
		||||
func (systemConfigService *SystemConfigService) GetSystemConfig() (conf config.Server, err error) {
 | 
			
		||||
	return global.GVA_CONFIG, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @description   set system config,
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: SetSystemConfig
 | 
			
		||||
//@description: 设置配置文件
 | 
			
		||||
//@param: system model.System
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (systemConfigService *SystemConfigService) SetSystemConfig(system system.System) (err error) {
 | 
			
		||||
	cs := utils.StructToMap(system.Config)
 | 
			
		||||
	for k, v := range cs {
 | 
			
		||||
		global.GVA_VP.Set(k, v)
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_VP.WriteConfig()
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
//@function: GetServerInfo
 | 
			
		||||
//@description: 获取服务器信息
 | 
			
		||||
//@return: server.exe.exe *utils.Server, err error
 | 
			
		||||
 | 
			
		||||
func (systemConfigService *SystemConfigService) GetServerInfo() (server *utils.Server, err error) {
 | 
			
		||||
	var s utils.Server
 | 
			
		||||
	s.Os = utils.InitOS()
 | 
			
		||||
	if s.Cpu, err = utils.InitCPU(); err != nil {
 | 
			
		||||
		global.GVA_LOG.Error("func utils.InitCPU() Failed", zap.String("err", err.Error()))
 | 
			
		||||
		return &s, err
 | 
			
		||||
	}
 | 
			
		||||
	if s.Ram, err = utils.InitRAM(); err != nil {
 | 
			
		||||
		global.GVA_LOG.Error("func utils.InitRAM() Failed", zap.String("err", err.Error()))
 | 
			
		||||
		return &s, err
 | 
			
		||||
	}
 | 
			
		||||
	if s.Disk, err = utils.InitDisk(); err != nil {
 | 
			
		||||
		global.GVA_LOG.Error("func utils.InitDisk() Failed", zap.String("err", err.Error()))
 | 
			
		||||
		return &s, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &s, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										245
									
								
								service/system/sys_user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								service/system/sys_user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,245 @@
 | 
			
		||||
package system
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/gofrs/uuid/v5"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"miniapp/global"
 | 
			
		||||
	"miniapp/model/common/request"
 | 
			
		||||
	"miniapp/model/system"
 | 
			
		||||
	"miniapp/utils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: Register
 | 
			
		||||
//@description: 用户注册
 | 
			
		||||
//@param: u model.SysUser
 | 
			
		||||
//@return: userInter system.SysUser, err error
 | 
			
		||||
 | 
			
		||||
type UserService struct{}
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) Register(u system.SysUser) (userInter system.SysUser, err error) {
 | 
			
		||||
	var user system.SysUser
 | 
			
		||||
	if !errors.Is(global.GVA_DB.Where("username = ?", u.Username).First(&user).Error, gorm.ErrRecordNotFound) { // 判断用户名是否注册
 | 
			
		||||
		return userInter, errors.New("用户名已注册")
 | 
			
		||||
	}
 | 
			
		||||
	// 否则 附加uuid 密码hash加密 注册
 | 
			
		||||
	u.Password = utils.BcryptHash(u.Password)
 | 
			
		||||
	u.UUID = uuid.Must(uuid.NewV4())
 | 
			
		||||
	err = global.GVA_DB.Create(&u).Error
 | 
			
		||||
	return u, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@author: [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
//@function: Login
 | 
			
		||||
//@description: 用户登录
 | 
			
		||||
//@param: u *model.SysUser
 | 
			
		||||
//@return: err error, userInter *model.SysUser
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) Login(u *system.SysUser) (userInter *system.SysUser, err error) {
 | 
			
		||||
	if nil == global.GVA_DB {
 | 
			
		||||
		return nil, fmt.Errorf("db not init")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var user system.SysUser
 | 
			
		||||
	err = global.GVA_DB.Where("username = ?", u.Username).Preload("Authorities").Preload("Authority").First(&user).Error
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		if ok := utils.BcryptCheck(u.Password, user.Password); !ok {
 | 
			
		||||
			return nil, errors.New("密码错误")
 | 
			
		||||
		}
 | 
			
		||||
		MenuServiceApp.UserAuthorityDefaultRouter(&user)
 | 
			
		||||
	}
 | 
			
		||||
	return &user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: ChangePassword
 | 
			
		||||
//@description: 修改用户密码
 | 
			
		||||
//@param: u *model.SysUser, newPassword string
 | 
			
		||||
//@return: userInter *model.SysUser,err error
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) ChangePassword(u *system.SysUser, newPassword string) (userInter *system.SysUser, err error) {
 | 
			
		||||
	var user system.SysUser
 | 
			
		||||
	if err = global.GVA_DB.Where("id = ?", u.ID).First(&user).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if ok := utils.BcryptCheck(u.Password, user.Password); !ok {
 | 
			
		||||
		return nil, errors.New("原密码错误")
 | 
			
		||||
	}
 | 
			
		||||
	user.Password = utils.BcryptHash(newPassword)
 | 
			
		||||
	err = global.GVA_DB.Save(&user).Error
 | 
			
		||||
	return &user, err
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: GetUserInfoList
 | 
			
		||||
//@description: 分页获取数据
 | 
			
		||||
//@param: info request.PageInfo
 | 
			
		||||
//@return: err error, list interface{}, total int64
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) GetUserInfoList(info request.PageInfo) (list interface{}, total int64, err error) {
 | 
			
		||||
	limit := info.PageSize
 | 
			
		||||
	offset := info.PageSize * (info.Page - 1)
 | 
			
		||||
	db := global.GVA_DB.Model(&system.SysUser{})
 | 
			
		||||
	var userList []system.SysUser
 | 
			
		||||
	err = db.Count(&total).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	err = db.Limit(limit).Offset(offset).Preload("Authorities").Preload("Authority").Find(&userList).Error
 | 
			
		||||
	return userList, total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: SetUserAuthority
 | 
			
		||||
//@description: 设置一个用户的权限
 | 
			
		||||
//@param: uuid uuid.UUID, authorityId string
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) SetUserAuthority(id uint, authorityId uint) (err error) {
 | 
			
		||||
	assignErr := global.GVA_DB.Where("sys_user_id = ? AND sys_authority_authority_id = ?", id, authorityId).First(&system.SysUserAuthority{}).Error
 | 
			
		||||
	if errors.Is(assignErr, gorm.ErrRecordNotFound) {
 | 
			
		||||
		return errors.New("该用户无此角色")
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", id).First(&system.SysUser{}).Update("authority_id", authorityId).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: SetUserAuthorities
 | 
			
		||||
//@description: 设置一个用户的权限
 | 
			
		||||
//@param: id uint, authorityIds []string
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) SetUserAuthorities(id uint, authorityIds []uint) (err error) {
 | 
			
		||||
	return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
 | 
			
		||||
		TxErr := tx.Delete(&[]system.SysUserAuthority{}, "sys_user_id = ?", id).Error
 | 
			
		||||
		if TxErr != nil {
 | 
			
		||||
			return TxErr
 | 
			
		||||
		}
 | 
			
		||||
		var useAuthority []system.SysUserAuthority
 | 
			
		||||
		for _, v := range authorityIds {
 | 
			
		||||
			useAuthority = append(useAuthority, system.SysUserAuthority{
 | 
			
		||||
				SysUserId: id, SysAuthorityAuthorityId: v,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		TxErr = tx.Create(&useAuthority).Error
 | 
			
		||||
		if TxErr != nil {
 | 
			
		||||
			return TxErr
 | 
			
		||||
		}
 | 
			
		||||
		TxErr = tx.Where("id = ?", id).First(&system.SysUser{}).Update("authority_id", authorityIds[0]).Error
 | 
			
		||||
		if TxErr != nil {
 | 
			
		||||
			return TxErr
 | 
			
		||||
		}
 | 
			
		||||
		// 返回 nil 提交事务
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: DeleteUser
 | 
			
		||||
//@description: 删除用户
 | 
			
		||||
//@param: id float64
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) DeleteUser(id int) (err error) {
 | 
			
		||||
	var user system.SysUser
 | 
			
		||||
	err = global.GVA_DB.Where("id = ?", id).Delete(&user).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = global.GVA_DB.Delete(&[]system.SysUserAuthority{}, "sys_user_id = ?", id).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: SetUserInfo
 | 
			
		||||
//@description: 设置用户信息
 | 
			
		||||
//@param: reqUser model.SysUser
 | 
			
		||||
//@return: err error, user model.SysUser
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) SetUserInfo(req system.SysUser) error {
 | 
			
		||||
	return global.GVA_DB.Model(&system.SysUser{}).
 | 
			
		||||
		Select("updated_at", "nick_name", "header_img", "phone", "email", "sideMode", "enable").
 | 
			
		||||
		Where("id=?", req.ID).
 | 
			
		||||
		Updates(map[string]interface{}{
 | 
			
		||||
			"updated_at": time.Now(),
 | 
			
		||||
			"nick_name":  req.NickName,
 | 
			
		||||
			"header_img": req.HeaderImg,
 | 
			
		||||
			"phone":      req.Phone,
 | 
			
		||||
			"email":      req.Email,
 | 
			
		||||
			"side_mode":  req.SideMode,
 | 
			
		||||
			"enable":     req.Enable,
 | 
			
		||||
		}).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: SetUserInfo
 | 
			
		||||
//@description: 设置用户信息
 | 
			
		||||
//@param: reqUser model.SysUser
 | 
			
		||||
//@return: err error, user model.SysUser
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) SetSelfInfo(req system.SysUser) error {
 | 
			
		||||
	return global.GVA_DB.Model(&system.SysUser{}).
 | 
			
		||||
		Where("id=?", req.ID).
 | 
			
		||||
		Updates(req).Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@author: [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
//@function: GetUserInfo
 | 
			
		||||
//@description: 获取用户信息
 | 
			
		||||
//@param: uuid uuid.UUID
 | 
			
		||||
//@return: err error, user system.SysUser
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) GetUserInfo(uuid uuid.UUID) (user system.SysUser, err error) {
 | 
			
		||||
	var reqUser system.SysUser
 | 
			
		||||
	err = global.GVA_DB.Preload("Authorities").Preload("Authority").First(&reqUser, "uuid = ?", uuid).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return reqUser, err
 | 
			
		||||
	}
 | 
			
		||||
	MenuServiceApp.UserAuthorityDefaultRouter(&reqUser)
 | 
			
		||||
	return reqUser, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
//@function: FindUserById
 | 
			
		||||
//@description: 通过id获取用户信息
 | 
			
		||||
//@param: id int
 | 
			
		||||
//@return: err error, user *model.SysUser
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) FindUserById(id int) (user *system.SysUser, err error) {
 | 
			
		||||
	var u system.SysUser
 | 
			
		||||
	err = global.GVA_DB.Where("`id` = ?", id).First(&u).Error
 | 
			
		||||
	return &u, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [SliverHorn](https://github.com/SliverHorn)
 | 
			
		||||
//@function: FindUserByUuid
 | 
			
		||||
//@description: 通过uuid获取用户信息
 | 
			
		||||
//@param: uuid string
 | 
			
		||||
//@return: err error, user *model.SysUser
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) FindUserByUuid(uuid string) (user *system.SysUser, err error) {
 | 
			
		||||
	var u system.SysUser
 | 
			
		||||
	if err = global.GVA_DB.Where("`uuid` = ?", uuid).First(&u).Error; err != nil {
 | 
			
		||||
		return &u, errors.New("用户不存在")
 | 
			
		||||
	}
 | 
			
		||||
	return &u, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//@author: [piexlmax](https://github.com/piexlmax)
 | 
			
		||||
//@function: resetPassword
 | 
			
		||||
//@description: 修改用户密码
 | 
			
		||||
//@param: ID uint
 | 
			
		||||
//@return: err error
 | 
			
		||||
 | 
			
		||||
func (userService *UserService) ResetPassword(ID uint) (err error) {
 | 
			
		||||
	err = global.GVA_DB.Model(&system.SysUser{}).Where("id = ?", ID).Update("password", utils.BcryptHash("123456")).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								service/system/todos.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								service/system/todos.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
package system
 | 
			
		||||
		Reference in New Issue
	
	Block a user