This commit is contained in:
孟帅
2022-02-25 17:11:17 +08:00
parent 9bd05abb2c
commit 8f3d679a57
897 changed files with 95731 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package com
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcache"
)
type cache struct {
}
var (
Cache = new(cache)
)
func (component *cache) New() *gcache.Cache {
c := gcache.New()
//redis
adapter := gcache.NewAdapterRedis(g.Redis())
//内存
//adapter := gcache.NewAdapterMemory()
c.SetAdapter(adapter)
return c
}

View File

@@ -0,0 +1,62 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package com
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
"github.com/mojocn/base64Captcha"
)
var Captcha = new(captcha)
type captcha struct{}
//
//  @Title  获取字母数字混合验证码
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Return  idKeyC
//  @Return  base64stringC
//
func (component *captcha) GetVerifyImgString(ctx context.Context) (idKeyC string, base64stringC string) {
driver := &base64Captcha.DriverString{
Height: 80,
Width: 240,
//NoiseCount: 50,
//ShowLineOptions: 20,
Length: 4,
Source: "abcdefghjkmnpqrstuvwxyz23456789",
Fonts: []string{"chromohv.ttf"},
}
driver = driver.ConvertFonts()
store := base64Captcha.DefaultMemStore
c := base64Captcha.NewCaptcha(driver, store)
idKeyC, base64stringC, err := c.Generate()
if err != nil {
g.Log().Error(ctx,err)
}
return
}
//
//  @Title  验证输入的验证码是否正确
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Param   id
//  @Param   answer
//  @Return  bool
//
func (component *captcha) VerifyString(id, answer string) bool {
driver := new(base64Captcha.DriverString)
store := base64Captcha.DefaultMemStore
c := base64Captcha.NewCaptcha(driver, store)
answer = gstr.ToLower(answer)
return c.Verify(id, answer, true)
}

View File

@@ -0,0 +1,107 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package com
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/model"
"github.com/gogf/gf/v2/net/ghttp"
)
type comContext struct{}
var Context = new(comContext)
//
//  @Title  初始化上下文对象指针到上下文对象中,以便后续的请求流程中可以修改
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//  @Param   customCtx
//
func (component *comContext) Init(r *ghttp.Request, customCtx *model.Context) {
r.SetCtxVar(consts.ContextKey, customCtx)
}
//
//  @Title  获得上下文变量如果没有设置那么返回nil
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Return  *model.Context
//
func (component *comContext) Get(ctx context.Context) *model.Context {
value := ctx.Value(consts.ContextKey)
if value == nil {
return nil
}
if localCtx, ok := value.(*model.Context); ok {
return localCtx
}
return nil
}
//
//  @Title  将上下文信息设置到上下文请求中,注意是完整覆盖
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   user
//
func (component *comContext) SetUser(ctx context.Context, user *model.Identity) {
component.Get(ctx).User = user
}
//
//  @Title  设置组件响应 用于全局日志使用
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   response
//
func (component *comContext) SetResponse(ctx context.Context, response *model.Response) {
component.Get(ctx).ComResponse = response
}
//
//  @Title  设置应用模块
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   module
//
func (component *comContext) SetModule(ctx context.Context, module string) {
component.Get(ctx).Module = module
}
//
//  @Title  设置请求耗时
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   module
//
func (component *comContext) SetTakeUpTime(ctx context.Context, takeUpTime int64) {
component.Get(ctx).TakeUpTime = takeUpTime
}
//
//  @Title  获取用户ID
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Return  int
//
func (component *comContext) GetUserId(ctx context.Context) int64 {
user := component.Get(ctx).User
if user == nil {
return 0
}
return user.Id
}

View File

@@ -0,0 +1,254 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package com
import (
"context"
"github.com/axgle/mahonia"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/bufanyun/hotgo/app/utils"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/kayon/iploc"
"time"
)
var Ip = new(ip)
type ip struct{}
type IpLocationData struct {
Ip string `json:"ip"`
Country string `json:"country"`
Region string `json:"region"`
Province string `json:"province"`
ProvinceCode int `json:"province_code"`
City string `json:"city"`
CityCode int `json:"city_code"`
Area string `json:"area"`
AreaCode int `json:"area_code"`
}
//
//  @Title  通过Whois接口查询IP归属地
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   ip
//  @Return  IpLocationData
//
func (component *ip) WhoisLocation(ctx context.Context, ip string) IpLocationData {
type whoisRegionData struct {
Ip string `json:"ip"`
Pro string `json:"pro" `
ProCode string `json:"proCode" `
City string `json:"city" `
CityCode string `json:"cityCode"`
Region string `json:"region"`
RegionCode string `json:"regionCode"`
Addr string `json:"addr"`
Err string `json:"err"`
}
if !utils.Validate.IsIp(ip) {
return IpLocationData{}
}
response, err := g.Client().Timeout(10*time.Second).Get(ctx, "http://whois.pconline.com.cn/ipJson.jsp?ip="+ip+"&json=true")
if err != nil {
err = gerror.New(err.Error())
return IpLocationData{
Ip: ip,
}
}
defer response.Close()
var enc mahonia.Decoder
enc = mahonia.NewDecoder("gbk")
data := enc.ConvertString(response.ReadAllString())
g.Log().Print(ctx, "data:", data)
whoisData := whoisRegionData{}
if err := gconv.Struct(data, &whoisData); err != nil {
err = gerror.New(err.Error())
g.Log().Print(ctx, "err:", err)
return IpLocationData{
Ip: ip,
}
}
g.Log().Print(ctx, "whoisData:", whoisData)
return IpLocationData{
Ip: whoisData.Ip,
//Country string `json:"country"`
Region: whoisData.Addr,
Province: whoisData.Pro,
ProvinceCode: gconv.Int(whoisData.ProCode),
City: whoisData.City,
CityCode: gconv.Int(whoisData.CityCode),
Area: whoisData.Region,
AreaCode: gconv.Int(whoisData.RegionCode),
}
}
//
//  @Title  通过Cz88的IP库查询IP归属地
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   ip
//  @Return  IpLocationData
//
func (component *ip) Cz88Find(ctx context.Context, ip string) IpLocationData {
if !utils.Validate.IsIp(ip) {
g.Log().Print(ctx, "ip格式错误:", ip)
return IpLocationData{}
}
loc, err := iploc.OpenWithoutIndexes("./storage/ip/qqwry-utf8.dat")
if err != nil {
err = gerror.New(err.Error())
return IpLocationData{
Ip: ip,
}
}
detail := loc.Find(ip)
if detail == nil {
return IpLocationData{
Ip: ip,
}
}
locationData := IpLocationData{
Ip: ip,
Country: detail.Country,
Region: detail.Region,
Province: detail.Province,
City: detail.City,
Area: detail.County,
}
if gstr.LenRune(locationData.Province) == 0 {
return locationData
}
var (
provinceModel *entity.SysProvinces
cityModel *entity.SysProvinces
areaModel *entity.SysProvinces
)
err = g.DB().Model("hg_common_provinces").
Where("level", 1).
WhereLike("title", "%"+locationData.Province+"%").
Scan(&provinceModel)
if err != nil {
err = gerror.New(err.Error())
return locationData
}
if provinceModel != nil {
locationData.ProvinceCode = provinceModel.Id
locationData.Province = provinceModel.Title
}
if gstr.LenRune(locationData.City) == 0 {
return locationData
// 是否为直辖市
} else if component.IsJurisdictionByIpTitle(locationData.City) {
locationData.CityCode = provinceModel.Id + 100
locationData.City = "直辖市"
} else {
//替换掉
locationData.City = gstr.Replace(locationData.City, "地区", "")
err = g.DB().Model("hg_common_provinces").
Where("level", 2).
Where("pid", locationData.ProvinceCode).
WhereLike("title", "%"+locationData.City+"%").
Scan(&cityModel)
if err != nil {
err = gerror.New(err.Error())
return locationData
}
if cityModel != nil {
locationData.CityCode = cityModel.Id
locationData.City = cityModel.Title
}
}
if gstr.LenRune(locationData.Area) == 0 {
return locationData
}
err = g.DB().Model("hg_common_provinces").
Where("level", 3).
Where("pid", locationData.CityCode).
WhereLike("title", "%"+locationData.Area+"%").
Scan(&areaModel)
if err != nil {
err = gerror.New(err.Error())
return locationData
}
if areaModel != nil {
locationData.AreaCode = areaModel.Id
locationData.Area = areaModel.Title
}
return locationData
}
//
//  @Title  判断地区名称是否为直辖市
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   title
//  @Return  bool
//
func (component *ip) IsJurisdictionByIpTitle(title string) bool {
lists := []string{"北京市", "天津市", "重庆市", "上海市"}
for i := 0; i < len(lists); i++ {
if gstr.Contains(lists[i], title) {
return true
}
}
return false
}
//
//  @Title  获取IP归属地信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   ip
//  @Return  IpLocationData
//
func (component *ip) GetLocation(ctx context.Context, ip string) IpLocationData {
method, _ := g.Cfg().Get(ctx, "hotgo.ipMethod", "cz88")
if method.String() == "whois" {
return component.WhoisLocation(ctx, ip)
}
return component.Cz88Find(ctx, ip)
}

View File

@@ -0,0 +1,161 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package com
import (
"context"
"fmt"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/model"
"github.com/dgrijalva/jwt-go"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"time"
)
type JWT struct{}
var Jwt = new(JWT)
//
//  @Title  为指定用户生成token
//  @Description  主要用于登录成功的jwt鉴权绑定
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   user 用户信息
//  @Param   isRefresh 是否是刷新token
//  @Return  interface{}
//  @Return  error
//
func (component *JWT) GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh bool) (interface{}, error) {
jwtVersion, _ := g.Cfg().Get(ctx, "jwt.version", "1.0")
jwtSign, _ := g.Cfg().Get(ctx, "jwt.sign", "hotGo")
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"id": user.Id,
"username": user.Username,
"realname": user.Realname,
"avatar": user.Avatar,
"email": user.Email,
"mobile": user.Mobile,
"last_time": user.LastTime,
"last_ip": user.LastIp,
"exp": user.Exp,
"expires": user.Expires,
"app": user.App,
"role": user.Role,
"visit_count": user.VisitCount,
"is_refresh": isRefresh,
"jwt_version": jwtVersion.String(),
})
tokenString, err := token.SignedString(jwtSign.Bytes())
if err != nil {
err := gerror.New(err.Error())
return nil, err
}
tokenStringMd5 := gmd5.MustEncryptString(tokenString)
// TODO 绑定登录token
cache := Cache.New()
key := consts.RedisJwtToken + tokenStringMd5
// TODO 将有效期转为持续时间,单位:秒
expires, _ := time.ParseDuration(fmt.Sprintf("+%vs", user.Expires))
err = cache.Set(ctx, key, tokenString, expires)
if err != nil {
err := gerror.New(err.Error())
return nil, err
}
_ = cache.Set(ctx, consts.RedisJwtUserBind+user.App+":"+gconv.String(user.Id), key, expires)
return tokenString, err
}
//
//  @Title  解析token
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   tokenString
//  @Param   secret
//  @Return  jwt.MapClaims
//  @Return  error
//
func (component *JWT) ParseToken(tokenString string, secret []byte) (jwt.MapClaims, error) {
if tokenString == "" {
err := gerror.New("token 为空")
return nil, err
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return secret, nil
})
if token == nil {
err := gerror.New("token不存在")
return nil, err
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return claims, nil
} else {
return nil, err
}
}
/**
token有效正确返回用户id
*/
//func(component *JWT) VerifyLoginToken(tokenString string) (uint, err error) {
// //if tokenString == "" {
// // err = gerror.New("token不能为空")
// // return 0, err
// //}
//
//}
//
//  @Title  获取 authorization
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//  @Return  string
//
func (component *JWT) GetAuthorization(r *ghttp.Request) string {
// TODO 默认从请求头获取
var authorization = r.Header.Get("Authorization")
// TODO 如果请求头不存在则从get参数获取
if authorization == "" {
return r.Get("authorization").String()
}
return gstr.Replace(authorization, "Bearer ", "")
}
/**
清掉所以的相关的redis
*/
func (component *JWT) Layout(adminUserId int, tokenString string) {
if tokenString == "" {
return
}
//g.Redis().Do("HDEL", "VerifyLoginToken", gmd5.MustEncryptString(tokenString))
//// 删除
//g.Redis().Do("HDEL", "VerifyLoginTokenAdminUserId", adminUserId)
}

View File

@@ -0,0 +1,83 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package com
import (
"context"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/database/gredis"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
)
var Redis = new(redis)
type redis struct{}
//
//  @Title  实例化redis
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Param   name
//  @Return  *gredis.Redis
//
func (component *redis) Instance(name ...string) *gredis.Redis {
return g.Redis(name...)
}
//
//  @Title  获取
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   key
//  @Return  *gvar.Var
//  @Return  error
//
func (component *redis) Get(ctx context.Context, key string) (*gvar.Var, error) {
data, err := Redis.Instance().Do(ctx, "GET", key)
if err != nil {
err := gerror.New(err.Error())
return nil, err
}
return data, nil
}
//
//  @Title  设置
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   key
//  @Param   value
//  @Param   expire
//  @Return  *gvar.Var
//  @Return  error
//
func (component *redis) Set(ctx context.Context, key string, value string, expire interface{}) (*gvar.Var, error) {
redisInstance := Redis.Instance()
response, err := redisInstance.Do(ctx, "SET", key, value)
if err != nil {
err := gerror.New(err.Error())
return nil, err
}
exp := gconv.Int(expire)
// TODO 设置有效期
if exp > 0 {
_, err = redisInstance.Do(ctx, "EXPIRE", key, exp)
if err != nil {
err := gerror.New(err.Error())
return nil, err
}
}
return response, nil
}

View File

@@ -0,0 +1,121 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package com
import (
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/model"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"time"
)
var Response = new(response)
type response struct{}
//
//  @Title  返回JSON数据并退出当前HTTP执行函数
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//  @Param   code
//  @Param   message
//  @Param   data
//
func (component *response) JsonExit(r *ghttp.Request, code int, message string, data ...interface{}) {
component.RJson(r, code, message, data...)
r.Exit()
}
//
//  @Title  标准返回结果数据结构封装
//  @Description  返回固定数据结构的JSON
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//  @Param   code 状态码(200:成功,302跳转和http请求状态码一至)
//  @Param   message 请求结果信息
//  @Param   data 请求结果,根据不同接口返回结果的数据结构不同
//
func (component *response) RJson(r *ghttp.Request, code int, message string, data ...interface{}) {
responseData := interface{}(nil)
if len(data) > 0 {
responseData = data[0]
}
Res := &model.Response{
Code: code,
Message: message,
Timestamp: time.Now().Unix(),
ReqId: Context.Get(r.Context()).ReqId,
}
// TODO 如果不是正常的返回则将data转为error
if consts.CodeOK == code {
Res.Data = responseData
} else {
Res.Error = responseData
}
// TODO 清空响应
r.Response.ClearBuffer()
// TODO 写入响应
if err := r.Response.WriteJson(Res); err != nil {
g.Log().Error(r.Context(), "响应异常:", err)
}
// TODO 加入到上下文
Context.SetResponse(r.Context(), Res)
}
//
//  @Title  返回成功JSON
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   isExit
//  @Param   r
//  @Param   message
//  @Param   data
//
func (component *response) SusJson(isExit bool, r *ghttp.Request, message string, data ...interface{}) {
if isExit {
component.JsonExit(r, consts.CodeOK, message, data...)
}
component.RJson(r, consts.CodeOK, message, data...)
}
//
//  @Title  返回失败JSON
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   isExit
//  @Param   r
//  @Param   message
//  @Param   data
//
func (component *response) FailJson(isExit bool, r *ghttp.Request, message string, data ...interface{}) {
if isExit {
component.JsonExit(r, consts.CodeNil, message, data...)
}
component.RJson(r, consts.CodeNil, message, data...)
}
//
//  @Title  重定向
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//  @Param   location
//  @Param   code
//
func (component *response) Redirect(r *ghttp.Request, location string, code ...int) {
r.Response.RedirectTo(location, code...)
}
func (component *response) Download(r *ghttp.Request, location string, code ...int) {
r.Response.ServeFileDownload("test.txt")
}

View File

@@ -0,0 +1,14 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
// 应用类型
const (
AppAdmin = "admin"
AppApi = "api"
AppDefault = "default"
)

View File

@@ -0,0 +1,31 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
// 全局状态码
const (
CodeNil = -1 // No error code specified.
CodeOK = 0 // It is OK.
CodeInternalError = 50 // An error occurred internally.
CodeValidationFailed = 51 // Data validation failed.
CodeDbOperationError = 52 // Database operation error.
CodeInvalidParameter = 53 // The given parameter for current operation is invalid.
CodeMissingParameter = 54 // Parameter for current operation is missing.
CodeInvalidOperation = 55 // The function cannot be used like this.
CodeInvalidConfiguration = 56 // The configuration is invalid for current operation.
CodeMissingConfiguration = 57 // The configuration is missing for current operation.
CodeNotImplemented = 58 // The operation is not implemented yet.
CodeNotSupported = 59 // The operation is not supported yet.
CodeOperationFailed = 60 // I tried, but I cannot give you what you want.
CodeNotAuthorized = 61 // Not Authorized.
CodeSecurityReason = 62 // Security Reason.
CodeServerBusy = 63 // Server is busy, please try again later.
CodeUnknown = 64 // Unknown error.
CodeNotFound = 65 // Resource does not exist.
CodeInvalidRequest = 66 // Invalid request.
CodeBusinessValidationFailed = 300 // Business validation failed.
)

View File

@@ -0,0 +1,12 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
// 上下文
const (
ContextKey = "HotGoContext"
)

View File

@@ -0,0 +1,8 @@
package consts
// 碎片
const (
// 默认分页
DebrisPageSize = 10
)

View File

@@ -0,0 +1,14 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
// 错误解释
const (
ErrorORM = "sql执行异常"
ErrorNotData = "数据不存在"
ErrorRotaPointer = "指针转换异常"
)

View File

@@ -0,0 +1,15 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
// 开放API
const (
OpenAPITitle = `HotGo`
OpenAPIDescription = `这是一个使用HotGo的简单演示HTTP服务器项目。 `
OpenAPIName = `HotGo`
OpenAPIURL = `http://hotgo.bufanyun.cn`
)

View File

@@ -0,0 +1,14 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
// 消息队列
const (
QueueName = `queue:`
QueueLogPath = "queue" // 需要在config中配置queue的log
QueueLogTopic = `request-log`
)

View File

@@ -0,0 +1,13 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
// redis
const (
RedisJwtToken = "jwtToken:" // JWT-token
RedisJwtUserBind = "jwtUserBind:" // JWT-用户身份绑定
)

View File

@@ -0,0 +1,14 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
//
const (
StatusEnabled = "1" // 启用
StatusDisable = "2" // 禁用
StatusDelete = "3" //已删除
)

View File

@@ -0,0 +1,12 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
// 应用版本
const (
VersionApp = "1.0.0"
)

View File

@@ -0,0 +1,172 @@
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/sysService"
"github.com/gogf/gf/v2/util/gconv"
)
var Config = config{}
type config struct{}
//
//  @Title  名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *config) GetValue(ctx context.Context, req *adminForm.ConfigGetValueReq) (*adminForm.ConfigGetValueRes, error) {
data, err := sysService.Config.GetValue(ctx, input.SysConfigGetValueInp{Key: req.Key})
if err != nil {
return nil, err
}
var res adminForm.ConfigGetValueRes
res.Value = data.Value
return &res, nil
}
//
//  @Title  名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *config) NameUnique(ctx context.Context, req *adminForm.ConfigNameUniqueReq) (*adminForm.ConfigNameUniqueRes, error) {
data, err := sysService.Config.NameUnique(ctx, input.SysConfigNameUniqueInp{Id: req.Id, Name: req.Name})
if err != nil {
return nil, err
}
var res adminForm.ConfigNameUniqueRes
res.IsUnique = data.IsUnique
return &res, nil
}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *config) Delete(ctx context.Context, req *adminForm.ConfigDeleteReq) (res *adminForm.ConfigDeleteRes, err error) {
var in input.SysConfigDeleteInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = sysService.Config.Delete(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *config) Edit(ctx context.Context, req *adminForm.ConfigEditReq) (res *adminForm.ConfigEditRes, err error) {
var in input.SysConfigEditInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = sysService.Config.Edit(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *config) MaxSort(ctx context.Context, req *adminForm.ConfigMaxSortReq) (*adminForm.ConfigMaxSortRes, error) {
data, err := sysService.Config.MaxSort(ctx, input.SysConfigMaxSortInp{Id: req.Id})
if err != nil {
return nil, err
}
var res adminForm.ConfigMaxSortRes
res.Sort = data.Sort
return &res, nil
}
//
//  @Title  获取指定信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *config) View(ctx context.Context, req *adminForm.ConfigViewReq) (*adminForm.ConfigViewRes, error) {
data, err := sysService.Config.View(ctx, input.SysConfigViewInp{Id: req.Id})
if err != nil {
return nil, err
}
var res adminForm.ConfigViewRes
res.SysConfigViewModel = data
return &res, nil
}
//
//  @Title  查看列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *config) List(ctx context.Context, req *adminForm.ConfigListReq) (*adminForm.ConfigListRes, error) {
var (
in input.SysConfigListInp
res adminForm.ConfigListRes
)
if err := gconv.Scan(req, &in); err != nil {
return nil, err
}
list, totalCount, err := sysService.Config.List(ctx, in)
if err != nil {
return nil, err
}
res.List = list
res.TotalCount = totalCount
res.Limit = req.Page
res.Limit = req.Limit
return &res, nil
}

View File

@@ -0,0 +1,176 @@
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/adminService"
"github.com/gogf/gf/v2/util/gconv"
)
var Dept = dept{}
type dept struct{}
//
//  @Title  名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dept) NameUnique(ctx context.Context, req *adminForm.DeptNameUniqueReq) (*adminForm.DeptNameUniqueRes, error) {
data, err := adminService.Dept.NameUnique(ctx, input.AdminDeptNameUniqueInp{Id: req.Id, Name: req.Name})
if err != nil {
return nil, err
}
var res adminForm.DeptNameUniqueRes
res.IsUnique = data.IsUnique
return &res, nil
}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dept) Delete(ctx context.Context, req *adminForm.DeptDeleteReq) (res *adminForm.DeptDeleteRes, err error) {
var in input.AdminDeptDeleteInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = adminService.Dept.Delete(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dept) Edit(ctx context.Context, req *adminForm.DeptEditReq) (res *adminForm.DeptEditRes, err error) {
var in input.AdminDeptEditInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = adminService.Dept.Edit(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dept) MaxSort(ctx context.Context, req *adminForm.DeptMaxSortReq) (*adminForm.DeptMaxSortRes, error) {
data, err := adminService.Dept.MaxSort(ctx, input.AdminDeptMaxSortInp{Id: req.Id})
if err != nil {
return nil, err
}
var res adminForm.DeptMaxSortRes
res.Sort = data.Sort
return &res, nil
}
//
//  @Title  获取指定信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dept) View(ctx context.Context, req *adminForm.DeptViewReq) (*adminForm.DeptViewRes, error) {
data, err := adminService.Dept.View(ctx, input.AdminDeptViewInp{Id: req.Id})
if err != nil {
return nil, err
}
var res adminForm.DeptViewRes
res.AdminDeptViewModel = data
return &res, nil
}
//
//  @Title  查看列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dept) List(ctx context.Context, req *adminForm.DeptListReq) (*adminForm.DeptListRes, error) {
var (
in input.AdminDeptListInp
res adminForm.DeptListRes
)
if err := gconv.Scan(req, &in); err != nil {
return nil, err
}
data, err := adminService.Dept.List(ctx, in)
if err != nil {
return nil, err
}
_ = gconv.Structs(data, &res)
return &res, nil
}
//
//  @Title  查看列表树
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dept) ListTree(ctx context.Context, req *adminForm.DeptListTreeReq) (*adminForm.DeptListTreeRes, error) {
var (
in input.AdminDeptListTreeInp
res adminForm.DeptListTreeRes
)
if err := gconv.Scan(req, &in); err != nil {
return nil, err
}
data, err := adminService.Dept.ListTree(ctx, in)
if err != nil {
return nil, err
}
_ = gconv.Structs(data, &res)
return &res, nil
}

View File

