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

201
LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

1
hotgo-server/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* linguist-language=GO

20
hotgo-server/.gitignore vendored Normal file
View File

@ -0,0 +1,20 @@
.DS_Store
.buildpath
.hgignore.swp
.project
.orig
.swp
.idea/
.settings/
runtime/log/logger/*.log
runtime/log/logger/exception/*.log
runtime/log/logger/queue/*.log
runtime/log/server/*.log
runtime/log/server/access/*.log
runtime/log/server/error/*.log
bin/
*/.DS_Store
.vscode
main.exe
main.exe~
hotgo.exe

21
hotgo-server/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 john@goframe.org https://goframe.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1
hotgo-server/README.MD Normal file
View File

@ -0,0 +1 @@
测试

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
}

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