diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -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. diff --git a/hotgo-server/.gitattributes b/hotgo-server/.gitattributes new file mode 100644 index 0000000..1fbf887 --- /dev/null +++ b/hotgo-server/.gitattributes @@ -0,0 +1 @@ +* linguist-language=GO \ No newline at end of file diff --git a/hotgo-server/.gitignore b/hotgo-server/.gitignore new file mode 100644 index 0000000..8aa20ab --- /dev/null +++ b/hotgo-server/.gitignore @@ -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 \ No newline at end of file diff --git a/hotgo-server/LICENSE b/hotgo-server/LICENSE new file mode 100644 index 0000000..d410ffc --- /dev/null +++ b/hotgo-server/LICENSE @@ -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. \ No newline at end of file diff --git a/hotgo-server/README.MD b/hotgo-server/README.MD new file mode 100644 index 0000000..61de0ed --- /dev/null +++ b/hotgo-server/README.MD @@ -0,0 +1 @@ +测试 \ No newline at end of file diff --git a/hotgo-server/app/com/cache_com.go b/hotgo-server/app/com/cache_com.go new file mode 100644 index 0000000..972bdaa --- /dev/null +++ b/hotgo-server/app/com/cache_com.go @@ -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 +} diff --git a/hotgo-server/app/com/captcha_com.go b/hotgo-server/app/com/captcha_com.go new file mode 100644 index 0000000..965189f --- /dev/null +++ b/hotgo-server/app/com/captcha_com.go @@ -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) +} \ No newline at end of file diff --git a/hotgo-server/app/com/context_com.go b/hotgo-server/app/com/context_com.go new file mode 100644 index 0000000..622e512 --- /dev/null +++ b/hotgo-server/app/com/context_com.go @@ -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 +} diff --git a/hotgo-server/app/com/ip_com.go b/hotgo-server/app/com/ip_com.go new file mode 100644 index 0000000..1506bbc --- /dev/null +++ b/hotgo-server/app/com/ip_com.go @@ -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) +} diff --git a/hotgo-server/app/com/jwt_com.go b/hotgo-server/app/com/jwt_com.go new file mode 100644 index 0000000..9bd1275 --- /dev/null +++ b/hotgo-server/app/com/jwt_com.go @@ -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) +} diff --git a/hotgo-server/app/com/redis_com.go b/hotgo-server/app/com/redis_com.go new file mode 100644 index 0000000..26dab5a --- /dev/null +++ b/hotgo-server/app/com/redis_com.go @@ -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 +} diff --git a/hotgo-server/app/com/response_com.go b/hotgo-server/app/com/response_com.go new file mode 100644 index 0000000..f21fc2c --- /dev/null +++ b/hotgo-server/app/com/response_com.go @@ -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") +} diff --git a/hotgo-server/app/consts/app_consts.go b/hotgo-server/app/consts/app_consts.go new file mode 100644 index 0000000..b097cf6 --- /dev/null +++ b/hotgo-server/app/consts/app_consts.go @@ -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" +) diff --git a/hotgo-server/app/consts/code_consts.go b/hotgo-server/app/consts/code_consts.go new file mode 100644 index 0000000..c86d07d --- /dev/null +++ b/hotgo-server/app/consts/code_consts.go @@ -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. +) diff --git a/hotgo-server/app/consts/context_consts.go b/hotgo-server/app/consts/context_consts.go new file mode 100644 index 0000000..cd62528 --- /dev/null +++ b/hotgo-server/app/consts/context_consts.go @@ -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" +) diff --git a/hotgo-server/app/consts/debris_consts.go b/hotgo-server/app/consts/debris_consts.go new file mode 100644 index 0000000..44e5dc4 --- /dev/null +++ b/hotgo-server/app/consts/debris_consts.go @@ -0,0 +1,8 @@ +package consts + +// 碎片 +const ( + + // 默认分页 + DebrisPageSize = 10 +) diff --git a/hotgo-server/app/consts/error_consts.go b/hotgo-server/app/consts/error_consts.go new file mode 100644 index 0000000..a8ff338 --- /dev/null +++ b/hotgo-server/app/consts/error_consts.go @@ -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 = "指针转换异常" +) diff --git a/hotgo-server/app/consts/openapi_consts.go b/hotgo-server/app/consts/openapi_consts.go new file mode 100644 index 0000000..886dc49 --- /dev/null +++ b/hotgo-server/app/consts/openapi_consts.go @@ -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` +) diff --git a/hotgo-server/app/consts/queue_consts.go b/hotgo-server/app/consts/queue_consts.go new file mode 100644 index 0000000..9a265b5 --- /dev/null +++ b/hotgo-server/app/consts/queue_consts.go @@ -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` +) diff --git a/hotgo-server/app/consts/redis_consts.go b/hotgo-server/app/consts/redis_consts.go new file mode 100644 index 0000000..6586a68 --- /dev/null +++ b/hotgo-server/app/consts/redis_consts.go @@ -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-用户身份绑定 +) diff --git a/hotgo-server/app/consts/status_consts.go b/hotgo-server/app/consts/status_consts.go new file mode 100644 index 0000000..cdcaf22 --- /dev/null +++ b/hotgo-server/app/consts/status_consts.go @@ -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" //已删除 +) diff --git a/hotgo-server/app/consts/version_consts.go b/hotgo-server/app/consts/version_consts.go new file mode 100644 index 0000000..77eaf01 --- /dev/null +++ b/hotgo-server/app/consts/version_consts.go @@ -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" +) diff --git a/hotgo-server/app/controller/adminController/config_controller.go b/hotgo-server/app/controller/adminController/config_controller.go new file mode 100644 index 0000000..cb100ea --- /dev/null +++ b/hotgo-server/app/controller/adminController/config_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/adminController/dept_controller.go b/hotgo-server/app/controller/adminController/dept_controller.go new file mode 100644 index 0000000..7f615be --- /dev/null +++ b/hotgo-server/app/controller/adminController/dept_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/adminController/dict_controller.go b/hotgo-server/app/controller/adminController/dict_controller.go new file mode 100644 index 0000000..cecf3f6 --- /dev/null +++ b/hotgo-server/app/controller/adminController/dict_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/adminController/log_controller.go b/hotgo-server/app/controller/adminController/log_controller.go new file mode 100644 index 0000000..b934841 --- /dev/null +++ b/hotgo-server/app/controller/adminController/log_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/adminController/login_controller.go b/hotgo-server/app/controller/adminController/login_controller.go new file mode 100644 index 0000000..b41a507 --- /dev/null +++ b/hotgo-server/app/controller/adminController/login_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/adminController/member_controller.go b/hotgo-server/app/controller/adminController/member_controller.go new file mode 100644 index 0000000..b15b415 --- /dev/null +++ b/hotgo-server/app/controller/adminController/member_controller.go @@ -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) +} diff --git a/hotgo-server/app/controller/adminController/menu_controller.go b/hotgo-server/app/controller/adminController/menu_controller.go new file mode 100644 index 0000000..84357bd --- /dev/null +++ b/hotgo-server/app/controller/adminController/menu_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/adminController/notice_controller.go b/hotgo-server/app/controller/adminController/notice_controller.go new file mode 100644 index 0000000..36ab285 --- /dev/null +++ b/hotgo-server/app/controller/adminController/notice_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/adminController/post_controller.go b/hotgo-server/app/controller/adminController/post_controller.go new file mode 100644 index 0000000..c955910 --- /dev/null +++ b/hotgo-server/app/controller/adminController/post_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/adminController/role_controller.go b/hotgo-server/app/controller/adminController/role_controller.go new file mode 100644 index 0000000..16d59c5 --- /dev/null +++ b/hotgo-server/app/controller/adminController/role_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/apiController/base_controller.go b/hotgo-server/app/controller/apiController/base_controller.go new file mode 100644 index 0000000..77c7ad5 --- /dev/null +++ b/hotgo-server/app/controller/apiController/base_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/apiController/dict_controller.go b/hotgo-server/app/controller/apiController/dict_controller.go new file mode 100644 index 0000000..7d22a59 --- /dev/null +++ b/hotgo-server/app/controller/apiController/dict_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/apiController/log_controller.go b/hotgo-server/app/controller/apiController/log_controller.go new file mode 100644 index 0000000..685599e --- /dev/null +++ b/hotgo-server/app/controller/apiController/log_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/apiController/login_controller.go b/hotgo-server/app/controller/apiController/login_controller.go new file mode 100644 index 0000000..fc14477 --- /dev/null +++ b/hotgo-server/app/controller/apiController/login_controller.go @@ -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 +} diff --git a/hotgo-server/app/controller/apiController/member_controller.go b/hotgo-server/app/controller/apiController/member_controller.go new file mode 100644 index 0000000..e10ed47 --- /dev/null +++ b/hotgo-server/app/controller/apiController/member_controller.go @@ -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 +} diff --git a/hotgo-server/app/factory/queue/kafkamq.go b/hotgo-server/app/factory/queue/kafkamq.go new file mode 100644 index 0000000..193af40 --- /dev/null +++ b/hotgo-server/app/factory/queue/kafkamq.go @@ -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 +} diff --git a/hotgo-server/app/factory/queue/list.go b/hotgo-server/app/factory/queue/list.go new file mode 100644 index 0000000..898a25e --- /dev/null +++ b/hotgo-server/app/factory/queue/list.go @@ -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() +} diff --git a/hotgo-server/app/factory/queue/logger.go b/hotgo-server/app/factory/queue/logger.go new file mode 100644 index 0000000..1f61a76 --- /dev/null +++ b/hotgo-server/app/factory/queue/logger.go @@ -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) +} diff --git a/hotgo-server/app/factory/queue/main.go b/hotgo-server/app/factory/queue/main.go new file mode 100644 index 0000000..db241c2 --- /dev/null +++ b/hotgo-server/app/factory/queue/main.go @@ -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) +} diff --git a/hotgo-server/app/factory/queue/queue_test.go b/hotgo-server/app/factory/queue/queue_test.go new file mode 100644 index 0000000..432eebf --- /dev/null +++ b/hotgo-server/app/factory/queue/queue_test.go @@ -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") + } + +} diff --git a/hotgo-server/app/factory/queue/redismq.go b/hotgo-server/app/factory/queue/redismq.go new file mode 100644 index 0000000..132d75e --- /dev/null +++ b/hotgo-server/app/factory/queue/redismq.go @@ -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 +} diff --git a/hotgo-server/app/factory/queue/rocketmq.go b/hotgo-server/app/factory/queue/rocketmq.go new file mode 100644 index 0000000..e278823 --- /dev/null +++ b/hotgo-server/app/factory/queue/rocketmq.go @@ -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 +} diff --git a/hotgo-server/app/factory/queue/rocketmq_rewrite_logger.go b/hotgo-server/app/factory/queue/rocketmq_rewrite_logger.go new file mode 100644 index 0000000..262c609 --- /dev/null +++ b/hotgo-server/app/factory/queue/rocketmq_rewrite_logger.go @@ -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)) + } +} diff --git a/hotgo-server/app/form/adminForm/config_form.go b/hotgo-server/app/form/adminForm/config_form.go new file mode 100644 index 0000000..5fbe83c --- /dev/null +++ b/hotgo-server/app/form/adminForm/config_form.go @@ -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:"排序"` +} diff --git a/hotgo-server/app/form/adminForm/dept_form.go b/hotgo-server/app/form/adminForm/dept_form.go new file mode 100644 index 0000000..bda2890 --- /dev/null +++ b/hotgo-server/app/form/adminForm/dept_form.go @@ -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:"排序"` +} diff --git a/hotgo-server/app/form/adminForm/dict_form.go b/hotgo-server/app/form/adminForm/dict_form.go new file mode 100644 index 0000000..b2df2a8 --- /dev/null +++ b/hotgo-server/app/form/adminForm/dict_form.go @@ -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:"是否唯一"` +} diff --git a/hotgo-server/app/form/adminForm/log_form.go b/hotgo-server/app/form/adminForm/log_form.go new file mode 100644 index 0000000..dcba676 --- /dev/null +++ b/hotgo-server/app/form/adminForm/log_form.go @@ -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 +} diff --git a/hotgo-server/app/form/adminForm/login_form.go b/hotgo-server/app/form/adminForm/login_form.go new file mode 100644 index 0000000..5904a93 --- /dev/null +++ b/hotgo-server/app/form/adminForm/login_form.go @@ -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"` +} diff --git a/hotgo-server/app/form/adminForm/member_form.go b/hotgo-server/app/form/adminForm/member_form.go new file mode 100644 index 0000000..3fb8e53 --- /dev/null +++ b/hotgo-server/app/form/adminForm/member_form.go @@ -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:"用户信息"` +} diff --git a/hotgo-server/app/form/adminForm/menu_form.go b/hotgo-server/app/form/adminForm/menu_form.go new file mode 100644 index 0000000..131f8c6 --- /dev/null +++ b/hotgo-server/app/form/adminForm/menu_form.go @@ -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"` +} diff --git a/hotgo-server/app/form/adminForm/notice_form.go b/hotgo-server/app/form/adminForm/notice_form.go new file mode 100644 index 0000000..8aed408 --- /dev/null +++ b/hotgo-server/app/form/adminForm/notice_form.go @@ -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:"排序"` +} diff --git a/hotgo-server/app/form/adminForm/post_form.go b/hotgo-server/app/form/adminForm/post_form.go new file mode 100644 index 0000000..27f830e --- /dev/null +++ b/hotgo-server/app/form/adminForm/post_form.go @@ -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:"是否唯一"` +} diff --git a/hotgo-server/app/form/adminForm/role_form.go b/hotgo-server/app/form/adminForm/role_form.go new file mode 100644 index 0000000..20a06aa --- /dev/null +++ b/hotgo-server/app/form/adminForm/role_form.go @@ -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 diff --git a/hotgo-server/app/form/apiForm/base_form.go b/hotgo-server/app/form/apiForm/base_form.go new file mode 100644 index 0000000..332ca3c --- /dev/null +++ b/hotgo-server/app/form/apiForm/base_form.go @@ -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{} diff --git a/hotgo-server/app/form/apiForm/dict_form.go b/hotgo-server/app/form/apiForm/dict_form.go new file mode 100644 index 0000000..dd8df5a --- /dev/null +++ b/hotgo-server/app/form/apiForm/dict_form.go @@ -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 diff --git a/hotgo-server/app/form/apiForm/log_form.go b/hotgo-server/app/form/apiForm/log_form.go new file mode 100644 index 0000000..0a48f87 --- /dev/null +++ b/hotgo-server/app/form/apiForm/log_form.go @@ -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 +} diff --git a/hotgo-server/app/form/apiForm/login_form.go b/hotgo-server/app/form/apiForm/login_form.go new file mode 100644 index 0000000..1a14f68 --- /dev/null +++ b/hotgo-server/app/form/apiForm/login_form.go @@ -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"` +} diff --git a/hotgo-server/app/form/apiForm/member_form.go b/hotgo-server/app/form/apiForm/member_form.go new file mode 100644 index 0000000..b150ac6 --- /dev/null +++ b/hotgo-server/app/form/apiForm/member_form.go @@ -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:"当前角色"` +} diff --git a/hotgo-server/app/form/common.go b/hotgo-server/app/form/common.go new file mode 100644 index 0000000..6e51118 --- /dev/null +++ b/hotgo-server/app/form/common.go @@ -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:"状态"` +} diff --git a/hotgo-server/app/form/input/admin_dept_input.go b/hotgo-server/app/form/input/admin_dept_input.go new file mode 100644 index 0000000..4c7df38 --- /dev/null +++ b/hotgo-server/app/form/input/admin_dept_input.go @@ -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 diff --git a/hotgo-server/app/form/input/admin_member_input.go b/hotgo-server/app/form/input/admin_member_input.go new file mode 100644 index 0000000..b5ff5d2 --- /dev/null +++ b/hotgo-server/app/form/input/admin_member_input.go @@ -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"` +} diff --git a/hotgo-server/app/form/input/admin_notice_input.go b/hotgo-server/app/form/input/admin_notice_input.go new file mode 100644 index 0000000..00877f1 --- /dev/null +++ b/hotgo-server/app/form/input/admin_notice_input.go @@ -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"` +} diff --git a/hotgo-server/app/form/input/admin_post_input.go b/hotgo-server/app/form/input/admin_post_input.go new file mode 100644 index 0000000..09a23da --- /dev/null +++ b/hotgo-server/app/form/input/admin_post_input.go @@ -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{} diff --git a/hotgo-server/app/form/input/admin_role_input.go b/hotgo-server/app/form/input/admin_role_input.go new file mode 100644 index 0000000..02b1f04 --- /dev/null +++ b/hotgo-server/app/form/input/admin_role_input.go @@ -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"` +} diff --git a/hotgo-server/app/form/input/sys_config_input.go b/hotgo-server/app/form/input/sys_config_input.go new file mode 100644 index 0000000..87ec6b6 --- /dev/null +++ b/hotgo-server/app/form/input/sys_config_input.go @@ -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"` +} diff --git a/hotgo-server/app/form/input/sys_log_input.go b/hotgo-server/app/form/input/sys_log_input.go new file mode 100644 index 0000000..c9aa62c --- /dev/null +++ b/hotgo-server/app/form/input/sys_log_input.go @@ -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"` +} diff --git a/hotgo-server/app/hook/hook.go b/hotgo-server/app/hook/hook.go new file mode 100644 index 0000000..b705720 --- /dev/null +++ b/hotgo-server/app/hook/hook.go @@ -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) +} diff --git a/hotgo-server/app/interfaces/queue_producer_interface.go b/hotgo-server/app/interfaces/queue_producer_interface.go new file mode 100644 index 0000000..253154e --- /dev/null +++ b/hotgo-server/app/interfaces/queue_producer_interface.go @@ -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 +} \ No newline at end of file diff --git a/hotgo-server/app/middleware/admin_auth.go b/hotgo-server/app/middleware/admin_auth.go new file mode 100644 index 0000000..df8301f --- /dev/null +++ b/hotgo-server/app/middleware/admin_auth.go @@ -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() +} diff --git a/hotgo-server/app/middleware/api_auth.go b/hotgo-server/app/middleware/api_auth.go new file mode 100644 index 0000000..b1ae655 --- /dev/null +++ b/hotgo-server/app/middleware/api_auth.go @@ -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() +} diff --git a/hotgo-server/app/middleware/handler_response.go b/hotgo-server/app/middleware/handler_response.go new file mode 100644 index 0000000..4c8a4ab --- /dev/null +++ b/hotgo-server/app/middleware/handler_response.go @@ -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) +} diff --git a/hotgo-server/app/middleware/middleware.go b/hotgo-server/app/middleware/middleware.go new file mode 100644 index 0000000..5723732 --- /dev/null +++ b/hotgo-server/app/middleware/middleware.go @@ -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() +} diff --git a/hotgo-server/app/model/context.go b/hotgo-server/app/model/context.go new file mode 100644 index 0000000..d6b5785 --- /dev/null +++ b/hotgo-server/app/model/context.go @@ -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:"登录应用"` +} diff --git a/hotgo-server/app/model/entity/admin_dept.go b/hotgo-server/app/model/entity/admin_dept.go new file mode 100644 index 0000000..035b774 --- /dev/null +++ b/hotgo-server/app/model/entity/admin_dept.go @@ -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:"更新时间"` +} diff --git a/hotgo-server/app/model/entity/admin_member.go b/hotgo-server/app/model/entity/admin_member.go new file mode 100644 index 0000000..9db55bc --- /dev/null +++ b/hotgo-server/app/model/entity/admin_member.go @@ -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:"修改时间"` +} diff --git a/hotgo-server/app/model/entity/admin_member_post.go b/hotgo-server/app/model/entity/admin_member_post.go new file mode 100644 index 0000000..88aaba2 --- /dev/null +++ b/hotgo-server/app/model/entity/admin_member_post.go @@ -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"` +} diff --git a/hotgo-server/app/model/entity/admin_member_role.go b/hotgo-server/app/model/entity/admin_member_role.go new file mode 100644 index 0000000..13a81b0 --- /dev/null +++ b/hotgo-server/app/model/entity/admin_member_role.go @@ -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"` +} diff --git a/hotgo-server/app/model/entity/admin_menu.go b/hotgo-server/app/model/entity/admin_menu.go new file mode 100644 index 0000000..cc16576 --- /dev/null +++ b/hotgo-server/app/model/entity/admin_menu.go @@ -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:"更新时间"` +} diff --git a/hotgo-server/app/model/entity/admin_menu_old.go b/hotgo-server/app/model/entity/admin_menu_old.go new file mode 100644 index 0000000..ea8d422 --- /dev/null +++ b/hotgo-server/app/model/entity/admin_menu_old.go @@ -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:"更新时间"` +} diff --git a/hotgo-server/app/model/entity/admin_notice.go b/hotgo-server/app/model/entity/admin_notice.go new file mode 100644 index 0000000..355c0d1 --- /dev/null +++ b/hotgo-server/app/model/entity/admin_notice.go @@ -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:"更新时间"` +} diff --git a/hotgo-server/app/model/entity/admin_post.go b/hotgo-server/app/model/entity/admin_post.go new file mode 100644 index 0000000..935a099 --- /dev/null +++ b/hotgo-server/app/model/entity/admin_post.go @@ -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:"更新时间"` +} diff --git a/hotgo-server/app/model/entity/admin_role.go b/hotgo-server/app/model/entity/admin_role.go new file mode 100644 index 0000000..2f0f92c --- /dev/null +++ b/hotgo-server/app/model/entity/admin_role.go @@ -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:"更新时间"` +} diff --git a/hotgo-server/app/model/entity/admin_role_dept.go b/hotgo-server/app/model/entity/admin_role_dept.go new file mode 100644 index 0000000..7a65652 --- /dev/null +++ b/hotgo-server/app/model/entity/admin_role_dept.go @@ -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"` +} diff --git a/hotgo-server/app/model/entity/admin_role_menu.go b/hotgo-server/app/model/entity/admin_role_menu.go new file mode 100644 index 0000000..47d3e9b --- /dev/null +++ b/hotgo-server/app/model/entity/admin_role_menu.go @@ -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"` +} diff --git a/hotgo-server/app/model/entity/sys_config.go b/hotgo-server/app/model/entity/sys_config.go new file mode 100644 index 0000000..2fc7844 --- /dev/null +++ b/hotgo-server/app/model/entity/sys_config.go @@ -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:"更新时间"` +} diff --git a/hotgo-server/app/model/entity/sys_dict_data.go b/hotgo-server/app/model/entity/sys_dict_data.go new file mode 100644 index 0000000..3a66971 --- /dev/null +++ b/hotgo-server/app/model/entity/sys_dict_data.go @@ -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:"更新时间"` +} diff --git a/hotgo-server/app/model/entity/sys_dict_type.go b/hotgo-server/app/model/entity/sys_dict_type.go new file mode 100644 index 0000000..51a247e --- /dev/null +++ b/hotgo-server/app/model/entity/sys_dict_type.go @@ -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:"更新时间"` +} diff --git a/hotgo-server/app/model/entity/sys_log.go b/hotgo-server/app/model/entity/sys_log.go new file mode 100644 index 0000000..7205ee3 --- /dev/null +++ b/hotgo-server/app/model/entity/sys_log.go @@ -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:"修改时间"` +} diff --git a/hotgo-server/app/model/entity/sys_provinces.go b/hotgo-server/app/model/entity/sys_provinces.go new file mode 100644 index 0000000..1c56a52 --- /dev/null +++ b/hotgo-server/app/model/entity/sys_provinces.go @@ -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:"排序"` +} diff --git a/hotgo-server/app/model/response.go b/hotgo-server/app/model/response.go new file mode 100644 index 0000000..7363b09 --- /dev/null +++ b/hotgo-server/app/model/response.go @@ -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"` +} diff --git a/hotgo-server/app/model/tree.go b/hotgo-server/app/model/tree.go new file mode 100644 index 0000000..cf722ec --- /dev/null +++ b/hotgo-server/app/model/tree.go @@ -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"` +} diff --git a/hotgo-server/app/service/adminService/dept_service.go b/hotgo-server/app/service/adminService/dept_service.go new file mode 100644 index 0000000..7fb351f --- /dev/null +++ b/hotgo-server/app/service/adminService/dept_service.go @@ -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 +} diff --git a/hotgo-server/app/service/adminService/member_post_service.go b/hotgo-server/app/service/adminService/member_post_service.go new file mode 100644 index 0000000..41304ba --- /dev/null +++ b/hotgo-server/app/service/adminService/member_post_service.go @@ -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 +} diff --git a/hotgo-server/app/service/adminService/member_service.go b/hotgo-server/app/service/adminService/member_service.go new file mode 100644 index 0000000..2f1b7ef --- /dev/null +++ b/hotgo-server/app/service/adminService/member_service.go @@ -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 +} diff --git a/hotgo-server/app/service/adminService/menu_service.go b/hotgo-server/app/service/adminService/menu_service.go new file mode 100644 index 0000000..35f9efd --- /dev/null +++ b/hotgo-server/app/service/adminService/menu_service.go @@ -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 +} diff --git a/hotgo-server/app/service/adminService/notice_service.go b/hotgo-server/app/service/adminService/notice_service.go new file mode 100644 index 0000000..fbefaed --- /dev/null +++ b/hotgo-server/app/service/adminService/notice_service.go @@ -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 +} diff --git a/hotgo-server/app/service/adminService/post_service.go b/hotgo-server/app/service/adminService/post_service.go new file mode 100644 index 0000000..2f9414f --- /dev/null +++ b/hotgo-server/app/service/adminService/post_service.go @@ -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 +} diff --git a/hotgo-server/app/service/adminService/role_service.go b/hotgo-server/app/service/adminService/role_service.go new file mode 100644 index 0000000..48a63f4 --- /dev/null +++ b/hotgo-server/app/service/adminService/role_service.go @@ -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 +} diff --git a/hotgo-server/app/service/apiService/member_service.go b/hotgo-server/app/service/apiService/member_service.go new file mode 100644 index 0000000..0ea9a02 --- /dev/null +++ b/hotgo-server/app/service/apiService/member_service.go @@ -0,0 +1,23 @@ +// +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2022 HotGo CLI +// @Author  Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// +package apiService + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" +) + +var Member = new(member) + +type member struct {} + +func (service *member) Test() (ctx context.Context) { + g.Log().Print(ctx, "apiService--WithMember--test...") + + //g.Log().Print(ctx, "api调用:" , service.App.Admin.Member.Test()) + return +} \ No newline at end of file diff --git a/hotgo-server/app/service/internal/dao/admin_dept.go b/hotgo-server/app/service/internal/dao/admin_dept.go new file mode 100644 index 0000000..c3e7a83 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_dept.go @@ -0,0 +1,81 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/model/entity" + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" + "github.com/gogf/gf/v2/errors/gerror" +) + +// adminDeptDao is the data access object for table hg_admin_dept. +// You can define custom methods on it to extend its functionality as you wish. +type adminDeptDao struct { + *internal.AdminDeptDao +} + +var ( + // AdminDept is globally public accessible object for table hg_admin_dept operations. + AdminDept = adminDeptDao{ + internal.NewAdminDeptDao(), + } +) + +// +//  @Title  判断名称是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   name +//  @Return  bool +//  @Return  error +// +func (dao *adminDeptDao) IsUniqueName(ctx context.Context, id int64, name string) (bool, error) { + var data *entity.AdminDept + m := dao.Ctx(ctx).Where("name", name) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} + +// +//  @Title  获取最上级pid +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   data +//  @Return  int64 +//  @Return  error +// +func (dao *adminDeptDao) TopPid(ctx context.Context, data *entity.AdminDept) (int64, error) { + var pidData *entity.AdminDept + if data.Pid == 0 { + return data.Id, nil + } + err := dao.Ctx(ctx).Where("id", data.Pid).Scan(&pidData) + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return 0, err + } + + return dao.TopPid(ctx, pidData) +} + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/admin_member.go b/hotgo-server/app/service/internal/dao/admin_member.go new file mode 100644 index 0000000..f8b3d61 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_member.go @@ -0,0 +1,118 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/model/entity" + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" + "github.com/gogf/gf/v2/errors/gerror" +) + +// adminMemberDao is the data access object for table hg_admin_member. +// You can define custom methods on it to extend its functionality as you wish. +type adminMemberDao struct { + *internal.AdminMemberDao +} + +var ( + // AdminMember is globally public accessible object for table hg_admin_member operations. + AdminMember = adminMemberDao{ + internal.NewAdminMemberDao(), + } +) + +// +//  @Title  判断用户名是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   name +//  @Return  bool +//  @Return  error +// +func (dao *adminMemberDao) IsUniqueName(ctx context.Context, id int64, name string) (bool, error) { + var data *entity.AdminDept + m := dao.Ctx(ctx).Where("username", name) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} + +// +//  @Title  判断邮箱是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   name +//  @Return  bool +//  @Return  error +// +func (dao *adminMemberDao) IsUniqueEmail(ctx context.Context, id int64, email string) (bool, error) { + var data *entity.AdminMember + m := dao.Ctx(ctx).Where("email", email) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} + +// +//  @Title  判断手机号是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   name +//  @Return  bool +//  @Return  error +// +func (dao *adminMemberDao) IsUniqueMobile(ctx context.Context, id int64, mobile string) (bool, error) { + var data *entity.AdminMember + m := dao.Ctx(ctx).Where("mobile", mobile) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/admin_member_post.go b/hotgo-server/app/service/internal/dao/admin_member_post.go new file mode 100644 index 0000000..8f85887 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_member_post.go @@ -0,0 +1,24 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" +) + +// adminMemberPostDao is the data access object for table hg_admin_member_post. +// You can define custom methods on it to extend its functionality as you wish. +type adminMemberPostDao struct { + *internal.AdminMemberPostDao +} + +var ( + // AdminMemberPost is globally public accessible object for table hg_admin_member_post operations. + AdminMemberPost = adminMemberPostDao{ + internal.NewAdminMemberPostDao(), + } +) + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/admin_member_role.go b/hotgo-server/app/service/internal/dao/admin_member_role.go new file mode 100644 index 0000000..d81409d --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_member_role.go @@ -0,0 +1,24 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" +) + +// adminMemberRoleDao is the data access object for table hg_admin_member_role. +// You can define custom methods on it to extend its functionality as you wish. +type adminMemberRoleDao struct { + *internal.AdminMemberRoleDao +} + +var ( + // AdminMemberRole is globally public accessible object for table hg_admin_member_role operations. + AdminMemberRole = adminMemberRoleDao{ + internal.NewAdminMemberRoleDao(), + } +) + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/admin_menu.go b/hotgo-server/app/service/internal/dao/admin_menu.go new file mode 100644 index 0000000..ac104ce --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_menu.go @@ -0,0 +1,180 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/model" + "github.com/bufanyun/hotgo/app/model/entity" + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" + "github.com/gogf/gf/v2/errors/gerror" +) + +// @Description +type adminMenuDao struct { + *internal.AdminMenuDao //  } +} + +var ( + // AdminMenu is globally public accessible object for table hg_admin_menu operations. + AdminMenu = adminMenuDao{ + internal.NewAdminMenuDao(), + } +) + +// +//  @Title  判断名称是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   name +//  @Return  bool +//  @Return  error +// +func (dao *adminMenuDao) IsUniqueName(ctx context.Context, id int64, name string) (bool, error) { + var data *entity.AdminMenu + m := dao.Ctx(ctx).Where("name", name) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} + +// +//  @Title  判断编码是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   code +//  @Return  bool +//  @Return  error +// +func (dao *adminMenuDao) IsUniqueCode(ctx context.Context, id int64, code string) (bool, error) { + var data *entity.AdminMenu + m := dao.Ctx(ctx).Where("code", code) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} + +// +//  @Title  生成kl树列表 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   pid +//  @Param   lists +//  @Return  []*model.TreeMenu +//  @Return  error +// +func (dao *adminMenuDao) GenLabelTreeList(ctx context.Context, pid int64) ([]*model.LabelTreeMenu, error) { + + var ( + newLst []*model.LabelTreeMenu + ) + if err := dao.Ctx(ctx).Where("pid", pid).Order("sort asc,id desc").Scan(&newLst); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return nil, err + } + + for i := 0; i < len(newLst); i++ { + newLst[i].Key = newLst[i].Id + newLst[i].Label = newLst[i].Name + err := dao.Ctx(ctx).Where("pid", newLst[i].Id).Order("sort asc,id desc").Scan(&newLst[i].Children) + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return nil, err + } + + for i2 := 0; i2 < len(newLst[i].Children); i2++ { + newLst[i].Children[i2].Key = newLst[i].Children[i2].Id + newLst[i].Children[i2].Label = newLst[i].Children[i2].Name + } + } + + return newLst, nil +} + +// +//  @Title  生成树列表 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   pid +//  @Param   lists +//  @Return  []*model.TreeMenu +//  @Return  error +// +func (dao *adminMenuDao) GenTreeList(ctx context.Context, pid int64, ids []int64) ([]*model.TreeMenu, error) { + + var ( + newLst []*model.TreeMenu + ) + if err := dao.Ctx(ctx).Where("id", ids).Where("pid", pid).Order("sort asc,id desc").Scan(&newLst); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return nil, err + } + + for i := 0; i < len(newLst); i++ { + err := dao.Ctx(ctx).Where("pid", newLst[i].Id).Order("sort asc,id desc").Scan(&newLst[i].Children) + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return nil, err + } + } + + return newLst, nil +} + +// +//  @Title  获取最上级pid +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   data +//  @Return  int64 +//  @Return  error +// +func (dao *adminMenuDao) TopPid(ctx context.Context, data *entity.AdminMenu) (int64, error) { + var pidData *entity.AdminMenu + if data.Pid == 0 { + return data.Id, nil + } + err := dao.Ctx(ctx).Where("id", data.Pid).Scan(&pidData) + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return 0, err + } + + return dao.TopPid(ctx, pidData) +} + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/admin_menu_old.go b/hotgo-server/app/service/internal/dao/admin_menu_old.go new file mode 100644 index 0000000..265e376 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_menu_old.go @@ -0,0 +1,24 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" +) + +// adminMenuOldDao is the data access object for table hg_admin_menu_old. +// You can define custom methods on it to extend its functionality as you wish. +type adminMenuOldDao struct { + *internal.AdminMenuOldDao +} + +var ( + // AdminMenuOld is globally public accessible object for table hg_admin_menu_old operations. + AdminMenuOld = adminMenuOldDao{ + internal.NewAdminMenuOldDao(), + } +) + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/admin_notice.go b/hotgo-server/app/service/internal/dao/admin_notice.go new file mode 100644 index 0000000..b64b4fa --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_notice.go @@ -0,0 +1,58 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/model/entity" + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" + "github.com/gogf/gf/v2/errors/gerror" +) + +// adminNoticeDao is the data access object for table hg_admin_notice. +// You can define custom methods on it to extend its functionality as you wish. +type adminNoticeDao struct { + *internal.AdminNoticeDao +} + +var ( + // AdminNotice is globally public accessible object for table hg_admin_notice operations. + AdminNotice = adminNoticeDao{ + internal.NewAdminNoticeDao(), + } +) + +// Fill with you ideas below. + +// +//  @Title  判断名称是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   name +//  @Return  bool +//  @Return  error +// +func (dao *adminNoticeDao) IsUniqueTitle(ctx context.Context, id int64, title string) (bool, error) { + var data *entity.AdminNotice + m := dao.Ctx(ctx).Where("title", title) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} diff --git a/hotgo-server/app/service/internal/dao/admin_post.go b/hotgo-server/app/service/internal/dao/admin_post.go new file mode 100644 index 0000000..4184e80 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_post.go @@ -0,0 +1,88 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/model/entity" + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" + "github.com/gogf/gf/v2/errors/gerror" +) + +// adminPostDao is the data access object for table hg_admin_post. +// You can define custom methods on it to extend its functionality as you wish. +type adminPostDao struct { + *internal.AdminPostDao +} + +var ( + // AdminPost is globally public accessible object for table hg_admin_post operations. + AdminPost = adminPostDao{ + internal.NewAdminPostDao(), + } +) + +// Fill with you ideas below. + +// +//  @Title  判断名称是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   name +//  @Return  bool +//  @Return  error +// +func (dao *adminPostDao) IsUniqueName(ctx context.Context, id int64, name string) (bool, error) { + var data *entity.AdminPost + m := dao.Ctx(ctx).Where("name", name) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} + +// +//  @Title  判断编码是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   code +//  @Return  bool +//  @Return  error +// +func (dao *adminPostDao) IsUniqueCode(ctx context.Context, id int64, code string) (bool, error) { + var data *entity.AdminPost + m := dao.Ctx(ctx).Where("code", code) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} diff --git a/hotgo-server/app/service/internal/dao/admin_role.go b/hotgo-server/app/service/internal/dao/admin_role.go new file mode 100644 index 0000000..3ef3b48 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_role.go @@ -0,0 +1,24 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" +) + +// adminRoleDao is the data access object for table hg_admin_role. +// You can define custom methods on it to extend its functionality as you wish. +type adminRoleDao struct { + *internal.AdminRoleDao +} + +var ( + // AdminRole is globally public accessible object for table hg_admin_role operations. + AdminRole = adminRoleDao{ + internal.NewAdminRoleDao(), + } +) + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/admin_role_dept.go b/hotgo-server/app/service/internal/dao/admin_role_dept.go new file mode 100644 index 0000000..2626c8b --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_role_dept.go @@ -0,0 +1,29 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +// +// @Package  dao +// @Description  +// @Author  Ms <133814250@qq.com> +// +package dao + +import ( + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" +) + +// adminRoleDeptDao is the data access object for table hg_admin_role_dept. +// You can define custom methods on it to extend its functionality as you wish. +type adminRoleDeptDao struct { + *internal.AdminRoleDeptDao +} + +var ( + // AdminRoleDept is globally public accessible object for table hg_admin_role_dept operations. + AdminRoleDept = adminRoleDeptDao{ + internal.NewAdminRoleDeptDao(), + } +) + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/admin_role_menu.go b/hotgo-server/app/service/internal/dao/admin_role_menu.go new file mode 100644 index 0000000..2bffe60 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/admin_role_menu.go @@ -0,0 +1,24 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" +) + +// adminRoleMenuDao is the data access object for table hg_admin_role_menu. +// You can define custom methods on it to extend its functionality as you wish. +type adminRoleMenuDao struct { + *internal.AdminRoleMenuDao +} + +var ( + // AdminRoleMenu is globally public accessible object for table hg_admin_role_menu operations. + AdminRoleMenu = adminRoleMenuDao{ + internal.NewAdminRoleMenuDao(), + } +) + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/internal/admin_dept.go b/hotgo-server/app/service/internal/dao/internal/admin_dept.go new file mode 100644 index 0000000..ab0226a --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_dept.go @@ -0,0 +1,96 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminDeptDao is the data access object for table hg_admin_dept. +type AdminDeptDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminDeptColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminDeptColumns defines and stores column names for table hg_admin_dept. +type AdminDeptColumns struct { + Id string // 部门id + Pid string // 父部门id + Ancestors string // 祖级列表 + Name string // 部门名称 + Code string // 部门编码 + Type string // 部门类型 + Leader string // 负责人 + Phone string // 联系电话 + Email string // 邮箱 + Sort string // 排序 + Status string // 部门状态 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 +} + +// adminDeptColumns holds the columns for table hg_admin_dept. +var adminDeptColumns = AdminDeptColumns{ + Id: "id", + Pid: "pid", + Ancestors: "ancestors", + Name: "name", + Code: "code", + Type: "type", + Leader: "leader", + Phone: "phone", + Email: "email", + Sort: "sort", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewAdminDeptDao creates and returns a new DAO object for table data access. +func NewAdminDeptDao() *AdminDeptDao { + return &AdminDeptDao{ + group: "default", + table: "hg_admin_dept", + columns: adminDeptColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminDeptDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminDeptDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminDeptDao) Columns() AdminDeptColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminDeptDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminDeptDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminDeptDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_member.go b/hotgo-server/app/service/internal/dao/internal/admin_member.go new file mode 100644 index 0000000..f0c629e --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_member.go @@ -0,0 +1,128 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminMemberDao is the data access object for table hg_admin_member. +type AdminMemberDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminMemberColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminMemberColumns defines and stores column names for table hg_admin_member. +type AdminMemberColumns struct { + Id string // + DeptId string // 部门ID + Username string // 帐号 + PasswordHash string // 密码 + Salt string // 密码盐 + AuthKey string // 授权令牌 + PasswordResetToken string // 密码重置令牌 + Type string // 1:普通管理员;10超级管理员 + Realname string // 真实姓名 + Avatar string // 头像 + Sex string // 性别[0:未知;1:男;2:女] + Qq string // qq + Email string // 邮箱 + Birthday string // 生日 + ProvinceId string // 省 + CityId string // 城市 + AreaId string // 地区 + Address string // 默认地址 + Mobile string // 手机号码 + HomePhone string // 家庭号码 + DingtalkRobotToken string // 钉钉机器人token + VisitCount string // 访问次数 + LastTime string // 最后一次登录时间 + LastIp string // 最后一次登录ip + Role string // 权限 + Remark string // 备注 + Status string // 状态 + CreatedAt string // 创建时间 + UpdatedAt string // 修改时间 +} + +// adminMemberColumns holds the columns for table hg_admin_member. +var adminMemberColumns = AdminMemberColumns{ + Id: "id", + DeptId: "dept_id", + Username: "username", + PasswordHash: "password_hash", + Salt: "salt", + AuthKey: "auth_key", + PasswordResetToken: "password_reset_token", + Type: "type", + Realname: "realname", + Avatar: "avatar", + Sex: "sex", + Qq: "qq", + Email: "email", + Birthday: "birthday", + ProvinceId: "province_id", + CityId: "city_id", + AreaId: "area_id", + Address: "address", + Mobile: "mobile", + HomePhone: "home_phone", + DingtalkRobotToken: "dingtalk_robot_token", + VisitCount: "visit_count", + LastTime: "last_time", + LastIp: "last_ip", + Role: "role", + Remark: "remark", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewAdminMemberDao creates and returns a new DAO object for table data access. +func NewAdminMemberDao() *AdminMemberDao { + return &AdminMemberDao{ + group: "default", + table: "hg_admin_member", + columns: adminMemberColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminMemberDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminMemberDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminMemberDao) Columns() AdminMemberColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminMemberDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminMemberDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminMemberDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_member_post.go b/hotgo-server/app/service/internal/dao/internal/admin_member_post.go new file mode 100644 index 0000000..d9492aa --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_member_post.go @@ -0,0 +1,74 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminMemberPostDao is the data access object for table hg_admin_member_post. +type AdminMemberPostDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminMemberPostColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminMemberPostColumns defines and stores column names for table hg_admin_member_post. +type AdminMemberPostColumns struct { + MemberId string // 用户ID + PostId string // 岗位ID +} + +// adminMemberPostColumns holds the columns for table hg_admin_member_post. +var adminMemberPostColumns = AdminMemberPostColumns{ + MemberId: "member_id", + PostId: "post_id", +} + +// NewAdminMemberPostDao creates and returns a new DAO object for table data access. +func NewAdminMemberPostDao() *AdminMemberPostDao { + return &AdminMemberPostDao{ + group: "default", + table: "hg_admin_member_post", + columns: adminMemberPostColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminMemberPostDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminMemberPostDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminMemberPostDao) Columns() AdminMemberPostColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminMemberPostDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminMemberPostDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminMemberPostDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_member_role.go b/hotgo-server/app/service/internal/dao/internal/admin_member_role.go new file mode 100644 index 0000000..b1b1f7e --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_member_role.go @@ -0,0 +1,74 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminMemberRoleDao is the data access object for table hg_admin_member_role. +type AdminMemberRoleDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminMemberRoleColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminMemberRoleColumns defines and stores column names for table hg_admin_member_role. +type AdminMemberRoleColumns struct { + MemberId string // 用户ID + RoleId string // 角色ID +} + +// adminMemberRoleColumns holds the columns for table hg_admin_member_role. +var adminMemberRoleColumns = AdminMemberRoleColumns{ + MemberId: "member_id", + RoleId: "role_id", +} + +// NewAdminMemberRoleDao creates and returns a new DAO object for table data access. +func NewAdminMemberRoleDao() *AdminMemberRoleDao { + return &AdminMemberRoleDao{ + group: "default", + table: "hg_admin_member_role", + columns: adminMemberRoleColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminMemberRoleDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminMemberRoleDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminMemberRoleDao) Columns() AdminMemberRoleColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminMemberRoleDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminMemberRoleDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminMemberRoleDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_menu.go b/hotgo-server/app/service/internal/dao/internal/admin_menu.go new file mode 100644 index 0000000..54de553 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_menu.go @@ -0,0 +1,110 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminMenuDao is the data access object for table hg_admin_menu. +type AdminMenuDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminMenuColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminMenuColumns defines and stores column names for table hg_admin_menu. +type AdminMenuColumns struct { + Id string // 菜单ID + Pid string // 父菜单ID + Name string // 菜单名称 + Code string // 菜单编码 + Icon string // 菜单图标 + Type string // 菜单类型(M目录 C菜单 F按钮) + Perms string // 权限标识 + Path string // 路由地址 + Component string // 组件路径 + Query string // 路由参数 + IsFrame string // 是否内嵌 + IsCache string // 是否不缓存 + IsVisible string // 是否隐藏 + Remark string // 备注 + Level string // 级别 + Tree string // 树 + Sort string // 排序 + Status string // 菜单状态 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 +} + +// adminMenuColumns holds the columns for table hg_admin_menu. +var adminMenuColumns = AdminMenuColumns{ + Id: "id", + Pid: "pid", + Name: "name", + Code: "code", + Icon: "icon", + Type: "type", + Perms: "perms", + Path: "path", + Component: "component", + Query: "query", + IsFrame: "is_frame", + IsCache: "is_cache", + IsVisible: "is_visible", + Remark: "remark", + Level: "level", + Tree: "tree", + Sort: "sort", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewAdminMenuDao creates and returns a new DAO object for table data access. +func NewAdminMenuDao() *AdminMenuDao { + return &AdminMenuDao{ + group: "default", + table: "hg_admin_menu", + columns: adminMenuColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminMenuDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminMenuDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminMenuDao) Columns() AdminMenuColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminMenuDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminMenuDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminMenuDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_menu_old.go b/hotgo-server/app/service/internal/dao/internal/admin_menu_old.go new file mode 100644 index 0000000..a2c50e8 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_menu_old.go @@ -0,0 +1,108 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminMenuOldDao is the data access object for table hg_admin_menu_old. +type AdminMenuOldDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminMenuOldColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminMenuOldColumns defines and stores column names for table hg_admin_menu_old. +type AdminMenuOldColumns struct { + Id string // 菜单ID + Pid string // 父菜单ID + Name string // 菜单名称 + Icon string // 菜单图标 + Type string // 菜单类型(M目录 C菜单 F按钮) + Perms string // 权限标识 + Path string // 路由地址 + Component string // 组件路径 + Query string // 路由参数 + IsFrame string // 是否为外链(0是 1否) + IsCache string // 是否缓存(0缓存 1不缓存) + IsVisible string // 菜单状态(0显示 1隐藏) + Remark string // 备注 + Level string // 级别 + Tree string // 树 + Sort string // 排序 + Status string // 菜单状态 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 +} + +// adminMenuOldColumns holds the columns for table hg_admin_menu_old. +var adminMenuOldColumns = AdminMenuOldColumns{ + Id: "id", + Pid: "pid", + Name: "name", + Icon: "icon", + Type: "type", + Perms: "perms", + Path: "path", + Component: "component", + Query: "query", + IsFrame: "is_frame", + IsCache: "is_cache", + IsVisible: "is_visible", + Remark: "remark", + Level: "level", + Tree: "tree", + Sort: "sort", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewAdminMenuOldDao creates and returns a new DAO object for table data access. +func NewAdminMenuOldDao() *AdminMenuOldDao { + return &AdminMenuOldDao{ + group: "default", + table: "hg_admin_menu_old", + columns: adminMenuOldColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminMenuOldDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminMenuOldDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminMenuOldDao) Columns() AdminMenuOldColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminMenuOldDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminMenuOldDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminMenuOldDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_notice.go b/hotgo-server/app/service/internal/dao/internal/admin_notice.go new file mode 100644 index 0000000..384de50 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_notice.go @@ -0,0 +1,86 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminNoticeDao is the data access object for table hg_admin_notice. +type AdminNoticeDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminNoticeColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminNoticeColumns defines and stores column names for table hg_admin_notice. +type AdminNoticeColumns struct { + Id string // 公告ID + Title string // 公告标题 + Type string // 公告类型(1通知 2公告) + Content string // 公告内容 + Remark string // 备注 + Status string // 公告状态 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 +} + +// adminNoticeColumns holds the columns for table hg_admin_notice. +var adminNoticeColumns = AdminNoticeColumns{ + Id: "id", + Title: "title", + Type: "type", + Content: "content", + Remark: "remark", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewAdminNoticeDao creates and returns a new DAO object for table data access. +func NewAdminNoticeDao() *AdminNoticeDao { + return &AdminNoticeDao{ + group: "default", + table: "hg_admin_notice", + columns: adminNoticeColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminNoticeDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminNoticeDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminNoticeDao) Columns() AdminNoticeColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminNoticeDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminNoticeDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminNoticeDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_post.go b/hotgo-server/app/service/internal/dao/internal/admin_post.go new file mode 100644 index 0000000..a0e3ef3 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_post.go @@ -0,0 +1,86 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminPostDao is the data access object for table hg_admin_post. +type AdminPostDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminPostColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminPostColumns defines and stores column names for table hg_admin_post. +type AdminPostColumns struct { + Id string // 岗位ID + Code string // 岗位编码 + Name string // 岗位名称 + Remark string // 备注 + Sort string // 显示顺序 + Status string // 状态 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 +} + +// adminPostColumns holds the columns for table hg_admin_post. +var adminPostColumns = AdminPostColumns{ + Id: "id", + Code: "code", + Name: "name", + Remark: "remark", + Sort: "sort", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewAdminPostDao creates and returns a new DAO object for table data access. +func NewAdminPostDao() *AdminPostDao { + return &AdminPostDao{ + group: "default", + table: "hg_admin_post", + columns: adminPostColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminPostDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminPostDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminPostDao) Columns() AdminPostColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminPostDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminPostDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminPostDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_role.go b/hotgo-server/app/service/internal/dao/internal/admin_role.go new file mode 100644 index 0000000..3af5500 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_role.go @@ -0,0 +1,92 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminRoleDao is the data access object for table hg_admin_role. +type AdminRoleDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminRoleColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminRoleColumns defines and stores column names for table hg_admin_role. +type AdminRoleColumns struct { + Id string // 角色ID + Name string // 角色名称 + Key string // 角色权限字符串 + DataScope string // 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + MenuCheckStrictly string // 菜单树选择项是否关联显示 + DeptCheckStrictly string // 部门树选择项是否关联显示 + Remark string // 备注 + Sort string // 排序 + Status string // 角色状态 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 +} + +// adminRoleColumns holds the columns for table hg_admin_role. +var adminRoleColumns = AdminRoleColumns{ + Id: "id", + Name: "name", + Key: "key", + DataScope: "data_scope", + MenuCheckStrictly: "menu_check_strictly", + DeptCheckStrictly: "dept_check_strictly", + Remark: "remark", + Sort: "sort", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewAdminRoleDao creates and returns a new DAO object for table data access. +func NewAdminRoleDao() *AdminRoleDao { + return &AdminRoleDao{ + group: "default", + table: "hg_admin_role", + columns: adminRoleColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminRoleDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminRoleDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminRoleDao) Columns() AdminRoleColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminRoleDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminRoleDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminRoleDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_role_dept.go b/hotgo-server/app/service/internal/dao/internal/admin_role_dept.go new file mode 100644 index 0000000..6cb3f02 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_role_dept.go @@ -0,0 +1,74 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminRoleDeptDao is the data access object for table hg_admin_role_dept. +type AdminRoleDeptDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminRoleDeptColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminRoleDeptColumns defines and stores column names for table hg_admin_role_dept. +type AdminRoleDeptColumns struct { + RoleId string // 角色ID + DeptId string // 部门ID +} + +// adminRoleDeptColumns holds the columns for table hg_admin_role_dept. +var adminRoleDeptColumns = AdminRoleDeptColumns{ + RoleId: "role_id", + DeptId: "dept_id", +} + +// NewAdminRoleDeptDao creates and returns a new DAO object for table data access. +func NewAdminRoleDeptDao() *AdminRoleDeptDao { + return &AdminRoleDeptDao{ + group: "default", + table: "hg_admin_role_dept", + columns: adminRoleDeptColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminRoleDeptDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminRoleDeptDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminRoleDeptDao) Columns() AdminRoleDeptColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminRoleDeptDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminRoleDeptDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminRoleDeptDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/admin_role_menu.go b/hotgo-server/app/service/internal/dao/internal/admin_role_menu.go new file mode 100644 index 0000000..c543072 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/admin_role_menu.go @@ -0,0 +1,74 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminRoleMenuDao is the data access object for table hg_admin_role_menu. +type AdminRoleMenuDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AdminRoleMenuColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminRoleMenuColumns defines and stores column names for table hg_admin_role_menu. +type AdminRoleMenuColumns struct { + RoleId string // 角色ID + MenuId string // 菜单ID +} + +// adminRoleMenuColumns holds the columns for table hg_admin_role_menu. +var adminRoleMenuColumns = AdminRoleMenuColumns{ + RoleId: "role_id", + MenuId: "menu_id", +} + +// NewAdminRoleMenuDao creates and returns a new DAO object for table data access. +func NewAdminRoleMenuDao() *AdminRoleMenuDao { + return &AdminRoleMenuDao{ + group: "default", + table: "hg_admin_role_menu", + columns: adminRoleMenuColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AdminRoleMenuDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AdminRoleMenuDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AdminRoleMenuDao) Columns() AdminRoleMenuColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AdminRoleMenuDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AdminRoleMenuDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AdminRoleMenuDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/sys_config.go b/hotgo-server/app/service/internal/dao/internal/sys_config.go new file mode 100644 index 0000000..98fd841 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/sys_config.go @@ -0,0 +1,88 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysConfigDao is the data access object for table hg_sys_config. +type SysConfigDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysConfigColumns // columns contains all the column names of Table for convenient usage. +} + +// SysConfigColumns defines and stores column names for table hg_sys_config. +type SysConfigColumns struct { + Id string // 配置ID + Name string // 参数名称 + Key string // 参数键名 + Value string // 参数键值 + IsDefault string // 是否默认 + Status string // 状态 + Remark string // 备注 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 +} + +// sysConfigColumns holds the columns for table hg_sys_config. +var sysConfigColumns = SysConfigColumns{ + Id: "id", + Name: "name", + Key: "key", + Value: "value", + IsDefault: "is_default", + Status: "status", + Remark: "remark", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewSysConfigDao creates and returns a new DAO object for table data access. +func NewSysConfigDao() *SysConfigDao { + return &SysConfigDao{ + group: "default", + table: "hg_sys_config", + columns: sysConfigColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysConfigDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysConfigDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysConfigDao) Columns() SysConfigColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysConfigDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysConfigDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysConfigDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/sys_dict_data.go b/hotgo-server/app/service/internal/dao/internal/sys_dict_data.go new file mode 100644 index 0000000..79cd3c7 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/sys_dict_data.go @@ -0,0 +1,92 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysDictDataDao is the data access object for table hg_sys_dict_data. +type SysDictDataDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysDictDataColumns // columns contains all the column names of Table for convenient usage. +} + +// SysDictDataColumns defines and stores column names for table hg_sys_dict_data. +type SysDictDataColumns struct { + Id string // 字典编码 + Label string // 字典标签 + Value string // 字典键值 + Type string // 字典类型 + ListClass string // 表格回显样式 + IsDefault string // 是否默认 + Sort string // 字典排序 + Remark string // 备注 + Status string // 状态 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 +} + +// sysDictDataColumns holds the columns for table hg_sys_dict_data. +var sysDictDataColumns = SysDictDataColumns{ + Id: "id", + Label: "label", + Value: "value", + Type: "type", + ListClass: "list_class", + IsDefault: "is_default", + Sort: "sort", + Remark: "remark", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewSysDictDataDao creates and returns a new DAO object for table data access. +func NewSysDictDataDao() *SysDictDataDao { + return &SysDictDataDao{ + group: "default", + table: "hg_sys_dict_data", + columns: sysDictDataColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysDictDataDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysDictDataDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysDictDataDao) Columns() SysDictDataColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysDictDataDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysDictDataDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysDictDataDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/sys_dict_type.go b/hotgo-server/app/service/internal/dao/internal/sys_dict_type.go new file mode 100644 index 0000000..affc22d --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/sys_dict_type.go @@ -0,0 +1,86 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysDictTypeDao is the data access object for table hg_sys_dict_type. +type SysDictTypeDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysDictTypeColumns // columns contains all the column names of Table for convenient usage. +} + +// SysDictTypeColumns defines and stores column names for table hg_sys_dict_type. +type SysDictTypeColumns struct { + Id string // 字典主键 + Name string // 字典名称 + Type string // 字典类型 + Sort string // 排序 + Remark string // 备注 + Status string // 状态 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 +} + +// sysDictTypeColumns holds the columns for table hg_sys_dict_type. +var sysDictTypeColumns = SysDictTypeColumns{ + Id: "id", + Name: "name", + Type: "type", + Sort: "sort", + Remark: "remark", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewSysDictTypeDao creates and returns a new DAO object for table data access. +func NewSysDictTypeDao() *SysDictTypeDao { + return &SysDictTypeDao{ + group: "default", + table: "hg_sys_dict_type", + columns: sysDictTypeColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysDictTypeDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysDictTypeDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysDictTypeDao) Columns() SysDictTypeColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysDictTypeDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysDictTypeDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysDictTypeDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/sys_log.go b/hotgo-server/app/service/internal/dao/internal/sys_log.go new file mode 100644 index 0000000..e52dfed --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/sys_log.go @@ -0,0 +1,116 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysLogDao is the data access object for table hg_sys_log. +type SysLogDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysLogColumns // columns contains all the column names of Table for convenient usage. +} + +// SysLogColumns defines and stores column names for table hg_sys_log. +type SysLogColumns struct { + Id string // + AppId string // 应用id + MerchantId string // 商户id + MemberId string // 用户id + Method string // 提交类型 + Module string // 模块 + Url string // 提交url + GetData string // get数据 + PostData string // post数据 + HeaderData string // header数据 + Ip string // ip地址 + ProvinceId string // 省编码 + CityId string // 市编码 + ErrorCode string // 报错code + ErrorMsg string // 报错信息 + ErrorData string // 报错日志 + ReqId string // 对外id + Timestamp string // 响应时间 + UserAgent string // UA信息 + TakeUpTime string // 请求耗时 + Status string // 状态 + CreatedAt string // 创建时间 + UpdatedAt string // 修改时间 +} + +// sysLogColumns holds the columns for table hg_sys_log. +var sysLogColumns = SysLogColumns{ + Id: "id", + AppId: "app_id", + MerchantId: "merchant_id", + MemberId: "member_id", + Method: "method", + Module: "module", + Url: "url", + GetData: "get_data", + PostData: "post_data", + HeaderData: "header_data", + Ip: "ip", + ProvinceId: "province_id", + CityId: "city_id", + ErrorCode: "error_code", + ErrorMsg: "error_msg", + ErrorData: "error_data", + ReqId: "req_id", + Timestamp: "timestamp", + UserAgent: "user_agent", + TakeUpTime: "take_up_time", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewSysLogDao creates and returns a new DAO object for table data access. +func NewSysLogDao() *SysLogDao { + return &SysLogDao{ + group: "default", + table: "hg_sys_log", + columns: sysLogColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysLogDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysLogDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysLogDao) Columns() SysLogColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysLogDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysLogDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/internal/sys_provinces.go b/hotgo-server/app/service/internal/dao/internal/sys_provinces.go new file mode 100644 index 0000000..714b542 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/internal/sys_provinces.go @@ -0,0 +1,94 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysProvincesDao is the data access object for table hg_sys_provinces. +type SysProvincesDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysProvincesColumns // columns contains all the column names of Table for convenient usage. +} + +// SysProvincesColumns defines and stores column names for table hg_sys_provinces. +type SysProvincesColumns struct { + Id string // ID + Title string // 栏目名 + Pid string // 父栏目 + ShortTitle string // 缩写 + Areacode string // 区域编码 + Zipcode string // 邮政编码 + Pinyin string // 拼音 + Lng string // 经度 + Lat string // 纬度 + Level string // 级别 + Tree string // + Sort string // 排序 +} + +// sysProvincesColumns holds the columns for table hg_sys_provinces. +var sysProvincesColumns = SysProvincesColumns{ + Id: "id", + Title: "title", + Pid: "pid", + ShortTitle: "short_title", + Areacode: "areacode", + Zipcode: "zipcode", + Pinyin: "pinyin", + Lng: "lng", + Lat: "lat", + Level: "level", + Tree: "tree", + Sort: "sort", +} + +// NewSysProvincesDao creates and returns a new DAO object for table data access. +func NewSysProvincesDao() *SysProvincesDao { + return &SysProvincesDao{ + group: "default", + table: "hg_sys_provinces", + columns: sysProvincesColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysProvincesDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysProvincesDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysProvincesDao) Columns() SysProvincesColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysProvincesDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysProvincesDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysProvincesDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/hotgo-server/app/service/internal/dao/sys_config.go b/hotgo-server/app/service/internal/dao/sys_config.go new file mode 100644 index 0000000..9915d79 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/sys_config.go @@ -0,0 +1,58 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/model/entity" + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" + "github.com/gogf/gf/v2/errors/gerror" +) + +// sysConfigDao is the data access object for table hg_sys_config. +// You can define custom methods on it to extend its functionality as you wish. +type sysConfigDao struct { + *internal.SysConfigDao +} + +var ( + // SysConfig is globally public accessible object for table hg_sys_config operations. + SysConfig = sysConfigDao{ + internal.NewSysConfigDao(), + } +) + +// +//  @Title  判断名称是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   name +//  @Return  bool +//  @Return  error +// +func (dao *sysConfigDao) IsUniqueName(ctx context.Context, id int64, name string) (bool, error) { + var data *entity.SysConfig + m := dao.Ctx(ctx).Where("name", name) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err := m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil +} + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/sys_dict_data.go b/hotgo-server/app/service/internal/dao/sys_dict_data.go new file mode 100644 index 0000000..c0b6b11 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/sys_dict_data.go @@ -0,0 +1,62 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/model/entity" + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" + "github.com/gogf/gf/v2/errors/gerror" +) + +// sysDictDataDao is the data access object for table hg_sys_dict_data. +// You can define custom methods on it to extend its functionality as you wish. +type sysDictDataDao struct { + *internal.SysDictDataDao +} + +var ( + // SysDictData is globally public accessible object for table hg_sys_dict_data operations. + SysDictData = sysDictDataDao{ + internal.NewSysDictDataDao(), + } +) + +// +//  @Title  判断字典类型是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   dictType +//  @Return  bool +//  @Return  error +// +func (dao *sysDictDataDao) IsUnique(ctx context.Context, id int64, dictType string, dictValue string) (bool, error) { + var ( + data *entity.SysDictData + err error + ) + m := dao.Ctx(ctx).Where("type", dictType).Where("value", dictValue) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err = m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil + +} + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/sys_dict_type.go b/hotgo-server/app/service/internal/dao/sys_dict_type.go new file mode 100644 index 0000000..0f6c73a --- /dev/null +++ b/hotgo-server/app/service/internal/dao/sys_dict_type.go @@ -0,0 +1,62 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/model/entity" + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" + "github.com/gogf/gf/v2/errors/gerror" +) + +// sysDictTypeDao is the data access object for table hg_sys_dict_type. +// You can define custom methods on it to extend its functionality as you wish. +type sysDictTypeDao struct { + *internal.SysDictTypeDao +} + +var ( + // SysDictType is globally public accessible object for table hg_sys_dict_type operations. + SysDictType = sysDictTypeDao{ + internal.NewSysDictTypeDao(), + } +) + +// +//  @Title  判断字典类型是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   id +//  @Param   dictType +//  @Return  bool +//  @Return  error +// +func (dao *sysDictTypeDao) IsUnique(ctx context.Context, id int64, dictType string) (bool, error) { + var ( + data *entity.SysDictType + err error + ) + m := dao.Ctx(ctx).Where("type", dictType) + + if id > 0 { + m = m.WhereNot("id", id) + } + + if err = m.Scan(&data); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return false, err + } + + if data == nil { + return true, nil + } + + return false, nil + +} + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/sys_log.go b/hotgo-server/app/service/internal/dao/sys_log.go new file mode 100644 index 0000000..b4a39fa --- /dev/null +++ b/hotgo-server/app/service/internal/dao/sys_log.go @@ -0,0 +1,24 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" +) + +// sysLogDao is the data access object for table hg_sys_log. +// You can define custom methods on it to extend its functionality as you wish. +type sysLogDao struct { + *internal.SysLogDao +} + +var ( + // SysLog is globally public accessible object for table hg_sys_log operations. + SysLog = sysLogDao{ + internal.NewSysLogDao(), + } +) + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dao/sys_provinces.go b/hotgo-server/app/service/internal/dao/sys_provinces.go new file mode 100644 index 0000000..9ab5ae2 --- /dev/null +++ b/hotgo-server/app/service/internal/dao/sys_provinces.go @@ -0,0 +1,73 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/service/internal/dao/internal" + "github.com/gogf/gf/v2/container/gvar" + "github.com/gogf/gf/v2/errors/gerror" +) + +// sysProvincesDao is the data access object for table hg_sys_provinces. +// You can define custom methods on it to extend its functionality as you wish. +type sysProvincesDao struct { + *internal.SysProvincesDao +} + +var ( + // SysProvinces is globally public accessible object for table hg_sys_provinces operations. + SysProvinces = sysProvincesDao{ + internal.NewSysProvincesDao(), + } +) + +// +//  @Title  获取省市编码对应的地区名称 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   province +//  @Param   city +//  @Param   spilt +//  @Return  string +//  @Return  error +// +func (dao *sysProvincesDao) GetRegion(ctx context.Context, province int, city int, spilt ...string) (string, error) { + + var ( + provinceName *gvar.Var + cityName *gvar.Var + err error + ) + // TODO  默认分隔符 + spiltSymbol := "-" + if len(spilt) > 0 { + spiltSymbol = spilt[0] + } + + if province > 0 { + provinceName, err = dao.Ctx(ctx).Where("id", province).Fields("title").Value() + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return "", err + } + + if city > 0 { + cityName, err = dao.Ctx(ctx).Where("id", city).Fields("title").Value() + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return "", err + } + } + } else { + return "内网IP", nil + } + + return provinceName.String() + spiltSymbol + cityName.String(), nil +} + +// Fill with you ideas below. diff --git a/hotgo-server/app/service/internal/dto/admin_dept.go b/hotgo-server/app/service/internal/dto/admin_dept.go new file mode 100644 index 0000000..0f3d80a --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_dept.go @@ -0,0 +1,28 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AdminDept is the golang structure of table hg_admin_dept for DAO operations like Where/Data. +type AdminDept struct { + g.Meta `orm:"table:hg_admin_dept, dto:true"` + Id interface{} // 部门id + Pid interface{} // 父部门id + Ancestors interface{} // 祖级列表 + Name interface{} // 部门名称 + Code interface{} // 部门编码 + Type interface{} // 部门类型 + Leader interface{} // 负责人 + Phone interface{} // 联系电话 + Email interface{} // 邮箱 + Sort interface{} // 排序 + Status interface{} // 部门状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/hotgo-server/app/service/internal/dto/admin_member.go b/hotgo-server/app/service/internal/dto/admin_member.go new file mode 100644 index 0000000..7515fca --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_member.go @@ -0,0 +1,44 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AdminMember is the golang structure of table hg_admin_member for DAO operations like Where/Data. +type AdminMember struct { + g.Meta `orm:"table:hg_admin_member, dto:true"` + Id interface{} // + DeptId interface{} // 部门ID + Username interface{} // 帐号 + PasswordHash interface{} // 密码 + Salt interface{} // 密码盐 + AuthKey interface{} // 授权令牌 + PasswordResetToken interface{} // 密码重置令牌 + Type interface{} // 1:普通管理员;10超级管理员 + Realname interface{} // 真实姓名 + Avatar interface{} // 头像 + Sex interface{} // 性别[0:未知;1:男;2:女] + Qq interface{} // qq + Email interface{} // 邮箱 + Birthday *gtime.Time // 生日 + ProvinceId interface{} // 省 + CityId interface{} // 城市 + AreaId interface{} // 地区 + Address interface{} // 默认地址 + Mobile interface{} // 手机号码 + HomePhone interface{} // 家庭号码 + DingtalkRobotToken interface{} // 钉钉机器人token + VisitCount interface{} // 访问次数 + LastTime interface{} // 最后一次登录时间 + LastIp interface{} // 最后一次登录ip + Role interface{} // 权限 + Remark interface{} // 备注 + Status interface{} // 状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 修改时间 +} diff --git a/hotgo-server/app/service/internal/dto/admin_member_post.go b/hotgo-server/app/service/internal/dto/admin_member_post.go new file mode 100644 index 0000000..0347b2d --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_member_post.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// AdminMemberPost is the golang structure of table hg_admin_member_post for DAO operations like Where/Data. +type AdminMemberPost struct { + g.Meta `orm:"table:hg_admin_member_post, dto:true"` + MemberId interface{} // 用户ID + PostId interface{} // 岗位ID +} diff --git a/hotgo-server/app/service/internal/dto/admin_member_role.go b/hotgo-server/app/service/internal/dto/admin_member_role.go new file mode 100644 index 0000000..8ac83f2 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_member_role.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// AdminMemberRole is the golang structure of table hg_admin_member_role for DAO operations like Where/Data. +type AdminMemberRole struct { + g.Meta `orm:"table:hg_admin_member_role, dto:true"` + MemberId interface{} // 用户ID + RoleId interface{} // 角色ID +} diff --git a/hotgo-server/app/service/internal/dto/admin_menu.go b/hotgo-server/app/service/internal/dto/admin_menu.go new file mode 100644 index 0000000..c15f45b --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_menu.go @@ -0,0 +1,35 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AdminMenu is the golang structure of table hg_admin_menu for DAO operations like Where/Data. +type AdminMenu struct { + g.Meta `orm:"table:hg_admin_menu, dto:true"` + Id interface{} // 菜单ID + Pid interface{} // 父菜单ID + Name interface{} // 菜单名称 + Code interface{} // 菜单编码 + Icon interface{} // 菜单图标 + Type interface{} // 菜单类型(M目录 C菜单 F按钮) + Perms interface{} // 权限标识 + Path interface{} // 路由地址 + Component interface{} // 组件路径 + Query interface{} // 路由参数 + IsFrame interface{} // 是否内嵌 + IsCache interface{} // 是否不缓存 + IsVisible interface{} // 是否隐藏 + Remark interface{} // 备注 + Level interface{} // 级别 + Tree interface{} // 树 + Sort interface{} // 排序 + Status interface{} // 菜单状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/hotgo-server/app/service/internal/dto/admin_menu_old.go b/hotgo-server/app/service/internal/dto/admin_menu_old.go new file mode 100644 index 0000000..bd0f3b4 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_menu_old.go @@ -0,0 +1,34 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AdminMenuOld is the golang structure of table hg_admin_menu_old for DAO operations like Where/Data. +type AdminMenuOld struct { + g.Meta `orm:"table:hg_admin_menu_old, dto:true"` + Id interface{} // 菜单ID + Pid interface{} // 父菜单ID + Name interface{} // 菜单名称 + Icon interface{} // 菜单图标 + Type interface{} // 菜单类型(M目录 C菜单 F按钮) + Perms interface{} // 权限标识 + Path interface{} // 路由地址 + Component interface{} // 组件路径 + Query interface{} // 路由参数 + IsFrame interface{} // 是否为外链(0是 1否) + IsCache interface{} // 是否缓存(0缓存 1不缓存) + IsVisible interface{} // 菜单状态(0显示 1隐藏) + Remark interface{} // 备注 + Level interface{} // 级别 + Tree interface{} // 树 + Sort interface{} // 排序 + Status interface{} // 菜单状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/hotgo-server/app/service/internal/dto/admin_notice.go b/hotgo-server/app/service/internal/dto/admin_notice.go new file mode 100644 index 0000000..796a76f --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_notice.go @@ -0,0 +1,23 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AdminNotice is the golang structure of table hg_admin_notice for DAO operations like Where/Data. +type AdminNotice struct { + g.Meta `orm:"table:hg_admin_notice, dto:true"` + Id interface{} // 公告ID + Title interface{} // 公告标题 + Type interface{} // 公告类型(1通知 2公告) + Content interface{} // 公告内容 + Remark interface{} // 备注 + Status interface{} // 公告状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/hotgo-server/app/service/internal/dto/admin_post.go b/hotgo-server/app/service/internal/dto/admin_post.go new file mode 100644 index 0000000..3116209 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_post.go @@ -0,0 +1,23 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AdminPost is the golang structure of table hg_admin_post for DAO operations like Where/Data. +type AdminPost struct { + g.Meta `orm:"table:hg_admin_post, dto:true"` + Id interface{} // 岗位ID + Code interface{} // 岗位编码 + Name interface{} // 岗位名称 + Remark interface{} // 备注 + Sort interface{} // 显示顺序 + Status interface{} // 状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/hotgo-server/app/service/internal/dto/admin_role.go b/hotgo-server/app/service/internal/dto/admin_role.go new file mode 100644 index 0000000..89c96bb --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_role.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AdminRole is the golang structure of table hg_admin_role for DAO operations like Where/Data. +type AdminRole struct { + g.Meta `orm:"table:hg_admin_role, dto:true"` + Id interface{} // 角色ID + Name interface{} // 角色名称 + Key interface{} // 角色权限字符串 + DataScope interface{} // 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + MenuCheckStrictly interface{} // 菜单树选择项是否关联显示 + DeptCheckStrictly interface{} // 部门树选择项是否关联显示 + Remark interface{} // 备注 + Sort interface{} // 排序 + Status interface{} // 角色状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/hotgo-server/app/service/internal/dto/admin_role_dept.go b/hotgo-server/app/service/internal/dto/admin_role_dept.go new file mode 100644 index 0000000..da2b391 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_role_dept.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// AdminRoleDept is the golang structure of table hg_admin_role_dept for DAO operations like Where/Data. +type AdminRoleDept struct { + g.Meta `orm:"table:hg_admin_role_dept, dto:true"` + RoleId interface{} // 角色ID + DeptId interface{} // 部门ID +} diff --git a/hotgo-server/app/service/internal/dto/admin_role_menu.go b/hotgo-server/app/service/internal/dto/admin_role_menu.go new file mode 100644 index 0000000..983aae5 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/admin_role_menu.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// AdminRoleMenu is the golang structure of table hg_admin_role_menu for DAO operations like Where/Data. +type AdminRoleMenu struct { + g.Meta `orm:"table:hg_admin_role_menu, dto:true"` + RoleId interface{} // 角色ID + MenuId interface{} // 菜单ID +} diff --git a/hotgo-server/app/service/internal/dto/sys_config.go b/hotgo-server/app/service/internal/dto/sys_config.go new file mode 100644 index 0000000..930ed94 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/sys_config.go @@ -0,0 +1,24 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysConfig is the golang structure of table hg_sys_config for DAO operations like Where/Data. +type SysConfig struct { + g.Meta `orm:"table:hg_sys_config, dto:true"` + Id interface{} // 配置ID + Name interface{} // 参数名称 + Key interface{} // 参数键名 + Value interface{} // 参数键值 + IsDefault interface{} // 是否默认 + Status interface{} // 状态 + Remark interface{} // 备注 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/hotgo-server/app/service/internal/dto/sys_dict_data.go b/hotgo-server/app/service/internal/dto/sys_dict_data.go new file mode 100644 index 0000000..654b4a7 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/sys_dict_data.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysDictData is the golang structure of table hg_sys_dict_data for DAO operations like Where/Data. +type SysDictData struct { + g.Meta `orm:"table:hg_sys_dict_data, dto:true"` + Id interface{} // 字典编码 + Label interface{} // 字典标签 + Value interface{} // 字典键值 + Type interface{} // 字典类型 + ListClass interface{} // 表格回显样式 + IsDefault interface{} // 是否默认 + Sort interface{} // 字典排序 + Remark interface{} // 备注 + Status interface{} // 状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/hotgo-server/app/service/internal/dto/sys_dict_type.go b/hotgo-server/app/service/internal/dto/sys_dict_type.go new file mode 100644 index 0000000..a03db93 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/sys_dict_type.go @@ -0,0 +1,23 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysDictType is the golang structure of table hg_sys_dict_type for DAO operations like Where/Data. +type SysDictType struct { + g.Meta `orm:"table:hg_sys_dict_type, dto:true"` + Id interface{} // 字典主键 + Name interface{} // 字典名称 + Type interface{} // 字典类型 + Sort interface{} // 排序 + Remark interface{} // 备注 + Status interface{} // 状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/hotgo-server/app/service/internal/dto/sys_log.go b/hotgo-server/app/service/internal/dto/sys_log.go new file mode 100644 index 0000000..b8cb299 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/sys_log.go @@ -0,0 +1,38 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysLog is the golang structure of table hg_sys_log for DAO operations like Where/Data. +type SysLog struct { + g.Meta `orm:"table:hg_sys_log, dto:true"` + Id interface{} // + AppId interface{} // 应用id + MerchantId interface{} // 商户id + MemberId interface{} // 用户id + Method interface{} // 提交类型 + Module interface{} // 模块 + Url interface{} // 提交url + GetData interface{} // get数据 + PostData interface{} // post数据 + HeaderData interface{} // header数据 + Ip interface{} // ip地址 + ProvinceId interface{} // 省编码 + CityId interface{} // 市编码 + ErrorCode interface{} // 报错code + ErrorMsg interface{} // 报错信息 + ErrorData interface{} // 报错日志 + ReqId interface{} // 对外id + Timestamp interface{} // 响应时间 + UserAgent interface{} // UA信息 + TakeUpTime interface{} // 请求耗时 + Status interface{} // 状态 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 修改时间 +} diff --git a/hotgo-server/app/service/internal/dto/sys_provinces.go b/hotgo-server/app/service/internal/dto/sys_provinces.go new file mode 100644 index 0000000..1e39430 --- /dev/null +++ b/hotgo-server/app/service/internal/dto/sys_provinces.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dto + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// SysProvinces is the golang structure of table hg_sys_provinces for DAO operations like Where/Data. +type SysProvinces struct { + g.Meta `orm:"table:hg_sys_provinces, dto:true"` + Id interface{} // ID + Title interface{} // 栏目名 + Pid interface{} // 父栏目 + ShortTitle interface{} // 缩写 + Areacode interface{} // 区域编码 + Zipcode interface{} // 邮政编码 + Pinyin interface{} // 拼音 + Lng interface{} // 经度 + Lat interface{} // 纬度 + Level interface{} // 级别 + Tree interface{} // + Sort interface{} // 排序 +} diff --git a/hotgo-server/app/service/sysService/config_service.go b/hotgo-server/app/service/sysService/config_service.go new file mode 100644 index 0000000..ee8dfa0 --- /dev/null +++ b/hotgo-server/app/service/sysService/config_service.go @@ -0,0 +1,233 @@ +package sysService + +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 Config = new(config) + +type config struct{} + +// +//  @Title  最大排序 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   req +//  @Return  *adminForm.DictDataMaxSortRes +//  @Return  error +// +func (service *config) GetValue(ctx context.Context, in input.SysConfigGetValueInp) (*input.SysConfigGetValueModel, error) { + var res input.SysConfigGetValueModel + + if err := dao.SysConfig.Ctx(ctx). + Fields("value"). + Where("key", in.Key). + Order("id desc"). + 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  *adminForm.DictTypeUniqueRes +//  @Return  error +// +func (service *config) NameUnique(ctx context.Context, in input.SysConfigNameUniqueInp) (*input.SysConfigNameUniqueModel, error) { + + var res input.SysConfigNameUniqueModel + isUnique, err := dao.SysConfig.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 *config) Delete(ctx context.Context, in input.SysConfigDeleteInp) error { + + exist, err := dao.SysConfig.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.SysConfig.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 *config) Edit(ctx context.Context, in input.SysConfigEditInp) (err error) { + + if in.Name == "" { + err = gerror.New("名称不能为空") + return err + } + + uniqueName, err := dao.SysConfig.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.SysConfig.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.SysConfig.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 *config) MaxSort(ctx context.Context, in input.SysConfigMaxSortInp) (*input.SysConfigMaxSortModel, error) { + var res input.SysConfigMaxSortModel + + if in.Id > 0 { + if err := dao.SysConfig.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 *config) View(ctx context.Context, in input.SysConfigViewInp) (res *input.SysConfigViewModel, err error) { + + if err = dao.SysConfig.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 *config) List(ctx context.Context, in input.SysConfigListInp) (list []*input.SysConfigListModel, totalCount int, err error) { + + mod := dao.SysConfig.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 +} diff --git a/hotgo-server/app/service/sysService/dict_service.go b/hotgo-server/app/service/sysService/dict_service.go new file mode 100644 index 0000000..2bfa589 --- /dev/null +++ b/hotgo-server/app/service/sysService/dict_service.go @@ -0,0 +1,505 @@ +// +// @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 sysService + +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/model" + "github.com/bufanyun/hotgo/app/model/entity" + "github.com/bufanyun/hotgo/app/service/internal/dao" + "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/net/ghttp" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" + "time" +) + +var Dict = new(dict) + +type dict struct{} + +// +//  @Title  数据键值是否唯一 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   req +//  @Return  *adminForm.DictTypeUniqueRes +//  @Return  error +// +func (service *dict) DataUnique(ctx context.Context, req *adminForm.DictDataUniqueReq) (*adminForm.DictDataUniqueRes, error) { + var ( + res adminForm.DictDataUniqueRes + err error + ) + + res.IsUnique, err = dao.SysDictData.IsUnique(ctx, req.Id, req.Type, req.Value) + 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.DictDataMaxSortRes +//  @Return  error +// +func (service *dict) DataMaxSort(ctx context.Context, req *adminForm.DictDataMaxSortReq) (*adminForm.DictDataMaxSortRes, error) { + var ( + m = dao.SysDictData.Ctx(ctx).Where("type", req.Type).Order("sort desc") + res adminForm.DictDataMaxSortRes + err error + ) + + if err = m.Scan(&res); err != nil && err.Error() != "sql: no rows in result set" { + + 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  error +// +func (service *dict) DataDelete(ctx context.Context, req *adminForm.DictDataDeleteReq) error { + var ( + m = dao.SysDictData.Ctx(ctx).Where("id", req.Id) + err error + ) + + _, err = m.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 *dict) DataEdit(ctx context.Context, req *adminForm.DictDataEditReq) error { + var ( + m = dao.SysDictData.Ctx(ctx) + isUnique bool + err error + ) + + if req.Label == "" { + err = gerror.New("字典标签不能为空") + return err + } + if req.Type == "" { + err = gerror.New("字典类型不能为空") + return err + } + if req.Value == "" { + err = gerror.New("字典键值不能为空") + return err + } + + isUnique, err = dao.SysDictData.IsUnique(ctx, req.Id, req.Type, req.Value) + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return err + } + + if !isUnique { + err = gerror.New("字典键值已存在") + return err + } + + req.UpdatedAt = gtime.Now() + + // 修改 + if req.Id > 0 { + _, err = m.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 = m.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 *dict) DataView(ctx context.Context, req *adminForm.DictDataViewReq) (*adminForm.DictDataViewRes, error) { + var ( + m = dao.SysDictData.Ctx(ctx).Where("id", req.Id) + res adminForm.DictDataViewRes + err error + ) + + if err = m.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  *adminForm.DictAttributeRes +//  @Return  error +// +func (service *dict) Attribute(ctx context.Context, req *adminForm.DictAttributeReq) (*adminForm.DictAttributeRes, error) { + var ( + m = dao.SysDictData.Ctx(ctx).Where("type", req.Type).Order("sort asc,id desc") + res adminForm.DictAttributeRes + err error + ) + + if err = m.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 *dict) DataList(ctx context.Context, req *adminForm.DictDataListReq) (*adminForm.DictDataListRes, error) { + var ( + m = dao.SysDictData.Ctx(ctx).Where("type", req.Type) + list []*entity.SysDictData + res adminForm.DictDataListRes + totalCount int + err error + ) + + totalCount, err = m.Count() + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return nil, err + } + + if err = m.Page(req.Page, req.Limit).Order("sort asc,id desc").Scan(&list); 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 +} + +// +//  @Title  导出字典类型 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   req +//  @Return  *adminForm.DictDataListRes +//  @Return  error +// +func (service *dict) TypeExport(ctx context.Context, req *adminForm.DictTypeExportReq) error { + + // 导出格式 + type exportImage struct { + Id int64 `json:"id" ` + Name string `json:"name" ` + Type string `json:"type" ` + Remark string `json:"remark" ` + Status string `json:"status" ` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + } + + var ( + list []exportImage + titleList = []string{"ID", "字典名称", "字典类型", "备注", "状态", "创建时间", "更新时间"} + fileName = "字典类型导出-" + com.Context.Get(ctx).ReqId + ".xlsx" + sheetName = "HotGo" + err error + ) + + if err = dao.SysDictType.Ctx(ctx).Page(req.Page, req.Limit).Order("sort asc,id desc").Scan(&list); err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return err + } + + // TODO 格式化格式 + for i := 0; i < len(list); i++ { + if list[i].Status == consts.StatusEnabled { + list[i].Status = "启用" + } else if list[i].Status == consts.StatusDisable { + list[i].Status = "禁用" + } else if list[i].Status == consts.StatusDelete { + list[i].Status = "已删除" + } + } + + // TODO 强转类型 + writer := com.Context.Get(ctx).Request.Response.Writer + w, _ := interface{}(writer).(*ghttp.ResponseWriter) + + g.Log().Print(ctx, "gconv.Interfaces(list):", gconv.Interfaces(list)) + if err = utils.Excel.ExportByStruct(w, titleList, gconv.Interfaces(list), fileName, sheetName); err != nil { + err = gerror.Wrap(err, "ExportByStruct:") + return err + } + + // TODO 加入到上下文 + com.Context.SetResponse(ctx, &model.Response{ + Code: consts.CodeOK, + Message: "导出成功", + Timestamp: time.Now().Unix(), + ReqId: com.Context.Get(ctx).ReqId, + }) + + return nil +} + +// +//  @Title  删除字典类型 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   req +//  @Return  error +// +func (service *dict) TypeDelete(ctx context.Context, req *adminForm.DictTypeDeleteReq) error { + var ( + m = dao.SysDictType.Ctx(ctx).Where("id", req.Id) + err error + ) + + _, err = m.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 *dict) TypeEdit(ctx context.Context, req *adminForm.DictTypeEditReq) error { + var ( + m = dao.SysDictType.Ctx(ctx) + isUnique bool + err error + ) + + if req.Name == "" { + err = gerror.New("字典名称不能为空") + return err + } + if req.Type == "" { + err = gerror.New("字典类型不能为空") + return err + } + + isUnique, err = dao.SysDictType.IsUnique(ctx, req.Id, req.Type) + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return err + } + + if !isUnique { + err = gerror.New("字典类型已存在") + return err + } + + req.UpdatedAt = gtime.Now() + + // 修改 + if req.Id > 0 { + _, err = m.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 = m.Where("id", req.Id).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.DictTypeUniqueRes +//  @Return  error +// +func (service *dict) TypeUnique(ctx context.Context, req *adminForm.DictTypeUniqueReq) (*adminForm.DictTypeUniqueRes, error) { + var ( + res adminForm.DictTypeUniqueRes + err error + ) + + res.IsUnique, err = dao.SysDictType.IsUnique(ctx, req.Id, req.Type) + 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.DictTypeViewRes +//  @Return  error +// +func (service *dict) TypeView(ctx context.Context, req *adminForm.DictTypeViewReq) (*adminForm.DictTypeViewRes, error) { + var ( + m = dao.SysDictType.Ctx(ctx).Where("id", req.Id) + res adminForm.DictTypeViewRes + err error + ) + + if err = m.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 *dict) TypeList(ctx context.Context, req *adminForm.DictTypeListReq) (*adminForm.DictTypeListRes, error) { + var ( + m = dao.SysDictType.Ctx(ctx) + list []*entity.SysDictType + res adminForm.DictTypeListRes + totalCount int + err error + ) + + if req.Name != "" { + m = m.WhereLike("name", "%"+req.Name+"%") + } + + if req.Type != "" { + m = m.Where("type", req.Type) + } + + // 日期范围 + if req.StartTime != "" { + m = m.WhereGTE("created_at", req.StartTime) + } + if req.EndTime != "" { + m = m.WhereLTE("created_at", req.EndTime) + } + + // 状态 + if req.Status > 0 { + m = m.Where("status", req.Status) + } + + totalCount, err = m.Count() + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return nil, err + } + + if err = m.Page(req.Page, req.Limit).Order("sort asc,id desc").Scan(&list); 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 +} diff --git a/hotgo-server/app/service/sysService/log_service.go b/hotgo-server/app/service/sysService/log_service.go new file mode 100644 index 0000000..7f38aef --- /dev/null +++ b/hotgo-server/app/service/sysService/log_service.go @@ -0,0 +1,400 @@ +// +// @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 sysService + +import ( + "context" + "encoding/json" + "github.com/bufanyun/hotgo/app/com" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/factory/queue" + "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/utils" + "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/os/gtime" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "time" +) + +var Log = new(log) + +type log struct{} + +// +//  @Title  导出 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   in +//  @Return  err +// +func (service *log) Export(ctx context.Context, in input.LogListInp) (err error) { + + // 导出格式 + type exportImage struct { + Id int64 `json:"id" description:""` + AppId string `json:"app_id" description:"应用id"` + Method string `json:"method" description:"提交类型"` + Module string `json:"module" description:"模块"` + Url string `json:"url" description:"提交url"` + Ip string `json:"ip" description:"ip地址"` + ErrorCode int `json:"error_code" description:"报错code"` + ErrorMsg string `json:"error_msg" description:"报错信息"` + ReqId string `json:"req_id" description:"对外id"` + TakeUpTime int64 `json:"take_up_time" description:"请求耗时"` + CreatedAt *gtime.Time `json:"created_at" description:"创建时间"` + MemberName string `json:"member_name"` + Region string `json:"region"` + } + + var ( + titleList = []string{"ID", "应用", "提交类型", "模块", "提交url", "ip地址", "报错code", "报错信息", "对外id", "请求耗时", "创建时间", "用户", "访问地"} + fileName = "全局日志导出-" + com.Context.Get(ctx).ReqId + ".xlsx" + sheetName = "HotGo" + exportList []exportImage + row exportImage + ) + + list, _, err := service.List(ctx, in) + if err != nil { + return err + } + + // TODO 格式化格式 + for i := 0; i < len(list); i++ { + row.Id = list[i].Id + row.AppId = list[i].AppId + row.Module = list[i].Module + row.Method = list[i].Method + row.Url = list[i].Url + row.Ip = list[i].Ip + row.ReqId = list[i].ReqId + row.ErrorCode = list[i].ErrorCode + row.ErrorMsg = list[i].ErrorMsg + row.TakeUpTime = list[i].TakeUpTime + row.CreatedAt = list[i].CreatedAt + row.MemberName = list[i].MemberName + row.Region = list[i].Region + exportList = append(exportList, row) + } + + // TODO 强转类型 + writer := com.Context.Get(ctx).Request.Response.Writer + w, _ := interface{}(writer).(*ghttp.ResponseWriter) + + if err = utils.Excel.ExportByStruct(w, titleList, gconv.Interfaces(exportList), fileName, sheetName); err != nil { + err = gerror.Wrap(err, "ExportByStruct:") + return err + } + + // TODO 加入到上下文 + com.Context.SetResponse(ctx, &model.Response{ + Code: consts.CodeOK, + Message: "导出成功", + Timestamp: time.Now().Unix(), + ReqId: com.Context.Get(ctx).ReqId, + }) + + return +} + +// +//  @Title  获取菜单列表 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   req +//  @Return  res +//  @Return  err +// +func (service *log) List(ctx context.Context, in input.LogListInp) (list []*input.LogListModel, totalCount int, err error) { + + mod := dao.SysLog.Ctx(ctx) + + // 访问路径 + if in.Url != "" { + mod = mod.WhereLike("url", "%"+in.Url+"%") + } + + // 模块 + if in.Module != "" { + mod = mod.Where("module", in.Module) + } + + // 请求方式 + if in.Method != "" { + mod = mod.Where("method", in.Method) + } + + // 用户 + if in.MemberId > 0 { + mod = mod.Where("member_id", in.MemberId) + } + + // 访问IP + if in.Ip != "" { + mod = mod.Where("ip", in.Ip) + } + + // 日期范围 + if in.StartTime != "" { + mod = mod.WhereGTE("created_at", in.StartTime) + } + if in.EndTime != "" { + mod = mod.WhereLTE("created_at", in.EndTime) + } + + // 状态码 + if in.ErrorCode != "" { + mod = mod.Where("error_code", in.ErrorCode) + } + + // 请求耗时 + if in.TakeUpTime > 0 { + mod = mod.WhereGTE("take_up_time", in.TakeUpTime) + } + + 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 + } + + for i := 0; i < len(list); i++ { + // TODO  管理员 + if list[i].AppId == consts.AppAdmin { + memberName, err := dao.AdminMember.Ctx(ctx).Fields("realname").Where("id", list[i].MemberId).Value() + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return list, totalCount, err + } + list[i].MemberName = memberName.String() + } + // TODO  接口 + if list[i].AppId == consts.AppApi { + //memberName, err = dao.Member.Ctx(ctx).Fields("realname").Where("id", res.List[i].MemberId).Value() + //if err != nil { + // err = gerror.Wrap(err, consts.ErrorORM) + // return nil, err + //} + } + + if list[i].MemberName == "" { + list[i].MemberName = "游客" + } + + // TODO  获取省市编码对应的地区名称 + region, err := dao.SysProvinces.GetRegion(ctx, list[i].ProvinceId, list[i].CityId) + if err != nil { + return list, totalCount, err + } + list[i].Region = region + + // TODO  截取请求url路径 + if gstr.Contains(list[i].Url, "?") { + list[i].Url = gstr.StrTillEx(list[i].Url, "?") + } + } + + return list, totalCount, err +} + +// +//  @Title  真实写入 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   commonLog +//  @Return  err +// +func (service *log) RealWrite(ctx context.Context, commonLog entity.SysLog) error { + + result, err := dao.SysLog.Ctx(ctx).Data(commonLog).Insert() + if err != nil { + return err + } + + if _, err := result.LastInsertId(); err != nil { + return err + } + + return nil +} + +// +//  @Title  根据配置自动记录请求日志 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Return  err +// +func (service *log) AutoLog(ctx context.Context) (err error) { + // TODO 日志开关 + logSwitch, _ := g.Cfg().Get(ctx, "hotgo.log.switch", true) + if !logSwitch.Bool() { + return nil + } + + data := service.AnalysisLog(ctx) + + // TODO 判断模块是否需要记录 + module, _ := g.Cfg().Get(ctx, "hotgo.log.module", nil) + if module == nil { + return nil + } + if exist := utils.Charset.IsExists(module.Strings(), data.Module); !exist { + return nil + } + + // TODO 判断状态码是否需要记录 + code, _ := g.Cfg().Get(ctx, "hotgo.log.skipCode", nil) + if code != nil { + if exist := utils.Charset.IsExists(code.Strings(), gconv.String(data.ErrorCode)); exist { + return nil + } + } + + // TODO 是否开启队列 + queueSwitch, _ := g.Cfg().Get(ctx, "hotgo.log.queue", true) + if queueSwitch.Bool() { + // TODO 获取生产者实例 + queueInstance, err := queue.InstanceProducer() + if err != nil { + queue.FatalLog(ctx, "InstanceProducer异常", err) + return err + } + + // TODO 生产消息 + mqMsg, err := queueInstance.SendMsg(consts.QueueLogTopic, gconv.String(data)) + + // TODO 记录生产日志 + queue.ProducerLog(ctx, consts.QueueLogTopic, mqMsg.MsgId, err) + + return err + } + + return service.RealWrite(ctx, data) +} + +// +//  @Title  队列消费 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   mqMsg +//  @Return  err +// +func (service *log) QueueJob(ctx context.Context, mqMsg queue.MqMsg) (err error) { + + var data entity.SysLog + if err = json.Unmarshal(mqMsg.Body, &data); err != nil { + return err + } + + return service.RealWrite(ctx, data) +} + +// +//  @Title  解析日志数据 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Return  entity.SysLog +// +func (service *log) AnalysisLog(ctx context.Context) entity.SysLog { + + var ( + modelContext = com.Context.Get(ctx) + response = modelContext.ComResponse + user = modelContext.User + request = modelContext.Request + module = modelContext.Module + ip = request.GetClientIp() + locationData = com.Ip.GetLocation(ctx, ip) + postData = "null" + getData = "null" + headerData = "null" + data = entity.SysLog{} + memberId = 0 + errorCode = 0 + errorMsg = "" + errorData = "null" + reqId = "" + timestamp = 0 + appId = "" + ) + + // TODO 响应数据 + if response != nil { + errorCode = response.Code + errorMsg = response.Message + reqId = response.ReqId + timestamp = gconv.Int(response.Timestamp) + + if len(gconv.String(response.Error)) > 0 { + errorData = gconv.String(response.Error) + } + } + + // TODO 请求头 + if reqHeadersBytes, _ := json.Marshal(request.Header); len(gconv.String(reqHeadersBytes)) > 0 { + headerData = gconv.String(reqHeadersBytes) + } + + // TODO post参数 + if gconv.String(request.PostForm) != "" { + postData = gconv.String(request.PostForm) + } + + // TODO get参数 + if len(request.URL.Query()) > 0 { + getData = gconv.String(request.URL.Query()) + } + + // TODO 当前登录用户 + if user != nil { + memberId = int(user.Id) + appId = user.App + } + + data = entity.SysLog{ + AppId: appId, + MerchantId: 0, + MemberId: memberId, + Method: request.Method, + Module: module, + Url: request.RequestURI, + GetData: getData, + PostData: postData, + HeaderData: headerData, + Ip: ip, + ProvinceId: locationData.ProvinceCode, + CityId: locationData.CityCode, + ErrorCode: errorCode, + ErrorMsg: errorMsg, + ErrorData: errorData, + ReqId: reqId, + Timestamp: timestamp, + UserAgent: request.Header.Get("User-Agent"), + Status: consts.StatusEnabled, + TakeUpTime: modelContext.TakeUpTime, + } + + return data +} diff --git a/hotgo-server/app/service/sysService/provinces_service.go b/hotgo-server/app/service/sysService/provinces_service.go new file mode 100644 index 0000000..b652873 --- /dev/null +++ b/hotgo-server/app/service/sysService/provinces_service.go @@ -0,0 +1,29 @@ +// +// @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 sysService + +import ( + "context" + "github.com/bufanyun/hotgo/app/com" +) + +var Provinces = new(provinces) + +type provinces struct{} + +// +//  @Title  获取地区中的省市编码 +//  @Description  +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   location +// +func (service *provinces) GetLocationCode(ctx context.Context, location com.IpLocationData) { + + return +} + diff --git a/hotgo-server/app/utils/auth_util.go b/hotgo-server/app/utils/auth_util.go new file mode 100644 index 0000000..1964418 --- /dev/null +++ b/hotgo-server/app/utils/auth_util.go @@ -0,0 +1,65 @@ +// +// @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 utils + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" +) + +// 权限认证类 +var Auth = new(auth) + +type auth struct{} + +// +//  @Title  是否是不需要验证权限的路由地址 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   path +//  @Return  bool +// +func (util *auth) IsExceptAuth(ctx context.Context, path string) bool { + + var pathList []string + + except, _ := g.Cfg().Get(ctx, "router.admin.exceptAuth") + pathList = except.Strings() + + for i := 0; i < len(pathList); i++ { + if Charset.IsExists(pathList[i], path) { + return true + } + } + + return false +} + +// +//  @Title  是否是不需要登录的路由地址 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   path +//  @Return  bool +// +func (util *auth) IsExceptLogin(ctx context.Context, path string) bool { + + var pathList []string + + except, _ := g.Cfg().Get(ctx, "router.admin.exceptLogin") + pathList = except.Strings() + + for i := 0; i < len(pathList); i++ { + if Charset.IsExists(pathList[i], path) { + return true + } + } + + return false +} diff --git a/hotgo-server/app/utils/charset_util.go b/hotgo-server/app/utils/charset_util.go new file mode 100644 index 0000000..9f1e49e --- /dev/null +++ b/hotgo-server/app/utils/charset_util.go @@ -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 utils + +import ( + "crypto/md5" + "crypto/rand" + "fmt" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + r "math/rand" + "time" +) + +// 字符类 +var Charset = new(charset) + +type charset struct{} + +// +//  @Title  获取map的所有key,字串符类型 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   m +//  @Return  []string +// +func (util *charset) GetMapKeysByString(m map[string]string) []string { + // 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高 + j := 0 + keys := make([]string, len(m)) + for k := range m { + keys[j] = k + j++ + } + return keys +} + +// +//  @Title  生成md5 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   str +//  @Return  string +// +func (util *charset) Md5ToString(str string) string { + md5str := fmt.Sprintf("%x", md5.Sum([]byte(str))) + return md5str +} + +// +//  @Title  生成随机字串符 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   n +//  @Param   alphabets +//  @Return  []byte +// +func (util *charset) RandomCreateBytes(n int, alphabets ...byte) []byte { + if len(alphabets) == 0 { + alphabets = []byte(`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`) + } + var bytes = make([]byte, n) + var randBy bool + r.Seed(time.Now().UnixNano()) + if num, err := rand.Read(bytes); num != n || err != nil { + randBy = true + } + for i, b := range bytes { + if randBy { + bytes[i] = alphabets[r.Intn(len(alphabets))] + } else { + bytes[i] = alphabets[b%byte(len(alphabets))] + } + } + return bytes +} + +// +//  @Title  格式化错误的堆栈信息 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   err +//  @Return  []string +// +func (util *charset) GetStack(err error) []string { + stackList := gstr.Split(gerror.Stack(err), "\n") + for i := 0; i < len(stackList); i++ { + stackList[i] = gstr.Replace(stackList[i], "\t", "--> ") + } + + return stackList +} + +// +//  @Title  判断字符或切片字符是否存在指定字符 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   elems +//  @Param   search +//  @Return  bool +// +func (util *charset) IsExists(elems interface{}, search string) bool { + switch elems.(type) { + case []string: + elem := gconv.Strings(elems) + for i := 0; i < len(elem); i++ { + if gconv.String(elem[i]) == search { + return true + } + } + default: + return gconv.String(elems) == search + } + + return false +} diff --git a/hotgo-server/app/utils/excel_util.go b/hotgo-server/app/utils/excel_util.go new file mode 100644 index 0000000..e248597 --- /dev/null +++ b/hotgo-server/app/utils/excel_util.go @@ -0,0 +1,87 @@ +// +// @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 utils + +import ( + "fmt" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/util/gconv" + "github.com/xuri/excelize/v2" + "net/url" + "reflect" +) + +// 字符类 +var Excel = new(excel) + +type excel struct{} + +func (util *excel) ExportByStruct(w *ghttp.ResponseWriter, titleList []string, data []interface{}, fileName string, sheetName string) error { + + f := excelize.NewFile() + f.SetSheetName("Sheet1", sheetName) + header := make([]string, 0) + for _, v := range titleList { + header = append(header, v) + } + + rowStyleID, _ := f.NewStyle(`{"font":{"color":"#666666","size":13,"family":"arial"},"alignment":{"vertical":"center","horizontal":"center"}}`) + _ = f.SetSheetRow(sheetName, "A1", &header) + _ = f.SetRowHeight("Sheet1", 1, 30) + length := len(titleList) + headStyle := util.letter(length) + var lastRow string + var widthRow string + for k, v := range headStyle { + if k == length-1 { + lastRow = fmt.Sprintf("%s1", v) + widthRow = v + } + } + if err := f.SetColWidth(sheetName, "A", widthRow, 30); err != nil { + return err + } + + rowNum := 1 + for _, v := range data { + t := reflect.TypeOf(v) + value := reflect.ValueOf(v) + row := make([]interface{}, 0) + for l := 0; l < t.NumField(); l++ { + val := value.Field(l).Interface() + row = append(row, val) + } + rowNum++ + err := f.SetSheetRow(sheetName, "A"+gconv.String(rowNum), &row) + _ = f.SetCellStyle(sheetName, fmt.Sprintf("A%d", rowNum), fmt.Sprintf("%s", lastRow), rowStyleID) + if err != nil { + return err + } + } + disposition := fmt.Sprintf("attachment; filename=%s.xlsx", url.QueryEscape(fileName)) + + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", disposition) + w.Header().Set("Content-Transfer-Encoding", "binary") + w.Header().Set("Access-Control-Expose-Headers", "Content-Disposition") + + err := f.Write(w) + if err != nil { + return err + } + + return nil +} + +// Letter 遍历a-z +func (util *excel) letter(length int) []string { + var str []string + for i := 0; i < length; i++ { + str = append(str, string(rune('A'+i))) + } + return str +} diff --git a/hotgo-server/app/utils/filter_util.go b/hotgo-server/app/utils/filter_util.go new file mode 100644 index 0000000..da4db92 --- /dev/null +++ b/hotgo-server/app/utils/filter_util.go @@ -0,0 +1,17 @@ +package utils + +// 过滤类 +var Filter = new(filter) + +type filter struct{} + +//func (util *filter) RangeDate(startTime string, endTime string) map[string]interface{} { +// g.Map{ +// "uid <=" : 1000, +// "age >=" : 18, +// } +// return g.Map{ +// "uid <=" : 1000, +// "age >=" : 18, +// } +//} diff --git a/hotgo-server/app/utils/signal_util.go b/hotgo-server/app/utils/signal_util.go new file mode 100644 index 0000000..be6096a --- /dev/null +++ b/hotgo-server/app/utils/signal_util.go @@ -0,0 +1,76 @@ +// +// @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 utils + +import ( + "sync" +) + +// 信号类 +var Signal = new(signal) + +type signal struct{} + +type StopSignal int32 + +type exitWait struct { + mutex sync.Mutex + wg *sync.WaitGroup + deferFuns []func() + stopSignList []chan StopSignal +} + +var exitWaitHandler *exitWait + +func init() { + exitWaitHandler = &exitWait{ + wg: &sync.WaitGroup{}, + } +} + +// +//  @Title  退出后等待处理完成 +//  @Description  +//  @Author  Ms <133814250@qq.com> +//  @Param   doFun +// +func (util *signal) ExitWaitFunDo(doFun func()) { + exitWaitHandler.wg.Add(1) + defer exitWaitHandler.wg.Done() + if doFun != nil { + doFun() + } +} + +// +//  @Title  应用退出后置操作 +//  @Description  +//  @Author  Ms <133814250@qq.com> +//  @Param   deferFun +// +func (util *signal) AppDefer(deferFun ...func()) { + exitWaitHandler.mutex.Lock() + defer exitWaitHandler.mutex.Unlock() + for _, funcItem := range deferFun { + if funcItem != nil { + exitWaitHandler.deferFuns = append(exitWaitHandler.deferFuns, funcItem) + } + } +} + +// +//  @Title  订阅app退出信号 +//  @Description  +//  @Author  Ms <133814250@qq.com> +//  @Param   stopSig +// +func (util *signal) ListenStop(stopSig chan StopSignal) { + exitWaitHandler.mutex.Lock() + defer exitWaitHandler.mutex.Unlock() + + exitWaitHandler.stopSignList = append(exitWaitHandler.stopSignList, stopSig) +} diff --git a/hotgo-server/app/utils/validate_util.go b/hotgo-server/app/utils/validate_util.go new file mode 100644 index 0000000..fd4adb0 --- /dev/null +++ b/hotgo-server/app/utils/validate_util.go @@ -0,0 +1,30 @@ +// +// @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 utils + +import ( + "net" +) + +// 验证类 +var Validate = new(validate) + +type validate struct{} + +// +//  @Title  是否为ipv4 +//  @Description  +//  @Author  Ms <133814250@qq.com> +//  @Param   ip +//  @Return  bool +// +func (util *validate) IsIp(ip string) bool { + if net.ParseIP(ip) != nil { + return true + } + return false +} diff --git a/hotgo-server/boot/queue.go b/hotgo-server/boot/queue.go new file mode 100644 index 0000000..1260e47 --- /dev/null +++ b/hotgo-server/boot/queue.go @@ -0,0 +1,42 @@ +// +// @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 boot + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/factory/queue" + "github.com/bufanyun/hotgo/app/service/sysService" +) + +// +//  @Title  消息队列监听 +//  @Description  +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +// +func QueueListen(ctx context.Context) { + + consumer, err := queue.InstanceConsumer() + if err != nil { + queue.FatalLog(ctx, "InstanceConsumer异常", err) + return + } + + // 全局日志 + if listenErr := consumer.ListenReceiveMsgDo(consts.QueueLogTopic, func(mqMsg queue.MqMsg) { + + // 自定义消费回调 + err := sysService.Log.QueueJob(ctx, mqMsg) + + // 记录消费日志 + queue.ConsumerLog(ctx, consts.QueueLogTopic, mqMsg, err) + }); listenErr != nil { + queue.FatalLog(ctx, "主题:"+consts.QueueLogTopic+" 监听失败", listenErr) + } + +} diff --git a/hotgo-server/boot/run.go b/hotgo-server/boot/run.go new file mode 100644 index 0000000..486f909 --- /dev/null +++ b/hotgo-server/boot/run.go @@ -0,0 +1,96 @@ +// +// @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 boot + +import ( + "context" + "github.com/bufanyun/hotgo/app/consts" + "github.com/bufanyun/hotgo/app/hook" + "github.com/bufanyun/hotgo/app/middleware" + "github.com/bufanyun/hotgo/app/model" + "github.com/bufanyun/hotgo/router" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gcmd" + "github.com/gogf/gf/v2/protocol/goai" +) + +var ( + Main = gcmd.Command{ + Name: "main", + Usage: "main", + Brief: "start http server of HotGo!", + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + s := g.Server() + + // 错误状态码接管 + s.BindStatusHandler(404, func(r *ghttp.Request) { + r.Response.Writeln("404 - 你似乎来到了没有知识存在的荒原…") + }) + s.BindStatusHandler(403, func(r *ghttp.Request) { + r.Response.Writeln("403 - 网站拒绝显示此网页") + }) + + // 请求结束事件回调 + s.BindHookHandler("/*any", ghttp.HookAfterOutput, hook.Instance().GlobalLog) + + s.Group("/", func(group *ghttp.RouterGroup) { + + // 注册全局中间件 + group.Middleware( + middleware.Instance().Ctx, //必须第一个加载 + middleware.Instance().CORS, + middleware.Instance().HandlerResponse, + ) + + // 注册默认首页路由 + group.ALL("/", func(r *ghttp.Request) { + r.Response.Write("hello hotGo!!") + }) + + // 注册后台路由 + router.Admin(ctx, group) + + // 注册API路由 + router.Api(ctx, group) + + }) + + // Custom enhance API document. + enhanceOpenAPIDoc(s) + + // 消息队列 + QueueListen(ctx) + + // Just run the server. + s.Run() + return nil + }, + } +) + +// +//  @Title  API document +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   s +// +func enhanceOpenAPIDoc(s *ghttp.Server) { + openapi := s.GetOpenApi() + openapi.Config.CommonResponse = model.Response{} + openapi.Config.CommonResponseDataField = `Data` + + // API description. + openapi.Info = goai.Info{ + Title: consts.OpenAPITitle, + Description: consts.OpenAPIDescription, + Contact: &goai.Contact{ + Name: consts.OpenAPIName, + URL: consts.OpenAPIURL, + }, + } +} diff --git a/hotgo-server/config/config.example.yaml b/hotgo-server/config/config.example.yaml new file mode 100644 index 0000000..fbd876b --- /dev/null +++ b/hotgo-server/config/config.example.yaml @@ -0,0 +1,132 @@ +# hotgo配置 +hotgo: + debug: true # debug开关,开启后:接口出现错误时会输出堆栈信息,默认为true + ipMethod: "cz88" # IP归属地解析方法,可选:cz88|whois,默认为cz88 + log: # 全局请求日志 + switch: true # 日志开关,默认为true + queue: true # 是否启用队列,启用时需要配置队列信息,默认为true + module: ["admin", "api"] # 需要记录的模块 + skipCode: [] # 不记录的状态码,如: ["0", "-1"] + +# 路由配置 +router: + # 后台 + admin: + # 前缀 + prefix: "/admin" + # 不需要验证登录的路由地址 + exceptLogin: [ + "/login/captcha", # 登录验证码 + "/login/sign", # 登录 + ] + # 不需要验证权限的路由地址 + exceptAuth: [ + "/member/info", # 登录用户信息 + "/role/dynamic", # 获取动态路由 + ] + # 接口 + api: + # 前缀 + prefix: "/api" + # 不需要验证登录的路由地址 + exceptPath: [] + + +# HTTP Server. +server: + address: ":8299" + serverRoot: "resource/public" + openapiPath: "/openApi.json" + swaggerPath: "/doc" + DumpRouterMap: false + logPath: "./runtime/log/server" + ErrorStack: true # 当Server捕获到异常时是否记录堆栈信息到日志中。默认为true + ErrorLogEnabled: true # 是否记录异常日志信息到日志中。默认为true + errorLogPattern: "error/{Y-m-d}.log" # 异常错误日志文件格式。默认为"error-{Ymd}.log" + accessLogEnabled: true # 是否记录访问日志。默认为false + accessLogPattern: "access/{Y-m-d}.log" # 访问日志文件格式。默认为"access-{Ymd}.log" + serverAgent: "HG HTTP Server" + + +# Global logging. +logger: + level: "all" + stdout: true + headerPrint: false + ctxKeys: [] + path: "./runtime/log/logger" # 日志文件路径。默认为空,表示关闭,仅输出到终端 + file: "{Y-m-d}.log" # 日志文件格式。默认为"{Y-m-d}.log" + exception: # 系统异常日志 + path: "./runtime/log/exception" + level: "all" + file: "{Y-m-d}.log" + queue: # 消息队列日志 + path: "./runtime/log/queue" + level: "all" + file: "{Y-m-d}.log" + +#JWT +jwt: + version: "1.0" # 版本号 + expires: "864000" # 有效期,单位:秒 + sign: "hotgo" # 秘钥,考虑安全问题请修改默认值 + multiPort: true # 是否允许多端登录,默认为true + +#消息队列 +queue: + switch: true # 队列开关,默认为true + driver: "redis" # 队列驱动,可选:redis|rocketmq|kafka + retry: 2 # 重试次数 + multiComsumer: true # 是否支持创建多个消费者 + groupName: "hotgo" # mq群组名称 + redis: + address: "127.0.0.1:6379" # redis服务地址,默认为127.0.0.1:6379 + db: 5 # 指定redis库 + pass: "meng133814250" # redis密码 + timeout: 0 # 队列超时时间(s) ,0为永不超时,当队列一直没有被消费到达超时时间则队列会被销毁 + rocketmq: + address: "127.0.0.1:9876" # brocker地址+端口 + logLevel: "all" # 系统日志级别,可选:all|close|debug|info|warn|error|fatal + kafka: + address: "127.0.0.1:9092" # kafka地址+端口 + version: "2.0.0.0" # kafka专属配置,默认2.0.0.0 + randClient: true # 开启随机生成clientID,可以实现启动多实例同时一起消费相同topic,加速消费能力的特性,默认为true + +# Redis数据库配置 +redis: + default: + address: "127.0.0.1:6379" + db: "5" + pass: "meng133814250" + idleTimeout: "20" +# cache: +# address: "127.0.0.1:6379" +# db: "5" +# pass: "meng133814250" +# idleTimeout: "20" + +# Database. +database: + logger: + level: "all" + stdout: true + + default: + link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo" + debug: true + Prefix: "hg_" + +# CLI. +gfcli: + build: + name: "hg" + gen: + dao: + - link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo" + path: "./app" + # tables: "" #指定当前数据库中需要执行代码生成的数据表。如果为空,表示数据库的所有表都会生成。 + # tablesEx: "" #指定当前数据库中需要排除代码生成的数据表。 + removePrefix: "hg_" + descriptionTag: true + noModelComment: true + jsonCase: "Snake" \ No newline at end of file diff --git a/hotgo-server/config/config.yaml b/hotgo-server/config/config.yaml new file mode 100644 index 0000000..99c574c --- /dev/null +++ b/hotgo-server/config/config.yaml @@ -0,0 +1,132 @@ +# hotgo配置 +hotgo: + debug: true # debug开关,开启后:接口出现错误时会输出堆栈信息,默认为true + ipMethod: "cz88" # IP归属地解析方法,可选:cz88|whois,默认为cz88 + log: # 全局请求日志 + switch: true # 日志开关,默认为true + queue: true # 是否启用队列,启用时需要配置队列信息,默认为true + module: ["admin", "api"] # 需要记录的模块 + skipCode: [] # 不记录的状态码,如: ["0", "-1"] + +# 路由配置 +router: + # 后台 + admin: + # 前缀 + prefix: "/admin" + # 不需要验证登录的路由地址 + exceptLogin: [ + "/login/captcha", # 登录验证码 + "/login/sign", # 登录 + ] + # 不需要验证权限的路由地址 + exceptAuth: [ + "/member/info", # 登录用户信息 + "/role/dynamic", # 获取动态路由 + ] + # 接口 + api: + # 前缀 + prefix: "/api" + # 不需要验证登录的路由地址 + exceptPath: [] + + +# HTTP Server. +server: + address: ":8299" + serverRoot: "resource/public" + openapiPath: "/openApi.json" + swaggerPath: "/doc" + DumpRouterMap: false + logPath: "./runtime/log/server" + ErrorStack: true # 当Server捕获到异常时是否记录堆栈信息到日志中。默认为true + ErrorLogEnabled: true # 是否记录异常日志信息到日志中。默认为true + errorLogPattern: "error/{Y-m-d}.log" # 异常错误日志文件格式。默认为"error-{Ymd}.log" + accessLogEnabled: true # 是否记录访问日志。默认为false + accessLogPattern: "access/{Y-m-d}.log" # 访问日志文件格式。默认为"access-{Ymd}.log" + serverAgent: "HG HTTP Server" + + +# Global logging. +logger: + level: "all" + stdout: true + headerPrint: false + ctxKeys: [] + path: "./runtime/log/logger" # 日志文件路径。默认为空,表示关闭,仅输出到终端 + file: "{Y-m-d}.log" # 日志文件格式。默认为"{Y-m-d}.log" + exception: # 系统异常日志 + path: "./runtime/log/exception" + level: "all" + file: "{Y-m-d}.log" + queue: # 消息队列日志 + path: "./runtime/log/queue" + level: "all" + file: "{Y-m-d}.log" + +#JWT +jwt: + version: "1.0" # 版本号 + expires: "864000" # 有效期,单位:秒 + sign: "hotgo" # 秘钥,考虑安全问题请修改默认值 + multiPort: true # 是否允许多端登录,默认为true + +#消息队列 +queue: + switch: true # 队列开关,默认为true + driver: "redis" # 队列驱动,可选:redis|rocketmq|kafka + retry: 2 # 重试次数 + multiComsumer: true # 是否支持创建多个消费者 + groupName: "hotgo" # mq群组名称 + redis: + address: "42.194.151.158:6379" # redis服务地址,默认为127.0.0.1:6379 + db: 5 # 指定redis库 + pass: "meng133814250" # redis密码 + timeout: 0 # 队列超时时间(s) ,0为永不超时,当队列一直没有被消费到达超时时间则队列会被销毁 + rocketmq: + address: "42.194.151.158:9876" # brocker地址+端口 + logLevel: "all" # 系统日志级别,可选:all|close|debug|info|warn|error|fatal + kafka: + address: "42.194.151.158:9092" # kafka地址+端口 + version: "2.0.0.0" # kafka专属配置,默认2.0.0.0 + randClient: true # 开启随机生成clientID,可以实现启动多实例同时一起消费相同topic,加速消费能力的特性,默认为true + +# Redis数据库配置 +redis: + default: + address: "42.194.151.158:6379" + db: "5" + pass: "meng133814250" + idleTimeout: "20" +# cache: +# address: "42.194.151.158:6379" +# db: "5" +# pass: "meng133814250" +# idleTimeout: "20" + +# Database. +database: + logger: + level: "all" + stdout: true + + default: + link: "mysql:hotgo:7P7KKABcknecLJFF@tcp(42.194.151.158:3306)/hotgo" + debug: true + Prefix: "hg_" + +# CLI. +gfcli: + build: + name: "hg" + gen: + dao: + - link: "mysql:hotgo:7P7KKABcknecLJFF@tcp(42.194.151.158:3306)/hotgo" + path: "./app" + # tables: "" #指定当前数据库中需要执行代码生成的数据表。如果为空,表示数据库的所有表都会生成。 + # tablesEx: "" #指定当前数据库中需要排除代码生成的数据表。 + removePrefix: "hg_" + descriptionTag: true + noModelComment: true + jsonCase: "Snake" \ No newline at end of file diff --git a/hotgo-server/go.mod b/hotgo-server/go.mod new file mode 100644 index 0000000..255b5b9 --- /dev/null +++ b/hotgo-server/go.mod @@ -0,0 +1,26 @@ +module github.com/bufanyun/hotgo + +go 1.15 + +require ( + github.com/Shopify/sarama v1.30.1 + github.com/apache/rocketmq-client-go/v2 v2.1.0 + github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 + github.com/bufanyun/pool v0.2.1 + github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/gogf/gf/v2 v2.0.0-rc2 + github.com/gomodule/redigo v2.0.0+incompatible + github.com/google/btree v1.0.1 // indirect + github.com/ip2location/ip2location-go v8.3.0+incompatible + github.com/json-iterator/go v1.1.10 // indirect + github.com/kayon/iploc v0.0.0-20200312105652-bda3e968a794 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/mojocn/base64Captcha v1.3.5 + github.com/pkg/errors v0.9.1 // indirect + github.com/spf13/pflag v1.0.5 + github.com/xuri/excelize/v2 v2.5.0 + go.opentelemetry.io/otel/trace v1.0.0 + go.uber.org/atomic v1.6.0 // indirect + golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 +) diff --git a/hotgo-server/go.sum b/hotgo-server/go.sum new file mode 100644 index 0000000..3f5a422 --- /dev/null +++ b/hotgo-server/go.sum @@ -0,0 +1,312 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Shopify/sarama v1.30.1 h1:z47lP/5PBw2UVKf1lvfS5uWXaJws6ggk9PLnKEHtZiQ= +github.com/Shopify/sarama v1.30.1/go.mod h1:hGgx05L/DiW8XYBXeJdKIN6V2QUy2H6JqME5VT1NLRw= +github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae h1:ePgznFqEG1v3AjMklnK8H7BSc++FDSo7xfK9K7Af+0Y= +github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0= +github.com/apache/rocketmq-client-go/v2 v2.1.0 h1:3eABKfxc1WmS2lLTTbKMe1gZfZV6u1Sx9orFnOfABV0= +github.com/apache/rocketmq-client-go/v2 v2.1.0/go.mod h1:oEZKFDvS7sz/RWU0839+dQBupazyBV7WX5cP6nrio0Q= +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg= +github.com/bufanyun/pool v0.2.1 h1:rW6TVJt+vS71d1uBI9sCMUjS39AWZFsUww+2XOh+338= +github.com/bufanyun/pool v0.2.1/go.mod h1:uZsjaA/H4agFQ1E0KWj4bnzRUVGmieM54pJiIKPTrAI= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= +github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gogf/gf/v2 v2.0.0-rc2 h1:WznHd6sGOQ0ef1r4UdejUnXHT4058b1R/cumQL5tooE= +github.com/gogf/gf/v2 v2.0.0-rc2/go.mod h1:apktt6TleWtCIwpz63vBqUnw8MX8gWKoZyxgDpXFtgM= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= +github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ip2location/ip2location-go v8.3.0+incompatible h1:QwUE+FlSbo6bjOWZpv2Grb57vJhWYFNPyBj2KCvfWaM= +github.com/ip2location/ip2location-go v8.3.0+incompatible/go.mod h1:3JUY1TBjTx1GdA7oRT7Zeqfc0bg3lMMuU5lXmzdpuME= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kayon/iploc v0.0.0-20200312105652-bda3e968a794 h1:dWJxw+KQOMeVcoyxqG9I5fppPld1hh1FG8ngv0fKNsQ= +github.com/kayon/iploc v0.0.0-20200312105652-bda3e968a794/go.mod h1:IwrOeG3O3K9vVXmcVvc9T0XLabw67QePi5pKQt5U+Kw= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0= +github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj3nKI= +github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= +github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o= +github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 h1:N8Bg45zpk/UcpNGnfJt2y/3lRWASHNTUET8owPYCgYI= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.2.1 h1:j0efZLrZUvNerEf6xqoi0NjWMK5YlLrR7Guo/dxY174= +github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 h1:rQ229MBgvW68s1/g6f1/63TgYwYxfF4E+bi/KC19P8g= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 h1:EpI0bqf/eX9SdZDwlMmahKM+CDBgNbsXMhsN28XrM8o= +github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/excelize/v2 v2.5.0 h1:nDDVfX0qaDuGjAvb+5zTd0Bxxoqa1Ffv9B4kiE23PTM= +github.com/xuri/excelize/v2 v2.5.0/go.mod h1:rSu0C3papjzxQA3sdK8cU544TebhrPUoTOaGPIh0Q1A= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI= +go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg= +go.opentelemetry.io/otel/sdk v1.0.0 h1:BNPMYUONPNbLneMttKSjQhOTlFLOD9U22HNG1KrIN2Y= +go.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM= +go.opentelemetry.io/otel/trace v1.0.0 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4= +go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210920023735-84f357641f63 h1:kETrAMYZq6WVGPa8IIixL0CaEcIUNi+1WX7grUoi3y8= +golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk= +golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y= +golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c= +stathat.com/c/consistent v1.0.0/go.mod h1:QkzMWzcbB+yQBL2AttO6sgsQS/JSTapcDISJalmCDS0= diff --git a/hotgo-server/main.go b/hotgo-server/main.go new file mode 100644 index 0000000..20efd7f --- /dev/null +++ b/hotgo-server/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "github.com/bufanyun/hotgo/boot" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" +) + +func main() { + + var ( + ctx = gctx.New() + ) + + if err := boot.Main.RunWithError(ctx); err != nil { + g.Log().Fatal(ctx, err) + } +} diff --git a/hotgo-server/pull.bat b/hotgo-server/pull.bat new file mode 100644 index 0000000..cfa6d5f --- /dev/null +++ b/hotgo-server/pull.bat @@ -0,0 +1,15 @@ +::强制和远程同步,不保留本地修改 +::git fetch --all +::git reset --hard origin/master +::git pull + + +::保存本地修改,拉取远程后恢复本地修改 +::git stash +::git pull origin master +::git stash pop +::git stash list +::git stash clear + +::拉取远程 +git pull origin master \ No newline at end of file diff --git a/hotgo-server/push.bat b/hotgo-server/push.bat new file mode 100644 index 0000000..fb2eecc --- /dev/null +++ b/hotgo-server/push.bat @@ -0,0 +1,11 @@ +echo -e "\n \n" >> ./README.md + +::git rm -r --cached -f . +git init && git add -A + +for /f "tokens=2 delims==" %%a in ('wmic path win32_operatingsystem get LocalDateTime /value') do (set t=%%a) +set Today=%t:~0,4%-%t:~4,2%-%t:~6,2% %t:~8,2%:%t:~10,2% + +git commit -m "%Today%" + +git push git@gitee.com:bufanyun/hotgo.git master \ No newline at end of file diff --git a/hotgo-server/resource/public/html/.gitkeep b/hotgo-server/resource/public/html/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/hotgo-server/resource/public/plugin/.gitkeep b/hotgo-server/resource/public/plugin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/hotgo-server/resource/public/plugin/layer-3.1.1/layer.js b/hotgo-server/resource/public/plugin/layer-3.1.1/layer.js new file mode 100644 index 0000000..12cb6b5 --- /dev/null +++ b/hotgo-server/resource/public/plugin/layer-3.1.1/layer.js @@ -0,0 +1,2 @@ +/*! layer-v3.1.1 Web弹层组件 MIT License http://layer.layui.com/ By 贤心 */ + ;!function(e,t){"use strict";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;n>0;n--)if("interactive"===t[n].readyState){e=t[n].src;break}return e||t[i].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName("head")[0],s=document.createElement("link");"string"==typeof i&&(n=i);var l=(n||t).replace(/\.|\//g,""),f="layuicss-"+l,c=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),"function"==typeof i&&!function u(){return++c>80?e.console&&console.error("layer.css: Invalid"):void(1989===parseInt(o.getStyle(document.getElementById(f),"width"))?i():setTimeout(u,100))}()}}},r={v:"3.1.1",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):o.link("theme/"+e.extend),this):this},ready:function(e){var t="layer",i="",n=(a?"modules/layer/":"theme/")+"default/layer.css?v="+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim-00","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"信息",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'
'+(f?r.title[0]:r.title)+"
":"";return r.zIndex=s,t([r.shade?'
':"",'
'+(e&&2!=r.type?"":u)+'
'+(0==r.type&&r.icon!==-1?'':"")+(1==r.type&&e?"":r.content||"")+'
'+function(){var e=c?'':"";return r.closeBtn&&(e+=''),e}()+""+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t'+r.btn[t]+"";return'
'+e+"
"}():"")+(r.resize?'':"")+"
"],u,i('
')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"http://layer.layui.com","auto"];t.content='';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i(".layui-layer-move")[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),i("#layui-layer-shade"+e.index).css({"background-color":t.shade[1]||"#000",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u="layer-anim "+l.anim[t.anim];e.layero.addClass(u).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i("#"+l[0]+e);""===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find("."+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css("padding-top"))))};switch(a.type){case 2:u("iframe");break;default:""===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u("."+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u("."+l[5])):u("."+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;af&&(a=f),ou&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&i("#layui-layer-shade"+t.index).on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){var a=i("#"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr("minLeft")||181*o.minIndex+"px",c=a.css("position");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr("position",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:"fixed",overflow:"hidden"},!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr("minLeft")||o.minIndex++,a.attr("minLeft",f)},r.restore=function(e){var t=i("#"+l[0]+e),n=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i("#"+l[0]+e),n=t.attr("type"),a="layer-anim-close";if(t[0]){var s="layui-layer-wrap",f=function(){if(n===o.type[1]&&"object"===t.attr("conType")){t.children(":not(."+l[5]+")").remove();for(var a=t.find("."+s),r=0;r<2;r++)a.unwrap();a.css("display",a.data("display")).removeClass(s)}else{if(n===o.type[2])try{var f=i("#"+l[4]+e)[0];f.contentWindow.document.write(""),f.contentWindow.close(),t.find("."+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML="",t.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data("isOutAnim")&&t.addClass("layer-anim "+a),i("#layui-layer-moves, #layui-layer-shade"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr("minLeft")&&(o.minIndex--,o.minLeft.push(t.attr("minLeft"))),r.ie&&r.ie<10||!t.data("isOutAnim")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i("."+l[0]),function(){var t=i(this),n=e?t.attr("type")===e:1;n&&r.close(t.attr("times")),n=null})};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'":function(){return''}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["确定","取消"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(e){s=e.find(".layui-layer-input"),s.focus(),"function"==typeof f&&f(e)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("最多输入"+(e.maxlength||500)+"个字数",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n="layui-this",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,a="";if(e>0)for(a=''+t[0].title+"";i"+t[i].title+"";return a}(),content:'
    '+function(){var e=t.length,i=1,a="";if(e>0)for(a='
  • '+(t[0].content||"no content")+"
  • ";i'+(t[i].content||"no content")+"";return a}()+"