@@ -0,0 +1,252 @@
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/service/sysService"
)
var Dict = dict{}
type dict struct{}
//
//  @Title  数据键值是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) DataUnique(ctx context.Context, req *adminForm.DictDataUniqueReq) (res *adminForm.DictDataUniqueRes, err error) {
res, err = sysService.Dict.DataUnique(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  查询字典数据最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) DataMaxSort(ctx context.Context, req *adminForm.DictDataMaxSortReq) (res *adminForm.DictDataMaxSortRes, err error) {
res, err = sysService.Dict.DataMaxSort(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  删除字典数据
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) DataDelete(ctx context.Context, req *adminForm.DictDataDeleteReq) (res *adminForm.DictDataDeleteRes, err error) {
if err = sysService.Dict.DataDelete(ctx, req); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  修改/新增字典数据
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) DataEdit(ctx context.Context, req *adminForm.DictDataEditReq) (res *adminForm.DictDataEditRes, err error) {
if err = sysService.Dict.DataEdit(ctx, req); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  获取指定字典类型信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) DataView(ctx context.Context, req *adminForm.DictDataViewReq) (res *adminForm.DictDataViewRes, err error) {
res, err = sysService.Dict.DataView(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  获取字典数据列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) DataList(ctx context.Context, req *adminForm.DictDataListReq) (res *adminForm.DictDataListRes, err error) {
res, err = sysService.Dict.DataList(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  获取指定字典类型的属性数据
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) Attribute(ctx context.Context, req *adminForm.DictAttributeReq) (res *adminForm.DictAttributeRes, err error) {
res, err = sysService.Dict.Attribute(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  导出字典类型
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) TypeExport(ctx context.Context, req *adminForm.DictTypeExportReq) (res *adminForm.DictTypeExportRes, err error) {
if err = sysService.Dict.TypeExport(ctx, req); err != nil {
return nil, err
}
return
}
//
//  @Title  刷新字典缓存
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) TypeRefreshCache(ctx context.Context, req *adminForm.DictTypeRefreshCacheReq) (res *adminForm.DictTypeRefreshCacheRes, err error) {
return nil, nil
}
//
//  @Title  删除字典类型
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) TypeDelete(ctx context.Context, req *adminForm.DictTypeDeleteReq) (res *adminForm.DictTypeDeleteRes, err error) {
if err = sysService.Dict.TypeDelete(ctx, req); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  修改/新增字典类型
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) TypeEdit(ctx context.Context, req *adminForm.DictTypeEditReq) (res *adminForm.DictTypeEditRes, err error) {
if err = sysService.Dict.TypeEdit(ctx, req); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  类型是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) TypeUnique(ctx context.Context, req *adminForm.DictTypeUniqueReq) (res *adminForm.DictTypeUniqueRes, err error) {
res, err = sysService.Dict.TypeUnique(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  获取指定字典类型信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) TypeView(ctx context.Context, req *adminForm.DictTypeViewReq) (res *adminForm.DictTypeViewRes, err error) {
res, err = sysService.Dict.TypeView(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  获取字典类型列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) TypeList(ctx context.Context, req *adminForm.DictTypeListReq) (res *adminForm.DictTypeListRes, err error) {
res, err = sysService.Dict.TypeList(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}

View File

@@ -0,0 +1,95 @@
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/sysService"
"github.com/gogf/gf/v2/errors/gerror"
)
var Log = log{}
type log struct{}
//
//  @Title  清空日志
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *log) Clear(ctx context.Context, req *adminForm.LogClearReq) (res *adminForm.LogClearRes, err error) {
err = gerror.New("考虑安全,请到数据库清空")
return
}
//
//  @Title  导出
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *log) Export(ctx context.Context, req *adminForm.LogExportReq) (res *adminForm.LogExportRes, err error) {
err = sysService.Log.Export(ctx, input.LogListInp{
Page: req.Page,
Limit: req.Limit,
Module: req.Module,
Method: req.Method,
Url: req.Url,
Ip: req.Ip,
ErrorCode: req.ErrorCode,
StartTime: req.StartTime,
EndTime: req.EndTime,
MemberId: req.MemberId,
TakeUpTime: req.TakeUpTime,
})
if err != nil {
return nil, err
}
return
}
//
//  @Title  获取全局日志列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *log) List(ctx context.Context, req *adminForm.LogListReq) (*adminForm.LogListRes, error) {
list, totalCount, err := sysService.Log.List(ctx, input.LogListInp{
Page: req.Page,
Limit: req.Limit,
Module: req.Module,
Method: req.Method,
Url: req.Url,
Ip: req.Ip,
ErrorCode: req.ErrorCode,
StartTime: req.StartTime,
EndTime: req.EndTime,
MemberId: req.MemberId,
TakeUpTime: req.TakeUpTime,
})
if err != nil {
return nil, err
}
var res adminForm.LogListRes
res.List = list
res.TotalCount = totalCount
res.Limit = req.Page
res.Limit = req.Limit
return &res, nil
}

View File

@@ -0,0 +1,104 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/adminService"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/util/gconv"
)
var Login = login{}
type login struct{}
//
//  @Title  登录验证码
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *login) Captcha(ctx context.Context, req *adminForm.LoginCaptchaReq) (res *adminForm.LoginCaptchaRes, err error) {
// TODO  获取生成的验证码图片
Cid, Base64 := com.Captcha.GetVerifyImgString(ctx)
res = &adminForm.LoginCaptchaRes{Cid: Cid, Base64: Base64}
return
}
//
//  @Title  提交登录
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *login) Sign(ctx context.Context, req *adminForm.LoginReq) (res *adminForm.LoginRes, err error) {
//// 校验 验证码
//if !com.Captcha.VerifyString(req.Cid, req.Code) {
// err = gerror.New("验证码错误")
// return
//}
var in input.AdminMemberLoginSignInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
model, err := adminService.Member.Login(ctx, in)
if err != nil {
return nil, err
}
if err = gconv.Scan(model, &res); err != nil {
return nil, err
}
return
}
//
//  @Title  注销登录
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *login) Logout(ctx context.Context, req *adminForm.LoginLogoutReq) (res *adminForm.LoginLogoutRes, err error) {
var authorization = com.Jwt.GetAuthorization(com.Context.Get(ctx).Request)
// TODO 获取jwtToken
jwtToken := consts.RedisJwtToken + gmd5.MustEncryptString(authorization)
if len(jwtToken) == 0 {
err = gerror.New("当前用户未登录!")
return res, err
}
// TODO  删除登录token
cache := com.Cache.New()
_, err = cache.Remove(ctx, jwtToken)
if err != nil {
return res, err
}
return
}

View File

@@ -0,0 +1,371 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/adminService"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/util/gconv"
)
var Member = member{}
type member struct{}
//
//  @Title  修改登录密码
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) UpdateProfile(ctx context.Context, req *adminForm.MemberUpdateProfileReq) (res *adminForm.MemberUpdateProfileRes, err error) {
var in input.AdminMemberUpdateProfileInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = adminService.Member.UpdateProfile(ctx, in); err != nil {
return nil, err
}
return
}
//
//  @Title  修改登录密码
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) UpdatePwd(ctx context.Context, req *adminForm.MemberUpdatePwdReq) (res *adminForm.MemberUpdatePwdRes, err error) {
memberId := com.Context.Get(ctx).User.Id
if memberId <= 0 {
err := gerror.New("获取用户信息失败!")
return nil, err
}
if err = adminService.Member.
UpdatePwd(ctx, input.AdminMemberUpdatePwdInp{Id: memberId, OldPassword: req.OldPassword, NewPassword: req.NewPassword}); err != nil {
return nil, err
}
return
}
//
//  @Title  获取登录用户的基本信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) Profile(ctx context.Context, req *adminForm.MemberProfileReq) (*adminForm.MemberProfileRes, error) {
var res adminForm.MemberProfileRes
memberId := com.Context.Get(ctx).User.Id
if memberId <= 0 {
err := gerror.New("获取用户信息失败!")
return nil, err
}
// TODO  用户基本信息
memberInfo, err := adminService.Member.View(ctx, input.AdminMemberViewInp{Id: memberId})
if err != nil {
return nil, err
}
res.User = memberInfo
// TODO  所在部门
sysDept, err := adminService.Dept.View(ctx, input.AdminDeptViewInp{Id: memberInfo.DeptId})
if err != nil {
return nil, err
}
res.SysDept = sysDept
// TODO  角色列表
sysRoles, err := adminService.Role.GetMemberList(ctx, memberInfo.Role)
if err != nil {
return nil, err
}
res.SysRoles = sysRoles
// TODO  获取角色名称
roleGroup, err := adminService.Role.GetName(ctx, memberInfo.Role)
if err != nil {
return nil, err
}
res.RoleGroup = roleGroup
// TODO  获取第一岗位名称
postGroup, err := adminService.Post.GetMemberByStartName(ctx, memberInfo.Id)
if err != nil {
return nil, err
}
res.PostGroup = postGroup
return &res, nil
}
//
//  @Title  重置密码
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) ResetPwd(ctx context.Context, req *adminForm.MemberResetPwdReq) (res *adminForm.MemberResetPwdRes, err error) {
if err = adminService.Member.
ResetPwd(ctx, input.AdminMemberResetPwdInp{Id: req.Id, Password: req.Password}); err != nil {
return nil, err
}
return
}
//
//  @Title  邮箱是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) EmailUnique(ctx context.Context, req *adminForm.MemberEmailUniqueReq) (*adminForm.MemberEmailUniqueRes, error) {
data, err := adminService.Member.EmailUnique(ctx, input.AdminMemberEmailUniqueInp{Id: req.Id, Email: req.Email})
if err != nil {
return nil, err
}
var res adminForm.MemberEmailUniqueRes
res.IsUnique = data.IsUnique
return &res, nil
}
//
//  @Title  手机号是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) MobileUnique(ctx context.Context, req *adminForm.MemberMobileUniqueReq) (*adminForm.MemberMobileUniqueRes, error) {
data, err := adminService.Member.MobileUnique(ctx, input.AdminMemberMobileUniqueInp{Id: req.Id, Mobile: req.Mobile})
if err != nil {
return nil, err
}
var res adminForm.MemberMobileUniqueRes
res.IsUnique = data.IsUnique
return &res, nil
}
//
//  @Title  名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) NameUnique(ctx context.Context, req *adminForm.MemberNameUniqueReq) (*adminForm.MemberNameUniqueRes, error) {
data, err := adminService.Member.NameUnique(ctx, input.AdminMemberNameUniqueInp{Id: req.Id, Username: req.Username})
if err != nil {
return nil, err
}
var res adminForm.MemberNameUniqueRes
res.IsUnique = data.IsUnique
return &res, nil
}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) Delete(ctx context.Context, req *adminForm.MemberDeleteReq) (res *adminForm.MemberDeleteRes, err error) {
err = gerror.New("考虑安全暂时不允许删除用户,请选择禁用!")
return nil, err
var in input.AdminMemberDeleteInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = adminService.Member.Delete(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) Edit(ctx context.Context, req *adminForm.MemberEditReq) (res *adminForm.MemberEditRes, err error) {
var in input.AdminMemberEditInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = adminService.Member.Edit(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) MaxSort(ctx context.Context, req *adminForm.MemberMaxSortReq) (*adminForm.MemberMaxSortRes, error) {
data, err := adminService.Member.MaxSort(ctx, input.AdminMemberMaxSortInp{Id: req.Id})
if err != nil {
return nil, err
}
var res adminForm.MemberMaxSortRes
res.Sort = data.Sort
return &res, nil
}
//
//  @Title  获取指定信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) View(ctx context.Context, req *adminForm.MemberViewReq) (*adminForm.MemberViewRes, error) {
postsList, _, err := adminService.Post.List(ctx, input.AdminPostListInp{})
if err != nil {
return nil, err
}
roleList, _, err := adminService.Role.List(ctx, input.AdminRoleListInp{})
if err != nil {
return nil, err
}
var res adminForm.MemberViewRes
res.Posts = postsList
res.Roles = roleList
if req.Id <= 0 {
return &res, err
}
memberInfo, err := adminService.Member.View(ctx, input.AdminMemberViewInp{Id: req.Id})
if err != nil {
return nil, err
}
res.AdminMemberViewModel = memberInfo
res.PostIds, err = adminService.MemberPost.GetMemberByIds(ctx, memberInfo.Id)
if err != nil {
return nil, err
}
res.RoleIds = []int64{memberInfo.Role}
res.DeptName, err = adminService.Dept.GetName(ctx, memberInfo.DeptId)
if err != nil {
return nil, err
}
return &res, nil
}
//
//  @Title  查看列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) List(ctx context.Context, req *adminForm.MemberListReq) (*adminForm.MemberListRes, error) {
var (
in input.AdminMemberListInp
res adminForm.MemberListRes
)
if err := gconv.Scan(req, &in); err != nil {
return nil, err
}
list, totalCount, err := adminService.Member.List(ctx, in)
if err != nil {
return nil, err
}
res.List = list
res.TotalCount = totalCount
res.Limit = req.Page
res.Limit = req.Limit
return &res, nil
}
//
//  @Title  登录用户信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) Info(ctx context.Context, req *adminForm.MemberInfoReq) (res *adminForm.MemberInfoRes, err error) {
return adminService.Member.LoginMemberInfo(ctx, req)
}

View File

@@ -0,0 +1,188 @@
//
// @Link  https://github.com/bufanyun/hotgo
// @Copyright  Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/adminService"
"github.com/gogf/gf/v2/util/gconv"
)
var Menu = menu{}
type menu struct{}
//
//  @Title  查询角色菜单列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *menu) RoleList(ctx context.Context, req *adminForm.MenuRoleListReq) (*adminForm.MenuRoleListRes, error) {
var in input.MenuRoleListInp
if err := gconv.Scan(req, &in); err != nil {
return nil, err
}
data, err := adminService.Menu.RoleList(ctx, in)
if err != nil {
return nil, err
}
var res adminForm.MenuRoleListRes
res.CheckedKeys = data.CheckedKeys
res.Menus = data.Menus
return &res, nil
}
//
//  @Title  查询菜单列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *menu) SearchList(ctx context.Context, req *adminForm.MenuSearchListReq) (res *adminForm.MenuSearchListRes, err error) {
res, err = adminService.Menu.SearchList(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *menu) MaxSort(ctx context.Context, req *adminForm.MenuMaxSortReq) (res *adminForm.MenuMaxSortRes, err error) {
res, err = adminService.Menu.MaxSort(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  菜单名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *menu) NameUnique(ctx context.Context, req *adminForm.MenuNameUniqueReq) (res *adminForm.MenuNameUniqueRes, err error) {
res, err = adminService.Menu.NameUnique(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  菜单编码是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *menu) CodeUnique(ctx context.Context, req *adminForm.MenuCodeUniqueReq) (res *adminForm.MenuCodeUniqueRes, err error) {
res, err = adminService.Menu.CodeUnique(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *menu) Delete(ctx context.Context, req *adminForm.MenuDeleteReq) (res *adminForm.MenuDeleteRes, err error) {
if err = adminService.Menu.Delete(ctx, req); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *menu) Edit(ctx context.Context, req *adminForm.MenuEditReq) (res *adminForm.MenuEditRes, err error) {
if err = adminService.Menu.Edit(ctx, req); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  获取信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *menu) View(ctx context.Context, req *adminForm.MenuViewReq) (res *adminForm.MenuViewRes, err error) {
res, err = adminService.Menu.View(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  获取列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *menu) List(ctx context.Context, req *adminForm.MenuListReq) (res *adminForm.MenuListRes, err error) {
res, err = adminService.Menu.List(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}

View File

@@ -0,0 +1,151 @@
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/adminService"
"github.com/gogf/gf/v2/util/gconv"
)
var Notice = notice{}
type notice struct{}
//
//  @Title  名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *notice) NameUnique(ctx context.Context, req *adminForm.NoticeNameUniqueReq) (*adminForm.NoticeNameUniqueRes, error) {
data, err := adminService.Notice.NameUnique(ctx, input.AdminNoticeNameUniqueInp{Id: req.Id, Title: req.Title})
if err != nil {
return nil, err
}
var res adminForm.NoticeNameUniqueRes
res.IsUnique = data.IsUnique
return &res, nil
}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *notice) Delete(ctx context.Context, req *adminForm.NoticeDeleteReq) (res *adminForm.NoticeDeleteRes, err error) {
var in input.AdminNoticeDeleteInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = adminService.Notice.Delete(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *notice) Edit(ctx context.Context, req *adminForm.NoticeEditReq) (res *adminForm.NoticeEditRes, err error) {
var in input.AdminNoticeEditInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = adminService.Notice.Edit(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *notice) MaxSort(ctx context.Context, req *adminForm.NoticeMaxSortReq) (*adminForm.NoticeMaxSortRes, error) {
data, err := adminService.Notice.MaxSort(ctx, input.AdminNoticeMaxSortInp{Id: req.Id})
if err != nil {
return nil, err
}
var res adminForm.NoticeMaxSortRes
res.Sort = data.Sort
return &res, nil
}
//
//  @Title  获取指定信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *notice) View(ctx context.Context, req *adminForm.NoticeViewReq) (*adminForm.NoticeViewRes, error) {
data, err := adminService.Notice.View(ctx, input.AdminNoticeViewInp{Id: req.Id})
if err != nil {
return nil, err
}
var res adminForm.NoticeViewRes
res.AdminNoticeViewModel = data
return &res, nil
}
//
//  @Title  查看列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *notice) List(ctx context.Context, req *adminForm.NoticeListReq) (*adminForm.NoticeListRes, error) {
var (
in input.AdminNoticeListInp
res adminForm.NoticeListRes
)
if err := gconv.Scan(req, &in); err != nil {
return nil, err
}
list, totalCount, err := adminService.Notice.List(ctx, in)
if err != nil {
return nil, err
}
res.List = list
res.TotalCount = totalCount
res.Limit = req.Page
res.Limit = req.Limit
return &res, nil
}

View File

@@ -0,0 +1,170 @@
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/adminService"
"github.com/gogf/gf/v2/util/gconv"
)
var Post = post{}
type post struct{}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *post) Delete(ctx context.Context, req *adminForm.PostDeleteReq) (res *adminForm.PostDeleteRes, err error) {
var in input.AdminPostDeleteInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = adminService.Post.Delete(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *post) Edit(ctx context.Context, req *adminForm.PostEditReq) (res *adminForm.PostEditRes, err error) {
var in input.AdminPostEditInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = adminService.Post.Edit(ctx, in); err != nil {
return nil, err
}
return res, nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *post) MaxSort(ctx context.Context, req *adminForm.PostMaxSortReq) (*adminForm.PostMaxSortRes, error) {
data, err := adminService.Post.MaxSort(ctx, input.AdminPostMaxSortInp{Id: req.Id})
if err != nil {
return nil, err
}
var res adminForm.PostMaxSortRes
res.Sort = data.Sort
return &res, nil
}
//
//  @Title  名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *post) NameUnique(ctx context.Context, req *adminForm.PostNameUniqueReq) (*adminForm.PostNameUniqueRes, error) {
data, err := adminService.Post.NameUnique(ctx, input.AdminPostNameUniqueInp{Id: req.Id, Name: req.Name})
if err != nil {
return nil, err
}
var res adminForm.PostNameUniqueRes
res.IsUnique = data.IsUnique
return &res, nil
}
//
//  @Title  编码是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *post) CodeUnique(ctx context.Context, req *adminForm.PostCodeUniqueReq) (*adminForm.PostCodeUniqueRes, error) {
data, err := adminService.Post.CodeUnique(ctx, input.AdminPostCodeUniqueInp{Id: req.Id, Code: req.Code})
if err != nil {
return nil, err
}
var res adminForm.PostCodeUniqueRes
res.IsUnique = data.IsUnique
return &res, nil
}
//
//  @Title  获取指定信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *post) View(ctx context.Context, req *adminForm.PostViewReq) (*adminForm.PostViewRes, error) {
data, err := adminService.Post.View(ctx, input.AdminPostViewInp{Id: req.Id})
if err != nil {
return nil, err
}
var res adminForm.PostViewRes
res.AdminPostViewModel = data
return &res, nil
}
//
//  @Title  获取列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *post) List(ctx context.Context, req *adminForm.PostListReq) (*adminForm.PostListRes, error) {
list, totalCount, err := adminService.Post.List(ctx, input.AdminPostListInp{
Page: req.Page,
Limit: req.Limit,
Name: req.Name,
Code: req.Code,
Status: req.Status,
})
if err != nil {
return nil, err
}
var res adminForm.PostListRes
res.List = list
res.TotalCount = totalCount
res.Limit = req.Page
res.Limit = req.Limit
return &res, nil
}

View File

@@ -0,0 +1,95 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminController
import (
"context"
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/adminService"
"github.com/gogf/gf/v2/util/gconv"
)
var Role = role{}
type role struct{}
//
//  @Title  获取角色下的会员列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *role) RoleMemberList(ctx context.Context, req *adminForm.RoleMemberListReq) (*adminForm.RoleMemberListRes, error) {
var in input.AdminRoleMemberListInp
if err := gconv.Scan(req, &in); err != nil {
return nil, err
}
list, totalCount, err := adminService.Member.RoleMemberList(ctx, in)
if err != nil {
return nil, err
}
var res adminForm.RoleMemberListRes
res.List = list
res.TotalCount = totalCount
res.Limit = req.Page
res.Limit = req.Limit
return &res, nil
}
//
//  @Title  获取列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *role) List(ctx context.Context, req *adminForm.RoleListReq) (*adminForm.RoleListRes, error) {
list, totalCount, err := adminService.Role.List(ctx, input.AdminRoleListInp{
Page: req.Page,
Limit: req.Limit,
})
if err != nil {
return nil, err
}
var res adminForm.RoleListRes
res.List = list
res.TotalCount = totalCount
res.Limit = req.Page
res.Limit = req.Limit
return &res, nil
}
//
//  @Title  动态路由
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *role) Dynamic(ctx context.Context, req *adminForm.RoleDynamicReq) (res *adminForm.RoleDynamicRes, err error) {
res, err = adminService.Menu.GetMenuList(ctx, com.Context.GetUserId(ctx))
if err != nil {
return nil, err
}
return res, nil
}

View File

@@ -0,0 +1,95 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package apiController
import (
"context"
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/form/apiForm"
"github.com/bufanyun/hotgo/app/model"
"github.com/gogf/gf/v2/frame/g"
"github.com/xuri/excelize/v2"
"time"
)
var Base = base{}
type base struct{}
//
//  @Title  获取lang信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *base) Lang(ctx context.Context, req *apiForm.BaseLangReq) (res *apiForm.BaseLangRes, err error) {
return
}
//
//  @Title  获取IP归属地信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *base) IpLocation(ctx context.Context, req *apiForm.IpLocationReq) (res *apiForm.IpLocationRes, err error) {
panic("测试panic...")
data := com.Ip.GetLocation(ctx, req.Ip)
res = &apiForm.IpLocationRes{data}
return
}
func (controller *base) Excel(ctx context.Context, req *apiForm.ExportReq) (res *apiForm.ExportRes, err error) {
w := com.Context.Get(ctx).Request.Response
// 文件名
fileName := "demo.xlsx"
// 创建excel文件 第三方excel包
file := excelize.NewFile()
// 填充数据
index := file.NewSheet("Sheet1")
err = file.SetCellValue("Sheet1", "A1", "Hello world.")
if err != nil {
g.Log().Print(ctx, "SetCellValue:", err)
return nil, err
}
err = file.SetCellValue("Sheet1", "B1", 100)
if err != nil {
g.Log().Print(ctx, "SetCellValue2:", err)
return nil, err
}
file.SetActiveSheet(index)
// 设置header头
w.Header().Add("Content-Disposition", "attachment; filename="+fileName)
w.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
// 写入字节数据
err = file.Write(w.Writer)
if err != nil {
g.Log().Print(ctx, "Write:", err)
return nil, err
}
// TODO 加入到上下文
com.Context.SetResponse(ctx, &model.Response{
Code: consts.CodeOK,
Message: "",
Timestamp: time.Now().Unix(),
ReqId: com.Context.Get(ctx).ReqId,
})
//com.Context.Get(ctx).Request.Exit()
return
}

View File

@@ -0,0 +1,29 @@
package apiController
import (
"context"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/service/sysService"
)
var Dict = dict{}
type dict struct{}
//
//  @Title  获取指定字典类型的属性数据
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *dict) Attribute(ctx context.Context, req *adminForm.DictAttributeReq) (res *adminForm.DictAttributeRes, err error) {
res, err = sysService.Dict.Attribute(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}

View File

@@ -0,0 +1,95 @@
package apiController
import (
"context"
"github.com/bufanyun/hotgo/app/form/apiForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/sysService"
"github.com/gogf/gf/v2/errors/gerror"
)
var Log = log{}
type log struct{}
//
//  @Title  清空日志
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *log) Clear(ctx context.Context, req *apiForm.LogClearReq) (res *apiForm.LogClearRes, err error) {
err = gerror.New("考虑安全,请到数据库清空")
return
}
//
//  @Title  导出
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *log) Export(ctx context.Context, req *apiForm.LogExportReq) (res *apiForm.LogExportRes, err error) {
err = sysService.Log.Export(ctx, input.LogListInp{
Page: req.Page,
Limit: req.Limit,
Module: req.Module,
Method: req.Method,
Url: req.Url,
Ip: req.Ip,
ErrorCode: req.ErrorCode,
StartTime: req.StartTime,
EndTime: req.EndTime,
MemberId: req.MemberId,
TakeUpTime: req.TakeUpTime,
})
if err != nil {
return nil, err
}
return
}
//
//  @Title  获取全局日志列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *log) List(ctx context.Context, req *apiForm.LogListReq) (*apiForm.LogListRes, error) {
list, totalCount, err := sysService.Log.List(ctx, input.LogListInp{
Page: req.Page,
Limit: req.Limit,
Module: req.Module,
Method: req.Method,
Url: req.Url,
Ip: req.Ip,
ErrorCode: req.ErrorCode,
StartTime: req.StartTime,
EndTime: req.EndTime,
MemberId: req.MemberId,
TakeUpTime: req.TakeUpTime,
})
if err != nil {
return nil, err
}
var res apiForm.LogListRes
res.List = list
res.TotalCount = totalCount
res.Limit = req.Page
res.Limit = req.Limit
return &res, nil
}

