This commit is contained in:
❀ » Cato Sweeney. ❀ » Console@the.bb
2025-12-03 12:53:19 +08:00
commit e9e409d958
370 changed files with 104606 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
# Binaries for programs and plugins
main
*.exe
*.exe~
*.dll
*.so
*.dylib
*.idea
# Test binary, built with `go test -c`
*.test
__debug*
*.git
/fatal
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

18
Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
FROM alpine:latest
LABEL MAINTAINER="PandaX"
WORKDIR /go/src/panda
COPY ./pandax ./
COPY ./config.yml ./
COPY ./resource ./resource
COPY ./uploads ./uploads
RUN chmod 755 ./pandax
EXPOSE 7788
EXPOSE 9001
EXPOSE 9002
EXPOSE 9003
EXPOSE 9003/udp
ENTRYPOINT ./pandax

12
api/function.js Normal file
View File

@@ -0,0 +1,12 @@
function add(a, b) {
return a+b
}
function main() {
let ip = payload.get().headers['Remote-Host']
ip = ip.toString()
return JSON.stringify({
status: add(199,1),
addr: ip,
})
}

30
apps/develop/api/gen.go Normal file
View File

@@ -0,0 +1,30 @@
package api
import (
"pandax/apps/develop/gen"
"pandax/apps/develop/services"
"pandax/kit/restfulx"
)
type GenApi struct {
GenTableApp services.SysGenTableModel
}
// Preview 代码视图
func (e *GenApi) Preview(rc *restfulx.ReqCtx) {
tableId := restfulx.PathParamInt(rc, "tableId")
rc.ResData = gen.Preview(int64(tableId))
}
// GenCode 代码生成
func (e *GenApi) GenCode(rc *restfulx.ReqCtx) {
tableId := restfulx.PathParamInt(rc, "tableId")
gen.GenCode(int64(tableId))
}
// GenConfigure 配置生成
func (e *GenApi) GenConfigure(rc *restfulx.ReqCtx) {
tableId := restfulx.PathParamInt(rc, "tableId")
menuId := restfulx.QueryInt(rc, "menuId", 0)
gen.GenConfigure(tableId, menuId)
}

131
apps/develop/api/table.go Normal file
View File

@@ -0,0 +1,131 @@
package api
import (
"pandax/apps/develop/api/vo"
"pandax/apps/develop/entity"
"pandax/apps/develop/gen"
"pandax/apps/develop/services"
"pandax/kit/biz"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
"strings"
"sync"
)
type GenTableApi struct {
GenTableApp services.SysGenTableModel
}
// GetDBTableList 获取数据库表列表
func (g *GenTableApi) GetDBTableList(rc *restfulx.ReqCtx) {
dbTables := entity.DBTables{}
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
dbTables.TableName = restfulx.QueryParam(rc, "tableName")
list, total, err := g.GenTableApp.FindDbTablesListPage(pageNum, pageSize, dbTables)
biz.ErrIsNil(err, "查询配置分页列表信息失败")
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
// GetTablePage 获取表页列表数据
func (g *GenTableApi) GetTablePage(rc *restfulx.ReqCtx) {
devGenTable := entity.DevGenTable{}
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
devGenTable.TableName = restfulx.QueryParam(rc, "tableName")
devGenTable.TableComment = restfulx.QueryParam(rc, "tableComment")
devGenTable.RoleId = rc.LoginAccount.RoleId
devGenTable.Owner = rc.LoginAccount.UserName
list, total, err := g.GenTableApp.FindListPage(pageNum, pageSize, devGenTable)
biz.ErrIsNil(err, "分页获取表失败")
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
// GetTableInfo 获取表信息
func (g *GenTableApi) GetTableInfo(rc *restfulx.ReqCtx) {
devGenTable := entity.DevGenTable{}
devGenTable.TableId = int64(restfulx.PathParamInt(rc, "tableId"))
devGenTable.RoleId = rc.LoginAccount.RoleId
result, err := g.GenTableApp.FindOne(devGenTable, true)
biz.ErrIsNil(err, "分页获取表信息失败")
rc.ResData = vo.TableInfoVo{
List: result.Columns,
Info: *result,
}
}
// GetTableInfoByName 获取表信息
func (g *GenTableApi) GetTableInfoByName(rc *restfulx.ReqCtx) {
devGenTable := entity.DevGenTable{}
devGenTable.TableName = restfulx.QueryParam(rc, "tableName")
devGenTable.RoleId = rc.LoginAccount.RoleId
result, err := g.GenTableApp.FindOne(devGenTable, true)
biz.ErrIsNil(err, "分页获取表信息失败")
rc.ResData = vo.TableInfoVo{
List: result.Columns,
Info: *result,
}
}
// GetTableTree 获取树表信息
func (g *GenTableApi) GetTableTree(rc *restfulx.ReqCtx) {
devGenTable := entity.DevGenTable{}
devGenTable.RoleId = rc.LoginAccount.RoleId
devGenTable.Owner = rc.LoginAccount.UserName
tree, err := g.GenTableApp.FindTree(devGenTable)
biz.ErrIsNil(err, "获取树表信息失败")
rc.ResData = tree
}
// Insert 添加表结构
func (g *GenTableApi) Insert(rc *restfulx.ReqCtx) {
tables := strings.Split(restfulx.QueryParam(rc, "tables"), ",")
var wg sync.WaitGroup
for _, table := range tables {
wg.Add(1)
go func(table string) {
defer wg.Done()
var tg = gen.Generator{
TableName: table,
}
genTable, err := tg.Generate()
if err != nil {
biz.ErrIsNil(err, "创建表结构")
}
genTable.OrgId = rc.LoginAccount.OrganizationId
genTable.Owner = rc.LoginAccount.UserName
g.GenTableApp.Insert(genTable)
}(table)
}
wg.Wait()
}
// Update 修改表结构
func (g *GenTableApi) Update(rc *restfulx.ReqCtx) {
var data entity.DevGenTable
restfulx.BindJsonAndValid(rc, &data)
_, err := g.GenTableApp.Update(data)
biz.ErrIsNil(err, "修改表结构")
}
// Delete 删除表结构
func (g *GenTableApi) Delete(rc *restfulx.ReqCtx) {
tableIds := restfulx.PathParam(rc, "tableId")
group := utils.IdsStrToIdsIntGroup(tableIds)
err := g.GenTableApp.Delete(group)
biz.ErrIsNil(err, "删除表结构")
}

View File

@@ -0,0 +1,14 @@
package vo
import "pandax/apps/develop/entity"
/**
* @Description
* @Author 熊猫
* @Date 2022/8/4 15:52
**/
type TableInfoVo struct {
List []entity.DevGenTableColumn `json:"list"`
Info entity.DevGenTable `json:"info"`
}

View File

@@ -0,0 +1,36 @@
package entity
import "pandax/kit/model"
type DevGenTable struct {
TableId int64 `gorm:"primaryKey;autoIncrement" json:"tableId"` // 编号
OrgId int64 `json:"orgId" gorm:"type:int;comment:机构ID"`
Owner string `json:"owner" gorm:"type:varchar(64);comment:创建者,所有者"`
TableName string `gorm:"table_name" json:"tableName"` // 表名称
TableComment string `gorm:"table_comment" json:"tableComment"` // 表描述
ClassName string `gorm:"class_name" json:"className"` // 实体类名称
TplCategory string `gorm:"tpl_category" json:"tplCategory"` // 使用的模板crud单表操作 tree树表操作
PackageName string `gorm:"package_name" json:"packageName"` // 生成包路径
ModuleName string `gorm:"module_name" json:"moduleName"` // 生成模块名
BusinessName string `gorm:"business_name" json:"businessName"` // 生成业务名
FunctionName string `gorm:"function_name" json:"functionName"` // 生成功能名
FunctionAuthor string `gorm:"function_author" json:"functionAuthor"` // 生成功能作者
Options string `gorm:"options" json:"options"` // 其它生成选项
Remark string `gorm:"remark" json:"remark"` // 备注
PkColumn string `gorm:"pk_column;" json:"pkColumn"`
PkJsonField string `gorm:"pk_json_field" json:"pkJsonField"`
Columns []DevGenTableColumn `gorm:"-" json:"columns"` // 字段信息
model.BaseModel
RoleId int64 `gorm:"-"` // 角色数据权限
}
type DBTables struct {
TableName string `gorm:"column:TABLE_NAME" json:"tableName"`
Engine string `gorm:"column:ENGINE" json:"engine"`
TableRows string `gorm:"column:TABLE_ROWS" json:"tableRows"`
TableCollation string `gorm:"column:TABLE_COLLATION" json:"tableCollation"`
CreateTime string `gorm:"column:CREATE_TIME" json:"createTime"`
UpdateTime string `gorm:"column:UPDATE_TIME" json:"updateTime"`
TableComment string `gorm:"column:TABLE_COMMENT" json:"tableComment"`
}

View File

@@ -0,0 +1,64 @@
package entity
type DevGenTableColumn struct {
ColumnId int64 `gorm:"primaryKey;autoIncrement" json:"columnId"` // 编号
OrgId int64 `json:"orgId" gorm:"type:int;comment:机构ID"`
Owner string `json:"owner" gorm:"type:varchar(64);comment:创建者,所有者"`
TableId int64 `gorm:"table_id" json:"tableId"` // 归属表编号
TableName string `gorm:"table_name" json:"tableName"` // 归属表名字
ColumnName string `gorm:"column_name" json:"columnName"` // 列名称
ColumnComment string `gorm:"column_comment" json:"columnComment"` // 列描述
ColumnType string `gorm:"column_type" json:"columnType"` // 列类型
ColumnKey string `gorm:"column_key" json:"columnKey"`
JsonField string `gorm:"json_field;" json:"jsonField"`
HtmlField string `gorm:"html_field" json:"htmlField"` // html字段名
IsPk string `gorm:"is_pk" json:"isPk"` // 是否主键1是
IsIncrement string `gorm:"is_increment" json:"isIncrement"` // 是否自增1是
IsRequired string `gorm:"is_required" json:"isRequired"` // 是否必填1是
IsInsert string `gorm:"is_insert" json:"isInsert"` // 是否为插入字段1是
IsEdit string `gorm:"is_edit" json:"isEdit"` // 是否编辑字段1是
IsList string `gorm:"is_list" json:"isList"` // 是否列表字段1是
IsQuery string `gorm:"is_query" json:"isQuery"` // 是否查询字段1是
QueryType string `gorm:"query_type" json:"queryType"` // 查询方式(等于、不等于、大于、小于、范围)
HtmlType string `gorm:"html_type" json:"htmlType"` // 显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)
DictType string `gorm:"dict_type" json:"dictType"` // 字典类型
Sort int `gorm:"sort" json:"sort"` // 排序
LinkTableId int64 `gorm:"link_table_id" json:"linkTableId"` // 关联编号
LinkTableName string `gorm:"link_table_name" json:"linkTableName"` // 关联表名
LinkTableClass string `gorm:"link_table_class" json:"linkTableClass"` // 关联表类名
LinkTablePackage string `gorm:"link_table_package" json:"linkTablePackage"` // 关联表包名
LinkLabelId string `gorm:"link_label_id" json:"linkLabelId"` // 关联表键名
LinkLabelName string `gorm:"link_label_name" json:"linkLabelName"` // 关联表字段值
RoleId int64 `gorm:"-"` // 角色数据权限
}
type DBColumns struct {
TableSchema string `gorm:"column:TABLE_SCHEMA" json:"tableSchema"`
TableName string `gorm:"column:TABLE_NAME" json:"tableName"`
ColumnName string `gorm:"column:COLUMN_NAME" json:"columnName"`
ColumnDefault string `gorm:"column:COLUMN_DEFAULT" json:"columnDefault"`
IsNullable string `gorm:"column:IS_NULLABLE" json:"isNullable"`
DataType string `gorm:"column:DATA_TYPE" json:"dataType"`
CharacterMaximumLength string `gorm:"column:CHARACTER_MAXIMUM_LENGTH" json:"characterMaximumLength"`
CharacterSetName string `gorm:"column:CHARACTER_SET_NAME" json:"characterSetName"`
ColumnType string `gorm:"column:COLUMN_TYPE" json:"columnType"`
ColumnKey string `gorm:"column:COLUMN_KEY" json:"columnKey"`
Extra string `gorm:"column:EXTRA" json:"extra"`
ColumnComment string `gorm:"column:COLUMN_COMMENT" json:"columnComment"`
}
type DBColumnsP struct {
TableSchema string `gorm:"column:table_schema" json:"tableSchema"`
TableName string `gorm:"column:table_name" json:"tableName"`
ColumnName string `gorm:"column:column_name" json:"columnName"`
ColumnDefault string `gorm:"column:column_default" json:"columnDefault"`
IsNullable string `gorm:"column:is_nullable" json:"isNullable"`
DataType string `gorm:"column:data_type" json:"dataType"`
CharacterMaximumLength string `gorm:"column:character_maximum_length" json:"characterMaximumLength"`
CharacterSetName string `gorm:"column:character_set_name" json:"characterSetName"`
ColumnType string `gorm:"column:udt_name" json:"columnType"`
ColumnKey string ` json:"columnKey"` // 判断自增比较困难
Extra string ` json:"extra"`
ColumnComment string ` json:"columnComment"`
}

445
apps/develop/gen/gen.go Normal file
View File

@@ -0,0 +1,445 @@
package gen
import (
"bytes"
"fmt"
"os"
"strconv"
"strings"
"sync"
"text/template"
"pandax/apps/develop/entity"
"pandax/apps/develop/services"
sysEntity "pandax/apps/system/entity"
sysServices "pandax/apps/system/services"
"pandax/kit/biz"
"pandax/pkg/global"
"github.com/kakuilan/kgo"
)
var ToolsGenTableColumn = toolsGenTableColumn{}
type toolsGenTableColumn struct{}
var (
ColumnTypeStr = []string{"char", "varchar", "narchar", "varchar2", "tinytext", "text", "mediumtext", "longtext"}
ColumnTypeTime = []string{"datetime", "time", "date", "timestamp", "timestamptz"}
ColumnTypeNumber = []string{"tinyint", "smallint", "mediumint", "int", "int2", "int4", "int8", "number", "integer", "numeric", "bigint", "float", "float4", "float8", "double", "decimal"}
ColumnNameNotEdit = []string{"create_by", "update_by", "create_time", "update_time", "delete_time"}
ColumnNameNotList = []string{"create_by", "update_by", "update_time", "delete_time"}
ColumnNameNotQuery = []string{"create_by", "update_by", "create_time", "update_time", "delete_time", "remark"}
)
func (s *toolsGenTableColumn) GetDbType(columnType string) string {
if strings.Index(columnType, "(") > 0 {
return columnType[0:strings.Index(columnType, "(")]
} else {
return columnType
}
}
func (s *toolsGenTableColumn) IsExistInArray(value string, array []string) bool {
for _, v := range array {
if strings.Contains(value, v) {
return true
}
}
return false
}
func (s *toolsGenTableColumn) GetColumnLength(columnType string) int {
start := strings.LastIndex(columnType, "(")
end := strings.LastIndex(columnType, ")")
if start >= 0 && end >= 0 {
result := columnType[start+1 : end]
i, _ := strconv.Atoi(result)
return i
}
return 0
}
func (s *toolsGenTableColumn) IsStringObject(dataType string) bool {
return s.IsExistInArray(dataType, ColumnTypeStr)
}
func (s *toolsGenTableColumn) IsTimeObject(dataType string) bool {
return s.IsExistInArray(dataType, ColumnTypeTime)
}
func (s *toolsGenTableColumn) IsNumberObject(dataType string) bool {
return s.IsExistInArray(dataType, ColumnTypeNumber)
}
func (s *toolsGenTableColumn) IsNotEdit(name string) bool {
if strings.Contains(name, "id") {
return true
}
return s.IsExistInArray(name, ColumnNameNotEdit)
}
func (s *toolsGenTableColumn) IsNotList(name string) bool {
return s.IsExistInArray(name, ColumnNameNotList)
}
func (s *toolsGenTableColumn) IsNotQuery(name string) bool {
return s.IsExistInArray(name, ColumnNameNotQuery)
}
func (s *toolsGenTableColumn) CheckNameColumn(columnName string) bool {
if len(columnName) >= 4 {
tmp := columnName[len(columnName)-4:]
return tmp == "name"
}
return false
}
func (s *toolsGenTableColumn) CheckStatusColumn(columnName string) bool {
if len(columnName) >= 6 {
tmp := columnName[len(columnName)-6:]
return tmp == "status"
}
return false
}
func (s *toolsGenTableColumn) CheckTypeColumn(columnName string) bool {
if len(columnName) >= 4 {
tmp := columnName[len(columnName)-4:]
return tmp == "type"
}
return false
}
func (s *toolsGenTableColumn) CheckSexColumn(columnName string) bool {
if len(columnName) >= 3 {
tmp := columnName[len(columnName)-4:]
return tmp == "sex"
}
return false
}
type Generator struct {
TableName string
}
func (g *Generator) Generate() (entity.DevGenTable, error) {
var data entity.DevGenTable
data.TableName = g.TableName
tableNameList := strings.Split(g.TableName, "_")
for i := 0; i < len(tableNameList); i++ {
strStart := string([]byte(tableNameList[i])[:1])
strEnd := string([]byte(tableNameList[i])[1:])
data.ClassName += strings.ToUpper(strStart) + strEnd
if i >= 1 {
data.BusinessName += strings.ToLower(strStart) + strEnd
data.FunctionName = strings.ToUpper(strStart) + strEnd
}
}
data.PackageName = "system"
data.TplCategory = "crud"
data.ModuleName = strings.Replace(g.TableName, "_", "-", -1)
dbColumn, err := services.DevTableColumnModelDao.FindDbTableColumnList(g.TableName)
if err != nil {
return data, err
}
data.TableComment = data.ClassName
data.FunctionAuthor = "xScript_Engine"
var wg sync.WaitGroup
columnChan := make(chan entity.DevGenTableColumn, len(dbColumn)) // 创建带缓冲的通道
for x := 0; x < len(dbColumn); x++ {
index := x
wg.Add(1)
go func(wg *sync.WaitGroup, y int) {
defer wg.Done()
var column entity.DevGenTableColumn
column.ColumnComment = dbColumn[y].ColumnComment
column.ColumnName = dbColumn[y].ColumnName
column.ColumnType = dbColumn[y].ColumnType
column.Sort = y + 1
column.IsPk = "0"
nameList := strings.Split(dbColumn[y].ColumnName, "_")
for i := 0; i < len(nameList); i++ {
strStart := string([]byte(nameList[i])[:1])
strend := string([]byte(nameList[i])[1:])
if i == 0 {
column.JsonField = strings.ToLower(strStart) + strend
} else {
column.JsonField += strings.ToUpper(strStart) + strend
}
}
if column.ColumnComment == "" {
column.ColumnComment = column.JsonField
}
dataType := strings.ToLower(column.ColumnType)
if ToolsGenTableColumn.IsStringObject(dataType) {
columnLength := ToolsGenTableColumn.GetColumnLength(column.ColumnType)
if columnLength >= 500 {
column.HtmlType = "textarea"
} else {
column.HtmlType = "input"
}
} else if ToolsGenTableColumn.IsTimeObject(dataType) {
column.HtmlType = "datetime"
} else if ToolsGenTableColumn.IsNumberObject(dataType) {
column.HtmlType = "input"
} else {
switch dataType {
case "bool":
column.HtmlType = "switch"
}
}
if strings.Contains(dbColumn[y].ColumnKey, "PR") {
column.IsPk = "1"
data.PkColumn = dbColumn[y].ColumnName
data.PkJsonField = column.JsonField
if dbColumn[y].Extra == "auto_increment" {
column.IsIncrement = "1"
}
}
if ToolsGenTableColumn.IsNotEdit(column.ColumnName) {
column.IsRequired = "0"
column.IsInsert = "0"
} else {
column.IsRequired = "0"
column.IsInsert = "1"
if strings.Contains(column.ColumnName, "name") || strings.Contains(column.ColumnName, "status") {
column.IsRequired = "1"
}
}
if ToolsGenTableColumn.IsNotEdit(column.ColumnName) {
column.IsEdit = "0"
} else {
if column.IsPk == "1" {
column.IsEdit = "0"
} else {
column.IsEdit = "1"
}
}
if ToolsGenTableColumn.IsNotList(column.ColumnName) {
column.IsList = "0"
} else {
column.IsList = "1"
}
if ToolsGenTableColumn.IsNotQuery(column.ColumnName) {
column.IsQuery = "0"
} else {
column.IsQuery = "1"
}
if ToolsGenTableColumn.CheckNameColumn(column.ColumnName) {
column.QueryType = "LIKE"
} else {
column.QueryType = "EQ"
}
if ToolsGenTableColumn.CheckStatusColumn(column.ColumnName) {
column.HtmlType = "radio"
} else if ToolsGenTableColumn.CheckTypeColumn(column.ColumnName) || ToolsGenTableColumn.CheckSexColumn(column.ColumnName) {
column.HtmlType = "select"
}
columnChan <- column // 将处理结果放入通道
}(&wg, index)
}
wg.Wait()
close(columnChan) // 关闭通道
for column := range columnChan {
data.Columns = append(data.Columns, column) // 将通道中的结果放入data.Columns
}
return data, nil
}
func Preview(tableId int64) map[string]interface{} {
defer func() {
if err := recover(); err != nil {
global.Log.Error(err)
}
}()
t1, err := template.ParseFiles("resource/template/js/function.template")
biz.ErrIsNil(err, "function模版读取失败")
t5, err := template.ParseFiles("resource/template/js/api.template")
biz.ErrIsNil(err, "api模版读取失败")
t6, err := template.ParseFiles("resource/template/vue/list-vue.template")
biz.ErrIsNil(err, "vue列表模版读取失败")
t7, err := template.ParseFiles("resource/template/vue/edit-vue.template")
biz.ErrIsNil(err, "vue编辑模版读取失败")
tab, _ := services.DevGenTableModelDao.FindOne(entity.DevGenTable{TableId: tableId}, false)
var b1 bytes.Buffer
t1.Execute(&b1, tab)
var b5 bytes.Buffer
t5.Execute(&b5, tab)
var b6 bytes.Buffer
t6.Execute(&b6, tab)
var b7 bytes.Buffer
t7.Execute(&b7, tab)
mp := make(map[string]interface{})
mp["template/function.template"] = b1.String()
mp["template/jsApi.template"] = b5.String()
mp["template/listVue.template"] = b6.String()
mp["template/editVue.template"] = b7.String()
return mp
}
func GenCode(tableId int64) {
defer func() {
if err := recover(); err != nil {
global.Log.Error(err)
}
}()
tab, err := services.DevGenTableModelDao.FindOne(entity.DevGenTable{TableId: tableId}, false)
biz.ErrIsNil(err, "读取表信息失败!")
tab.ModuleName = strings.Replace(tab.TableName, "_", "-", -1)
t1, err := template.ParseFiles("resource/template/js/function.template")
biz.ErrIsNil(err, "function模版读取失败")
t5, err := template.ParseFiles("resource/template/js/api.template")
biz.ErrIsNil(err, "js模版读取失败")
t6, err := template.ParseFiles("resource/template/vue/list-vue.template")
biz.ErrIsNil(err, "vue列表模版读取失败")
t7, err := template.ParseFiles("resource/template/vue/edit-vue.template")
biz.ErrIsNil(err, "vue编辑模版读取失败")
kgo.KFile.Mkdir("./"+tab.PackageName+"/"+tab.BusinessName+"/", os.ModePerm)
kgo.KFile.Mkdir(global.Conf.Gen.Frontpath+"/views/"+tab.PackageName+"/"+tab.BusinessName+"/", os.ModePerm)
kgo.KFile.Mkdir(global.Conf.Gen.Frontpath+"/views/"+tab.PackageName+"/"+tab.BusinessName+"/"+"component"+"/", os.ModePerm)
var b1 bytes.Buffer
t1.Execute(&b1, tab)
var b5 bytes.Buffer
t5.Execute(&b5, tab)
var b6 bytes.Buffer
t6.Execute(&b6, tab)
var b7 bytes.Buffer
t7.Execute(&b7, tab)
kgo.KFile.WriteFile("./"+tab.PackageName+"/"+tab.BusinessName+"/"+tab.ModuleName+"/function.js", b1.Bytes())
kgo.KFile.WriteFile(global.Conf.Gen.Frontpath+"/api/"+tab.PackageName+"/"+tab.BusinessName+".ts", b5.Bytes())
kgo.KFile.WriteFile(global.Conf.Gen.Frontpath+"/views/"+tab.PackageName+"/"+tab.BusinessName+"/index.vue", b6.Bytes())
kgo.KFile.WriteFile(global.Conf.Gen.Frontpath+"/views/"+tab.PackageName+"/"+tab.BusinessName+"/"+"component"+"/editModule.vue", b7.Bytes())
}
func GenConfigure(tableId, parentId int) {
tab, err := services.DevGenTableModelDao.FindOne(entity.DevGenTable{TableId: int64(tableId)}, false)
if err != nil {
return
}
component := "Layout"
if parentId != 0 {
component = fmt.Sprintf("/%s/%s/%s/index", tab.PackageName, tab.BusinessName, tab.ModuleName)
}
menu := sysEntity.SysMenu{
ParentId: int64(parentId),
MenuName: tab.TableComment,
MenuType: "C",
Sort: 1,
Icon: "elementSetting",
Path: fmt.Sprintf("/%s/%s/%s", tab.PackageName, tab.BusinessName, tab.ModuleName),
Component: component,
IsIframe: "1",
IsHide: "0",
IsKeepAlive: "1",
IsAffix: "1",
Permission: fmt.Sprintf("%s:%s:%s:list", tab.PackageName, tab.BusinessName, tab.ModuleName),
Status: "0",
CreateBy: "admin",
}
insert := sysServices.SysMenuModelDao.Insert(menu)
menuA := sysEntity.SysMenu{
ParentId: insert.MenuId,
MenuName: "新增" + tab.TableComment,
MenuType: "F",
Sort: 1,
Permission: fmt.Sprintf("%s:%s:%s:add", tab.PackageName, tab.BusinessName, tab.ModuleName),
Status: "0",
CreateBy: "gen",
}
go sysServices.SysMenuModelDao.Insert(menuA)
menuE := sysEntity.SysMenu{
ParentId: insert.MenuId,
MenuName: "修改" + tab.TableComment,
MenuType: "F",
Sort: 2,
Permission: fmt.Sprintf("%s:%s:%s:edit", tab.PackageName, tab.BusinessName, tab.ModuleName),
Status: "0",
CreateBy: "gen",
}
go sysServices.SysMenuModelDao.Insert(menuE)
menuD := sysEntity.SysMenu{
ParentId: insert.MenuId,
MenuName: "删除" + tab.TableComment,
MenuType: "F",
Sort: 3,
Permission: fmt.Sprintf("%s:%s:%s:delete", tab.PackageName, tab.BusinessName, tab.ModuleName),
Status: "0",
CreateBy: "gen",
}
go sysServices.SysMenuModelDao.Insert(menuD)
apiG := sysEntity.SysApi{
Path: fmt.Sprintf("/%s/%s/%s", tab.PackageName, tab.BusinessName, tab.ModuleName),
Description: fmt.Sprintf("获取%s信息(列表)", tab.TableComment),
ApiGroup: tab.BusinessName,
Method: "GET",
}
go sysServices.SysApiModelDao.Insert(apiG)
apiB := sysEntity.SysApi{
Path: fmt.Sprintf("/%s/%s/%s/:filter", tab.PackageName, tab.BusinessName, tab.ModuleName),
Description: fmt.Sprintf("获取%s信息", tab.TableComment),
ApiGroup: tab.BusinessName,
Method: "GET",
}
go sysServices.SysApiModelDao.Insert(apiB)
apiA := sysEntity.SysApi{
Path: fmt.Sprintf("/%s/%s/%s", tab.PackageName, tab.BusinessName, tab.ModuleName),
Description: fmt.Sprintf("添加%s信息", tab.TableComment),
ApiGroup: tab.BusinessName,
Method: "POST",
}
go sysServices.SysApiModelDao.Insert(apiA)
apiE := sysEntity.SysApi{
Path: fmt.Sprintf("/%s/%s/%s", tab.PackageName, tab.BusinessName, tab.ModuleName),
Description: fmt.Sprintf("修改%s信息", tab.TableComment),
ApiGroup: tab.BusinessName,
Method: "PUT",
}
go sysServices.SysApiModelDao.Insert(apiE)
apiD := sysEntity.SysApi{
Path: fmt.Sprintf("/%s/%s/%s/:filter", tab.PackageName, tab.BusinessName, tab.ModuleName),
Description: fmt.Sprintf("修改%s信息", tab.TableComment),
ApiGroup: tab.BusinessName,
Method: "PUT",
}
go sysServices.SysApiModelDao.Insert(apiD)
apiF := sysEntity.SysApi{
Path: fmt.Sprintf("/%s/%s/%s", tab.PackageName, tab.BusinessName, tab.ModuleName),
Description: fmt.Sprintf("删除%s信息", tab.TableComment),
ApiGroup: tab.BusinessName,
Method: "DELETE",
}
go sysServices.SysApiModelDao.Insert(apiF)
}

View File

@@ -0,0 +1,51 @@
package router
import (
"pandax/apps/develop/api"
"pandax/apps/develop/services"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitGenRouter(container *restful.Container) {
// 登录日志
s := &api.GenApi{
GenTableApp: services.DevGenTableModelDao,
}
ws := new(restful.WebService)
ws.Path("/develop/code/gen").Produces(restful.MIME_JSON)
tags := []string{"代码生成"}
ws.Route(ws.GET("/preview/{tableId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取生成代码视图").Handle(s.Preview)
}).
Doc("获取生成代码视图").
Param(ws.PathParameter("tableId", "Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", map[string]any{}).
Returns(404, "Not Found", nil))
ws.Route(ws.GET("/code/{tableId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("生成代码").Handle(s.GenCode)
}).
Doc("生成代码").
Param(ws.PathParameter("tableId", "Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", map[string]any{}).
Returns(404, "Not Found", nil))
ws.Route(ws.GET("/configure/{tableId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("生成配置").Handle(s.GenConfigure)
}).
Doc("生成配置").
Param(ws.PathParameter("tableId", "Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", map[string]any{}).
Returns(404, "Not Found", nil))
container.Add(ws)
}

View File

@@ -0,0 +1,82 @@
package router
import (
"pandax/apps/develop/api"
"pandax/apps/develop/api/vo"
"pandax/apps/develop/entity"
"pandax/apps/develop/services"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitGenTableRouter(container *restful.Container) {
// 登录日志
s := &api.GenTableApi{
GenTableApp: services.DevGenTableModelDao,
}
ws := new(restful.WebService)
ws.Path("/develop/code/table").Produces(restful.MIME_JSON)
tags := []string{"codetable"}
ws.Route(ws.GET("/db/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取数据库列表").Handle(s.GetDBTableList)
}).
Doc("获取数据库列表").
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取表列表").Handle(s.GetTablePage)
}).
Doc("获取表列表").
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/info/tableName").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取表信息By tableName").Handle(s.GetTableInfoByName)
}).
Doc("获取表信息By tableName").
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", vo.TableInfoVo{}))
ws.Route(ws.GET("/info/{tableId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取表信息").Handle(s.GetTableInfo)
}).
Doc("获取表信息").
Param(ws.PathParameter("tenantId", "租户Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", vo.TableInfoVo{}).
Returns(404, "Not Found", nil))
ws.Route(ws.GET("/tableTree").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取表树").Handle(s.GetTableTree)
}).
Doc("获取表树").
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", []entity.DevGenTable{}))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("新增表").Handle(s.Insert)
}).
Doc("新增表").
Metadata(restfulspec.KeyOpenAPITags, tags)) // from the request
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改表").Handle(s.Update)
}).
Doc("修改表").
Metadata(restfulspec.KeyOpenAPITags, tags)) // from the request
ws.Route(ws.DELETE("/{tableId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除表").Handle(s.Delete)
}).
Doc("删除表").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("tableId", "多id 1,2,3").DataType("string")))
container.Add(ws)
}

View File