",success:function(t){var o=t.find(".layui-layer-title").children(),r=t.find(".layui-layer-tabmain").children();o.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),"function"==typeof e.change&&e.change(o)}),"function"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("没有图片")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext()}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]'+(u[d].alt||
'+(u.length>1?'':"")+'
'+(u[d].alt||"")+""+s.imgIndex+"/"+u.length+"
",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imguide,.layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("当前图片地址异常
是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window); \ No newline at end of file diff --git a/hotgo-server/resource/public/plugin/layer-3.1.1/mobile/layer.js b/hotgo-server/resource/public/plugin/layer-3.1.1/mobile/layer.js new file mode 100644 index 0000000..f9cf693 --- /dev/null +++ b/hotgo-server/resource/public/plugin/layer-3.1.1/mobile/layer.js @@ -0,0 +1,2 @@ +/*! layer mobile-v2.0.0 Web弹层组件 MIT License http://layer.layui.com/mobile By 贤心 */ + ;!function(e){"use strict";var t=document,n="querySelectorAll",i="getElementsByClassName",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var r=0,o=["layui-m-layer"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement("div");e.id=s.id=o[0]+r,s.setAttribute("class",o[0]+" "+o[0]+(n.type||0)),s.setAttribute("index",r);var l=function(){var e="object"==typeof n.title;return n.title?'

'+(e?n.title[0]:n.title)+"

":""}(),c=function(){"string"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e=''+n.btn[0]+"",2===t&&(e=''+n.btn[1]+""+e),'
'+e+"
"):""}();if(n.fixed||(n.top=n.hasOwnProperty("top")?n.top:100,n.style=n.style||"",n.style+=" top:"+(t.body.scrollTop+n.top)+"px"),2===n.type&&(n.content='

'+(n.content||"")+"

"),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"
':"")+'
"+l+'
'+n.content+"
"+c+"
",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute("index"))}document.body.appendChild(s);var u=e.elem=a("#"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i]("layui-m-layerbtn")[0].children,r=s.length,o=0;odiv{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px} \ No newline at end of file diff --git a/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/icon-ext.png b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/icon-ext.png new file mode 100644 index 0000000..bbbb669 Binary files /dev/null and b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/icon-ext.png differ diff --git a/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/icon.png b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/icon.png new file mode 100644 index 0000000..3e17da8 Binary files /dev/null and b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/icon.png differ diff --git a/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/layer.css b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/layer.css new file mode 100644 index 0000000..820b4a9 --- /dev/null +++ b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/layer.css @@ -0,0 +1 @@ +.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;background-color:#F8F8F8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1E9FFF;background-color:#1E9FFF;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:230px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:43px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}} \ No newline at end of file diff --git a/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/loading-0.gif b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/loading-0.gif new file mode 100644 index 0000000..6f3c953 Binary files /dev/null and b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/loading-0.gif differ diff --git a/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/loading-1.gif b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/loading-1.gif new file mode 100644 index 0000000..db3a483 Binary files /dev/null and b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/loading-1.gif differ diff --git a/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/loading-2.gif b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/loading-2.gif new file mode 100644 index 0000000..5bb90fd Binary files /dev/null and b/hotgo-server/resource/public/plugin/layer-3.1.1/theme/default/loading-2.gif differ diff --git a/hotgo-server/resource/public/resource/css/.gitkeep b/hotgo-server/resource/public/resource/css/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/hotgo-server/resource/public/resource/image/.gitkeep b/hotgo-server/resource/public/resource/image/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/hotgo-server/resource/public/resource/image/cover.png b/hotgo-server/resource/public/resource/image/cover.png new file mode 100644 index 0000000..7ec4407 Binary files /dev/null and b/hotgo-server/resource/public/resource/image/cover.png differ diff --git a/hotgo-server/resource/public/resource/image/favicon.ico b/hotgo-server/resource/public/resource/image/favicon.ico new file mode 100644 index 0000000..2bcdf57 Binary files /dev/null and b/hotgo-server/resource/public/resource/image/favicon.ico differ diff --git a/hotgo-server/resource/public/resource/image/gf.ico b/hotgo-server/resource/public/resource/image/gf.ico new file mode 100644 index 0000000..cb00538 Binary files /dev/null and b/hotgo-server/resource/public/resource/image/gf.ico differ diff --git a/hotgo-server/resource/public/resource/js/.gitkeep b/hotgo-server/resource/public/resource/js/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/hotgo-server/resource/template/.gitkeep b/hotgo-server/resource/template/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/hotgo-server/router/admin.go b/hotgo-server/router/admin.go new file mode 100644 index 0000000..58eb3b6 --- /dev/null +++ b/hotgo-server/router/admin.go @@ -0,0 +1,43 @@ +// +// @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 router + +import ( + "context" + "github.com/bufanyun/hotgo/app/controller/adminController" + "github.com/bufanyun/hotgo/app/middleware" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" +) + +// +//  @Title  后台路由配置 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   group +// +func Admin(ctx context.Context, group *ghttp.RouterGroup) { + + routerPrefix, _ := g.Cfg().Get(ctx, "router.admin.prefix", "/admin") + + group.Group(routerPrefix.String(), func(group *ghttp.RouterGroup) { + group.Middleware(middleware.Instance().AdminAuth) + group.Bind( + adminController.Login, // 登录 + adminController.Role, // 路由 + adminController.Member, // 会员 + adminController.Menu, // 菜单 + adminController.Log, // 日志 + adminController.Dict, // 字典 + adminController.Post, // 字典 + adminController.Dept, // 部门 + adminController.Config, // 配置 + adminController.Notice, // 公告 + ) + }) +} diff --git a/hotgo-server/router/api.go b/hotgo-server/router/api.go new file mode 100644 index 0000000..c32c20a --- /dev/null +++ b/hotgo-server/router/api.go @@ -0,0 +1,38 @@ +// +// @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 router + +import ( + "context" + "github.com/bufanyun/hotgo/app/controller/apiController" + "github.com/bufanyun/hotgo/app/middleware" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" +) + +// +//  @Title  接口路由配置 +//  @Description +//  @Author  Ms <133814250@qq.com> +//  @Param   ctx +//  @Param   group +// +func Api(ctx context.Context, group *ghttp.RouterGroup) { + + routerPrefix, _ := g.Cfg().Get(ctx, "router.api.prefix", "/api") + + group.Group(routerPrefix.String(), func(group *ghttp.RouterGroup) { + group.Middleware(middleware.Instance().ApiAuth) + group.Bind( + apiController.Login, // 登录 + apiController.Base, // 基础 + apiController.Member, // 会员 + apiController.Dict, // 字典 + apiController.Log, // 日志 + ) + }) +} diff --git a/hotgo-server/runtime/log/exception/.gitignore b/hotgo-server/runtime/log/exception/.gitignore new file mode 100644 index 0000000..bf0824e --- /dev/null +++ b/hotgo-server/runtime/log/exception/.gitignore @@ -0,0 +1 @@ +*.log \ No newline at end of file diff --git a/hotgo-server/runtime/log/logger/.gitignore b/hotgo-server/runtime/log/logger/.gitignore new file mode 100644 index 0000000..bf0824e --- /dev/null +++ b/hotgo-server/runtime/log/logger/.gitignore @@ -0,0 +1 @@ +*.log \ No newline at end of file diff --git a/hotgo-server/runtime/log/queue/.gitignore b/hotgo-server/runtime/log/queue/.gitignore new file mode 100644 index 0000000..bf0824e --- /dev/null +++ b/hotgo-server/runtime/log/queue/.gitignore @@ -0,0 +1 @@ +*.log \ No newline at end of file diff --git a/hotgo-server/runtime/log/server/.gitignore b/hotgo-server/runtime/log/server/.gitignore new file mode 100644 index 0000000..bf0824e --- /dev/null +++ b/hotgo-server/runtime/log/server/.gitignore @@ -0,0 +1 @@ +*.log \ No newline at end of file diff --git a/hotgo-server/runtime/log/server/access/.gitignore b/hotgo-server/runtime/log/server/access/.gitignore new file mode 100644 index 0000000..bf0824e --- /dev/null +++ b/hotgo-server/runtime/log/server/access/.gitignore @@ -0,0 +1 @@ +*.log \ No newline at end of file diff --git a/hotgo-server/runtime/log/server/error/.gitignore b/hotgo-server/runtime/log/server/error/.gitignore new file mode 100644 index 0000000..bf0824e --- /dev/null +++ b/hotgo-server/runtime/log/server/error/.gitignore @@ -0,0 +1 @@ +*.log \ No newline at end of file diff --git a/hotgo-server/storage/ip/qqwry-utf8.dat b/hotgo-server/storage/ip/qqwry-utf8.dat new file mode 100644 index 0000000..a4c6276 Binary files /dev/null and b/hotgo-server/storage/ip/qqwry-utf8.dat differ diff --git a/hotgo-uniapp/.gitignore b/hotgo-uniapp/.gitignore new file mode 100644 index 0000000..f8d42ed --- /dev/null +++ b/hotgo-uniapp/.gitignore @@ -0,0 +1,7 @@ +/unpackage/dist/* +/unpackage/cache/* +/unpackage/release/* +/node_modules/* +/.hbuilderx/* +/.idea/* +deploy.sh diff --git a/hotgo-uniapp/.vscode/settings.json b/hotgo-uniapp/.vscode/settings.json new file mode 100644 index 0000000..4d2173b --- /dev/null +++ b/hotgo-uniapp/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "i18n-ally.localesPaths": [ + "common/locales" + ] +} \ No newline at end of file diff --git a/hotgo-uniapp/App.vue b/hotgo-uniapp/App.vue new file mode 100644 index 0000000..9528aac --- /dev/null +++ b/hotgo-uniapp/App.vue @@ -0,0 +1,26 @@ + + \ No newline at end of file diff --git a/hotgo-uniapp/LICENSE b/hotgo-uniapp/LICENSE new file mode 100644 index 0000000..671baba --- /dev/null +++ b/hotgo-uniapp/LICENSE @@ -0,0 +1,223 @@ + 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 (C) 2013-Now, http://jeesite.com (thinkgem@163.com). + + 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. 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款。 +2. 不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 +3. 在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议、版权声明和其他原作者 + 规定需要包含的说明(请尊重原作者的著作权,不要删除或修改文件中的`Copyright`和`@author`信息) + 更不要,全局替换源代码中的 jeesite 或 ThinkGem 等字样,否则你将违反本协议条款承担责任。 +4. 基于本软件完成的软件作品,只能使用 JeeSite 作为后台服务,除外情况不允许二次分发或开源。 +5. 您若套用本软件的一些代码或功能参考,请保留源文件中的版权和作者,需要在您的软件介绍明显位置 + 说明出处,举例:本软件基于 JeeSite 快速开发平台-手机端,并附带链接:http://jeesite.com +6. 任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 +7. 如果你对本软件有改进,希望可以贡献给我们,共同进步。 +8. 本项目已申请软件著作权,请尊重开源,感谢阅读。 + +版权所有:济南卓源软件有限公司 + +官方网址:http://jeesite.com + +技术服务:http://s.jeesite.com diff --git a/hotgo-uniapp/README.md b/hotgo-uniapp/README.md new file mode 100644 index 0000000..ce6d6b6 --- /dev/null +++ b/hotgo-uniapp/README.md @@ -0,0 +1,151 @@ +

+ JeeSite +

+

快速开发平台 - 手机端

+ +## 引言 + +JeeSite Mobile Uni-App 是 JeeSite 手机端框架/移动端框架,基于 uni-app、uView UI 实现。 + +uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web、 +以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉/淘宝)、快应用等多个平台。 + +uView UI,是 uni-app 生态最优秀的 UI 框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水。 + +## 特性 + +* 支持 Android,iOS,H5,微信小程序,等其它小程序平台。 +* 移动端是无 Cookie 环境的,该项目对移动端进行会话环境封装, +* 让你像 Cookie 一样使用 token,无需特别处理,有框架帮你完成。 +* 化繁为简,封装 vuex 的繁琐,简单通过 api 即可进行 state 存取。 +* 贴心的表单组件封装,下拉框、复选框、文件上传,完美与后端 JeeSite 结合。 +* uView 提供 60+ 精选组件,功能丰富,多端兼容,让您快速集成,开箱即用。 +* 众多贴心的 JS 利器,让您飞镖在手,召之即来,百步穿杨。 +* 众多的常用页面和布局,让您专注逻辑,事半功倍。 +* 合理使用 style 的 scoped 减少包体积大小。 +* 详尽的文档支持,现代化的演示效果。 +* 按需引入,精简打包体积。 +* 移动端完整开源。 + +## 功能列表 + +* 账号登录、记住我(下次免登录) +* 自助服务:找回密码功能、账号注册功能 +* 我的主页:修改个人信息、修改头像和裁剪、修改密码 +* 辅助功能:关于我们、意见反馈、检查更新、帮助中心 +* 工作台功能列表主页、消息列表页面 +* 增删改查示例 +* 工作流引擎 + +## 快速体验 + +1、H5 APP 端访问地址:https://demo.jeesite.com/app (最新演示) +
      获得H5最佳体验,操作方法:Chrome 为例,在浏览器上按 F12 打开“开发者工具”,点击该工具左上角第二个按钮 +“Toggle device toolbar”,显示“切换设备工具栏”,然后在该工具栏上点击“Responsive”下拉选择“iPhone6/7/8”,再按“F5”刷新页面,即可。 + +2、微信小程序端:通过**微信**扫码(最佳体验,但不是最新演示,更新延迟)

+ + +3、安卓 Android 安装包,点击下载:[JeeSite4.3.1.apk](https://gitee.com/thinkgem/jeesite4/attach_files/925161/download) + +## 快速运行 + +1、下载并安装:集成开发环境 HBuilderX + (推荐,也可以使用 VSCode 或 WebStorm) + +2、菜单:文件 -> 导入 -> 从本地目录导入,选择 “jeesite4-uniapp” 文件夹。 + +3、菜单:运行 -> 运行到内置浏览器(或运行到浏览器 -> Chrome 浏览器)。 + +4、等待 HBuliderX 控制台编译完成后,会自动弹出手机登录页面。 + +## 安装服务端 + +本项目后台服务默认连接的是 demo.jeesite.com 官网演示环境,你需要替换为你的 JeeSite 后台,步骤如下: + +1、安装 JeeSite 最新版:https://gitee.com/thinkgem/jeesite4#本地运行 + (本项目支持 v4.2.3 或以上版本,若已安装,请执行 `bin/package.bat` 更新依赖) + +2、打开 application.yml 修改如下配置(Ajax跨域设置和与后台基础交互的请求头名): + +```yml +# Shiro 相关 +shiro: + + # 是否允许跨域访问 CORS,如果允许,设置允许的域名。v4.2.3 开始支持多个域名和模糊匹配,例如:http://*.jeesite.com,http://*.jeesite.net + accessControlAllowOrigin: '*' + + # 允许跨域访问时 CORS,可以获取和返回的方法和请求头 + accessControlAllowMethods: GET, POST, OPTIONS + accessControlAllowHeaders: content-type, x-requested-with, x-ajax, x-token, x-remember + accessControlExposeHeaders: x-remember + +# Session 相关 +session: + + # 设置接收 SessionId 请求参数和请求头名称 + sessionIdHeaderName: x-token + + # 记住我的请求参数和请求头的名称 + rememberMeHeaderName: x-remember + +# Web 相关 +web: + + # AJAX 接受参数名和请求头名 + ajaxHeaderName: x-ajax + +``` + +3、打开手机端项目的 `/common/config.js` 修改 `config.baseUrl` 后端服务地址为你安装的 JeeSite 服务地址。 + +## 生态系统 + +* 分布式微服务系统(Spring Cloud): +* JFlow工作流引擎: +* Flowable业务流程模块(BPM): +* 内容管理模块(CMS): +* 手机端移动端: + +## 学习路线 + +1. 什么是 uni-app、为什么选择 uni-app +2. 集成开发环境 HBuilderX 下载 +3. uni-app 官方视频教程 +4. 如果你熟悉 h5,但不熟悉 Vue 和小程序,请看这篇白话 uni-app +5. Vue.js 视频 + 文档教程 + +## 学习文档 + +* uni-app 框架文档 +* uni-app 组件文档 +* uView 组件文档 +* uView JS 文档 + +## 打包发布 + +* 打开 `/common/config.js` 找到 `config.baseUrl` 修改为正式的手机端后台服务地址 +* 阅读这篇文章:如何发布 uni-app 软件 +* uni-app 整包升级、冷更新 +* uni-app 资源升级、热更新 + +## 授权许可协议条款 + +1. 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款。 +2. 不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 +3. 在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议、版权声明和其他原作者 + 规定需要包含的说明(请尊重原作者的著作权,不要删除或修改文件中的`Copyright`和`@author`信息) + 更不要,全局替换源代码中的 jeesite 或 ThinkGem 等字样,否则你将违反本协议条款承担责任。 +4. 基于本软件完成的软件作品,只能使用 JeeSite 作为后台服务,除外情况不允许二次分发或开源。 +5. 您若套用本软件的一些代码或功能参考,请保留源文件中的版权和作者,需要在您的软件介绍明显位置 + 说明出处,举例:本软件基于 JeeSite 快速开发平台-手机端,并附带链接:http://jeesite.com +6. 任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 +7. 如果你对本软件有改进,希望可以贡献给我们,共同进步。 +8. 本项目已申请软件著作权,请尊重开源,感谢阅读。 + +## 技术服务与支持 + +* 本软件免费,我们也提供了相应的收费服务,因为: +* 没有资金的支撑就很难得到发展,特别是一个好的产品,如果 JeeSite 帮助了您,请为我们点赞(本软件Git仓库首页,右上角点击 star 按钮,关注我们)。支持我们,您可以得到一些回报,有了这些我们会把公益事业做的更好,回报社区和社会,请给我们一些动力吧,在此非常感谢已支持我们的朋友! +* **联系方式(官方商务)QQ:[1766571055](http://wpa.qq.com/msgrd?v=3&uin=1766571055&site=qq&menu=yes)** +* 技术服务支持网页: diff --git a/hotgo-uniapp/common/base64.js b/hotgo-uniapp/common/base64.js new file mode 100644 index 0000000..3edc008 --- /dev/null +++ b/hotgo-uniapp/common/base64.js @@ -0,0 +1,74 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], function() {factory(root);}); + } else factory(root); +// node.js has always supported base64 conversions, while browsers that support +// web workers support base64 too, but you may never know. +})(typeof exports !== "undefined" ? exports : this, function(root) { + if (root.atob) { + // Some browsers' implementation of atob doesn't support whitespaces + // in the encoded string (notably, IE). This wraps the native atob + // in a function that strips the whitespaces. + // The original function can be retrieved in atob.original + try { + root.atob(" "); + } catch(e) { + root.atob = (function(atob) { + var func = function(string) { + return atob(String(string).replace(/[\t\n\f\r ]+/g, "")); + }; + func.original = atob; + return func; + })(root.atob); + } + return; + } + + // base64 character set, plus padding character (=) + var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + // Regular expression to check formal correctness of base64 encoded strings + b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/; + + root.btoa = function(string) { + string = String(string); + var bitmap, a, b, c, + result = "", i = 0, + rest = string.length % 3; // To determine the final padding + + for (; i < string.length;) { + if ((a = string.charCodeAt(i++)) > 255 + || (b = string.charCodeAt(i++)) > 255 + || (c = string.charCodeAt(i++)) > 255) + throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range."); + + bitmap = (a << 16) | (b << 8) | c; + result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) + + b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63); + } + + // If there's need of padding, replace the last 'A's with equal signs + return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result; + }; + + root.atob = function(string) { + // atob can work with strings with whitespaces, even inside the encoded part, + // but only \t, \n, \f, \r and ' ', which can be stripped. + string = String(string).replace(/[\t\n\f\r ]+/g, ""); + if (!b64re.test(string)) + throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded."); + + // Adding the padding if missing, for semplicity + string += "==".slice(2 - (string.length & 3)); + var bitmap, result = "", r1, r2, i = 0; + for (; i < string.length;) { + bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12 + | (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++))); + + result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255) + : r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255) + : String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255); + } + return result; + }; +}); \ No newline at end of file diff --git a/hotgo-uniapp/common/config.js b/hotgo-uniapp/common/config.js new file mode 100644 index 0000000..9b5cb13 --- /dev/null +++ b/hotgo-uniapp/common/config.js @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +const config = { + + // 产品名称 + productName: 'JeeSite Mobile', + + // 公司名称 + companyName: 'ThinkGem', + + // 产品版本号 + productVersion: 'V4.3.2', + + // 版本检查标识 + appCode: 'android', + + // 内部版本号码 + appVersion: 1, + + // 管理基础路径 + adminPath: '' + +} + +// 设置后台接口服务的基础地址 +config.baseUrl = 'http://localhost:8299/api'; + +// 建议:打开下面注释,方便根据环境,自动设定服务地址 +if (process.env.NODE_ENV === 'development'){ + // config.baseUrl = '/../js'; // 代理模式 vue.config.js 中找到 devServer 设置的地址 + // config.baseUrl = 'http://127.0.0.1:8980/js'; +} + +export default config; \ No newline at end of file diff --git a/hotgo-uniapp/common/http.api.js b/hotgo-uniapp/common/http.api.js new file mode 100644 index 0000000..dfaa2c5 --- /dev/null +++ b/hotgo-uniapp/common/http.api.js @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +// 此处第二个参数vm,就是我们在页面使用的this,你可以通过vm获取vuex等操作 +const install = (Vue, vm) => { + + // 参数配置对象 + const config = vm.vuex_config; + + // 将各个定义的接口名称,统一放进对象挂载到vm.$u.api(因为vm就是this,也即this.$u.api)下 + vm.$u.api = { + /** 登录 */ + loginCheck: (params = {}) => vm.$u.get(config.adminPath + '/login/check', params), + login: (params = {}) => vm.$u.post(config.adminPath + '/login/sign', params), + logout: (params = {}) => vm.$u.get(config.adminPath + '/login/logout', params), + + /** 会员 */ + memberProfile: (params = {}) => vm.$u.get(config.adminPath + '/member/profile', params), + + // 基础服务:登录登出、身份信息、菜单授权、切换系统、字典数据等 + lang: (params = {}) => vm.$u.get('/base/lang', {'l': params.lang}), + index: (params = {}) => vm.$u.get(config.adminPath + '/index', params), + authInfo: (params = {}) => vm.$u.get(config.adminPath + '/authInfo', params), + menuTree: (params = {}) => vm.$u.get(config.adminPath + '/menuTree', params), + switchSys: (params = {}) => vm.$u.get(config.adminPath + '/switch/' + params.sysCode), + dictData: (params = {}) => vm.$u.get(config.adminPath + '/dict/attribute', params), + + // 账号服务:验证码接口、忘记密码接口、注册账号接口等 + validCode: (params = {}) => vm.$u.getText('/validCode', params), + getFpValidCode: (params = {}) => vm.$u.post('/account/getFpValidCode', params), + savePwdByValidCode: (params = {}) => vm.$u.post('/account/savePwdByValidCode', params), + getRegValidCode: (params = {}) => vm.$u.post('/account/getRegValidCode', params), + saveRegByValidCode: (params = {}) => vm.$u.post('/account/saveRegByValidCode', params), + + // APP公共服务 + upgradeCheck: () => vm.$u.post('/app/upgrade/check', {appCode: config.appCode, appVersion: config.appVersion}), + commentSave: (params = {}) => vm.$u.post('/app/comment/save', params), + + // 个人信息修改 + user: { + infoSaveBase: (params = {}) => vm.$u.post(config.adminPath + '/sys/user/infoSaveBase', params), + infoSavePwd: (params = {}) => vm.$u.post(config.adminPath + '/sys/user/infoSavePwd', params), + infoSavePqa: (params = {}) => vm.$u.post(config.adminPath + '/sys/user/infoSavePqa', params), + }, + + // 员工用户查询 + empUser: { + listData: (params = {}) => vm.$u.get(config.adminPath + '/sys/empUser/listData', params), + }, + + // 组织机构查询 + office: { + treeData: (params = {}) => vm.$u.get(config.adminPath + '/sys/office/treeData', params), + }, + + // 增删改查例子 + testData: { + form: (params = {}) => vm.$u.post(config.adminPath + '/test/testData/form', params), + list: (params = {}) => vm.$u.get(config.adminPath + '/log/list', params), + save: (params = {}) => vm.$u.postJson(config.adminPath + '/test/testData/save', params), + disable: (params = {}) => vm.$u.post(config.adminPath + '/test/testData/disable', params), + enable: (params = {}) => vm.$u.post(config.adminPath + '/test/testData/enable', params), + delete: (params = {}) => vm.$u.post(config.adminPath + '/test/testData/delete', params), + }, + + }; + +} + +export default { + install +} \ No newline at end of file diff --git a/hotgo-uniapp/common/http.interceptor.js b/hotgo-uniapp/common/http.interceptor.js new file mode 100644 index 0000000..58b2a2f --- /dev/null +++ b/hotgo-uniapp/common/http.interceptor.js @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +// 此处第二个参数vm,就是我们在页面使用的this,你可以通过vm获取vuex等操作 +const install = (Vue, vm) => { + + // 通用请求头设定 + const ajaxHeader = 'x-ajax'; + const sessionIdHeader = 'Authorization'; + const rememberMeHeader = 'x-remember'; + + // 请求参数默认配置 + Vue.prototype.$u.http.setConfig({ + baseUrl: vm.vuex_config.baseUrl, + originalData: true, + // 默认头部,http2约定header名称统一小写 ThinkGem + header: { + 'content-type': 'application/x-www-form-urlencoded', + 'x-requested-with': 'XMLHttpRequest' + } + }); + + // 请求拦截,配置Token等参数 + Vue.prototype.$u.http.interceptor.request = (req) => { + + if (!req.header) { + req.header = []; + } + + // 默认指定返回 JSON 数据 + if (!req.header[ajaxHeader]) { + req.header[ajaxHeader] = 'json'; + } + + // 设定传递 Token 认证参数 ThinkGem + if (!req.header[sessionIdHeader] && vm.vuex_token) { + req.header[sessionIdHeader] = 'Bearer ' + vm.vuex_token; + } + + // 为节省流量,记住我数据不是每次都发送的,当会话失效后,尝试重试登录 ThinkGem + if (!req.header[rememberMeHeader] && vm.vuex_remember && req.remember) { + req.header[rememberMeHeader] = vm.vuex_remember; + req.remember = false; + } + + // console.log('request', req); + return req; + } + + // 响应拦截,判断状态码是否通过 + Vue.prototype.$u.http.interceptor.response = async (res, req) => { + + // console.log('拦截器response:' + JSON.stringify(res)) + // console.log('options:' + JSON.stringify(req)) + let data = res.data; + if (!(data)) { + vm.$u.toast('未连接到服务器'); + return false; + } + + if (typeof data === 'object') { + // 异常接管 + if (data.code === 61) { + this.$u.toast('请重新登录'); + setTimeout(() => { + uni.reLaunch({ + url: '/pages/sys/login/index' + }); + }, 500); + return + } + if (data.code === -1 || data.code >= 50 && data.code <= 70) { + this.$u.toast(data.message); + return + } + // 登录 + if (req.url.indexOf("/api/login/sign") !== -1) { + vm.$u.vuex('vuex_token', data.data.token); + vm.$u.vuex('vuex_user', data.data); + } + + if (data.result === 'login') { + vm.$u.vuex('vuex_token', ''); + vm.$u.vuex('vuex_user', {}); + if (req.tryagain === undefined || req.tryagain) { + req.tryagain = false; + req.remember = true; + await vm.$u.http.request(req).then(res => { + data = res; + }); + } + if (data.result === 'login') { + if (!req.data.loginCheck) { + vm.$u.toast(data.message); + } + req.tryagain = true; + } + } + } + + if (res.header && res.header[rememberMeHeader]) { + let remember = res.header[rememberMeHeader]; + if (remember && remember !== 'deleteMe') { + vm.$u.vuex('vuex_remember', remember); + } else { + vm.$u.vuex('vuex_remember', ''); + } + } + + return data; + } + + // 封装 get text 请求 + vm.$u.getText = (url, data = {}, header = {}) => { + return vm.$u.http.request({ + dataType: 'text', + method: 'GET', + url, + header, + data + }) + } + + // 封装 post json 请求 + vm.$u.postJson = (url, data = {}, header = {}) => { + header['content-type'] = 'application/json'; + return vm.$u.http.request({ + url, + method: 'POST', + header, + data + }) + } + +} + +export default { + install +} \ No newline at end of file diff --git a/hotgo-uniapp/common/locales/en.js b/hotgo-uniapp/common/locales/en.js new file mode 100644 index 0000000..62ec621 --- /dev/null +++ b/hotgo-uniapp/common/locales/en.js @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +export default { + common: { + title: 'JeeSite', + }, + nav: { + home: 'Home', + user: 'User', + msg: 'Msg' + }, + login: { + title: 'Login', + placeholderAccount: 'Enter Account', + placeholderPassword: 'Enter Password', + autoLogin: 'Auto Login', + loginButton: 'Login', + logoutButton: 'Logout', + forget: 'Forget Password', + reg: 'Resister Account', + noLogin: 'No Login' + }, + home: { + title: 'Home' + }, + user: { + title: 'User' + }, + msg: { + title: 'Message' + } +} \ No newline at end of file diff --git a/hotgo-uniapp/common/locales/zh_CN.js b/hotgo-uniapp/common/locales/zh_CN.js new file mode 100644 index 0000000..9211c06 --- /dev/null +++ b/hotgo-uniapp/common/locales/zh_CN.js @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +export default { + common: { + title: 'JeeSite', + }, + nav: { + home: '工作台', + user: '用户', + msg: '消息' + }, + login: { + title: '登录', + placeholderAccount: '请输入账号', + placeholderPassword: '请输入密码', + autoLogin: '自动登录', + loginButton: '登录', + logoutButton: '退出登录', + forget: '忘记密码', + reg: '注册账号', + noLogin: '未登录' + }, + home: { + title: '工作台' + }, + user: { + title: '用户中心' + }, + msg: { + title: '消息提醒' + } +} \ No newline at end of file diff --git a/hotgo-uniapp/common/spark-md5.js b/hotgo-uniapp/common/spark-md5.js new file mode 100644 index 0000000..d2bdbbb --- /dev/null +++ b/hotgo-uniapp/common/spark-md5.js @@ -0,0 +1,751 @@ +(function (factory) { + if (typeof exports === 'object') { + // Node/CommonJS + module.exports = factory(); + } else if (typeof define === 'function' && define.amd) { + // AMD + define(factory); + } else { + // Browser globals (with support for web workers) + var glob; + + try { + glob = window; + } catch (e) { + glob = self; + } + + glob.SparkMD5 = factory(); + } +}(function (undefined) { + + 'use strict'; + + /* + * Fastest md5 implementation around (JKM md5). + * Credits: Joseph Myers + * + * @see http://www.myersdaily.org/joseph/javascript/md5-text.html + * @see http://jsperf.com/md5-shootout/7 + */ + + /* this function is much faster, + so if possible we use it. Some IEs + are the only ones I know of that + need the idiotic second function, + generated by an if clause. */ + var add32 = function (a, b) { + return (a + b) & 0xFFFFFFFF; + }, + hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; + + + function cmn(q, a, b, x, s, t) { + a = add32(add32(a, q), add32(x, t)); + return add32((a << s) | (a >>> (32 - s)), b); + } + + function md5cycle(x, k) { + var a = x[0], + b = x[1], + c = x[2], + d = x[3]; + + a += (b & c | ~b & d) + k[0] - 680876936 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[1] - 389564586 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[2] + 606105819 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[3] - 1044525330 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[4] - 176418897 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[5] + 1200080426 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[6] - 1473231341 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[7] - 45705983 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[8] + 1770035416 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[9] - 1958414417 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[10] - 42063 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[11] - 1990404162 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[12] + 1804603682 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[13] - 40341101 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[14] - 1502002290 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[15] + 1236535329 | 0; + b = (b << 22 | b >>> 10) + c | 0; + + a += (b & d | c & ~d) + k[1] - 165796510 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[6] - 1069501632 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[11] + 643717713 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[0] - 373897302 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[5] - 701558691 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[10] + 38016083 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[15] - 660478335 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[4] - 405537848 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[9] + 568446438 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[14] - 1019803690 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[3] - 187363961 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[8] + 1163531501 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[13] - 1444681467 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[2] - 51403784 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[7] + 1735328473 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[12] - 1926607734 | 0; + b = (b << 20 | b >>> 12) + c | 0; + + a += (b ^ c ^ d) + k[5] - 378558 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[8] - 2022574463 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[11] + 1839030562 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[14] - 35309556 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[1] - 1530992060 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[4] + 1272893353 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[7] - 155497632 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[10] - 1094730640 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[13] + 681279174 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[0] - 358537222 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[3] - 722521979 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[6] + 76029189 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[9] - 640364487 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[12] - 421815835 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[15] + 530742520 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[2] - 995338651 | 0; + b = (b << 23 | b >>> 9) + c | 0; + + a += (c ^ (b | ~d)) + k[0] - 198630844 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[5] - 57434055 | 0; + b = (b << 21 |b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[10] - 1051523 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0; + b = (b << 21 |b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[15] - 30611744 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0; + b = (b << 21 |b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[4] - 145523070 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[2] + 718787259 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[9] - 343485551 | 0; + b = (b << 21 | b >>> 11) + c | 0; + + x[0] = a + x[0] | 0; + x[1] = b + x[1] | 0; + x[2] = c + x[2] | 0; + x[3] = d + x[3] | 0; + } + + function md5blk(s) { + var md5blks = [], + i; /* Andy King said do it this way. */ + + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24); + } + return md5blks; + } + + function md5blk_array(a) { + var md5blks = [], + i; /* Andy King said do it this way. */ + + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24); + } + return md5blks; + } + + function md51(s) { + var n = s.length, + state = [1732584193, -271733879, -1732584194, 271733878], + i, + length, + tail, + tmp, + lo, + hi; + + for (i = 64; i <= n; i += 64) { + md5cycle(state, md5blk(s.substring(i - 64, i))); + } + s = s.substring(i - 64); + length = s.length; + tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (i = 0; i < length; i += 1) { + tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3); + } + tail[i >> 2] |= 0x80 << ((i % 4) << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i += 1) { + tail[i] = 0; + } + } + + // Beware that the final length might not fit in 32 bits so we take care of that + tmp = n * 8; + tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); + lo = parseInt(tmp[2], 16); + hi = parseInt(tmp[1], 16) || 0; + + tail[14] = lo; + tail[15] = hi; + + md5cycle(state, tail); + return state; + } + + function md51_array(a) { + var n = a.length, + state = [1732584193, -271733879, -1732584194, 271733878], + i, + length, + tail, + tmp, + lo, + hi; + + for (i = 64; i <= n; i += 64) { + md5cycle(state, md5blk_array(a.subarray(i - 64, i))); + } + + // Not sure if it is a bug, however IE10 will always produce a sub array of length 1 + // containing the last element of the parent array if the sub array specified starts + // beyond the length of the parent array - weird. + // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue + a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0); + + length = a.length; + tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (i = 0; i < length; i += 1) { + tail[i >> 2] |= a[i] << ((i % 4) << 3); + } + + tail[i >> 2] |= 0x80 << ((i % 4) << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i += 1) { + tail[i] = 0; + } + } + + // Beware that the final length might not fit in 32 bits so we take care of that + tmp = n * 8; + tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); + lo = parseInt(tmp[2], 16); + hi = parseInt(tmp[1], 16) || 0; + + tail[14] = lo; + tail[15] = hi; + + md5cycle(state, tail); + + return state; + } + + function rhex(n) { + var s = '', + j; + for (j = 0; j < 4; j += 1) { + s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F]; + } + return s; + } + + function hex(x) { + var i; + for (i = 0; i < x.length; i += 1) { + x[i] = rhex(x[i]); + } + return x.join(''); + } + + // In some cases the fast add32 function cannot be used.. + if (hex(md51('hello')) !== '5d41402abc4b2a76b9719d911017c592') { + add32 = function (x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + }; + } + + // --------------------------------------------------- + + /** + * ArrayBuffer slice polyfill. + * + * @see https://github.com/ttaubert/node-arraybuffer-slice + */ + + if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) { + (function () { + function clamp(val, length) { + val = (val | 0) || 0; + + if (val < 0) { + return Math.max(val + length, 0); + } + + return Math.min(val, length); + } + + ArrayBuffer.prototype.slice = function (from, to) { + var length = this.byteLength, + begin = clamp(from, length), + end = length, + num, + target, + targetArray, + sourceArray; + + if (to !== undefined) { + end = clamp(to, length); + } + + if (begin > end) { + return new ArrayBuffer(0); + } + + num = end - begin; + target = new ArrayBuffer(num); + targetArray = new Uint8Array(target); + + sourceArray = new Uint8Array(this, begin, num); + targetArray.set(sourceArray); + + return target; + }; + })(); + } + + // --------------------------------------------------- + + /** + * Helpers. + */ + + function toUtf8(str) { + if (/[\u0080-\uFFFF]/.test(str)) { + str = unescape(encodeURIComponent(str)); + } + + return str; + } + + function utf8Str2ArrayBuffer(str, returnUInt8Array) { + var length = str.length, + buff = new ArrayBuffer(length), + arr = new Uint8Array(buff), + i; + + for (i = 0; i < length; i += 1) { + arr[i] = str.charCodeAt(i); + } + + return returnUInt8Array ? arr : buff; + } + + function arrayBuffer2Utf8Str(buff) { + return String.fromCharCode.apply(null, new Uint8Array(buff)); + } + + function concatenateArrayBuffers(first, second, returnUInt8Array) { + var result = new Uint8Array(first.byteLength + second.byteLength); + + result.set(new Uint8Array(first)); + result.set(new Uint8Array(second), first.byteLength); + + return returnUInt8Array ? result : result.buffer; + } + + function hexToBinaryString(hex) { + var bytes = [], + length = hex.length, + x; + + for (x = 0; x < length - 1; x += 2) { + bytes.push(parseInt(hex.substr(x, 2), 16)); + } + + return String.fromCharCode.apply(String, bytes); + } + + // --------------------------------------------------- + + /** + * SparkMD5 OOP implementation. + * + * Use this class to perform an incremental md5, otherwise use the + * static methods instead. + */ + + function SparkMD5() { + // call reset to init the instance + this.reset(); + } + + /** + * Appends a string. + * A conversion will be applied if an utf8 string is detected. + * + * @param {String} str The string to be appended + * + * @return {SparkMD5} The instance itself + */ + SparkMD5.prototype.append = function (str) { + // Converts the string to utf8 bytes if necessary + // Then append as binary + this.appendBinary(toUtf8(str)); + + return this; + }; + + /** + * Appends a binary string. + * + * @param {String} contents The binary string to be appended + * + * @return {SparkMD5} The instance itself + */ + SparkMD5.prototype.appendBinary = function (contents) { + this._buff += contents; + this._length += contents.length; + + var length = this._buff.length, + i; + + for (i = 64; i <= length; i += 64) { + md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i))); + } + + this._buff = this._buff.substring(i - 64); + + return this; + }; + + /** + * Finishes the incremental computation, reseting the internal state and + * returning the result. + * + * @param {Boolean} raw True to get the raw string, false to get the hex string + * + * @return {String} The result + */ + SparkMD5.prototype.end = function (raw) { + var buff = this._buff, + length = buff.length, + i, + tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + ret; + + for (i = 0; i < length; i += 1) { + tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3); + } + + this._finish(tail, length); + ret = hex(this._hash); + + if (raw) { + ret = hexToBinaryString(ret); + } + + this.reset(); + + return ret; + }; + + /** + * Resets the internal state of the computation. + * + * @return {SparkMD5} The instance itself + */ + SparkMD5.prototype.reset = function () { + this._buff = ''; + this._length = 0; + this._hash = [1732584193, -271733879, -1732584194, 271733878]; + + return this; + }; + + /** + * Gets the internal state of the computation. + * + * @return {Object} The state + */ + SparkMD5.prototype.getState = function () { + return { + buff: this._buff, + length: this._length, + hash: this._hash.slice() + }; + }; + + /** + * Gets the internal state of the computation. + * + * @param {Object} state The state + * + * @return {SparkMD5} The instance itself + */ + SparkMD5.prototype.setState = function (state) { + this._buff = state.buff; + this._length = state.length; + this._hash = state.hash; + + return this; + }; + + /** + * Releases memory used by the incremental buffer and other additional + * resources. If you plan to use the instance again, use reset instead. + */ + SparkMD5.prototype.destroy = function () { + delete this._hash; + delete this._buff; + delete this._length; + }; + + /** + * Finish the final calculation based on the tail. + * + * @param {Array} tail The tail (will be modified) + * @param {Number} length The length of the remaining buffer + */ + SparkMD5.prototype._finish = function (tail, length) { + var i = length, + tmp, + lo, + hi; + + tail[i >> 2] |= 0x80 << ((i % 4) << 3); + if (i > 55) { + md5cycle(this._hash, tail); + for (i = 0; i < 16; i += 1) { + tail[i] = 0; + } + } + + // Do the final computation based on the tail and length + // Beware that the final length may not fit in 32 bits so we take care of that + tmp = this._length * 8; + tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); + lo = parseInt(tmp[2], 16); + hi = parseInt(tmp[1], 16) || 0; + + tail[14] = lo; + tail[15] = hi; + md5cycle(this._hash, tail); + }; + + /** + * Performs the md5 hash on a string. + * A conversion will be applied if utf8 string is detected. + * + * @param {String} str The string + * @param {Boolean} [raw] True to get the raw string, false to get the hex string + * + * @return {String} The result + */ + SparkMD5.hash = function (str, raw) { + // Converts the string to utf8 bytes if necessary + // Then compute it using the binary function + return SparkMD5.hashBinary(toUtf8(str), raw); + }; + + /** + * Performs the md5 hash on a binary string. + * + * @param {String} content The binary string + * @param {Boolean} [raw] True to get the raw string, false to get the hex string + * + * @return {String} The result + */ + SparkMD5.hashBinary = function (content, raw) { + var hash = md51(content), + ret = hex(hash); + + return raw ? hexToBinaryString(ret) : ret; + }; + + // --------------------------------------------------- + + /** + * SparkMD5 OOP implementation for array buffers. + * + * Use this class to perform an incremental md5 ONLY for array buffers. + */ + SparkMD5.ArrayBuffer = function () { + // call reset to init the instance + this.reset(); + }; + + /** + * Appends an array buffer. + * + * @param {ArrayBuffer} arr The array to be appended + * + * @return {SparkMD5.ArrayBuffer} The instance itself + */ + SparkMD5.ArrayBuffer.prototype.append = function (arr) { + var buff = concatenateArrayBuffers(this._buff.buffer, arr, true), + length = buff.length, + i; + + this._length += arr.byteLength; + + for (i = 64; i <= length; i += 64) { + md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i))); + } + + this._buff = (i - 64) < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0); + + return this; + }; + + /** + * Finishes the incremental computation, reseting the internal state and + * returning the result. + * + * @param {Boolean} raw True to get the raw string, false to get the hex string + * + * @return {String} The result + */ + SparkMD5.ArrayBuffer.prototype.end = function (raw) { + var buff = this._buff, + length = buff.length, + tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + i, + ret; + + for (i = 0; i < length; i += 1) { + tail[i >> 2] |= buff[i] << ((i % 4) << 3); + } + + this._finish(tail, length); + ret = hex(this._hash); + + if (raw) { + ret = hexToBinaryString(ret); + } + + this.reset(); + + return ret; + }; + + /** + * Resets the internal state of the computation. + * + * @return {SparkMD5.ArrayBuffer} The instance itself + */ + SparkMD5.ArrayBuffer.prototype.reset = function () { + this._buff = new Uint8Array(0); + this._length = 0; + this._hash = [1732584193, -271733879, -1732584194, 271733878]; + + return this; + }; + + /** + * Gets the internal state of the computation. + * + * @return {Object} The state + */ + SparkMD5.ArrayBuffer.prototype.getState = function () { + var state = SparkMD5.prototype.getState.call(this); + + // Convert buffer to a string + state.buff = arrayBuffer2Utf8Str(state.buff); + + return state; + }; + + /** + * Gets the internal state of the computation. + * + * @param {Object} state The state + * + * @return {SparkMD5.ArrayBuffer} The instance itself + */ + SparkMD5.ArrayBuffer.prototype.setState = function (state) { + // Convert string to buffer + state.buff = utf8Str2ArrayBuffer(state.buff, true); + + return SparkMD5.prototype.setState.call(this, state); + }; + + SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy; + + SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish; + + /** + * Performs the md5 hash on an array buffer. + * + * @param {ArrayBuffer} arr The array buffer + * @param {Boolean} [raw] True to get the raw string, false to get the hex one + * + * @return {String} The result + */ + SparkMD5.ArrayBuffer.hash = function (arr, raw) { + var hash = md51_array(new Uint8Array(arr)), + ret = hex(hash); + + return raw ? hexToBinaryString(ret) : ret; + }; + + return SparkMD5; +})); diff --git a/hotgo-uniapp/common/vue-i18n.min.js b/hotgo-uniapp/common/vue-i18n.min.js new file mode 100644 index 0000000..8d0a5c0 --- /dev/null +++ b/hotgo-uniapp/common/vue-i18n.min.js @@ -0,0 +1,6 @@ +/*! + * vue-i18n v8.20.0 + * (c) 2020 kazuya kawaguchi + * Released under the MIT License. + */ +var t,e;t=this,e=function(){"use strict";var t=["style","currency","currencyDisplay","useGrouping","minimumIntegerDigits","minimumFractionDigits","maximumFractionDigits","minimumSignificantDigits","maximumSignificantDigits","localeMatcher","formatMatcher","unit"];function e(t,e){"undefined"!=typeof console&&(console.warn("[vue-i18n] "+t),e&&console.warn(e.stack))}var n=Array.isArray;function r(t){return null!==t&&"object"==typeof t}function a(t){return"string"==typeof t}var i=Object.prototype.toString,o="[object Object]";function s(t){return i.call(t)===o}function l(t){return null==t}function c(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];var n=null,a=null;return 1===t.length?r(t[0])||Array.isArray(t[0])?a=t[0]:"string"==typeof t[0]&&(n=t[0]):2===t.length&&("string"==typeof t[0]&&(n=t[0]),(r(t[1])||Array.isArray(t[1]))&&(a=t[1])),{locale:n,params:a}}function u(t){return JSON.parse(JSON.stringify(t))}function h(t,e){return!!~t.indexOf(e)}var f=Object.prototype.hasOwnProperty;function p(t,e){return f.call(t,e)}function m(t){for(var e=arguments,n=Object(t),a=1;a0;)e[n]=arguments[n+1];var r=this.$i18n;return r._t.apply(r,[t,r.locale,r._getMessages(),this].concat(e))},t.prototype.$tc=function(t,e){for(var n=[],r=arguments.length-2;r-- >0;)n[r]=arguments[r+2];var a=this.$i18n;return a._tc.apply(a,[t,a.locale,a._getMessages(),this,e].concat(n))},t.prototype.$te=function(t,e){var n=this.$i18n;return n._te(t,n.locale,n._getMessages(),e)},t.prototype.$d=function(t){for(var e,n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(e=this.$i18n).d.apply(e,[t].concat(n))},t.prototype.$n=function(t){for(var e,n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(e=this.$i18n).n.apply(e,[t].concat(n))}}(F),F.mixin(g),F.directive("t",{bind:w,update:$,unbind:M}),F.component(v.name,v),F.component(k.name,k),F.config.optionMergeStrategies.i18n=function(t,e){return void 0===e?t:e}}var D=function(){this._caches=Object.create(null)};D.prototype.interpolate=function(t,e){if(!e)return[t];var n=this._caches[t];return n||(n=function(t){var e=[],n=0,r="";for(;n0)h--,u=R,f[W]();else{if(h=0,void 0===n)return!1;if(!1===(n=J(n)))return!1;f[j]()}};null!==u;)if("\\"!==(e=t[++c])||!p()){if(a=U(e),(i=(s=z[u])[a]||s.else||E)===E)return;if(u=i[0],(o=f[i[1]])&&(r=void 0===(r=i[2])?e:r,!1===o()))return;if(u===V)return l}}(t))&&(this._cache[t]=e),e||[]},q.prototype.getPathValue=function(t,e){if(!r(t))return null;var n=this.parsePath(e);if(0===n.length)return null;for(var a=n.length,i=t,o=0;o/,Z=/(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g,K=/^@(?:\.([a-z]+))?:/,Q=/[()]/g,Y={upper:function(t){return t.toLocaleUpperCase()},lower:function(t){return t.toLocaleLowerCase()},capitalize:function(t){return""+t.charAt(0).toLocaleUpperCase()+t.substr(1)}},tt=new D,et=function(t){var e=this;void 0===t&&(t={}),!F&&"undefined"!=typeof window&&window.Vue&&I(window.Vue);var n=t.locale||"en-US",r=!1!==t.fallbackLocale&&(t.fallbackLocale||"en-US"),a=t.messages||{},i=t.dateTimeFormats||{},o=t.numberFormats||{};this._vm=null,this._formatter=t.formatter||tt,this._modifiers=t.modifiers||{},this._missing=t.missing||null,this._root=t.root||null,this._sync=void 0===t.sync||!!t.sync,this._fallbackRoot=void 0===t.fallbackRoot||!!t.fallbackRoot,this._formatFallbackMessages=void 0!==t.formatFallbackMessages&&!!t.formatFallbackMessages,this._silentTranslationWarn=void 0!==t.silentTranslationWarn&&t.silentTranslationWarn,this._silentFallbackWarn=void 0!==t.silentFallbackWarn&&!!t.silentFallbackWarn,this._dateTimeFormatters={},this._numberFormatters={},this._path=new q,this._dataListeners=[],this._componentInstanceCreatedListener=t.componentInstanceCreatedListener||null,this._preserveDirectiveContent=void 0!==t.preserveDirectiveContent&&!!t.preserveDirectiveContent,this.pluralizationRules=t.pluralizationRules||{},this._warnHtmlInMessage=t.warnHtmlInMessage||"off",this._postTranslation=t.postTranslation||null,this.getChoiceIndex=function(t,n){var r=Object.getPrototypeOf(e);if(r&&r.getChoiceIndex)return r.getChoiceIndex.call(e,t,n);var a,i;return e.locale in e.pluralizationRules?e.pluralizationRules[e.locale].apply(e,[t,n]):(a=t,i=n,a=Math.abs(a),2===i?a?a>1?1:0:1:a?Math.min(a,2):0)},this._exist=function(t,n){return!(!t||!n)&&(!l(e._path.getPathValue(t,n))||!!t[n])},"warn"!==this._warnHtmlInMessage&&"error"!==this._warnHtmlInMessage||Object.keys(a).forEach(function(t){e._checkLocaleMessage(t,e._warnHtmlInMessage,a[t])}),this._initVM({locale:n,fallbackLocale:r,messages:a,dateTimeFormats:i,numberFormats:o})},nt={vm:{configurable:!0},messages:{configurable:!0},dateTimeFormats:{configurable:!0},numberFormats:{configurable:!0},availableLocales:{configurable:!0},locale:{configurable:!0},fallbackLocale:{configurable:!0},formatFallbackMessages:{configurable:!0},missing:{configurable:!0},formatter:{configurable:!0},silentTranslationWarn:{configurable:!0},silentFallbackWarn:{configurable:!0},preserveDirectiveContent:{configurable:!0},warnHtmlInMessage:{configurable:!0},postTranslation:{configurable:!0}};return et.prototype._checkLocaleMessage=function(t,n,r){var i=function(t,n,r,o){if(s(r))Object.keys(r).forEach(function(e){var a=r[e];s(a)?(o.push(e),o.push("."),i(t,n,a,o),o.pop(),o.pop()):(o.push(e),i(t,n,a,o),o.pop())});else if(Array.isArray(r))r.forEach(function(e,r){s(e)?(o.push("["+r+"]"),o.push("."),i(t,n,e,o),o.pop(),o.pop()):(o.push("["+r+"]"),i(t,n,e,o),o.pop())});else if(a(r)){if(X.test(r)){var l="Detected HTML in message '"+r+"' of keypath '"+o.join("")+"' at '"+n+"'. Consider component interpolation with '' to avoid XSS. See https://bit.ly/2ZqJzkp";"warn"===t?e(l):"error"===t&&function(t,e){"undefined"!=typeof console&&(console.error("[vue-i18n] "+t),e&&console.error(e.stack))}(l)}}};i(n,t,r,[])},et.prototype._initVM=function(t){var e=F.config.silent;F.config.silent=!0,this._vm=new F({data:t}),F.config.silent=e},et.prototype.destroyVM=function(){this._vm.$destroy()},et.prototype.subscribeDataChanging=function(t){this._dataListeners.push(t)},et.prototype.unsubscribeDataChanging=function(t){!function(t,e){if(t.length){var n=t.indexOf(e);if(n>-1)t.splice(n,1)}}(this._dataListeners,t)},et.prototype.watchI18nData=function(){var t=this;return this._vm.$watch("$data",function(){for(var e=t._dataListeners.length;e--;)F.nextTick(function(){t._dataListeners[e]&&t._dataListeners[e].$forceUpdate()})},{deep:!0})},et.prototype.watchLocale=function(){if(!this._sync||!this._root)return null;var t=this._vm;return this._root.$i18n.vm.$watch("locale",function(e){t.$set(t,"locale",e),t.$forceUpdate()},{immediate:!0})},et.prototype.onComponentInstanceCreated=function(t){this._componentInstanceCreatedListener&&this._componentInstanceCreatedListener(t,this)},nt.vm.get=function(){return this._vm},nt.messages.get=function(){return u(this._getMessages())},nt.dateTimeFormats.get=function(){return u(this._getDateTimeFormats())},nt.numberFormats.get=function(){return u(this._getNumberFormats())},nt.availableLocales.get=function(){return Object.keys(this.messages).sort()},nt.locale.get=function(){return this._vm.locale},nt.locale.set=function(t){this._vm.$set(this._vm,"locale",t)},nt.fallbackLocale.get=function(){return this._vm.fallbackLocale},nt.fallbackLocale.set=function(t){this._localeChainCache={},this._vm.$set(this._vm,"fallbackLocale",t)},nt.formatFallbackMessages.get=function(){return this._formatFallbackMessages},nt.formatFallbackMessages.set=function(t){this._formatFallbackMessages=t},nt.missing.get=function(){return this._missing},nt.missing.set=function(t){this._missing=t},nt.formatter.get=function(){return this._formatter},nt.formatter.set=function(t){this._formatter=t},nt.silentTranslationWarn.get=function(){return this._silentTranslationWarn},nt.silentTranslationWarn.set=function(t){this._silentTranslationWarn=t},nt.silentFallbackWarn.get=function(){return this._silentFallbackWarn},nt.silentFallbackWarn.set=function(t){this._silentFallbackWarn=t},nt.preserveDirectiveContent.get=function(){return this._preserveDirectiveContent},nt.preserveDirectiveContent.set=function(t){this._preserveDirectiveContent=t},nt.warnHtmlInMessage.get=function(){return this._warnHtmlInMessage},nt.warnHtmlInMessage.set=function(t){var e=this,n=this._warnHtmlInMessage;if(this._warnHtmlInMessage=t,n!==t&&("warn"===t||"error"===t)){var r=this._getMessages();Object.keys(r).forEach(function(t){e._checkLocaleMessage(t,e._warnHtmlInMessage,r[t])})}},nt.postTranslation.get=function(){return this._postTranslation},nt.postTranslation.set=function(t){this._postTranslation=t},et.prototype._getMessages=function(){return this._vm.messages},et.prototype._getDateTimeFormats=function(){return this._vm.dateTimeFormats},et.prototype._getNumberFormats=function(){return this._vm.numberFormats},et.prototype._warnDefault=function(t,e,n,r,i,o){if(!l(n))return n;if(this._missing){var s=this._missing.apply(null,[t,e,r,i]);if(a(s))return s}if(this._formatFallbackMessages){var u=c.apply(void 0,i);return this._render(e,o,u.params,e)}return e},et.prototype._isFallbackRoot=function(t){return!t&&!l(this._root)&&this._fallbackRoot},et.prototype._isSilentFallbackWarn=function(t){return this._silentFallbackWarn instanceof RegExp?this._silentFallbackWarn.test(t):this._silentFallbackWarn},et.prototype._isSilentFallback=function(t,e){return this._isSilentFallbackWarn(e)&&(this._isFallbackRoot()||t!==this.fallbackLocale)},et.prototype._isSilentTranslationWarn=function(t){return this._silentTranslationWarn instanceof RegExp?this._silentTranslationWarn.test(t):this._silentTranslationWarn},et.prototype._interpolate=function(t,e,n,r,i,o,c){if(!e)return null;var u,h=this._path.getPathValue(e,n);if(Array.isArray(h)||s(h))return h;if(l(h)){if(!s(e))return null;if(!a(u=e[n]))return null}else{if(!a(h))return null;u=h}return(u.indexOf("@:")>=0||u.indexOf("@.")>=0)&&(u=this._link(t,e,u,r,"raw",o,c)),this._render(u,i,o,n)},et.prototype._link=function(t,e,n,r,a,i,o){var s=n,l=s.match(Z);for(var c in l)if(l.hasOwnProperty(c)){var u=l[c],f=u.match(K),p=f[0],m=f[1],_=u.replace(p,"").replace(Q,"");if(h(o,_))return s;o.push(_);var g=this._interpolate(t,e,_,r,"raw"===a?"string":a,"raw"===a?void 0:i,o);if(this._isFallbackRoot(g)){if(!this._root)throw Error("unexpected error");var v=this._root.$i18n;g=v._translate(v._getMessages(),v.locale,v.fallbackLocale,_,r,a,i)}g=this._warnDefault(t,_,g,r,Array.isArray(i)?i:[i],a),this._modifiers.hasOwnProperty(m)?g=this._modifiers[m](g):Y.hasOwnProperty(m)&&(g=Y[m](g)),o.pop(),s=g?s.replace(u,g):s}return s},et.prototype._render=function(t,e,n,r){var i=this._formatter.interpolate(t,n,r);return i||(i=tt.interpolate(t,n,r)),"string"!==e||a(i)?i:i.join("")},et.prototype._appendItemToChain=function(t,e,n){var r=!1;return h(t,e)||(r=!0,e&&(r="!"!==e[e.length-1],e=e.replace(/!/g,""),t.push(e),n&&n[e]&&(r=n[e]))),r},et.prototype._appendLocaleToChain=function(t,e,n){var r,a=e.split("-");do{var i=a.join("-");r=this._appendItemToChain(t,i,n),a.splice(-1,1)}while(a.length&&!0===r);return r},et.prototype._appendBlockToChain=function(t,e,n){for(var r=!0,i=0;i0;)i[o]=arguments[o+4];if(!t)return"";var s=c.apply(void 0,i),l=s.locale||e,u=this._translate(n,l,this.fallbackLocale,t,r,"string",s.params);if(this._isFallbackRoot(u)){if(!this._root)throw Error("unexpected error");return(a=this._root).$t.apply(a,[t].concat(i))}return u=this._warnDefault(l,t,u,r,i,"string"),this._postTranslation&&null!=u&&(u=this._postTranslation(u,t)),u},et.prototype.t=function(t){for(var e,n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(e=this)._t.apply(e,[t,this.locale,this._getMessages(),null].concat(n))},et.prototype._i=function(t,e,n,r,a){var i=this._translate(n,e,this.fallbackLocale,t,r,"raw",a);if(this._isFallbackRoot(i)){if(!this._root)throw Error("unexpected error");return this._root.$i18n.i(t,e,a)}return this._warnDefault(e,t,i,r,[a],"raw")},et.prototype.i=function(t,e,n){return t?(a(e)||(e=this.locale),this._i(t,e,this._getMessages(),null,n)):""},et.prototype._tc=function(t,e,n,r,a){for(var i,o=[],s=arguments.length-5;s-- >0;)o[s]=arguments[s+5];if(!t)return"";void 0===a&&(a=1);var l={count:a,n:a},u=c.apply(void 0,o);return u.params=Object.assign(l,u.params),o=null===u.locale?[u.params]:[u.locale,u.params],this.fetchChoice((i=this)._t.apply(i,[t,e,n,r].concat(o)),a)},et.prototype.fetchChoice=function(t,e){if(!t&&!a(t))return null;var n=t.split("|");return n[e=this.getChoiceIndex(e,n.length)]?n[e].trim():t},et.prototype.tc=function(t,e){for(var n,r=[],a=arguments.length-2;a-- >0;)r[a]=arguments[a+2];return(n=this)._tc.apply(n,[t,this.locale,this._getMessages(),null,e].concat(r))},et.prototype._te=function(t,e,n){for(var r=[],a=arguments.length-3;a-- >0;)r[a]=arguments[a+3];var i=c.apply(void 0,r).locale||e;return this._exist(n[i],t)},et.prototype.te=function(t,e){return this._te(t,this.locale,this._getMessages(),e)},et.prototype.getLocaleMessage=function(t){return u(this._vm.messages[t]||{})},et.prototype.setLocaleMessage=function(t,e){"warn"!==this._warnHtmlInMessage&&"error"!==this._warnHtmlInMessage||this._checkLocaleMessage(t,this._warnHtmlInMessage,e),this._vm.$set(this._vm.messages,t,e)},et.prototype.mergeLocaleMessage=function(t,e){"warn"!==this._warnHtmlInMessage&&"error"!==this._warnHtmlInMessage||this._checkLocaleMessage(t,this._warnHtmlInMessage,e),this._vm.$set(this._vm.messages,t,m({},this._vm.messages[t]||{},e))},et.prototype.getDateTimeFormat=function(t){return u(this._vm.dateTimeFormats[t]||{})},et.prototype.setDateTimeFormat=function(t,e){this._vm.$set(this._vm.dateTimeFormats,t,e),this._clearDateTimeFormat(t,e)},et.prototype.mergeDateTimeFormat=function(t,e){this._vm.$set(this._vm.dateTimeFormats,t,m(this._vm.dateTimeFormats[t]||{},e)),this._clearDateTimeFormat(t,e)},et.prototype._clearDateTimeFormat=function(t,e){for(var n in e){var r=t+"__"+n;this._dateTimeFormatters.hasOwnProperty(r)&&delete this._dateTimeFormatters[r]}},et.prototype._localizeDateTime=function(t,e,n,r,a){for(var i=e,o=r[i],s=this._getLocaleChain(e,n),c=0;c0;)e[n]=arguments[n+1];var i=this.locale,o=null;return 1===e.length?a(e[0])?o=e[0]:r(e[0])&&(e[0].locale&&(i=e[0].locale),e[0].key&&(o=e[0].key)):2===e.length&&(a(e[0])&&(o=e[0]),a(e[1])&&(i=e[1])),this._d(t,i,o)},et.prototype.getNumberFormat=function(t){return u(this._vm.numberFormats[t]||{})},et.prototype.setNumberFormat=function(t,e){this._vm.$set(this._vm.numberFormats,t,e),this._clearNumberFormat(t,e)},et.prototype.mergeNumberFormat=function(t,e){this._vm.$set(this._vm.numberFormats,t,m(this._vm.numberFormats[t]||{},e)),this._clearNumberFormat(t,e)},et.prototype._clearNumberFormat=function(t,e){for(var n in e){var r=t+"__"+n;this._numberFormatters.hasOwnProperty(r)&&delete this._numberFormatters[r]}},et.prototype._getNumberFormatter=function(t,e,n,r,a,i){for(var o=e,s=r[o],c=this._getLocaleChain(e,n),u=0;u0;)n[i]=arguments[i+1];var o=this.locale,s=null,l=null;return 1===n.length?a(n[0])?s=n[0]:r(n[0])&&(n[0].locale&&(o=n[0].locale),n[0].key&&(s=n[0].key),l=Object.keys(n[0]).reduce(function(e,r){var a;return h(t,r)?Object.assign({},e,((a={})[r]=n[0][r],a)):e},null)):2===n.length&&(a(n[0])&&(s=n[0]),a(n[1])&&(o=n[1])),this._n(e,o,s,l)},et.prototype._ntp=function(t,e,n,r){if(!et.availabilities.numberFormat)return[];if(!n)return(r?new Intl.NumberFormat(e,r):new Intl.NumberFormat(e)).formatToParts(t);var a=this._getNumberFormatter(t,e,this.fallbackLocale,this._getNumberFormats(),n,r),i=a&&a.formatToParts(t);if(this._isFallbackRoot(i)){if(!this._root)throw Error("unexpected error");return this._root.$i18n._ntp(t,e,n,r)}return i||[]},Object.defineProperties(et.prototype,nt),Object.defineProperty(et,"availabilities",{get:function(){if(!G){var t="undefined"!=typeof Intl;G={dateTimeFormat:t&&void 0!==Intl.DateTimeFormat,numberFormat:t&&void 0!==Intl.NumberFormat}}return G}}),et.install=I,et.version="8.20.0",et},"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueI18n=e(); \ No newline at end of file diff --git a/hotgo-uniapp/components/js-checkbox/js-checkbox.vue b/hotgo-uniapp/components/js-checkbox/js-checkbox.vue new file mode 100644 index 0000000..f77af46 --- /dev/null +++ b/hotgo-uniapp/components/js-checkbox/js-checkbox.vue @@ -0,0 +1,102 @@ + + + diff --git a/hotgo-uniapp/components/js-lang/js-lang.vue b/hotgo-uniapp/components/js-lang/js-lang.vue new file mode 100644 index 0000000..139b365 --- /dev/null +++ b/hotgo-uniapp/components/js-lang/js-lang.vue @@ -0,0 +1,69 @@ + + + diff --git a/hotgo-uniapp/components/js-radio/js-radio.vue b/hotgo-uniapp/components/js-radio/js-radio.vue new file mode 100644 index 0000000..bd7513b --- /dev/null +++ b/hotgo-uniapp/components/js-radio/js-radio.vue @@ -0,0 +1,93 @@ + + + diff --git a/hotgo-uniapp/components/js-select/js-select.vue b/hotgo-uniapp/components/js-select/js-select.vue new file mode 100644 index 0000000..f460c97 --- /dev/null +++ b/hotgo-uniapp/components/js-select/js-select.vue @@ -0,0 +1,215 @@ + + + diff --git a/hotgo-uniapp/components/js-uploadfile/js-uploadfile.vue b/hotgo-uniapp/components/js-uploadfile/js-uploadfile.vue new file mode 100644 index 0000000..68fecff --- /dev/null +++ b/hotgo-uniapp/components/js-uploadfile/js-uploadfile.vue @@ -0,0 +1,278 @@ + + + diff --git a/hotgo-uniapp/h5.html b/hotgo-uniapp/h5.html new file mode 100644 index 0000000..c8e298b --- /dev/null +++ b/hotgo-uniapp/h5.html @@ -0,0 +1,50 @@ + + + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + + + + + + + + + + + +
+ + + + diff --git a/hotgo-uniapp/main.js b/hotgo-uniapp/main.js new file mode 100644 index 0000000..b81e8ef --- /dev/null +++ b/hotgo-uniapp/main.js @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +import Vue from 'vue'; +import App from './App'; + +Vue.config.productionTip = false; + +App.mpType = 'app'; + +// 引入全局 uView 框架 +import uView from 'uview-ui'; +Vue.use(uView); + +// 全局存储 vuex 的封装 +import store from '@/store'; + +// 引入 uView 提供的对 vuex 的简写法文件 +let vuexStore = require('@/store/$u.mixin.js'); +Vue.mixin(vuexStore); + +// 引入 uView 对小程序分享的 mixin 封装 +let mpShare = require('uview-ui/libs/mixin/mpShare.js'); +Vue.mixin(mpShare); + +// Vue i18n 国际化 +import VueI18n from '@/common/vue-i18n.min.js'; +Vue.use(VueI18n); + +// i18n 部分的配置,引入语言包,注意路径 +import lang_zh_CN from '@/common/locales/zh_CN.js'; +import lang_en from '@/common/locales/en.js'; + +const i18n = new VueI18n({ + // 默认语言 + locale: 'zh_CN', + // 引入语言文件 + messages: { + 'zh_CN': lang_zh_CN, + 'en': lang_en, + } +}); + +// 由于微信小程序的运行机制问题,需声明如下一行,H5和APP非必填 +Vue.prototype._i18n = i18n; +const app = new Vue({ + i18n, + store, + ...App +}); + +// http 拦截器,将此部分放在 new Vue() 和 app.$mount() 之间,才能 App.vue 中正常使用 +import httpInterceptor from '@/common/http.interceptor.js'; +Vue.use(httpInterceptor, app); + +// http 接口 API 抽离,免于写 url 或者一些固定的参数 +import httpApi from '@/common/http.api.js'; +Vue.use(httpApi, app); + +app.$mount(); diff --git a/hotgo-uniapp/manifest.json b/hotgo-uniapp/manifest.json new file mode 100644 index 0000000..47c8a4d --- /dev/null +++ b/hotgo-uniapp/manifest.json @@ -0,0 +1,158 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +{ + "name": "JeeSite", + "appid": "__UNI__841DCAE", + "description": "JeeSite快速开发平台", + "versionName": "4.3.2", + "versionCode": "100", + "transformPx": false, + "app-plus": { + // APP-VUE分包,可提APP升启动速度,2.7.12开始支持,兼容微信小程序分包方案,默认关闭 + "optimization": { + "subPackages": true + }, + "safearea": { + "bottom": { + "offset": "none" + } + }, + "splashscreen": { + "alwaysShowBeforeRender": true, + "waiting": true, + "autoclose": true, + "delay": 0 + }, + "usingComponents": true, + "nvueCompiler": "uni-app", + "compilerVersion": 3, + "modules": {}, + "distribute": { + "android": { + "permissions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "abiFilters": ["armeabi-v7a", "arm64-v8a"] + }, + "ios": {}, + "sdkConfigs": { + "ad": {}, + "oauth": {} + }, + "icons": { + "android": { + "hdpi": "unpackage/res/icons/72x72.png", + "xhdpi": "unpackage/res/icons/96x96.png", + "xxhdpi": "unpackage/res/icons/144x144.png", + "xxxhdpi": "unpackage/res/icons/192x192.png" + }, + "ios": { + "appstore": "unpackage/res/icons/1024x1024.png", + "ipad": { + "app": "unpackage/res/icons/76x76.png", + "app@2x": "unpackage/res/icons/152x152.png", + "notification": "unpackage/res/icons/20x20.png", + "notification@2x": "unpackage/res/icons/40x40.png", + "proapp@2x": "unpackage/res/icons/167x167.png", + "settings": "unpackage/res/icons/29x29.png", + "settings@2x": "unpackage/res/icons/58x58.png", + "spotlight": "unpackage/res/icons/40x40.png", + "spotlight@2x": "unpackage/res/icons/80x80.png" + }, + "iphone": { + "app@2x": "unpackage/res/icons/120x120.png", + "app@3x": "unpackage/res/icons/180x180.png", + "notification@2x": "unpackage/res/icons/40x40.png", + "notification@3x": "unpackage/res/icons/60x60.png", + "settings@2x": "unpackage/res/icons/58x58.png", + "settings@3x": "unpackage/res/icons/87x87.png", + "spotlight@2x": "unpackage/res/icons/80x80.png", + "spotlight@3x": "unpackage/res/icons/120x120.png" + } + } + }, + "splashscreen": { + "androidStyle": "common" + } + } + }, + "quickapp": {}, + "mp-weixin": { + "appid": "wx335f34af8ccb4131", + "setting": { + "urlCheck": true, + "es6": false, + "minified": true, + "postcss": true + }, + "optimization": { + "subPackages": true + }, + "usingComponents": true + }, + "mp-alipay": { + "usingComponents": true, + "component2": true + }, + "mp-qq": { + "optimization": { + "subPackages": true + }, + "appid": "" + }, + "mp-baidu": { + "usingComponents": true, + "appid": "" + }, + "mp-toutiao": { + "usingComponents": true, + "appid": "" + }, + "h5": { + "devServer": { + "port": 8080, //这边填当前项目的编译端口,编译时直接使用此端口,也是代理端口 + "disableHostCheck": true, //vue关闭主机检查 + "proxy": { + "/api": { //代理API域名的路径 + "target": "http://localhost:8299/api", //代理API域名地址+端口+路径 + "changeOrigin": true, //是否跨域 + "secure": false, //ssl,如果是https要更改为:true + "pathRewrite":{"^/api":""} //代理请求时的重写路径,和"/api2"、"/api2".target保持一致即可 + } + } + }, + "template": "h5.html", + "router": { + "mode": "hash", + "base": "/app" + }, + "optimization": { + "treeShaking": { + "enable": false + } + }, + "title": "JeeSite", + "domain": "/app" + } +} diff --git a/hotgo-uniapp/package-lock.json b/hotgo-uniapp/package-lock.json new file mode 100644 index 0000000..e6ec137 --- /dev/null +++ b/hotgo-uniapp/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "JeeSite4", + "version": "4.3.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "vue-i18n": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.20.0.tgz", + "integrity": "sha512-ZiAOoeR4d/JtKpbjipx3I80ey7cYG1ki5gQ7HwzWm4YFio9brA15BEYHjalEoBaEfzF5OBEZP+Y2MvAaWnyXXg==" + } + } +} diff --git a/hotgo-uniapp/package.json b/hotgo-uniapp/package.json new file mode 100644 index 0000000..cb3711e --- /dev/null +++ b/hotgo-uniapp/package.json @@ -0,0 +1,26 @@ +{ + "name": "JeeSite4", + "version": "4.3.0", + "description": "JeeSite4 移动端快速开发框架", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://gitee.com/thinkgem/jeesite4-uniapp.git" + }, + "keywords": [ + "JeeSite", + "快速开发平台" + ], + "author": "ThinkGem", + "license": "MIT", + "bugs": { + "url": "https://github.com/thinkgem/jeesite4-uniapp/issues" + }, + "homepage": "https://github.com/thinkgem/jeesite4-uniapp#readme", + "dependencies": { + "vue-i18n": "^8.20.0" + } +} diff --git a/hotgo-uniapp/pages.json b/hotgo-uniapp/pages.json new file mode 100644 index 0000000..69089ae --- /dev/null +++ b/hotgo-uniapp/pages.json @@ -0,0 +1,160 @@ +{ + "easycom": { + "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue" + }, + "pages": [ + + /* 登录 */ + { + "path": "pages/sys/login/index", + "style": { + "navigationBarTitleText": "登录" + } + }, + { + "path": "pages/sys/login/forget", + "style": { + "navigationBarTitleText": "忘记密码" + } + }, + { + "path": "pages/sys/login/reg", + "style": { + "navigationBarTitleText": "注册账号" + } + }, + + /* 主页 */ + { + "path": "pages/sys/home/index", + "style": { + "navigationBarTitleText": "工作台" + } + }, + + /* 用户 */ + { + "path": "pages/sys/user/index", + "style": { + "navigationBarTitleText": "用户中心", + "backgroundColor": "#f8f8f8", + "navigationBarBackgroundColor":"#f8f8f8" + } + }, + { + "path": "pages/sys/user/info", + "style": { + "navigationBarTitleText": "个人信息" + } + }, + { + "path": "uview-ui/components/u-avatar-cropper/u-avatar-cropper", + "style": { + "navigationBarTitleText": "头像裁剪", + "navigationBarBackgroundColor": "#000000" + } + }, + { + "path": "pages/sys/user/help", + "style": { + "navigationBarTitleText": "帮助中心" + } + }, + { + "path": "pages/sys/user/pwd", + "style": { + "navigationBarTitleText": "修改密码" + } + }, + { + "path": "pages/sys/user/setting", + "style": { + "navigationBarTitleText": "系统设置" + } + }, + { + "path": "pages/sys/user/comment", + "style": { + "navigationBarTitleText": "意见反馈" + } + }, + { + "path": "pages/sys/user/about", + "style": { + "navigationBarTitleText": "关于我们" + } + }, + + /* 消息 */ + { + "path": "pages/sys/msg/index", + "style": { + "navigationBarTitleText": "消息提醒" + } + }, + { + "path": "pages/sys/msg/form", + "style": { + "navigationBarTitleText": "查看详情" + } + }, + + /* 增删改查例子 */ + { + "path": "pages/testData/form", + "style": { + "navigationBarTitleText": "新增编辑" + } + }, + { + "path": "pages/testData/index", + "style": { + "navigationBarTitleText": "增删改查" + } + }, + + /* Common */ + { + "path": "pages/common/webview", + "style": { + "navigationBarTitleText": "浏览网页" + } + } + ], + "subPackages": [ + + ], + "preloadRule": { + + }, + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "JeeSite", + "navigationBarBackgroundColor": "#f8f8f8" + }, + "tabBar": { + "color": "#909399", + "selectedColor": "#303133", + "backgroundColor": "#ffffff", + "borderStyle": "white", + "list": [{ + "pagePath": "pages/sys/msg/index", + "iconPath": "static/jeesite/tabbar/msg_1.png", + "selectedIconPath": "static/jeesite/tabbar/msg_2.png", + "text": "消息" + }, + { + "pagePath": "pages/sys/home/index", + "iconPath": "static/jeesite/tabbar/home_1.png", + "selectedIconPath": "static/jeesite/tabbar/home_2.png", + "text": "工作台" + }, + { + "pagePath": "pages/sys/user/index", + "iconPath": "static/jeesite/tabbar/my_1.png", + "selectedIconPath": "static/jeesite/tabbar/my_2.png", + "text": "我的" + } + ] + } +} diff --git a/hotgo-uniapp/pages/common/jeesite.scss b/hotgo-uniapp/pages/common/jeesite.scss new file mode 100644 index 0000000..b974afe --- /dev/null +++ b/hotgo-uniapp/pages/common/jeesite.scss @@ -0,0 +1,121 @@ +/*! + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + * @author ThinkGem + * @version 2020-9-1 + */ +.u-btn { + &--info { + color: #ffffff; + border-color: #01abb4; + background-color: #01abb4; + } + &--purple { + color: #ffffff; + border-color: #5d5fe7; + background-color: #5d5fe7; + } +} + +.u-cell-box { + + .u-cell { + font-size: 30rpx; + } + + .u-cell_title { + font-size: 30rpx; + } + + .u-cell__left-icon-wrap { + margin-right: 18rpx; + } +} + +.search{ + padding: 20rpx 20rpx 0; + background: #f8f8f8; + height: 105rpx; +} + +.scroll-list { + height: calc(100vh - var(--window-top) - var(--window-bottom) - 105rpx); // 105rpx 为 .search 的高度 + width: 100%; + + .loadmore { + padding: 30rpx; + } +} + +.box { + padding-bottom: 10rpx; + + .item { + margin: 0 20rpx 20rpx; + padding: 8rpx 20rpx; + border-radius: 20rpx; + box-sizing: border-box; + background-color: #fff; + font-size: 28rpx; + + .title { + display: flex; + justify-content: space-between; + background-color: #fff; + padding-left: 15rpx; + align-items: center; + + .text { + margin: 0 20rpx; + font-size: 35rpx; + font-weight: bold; + } + + } + } + +} + +.list { + + .u-cell-item-box { + + .u-swipe-content { + width: 750rpx; + } + + .u-cell_title { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + min-width: 655rpx; + } + + .u-border-bottom:after { + border-bottom-width: 0; + } + + } + +} + +.form { + display: flex; + flex-direction: column; + padding: 20rpx 30rpx; + + .u-cell-item-box { + border-radius: 20rpx; + } +} + +.form-footer { + display: flex; + margin: 10rpx; + padding-bottom: 30rpx; + + .btn { + flex: 1; + margin: 20rpx; + margin-bottom: 10rpx; + } +} diff --git a/hotgo-uniapp/pages/common/webview.vue b/hotgo-uniapp/pages/common/webview.vue new file mode 100644 index 0000000..f7c6bfa --- /dev/null +++ b/hotgo-uniapp/pages/common/webview.vue @@ -0,0 +1,33 @@ + + + diff --git a/hotgo-uniapp/pages/sys/home/index.scss b/hotgo-uniapp/pages/sys/home/index.scss new file mode 100644 index 0000000..81bcf0d --- /dev/null +++ b/hotgo-uniapp/pages/sys/home/index.scss @@ -0,0 +1,22 @@ +/*! + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + * @author ThinkGem + * @version 2020-9-1 + */ + +.toolbar { + padding-top: 5px; + background-color: #fff; +} + +.grid { + + .grid-icon { + color: #666; + } + + .grid-text { + font-size: 32rpx; + padding: 15rpx; + } +} \ No newline at end of file diff --git a/hotgo-uniapp/pages/sys/home/index.vue b/hotgo-uniapp/pages/sys/home/index.vue new file mode 100644 index 0000000..bb0b2c6 --- /dev/null +++ b/hotgo-uniapp/pages/sys/home/index.vue @@ -0,0 +1,225 @@ + + + diff --git a/hotgo-uniapp/pages/sys/login/forget.vue b/hotgo-uniapp/pages/sys/login/forget.vue new file mode 100644 index 0000000..21eb89b --- /dev/null +++ b/hotgo-uniapp/pages/sys/login/forget.vue @@ -0,0 +1,144 @@ + + + diff --git a/hotgo-uniapp/pages/sys/login/index.scss b/hotgo-uniapp/pages/sys/login/index.scss new file mode 100644 index 0000000..e0b730f --- /dev/null +++ b/hotgo-uniapp/pages/sys/login/index.scss @@ -0,0 +1,81 @@ +/*! + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + * @author ThinkGem + * @version 2020-9-1 + */ +.wrap { + display: flex; + flex-direction: column; + justify-content: center; +} + +.list { + display: flex; + flex-direction: column; + padding: 40rpx 70rpx 40rpx 70rpx; +} + +.list-call { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding-top: 10rpx; + height: 120rpx; + font-weight: normal; + color: #333333; + border-bottom: 0.5px solid #e2e2e2; +} + +.list-call .u-input { + flex: 1; + font-size: 39rpx; + text-align: left; + margin-left: 16rpx; +} + +.list-call .u-icon-right { + color: #aaaaaa; + width: 50rpx; + height: 40rpx; +} + +.button { + color: #ffffff; + font-size: 39rpx; + width: 470rpx; + height: 100rpx; + background: linear-gradient(-90deg, rgba(72, 156, 230, 1), rgba(15, 168, 250, 1)); + box-shadow: 0rpx 0rpx 13rpx 0rpx rgba(15, 168, 250, 0.4); + border-radius: 50rpx; + line-height: 100rpx; + text-align: center; + margin: 50rpx auto 0; +} + +.button-hover { + background: linear-gradient(-90deg, rgba(72, 156, 230, 0.8), rgba(15, 168, 250, 0.8)); +} + +.img-valid-code img { + width: 30rpx; + heigth: 50rpx; +} + +.btn-valid-code { + color: #da7918; + font-size: 40rpx; + line-height: 60rpx; + padding: 0 35rpx; + border: 1rpx solid #da7918; + border-radius: 50rpx; +} + +.btn-valid-code-hover { + background-color: #f3f3f3; +} + +.btn-valid-codes { + color: #999999 !important; + border: 1rpx solid #999999; +} diff --git a/hotgo-uniapp/pages/sys/login/index.vue b/hotgo-uniapp/pages/sys/login/index.vue new file mode 100644 index 0000000..1359901 --- /dev/null +++ b/hotgo-uniapp/pages/sys/login/index.vue @@ -0,0 +1,192 @@ + + + diff --git a/hotgo-uniapp/pages/sys/login/reg.vue b/hotgo-uniapp/pages/sys/login/reg.vue new file mode 100644 index 0000000..edb5b5e --- /dev/null +++ b/hotgo-uniapp/pages/sys/login/reg.vue @@ -0,0 +1,187 @@ + + + diff --git a/hotgo-uniapp/pages/sys/msg/form.vue b/hotgo-uniapp/pages/sys/msg/form.vue new file mode 100644 index 0000000..23b25ab --- /dev/null +++ b/hotgo-uniapp/pages/sys/msg/form.vue @@ -0,0 +1,77 @@ + + + diff --git a/hotgo-uniapp/pages/sys/msg/index.vue b/hotgo-uniapp/pages/sys/msg/index.vue new file mode 100644 index 0000000..0aad943 --- /dev/null +++ b/hotgo-uniapp/pages/sys/msg/index.vue @@ -0,0 +1,163 @@ + + + diff --git a/hotgo-uniapp/pages/sys/user/about.vue b/hotgo-uniapp/pages/sys/user/about.vue new file mode 100644 index 0000000..0d4e21b --- /dev/null +++ b/hotgo-uniapp/pages/sys/user/about.vue @@ -0,0 +1,78 @@ + + + diff --git a/hotgo-uniapp/pages/sys/user/comment.vue b/hotgo-uniapp/pages/sys/user/comment.vue new file mode 100644 index 0000000..2f83965 --- /dev/null +++ b/hotgo-uniapp/pages/sys/user/comment.vue @@ -0,0 +1,98 @@ + + + diff --git a/hotgo-uniapp/pages/sys/user/help.vue b/hotgo-uniapp/pages/sys/user/help.vue new file mode 100644 index 0000000..344c65e --- /dev/null +++ b/hotgo-uniapp/pages/sys/user/help.vue @@ -0,0 +1,106 @@ + + + diff --git a/hotgo-uniapp/pages/sys/user/index.scss b/hotgo-uniapp/pages/sys/user/index.scss new file mode 100644 index 0000000..7b95ae7 --- /dev/null +++ b/hotgo-uniapp/pages/sys/user/index.scss @@ -0,0 +1,98 @@ +/*! + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + * @author ThinkGem + * @version 2020-9-1 + */ +.header { + background-color: #4094ff; + + .userinfo { + display: flex; + padding: 40rpx; + + .image { + flex-shrink: 0; + width: 120rpx; + height: 120rpx; + image { + border-radius: 100%; + width: 100%; + height: 100%; + } + } + + .info { + display: flex; + flex-flow: wrap; + padding-left: 30rpx; + color: #fff; + + .username { + width: 100%; + font-size: 40rpx; + padding-top: 8rpx; + } + + .usercode { + height: 48rpx; + padding: 0 20rpx; + margin-top: 10rpx; + background-color: rgba(0, 0, 0, 0.1); + border-radius: 20rpx; + font-size: 30rpx; + } + } + } + + .logout { + flex-shrink: 0; + position: absolute; + right: 70rpx; + top: 65rpx; + .u-btn { + font-size: 30rpx; + } + } +} + +.toolbar { + padding: 0 4%; + margin-bottom: 5rpx; + border-radius: 0 0 100% 100%; + background-color: #4094ff; + + .box { + display: flex; + flex-direction: row; + justify-content: space-around; + padding: 10rpx; + border-radius: 15rpx; + box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.15); + background-color: #fefefe; + + .item { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + // flex-flow: wrap; + height: 120rpx; + color: #666666; + font-size: 30rpx; + padding: 10rpx 10rpx; + + .icon { + font-size: 50rpx; + } + + .label { + padding: 10rpx; + } + } + + .hover { + background-color: #f6f6f6; + border-radius: 15rpx; + } + } +} diff --git a/hotgo-uniapp/pages/sys/user/index.vue b/hotgo-uniapp/pages/sys/user/index.vue new file mode 100644 index 0000000..2140c74 --- /dev/null +++ b/hotgo-uniapp/pages/sys/user/index.vue @@ -0,0 +1,128 @@ + + + diff --git a/hotgo-uniapp/pages/sys/user/info.vue b/hotgo-uniapp/pages/sys/user/info.vue new file mode 100644 index 0000000..491045a --- /dev/null +++ b/hotgo-uniapp/pages/sys/user/info.vue @@ -0,0 +1,224 @@ + + + diff --git a/hotgo-uniapp/pages/sys/user/pwd.vue b/hotgo-uniapp/pages/sys/user/pwd.vue new file mode 100644 index 0000000..00bc512 --- /dev/null +++ b/hotgo-uniapp/pages/sys/user/pwd.vue @@ -0,0 +1,106 @@ + + + diff --git a/hotgo-uniapp/pages/sys/user/setting.vue b/hotgo-uniapp/pages/sys/user/setting.vue new file mode 100644 index 0000000..a17911f --- /dev/null +++ b/hotgo-uniapp/pages/sys/user/setting.vue @@ -0,0 +1,87 @@ + + + diff --git a/hotgo-uniapp/pages/testData/form.vue b/hotgo-uniapp/pages/testData/form.vue new file mode 100644 index 0000000..2c7a5bc --- /dev/null +++ b/hotgo-uniapp/pages/testData/form.vue @@ -0,0 +1,129 @@ + + + diff --git a/hotgo-uniapp/pages/testData/index.vue b/hotgo-uniapp/pages/testData/index.vue new file mode 100644 index 0000000..ac8dfed --- /dev/null +++ b/hotgo-uniapp/pages/testData/index.vue @@ -0,0 +1,123 @@ + + + diff --git a/hotgo-uniapp/static/common/img/iPhoneX.png b/hotgo-uniapp/static/common/img/iPhoneX.png new file mode 100644 index 0000000..257ba00 Binary files /dev/null and b/hotgo-uniapp/static/common/img/iPhoneX.png differ diff --git a/hotgo-uniapp/static/common/js/touch-emulator.js b/hotgo-uniapp/static/common/js/touch-emulator.js new file mode 100644 index 0000000..9632413 --- /dev/null +++ b/hotgo-uniapp/static/common/js/touch-emulator.js @@ -0,0 +1,363 @@ +(function(window, document, exportName, undefined) { + "use strict"; + + var isMultiTouch = false; + var multiTouchStartPos; + var eventTarget; + var touchElements = {}; + + // polyfills + if(!document.createTouch) { + document.createTouch = function(view, target, identifier, pageX, pageY, screenX, screenY, clientX, clientY) { + // auto set + if(clientX == undefined || clientY == undefined) { + clientX = pageX - window.pageXOffset; + clientY = pageY - window.pageYOffset; + } + + return new Touch(target, identifier, { + pageX: pageX, + pageY: pageY, + screenX: screenX, + screenY: screenY, + clientX: clientX, + clientY: clientY + }); + }; + } + + if(!document.createTouchList) { + document.createTouchList = function() { + var touchList = new TouchList(); + for (var i = 0; i < arguments.length; i++) { + touchList[i] = arguments[i]; + } + touchList.length = arguments.length; + return touchList; + }; + } + + /** + * create an touch point + * @constructor + * @param target + * @param identifier + * @param pos + * @param deltaX + * @param deltaY + * @returns {Object} touchPoint + */ + function Touch(target, identifier, pos, deltaX, deltaY) { + deltaX = deltaX || 0; + deltaY = deltaY || 0; + + this.identifier = identifier; + this.target = target; + this.clientX = pos.clientX + deltaX; + this.clientY = pos.clientY + deltaY; + this.screenX = pos.screenX + deltaX; + this.screenY = pos.screenY + deltaY; + this.pageX = pos.pageX + deltaX; + this.pageY = pos.pageY + deltaY; + } + + /** + * create empty touchlist with the methods + * @constructor + * @returns touchList + */ + function TouchList() { + var touchList = []; + + touchList.item = function(index) { + return this[index] || null; + }; + + // specified by Mozilla + touchList.identifiedTouch = function(id) { + return this[id + 1] || null; + }; + + return touchList; + } + + + /** + * Simple trick to fake touch event support + * this is enough for most libraries like Modernizr and Hammer + */ + function fakeTouchSupport() { + var objs = [window, document.documentElement]; + var props = ['ontouchstart', 'ontouchmove', 'ontouchcancel', 'ontouchend']; + + for(var o=0; o 2; // pointer events + } + + /** + * disable mouseevents on the page + * @param ev + */ + function preventMouseEvents(ev) { + // 注释启用默认事件 + // ev.preventDefault(); + // ev.stopPropagation(); + } + + /** + * only trigger touches when the left mousebutton has been pressed + * @param touchType + * @returns {Function} + */ + function onMouse(touchType) { + return function(ev) { + // prevent mouse events + preventMouseEvents(ev); + + if (ev.which !== 1) { + return; + } + + // The EventTarget on which the touch point started when it was first placed on the surface, + // even if the touch point has since moved outside the interactive area of that element. + // also, when the target doesnt exist anymore, we update it + if (ev.type == 'mousedown' || !eventTarget || (eventTarget && !eventTarget.dispatchEvent)) { + eventTarget = ev.target; + } + + // shiftKey has been lost, so trigger a touchend + if (isMultiTouch && !ev.shiftKey) { + triggerTouch('touchend', ev); + isMultiTouch = false; + } + + triggerTouch(touchType, ev); + + // we're entering the multi-touch mode! + if (!isMultiTouch && ev.shiftKey) { + isMultiTouch = true; + multiTouchStartPos = { + pageX: ev.pageX, + pageY: ev.pageY, + clientX: ev.clientX, + clientY: ev.clientY, + screenX: ev.screenX, + screenY: ev.screenY + }; + triggerTouch('touchstart', ev); + } + + // reset + if (ev.type == 'mouseup') { + multiTouchStartPos = null; + isMultiTouch = false; + eventTarget = null; + } + } + } + + /** + * trigger a touch event + * @param eventName + * @param mouseEv + */ + function triggerTouch(eventName, mouseEv) { + var touchEvent = document.createEvent('Event'); + touchEvent.initEvent(eventName, true, true); + + touchEvent.altKey = mouseEv.altKey; + touchEvent.ctrlKey = mouseEv.ctrlKey; + touchEvent.metaKey = mouseEv.metaKey; + touchEvent.shiftKey = mouseEv.shiftKey; + + touchEvent.touches = getActiveTouches(mouseEv, eventName); + touchEvent.targetTouches = getActiveTouches(mouseEv, eventName); + touchEvent.changedTouches = getChangedTouches(mouseEv, eventName); + + eventTarget.dispatchEvent(touchEvent); + } + + /** + * create a touchList based on the mouse event + * @param mouseEv + * @returns {TouchList} + */ + function createTouchList(mouseEv) { + var touchList = new TouchList(); + + if (isMultiTouch) { + var f = TouchEmulator.multiTouchOffset; + var deltaX = multiTouchStartPos.pageX - mouseEv.pageX; + var deltaY = multiTouchStartPos.pageY - mouseEv.pageY; + + touchList.push(new Touch(eventTarget, 1, multiTouchStartPos, (deltaX*-1) - f, (deltaY*-1) + f)); + touchList.push(new Touch(eventTarget, 2, multiTouchStartPos, deltaX+f, deltaY-f)); + } else { + touchList.push(new Touch(eventTarget, 1, mouseEv, 0, 0)); + } + + return touchList; + } + + /** + * receive all active touches + * @param mouseEv + * @returns {TouchList} + */ + function getActiveTouches(mouseEv, eventName) { + // empty list + if (mouseEv.type == 'mouseup') { + return new TouchList(); + } + + var touchList = createTouchList(mouseEv); + if(isMultiTouch && mouseEv.type != 'mouseup' && eventName == 'touchend') { + touchList.splice(1, 1); + } + return touchList; + } + + /** + * receive a filtered set of touches with only the changed pointers + * @param mouseEv + * @param eventName + * @returns {TouchList} + */ + function getChangedTouches(mouseEv, eventName) { + var touchList = createTouchList(mouseEv); + + // we only want to return the added/removed item on multitouch + // which is the second pointer, so remove the first pointer from the touchList + // + // but when the mouseEv.type is mouseup, we want to send all touches because then + // no new input will be possible + if(isMultiTouch && mouseEv.type != 'mouseup' && + (eventName == 'touchstart' || eventName == 'touchend')) { + touchList.splice(0, 1); + } + + return touchList; + } + + /** + * show the touchpoints on the screen + */ + function showTouches(ev) { + var touch, i, el, styles; + + // first all visible touches + for(i = 0; i < ev.touches.length; i++) { + touch = ev.touches[i]; + el = touchElements[touch.identifier]; + if(!el) { + el = touchElements[touch.identifier] = document.createElement("div"); + document.body.appendChild(el); + } + + styles = TouchEmulator.template(touch); + for(var prop in styles) { + el.style[prop] = styles[prop]; + } + } + + // remove all ended touches + if(ev.type == 'touchend' || ev.type == 'touchcancel') { + for(i = 0; i < ev.changedTouches.length; i++) { + touch = ev.changedTouches[i]; + el = touchElements[touch.identifier]; + if(el) { + el.parentNode.removeChild(el); + delete touchElements[touch.identifier]; + } + } + } + } + + /** + * TouchEmulator initializer + */ + function TouchEmulator() { + if (hasTouchSupport()) { + return; + } + + fakeTouchSupport(); + + window.addEventListener("mousedown", onMouse('touchstart'), true); + window.addEventListener("mousemove", onMouse('touchmove'), true); + window.addEventListener("mouseup", onMouse('touchend'), true); + + window.addEventListener("mouseenter", preventMouseEvents, true); + window.addEventListener("mouseleave", preventMouseEvents, true); + window.addEventListener("mouseout", preventMouseEvents, true); + window.addEventListener("mouseover", preventMouseEvents, true); + + // it uses itself! + window.addEventListener("touchstart", showTouches, true); + window.addEventListener("touchmove", showTouches, true); + window.addEventListener("touchend", showTouches, true); + window.addEventListener("touchcancel", showTouches, true); + } + + // start distance when entering the multitouch mode + TouchEmulator.multiTouchOffset = 75; + + /** + * css template for the touch rendering + * @param touch + * @returns object + */ + TouchEmulator.template = function(touch) { + var size = 0; + var transform = 'translate('+ (touch.clientX-(size/2)) +'px, '+ (touch.clientY-(size/2)) +'px)'; + return { + position: 'fixed', + left: 0, + top: 0, + background: '#fff', + border: 'solid 1px #999', + opacity: .6, + borderRadius: '100%', + height: size + 'px', + width: size + 'px', + padding: 0, + margin: 0, + display: 'block', + overflow: 'hidden', + pointerEvents: 'none', + webkitUserSelect: 'none', + mozUserSelect: 'none', + userSelect: 'none', + webkitTransform: transform, + mozTransform: transform, + transform: transform, + zIndex: 100 + } + }; + + // export + if (typeof define == "function" && define.amd) { + define(function() { + return TouchEmulator; + }); + } else if (typeof module != "undefined" && module.exports) { + module.exports = TouchEmulator; + } else { + window[exportName] = TouchEmulator; + } +})(window, document, "TouchEmulator"); \ No newline at end of file diff --git a/hotgo-uniapp/static/index.html b/hotgo-uniapp/static/index.html new file mode 100644 index 0000000..2a675fa --- /dev/null +++ b/hotgo-uniapp/static/index.html @@ -0,0 +1,52 @@ + + + + + + + + + + JeeSite Mobile APP + + + + +
+
+ +
+
+ + diff --git a/hotgo-uniapp/static/jeesite/banner/1.svg b/hotgo-uniapp/static/jeesite/banner/1.svg new file mode 100644 index 0000000..661ed39 --- /dev/null +++ b/hotgo-uniapp/static/jeesite/banner/1.svg @@ -0,0 +1,843 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hotgo-uniapp/static/jeesite/banner/2.svg b/hotgo-uniapp/static/jeesite/banner/2.svg new file mode 100644 index 0000000..36441bf --- /dev/null +++ b/hotgo-uniapp/static/jeesite/banner/2.svg @@ -0,0 +1,966 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hotgo-uniapp/static/jeesite/banner/3.svg b/hotgo-uniapp/static/jeesite/banner/3.svg new file mode 100644 index 0000000..0bea8cd --- /dev/null +++ b/hotgo-uniapp/static/jeesite/banner/3.svg @@ -0,0 +1,479 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hotgo-uniapp/static/jeesite/favicon.png b/hotgo-uniapp/static/jeesite/favicon.png new file mode 100644 index 0000000..72734e5 Binary files /dev/null and b/hotgo-uniapp/static/jeesite/favicon.png differ diff --git a/hotgo-uniapp/static/jeesite/login/eye_close.png b/hotgo-uniapp/static/jeesite/login/eye_close.png new file mode 100644 index 0000000..66d6ea1 Binary files /dev/null and b/hotgo-uniapp/static/jeesite/login/eye_close.png differ diff --git a/hotgo-uniapp/static/jeesite/login/eye_open.png b/hotgo-uniapp/static/jeesite/login/eye_open.png new file mode 100644 index 0000000..5aaab64 Binary files /dev/null and b/hotgo-uniapp/static/jeesite/login/eye_open.png differ diff --git a/hotgo-uniapp/static/jeesite/logo200.png b/hotgo-uniapp/static/jeesite/logo200.png new file mode 100644 index 0000000..486d1df Binary files /dev/null and b/hotgo-uniapp/static/jeesite/logo200.png differ diff --git a/hotgo-uniapp/static/jeesite/tabbar/home_1.png b/hotgo-uniapp/static/jeesite/tabbar/home_1.png new file mode 100644 index 0000000..6c90ba4 Binary files /dev/null and b/hotgo-uniapp/static/jeesite/tabbar/home_1.png differ diff --git a/hotgo-uniapp/static/jeesite/tabbar/home_2.png b/hotgo-uniapp/static/jeesite/tabbar/home_2.png new file mode 100644 index 0000000..614754d Binary files /dev/null and b/hotgo-uniapp/static/jeesite/tabbar/home_2.png differ diff --git a/hotgo-uniapp/static/jeesite/tabbar/msg_1.png b/hotgo-uniapp/static/jeesite/tabbar/msg_1.png new file mode 100644 index 0000000..87cf395 Binary files /dev/null and b/hotgo-uniapp/static/jeesite/tabbar/msg_1.png differ diff --git a/hotgo-uniapp/static/jeesite/tabbar/msg_2.png b/hotgo-uniapp/static/jeesite/tabbar/msg_2.png new file mode 100644 index 0000000..cba5292 Binary files /dev/null and b/hotgo-uniapp/static/jeesite/tabbar/msg_2.png differ diff --git a/hotgo-uniapp/static/jeesite/tabbar/my_1.png b/hotgo-uniapp/static/jeesite/tabbar/my_1.png new file mode 100644 index 0000000..a0d0f34 Binary files /dev/null and b/hotgo-uniapp/static/jeesite/tabbar/my_1.png differ diff --git a/hotgo-uniapp/static/jeesite/tabbar/my_2.png b/hotgo-uniapp/static/jeesite/tabbar/my_2.png new file mode 100644 index 0000000..e6b18de Binary files /dev/null and b/hotgo-uniapp/static/jeesite/tabbar/my_2.png differ diff --git a/hotgo-uniapp/static/uview/common/favicon.ico b/hotgo-uniapp/static/uview/common/favicon.ico new file mode 100644 index 0000000..e0af368 Binary files /dev/null and b/hotgo-uniapp/static/uview/common/favicon.ico differ diff --git a/hotgo-uniapp/static/uview/common/logo.png b/hotgo-uniapp/static/uview/common/logo.png new file mode 100644 index 0000000..05b3aed Binary files /dev/null and b/hotgo-uniapp/static/uview/common/logo.png differ diff --git a/hotgo-uniapp/static/uview/example/component.png b/hotgo-uniapp/static/uview/example/component.png new file mode 100644 index 0000000..09bd020 Binary files /dev/null and b/hotgo-uniapp/static/uview/example/component.png differ diff --git a/hotgo-uniapp/static/uview/example/component_select.png b/hotgo-uniapp/static/uview/example/component_select.png new file mode 100644 index 0000000..3d704a8 Binary files /dev/null and b/hotgo-uniapp/static/uview/example/component_select.png differ diff --git a/hotgo-uniapp/static/uview/example/js.png b/hotgo-uniapp/static/uview/example/js.png new file mode 100644 index 0000000..b904664 Binary files /dev/null and b/hotgo-uniapp/static/uview/example/js.png differ diff --git a/hotgo-uniapp/static/uview/example/js_bak.png b/hotgo-uniapp/static/uview/example/js_bak.png new file mode 100644 index 0000000..d280e3d Binary files /dev/null and b/hotgo-uniapp/static/uview/example/js_bak.png differ diff --git a/hotgo-uniapp/static/uview/example/js_select.png b/hotgo-uniapp/static/uview/example/js_select.png new file mode 100644 index 0000000..9411c91 Binary files /dev/null and b/hotgo-uniapp/static/uview/example/js_select.png differ diff --git a/hotgo-uniapp/static/uview/example/js_select_bak.png b/hotgo-uniapp/static/uview/example/js_select_bak.png new file mode 100644 index 0000000..2ea6122 Binary files /dev/null and b/hotgo-uniapp/static/uview/example/js_select_bak.png differ diff --git a/hotgo-uniapp/static/uview/example/min_button.png b/hotgo-uniapp/static/uview/example/min_button.png new file mode 100644 index 0000000..077eb43 Binary files /dev/null and b/hotgo-uniapp/static/uview/example/min_button.png differ diff --git a/hotgo-uniapp/static/uview/example/min_button_select.png b/hotgo-uniapp/static/uview/example/min_button_select.png new file mode 100644 index 0000000..703a8bd Binary files /dev/null and b/hotgo-uniapp/static/uview/example/min_button_select.png differ diff --git a/hotgo-uniapp/static/uview/example/template.png b/hotgo-uniapp/static/uview/example/template.png new file mode 100644 index 0000000..5d27f97 Binary files /dev/null and b/hotgo-uniapp/static/uview/example/template.png differ diff --git a/hotgo-uniapp/static/uview/example/template_select.png b/hotgo-uniapp/static/uview/example/template_select.png new file mode 100644 index 0000000..be4b338 Binary files /dev/null and b/hotgo-uniapp/static/uview/example/template_select.png differ diff --git a/hotgo-uniapp/store/$u.mixin.js b/hotgo-uniapp/store/$u.mixin.js new file mode 100644 index 0000000..61ae187 --- /dev/null +++ b/hotgo-uniapp/store/$u.mixin.js @@ -0,0 +1,27 @@ +import { mapState } from 'vuex' +import store from "@/store" + +// 尝试将用户在根目录中的store/index.js的vuex的state变量,全部加载到全局变量中 +let $uStoreKey = []; +try{ + $uStoreKey = store.state ? Object.keys(store.state) : []; +}catch(e){ + +} + +module.exports = { + beforeCreate() { + // 将vuex方法挂在到$u中 + // 使用方法为:如果要修改vuex的state中的user.name变量为"史诗" => this.$u.vuex('user.name', '史诗') + // 如果要修改vuex的state的version变量为1.0.1 => this.$u.vuex('version', '1.0.1') + this.$u.vuex = (name, value) => { + this.$store.commit('$uStore', { + name,value + }) + } + }, + computed: { + // 将vuex的state中的所有变量,解构到全局混入的mixin中 + ...mapState($uStoreKey) + } +} \ No newline at end of file diff --git a/hotgo-uniapp/store/index.js b/hotgo-uniapp/store/index.js new file mode 100644 index 0000000..ba8a3a6 --- /dev/null +++ b/hotgo-uniapp/store/index.js @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +import config from '@/common/config.js'; +import Vue from 'vue' +import Vuex from 'vuex' +Vue.use(Vuex) + +let lifeData = {}; + +try{ + // 尝试获取本地是否存在lifeData变量,第一次启动APP时是不存在的 + lifeData = uni.getStorageSync('lifeData'); +}catch(e){ + +} + +// 需要永久存储,且下次APP启动需要取出的,在state中的变量名 +let saveStateKeys = ['vuex_user', 'vuex_token', 'vuex_remember', 'vuex_locale']; + +// 保存变量到本地存储中 +const saveLifeData = function(key, value){ + // 判断变量名是否在需要存储的数组中 + if(saveStateKeys.indexOf(key) != -1) { + // 获取本地存储的lifeData对象,将变量添加到对象中 + let tmp = uni.getStorageSync('lifeData'); + // 第一次打开APP,不存在lifeData变量,故放一个{}空对象 + tmp = tmp ? tmp : {}; + tmp[key] = value; + // 执行这一步后,所有需要存储的变量,都挂载在本地的lifeData对象中 + uni.setStorageSync('lifeData', tmp); + } +} +// 简化 vuex 操作,文档:https://uviewui.com/components/vuexDetail.html +const store = new Vuex.Store({ + state: { + // 如果上面从本地获取的lifeData对象下有对应的属性,就赋值给state中对应的变量 + // 加上vuex_前缀,是防止变量名冲突,也让人一目了然 + vuex_user: lifeData.vuex_user ? lifeData.vuex_user : {userName: 'JeeSite'}, + vuex_token: lifeData.vuex_token ? lifeData.vuex_token : '', + vuex_remember: lifeData.vuex_remember ? lifeData.vuex_remember : '', + vuex_locale: lifeData.vuex_locale ? lifeData.vuex_locale : '', + + // 如果vuex_version无需保存到本地永久存储,无需lifeData.vuex_version方式 + vuex_config: config, + + // 自定义tabbar数据 + // vuex_tabbar: [{ + // iconPath: "/static/uview/example/component.png", + // selectedIconPath: "/static/uview/example/component_select.png", + // text: '组件', + // pagePath: '/pages/example/components' + // }, + // { + // iconPath: "/static/uview/example/js.png", + // selectedIconPath: "/static/uview/example/js_select.png", + // text: '工具', + // midButton: true, + // pagePath: '/pages/example/js' + // }, + // { + // iconPath: "/static/uview/example/template.png", + // selectedIconPath: "/static/uview/example/template_select.png", + // text: '模板', + // pagePath: '/pages/example/template' + // } + // ] + }, + mutations: { + $uStore(state, payload) { + // 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1 + let nameArr = payload.name.split('.'); + let saveKey = ''; + let len = nameArr.length; + if(len >= 2) { + let obj = state[nameArr[0]]; + for(let i = 1; i < len - 1; i ++) { + obj = obj[nameArr[i]]; + } + obj[nameArr[len - 1]] = payload.value; + saveKey = nameArr[0]; + } else { + // 单层级变量,在state就是一个普通变量的情况 + state[payload.name] = payload.value; + saveKey = payload.name; + } + // 保存变量到本地,见顶部函数定义 + saveLifeData(saveKey, state[saveKey]) + } + } +}) + +export default store diff --git a/hotgo-uniapp/uni.scss b/hotgo-uniapp/uni.scss new file mode 100644 index 0000000..606e564 --- /dev/null +++ b/hotgo-uniapp/uni.scss @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + * 下方引入的为uView UI的集成样式文件,为scss预处理器,其中包含了一些"u-"开头的自定义变量 + * 使用的时候,请将下面的一行复制到您的uniapp项目根目录的uni.scss中即可 + * uView自定义的css类名和scss变量,均以"u-"开头,不会造成冲突,请放心使用 + */ + +$u-main-color: #303133; +$u-content-color: #505256; +$u-tips-color: #909399; +$u-light-color: #c0c4cc; +$u-border-color: #e4e7ed; +$u-bg-color: #f3f4f6; + +$u-type-primary: #2979ff; +$u-type-primary-light: #ecf5ff; +$u-type-primary-disabled: #a0cfff; +$u-type-primary-dark: #2b85e4; + +$u-type-warning: #ff9900; +$u-type-warning-disabled: #fcbd71; +$u-type-warning-dark: #f29100; +$u-type-warning-light: #fdf6ec; + +$u-type-success: #19be6b; +$u-type-success-disabled: #71d5a1; +$u-type-success-dark: #18b566; +$u-type-success-light: #dbf1e1; + +$u-type-error: #fa3534; +$u-type-error-disabled: #fab6b6; +$u-type-error-dark: #dd6161; +$u-type-error-light: #fef0f0; + +$u-type-info: #909399; +$u-type-info-disabled: #c8c9cc; +$u-type-info-dark: #82848a; +$u-type-info-light: #f4f4f5; + +$u-form-item-height: 70rpx; +$u-form-item-border-color: #dcdfe6; diff --git a/hotgo-uniapp/unpackage/res/icons/1024x1024.png b/hotgo-uniapp/unpackage/res/icons/1024x1024.png new file mode 100644 index 0000000..ade053d Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/1024x1024.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/120x120.png b/hotgo-uniapp/unpackage/res/icons/120x120.png new file mode 100644 index 0000000..eb4fbe8 Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/120x120.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/144x144.png b/hotgo-uniapp/unpackage/res/icons/144x144.png new file mode 100644 index 0000000..e3523a3 Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/144x144.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/152x152.png b/hotgo-uniapp/unpackage/res/icons/152x152.png new file mode 100644 index 0000000..3ba7d83 Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/152x152.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/167x167.png b/hotgo-uniapp/unpackage/res/icons/167x167.png new file mode 100644 index 0000000..f760ec2 Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/167x167.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/180x180.png b/hotgo-uniapp/unpackage/res/icons/180x180.png new file mode 100644 index 0000000..8a83d3e Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/180x180.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/192x192.png b/hotgo-uniapp/unpackage/res/icons/192x192.png new file mode 100644 index 0000000..bed84a0 Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/192x192.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/20x20.png b/hotgo-uniapp/unpackage/res/icons/20x20.png new file mode 100644 index 0000000..a2eb9fa Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/20x20.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/29x29.png b/hotgo-uniapp/unpackage/res/icons/29x29.png new file mode 100644 index 0000000..d63a6fc Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/29x29.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/40x40.png b/hotgo-uniapp/unpackage/res/icons/40x40.png new file mode 100644 index 0000000..9f4f0fd Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/40x40.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/58x58.png b/hotgo-uniapp/unpackage/res/icons/58x58.png new file mode 100644 index 0000000..4075bfa Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/58x58.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/60x60.png b/hotgo-uniapp/unpackage/res/icons/60x60.png new file mode 100644 index 0000000..7c4d4e5 Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/60x60.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/72x72.png b/hotgo-uniapp/unpackage/res/icons/72x72.png new file mode 100644 index 0000000..901f118 Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/72x72.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/76x76.png b/hotgo-uniapp/unpackage/res/icons/76x76.png new file mode 100644 index 0000000..b767560 Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/76x76.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/80x80.png b/hotgo-uniapp/unpackage/res/icons/80x80.png new file mode 100644 index 0000000..1da51ae Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/80x80.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/87x87.png b/hotgo-uniapp/unpackage/res/icons/87x87.png new file mode 100644 index 0000000..68adbbd Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/87x87.png differ diff --git a/hotgo-uniapp/unpackage/res/icons/96x96.png b/hotgo-uniapp/unpackage/res/icons/96x96.png new file mode 100644 index 0000000..81aadbc Binary files /dev/null and b/hotgo-uniapp/unpackage/res/icons/96x96.png differ diff --git a/hotgo-uniapp/uview-ui/LICENSE b/hotgo-uniapp/uview-ui/LICENSE new file mode 100644 index 0000000..8e39ead --- /dev/null +++ b/hotgo-uniapp/uview-ui/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 www.uviewui.com + +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. \ No newline at end of file diff --git a/hotgo-uniapp/uview-ui/README.md b/hotgo-uniapp/uview-ui/README.md new file mode 100644 index 0000000..06d5676 --- /dev/null +++ b/hotgo-uniapp/uview-ui/README.md @@ -0,0 +1,106 @@ +

+ logo +

+

uView

+

多平台快速开发的UI框架

+ + +## 说明 + +uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水 + +## 特性 + +- 兼容安卓,iOS,微信小程序,H5,QQ小程序,百度小程序,支付宝小程序,头条小程序 +- 60+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用 +- 众多贴心的JS利器,让您飞镖在手,召之即来,百步穿杨 +- 众多的常用页面和布局,让您专注逻辑,事半功倍 +- 详尽的文档支持,现代化的演示效果 +- 按需引入,精简打包体积 + + +## 安装 + +```bash +# npm方式安装 +npm i uview-ui +``` + +## 快速上手 + +1. `main.js`引入uView库 +```js +// main.js +import uView from 'uview-ui'; +Vue.use(uView); +``` + +2. `App.vue`引入基础样式(注意style标签需声明scss属性支持) +```css +/* App.vue */ + +``` + +3. `uni.scss`引入全局scss变量文件 +```css +/* uni.scss */ +@import "uview-ui/theme.scss"; +``` + +4. `pages.json`配置easycom规则(按需引入) + +```js +// pages.json +{ + "easycom": { + // npm安装的方式不需要前面的"@/",下载安装的方式需要"@/" + // npm安装方式 + "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue" + // 下载安装方式 + // "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue" + }, + // 此为本身已有的内容 + "pages": [ + // ...... + ] +} +``` + +请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容 + +## 使用方法 +配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。 + +```html + +``` + +请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容 + +## 链接 + +- [官方文档](https://uviewui.com/) +- [更新日志](https://uviewui.com/components/changelog.html) +- [升级指南](https://uviewui.com/components/changelog.html) +- [关于我们](https://uviewui.com/cooperation/about.html) + +## 预览 + +您可以通过**微信**扫码,查看最佳的演示效果。 +
+
+ + + +## 版权信息 +uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。 diff --git a/hotgo-uniapp/uview-ui/components/u-action-sheet/u-action-sheet.vue b/hotgo-uniapp/uview-ui/components/u-action-sheet/u-action-sheet.vue new file mode 100644 index 0000000..722b668 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-action-sheet/u-action-sheet.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-alert-tips/u-alert-tips.vue b/hotgo-uniapp/uview-ui/components/u-alert-tips/u-alert-tips.vue new file mode 100644 index 0000000..e81fc37 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-alert-tips/u-alert-tips.vue @@ -0,0 +1,256 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue b/hotgo-uniapp/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue new file mode 100644 index 0000000..a48dd54 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue @@ -0,0 +1,290 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-avatar-cropper/weCropper.js b/hotgo-uniapp/uview-ui/components/u-avatar-cropper/weCropper.js new file mode 100644 index 0000000..df02483 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-avatar-cropper/weCropper.js @@ -0,0 +1,1265 @@ +/** + * we-cropper v1.3.9 + * (c) 2020 dlhandsome + * @license MIT + */ +(function(global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.WeCropper = factory()); +}(this, (function() { + 'use strict'; + + var device = void 0; + var TOUCH_STATE = ['touchstarted', 'touchmoved', 'touchended']; + + function firstLetterUpper(str) { + return str.charAt(0).toUpperCase() + str.slice(1) + } + + function setTouchState(instance) { + var arg = [], + len = arguments.length - 1; + while (len-- > 0) arg[len] = arguments[len + 1]; + + TOUCH_STATE.forEach(function(key, i) { + if (arg[i] !== undefined) { + instance[key] = arg[i]; + } + }); + } + + function validator(instance, o) { + Object.defineProperties(instance, o); + } + + function getDevice() { + if (!device) { + device = uni.getSystemInfoSync(); + } + return device + } + + var tmp = {}; + + var ref = getDevice(); + var pixelRatio = ref.pixelRatio; + + var DEFAULT = { + id: { + default: 'cropper', + get: function get() { + return tmp.id + }, + set: function set(value) { + if (typeof(value) !== 'string') { + console.error(("id:" + value + " is invalid")); + } + tmp.id = value; + } + }, + width: { + default: 750, + get: function get() { + return tmp.width + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("width:" + value + " is invalid")); + } + tmp.width = value; + } + }, + height: { + default: 750, + get: function get() { + return tmp.height + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("height:" + value + " is invalid")); + } + tmp.height = value; + } + }, + pixelRatio: { + default: pixelRatio, + get: function get() { + return tmp.pixelRatio + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("pixelRatio:" + value + " is invalid")); + } + tmp.pixelRatio = value; + } + }, + scale: { + default: 2.5, + get: function get() { + return tmp.scale + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("scale:" + value + " is invalid")); + } + tmp.scale = value; + } + }, + zoom: { + default: 5, + get: function get() { + return tmp.zoom + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("zoom:" + value + " is invalid")); + } else if (value < 0 || value > 10) { + console.error("zoom should be ranged in 0 ~ 10"); + } + tmp.zoom = value; + } + }, + src: { + default: '', + get: function get() { + return tmp.src + }, + set: function set(value) { + if (typeof(value) !== 'string') { + console.error(("src:" + value + " is invalid")); + } + tmp.src = value; + } + }, + cut: { + default: {}, + get: function get() { + return tmp.cut + }, + set: function set(value) { + if (typeof(value) !== 'object') { + console.error(("cut:" + value + " is invalid")); + } + tmp.cut = value; + } + }, + boundStyle: { + default: {}, + get: function get() { + return tmp.boundStyle + }, + set: function set(value) { + if (typeof(value) !== 'object') { + console.error(("boundStyle:" + value + " is invalid")); + } + tmp.boundStyle = value; + } + }, + onReady: { + default: null, + get: function get() { + return tmp.ready + }, + set: function set(value) { + tmp.ready = value; + } + }, + onBeforeImageLoad: { + default: null, + get: function get() { + return tmp.beforeImageLoad + }, + set: function set(value) { + tmp.beforeImageLoad = value; + } + }, + onImageLoad: { + default: null, + get: function get() { + return tmp.imageLoad + }, + set: function set(value) { + tmp.imageLoad = value; + } + }, + onBeforeDraw: { + default: null, + get: function get() { + return tmp.beforeDraw + }, + set: function set(value) { + tmp.beforeDraw = value; + } + } + }; + + var ref$1 = getDevice(); + var windowWidth = ref$1.windowWidth; + + function prepare() { + var self = this; + + // v1.4.0 版本中将不再自动绑定we-cropper实例 + self.attachPage = function() { + var pages = getCurrentPages(); + // 获取到当前page上下文 + var pageContext = pages[pages.length - 1]; + // 把this依附在Page上下文的wecropper属性上,便于在page钩子函数中访问 + Object.defineProperty(pageContext, 'wecropper', { + get: function get() { + console.warn( + 'Instance will not be automatically bound to the page after v1.4.0\n\n' + + 'Please use a custom instance name instead\n\n' + + 'Example: \n' + + 'this.mycropper = new WeCropper(options)\n\n' + + '// ...\n' + + 'this.mycropper.getCropperImage()' + ); + return self + }, + configurable: true + }); + }; + + self.createCtx = function() { + var id = self.id; + var targetId = self.targetId; + + if (id) { + self.ctx = self.ctx || uni.createCanvasContext(id); + self.targetCtx = self.targetCtx || uni.createCanvasContext(targetId); + } else { + console.error("constructor: create canvas context failed, 'id' must be valuable"); + } + }; + + self.deviceRadio = windowWidth / 750; + } + + var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== + 'undefined' ? self : {}; + + + + + + function createCommonjsModule(fn, module) { + return module = { + exports: {} + }, fn(module, module.exports), module.exports; + } + + var tools = createCommonjsModule(function(module, exports) { + /** + * String type check + */ + exports.isStr = function(v) { + return typeof v === 'string'; + }; + /** + * Number type check + */ + exports.isNum = function(v) { + return typeof v === 'number'; + }; + /** + * Array type check + */ + exports.isArr = Array.isArray; + /** + * undefined type check + */ + exports.isUndef = function(v) { + return v === undefined; + }; + + exports.isTrue = function(v) { + return v === true; + }; + + exports.isFalse = function(v) { + return v === false; + }; + /** + * Function type check + */ + exports.isFunc = function(v) { + return typeof v === 'function'; + }; + /** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + */ + exports.isObj = exports.isObject = function(obj) { + return obj !== null && typeof obj === 'object' + }; + + /** + * Strict object type check. Only returns true + * for plain JavaScript objects. + */ + var _toString = Object.prototype.toString; + exports.isPlainObject = function(obj) { + return _toString.call(obj) === '[object Object]' + }; + + /** + * Check whether the object has the property. + */ + var hasOwnProperty = Object.prototype.hasOwnProperty; + exports.hasOwn = function(obj, key) { + return hasOwnProperty.call(obj, key) + }; + + /** + * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/) + */ + exports.noop = function(a, b, c) {}; + + /** + * Check if val is a valid array index. + */ + exports.isValidArrayIndex = function(val) { + var n = parseFloat(String(val)); + return n >= 0 && Math.floor(n) === n && isFinite(val) + }; + }); + + var tools_7 = tools.isFunc; + var tools_10 = tools.isPlainObject; + + var EVENT_TYPE = ['ready', 'beforeImageLoad', 'beforeDraw', 'imageLoad']; + + function observer() { + var self = this; + + self.on = function(event, fn) { + if (EVENT_TYPE.indexOf(event) > -1) { + if (tools_7(fn)) { + event === 'ready' ? + fn(self) : + self[("on" + (firstLetterUpper(event)))] = fn; + } + } else { + console.error(("event: " + event + " is invalid")); + } + return self + }; + } + + function wxPromise(fn) { + return function(obj) { + var args = [], + len = arguments.length - 1; + while (len-- > 0) args[len] = arguments[len + 1]; + + if (obj === void 0) obj = {}; + return new Promise(function(resolve, reject) { + obj.success = function(res) { + resolve(res); + }; + obj.fail = function(err) { + reject(err); + }; + fn.apply(void 0, [obj].concat(args)); + }) + } + } + + function draw(ctx, reserve) { + if (reserve === void 0) reserve = false; + + return new Promise(function(resolve) { + ctx.draw(reserve, resolve); + }) + } + + var getImageInfo = wxPromise(uni.getImageInfo); + + var canvasToTempFilePath = wxPromise(uni.canvasToTempFilePath); + + var base64 = createCommonjsModule(function(module, exports) { + /*! http://mths.be/base64 v0.1.0 by @mathias | MIT license */ + (function(root) { + + // Detect free variables `exports`. + var freeExports = 'object' == 'object' && exports; + + // Detect free variable `module`. + var freeModule = 'object' == 'object' && module && + module.exports == freeExports && module; + + // Detect free variable `global`, from Node.js or Browserified code, and use + // it as `root`. + var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal; + if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { + root = freeGlobal; + } + + /*--------------------------------------------------------------------------*/ + + var InvalidCharacterError = function(message) { + this.message = message; + }; + InvalidCharacterError.prototype = new Error; + InvalidCharacterError.prototype.name = 'InvalidCharacterError'; + + var error = function(message) { + // Note: the error messages used throughout this file match those used by + // the native `atob`/`btoa` implementation in Chromium. + throw new InvalidCharacterError(message); + }; + + var TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + // http://whatwg.org/html/common-microsyntaxes.html#space-character + var REGEX_SPACE_CHARACTERS = /[\t\n\f\r ]/g; + + // `decode` is designed to be fully compatible with `atob` as described in the + // HTML Standard. http://whatwg.org/html/webappapis.html#dom-windowbase64-atob + // The optimized base64-decoding algorithm used is based on @atk’s excellent + // implementation. https://gist.github.com/atk/1020396 + var decode = function(input) { + input = String(input) + .replace(REGEX_SPACE_CHARACTERS, ''); + var length = input.length; + if (length % 4 == 0) { + input = input.replace(/==?$/, ''); + length = input.length; + } + if ( + length % 4 == 1 || + // http://whatwg.org/C#alphanumeric-ascii-characters + /[^+a-zA-Z0-9/]/.test(input) + ) { + error( + 'Invalid character: the string to be decoded is not correctly encoded.' + ); + } + var bitCounter = 0; + var bitStorage; + var buffer; + var output = ''; + var position = -1; + while (++position < length) { + buffer = TABLE.indexOf(input.charAt(position)); + bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer; + // Unless this is the first of a group of 4 characters… + if (bitCounter++ % 4) { + // …convert the first 8 bits to a single ASCII character. + output += String.fromCharCode( + 0xFF & bitStorage >> (-2 * bitCounter & 6) + ); + } + } + return output; + }; + + // `encode` is designed to be fully compatible with `btoa` as described in the + // HTML Standard: http://whatwg.org/html/webappapis.html#dom-windowbase64-btoa + var encode = function(input) { + input = String(input); + if (/[^\0-\xFF]/.test(input)) { + // Note: no need to special-case astral symbols here, as surrogates are + // matched, and the input is supposed to only contain ASCII anyway. + error( + 'The string to be encoded contains characters outside of the ' + + 'Latin1 range.' + ); + } + var padding = input.length % 3; + var output = ''; + var position = -1; + var a; + var b; + var c; + var buffer; + // Make sure any padding is handled outside of the loop. + var length = input.length - padding; + + while (++position < length) { + // Read three bytes, i.e. 24 bits. + a = input.charCodeAt(position) << 16; + b = input.charCodeAt(++position) << 8; + c = input.charCodeAt(++position); + buffer = a + b + c; + // Turn the 24 bits into four chunks of 6 bits each, and append the + // matching character for each of them to the output. + output += ( + TABLE.charAt(buffer >> 18 & 0x3F) + + TABLE.charAt(buffer >> 12 & 0x3F) + + TABLE.charAt(buffer >> 6 & 0x3F) + + TABLE.charAt(buffer & 0x3F) + ); + } + + if (padding == 2) { + a = input.charCodeAt(position) << 8; + b = input.charCodeAt(++position); + buffer = a + b; + output += ( + TABLE.charAt(buffer >> 10) + + TABLE.charAt((buffer >> 4) & 0x3F) + + TABLE.charAt((buffer << 2) & 0x3F) + + '=' + ); + } else if (padding == 1) { + buffer = input.charCodeAt(position); + output += ( + TABLE.charAt(buffer >> 2) + + TABLE.charAt((buffer << 4) & 0x3F) + + '==' + ); + } + + return output; + }; + + var base64 = { + 'encode': encode, + 'decode': decode, + 'version': '0.1.0' + }; + + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + typeof undefined == 'function' && + typeof undefined.amd == 'object' && + undefined.amd + ) { + undefined(function() { + return base64; + }); + } else if (freeExports && !freeExports.nodeType) { + if (freeModule) { // in Node.js or RingoJS v0.8.0+ + freeModule.exports = base64; + } else { // in Narwhal or RingoJS v0.7.0- + for (var key in base64) { + base64.hasOwnProperty(key) && (freeExports[key] = base64[key]); + } + } + } else { // in Rhino or a web browser + root.base64 = base64; + } + + }(commonjsGlobal)); + }); + + function makeURI(strData, type) { + return 'data:' + type + ';base64,' + strData + } + + function fixType(type) { + type = type.toLowerCase().replace(/jpg/i, 'jpeg'); + var r = type.match(/png|jpeg|bmp|gif/)[0]; + return 'image/' + r + } + + function encodeData(data) { + var str = ''; + if (typeof data === 'string') { + str = data; + } else { + for (var i = 0; i < data.length; i++) { + str += String.fromCharCode(data[i]); + } + } + return base64.encode(str) + } + + /** + * 获取图像区域隐含的像素数据 + * @param canvasId canvas标识 + * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标 + * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标 + * @param width 将要被提取的图像数据矩形区域的宽度 + * @param height 将要被提取的图像数据矩形区域的高度 + * @param done 完成回调 + */ + function getImageData(canvasId, x, y, width, height, done) { + uni.canvasGetImageData({ + canvasId: canvasId, + x: x, + y: y, + width: width, + height: height, + success: function success(res) { + done(res, null); + }, + fail: function fail(res) { + done(null, res); + } + }); + } + + /** + * 生成bmp格式图片 + * 按照规则生成图片响应头和响应体 + * @param oData 用来描述 canvas 区域隐含的像素数据 { data, width, height } = oData + * @returns {*} base64字符串 + */ + function genBitmapImage(oData) { + // + // BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx + // BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx + // + var biWidth = oData.width; + var biHeight = oData.height; + var biSizeImage = biWidth * biHeight * 3; + var bfSize = biSizeImage + 54; // total header size = 54 bytes + + // + // typedef struct tagBITMAPFILEHEADER { + // WORD bfType; + // DWORD bfSize; + // WORD bfReserved1; + // WORD bfReserved2; + // DWORD bfOffBits; + // } BITMAPFILEHEADER; + // + var BITMAPFILEHEADER = [ + // WORD bfType -- The file type signature; must be "BM" + 0x42, 0x4D, + // DWORD bfSize -- The size, in bytes, of the bitmap file + bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff, + // WORD bfReserved1 -- Reserved; must be zero + 0, 0, + // WORD bfReserved2 -- Reserved; must be zero + 0, 0, + // DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits. + 54, 0, 0, 0 + ]; + + // + // typedef struct tagBITMAPINFOHEADER { + // DWORD biSize; + // LONG biWidth; + // LONG biHeight; + // WORD biPlanes; + // WORD biBitCount; + // DWORD biCompression; + // DWORD biSizeImage; + // LONG biXPelsPerMeter; + // LONG biYPelsPerMeter; + // DWORD biClrUsed; + // DWORD biClrImportant; + // } BITMAPINFOHEADER, *PBITMAPINFOHEADER; + // + var BITMAPINFOHEADER = [ + // DWORD biSize -- The number of bytes required by the structure + 40, 0, 0, 0, + // LONG biWidth -- The width of the bitmap, in pixels + biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff, + // LONG biHeight -- The height of the bitmap, in pixels + biHeight & 0xff, biHeight >> 8 & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff, + // WORD biPlanes -- The number of planes for the target device. This value must be set to 1 + 1, 0, + // WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap + // has a maximum of 2^24 colors (16777216, Truecolor) + 24, 0, + // DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed + 0, 0, 0, 0, + // DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps + biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff, + // LONG biXPelsPerMeter, unused + 0, 0, 0, 0, + // LONG biYPelsPerMeter, unused + 0, 0, 0, 0, + // DWORD biClrUsed, the number of color indexes of palette, unused + 0, 0, 0, 0, + // DWORD biClrImportant, unused + 0, 0, 0, 0 + ]; + + var iPadding = (4 - ((biWidth * 3) % 4)) % 4; + + var aImgData = oData.data; + + var strPixelData = ''; + var biWidth4 = biWidth << 2; + var y = biHeight; + var fromCharCode = String.fromCharCode; + + do { + var iOffsetY = biWidth4 * (y - 1); + var strPixelRow = ''; + for (var x = 0; x < biWidth; x++) { + var iOffsetX = x << 2; + strPixelRow += fromCharCode(aImgData[iOffsetY + iOffsetX + 2]) + + fromCharCode(aImgData[iOffsetY + iOffsetX + 1]) + + fromCharCode(aImgData[iOffsetY + iOffsetX]); + } + + for (var c = 0; c < iPadding; c++) { + strPixelRow += String.fromCharCode(0); + } + + strPixelData += strPixelRow; + } while (--y) + + var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData); + + return strEncoded + } + + /** + * 转换为图片base64 + * @param canvasId canvas标识 + * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标 + * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标 + * @param width 将要被提取的图像数据矩形区域的宽度 + * @param height 将要被提取的图像数据矩形区域的高度 + * @param type 转换图片类型 + * @param done 完成回调 + */ + function convertToImage(canvasId, x, y, width, height, type, done) { + if (done === void 0) done = function() {}; + + if (type === undefined) { + type = 'png'; + } + type = fixType(type); + if (/bmp/.test(type)) { + getImageData(canvasId, x, y, width, height, function(data, err) { + var strData = genBitmapImage(data); + tools_7(done) && done(makeURI(strData, 'image/' + type), err); + }); + } else { + console.error('暂不支持生成\'' + type + '\'类型的base64图片'); + } + } + + var CanvasToBase64 = { + convertToImage: convertToImage, + // convertToPNG: function (width, height, done) { + // return convertToImage(width, height, 'png', done) + // }, + // convertToJPEG: function (width, height, done) { + // return convertToImage(width, height, 'jpeg', done) + // }, + // convertToGIF: function (width, height, done) { + // return convertToImage(width, height, 'gif', done) + // }, + convertToBMP: function(ref, done) { + if (ref === void 0) ref = {}; + var canvasId = ref.canvasId; + var x = ref.x; + var y = ref.y; + var width = ref.width; + var height = ref.height; + if (done === void 0) done = function() {}; + + return convertToImage(canvasId, x, y, width, height, 'bmp', done) + } + }; + + function methods() { + var self = this; + + var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度 + var boundHeight = self.height; // 裁剪框默认高度,即整个画布高度 + + var id = self.id; + var targetId = self.targetId; + var pixelRatio = self.pixelRatio; + + var ref = self.cut; + var x = ref.x; + if (x === void 0) x = 0; + var y = ref.y; + if (y === void 0) y = 0; + var width = ref.width; + if (width === void 0) width = boundWidth; + var height = ref.height; + if (height === void 0) height = boundHeight; + + self.updateCanvas = function(done) { + if (self.croperTarget) { + // 画布绘制图片 + self.ctx.drawImage( + self.croperTarget, + self.imgLeft, + self.imgTop, + self.scaleWidth, + self.scaleHeight + ); + } + tools_7(self.onBeforeDraw) && self.onBeforeDraw(self.ctx, self); + + self.setBoundStyle(self.boundStyle); // 设置边界样式 + + self.ctx.draw(false, done); + return self + }; + + self.pushOrigin = self.pushOrign = function(src) { + self.src = src; + + tools_7(self.onBeforeImageLoad) && self.onBeforeImageLoad(self.ctx, self); + + return getImageInfo({ + src: src + }) + .then(function(res) { + var innerAspectRadio = res.width / res.height; + var customAspectRadio = width / height; + + self.croperTarget = res.path; + + if (innerAspectRadio < customAspectRadio) { + self.rectX = x; + self.baseWidth = width; + self.baseHeight = width / innerAspectRadio; + self.rectY = y - Math.abs((height - self.baseHeight) / 2); + } else { + self.rectY = y; + self.baseWidth = height * innerAspectRadio; + self.baseHeight = height; + self.rectX = x - Math.abs((width - self.baseWidth) / 2); + } + + self.imgLeft = self.rectX; + self.imgTop = self.rectY; + self.scaleWidth = self.baseWidth; + self.scaleHeight = self.baseHeight; + + self.update(); + + return new Promise(function(resolve) { + self.updateCanvas(resolve); + }) + }) + .then(function() { + tools_7(self.onImageLoad) && self.onImageLoad(self.ctx, self); + }) + }; + + self.removeImage = function() { + self.src = ''; + self.croperTarget = ''; + return draw(self.ctx) + }; + + self.getCropperBase64 = function(done) { + if (done === void 0) done = function() {}; + + CanvasToBase64.convertToBMP({ + canvasId: id, + x: x, + y: y, + width: width, + height: height + }, done); + }; + + self.getCropperImage = function(opt, fn) { + var customOptions = opt; + + var canvasOptions = { + canvasId: id, + x: x, + y: y, + width: width, + height: height + }; + + var task = function() { + return Promise.resolve(); + }; + + if ( + tools_10(customOptions) && + customOptions.original + ) { + // original mode + task = function() { + self.targetCtx.drawImage( + self.croperTarget, + self.imgLeft * pixelRatio, + self.imgTop * pixelRatio, + self.scaleWidth * pixelRatio, + self.scaleHeight * pixelRatio + ); + + canvasOptions = { + canvasId: targetId, + x: x * pixelRatio, + y: y * pixelRatio, + width: width * pixelRatio, + height: height * pixelRatio + }; + + return draw(self.targetCtx) + }; + } + + return task() + .then(function() { + if (tools_10(customOptions)) { + canvasOptions = Object.assign({}, canvasOptions, customOptions); + } + + if (tools_7(customOptions)) { + fn = customOptions; + } + + var arg = canvasOptions.componentContext ? + [canvasOptions, canvasOptions.componentContext] : + [canvasOptions]; + + return canvasToTempFilePath.apply(null, arg) + }) + .then(function(res) { + var tempFilePath = res.tempFilePath; + + return tools_7(fn) ? + fn.call(self, tempFilePath, null) : + tempFilePath + }) + .catch(function(err) { + if (tools_7(fn)) { + fn.call(self, null, err); + } else { + throw err + } + }) + }; + } + + /** + * 获取最新缩放值 + * @param oldScale 上一次触摸结束后的缩放值 + * @param oldDistance 上一次触摸结束后的双指距离 + * @param zoom 缩放系数 + * @param touch0 第一指touch对象 + * @param touch1 第二指touch对象 + * @returns {*} + */ + var getNewScale = function(oldScale, oldDistance, zoom, touch0, touch1) { + var xMove, yMove, newDistance; + // 计算二指最新距离 + xMove = Math.round(touch1.x - touch0.x); + yMove = Math.round(touch1.y - touch0.y); + newDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove)); + + return oldScale + 0.001 * zoom * (newDistance - oldDistance) + }; + + function update() { + var self = this; + + if (!self.src) { + return + } + + self.__oneTouchStart = function(touch) { + self.touchX0 = Math.round(touch.x); + self.touchY0 = Math.round(touch.y); + }; + + self.__oneTouchMove = function(touch) { + var xMove, yMove; + // 计算单指移动的距离 + if (self.touchended) { + return self.updateCanvas() + } + xMove = Math.round(touch.x - self.touchX0); + yMove = Math.round(touch.y - self.touchY0); + + var imgLeft = Math.round(self.rectX + xMove); + var imgTop = Math.round(self.rectY + yMove); + + self.outsideBound(imgLeft, imgTop); + + self.updateCanvas(); + }; + + self.__twoTouchStart = function(touch0, touch1) { + var xMove, yMove, oldDistance; + + self.touchX1 = Math.round(self.rectX + self.scaleWidth / 2); + self.touchY1 = Math.round(self.rectY + self.scaleHeight / 2); + + // 计算两指距离 + xMove = Math.round(touch1.x - touch0.x); + yMove = Math.round(touch1.y - touch0.y); + oldDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove)); + + self.oldDistance = oldDistance; + }; + + self.__twoTouchMove = function(touch0, touch1) { + var oldScale = self.oldScale; + var oldDistance = self.oldDistance; + var scale = self.scale; + var zoom = self.zoom; + + self.newScale = getNewScale(oldScale, oldDistance, zoom, touch0, touch1); + + // 设定缩放范围 + self.newScale <= 1 && (self.newScale = 1); + self.newScale >= scale && (self.newScale = scale); + + self.scaleWidth = Math.round(self.newScale * self.baseWidth); + self.scaleHeight = Math.round(self.newScale * self.baseHeight); + var imgLeft = Math.round(self.touchX1 - self.scaleWidth / 2); + var imgTop = Math.round(self.touchY1 - self.scaleHeight / 2); + + self.outsideBound(imgLeft, imgTop); + + self.updateCanvas(); + }; + + self.__xtouchEnd = function() { + self.oldScale = self.newScale; + self.rectX = self.imgLeft; + self.rectY = self.imgTop; + }; + } + + var handle = { + // 图片手势初始监测 + touchStart: function touchStart(e) { + var self = this; + var ref = e.touches; + var touch0 = ref[0]; + var touch1 = ref[1]; + + if (!self.src) { + return + } + + setTouchState(self, true, null, null); + + // 计算第一个触摸点的位置,并参照改点进行缩放 + self.__oneTouchStart(touch0); + + // 两指手势触发 + if (e.touches.length >= 2) { + self.__twoTouchStart(touch0, touch1); + } + }, + + // 图片手势动态缩放 + touchMove: function touchMove(e) { + var self = this; + var ref = e.touches; + var touch0 = ref[0]; + var touch1 = ref[1]; + + if (!self.src) { + return + } + + setTouchState(self, null, true); + + // 单指手势时触发 + if (e.touches.length === 1) { + self.__oneTouchMove(touch0); + } + // 两指手势触发 + if (e.touches.length >= 2) { + self.__twoTouchMove(touch0, touch1); + } + }, + + touchEnd: function touchEnd(e) { + var self = this; + + if (!self.src) { + return + } + + setTouchState(self, false, false, true); + self.__xtouchEnd(); + } + }; + + function cut() { + var self = this; + var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度 + var boundHeight = self.height; + // 裁剪框默认高度,即整个画布高度 + var ref = self.cut; + var x = ref.x; + if (x === void 0) x = 0; + var y = ref.y; + if (y === void 0) y = 0; + var width = ref.width; + if (width === void 0) width = boundWidth; + var height = ref.height; + if (height === void 0) height = boundHeight; + + /** + * 设置边界 + * @param imgLeft 图片左上角横坐标值 + * @param imgTop 图片左上角纵坐标值 + */ + self.outsideBound = function(imgLeft, imgTop) { + self.imgLeft = imgLeft >= x ? + x : + self.scaleWidth + imgLeft - x <= width ? + x + width - self.scaleWidth : + imgLeft; + + self.imgTop = imgTop >= y ? + y : + self.scaleHeight + imgTop - y <= height ? + y + height - self.scaleHeight : + imgTop; + }; + + /** + * 设置边界样式 + * @param color 边界颜色 + */ + self.setBoundStyle = function(ref) { + if (ref === void 0) ref = {}; + var color = ref.color; + if (color === void 0) color = '#04b00f'; + var mask = ref.mask; + if (mask === void 0) mask = 'rgba(0, 0, 0, 0.3)'; + var lineWidth = ref.lineWidth; + if (lineWidth === void 0) lineWidth = 1; + + var half = lineWidth / 2; + var boundOption = [{ + start: { + x: x - half, + y: y + 10 - half + }, + step1: { + x: x - half, + y: y - half + }, + step2: { + x: x + 10 - half, + y: y - half + } + }, + { + start: { + x: x - half, + y: y + height - 10 + half + }, + step1: { + x: x - half, + y: y + height + half + }, + step2: { + x: x + 10 - half, + y: y + height + half + } + }, + { + start: { + x: x + width - 10 + half, + y: y - half + }, + step1: { + x: x + width + half, + y: y - half + }, + step2: { + x: x + width + half, + y: y + 10 - half + } + }, + { + start: { + x: x + width + half, + y: y + height - 10 + half + }, + step1: { + x: x + width + half, + y: y + height + half + }, + step2: { + x: x + width - 10 + half, + y: y + height + half + } + } + ]; + + // 绘制半透明层 + self.ctx.beginPath(); + self.ctx.setFillStyle(mask); + self.ctx.fillRect(0, 0, x, boundHeight); + self.ctx.fillRect(x, 0, width, y); + self.ctx.fillRect(x, y + height, width, boundHeight - y - height); + self.ctx.fillRect(x + width, 0, boundWidth - x - width, boundHeight); + self.ctx.fill(); + + boundOption.forEach(function(op) { + self.ctx.beginPath(); + self.ctx.setStrokeStyle(color); + self.ctx.setLineWidth(lineWidth); + self.ctx.moveTo(op.start.x, op.start.y); + self.ctx.lineTo(op.step1.x, op.step1.y); + self.ctx.lineTo(op.step2.x, op.step2.y); + self.ctx.stroke(); + }); + }; + } + + var version = "1.3.9"; + + var WeCropper = function WeCropper(params) { + var self = this; + var _default = {}; + + validator(self, DEFAULT); + + Object.keys(DEFAULT).forEach(function(key) { + _default[key] = DEFAULT[key].default; + }); + Object.assign(self, _default, params); + + self.prepare(); + self.attachPage(); + self.createCtx(); + self.observer(); + self.cutt(); + self.methods(); + self.init(); + self.update(); + + return self + }; + + WeCropper.prototype.init = function init() { + var self = this; + var src = self.src; + + self.version = version; + + typeof self.onReady === 'function' && self.onReady(self.ctx, self); + + if (src) { + self.pushOrign(src); + } else { + self.updateCanvas(); + } + setTouchState(self, false, false, false); + + self.oldScale = 1; + self.newScale = 1; + + return self + }; + + Object.assign(WeCropper.prototype, handle); + + WeCropper.prototype.prepare = prepare; + WeCropper.prototype.observer = observer; + WeCropper.prototype.methods = methods; + WeCropper.prototype.cutt = cut; + WeCropper.prototype.update = update; + + return WeCropper; + +}))); diff --git a/hotgo-uniapp/uview-ui/components/u-avatar/u-avatar.vue b/hotgo-uniapp/uview-ui/components/u-avatar/u-avatar.vue new file mode 100644 index 0000000..289b9b0 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-avatar/u-avatar.vue @@ -0,0 +1,244 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-back-top/u-back-top.vue b/hotgo-uniapp/uview-ui/components/u-back-top/u-back-top.vue new file mode 100644 index 0000000..7970fc7 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-back-top/u-back-top.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-badge/u-badge.vue b/hotgo-uniapp/uview-ui/components/u-badge/u-badge.vue new file mode 100644 index 0000000..e85b133 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-badge/u-badge.vue @@ -0,0 +1,216 @@ + + + + + \ No newline at end of file diff --git a/hotgo-uniapp/uview-ui/components/u-button/u-button.vue b/hotgo-uniapp/uview-ui/components/u-button/u-button.vue new file mode 100644 index 0000000..82c3a6f --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-button/u-button.vue @@ -0,0 +1,596 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-calendar/u-calendar.vue b/hotgo-uniapp/uview-ui/components/u-calendar/u-calendar.vue new file mode 100644 index 0000000..2b30184 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-calendar/u-calendar.vue @@ -0,0 +1,639 @@ + + + + \ No newline at end of file diff --git a/hotgo-uniapp/uview-ui/components/u-car-keyboard/u-car-keyboard.vue b/hotgo-uniapp/uview-ui/components/u-car-keyboard/u-car-keyboard.vue new file mode 100644 index 0000000..84b1467 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-car-keyboard/u-car-keyboard.vue @@ -0,0 +1,257 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-card/u-card.vue b/hotgo-uniapp/uview-ui/components/u-card/u-card.vue new file mode 100644 index 0000000..a3cb2aa --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-card/u-card.vue @@ -0,0 +1,299 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-cell-group/u-cell-group.vue b/hotgo-uniapp/uview-ui/components/u-cell-group/u-cell-group.vue new file mode 100644 index 0000000..3fbca72 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-cell-group/u-cell-group.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-cell-item/u-cell-item.vue b/hotgo-uniapp/uview-ui/components/u-cell-item/u-cell-item.vue new file mode 100644 index 0000000..055af3a --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-cell-item/u-cell-item.vue @@ -0,0 +1,316 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-checkbox-group/u-checkbox-group.vue b/hotgo-uniapp/uview-ui/components/u-checkbox-group/u-checkbox-group.vue new file mode 100644 index 0000000..6a149b3 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-checkbox-group/u-checkbox-group.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-checkbox/u-checkbox.vue b/hotgo-uniapp/uview-ui/components/u-checkbox/u-checkbox.vue new file mode 100644 index 0000000..9414461 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-checkbox/u-checkbox.vue @@ -0,0 +1,284 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-circle-progress/u-circle-progress.vue b/hotgo-uniapp/uview-ui/components/u-circle-progress/u-circle-progress.vue new file mode 100644 index 0000000..46e7c18 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-circle-progress/u-circle-progress.vue @@ -0,0 +1,220 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-circle-progress/u-line-progress/u-line-progress.vue b/hotgo-uniapp/uview-ui/components/u-circle-progress/u-line-progress/u-line-progress.vue new file mode 100644 index 0000000..77e2da2 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-circle-progress/u-line-progress/u-line-progress.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-col/u-col.vue b/hotgo-uniapp/uview-ui/components/u-col/u-col.vue new file mode 100644 index 0000000..3b6cc64 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-col/u-col.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-collapse-item/u-collapse-item.vue b/hotgo-uniapp/uview-ui/components/u-collapse-item/u-collapse-item.vue new file mode 100644 index 0000000..3b66bfa --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-collapse-item/u-collapse-item.vue @@ -0,0 +1,204 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-collapse/u-collapse.vue b/hotgo-uniapp/uview-ui/components/u-collapse/u-collapse.vue new file mode 100644 index 0000000..8572957 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-collapse/u-collapse.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-column-notice/u-column-notice.vue b/hotgo-uniapp/uview-ui/components/u-column-notice/u-column-notice.vue new file mode 100644 index 0000000..dd8bd31 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-column-notice/u-column-notice.vue @@ -0,0 +1,237 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-count-down/u-count-down.vue b/hotgo-uniapp/uview-ui/components/u-count-down/u-count-down.vue new file mode 100644 index 0000000..7285d67 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-count-down/u-count-down.vue @@ -0,0 +1,318 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-count-to/u-count-to.vue b/hotgo-uniapp/uview-ui/components/u-count-to/u-count-to.vue new file mode 100644 index 0000000..053dc5f --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-count-to/u-count-to.vue @@ -0,0 +1,241 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-divider/u-divider.vue b/hotgo-uniapp/uview-ui/components/u-divider/u-divider.vue new file mode 100644 index 0000000..6f8d7e6 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-divider/u-divider.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-dropdown-item/u-dropdown-item.vue b/hotgo-uniapp/uview-ui/components/u-dropdown-item/u-dropdown-item.vue new file mode 100644 index 0000000..ba60d8f --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-dropdown-item/u-dropdown-item.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-dropdown/u-dropdown.vue b/hotgo-uniapp/uview-ui/components/u-dropdown/u-dropdown.vue new file mode 100644 index 0000000..a62e469 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-dropdown/u-dropdown.vue @@ -0,0 +1,298 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-empty/u-empty.vue b/hotgo-uniapp/uview-ui/components/u-empty/u-empty.vue new file mode 100644 index 0000000..2c77b24 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-empty/u-empty.vue @@ -0,0 +1,193 @@ + + + + + diff --git a/hotgo-uniapp/uview-ui/components/u-field/u-field.vue b/hotgo-uniapp/uview-ui/components/u-field/u-field.vue new file mode 100644 index 0000000..b562798 --- /dev/null +++ b/hotgo-uniapp/uview-ui/components/u-field/u-field.vue @@ -0,0 +1,384 @@ +