View File

@@ -0,0 +1,98 @@
package apiController
import (
"context"
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/form/apiForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/adminService"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/util/gconv"
)
var Login = login{}
type login struct{}
//
//  @Title  检查登录
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *login) Check(ctx context.Context, req *apiForm.LoginCheckReq) (*apiForm.LoginCheckRes, error) {
var res apiForm.LoginCheckRes
res.IsValidCodeLogin = false
res.Result = "login"
return &res, nil
}
//
//  @Title  提交登录
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *login) Sign(ctx context.Context, req *apiForm.LoginReq) (res *apiForm.LoginRes, err error) {
//// 校验 验证码
//if !com.Captcha.VerifyString(req.Cid, req.Code) {
// err = gerror.New("验证码错误")
// return
//}
var in input.AdminMemberLoginSignInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
model, err := adminService.Member.Login(ctx, in)
if err != nil {
return nil, err
}
if err = gconv.Scan(model, &res); err != nil {
return nil, err
}
return
}
//
//  @Title  注销登录
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *login) Logout(ctx context.Context, req *apiForm.LoginLogoutReq) (res *apiForm.LoginLogoutRes, err error) {
var authorization = com.Jwt.GetAuthorization(com.Context.Get(ctx).Request)
// TODO 获取jwtToken
jwtToken := consts.RedisJwtToken + gmd5.MustEncryptString(authorization)
if len(jwtToken) == 0 {
err = gerror.New("当前用户未登录!")
return res, err
}
// TODO  删除登录token
cache := com.Cache.New()
_, err = cache.Remove(ctx, jwtToken)
if err != nil {
return res, err
}
return
}

View File

@@ -0,0 +1,71 @@
package apiController
import (
"context"
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/form/apiForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/adminService"
"github.com/gogf/gf/v2/errors/gerror"
)
var Member = member{}
type member struct{}
//
//  @Title  获取登录用户的基本信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (controller *member) Profile(ctx context.Context, req *apiForm.MemberProfileReq) (*apiForm.MemberProfileRes, error) {
var res apiForm.MemberProfileRes
memberId := com.Context.Get(ctx).User.Id
if memberId <= 0 {
err := gerror.New("获取用户信息失败!")
return nil, err
}
// TODO  用户基本信息
memberInfo, err := adminService.Member.View(ctx, input.AdminMemberViewInp{Id: memberId})
if err != nil {
return nil, err
}
res.User = memberInfo
// TODO  所在部门
sysDept, err := adminService.Dept.View(ctx, input.AdminDeptViewInp{Id: memberInfo.DeptId})
if err != nil {
return nil, err
}
res.SysDept = sysDept
// TODO  角色列表
sysRoles, err := adminService.Role.GetMemberList(ctx, memberInfo.Role)
if err != nil {
return nil, err
}
res.SysRoles = sysRoles
// TODO  获取角色名称
roleGroup, err := adminService.Role.GetName(ctx, memberInfo.Role)
if err != nil {
return nil, err
}
res.RoleGroup = roleGroup
// TODO  获取第一岗位名称
postGroup, err := adminService.Post.GetMemberByStartName(ctx, memberInfo.Id)
if err != nil {
return nil, err
}
res.PostGroup = postGroup
return &res, nil
}

View File

@@ -0,0 +1,246 @@
package queue
import (
"context"
"fmt"
"github.com/Shopify/sarama"
"github.com/bufanyun/hotgo/app/utils"
"github.com/gogf/gf/v2/errors/gerror"
"sync"
"time"
)
type KafkaMq struct {
endPoints []string
Partitions int32
producerIns sarama.AsyncProducer
consumerIns sarama.ConsumerGroup
}
type KafkaConfig struct {
ClientId string
Brokers []string
GroupID string
Partitions int32
Replication int16
Version string
UserName string
Password string
}
var wg sync.WaitGroup
// SendMsg 按字符串类型生产数据
func (r *KafkaMq) SendMsg(topic string, body string) (mqMsg MqMsg, err error) {
return r.SendByteMsg(topic, []byte(body))
}
// SendByteMsg 生产数据
func (r *KafkaMq) SendByteMsg(topic string, body []byte) (mqMsg MqMsg, err error) {
msg := &sarama.ProducerMessage{
Topic: topic,
Value: sarama.ByteEncoder(body),
Timestamp: time.Now(),
}
if r.producerIns == nil {
return mqMsg, gerror.New("queue kafka producerIns is nil")
}
r.producerIns.Input() <- msg
ctx, cancle := context.WithTimeout(context.Background(), 5*time.Second)
defer cancle()
select {
case info := <-r.producerIns.Successes():
return MqMsg{
RunType: SendMsg,
Topic: info.Topic,
Offset: info.Offset,
Partition: info.Partition,
Timestamp: info.Timestamp,
}, nil
case fail := <-r.producerIns.Errors():
if nil != fail {
return mqMsg, fail.Err
}
case <-ctx.Done():
return mqMsg, gerror.New("send mqMst timeout")
}
return mqMsg, nil
}
// ListenReceiveMsgDo 消费数据
func (r *KafkaMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg)) (err error) {
if r.consumerIns == nil {
return gerror.New("queue kafka consumer not register")
}
consumer := Consumer{
ready: make(chan bool),
receiveDoFun: receiveDo,
}
ctx, cancel := context.WithCancel(context.Background())
go func() {
for {
if err := r.consumerIns.Consume(ctx, []string{topic}, &consumer); err != nil {
FatalLog(ctx, "kafka Error from consumer", err)
}
if ctx.Err() != nil {
Log(ctx, fmt.Sprint("kafka consoumer stop : %v", ctx.Err()))
return
}
consumer.ready = make(chan bool)
}
}()
<-consumer.ready // Await till the consumer has been set up
Log(ctx, "kafka consumer up and running!...")
utils.Signal.AppDefer(func() {
Log(ctx, "kafka consumer close...")
cancel()
if err = r.consumerIns.Close(); err != nil {
FatalLog(ctx, "kafka Error closing client", err)
}
})
return
}
// RegisterRedisMqConsumerMust 注册消费者
func RegisterKafkaMqConsumerMust(connOpt KafkaConfig) (client MqConsumer) {
mqIns := &KafkaMq{}
kfkVersion, _ := sarama.ParseKafkaVersion(connOpt.Version)
if validateVersion(kfkVersion) == false {
kfkVersion = sarama.V2_4_0_0
}
brokers := connOpt.Brokers
config := sarama.NewConfig()
config.Consumer.Return.Errors = true
config.Version = kfkVersion
if connOpt.UserName != "" {
config.Net.SASL.Enable = true
config.Net.SASL.User = connOpt.UserName
config.Net.SASL.Password = connOpt.Password
}
// 默认按随机方式消费
config.Consumer.Group.Rebalance.Strategy = sarama.BalanceStrategyRange
config.Consumer.Offsets.Initial = sarama.OffsetNewest
config.Consumer.Offsets.AutoCommit.Interval = 10 * time.Millisecond
config.ClientID = connOpt.ClientId
consumerClient, err := sarama.NewConsumerGroup(brokers, connOpt.GroupID, config)
if err != nil {
panic(err)
}
mqIns.consumerIns = consumerClient
return mqIns
}
// RegisterKafkaProducerMust 注册并启动生产者接口实现
func RegisterKafkaProducerMust(connOpt KafkaConfig) (client MqProducer) {
mqIns := &KafkaMq{}
connOpt.ClientId = "HOTGO-Producer"
RegisterKafkaProducer(connOpt, mqIns) //这里如果使用go程需要处理chan同步问题
return mqIns
}
// RegisterKafkaProducerAsync 注册同步类型实例
func RegisterKafkaProducer(connOpt KafkaConfig, mqIns *KafkaMq) {
kfkVersion, _ := sarama.ParseKafkaVersion(connOpt.Version)
if validateVersion(kfkVersion) == false {
kfkVersion = sarama.V2_4_0_0
}
brokers := connOpt.Brokers
config := sarama.NewConfig()
// 等待服务器所有副本都保存成功后的响应
config.Producer.RequiredAcks = sarama.WaitForAll
// 随机向partition发送消息
config.Producer.Partitioner = sarama.NewRandomPartitioner
// 是否等待成功和失败后的响应,只有上面的RequireAcks设置不是NoReponse这里才有用.
config.Producer.Return.Successes = true
config.Producer.Return.Errors = true
config.Producer.Compression = sarama.CompressionNone
config.ClientID = connOpt.ClientId
config.Version = kfkVersion
if connOpt.UserName != "" {
config.Net.SASL.Enable = true
config.Net.SASL.User = connOpt.UserName
config.Net.SASL.Password = connOpt.Password
}
var err error
mqIns.producerIns, err = sarama.NewAsyncProducer(brokers, config)
if err != nil {
panic(err)
}
utils.Signal.AppDefer(func() {
Log(ctx, "kafka producer AsyncClose...")
mqIns.producerIns.AsyncClose()
})
}
// validateVersion 验证版本是否有效
func validateVersion(version sarama.KafkaVersion) bool {
for _, item := range sarama.SupportedVersions {
if version.String() == item.String() {
return true
}
}
return false
}
type Consumer struct {
ready chan bool
receiveDoFun func(mqMsg MqMsg)
}
// Setup is run at the beginning of a new session, before ConsumeClaim
func (consumer *Consumer) Setup(sarama.ConsumerGroupSession) error {
// Mark the consumer as ready
close(consumer.ready)
return nil
}
// Cleanup is run at the end of a session, once all ConsumeClaim goroutines have exited
func (consumer *Consumer) Cleanup(sarama.ConsumerGroupSession) error {
return nil
}
// ConsumeClaim must start a consumer loop of ConsumerGroupClaim's Messages().
func (consumer *Consumer) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {
// NOTE:
// Do not move the code below to a goroutine.
// The `ConsumeClaim` itself is called within a goroutine, see:
// https://github.com/Shopify/sarama/blob/master/consumer_group.go#L27-L29
// `ConsumeClaim` 方法已经是 goroutine 调用 不要在该方法内进行 goroutine
for message := range claim.Messages() {
consumer.receiveDoFun(MqMsg{
RunType: ReceiveMsg,
Topic: message.Topic,
Body: message.Value,
Offset: message.Offset,
Timestamp: message.Timestamp,
Partition: message.Partition,
})
session.MarkMessage(message, "")
}
return nil
}

View File

@@ -0,0 +1,63 @@
package queue
import (
"container/list"
"sync"
)
type Queue struct {
l *list.List
m sync.Mutex
}
func NewQueue() *Queue {
return &Queue{l: list.New()}
}
func (q *Queue) LPush(v interface{}) {
if v == nil {
return
}
q.m.Lock()
defer q.m.Unlock()
q.l.PushFront(v)
}
func (q *Queue) RPush(v interface{}) {
if v == nil {
return
}
q.m.Lock()
defer q.m.Unlock()
q.l.PushBack(v)
}
func (q *Queue) LPop() interface{} {
q.m.Lock()
defer q.m.Unlock()
element := q.l.Front()
if element == nil {
return nil
}
q.l.Remove(element)
return element.Value
}
func (q *Queue) RPop() interface{} {
q.m.Lock()
defer q.m.Unlock()
element := q.l.Back()
if element == nil {
return nil
}
q.l.Remove(element)
return element.Value
}
func (q *Queue) Len() int {
return q.l.Len()
}

View File

@@ -0,0 +1,39 @@
package queue
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
)
// 消费日志
func ConsumerLog(ctx context.Context, topic string, mqMsg MqMsg, err error) {
if err != nil {
g.Log(consts.QueueLogPath).Error(ctx, "消费 ["+topic+"] 失败", mqMsg, err)
} else {
g.Log(consts.QueueLogPath).Print(ctx, "消费 ["+topic+"] 成功", mqMsg.MsgId)
}
}
// 生产日志
func ProducerLog(ctx context.Context, topic string, data interface{}, err error) {
if err != nil {
g.Log(consts.QueueLogPath).Error(ctx, "生产 ["+topic+"] 失败", gconv.String(data))
} else {
g.Log(consts.QueueLogPath).Print(ctx, "生产 ["+topic+"] 成功", gconv.String(data))
}
}
// 致命日志
func FatalLog(ctx context.Context, text string, err error) {
g.Log(consts.QueueLogPath).Fatal(ctx, text+":", err)
}
// 通用
func Log(ctx context.Context, text string) {
g.Log(consts.QueueLogPath).Print(ctx, text)
}

View File

@@ -0,0 +1,248 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package queue
import (
"github.com/bufanyun/hotgo/app/utils"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"sync"
"time"
)
//
//  MqProducer
//  @Description 
//
type MqProducer interface {
SendMsg(topic string, body string) (mqMsg MqMsg, err error)
SendByteMsg(topic string, body []byte) (mqMsg MqMsg, err error)
}
//
//  MqConsumer
//  @Description 
//
type MqConsumer interface {
ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg)) (err error)
}
const (
_ = iota
SendMsg
ReceiveMsg
)
type MqMsg struct {
RunType int `json:"run_type"`
Topic string `json:"topic"`
MsgId string `json:"msg_id"`
Offset int64 `json:"offset"`
Partition int32 `json:"partition"`
Timestamp time.Time `json:"timestamp"`
Body []byte `json:"body"`
}
var (
ctx = gctx.New()
mqProducerInstanceMap map[string]MqProducer
mqConsumerInstanceMap map[string]MqConsumer
mutex sync.Mutex
)
func init() {
mqProducerInstanceMap = make(map[string]MqProducer)
mqConsumerInstanceMap = make(map[string]MqConsumer)
}
//
//  @Title  实例化消费者
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Return  mqClient
//  @Return  err
//
func InstanceConsumer() (mqClient MqConsumer, err error) {
groupName, _ := g.Cfg().Get(ctx, "queue.groupName", "hotgo")
return NewConsumer(groupName.String())
}
//
//  @Title  实例化生产者
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Return  mqClient
//  @Return  err
//
func InstanceProducer() (mqClient MqProducer, err error) {
groupName, _ := g.Cfg().Get(ctx, "queue.groupName", "hotgo")
return NewProducer(groupName.String())
}
//
//  @Title  新建一个生产者实例
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Param   groupName
//  @Return  mqClient
//  @Return  err
//
func NewProducer(groupName string) (mqClient MqProducer, err error) {
if item, ok := mqProducerInstanceMap[groupName]; ok {
return item, nil
}
if groupName == "" {
return mqClient, gerror.New("mq groupName is empty.")
}
// 驱动
driver, _ := g.Cfg().Get(ctx, "queue.driver", "")
// 重试次数
retryCount, _ := g.Cfg().Get(ctx, "queue.retry", 2)
retry := retryCount.Int()
switch driver.String() {
case "rocketmq":
address, _ := g.Cfg().Get(ctx, "queue.rocketmq.address", nil)
if len(address.Strings()) == 0 {
panic("queue rocketmq address is not support")
}
mqClient = RegisterRocketProducerMust(address.Strings(), groupName, retry)
case "kafka":
address, _ := g.Cfg().Get(ctx, "queue.kafka.address", nil)
if len(address.Strings()) == 0 {
panic("queue kafka address is not support")
}
version, _ := g.Cfg().Get(ctx, "queue.kafka.version", "2.0.0")
mqClient = RegisterKafkaProducerMust(KafkaConfig{
Brokers: address.Strings(),
GroupID: groupName,
Version: version.String(),
})
case "redis":
address, _ := g.Cfg().Get(ctx, "queue.redis.address", nil)
if len(address.String()) == 0 {
panic("queue redis address is not support")
}
db, _ := g.Cfg().Get(ctx, "queue.redis.db", 0)
pass, _ := g.Cfg().Get(ctx, "queue.redis.pass", "")
timeout, _ := g.Cfg().Get(ctx, "queue.redis.timeout", 0)
mqClient = RegisterRedisMqProducerMust(RedisOption{
Addr: address.String(),
Passwd: pass.String(),
DBnum: db.Int(),
Timeout: timeout.Int(),
}, PoolOption{
5, 50, 5,
}, groupName, retry)
default:
panic("queue driver is not support")
}
mutex.Lock()
defer mutex.Unlock()
mqProducerInstanceMap[groupName] = mqClient
return mqClient, nil
}
//
//  @Title  新建一个消费者实例
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Param   groupName
//  @Return  mqClient
//  @Return  err
//
func NewConsumer(groupName string) (mqClient MqConsumer, err error) {
// 是否支持创建多个消费者
multiComsumer, _ := g.Cfg().Get(ctx, "queue.multiComsumer", true)
randTag := string(utils.Charset.RandomCreateBytes(6))
if multiComsumer.Bool() == false {
randTag = "001"
}
if item, ok := mqConsumerInstanceMap[groupName+"-"+randTag]; ok {
return item, nil
}
driver, _ := g.Cfg().Get(ctx, "queue.driver", "")
if groupName == "" {
return mqClient, gerror.New("mq groupName is empty.")
}
switch driver.String() {
case "rocketmq":
address, _ := g.Cfg().Get(ctx, "queue.rocketmq.address", nil)
if address == nil {
return nil, gerror.New("queue.rocketmq.address is empty.")
}
mqClient = RegisterRocketConsumerMust(address.Strings(), groupName)
case "kafka":
address, _ := g.Cfg().Get(ctx, "queue.kafka.address", nil)
if len(address.Strings()) == 0 {
panic("queue kafka address is not support")
}
version, _ := g.Cfg().Get(ctx, "queue.kafka.version", "2.0.0")
clientId := "HOTGO-Consumer-" + groupName
randClient, _ := g.Cfg().Get(ctx, "queue.kafka.randClient", true)
if randClient.Bool() {
clientId += "-" + randTag
}
mqClient = RegisterKafkaMqConsumerMust(KafkaConfig{
Brokers: address.Strings(),
GroupID: groupName,
Version: version.String(),
ClientId: clientId,
})
case "redis":
address, _ := g.Cfg().Get(ctx, "queue.redis.address", nil)
if len(address.String()) == 0 {
panic("queue redis address is not support")
}
db, _ := g.Cfg().Get(ctx, "queue.redis.db", 0)
pass, _ := g.Cfg().Get(ctx, "queue.redis.pass", "")
timeout, _ := g.Cfg().Get(ctx, "queue.redis.pass", 0)
mqClient = RegisterRedisMqConsumerMust(RedisOption{
Addr: address.String(),
Passwd: pass.String(),
DBnum: db.Int(),
Timeout: timeout.Int(),
}, PoolOption{
5, 50, 5,
}, groupName)
default:
panic("queue driver is not support")
}
mutex.Lock()
defer mutex.Unlock()
mqConsumerInstanceMap[groupName] = mqClient
return mqClient, nil
}
//
//  @Title  返回消息体
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Return  string
//
func (m *MqMsg) BodyString() string {
return string(m.Body)
}

View File

@@ -0,0 +1,133 @@
package queue
import (
"fmt"
"testing"
"time"
)
func TestRPushQueue(t *testing.T) {
ll := NewQueue()
ll.RPush("1")
ll.RPush("2")
ll.RPush("3")
go func() {
ll.RPush("4")
}()
go func() {
ll.RPush("5")
}()
go func() {
ll.RPush("6")
}()
time.Sleep(1 * time.Second)
if ll.Len() != 6 {
t.Error("list Len() do error #1")
}
listVal := fmt.Sprintf("num=>%v,%v,%v", ll.LPop(), ll.LPop(), ll.LPop())
if listVal != "num=>1,2,3" {
t.Error("list do error #2")
}
if ll.Len() != 3 {
t.Error("list Len() do error #3")
}
ll.LPop()
ll.LPop()
ll.LPop()
c := ll.LPop()
if c != nil {
t.Error("list LPop() do error #4")
}
time.Sleep(1 * time.Second)
}
func TestLPushQueue(t *testing.T) {
ll := NewQueue()
ll.LPush("1")
ll.LPush("2")
ll.LPush("3")
go func() {
ll.LPush("4")
}()
go func() {
ll.LPush("5")
}()
go func() {
ll.LPush("6")
}()
time.Sleep(1 * time.Second)
if ll.Len() != 6 {
t.Error("list Len() do error #1")
}
listVal := fmt.Sprintf("num=>%v,%v,%v", ll.RPop(), ll.RPop(), ll.RPop())
if listVal != "num=>1,2,3" {
t.Error("list do error #2")
}
if ll.Len() != 3 {
t.Error("list Len() do error #3")
}
ll.RPop()
ll.RPop()
ll.RPop()
c := ll.RPop()
if c != nil {
t.Error("list RPop() do error #4")
}
time.Sleep(1 * time.Second)
}
func TestRegisterRocketMqProducer(t *testing.T) {
ins, err := RegisterRocketMqProducer([]string{}, "tests", 2)
if err == nil {
t.Error("RegisterRocketMqProducer err #1")
}
ins, err = RegisterRocketMqProducer([]string{"192.168.1.1:9876"}, "tests", 2)
if err != nil {
t.Error("RegisterRocketMqProducer err #2")
}
if ins.endPoints[0] != "192.168.1.1:9876" {
t.Error("RegisterRocketMqProducer err #3")
}
}
func TestRegisterRocketMqConsumer(t *testing.T) {
ins, err := RegisterRocketMqConsumer([]string{}, "tests")
if err == nil {
t.Error("RegisterRocketMqConsumer err #1")
}
ins, err = RegisterRocketMqProducer([]string{"192.168.1.1:9876"}, "tests", 2)
if err != nil {
t.Error("RegisterRocketMqConsumer err #2")
}
if ins.endPoints[0] != "192.168.1.1:9876" {
t.Error("RegisterRocketMqConsumer err #3")
}
}

View File

