基础架构变更 增加模块化

This commit is contained in:
pixel
2021-07-17 14:18:52 +08:00
parent b5c1babec9
commit c7de76b849
95 changed files with 1279 additions and 710 deletions
+19
View File
@@ -0,0 +1,19 @@
package system
type ServiceGroup struct {
JwtService
ApiService
AuthorityService
AutoCodeService
AutoCodeHistoryService
BaseMenuService
CasbinService
DictionaryService
DictionaryDetailService
EmailService
InitDBService
MenuService
OperationRecordService
SystemConfigService
UserService
}
+61
View File
@@ -0,0 +1,61 @@
package system
import (
"context"
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model/system"
"time"
"gorm.io/gorm"
)
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
return
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: IsBlacklist
//@description: 判断JWT是否在黑名单内部
//@param: jwt string
//@return: bool
func (jwtService *JwtService) IsBlacklist(jwt string) bool {
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: err error, redisJWT string
func (jwtService *JwtService) GetRedisJWT(userName string) (err error, redisJWT string) {
redisJWT, err = global.GVA_REDIS.Get(context.Background(), userName).Result()
return err, redisJWT
}
//@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过期时间
timer := time.Duration(global.GVA_CONFIG.JWT.ExpiresTime) * time.Second
err = global.GVA_REDIS.Set(context.Background(), userName, jwt, timer).Err()
return err
}
+152
View File
@@ -0,0 +1,152 @@
package system
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model/common/request"
"gin-vue-admin/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) {
err = global.GVA_DB.Delete(&api).Error
CasbinServiceApp.ClearCasbin(1, api.Path, api.Method)
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetAPIInfoList
//@description: 分页获取数据,
//@param: api model.SysApi, info request.PageInfo, order string, desc bool
//@return: err error
func (apiService *ApiService) GetAPIInfoList(api system.SysApi, info request.PageInfo, order string, desc bool) (err error, list interface{}, total int64) {
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 err, apiList, total
} else {
db = db.Limit(limit).Offset(offset)
if order != "" {
var OrderStr string
if desc {
OrderStr = order + " desc"
} else {
OrderStr = order
}
err = db.Order(OrderStr).Find(&apiList).Error
} else {
err = db.Order("api_group").Find(&apiList).Error
}
}
return err, apiList, total
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetAllApis
//@description: 获取所有的api
//@return: err error, apis []model.SysApi
func (apiService *ApiService) GetAllApis() (err error, apis []system.SysApi) {
err = global.GVA_DB.Find(&apis).Error
return
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetApiById
//@description: 根据id获取api
//@param: id float64
//@return: err error, api model.SysApi
func (apiService *ApiService) GetApiById(id float64) (err error, api system.SysApi) {
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) {
err = global.GVA_DB.Delete(&[]system.SysApi{}, "id in ?", ids.Ids).Error
return err
}
func (apiService *ApiService) DeleteApiByIds(ids []string) (err error) {
return global.GVA_DB.Delete(system.SysApi{}, ids).Error
}
+170
View File
@@ -0,0 +1,170 @@
package system
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model/common/request"
"gin-vue-admin/model/system"
"gin-vue-admin/model/system/response"
"gorm.io/gorm"
"strconv"
)
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateAuthority
//@description: 创建一个角色
//@param: auth model.SysAuthority
//@return: err error, authority model.SysAuthority
type AuthorityService struct {
}
var AuthorityServiceApp = new(AuthorityService)
func (authorityService *AuthorityService) CreateAuthority(auth system.SysAuthority) (err error, authority system.SysAuthority) {
var authorityBox system.SysAuthority
if !errors.Is(global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&authorityBox).Error, gorm.ErrRecordNotFound) {
return errors.New("存在相同角色id"), auth
}
err = global.GVA_DB.Create(&auth).Error
return err, auth
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CopyAuthority
//@description: 复制一个角色
//@param: copyInfo response.SysAuthorityCopyResponse
//@return: err error, authority model.SysAuthority
func (authorityService *AuthorityService) CopyAuthority(copyInfo response.SysAuthorityCopyResponse) (err error, authority system.SysAuthority) {
var authorityBox system.SysAuthority
if !errors.Is(global.GVA_DB.Where("authority_id = ?", copyInfo.Authority.AuthorityId).First(&authorityBox).Error, gorm.ErrRecordNotFound) {
return errors.New("存在相同角色id"), authority
}
copyInfo.Authority.Children = []system.SysAuthority{}
err, menus := MenuServiceApp.GetMenuAuthority(&request.GetAuthorityId{AuthorityId: copyInfo.OldAuthorityId})
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(&copyInfo.Authority).Error
paths := CasbinServiceApp.GetPolicyPathByAuthorityId(copyInfo.OldAuthorityId)
err = CasbinServiceApp.UpdateCasbin(copyInfo.Authority.AuthorityId, paths)
if err != nil {
_ = authorityService.DeleteAuthority(&copyInfo.Authority)
}
return err, copyInfo.Authority
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: UpdateAuthority
//@description: 更改一个角色
//@param: auth model.SysAuthority
//@return: err error, authority model.SysAuthority
func (authorityService *AuthorityService) UpdateAuthority(auth system.SysAuthority) (err error, authority system.SysAuthority) {
err = global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&system.SysAuthority{}).Updates(&auth).Error
return err, auth
}
//@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.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").Where("authority_id = ?", auth.AuthorityId).First(auth)
err = db.Unscoped().Delete(auth).Error
if len(auth.SysBaseMenus) > 0 {
err = global.GVA_DB.Model(auth).Association("SysBaseMenus").Delete(auth.SysBaseMenus)
//err = db.Association("SysBaseMenus").Delete(&auth)
} else {
err = db.Error
}
CasbinServiceApp.ClearCasbin(0, auth.AuthorityId)
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetAuthorityInfoList
//@description: 分页获取数据
//@param: info request.PageInfo
//@return: err error, list interface{}, total int64
func (authorityService *AuthorityService) GetAuthorityInfoList(info request.PageInfo) (err error, list interface{}, total int64) {
limit := info.PageSize
offset := info.PageSize * (info.Page - 1)
db := global.GVA_DB
var authority []system.SysAuthority
err = db.Limit(limit).Offset(offset).Preload("DataAuthorityId").Where("parent_id = 0").Find(&authority).Error
if len(authority) > 0 {
for k := range authority {
err = authorityService.findChildrenAuthority(&authority[k])
}
}
return err, authority, total
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetAuthorityInfo
//@description: 获取所有角色信息
//@param: auth model.SysAuthority
//@return: err error, sa model.SysAuthority
func (authorityService *AuthorityService) GetAuthorityInfo(auth system.SysAuthority) (err error, sa system.SysAuthority) {
err = global.GVA_DB.Preload("DataAuthorityId").Where("authority_id = ?", auth.AuthorityId).First(&sa).Error
return err, sa
}
//@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
}
+449
View File
@@ -0,0 +1,449 @@
package system
import (
"encoding/json"
"errors"
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model/system"
"gin-vue-admin/model/system/request"
"gin-vue-admin/utils"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"text/template"
"gorm.io/gorm"
)
const (
autoPath = "autoCode/"
basePath = "resource/template"
)
type tplData struct {
template *template.Template
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) {
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, 0755)
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, 0755)
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 := ioutil.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
}
//@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) {
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, 0755)
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 { // 判断是否需要自动转移
for index := range dataList {
autoCodeService.addAutoMoveFile(&dataList[index])
}
for _, value := range dataList { // 移动文件
if err := utils.FileMove(value.autoCodePath, value.autoMoveFilePath); err != nil {
return err
}
}
initializeGormFilePath := filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "gorm.go")
initializeRouterFilePath := filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "router.go")
err = utils.AutoInjectionCode(initializeGormFilePath, "MysqlTables", "model."+autoCode.StructName+"{},")
if err != nil {
return err
}
err = utils.AutoInjectionCode(initializeRouterFilePath, "Routers", "router.Init"+autoCode.StructName+"Router(PrivateGroup)")
if err != nil {
return err
}
injectionCodeMeta.WriteString(fmt.Sprintf("%s@%s@%s", initializeGormFilePath, "MysqlTables", "model."+autoCode.StructName+"{},"))
injectionCodeMeta.WriteString(";")
injectionCodeMeta.WriteString(fmt.Sprintf("%s@%s@%s", initializeRouterFilePath, "Routers", "router.Init"+autoCode.StructName+"Router(PrivateGroup)"))
// 保存生成信息
for _, data := range dataList {
if len(data.autoMoveFilePath) != 0 {
bf.WriteString(data.autoMoveFilePath)
bf.WriteString(";")
}
}
if global.GVA_CONFIG.AutoCode.TransferRestart {
go func() {
_ = utils.Reload()
}()
}
//return errors.New("创建代码成功并移动文件成功")
} 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(),
)
} else {
err = AutoCodeHistoryServiceApp.CreateAutoCodeHistory(
string(meta),
autoCode.StructName,
autoCode.Description,
bf.String(),
injectionCodeMeta.String(),
autoCode.StructName,
idBf.String(),
)
}
}
if err != nil {
return err
}
if autoCode.AutoMoveFile {
return errors.New("创建代码成功并移动文件成功")
}
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 := ioutil.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: GetTables
//@description: 获取数据库的所有表名
//@param: dbName string
//@return: err error, TableNames []request.TableReq
func (autoCodeService *AutoCodeService) GetTables(dbName string) (err error, TableNames []request.TableReq) {
err = global.GVA_DB.Raw("select table_name as table_name from information_schema.tables where table_schema = ?", dbName).Scan(&TableNames).Error
return err, TableNames
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetDB
//@description: 获取数据库的所有数据库名
//@return: err error, DBNames []request.DBReq
func (autoCodeService *AutoCodeService) GetDB() (err error, DBNames []request.DBReq) {
err = global.GVA_DB.Raw("SELECT SCHEMA_NAME AS `database` FROM INFORMATION_SCHEMA.SCHEMATA;").Scan(&DBNames).Error
return err, DBNames
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetDB
//@description: 获取指定数据库和指定数据表的所有字段名,类型值等
//@param: tableName string, dbName string
//@return: err error, Columns []request.ColumnReq
func (autoCodeService *AutoCodeService) GetColumn(tableName string, dbName string) (err error, Columns []request.ColumnReq) {
err = global.GVA_DB.Raw("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 = ?", tableName, dbName).Scan(&Columns).Error
return err, Columns
}
func (autoCodeService *AutoCodeService) DropTable(tableName string) error {
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") {
if strings.Contains(fileSlice[n-2], "router") {
data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server,
global.GVA_CONFIG.AutoCode.SRouter, base)
} else if strings.Contains(fileSlice[n-2], "api") {
data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SApi, base)
} else if strings.Contains(fileSlice[n-2], "service") {
data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SService, base)
} else if strings.Contains(fileSlice[n-2], "model") {
data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SModel, base)
} else if strings.Contains(fileSlice[n-2], "request") {
data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SRequest, 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) {
var apiList = []system.SysApi{
{
Path: "/" + a.Abbreviation + "/" + "create" + a.StructName,
Description: "新增" + a.Description,
ApiGroup: a.Abbreviation,
Method: "POST",
},
{
Path: "/" + a.Abbreviation + "/" + "delete" + a.StructName,
Description: "删除" + a.Description,
ApiGroup: a.Abbreviation,
Method: "DELETE",
},
{
Path: "/" + a.Abbreviation + "/" + "delete" + a.StructName + "ByIds",
Description: "批量删除" + a.Description,
ApiGroup: a.Abbreviation,
Method: "DELETE",
},
{
Path: "/" + a.Abbreviation + "/" + "update" + a.StructName,
Description: "更新" + a.Description,
ApiGroup: a.Abbreviation,
Method: "PUT",
},
{
Path: "/" + a.Abbreviation + "/" + "find" + a.StructName,
Description: "根据ID获取" + a.Description,
ApiGroup: a.Abbreviation,
Method: "GET",
},
{
Path: "/" + a.Abbreviation + "/" + "get" + a.StructName + "List",
Description: "获取" + a.Description + "列表",
ApiGroup: a.Abbreviation,
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(basePath, 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})
}
// 生成 *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
autoPath := "autoCode/"
for index, value := range dataList {
trimBase := strings.TrimPrefix(value.locationPath, basePath+"/")
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
}
@@ -0,0 +1,92 @@
package system
import (
"gin-vue-admin/global"
"gin-vue-admin/model/common/request"
"gin-vue-admin/model/system"
"gin-vue-admin/utils"
"strings"
"go.uber.org/zap"
)
type AutoCodeHistoryService struct {
}
var AutoCodeHistoryServiceApp = new(AutoCodeHistoryService)
// CreateAutoCodeHistory RouterPath : RouterPath@RouterString;RouterPath2@RouterString2
func (autoCodeHistoryService *AutoCodeHistoryService) CreateAutoCodeHistory(meta, structName, structCNName, autoCodePath string, injectionMeta string, tableName string, apiIds string) error {
return global.GVA_DB.Create(&system.SysAutoCodeHistory{
RequestMeta: meta,
AutoCodePath: autoCodePath,
InjectionMeta: injectionMeta,
StructName: structName,
StructCNName: structCNName,
TableName: tableName,
ApiIDs: apiIds,
}).Error
}
// RollBack 回滚
func (autoCodeHistoryService *AutoCodeHistoryService) RollBack(id uint) error {
md := system.SysAutoCodeHistory{}
if err := global.GVA_DB.First(&md, id).Error; err != nil {
return err
}
// 清除API表
err := ApiServiceApp.DeleteApiByIds(strings.Split(md.ApiIDs, ";"))
if err != nil {
global.GVA_LOG.Error("ClearTag DeleteApiByIds:", zap.Error(err))
}
// 获取全部表名
err, dbNames := AutoCodeServiceApp.GetTables(global.GVA_CONFIG.Mysql.Dbname)
if err != nil {
global.GVA_LOG.Error("ClearTag GetTables:", zap.Error(err))
}
// 删除表
for _, name := range dbNames {
if strings.Contains(strings.ToUpper(strings.Replace(name.TableName, "_", "", -1)), strings.ToUpper(md.TableName)) {
// 删除表
if err = AutoCodeServiceApp.DropTable(name.TableName); err != nil {
global.GVA_LOG.Error("ClearTag DropTable:", zap.Error(err))
}
}
}
// 删除文件
for _, path := range strings.Split(md.AutoCodePath, ";") {
_ = 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])
}
}
md.Flag = 1
return global.GVA_DB.Save(&md).Error
}
func (autoCodeHistoryService *AutoCodeHistoryService) GetMeta(id uint) (string, error) {
var meta string
return meta, global.GVA_DB.Model(system.SysAutoCodeHistory{}).Select("request_meta").First(&meta, id).Error
}
// GetSysHistoryPage 获取系统历史数据
func (autoCodeHistoryService *AutoCodeHistoryService) GetSysHistoryPage(info request.PageInfo) (err error, list interface{}, total int64) {
limit := info.PageSize
offset := info.PageSize * (info.Page - 1)
db := global.GVA_DB
var fileLists []system.SysAutoCodeHistory
err = db.Find(&fileLists).Count(&total).Error
err = db.Limit(limit).Offset(offset).Order("updated_at desc").Select("id,created_at,updated_at,struct_name,struct_cn_name,flag,table_name").Find(&fileLists).Error
return err, fileLists, total
}
// DeletePage 删除历史数据
func (autoCodeHistoryService *AutoCodeHistoryService) DeletePage(id uint) error {
return global.GVA_DB.Delete(system.SysAutoCodeHistory{}, id).Error
}
+100
View File
@@ -0,0 +1,100 @@
package system
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model/system"
"gorm.io/gorm"
)
type BaseMenuService struct {
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: DeleteBaseMenu
//@description: 删除基础路由
//@param: id float64
//@return: err error
func (baseMenuService *BaseMenuService) DeleteBaseMenu(id float64) (err error) {
err = global.GVA_DB.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
if len(menu.SysAuthoritys) > 0 {
err = global.GVA_DB.Model(&menu).Association("SysAuthoritys").Delete(&menu.SysAuthoritys)
} else {
err = db.Error
}
} 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["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
}
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
}
}
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: err error, menu model.SysBaseMenu
func (baseMenuService *BaseMenuService) GetBaseMenuById(id float64) (err error, menu system.SysBaseMenu) {
err = global.GVA_DB.Preload("Parameters").Where("id = ?", id).First(&menu).Error
return
}
+135
View File
@@ -0,0 +1,135 @@
package system
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model/system"
"gin-vue-admin/model/system/request"
"github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/util"
gormadapter "github.com/casbin/gorm-adapter/v3"
_ "github.com/go-sql-driver/mysql"
"strings"
"sync"
)
//@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 string, casbinInfos []request.CasbinInfo) error {
casbinService.ClearCasbin(0, authorityId)
rules := [][]string{}
for _, v := range casbinInfos {
cm := system.CasbinModel{
Ptype: "p",
AuthorityId: authorityId,
Path: v.Path,
Method: v.Method,
}
rules = append(rules, []string{cm.AuthorityId, cm.Path, cm.Method})
}
e := casbinService.Casbin()
success, _ := e.AddPolicies(rules)
if success == false {
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.Table("casbin_rule").Model(&system.CasbinModel{}).Where("v1 = ? AND v2 = ?", oldPath, oldMethod).Updates(map[string]interface{}{
"v1": newPath,
"v2": newMethod,
}).Error
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetPolicyPathByAuthorityId
//@description: 获取权限列表
//@param: authorityId string
//@return: pathMaps []request.CasbinInfo
func (casbinService *CasbinService) GetPolicyPathByAuthorityId(authorityId string) (pathMaps []request.CasbinInfo) {
e := casbinService.Casbin()
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 (
syncedEnforcer *casbin.SyncedEnforcer
once sync.Once
)
func (casbinService *CasbinService) Casbin() *casbin.SyncedEnforcer {
once.Do(func() {
a, _ := gormadapter.NewAdapterByDB(global.GVA_DB)
syncedEnforcer, _ = casbin.NewSyncedEnforcer(global.GVA_CONFIG.Casbin.ModelPath, a)
syncedEnforcer.AddFunction("ParamsMatch", casbinService.ParamsMatchFunc)
})
_ = syncedEnforcer.LoadPolicy()
return syncedEnforcer
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: ParamsMatch
//@description: 自定义规则函数
//@param: fullNameKey1 string, key2 string
//@return: bool
func (casbinService *CasbinService) ParamsMatch(fullNameKey1 string, key2 string) bool {
key1 := strings.Split(fullNameKey1, "?")[0]
// 剥离路径后再使用casbin的keyMatch2
return util.KeyMatch2(key1, key2)
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: ParamsMatchFunc
//@description: 自定义规则函数
//@param: args ...interface{}
//@return: interface{}, error
func (casbinService *CasbinService) ParamsMatchFunc(args ...interface{}) (interface{}, error) {
name1 := args[0].(string)
name2 := args[1].(string)
return casbinService.ParamsMatch(name1, name2), nil
}
+106
View File
@@ -0,0 +1,106 @@
package system
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model/system"
"gin-vue-admin/model/system/request"
"gorm.io/gorm"
)
//@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.Delete(&sysDictionary).Delete(&sysDictionary.SysDictionaryDetails).Error
return err
}
//@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 {
err = db.Updates(sysDictionaryMap).Error
} else {
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) (err error, sysDictionary system.SysDictionary) {
err = global.GVA_DB.Where("type = ? OR id = ?", Type, Id).Preload("SysDictionaryDetails").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) (err error, list interface{}, total int64) {
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
err = db.Limit(limit).Offset(offset).Find(&sysDictionarys).Error
return err, sysDictionarys, total
}
@@ -0,0 +1,84 @@
package system
import (
"gin-vue-admin/global"
"gin-vue-admin/model/system"
"gin-vue-admin/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: err error, sysDictionaryDetail model.SysDictionaryDetail
func (dictionaryDetailService *DictionaryDetailService) GetSysDictionaryDetail(id uint) (err error, sysDictionaryDetail system.SysDictionaryDetail) {
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: err error, list interface{}, total int64
func (dictionaryDetailService *DictionaryDetailService) GetSysDictionaryDetailInfoList(info request.SysDictionaryDetailSearch) (err error, list interface{}, total int64) {
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
err = db.Limit(limit).Offset(offset).Find(&sysDictionaryDetails).Error
return err, sysDictionaryDetails, total
}
+20
View File
@@ -0,0 +1,20 @@
package system
import (
"gin-vue-admin/utils"
)
type EmailService struct {
}
//@author: [maplepie](https://github.com/maplepie)
//@function: EmailTest
//@description: 发送邮件测试
//@return: err error
func (e *EmailService) EmailTest() (err error) {
subject := "test"
body := "test"
err = utils.EmailTest(subject, body)
return err
}
+165
View File
@@ -0,0 +1,165 @@
package system
import (
"database/sql"
"fmt"
"gin-vue-admin/config"
"gin-vue-admin/global"
"gin-vue-admin/model/example"
"gin-vue-admin/model/system"
"gin-vue-admin/model/system/request"
"gin-vue-admin/source"
"gin-vue-admin/utils"
"path/filepath"
"github.com/spf13/viper"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: writeConfig
//@description: 回写配置
//@param: viper *viper.Viper, mysql config.Mysql
//@return: error
type InitDBService struct {
}
func (initDBService *InitDBService) writeConfig(viper *viper.Viper, mysql config.Mysql) error {
global.GVA_CONFIG.Mysql = mysql
cs := utils.StructToMap(global.GVA_CONFIG)
for k, v := range cs {
viper.Set(k, v)
}
return viper.WriteConfig()
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: createTable
//@description: 创建数据库(mysql)
//@param: dsn string, driver string, createSql
//@return: error
func (initDBService *InitDBService) createTable(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 {
}
}(db)
if err = db.Ping(); err != nil {
return err
}
_, err = db.Exec(createSql)
return err
}
func (initDBService *InitDBService) initDB(InitDBFunctions ...system.InitDBFunc) (err error) {
for _, v := range InitDBFunctions {
err = v.Init()
if err != nil {
return err
}
}
return nil
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: InitDB
//@description: 创建数据库并初始化
//@param: conf request.InitDB
//@return: error
func (initDBService *InitDBService) InitDB(conf request.InitDB) error {
if conf.Host == "" {
conf.Host = "127.0.0.1"
}
if conf.Port == "" {
conf.Port = "3306"
}
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/", conf.UserName, conf.Password, conf.Host, conf.Port)
createSql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;", conf.DBName)
if err := initDBService.createTable(dsn, "mysql", createSql); err != nil {
return err
}
MysqlConfig := config.Mysql{
Path: fmt.Sprintf("%s:%s", conf.Host, conf.Port),
Dbname: conf.DBName,
Username: conf.UserName,
Password: conf.Password,
Config: "charset=utf8mb4&parseTime=True&loc=Local",
}
if MysqlConfig.Dbname == "" {
return nil
}
linkDns := MysqlConfig.Username + ":" + MysqlConfig.Password + "@tcp(" + MysqlConfig.Path + ")/" + MysqlConfig.Dbname + "?" + MysqlConfig.Config
mysqlConfig := mysql.Config{
DSN: linkDns, // DSN data source name
DefaultStringSize: 191, // string 类型字段的默认长度
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
SkipInitializeWithVersion: false, // 根据版本自动配置
}
if db, err := gorm.Open(mysql.New(mysqlConfig), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}); err != nil {
return nil
} else {
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(MysqlConfig.MaxIdleConns)
sqlDB.SetMaxOpenConns(MysqlConfig.MaxOpenConns)
global.GVA_DB = db
}
err := global.GVA_DB.AutoMigrate(
system.SysUser{},
system.SysAuthority{},
system.SysApi{},
system.SysBaseMenu{},
system.SysBaseMenuParameter{},
system.JwtBlacklist{},
system.SysDictionary{},
system.SysDictionaryDetail{},
example.ExaFileUploadAndDownload{},
example.ExaFile{},
example.ExaFileChunk{},
example.ExaSimpleUploader{},
example.ExaCustomer{},
system.SysOperationRecord{},
system.SysAutoCodeHistory{},
)
if err != nil {
global.GVA_DB = nil
return err
}
err = initDBService.initDB(
source.Admin,
source.Api,
source.AuthorityMenu,
source.Authority,
source.AuthoritiesMenus,
source.Casbin,
source.DataAuthorities,
source.Dictionary,
source.DictionaryDetail,
source.File,
source.BaseMenu)
if err != nil {
global.GVA_DB = nil
return err
}
if err = initDBService.writeConfig(global.GVA_VP, MysqlConfig); err != nil {
return err
}
global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..")
return nil
}
+158
View File
@@ -0,0 +1,158 @@
package system
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model/common/request"
"gin-vue-admin/model/system"
"gorm.io/gorm"
"strconv"
)
//@author: [piexlmax](https://github.com/piexlmax)
//@function: getMenuTreeMap
//@description: 获取路由总树map
//@param: authorityId string
//@return: err error, treeMap map[string][]model.SysMenu
type MenuService struct {
}
var MenuServiceApp = new(MenuService)
func (menuService *MenuService) getMenuTreeMap(authorityId string) (err error, treeMap map[string][]system.SysMenu) {
var allMenus []system.SysMenu
treeMap = make(map[string][]system.SysMenu)
err = global.GVA_DB.Where("authority_id = ?", authorityId).Order("sort").Preload("Parameters").Find(&allMenus).Error
for _, v := range allMenus {
treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
}
return err, treeMap
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetMenuTree
//@description: 获取动态菜单树
//@param: authorityId string
//@return: err error, menus []model.SysMenu
func (menuService *MenuService) GetMenuTree(authorityId string) (err error, menus []system.SysMenu) {
err, menuTree := menuService.getMenuTreeMap(authorityId)
menus = menuTree["0"]
for i := 0; i < len(menus); i++ {
err = menuService.getChildrenList(&menus[i], menuTree)
}
return err, menus
}
//@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: err error, list interface{}, total int64
func (menuService *MenuService) GetInfoList() (err error, list interface{}, total int64) {
var menuList []system.SysBaseMenu
err, treeMap := menuService.getBaseMenuTreeMap()
menuList = treeMap["0"]
for i := 0; i < len(menuList); i++ {
err = menuService.getBaseChildrenList(&menuList[i], treeMap)
}
return err, menuList, total
}
//@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: err error, treeMap map[string][]model.SysBaseMenu
func (menuService *MenuService) getBaseMenuTreeMap() (err error, treeMap map[string][]system.SysBaseMenu) {
var allMenus []system.SysBaseMenu
treeMap = make(map[string][]system.SysBaseMenu)
err = global.GVA_DB.Order("sort").Preload("Parameters").Find(&allMenus).Error
for _, v := range allMenus {
treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
}
return err, treeMap
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetBaseMenuTree
//@description: 获取基础路由树
//@return: err error, menus []model.SysBaseMenu
func (menuService *MenuService) GetBaseMenuTree() (err error, menus []system.SysBaseMenu) {
err, treeMap := menuService.getBaseMenuTreeMap()
menus = treeMap["0"]
for i := 0; i < len(menus); i++ {
err = menuService.getBaseChildrenList(&menus[i], treeMap)
}
return err, menus
}
//@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 string) (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: err error, menus []model.SysMenu
func (menuService *MenuService) GetMenuAuthority(info *request.GetAuthorityId) (err error, menus []system.SysMenu) {
err = global.GVA_DB.Where("authority_id = ? ", info.AuthorityId).Order("sort").Find(&menus).Error
//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 err, menus
}
@@ -0,0 +1,84 @@
package system
import (
"gin-vue-admin/global"
"gin-vue-admin/model/common/request"
"gin-vue-admin/model/system"
systemReq "gin-vue-admin/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: err error, sysOperationRecord model.SysOperationRecord
func (operationRecordService *OperationRecordService) GetSysOperationRecord(id uint) (err error, sysOperationRecord system.SysOperationRecord) {
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: err error, list interface{}, total int64
func (operationRecordService *OperationRecordService) GetSysOperationRecordInfoList(info systemReq.SysOperationRecordSearch) (err error, list interface{}, total int64) {
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
err = db.Order("id desc").Limit(limit).Offset(offset).Preload("User").Find(&sysOperationRecords).Error
return err, sysOperationRecords, total
}
+61
View File
@@ -0,0 +1,61 @@
package system
import (
"gin-vue-admin/config"
"gin-vue-admin/global"
"gin-vue-admin/model/system"
"gin-vue-admin/utils"
"go.uber.org/zap"
)
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetSystemConfig
//@description: 读取配置文件
//@return: err error, conf config.Server
type SystemConfigService struct {
}
func (systemConfigService *SystemConfigService) GetSystemConfig() (err error, conf config.Server) {
return nil, global.GVA_CONFIG
}
// @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 *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.Rrm, 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
}
+134
View File
@@ -0,0 +1,134 @@
package system
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model/common/request"
"gin-vue-admin/model/system"
"gin-vue-admin/utils"
uuid "github.com/satori/go.uuid"
"gorm.io/gorm"
)
//@author: [piexlmax](https://github.com/piexlmax)
//@function: Register
//@description: 用户注册
//@param: u model.SysUser
//@return: err error, userInter model.SysUser
type UserService struct {
}
func (userService *UserService) Register(u system.SysUser) (err error, userInter system.SysUser) {
var user system.SysUser
if !errors.Is(global.GVA_DB.Where("username = ?", u.Username).First(&user).Error, gorm.ErrRecordNotFound) { // 判断用户名是否注册
return errors.New("用户名已注册"), userInter
}
// 否则 附加uuid 密码md5简单加密 注册
u.Password = utils.MD5V([]byte(u.Password))
u.UUID = uuid.NewV4()
err = global.GVA_DB.Create(&u).Error
return err, u
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: Login
//@description: 用户登录
//@param: u *model.SysUser
//@return: err error, userInter *model.SysUser
func (userService *UserService) Login(u *system.SysUser) (err error, userInter *system.SysUser) {
var user system.SysUser
u.Password = utils.MD5V([]byte(u.Password))
err = global.GVA_DB.Where("username = ? AND password = ?", u.Username, u.Password).Preload("Authority").First(&user).Error
return err, &user
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: ChangePassword
//@description: 修改用户密码
//@param: u *model.SysUser, newPassword string
//@return: err error, userInter *model.SysUser
func (userService *UserService) ChangePassword(u *system.SysUser, newPassword string) (err error, userInter *system.SysUser) {
var user system.SysUser
u.Password = utils.MD5V([]byte(u.Password))
err = global.GVA_DB.Where("username = ? AND password = ?", u.Username, u.Password).First(&user).Update("password", utils.MD5V([]byte(newPassword))).Error
return err, u
}
//@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) (err error, list interface{}, total int64) {
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
err = db.Limit(limit).Offset(offset).Preload("Authority").Find(&userList).Error
return err, userList, total
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: SetUserAuthority
//@description: 设置一个用户的权限
//@param: uuid uuid.UUID, authorityId string
//@return: err error
func (userService *UserService) SetUserAuthority(uuid uuid.UUID, authorityId string) (err error) {
err = global.GVA_DB.Where("uuid = ?", uuid).First(&system.SysUser{}).Update("authority_id", authorityId).Error
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: DeleteUser
//@description: 删除用户
//@param: id float64
//@return: err error
func (userService *UserService) DeleteUser(id float64) (err error) {
var user system.SysUser
err = global.GVA_DB.Where("id = ?", id).Delete(&user).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(reqUser system.SysUser) (err error, user system.SysUser) {
err = global.GVA_DB.Updates(&reqUser).Error
return err, reqUser
}
//@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) (err error, user *system.SysUser) {
var u system.SysUser
err = global.GVA_DB.Where("`id` = ?", id).First(&u).Error
return err, &u
}
//@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) (err error, user *system.SysUser) {
var u system.SysUser
if err = global.GVA_DB.Where("`uuid` = ?", uuid).First(&u).Error; err != nil {
return errors.New("用户不存在"), &u
}
return nil, &u
}