@@ -0,0 +1,257 @@
package services
import (
"errors"
"pandax/apps/develop/entity"
"pandax/kit/biz"
"pandax/kit/utils"
"pandax/pkg/global"
"pandax/pkg/global/model"
)
/**
* @Description
* @Author Panda
* @Date 2021/12/31 8:58
**/
type (
SysGenTableModel interface {
FindDbTablesListPage(page, pageSize int, data entity.DBTables) (*[]entity.DBTables, int64, error)
FindDbTableOne(tableName string) (*entity.DBTables, error)
// 导入表数据
Insert(data entity.DevGenTable) error
FindOne(data entity.DevGenTable, exclude bool) (*entity.DevGenTable, error)
FindTree(data entity.DevGenTable) (*[]entity.DevGenTable, error)
FindListPage(page, pageSize int, data entity.DevGenTable) (*[]entity.DevGenTable, int64, error)
Update(data entity.DevGenTable) (*entity.DevGenTable, error)
Delete(tableIds []int64) error
}
devGenTableModelImpl struct {
table string
}
)
var DevGenTableModelDao SysGenTableModel = &devGenTableModelImpl{
table: "dev_gen_tables",
}
func (m *devGenTableModelImpl) FindDbTablesListPage(page, pageSize int, data entity.DBTables) (*[]entity.DBTables, int64, error) {
list := make([]entity.DBTables, 0)
pgdata := make([]map[string]any, 0)
var total int64 = 0
offset := pageSize * (page - 1)
if global.Conf.Server.DbType != "mysql" && global.Conf.Server.DbType != "postgresql" {
biz.ErrIsNil(errors.New("只支持mysql和postgresql数据库"), "只支持mysql和postgresql数据库")
}
db := global.Db.Table("information_schema.tables")
if global.Conf.Server.DbType == "mysql" {
db = db.Where("table_schema= ? ", global.Conf.Gen.Dbname)
}
if global.Conf.Server.DbType == "postgresql" {
db = db.Where("table_schema = ? ", "public")
}
//db = db.Where("table_name NOT LIKE 'dev_%'")
if data.TableName != "" {
db = db.Where("table_name like ?", "%"+data.TableName+"%")
}
if global.Conf.Server.DbType == "mysql" {
err := db.Limit(pageSize).Offset(offset).Find(&list).Count(&total).Error
return &list, total, err
} else {
err := db.Limit(pageSize).Offset(offset).Find(&pgdata).Count(&total).Error
for _, pd := range pgdata {
list = append(list, entity.DBTables{TableName: utils.B2S(pd["table_name"].([]uint8))})
}
return &list, total, err
}
}
func (m *devGenTableModelImpl) FindDbTableOne(tableName string) (*entity.DBTables, error) {
resData := new(entity.DBTables)
if global.Conf.Server.DbType != "mysql" && global.Conf.Server.DbType != "postgresql" {
return nil, errors.New("只支持mysql和postgresql数据库")
}
db := global.Db.Table("information_schema.tables")
if global.Conf.Server.DbType == "mysql" {
db = db.Where("table_schema= ? ", global.Conf.Gen.Dbname)
}
if global.Conf.Server.DbType == "postgresql" {
db = db.Where("table_schema= ? ", "public")
}
db = db.Where("table_name = ?", tableName)
err := db.First(&resData).Error
return resData, err
}
func (m *devGenTableModelImpl) Insert(dgt entity.DevGenTable) error {
err := global.Db.Table(m.table).Create(&dgt).Error
if err != nil {
return err
}
var columnsToInsert []entity.DevGenTableColumn
for i := 0; i < len(dgt.Columns); i++ {
dgt.Columns[i].TableId = dgt.TableId
columns := dgt.Columns[i]
columns.OrgId = dgt.OrgId
columns.Owner = dgt.Owner
columnsToInsert = append(columnsToInsert, columns)
}
DevTableColumnModelDao.InsertBatch(columnsToInsert)
return nil
}
func (m *devGenTableModelImpl) FindOne(data entity.DevGenTable, exclude bool) (*entity.DevGenTable, error) {
resData := new(entity.DevGenTable)
db := global.Db.Table(m.table)
if data.TableName != "" {
db = db.Where("table_name = ?", data.TableName)
}
if data.TableId != 0 {
db = db.Where("table_id = ?", data.TableId)
}
if data.TableComment != "" {
db = db.Where("table_comment = ?", data.TableComment)
}
err := db.First(resData).Error
if err != nil {
return resData, err
}
list, err := DevTableColumnModelDao.FindList(entity.DevGenTableColumn{TableId: resData.TableId}, exclude)
resData.Columns = *list
return resData, err
}
func (m *devGenTableModelImpl) FindTree(data entity.DevGenTable) (*[]entity.DevGenTable, error) {
resData := make([]entity.DevGenTable, 0)
db := global.Db.Table(m.table)
if data.TableName != "" {
db = db.Where("table_name = ?", data.TableName)
}
if data.TableId != 0 {
db = db.Where("table_id = ?", data.TableId)
}
if data.TableComment != "" {
db = db.Where("table_comment = ?", data.TableComment)
}
// 组织数据访问权限
if err := model.OrgAuthSet(db, data.RoleId, data.Owner); err != nil {
return nil, err
}
if err := db.Find(&resData).Error; err != nil {
return nil, err
}
for i := 0; i < len(resData); i++ {
var col entity.DevGenTableColumn
col.TableId = resData[i].TableId
col.RoleId = data.RoleId
columns, _ := DevTableColumnModelDao.FindList(col, false)
resData[i].Columns = *columns
}
return &resData, nil
}
func (m *devGenTableModelImpl) FindListPage(page, pageSize int, data entity.DevGenTable) (*[]entity.DevGenTable, int64, error) {
list := make([]entity.DevGenTable, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.TableName != "" {
db = db.Where("table_name = ?", data.TableName)
}
if data.TableComment != "" {
db = db.Where("table_comment = ?", data.TableComment)
}
// 组织数据访问权限
if err := model.OrgAuthSet(db, data.RoleId, data.Owner); err != nil {
return &list, total, err
}
db.Where("delete_time IS NULL")
if err := db.Count(&total).Error; err != nil {
return &list, total, err
}
if err := db.Limit(pageSize).Offset(offset).Find(&list).Error; err != nil {
return &list, total, err
}
return &list, total, nil
}
func (m *devGenTableModelImpl) Update(data entity.DevGenTable) (*entity.DevGenTable, error) {
err := global.Db.Table(m.table).Model(&data).Updates(&data).Error
if err != nil {
return nil, err
}
tableNames := make([]string, 0)
for i := range data.Columns {
if data.Columns[i].LinkTableName != "" {
tableNames = append(tableNames, data.Columns[i].LinkTableName)
}
}
tables := make([]entity.DevGenTable, 0)
tableMap := make(map[string]*entity.DevGenTable)
if len(tableNames) > 0 {
err = global.Db.Table(m.table).Where("table_name in (?)", tableNames).Find(&tables).Error
if err != nil {
return nil, err
}
for i := range tables {
tableMap[tables[i].TableName] = &tables[i]
}
}
for i := 0; i < len(data.Columns); i++ {
if data.Columns[i].LinkTableName != "" {
t, ok := tableMap[data.Columns[i].LinkTableName]
if ok {
data.Columns[i].LinkTableId = t.TableId
data.Columns[i].LinkTableClass = t.ClassName
data.Columns[i].LinkTablePackage = t.BusinessName
data.Columns[i].LinkLabelId = t.PkColumn
data.Columns[i].LinkLabelName = t.PkJsonField
}
}
DevTableColumnModelDao.Update(data.Columns[i])
}
return &data, nil
}
func (e *devGenTableModelImpl) DeleteTables(tableId int64) (bool, error) {
var err error
success := false
tx := global.Db.Begin()
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
if err = tx.Table("sys_tables").Delete(entity.DevGenTable{}, "table_id = ?", tableId).Error; err != nil {
return success, err
}
if err = tx.Table("sys_columns").Delete(entity.DevGenTableColumn{}, "table_id = ?", tableId).Error; err != nil {
return success, err
}
success = true
return success, nil
}
func (m *devGenTableModelImpl) Delete(configIds []int64) error {
err := global.Db.Table(m.table).Delete(&entity.DevGenTable{}, "table_id in (?)", configIds).Error
if err != nil {
return errors.New("删除生成代码信息失败")
}
DevTableColumnModelDao.Delete(configIds)
return nil
}

View File

@@ -0,0 +1,185 @@
package services
import (
"errors"
"pandax/apps/develop/entity"
"pandax/pkg/global"
)
/**
* @Description
* @Author Panda
* @Date 2021/12/31 14:44
**/
type (
SysGenTableColumnModel interface {
FindDbTablesColumnListPage(page, pageSize int, data entity.DBColumns) (*[]entity.DBColumns, int64, error)
FindDbTableColumnList(tableName string) ([]entity.DBColumns, error)
Insert(data entity.DevGenTableColumn) (*entity.DevGenTableColumn, error)
InsertBatch(data []entity.DevGenTableColumn) error
FindList(data entity.DevGenTableColumn, exclude bool) (*[]entity.DevGenTableColumn, error)
Update(data entity.DevGenTableColumn) (*entity.DevGenTableColumn, error)
Delete(tableId []int64) error
}
devTableColumnModelImpl struct {
table string
}
)
var DevTableColumnModelDao SysGenTableColumnModel = &devTableColumnModelImpl{
table: "dev_gen_table_columns",
}
func (m *devTableColumnModelImpl) FindDbTablesColumnListPage(page, pageSize int, data entity.DBColumns) (*[]entity.DBColumns, int64, error) {
list := make([]entity.DBColumns, 0)
var total int64 = 0
offset := pageSize * (page - 1)
if global.Conf.Server.DbType != "mysql" && global.Conf.Server.DbType != "postgresql" {
return nil, 0, errors.New("只支持mysql和postgresql数据库")
}
db := global.Db.Table("information_schema.COLUMNS")
if global.Conf.Server.DbType == "mysql" {
db = db.Where("table_schema= ? ", global.Conf.Gen.Dbname)
}
if global.Conf.Server.DbType == "postgresql" {
db = db.Where("table_schema = ? ", "public")
}
if data.TableName != "" {
db = db.Where("table_name = ?", data.TableName)
}
err := db.Count(&total).Error
err = db.Limit(pageSize).Offset(offset).Find(&list).Error
return &list, total, err
}
func (m *devTableColumnModelImpl) FindDbTableColumnList(tableName string) ([]entity.DBColumns, error) {
if global.Conf.Server.DbType != "mysql" && global.Conf.Server.DbType != "postgresql" {
return nil, errors.New("只支持mysql和postgresql数据库")
}
db := global.Db.Table("information_schema.columns")
if global.Conf.Server.DbType == "mysql" {
db = db.Where("table_schema= ? ", global.Conf.Gen.Dbname)
}
if global.Conf.Server.DbType == "postgresql" {
db = db.Where("table_schema = ? ", "public")
}
if tableName == "" {
return nil, errors.New("table name cannot be empty")
}
db = db.Where("table_name = ?", tableName)
resData := make([]entity.DBColumns, 0)
if global.Conf.Server.DbType == "mysql" {
err := db.Find(&resData).Error
return resData, err
}
if global.Conf.Server.DbType == "postgresql" {
pr, err := getPgPR(tableName)
if err != nil {
return resData, errors.New("查询PG表主键字段失败")
}
resDataP := make([]entity.DBColumnsP, 0)
err = db.Find(&resDataP).Error
if err != nil {
return resData, errors.New("查询表字段失败")
}
for _, data := range resDataP {
dbc := entity.DBColumns{
TableSchema: data.TableSchema,
TableName: data.TableName,
ColumnName: data.ColumnName,
ColumnDefault: data.ColumnDefault,
IsNullable: data.IsNullable,
DataType: data.DataType,
CharacterMaximumLength: data.CharacterMaximumLength,
CharacterSetName: data.CharacterSetName,
ColumnType: data.ColumnType,
ColumnKey: data.ColumnKey,
Extra: data.Extra,
ColumnComment: data.ColumnComment,
}
// 设置为主键
if pr == data.ColumnName {
dbc.ColumnKey = "PRIMARY KEY"
}
resData = append(resData, dbc)
}
return resData, nil
}
return resData, nil
}
func getPgPR(tableName string) (string, error) {
sql := `SELECT
kcu.column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name
WHERE
tc.constraint_type = 'PRIMARY KEY'
AND tc.table_schema = 'public'
AND tc.table_name = ?;`
var pkname string
err := global.Db.Raw(sql, tableName).Scan(&pkname).Error
return pkname, err
}
func (m *devTableColumnModelImpl) Insert(dgt entity.DevGenTableColumn) (*entity.DevGenTableColumn, error) {
err := global.Db.Table(m.table).Create(&dgt).Error
if err != nil {
global.Log.Error(err)
}
return &dgt, err
}
func (m *devTableColumnModelImpl) InsertBatch(columns []entity.DevGenTableColumn) error {
tx := global.Db.Begin()
for _, column := range columns {
err := tx.Table(m.table).Create(&column).Error
if err != nil {
tx.Rollback()
global.Log.Error(err)
return err
}
}
err := tx.Commit().Error
if err != nil {
global.Log.Error(err)
return err
}
return nil
}
func (m *devTableColumnModelImpl) FindList(data entity.DevGenTableColumn, exclude bool) (*[]entity.DevGenTableColumn, error) {
list := make([]entity.DevGenTableColumn, 0)
db := global.Db.Table(m.table).Where("table_id = ?", data.TableId)
if exclude {
notIn := make([]string, 6)
notIn = append(notIn, "id")
notIn = append(notIn, "create_by")
notIn = append(notIn, "update_by")
notIn = append(notIn, "create_time")
notIn = append(notIn, "update_time")
notIn = append(notIn, "delete_time")
db = db.Where("column_name not in(?)", notIn)
}
err := db.Find(&list).Error
return &list, err
}
func (m *devTableColumnModelImpl) Update(data entity.DevGenTableColumn) (*entity.DevGenTableColumn, error) {
err := global.Db.Table(m.table).Model(&data).Updates(&data).Error
return &data, err
}
func (m *devTableColumnModelImpl) Delete(tableId []int64) error {
err := global.Db.Table(m.table).Delete(&entity.DevGenTableColumn{}, "table_id in (?)", tableId).Error
return err
}

48
apps/log/api/log_login.go Normal file
View File

@@ -0,0 +1,48 @@
package api
import (
"pandax/apps/log/entity"
"pandax/apps/log/services"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
)
type LogLoginApi struct {
LogLoginApp services.LogLoginModel
}
func (l *LogLoginApi) GetLoginLogList(rc *restfulx.ReqCtx) {
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
loginLocation := restfulx.QueryParam(rc, "loginLocation")
username := restfulx.QueryParam(rc, "username")
list, total := l.LogLoginApp.FindListPage(pageNum, pageSize, entity.LogLogin{LoginLocation: loginLocation, Username: username})
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
func (l *LogLoginApi) GetLoginLog(rc *restfulx.ReqCtx) {
infoId := restfulx.PathParamInt(rc, "infoId")
rc.ResData = l.LogLoginApp.FindOne(int64(infoId))
}
func (l *LogLoginApi) UpdateLoginLog(rc *restfulx.ReqCtx) {
var log entity.LogLogin
restfulx.BindQuery(rc, &log)
l.LogLoginApp.Update(log)
}
func (l *LogLoginApi) DeleteLoginLog(rc *restfulx.ReqCtx) {
infoIds := restfulx.PathParam(rc, "infoId")
group := utils.IdsStrToIdsIntGroup(infoIds)
l.LogLoginApp.Delete(group)
}
func (l *LogLoginApi) DeleteAll(rc *restfulx.ReqCtx) {
l.LogLoginApp.DeleteAll()
}

43
apps/log/api/log_oper.go Normal file
View File

@@ -0,0 +1,43 @@
package api
import (
"pandax/apps/log/entity"
"pandax/apps/log/services"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
)
type LogOperApi struct {
LogOperApp services.LogOperModel
}
func (l *LogOperApi) GetOperLogList(rc *restfulx.ReqCtx) {
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
businessType := restfulx.QueryParam(rc, "businessType")
operName := restfulx.QueryParam(rc, "operName")
title := restfulx.QueryParam(rc, "title")
list, total := l.LogOperApp.FindListPage(pageNum, pageSize, entity.LogOper{BusinessType: businessType, OperName: operName, Title: title})
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
func (l *LogOperApi) GetOperLog(rc *restfulx.ReqCtx) {
operId := restfulx.PathParamInt(rc, "operId")
rc.ResData = l.LogOperApp.FindOne(int64(operId))
}
func (l *LogOperApi) DeleteOperLog(rc *restfulx.ReqCtx) {
operIds := restfulx.PathParam(rc, "operId")
group := utils.IdsStrToIdsIntGroup(operIds)
l.LogOperApp.Delete(group)
}
func (l *LogOperApi) DeleteAll(rc *restfulx.ReqCtx) {
l.LogOperApp.DeleteAll()
}

View File

@@ -0,0 +1,24 @@
package entity
import (
"pandax/kit/model"
"time"
)
type LogLogin struct {
InfoId int64 `json:"infoId" gorm:"primary_key;AUTO_INCREMENT"` //主键
Username string `json:"username" gorm:"type:varchar(128);comment:用户名"`
Status string `json:"status" gorm:"type:varchar(1);comment:状态"`
Ipaddr string `json:"ipaddr" gorm:"type:varchar(255);comment:ip地址"`
LoginLocation string `json:"loginLocation" gorm:"type:varchar(255);comment:归属地"`
Browser string `json:"browser" gorm:"type:varchar(255);comment:浏览器"`
Os string `json:"os" gorm:"type:varchar(255);comment:系统"`
Platform string `json:"platform" gorm:"type:varchar(255);comment:固件"`
LoginTime time.Time `json:"loginTime" gorm:"type:timestamp;comment:登录时间"`
CreateBy string `json:"createBy" gorm:"type:varchar(128);comment:创建人"`
UpdateBy string `json:"updateBy" gorm:"type:varchar(128);comment:更新者"`
Params string `json:"params" gorm:"-"`
Remark string `json:"remark" gorm:"type:varchar(255);"` //备注
Msg string `json:"msg" gorm:"type:varchar(255);"`
model.BaseModel
}

View File

@@ -0,0 +1,19 @@
package entity
import (
"pandax/kit/model"
)
type LogOper struct {
OperId int64 `json:"operId" gorm:"primary_key;AUTO_INCREMENT"` //主键
Title string `json:"title" gorm:"type:varchar(128);comment:操作的模块"`
BusinessType string `json:"businessType" gorm:"type:varchar(1);comment:0其它 1新增 2修改 3删除"`
Method string `json:"method" gorm:"type:varchar(255);comment:请求方法"`
OperName string `json:"operName" gorm:"type:varchar(255);comment:操作人员"`
OperUrl string `json:"operUrl" gorm:"type:varchar(255);comment:操作url"`
OperIp string `json:"operIp" gorm:"type:varchar(255);comment:操作IP"`
OperLocation string `json:"operLocation" gorm:"type:varchar(255);comment:操作地点"`
OperParam string `json:"operParam" gorm:"type:varchar(255);comment:请求参数"` //
Status string `json:"status" gorm:"type:varchar(1);comment:0=正常,1=异常"`
model.BaseModel
}

View File

@@ -0,0 +1,68 @@
package router
import (
"pandax/apps/log/api"
"pandax/apps/log/entity"
"pandax/apps/log/services"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitLoginLogRouter(container *restful.Container) {
// 登录日志
s := &api.LogLoginApi{
LogLoginApp: services.LogLoginModelDao,
}
ws := new(restful.WebService)
ws.Path("/log/logLogin").Produces(restful.MIME_JSON)
tags := []string{"logLogin"}
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取登录日志列表").Handle(s.GetLoginLogList)
}).
Doc("获取登录日志列表").
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Param(ws.QueryParameter("loginLocation", "loginLocation").DataType("string")).
Param(ws.QueryParameter("username", "username").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/{infoId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取登录日志信息").Handle(s.GetLoginLog)
}).
Doc("获取登录日志信息").
Param(ws.PathParameter("infoId", "Id").DataType("int")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(entity.LogLogin{}). // on the response
Returns(200, "OK", entity.LogLogin{}).
Returns(404, "Not Found", nil))
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改登录日志信息").Handle(s.UpdateLoginLog)
}).
Doc("修改登录日志信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.LogLogin{}))
ws.Route(ws.DELETE("/{infoId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除登录日志信息").Handle(s.DeleteLoginLog)
}).
Doc("删除登录日志信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("infoId", "多id 1,2,3").DataType("string")))
ws.Route(ws.DELETE("/all").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("清空登录日志信息").Handle(s.DeleteAll)
}).
Doc("清空登录日志信息").
Metadata(restfulspec.KeyOpenAPITags, tags))
container.Add(ws)
}

View File

@@ -0,0 +1,61 @@
package router
import (
"pandax/apps/log/api"
"pandax/apps/log/entity"
"pandax/apps/log/services"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitOperLogRouter(container *restful.Container) {
// 操作日志
s := &api.LogOperApi{
LogOperApp: services.LogOperModelDao,
}
ws := new(restful.WebService)
ws.Path("/log/logOper").Produces(restful.MIME_JSON)
tags := []string{"logOper"}
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取操作日志列表").Handle(s.GetOperLogList)
}).
Doc("获取操作日志列表").
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Param(ws.QueryParameter("businessType", "businessType").DataType("string")).
Param(ws.QueryParameter("operName", "operName").DataType("string")).
Param(ws.QueryParameter("title", "title").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/{operId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取操作日志信息").Handle(s.GetOperLog)
}).
Doc("获取操作日志信息").
Param(ws.PathParameter("operId", "Id").DataType("int")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(entity.LogOper{}). // on the response
Returns(200, "OK", entity.LogOper{}).
Returns(404, "Not Found", nil))
ws.Route(ws.DELETE("/{operId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除操作日志信息").Handle(s.DeleteOperLog)
}).
Doc("删除操作日志信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("operId", "多id 1,2,3").DataType("string")))
ws.Route(ws.DELETE("/all").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("清空操作日志信息").Handle(s.DeleteAll)
}).
Doc("清空操作日志信息").
Metadata(restfulspec.KeyOpenAPITags, tags))
container.Add(ws)
}

View File