@@ -0,0 +1,284 @@
package queue
import (
"encoding/json"
"fmt"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/utils"
"github.com/bufanyun/pool"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gomodule/redigo/redis"
"math/rand"
"time"
)
type RedisMq struct {
poolName string
groupName string
retry int
timeout int
}
type PoolOption struct {
InitCap int
MaxCap int
IdleTimeout int
}
type RedisOption struct {
Addr string
Passwd string
DBnum int
Timeout int
}
var redisPoolMap map[string]pool.Pool
func init() {
redisPoolMap = make(map[string]pool.Pool)
}
// SendMsg 按字符串类型生产数据
func (r *RedisMq) SendMsg(topic string, body string) (mqMsg MqMsg, err error) {
return r.SendByteMsg(topic, []byte(body))
}
// SendByteMsg 生产数据
func (r *RedisMq) SendByteMsg(topic string, body []byte) (mqMsg MqMsg, err error) {
if r.poolName == "" {
return mqMsg, gerror.New("RedisMq producer not register")
}
if topic == "" {
return mqMsg, gerror.New("RedisMq topic is empty")
}
msgId := getRandMsgId()
rdx, put, err := getRedis(r.poolName, r.retry)
defer put()
if err != nil {
return mqMsg, gerror.New(fmt.Sprint("queue redis 生产者获取redis实例失败:", err))
}
mqMsg = MqMsg{
RunType: SendMsg,
Topic: topic,
MsgId: msgId,
Body: body,
}
mqMsgJson, err := json.Marshal(mqMsg)
if err != nil {
return mqMsg, gerror.New(fmt.Sprint("queue redis 生产者解析json消息失败:", err))
}
queueName := r.genQueueName(r.groupName, topic)
_, err = redis.Int64(rdx.Do("LPUSH", queueName, mqMsgJson))
if err != nil {
return mqMsg, gerror.New(fmt.Sprint("queue redis 生产者添加消息失败:", err))
}
if r.timeout > 0 {
_, err = rdx.Do("EXPIRE", queueName, r.timeout)
if err != nil {
return mqMsg, gerror.New(fmt.Sprint("queue redis 生产者设置过期时间失败:", err))
}
}
return
}
// ListenReceiveMsgDo 消费数据
func (r *RedisMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg)) (err error) {
if r.poolName == "" {
return gerror.New("RedisMq producer not register")
}
if topic == "" {
return gerror.New("RedisMq topic is empty")
}
queueName := r.genQueueName(r.groupName, topic)
go func() {
for range time.Tick(1000 * time.Millisecond) {
mqMsgList := r.loopReadQueue(queueName)
for _, mqMsg := range mqMsgList {
receiveDo(mqMsg)
}
}
}()
return
}
// 生成队列名称
func (r *RedisMq) genQueueName(groupName string, topic string) string {
return fmt.Sprintf(consts.QueueName+"%s-%s", groupName, topic)
}
func (r *RedisMq) loopReadQueue(queueName string) (mqMsgList []MqMsg) {
rdx, put, err := getRedis(r.poolName, r.retry)
defer put()
if err != nil {
return
}
for {
infoByte, err := redis.Bytes(rdx.Do("RPOP", queueName))
if err != nil || len(infoByte) == 0 {
break
}
var mqMsg MqMsg
json.Unmarshal(infoByte, &mqMsg)
if mqMsg.MsgId != "" {
mqMsgList = append(mqMsgList, mqMsg)
}
}
return mqMsgList
}
func RegisterRedisMqProducerMust(connOpt RedisOption, poolOpt PoolOption, groupName string, retry int) (client MqProducer) {
var err error
client, err = RegisterRedisMq(connOpt, poolOpt, groupName, retry)
if err != nil {
panic(err)
}
return client
}
// RegisterRedisMqConsumerMust 注册消费者
func RegisterRedisMqConsumerMust(connOpt RedisOption, poolOpt PoolOption, groupName string) (client MqConsumer) {
var err error
client, err = RegisterRedisMq(connOpt, poolOpt, groupName, 0)
if err != nil {
panic(err)
}
return client
}
// RegisterRedisMq 注册redismq实例
func RegisterRedisMq(connOpt RedisOption, poolOpt PoolOption, groupName string, retry int) (mqIns *RedisMq, err error) {
poolName, err := registerRedis(connOpt.Addr, connOpt.Passwd, connOpt.DBnum, poolOpt)
if err != nil {
return
}
if retry <= 0 {
retry = 0
}
mqIns = &RedisMq{
poolName: poolName,
groupName: groupName,
retry: retry,
timeout: connOpt.Timeout,
}
return mqIns, nil
}
// RegisterRedis 注册一个redis配置
func registerRedis(host, pass string, dbnum int, opt PoolOption) (poolName string, err error) {
poolName = utils.Charset.Md5ToString(fmt.Sprintf("%s-%s-%d", host, pass, dbnum))
if _, ok := redisPoolMap[poolName]; ok {
return poolName, nil
}
connRedis := func() (interface{}, error) {
conn, err := redis.Dial("tcp", host)
if err != nil {
return nil, err
}
if pass != "" {
_, err := conn.Do("AUTH", pass)
if err != nil {
return nil, err
}
}
if dbnum > 0 {
_, err := conn.Do("SELECT", dbnum)
if err != nil {
return nil, err
}
}
return conn, err
}
// closeRedis 关闭连接
closeRedis := func(v interface{}) error {
return v.(redis.Conn).Close()
}
// pingRedis 检测连接连通性
pingRedis := func(v interface{}) error {
conn := v.(redis.Conn)
val, err := redis.String(conn.Do("PING"))
if err != nil {
return err
}
if val != "PONG" {
return gerror.New("queue redis ping is error ping => " + val)
}
return nil
}
p, err := pool.NewChannelPool(&pool.Config{
InitialCap: opt.InitCap,
MaxCap: opt.MaxCap,
Factory: connRedis,
Close: closeRedis,
Ping: pingRedis,
IdleTimeout: time.Duration(opt.IdleTimeout) * time.Second,
})
if err != nil {
return poolName, err
}
mutex.Lock()
defer mutex.Unlock()
redisPoolMap[poolName] = p
return poolName, nil
}
// getRedis 获取一个redis db连接
func getRedis(poolName string, retry int) (db redis.Conn, put func(), err error) {
put = func() {}
if _, ok := redisPoolMap[poolName]; ok == false {
return nil, put, gerror.New("db connect is nil")
}
redisPool := redisPoolMap[poolName]
conn, err := redisPool.Get()
for i := 0; i < retry; i++ {
if err == nil {
break
}
conn, err = redisPool.Get()
time.Sleep(time.Second)
}
if err != nil {
return nil, put, err
}
put = func() {
redisPool.Put(conn)
}
db = conn.(redis.Conn)
return db, put, nil
}
func getRandMsgId() (msgId string) {
rand.Seed(time.Now().UnixNano())
radium := rand.Intn(999) + 1
timeCode := time.Now().UnixNano()
msgId = fmt.Sprintf("%d%.4d", timeCode, radium)
return msgId
}

View File

@@ -0,0 +1,165 @@
package queue
import (
"context"
"errors"
"fmt"
"github.com/apache/rocketmq-client-go/v2"
"github.com/apache/rocketmq-client-go/v2/consumer"
"github.com/apache/rocketmq-client-go/v2/primitive"
"github.com/apache/rocketmq-client-go/v2/producer"
"github.com/apache/rocketmq-client-go/v2/rlog"
"github.com/gogf/gf/v2/frame/g"
)
type RocketMq struct {
endPoints []string
producerIns rocketmq.Producer
consumerIns rocketmq.PushConsumer
}
// 重写日志
func rewriteLog() {
level, _ := g.Cfg().Get(ctx, "queue.rocketmq.logLevel", "debug")
rlog.SetLogger(&RocketMqLogger{Flag: "[rocket_mq]", LevelLog: level.String()})
}
// RegisterRocketProducerMust 注册并启动生产者接口实现
func RegisterRocketProducerMust(endPoints []string, groupName string, retry int) (client MqProducer) {
rewriteLog()
var err error
client, err = RegisterRocketMqProducer(endPoints, groupName, retry)
if err != nil {
panic(err)
}
return client
}
// RegisterRocketConsumerMust 注册消费者
func RegisterRocketConsumerMust(endPoints []string, groupName string) (client MqConsumer) {
rewriteLog()
var err error
client, err = RegisterRocketMqConsumer(endPoints, groupName)
if err != nil {
panic(err)
}
return client
}
// SendMsg 按字符串类型生产数据
func (r *RocketMq) SendMsg(topic string, body string) (mqMsg MqMsg, err error) {
return r.SendByteMsg(topic, []byte(body))
}
// SendByteMsg 生产数据
func (r *RocketMq) SendByteMsg(topic string, body []byte) (mqMsg MqMsg, err error) {
if r.producerIns == nil {
return mqMsg, errors.New("RocketMq producer not register")
}
result, err := r.producerIns.SendSync(context.Background(), &primitive.Message{
Topic: topic,
Body: body,
})
if err != nil {
return
}
if result.Status != primitive.SendOK {
return mqMsg, errors.New(fmt.Sprintf("RocketMq producer send msg error status:%v", result.Status))
}
mqMsg = MqMsg{
RunType: SendMsg,
Topic: topic,
MsgId: result.MsgID,
Body: body,
}
return mqMsg, nil
}
// ListenReceiveMsgDo 消费数据
func (r *RocketMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg)) (err error) {
if r.consumerIns == nil {
return errors.New("RocketMq consumer not register")
}
err = r.consumerIns.Subscribe(topic, consumer.MessageSelector{}, func(ctx context.Context,
msgs ...*primitive.MessageExt) (consumer.ConsumeResult, error) {
for _, item := range msgs {
go receiveDo(MqMsg{
RunType: ReceiveMsg,
Topic: item.Topic,
MsgId: item.MsgId,
Body: item.Body,
})
}
return consumer.ConsumeSuccess, nil
})
if err != nil {
return err
}
err = r.consumerIns.Start()
if err != nil {
r.consumerIns.Unsubscribe(topic)
return err
}
return
}
// RegisterRocketMqProducer 注册rocketmq生产者
func RegisterRocketMqProducer(endPoints []string, groupName string, retry int) (mqIns *RocketMq, err error) {
addr, err := primitive.NewNamesrvAddr(endPoints...)
if err != nil {
return nil, err
}
mqIns = &RocketMq{
endPoints: endPoints,
}
if retry <= 0 {
retry = 0
}
mqIns.producerIns, err = rocketmq.NewProducer(
producer.WithNameServer(addr),
producer.WithRetry(retry),
producer.WithGroupName(groupName),
)
if err != nil {
return nil, err
}
err = mqIns.producerIns.Start()
if err != nil {
return nil, err
}
return mqIns, nil
}
// RegisterRocketMqConsumer 注册rocketmq消费者
func RegisterRocketMqConsumer(endPoints []string, groupName string) (mqIns *RocketMq, err error) {
addr, err := primitive.NewNamesrvAddr(endPoints...)
if err != nil {
return nil, err
}
mqIns = &RocketMq{
endPoints: endPoints,
}
mqIns.consumerIns, err = rocketmq.NewPushConsumer(
consumer.WithNameServer(addr),
consumer.WithConsumerModel(consumer.Clustering),
consumer.WithGroupName(groupName),
)
if err != nil {
return nil, err
}
return mqIns, nil
}

View File

@@ -0,0 +1,83 @@
package queue
import (
"fmt"
)
type RocketMqLogger struct {
Flag string
LevelLog string
}
func (l *RocketMqLogger) Debug(msg string, fields map[string]interface{}) {
if l.LevelLog == "close" {
return
}
if msg == "" && len(fields) == 0 {
return
}
if l.LevelLog == "debug" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [debug] ", msg))
}
}
func (l *RocketMqLogger) Level(level string) {
Log(ctx, fmt.Sprint(l.Flag, " [level] ", level))
}
func (l *RocketMqLogger) OutputPath(path string) (err error) {
Log(ctx, fmt.Sprint(l.Flag, " [path] ", path))
return nil
}
func (l *RocketMqLogger) Info(msg string, fields map[string]interface{}) {
if l.LevelLog == "close" {
return
}
if msg == "" && len(fields) == 0 {
return
}
if l.LevelLog == "info" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [info] ", msg))
}
}
func (l *RocketMqLogger) Warning(msg string, fields map[string]interface{}) {
if l.LevelLog == "close" {
return
}
if msg == "" && len(fields) == 0 {
return
}
if l.LevelLog == "warn" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [warn] ", msg))
}
}
func (l *RocketMqLogger) Error(msg string, fields map[string]interface{}) {
if l.LevelLog == "close" {
return
}
if msg == "" && len(fields) == 0 {
return
}
if l.LevelLog == "error" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [error] ", msg))
}
}
func (l *RocketMqLogger) Fatal(msg string, fields map[string]interface{}) {
if l.LevelLog == "close" {
return
}
if msg == "" && len(fields) == 0 {
return
}
if l.LevelLog == "fatal" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [fatal] ", msg))
}
}

View File

@@ -0,0 +1,73 @@
package adminForm
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
// 获取指定配置键的值
type ConfigGetValueReq struct {
Key string `json:"key" v:"required#配置键不能为空" description:"配置键"`
g.Meta `path:"/config/get_value" method:"get" tags:"配置" summary:"获取指定配置键的值"`
}
type ConfigGetValueRes struct {
Value string `json:"value" description:"配置值"`
}
// 名称是否唯一
type ConfigNameUniqueReq struct {
Name string `json:"name" v:"required#配置名称不能为空" description:"配置名称"`
Id int64 `json:"id" description:"配置ID"`
g.Meta `path:"/config/name_unique" method:"get" tags:"配置" summary:"配置名称是否唯一"`
}
type ConfigNameUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 查询列表
type ConfigListReq struct {
form.PageReq
form.RangeDateReq
form.StatusReq
Name string `json:"name" description:"配置名称"`
g.Meta `path:"/config/list" method:"get" tags:"配置" summary:"获取配置列表"`
}
type ConfigListRes struct {
List []*input.SysConfigListModel `json:"list" description:"数据列表"`
form.PageRes
}
// 获取指定信息
type ConfigViewReq struct {
Id string `json:"id" v:"required#配置ID不能为空" description:"配置ID"`
g.Meta `path:"/config/view" method:"get" tags:"配置" summary:"获取指定信息"`
}
type ConfigViewRes struct {
*input.SysConfigViewModel
}
// 修改/新增
type ConfigEditReq struct {
entity.SysConfig
g.Meta `path:"/config/edit" method:"post" tags:"配置" summary:"修改/新增配置"`
}
type ConfigEditRes struct{}
// 删除
type ConfigDeleteReq struct {
Id interface{} `json:"id" v:"required#配置ID不能为空" description:"配置ID"`
g.Meta `path:"/config/delete" method:"post" tags:"配置" summary:"删除配置"`
}
type ConfigDeleteRes struct{}
// 最大排序
type ConfigMaxSortReq struct {
Id int64 `json:"id" description:"配置ID"`
g.Meta `path:"/config/max_sort" method:"get" tags:"配置" summary:"配置最大排序"`
}
type ConfigMaxSortRes struct {
Sort int `json:"sort" description:"排序"`
}

View File

@@ -0,0 +1,65 @@
package adminForm
import (
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
// 名称是否唯一
type DeptNameUniqueReq struct {
Name string `json:"name" v:"required#部门名称不能为空" description:"部门名称"`
Id int64 `json:"id" description:"部门ID"`
g.Meta `path:"/dept/name_unique" method:"get" tags:"部门" summary:"部门名称是否唯一"`
}
type DeptNameUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 查询列表树
type DeptListTreeReq struct {
Id int64 `json:"id" description:"部门ID"`
g.Meta `path:"/dept/list_tree" method:"get" tags:"部门" summary:"获取部门列表树"`
}
type DeptListTreeRes []*input.AdminDeptListTreeModel
// 查询列表
type DeptListReq struct {
Name string `json:"name" description:"部门名称"`
g.Meta `path:"/dept/list" method:"get" tags:"部门" summary:"获取部门列表"`
}
type DeptListRes []*input.AdminDeptListModel
// 获取指定信息
type DeptViewReq struct {
Id int64 `json:"id" v:"required#部门ID不能为空" description:"部门ID"`
g.Meta `path:"/dept/view" method:"get" tags:"部门" summary:"获取指定信息"`
}
type DeptViewRes struct {
*input.AdminDeptViewModel
}
// 修改/新增字典数据
type DeptEditReq struct {
entity.AdminDept
g.Meta `path:"/dept/edit" method:"post" tags:"部门" summary:"修改/新增部门"`
}
type DeptEditRes struct{}
// 删除字典类型
type DeptDeleteReq struct {
Id interface{} `json:"id" v:"required#部门ID不能为空" description:"部门ID"`
g.Meta `path:"/dept/delete" method:"post" tags:"部门" summary:"删除部门"`
}
type DeptDeleteRes struct{}
// 最大排序
type DeptMaxSortReq struct {
Id int64 `json:"id" description:"部门ID"`
g.Meta `path:"/dept/max_sort" method:"get" tags:"部门" summary:"部门最大排序"`
}
type DeptMaxSortRes struct {
Sort int `json:"sort" description:"排序"`
}

View File

@@ -0,0 +1,136 @@
package adminForm
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
/************************ 字典数据 *****************/
// 数据键值是否唯一
type DictDataUniqueReq struct {
Value string `json:"value" v:"required#数据键值不能为空" description:"数据键值"`
Type string `json:"type" example:"sys_common_status" v:"required#字典类型不能为空" description:"字典类型"`
Id int64 `json:"id" description:"字典数据ID"`
g.Meta `path:"/dict_data/unique" method:"get" tags:"字典" summary:"数据键值是否唯一"`
}
type DictDataUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 查询字典数据最大排序
type DictDataMaxSortReq struct {
Type string `json:"type" example:"sys_common_status" v:"required#字典类型不能为空" description:"字典类型"`
g.Meta `path:"/dict_data/max_sort" method:"get" tags:"字典" summary:"查询字典数据最大排序"`
}
type DictDataMaxSortRes struct {
Sort int `json:"sort" description:"排序"`
}
// 修改/新增字典数据
type DictDataEditReq struct {
entity.SysDictData
g.Meta `path:"/dict_data/edit" method:"post" tags:"字典" summary:"修改/新增字典数据"`
}
type DictDataEditRes struct{}
// 删除字典类型
type DictDataDeleteReq struct {
Id interface{} `json:"id" v:"required#字典数据ID不能为空" description:"字典数据ID"`
g.Meta `path:"/dict_data/delete" method:"post" tags:"字典" summary:"删除字典数据"`
}
type DictDataDeleteRes struct{}
// 获取指定字典数据信息
type DictDataViewReq struct {
Id string `json:"id" v:"required#字典数据ID不能为空" description:"字典数据ID"`
g.Meta `path:"/dict_data/view" method:"get" tags:"字典" summary:"获取指定字典数据信息"`
}
type DictDataViewRes struct {
*entity.SysDictData
}
// 获取字典数据列表
type DictDataListReq struct {
form.PageReq
Type string `json:"type" example:"sys_common_status" v:"required#字典类型不能为空" description:"字典类型"`
g.Meta `path:"/dict_data/list" method:"get" tags:"字典" summary:"获取字典数据列表"`
}
type DictDataListRes struct {
List []*entity.SysDictData `json:"list" description:"数据列表"`
form.PageRes
}
// 获取指定字典类型的属性数据
type DictAttributeReq struct {
Type string `json:"type" example:"sys_common_status" v:"required#字典类型不能为空" description:"字典类型"`
g.Meta `path:"/dict/attribute" method:"get" tags:"字典" summary:"获取指定字典类型的属性数据"`
}
type DictAttributeRes []*entity.SysDictData
/************************ 字典类型 *****************/
// 修改/新增字典类型
type DictTypeExportReq struct {
form.PageReq
form.RangeDateReq
form.StatusReq
Name string `json:"name" description:"字典名称"`
Type string `json:"type" description:"字典类型"`
g.Meta `path:"/dict_type/export" method:"get" tags:"字典" summary:"导出字典类型"`
}
type DictTypeExportRes struct{}
// 刷新字典缓存
type DictTypeRefreshCacheReq struct {
g.Meta `path:"/dict_type/refresh_cache" method:"get" tags:"字典" summary:"刷新字典缓存"`
}
type DictTypeRefreshCacheRes struct{}
// 获取字典类型列表
type DictTypeListReq struct {
form.PageReq
form.RangeDateReq
form.StatusReq
Name string `json:"name" description:"字典名称"`
Type string `json:"type" description:"字典类型"`
g.Meta `path:"/dict_type/list" method:"get" tags:"字典" summary:"获取字典类型列表"`
}
type DictTypeListRes struct {
List []*entity.SysDictType `json:"list" description:"数据列表"`
form.PageRes
}
// 修改/新增字典类型
type DictTypeEditReq struct {
entity.SysDictType
g.Meta `path:"/dict_type/edit" method:"post" tags:"字典" summary:"修改/新增字典类型"`
}
type DictTypeEditRes struct{}
// 删除字典类型
type DictTypeDeleteReq struct {
Id interface{} `json:"id" v:"required#字典类型ID不能为空" description:"字典类型ID"`
g.Meta `path:"/dict_type/delete" method:"post" tags:"字典" summary:"删除字典类型"`
}
type DictTypeDeleteRes struct{}
// 获取指定字典类型信息
type DictTypeViewReq struct {
Id string `json:"id" v:"required#字典类型ID不能为空" description:"字典类型ID"`
g.Meta `path:"/dict_type/view" method:"get" tags:"字典" summary:"获取指定字典类型信息"`
}
type DictTypeViewRes struct {
*entity.SysDictType
}
// 类型是否唯一
type DictTypeUniqueReq struct {
Type string `json:"type" example:"sys_common_status" v:"required#字典类型不能为空" description:"字典类型"`
Id int64 `json:"id" description:"字典类型ID"`
g.Meta `path:"/dict_type/unique" method:"get" tags:"字典" summary:"类型是否唯一"`
}
type DictTypeUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}

View File

@@ -0,0 +1,47 @@
package adminForm
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/gogf/gf/v2/frame/g"
)
// 清空日志
type LogClearReq struct {
g.Meta `path:"/log/clear" method:"post" tags:"日志" summary:"清空日志"`
}
type LogClearRes struct{}
// 导出
type LogExportReq struct {
form.PageReq
form.RangeDateReq
Module string `json:"module" description:"应用端口"`
MemberId int `json:"member_id" description:"用户ID"`
TakeUpTime int `json:"take_up_time" description:"请求耗时"`
Method string `json:"method" description:"请求方式"`
Url string `json:"url" description:"请求路径"`
Ip string `json:"ip" description:"访问IP"`
ErrorCode string `json:"error_code" description:"状态码"`
g.Meta `path:"/log/export" method:"get" tags:"日志" summary:"导出日志"`
}
type LogExportRes struct{}
// 获取菜单列表
type LogListReq struct {
form.PageReq
form.RangeDateReq
Module string `json:"module" description:"应用端口"`
MemberId int `json:"member_id" description:"用户ID"`
TakeUpTime int `json:"take_up_time" description:"请求耗时"`
Method string `json:"method" description:"请求方式"`
Url string `json:"url" description:"请求路径"`
Ip string `json:"ip" description:"访问IP"`
ErrorCode string `json:"error_code" description:"状态码"`
g.Meta `path:"/log/list" method:"get" tags:"日志" summary:"获取日志列表"`
}
type LogListRes struct {
List []*input.LogListModel `json:"list" description:"数据列表"`
form.PageRes
}

View File

@@ -0,0 +1,41 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminForm
import (
"github.com/bufanyun/hotgo/app/model"
"github.com/gogf/gf/v2/frame/g"
)
// 注销登录
type LoginLogoutReq struct {
g.Meta `path:"/login/logout" method:"post" tags:"登录" summary:"注销登录"`
}
type LoginLogoutRes struct{}
// 获取登录验证码
type LoginCaptchaReq struct {
g.Meta `path:"/login/captcha" method:"get" tags:"登录" summary:"获取登录验证码"`
}
type LoginCaptchaRes struct {
Cid string `json:"cid" v:"" description:"验证码ID"`
Base64 string `json:"base64" v:"" description:"验证码"`
}
// 提交登录
type LoginReq struct {
g.Meta `path:"/login/sign" method:"post" tags:"登录" summary:"提交登录"`
Username string `json:"username" v:"required#用户名不能为空" description:"用户名"`
Password string `json:"password" v:"required#密码不能为空" description:"密码"`
Cid string `json:"cid" v:"required#验证码ID不能为空" description:"验证码ID"`
Code string `json:"code" v:"required#验证码不能为空" description:"验证码"`
Device string `json:"device" description:"登录设备"`
}
type LoginRes struct {
model.Identity
Token string `json:"token" v:"" description:"登录token"`
}

View File

@@ -0,0 +1,212 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminForm
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// 更新会员资料
type MemberUpdateProfileReq struct {
Mobile int `json:"mobile" description:"手机号"`
Email string `json:"email" description:"邮箱"`
Realname string `json:"realname" description:"真实姓名"`
g.Meta `path:"/member/update_profile" method:"post" tags:"会员" summary:"更新会员资料"`
}
type MemberUpdateProfileRes struct{}
// 修改登录密码
type MemberUpdatePwdReq struct {
OldPassword string `json:"oldPassword" v:"required#原密码不能为空" description:"原密码"`
NewPassword string `json:"newPassword" v:"required|length:6,16#新密码不能为空#新密码需在6~16之间" description:"新密码"`
g.Meta `path:"/member/update_pwd" method:"post" tags:"会员" summary:"重置密码"`
}
type MemberUpdatePwdRes struct{}
// 获取登录用户的基本信息
type MemberProfileReq struct {
g.Meta `path:"/member/profile" method:"get" tags:"会员" summary:"获取登录用户的基本信息"`
}
type MemberProfileRes struct {
PostGroup string `json:"postGroup" description:"岗位名称"`
RoleGroup string `json:"roleGroup" description:"角色名称"`
User *input.AdminMemberViewModel `json:"user" description:"用户基本信息"`
SysDept *input.AdminDeptViewModel `json:"sysDept" description:"部门信息"`
SysRoles []*input.AdminRoleListModel `json:"sysRoles" description:"角色列表"`
PostIds int64 `json:"postIds" description:"当前岗位"`
RoleIds int64 `json:"roleIds" description:"当前角色"`
}
// 重置密码
type MemberResetPwdReq struct {
Password string `json:"password" v:"required#密码不能为空" description:"密码"`
Id int64 `json:"id" description:"会员ID"`
g.Meta `path:"/member/reset_pwd" method:"post" tags:"会员" summary:"重置密码"`
}
type MemberResetPwdRes struct{}
// 邮箱是否唯一
type MemberEmailUniqueReq struct {
Email string `json:"email" v:"required#邮箱不能为空" description:"邮箱"`
Id int64 `json:"id" description:"会员ID"`
g.Meta `path:"/member/email_unique" method:"get" tags:"会员" summary:"邮箱是否唯一"`
}
type MemberEmailUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 手机号是否唯一
type MemberMobileUniqueReq struct {
Mobile string `json:"mobile" v:"required#手机号不能为空" description:"手机号"`
Id int64 `json:"id" description:"会员ID"`
g.Meta `path:"/member/mobile_unique" method:"get" tags:"会员" summary:"手机号是否唯一"`
}
type MemberMobileUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 名称是否唯一
type MemberNameUniqueReq struct {
Username string `json:"username" v:"required#会员名称不能为空" description:"会员名称"`
Id int64 `json:"id" description:"会员ID"`
g.Meta `path:"/member/name_unique" method:"get" tags:"会员" summary:"会员名称是否唯一"`
}
type MemberNameUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 查询列表
type MemberListReq struct {
form.PageReq
form.RangeDateReq
form.StatusReq
DeptId int `json:"dept_id" description:"部门ID"`
Mobile int `json:"mobile" description:"手机号"`
Username string `json:"username" description:"用户名"`
Realname string `json:"realname" description:"真实姓名"`
StartTime string `json:"start_time" description:"开始时间"`
EndTime string `json:"end_time" description:"结束时间"`
Name string `json:"name" description:"岗位名称"`
Code string `json:"code" description:"岗位编码"`
g.Meta `path:"/member/list" method:"get" tags:"会员" summary:"获取会员列表"`
}
type MemberListRes struct {
List []*input.AdminMemberListModel `json:"list" description:"数据列表"`
form.PageRes
}
// 获取指定信息
type MemberViewReq struct {
Id int64 `json:"id" description:"会员ID"` // v:"required#会员ID不能为空"
g.Meta `path:"/member/view" method:"get" tags:"会员" summary:"获取指定信息"`
}
type MemberViewRes struct {
*input.AdminMemberViewModel
Posts []*input.AdminPostListModel `json:"posts" description:"可选岗位"`
PostIds []int64 `json:"postIds" description:"当前岗位"`
Roles []*input.AdminRoleListModel `json:"roles" description:"可选角色"`
RoleIds []int64 `json:"roleIds" description:"当前角色"`
DeptName string `json:"dept_name" description:"部门名称"`
}
// 修改/新增
type MemberEditReq struct {
input.AdminMemberEditInp
g.Meta `path:"/member/edit" method:"post" tags:"会员" summary:"修改/新增会员"`
}
type MemberEditRes struct{}
// 删除
type MemberDeleteReq struct {
Id interface{} `json:"id" v:"required#会员ID不能为空" description:"会员ID"`
g.Meta `path:"/member/delete" method:"post" tags:"会员" summary:"删除会员"`
}
type MemberDeleteRes struct{}
// 最大排序
type MemberMaxSortReq struct {
Id int64 `json:"id" description:"会员ID"`
g.Meta `path:"/member/max_sort" method:"get" tags:"会员" summary:"会员最大排序"`
}
type MemberMaxSortRes struct {
Sort int `json:"sort" description:"排序"`
}
// 获取登录用户信息
type MemberInfoReq struct {
g.Meta `path:"/member/info" method:"get" tags:"会员" summary:"获取登录用户信息" description:"获取管理后台的登录用户信息"`
}
type PortalConfigContentOptions struct {
TitleRequired bool `json:"titleRequired" titleRequired:""`
MoreUrl string `json:"moreUrl" description:"模块地址"`
Refresh int `json:"refresh" description:"刷新"`
}
type PortalConfigContent struct {
Id int `json:"id" description:"内容ID"`
X int `json:"x" description:""`
Y int `json:"y" description:""`
W int `json:"w" description:"宽"`
H int `json:"h" description:"高"`
I int `json:"i" description:""`
Key string `json:"key" description:""`
IsShowTitle string `json:"isShowTitle" description:""`
IsAllowDrag bool `json:"isAllowDrag" description:""`
Name string `json:"name" description:""`
Type string `json:"type" description:""`
Url string `json:"url" description:""`
Options []*PortalConfigContentOptions `json:"options" description:""`
Moved bool `json:"moved" description:""`
}
type PortalConfig struct {
CreateByName string `json:"createByName" description:"创建者名称"`
CreateDeptName string `json:"createDeptName" description:"创建部门名称"`
ImportErrInfo string `json:"importErrInfo" description:"导出错误信息"`
Id string `json:"id" description:"用户ID"`
SearchValue string `json:"searchValue" description:"搜索内容"`
CreateBy string `json:"createBy" description:"创建者名称"`
CreateDept string `json:"createDept" description:"创建部门名称"`
CreateTime *gtime.Time `json:"createTime" description:"创建时间"`
UpdateBy string `json:"updateBy" description:"更新者名称"`
UpdateTime *gtime.Time `json:"updateTime" description:"更新时间"`
UpdateIp string `json:"updateIp" description:"更新iP"`
Remark string `json:"remark" description:"备注"`
Version string `json:"version" description:"版本号"`
DelFlag string `json:"delFlag" description:"删除标签"`
HandleType string `json:"handleType" description:""`
Params string `json:"params" description:""`
Name string `json:"name" description:"配置名称"`
Code string `json:"code" description:"配置代码"`
ApplicationRange string `json:"applicationRange" description:""`
IsDefault string `json:"isDefault" description:"是否默认"`
ResourceId string `json:"resourceId" description:""`
ResourceName string `json:"resourceName" description:""`
SystemDefinedId string `json:"systemDefinedId" description:""`
Sort string `json:"sort" description:"排序"`
SaveType string `json:"saveType" description:""`
Status string `json:"status" description:"状态"`
RecordLog string `json:"recordLog" description:""`
PortalConfigContent string `json:"content" description:"配置内容"`
}
type MemberInfoRes struct {
DefaultPortalConfig []*PortalConfig `json:"defaultPortalConfig" description:"默认用户配置"`
LincenseInfo string `json:"lincenseInfo" description:"应用版本号"`
Permissions []string `json:"permissions"description:"权限"`
Roles []string `json:"roles" description:"角色"`
SysNoticeList []*entity.AdminNotice `json:"sysNoticeList" description:"系统公告"`
UserPortalConfig []*PortalConfig `json:"userPortalConfig" description:"用户配置"`
User model.Identity `json:"user" description:"用户信息"`
}

View File

@@ -0,0 +1,92 @@
package adminForm
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/model"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
// 菜单最大排序
type MenuMaxSortReq struct {
Id int64 `json:"id" description:"菜单ID"`
g.Meta `path:"/menu/max_sort" method:"get" tags:"菜单" summary:"菜单最大排序"`
}
type MenuMaxSortRes struct {
Sort int `json:"sort" description:"排序"`
}
// 菜单编码是否唯一
type MenuCodeUniqueReq struct {
Code string `json:"code" v:"required#菜单编码不能为空" description:"菜单编码"`
Id int64 `json:"id" description:"菜单ID"`
g.Meta `path:"/menu/code_unique" method:"get" tags:"菜单" summary:"菜单编码是否唯一"`
}
type MenuCodeUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 菜单名称是否唯一
type MenuNameUniqueReq struct {
Name string `json:"name" v:"required#菜单名称不能为空" description:"菜单名称"`
Id int64 `json:"id" description:"菜单ID"`
g.Meta `path:"/menu/name_unique" method:"get" tags:"菜单" summary:"菜单名称是否唯一"`
}
type MenuNameUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 修改/新增字典数据
type MenuEditReq struct {
entity.AdminMenu
g.Meta `path:"/menu/edit" method:"post" tags:"菜单" summary:"修改/新增菜单"`
}
type MenuEditRes struct{}
// 删除字典类型
type MenuDeleteReq struct {
Id interface{} `json:"id" v:"required#菜单ID不能为空" description:"菜单ID"`
g.Meta `path:"/menu/delete" method:"post" tags:"菜单" summary:"删除菜单"`
}
type MenuDeleteRes struct{}
// 获取指定字典数据信息
type MenuViewReq struct {
Id string `json:"id" v:"required#菜单ID不能为空" description:"菜单ID"`
g.Meta `path:"/menu/view" method:"get" tags:"菜单" summary:"获取指定菜单信息"`
}
type MenuViewRes struct {
*entity.AdminMenu
}
// 获取菜单列表
type MenuListReq struct {
form.PageReq
Pid int64 `json:"pid" description:"父ID"`
g.Meta `path:"/menu/list" method:"get" tags:"菜单" summary:"获取菜单列表"`
}
type MenuListRes struct {
List []*entity.AdminMenu `json:"list" description:"数据列表"`
form.PageRes
}
// 查询菜单列表
type MenuSearchListReq struct {
Name string `json:"name" description:"菜单名称"`
form.StatusReq
g.Meta `path:"/menu/search_list" method:"get" tags:"菜单" summary:"获取菜单列表"`
}
type MenuSearchListRes []*model.TreeMenu
// 查询角色菜单列表
type MenuRoleListReq struct {
RoleId string `json:"role_id" description:"角色ID"`
g.Meta `path:"/menu/role_list" method:"get" tags:"菜单" summary:"查询角色菜单列表"`
}
type MenuRoleListRes struct {
Menus []*model.LabelTreeMenu `json:"menus" description:"菜单列表"`
CheckedKeys []int64 `json:"checkedKeys" description:"选择的菜单ID"`
}

View File

@@ -0,0 +1,64 @@
package adminForm
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
// 名称是否唯一
type NoticeNameUniqueReq struct {
Title string `json:"name" v:"required#公告名称不能为空" description:"公告名称"`
Id int64 `json:"id" description:"公告ID"`
g.Meta `path:"/notice/name_unique" method:"get" tags:"公告" summary:"公告名称是否唯一"`
}
type NoticeNameUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 查询列表
type NoticeListReq struct {
form.PageReq
form.RangeDateReq
form.StatusReq
Name string `json:"name" description:"公告名称"`
g.Meta `path:"/notice/list" method:"get" tags:"公告" summary:"获取公告列表"`
}
type NoticeListRes struct {
List []*input.AdminNoticeListModel `json:"list" description:"数据列表"`
form.PageRes
}
// 获取指定信息
type NoticeViewReq struct {
Id string `json:"id" v:"required#公告ID不能为空" description:"公告ID"`
g.Meta `path:"/notice/view" method:"get" tags:"公告" summary:"获取指定信息"`
}
type NoticeViewRes struct {
*input.AdminNoticeViewModel
}
// 修改/新增
type NoticeEditReq struct {
entity.AdminNotice
g.Meta `path:"/notice/edit" method:"post" tags:"公告" summary:"修改/新增公告"`
}
type NoticeEditRes struct{}
// 删除
type NoticeDeleteReq struct {
Id interface{} `json:"id" v:"required#公告ID不能为空" description:"公告ID"`
g.Meta `path:"/notice/delete" method:"post" tags:"公告" summary:"删除公告"`
}
type NoticeDeleteRes struct{}
// 最大排序
type NoticeMaxSortReq struct {
Id int64 `json:"id" description:"公告ID"`
g.Meta `path:"/notice/max_sort" method:"get" tags:"公告" summary:"公告最大排序"`
}
type NoticeMaxSortRes struct {
Sort int `json:"sort" description:"排序"`
}

View File

@@ -0,0 +1,75 @@
package adminForm
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
// 修改/新增字典数据
type PostEditReq struct {
entity.AdminPost
g.Meta `path:"/post/edit" method:"post" tags:"岗位" summary:"修改/新增岗位"`
}
type PostEditRes struct{}
// 删除字典类型
type PostDeleteReq struct {
Id interface{} `json:"id" v:"required#岗位ID不能为空" description:"岗位ID"`
g.Meta `path:"/post/delete" method:"post" tags:"岗位" summary:"删除岗位"`
}
type PostDeleteRes struct{}
// 最大排序
type PostMaxSortReq struct {
Id int64 `json:"id" description:"岗位ID"`
g.Meta `path:"/post/max_sort" method:"get" tags:"岗位" summary:"岗位最大排序"`
}
type PostMaxSortRes struct {
Sort int `json:"sort" description:"排序"`
}
// 获取列表
type PostListReq struct {
form.PageReq
form.RangeDateReq
form.StatusReq
Name string `json:"name" description:"岗位名称"`
Code string `json:"code" description:"岗位编码"`
g.Meta `path:"/post/list" method:"get" tags:"岗位" summary:"获取岗位列表"`
}
type PostListRes struct {
List []*input.AdminPostListModel `json:"list" description:"数据列表"`
form.PageRes
}
// 获取指定信息
type PostViewReq struct {
Id string `json:"id" v:"required#岗位ID不能为空" description:"岗位ID"`
g.Meta `path:"/post/view" method:"get" tags:"岗位" summary:"获取指定信息"`
}
type PostViewRes struct {
*input.AdminPostViewModel
}
// 编码是否唯一
type PostCodeUniqueReq struct {
Code string `json:"code" v:"required#岗位编码不能为空" description:"岗位编码"`
Id int64 `json:"id" description:"岗位ID"`
g.Meta `path:"/post/code_unique" method:"get" tags:"岗位" summary:"岗位编码是否唯一"`
}
type PostCodeUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}
// 名称是否唯一
type PostNameUniqueReq struct {
Name string `json:"name" v:"required#岗位名称不能为空" description:"岗位名称"`
Id int64 `json:"id" description:"岗位ID"`
g.Meta `path:"/post/name_unique" method:"get" tags:"岗位" summary:"岗位名称是否唯一"`
}
type PostNameUniqueRes struct {
IsUnique bool `json:"is_unique" description:"是否唯一"`
}

View File

@@ -0,0 +1,89 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminForm
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/gogf/gf/v2/frame/g"
)
// 查询列表
type RoleMemberListReq struct {
form.PageReq
form.RangeDateReq
form.StatusReq
Role int `json:"role" description:"角色ID"`
DeptId int `json:"dept_id" description:"部门ID"`
Mobile int `json:"mobile" description:"手机号"`
Username string `json:"username" description:"用户名"`
Realname string `json:"realname" description:"真实姓名"`
StartTime string `json:"start_time" description:"开始时间"`
EndTime string `json:"end_time" description:"结束时间"`
Name string `json:"name" description:"岗位名称"`
Code string `json:"code" description:"岗位编码"`
g.Meta `path:"/role/member_list" method:"get" tags:"角色" summary:"获取角色下的会员列表"`
}
type RoleMemberListRes struct {
List []*input.AdminMemberListModel `json:"list" description:"数据列表"`
form.PageRes
}
// 查询列表
type RoleListReq struct {
form.PageReq
form.RangeDateReq
form.StatusReq
DeptId int `json:"dept_id" description:"部门ID"`
Mobile int `json:"mobile" description:"手机号"`
Username string `json:"username" description:"用户名"`
Realname string `json:"realname" description:"真实姓名"`
StartTime string `json:"start_time" description:"开始时间"`
EndTime string `json:"end_time" description:"结束时间"`
Name string `json:"name" description:"岗位名称"`
Code string `json:"code" description:"岗位编码"`
g.Meta `path:"/role/list" method:"get" tags:"角色" summary:"获取角色列表"`
}
type RoleListRes struct {
List []*input.AdminRoleListModel `json:"list" description:"数据列表"`
form.PageRes
}
// 动态路由
type RoleDynamicReq struct {
g.Meta `path:"/role/dynamic" method:"get" tags:"路由" summary:"获取动态路由" description:"获取登录用户动态路由"`
}
type RoleDynamicMeta struct {
Title string `json:"title" description:"菜单标题"`
Icon string `json:"icon" description:"菜单图标"`
NoCache bool `json:"noCache" description:"是否缓存"`
Remark string `json:"remark" description:"备注"`
}
type RoleDynamicBase struct {
Id int64 `json:"id" description:"菜单ID"`
Pid int64 `json:"pid" description:"父ID"`
Name string `json:"name" description:"菜单名称"`
Code string `json:"code" description:"菜单编码"`
Path string `json:"path" description:"路由地址"`
Hidden bool `json:"hidden" description:"是否隐藏"`
Redirect string `json:"redirect" description:"重定向"`
Component string `json:"component" description:"组件路径"`
AlwaysShow bool `json:"alwaysShow" description:"暂时不知道干啥"`
IsFrame string `json:"isFrame" description:"是否为外链0是 1否"`
Meta *RoleDynamicMeta `json:"meta" description:"配置数据集"`
}
type RoleDynamicMenu struct {
RoleDynamicBase
Children []*RoleDynamicBase `json:"children" description:"子菜单"`
}
type RoleDynamicRes []*RoleDynamicMenu

View File

@@ -0,0 +1,34 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package apiForm
import (
"github.com/bufanyun/hotgo/app/com"
"github.com/gogf/gf/v2/frame/g"
)
// 获取lang信息
type BaseLangReq struct {
g.Meta `path:"/base/lang" method:"get" tags:"基础" summary:"获取lang信息"`
L string `json:"l" v:"required#语言不能为空" description:"语言"`
}
type BaseLangRes struct {
}
// 获取登录验证码
type IpLocationReq struct {
g.Meta `path:"/base/ip_location" method:"get" tags:"基础" summary:"获取IP归属地信息"`
Ip string `json:"ip" v:"required#ip不能为空" description:"ipv4地址"`
}
type IpLocationRes struct {
com.IpLocationData
}
type ExportReq struct {
g.Meta `path:"/base/export" method:"get" tags:"字典" summary:"导出字典类型"`
}
type ExportRes struct{}

View File

@@ -0,0 +1,13 @@
package apiForm
import (
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/gogf/gf/v2/frame/g"
)
// 获取指定字典类型的属性数据
type DictAttributeReq struct {
Type string `json:"type" example:"sys_common_status" v:"required#字典类型不能为空" description:"字典类型"`
g.Meta `path:"/dict/attribute" method:"get" tags:"字典" summary:"获取指定字典类型的属性数据"`
}
type DictAttributeRes []*entity.SysDictData

View File

@@ -0,0 +1,47 @@
package apiForm
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/gogf/gf/v2/frame/g"
)
// 清空日志
type LogClearReq struct {
g.Meta `path:"/log/clear" method:"post" tags:"日志" summary:"清空日志"`
}
type LogClearRes struct{}
// 导出
type LogExportReq struct {
form.PageReq
form.RangeDateReq
Module string `json:"module" description:"应用端口"`
MemberId int `json:"member_id" description:"用户ID"`
TakeUpTime int `json:"take_up_time" description:"请求耗时"`
Method string `json:"method" description:"请求方式"`
Url string `json:"url" description:"请求路径"`
Ip string `json:"ip" description:"访问IP"`
ErrorCode string `json:"error_code" description:"状态码"`
g.Meta `path:"/log/export" method:"get" tags:"日志" summary:"导出日志"`
}
type LogExportRes struct{}
// 获取菜单列表
type LogListReq struct {
form.PageReq
form.RangeDateReq
Module string `json:"module" description:"应用端口"`
MemberId int `json:"member_id" description:"用户ID"`
TakeUpTime int `json:"take_up_time" description:"请求耗时"`
Method string `json:"method" description:"请求方式"`
Url string `json:"url" description:"请求路径"`
Ip string `json:"ip" description:"访问IP"`
ErrorCode string `json:"error_code" description:"状态码"`
g.Meta `path:"/log/list" method:"get" tags:"日志" summary:"获取日志列表"`
}
type LogListRes struct {
List []*input.LogListModel `json:"list" description:"数据列表"`
form.PageRes
}

View File

@@ -0,0 +1,37 @@
package apiForm
import (
"github.com/bufanyun/hotgo/app/model"
"github.com/gogf/gf/v2/frame/g"
)
// 注销登录
type LoginLogoutReq struct {
g.Meta `path:"/login/logout" method:"get" tags:"登录" summary:"注销登录"`
}
type LoginLogoutRes struct{}
// 登录效验
type LoginCheckReq struct {
g.Meta `path:"/login/check" method:"get" tags:"登录" summary:"登录效验"`
}
type LoginCheckRes struct {
IsValidCodeLogin bool `json:"isValidCodeLogin" description:"是否验证码"`
Message string `json:"message" description:"消息"`
Result string `json:"result" description:"响应"`
// Sessionid string `json:"sessionid" description:"sessionid"`
}
// 提交登录
type LoginReq struct {
g.Meta `path:"/login/sign" method:"post" tags:"登录" summary:"提交登录"`
Username string `json:"username" v:"required#用户名不能为空" description:"用户名"`
Password string `json:"password" v:"required#密码不能为空" description:"密码"`
Cid string `json:"cid" v:"required#验证码ID不能为空" description:"验证码ID"`
Code string `json:"code" v:"required#验证码不能为空" description:"验证码"`
Device string `json:"device" description:"登录设备"`
}
type LoginRes struct {
model.Identity
Token string `json:"token" v:"" description:"登录token"`
}

View File

@@ -0,0 +1,20 @@
package apiForm
import (
"github.com/bufanyun/hotgo/app/form/input"
"github.com/gogf/gf/v2/frame/g"
)
// 获取登录用户的基本信息
type MemberProfileReq struct {
g.Meta `path:"/member/profile" method:"get" tags:"会员" summary:"获取登录用户的基本信息"`
}
type MemberProfileRes struct {
PostGroup string `json:"postGroup" description:"岗位名称"`
RoleGroup string `json:"roleGroup" description:"角色名称"`
User *input.AdminMemberViewModel `json:"user" description:"用户基本信息"`
SysDept *input.AdminDeptViewModel `json:"sysDept" description:"部门信息"`
SysRoles []*input.AdminRoleListModel `json:"sysRoles" description:"角色列表"`
PostIds int64 `json:"postIds" description:"当前岗位"`
RoleIds int64 `json:"roleIds" description:"当前角色"`
}

View File

@@ -0,0 +1,28 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package form
// 分页
type PageReq struct {
Page int `json:"page" example:"10" d:"1" v:"min:1#页码最小值不能低于1" description:"当前页码"`
Limit int `json:"limit" example:"1" d:"10" v:"min:1|max:100#|每页数量最小值不能低于1|最大值不能大于100" description:"每页数量"`
}
type PageRes struct {
PageReq
TotalCount int `json:"total_count" example:"0" description:"全部数据量"`
}
// 时间查询
type RangeDateReq struct {
StartTime string `json:"start_time" v:"date#开始日期格式不正确" description:"开始日期"`
EndTime string `json:"end_time" v:"date#结束日期格式不正确" description:"结束日期"`
}
// 状态查询
type StatusReq struct {
Status int `json:"status" v:"in:0,1,2,3#状态可选范围0~3" description:"状态"`
}

View File

@@ -0,0 +1,75 @@
package input
import "github.com/bufanyun/hotgo/app/model/entity"
// 名称是否唯一
type AdminDeptNameUniqueInp struct {
Name string
Id int64
}
type AdminDeptNameUniqueModel struct {
IsUnique bool
}
// 最大排序
type AdminDeptMaxSortInp struct {
Id int64
}
type AdminDeptMaxSortModel struct {
Sort int
}
// 修改/新增字典数据
type AdminDeptEditInp struct {
entity.AdminDept
}
type AdminDeptEditModel struct{}
// 删除字典类型
type AdminDeptDeleteInp struct {
Id interface{}
}
type AdminDeptDeleteModel struct{}
// 获取信息
type AdminDeptViewInp struct {
Id int64
}
type AdminDeptViewModel struct {
entity.AdminDept
}
// 获取列表
type AdminDeptListInp struct {
Name string
}
// 
type AdminDeptTreeDept struct {
entity.AdminDept
Children []*AdminDeptTreeDept `json:"children"`
}
type AdminDeptListModel AdminDeptTreeDept
// 获取列表树
type AdminDeptListTreeInp struct {
Name string
}
// 
type AdminDeptListTreeDept struct {
Id int64 `json:"id" `
Key int64 `json:"key" `
Pid int64 `json:"pid" `
Label string `json:"label"`
Title string `json:"title"`
Name string `json:"name"`
Type string `json:"type"`
Children []*AdminDeptListTreeDept `json:"children"`
}
type AdminDeptListTreeModel AdminDeptListTreeDept

View File