@@ -0,0 +1,76 @@
package services
import (
"pandax/apps/log/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
LogLoginModel interface {
Insert(data entity.LogLogin) *entity.LogLogin
FindOne(infoId int64) *entity.LogLogin
FindListPage(page, pageSize int, data entity.LogLogin) (*[]entity.LogLogin, int64)
Update(data entity.LogLogin) *entity.LogLogin
Delete(infoId []int64)
DeleteAll()
}
logLoginModelImpl struct {
table string
}
)
var LogLoginModelDao LogLoginModel = &logLoginModelImpl{
table: `log_logins`,
}
func (m *logLoginModelImpl) Insert(data entity.LogLogin) *entity.LogLogin {
global.Db.Table(m.table).Create(&data)
return &data
}
func (m *logLoginModelImpl) FindOne(infoId int64) *entity.LogLogin {
resData := new(entity.LogLogin)
err := global.Db.Table(m.table).Where("info_id = ?", infoId).First(resData).Error
biz.ErrIsNil(err, "查询登录日志信息失败")
return resData
}
func (m *logLoginModelImpl) FindListPage(page, pageSize int, data entity.LogLogin) (*[]entity.LogLogin, int64) {
list := make([]entity.LogLogin, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
if data.LoginLocation != "" {
db = db.Where("login_location like ?", "%"+data.LoginLocation+"%")
}
if data.Username != "" {
db = db.Where("username like ?", "%"+data.Username+"%")
}
err := db.Where("delete_time IS NULL").Count(&total).Error
err = db.Order("info_id desc").Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询登录分页日志信息失败")
return &list, total
}
func (m *logLoginModelImpl) Update(data entity.LogLogin) *entity.LogLogin {
err := global.Db.Table(m.table).Updates(&data).Error
biz.ErrIsNil(err, "修改登录日志信息失败")
return &data
}
func (m *logLoginModelImpl) Delete(infoIds []int64) {
err := global.Db.Table(m.table).Delete(&entity.LogLogin{}, "info_id in (?)", infoIds).Error
biz.ErrIsNil(err, "删除登录日志信息失败")
return
}
func (m *logLoginModelImpl) DeleteAll() {
global.Db.Exec("DELETE FROM log_logins")
}

View File

@@ -0,0 +1,72 @@
package services
import (
"pandax/apps/log/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
LogOperModel interface {
Insert(data entity.LogOper) *entity.LogOper
FindOne(infoId int64) *entity.LogOper
FindListPage(page, pageSize int, data entity.LogOper) (*[]entity.LogOper, int64)
Delete(infoId []int64)
DeleteAll()
}
logLogOperModelImpl struct {
table string
}
)
var LogOperModelDao LogOperModel = &logLogOperModelImpl{
table: `log_opers`,
}
func (m *logLogOperModelImpl) Insert(data entity.LogOper) *entity.LogOper {
global.Db.Table(m.table).Create(&data)
return &data
}
func (m *logLogOperModelImpl) FindOne(operId int64) *entity.LogOper {
resData := new(entity.LogOper)
err := global.Db.Table(m.table).Where("oper_id = ?", operId).First(resData).Error
biz.ErrIsNil(err, "查询操作日志信息失败")
return resData
}
func (m *logLogOperModelImpl) FindListPage(page, pageSize int, data entity.LogOper) (*[]entity.LogOper, int64) {
list := make([]entity.LogOper, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.BusinessType != "" {
db = db.Where("business_type = ?", data.BusinessType)
}
if data.OperLocation != "" {
db = db.Where("oper_location like ?", "%"+data.OperLocation+"%")
}
if data.Title != "" {
db = db.Where("title like ?", "%"+data.Title+"%")
}
if data.OperName != "" {
db = db.Where("oper_name like ?", "%"+data.OperName+"%")
}
err := db.Where("delete_time IS NULL").Count(&total).Error
err = db.Order("create_time desc").Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询操作分页日志信息失败")
return &list, total
}
func (m *logLogOperModelImpl) Delete(operIds []int64) {
err := global.Db.Table(m.table).Delete(&entity.LogOper{}, "oper_id in (?)", operIds).Error
biz.ErrIsNil(err, "删除操作日志信息失败")
return
}
func (m *logLogOperModelImpl) DeleteAll() {
global.Db.Exec("DELETE FROM log_opers")
}

1066
apps/script/call.go Normal file

File diff suppressed because it is too large Load Diff

46
apps/script/checkChace.go Normal file
View File

@@ -0,0 +1,46 @@
package script
import (
"crypto/sha1"
"fmt"
"net/http"
_ "net/http/pprof"
"os"
"time"
)
var threadPool string
var rootPath, _ = os.Getwd()
// func init() {
// rootPath, _ = os.Executable()
// rootPath = filepath.Dir(rootPath)
// }
func checkChace(wr http.ResponseWriter, data []byte) bool {
if wr == nil {
return false
}
hash := sha1.New()
hash.Write(data)
hashString := fmt.Sprintf("\"%x\"", hash.Sum(nil))
wr.Header().Set("Date", time.Now().Format(time.RFC1123))
wr.Header().Set("ETag", hashString)
if match := wr.Header().Get("If-Match"); match != "" {
wr.Header().Del("If-Match")
if match != hashString {
wr.WriteHeader(http.StatusPreconditionFailed)
return true
}
}
if match := wr.Header().Get("If-None-Match"); match != "" {
wr.Header().Del("If-None-Match")
if match == hashString {
wr.WriteHeader(http.StatusNotModified)
return true
}
}
return false
}

21
apps/script/gzip.go Normal file
View File

@@ -0,0 +1,21 @@
package script
import (
"mime"
"path/filepath"
)
func GetMimeType(filename string) string {
extension := filepath.Ext(filename)
mimeType := mime.TypeByExtension(extension)
return mimeType
}
// type gzipResponseWriter struct {
// http.ResponseWriter
// io.Writer
// }
// func (w *gzipResponseWriter) Write(data []byte) (int, error) {
// return w.Writer.Write(data)
// }

74
apps/script/handle.go Normal file
View File

@@ -0,0 +1,74 @@
package script
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"pandax/kit/restfulx"
)
type ScriptApi struct{}
func (up *ScriptApi) Call(rc *restfulx.ReqCtx) {
rc.Response.Header().Set("Alt-Svc", "h2=:7788; ma=2592000; v=\"46,43,39,35\";")
rc.Response.Header().Set("Accept-Ch", "Sec-CH-UA-Arch, Sec-CH-UA-Bitness, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, DPR, Viewport-Width, Width, ETag, If-Match, If-None-Match")
rc.Response.Header().Set("Access-Control-Max-Age", "31536000")
rc.Response.Header().Set("Cache-Control", "no-transform,no-siteapp,max-age=31536000")
rc.Response.Header().Set("Date", time.Now().Format(time.RFC1123))
rc.Response.Header().Set("X-Request-Receive-Date", time.Now().Format(time.RFC1123))
rc.Response.Header().Set("X-Content-Type-Options", "nosniff")
rc.Response.Header().Set("Save-Data", "off")
rc.Response.Header().Set("Vary", "ETag")
rc.Response.Header().Set("X-Runtime-Info", "xScript Enging for xMagic 1.15.1.0")
// 判断是否支持gzip压缩
if strings.Contains(rc.Request.Request.Header.Get("Accept-Encoding"), "gzip") {
rc.Response.Header().Set("Content-Encoding", "gzip")
}
if clear := strings.Contains(rc.Request.Request.Header.Get("Cache-Control"), "clear"); clear {
rc.Response.Header().Add("Clear-Site-Data", "cache, cookies, storage, executionContexts")
}
if cacheMatch := rc.Request.Request.Header.Get("If-Match"); cacheMatch != "" {
rc.Response.Header().Set("If-Match", cacheMatch)
}
if cacheMatch := rc.Request.Request.Header.Get("If-None-Match"); cacheMatch != "" {
rc.Response.Header().Set("If-None-Match", cacheMatch)
}
path := filepath.Join(rootPath, rc.Request.Request.URL.Path)
// 默认的 Content-Type
rc.Response.Header().Set("Content-Type", GetMimeType(rc.Request.Request.URL.Path))
if rc.Response.Header().Get("Content-Type") == "" {
rc.Response.Header().Set("Content-Type", "application/json;charset=utf-8")
}
// 如果path末尾被浏览器追加了#,则去掉
path = strings.TrimSuffix(path, "#")
info, err := os.Stat(path)
if err == nil {
if info.IsDir() {
if !strings.HasSuffix(path, "/") {
path += "/"
}
}
}
// 判断s.Path下是否存在文件core.js, 如果存在则执行core.js
coreFilePath := filepath.Join(rootPath, "core.js")
if _, err := os.Stat(coreFilePath); err == nil {
var userInfo []string
if rc.LoginAccount != nil {
userInfo = []string{fmt.Sprintf("%d", rc.LoginAccount.UserId), rc.LoginAccount.UserName}
}
rc.ResData = executeScript(false, rc.Response, rc.Request.Request, coreFilePath, userInfo).String()
return
}
}

103
apps/script/put.go Normal file
View File

@@ -0,0 +1,103 @@
package script
import (
"bufio"
"fmt"
"io"
"math"
"net/http"
"os"
"path/filepath"
)
func uploadFile(wr http.ResponseWriter, r *http.Request, path string) (string, string, int64) {
file, fh, err := r.FormFile("file")
if err != nil {
wr.WriteHeader(http.StatusBadRequest)
// l.Echo().WithError(err).Warn("Failed to get file from request")
fmt.Println("无法从请求中获取文件", err)
return "", "", 0
}
defer file.Close()
fileName, fileType, fileSize := fh.Filename, fh.Header.Get("Content-Type"), fh.Size
cachePath := path + ".cache"
err = os.MkdirAll(filepath.Dir(path), os.ModePerm)
if err != nil {
wr.WriteHeader(http.StatusInternalServerError)
// l.Echo().WithError(err).Warn("Failed to create directory")
fmt.Println("创建目录失败", err)
return "", "", 0
}
f, err := os.OpenFile(cachePath, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
wr.WriteHeader(http.StatusInternalServerError)
// l.Echo().WithError(err).Warn("Failed to create file")
fmt.Println("无法创建文件", err)
return "", "", 0
}
defer f.Close()
var bufSize int64
switch {
case fileSize < 10*1024*1024:
bufSize = 100 * 1024
case fileSize < 100*1024*1024:
bufSize = 1024 * 1024
case fileSize < 500*1024*1024:
bufSize = 50 * 1024 * 1024
case fileSize >= 500*1024*1024:
bufSize = 100 * 1024 * 1024
}
_, err = file.Seek(0, io.SeekStart)
if err != nil {
wr.WriteHeader(http.StatusInternalServerError)
fmt.Println("无法操作文件游标", err)
return "", "", 0
}
wr.Header().Set("Content-Type", "text/event-stream")
buf := make([]byte, bufSize)
reader := bufio.NewReader(file)
writer := bufio.NewWriter(f)
totalChunks := int(math.Ceil(float64(fileSize) / float64(bufSize)))
for i := 0; i < totalChunks; i++ {
n, err := reader.Read(buf)
if err != nil && err != io.EOF {
wr.WriteHeader(http.StatusInternalServerError)
fmt.Println("读取文件失败", err)
return "", "", 0
}
_, err = writer.Write(buf[:n])
if err != nil {
wr.WriteHeader(http.StatusInternalServerError)
fmt.Println("写出文件失败", err)
return "", "", 0
}
progress := float64(i+1) / float64(totalChunks) * 100
wr.Write([]byte(fmt.Sprintf("event: progress\ndata: %.2f\n\n", progress)))
wr.(http.Flusher).Flush() // 实时返回数据
}
writer.Flush()
os.Remove(path)
err = os.Rename(cachePath, path)
if err != nil {
wr.WriteHeader(http.StatusInternalServerError)
fmt.Println("重命名文件失败", err)
return "", "", 0
}
return fileName, fileType, fileSize
}

189
apps/script/request.go Normal file
View File

@@ -0,0 +1,189 @@
package script
import (
"bytes"
"fmt"
"io"
"net/http"
"pandax/pkg/xscript/buffer"
"pandax/pkg/xscript/engine"
"strings"
"sync"
)
type RequestInfo struct {
sync.Mutex
// Method specifies the HTTP method (GET, POST, PUT, etc.).
// For client requests, an empty string means GET.
//
// Go's HTTP client does not support sending a request with
// the CONNECT method. See the documentation on Transport for
// details.
Method string `json:"method"`
// URL specifies either the URI being requested (for server
// requests) or the URL to access (for client requests).
//
// For server requests, the URL is parsed from the URI
// supplied on the Request-Line as stored in RequestURI. For
// most requests, fields other than Path and RawQuery will be
// empty. (See RFC 7230, Section 5.3)
//
// For client requests, the URL's Host specifies the server to
// connect to, while the Request's Host field optionally
// specifies the Host header value to send in the HTTP
// request.
URL string `json:"url"`
// The path portion of the request URL.
Path string `json:"path"`
// The protocol version for incoming server requests.
//
// For client requests, these fields are ignored. The HTTP
// client code always uses either HTTP/1.1 or HTTP/2.
// See the docs on Transport for details.
Proto string `json:"proto"` // "HTTP/1.0"
ProtoMajor int `json:"proto_major"` // 1
ProtoMinor int `json:"proro_minor"` // 0
// Header contains the request header fields either received
// by the server or to be sent by the client.
//
// If a server received a request with header lines,
//
// Host: example.com
// accept-encoding: gzip, deflate
// Accept-Language: en-us
// fOO: Bar
// foo: two
//
// then
//
// Header = map[string][]string{
// "Accept-Encoding": {"gzip, deflate"},
// "Accept-Language": {"en-us"},
// "Foo": {"Bar", "two"},
// }
//
// For incoming requests, the Host header is promoted to the
// Request.Host field and removed from the Header map.
//
// HTTP defines that header names are case-insensitive. The
// request parser implements this by using CanonicalHeaderKey,
// making the first character and any characters following a
// hyphen uppercase and the rest lowercase.
//
// For client requests, certain headers such as Content-Length
// and Connection are automatically written when needed and
// values in Header may be ignored. See the documentation
// for the Request.Write method.
Header map[string][]string `json:"headers"`
// Body is the request's body.
//
// For client requests, a nil body means the request has no
// body, such as a GET request.
Body engine.Value `json:"body"`
// ContentLength records the length of the associated content.
// The value -1 indicates that the length is unknown.
// Values >= 0 indicate that the given number of bytes may
// be read from Body.
//
// For client requests, a value of 0 with a non-nil Body is
// also treated as unknown.
ContentLength int64 `json:"content_length"`
// For server requests, Host specifies the host on which the
// URL is sought. For HTTP/1 (per RFC 7230, section 5.4), this
// is either the value of the "Host" header or the host name
// given in the URL itself. For HTTP/2, it is the value of the
// ":authority" pseudo-header field.
// It may be of the form "host:port". For international domain
// names, Host may be in Punycode or Unicode form. Use
// golang.org/x/net/idna to convert it to either format if
// needed.
// To prevent DNS rebinding attacks, server Handlers should
// validate that the Host header has a value for which the
// Handler considers itself authoritative. The included
// ServeMux supports patterns registered to particular host
// names and thus protects its registered Handlers.
//
// For client requests, Host optionally overrides the Host
// header to send. If empty, the Request.Write method uses
// the value of URL.Host. Host may contain an international
// domain name.
Host string `json:"host"`
// Form contains the parsed form data, including both the URL
// field's query parameters and the PATCH, POST, or PUT form data.
// This field is only available after ParseForm is called.
// The HTTP client ignores Form and uses Body instead.
Form map[string][]string `json:"form"`
Files map[string][]string `json:"files"`
Query map[string][]string `json:"query"`
// RemoteAddr allows HTTP servers and other software to record
// the network address that sent the request, usually for
// logging. This field is not filled in by ReadRequest and
// has no defined format. The HTTP server in this package
// sets RemoteAddr to an "IP:port" address before invoking a
// handler.
// This field is ignored by the HTTP client.
RemoteAddr string `json:"remote_addr"`
}
func extractRequestInfo(vm *engine.Runtime, r *http.Request) *RequestInfo {
// 提取请求信息的逻辑
requestInfo := &RequestInfo{
Method: r.Method,
URL: r.URL.String(),
Path: r.URL.Path,
Header: r.Header,
Proto: r.Proto,
ProtoMajor: r.ProtoMajor,
ProtoMinor: r.ProtoMinor,
ContentLength: r.ContentLength,
Form: make(map[string][]string),
Query: r.URL.Query(),
Host: r.Host,
RemoteAddr: r.RemoteAddr,
}
contentType := r.Header.Get("Content-Type")
if strings.Contains(contentType, "application/x-www-form-urlencoded") && requestInfo.Body != nil {
data := requestInfo.Body.Export().([]byte)
requestInfo.Form, _ = parseFormUrlEncoded(data)
}
// 将请求体内容拷贝到bytes.Buffer中
bodyBuffer := new(bytes.Buffer)
if _, err := io.Copy(bodyBuffer, r.Body); err != nil {
fmt.Println("复制请求体失败,错误:", err)
return requestInfo
}
// 将bytes.Buffer的内容赋值给RequestInfo结构体的Body字段
data := bodyBuffer.Bytes()
requestInfo.Body = buffer.Format(vm, data)
r.Body = io.NopCloser(bytes.NewBuffer(data))
return requestInfo
}
func parseFormUrlEncoded(body []byte) (map[string][]string, error) {
formData := make(map[string][]string)
kvPairs := strings.Split(string(body), "&")
for _, kv := range kvPairs {
kv := strings.Split(kv, "=")
if len(kv) == 2 {
key, value := kv[0], kv[1]
formData[key] = append(formData[key], value)
}
}
return formData, nil
}

196
apps/script/runtime.go Normal file
View File

@@ -0,0 +1,196 @@
package script
import (
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"time"
"pandax/pkg/xscript/buffer"
"pandax/pkg/xscript/console"
"pandax/pkg/xscript/crypto"
"pandax/pkg/xscript/database/cache"
"pandax/pkg/xscript/database/mongo"
"pandax/pkg/xscript/database/redis"
"pandax/pkg/xscript/database/sql"
"pandax/pkg/xscript/encoding"
"pandax/pkg/xscript/engine"
"pandax/pkg/xscript/extension"
"pandax/pkg/xscript/fs"
"pandax/pkg/xscript/jwt"
"pandax/pkg/xscript/net"
jos "pandax/pkg/xscript/os"
"pandax/pkg/xscript/querystring"
"pandax/pkg/xscript/request"
"pandax/pkg/xscript/require"
"pandax/pkg/xscript/zip"
"pandax/pkg/http_client"
jsUrl "pandax/pkg/xscript/url"
)
func newRuntime() *engine.Runtime {
vm := engine.New()
dir, _ := os.Getwd()
vm.Set("runtimePath", dir)
vm.SetFieldNameMapper(engine.TagFieldNameMapper("json", true))
registry := new(require.Registry) // this can be shared by multiple runtimes
// 定义外部库
querystring.Enable(vm)
extension.Enable(vm)
registry.Enable(vm)
console.Enable(vm)
encoding.Enable(vm)
request.Enable(vm)
buffer.Enable(vm)
crypto.Enable(vm)
jsUrl.Enable(vm)
cache.Enable(vm)
redis.Enable(vm)
mongo.Enable(vm)
jwt.Enable(vm)
sql.Enable(vm)
net.Enable(vm)
jos.Enable(vm)
zip.Enable(vm)
fs.Enable(vm)
return vm
}
func loadScript(filepath string) (string, error) {
scriptData, err := os.ReadFile(filepath)
if err != nil {
return "", err
}
return string(scriptData), nil
}
func getScriptFromURL(url, jsPath string) error {
// 判断文件是否存在如果存在取修改时间若修改时间小于1小时则返回nil
if _, err := os.Stat(jsPath); err == nil {
fileInfo, err := os.Stat(jsPath)
if err == nil {
if time.Since(fileInfo.ModTime()) < time.Hour {
return nil
}
}
}
_, err := http_client.DefaultClient.SetUrl(url).Do()
if err != nil {
return err
}
http_client.DefaultClient.SaveToFile(jsPath)
return nil
}
func removeComments(scriptData string) string {
// 删除单行注释
commentRegExp := regexp.MustCompile(`(^| )\/\/.*`)
scriptData = commentRegExp.ReplaceAllString(scriptData, "")
// 删除多行注释
multilineCommentRegExp := regexp.MustCompile(`\/\*(.|\n)*?\*\/\n`)
scriptData = multilineCommentRegExp.ReplaceAllString(scriptData, "")
// 删除HTML注释
commentRegex := regexp.MustCompile(`<!--(.*?)-->`)
scriptData = commentRegex.ReplaceAllString(scriptData, "")
return scriptData
}
func loadAndCheckScript(jsPath, secret string) (string, error) {
// 加载脚本内容
scriptData, err := loadScript(jsPath)
if err != nil {
return "", err
}
jsPath = filepath.Dir(jsPath)
// 删除注释
scriptData = removeComments(scriptData)
requireRegExp := regexp.MustCompile(`require\(["']([^"']+)["']\)`)
requireMatches := requireRegExp.FindAllStringSubmatch(scriptData, -1)
jsPath += "/moudles"
var filename string
filenameRegExp := regexp.MustCompile(`\?.*`)
for _, match := range requireMatches {
if !strings.HasPrefix(match[1], "//") {
continue
}
// 如果jsPath不存在则创建
if _, err := os.Stat(jsPath); os.IsNotExist(err) {
os.MkdirAll(jsPath, os.ModePerm)
}
url := strings.Replace(match[1], "//", "", 1)
parts := strings.Split(url, "/")
filename := path.Base(parts[len(parts)-1])
filename = filenameRegExp.ReplaceAllString(filename, "")
filename = filepath.Join(jsPath, filename)
err = getScriptFromURL(url, filename)
if err != nil {
fmt.Printf("无法从url获取脚本: %s\n", url)
fmt.Printf("尝试使用本地缓存脚本文件: %s\n", filename)
}
// 合并requireScript到scriptData变量中
scriptData = strings.ReplaceAll(scriptData, match[1], filename)
}
useRegExp := regexp.MustCompile(`(?m)(^|^\s+)'use\s+(.*?.js)'`)
useMatches := useRegExp.FindAllStringSubmatch(scriptData, -1)
for _, match := range useMatches {
filename = match[2]
if strings.HasPrefix(filename, "//") {
// 如果jsPath不存在则创建
if _, err := os.Stat(jsPath); os.IsNotExist(err) {
os.MkdirAll(jsPath, os.ModePerm)
}
url := strings.Replace(filename, "//", "", 1)
parts := strings.Split(url, "/")
filename := path.Base(parts[len(parts)-1])
filename = filenameRegExp.ReplaceAllString(filename, "")
filename = filepath.Join(jsPath, filename)
err = getScriptFromURL(url, filename)
if err != nil {
fmt.Printf("无法从url获取脚本: %s\n", url)
fmt.Printf("尝试使用本地缓存脚本文件: %s\n", filename)
}
}
// 读取文件内容
scriptContent, err := loadAndCheckScript(filename, secret)
if err != nil {
fmt.Printf("脚本文件读取失败: %s\n", filename)
return "", err
}
// 合并requireScript到scriptData变量中
scriptData = strings.ReplaceAll(scriptData, match[0], fmt.Sprintf("\n%s\n", string(scriptContent)))
}
// 删除注释
scriptData = removeComments(scriptData)
// fmt.Println(fmt.Sprintf("合并后的脚本: %s\n", scriptData))
return scriptData, nil
}

104
apps/script/script.go Normal file
View File

@@ -0,0 +1,104 @@
package script
import (
"crypto/rc4"
"fmt"
"net/http"
"path/filepath"
"regexp"
"strings"
"time"
"pandax/pkg/xscript/buffer"
"pandax/pkg/xscript/database/cache"
"pandax/pkg/xscript/engine"
)
var scriptCache = cache.NewKVStore(1024)
func executeScriptWithSecret(isCall bool, wr http.ResponseWriter, r *http.Request, path, secret string, args []string) engine.Value {
var err error
var functionScript, globalScript string
functionJSPath := filepath.Join(path, "function.js")
globalJSPath := filepath.Join(rootPath, "global.js")
if strings.Contains(path, ".js") {
functionJSPath = path
}
if secret == "" {
secret = "/__/vlan/"
}
cipher, err := rc4.NewCipher([]byte(secret))
if err != nil {
return nil
}
var output []byte
if script, ok := scriptCache.Get(functionJSPath); ok {
fmt.Println("函数缓存命中:", functionJSPath)
output = script.([]byte)
plain := make([]byte, len(output))
cipher.XORKeyStream(plain, output)
functionScript = string(output)
} else if functionScript, err = loadAndCheckScript(functionJSPath, secret); err == nil {
if globalScript, err = loadAndCheckScript(globalJSPath, secret); err == nil {
// 因为 global.js 会被其他脚本引用,因此不允许定义 main 函数或名为 main 的变量
mainCheckRegExp := regexp.MustCompile(`^(function|var|let|const)\s+main\b`)
if mainCheckRegExp.MatchString(globalScript) {
fmt.Println("文件 global.js 中不能包含名为 main 的函数或变量定义", err)
return engine.Null()
}
functionScript = fmt.Sprintf("%s\n%s", globalScript, functionScript)
}
output = []byte(functionScript)
plain := make([]byte, len(output))
cipher.XORKeyStream(plain, output)
scriptCache.Set(functionJSPath, output, time.Hour*24)
} else {
if wr != nil && !isCall {
wr.WriteHeader(http.StatusInternalServerError)
}
fmt.Println("调用 core.js 失败", err)
return engine.Null()
}
vm := newRuntime()
vm.Set("args", args)
vm.Set("rootPath", rootPath)
vm.Set("scriptPath", path)
responeCall(vm, wr, r, path)
if wr != nil && !isCall {
wr.Header().Set("X-Request-Receive-Date", time.Now().Format(time.RFC1123))
}
function := r.Header.Get("X-Method")
if (function == "" || path == filepath.Join(rootPath, "core.js")) && (strings.Contains(functionScript, " main ") || strings.Contains(functionScript, " main(")) {
function = "main"
}
functionScript = fmt.Sprintf("%s\n%s()", functionScript, function)
result, err := vm.RunScript(path, functionScript)
if err != nil {
if wr != nil && !isCall {
wr.WriteHeader(http.StatusInternalServerError)
}
// s.l.Echo().WithError(err).Warn("Failed to execute script %s", path)
fmt.Println("函数代码语法错误", err)
return engine.Null()
}
if !isCall {
checkChace(wr, []byte(result.String()))
fmt.Fprint(wr, result)
}
return buffer.Format(vm, result.String())
}
func executeScript(isCall bool, wr http.ResponseWriter, r *http.Request, path string, args []string) engine.Value {
return executeScriptWithSecret(isCall, wr, r, path, "", args)
}

65
apps/system/api/api.go Normal file
View File

@@ -0,0 +1,65 @@
package api
import (
entity "pandax/apps/system/entity"
services "pandax/apps/system/services"
"pandax/kit/casbin"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
"pandax/pkg/global"
)
type SystemApiApi struct {
ApiApp services.SysApiModel
}
func (s *SystemApiApi) CreateApi(rc *restfulx.ReqCtx) {
var api entity.SysApi
restfulx.BindJsonAndValid(rc, &api)
s.ApiApp.Insert(api)
}
func (s *SystemApiApi) DeleteApi(rc *restfulx.ReqCtx) {
ids := rc.Request.PathParameter("id")
s.ApiApp.Delete(utils.IdsStrToIdsIntGroup(ids))
}
func (s *SystemApiApi) GetApiList(rc *restfulx.ReqCtx) {
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
path := rc.Request.QueryParameter("path")
description := rc.Request.QueryParameter("description")
method := rc.Request.QueryParameter("method")
apiGroup := rc.Request.QueryParameter("apiGroup")
api := entity.SysApi{Path: path, Description: description, Method: method, ApiGroup: apiGroup}
list, total := s.ApiApp.FindListPage(pageNum, pageSize, api)
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
func (s *SystemApiApi) GetApiById(rc *restfulx.ReqCtx) {
id := restfulx.QueryInt(rc, "id", 0)
rc.ResData = s.ApiApp.FindOne(int64(id))
}
func (s *SystemApiApi) UpdateApi(rc *restfulx.ReqCtx) {
var api entity.SysApi
restfulx.BindJsonAndValid(rc, &api)
s.ApiApp.Update(api)
}
func (s *SystemApiApi) GetAllApis(rc *restfulx.ReqCtx) {
rc.ResData = s.ApiApp.FindList(entity.SysApi{})
}
func (s *SystemApiApi) GetPolicyPathByRoleId(rc *restfulx.ReqCtx) {
roleKey := rc.Request.QueryParameter("roleKey")
ca := casbin.CasbinService{ModelPath: global.Conf.Casbin.ModelPath}
rc.ResData = ca.GetPolicyPathByRoleId(roleKey)
}

60
apps/system/api/config.go Normal file
View File

@@ -0,0 +1,60 @@
package api
import (
entity "pandax/apps/system/entity"
services "pandax/apps/system/services"
"pandax/kit/biz"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
)
type ConfigApi struct {
ConfigApp services.SysConfigModel
}
func (p *ConfigApi) GetConfigList(rc *restfulx.ReqCtx) {
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
configName := rc.Request.QueryParameter("configName")
configKey := rc.Request.QueryParameter("configKey")
configType := rc.Request.QueryParameter("configType")
config := entity.SysConfig{ConfigName: configName, ConfigKey: configKey, ConfigType: configType}
list, total := p.ConfigApp.FindListPage(pageNum, pageSize, config)
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
func (p *ConfigApi) GetConfigListByKey(rc *restfulx.ReqCtx) {
configKey := rc.Request.QueryParameter("configKey")
biz.IsTrue(configKey != "", "请传入配置Key")
rc.ResData = p.ConfigApp.FindList(entity.SysConfig{ConfigKey: configKey})
}
func (p *ConfigApi) GetConfig(rc *restfulx.ReqCtx) {
id := restfulx.PathParamInt(rc, "configId")
p.ConfigApp.FindOne(int64(id))
}
func (p *ConfigApi) InsertConfig(rc *restfulx.ReqCtx) {
var config entity.SysConfig
restfulx.BindJsonAndValid(rc, &config)
p.ConfigApp.Insert(config)
}
func (p *ConfigApi) UpdateConfig(rc *restfulx.ReqCtx) {
var post entity.SysConfig
restfulx.BindJsonAndValid(rc, &post)
p.ConfigApp.Update(post)
}
func (p *ConfigApi) DeleteConfig(rc *restfulx.ReqCtx) {
configId := rc.Request.PathParameter("configId")
p.ConfigApp.Delete(utils.IdsStrToIdsIntGroup(configId))
}

121
apps/system/api/dict.go Normal file
View File

@@ -0,0 +1,121 @@
package api
import (
"fmt"
entity "pandax/apps/system/entity"
services "pandax/apps/system/services"
"pandax/kit/biz"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
"pandax/pkg/global"
)
type DictApi struct {
DictType services.SysDictTypeModel
DictData services.SysDictDataModel
}
func (p *DictApi) GetDictTypeList(rc *restfulx.ReqCtx) {
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
status := restfulx.QueryParam(rc, "status")
dictName := restfulx.QueryParam(rc, "dictName")
dictType := restfulx.QueryParam(rc, "dictType")
list, total := p.DictType.FindListPage(pageNum, pageSize, entity.SysDictType{Status: status, DictName: dictName, DictType: dictType})
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
func (p *DictApi) GetDictType(rc *restfulx.ReqCtx) {
dictId := restfulx.PathParamInt(rc, "dictId")
p.DictType.FindOne(int64(dictId))
}
func (p *DictApi) InsertDictType(rc *restfulx.ReqCtx) {
var dict entity.SysDictType
restfulx.BindJsonAndValid(rc, &dict)
dict.CreateBy = rc.LoginAccount.UserName
p.DictType.Insert(dict)
}
func (p *DictApi) UpdateDictType(rc *restfulx.ReqCtx) {
var dict entity.SysDictType
restfulx.BindJsonAndValid(rc, &dict)
dict.CreateBy = rc.LoginAccount.UserName
p.DictType.Update(dict)
}
func (p *DictApi) DeleteDictType(rc *restfulx.ReqCtx) {
dictId := restfulx.PathParam(rc, "dictId")
dictIds := utils.IdsStrToIdsIntGroup(dictId)
deList := make([]int64, 0)
for _, id := range dictIds {
one := p.DictType.FindOne(id)
list := p.DictData.FindList(entity.SysDictData{DictType: one.DictType})
if len(*list) == 0 {
deList = append(deList, id)
} else {
global.Log.Info(fmt.Sprintf("dictId: %d 存在字典数据绑定无法删除", id))
}
}
p.DictType.Delete(deList)
}
func (p *DictApi) ExportDictType(rc *restfulx.ReqCtx) {
filename := restfulx.QueryParam(rc, "filename")
status := restfulx.QueryParam(rc, "status")
dictName := restfulx.QueryParam(rc, "dictName")
dictType := restfulx.QueryParam(rc, "dictType")
list := p.DictType.FindList(entity.SysDictType{Status: status, DictName: dictName, DictType: dictType})
fileName := utils.GetFileName(global.Conf.Server.ExcelDir, filename)
utils.InterfaceToExcel(*list, fileName)
rc.Download(fileName)
}
func (p *DictApi) GetDictDataList(rc *restfulx.ReqCtx) {
dictLabel := restfulx.QueryParam(rc, "dictLabel")
dictType := restfulx.QueryParam(rc, "dictType")
status := restfulx.QueryParam(rc, "status")
rc.ResData = p.DictData.FindList(entity.SysDictData{Status: status, DictType: dictType, DictLabel: dictLabel})
}
func (p *DictApi) GetDictDataListByDictType(rc *restfulx.ReqCtx) {
dictType := restfulx.QueryParam(rc, "dictType")
biz.IsTrue(dictType != "", "请传入字典类型")
rc.ResData = p.DictData.FindList(entity.SysDictData{DictType: dictType})
}
func (p *DictApi) GetDictData(rc *restfulx.ReqCtx) {
dictCode := restfulx.PathParamInt(rc, "dictCode")
p.DictData.FindOne(int64(dictCode))
}
func (p *DictApi) InsertDictData(rc *restfulx.ReqCtx) {
var data entity.SysDictData
restfulx.BindJsonAndValid(rc, &data)
data.CreateBy = rc.LoginAccount.UserName
p.DictData.Insert(data)
}
func (p *DictApi) UpdateDictData(rc *restfulx.ReqCtx) {
var data entity.SysDictData
restfulx.BindJsonAndValid(rc, &data)
data.CreateBy = rc.LoginAccount.UserName
p.DictData.Update(data)
}
func (p *DictApi) DeleteDictData(rc *restfulx.ReqCtx) {
dictCode := restfulx.PathParam(rc, "dictCode")
p.DictData.Delete(utils.IdsStrToIdsIntGroup(dictCode))
}

View File

@@ -0,0 +1,22 @@
package form
// 分配角色资源表单信息
type RoleResourceForm struct {
Id int
ResourceIds string
}
// 保存角色信息表单
type RoleForm struct {
Id int
Status int `json:"status"` // 1可用-1不可用
Name string `binding:"required"`
Code string `binding:"required"`
Remark string `json:"remark"`
}
// 账号分配角色表单
type AccountRoleForm struct {
Id int `binding:"required"`
RoleIds string
}

View File

@@ -0,0 +1,34 @@
package form
// User register structure
type Register struct {
Username string `json:"userName"`
Password string `json:"passWord"`
NickName string `json:"nickName" gorm:"default:'QMPlusUser'"`
HeaderImg string `json:"headerImg" gorm:"default:'http://www.henrongyi.top/avatar/lufu.jpg'"`
AuthorityId string `json:"authorityId" gorm:"default:888"`
}
// User login structure
type Login struct {
Username string `json:"username" ` // 用户名
Password string `json:"password"` // 密码
Captcha string `json:"captcha"` // 验证码
CaptchaId string `json:"captchaId"` // 验证码ID
}
// Modify password structure
type ChangePasswordStruct struct {
Username string `json:"username"` // 用户名
Password string `json:"password"` // 密码
NewPassword string `json:"newPassword"` // 新密码
}
type UserSearch struct {
Username string `json:"username"` // 用户UUID
NickName string `json:"nickName"` // 角色ID
Status int64 `json:"status"` // 角色ID
Phone string `json:"phone"` // 角色ID
PostId int64 `json:"postId"` // 角色ID
OrganizationId int64 `json:"organizationId"` // 角色ID
}

98
apps/system/api/menu.go Normal file
View File

@@ -0,0 +1,98 @@
package api
import (
"pandax/apps/system/api/vo"
entity "pandax/apps/system/entity"
services "pandax/apps/system/services"
"pandax/kit/biz"
"pandax/kit/restfulx"
"pandax/kit/utils"
)
type MenuApi struct {
MenuApp services.SysMenuModel
OrganizationApp services.SysOrganizationModel
RoleMenuApp services.SysRoleMenuModel
RoleApp services.SysRoleModel
}
func (m *MenuApi) GetMenuTreeSelect(rc *restfulx.ReqCtx) {
lable := m.MenuApp.SelectMenuLable(entity.SysMenu{})
rc.ResData = lable
}
func (m *MenuApi) GetMenuRole(rc *restfulx.ReqCtx) {
roleKey := restfulx.QueryParam(rc, "roleKey")
biz.IsTrue(roleKey != "", "请传入角色Key")
rc.ResData = Build(*m.MenuApp.SelectMenuRole(roleKey))
}
func (m *MenuApi) GetMenuTreeRoleSelect(rc *restfulx.ReqCtx) {
roleId := restfulx.PathParamInt(rc, "roleId")
result := m.MenuApp.SelectMenuLable(entity.SysMenu{})
menuIds := make([]int64, 0)
if roleId != 0 {
menuIds = m.RoleApp.GetRoleMeunId(entity.SysRole{RoleId: int64(roleId)})
}
rc.ResData = vo.MenuTreeVo{
Menus: *result,
CheckedKeys: menuIds,
}
}
func (m *MenuApi) GetMenuPaths(rc *restfulx.ReqCtx) {
roleKey := restfulx.QueryParam(rc, "roleKey")
biz.IsTrue(roleKey != "", "请传入角色Key")
rc.ResData = m.RoleMenuApp.GetMenuPaths(entity.SysRoleMenu{RoleName: roleKey})
}
func (m *MenuApi) GetMenuList(rc *restfulx.ReqCtx) {
menuName := restfulx.QueryParam(rc, "menuName")
status := restfulx.QueryParam(rc, "status")
menu := entity.SysMenu{MenuName: menuName, Status: status}
if menu.MenuName == "" {
rc.ResData = m.MenuApp.SelectMenu(menu)
} else {
rc.ResData = m.MenuApp.FindList(menu)
}
}
func (m *MenuApi) GetMenu(rc *restfulx.ReqCtx) {
menuId := restfulx.PathParamInt(rc, "menuId")
rc.ResData = m.MenuApp.FindOne(int64(menuId))
}
func (m *MenuApi) InsertMenu(rc *restfulx.ReqCtx) {
var menu entity.SysMenu
restfulx.BindJsonAndValid(rc, &menu)
menu.CreateBy = rc.LoginAccount.UserName
m.MenuApp.Insert(menu)
permis := m.RoleMenuApp.GetPermis(rc.LoginAccount.RoleId)
menus := m.MenuApp.SelectMenuRole(rc.LoginAccount.RoleKey)
rc.ResData = vo.MenuPermisVo{
Menus: Build(*menus),
Permissions: permis,
}
}
func (m *MenuApi) UpdateMenu(rc *restfulx.ReqCtx) {
var menu entity.SysMenu
restfulx.BindJsonAndValid(rc, &menu)
menu.UpdateBy = rc.LoginAccount.UserName
m.MenuApp.Update(menu)
permis := m.RoleMenuApp.GetPermis(rc.LoginAccount.RoleId)
menus := m.MenuApp.SelectMenuRole(rc.LoginAccount.RoleKey)
rc.ResData = vo.MenuPermisVo{
Menus: Build(*menus),
Permissions: permis,
}
}
func (m *MenuApi) DeleteMenu(rc *restfulx.ReqCtx) {
menuId := restfulx.PathParam(rc, "menuId")
m.MenuApp.Delete(utils.IdsStrToIdsIntGroup(menuId))
}

61
apps/system/api/notice.go Normal file
View File

@@ -0,0 +1,61 @@
package api
import (
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
"strings"
)
type NoticeApi struct {
OrganizationApp services.SysOrganizationModel
NoticeApp services.SysNoticeModel
}
// GetNoticeList 通知列表数据
func (p *NoticeApi) GetNoticeList(rc *restfulx.ReqCtx) {
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
noticeType := restfulx.QueryParam(rc, "noticeType")
title := restfulx.QueryParam(rc, "title")
// 获取组织的子组织id
one := p.OrganizationApp.FindOne(rc.LoginAccount.OrganizationId)
split := strings.Split(strings.Trim(one.OrganizationPath, "/"), "/")
// 获取所有父组织id
ids := utils.OrganizationPCIds(split, rc.LoginAccount.OrganizationId, true)
notice := entity.SysNotice{NoticeType: noticeType, Title: title, OrganizationIds: ids}
list, total := p.NoticeApp.FindListPage(pageNum, pageSize, notice)
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
// InsertNotice 添加通知
func (p *NoticeApi) InsertNotice(rc *restfulx.ReqCtx) {
var notice entity.SysNotice
restfulx.BindJsonAndValid(rc, &notice)
notice.UserName = rc.LoginAccount.UserName
p.NoticeApp.Insert(notice)
}
// UpdateNotice 修改通知
func (p *NoticeApi) UpdateNotice(rc *restfulx.ReqCtx) {
var notice entity.SysNotice
restfulx.BindJsonAndValid(rc, &notice)
p.NoticeApp.Update(notice)
}
// DeleteNotice 删除通知
func (p *NoticeApi) DeleteNotice(rc *restfulx.ReqCtx) {
noticeId := restfulx.PathParam(rc, "noticeId")
noticeIds := utils.IdsStrToIdsIntGroup(noticeId)
p.NoticeApp.Delete(noticeIds)
}

View File

@@ -0,0 +1,105 @@
package api
import (
"errors"
"fmt"
"pandax/apps/system/api/vo"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/biz"
"pandax/kit/restfulx"
"pandax/kit/utils"
"pandax/pkg/global"
)
type OrganizationApi struct {
OrganizationApp services.SysOrganizationModel
UserApp services.SysUserModel
RoleApp services.SysRoleModel
}
func (m *OrganizationApi) GetOrganizationTreeRoleSelect(rc *restfulx.ReqCtx) {
roleId := restfulx.PathParamInt(rc, "roleId")
var organization entity.SysOrganization
result := m.OrganizationApp.SelectOrganizationLable(organization)
organizationIds := make([]int64, 0)
if roleId != 0 {
organizationIds = m.RoleApp.GetRoleOrganizationId(entity.SysRole{RoleId: int64(roleId)})
}
rc.ResData = vo.OrganizationTreeVo{
Organizations: result,
CheckedKeys: organizationIds,
}
}
func (a *OrganizationApi) GetOrganizationList(rc *restfulx.ReqCtx) {
//pageNum := restfulx.QueryInt(rc.GinCtx, "pageNum", 1)
//pageSize := restfulx.QueryInt(rc.GinCtx, "pageSize", 10)
organizationName := restfulx.QueryParam(rc, "organizationName")
status := restfulx.QueryParam(rc, "status")
organizationId := restfulx.QueryInt(rc, "organizationId", 0)
organization := entity.SysOrganization{OrganizationName: organizationName, Status: status, OrganizationId: int64(organizationId)}
if organization.OrganizationName == "" {
rc.ResData = a.OrganizationApp.SelectOrganization(organization)
} else {
rc.ResData = a.OrganizationApp.FindList(organization)
}
}
func (a *OrganizationApi) GetOrdinaryOrganizationList(rc *restfulx.ReqCtx) {
var organization entity.SysOrganization
rc.ResData = a.OrganizationApp.FindList(organization)
}
func (a *OrganizationApi) GetOrganizationTree(rc *restfulx.ReqCtx) {
organizationName := restfulx.QueryParam(rc, "organizationName")
status := restfulx.QueryParam(rc, "status")
organizationId := restfulx.QueryInt(rc, "organizationId", 0)
organization := entity.SysOrganization{OrganizationName: organizationName, Status: status, OrganizationId: int64(organizationId)}
rc.ResData = a.OrganizationApp.SelectOrganization(organization)
}
func (a *OrganizationApi) GetOrganization(rc *restfulx.ReqCtx) {
organizationId := restfulx.PathParamInt(rc, "organizationId")
rc.ResData = a.OrganizationApp.FindOne(int64(organizationId))
}
func (a *OrganizationApi) InsertOrganization(rc *restfulx.ReqCtx) {
var organization entity.SysOrganization
restfulx.BindJsonAndValid(rc, &organization)
organization.CreateBy = rc.LoginAccount.UserName
a.OrganizationApp.Insert(organization)
}
func (a *OrganizationApi) UpdateOrganization(rc *restfulx.ReqCtx) {
var organization entity.SysOrganization
restfulx.BindJsonAndValid(rc, &organization)
organization.UpdateBy = rc.LoginAccount.UserName
a.OrganizationApp.Update(organization)
}
func (a *OrganizationApi) DeleteOrganization(rc *restfulx.ReqCtx) {
organizationId := restfulx.PathParam(rc, "organizationId")
organizationIds := utils.IdsStrToIdsIntGroup(organizationId)
deList := make([]int64, 0)
for _, id := range organizationIds {
user := entity.SysUser{}
user.OrganizationId = id
list := a.UserApp.FindList(user)
if len(*list) == 0 {
deList = append(deList, id)
} else {
global.Log.Info(fmt.Sprintf("dictId: %d 存在用户绑定无法删除", id))
}
}
if len(deList) == 0 {
biz.ErrIsNil(errors.New("所有组织都已绑定用户无法删除"), "所有组织都已绑定用户,无法删除")
}
a.OrganizationApp.Delete(deList)
}

84
apps/system/api/post.go Normal file
View File

@@ -0,0 +1,84 @@
package api
import (
"errors"
"fmt"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/biz"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
"pandax/pkg/global"
)
type PostApi struct {
PostApp services.SysPostModel
UserApp services.SysUserModel
RoleApp services.SysRoleModel
}
// GetPostList 职位列表数据
func (p *PostApi) GetPostList(rc *restfulx.ReqCtx) {
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
status := restfulx.QueryParam(rc, "status")
postName := restfulx.QueryParam(rc, "postName")
postCode := restfulx.QueryParam(rc, "postCode")
post := entity.SysPost{Status: status, PostName: postName, PostCode: postCode}
list, total := p.PostApp.FindListPage(pageNum, pageSize, post)
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
// GetPost 获取职位
func (p *PostApi) GetPost(rc *restfulx.ReqCtx) {
postId := restfulx.PathParamInt(rc, "postId")
p.PostApp.FindOne(int64(postId))
}
// InsertPost 添加职位
func (p *PostApi) InsertPost(rc *restfulx.ReqCtx) {
var post entity.SysPost
restfulx.BindJsonAndValid(rc, &post)
post.CreateBy = rc.LoginAccount.UserName
p.PostApp.Insert(post)
}
// UpdatePost 修改职位
func (p *PostApi) UpdatePost(rc *restfulx.ReqCtx) {
var post entity.SysPost
restfulx.BindJsonAndValid(rc, &post)
post.CreateBy = rc.LoginAccount.UserName
p.PostApp.Update(post)
}
// DeletePost 删除职位
func (p *PostApi) DeletePost(rc *restfulx.ReqCtx) {
postId := restfulx.PathParam(rc, "postId")
postIds := utils.IdsStrToIdsIntGroup(postId)
deList := make([]int64, 0)
for _, id := range postIds {
user := entity.SysUser{}
user.PostId = id
list := p.UserApp.FindList(user)
if len(*list) == 0 {
deList = append(deList, id)
} else {
global.Log.Info(fmt.Sprintf("dictId: %d 存在岗位绑定用户无法删除", id))
}
}
if len(deList) == 0 {
biz.ErrIsNil(errors.New("所有岗位都已绑定用户,无法删除"), "所有岗位都已绑定用户,无法删除")
}
p.PostApp.Delete(deList)
}

168
apps/system/api/role.go Normal file
View File

@@ -0,0 +1,168 @@
package api
import (
"errors"
"fmt"
entity "pandax/apps/system/entity"
services "pandax/apps/system/services"
"pandax/kit/biz"
"pandax/kit/casbin"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
"pandax/pkg/global"
)
type RoleApi struct {
RoleApp services.SysRoleModel
UserApp services.SysUserModel
RoleMenuApp services.SysRoleMenuModel
OrganizationApp services.SysOrganizationModel
RoleOrganizationApp services.SysRoleOrganizationModel
}
// GetRoleList角色列表数据
func (r *RoleApi) GetRoleList(rc *restfulx.ReqCtx) {
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
status := restfulx.QueryParam(rc, "status")
roleName := restfulx.QueryParam(rc, "roleName")
roleKey := restfulx.QueryParam(rc, "roleKey")
role := entity.SysRole{Status: status, RoleName: roleName, RoleKey: roleKey}
list, total := r.RoleApp.FindListPage(pageNum, pageSize, role)
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
// GetRole 获取Role数据
func (r *RoleApi) GetRole(rc *restfulx.ReqCtx) {
roleId := restfulx.PathParamInt(rc, "roleId")
role := r.RoleApp.FindOne(int64(roleId))
role.MenuIds = r.RoleApp.GetRoleMeunId(entity.SysRole{RoleId: int64(roleId)})
rc.ResData = role
}
// InsertRole 创建角色
func (r *RoleApi) InsertRole(rc *restfulx.ReqCtx) {
var role entity.SysRole
restfulx.BindJsonAndValid(rc, &role)
role.CreateBy = rc.LoginAccount.UserName
if role.DataScope == "" {
role.DataScope = "0"
}
// 添加角色对应的菜单
insert := r.RoleApp.Insert(role)
role.RoleId = insert.RoleId
r.RoleMenuApp.Insert(insert.RoleId, role.MenuIds)
//添加权限
ca := casbin.CasbinService{ModelPath: global.Conf.Casbin.ModelPath}
ca.UpdateCasbin(role.RoleKey, role.ApiIds)
}
// UpdateRole 修改用户角色
func (r *RoleApi) UpdateRole(rc *restfulx.ReqCtx) {
var role entity.SysRole
restfulx.BindJsonAndValid(rc, &role)
role.UpdateBy = rc.LoginAccount.UserName
// 修改角色
r.RoleApp.Update(role)
// 删除角色的菜单绑定
r.RoleMenuApp.DeleteRoleMenu(role.RoleId)
// 添加角色菜单绑定
r.RoleMenuApp.Insert(role.RoleId, role.MenuIds)
//修改api权限
ca := casbin.CasbinService{ModelPath: global.Conf.Casbin.ModelPath}
ca.UpdateCasbin(role.RoleKey, role.ApiIds)
}
// UpdateRoleStatus 修改用户角色状态
func (r *RoleApi) UpdateRoleStatus(rc *restfulx.ReqCtx) {
var role entity.SysRole
restfulx.BindJsonAndValid(rc, &role)
role.UpdateBy = rc.LoginAccount.UserName
// 修改角色
r.RoleApp.Update(role)
}
// UpdateRoleDataScope 修改用户角色组织
func (r *RoleApi) UpdateRoleDataScope(rc *restfulx.ReqCtx) {
var role entity.SysRole
restfulx.BindJsonAndValid(rc, &role)
role.UpdateBy = rc.LoginAccount.UserName
// 修改角色
update := r.RoleApp.Update(role)
go func() {
if role.DataScope != entity.SELFDATASCOPE {
organizationIds := make([]int64, 0)
if role.DataScope == entity.ALLDATASCOPE {
for _, organization := range *r.OrganizationApp.FindList(entity.SysOrganization{}) {
organizationIds = append(organizationIds, organization.OrganizationId)
}
}
if role.DataScope == entity.DIYDATASCOPE {
organizationIds = role.OrganizationIds
}
if role.DataScope == entity.ORGDATASCOPE {
organizationIds = append(organizationIds, rc.LoginAccount.OrganizationId)
}
if role.DataScope == entity.ORGALLDATASCOPE {
//organizationIds = append(organizationIds, rc.LoginAccount.OrganizationId)
organizationIds = r.OrganizationApp.SelectOrganizationIds(entity.SysOrganization{OrganizationId: rc.LoginAccount.OrganizationId})
}
// 删除角色的组织绑定
r.RoleOrganizationApp.Delete(entity.SysRoleOrganization{RoleId: update.RoleId})
// 添加角色组织绑定
r.RoleOrganizationApp.Insert(role.RoleId, organizationIds)
}
}()
}
// DeleteRole 删除用户角色
func (r *RoleApi) DeleteRole(rc *restfulx.ReqCtx) {
roleId := restfulx.PathParam(rc, "roleId")
roleIds := utils.IdsStrToIdsIntGroup(roleId)
user := entity.SysUser{}
delList := make([]int64, 0)
// 判断角色下面是否绑定用户
for _, rid := range roleIds {
user.RoleId = rid
role := r.RoleApp.FindOne(rid)
list := r.UserApp.FindList(user)
if len(*list) == 0 {
delList = append(delList, rid)
//删除角色绑定api
ca := casbin.CasbinService{ModelPath: global.Conf.Casbin.ModelPath}
ca.ClearCasbin(0, role.RoleKey)
} else {
global.Log.Info(fmt.Sprintf("role:%d 存在用户无法删除", rid))
}
}
if len(delList) == 0 {
biz.ErrIsNil(errors.New("所有角色都已绑定用户无法删除"), "所有角色都已绑定用户,无法删除")
}
r.RoleApp.Delete(delList)
r.RoleMenuApp.DeleteRoleMenus(delList)
}
// ExportRole 导出角色
func (p *RoleApi) ExportRole(rc *restfulx.ReqCtx) {
filename := restfulx.QueryParam(rc, "filename")
status := restfulx.QueryParam(rc, "status")
roleName := restfulx.QueryParam(rc, "roleName")
roleKey := restfulx.QueryParam(rc, "roleKey")
role := entity.SysRole{Status: status, RoleName: roleName, RoleKey: roleKey}
list := p.RoleApp.FindList(role)
fileName := utils.GetFileName(global.Conf.Server.ExcelDir, filename)
utils.InterfaceToExcel(*list, fileName)
rc.Download(fileName)
}

83
apps/system/api/system.go Normal file
View File

@@ -0,0 +1,83 @@
package api
import (
"fmt"
"pandax/kit/biz"
"pandax/kit/restfulx"
"pandax/kit/ws"
"pandax/pkg/middleware"
"runtime"
"github.com/emicklei/go-restful/v3"
"github.com/gorilla/websocket"
"github.com/kakuilan/kgo"
)
type System struct{}
const (
B = 1
KB = 1024 * B
MB = 1024 * KB
GB = 1024 * MB
)
func (s *System) ServerInfo(request *restful.Request, response *restful.Response) {
osDic := make(map[string]any, 0)
osDic["goOs"] = runtime.GOOS
osDic["arch"] = runtime.GOARCH
osDic["mem"] = runtime.MemProfileRate
osDic["compiler"] = runtime.Compiler
osDic["version"] = runtime.Version()
osDic["numGoroutine"] = runtime.NumGoroutine()
info := kgo.KOS.GetSystemInfo()
diskDic := make(map[string]any, 0)
diskDic["total"] = info.DiskTotal / GB
diskDic["free"] = info.DiskFree / GB
diskDic["used"] = info.DiskUsed / GB
diskDic["progress"] = fmt.Sprintf("%.2f", (float64(info.DiskUsed)/float64(info.DiskTotal))*100)
memDic := make(map[string]any, 0)
memDic["total"] = info.MemTotal / GB
memDic["used"] = info.MemUsed / GB
memDic["free"] = info.MemFree / GB
memDic["progress"] = fmt.Sprintf("%.2f", (float64(info.MemUsed)/float64(info.MemTotal))*100)
cpuDic := make(map[string]any, 0)
cpuDic["num"] = info.CpuNum
cpuDic["used"] = fmt.Sprintf("%.2f", info.CpuUser*100)
cpuDic["free"] = fmt.Sprintf("%.2f", info.CpuFree*100)
response.WriteEntity(map[string]any{
"code": 200,
"os": osDic,
"mem": memDic,
"cpu": cpuDic,
"disk": diskDic,
})
}
// ConnectWs 连接websocket
func (s *System) ConnectWs(request *restful.Request, response *restful.Response) {
wsConn, err := ws.Upgrader.Upgrade(response, request.Request, nil)
defer func() {
if err := recover(); &err != nil {
wsConn.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("websocket 失败: %v", err)))
wsConn.Close()
}
}()
if err != nil {
panic(any(biz.NewBizErr("升级websocket失败")))
}
// 权限校验
rc := restfulx.NewReqCtx(request, response)
if err = middleware.PermissionHandler(rc); err != nil {
panic(any(biz.NewBizErr("没有权限")))
}
// 登录账号信息
la := rc.LoginAccount
ws.Put(uint64(la.UserId), wsConn)
}

74
apps/system/api/tenant.go Normal file
View File

@@ -0,0 +1,74 @@
package api
/**
* @Description
* @Author 熊猫
* @Date 2022/7/14 17:55
**/
import (
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/model"
"pandax/kit/restfulx"
"pandax/kit/utils"
)
type SysTenantsApi struct {
SysTenantsApp services.SysTenantsModel
}
func (p *SysTenantsApi) GetSysTenantsList(rc *restfulx.ReqCtx) {
data := entity.SysTenants{}
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
list, total := p.SysTenantsApp.FindListPage(pageNum, pageSize, data)
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
func (p *SysTenantsApi) GetSysTenantsAll(rc *restfulx.ReqCtx) {
list := make([]entity.SysTenants, 0)
if rc.LoginAccount.RoleKey == "admin" {
data := entity.SysTenants{}
list = *p.SysTenantsApp.FindList(data)
} else {
list = append(list, *p.SysTenantsApp.FindOne(rc.LoginAccount.TenantId))
}
rc.ResData = list
}
func (p *SysTenantsApi) GetSysTenants(rc *restfulx.ReqCtx) {
tenantId := restfulx.PathParamInt(rc, "tenantId")
p.SysTenantsApp.FindOne(int64(tenantId))
}
func (p *SysTenantsApi) InsertSysTenants(rc *restfulx.ReqCtx) {
var data entity.SysTenants
restfulx.BindQuery(rc, &data)
p.SysTenantsApp.Insert(data)
}
func (p *SysTenantsApi) UpdateSysTenants(rc *restfulx.ReqCtx) {
var data entity.SysTenants
restfulx.BindQuery(rc, &data)
p.SysTenantsApp.Update(data)
}
func (p *SysTenantsApi) DeleteSysTenants(rc *restfulx.ReqCtx) {
tenantId := rc.Request.PathParameter("tenantId")
tenantIds := utils.IdsStrToIdsIntGroup(tenantId)
p.SysTenantsApp.Delete(tenantIds)
}
// IsTenantAdmin 是否为主租户
func IsTenantAdmin(tenantId int64) bool {
return tenantId == 1
}

430
apps/system/api/user.go Normal file
View File

@@ -0,0 +1,430 @@
package api
import (
"fmt"
"pandax/apps/system/api/form"
"pandax/apps/system/api/vo"
"pandax/apps/system/entity"
"pandax/kit/model"
"pandax/kit/token"
"github.com/dgrijalva/jwt-go"
"github.com/emicklei/go-restful/v3"
"github.com/kakuilan/kgo"
"github.com/mssola/user_agent"
logEntity "pandax/apps/log/entity"
logServices "pandax/apps/log/services"
"pandax/apps/system/services"
"pandax/kit/biz"
"pandax/kit/captcha"
filek "pandax/kit/file"
"pandax/kit/restfulx"
"pandax/kit/utils"
"pandax/pkg/global"
"strings"
"time"
)
type UserApi struct {
UserApp services.SysUserModel
MenuApp services.SysMenuModel
PostApp services.SysPostModel
RoleApp services.SysRoleModel
RoleMenuApp services.SysRoleMenuModel
OrganizationApp services.SysOrganizationModel
LogLogin logServices.LogLoginModel
}
// GenerateCaptcha 获取验证码
func (u *UserApi) GenerateCaptcha(request *restful.Request, response *restful.Response) {
id, image, _ := captcha.Generate()
response.WriteEntity(vo.CaptchaVo{Base64Captcha: image, CaptchaId: id})
}
// RefreshToken 刷新token
func (u *UserApi) RefreshToken(rc *restfulx.ReqCtx) {
tokenStr := rc.Request.Request.Header.Get("X-TOKEN")
// 如果token为空从请求参数中获取
if tokenStr == "" {
tokenStr = rc.Request.Request.URL.Query().Get("token")
}
j := token.NewJWT("", []byte(global.Conf.Jwt.Key), jwt.SigningMethodHS256)
token, err := j.RefreshToken(tokenStr)
if err != nil {
fmt.Printf("刷新Token失败: %s\n", err.Error())
return
}
rc.ResData = vo.TokenVo{
Token: token,
Expire: time.Now().Unix() + global.Conf.Jwt.ExpireTime,
}
}
// Login 用户登录
func (u *UserApi) Login(rc *restfulx.ReqCtx) {
var l form.Login
restfulx.BindJsonAndValid(rc, &l)
if captcha.Verify(l.CaptchaId, l.Captcha) {
fmt.Println("验证码认证失败")
return
}
login := u.UserApp.Login(entity.Login{Username: l.Username, Password: l.Password})
role := u.RoleApp.FindOne(login.RoleId)
j := token.NewJWT("", []byte(global.Conf.Jwt.Key), jwt.SigningMethodHS256)
token, err := j.CreateToken(token.Claims{
UserId: login.UserId,
UserName: login.Username,
RoleId: login.RoleId,
RoleKey: role.RoleKey,
OrganizationId: login.OrganizationId,
PostId: login.PostId,
StandardClaims: jwt.StandardClaims{
NotBefore: time.Now().Unix() - 1000, // 签名生效时间
ExpiresAt: time.Now().Unix() + global.Conf.Jwt.ExpireTime, // 过期时间 7天 配置文件
Issuer: global.Conf.Jwt.Key, // 签名的发行者
},
})
if err != nil {
fmt.Printf("生成Token失败: %s\n", err.Error())
return
}
rc.ResData = vo.TokenVo{
Token: token,
Expire: time.Now().Unix() + global.Conf.Jwt.ExpireTime,
}
go func() {
var loginLog logEntity.LogLogin
ua := user_agent.New(rc.Request.Request.UserAgent())
loginLog.Ipaddr = rc.Request.Request.RemoteAddr
loginLog.LoginLocation = utils.GetRealAddressByIP(strings.Split(rc.Request.Request.RemoteAddr, ":")[0])
loginLog.LoginTime = time.Now()
loginLog.Status = "0"
loginLog.Remark = rc.Request.Request.UserAgent()
browserName, browserVersion := ua.Browser()
loginLog.Browser = browserName + " " + browserVersion
loginLog.Os = ua.OS()
loginLog.Platform = ua.Platform()
loginLog.Username = login.Username
loginLog.Msg = "登录成功"
loginLog.CreateBy = login.Username
u.LogLogin.Insert(loginLog)
}()
}
// GetToken 用户登录
func (u *UserApi) GetToken(rc *restfulx.ReqCtx) {
var l form.Login
restfulx.BindJsonAndValid(rc, &l)
login := u.UserApp.Login(entity.Login{Username: l.Username, Password: l.Password})
role := u.RoleApp.FindOne(login.RoleId)
j := token.NewJWT("", []byte(global.Conf.Jwt.Key), jwt.SigningMethodHS256)
token, err := j.CreateToken(token.Claims{
UserId: login.UserId,
UserName: login.Username,
RoleId: login.RoleId,
RoleKey: role.RoleKey,
OrganizationId: login.OrganizationId,
PostId: login.PostId,
StandardClaims: jwt.StandardClaims{
NotBefore: time.Now().Unix() - 1000, // 签名生效时间
ExpiresAt: time.Now().Unix() + global.Conf.Jwt.ExpireTime, // 过期时间 7天 配置文件
Issuer: global.Conf.Jwt.Key, // 签名的发行者
},
})
if err != nil {
fmt.Printf("生成Token失败: %s\n", err.Error())
return
}
rc.ResData = vo.TokenVo{
Token: token,
Expire: time.Now().Unix() + global.Conf.Jwt.ExpireTime,
}
go func() {
var loginLog logEntity.LogLogin
ua := user_agent.New(rc.Request.Request.UserAgent())
loginLog.Ipaddr = rc.Request.Request.RemoteAddr
loginLog.LoginLocation = utils.GetRealAddressByIP(strings.Split(rc.Request.Request.RemoteAddr, ":")[0])
loginLog.LoginTime = time.Now()
loginLog.Status = "0"
loginLog.Remark = rc.Request.Request.UserAgent()
browserName, browserVersion := ua.Browser()
loginLog.Browser = browserName + " " + browserVersion
loginLog.Os = ua.OS()
loginLog.Platform = ua.Platform()
loginLog.Username = login.Username
loginLog.Msg = "登录成功"
loginLog.CreateBy = login.Username
u.LogLogin.Insert(loginLog)
}()
}
// Auth 用户权限信息
func (u *UserApi) Auth(rc *restfulx.ReqCtx) {
userName := restfulx.QueryParam(rc, "username")
if userName == "" {
fmt.Println("用户名不能为空")
return
}
var user entity.SysUser
user.Username = userName
userData := u.UserApp.FindOne(user)
role := u.RoleApp.FindOne(userData.RoleId)
//前端权限
permis := u.RoleMenuApp.GetPermis(role.RoleId)
menus := u.MenuApp.SelectMenuRole(role.RoleKey)
rc.ResData = vo.AuthVo{
User: *userData,
Role: *role,
Permissions: permis,
Menus: Build(*menus),
}
}
// LogOut 退出登录
func (u *UserApi) LogOut(rc *restfulx.ReqCtx) {
var loginLog logEntity.LogLogin
ua := user_agent.New(rc.Request.Request.UserAgent())
loginLog.Ipaddr = rc.Request.Request.RemoteAddr
loginLog.LoginTime = time.Now()
loginLog.Status = "0"
loginLog.Remark = rc.Request.Request.UserAgent()
browserName, browserVersion := ua.Browser()
loginLog.Browser = browserName + " " + browserVersion
loginLog.Os = ua.OS()
loginLog.Platform = ua.Platform()
loginLog.Username = rc.LoginAccount.UserName
loginLog.Msg = "退出成功"
u.LogLogin.Insert(loginLog)
}
// GetSysUserList 列表数据
func (u *UserApi) GetSysUserList(rc *restfulx.ReqCtx) {
pageNum := restfulx.QueryInt(rc, "pageNum", 1)
pageSize := restfulx.QueryInt(rc, "pageSize", 10)
status := restfulx.QueryParam(rc, "status")
username := restfulx.QueryParam(rc, "username")
phone := restfulx.QueryParam(rc, "phone")
organizationId := restfulx.QueryInt(rc, "organizationId", 0)
var user entity.SysUser
user.Status = status
user.Username = username
user.Phone = phone
user.OrganizationId = int64(organizationId)
list, total := u.UserApp.FindListPage(pageNum, pageSize, user)
rc.ResData = model.ResultPage{
Total: total,
PageNum: int64(pageNum),
PageSize: int64(pageSize),
Data: list,
}
}
// GetSysUserProfile 获取当前登录用户
func (u *UserApi) GetSysUserProfile(rc *restfulx.ReqCtx) {
sysUser := entity.SysUser{}
sysUser.UserId = rc.LoginAccount.UserId
user := u.UserApp.FindOne(sysUser)
//获取角色列表
roleList := u.RoleApp.FindList(entity.SysRole{RoleId: rc.LoginAccount.RoleId})
//岗位列表
postList := u.PostApp.FindList(entity.SysPost{PostId: rc.LoginAccount.PostId})
//获取组织列表
organizationList := u.OrganizationApp.FindList(entity.SysOrganization{OrganizationId: rc.LoginAccount.OrganizationId})
postIds := make([]int64, 0)
postIds = append(postIds, rc.LoginAccount.PostId)
roleIds := make([]int64, 0)
roleIds = append(roleIds, rc.LoginAccount.RoleId)
rc.ResData = vo.UserProfileVo{
Data: user,
PostIds: postIds,
RoleIds: roleIds,
Roles: *roleList,
Posts: *postList,
Organization: *organizationList,
}
}
// InsetSysUserAvatar 修改头像
func (u *UserApi) InsetSysUserAvatar(rc *restfulx.ReqCtx) {
form := rc.Request.Request.MultipartForm
files := form.File["upload[]"]
guid, _ := kgo.KStr.UuidV4()
filPath := "static/uploadfile/" + guid + ".jpg"
for _, file := range files {
global.Log.Info(file.Filename)
// 上传文件至指定目录
biz.ErrIsNil(filek.SaveUploadedFile(file, filPath), "保存头像失败")
}
sysuser := entity.SysUser{}
sysuser.UserId = rc.LoginAccount.UserId
sysuser.Avatar = "/" + filPath
sysuser.UpdateBy = rc.LoginAccount.UserName
u.UserApp.Update(sysuser)
}
// SysUserUpdatePwd 修改密码
func (u *UserApi) SysUserUpdatePwd(rc *restfulx.ReqCtx) {
var pws entity.SysUserPwd
restfulx.BindJsonAndValid(rc, &pws)
user := entity.SysUser{}
user.UserId = rc.LoginAccount.UserId
u.UserApp.SetPwd(user, pws)
}
// GetSysUser 获取用户
func (u *UserApi) GetSysUser(rc *restfulx.ReqCtx) {
userId := restfulx.PathParamInt(rc, "userId")
user := entity.SysUser{}
user.UserId = int64(userId)
result := u.UserApp.FindOne(user)
var role entity.SysRole
var post entity.SysPost
var organization entity.SysOrganization
rc.ResData = vo.UserVo{
Data: result,
PostIds: result.PostIds,
RoleIds: result.RoleIds,
Roles: *u.RoleApp.FindList(role),
Posts: *u.PostApp.FindList(post),
Organizations: u.OrganizationApp.SelectOrganization(organization),
}
}
// GetSysUserInit 获取添加用户角色和职位
func (u *UserApi) GetSysUserInit(rc *restfulx.ReqCtx) {
var role entity.SysRole
roles := u.RoleApp.FindList(role)
var post entity.SysPost
posts := u.PostApp.FindList(post)
rc.ResData = vo.UserRolePost{
Roles: *roles,
Posts: *posts,
}
}
// GetUserRolePost 获取添加用户角色和职位
func (u *UserApi) GetUserRolePost(rc *restfulx.ReqCtx) {
var user entity.SysUser
user.UserId = rc.LoginAccount.UserId
resData := u.UserApp.FindOne(user)
roles := make([]entity.SysRole, 0)
posts := make([]entity.SysPost, 0)
for _, roleId := range strings.Split(resData.RoleIds, ",") {
ro := u.RoleApp.FindOne(kgo.KConv.Str2Int64(roleId))
roles = append(roles, *ro)
}
for _, postId := range strings.Split(resData.PostIds, ",") {
po := u.PostApp.FindOne(kgo.KConv.Str2Int64(postId))
posts = append(posts, *po)
}
rc.ResData = vo.UserRolePost{
Roles: roles,
Posts: posts,
}
}
// InsertSysUser 创建用户
func (u *UserApi) InsertSysUser(rc *restfulx.ReqCtx) {
var sysUser entity.SysUser
restfulx.BindJsonAndValid(rc, &sysUser)
sysUser.CreateBy = rc.LoginAccount.UserName
u.UserApp.Insert(sysUser)
}
// UpdateSysUser 修改用户数据
func (u *UserApi) UpdateSysUser(rc *restfulx.ReqCtx) {
var sysUser entity.SysUser
restfulx.BindJsonAndValid(rc, &sysUser)
sysUser.CreateBy = rc.LoginAccount.UserName
u.UserApp.Update(sysUser)
}
// UpdateSysUserStu 修改用户状态
func (u *UserApi) UpdateSysUserStu(rc *restfulx.ReqCtx) {
var sysUser entity.SysUser
restfulx.BindJsonAndValid(rc, &sysUser)
sysUser.CreateBy = rc.LoginAccount.UserName
u.UserApp.Update(sysUser)
}
// DeleteSysUser 删除用户数据
func (u *UserApi) DeleteSysUser(rc *restfulx.ReqCtx) {
userIds := restfulx.PathParam(rc, "userId")
u.UserApp.Delete(utils.IdsStrToIdsIntGroup(userIds))
}
// ExportUser 导出用户
func (u *UserApi) ExportUser(rc *restfulx.ReqCtx) {
filename := restfulx.QueryParam(rc, "filename")
status := restfulx.QueryParam(rc, "status")
username := restfulx.QueryParam(rc, "username")
phone := restfulx.QueryParam(rc, "phone")
var user entity.SysUser
user.Status = status
user.Username = username
user.Phone = phone
list := u.UserApp.FindList(user)
fileName := utils.GetFileName(global.Conf.Server.ExcelDir, filename)
utils.InterfaceToExcel(*list, fileName)
rc.Download(fileName)
}
// Build 构建前端路由
func Build(menus []entity.SysMenu) []vo.RouterVo {
equals := func(a string, b string) bool {
return a == b
}
rvs := make([]vo.RouterVo, 0)
for _, ms := range menus {
var rv vo.RouterVo
rv.Name = ms.Path
rv.Path = ms.Path
rv.Component = ms.Component
auth := make([]string, 0)
if ms.Permission != "" {
auth = strings.Split(ms.Permission, ",")
}
rv.Meta = vo.MetaVo{
Title: ms.MenuName,
IsLink: ms.IsLink,
IsHide: equals("1", ms.IsHide),
IsKeepAlive: equals("0", ms.IsKeepAlive),
IsAffix: equals("0", ms.IsAffix),
IsIframe: equals("0", ms.IsIframe),
Auth: auth,
Icon: ms.Icon,
}
rv.Children = Build(ms.Children)
rvs = append(rvs, rv)
}
return rvs
}

View File

@@ -0,0 +1,25 @@
package vo
/**s
* 路由meta对象参数说明
* meta: {
* title: 菜单栏及 tagsView 栏、菜单搜索名称
* isLink 是否超链接菜单,开启外链条件,`1、isLink:true 2、链接地址不为空`
* isHide 是否隐藏此路由
* isKeepAlive 是否缓存组件状态
* isAffix 是否固定在 tagsView 栏上
* isFrame 是否内嵌窗口,,开启条件,`1、isFrame:true 2、链接地址不为空`
* auth 当前路由权限标识(多个请用逗号隔开),最后转成数组格式,用于与当前用户权限进行对比,控制路由显示、隐藏
* icon 菜单、tagsView 图标,阿里:加 `iconfont xxx`fontawesome加 `fa xxx`
* }
*/
type MetaVo struct {
Title string `json:"title"`
IsLink string `json:"isLink"`
IsHide bool `json:"isHide"`
IsKeepAlive bool `json:"isKeepAlive"`
IsAffix bool `json:"isAffix"`
IsIframe bool `json:"isIframe"`
Auth []string `json:"auth"`
Icon string `json:"icon"`
}

View File

@@ -0,0 +1,31 @@
package vo
/**
* 路由对象参数说明
* {
* component: 组件地址
* redirect: 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
* path: 路由地址
* name: 路由名字
* // 路由meta对象参数说明
* meta: {
* title: 菜单栏及 tagsView 栏、菜单搜索名称(国际化)
* isLink 是否超链接菜单,开启外链条件,`1、isLink:true 2、链接地址不为空`
* isHide 是否隐藏此路由
* isKeepAlive 是否缓存组件状态
* isAffix 是否固定在 tagsView 栏上
* isFrame 是否内嵌窗口,,开启条件,`1、isIframe:true 2、链接地址不为空`
* auth 当前路由权限标识(多个请用逗号隔开),最后转成数组格式,用于与当前用户权限进行对比,控制路由显示、隐藏
* icon 菜单、tagsView 图标,阿里:加 `iconfont xxx`fontawesome加 `fa xxx`
* }
* }
*
*/
type RouterVo struct {
Name string `json:"name"`
Path string `json:"path"`
Redirect string `json:"redirect"`
Component string `json:"component"`
Meta MetaVo `json:"meta"`
Children []RouterVo `json:"children"`
}

View File

@@ -0,0 +1,64 @@
package vo
import "pandax/apps/system/entity"
/**
* @Description
* @Author 熊猫
* @Date 2022/8/4 15:25
**/
type OrganizationTreeVo struct {
Organizations []entity.OrganizationLable `json:"organizations"`
CheckedKeys []int64 `json:"checkedKeys"`
}
type MenuTreeVo struct {
Menus []entity.MenuLable `json:"menus"`
CheckedKeys []int64 `json:"checkedKeys"`
}
type MenuPermisVo struct {
Menus []RouterVo `json:"menus"`
Permissions []string `json:"permissions"`
}
type CaptchaVo struct {
Base64Captcha string `json:"base64Captcha"`
CaptchaId string `json:"captchaId"`
}
type TokenVo struct {
Token string `json:"token"`
Expire int64 `json:"expire"`
}
type AuthVo struct {
User entity.SysUserView `json:"user"`
Role entity.SysRole `json:"role"`
Permissions []string `json:"permissions"`
Menus []RouterVo `json:"menus"`
}
type UserProfileVo struct {
Data any `json:"data"`
PostIds []int64 `json:"postIds"`
RoleIds []int64 `json:"roleIds"`
Roles []entity.SysRole `json:"roles"`
Posts []entity.SysPost `json:"posts"`
Organization []entity.SysOrganization `json:"organization"`
}
type UserVo struct {
Data any `json:"data"`
PostIds string `json:"postIds"`
RoleIds string `json:"roleIds"`
Roles []entity.SysRole `json:"roles"`
Posts []entity.SysPost `json:"posts"`
Organizations []entity.SysOrganization `json:"organizations"`
}
type UserRolePost struct {
Roles []entity.SysRole `json:"roles"`
Posts []entity.SysPost `json:"posts"`
}

11
apps/system/entity/api.go Normal file
View File

@@ -0,0 +1,11 @@
package entity
import "pandax/kit/model"
type SysApi struct {
model.BaseAutoModel
Path string `json:"path" gorm:"comment:api路径" binding:"required"` // api路径
Description string `json:"description" gorm:"comment:api中文描述"` // api中文描述
ApiGroup string `json:"apiGroup" gorm:"comment:api组"` // api组
Method string `json:"method" gorm:"comment:方法"` // 方法:创建POST(默认)|查看GET|更新PUT|删除DELETE
}

View File

@@ -0,0 +1,14 @@
package entity
import "pandax/kit/model"
type SysConfig struct {
ConfigId int64 `json:"configId" gorm:"primaryKey;AUTO_INCREMENT;comment:主键编码"`
ConfigName string `json:"configName" gorm:"type:varchar(128);comment:ConfigName"`
ConfigKey string `json:"configKey" gorm:"type:varchar(128);comment:ConfigKey"`
ConfigValue string `json:"configValue" gorm:"type:varchar(255);comment:ConfigValue"`
ConfigType string `json:"configType" gorm:"type:varchar(64);comment:是否系统内置01"`
IsFrontend string `json:"isFrontend" gorm:"type:varchar(1);comment:是否前台"`
Remark string `json:"remark" gorm:"type:varchar(128);comment:Remark"`
model.BaseModel
}

View File

@@ -0,0 +1,30 @@
package entity
import "pandax/kit/model"
type SysDictData struct {
DictCode int64 `json:"dictCode" gorm:"primary_key;AUTO_INCREMENT"`
DictSort int `json:"dictSort" gorm:"type:int;comment:排序"`
DictLabel string `json:"dictLabel" gorm:"type:varchar(64);comment:标签"`
DictValue string `json:"dictValue" gorm:"type:varchar(64);comment:值"`
DictType string `json:"dictType" gorm:"type:varchar(64);comment:字典类型"`
Status string `json:"status" gorm:"type:varchar(1);comment:状态0正常 1停用"`
CssClass string `json:"cssClass" gorm:"type:varchar(128);comment:CssClass"`
ListClass string `json:"listClass" gorm:"type:varchar(128);comment:ListClass"`
IsDefault string `json:"isDefault" gorm:"type:varchar(8);comment:IsDefault"`
CreateBy string `json:"createBy"`
UpdateBy string `json:"updateBy"`
Remark string `json:"remark" gorm:"type:varchar(256);comment:备注"`
model.BaseModel
}
type SysDictType struct {
DictId int64 `json:"dictId" gorm:"primary_key;AUTO_INCREMENT"`
DictName string `json:"dictName" gorm:"type:varchar(64);comment:名称"`
DictType string `json:"dictType" gorm:"type:varchar(64);comment:类型"`
Status string `json:"status" gorm:"type:varchar(1);comment:状态"`
CreateBy string `json:"createBy"`
UpdateBy string `json:"updateBy"`
Remark string `json:"remark" gorm:"type:varchar(256);comment:备注"`
model.BaseModel
}

View File

@@ -0,0 +1,38 @@
package entity
import "pandax/kit/model"
type SysMenu struct {
MenuId int64 `json:"menuId" gorm:"primary_key;AUTO_INCREMENT"`
MenuName string `json:"menuName" gorm:"type:varchar(128);"`
Title string `json:"title" gorm:"type:varchar(64);"`
ParentId int64 `json:"parentId" gorm:"type:int;"`
Sort int64 `json:"sort" gorm:"type:int;"`
Icon string `json:"icon" gorm:"type:varchar(128);"`
Path string `json:"path" gorm:"type:varchar(128);"`
Component string `json:"component" gorm:"type:varchar(255);"` // 组件路径
IsIframe string `json:"isIframe" gorm:"type:varchar(1);"` //是否为内嵌
IsLink string `json:"isLink" gorm:"type:varchar(255);"` //是否超链接菜单
MenuType string `json:"menuType" gorm:"type:varchar(1);"` //菜单类型M目录 C菜单 F按钮
IsHide string `json:"isHide" gorm:"type:varchar(1);"` //显示状态0显示 1隐藏
IsKeepAlive string `json:"isKeepAlive" gorm:"type:varchar(1);"` //是否缓存组件状态0是 1否
IsAffix string `json:"isAffix" gorm:"type:varchar(1);"` //是否固定在 tagsView 栏上0是 1否
Permission string `json:"permission" gorm:"type:varchar(32);"` //权限标识
Status string `json:"status" gorm:"type:varchar(1);` // 菜单状态0正常 1停用
CreateBy string `json:"createBy" gorm:"type:varchar(128);"`
UpdateBy string `json:"updateBy" gorm:"type:varchar(128);"`
Remark string `json:"remark" gorm:"type:varchar(256);` // 备注
Children []SysMenu `json:"children" gorm:"-"`
model.BaseModel
}
type MenuLable struct {
MenuId int64 `json:"menuId" gorm:"-"`
MenuName string `json:"menuName" gorm:"-"`
Children []MenuLable `json:"children" gorm:"-"`
}
type MenuRole struct {
SysMenu
IsSelect bool `json:"is_select" gorm:"-"`
}

View File

@@ -0,0 +1,15 @@
package entity
import "pandax/kit/model"
type SysNotice struct {
NoticeId int64 `json:"noticeId" gorm:"primary_key;AUTO_INCREMENT"`
Title string `json:"title" gorm:"type:varchar(128);comment:标题"`
Content string `json:"content" gorm:"type:text;comment:标题"`
NoticeType string `json:"noticeType" gorm:"type:varchar(1);comment:通知类型"`
OrganizationId int64 `json:"organizationId" gorm:"type:int;comment:组织Id,组织及子组织"`
UserName string `json:"userName" gorm:"type:varchar(64);comment:发布人"`
OrganizationIds []int64 `json:"organizationIds" gorm:"-"`
model.BaseModel
}

View File

@@ -0,0 +1,26 @@
package entity
import "pandax/kit/model"
// 组织组织
type SysOrganization struct {
OrganizationId int64 `json:"organizationId" gorm:"primary_key;AUTO_INCREMENT"` //组织编码
ParentId int64 `json:"parentId" gorm:"type:int;comment:上级组织"`
OrganizationPath string `json:"organizationPath" gorm:"type:varchar(255);comment:组织路径"`
OrganizationName string `json:"organizationName" gorm:"type:varchar(128);comment:组织名称"`
Sort int64 `json:"sort" gorm:"type:int;comment:排序"`
Leader string `json:"leader" gorm:"type:varchar(64);comment:负责人"` // userId
Phone string `json:"phone" gorm:"type:varchar(11);comment:手机"`
Email string `json:"email" gorm:"type:varchar(64);comment:邮箱"`
Status string `json:"status" gorm:"type:varchar(1);comment:状态"`
CreateBy string `json:"createBy" gorm:"type:varchar(64);comment:创建人"`
UpdateBy string `json:"updateBy" gorm:"type:varchar(64);comment:修改人"`
Children []SysOrganization `json:"children" gorm:"-"`
model.BaseModel
}
type OrganizationLable struct {
OrganizationId int64 `gorm:"-" json:"organizationId"`
OrganizationName string `gorm:"-" json:"organizationName"`
Children []OrganizationLable `gorm:"-" json:"children"`
}

View File

@@ -0,0 +1,15 @@
package entity
import "pandax/kit/model"
type SysPost struct {
PostId int64 `gorm:"primary_key;AUTO_INCREMENT" json:"postId"`
PostName string `gorm:"type:varchar(128);comment:岗位名称" json:"postName"`
PostCode string `gorm:"type:varchar(128);comment:岗位代码" json:"postCode"`
Sort int64 `gorm:"type:int;comment:岗位排序" json:"sort"`
Status string `gorm:"type:varchar(1);comment:状态" json:"status"`
Remark string `gorm:"type:varchar(255);comment:描述" json:"remark"`
CreateBy string `gorm:"type:varchar(128);" json:"createBy"`
UpdateBy string `gorm:"type:varchar(128);" json:"updateBy"`
model.BaseModel
}

View File

@@ -0,0 +1,41 @@
package entity
import (
"pandax/kit/casbin"
"pandax/kit/model"
)
const (
SELFDATASCOPE = "0"
ALLDATASCOPE = "1"
DIYDATASCOPE = "2"
ORGDATASCOPE = "3"
ORGALLDATASCOPE = "4"
)
type SysRole struct {
model.BaseModel
RoleId int64 `json:"roleId" gorm:"primary_key;AUTO_INCREMENT"`
RoleName string `json:"roleName" gorm:"type:varchar(128);comment:角色名称"`
Status string `json:"status" gorm:"type:varchar(1);comment:状态"`
RoleKey string `json:"roleKey" gorm:"type:varchar(128);comment:角色代码"`
RoleSort int64 `json:"roleSort" gorm:"type:int;comment:角色排序"`
DataScope string `json:"dataScope" gorm:"type:varchar(1);comment:数据范围0: 本人数据 1全部数据权限 2自定数据权限 3本组织数据权限 4本组织及以下数据权限"`
CreateBy string `json:"createBy" gorm:"type:varchar(128);comment:创建人"`
UpdateBy string `json:"updateBy" gorm:"type:varchar(128);comment:修改人"`
Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
ApiIds []casbin.CasbinRule `json:"apiIds" gorm:"-"`
MenuIds []int64 `json:"menuIds" gorm:"-"`
OrganizationIds []int64 `json:"organizationIds" gorm:"-"`
}
type SysRoleAuth struct {
Org string `json:"org" gorm:"column:org"`
DataScope string `json:"dataScope"`
}
type MenuIdList struct {
MenuId int64 `json:"menuId"`
}
type OrganizationIdList struct {
OrganizationId int64 `json:"organizationId"`
}

View File

@@ -0,0 +1,12 @@
package entity
type SysRoleMenu struct {
RoleId int64 `gorm:"type:int"`
MenuId int64 `gorm:"type:int"`
RoleName string `gorm:"type:varchar(128)"`
Id int64 `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id" form:"id"`
}
type MenuPath struct {
Path string `json:"path"`
}

View File

@@ -0,0 +1,7 @@
package entity
type SysRoleOrganization struct {
RoleId int64 `gorm:"type:int"`
OrganizationId int64 `gorm:"type:int"`
Id int64 `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id" form:"id"`
}

View File

@@ -0,0 +1,23 @@
package entity
import (
"pandax/kit/model"
"time"
)
/**
* @Description
* @Author 熊猫
* @Date 2022/7/14 16:14
**/
type SysTenants struct {
model.BaseAutoModel
TenantName string `json:"tenantName" gorm:"type:varchar(255);comment:租户名"`
Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
ExpireTime time.Time `json:"expireTime" gorm:"comment:过期时间"`
}
func (SysTenants) TableName() string {
return "sys_tenants"
}

View File

@@ -0,0 +1,63 @@
package entity
import "pandax/kit/model"
type LoginM struct {
Username string `gorm:"type:varchar(64)" json:"username"`
Password string `gorm:"type:varchar(128)" json:"password"`
}
type SysUserId struct {
UserId int64 `gorm:"primary_key;AUTO_INCREMENT" json:"userId"` // 编码
}
type SysUserB struct {
NickName string `gorm:"type:varchar(128)" json:"nickName"` // 昵称
Phone string `gorm:"type:varchar(11)" json:"phone"` // 手机号
RoleId int64 `gorm:"type:int" json:"roleId"` // 角色编码
Salt string `gorm:"type:varchar(255)" json:"salt"` //盐
Avatar string `gorm:"type:varchar(255)" json:"avatar"` //头像
Sex string `gorm:"type:varchar(255)" json:"sex"` //性别
Email string `gorm:"type:varchar(128)" json:"email"` //邮箱
OrganizationId int64 `gorm:"type:int" json:"organizationId"` //组织编码
PostId int64 `gorm:"type:int" json:"postId"` //职位编码
RoleIds string `gorm:"type:varchar(255)" json:"roleIds"` //多角色
PostIds string `gorm:"type:varchar(255)" json:"postIds"` // 多岗位
CreateBy string `gorm:"type:varchar(128)" json:"createBy"` //
UpdateBy string `gorm:"type:varchar(128)" json:"updateBy"` //
Remark string `gorm:"type:varchar(255)" json:"remark"` //备注
Status string `gorm:"type:varchar(1);" json:"status"`
model.BaseModel
}
type SysUser struct {
SysUserId
SysUserB
LoginM
}
type SysUserPwd struct {
OldPassword string `json:"oldPassword" form:"oldPassword"`
NewPassword string `json:"newPassword" form:"newPassword"`
}
type SysUserPage struct {
SysUserId
SysUserB
LoginM
OrganizationName string `gorm:"-" json:"organizationName"`
}
type Login struct {
Username string `form:"username" json:"username" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
Code string `form:"code" json:"code" binding:"required"`
UUID string `form:"UUID" json:"uuid" binding:"required"`
}
type SysUserView struct {
SysUserId
SysUserB
LoginM
RoleName string `gorm:"column:role_name" json:"role_name"`
}

87
apps/system/router/api.go Normal file
View File

@@ -0,0 +1,87 @@
package router
import (
"pandax/apps/system/api"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/casbin"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitApiRouter(container *restful.Container) {
s := &api.SystemApiApi{
ApiApp: services.SysApiModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/api").Produces(restful.MIME_JSON)
tags := []string{"api"}
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取api分页列表").Handle(s.GetApiList)
}).
Doc("获取api分页列表").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Param(ws.QueryParameter("path", "路径").DataType("string")).
Param(ws.QueryParameter("description", "描述").DataType("string")).
Param(ws.QueryParameter("method", "方法").DataType("string")).
Param(ws.QueryParameter("apiGroup", "API组").DataType("string")).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/all").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取所有api").Handle(s.GetAllApis)
}).
Doc("获取所有api").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]entity.SysApi{}).
Returns(200, "OK", []entity.SysApi{}))
ws.Route(ws.GET("/getPolicyPathByRoleId").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取角色拥有的api权限").Handle(s.GetPolicyPathByRoleId)
}).
Doc("获取角色拥有的api权限").
Param(ws.QueryParameter("roleKey", "校色key").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]casbin.CasbinRule{}).
Returns(200, "OK", []casbin.CasbinRule{}))
ws.Route(ws.GET("/{id}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取api信息").Handle(s.GetApiById)
}).
Doc("获取api信息").
Param(ws.PathParameter("id", "Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(entity.SysApi{}). // on the response
Returns(200, "OK", entity.SysApi{}).
Returns(404, "Not Found", nil))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加api信息").Handle(s.CreateApi)
}).
Doc("添加api信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysApi{}))
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改api信息").Handle(s.UpdateApi)
}).
Doc("修改api信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysApi{})) // from the request
ws.Route(ws.DELETE("/{id}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除api信息").Handle(s.DeleteApi)
}).
Doc("删除api信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("id", "id").DataType("int")))
container.Add(ws)
}

View File

@@ -0,0 +1,79 @@
package router
import (
"pandax/apps/system/api"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitConfigRouter(container *restful.Container) {
s := &api.ConfigApi{
ConfigApp: services.SysSysConfigModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/config").Produces(restful.MIME_JSON)
tags := []string{"config"}
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取配置分页列表").Handle(s.GetConfigList)
}).
Doc("获取配置分页列表").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Param(ws.QueryParameter("configName", "configName").DataType("string")).
Param(ws.QueryParameter("configKey", "configKey").DataType("string")).
Param(ws.QueryParameter("configType", "configType").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/configKey").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取配置列表通过ConfigKey").Handle(s.GetConfigListByKey)
}).
Doc("获取配置列表通过ConfigKey").
Param(ws.QueryParameter("configKey", "configKey").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]entity.SysConfig{}).
Returns(200, "OK", []entity.SysConfig{}))
ws.Route(ws.GET("/{configId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取配置信息").Handle(s.GetConfig)
}).
Doc("获取配置信息").
Param(ws.PathParameter("configId", "configId").DataType("int")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(entity.SysConfig{}).
Returns(200, "OK", entity.SysConfig{}).
Returns(404, "Not Found", nil))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加配置信息").Handle(s.InsertConfig)
}).
Doc("添加配置信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysConfig{}))
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改配置信息").Handle(s.UpdateConfig)
}).
Doc("修改配置信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysConfig{})) // from the request
ws.Route(ws.DELETE("/{configId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除配置信息").Handle(s.DeleteConfig)
}).
Doc("删除配置信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("configId", "多id 1,2,3").DataType("string")))
container.Add(ws)
}

124
apps/system/router/dict.go Normal file
View File

@@ -0,0 +1,124 @@
package router
import (
"pandax/apps/system/api"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitDictRouter(container *restful.Container) {
s := &api.DictApi{
DictType: services.SysDictTypeModelDao,
DictData: services.SysDictDataModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/dict").Produces(restful.MIME_JSON)
tags := []string{"dict"}
ws.Route(ws.GET("/type/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取字典类型分页列表").Handle(s.GetDictTypeList)
}).
Doc("获取字典类型分页列表").
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Param(ws.QueryParameter("dictName", "dictName").DataType("string")).
Param(ws.QueryParameter("dictType", "dictType").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/type/{dictId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取字典类型信息").Handle(s.GetDictType)
}).
Doc("获取字典类型信息").
Param(ws.PathParameter("dictId", "Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", entity.SysDictType{}))
ws.Route(ws.POST("/type").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加字典类型信息").Handle(s.InsertDictType)
}).
Doc("添加字典类型信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysDictType{}))
ws.Route(ws.PUT("/type").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改字典类型信息").Handle(s.UpdateDictType)
}).
Doc("修改字典类型信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysDictType{}))
ws.Route(ws.DELETE("/type/{dictId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除字典类型信息").Handle(s.DeleteDictType)
}).
Doc("删除字典类型信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("dictId", "多id 1,2,3").DataType("string")))
ws.Route(ws.GET("/type/export").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("导出字典类型信息").Handle(s.ExportDictType)
}).
Doc("导出字典类型信息").
Param(ws.QueryParameter("filename", "filename").DataType("string")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Param(ws.QueryParameter("dictName", "dictName").DataType("string")).
Param(ws.QueryParameter("dictType", "dictType").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/data/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取字典数据分页列表").Handle(s.GetDictDataList)
}).
Doc("获取字典数据分页列表").
Param(ws.QueryParameter("dictLabel", "dictLabel").DataType("string")).
Param(ws.QueryParameter("dictType", "dictType").DataType("string")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", []entity.SysDictData{}))
ws.Route(ws.GET("/data/type").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取字典数据列表通过字典类型").Handle(s.GetDictDataListByDictType)
}).
Doc("获取字典数据列表通过字典类型").
Param(ws.QueryParameter("dictType", "dictType").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", []entity.SysDictData{}))
ws.Route(ws.GET("/data/{dictCode}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取字典数据信息").Handle(s.GetDictData)
}).
Doc("获取字典数据信息").
Param(ws.PathParameter("dictCode", "dictCode").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", entity.SysDictData{}))
ws.Route(ws.POST("/data").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加字典数据信息").Handle(s.InsertDictData)
}).
Doc("添加字典数据信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysDictData{}))
ws.Route(ws.PUT("/data").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改字典数据信息").Handle(s.UpdateDictData)
}).
Doc("修改字典数据信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysDictData{}))
ws.Route(ws.DELETE("data/{dictCode}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除字典数据信息").Handle(s.DeleteDictData)
}).
Doc("删除字典数据信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("dictCode", "多id 1,2,3").DataType("string")))
container.Add(ws)
}

103
apps/system/router/menu.go Normal file
View File

@@ -0,0 +1,103 @@
package router
import (
"pandax/apps/system/api"
"pandax/apps/system/api/vo"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitMenuRouter(container *restful.Container) {
s := &api.MenuApi{
MenuApp: services.SysMenuModelDao,
RoleApp: services.SysRoleModelDao,
RoleMenuApp: services.SysRoleMenuModelDao,
OrganizationApp: services.SysOrganizationModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/menu").Produces(restful.MIME_JSON)
tags := []string{"menu"}
ws.Route(ws.GET("/menuTreeSelect").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取菜单树").WithNeedToken(false).WithNeedCasbin(false).Handle(s.GetMenuTreeSelect)
}).
Doc("获取菜单树").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]entity.MenuLable{}).
Returns(200, "OK", []entity.MenuLable{}))
ws.Route(ws.GET("/menuRole").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取角色菜单").Handle(s.GetMenuRole)
}).
Doc("获取角色菜单").
Param(ws.QueryParameter("roleKey", "roleKey").Required(true).DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]vo.RouterVo{}).
Returns(200, "OK", []vo.RouterVo{}))
ws.Route(ws.GET("/roleMenuTreeSelect/{roleId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取角色菜单树").Handle(s.GetMenuTreeRoleSelect)
}).
Doc("获取角色菜单树").
Param(ws.PathParameter("roleId", "Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(vo.MenuTreeVo{}).
Returns(200, "OK", vo.MenuTreeVo{}).
Returns(404, "Not Found", nil))
ws.Route(ws.GET("/menuPaths").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取角色菜单路径列表").Handle(s.GetMenuPaths)
}).
Doc("获取角色菜单").
Param(ws.QueryParameter("roleKey", "roleKey").Required(true).DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]entity.MenuPath{}).
Returns(200, "OK", []entity.MenuPath{}))
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取菜单列表").Handle(s.GetMenuList)
}).
Doc("获取菜单列表").
Param(ws.QueryParameter("menuName", "menuName").DataType("string")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]entity.SysMenu{}).
Returns(200, "OK", []entity.SysMenu{}))
ws.Route(ws.GET("/{menuId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取菜单信息").Handle(s.GetMenu)
}).
Doc("获取菜单信息").
Param(ws.PathParameter("menuId", "Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(entity.SysMenu{}). // on the response
Returns(200, "OK", entity.SysMenu{}).
Returns(404, "Not Found", nil))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加菜单信息").Handle(s.InsertMenu)
}).
Doc("添加菜单信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysMenu{})) // from the request
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改菜单信息").Handle(s.UpdateMenu)
}).
Doc("修改菜单信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysMenu{})) // from the request
ws.Route(ws.DELETE("/{menuId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除菜单信息").Handle(s.DeleteMenu)
}).
Doc("删除SysTenant信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("menuId", "多id 1,2,3").DataType("string")))
container.Add(ws)
}

View File

@@ -0,0 +1,58 @@
package router
import (
"pandax/apps/system/api"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitNoticeRouter(container *restful.Container) {
s := &api.NoticeApi{
OrganizationApp: services.SysOrganizationModelDao,
NoticeApp: services.SysNoticeModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/notice").Produces(restful.MIME_JSON)
tags := []string{"notice"}
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取通知分页列表").Handle(s.GetNoticeList)
}).
Doc("获取通知分页列表").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Param(ws.QueryParameter("noticeType", "noticeType").DataType("string")).
Param(ws.QueryParameter("title", "title").DataType("string")).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加通知信息").Handle(s.InsertNotice)
}).
Doc("添加通知信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysNotice{}))
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改通知信息").Handle(s.UpdateNotice)
}).
Doc("修改通知信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysNotice{}))
ws.Route(ws.DELETE("/{noticeId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除通知信息").Handle(s.DeleteNotice)
}).
Doc("删除通知信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("noticeId", "多id 1,2,3").DataType("string")))
container.Add(ws)
}

View File

@@ -0,0 +1,91 @@
package router
import (
"pandax/apps/system/api"
"pandax/apps/system/api/vo"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitOrganizationRouter(container *restful.Container) {
s := &api.OrganizationApi{
OrganizationApp: services.SysOrganizationModelDao,
RoleApp: services.SysRoleModelDao,
UserApp: services.SysUserModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/organization").Produces(restful.MIME_JSON)
tags := []string{"organization"}
ws.Route(ws.GET("/roleOrganizationTreeSelect/{roleId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取角色组织树").Handle(s.GetOrganizationTreeRoleSelect)
}).
Doc("获取角色组织树").
Param(ws.PathParameter("roleId", "角色Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(vo.OrganizationTreeVo{}).
Returns(200, "OK", vo.OrganizationTreeVo{}).
Returns(404, "Not Found", nil))
ws.Route(ws.GET("/organizationTree").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取所有组织树").Handle(s.GetOrganizationTree)
}).
Doc("获取所有组织树").
Param(ws.QueryParameter("organizationName", "organizationName").DataType("string")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Param(ws.QueryParameter("organizationId", "organizationId").DataType("int")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]entity.SysOrganization{}).
Returns(200, "OK", []entity.SysOrganization{}).
Returns(404, "Not Found", nil))
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取组织列表").Handle(s.GetOrganizationList)
}).
Doc("获取组织列表").
Param(ws.QueryParameter("organizationName", "organizationName").DataType("string")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Param(ws.QueryParameter("organizationId", "organizationId").DataType("int")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]entity.SysOrganization{}).
Returns(200, "OK", []entity.SysOrganization{}))
ws.Route(ws.GET("/{organizationId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取组织信息").Handle(s.GetOrganization)
}).
Doc("获取组织信息").
Param(ws.PathParameter("organizationId", "组织Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(entity.SysOrganization{}). // on the response
Returns(200, "OK", entity.SysOrganization{}).
Returns(404, "Not Found", nil))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加组织信息").Handle(s.InsertOrganization)
}).
Doc("添加组织信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysOrganization{}))
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改组织信息").Handle(s.UpdateOrganization)
}).
Doc("修改组织信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysOrganization{}))
ws.Route(ws.DELETE("/{organizationId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除组织信息").Handle(s.DeleteOrganization)
}).
Doc("删除组织信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("organizationId", "多id 1,2,3").DataType("int")))
container.Add(ws)
}

View File

@@ -0,0 +1,69 @@
package router
import (
"pandax/apps/system/api"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitPostRouter(container *restful.Container) {
s := &api.PostApi{
PostApp: services.SysPostModelDao,
UserApp: services.SysUserModelDao,
RoleApp: services.SysRoleModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/post").Produces(restful.MIME_JSON)
tags := []string{"post"}
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取岗位分页列表").Handle(s.GetPostList)
}).
Doc("获取岗位分页列表").
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Param(ws.QueryParameter("postName", "postName").DataType("string")).
Param(ws.QueryParameter("postCode", "postCode").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/{postId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取岗位信息").Handle(s.GetPost)
}).
Doc("获取岗位信息").
Param(ws.PathParameter("postId", "Id").DataType("int")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(entity.SysPost{}).
Returns(200, "OK", entity.SysPost{}).
Returns(404, "Not Found", nil))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加岗位信息").Handle(s.InsertPost)
}).
Doc("添加岗位信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysPost{}))
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改岗位信息").Handle(s.UpdatePost)
}).
Doc("修改岗位信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysPost{}))
ws.Route(ws.DELETE("/{postId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除岗位信息").Handle(s.DeletePost)
}).
Doc("删除岗位信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("postId", "多id 1,2,3").DataType("string")))
container.Add(ws)
}

View File

@@ -0,0 +1,95 @@
package router
import (
"pandax/apps/system/api"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitRoleRouter(container *restful.Container) {
s := &api.RoleApi{
RoleApp: services.SysRoleModelDao,
RoleMenuApp: services.SysRoleMenuModelDao,
OrganizationApp: services.SysOrganizationModelDao,
RoleOrganizationApp: services.SysRoleOrganizationModelDao,
UserApp: services.SysUserModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/role").Produces(restful.MIME_JSON)
tags := []string{"role"}
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取角色分页列表").Handle(s.GetRoleList)
}).
Doc("获取角色分页列表").
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Param(ws.QueryParameter("roleName", "roleName").DataType("string")).
Param(ws.QueryParameter("roleKey", "roleKey").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/{roleId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取角色信息").Handle(s.GetRole)
}).
Doc("获取角色信息").
Param(ws.PathParameter("roleId", "Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(entity.SysRole{}).
Returns(200, "OK", entity.SysRole{}).
Returns(404, "Not Found", nil))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加角色信息").Handle(s.InsertRole)
}).
Doc("添加角色信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysRole{}))
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改角色信息").Handle(s.UpdateRole)
}).
Doc("修改角色信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysRole{}))
ws.Route(ws.PUT("/changeStatus").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改角色状态").Handle(s.UpdateRoleStatus)
}).
Doc("修改角色状态").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysRole{}))
ws.Route(ws.PUT("/dataScope").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改角色组织权限").Handle(s.UpdateRoleDataScope)
}).
Doc("修改角色组织权限").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysRole{}))
ws.Route(ws.DELETE("/{roleId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除角色信息").Handle(s.DeleteRole)
}).
Doc("删除角色信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("roleId", "多id 1,2,3").DataType("string")))
ws.Route(ws.GET("/export").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("导出角色信息").Handle(s.ExportRole)
}).
Doc("导出角色信息").
Param(ws.QueryParameter("filename", "filename").DataType("string")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Param(ws.QueryParameter("roleName", "roleName").DataType("string")).
Param(ws.QueryParameter("roleKey", "roleKey").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags))
container.Add(ws)
}

View File

@@ -0,0 +1,15 @@
package router
import (
"github.com/emicklei/go-restful/v3"
"pandax/apps/system/api"
)
func InitSystemRouter(container *restful.Container) {
s := &api.System{}
ws := new(restful.WebService)
ws.Path("/system").Produces(restful.MIME_JSON)
ws.Route(ws.GET("/").To(s.ConnectWs))
ws.Route(ws.GET("/server").To(s.ServerInfo))
container.Add(ws)
}

View File

@@ -0,0 +1,78 @@
package router
/**
* @Description
* @Author 熊猫
* @Date 2022/7/14 17:52
**/
import (
"pandax/apps/system/api"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/model"
"pandax/kit/restfulx"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func InitSysTenantRouter(container *restful.Container) {
s := &api.SysTenantsApi{
SysTenantsApp: services.SysTenantModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/tenant").Produces(restful.MIME_JSON)
tags := []string{"tenant"}
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取SysTenant分页列表").Handle(s.GetSysTenantsList)
}).
Doc("获取SysTenant分页列表").
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/lists").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取SysTenant列表").Handle(s.GetSysTenantsAll)
}).
Doc("获取SysTenant列表").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]entity.SysTenants{}).
Returns(200, "OK", []entity.SysTenants{}))
ws.Route(ws.GET("/{tenantId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取SysTenant信息").Handle(s.GetSysTenants)
}).
Doc("获取SysTenant信息").
Param(ws.PathParameter("tenantId", "租户Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(entity.SysTenants{}).
Returns(200, "OK", entity.SysTenants{}).
Returns(404, "Not Found", nil))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加SysTenant信息").Handle(s.InsertSysTenants)
}).
Doc("添加SysTenant信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysTenants{}))
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改SysTenant信息").Handle(s.UpdateSysTenants)
}).
Doc("修改SysTenant信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysTenants{}))
ws.Route(ws.DELETE("/{tenantId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除SysTenant信息").Handle(s.DeleteSysTenants)
}).
Doc("删除SysTenant信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("tenantId", "多id 1,2,3").DataType("string")))
container.Add(ws)
}

169
apps/system/router/user.go Normal file
View File

@@ -0,0 +1,169 @@
package router
import (
"pandax/apps/system/api"
"pandax/apps/system/api/form"
"pandax/apps/system/api/vo"
"pandax/apps/system/entity"
"pandax/apps/system/services"
"pandax/kit/model"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
logServices "pandax/apps/log/services"
"pandax/kit/restfulx"
)
func InitUserRouter(container *restful.Container) {
s := &api.UserApi{
RoleApp: services.SysRoleModelDao,
MenuApp: services.SysMenuModelDao,
RoleMenuApp: services.SysRoleMenuModelDao,
UserApp: services.SysUserModelDao,
LogLogin: logServices.LogLoginModelDao,
OrganizationApp: services.SysOrganizationModelDao,
PostApp: services.SysPostModelDao,
}
ws := new(restful.WebService)
ws.Path("/system/user").Produces(restful.MIME_JSON)
tags := []string{"user"}
ws.Route(ws.GET("/getCaptcha").To(s.GenerateCaptcha).Doc("获取验证码"))
ws.Route(ws.POST("/login").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithNeedToken(false).WithNeedCasbin(false).WithLog("登录").Handle(s.Login)
}).
Doc("登录").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(form.Login{}).
Writes(vo.TokenVo{}).
Returns(200, "OK", vo.TokenVo{}))
ws.Route(ws.POST("/access").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithNeedToken(false).WithNeedCasbin(false).WithLog("获取Token").Handle(s.GetToken)
}).
Doc("获取Token").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(form.Login{}).
Writes(vo.TokenVo{}).
Returns(200, "OK", vo.TokenVo{}))
ws.Route(ws.POST("/logout").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithNeedToken(false).WithNeedCasbin(false).WithLog("退出登录").Handle(s.LogOut)
}).
Doc("退出登录").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/auth").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithNeedCasbin(false).WithLog("认证信息").Handle(s.Auth)
}).
Doc("认证信息").
Param(ws.QueryParameter("username", "username").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(vo.AuthVo{}).
Returns(200, "OK", vo.AuthVo{}))
ws.Route(ws.GET("/list").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("得到用户分页列表").Handle(s.GetSysUserList)
}).
Doc("得到用户分页列表").
Param(ws.QueryParameter("pageNum", "页数").Required(true).DataType("int")).
Param(ws.QueryParameter("pageSize", "每页条数").Required(true).DataType("int")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Param(ws.QueryParameter("username", "username").DataType("string")).
Param(ws.QueryParameter("phone", "phone").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(model.ResultPage{}).
Returns(200, "OK", model.ResultPage{}))
ws.Route(ws.GET("/me").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取个人信息").Handle(s.GetSysUserProfile)
}).
Doc("获取个人信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(vo.UserVo{}).
Returns(200, "OK", vo.UserVo{}))
ws.Route(ws.GET("/getById/{userId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取用户信息").Handle(s.GetSysUser)
}).
Doc("获取用户信息").
Param(ws.PathParameter("userId", "Id").DataType("int").DefaultValue("1")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(vo.UserVo{}).
Returns(200, "OK", vo.UserVo{}).
Returns(404, "Not Found", nil))
ws.Route(ws.GET("/getInit").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取初始化角色岗位信息(添加用户初始化)").Handle(s.GetSysUserInit)
}).
Doc("获取初始化角色岗位信息(添加用户初始化)").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(vo.UserRolePost{}). // on the response
Returns(200, "OK", vo.UserRolePost{}).
Returns(404, "Not Found", nil))
ws.Route(ws.GET("/getRoPo").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("获取用户角色岗位信息(添加用户初始化)").Handle(s.GetUserRolePost)
}).
Doc("获取用户角色岗位信息(添加用户初始化)").
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "OK", vo.UserRolePost{}).
Returns(404, "Not Found", nil))
ws.Route(ws.POST("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("添加用户信息").Handle(s.InsertSysUser)
}).
Doc("添加用户信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysUser{})) // from the request
ws.Route(ws.PUT("").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改用户信息").Handle(s.UpdateSysUser)
}).
Doc("修改用户信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysUser{}))
ws.Route(ws.PUT("/changeStatus").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改用户状态").Handle(s.UpdateSysUserStu)
}).
Doc("修改用户状态").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(entity.SysUser{}))
ws.Route(ws.DELETE("/{userId}").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("删除用户信息").Handle(s.DeleteSysUser)
}).
Doc("删除用户信息").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("userId", "多id 1,2,3").DataType("string")))
ws.Route(ws.POST("/avatar").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改用户头像").Handle(s.InsetSysUserAvatar)
}).
Doc("修改用户头像").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.PUT("pwd").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("修改用户密码").Handle(s.SysUserUpdatePwd)
}).
Doc("修改用户密码").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/export").To(func(request *restful.Request, response *restful.Response) {
restfulx.NewReqCtx(request, response).WithLog("导出用户信息").Handle(s.ExportUser)
}).
Doc("导出用户信息").
Param(ws.QueryParameter("filename", "filename").DataType("string")).
Param(ws.QueryParameter("status", "status").DataType("string")).
Param(ws.QueryParameter("username", "username").DataType("string")).
Param(ws.QueryParameter("phone", "phone").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags))
container.Add(ws)
}

121
apps/system/services/api.go Normal file
View File

@@ -0,0 +1,121 @@
package services
import (
"errors"
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/kit/casbin"
"pandax/pkg/global"
"gorm.io/gorm"
)
type (
SysApiModel interface {
Insert(data entity.SysApi) *entity.SysApi
FindOne(id int64) *entity.SysApi
FindListPage(page, pageSize int, data entity.SysApi) (*[]entity.SysApi, int64)
FindList(data entity.SysApi) *[]entity.SysApi
Update(data entity.SysApi) *entity.SysApi
Delete(ids []int64)
}
sysApiModelImpl struct {
table string
}
)
var SysApiModelDao SysApiModel = &sysApiModelImpl{
table: `sys_apis`,
}
func (m *sysApiModelImpl) Insert(api entity.SysApi) *entity.SysApi {
err := global.Db.Table(m.table).Where("path = ? AND method = ?", api.Path, api.Method).First(&entity.SysApi{}).Error
biz.IsTrue(errors.Is(err, gorm.ErrRecordNotFound), "存在相同api")
err = global.Db.Table(m.table).Create(&api).Error
biz.ErrIsNil(err, "新增Api失败")
return &api
}
func (m *sysApiModelImpl) FindOne(id int64) (resData *entity.SysApi) {
resData = new(entity.SysApi)
err := global.Db.Table(m.table).Where("id = ?", id).First(&resData).Error
biz.ErrIsNil(err, "查询Api失败")
return
}
func (m *sysApiModelImpl) FindListPage(page, pageSize int, data entity.SysApi) (*[]entity.SysApi, int64) {
list := make([]entity.SysApi, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
if data.Path != "" {
db = db.Where("path LIKE ?", "%"+data.Path+"%")
}
if data.Description != "" {
db = db.Where("description LIKE ?", "%"+data.Description+"%")
}
if data.Method != "" {
db = db.Where("method = ?", data.Method)
}
if data.ApiGroup != "" {
db = db.Where("api_group = ?", data.ApiGroup)
}
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Order("api_group").Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询配置分页列表信息失败")
return &list, total
}
func (m *sysApiModelImpl) FindList(data entity.SysApi) *[]entity.SysApi {
list := make([]entity.SysApi, 0)
db := global.Db.Table(m.table)
if data.Path != "" {
db = db.Where("path LIKE ?", "%"+data.Path+"%")
}
if data.Description != "" {
db = db.Where("description LIKE ?", "%"+data.Description+"%")
}
if data.Method != "" {
db = db.Where("method = ?", data.Method)
}
if data.ApiGroup != "" {
db = db.Where("api_group = ?", data.ApiGroup)
}
db.Where("delete_time IS NULL")
err := db.Order("api_group").Find(&list).Error
biz.ErrIsNil(err, "查询Api列表信息失败")
return &list
}
func (m *sysApiModelImpl) Update(api entity.SysApi) *entity.SysApi {
var oldA entity.SysApi
err := global.Db.Table(m.table).Where("id = ?", api.Id).First(&oldA).Error
biz.ErrIsNil(err, "【修改api】查询api失败")
if oldA.Path != api.Path || oldA.Method != api.Method {
err := global.Db.Table(m.table).Where("path = ? AND method = ?", api.Path, api.Method).First(&entity.SysApi{}).Error
biz.IsTrue(errors.Is(err, gorm.ErrRecordNotFound), "存在相同api路径")
}
// 异常直接抛错误
ca := casbin.CasbinService{ModelPath: global.Conf.Casbin.ModelPath}
ca.UpdateCasbinApi(oldA.Path, api.Path, oldA.Method, api.Method)
err = global.Db.Table(m.table).Model(&api).Updates(&api).Error
biz.ErrIsNil(err, "修改api信息失败")
return &api
}
func (m *sysApiModelImpl) Delete(ids []int64) {
err := global.Db.Table(m.table).Delete(&entity.SysApi{}, "id in (?)", ids).Error
biz.ErrIsNil(err, "删除配置信息失败")
}

View File

@@ -0,0 +1,94 @@
package services
import (
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysConfigModel interface {
Insert(data entity.SysConfig) *entity.SysConfig
FindOne(dictCode int64) *entity.SysConfig
FindListPage(page, pageSize int, data entity.SysConfig) (*[]entity.SysConfig, int64)
FindList(data entity.SysConfig) *[]entity.SysConfig
Update(data entity.SysConfig) *entity.SysConfig
Delete(dictCode []int64)
}
sysSysConfigModelImpl struct {
table string
}
)
var SysSysConfigModelDao SysConfigModel = &sysSysConfigModelImpl{
table: `sys_configs`,
}
func (m *sysSysConfigModelImpl) Insert(data entity.SysConfig) *entity.SysConfig {
err := global.Db.Table(m.table).Create(&data).Error
biz.ErrIsNil(err, "新增配置失败")
return &data
}
func (m *sysSysConfigModelImpl) FindOne(configId int64) *entity.SysConfig {
resData := new(entity.SysConfig)
err := global.Db.Table(m.table).Where("config_id = ?", configId).First(resData).Error
biz.ErrIsNil(err, "查询配置信息失败")
return resData
}
func (m *sysSysConfigModelImpl) FindListPage(page, pageSize int, data entity.SysConfig) (*[]entity.SysConfig, int64) {
list := make([]entity.SysConfig, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.ConfigName != "" {
db = db.Where("config_name like ?", "%"+data.ConfigName+"%")
}
if data.ConfigKey != "" {
db = db.Where("config_key like ?", "%"+data.ConfigKey+"%")
}
if data.ConfigType != "" {
db = db.Where("config_type = ?", data.ConfigType)
}
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询配置分页列表信息失败")
return &list, total
}
func (m *sysSysConfigModelImpl) FindList(data entity.SysConfig) *[]entity.SysConfig {
list := make([]entity.SysConfig, 0)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.ConfigName != "" {
db = db.Where("config_name like ?", "%"+data.ConfigName+"%")
}
if data.ConfigKey != "" {
db = db.Where("config_key like ?", "%"+data.ConfigKey+"%")
}
if data.ConfigType != "" {
db = db.Where("config_type = ?", data.ConfigType)
}
db.Where("delete_time IS NULL")
err := db.Order("create_time").Find(&list).Error
biz.ErrIsNil(err, "查询配置列表信息失败")
return &list
}
func (m *sysSysConfigModelImpl) Update(data entity.SysConfig) *entity.SysConfig {
err := global.Db.Table(m.table).Model(&data).Updates(&data).Error
biz.ErrIsNil(err, "修改配置信息失败")
return &data
}
func (m *sysSysConfigModelImpl) Delete(configIds []int64) {
err := global.Db.Table(m.table).Delete(&entity.SysConfig{}, "config_id in (?)", configIds).Error
biz.ErrIsNil(err, "删除配置信息失败")
return
}

View File

@@ -0,0 +1,94 @@
package services
import (
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysDictDataModel interface {
Insert(data entity.SysDictData) *entity.SysDictData
FindOne(dictCode int64) *entity.SysDictData
FindListPage(page, pageSize int, data entity.SysDictData) (*[]entity.SysDictData, int64)
FindList(data entity.SysDictData) *[]entity.SysDictData
Update(data entity.SysDictData) *entity.SysDictData
Delete(dictCode []int64)
}
sysDictDataModelImpl struct {
table string
}
)
var SysDictDataModelDao SysDictDataModel = &sysDictDataModelImpl{
table: `sys_dict_data`,
}
func (m *sysDictDataModelImpl) Insert(data entity.SysDictData) *entity.SysDictData {
err := global.Db.Table(m.table).Create(&data).Error
biz.ErrIsNil(err, "新增字典数据失败")
return &data
}
func (m *sysDictDataModelImpl) FindOne(codeId int64) *entity.SysDictData {
resData := new(entity.SysDictData)
err := global.Db.Table(m.table).Where("dict_code = ?", codeId).First(resData).Error
biz.ErrIsNil(err, "查询字典数据信息失败")
return resData
}
func (m *sysDictDataModelImpl) FindListPage(page, pageSize int, data entity.SysDictData) (*[]entity.SysDictData, int64) {
list := make([]entity.SysDictData, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.DictLabel != "" {
db = db.Where("dict_label = ?", data.DictLabel)
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
if data.DictType != "" {
db = db.Where("dict_type = ?", data.DictType)
}
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Order("dict_sort").Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询字典数据分页列表信息失败")
return &list, total
}
func (m *sysDictDataModelImpl) FindList(data entity.SysDictData) *[]entity.SysDictData {
list := make([]entity.SysDictData, 0)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.DictLabel != "" {
db = db.Where("dict_label like ?", "%"+data.DictLabel+"%")
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
if data.DictType != "" {
db = db.Where("dict_type = ?", data.DictType)
}
db.Where("delete_time IS NULL")
err := db.Order("dict_sort").Find(&list).Error
biz.ErrIsNil(err, "查询字典数据列表信息失败")
return &list
}
func (m *sysDictDataModelImpl) Update(data entity.SysDictData) *entity.SysDictData {
err := global.Db.Table(m.table).Where("dict_code = ?", data.DictCode).Updates(&data).Error
biz.ErrIsNil(err, "修改字典数据信息失败")
return &data
}
func (m *sysDictDataModelImpl) Delete(codeIds []int64) {
err := global.Db.Table(m.table).Delete(&entity.SysOrganization{}, "dict_code in (?)", codeIds).Error
biz.ErrIsNil(err, "删除字典数据信息失败")
return
}

View File

@@ -0,0 +1,94 @@
package services
import (
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysDictTypeModel interface {
Insert(data entity.SysDictType) *entity.SysDictType
FindOne(organizationId int64) *entity.SysDictType
FindListPage(page, pageSize int, data entity.SysDictType) (*[]entity.SysDictType, int64)
FindList(data entity.SysDictType) *[]entity.SysDictType
Update(data entity.SysDictType) *entity.SysDictType
Delete(organizationId []int64)
}
sysDictTypeModelImpl struct {
table string
}
)
var SysDictTypeModelDao SysDictTypeModel = &sysDictTypeModelImpl{
table: `sys_dict_types`,
}
func (m *sysDictTypeModelImpl) Insert(data entity.SysDictType) *entity.SysDictType {
err := global.Db.Table(m.table).Create(&data).Error
biz.ErrIsNil(err, "新增字典类型失败")
return &data
}
func (m *sysDictTypeModelImpl) FindOne(dictId int64) *entity.SysDictType {
resData := new(entity.SysDictType)
err := global.Db.Table(m.table).Where("dict_id = ?", dictId).First(resData).Error
biz.ErrIsNil(err, "查询字典类型信息失败")
return resData
}
func (m *sysDictTypeModelImpl) FindListPage(page, pageSize int, data entity.SysDictType) (*[]entity.SysDictType, int64) {
list := make([]entity.SysDictType, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.DictName != "" {
db = db.Where("dict_name like ?", "%"+data.DictName+"%")
}
if data.DictType != "" {
db = db.Where("dict_type like ?", "%"+data.DictType+"%")
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询字典类型分页列表信息失败")
return &list, total
}
func (m *sysDictTypeModelImpl) FindList(data entity.SysDictType) *[]entity.SysDictType {
list := make([]entity.SysDictType, 0)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.DictName != "" {
db = db.Where("dict_name like ?", "%"+data.DictName+"%")
}
if data.DictType != "" {
db = db.Where("dict_type like ?", "%"+data.DictType+"%")
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
db.Where("delete_time IS NULL")
err := db.Order("create_time").Find(&list).Error
biz.ErrIsNil(err, "查询字典类型列表信息失败")
return &list
}
func (m *sysDictTypeModelImpl) Update(data entity.SysDictType) *entity.SysDictType {
err := global.Db.Table(m.table).Where("dict_id = ?", data.DictId).Updates(&data).Error
biz.ErrIsNil(err, "修改字典类型信息失败")
return &data
}
func (m *sysDictTypeModelImpl) Delete(dictIds []int64) {
err := global.Db.Table(m.table).Delete(&entity.SysDictType{}, "dict_id in (?)", dictIds).Error
biz.ErrIsNil(err, "删除字典类型信息失败")
return
}

View File

@@ -0,0 +1,235 @@
package services
import (
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysMenuModel interface {
Insert(data entity.SysMenu) *entity.SysMenu
FindOne(menuId int64) *entity.SysMenu
FindListPage(page, pageSize int, data entity.SysMenu) (*[]entity.SysMenu, int64)
FindList(data entity.SysMenu) *[]entity.SysMenu
Update(data entity.SysMenu) *entity.SysMenu
Delete(menuId []int64)
SelectMenu(data entity.SysMenu) *[]entity.SysMenu
SelectMenuLable(data entity.SysMenu) *[]entity.MenuLable
SelectMenuRole(roleName string) *[]entity.SysMenu
GetMenuRole(data entity.MenuRole) *[]entity.MenuRole
}
sysMenuModelImpl struct {
table string
}
)
var SysMenuModelDao SysMenuModel = &sysMenuModelImpl{
table: `sys_menus`,
}
func (m *sysMenuModelImpl) Insert(data entity.SysMenu) *entity.SysMenu {
err := global.Db.Table(m.table).Create(&data).Error
biz.ErrIsNil(err, "添加菜单失败")
return &data
}
func (m *sysMenuModelImpl) FindOne(menuId int64) *entity.SysMenu {
resData := new(entity.SysMenu)
err := global.Db.Table(m.table).Where("menu_id = ?", menuId).First(resData).Error
biz.ErrIsNil(err, "查询菜单失败")
return resData
}
func (m *sysMenuModelImpl) FindListPage(page, pageSize int, data entity.SysMenu) (*[]entity.SysMenu, int64) {
list := make([]entity.SysMenu, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询分页菜单失败")
return &list, total
}
func (m *sysMenuModelImpl) FindList(data entity.SysMenu) *[]entity.SysMenu {
list := make([]entity.SysMenu, 0)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.MenuName != "" {
db = db.Where("menu_name like ?", "%"+data.MenuName+"%")
}
if data.Path != "" {
db = db.Where("path = ?", data.Path)
}
if data.MenuType != "" {
db = db.Where("menu_type = ?", data.MenuType)
}
if data.Title != "" {
db = db.Where("title like ?", "%"+data.Title+"%")
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
db.Where("delete_time IS NULL")
err := db.Order("sort").Find(&list).Error
biz.ErrIsNil(err, "查询菜单列表失败")
return &list
}
func (m *sysMenuModelImpl) Update(data entity.SysMenu) *entity.SysMenu {
err := global.Db.Table(m.table).Select("*").Updates(data).Error
biz.ErrIsNil(err, "修改菜单失败")
return &data
}
func (m *sysMenuModelImpl) Delete(menuIds []int64) {
err := global.Db.Table(m.table).Delete(&entity.SysMenu{}, "menu_id in (?)", menuIds).Error
biz.ErrIsNil(err, "修改菜单失败")
return
}
func (m *sysMenuModelImpl) SelectMenu(data entity.SysMenu) *[]entity.SysMenu {
menuList := m.FindList(data)
redData := make([]entity.SysMenu, 0)
ml := *menuList
for i := 0; i < len(ml); i++ {
if ml[i].ParentId != 0 {
continue
}
menusInfo := DiguiMenu(menuList, ml[i])
redData = append(redData, menusInfo)
}
return &redData
}
func (m *sysMenuModelImpl) SelectMenuLable(data entity.SysMenu) *[]entity.MenuLable {
menuList := m.FindList(data)
redData := make([]entity.MenuLable, 0)
ml := *menuList
for i := 0; i < len(ml); i++ {
if ml[i].ParentId != 0 {
continue
}
e := entity.MenuLable{}
e.MenuId = ml[i].MenuId
e.MenuName = ml[i].MenuName
menusInfo := DiguiMenuLable(menuList, e)
redData = append(redData, menusInfo)
}
return &redData
}
func (m *sysMenuModelImpl) GetMenuByRoleKey(roleKey string) *[]entity.SysMenu {
menus := make([]entity.SysMenu, 0)
db := global.Db.Table(m.table).Select("sys_menus.*").Joins("left join sys_role_menus on sys_role_menus.menu_id=sys_menus.menu_id")
db = db.Where("sys_role_menus.role_name=? and menu_type in ('M','C')", roleKey)
db.Where("sys_menus.delete_time IS NULL")
err := db.Order("sort").Find(&menus).Error
biz.ErrIsNil(err, "通过角色名查询菜单失败")
return &menus
}
func (m *sysMenuModelImpl) SelectMenuRole(roleKey string) *[]entity.SysMenu {
redData := make([]entity.SysMenu, 0)
menulist := m.GetMenuByRoleKey(roleKey)
menuList := *menulist
redData = make([]entity.SysMenu, 0)
for i := 0; i < len(menuList); i++ {
if menuList[i].ParentId != 0 {
continue
}
menusInfo := DiguiMenu(&menuList, menuList[i])
redData = append(redData, menusInfo)
}
return &redData
}
func (m *sysMenuModelImpl) GetMenuRole(data entity.MenuRole) *[]entity.MenuRole {
menus := make([]entity.MenuRole, 0)
db := global.Db.Table(m.table)
if data.MenuName != "" {
db = db.Where("menu_name = ?", data.MenuName)
}
db.Where("delete_time IS NULL")
biz.ErrIsNil(db.Order("sort").Find(&menus).Error, "查询角色菜单失败")
return &menus
}
func DiguiMenu(menulist *[]entity.SysMenu, menu entity.SysMenu) entity.SysMenu {
list := *menulist
min := make([]entity.SysMenu, 0)
for j := 0; j < len(list); j++ {
if menu.MenuId != list[j].ParentId {
continue
}
mi := entity.SysMenu{}
mi.MenuId = list[j].MenuId
mi.MenuName = list[j].MenuName
mi.Title = list[j].Title
mi.Icon = list[j].Icon
mi.Path = list[j].Path
mi.MenuType = list[j].MenuType
mi.IsKeepAlive = list[j].IsKeepAlive
mi.Permission = list[j].Permission
mi.ParentId = list[j].ParentId
mi.IsAffix = list[j].IsAffix
mi.IsIframe = list[j].IsIframe
mi.IsLink = list[j].IsLink
mi.Component = list[j].Component
mi.Sort = list[j].Sort
mi.Status = list[j].Status
mi.IsHide = list[j].IsHide
mi.CreatedAt = list[j].CreatedAt
mi.UpdatedAt = list[j].UpdatedAt
mi.Children = []entity.SysMenu{}
if mi.MenuType != "F" {
ms := DiguiMenu(menulist, mi)
min = append(min, ms)
} else {
min = append(min, mi)
}
}
menu.Children = min
return menu
}
func DiguiMenuLable(menulist *[]entity.SysMenu, menu entity.MenuLable) entity.MenuLable {
list := *menulist
min := make([]entity.MenuLable, 0)
for j := 0; j < len(list); j++ {
if menu.MenuId != list[j].ParentId {
continue
}
mi := entity.MenuLable{}
mi.MenuId = list[j].MenuId
mi.MenuName = list[j].MenuName
mi.Children = []entity.MenuLable{}
if list[j].MenuType != "F" {
ms := DiguiMenuLable(menulist, mi)
min = append(min, ms)
} else {
min = append(min, mi)
}
}
menu.Children = min
return menu
}

View File

@@ -0,0 +1,69 @@
package services
import (
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysNoticeModel interface {
Insert(data entity.SysNotice) *entity.SysNotice
FindOne(postId int64) *entity.SysNotice
FindListPage(page, pageSize int, data entity.SysNotice) (*[]entity.SysNotice, int64)
Update(data entity.SysNotice) *entity.SysNotice
Delete(postId []int64)
}
sysNoticeModelImpl struct {
table string
}
)
var SysNoticeModelDao SysNoticeModel = &sysNoticeModelImpl{
table: `sys_notices`,
}
func (m *sysNoticeModelImpl) Insert(data entity.SysNotice) *entity.SysNotice {
err := global.Db.Table(m.table).Create(&data).Error
biz.ErrIsNil(err, "添加通知失败")
return &data
}
func (m *sysNoticeModelImpl) FindOne(postId int64) *entity.SysNotice {
resData := new(entity.SysNotice)
err := global.Db.Table(m.table).Where("post_id = ?", postId).First(resData).Error
biz.ErrIsNil(err, "查询通知失败")
return resData
}
func (m *sysNoticeModelImpl) FindListPage(page, pageSize int, data entity.SysNotice) (*[]entity.SysNotice, int64) {
list := make([]entity.SysNotice, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.Title != "" {
db = db.Where("title like ?", "%"+data.Title+"%")
}
if data.NoticeType != "" {
db = db.Where("notice_type = ?", data.NoticeType)
}
if len(data.OrganizationIds) > 0 {
db = db.Where("organization_id in (?)", data.OrganizationIds)
}
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Order("create_time").Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询通知分页列表失败")
return &list, total
}
func (m *sysNoticeModelImpl) Update(data entity.SysNotice) *entity.SysNotice {
biz.ErrIsNil(global.Db.Table(m.table).Updates(&data).Error, "修改通知失败")
return &data
}
func (m *sysNoticeModelImpl) Delete(postIds []int64) {
biz.ErrIsNil(global.Db.Table(m.table).Delete(&entity.SysNotice{}, "notice_id in (?)", postIds).Error, "删除通知失败")
}

View File

@@ -0,0 +1,238 @@
package services
import (
"errors"
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
"github.com/kakuilan/kgo"
)
type (
SysOrganizationModel interface {
Insert(data entity.SysOrganization) *entity.SysOrganization
FindOne(organizationId int64) *entity.SysOrganization
FindListPage(page, pageSize int, data entity.SysOrganization) (*[]entity.SysOrganization, int64)
FindList(data entity.SysOrganization) *[]entity.SysOrganization
Update(data entity.SysOrganization) *entity.SysOrganization
Delete(organizationId []int64)
SelectOrganization(data entity.SysOrganization) []entity.SysOrganization
SelectOrganizationLable(data entity.SysOrganization) []entity.OrganizationLable
SelectOrganizationIds(data entity.SysOrganization) []int64
}
sysOrganizationModelImpl struct {
table string
}
)
var SysOrganizationModelDao SysOrganizationModel = &sysOrganizationModelImpl{
table: `sys_organizations`,
}
func (m *sysOrganizationModelImpl) Insert(data entity.SysOrganization) *entity.SysOrganization {
biz.ErrIsNil(global.Db.Table(m.table).Create(&data).Error, "新增组织信息失败")
organizationPath := "/" + kgo.KConv.Int2Str(data.OrganizationId)
if int(data.ParentId) != 0 {
organizationP := m.FindOne(data.ParentId)
organizationPath = organizationP.OrganizationPath + organizationPath
} else {
organizationPath = "/0" + organizationPath
}
data.OrganizationPath = organizationPath
biz.ErrIsNil(global.Db.Table(m.table).Model(&data).Updates(&data).Error, "修改组织信息失败")
return &data
}
func (m *sysOrganizationModelImpl) FindOne(organizationId int64) *entity.SysOrganization {
resData := new(entity.SysOrganization)
err := global.Db.Table(m.table).Where("organization_id = ?", organizationId).First(resData).Error
biz.ErrIsNil(err, "查询组织信息失败")
return resData
}
func (m *sysOrganizationModelImpl) FindListPage(page, pageSize int, data entity.SysOrganization) (*[]entity.SysOrganization, int64) {
list := make([]entity.SysOrganization, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.OrganizationId != 0 {
db = db.Where("organization_id = ?", data.OrganizationId)
}
if data.OrganizationName != "" {
db = db.Where("organization_name like ?", "%"+data.OrganizationName+"%")
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
if data.OrganizationPath != "" {
db = db.Where("organizationPath like %?%", data.OrganizationPath)
}
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询组织分页列表信息失败")
return &list, total
}
func (m *sysOrganizationModelImpl) FindList(data entity.SysOrganization) *[]entity.SysOrganization {
list := make([]entity.SysOrganization, 0)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.OrganizationId != 0 {
db = db.Where("organization_id = ?", data.OrganizationId)
}
if data.OrganizationName != "" {
db = db.Where("organization_name like ?", "%"+data.OrganizationName+"%")
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
db.Where("delete_time IS NULL")
err := db.Order("sort").Find(&list).Error
biz.ErrIsNil(err, "查询组织列表信息失败")
return &list
}
func (m *sysOrganizationModelImpl) Update(data entity.SysOrganization) *entity.SysOrganization {
one := m.FindOne(data.OrganizationId)
organizationPath := "/" + kgo.KConv.Int2Str(data.OrganizationId)
if int(data.ParentId) != 0 {
organizationP := m.FindOne(data.ParentId)
organizationPath = organizationP.OrganizationPath + organizationPath
} else {
organizationPath = "/0" + organizationPath
}
data.OrganizationPath = organizationPath
if data.OrganizationPath != "" && data.OrganizationPath != one.OrganizationPath {
biz.ErrIsNil(errors.New("上级组织不允许修改!"), "上级组织不允许修改")
}
biz.ErrIsNil(global.Db.Table(m.table).Model(&data).Updates(&data).Error, "修改组织信息失败")
return &data
}
func (m *sysOrganizationModelImpl) Delete(organizationIds []int64) {
err := global.Db.Table(m.table).Delete(&entity.SysOrganization{}, "organization_id in (?)", organizationIds).Error
biz.ErrIsNil(err, "删除组织信息失败")
return
}
func (m *sysOrganizationModelImpl) SelectOrganization(data entity.SysOrganization) []entity.SysOrganization {
list := m.FindList(data)
sd := make([]entity.SysOrganization, 0)
li := *list
for i := 0; i < len(li); i++ {
if li[i].ParentId != 0 {
continue
}
info := Digui(list, li[i])
sd = append(sd, info)
}
return sd
}
func (m *sysOrganizationModelImpl) SelectOrganizationLable(data entity.SysOrganization) []entity.OrganizationLable {
organizationlist := m.FindList(data)
dl := make([]entity.OrganizationLable, 0)
organizationl := *organizationlist
for i := 0; i < len(organizationl); i++ {
if organizationl[i].ParentId != 0 {
continue
}
e := entity.OrganizationLable{}
e.OrganizationId = organizationl[i].OrganizationId
e.OrganizationName = organizationl[i].OrganizationName
organizationsInfo := DiguiOrganizationLable(organizationlist, e)
dl = append(dl, organizationsInfo)
}
return dl
}
func (m *sysOrganizationModelImpl) SelectOrganizationIds(data entity.SysOrganization) []int64 {
organizationlist := m.FindList(data)
dl := make([]int64, 0)
organizationl := *organizationlist
for i := 0; i < len(organizationl); i++ {
if organizationl[i].ParentId != 0 {
continue
}
dl = append(dl, organizationl[i].OrganizationId)
e := entity.OrganizationLable{}
e.OrganizationId = organizationl[i].OrganizationId
e.OrganizationName = organizationl[i].OrganizationName
id := DiguiOrganizationId(organizationlist, e)
dl = append(dl, id...)
}
return dl
}
func Digui(organizationlist *[]entity.SysOrganization, menu entity.SysOrganization) entity.SysOrganization {
list := *organizationlist
min := make([]entity.SysOrganization, 0)
for j := 0; j < len(list); j++ {
if menu.OrganizationId != list[j].ParentId {
continue
}
mi := entity.SysOrganization{}
mi.OrganizationId = list[j].OrganizationId
mi.ParentId = list[j].ParentId
mi.OrganizationPath = list[j].OrganizationPath
mi.OrganizationName = list[j].OrganizationName
mi.Sort = list[j].Sort
mi.Leader = list[j].Leader
mi.Phone = list[j].Phone
mi.Email = list[j].Email
mi.Status = list[j].Status
mi.CreatedAt = list[j].CreatedAt
mi.UpdatedAt = list[j].UpdatedAt
mi.Children = []entity.SysOrganization{}
ms := Digui(organizationlist, mi)
min = append(min, ms)
}
menu.Children = min
return menu
}
func DiguiOrganizationLable(organizationlist *[]entity.SysOrganization, organization entity.OrganizationLable) entity.OrganizationLable {
list := *organizationlist
min := make([]entity.OrganizationLable, 0)
for j := 0; j < len(list); j++ {
if organization.OrganizationId != list[j].ParentId {
continue
}
mi := entity.OrganizationLable{list[j].OrganizationId, list[j].OrganizationName, []entity.OrganizationLable{}}
ms := DiguiOrganizationLable(organizationlist, mi)
min = append(min, ms)
}
organization.Children = min
return organization
}
func DiguiOrganizationId(organizationlist *[]entity.SysOrganization, organization entity.OrganizationLable) []int64 {
list := *organizationlist
min := make([]int64, 0)
for j := 0; j < len(list); j++ {
if organization.OrganizationId != list[j].ParentId {
continue
}
min = append(min, list[j].OrganizationId)
mi := entity.OrganizationLable{list[j].OrganizationId, list[j].OrganizationName, []entity.OrganizationLable{}}
id := DiguiOrganizationId(organizationlist, mi)
min = append(min, id...)
}
return min
}

View File

@@ -0,0 +1,94 @@
package services
import (
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysPostModel interface {
Insert(data entity.SysPost) *entity.SysPost
FindOne(postId int64) *entity.SysPost
FindListPage(page, pageSize int, data entity.SysPost) (*[]entity.SysPost, int64)
FindList(data entity.SysPost) *[]entity.SysPost
Update(data entity.SysPost) *entity.SysPost
Delete(postId []int64)
}
sysPostModelImpl struct {
table string
}
)
var SysPostModelDao SysPostModel = &sysPostModelImpl{
table: `sys_posts`,
}
func (m *sysPostModelImpl) Insert(data entity.SysPost) *entity.SysPost {
err := global.Db.Table(m.table).Create(&data).Error
biz.ErrIsNil(err, "添加岗位失败")
return &data
}
func (m *sysPostModelImpl) FindOne(postId int64) *entity.SysPost {
resData := new(entity.SysPost)
err := global.Db.Table(m.table).Where("post_id = ?", postId).First(resData).Error
biz.ErrIsNil(err, "查询岗位失败")
return resData
}
func (m *sysPostModelImpl) FindListPage(page, pageSize int, data entity.SysPost) (*[]entity.SysPost, int64) {
list := make([]entity.SysPost, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.PostId != 0 {
db = db.Where("post_id = ?", data.PostId)
}
if data.PostName != "" {
db = db.Where("post_name like ?", "%"+data.PostName+"%")
}
if data.PostCode != "" {
db = db.Where("post_code like ?", "%"+data.PostCode+"%")
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Order("sort").Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询岗位分页列表失败")
return &list, total
}
func (m *sysPostModelImpl) FindList(data entity.SysPost) *[]entity.SysPost {
list := make([]entity.SysPost, 0)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.PostId != 0 {
db = db.Where("post_id = ?", data.PostId)
}
if data.PostName != "" {
db = db.Where("post_name = ?", data.PostName)
}
if data.PostCode != "" {
db = db.Where("post_code = ?", data.PostCode)
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
db.Where("delete_time IS NULL")
biz.ErrIsNil(db.Order("sort").Find(&list).Error, "查询岗位列表失败")
return &list
}
func (m *sysPostModelImpl) Update(data entity.SysPost) *entity.SysPost {
biz.ErrIsNil(global.Db.Table(m.table).Updates(&data).Error, "修改岗位失败")
return &data
}
func (m *sysPostModelImpl) Delete(postIds []int64) {
biz.ErrIsNil(global.Db.Table(m.table).Delete(&entity.SysPost{}, "post_id in (?)", postIds).Error, "删除岗位失败")
}

View File

@@ -0,0 +1,143 @@
package services
import (
"errors"
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysRoleModel interface {
Insert(data entity.SysRole) *entity.SysRole
FindOne(roleId int64) *entity.SysRole
FindListPage(page, pageSize int, data entity.SysRole) (list *[]entity.SysRole, total int64)
FindList(data entity.SysRole) (list *[]entity.SysRole)
Update(data entity.SysRole) *entity.SysRole
Delete(roleId []int64)
GetRoleMeunId(data entity.SysRole) []int64
GetRoleOrganizationId(data entity.SysRole) []int64
FindOrganizationsByRoleId(roleId int64) (entity.SysRoleAuth, error)
}
sysRoleModel struct {
table string
}
)
var SysRoleModelDao SysRoleModel = &sysRoleModel{
table: `sys_roles`,
}
func (m *sysRoleModel) Insert(data entity.SysRole) *entity.SysRole {
var i int64 = 0
global.Db.Table(m.table).Where("(role_name = ? or role_key = ?) and delete_time IS NULL", data.RoleName, data.RoleKey).Count(&i)
biz.IsTrue(i == 0, "角色名称或者角色标识已经存在!")
data.UpdateBy = ""
err := global.Db.Table(m.table).Create(&data).Error
biz.ErrIsNil(err, "添加角色失败")
return &data
}
func (m *sysRoleModel) FindOne(roleId int64) *entity.SysRole {
resData := new(entity.SysRole)
biz.ErrIsNil(global.Db.Table(m.table).Where("role_id = ?", roleId).First(resData).Error, "查询角色失败")
return resData
}
func (m *sysRoleModel) FindListPage(page, pageSize int, data entity.SysRole) (*[]entity.SysRole, int64) {
list := make([]entity.SysRole, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.RoleId != 0 {
db = db.Where("role_id = ?", data.RoleId)
}
if data.RoleName != "" {
db = db.Where("role_name like ?", "%"+data.RoleName+"%")
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
if data.RoleKey != "" {
db = db.Where("role_key like ?", "%"+data.RoleKey+"%")
}
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Order("role_sort").Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询角色分页列表失败")
return &list, total
}
func (m *sysRoleModel) FindList(data entity.SysRole) *[]entity.SysRole {
list := make([]entity.SysRole, 0)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.RoleName != "" {
db = db.Where("role_name like ?", "%"+data.RoleName+"%")
}
if data.Status != "" {
db = db.Where("status = ?", data.Status)
}
if data.RoleKey != "" {
db = db.Where("role_key like ?", "%"+data.RoleKey+"%")
}
db.Where("delete_time IS NULL")
biz.ErrIsNil(db.Order("role_sort").Find(&list).Error, "查询角色列表失败")
return &list
}
func (m *sysRoleModel) Update(data entity.SysRole) *entity.SysRole {
update := new(entity.SysRole)
biz.ErrIsNil(global.Db.Table(m.table).First(update, data.RoleId).Error, "查询角色失败")
if data.RoleKey != "" && data.RoleKey != update.RoleKey {
biz.ErrIsNil(errors.New("角色标识不允许修改!"), "角色标识不允许修改!")
}
biz.ErrIsNil(global.Db.Table(m.table).Updates(&data).Error, "修改角色失败")
return &data
}
func (m *sysRoleModel) Delete(roleIds []int64) {
biz.ErrIsNil(global.Db.Table(m.table).Delete(&entity.SysRole{}, "role_id in (?)", roleIds).Error, "删除角色失败")
return
}
// 获取角色对应的菜单ids
func (m *sysRoleModel) GetRoleMeunId(data entity.SysRole) []int64 {
menuIds := make([]int64, 0)
menuList := make([]entity.MenuIdList, 0)
err := global.Db.Table("sys_menus").Select("sys_menus.menu_id").Joins("LEFT JOIN sys_role_menus on sys_role_menus.menu_id=sys_menus.menu_id").Where("sys_role_menus.role_id = ? ", data.RoleId).Where("sys_menus.menu_id not in (select sys_menus.parent_id from sys_menus LEFT JOIN sys_role_menus on sys_menus.menu_id=sys_role_menus.menu_id where sys_role_menus.role_id =? )", data.RoleId).Find(&menuList).Error
biz.ErrIsNil(err, "查询角色菜单列表失败")
for i := 0; i < len(menuList); i++ {
menuIds = append(menuIds, menuList[i].MenuId)
}
return menuIds
}
func (m *sysRoleModel) GetRoleOrganizationId(data entity.SysRole) []int64 {
organizationIds := make([]int64, 0)
organizationList := make([]entity.OrganizationIdList, 0)
err := global.Db.Table("sys_role_organizations").Select("sys_role_organizations.organization_id").Joins("LEFT JOIN sys_organizations on sys_organizations.organization_id=sys_role_organizations.organization_id").Where("role_id = ? ", data.RoleId).Where(" sys_role_organizations.organization_id not in(select sys_organizations.parent_id from sys_role_organizations LEFT JOIN sys_organizations on sys_organizations.organization_id=sys_role_organizations.organization_id where role_id =? )", data.RoleId).Find(&organizationList).Error
biz.ErrIsNil(err, "查询角色组织列表失败")
for i := 0; i < len(organizationList); i++ {
organizationIds = append(organizationIds, organizationList[i].OrganizationId)
}
return organizationIds
}
func (m *sysRoleModel) FindOrganizationsByRoleId(roleId int64) (entity.SysRoleAuth, error) {
var roleData entity.SysRoleAuth
GROUP_CONCAT := "GROUP_CONCAT(sys_role_organizations.organization_id) as org"
if global.Conf.Server.DbType == "postgresql" {
GROUP_CONCAT = "string_agg(CAST(sys_role_organizations.organization_id AS VARCHAR), ',') as org"
}
err := global.Db.Raw("SELECT sys_roles.data_scope, "+GROUP_CONCAT+" FROM sys_roles LEFT JOIN sys_role_organizations ON sys_roles.role_id = sys_role_organizations.role_id WHERE sys_roles.role_id = ? GROUP BY sys_roles.role_id", roleId).Scan(&roleData).Error
return roleData, err
}

View File

@@ -0,0 +1,124 @@
package services
import (
"fmt"
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysRoleMenuModel interface {
Insert(roleId int64, menuId []int64) bool
FindList(data entity.SysRoleMenu) *[]entity.SysRoleMenu
Update(data entity.SysRoleMenu) *entity.SysRoleMenu
Delete(RoleId int64, MenuID int64)
GetPermis(roleId int64) []string
GetMenuPaths(rm entity.SysRoleMenu) []entity.MenuPath
DeleteRoleMenu(RoleId int64)
DeleteRoleMenus(roleIds []int64)
}
sysRoleMenuImpl struct {
table string
}
)
var SysRoleMenuModelDao SysRoleMenuModel = &sysRoleMenuImpl{
table: `sys_role_menus`,
}
func (m *sysRoleMenuImpl) Insert(roleId int64, menuId []int64) bool {
var role entity.SysRole
biz.ErrIsNil(global.Db.Table("sys_roles").Where("role_id = ?", roleId).First(&role).Error, "查询角色失败")
var menu []entity.SysMenu
biz.ErrIsNil(global.Db.Table("sys_menus").Where("menu_id in (?)", menuId).Find(&menu).Error, "查询菜单失败")
//拼接 sql 串
sql := "INSERT INTO sys_role_menus (role_id,menu_id,role_name) VALUES "
for i := 0; i < len(menu); i++ {
if len(menu)-1 == i {
//最后一条数据 以分号结尾
sql += fmt.Sprintf("(%d,%d,'%s');", role.RoleId, menu[i].MenuId, role.RoleKey)
} else {
sql += fmt.Sprintf("(%d,%d,'%s'),", role.RoleId, menu[i].MenuId, role.RoleKey)
}
}
biz.ErrIsNil(global.Db.Exec(sql).Error, "新增角色菜单失败")
return true
}
func (m *sysRoleMenuImpl) FindList(data entity.SysRoleMenu) *[]entity.SysRoleMenu {
list := make([]entity.SysRoleMenu, 0)
db := global.Db.Table(m.table)
// 此处填写 where参数判断
if data.RoleId != 0 {
db = db.Where("role_id = ?", data.RoleId)
}
biz.ErrIsNil(db.Find(&list).Error, "查询角色菜单失败")
return &list
}
// 查询权限标识
func (m *sysRoleMenuImpl) GetPermis(roleId int64) []string {
var r []entity.SysMenu
db := global.Db.Select("sys_menus.permission").Table("sys_menus").Joins("left join sys_role_menus on sys_menus.menu_id = sys_role_menus.menu_id")
db = db.Where("role_id = ?", roleId)
db = db.Where("sys_menus.menu_type in ('F','C')")
biz.ErrIsNil(db.Find(&r).Error, "查询查询权限标识列表失败")
var list []string
for i := 0; i < len(r); i++ {
list = append(list, r[i].Permission)
}
return list
}
func (m *sysRoleMenuImpl) GetMenuPaths(rm entity.SysRoleMenu) []entity.MenuPath {
var r []entity.MenuPath
db := global.Db.Select("sys_menus.path").Table(m.table)
db = db.Joins("left join sys_roles on sys_roles.role_id=sys_role_menus.role_id")
db = db.Joins("left join sys_menus on sys_menus.id=sys_role_menus.menu_id")
db = db.Where("sys_roles.role_key = ? and sys_menus.type=1", rm.RoleName)
biz.ErrIsNil(db.Find(&r).Error, "查询菜单路径失败")
return r
}
func (m *sysRoleMenuImpl) Update(data entity.SysRoleMenu) *entity.SysRoleMenu {
biz.ErrIsNil(global.Db.Table(m.table).Updates(&data).Error, "修改菜单失败")
return &data
}
func (m *sysRoleMenuImpl) DeleteRoleMenu(roleId int64) {
var rm entity.SysRoleMenu
if err := global.Db.Table(m.table).Where("role_id = ?", roleId).Delete(&rm).Error; err != nil {
biz.ErrIsNil(err, "删除角色菜单失败")
}
return
}
func (m *sysRoleMenuImpl) DeleteRoleMenus(roleIds []int64) {
var rm entity.SysRoleMenu
biz.ErrIsNil(global.Db.Table(m.table).Where("role_id in (?)", roleIds).Delete(&rm).Error, "批量删除角色菜单失败")
}
func (m *sysRoleMenuImpl) Delete(RoleId int64, MenuID int64) {
var rm entity.SysRoleMenu
rm.RoleId = RoleId
db := global.Db.Table(m.table).Where("role_id = ?", RoleId)
if MenuID != 0 {
db = db.Where("menu_id = ?", MenuID)
}
biz.ErrIsNil(db.Delete(&rm).Error, "删除角色菜单失败")
return
}

View File

@@ -0,0 +1,50 @@
package services
import (
"fmt"
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysRoleOrganizationModel interface {
Insert(roleId int64, organizationIds []int64) bool
FindOrganizationsByRoleId(roleId int64) ([]int64, error)
Delete(rm entity.SysRoleOrganization)
}
sysRoleOrganizationImpl struct {
table string
}
)
var SysRoleOrganizationModelDao SysRoleOrganizationModel = &sysRoleOrganizationImpl{
table: `sys_role_organizations`,
}
func (m *sysRoleOrganizationImpl) Insert(roleId int64, organizationIds []int64) bool {
sql := "INSERT INTO sys_role_organizations (role_id, organization_id) VALUES "
for i := 0; i < len(organizationIds); i++ {
if len(organizationIds)-1 == i {
//最后一条数据 以分号结尾
sql += fmt.Sprintf("(%d,%d);", roleId, organizationIds[i])
} else {
sql += fmt.Sprintf("(%d,%d),", roleId, organizationIds[i])
}
}
global.Db.Exec(sql)
return true
}
func (m *sysRoleOrganizationImpl) FindOrganizationsByRoleId(roleId int64) ([]int64, error) {
var result []int64
err := global.Db.Table(m.table).Where("role_id = ?", roleId).Pluck("organization_id", &result).Error
return result, err
}
func (m *sysRoleOrganizationImpl) Delete(rm entity.SysRoleOrganization) {
biz.ErrIsNil(global.Db.Table(m.table).Where("role_id = ?", rm.RoleId).Delete(&rm).Error, "删除角色失败")
return
}

View File

@@ -0,0 +1,85 @@
package services
/**
* @Description
* @Author 熊猫
* @Date 2022/7/14 17:49
**/
import (
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
)
type (
SysTenantsModel interface {
Insert(data entity.SysTenants) *entity.SysTenants
FindOne(tenantId int64) *entity.SysTenants
FindListPage(page, pageSize int, data entity.SysTenants) (*[]entity.SysTenants, int64)
FindList(data entity.SysTenants) *[]entity.SysTenants
Update(data entity.SysTenants) *entity.SysTenants
Delete(tenantIds []int64)
}
SysTenantModelImpl struct {
table string
}
)
var SysTenantModelDao SysTenantsModel = &SysTenantModelImpl{
table: `sys_tenants`,
}
func (m *SysTenantModelImpl) Insert(data entity.SysTenants) *entity.SysTenants {
err := global.Db.Table(m.table).Create(&data).Error
biz.ErrIsNil(err, "添加SysTenant失败")
return &data
}
func (m *SysTenantModelImpl) FindOne(tenantId int64) *entity.SysTenants {
resData := new(entity.SysTenants)
err := global.Db.Table(m.table).Where("id = ?", tenantId).First(resData).Error
biz.ErrIsNil(err, "查询SysTenant失败")
return resData
}
func (m *SysTenantModelImpl) FindListPage(page, pageSize int, data entity.SysTenants) (*[]entity.SysTenants, int64) {
list := make([]entity.SysTenants, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table)
if data.TenantName != "" {
db = db.Where("tenant_name like ?", "%"+data.TenantName+"%")
}
if data.Id != 0 {
db = db.Where("id = ?", data.Id)
}
db.Where("delete_time IS NULL")
err := db.Count(&total).Error
err = db.Order("create_time").Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询SysTenant分页列表失败")
return &list, total
}
func (m *SysTenantModelImpl) FindList(data entity.SysTenants) *[]entity.SysTenants {
list := make([]entity.SysTenants, 0)
db := global.Db.Table(m.table)
if data.TenantName != "" {
db = db.Where("tenant_name like ?", "%"+data.TenantName+"%")
}
if data.Id != 0 {
db = db.Where("id = ?", data.Id)
}
db.Where("delete_time IS NULL")
biz.ErrIsNil(db.Order("create_time").Find(&list).Error, "查询SysTenant列表失败")
return &list
}
func (m *SysTenantModelImpl) Update(data entity.SysTenants) *entity.SysTenants {
biz.ErrIsNil(global.Db.Table(m.table).Updates(&data).Error, "修改SysTenant失败")
return &data
}
func (m *SysTenantModelImpl) Delete(tenantIds []int64) {
biz.ErrIsNil(global.Db.Table(m.table).Delete(&entity.SysTenants{}, "id in (?)", tenantIds).Error, "删除SysTenant失败")
}

View File

@@ -0,0 +1,184 @@
package services
import (
"pandax/apps/system/entity"
"pandax/kit/biz"
"pandax/pkg/global"
"github.com/kakuilan/kgo"
"golang.org/x/crypto/bcrypt"
)
type (
SysUserModel interface {
Login(u entity.Login) *entity.SysUser
Insert(data entity.SysUser) *entity.SysUser
FindOne(data entity.SysUser) (resData *entity.SysUserView)
FindListPage(page, pageSize int, data entity.SysUser) (list *[]entity.SysUserPage, total int64)
FindList(data entity.SysUser) (list *[]entity.SysUserView)
Update(data entity.SysUser) *entity.SysUser
Delete(userId []int64)
SetPwd(data entity.SysUser, pwd entity.SysUserPwd) bool
}
sysUserModelImpl struct {
table string
}
)
var SysUserModelDao SysUserModel = &sysUserModelImpl{
table: `sys_users`,
}
func (m *sysUserModelImpl) Login(u entity.Login) *entity.SysUser {
user := new(entity.SysUser)
err := global.Db.Table(m.table).Where("username = ? ", u.Username).Find(user)
biz.ErrIsNil(err.Error, "查询用户信息失败")
// 验证密码
b := kgo.KEncr.PasswordVerify([]byte(u.Password), []byte(user.Password))
biz.IsTrue(b, "密码错误")
return user
}
func (m *sysUserModelImpl) Insert(data entity.SysUser) *entity.SysUser {
bytes, _ := kgo.KEncr.PasswordHash([]byte(data.Password), bcrypt.DefaultCost)
data.Password = string(bytes)
// check 用户名
var count int64
global.Db.Table(m.table).Where("username = ? and delete_time IS NULL", data.Username).Count(&count)
biz.IsTrue(count == 0, "账户已存在!")
biz.ErrIsNil(global.Db.Table(m.table).Create(&data).Error, "添加用户失败")
return &data
}
func (m *sysUserModelImpl) FindOne(data entity.SysUser) *entity.SysUserView {
resData := new(entity.SysUserView)
db := global.Db.Table(m.table).Select([]string{"sys_users.*", "sys_roles.role_name"})
db = db.Joins("left join sys_roles on sys_users.role_id=sys_roles.role_id")
if data.UserId != 0 {
db = db.Where("user_id = ?", data.UserId)
}
if data.Username != "" {
db = db.Where("username = ?", data.Username)
}
if data.Password != "" {
db = db.Where("password = ?", data.Password)
}
if data.RoleId != 0 {
db = db.Where("role_id = ?", data.RoleId)
}
if data.OrganizationId != 0 {
db = db.Where("organization_id = ?", data.OrganizationId)
}
if data.PostId != 0 {
db = db.Where("post_id = ?", data.PostId)
}
biz.ErrIsNil(db.First(resData).Error, "查询用户失败")
return resData
}
func (m *sysUserModelImpl) FindListPage(page, pageSize int, data entity.SysUser) (*[]entity.SysUserPage, int64) {
list := make([]entity.SysUserPage, 0)
var total int64 = 0
offset := pageSize * (page - 1)
db := global.Db.Table(m.table).Select("sys_users.*,sys_organizations.organization_name")
db = db.Joins("left join sys_organizations on sys_organizations.organization_id = sys_users.organization_id")
// 此处填写 where参数判断
if data.Username != "" {
db = db.Where("sys_users.username = ?", data.Username)
}
if data.NickName != "" {
db = db.Where("sys_users.nick_name like ?", "%"+data.NickName+"%")
}
if data.Status != "" {
db = db.Where("sys_users.status = ?", data.Status)
}
if data.Phone != "" {
db = db.Where("sys_users.phone like ?", "%"+data.Phone+"%")
}
if data.OrganizationId != 0 {
db = db.Where("sys_users.organization_id = ?", data.OrganizationId)
}
db.Where("sys_users.delete_time IS NULL")
err := db.Count(&total).Error
err = db.Limit(pageSize).Offset(offset).Find(&list).Error
biz.ErrIsNil(err, "查询用户分页列表失败")
return &list, total
}
func (m *sysUserModelImpl) FindList(data entity.SysUser) *[]entity.SysUserView {
list := make([]entity.SysUserView, 0)
// 此处填写 where参数判断
db := global.Db.Table(m.table).Select([]string{"sys_users.*", "sys_roles.role_name"})
db = db.Joins("left join sys_roles on sys_users.role_id=sys_roles.role_id")
if data.UserId != 0 {
db = db.Where("user_id = ?", data.UserId)
}
if data.Username != "" {
db = db.Where("username = ?", data.Username)
}
if data.Password != "" {
db = db.Where("password = ?", data.Password)
}
if data.RoleId != 0 {
db = db.Where("sys_users.role_id = ?", data.RoleId)
}
if data.OrganizationId != 0 {
db = db.Where("sys_users.organization_id = ?", data.OrganizationId)
}
if data.PostId != 0 {
db = db.Where("sys_users.post_id = ?", data.PostId)
}
if data.Status != "" {
db = db.Where("sys_users.status = ?", data.Status)
}
db.Where("sys_users.delete_time IS NULL")
biz.ErrIsNilAppendErr(db.Find(&list).Error, "查询用户列表失败")
return &list
}
func (m *sysUserModelImpl) Update(data entity.SysUser) *entity.SysUser {
if data.Password != "" {
bytes, _ := kgo.KEncr.PasswordHash([]byte(data.Password), bcrypt.DefaultCost)
data.Password = string(bytes)
}
update := new(entity.SysUser)
biz.ErrIsNil(global.Db.Table(m.table).First(update, data.UserId).Error, "查询用户失败")
if data.RoleId == 0 {
data.RoleId = update.RoleId
}
biz.ErrIsNil(global.Db.Table(m.table).Updates(&data).Error, "修改用户失败")
return &data
}
func (m *sysUserModelImpl) Delete(userIds []int64) {
biz.ErrIsNil(global.Db.Table(m.table).Delete(&entity.SysUser{}, "user_id in (?)", userIds).Error, "删除用户失败")
}
func (m *sysUserModelImpl) SetPwd(data entity.SysUser, pwd entity.SysUserPwd) bool {
user := m.FindOne(data)
bl := kgo.KEncr.PasswordVerify([]byte(pwd.OldPassword), []byte(user.Password))
biz.IsTrue(bl, "旧密码输入错误")
data.Password = pwd.NewPassword
m.Update(data)
return true
}

53
config.yml Normal file
View File

@@ -0,0 +1,53 @@
app:
name: xMagic
version: 1.0.0
server:
port: 7788
cors: true
# 接口限流
rate:
enable: true
rate-num: 100
db-type: mysql
excel-dir: ./resource/excel/
tls:
enable: true
key-file: /www/server/panel/vhost/ssl/r.l-l.cn/privkey.pem
cert-file: /www/server/panel/vhost/ssl/r.l-l.cn/fullchain.pem
jwt:
key: xMagic
# 过期时间单位秒 7天
expire-time: 604800
mysql:
host: sh-cynosdbmysql-grp-l1s8n3g4.sql.tencentcdb.com:28799
username: root
password: "LMxeon5x"
db-name: tita
config: charset=utf8&loc=Local&parseTime=true
postgresql:
username: postgres
password: 123456
host: 127.0.0.1
port: 5432
db-name: pandax_iot
max-idle-conns: 10
max-open-conns: 10
casbin:
model-path: "./resource/rbac_model.conf"
gen:
# 代码生成读取的数据库名称
dbname: x_magic
# 代码生成是使用前端代码存放位置需要指定到src文件夹相对路径
frontpath: ../PandaUi/src
log:
# 日志等级, trace, debug, info, warn, error, fatal
level: info
# file:
# path: ./
# name: panda_log.log

109
core.js Normal file
View File

@@ -0,0 +1,109 @@
// core.js 的 main 函数是一切脚本函数执行的预处理入口
function main() {
// 拒绝任何请求访问和操作以下文件名的路径
if (
payload.get().url.includes('function.js') ||
payload.get().url.includes('core.js') ||
payload.get().url.includes('global.js')
) {
//当请求的路径包含以上文件名时,返回 404
response.contentType.html()
response.status.notFound()
return `<h1>404!</h1>`
}
// 声明路径
const filePath = rootPath + payload.get().path
switch (payload.get().method) {
case 'OPTIONS':
// 这样对于所有的 OPTIONS 请求都会返回 200 (OK) 状态码
response.status.ok()
return
// 当接收的请求为 GET 时
case 'GET':
// 声明缓存
response.headers.set(
'Cache-Control',
'no-transform,max-age=31536000,immutable'
)
// 拒绝任何接口通过GET访问和操作以下文件名的路径
if (
payload.get().url.includes('/api') &&
payload.get().url.includes('function.js')
) {
//当请求的路径包含以上文件名时,返回 404
response.contentType.html()
response.status.notFound()
return `<h1>404!</h1>`
}
// 判断路径是否为目录
if (fs.isDir(filePath)) {
// 设置 Content-Type
response.headers.set('Content-Type', 'text/html; charset=utf-8;')
// 如果是目录,则尝试返回目录下的 index.htm
var indexFile = filePath + '/index.htm'
if (fs.exists(filePath)) {
// 如果 index.htm 存在,则返回 index.htm
response.file(filePath)
return ``
}
// 如果是index.htm不存在则尝试返回目录下的 index.html
indexFile = indexFile + 'l'
if (fs.exists(filePath)) {
// 如果 index.html 存在,则返回 index.html
response.file(filePath)
return ``
}
// 则将请求移交给对应path下的 function.js 进行处理。
runtime.call(filePath) // call会将 return 的内容写到 response.body 里面。
return `` // 如果不需要在call的结果后面追加内容这里请设置为空
}
// 如果不是目录,则尝试返回文件
if (fs.exists(filePath)) {
if (payload.get().query.download) {
// 设置 Content-Disposition
response.headers.set('Content-Disposition', 'attachment;')
}
if (
filePath.includes('.html') ||
filePath.includes('.htm') ||
filePath[filePath.length - 1] == '/'
) {
response.headers.set('Content-Type', 'text/html; charset=utf-8;')
}
// response.headers.set("Content-Type", "text/html; charset=utf-8;")
// 设置 Content-Type虽然会根据URL的文件后缀自动设置但是为了安全起见你也可以手动设置一下。
// response.headers.set("Content-Type", "application/octet-stream; charset=utf-8")
// 如果文件存在,则返回文件
response.file(filePath)
return `` // 如果不需要在call的结果后面追加内容这里请设置为空
}
// 则将请求移交给对应path下的 function.js 进行处理。
runtime.call(filePath) // call会将 return 的内容写到 response.body 里面。
return `` // 如果不需要在call的结果后面追加内容这里请设置为空
// 如果客户端发起 POST
case 'POST':
// 则将请求移交给对应path下的 function.js 进行处理。
runtime.call(filePath) // call会将 return 的内容写到 response.body 里面。
return `` // 如果不需要在call的结果后面追加内容这里请设置为空
// 如果客户端发起 PUT
case 'PUT':
// 将请求交给 response 库的的 upload 函数处理
// console.log(payload.get().body);
// return encoding.from(payload.get().body).toString();
response.upload(filePath)
return ``
}
// 当路由处理逻辑不存在
response.contentType.html()
response.status.methodNotAllowed()
return `<h1>405!</h1>`
}

108
go.mod Normal file
View File

@@ -0,0 +1,108 @@
module pandax
go 1.23.0
replace git.weixin.qq.com/__/vlan => ../vlan
require (
git.weixin.qq.com/__/vlan v0.0.0-00010101000000-000000000000
github.com/casbin/casbin/v2 v2.37.4
github.com/casbin/gorm-adapter/v3 v3.4.6
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/didip/tollbooth v4.0.2+incompatible
github.com/dlclark/regexp2 v1.10.0
github.com/emicklei/go-restful-openapi/v2 v2.9.0
github.com/emicklei/go-restful/v3 v3.9.0
github.com/emmansun/gmsm v0.24.3
github.com/go-playground/validator/v10 v10.8.0
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.7.1
github.com/go-sqlite/sqlite3 v0.0.0-20180313105335-53dd8e640ee7
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6
github.com/google/uuid v1.3.0
github.com/gorilla/schema v1.2.0
github.com/gorilla/websocket v1.5.1
github.com/kakuilan/kgo v0.1.8
github.com/lib/pq v1.10.9
github.com/mojocn/base64Captcha v1.3.6
github.com/mssola/user_agent v0.5.3
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.5.0
github.com/tidwall/gjson v1.17.0
github.com/xuri/excelize/v2 v2.4.1
go.mongodb.org/mongo-driver v1.13.1
golang.org/x/crypto v0.41.0
golang.org/x/net v0.43.0
golang.org/x/text v0.28.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.2.0
gorm.io/driver/postgres v1.2.3
gorm.io/gorm v1.22.3
gvisor.dev/gvisor v0.0.0-20240119232905-7b151e25d076
)
require (
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
github.com/brianvoe/gofakeit/v6 v6.0.2 // indirect
github.com/denisenkom/go-mssqldb v0.12.3 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/spec v0.20.6 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gonuts/binary v0.2.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.10.1 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.2.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.9.0 // indirect
github.com/jackc/pgx/v4 v4.14.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.38.2 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/richardlehane/mscfb v1.0.3 // indirect
github.com/richardlehane/msoleps v1.0.1 // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
golang.org/x/image v0.13.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/time v0.5.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/sqlserver v1.2.1 // indirect
gorm.io/plugin/dbresolver v1.1.0 // indirect
)

504
go.sum Normal file
View File

@@ -0,0 +1,504 @@
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjlRbWyNqkPsJ3Fg+tQZCbgeX1VGljbQY=
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/brianvoe/gofakeit/v6 v6.0.2 h1:MDvplMAKJMcKZDwQvsIbhT7BV/8UF/3EEy2n14ynUyA=
github.com/brianvoe/gofakeit/v6 v6.0.2/go.mod h1:palrJUk4Fyw38zIFB/uBZqsgzW5VsNllhHKKwAebzew=
github.com/casbin/casbin/v2 v2.37.4 h1:RWSKPjaZ8JlOBlcW1bI/FTII8OPxvQ9jVy9JwyNL6DQ=
github.com/casbin/casbin/v2 v2.37.4/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/gorm-adapter/v3 v3.4.6 h1:JuLN3/CBTPPlvNyQqY3uXt4Zqnt+hs2sM353aCtLTP4=
github.com/casbin/gorm-adapter/v3 v3.4.6/go.mod h1:6mIYgpByH/uSkfCv4G/vr/12cVZc3rXBQ9KrqS9oTUU=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/didip/tollbooth v4.0.2+incompatible h1:fVSa33JzSz0hoh2NxpwZtksAzAgd7zjmGO20HCZtF4M=
github.com/didip/tollbooth v4.0.2+incompatible/go.mod h1:A9b0665CE6l1KmzpDws2++elm/CsuWBMa5Jv4WY0PEY=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/emicklei/go-restful-openapi/v2 v2.9.0 h1:djsWqjhI0EVYfkLCCX6jZxUkLmYUq2q9tt09ZbixfyE=
github.com/emicklei/go-restful-openapi/v2 v2.9.0/go.mod h1:VKNgZyYviM1hnyrjD9RDzP2RuE94xTXxV+u6MGN4v4k=
github.com/emicklei/go-restful/v3 v3.7.3/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emmansun/gmsm v0.24.3 h1:BBSGqmMcKD2xegxc3BAZE97Gjyh250UYMr0q2pW4X0c=
github.com/emmansun/gmsm v0.24.3/go.mod h1:tKoGqGHkNwJM8wI1BGURqzRx3dsQF7rr2hp8rhrPOb4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ=
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.8.0 h1:1kAa0fCrnpv+QYdkdcRzrRM7AyYs5o8+jZdJCz9xj6k=
github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sqlite/sqlite3 v0.0.0-20180313105335-53dd8e640ee7 h1:ow5vK9Q/DSKkxbEIJHBST6g+buBDwdaDIyk1dGGwpQo=
github.com/go-sqlite/sqlite3 v0.0.0-20180313105335-53dd8e640ee7/go.mod h1:JxSQ+SvsjFb+p8Y+bn+GhTkiMfKVGBD0fq43ms2xw04=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gonuts/binary v0.2.0 h1:caITwMWAoQWlL0RNvv2lTU/AHqAJlVuu6nZmNgfbKW4=
github.com/gonuts/binary v0.2.0/go.mod h1:kM+CtBrCGDSKdv8WXTuCUsw+loiy8f/QEI8YCCC0M/E=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.10.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8=
github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns=
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.8.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgtype v1.9.0 h1:/SH1RxEtltvJgsDqp3TbiTFApD3mey3iygpuEGeuBXk=
github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.13.0/go.mod h1:9P4X524sErlaxj0XSGZk7s+LD0eOyu1ZDUrrpznYDF0=
github.com/jackc/pgx/v4 v4.14.0 h1:TgdrmgnM7VY72EuSQzBbBd4JA1RLqJolrw9nQVZABVc=
github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kakuilan/kgo v0.1.8 h1:b9UfGYNbUpWjPheOEgu/MsWUVDNWbcSit6BbNsBAPl0=
github.com/kakuilan/kgo v0.1.8/go.mod h1:S9driqss6OluzqiOfUx7xN8nw0H6bFu5v7c19P09RRc=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew03H+Tw=
github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/mssola/user_agent v0.5.3 h1:lBRPML9mdFuIZgI2cmlQ+atbpJdLdeVl2IDodjBR578=
github.com/mssola/user_agent v0.5.3/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj3nKI=
github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 h1:EpI0bqf/eX9SdZDwlMmahKM+CDBgNbsXMhsN28XrM8o=
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.4.1 h1:veeeFLAJwsNEBPBlDepzPIYS1eLyBVcXNZUW79exZ1E=
github.com/xuri/excelize/v2 v2.4.1/go.mod h1:rSu0C3papjzxQA3sdK8cU544TebhrPUoTOaGPIh0Q1A=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk=
go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg=
golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
gorm.io/driver/mysql v1.1.2/go.mod h1:4P/X9vSc3WTrhTLZ259cpFd6xKNYiSSdSZngkSBGIMM=
gorm.io/driver/mysql v1.2.0 h1:l8+9VwjjyzEkw0PNPBOr2JHhLOGVk7XEnl5hk42bcvs=
gorm.io/driver/mysql v1.2.0/go.mod h1:4RQmTg4okPghdt+kbe6e1bTXIQp7Ny1NnBn/3Z6ghjk=
gorm.io/driver/postgres v1.2.2/go.mod h1:Ik3tK+a3FMp8ORZl29v4b3M0RsgXsaeMXh9s9eVMXco=
gorm.io/driver/postgres v1.2.3 h1:f4t0TmNMy9gh3TU2PX+EppoA6YsgFnyq8Ojtddb42To=
gorm.io/driver/postgres v1.2.3/go.mod h1:pJV6RgYQPG47aM1f0QeOzFH9HxQc8JcmAgjRCgS0wjs=
gorm.io/driver/sqlserver v1.2.1 h1:KhGOjvPX7JZ5hPyQICTJfMuTz88zgJ2lk9bWiHVNHd8=
gorm.io/driver/sqlserver v1.2.1/go.mod h1:nixq0OB3iLXZDiPv6JSOjWuPgpyaRpOIIevYtA4Ulb4=
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.11/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.3 h1:/JS6z+GStEQvJNW3t1FTwJwG/gZ+A7crFdRqtvG5ehA=
gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/plugin/dbresolver v1.1.0 h1:cegr4DeprR6SkLIQlKhJLYxH8muFbJ4SmnojXvoeb00=
gorm.io/plugin/dbresolver v1.1.0/go.mod h1:tpImigFAEejCALOttyhWqsy4vfa2Uh/vAUVnL5IRF7Y=
gvisor.dev/gvisor v0.0.0-20240119232905-7b151e25d076 h1:LbaTr9qML03qYVNb18i2L5QYAf5Go7BoFILZQ3KXETs=
gvisor.dev/gvisor v0.0.0-20240119232905-7b151e25d076/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

1
index.htm Normal file
View File

@@ -0,0 +1 @@
<h1>kia ora!</h1>

84
kit/biz/assert.go Normal file
View File

@@ -0,0 +1,84 @@
package biz
import (
"errors"
"fmt"
"pandax/kit/utils"
"reflect"
)
func ErrIsNil(err error, msg string, params ...any) error {
if err != nil {
if err.Error() == "record not found" {
return nil
}
return fmt.Errorf(msg, params...)
}
return nil
}
func ErrIsNilAppendErr(err error, msg string) error {
if err != nil {
return fmt.Errorf(msg, err.Error())
}
return nil
}
func IsNil(err error) error {
switch t := err.(type) {
case *BizError:
return errors.New(t.Error())
case error:
return fmt.Errorf("非业务异常: %s", err.Error())
}
return nil
}
func IsTrue(exp bool, msg string, params ...any) error {
if !exp {
return fmt.Errorf(msg, params...)
}
return nil
}
func IsTrueBy(exp bool, err BizError) error {
if !exp {
return errors.New(err.Error())
}
return nil
}
func NotEmpty(str string, msg string, params ...any) error {
if str == "" {
return fmt.Errorf(msg, params...)
}
return nil
}
func NotNil(data any, msg string) error {
if reflect.ValueOf(data).IsNil() {
return errors.New(msg)
}
return nil
}
func NotBlank(data any, msg string) error {
if utils.IsBlank(reflect.ValueOf(data)) {
return errors.New(msg)
}
return nil
}
func IsEquals(data1 any, data2 any, msg string) error {
if !reflect.DeepEqual(data1, data2) {
return errors.New(msg)
}
return nil
}
func Nil(data any, msg string) error {
if !reflect.ValueOf(data).IsNil() {
return errors.New(msg)
}
return nil
}

35
kit/biz/bizerror.go Normal file
View File

@@ -0,0 +1,35 @@
package biz
// 业务错误
type BizError struct {
code int16
err string
}
var (
Success *BizError = NewBizErrCode(200, "success")
BizErr *BizError = NewBizErrCode(400, "biz error")
ServerError *BizError = NewBizErrCode(500, "服务器异常,请联系管理员")
PermissionErr *BizError = NewBizErrCode(4001, "没有权限操作可能是TOKEN过期了请先登录")
CasbinErr *BizError = NewBizErrCode(403, "没有API接口访问权限请联系管理员")
)
// 错误消息
func (e *BizError) Error() string {
return e.err
}
// 错误码
func (e *BizError) Code() int16 {
return e.code
}
// 创建业务逻辑错误结构体,默认为业务逻辑错误
func NewBizErr(msg string) *BizError {
return &BizError{code: BizErr.code, err: msg}
}
// 创建业务逻辑错误结构体可设置指定错误code
func NewBizErrCode(code int16, msg string) *BizError {
return &BizError{code: code, err: msg}
}

25
kit/captcha/captcha.go Normal file
View File

@@ -0,0 +1,25 @@
package captcha
import (
"github.com/mojocn/base64Captcha"
)
var store = base64Captcha.DefaultMemStore
var driver base64Captcha.Driver = base64Captcha.NewDriverDigit(80, 240, 4, 0.7, 80)
// 生成验证码
func Generate() (string, string, string) {
c := base64Captcha.NewCaptcha(driver, store)
// 获取
id, b64s, answer, _ := c.Generate()
return id, b64s, answer
}
// 验证验证码
func Verify(id string, val string) bool {
if id == "" || val == "" {
return false
}
// 同时清理掉这个图片
return store.Verify(id, val, true)
}

81
kit/casbin/casbin.go Normal file
View File

@@ -0,0 +1,81 @@
package casbin
import (
"pandax/kit/biz"
"pandax/kit/starter"
"sync"
"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v3"
)
type CasbinService struct {
ModelPath string
}
func (c *CasbinService) UpdateCasbin(roleKey string, casbinInfos []CasbinRule) error {
c.ClearCasbin(0, roleKey)
rules := [][]string{}
for _, v := range casbinInfos {
rules = append(rules, []string{roleKey, v.Path, v.Method})
}
e := c.GetCasbinEnforcer()
success, err := e.AddPolicies(rules)
if err != nil {
return err
}
if !success {
return biz.NewBizErr("存在相同api,添加失败,请联系管理员")
}
return nil
}
func (c *CasbinService) UpdateCasbinApi(oldPath string, newPath string, oldMethod string, newMethod string) error {
err := starter.Db.Table("casbin_rule").Model(&CasbinRule{}).Where("v1 = ? AND v2 = ?", oldPath, oldMethod).Updates(map[string]interface{}{
"v1": newPath,
"v2": newMethod,
}).Error
if err != nil {
return biz.NewBizErr("修改api失败")
}
return nil
}
func (c *CasbinService) GetPolicyPathByRoleId(roleKey string) []CasbinRule {
e := c.GetCasbinEnforcer()
list := e.GetFilteredPolicy(0, roleKey)
pathMaps := make([]CasbinRule, len(list))
for i, v := range list {
pathMaps[i] = CasbinRule{
Path: v[1],
Method: v[2],
}
}
return pathMaps
}
func (c *CasbinService) ClearCasbin(v int, p ...string) bool {
e := c.GetCasbinEnforcer()
success, _ := e.RemoveFilteredPolicy(v, p...)
return success
}
var (
syncedEnforcer *casbin.SyncedEnforcer
once sync.Once
)
func (c *CasbinService) GetCasbinEnforcer() *casbin.SyncedEnforcer {
once.Do(func() {
a, err := gormadapter.NewAdapterByDB(starter.Db)
if err != nil {
panic(biz.NewBizErr("新建权限适配器失败"))
}
syncedEnforcer, err = casbin.NewSyncedEnforcer(c.ModelPath, a)
if err != nil {
panic(biz.NewBizErr("新建权限适配器失败"))
}
})
_ = syncedEnforcer.LoadPolicy()
return syncedEnforcer
}

View File

@@ -0,0 +1,16 @@
package casbin
type CasbinRule struct {
Ptype string `json:"ptype" gorm:"column:ptype"`
RoleKey string `json:"roleKey" gorm:"column:v0"`
Path string `json:"path" gorm:"column:v1"`
Method string `json:"method" gorm:"column:v2"`
V3 string `json:"v3" gorm:"column:v3"`
V4 string `json:"v4" gorm:"column:v4"`
V5 string `json:"v5" gorm:"column:v5"`
Id int `json:"id" gorm:"primary_key;AUTO_INCREMENT;column:id"`
}
func (CasbinRule) TableName() string {
return "casbin_rule"
}

132
kit/file/file.go Normal file
View File

@@ -0,0 +1,132 @@
package utilFile
import (
"io"
"mime/multipart"
"net/http"
"os"
"pandax/kit/biz"
"strconv"
"sync"
)
const (
MaxConcurrency = 16 // 最大并发数
)
type DownloadTask struct {
URL string
FilePath string
}
func DownloadFileWithConcurrency(url, filepath string) error {
resp, err := http.Head(url)
if err != nil {
return err
}
defer resp.Body.Close()
fileSize, err := strconv.Atoi(resp.Header.Get("Content-Length"))
if err != nil {
return err
}
file, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
return err
}
defer file.Close()
// 检查本地文件大小
localFileSize, err := file.Seek(0, io.SeekEnd)
if err != nil {
return err
}
// 计算剩余未下载的文件大小
remainingSize := fileSize - int(localFileSize)
// 计算每个片段的大小
chunkSize := remainingSize / MaxConcurrency
// 创建等待组用于等待所有goroutine完成
var wg sync.WaitGroup
wg.Add(MaxConcurrency)
// 创建并发下载任务
for i := 0; i < MaxConcurrency; i++ {
start := localFileSize + int64(i*chunkSize)
end := start + int64(chunkSize) - 1
// 最后一个片段的结束位置可能超过文件大小,需要修正
if i == MaxConcurrency-1 {
end = int64(fileSize) - 1
}
go func(index int, start, end int64) {
defer wg.Done()
err := downloadChunk(url, filepath, start, end)
if err != nil {
biz.NewBizErr("文件下载失败")
// 处理下载错误
}
}(i, start, end)
}
// 等待所有goroutine完成
wg.Wait()
return nil
}
func downloadChunk(url, filepath string, start, end int64) error {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
// 设置Range头部
req.Header.Set("Range", "bytes="+strconv.FormatInt(start, 10)+"-"+strconv.FormatInt(end, 10))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
file, err := os.OpenFile(filepath, os.O_RDWR, 0666)
if err != nil {
return err
}
defer file.Close()
_, err = file.Seek(start, io.SeekStart)
if err != nil {
return err
}
_, err = io.CopyN(file, resp.Body, end-start+1)
if err != nil {
return err
}
return nil
}
func SaveUploadedFile(file *multipart.FileHeader, dst string) error {
src, err := file.Open()
if err != nil {
return err
}
defer src.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, src)
return err
}

64
kit/logger/logger.go Normal file
View File

@@ -0,0 +1,64 @@
package logger
import (
"fmt"
"os"
"strings"
"time"
"github.com/sirupsen/logrus"
)
var Log *logrus.Logger
func InitLog(fileName, level string) *logrus.Logger {
Log = logrus.New()
Log.SetFormatter(new(LogFormatter))
Log.SetReportCaller(true)
// 根据配置文件设置日志级别
if level != "" {
l, err := logrus.ParseLevel(level)
if err != nil {
panic(any(fmt.Sprintf("日志级别不存在: %s", level)))
}
Log.SetLevel(l)
} else {
Log.SetLevel(logrus.DebugLevel)
}
if fileName != "" {
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend|0666)
if err != nil {
panic(any(fmt.Sprintf("创建日志文件失败: %s", err.Error())))
}
Log.Out = file
}
return Log
}
type LogFormatter struct{}
func (l *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
timestamp := time.Now().Local().Format("2006-01-02 15:04:05.000")
level := entry.Level
logMsg := fmt.Sprintf("%s [%s]", timestamp, strings.ToUpper(level.String()))
// 如果存在调用信息且为error级别以上记录文件及行号
if caller := entry.Caller; caller != nil {
var fp string
// 全路径切割,只获取项目相关路径,
// 即/Users/hml/Desktop/project/go/pandax/test.go只获取/test.go
ps := strings.Split(caller.File, "pandax/")
if len(ps) >= 2 {
fp = ps[1]
} else {
fp = ps[0]
}
logMsg = logMsg + fmt.Sprintf(" [%s:%d]", fp, caller.Line)
}
for k, v := range entry.Data {
logMsg = logMsg + fmt.Sprintf(" [%s=%v]", k, v)
}
logMsg = logMsg + fmt.Sprintf(" : %s\n", entry.Message)
return []byte(logMsg), nil
}

33
kit/model/base_model.go Normal file
View File

@@ -0,0 +1,33 @@
package model
import (
"gorm.io/gorm"
"time"
)
// BaseAutoModel 使用代码生成需要此不能自由命名id
type BaseAutoModel struct {
Id int `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id" form:"id"`
CreatedAt time.Time `gorm:"column:create_time" json:"createTime" form:"createTime"`
UpdatedAt time.Time `gorm:"column:update_time" json:"updateTime" form:"updateTime"`
DeletedAt gorm.DeletedAt `gorm:"column:delete_time" sql:"index" json:"-"`
}
// BaseAutoModelD 表想要硬删除使用他
type BaseAutoModelD struct {
Id int `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id" form:"id"`
CreatedAt time.Time `gorm:"column:create_time" json:"createTime" form:"createTime"`
UpdatedAt time.Time `gorm:"column:update_time" json:"updateTime" form:"updateTime"`
}
type BaseModel struct {
CreatedAt time.Time `gorm:"column:create_time" json:"createTime" form:"createTime"`
UpdatedAt time.Time `gorm:"column:update_time" json:"updateTime" form:"updateTime"`
DeletedAt gorm.DeletedAt `gorm:"column:delete_time" sql:"index" json:"-"`
}
// BaseModelD 硬删除
type BaseModelD struct {
CreatedAt time.Time `gorm:"column:create_time" json:"createTime" form:"create_time"`
UpdatedAt time.Time `gorm:"column:update_time" json:"updateTime" form:"update_time"`
}

36
kit/model/jsonb.go Normal file
View File

@@ -0,0 +1,36 @@
package model
import (
"database/sql/driver"
"encoding/json"
"errors"
)
type JSONB map[string]interface{}
func (a JSONB) Value() (driver.Value, error) {
return json.Marshal(a)
}
func (a *JSONB) Scan(value interface{}) error {
b, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(b, &a)
}
// JSONBS Interface for JSONB Field of yourTableName Table
type JSONBS []interface{}
func (a JSONBS) Value() (driver.Value, error) {
return json.Marshal(a)
}
func (a *JSONBS) Scan(value interface{}) error {
b, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(b, &a)
}

View File

@@ -0,0 +1,39 @@
package model
import "time"
type AppContext struct {
}
type LoginAccount struct {
UserId int64
TenantId int64
OrganizationId int64
RoleId int64
DeptId int64
PostId int64
Username string
RoleKey string
}
type OauthAccount struct {
ID uint `json:"id" gorm:"autoIncrement;primaryKey"`
Name string `json:"name" gorm:"size:100;not null;unique"`
Password string `json:"-" gorm:"size:256;"`
Email string `json:"email" gorm:"size:256;"`
Avatar string `json:"avatar" gorm:"size:256;"`
AuthInfos []AuthInfo `json:"authInfos" gorm:"foreignKey:UserId;references:ID"`
}
type AuthInfo struct {
ID uint `json:"id" gorm:"autoIncrement;primaryKey"`
UserId uint `json:"userId" gorm:"size:256"`
Url string `json:"url" gorm:"size:256"`
AuthType string `json:"authType" gorm:"size:256"`
AuthId string `json:"authId" gorm:"size:256"`
AccessToken string `json:"-" gorm:"size:256"`
RefreshToken string `json:"-" gorm:"size:256"`
Expiry time.Time `json:"-"`
BaseModel
}

199
kit/model/model.go Normal file
View File

@@ -0,0 +1,199 @@
package model
import (
"fmt"
"pandax/kit/biz"
"pandax/kit/starter"
"strconv"
"strings"
"time"
"gorm.io/gorm"
)
type Model struct {
BaseAutoModel
CreatorId int64 `json:"creatorId"`
Creator string `json:"creator"` //创建者
ModifierId int64 `json:"modifierId"`
Modifier string `json:"modifier"` //修改者
}
// 设置基础信息. 如创建时间,修改时间,创建者,修改者信息
func (m *Model) SetBaseInfo(account *LoginAccount) {
nowTime := time.Now()
isCreate := m.Id == 0
if isCreate {
m.CreatedAt = nowTime
}
m.UpdatedAt = nowTime
if account == nil {
return
}
id := account.UserId
name := account.Username
if isCreate {
m.CreatorId = id
m.Creator = name
}
m.Modifier = name
m.ModifierId = id
}
// 事务
func Tx(funcs ...func(db *gorm.DB) error) (err error) {
tx := starter.Db.Begin()
defer func() {
var err any
err = recover()
if err != nil {
tx.Rollback()
err = fmt.Errorf("%v", err)
}
}()
for _, f := range funcs {
err = f(tx)
if err != nil {
tx.Rollback()
return
}
}
err = tx.Commit().Error
return
}
// 根据id获取实体对象。model需为指针类型需要将查询出来的值赋值给model
//
// 若error不为nil则为不存在该记录
func GetById(model any, id uint64, cols ...string) error {
return starter.Db.Select(cols).Where("id = ?", id).First(model).Error
}
// 根据id列表查询
func GetByIdIn(model any, list any, ids []uint64, orderBy ...string) {
var orderByStr string
if orderBy == nil {
orderByStr = "id desc"
} else {
orderByStr = strings.Join(orderBy, ",")
}
starter.Db.Model(model).Where("id in (?)", ids).Order(orderByStr).Find(list)
}
// 根据id列表查询 model可以是对象也可以是map[string]interface{}
func CountBy(model any) int64 {
var count int64
starter.Db.Model(model).Where(model).Count(&count)
return count
}
// 根据id更新model更新字段为model中不为空的值即int类型不为0ptr类型不为nil这类字段值
func UpdateById(model any) error {
return starter.Db.Model(model).Updates(model).Error
}
func UpdateByWhere(model any, where any) error {
return starter.Db.Model(model).Where(where).Updates(model).Error
}
// 根据id删除model
func DeleteById(model any, id uint64) error {
return starter.Db.Delete(model, "id = ?", id).Error
}
// 根据条件删除
func DeleteByCondition(model any) error {
return starter.Db.Where(model).Delete(model).Error
}
// 插入model
func Insert(model any) error {
return starter.Db.Create(model).Error
}
// 获取满足model中不为空的字段值条件的所有数据.
//
// list为数组类型 如 var users *[]User可指定为非model结构体即只包含需要返回的字段结构体
func ListBy(model any, list any, cols ...string) {
starter.Db.Model(model).Select(cols).Where(model).Find(list)
}
// 获取满足model中不为空的字段值条件的所有数据.
//
// list为数组类型 如 var users *[]User可指定为非model结构体
func ListByOrder(model any, list any, order ...string) {
var orderByStr string
if order == nil {
orderByStr = "id desc"
} else {
orderByStr = strings.Join(order, ",")
}
starter.Db.Model(model).Where(model).Order(orderByStr).Find(list)
}
// 获取满足model中不为空的字段值条件的单个对象。model需为指针类型需要将查询出来的值赋值给model
//
// 若 error不为nil则为不存在该记录
func GetBy(model any, cols ...string) error {
return starter.Db.Select(cols).Where(model).First(model).Error
}
// 获取满足conditionModel中不为空的字段值条件的单个对象。model需为指针类型需要将查询出来的值赋值给model
// toModel 需要查询的字段
// 若 error不为nil则为不存在该记录
func GetByConditionTo(conditionModel any, toModel any) error {
return starter.Db.Model(conditionModel).Where(conditionModel).First(toModel).Error
}
// 获取分页结果
func GetPage(pageParam *PageParam, conditionModel any, toModels any, orderBy ...string) *ResultPage {
var count int64
err := starter.Db.Model(conditionModel).Where(conditionModel).Count(&count).Error
biz.ErrIsNilAppendErr(err, " 查询错误:%s")
if count == 0 {
return &ResultPage{Total: 0, Data: []string{}}
}
page := pageParam.PageNum
pageSize := pageParam.PageSize
var orderByStr string
if orderBy == nil {
orderByStr = "id desc"
} else {
orderByStr = strings.Join(orderBy, ",")
}
err = starter.Db.Model(conditionModel).Where(conditionModel).Order(orderByStr).Limit(pageSize).Offset((page - 1) * pageSize).Find(toModels).Error
biz.ErrIsNil(err, "查询失败")
return &ResultPage{Total: count, Data: toModels}
}
// 根据sql获取分页对象
func GetPageBySql(sql string, param *PageParam, toModel any, args ...any) *ResultPage {
db := starter.Db
selectIndex := strings.Index(sql, "SELECT ") + 7
fromIndex := strings.Index(sql, " FROM")
selectCol := sql[selectIndex:fromIndex]
countSql := strings.Replace(sql, selectCol, "COUNT(*) AS total ", 1)
// 查询count
var count int
db.Raw(countSql, args...).Scan(&count)
if count == 0 {
return &ResultPage{Total: 0, Data: []string{}}
}
// 分页查询
limitSql := sql + " LIMIT " + strconv.Itoa(param.PageNum-1) + ", " + strconv.Itoa(param.PageSize)
err := db.Raw(limitSql).Scan(toModel).Error
biz.ErrIsNil(err, "查询失败")
return &ResultPage{Total: int64(count), Data: toModel}
}
func GetListBySql(sql string, params ...any) []map[string]any {
var maps []map[string]any
starter.Db.Raw(sql, params).Scan(&maps)
return maps
}
func GetListBySql2Model(sql string, toEntity any, params ...any) error {
return starter.Db.Raw(sql, params).Find(toEntity).Error
}

15
kit/model/page.go Normal file
View File

@@ -0,0 +1,15 @@
package model
// 分页参数
type PageParam struct {
PageNum int `json:"pageNum"`
PageSize int `json:"pageSize"`
Params string `json:"params"`
}
type ResultPage struct {
Total int64 `json:"total"`
PageNum int64 `json:"pageNum"`
PageSize int64 `json:"pageSize"`
Data any `json:"data"`
}

62
kit/model/result.go Normal file
View File

@@ -0,0 +1,62 @@
package model
import (
"encoding/json"
"fmt"
"pandax/kit/biz"
)
const (
SuccessCode = 200
SuccessMsg = "success"
)
// 统一返回结果结构体
type Result struct {
Code int16 `json:"code"`
Msg string `json:"msg"`
Data any `json:"data"`
}
// 将Result转为json字符串
func (r *Result) ToJson() string {
jsonData, err := json.Marshal(r)
if err != nil {
fmt.Println("data转json错误")
}
return string(jsonData)
}
// 判断该Result是否为成功状态
func (r *Result) IsSuccess() bool {
return r.Code == SuccessCode
}
// 返回成功状态的Result
// data 成功附带的数据消息
func Success(data any) *Result {
return &Result{Code: SuccessCode, Msg: SuccessMsg, Data: data}
}
// 返回成功状态的Result
// data 成功不附带数据
func SuccessNoData() *Result {
return &Result{Code: SuccessCode, Msg: SuccessMsg}
}
func Error(bizerr *biz.BizError) *Result {
return &Result{Code: bizerr.Code(), Msg: bizerr.Error()}
}
// 返回服务器错误Result
func ServerError() *Result {
return Error(biz.ServerError)
}
func TokenError() *Result {
return Error(biz.PermissionErr)
}
func ErrorBy(code int16, msg string) *Result {
return &Result{Code: code, Msg: msg}
}

View File

@@ -0,0 +1,15 @@
package restfulx
type LogInfo struct {
LogResp bool // 是否记录返回结果
Description string // 请求描述
}
func NewLogInfo(description string) *LogInfo {
return &LogInfo{Description: description, LogResp: false}
}
func (i *LogInfo) WithLogResp(logResp bool) *LogInfo {
i.LogResp = logResp
return i
}

Some files were not shown because too many files have changed in this diff Show More