@@ -0,0 +1,171 @@
package input
import (
"github.com/bufanyun/hotgo/app/model"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/gogf/gf/v2/os/gtime"
)
// 更新会员资料
type AdminMemberUpdateProfileInp struct {
Mobile int
Email string
Realname string
}
//  获取指定会员资料
type AdminMemberProfileInp struct {
Id int64
}
type AdminMemberProfileModel struct {
PostGroup string `json:"postGroup" description:"岗位名称"`
RoleGroup string `json:"roleGroup" description:"角色名称"`
User *AdminMemberViewModel `json:"user" description:"用户基本信息"`
SysDept *AdminDeptViewModel `json:"sysDept" description:"部门信息"`
SysRoles []*AdminRoleListModel `json:"sysRoles" description:"角色列表"`
PostIds int64 `json:"postIds" description:"当前岗位"`
RoleIds int64 `json:"roleIds" description:"当前角色"`
}
// 更新会员资料
type MemberUpdateProfileInp struct {
Mobile int
Email string
Realname string
}
// 修改登录密码
type AdminMemberUpdatePwdInp struct {
Id int64
OldPassword string
NewPassword string
}
//  重置密码
type AdminMemberResetPwdInp struct {
Password string
Id int64
}
// 邮箱是否唯一
type AdminMemberEmailUniqueInp struct {
Email string
Id int64
}
type AdminMemberEmailUniqueModel struct {
IsUnique bool
}
// 手机号是否唯一
type AdminMemberMobileUniqueInp struct {
Mobile string
Id int64
}
type AdminMemberMobileUniqueModel struct {
IsUnique bool
}
// 名称是否唯一
type AdminMemberNameUniqueInp struct {
Username string
Id int64
}
type AdminMemberNameUniqueModel struct {
IsUnique bool
}
// 最大排序
type AdminMemberMaxSortInp struct {
Id int64
}
type AdminMemberMaxSortModel struct {
Sort int
}
// 修改/新增字典数据
type AdminMemberEditInp struct {
Id int64 `json:"id" description:""`
PostIds []int64 `json:"postIds" v:"required#岗位不能为空" description:"岗位ID"`
DeptId int64 `json:"dept_id" v:"required#部门不能为空" description:"部门ID"`
Username string `json:"username" v:"required#账号不能为空" description:"帐号"`
Password string `json:"password" description:"密码"`
Realname string `json:"realname" description:"真实姓名"`
Avatar string `json:"avatar" description:"头像"`
Sex string `json:"sex" description:"性别[0:未知;1:男;2:女]"`
Qq string `json:"qq" description:"qq"`
Email string `json:"email" description:"邮箱"`
Birthday *gtime.Time `json:"birthday" description:"生日"`
ProvinceId int `json:"province_id" description:"省"`
CityId int `json:"city_id" description:"城市"`
AreaId int `json:"area_id" description:"地区"`
Address string `json:"address" description:"默认地址"`
Mobile string `json:"mobile" description:"手机号码"`
HomePhone string `json:"home_phone" description:"家庭号码"`
DingtalkRobotToken string `json:"dingtalk_robot_token" description:"钉钉机器人token"`
Role int `json:"role" v:"required#角色不能为空" description:"权限"`
Remark string `json:"remark" description:"备注"`
Status string `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"修改时间"`
}
type AdminMemberAddInp struct {
AdminMemberEditInp
PasswordHash string `json:"password_hash" description:"密码hash"`
Salt string `json:"salt" description:"密码盐"`
}
type AdminMemberEditModel struct{}
// 删除字典类型
type AdminMemberDeleteInp struct {
Id interface{}
}
type AdminMemberDeleteModel struct{}
// 获取信息
type AdminMemberViewInp struct {
Id int64
}
type AdminMemberViewModel struct {
entity.AdminMember
}
// 获取列表
type AdminMemberListInp struct {
Page int
Limit int
Name string
Code string
DeptId int
Mobile int
Username string
Realname string
StartTime string
EndTime string
Status int
}
type AdminMemberListModel struct {
entity.AdminMember
DeptName string `json:"dept_name"`
RoleName string `json:"role_name"`
}
// 登录
type AdminMemberLoginSignInp struct {
Username string
Password string
Device string
Cid string
Code string
}
type AdminMemberLoginSignModel struct {
model.Identity
Token string `json:"token" v:"" description:"登录token"`
}

View File

@@ -0,0 +1,64 @@
package input
import "github.com/bufanyun/hotgo/app/model/entity"
// 名称是否唯一
type AdminNoticeNameUniqueInp struct {
Title string
Id int64
}
type AdminNoticeNameUniqueModel struct {
IsUnique bool
}
// 最大排序
type AdminNoticeMaxSortInp struct {
Id int64
}
type AdminNoticeMaxSortModel struct {
Sort int
}
// 修改/新增字典数据
type AdminNoticeEditInp struct {
entity.AdminNotice
}
type AdminNoticeEditModel struct{}
// 删除字典类型
type AdminNoticeDeleteInp struct {
Id interface{}
}
type AdminNoticeDeleteModel struct{}
// 获取信息
type AdminNoticeViewInp struct {
Id string
}
type AdminNoticeViewModel struct {
entity.AdminNotice
}
// 获取列表
type AdminNoticeListInp struct {
Page int
Limit int
Name string
Code string
DeptId int
Mobile int
Username string
Realname string
StartTime string
EndTime string
Status int
}
type AdminNoticeListModel struct {
entity.AdminNotice
DeptName string `json:"dept_name"`
RoleName string `json:"role_name"`
}

View File

@@ -0,0 +1,68 @@
package input
import (
"github.com/bufanyun/hotgo/app/model/entity"
)
// 获取列表
type AdminPostListInp struct {
Page int
Limit int
Name string
Code string
Status int
}
type AdminPostListModel struct {
entity.AdminPost
}
// 获取信息
type AdminPostViewInp struct {
Id string
}
type AdminPostViewModel struct {
entity.AdminPost
}
// 编码是否唯一
type AdminPostCodeUniqueInp struct {
Code string
Id int64
}
type AdminPostCodeUniqueModel struct {
IsUnique bool
}
// 名称是否唯一
type AdminPostNameUniqueInp struct {
Name string
Id int64
}
type AdminPostNameUniqueModel struct {
IsUnique bool
}
// 最大排序
type AdminPostMaxSortInp struct {
Id int64
}
type AdminPostMaxSortModel struct {
Sort int
}
// 修改/新增字典数据
type AdminPostEditInp struct {
entity.AdminPost
}
type AdminPostEditModel struct{}
// 删除字典类型
type AdminPostDeleteInp struct {
Id interface{}
}
type AdminPostDeleteModel struct{}

View File

@@ -0,0 +1,44 @@
package input
import (
"github.com/bufanyun/hotgo/app/form"
"github.com/bufanyun/hotgo/app/model"
"github.com/bufanyun/hotgo/app/model/entity"
)
// 获取列表
type AdminRoleListInp struct {
Page int
Limit int
}
type AdminRoleListModel struct {
entity.AdminRole
}
// 查询列表
type AdminRoleMemberListInp struct {
form.PageReq
form.RangeDateReq
form.StatusReq
Role int `json:"role" description:"角色ID"`
DeptId int `json:"dept_id" description:"部门ID"`
Mobile int `json:"mobile" description:"手机号"`
Username string `json:"username" description:"用户名"`
Realname string `json:"realname" description:"真实姓名"`
StartTime string `json:"start_time" description:"开始时间"`
EndTime string `json:"end_time" description:"结束时间"`
Name string `json:"name" description:"岗位名称"`
Code string `json:"code" description:"岗位编码"`
}
type AdminRoleMemberListModel []*AdminMemberListModel
// 查询角色菜单列表
type MenuRoleListInp struct {
RoleId int64
}
type MenuRoleListModel struct {
Menus []*model.LabelTreeMenu `json:"menus" description:"菜单列表"`
CheckedKeys []int64 `json:"checkedKeys" description:"选择的菜单ID"`
}

View File

@@ -0,0 +1,72 @@
package input
import "github.com/bufanyun/hotgo/app/model/entity"
// 获取指定配置键的值
type SysConfigGetValueInp struct {
Key string
}
type SysConfigGetValueModel struct {
Value string
}
// 名称是否唯一
type SysConfigNameUniqueInp struct {
Name string
Id int64
}
type SysConfigNameUniqueModel struct {
IsUnique bool
}
// 最大排序
type SysConfigMaxSortInp struct {
Id int64
}
type SysConfigMaxSortModel struct {
Sort int
}
// 修改/新增字典数据
type SysConfigEditInp struct {
entity.SysConfig
}
type SysConfigEditModel struct{}
// 删除字典类型
type SysConfigDeleteInp struct {
Id interface{}
}
type SysConfigDeleteModel struct{}
// 获取信息
type SysConfigViewInp struct {
Id string
}
type SysConfigViewModel struct {
entity.SysConfig
}
// 获取列表
type SysConfigListInp struct {
Page int
Limit int
Name string
Code string
DeptId int
Mobile int
Username string
Realname string
StartTime string
EndTime string
Status int
}
type SysConfigListModel struct {
entity.SysConfig
DeptName string `json:"dept_name"`
RoleName string `json:"role_name"`
}

View File

@@ -0,0 +1,26 @@
package input
import (
"github.com/bufanyun/hotgo/app/model/entity"
)
// 获取菜单列表
type LogListInp struct {
Page int
Limit int
Module string
MemberId int
TakeUpTime int
Method string
Url string
Ip string
ErrorCode string
StartTime string
EndTime string
}
type LogListModel struct {
entity.SysLog
MemberName string `json:"member_name"`
Region string `json:"region"`
}

View File

@@ -0,0 +1,45 @@
//
// @Link  https://github.com/bufanyun/hotgo
// @Copyright  Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package hook
import (
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/service/sysService"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
)
type (
// sHook is service struct of module Hook.
sHook struct{}
)
var (
// insHook is the instance of service Hook.
insHook = sHook{}
)
// Hook returns the interface of Hook service.
func Instance() *sHook {
return &insHook
}
//
//  @Title  全局日志
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//
func (s *sHook) GlobalLog(r *ghttp.Request) {
var (
ctx = r.Context()
)
com.Context.SetTakeUpTime(ctx, gtime.TimestampMilli()-r.EnterTime)
go sysService.Log.AutoLog(ctx)
}

View File

@@ -0,0 +1,20 @@
//
// @Package  interfaces
// @Description 
// @Author  Ms <133814250@qq.com>
//
package interfaces
//
//  QueueProducer
//  @Description 
//
type QueueProducer interface {
//
//  @Title 
//  @Description 
//  @Author  Ms <133814250@qq.com>
//  @Return  string
//
Push() string
}

View File

@@ -0,0 +1,127 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package middleware
import (
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/model"
"github.com/bufanyun/hotgo/app/utils"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
//
//  @Title  后台中间件
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//
func (s *sMiddleware) AdminAuth(r *ghttp.Request) {
var (
ctx = r.Context()
user = new(model.Identity)
authorization = com.Jwt.GetAuthorization(r)
)
// TODO 替换掉模块前缀
routerPrefix, _ := g.Cfg().Get(ctx, "router.admin.prefix", "/admin")
path := gstr.Replace(r.URL.Path, routerPrefix.String(), "", 1)
/// TODO 不需要验证登录的路由地址
if utils.Auth.IsExceptLogin(ctx, path) {
r.Middleware.Next()
return
}
if authorization == "" {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "请先登录!")
return
}
// TODO 获取jwtToken
jwtToken := consts.RedisJwtToken + gmd5.MustEncryptString(authorization)
jwtSign, _ := g.Cfg().Get(ctx, "jwt.sign", "hotgo")
data, ParseErr := com.Jwt.ParseToken(authorization, jwtSign.Bytes())
if ParseErr != nil {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "token不正确或已过期", ParseErr.Error())
}
parseErr := gconv.Struct(data, &user)
if parseErr != nil {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "登录信息解析异常,请重新登录!", parseErr.Error())
}
// TODO 判断token跟redis的缓存的token是否一样
cache := com.Cache.New()
isContains, containsErr := cache.Contains(ctx, jwtToken)
if containsErr != nil {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "token无效", containsErr.Error())
return
}
if !isContains {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "token已过期")
return
}
// TODO 是否开启多端登录
if multiPort, _ := g.Cfg().Get(ctx, "jwt.multiPort", true); !multiPort.Bool() {
key := consts.RedisJwtUserBind + consts.AppAdmin + ":" + gconv.String(user.Id)
originJwtToken, originErr := cache.Get(ctx, key)
if originErr != nil {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "信息异常,请重新登录!", originErr.Error())
return
}
if originJwtToken == nil || originJwtToken.IsEmpty() {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "token已过期")
return
}
if jwtToken != originJwtToken.String() {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "账号已在其他地方登录!")
return
}
}
// TODO 保存到上下文
customCtx := &model.Context{}
if user != nil {
customCtx.User = &model.Identity{
Id: user.Id,
Username: user.Username,
Realname: user.Realname,
Avatar: user.Avatar,
Email: user.Email,
Mobile: user.Mobile,
VisitCount: user.VisitCount,
LastTime: user.LastTime,
LastIp: user.LastIp,
Role: user.Role,
Exp: user.Exp,
Expires: user.Expires,
App: user.App,
}
}
com.Context.SetUser(ctx, customCtx.User)
com.Context.SetModule(ctx, consts.AppAdmin)
//// TODO 验证路由访问权限
//verify := adminService.Role.Verify(ctx, customCtx.User.Id, path)
//if !verify {
// com.Response.JsonExit(r, gcode.CodeSecurityReason.Code(), "你没有访问权限!")
// return
//}
r.Middleware.Next()
}

View File

@@ -0,0 +1,127 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package middleware
import (
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/model"
"github.com/bufanyun/hotgo/app/utils"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
//
//  @Title  接口中间件
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//
func (s *sMiddleware) ApiAuth(r *ghttp.Request) {
var (
ctx = r.Context()
user = new(model.Identity)
authorization = com.Jwt.GetAuthorization(r)
)
// TODO 替换掉模块前缀
routerPrefix, _ := g.Cfg().Get(ctx, "router.api.prefix", "/api")
path := gstr.Replace(r.URL.Path, routerPrefix.String(), "", 1)
/// TODO 不需要验证登录的路由地址
if utils.Auth.IsExceptLogin(ctx, path) {
r.Middleware.Next()
return
}
if authorization == "" {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "请先登录!")
return
}
// TODO 获取jwtToken
jwtToken := consts.RedisJwtToken + gmd5.MustEncryptString(authorization)
jwtSign, _ := g.Cfg().Get(ctx, "jwt.sign", "hotgo")
data, ParseErr := com.Jwt.ParseToken(authorization, jwtSign.Bytes())
if ParseErr != nil {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "token不正确或已过期", ParseErr.Error())
}
parseErr := gconv.Struct(data, &user)
if parseErr != nil {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "登录信息解析异常,请重新登录!", parseErr.Error())
}
// TODO 判断token跟redis的缓存的token是否一样
cache := com.Cache.New()
isContains, containsErr := cache.Contains(ctx, jwtToken)
if containsErr != nil {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "token无效", containsErr.Error())
return
}
if !isContains {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "token已过期")
return
}
// TODO 是否开启多端登录
if multiPort, _ := g.Cfg().Get(ctx, "jwt.multiPort", true); !multiPort.Bool() {
key := consts.RedisJwtUserBind + consts.AppApi + ":" + gconv.String(user.Id)
originJwtToken, originErr := cache.Get(ctx, key)
if originErr != nil {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "信息异常,请重新登录!", originErr.Error())
return
}
if originJwtToken == nil || originJwtToken.IsEmpty() {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "token已过期")
return
}
if jwtToken != originJwtToken.String() {
com.Response.JsonExit(r, gcode.CodeNotAuthorized.Code(), "账号已在其他地方登录!")
return
}
}
// TODO 保存到上下文
customCtx := &model.Context{}
if user != nil {
customCtx.User = &model.Identity{
Id: user.Id,
Username: user.Username,
Realname: user.Realname,
Avatar: user.Avatar,
Email: user.Email,
Mobile: user.Mobile,
VisitCount: user.VisitCount,
LastTime: user.LastTime,
LastIp: user.LastIp,
Role: user.Role,
Exp: user.Exp,
Expires: user.Expires,
App: user.App,
}
}
com.Context.SetUser(ctx, customCtx.User)
com.Context.SetModule(ctx, consts.AppApi)
//// TODO 验证路由访问权限
//verify := adminService.Role.Verify(ctx, customCtx.User.Id, path)
//if !verify {
// com.Response.JsonExit(r, gcode.CodeSecurityReason.Code(), "你没有访问权限!")
// return
//}
r.Middleware.Next()
}

View File

@@ -0,0 +1,74 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package middleware
import (
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/utils"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
//
//  @Title  全局响应中间件
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//
func (s *sMiddleware) HandlerResponse(r *ghttp.Request) {
r.Middleware.Next()
var (
ctx = r.Context()
comResponse = com.Context.Get(ctx).ComResponse
code = gcode.CodeOK.Code()
message = "操作成功"
data interface{}
err error
)
if err := r.GetError(); err != nil {
g.Log().Print(ctx, err)
// 记录到自定义错误日志文件
//g.Log("exception").Error(err)
////返回固定的友好信息
//r.Response.ClearBuffer()
//r.Response.Writeln("服务器居然开小差了,请稍后再试吧!")
}
// TODO 已存在响应内容且是comResponse返回的时中断运行
if r.Response.BufferLength() > 0 && comResponse != nil {
return
}
if err = r.GetError(); err != nil {
// TODO 记录到自定义错误日志文件
g.Log("exception").Print(r.Context(), "exception:", err)
code = consts.CodeInternalError
message = "服务器居然开小差了,请稍后再试吧!"
// TODO 是否输出错误到页面
if debug, _ := g.Cfg().Get(ctx, "hotgo.debug", true); debug.Bool() {
data = utils.Charset.GetStack(err)
}
} else if data, err = r.GetHandlerResponse(); err != nil {
errCode := gerror.Code(err)
if errCode == gcode.CodeNil {
errCode = gcode.CodeInternalError
}
code = errCode.Code()
message = err.Error()
}
// TODO 返回固定的友好信息
com.Response.RJson(r, code, message, data)
}

View File

@@ -0,0 +1,64 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package middleware
import (
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/model"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/util/grand"
"github.com/gogf/gf/v2/util/guid"
"go.opentelemetry.io/otel/trace"
)
type (
// sMiddleware is service struct of module Middleware.
sMiddleware struct{}
)
var (
// insMiddleware is the instance of service Middleware.
insMiddleware = sMiddleware{}
)
// Middleware returns the interface of Middleware service.
func Instance() *sMiddleware {
return &insMiddleware
}
//
//  @Title  初始化请求上下文
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   r
//
func (s *sMiddleware) Ctx(r *ghttp.Request) {
spanCtx := trace.SpanContextFromContext(r.Context())
reqId := guid.S(grand.B(64))
if traceId := spanCtx.TraceID(); traceId.IsValid() {
reqId = traceId.String()
}
customCtx := &model.Context{
Data: make(g.Map),
Request: r,
ReqId: reqId,
}
com.Context.Init(r, customCtx)
r.Middleware.Next()
}
// CORS allows Cross-origin resource sharing.
func (s *sMiddleware) CORS(r *ghttp.Request) {
r.Response.CORSDefault()
r.Middleware.Next()
}

View File

@@ -0,0 +1,40 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package model
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
// Context 请求上下文结构
type Context struct {
ReqId string // 上下文ID
Module string // 应用模块
TakeUpTime int64 // 请求耗时 ms
Request *ghttp.Request // 当前Request管理对象
User *Identity // 上下文用户信息
ComResponse *Response // 组件响应
Data g.Map // 自定KV变量业务模块根据需要设置不固定
}
// 通用身份模型
type Identity struct {
Id int64 `json:"id" description:"会员ID"`
Username string `json:"username" description:"用户名"`
Realname string `json:"realname" description:"昵称"`
Avatar string `json:"avatar" description:"头像"`
Email string `json:"email" description:"邮箱"`
Mobile string `json:"mobile" description:"手机号码"`
VisitCount uint `json:"visit_count" description:"访问次数"`
LastTime int `json:"last_time" description:"最后一次登录时间"`
LastIp string `json:"last_ip" description:"最后一次登录ip"`
Role int64 `json:"role" description:"权限"`
Exp int64 `json:"exp" description:"登录有效期截止时间戳"`
Expires int64 `json:"expires" description:"登录有效期"`
App string `json:"app" description:"登录应用"`
}

View File

@@ -0,0 +1,26 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// AdminDept is the golang structure for table admin_dept.
type AdminDept struct {
Id int64 `json:"id" description:"部门id"`
Pid int64 `json:"pid" description:"父部门id"`
Ancestors string `json:"ancestors" description:"祖级列表"`
Name string `json:"name" description:"部门名称"`
Code string `json:"code" description:"部门编码"`
Type string `json:"type" description:"部门类型"`
Leader string `json:"leader" description:"负责人"`
Phone string `json:"phone" description:"联系电话"`
Email string `json:"email" description:"邮箱"`
Sort int `json:"sort" description:"排序"`
Status string `json:"status" description:"部门状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"更新时间"`
}

View File

@@ -0,0 +1,42 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// AdminMember is the golang structure for table admin_member.
type AdminMember struct {
Id int64 `json:"id" description:""`
DeptId int64 `json:"dept_id" description:"部门ID"`
Username string `json:"username" description:"帐号"`
PasswordHash string `json:"password_hash" description:"密码"`
Salt string `json:"salt" description:"密码盐"`
AuthKey string `json:"auth_key" description:"授权令牌"`
PasswordResetToken string `json:"password_reset_token" description:"密码重置令牌"`
Type string `json:"type" description:"1:普通管理员;10超级管理员"`
Realname string `json:"realname" description:"真实姓名"`
Avatar string `json:"avatar" description:"头像"`
Sex string `json:"sex" description:"性别[0:未知;1:男;2:女]"`
Qq string `json:"qq" description:"qq"`
Email string `json:"email" description:"邮箱"`
Birthday *gtime.Time `json:"birthday" description:"生日"`
ProvinceId int `json:"province_id" description:"省"`
CityId int `json:"city_id" description:"城市"`
AreaId int `json:"area_id" description:"地区"`
Address string `json:"address" description:"默认地址"`
Mobile string `json:"mobile" description:"手机号码"`
HomePhone string `json:"home_phone" description:"家庭号码"`
DingtalkRobotToken string `json:"dingtalk_robot_token" description:"钉钉机器人token"`
VisitCount uint `json:"visit_count" description:"访问次数"`
LastTime int `json:"last_time" description:"最后一次登录时间"`
LastIp string `json:"last_ip" description:"最后一次登录ip"`
Role int64 `json:"role" description:"权限"`
Remark string `json:"remark" description:"备注"`
Status string `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"修改时间"`
}

View File

@@ -0,0 +1,11 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
// AdminMemberPost is the golang structure for table admin_member_post.
type AdminMemberPost struct {
MemberId int64 `json:"member_id" description:"用户ID"`
PostId int64 `json:"post_id" description:"岗位ID"`
}

View File

@@ -0,0 +1,11 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
// AdminMemberRole is the golang structure for table admin_member_role.
type AdminMemberRole struct {
MemberId int64 `json:"member_id" description:"用户ID"`
RoleId int64 `json:"role_id" description:"角色ID"`
}

View File

@@ -0,0 +1,33 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// AdminMenu is the golang structure for table admin_menu.
type AdminMenu struct {
Id int64 `json:"id" description:"菜单ID"`
Pid int64 `json:"pid" description:"父菜单ID"`
Name string `json:"name" description:"菜单名称"`
Code string `json:"code" description:"菜单编码"`
Icon string `json:"icon" description:"菜单图标"`
Type string `json:"type" description:"菜单类型M目录 C菜单 F按钮"`
Perms string `json:"perms" description:"权限标识"`
Path string `json:"path" description:"路由地址"`
Component string `json:"component" description:"组件路径"`
Query string `json:"query" description:"路由参数"`
IsFrame string `json:"is_frame" description:"是否内嵌"`
IsCache string `json:"is_cache" description:"是否不缓存"`
IsVisible string `json:"is_visible" description:"是否隐藏"`
Remark string `json:"remark" description:"备注"`
Level int `json:"level" description:"级别"`
Tree string `json:"tree" description:"树"`
Sort int `json:"sort" description:"排序"`
Status string `json:"status" description:"菜单状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"更新时间"`
}

View File

@@ -0,0 +1,32 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// AdminMenuOld is the golang structure for table admin_menu_old.
type AdminMenuOld struct {
Id int64 `json:"id" description:"菜单ID"`
Pid int64 `json:"pid" description:"父菜单ID"`
Name string `json:"name" description:"菜单名称"`
Icon string `json:"icon" description:"菜单图标"`
Type string `json:"type" description:"菜单类型M目录 C菜单 F按钮"`
Perms string `json:"perms" description:"权限标识"`
Path string `json:"path" description:"路由地址"`
Component string `json:"component" description:"组件路径"`
Query string `json:"query" description:"路由参数"`
IsFrame int `json:"is_frame" description:"是否为外链0是 1否"`
IsCache int `json:"is_cache" description:"是否缓存0缓存 1不缓存"`
IsVisible int `json:"is_visible" description:"菜单状态0显示 1隐藏"`
Remark string `json:"remark" description:"备注"`
Level int `json:"level" description:"级别"`
Tree string `json:"tree" description:"树"`
Sort int `json:"sort" description:"排序"`
Status int `json:"status" description:"菜单状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"更新时间"`
}

View File

@@ -0,0 +1,21 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// AdminNotice is the golang structure for table admin_notice.
type AdminNotice struct {
Id int64 `json:"id" description:"公告ID"`
Title string `json:"title" description:"公告标题"`
Type string `json:"type" description:"公告类型1通知 2公告"`
Content string `json:"content" description:"公告内容"`
Remark string `json:"remark" description:"备注"`
Status string `json:"status" description:"公告状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"更新时间"`
}

View File

@@ -0,0 +1,21 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// AdminPost is the golang structure for table admin_post.
type AdminPost struct {
Id int64 `json:"id" description:"岗位ID"`
Code string `json:"code" description:"岗位编码"`
Name string `json:"name" description:"岗位名称"`
Remark string `json:"remark" description:"备注"`
Sort int `json:"sort" description:"显示顺序"`
Status string `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"更新时间"`
}

View File

@@ -0,0 +1,24 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// AdminRole is the golang structure for table admin_role.
type AdminRole struct {
Id int64 `json:"id" description:"角色ID"`
Name string `json:"name" description:"角色名称"`
Key string `json:"key" description:"角色权限字符串"`
DataScope int `json:"data_scope" description:"数据范围1全部数据权限 2自定数据权限 3本部门数据权限 4本部门及以下数据权限"`
MenuCheckStrictly int `json:"menu_check_strictly" description:"菜单树选择项是否关联显示"`
DeptCheckStrictly int `json:"dept_check_strictly" description:"部门树选择项是否关联显示"`
Remark string `json:"remark" description:"备注"`
Sort int `json:"sort" description:"排序"`
Status string `json:"status" description:"角色状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"更新时间"`
}

View File

@@ -0,0 +1,11 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
// AdminRoleDept is the golang structure for table admin_role_dept.
type AdminRoleDept struct {
RoleId int64 `json:"role_id" description:"角色ID"`
DeptId int64 `json:"dept_id" description:"部门ID"`
}

View File

@@ -0,0 +1,11 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
// AdminRoleMenu is the golang structure for table admin_role_menu.
type AdminRoleMenu struct {
RoleId int64 `json:"role_id" description:"角色ID"`
MenuId int64 `json:"menu_id" description:"菜单ID"`
}

View File

@@ -0,0 +1,22 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// SysConfig is the golang structure for table sys_config.
type SysConfig struct {
Id int64 `json:"id" description:"配置ID"`
Name string `json:"name" description:"参数名称"`
Key string `json:"key" description:"参数键名"`
Value string `json:"value" description:"参数键值"`
IsDefault string `json:"is_default" description:"是否默认"`
Status string `json:"status" description:"状态"`
Remark string `json:"remark" description:"备注"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"更新时间"`
}

View File

@@ -0,0 +1,24 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// SysDictData is the golang structure for table sys_dict_data.
type SysDictData struct {
Id int64 `json:"id" description:"字典编码"`
Label string `json:"label" description:"字典标签"`
Value string `json:"value" description:"字典键值"`
Type string `json:"type" description:"字典类型"`
ListClass string `json:"list_class" description:"表格回显样式"`
IsDefault string `json:"is_default" description:"是否默认"`
Sort int `json:"sort" description:"字典排序"`
Remark string `json:"remark" description:"备注"`
Status string `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"更新时间"`
}

View File

@@ -0,0 +1,21 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// SysDictType is the golang structure for table sys_dict_type.
type SysDictType struct {
Id int64 `json:"id" description:"字典主键"`
Name string `json:"name" description:"字典名称"`
Type string `json:"type" description:"字典类型"`
Sort int `json:"sort" description:"排序"`
Remark string `json:"remark" description:"备注"`
Status string `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"更新时间"`
}

View File

@@ -0,0 +1,36 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// SysLog is the golang structure for table sys_log.
type SysLog struct {
Id int64 `json:"id" description:""`
AppId string `json:"app_id" description:"应用id"`
MerchantId uint `json:"merchant_id" description:"商户id"`
MemberId int `json:"member_id" description:"用户id"`
Method string `json:"method" description:"提交类型"`
Module string `json:"module" description:"模块"`
Url string `json:"url" description:"提交url"`
GetData string `json:"get_data" description:"get数据"`
PostData string `json:"post_data" description:"post数据"`
HeaderData string `json:"header_data" description:"header数据"`
Ip string `json:"ip" description:"ip地址"`
ProvinceId int `json:"province_id" description:"省编码"`
CityId int `json:"city_id" description:"市编码"`
ErrorCode int `json:"error_code" description:"报错code"`
ErrorMsg string `json:"error_msg" description:"报错信息"`
ErrorData string `json:"error_data" description:"报错日志"`
ReqId string `json:"req_id" description:"对外id"`
Timestamp int `json:"timestamp" description:"响应时间"`
UserAgent string `json:"user_agent" description:"UA信息"`
TakeUpTime int64 `json:"take_up_time" description:"请求耗时"`
Status string `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updated_at" description:"修改时间"`
}

View File

@@ -0,0 +1,21 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
// SysProvinces is the golang structure for table sys_provinces.
type SysProvinces struct {
Id int `json:"id" description:"ID"`
Title string `json:"title" description:"栏目名"`
Pid int `json:"pid" description:"父栏目"`
ShortTitle string `json:"short_title" description:"缩写"`
Areacode int `json:"areacode" description:"区域编码"`
Zipcode int `json:"zipcode" description:"邮政编码"`
Pinyin string `json:"pinyin" description:"拼音"`
Lng string `json:"lng" description:"经度"`
Lat string `json:"lat" description:"纬度"`
Level int `json:"level" description:"级别"`
Tree string `json:"tree" description:""`
Sort uint `json:"sort" description:"排序"`
}

View File

@@ -0,0 +1,17 @@
//
// @Link  https://github.com/bufanyun/hotgo
// @Copyright  Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package model
// HTTP响应
type Response struct {
Code int `json:"code" example:"0" description:"状态码"`
Message string `json:"message" example:"操作成功" description:"提示消息"`
Data interface{} `json:"data" description:"数据集"`
Error interface{} `json:"error" description:"错误信息"`
Timestamp int64 `json:"timestamp" example:"1640966400" description:"服务器时间戳"`
ReqId string `json:"req_id" v:"0" example:"d0bb93048bc5c9164cdee845dcb7f820" description:"唯一请求ID"`
}

View File

@@ -0,0 +1,23 @@
//
// @Link  https://github.com/bufanyun/hotgo
// @Copyright  Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package model
import "github.com/bufanyun/hotgo/app/model/entity"
//  菜单树
type TreeMenu struct {
entity.AdminMenu
Children []*TreeMenu `json:"children"`
}
//  菜单kl树
type LabelTreeMenu struct {
entity.AdminMenu
Key int64 `json:"key" description:"键名"`
Label string `json:"label" description:"键标签"`
Children []*LabelTreeMenu `json:"children"`
}

View File

@@ -0,0 +1,358 @@
package adminService
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/bufanyun/hotgo/app/service/internal/dao"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
)
var Dept = dept{}
type dept struct{}
//
//  @Title  菜单名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *dept) NameUnique(ctx context.Context, in input.AdminDeptNameUniqueInp) (*input.AdminDeptNameUniqueModel, error) {
var res input.AdminDeptNameUniqueModel
isUnique, err := dao.AdminDept.IsUniqueName(ctx, in.Id, in.Name)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
res.IsUnique = isUnique
return &res, nil
}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *dept) Delete(ctx context.Context, in input.AdminDeptDeleteInp) error {
exist, err := dao.AdminRoleDept.Ctx(ctx).Where("dept_id", in.Id).One()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !exist.IsEmpty() {
return gerror.New("请先解除该部门下所有已关联用户关联关系!")
}
_, err = dao.AdminDept.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *dept) Edit(ctx context.Context, in input.AdminDeptEditInp) (err error) {
if in.Name == "" {
err = gerror.New("名称不能为空")
return err
}
uniqueName, err := dao.AdminDept.IsUniqueName(ctx, in.Id, in.Name)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !uniqueName {
err = gerror.New("名称已存在")
return err
}
// 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 {
_, err = dao.AdminDept.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// 新增
in.CreatedAt = gtime.Now()
_, err = dao.AdminDept.Ctx(ctx).Data(in).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictDataMaxSortRes
//  @Return  error
//
func (service *dept) MaxSort(ctx context.Context, in input.AdminDeptMaxSortInp) (*input.AdminDeptMaxSortModel, error) {
var res input.AdminDeptMaxSortModel
if in.Id > 0 {
if err := dao.AdminDept.Ctx(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
}
res.Sort = res.Sort + 10
return &res, nil
}
//
//  @Title  获取指定字典类型信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeViewRes
//  @Return  error
//
func (service *dept) View(ctx context.Context, in input.AdminDeptViewInp) (res *input.AdminDeptViewModel, err error) {
if err = dao.AdminDept.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
}
//
//  @Title  获取列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *dept) List(ctx context.Context, in input.AdminDeptListInp) (list []*input.AdminDeptListModel, err error) {
mod := dao.AdminDept.Ctx(ctx)
var (
dataList []*entity.AdminDept
models []*DeptTree
//searchResult []*entity.AdminDept
//id int64
//ids []int64
)
// 部门名称
if in.Name != "" {
//err = dao.AdminDept.Ctx(ctx).WhereLike("name", "%"+in.Name+"%").Scan(&searchResult)
//if err != nil {
// err = gerror.Wrap(err, consts.ErrorORM)
// return nil, err
//}
//for i := 0; i < len(searchResult); i++ {
// id, err = dao.AdminDept.TopPid(ctx, searchResult[i])
// ids = append(ids, id)
//}
//
//if len(ids) == 0 {
// return nil, nil
//}
//mod = mod.Where("id", ids)
}
err = mod.Order("id desc").Scan(&dataList)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, err
}
_ = gconv.Structs(dataList, &models)
childIds := service.getDeptChildIds(ctx, models, 0)
_ = gconv.Structs(childIds, &list)
return list, nil
}
type DeptTree struct {
entity.AdminDept
Children []*DeptTree `json:"children"`
}
//
//  @Title  将列表转为父子关系列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   lists
//  @Param   pid
//  @Return  []*RelationTree
//
func (service *dept) getDeptChildIds(ctx context.Context, lists []*DeptTree, pid int64) []*DeptTree {
var (
count = len(lists)
newLists []*DeptTree
)
if count == 0 {
return nil
}
for i := 0; i < len(lists); i++ {
if lists[i].Id > 0 && lists[i].Pid == pid {
var row *DeptTree
if err := gconv.Structs(lists[i], &row); err != nil {
panic(err)
}
row.Children = service.getDeptChildIds(ctx, lists, row.Id)
newLists = append(newLists, row)
}
}
return newLists
}
type DeptListTree struct {
Id int64 `json:"id" `
Key int64 `json:"key" `
Pid int64 `json:"pid" `
Label string `json:"label"`
Title string `json:"title"`
Name string `json:"name"`
Type string `json:"type"`
Children []*DeptListTree `json:"children"`
}
//
//  @Title  获取列表树
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *dept) ListTree(ctx context.Context, in input.AdminDeptListTreeInp) (list []*input.AdminDeptListTreeModel, err error) {
mod := dao.AdminDept.Ctx(ctx)
var (
dataList []*entity.AdminDept
models []*DeptListTree
)
err = mod.Order("id desc").Scan(&dataList)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, err
}
_ = gconv.Structs(dataList, &models)
// TODO  重写树入参
for i := 0; i < len(models); i++ {
models[i].Key = models[i].Id
models[i].Title = models[i].Name
models[i].Label = models[i].Name
}
childIds := service.getDeptTreeChildIds(ctx, models, 0)
_ = gconv.Structs(childIds, &list)
return list, nil
}
//
//  @Title  将列表转为父子关系列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   lists
//  @Param   pid
//  @Return  []*RelationTree
//
func (service *dept) getDeptTreeChildIds(ctx context.Context, lists []*DeptListTree, pid int64) []*DeptListTree {
var (
count = len(lists)
newLists []*DeptListTree
)
if count == 0 {
return nil
}
for i := 0; i < len(lists); i++ {
if lists[i].Id > 0 && lists[i].Pid == pid {
var row *DeptListTree
if err := gconv.Structs(lists[i], &row); err != nil {
panic(err)
}
row.Children = service.getDeptTreeChildIds(ctx, lists, row.Id)
newLists = append(newLists, row)
}
}
return newLists
}
//
//  @Title  获取部门名称
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   id
//  @Return  name
//  @Return  err
//
func (service *dept) GetName(ctx context.Context, id int64) (name string, err error) {
var data entity.AdminDept
err = dao.AdminDept.Ctx(ctx).
Where("id", id).
Fields("name").
Scan(&data)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return name, err
}
return data.Name, nil
}

View File

@@ -0,0 +1,67 @@
package adminService
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/bufanyun/hotgo/app/service/internal/dao"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
)
var MemberPost = new(memberPost)
type memberPost struct{}
func (service *memberPost) UpdatePostIds(ctx context.Context, member_id int64, post_ids []int64) (err error) {
_, err = dao.AdminMemberPost.Ctx(ctx).
Where("member_id", member_id).
Delete()
if err != nil {
err = gerror.Wrap(err, "删除失败")
return err
}
for i := 0; i < len(post_ids); i++ {
_, err = dao.AdminMemberPost.Ctx(ctx).
Insert(entity.AdminMemberPost{
MemberId: member_id,
PostId: post_ids[i],
})
if err != nil {
err = gerror.Wrap(err, "插入会员岗位失败")
return err
}
}
return nil
}
//
//  @Title  获取指定会员的岗位ids
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   member_id
//  @Return  post_ids
//  @Return  err
//
func (service *memberPost) GetMemberByIds(ctx context.Context, member_id int64) (post_ids []int64, err error) {
var list []*entity.AdminMemberPost
err = dao.AdminMemberPost.Ctx(ctx).
Fields("post_id").
Where("member_id", member_id).
Scan(&list)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return post_ids, err
}
for i := 0; i < len(list); i++ {
post_ids = append(post_ids, list[i].PostId)
}
g.Log().Print(ctx, "post_ids:", post_ids)
return post_ids, nil
}

View File

@@ -0,0 +1,657 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminService
import (
"context"
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/bufanyun/hotgo/app/service/internal/dao"
"github.com/bufanyun/hotgo/app/service/internal/dto"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
)
var Member = new(member)
type member struct{}
//
//  @Title  修改登录密码
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *member) UpdateProfile(ctx context.Context, in input.AdminMemberUpdateProfileInp) (err error) {
memberId := com.Context.Get(ctx).User.Id
if memberId <= 0 {
err := gerror.New("获取用户信息失败!")
return err
}
var memberInfo entity.AdminMember
if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&memberInfo); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
_, err = dao.AdminMember.Ctx(ctx).
Where("id", memberId).
Data(g.Map{
"mobile": in.Mobile,
"email": in.Email,
"realname": in.Realname,
}).
Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return
}
//
//  @Title  修改登录密码
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *member) UpdatePwd(ctx context.Context, in input.AdminMemberUpdatePwdInp) (err error) {
var memberInfo entity.AdminMember
if err = dao.AdminMember.Ctx(ctx).Where("id", in.Id).Scan(&memberInfo); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if gmd5.MustEncryptString(in.OldPassword+memberInfo.Salt) != memberInfo.PasswordHash {
err = gerror.New("原密码不正确")
return err
}
_, err = dao.AdminMember.Ctx(ctx).
Where("id", in.Id).
Data(g.Map{
"password_hash": gmd5.MustEncryptString(in.NewPassword + memberInfo.Salt),
"updated_at": gtime.Now(),
}).
Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return
}
//
//  @Title  重置密码
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *member) ResetPwd(ctx context.Context, in input.AdminMemberResetPwdInp) (err error) {
var memberInfo entity.AdminMember
if err = dao.AdminMember.Ctx(ctx).Where("id", in.Id).Scan(&memberInfo); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
_, err = dao.AdminMember.Ctx(ctx).
Where("id", in.Id).
Data(g.Map{
"password_hash": gmd5.MustEncryptString(in.Password + memberInfo.Salt),
"updated_at": gtime.Now(),
}).
Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return
}
//
//  @Title  菜单名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *member) EmailUnique(ctx context.Context, in input.AdminMemberEmailUniqueInp) (*input.AdminMemberEmailUniqueModel, error) {
var res input.AdminMemberEmailUniqueModel
isUnique, err := dao.AdminMember.IsUniqueEmail(ctx, in.Id, in.Email)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
res.IsUnique = isUnique
return &res, nil
}
//
//  @Title  手机号是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *member) MobileUnique(ctx context.Context, in input.AdminMemberMobileUniqueInp) (*input.AdminMemberMobileUniqueModel, error) {
var res input.AdminMemberMobileUniqueModel
isUnique, err := dao.AdminMember.IsUniqueMobile(ctx, in.Id, in.Mobile)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
res.IsUnique = isUnique
return &res, nil
}
//
//  @Title  菜单名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *member) NameUnique(ctx context.Context, in input.AdminMemberNameUniqueInp) (*input.AdminMemberNameUniqueModel, error) {
var res input.AdminMemberNameUniqueModel
isUnique, err := dao.AdminMember.IsUniqueName(ctx, in.Id, in.Username)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
res.IsUnique = isUnique
return &res, nil
}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *member) Delete(ctx context.Context, in input.AdminMemberDeleteInp) error {
exist, err := dao.AdminMember.Ctx(ctx).Where("member_id", in.Id).One()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !exist.IsEmpty() {
return gerror.New("请先解除该部门下所有已关联用户关联关系!")
}
_, err = dao.AdminMember.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *member) Edit(ctx context.Context, in input.AdminMemberEditInp) (err error) {
if in.Username == "" {
err = gerror.New("帐号不能为空")
return err
}
uniqueName, err := dao.AdminMember.IsUniqueName(ctx, in.Id, in.Username)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !uniqueName {
err = gerror.New("帐号已存在")
return err
}
if in.Mobile != "" {
uniqueMobile, err := dao.AdminMember.IsUniqueMobile(ctx, in.Id, in.Mobile)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !uniqueMobile {
err = gerror.New("手机号已存在")
return err
}
}
if in.Email != "" {
uniqueEmail, err := dao.AdminMember.IsUniqueMobile(ctx, in.Id, in.Email)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !uniqueEmail {
err = gerror.New("邮箱已存在")
return err
}
}
// 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 {
_, err = dao.AdminMember.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
// 更新岗位
err = MemberPost.UpdatePostIds(ctx, in.Id, in.PostIds)
if err != nil {
return err
}
return nil
}
// 新增
in.CreatedAt = gtime.Now()
// 新增用户时的额外属性
var data input.AdminMemberAddInp
data.AdminMemberEditInp = in
data.Salt = grand.S(6)
data.PasswordHash = gmd5.MustEncryptString(data.Password + data.Salt)
g.Log().Print(ctx, "data.Salt:", data)
insert, err := dao.AdminMember.Ctx(ctx).Data(data).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
// 更新岗位
id, err := insert.LastInsertId()
if err != nil {
return err
}
err = MemberPost.UpdatePostIds(ctx, id, in.PostIds)
if err != nil {
return err
}
return nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictDataMaxSortRes
//  @Return  error
//
func (service *member) MaxSort(ctx context.Context, in input.AdminMemberMaxSortInp) (*input.AdminMemberMaxSortModel, error) {
var res input.AdminMemberMaxSortModel
if in.Id > 0 {
if err := dao.AdminMember.Ctx(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
}
res.Sort = res.Sort + 10
return &res, nil
}
//
//  @Title  获取指定字典类型信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeViewRes
//  @Return  error
//
func (service *member) View(ctx context.Context, in input.AdminMemberViewInp) (res *input.AdminMemberViewModel, err error) {
if err = dao.AdminMember.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
}
//
//  @Title  获取列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *member) List(ctx context.Context, in input.AdminMemberListInp) (list []*input.AdminMemberListModel, totalCount int, err error) {
var authorization = com.Jwt.GetAuthorization(com.Context.Get(ctx).Request)
// TODO 获取jwtToken
jwtToken := consts.RedisJwtToken + gmd5.MustEncryptString(authorization)
g.Log().Print(ctx, "jwtToken:", jwtToken)
mod := dao.AdminMember.Ctx(ctx)
if in.Realname != "" {
mod = mod.WhereLike("realname", "%"+in.Realname+"%")
}
if in.Username != "" {
mod = mod.WhereLike("username", "%"+in.Username+"%")
}
if in.Mobile > 0 {
mod = mod.Where("mobile", in.Mobile)
}
if in.Status > 0 {
mod = mod.Where("status", in.Status)
}
if in.DeptId > 0 {
mod = mod.Where("dept_id", in.DeptId)
}
// 日期范围
if in.StartTime != "" {
mod = mod.WhereGTE("created_at", in.StartTime)
}
if in.EndTime != "" {
mod = mod.WhereLTE("created_at", in.EndTime)
}
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
err = mod.Page(in.Page, in.Limit).Order("id desc").Scan(&list)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
// TODO  重写树入参
for i := 0; i < len(list); i++ {
// TODO  部门
deptName, err := dao.AdminDept.Ctx(ctx).
Fields("name").
Where("id", list[i].DeptId).
Value()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
list[i].DeptName = deptName.String()
// TODO  角色
roleName, err := dao.AdminRole.Ctx(ctx).
Fields("name").
Where("id", list[i].Role).
Value()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
list[i].RoleName = roleName.String()
}
return list, totalCount, err
}
// //
//  @Title  获取登录用户信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *member) LoginMemberInfo(ctx context.Context, req *adminForm.MemberInfoReq) (res *adminForm.MemberInfoRes, err error) {
var (
defaultPortalConfig adminForm.PortalConfig
defaultPortalConfigs []*adminForm.PortalConfig
configContent adminForm.PortalConfigContent
configContents []*adminForm.PortalConfigContent
configContentOptions []*adminForm.PortalConfigContentOptions
Options adminForm.PortalConfigContentOptions
)
g.Log().Print(ctx, "测试")
// TODO  配置内容选项
Options.TitleRequired = true
Options.Refresh = 1
configContentOptions = append(configContentOptions, &Options)
// TODO  配置内容
configContent.Options = configContentOptions
configContent.Id = 1
configContent.X = 0
configContent.Y = 0
configContent.W = 3
configContent.H = 262
configContent.I = 1
configContent.Key = "kuaijierukou"
configContent.IsShowTitle = "N"
configContent.IsAllowDrag = false
configContent.Name = "快捷入口"
configContent.Type = "smallPage"
configContent.Url = "dashboard/portal/CommonUse"
configContent.Moved = true
configContents = append(configContents, &configContent)
// TODO  默认配置
defaultPortalConfig.Id = "4ae60dd1debe462096698e1da993317a"
defaultPortalConfig.Name = "首页"
defaultPortalConfig.Code = "6c297eb4651940edbb45c87c75be00d7"
defaultPortalConfig.ApplicationRange = "U"
defaultPortalConfig.IsDefault = "Y"
defaultPortalConfig.ResourceId = "1"
defaultPortalConfig.SystemDefinedId = "app1"
defaultPortalConfig.PortalConfigContent = gconv.String(configContents)
defaultPortalConfigs = append(defaultPortalConfigs, &defaultPortalConfig)
member := com.Context.Get(ctx).User
noticeList, err := Notice.WhereAll(ctx, dto.AdminNotice{
Status: consts.StatusEnabled,
})
if err != nil {
noticeList = nil
}
res = &adminForm.MemberInfoRes{
LincenseInfo: consts.VersionApp,
Permissions: []string{"*:*:*"},
Roles: []string{"admin"},
User: *member,
DefaultPortalConfig: defaultPortalConfigs,
UserPortalConfig: defaultPortalConfigs,
SysNoticeList: noticeList,
}
return
}
//
//  @Title  提交登录
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *member) Login(ctx context.Context, in input.AdminMemberLoginSignInp) (res *input.AdminMemberLoginSignModel, err error) {
var member *entity.AdminMember
err = dao.AdminMember.Ctx(ctx).Where("username", in.Username).Scan(&member)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return
}
if member == nil {
err = gerror.New(consts.ErrorNotData)
return
}
if member.Salt == "" {
err = gerror.New("用户信息错误")
return
}
if member.PasswordHash != gmd5.MustEncryptString(in.Password+member.Salt) {
err = gerror.New("用户密码不正确")
return
}
// 默认设备
if in.Device != consts.AppAdmin && in.Device != consts.AppApi {
in.Device = consts.AppAdmin
}
// TODO  生成token
jwtExpires, err := g.Cfg().Get(ctx, "jwt.expires", 1)
if err != nil {
err := gerror.New(err.Error())
return nil, err
}
// TODO  有效期
expires := jwtExpires.Int64()
// TODO  过期时间戳
exp := gconv.Int64(gtime.Timestamp()) + expires
var identity *model.Identity
identity = &model.Identity{
Id: member.Id,
Username: member.Username,
Realname: member.Realname,
Avatar: member.Avatar,
Email: member.Email,
Mobile: member.Mobile,
VisitCount: member.VisitCount,
LastTime: member.LastTime,
LastIp: member.LastIp,
Role: member.Role,
Exp: exp,
Expires: expires,
App: consts.AppAdmin,
}
token, err := com.Jwt.GenerateLoginToken(ctx, identity, false)
if err != nil {
err = gerror.New(err.Error())
return
}
// TODO  更新登录信息
authKey := gmd5.MustEncryptString(gconv.String(token))
_, err = dao.AdminMember.Ctx(ctx).Data(dto.AdminMember{
AuthKey: gmd5.MustEncryptString(authKey),
VisitCount: member.VisitCount + 1,
LastTime: gtime.Timestamp(),
LastIp: com.Context.Get(ctx).Request.GetClientIp(),
}).Where(dto.AdminMember{
Id: member.Id,
}).Update()
if err != nil {
err = gerror.New(err.Error())
return
}
res = &input.AdminMemberLoginSignModel{
Identity: *identity,
Token: gconv.String(token),
}
return res, nil
}
//
//  @Title  获取角色下的会员列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *member) RoleMemberList(ctx context.Context, in input.AdminRoleMemberListInp) (list []*input.AdminMemberListModel, totalCount int, err error) {
mod := dao.AdminMember.Ctx(ctx)
if in.Role > 0 {
mod = mod.Where("role", in.Role)
}
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
err = mod.Page(in.Page, in.Limit).Order("id desc").Scan(&list)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
return list, totalCount, err
}

View File

@@ -0,0 +1,533 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminService
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/form/adminForm"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/bufanyun/hotgo/app/service/internal/dao"
"github.com/bufanyun/hotgo/app/service/internal/dto"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
)
var Menu = new(menu)
type menu struct{}
//
//  @Title  查询角色菜单列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.MenuSearchListRes
//  @Return  error
//
func (service *menu) RoleList(ctx context.Context, in input.MenuRoleListInp) (*input.MenuRoleListModel, error) {
var (
mod = dao.AdminRoleMenu.Ctx(ctx)
roleMenu []*entity.AdminRoleMenu
lst []*model.LabelTreeMenu
res input.MenuRoleListModel
err error
checkedKeys []int64
)
// TODO  获取选中菜单ID
if in.RoleId > 0 {
mod = mod.Where("role_id", in.RoleId)
}
err = mod.Fields().Scan(&roleMenu)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
for i := 0; i < len(roleMenu); i++ {
checkedKeys = append(checkedKeys, roleMenu[i].MenuId)
}
res.CheckedKeys = checkedKeys
// TODO  获取菜单树
lst, err = dao.AdminMenu.GenLabelTreeList(ctx, 0)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
_ = gconv.Structs(lst, &res.Menus)
return &res, nil
}
//
//  @Title  查询菜单列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.MenuSearchListRes
//  @Return  error
//
func (service *menu) SearchList(ctx context.Context, req *adminForm.MenuSearchListReq) (*adminForm.MenuSearchListRes, error) {
var (
mod = dao.AdminMenu.Ctx(ctx)
lst []*model.TreeMenu
res adminForm.MenuSearchListRes
searchResult []*entity.AdminMenu
id int64
ids []int64
err error
)
if req.Name != "" {
mod = mod.WhereLike("name", "%"+req.Name+"%")
}
if req.Status > 0 {
mod = mod.Where("status", req.Status)
}
if req.Name != "" || req.Status > 0 {
err = mod.Scan(&searchResult)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
for i := 0; i < len(searchResult); i++ {
id, err = dao.AdminMenu.TopPid(ctx, searchResult[i])
ids = append(ids, id)
}
}
lst, err = dao.AdminMenu.GenTreeList(ctx, 0, ids)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
_ = gconv.Structs(lst, &res)
return &res, nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictDataMaxSortRes
//  @Return  error
//
func (service *menu) MaxSort(ctx context.Context, req *adminForm.MenuMaxSortReq) (*adminForm.MenuMaxSortRes, error) {
var (
res adminForm.MenuMaxSortRes
err error
)
if req.Id > 0 {
if err = dao.AdminMenu.Ctx(ctx).Where("id", req.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
}
res.Sort = res.Sort + 10
return &res, nil
}
//
//  @Title  菜单名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *menu) NameUnique(ctx context.Context, req *adminForm.MenuNameUniqueReq) (*adminForm.MenuNameUniqueRes, error) {
var (
res adminForm.MenuNameUniqueRes
err error
)
res.IsUnique, err = dao.AdminMenu.IsUniqueName(ctx, req.Id, req.Name)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return &res, nil
}
//
//  @Title  菜单编码是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *menu) CodeUnique(ctx context.Context, req *adminForm.MenuCodeUniqueReq) (*adminForm.MenuCodeUniqueRes, error) {
var (
res adminForm.MenuCodeUniqueRes
err error
)
res.IsUnique, err = dao.AdminMenu.IsUniqueCode(ctx, req.Id, req.Code)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return &res, nil
}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *menu) Delete(ctx context.Context, req *adminForm.MenuDeleteReq) error {
exist, err := dao.AdminMenu.Ctx(ctx).Where("pid", req.Id).One()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !exist.IsEmpty() {
return gerror.New("请先删除该菜单下的所有菜单!")
}
_, err = dao.AdminMenu.Ctx(ctx).Where("id", req.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *menu) Edit(ctx context.Context, req *adminForm.MenuEditReq) (err error) {
var (
pidData *dto.AdminMenu
uniqueName bool
uniqueCode bool
)
if req.Name == "" {
err = gerror.New("菜单名称不能为空")
return err
}
if req.Path == "" {
err = gerror.New("菜单路径不能为空")
return err
}
if req.Code == "" {
err = gerror.New("菜单编码不能为空")
return err
}
uniqueName, err = dao.AdminMenu.IsUniqueName(ctx, req.Id, req.Name)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !uniqueName {
err = gerror.New("菜单名称已存在")
return err
}
uniqueCode, err = dao.AdminMenu.IsUniqueCode(ctx, req.Id, req.Code)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !uniqueCode {
err = gerror.New("菜单编码已存在")
return err
}
// TODO 维护菜单等级
if req.Pid == 0 {
req.Level = 1
} else {
if err = dao.AdminMenu.Ctx(ctx).Where("id", req.Pid).Scan(&pidData); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if pidData == nil {
return gerror.New("上级菜单信息错误")
}
req.Level = gconv.Int(pidData.Level) + 1
}
// 修改
req.UpdatedAt = gtime.Now()
if req.Id > 0 {
if req.Pid == req.Id {
return gerror.New("上级菜单不能是当前菜单")
}
_, err = dao.AdminMenu.Ctx(ctx).Where("id", req.Id).Data(req).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// 新增
req.CreatedAt = gtime.Now()
_, err = dao.AdminMenu.Ctx(ctx).Data(req).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
//
//  @Title  获取信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeViewRes
//  @Return  error
//
func (service *menu) View(ctx context.Context, req *adminForm.MenuViewReq) (res *adminForm.MenuViewRes, err error) {
//var (
// res adminForm.MenuViewRes
//)
if err = dao.AdminMenu.Ctx(ctx).Where("id", req.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
}
//
//  @Title  获取菜单列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *menu) List(ctx context.Context, req *adminForm.MenuListReq) (*adminForm.MenuListRes, error) {
var (
m = dao.AdminMenu.Ctx(ctx)
list []*entity.AdminMenu
res adminForm.MenuListRes
totalCount int
err error
)
if req.Pid == 0 {
m = m.Where("level", 1)
} else {
m = m.Where("pid", req.Pid)
}
totalCount, err = m.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
err = m.Page(req.Page, req.Limit).Scan(&list)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
res.List = list
res.Page = req.Page
res.Limit = req.Limit
res.TotalCount = totalCount
return &res, nil
}
type RelationTree struct {
adminForm.RoleDynamicBase
Children []*RelationTree `json:"children"`
}
//
//  @Title  获取菜单列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   member_id
//
func (service *menu) GetMenuList(ctx context.Context, member_id int64) (lists *adminForm.RoleDynamicRes, err error) {
var (
results []*entity.AdminMenu
models []*RelationTree
recursion []*adminForm.RoleDynamicBase
finalResponse adminForm.RoleDynamicRes
)
err = dao.AdminMenu.Ctx(ctx).Order("sort asc,id desc").Scan(&results)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
for i := 0; i < len(results); i++ {
// 元数据
var (
meta adminForm.RoleDynamicMeta
rec adminForm.RoleDynamicBase
)
meta.Title = results[i].Name
meta.Icon = results[i].Icon
meta.NoCache = gconv.Bool(results[i].IsCache)
meta.Remark = results[i].Remark
rec.Id = results[i].Id
rec.Pid = results[i].Pid
rec.IsFrame = results[i].IsFrame
rec.Name = results[i].Name
rec.Code = results[i].Code
rec.Path = results[i].Path
rec.Hidden = results[i].IsVisible == "1"
rec.Redirect = service.getRedirect(results[i])
rec.Component = service.getComponent(results[i])
rec.AlwaysShow = true
rec.Meta = &meta
recursion = append(recursion, &rec)
}
_ = gconv.Structs(recursion, &models)
childIds := service.getChildIds(ctx, models, 0)
_ = gconv.Structs(childIds, &finalResponse)
return &finalResponse, nil
}
//
//  @Title  获取菜单的组件配置
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   model
//  @Return  string
//
func (service *menu) getComponent(mod *entity.AdminMenu) string {
if mod.Type == "M" {
return "Layout"
}
if mod.Type == "C" {
return mod.Component
}
return mod.Component
}
//
//  @Title  获取菜单是否重定向
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   model
//  @Return  string
//
func (service *menu) getRedirect(model *entity.AdminMenu) string {
if model.Type == "M" {
return "noRedirect"
}
return ""
}
//
//  @Title  将菜单转为父子关系菜单
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   lists
//  @Param   pid
//  @Return  []*RelationTree
//
func (service *menu) getChildIds(ctx context.Context, lists []*RelationTree, pid int64) []*RelationTree {
var (
count = len(lists)
newLists []*RelationTree
)
if count == 0 {
return nil
}
for i := 0; i < len(lists); i++ {
if lists[i].Id > 0 && lists[i].Pid == pid {
var row *RelationTree
if err := gconv.Structs(lists[i], &row); err != nil {
panic(err)
}
row.Children = service.getChildIds(ctx, lists, row.Id)
newLists = append(newLists, row)
}
}
return newLists
}
//
//  @Title  根据条件查询一行的数据
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   where
//  @Return  *entity.AdminMenu
//
func (service *menu) WhereScan(ctx context.Context, where dto.AdminMenu) *entity.AdminMenu {
var (
mod *entity.AdminMenu
err error
)
if err = dao.AdminMenu.Ctx(ctx).Where(where).Scan(&mod); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil
}
return mod
}

View File

@@ -0,0 +1,263 @@
//
// @Link  https://github.com/bufanyun/hotgo
// @Copyright  Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminService
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/bufanyun/hotgo/app/service/internal/dao"
"github.com/bufanyun/hotgo/app/service/internal/dto"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
)
var Notice = new(notice)
type notice struct{}
//
//  @Title  菜单名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *notice) NameUnique(ctx context.Context, in input.AdminNoticeNameUniqueInp) (*input.AdminNoticeNameUniqueModel, error) {
var res input.AdminNoticeNameUniqueModel
isUnique, err := dao.AdminNotice.IsUniqueTitle(ctx, in.Id, in.Title)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
res.IsUnique = isUnique
return &res, nil
}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *notice) Delete(ctx context.Context, in input.AdminNoticeDeleteInp) error {
_, err := dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *notice) Edit(ctx context.Context, in input.AdminNoticeEditInp) (err error) {
if in.Title == "" {
err = gerror.New("名称不能为空")
return err
}
uniqueName, err := dao.AdminNotice.IsUniqueTitle(ctx, in.Id, in.Title)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !uniqueName {
err = gerror.New("名称已存在")
return err
}
// 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 {
_, err = dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// 新增
in.CreatedAt = gtime.Now()
_, err = dao.AdminNotice.Ctx(ctx).Data(in).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictDataMaxSortRes
//  @Return  error
//
func (service *notice) MaxSort(ctx context.Context, in input.AdminNoticeMaxSortInp) (*input.AdminNoticeMaxSortModel, error) {
var res input.AdminNoticeMaxSortModel
if in.Id > 0 {
if err := dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
}
res.Sort = res.Sort + 10
return &res, nil
}
//
//  @Title  获取指定字典类型信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeViewRes
//  @Return  error
//
func (service *notice) View(ctx context.Context, in input.AdminNoticeViewInp) (res *input.AdminNoticeViewModel, err error) {
if err = dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
}
//
//  @Title  获取列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *notice) List(ctx context.Context, in input.AdminNoticeListInp) (list []*input.AdminNoticeListModel, totalCount int, err error) {
mod := dao.AdminNotice.Ctx(ctx)
if in.Realname != "" {
mod = mod.WhereLike("realname", "%"+in.Realname+"%")
}
if in.Username != "" {
mod = mod.WhereLike("username", "%"+in.Username+"%")
}
if in.Mobile > 0 {
mod = mod.Where("mobile", in.Mobile)
}
if in.Status > 0 {
mod = mod.Where("status", in.Status)
}
if in.DeptId > 0 {
mod = mod.Where("dept_id", in.DeptId)
}
// 日期范围
if in.StartTime != "" {
mod = mod.WhereGTE("created_at", in.StartTime)
}
if in.EndTime != "" {
mod = mod.WhereLTE("created_at", in.EndTime)
}
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
err = mod.Page(in.Page, in.Limit).Order("id desc").Scan(&list)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
//// TODO  重写树入参
//for i := 0; i < len(list); i++ {
//}
return list, totalCount, err
}
//
//  @Title  根据条件查询所有数据
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   where
//  @Return  []*entity.AdminNotice
//  @Return  error
//
func (service *notice) WhereAll(ctx context.Context, where dto.AdminNotice) ([]*entity.AdminNotice, error) {
var (
model []*entity.AdminNotice
err error
result gdb.Result
)
result, err = dao.AdminNotice.Ctx(ctx).Where(where).All()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
err = gconv.Scan(result, &model)
if err != nil {
err = gerror.Wrap(err, consts.ErrorRotaPointer)
return nil, err
}
return model, nil
}
//
//  @Title  根据条件查询一行的数据
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   where
//  @Return  *entity.AdminMenu
//
func (service *notice) WhereScan(ctx context.Context, where dto.AdminNotice) *entity.AdminNotice {
var (
model *entity.AdminNotice
err error
)
if err = dao.AdminMenu.Ctx(ctx).Where(where).Scan(&model); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil
}
return model
}

View File

@@ -0,0 +1,274 @@
//
// @Link  https://github.com/bufanyun/hotgo
// @Copyright  Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminService
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/internal/dao"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
)
var Post = new(post)
type post struct{}
//
//  @Title  删除
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *post) Delete(ctx context.Context, in input.AdminPostDeleteInp) error {
exist, err := dao.AdminMemberPost.Ctx(ctx).Where("post_id", in.Id).One()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !exist.IsEmpty() {
return gerror.New("请先解除该岗位下所有已关联用户关联关系!")
}
_, err = dao.AdminPost.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
//
//  @Title  修改/新增
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  error
//
func (service *post) Edit(ctx context.Context, in input.AdminPostEditInp) (err error) {
if in.Name == "" {
err = gerror.New("名称不能为空")
return err
}
if in.Code == "" {
err = gerror.New("编码不能为空")
return err
}
uniqueName, err := dao.AdminPost.IsUniqueName(ctx, in.Id, in.Name)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !uniqueName {
err = gerror.New("名称已存在")
return err
}
uniqueCode, err := dao.AdminPost.IsUniqueCode(ctx, in.Id, in.Code)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !uniqueCode {
err = gerror.New("编码已存在")
return err
}
// 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 {
_, err = dao.AdminPost.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// 新增
in.CreatedAt = gtime.Now()
_, err = dao.AdminPost.Ctx(ctx).Data(in).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
//
//  @Title  最大排序
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictDataMaxSortRes
//  @Return  error
//
func (service *post) MaxSort(ctx context.Context, in input.AdminPostMaxSortInp) (*input.AdminPostMaxSortModel, error) {
var res input.AdminPostMaxSortModel
if in.Id > 0 {
if err := dao.AdminMenu.Ctx(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
}
res.Sort = res.Sort + 10
return &res, nil
}
//
//  @Title  菜单名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *post) NameUnique(ctx context.Context, in input.AdminPostNameUniqueInp) (*input.AdminPostNameUniqueModel, error) {
var res input.AdminPostNameUniqueModel
isUnique, err := dao.AdminPost.IsUniqueName(ctx, in.Id, in.Name)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
res.IsUnique = isUnique
return &res, nil
}
//
//  @Title  编码是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeUniqueRes
//  @Return  error
//
func (service *post) CodeUnique(ctx context.Context, in input.AdminPostCodeUniqueInp) (*input.AdminPostCodeUniqueModel, error) {
var res input.AdminPostCodeUniqueModel
isUnique, err := dao.AdminPost.IsUniqueCode(ctx, in.Id, in.Code)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
res.IsUnique = isUnique
return &res, nil
}
//
//  @Title  获取指定字典类型信息
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  *adminForm.DictTypeViewRes
//  @Return  error
//
func (service *post) View(ctx context.Context, in input.AdminPostViewInp) (res *input.AdminPostViewModel, err error) {
if err = dao.AdminPost.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
}
//
//  @Title  获取列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *post) List(ctx context.Context, in input.AdminPostListInp) (list []*input.AdminPostListModel, totalCount int, err error) {
mod := dao.AdminPost.Ctx(ctx)
// 访问路径
if in.Name != "" {
mod = mod.WhereLike("name", "%"+in.Name+"%")
}
// 模块
if in.Code != "" {
mod = mod.Where("code", in.Code)
}
// 请求方式
if in.Status > 0 {
mod = mod.Where("status", in.Status)
}
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
err = mod.Page(in.Page, in.Limit).Order("id desc").Scan(&list)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
return list, totalCount, err
}
//
//  @Title  获取指定用户的第一岗位
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   RoleId
//  @Return  name
//  @Return  err
//
func (service *post) GetMemberByStartName(ctx context.Context, memberId int64) (name string, err error) {
// TODO  默认取第一岗位
postId, err := dao.AdminMemberPost.Ctx(ctx).
Fields("post_id").
Where("member_id", memberId).
Limit(1).
Value()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return name, err
}
val, err := dao.AdminPost.Ctx(ctx).
Fields("name").
Where("id", postId.Int()).
Order("id desc").
Value()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return name, err
}
return val.String(), nil
}

View File

@@ -0,0 +1,130 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package adminService
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/service/internal/dao"
"github.com/bufanyun/hotgo/app/service/internal/dto"
"github.com/bufanyun/hotgo/app/utils"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
)
var Role = new(role)
type role struct{}
//
//  @Title  验证权限
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   member_id
//  @Param   path
//  @Return  bool
//
func (service *role) Verify(ctx context.Context, member_id int, path string) bool {
var (
err error
)
if utils.Auth.IsExceptAuth(ctx, path) {
return true
}
menu := Menu.WhereScan(ctx, dto.AdminMenu{
Path: path,
Status: consts.StatusEnabled,
})
if menu == nil {
err = gerror.New(consts.ErrorNotData)
return false
}
g.Log().Print(ctx, "menu:", menu)
g.Log().Print(ctx, "err:", err)
return true
}
//
//  @Title  获取列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *role) List(ctx context.Context, in input.AdminRoleListInp) (list []*input.AdminRoleListModel, totalCount int, err error) {
mod := dao.AdminRole.Ctx(ctx)
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
err = mod.Page(in.Page, in.Limit).Order("id asc").Scan(&list)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
return list, totalCount, err
}
//
//  @Title  获取指定角色的名称
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   RoleId
//  @Return  name
//  @Return  err
//
func (service *role) GetName(ctx context.Context, RoleId int64) (name string, err error) {
roleName, err := dao.AdminRole.Ctx(ctx).
Fields("name").
Where("id", RoleId).
Order("id desc").
Value()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return name, err
}
return roleName.String(), nil
}
//
//  @Title  获取指定会员的岗位列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *role) GetMemberList(ctx context.Context, RoleId int64) (list []*input.AdminRoleListModel, err error) {
err = dao.AdminRole.Ctx(ctx).
Where("id", RoleId).
Order("id desc").
Scan(&list)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, err
}
return list, err
}

View File

@@ -0,0 +1,23 @@
//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package apiService
import (
"context"
"github.com/gogf/gf/v2/frame/g"
)
var Member = new(member)
type member struct {}
func (service *member) Test() (ctx context.Context) {
g.Log().Print(ctx, "apiService--WithMember--test...")
//g.Log().Print(ctx, "api调用" , service.App.Admin.Member.Test())
return
}

View File

@@ -0,0 +1,81 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/bufanyun/hotgo/app/service/internal/dao/internal"
"github.com/gogf/gf/v2/errors/gerror"
)
// adminDeptDao is the data access object for table hg_admin_dept.
// You can define custom methods on it to extend its functionality as you wish.
type adminDeptDao struct {
*internal.AdminDeptDao
}
var (
// AdminDept is globally public accessible object for table hg_admin_dept operations.
AdminDept = adminDeptDao{
internal.NewAdminDeptDao(),
}
)
//
//  @Title  判断名称是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   id
//  @Param   name
//  @Return  bool
//  @Return  error
//
func (dao *adminDeptDao) IsUniqueName(ctx context.Context, id int64, name string) (bool, error) {
var data *entity.AdminDept
m := dao.Ctx(ctx).Where("name", name)
if id > 0 {
m = m.WhereNot("id", id)
}
if err := m.Scan(&data); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return false, err
}
if data == nil {
return true, nil
}
return false, nil
}
//
//  @Title  获取最上级pid
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   data
//  @Return  int64
//  @Return  error
//
func (dao *adminDeptDao) TopPid(ctx context.Context, data *entity.AdminDept) (int64, error) {
var pidData *entity.AdminDept
if data.Pid == 0 {
return data.Id, nil
}
err := dao.Ctx(ctx).Where("id", data.Pid).Scan(&pidData)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return 0, err
}
return dao.TopPid(ctx, pidData)
}
// Fill with you ideas below.

View File

@@ -0,0 +1,118 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"context"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/bufanyun/hotgo/app/service/internal/dao/internal"
"github.com/gogf/gf/v2/errors/gerror"
)
// adminMemberDao is the data access object for table hg_admin_member.
// You can define custom methods on it to extend its functionality as you wish.
type adminMemberDao struct {
*internal.AdminMemberDao
}
var (
// AdminMember is globally public accessible object for table hg_admin_member operations.
AdminMember = adminMemberDao{
internal.NewAdminMemberDao(),
}
)
//
//  @Title  判断用户名是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   id
//  @Param   name
//  @Return  bool
//  @Return  error
//
func (dao *adminMemberDao) IsUniqueName(ctx context.Context, id int64, name string) (bool, error) {
var data *entity.AdminDept
m := dao.Ctx(ctx).Where("username", name)
if id > 0 {
m = m.WhereNot("id", id)
}
if err := m.Scan(&data); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return false, err
}
if data == nil {
return true, nil
}
return false, nil
}
//
//  @Title  判断邮箱是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   id
//  @Param   name
//  @Return  bool
//  @Return  error
//
func (dao *adminMemberDao) IsUniqueEmail(ctx context.Context, id int64, email string) (bool, error) {
var data *entity.AdminMember
m := dao.Ctx(ctx).Where("email", email)
if id > 0 {
m = m.WhereNot("id", id)
}
if err := m.Scan(&data); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return false, err
}
if data == nil {
return true, nil
}
return false, nil
}
//
//  @Title  判断手机号是否唯一
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   id
//  @Param   name
//  @Return  bool
//  @Return  error
//
func (dao *adminMemberDao) IsUniqueMobile(ctx context.Context, id int64, mobile string) (bool, error) {
var data *entity.AdminMember
m := dao.Ctx(ctx).Where("mobile", mobile)
if id > 0 {
m = m.WhereNot("id", id)
}
if err := m.Scan(&data); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return false, err
}
if data == nil {
return true, nil
}
return false, nil
}
// Fill with you ideas below.

View File

@@ -0,0 +1,24 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"github.com/bufanyun/hotgo/app/service/internal/dao/internal"
)
// adminMemberPostDao is the data access object for table hg_admin_member_post.
// You can define custom methods on it to extend its functionality as you wish.
type adminMemberPostDao struct {
*internal.AdminMemberPostDao
}
var (
// AdminMemberPost is globally public accessible object for table hg_admin_member_post operations.
AdminMemberPost = adminMemberPostDao{
internal.NewAdminMemberPostDao(),
}
)
// Fill with you ideas below.

View File

@@ -0,0 +1,24 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"github.com/bufanyun/hotgo/app/service/internal/dao/internal"
)
// adminMemberRoleDao is the data access object for table hg_admin_member_role.
// You can define custom methods on it to extend its functionality as you wish.
type adminMemberRoleDao struct {
*internal.AdminMemberRoleDao
}
var (
// AdminMemberRole is globally public accessible object for table hg_admin_member_role operations.
AdminMemberRole = adminMemberRoleDao{
internal.NewAdminMemberRoleDao(),
}
)
// Fill with you ideas below.

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