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] ",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?"
':"")+'",!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 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 @@
+
+
+
+ {{item.label}}
+
+
+
+
+
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 @@
+
+
+
+ {{item.label}}
+
+
+
+
+
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 %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 本站点必须要开启JavaScript才能运行
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+ 待办任务
+
+
+
+ 已办任务
+
+
+
+ 我相关的
+
+
+
+
+
+
+
+
+ {{menu.menuName}}
+
+
+
+
+ {{child.menuName}}
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{tips}}
+
+
+ 修改密码
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+ {{$t('login.autoLogin')}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{$t('login.loginButton')}}
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{tips}}
+
+
+
+ 我已阅读并同意
+ 《软件用户协议》
+
+ 注册账号
+
+
+
+
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 @@
+
+
+ {{banner.title}}
+
+ {{banner.author_name}} 发起于 {{banner.published_at}}
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+ {{child.name}}
+ 发送者:{{child.createByName}} | 时间:{{child.createDate}}
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+ {{vuex_config.productName}}
+ {{vuex_config.productVersion}}
+
+
+
+
+
+
+
+ https://jeesite.com
+
+
+ http://s.jeesite.com/
+
+
+
+ 卓源软件 版权所有
+ Copyright © 2021 jeesite.com
+ All Rights Reserved
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+ {{child.name}}
+ 发送者:{{child.createByName}} | 时间:{{child.createDate}}
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+ 选择头像
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{this.$u.date(model.last_time, 'yyyy-mm-dd hh:MM:ss')}}
+
+
+ {{model.last_ip}}
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+ ID: {{item.testInput || item.id}}
+ 访问路径:{{item.url}} | 时间:{{item.created_at}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+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 @@
+
+
+
+ {{tips.text}}
+
+
+
+ {{item.text}}
+ {{item.subText}}
+
+
+
+
+ {{cancelText}}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+ {{title}}
+
+
+ {{description}}
+
+
+
+
+
+ {{closeText}}
+
+
+
+
+
+
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 @@
+
+
+
+ {{uText}}
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{tips}}
+
+
+
+
+
+
+
+
+
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 @@
+
+
+ {{showText}}
+
+
+
+
+
+
\ 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 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ showTitle }}
+
+
+
+
+
+
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+ {{ index + 1 }}
+
+ {{startText}}
+ {{endText}}
+
+ {{month}}
+
+
+
+ {{mode == 'date' ? activeDate : startDate}}
+ 至{{endDate}}
+
+
+ 确定
+
+
+
+
+
+
+
+
\ 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 @@
+
+ {}">
+
+
+
+
+ {{ item }}
+
+
+
+
+
+
+ 中
+ /
+ 英
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+ {{ subTitle }}
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+ {{title}}
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+ {{ title }}
+
+
+
+ {{ label }}
+
+
+
+
+
+ {{ value }}
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{percent + '%'}}
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+ {{ item }}
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+ {{ d }}
+
+
+
+ {{ separator == 'colon' ? ':' : '天' }}
+
+
+
+ {{ h }}
+
+
+
+ {{ separator == 'colon' ? ':' : '时' }}
+
+
+
+ {{ i }}
+
+
+
+ {{ separator == 'colon' ? ':' : '分' }}
+
+
+
+ {{ s }}
+
+
+
+ 秒
+
+
+
+
+
+
+
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 @@
+
+
+ {{ displayValue }}
+
+
+
+
+
+
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 @@
+
+ {}" @tap.stop.prevent="() => {}">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ errorMessage }}
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-form-item/u-form-item.vue b/hotgo-uniapp/uview-ui/components/u-form-item/u-form-item.vue
new file mode 100644
index 0000000..d6b8c8b
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-form-item/u-form-item.vue
@@ -0,0 +1,431 @@
+
+
+
+
+
+
+
+
+ *
+
+
+
+
+ {{label}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{validateMessage}}
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-form/u-form.vue b/hotgo-uniapp/uview-ui/components/u-form/u-form.vue
new file mode 100644
index 0000000..bdbafaf
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-form/u-form.vue
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-full-screen/u-full-screen.vue b/hotgo-uniapp/uview-ui/components/u-full-screen/u-full-screen.vue
new file mode 100644
index 0000000..4f7e7d9
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-full-screen/u-full-screen.vue
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-gap/u-gap.vue b/hotgo-uniapp/uview-ui/components/u-gap/u-gap.vue
new file mode 100644
index 0000000..6c01f94
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-gap/u-gap.vue
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-grid-item/u-grid-item.vue b/hotgo-uniapp/uview-ui/components/u-grid-item/u-grid-item.vue
new file mode 100644
index 0000000..0773307
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-grid-item/u-grid-item.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-grid/u-grid.vue b/hotgo-uniapp/uview-ui/components/u-grid/u-grid.vue
new file mode 100644
index 0000000..6588c06
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-grid/u-grid.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-icon/u-icon.vue b/hotgo-uniapp/uview-ui/components/u-icon/u-icon.vue
new file mode 100644
index 0000000..db1b019
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-icon/u-icon.vue
@@ -0,0 +1,336 @@
+
+
+
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-image/u-image.vue b/hotgo-uniapp/uview-ui/components/u-image/u-image.vue
new file mode 100644
index 0000000..c729c3c
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-image/u-image.vue
@@ -0,0 +1,267 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-index-anchor/u-index-anchor.vue b/hotgo-uniapp/uview-ui/components/u-index-anchor/u-index-anchor.vue
new file mode 100644
index 0000000..5038827
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-index-anchor/u-index-anchor.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+ {{ index }}
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-index-list/u-index-list.vue b/hotgo-uniapp/uview-ui/components/u-index-list/u-index-list.vue
new file mode 100644
index 0000000..30fcda0
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-index-list/u-index-list.vue
@@ -0,0 +1,315 @@
+
+
+
+
+
+
+
+ {{indexList[touchmoveIndex]}}
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-input/u-input.vue b/hotgo-uniapp/uview-ui/components/u-input/u-input.vue
new file mode 100644
index 0000000..f2aea72
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-input/u-input.vue
@@ -0,0 +1,387 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-keyboard/u-keyboard.vue b/hotgo-uniapp/uview-ui/components/u-keyboard/u-keyboard.vue
new file mode 100644
index 0000000..1904a2b
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-keyboard/u-keyboard.vue
@@ -0,0 +1,217 @@
+
+
+
+
+
+ {{cancelBtn ? cancelText : ''}}
+
+
+ {{tips ? tips : mode == 'number' ? '数字键盘' : mode == 'card' ? '身份证键盘' : '车牌号键盘'}}
+
+
+ {{confirmBtn ? confirmText : ''}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-lazy-load/u-lazy-load.vue b/hotgo-uniapp/uview-ui/components/u-lazy-load/u-lazy-load.vue
new file mode 100644
index 0000000..429a680
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-lazy-load/u-lazy-load.vue
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-line-progress/u-line-progress.vue b/hotgo-uniapp/uview-ui/components/u-line-progress/u-line-progress.vue
new file mode 100644
index 0000000..77e2da2
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-line-progress/u-line-progress.vue
@@ -0,0 +1,147 @@
+
+
+
+
+
+ {{percent + '%'}}
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-line/u-line.vue b/hotgo-uniapp/uview-ui/components/u-line/u-line.vue
new file mode 100644
index 0000000..c56fbc3
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-line/u-line.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-link/u-link.vue b/hotgo-uniapp/uview-ui/components/u-link/u-link.vue
new file mode 100644
index 0000000..2dd2a73
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-link/u-link.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-loading-page/u-loading-page.vue b/hotgo-uniapp/uview-ui/components/u-loading-page/u-loading-page.vue
new file mode 100644
index 0000000..7e04401
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-loading-page/u-loading-page.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-loading/u-loading.vue b/hotgo-uniapp/uview-ui/components/u-loading/u-loading.vue
new file mode 100644
index 0000000..c747f64
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-loading/u-loading.vue
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-loadmore/u-loadmore.vue b/hotgo-uniapp/uview-ui/components/u-loadmore/u-loadmore.vue
new file mode 100644
index 0000000..6b852a8
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-loadmore/u-loadmore.vue
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+ {{ showText }}
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-mask/u-mask.vue b/hotgo-uniapp/uview-ui/components/u-mask/u-mask.vue
new file mode 100644
index 0000000..0b55d9d
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-mask/u-mask.vue
@@ -0,0 +1,123 @@
+
+ {}" :class="{
+ 'u-mask-zoom': zoom,
+ 'u-mask-show': show
+ }">
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-message-input/u-message-input.vue b/hotgo-uniapp/uview-ui/components/u-message-input/u-message-input.vue
new file mode 100644
index 0000000..41e0719
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-message-input/u-message-input.vue
@@ -0,0 +1,311 @@
+
+
+
+
+
+
+
+
+
+ {{ charArr[index] ? charArr[index] : ''}}
+
+ {{ charArr[index] ? '●' : ''}}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-modal/u-modal.vue b/hotgo-uniapp/uview-ui/components/u-modal/u-modal.vue
new file mode 100644
index 0000000..ce58113
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-modal/u-modal.vue
@@ -0,0 +1,283 @@
+
+
+
+
+ {{ title }}
+
+
+
+
+ {{ content }}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-navbar/u-navbar.vue b/hotgo-uniapp/uview-ui/components/u-navbar/u-navbar.vue
new file mode 100644
index 0000000..450242e
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-navbar/u-navbar.vue
@@ -0,0 +1,315 @@
+
+
+
+
+
+
+
+
+
+ {{ backText }}
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-no-network/u-no-network.vue b/hotgo-uniapp/uview-ui/components/u-no-network/u-no-network.vue
new file mode 100644
index 0000000..51d9f4f
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-no-network/u-no-network.vue
@@ -0,0 +1,233 @@
+
+ {}">
+
+
+
+ {{tips}}
+
+
+
+
+ 请检查网络,或前往设置
+
+
+
+ 重试
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-notice-bar/u-notice-bar.vue b/hotgo-uniapp/uview-ui/components/u-notice-bar/u-notice-bar.vue
new file mode 100644
index 0000000..41a6cc4
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-notice-bar/u-notice-bar.vue
@@ -0,0 +1,272 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-number-box/u-number-box.vue b/hotgo-uniapp/uview-ui/components/u-number-box/u-number-box.vue
new file mode 100644
index 0000000..54a679e
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-number-box/u-number-box.vue
@@ -0,0 +1,363 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-number-keyboard/u-number-keyboard.vue b/hotgo-uniapp/uview-ui/components/u-number-keyboard/u-number-keyboard.vue
new file mode 100644
index 0000000..6425a1f
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-number-keyboard/u-number-keyboard.vue
@@ -0,0 +1,158 @@
+
+ {}">
+
+
+ {{ item }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-parse/libs/CssHandler.js b/hotgo-uniapp/uview-ui/components/u-parse/libs/CssHandler.js
new file mode 100644
index 0000000..75c6015
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-parse/libs/CssHandler.js
@@ -0,0 +1,100 @@
+const cfg = require('./config.js'),
+ isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+
+function CssHandler(tagStyle) {
+ var styles = Object.assign(Object.create(null), cfg.userAgentStyles);
+ for (var item in tagStyle)
+ styles[item] = (styles[item] ? styles[item] + ';' : '') + tagStyle[item];
+ this.styles = styles;
+}
+CssHandler.prototype.getStyle = function(data) {
+ this.styles = new parser(data, this.styles).parse();
+}
+CssHandler.prototype.match = function(name, attrs) {
+ var tmp, matched = (tmp = this.styles[name]) ? tmp + ';' : '';
+ if (attrs.class) {
+ var items = attrs.class.split(' ');
+ for (var i = 0, item; item = items[i]; i++)
+ if (tmp = this.styles['.' + item])
+ matched += tmp + ';';
+ }
+ if (tmp = this.styles['#' + attrs.id])
+ matched += tmp + ';';
+ return matched;
+}
+module.exports = CssHandler;
+
+function parser(data, init) {
+ this.data = data;
+ this.floor = 0;
+ this.i = 0;
+ this.list = [];
+ this.res = init;
+ this.state = this.Space;
+}
+parser.prototype.parse = function() {
+ for (var c; c = this.data[this.i]; this.i++)
+ this.state(c);
+ return this.res;
+}
+parser.prototype.section = function() {
+ return this.data.substring(this.start, this.i);
+}
+// 状态机
+parser.prototype.Space = function(c) {
+ if (c == '.' || c == '#' || isLetter(c)) {
+ this.start = this.i;
+ this.state = this.Name;
+ } else if (c == '/' && this.data[this.i + 1] == '*')
+ this.Comment();
+ else if (!cfg.blankChar[c] && c != ';')
+ this.state = this.Ignore;
+}
+parser.prototype.Comment = function() {
+ this.i = this.data.indexOf('*/', this.i) + 1;
+ if (!this.i) this.i = this.data.length;
+ this.state = this.Space;
+}
+parser.prototype.Ignore = function(c) {
+ if (c == '{') this.floor++;
+ else if (c == '}' && !--this.floor) {
+ this.list = [];
+ this.state = this.Space;
+ }
+}
+parser.prototype.Name = function(c) {
+ if (cfg.blankChar[c]) {
+ this.list.push(this.section());
+ this.state = this.NameSpace;
+ } else if (c == '{') {
+ this.list.push(this.section());
+ this.Content();
+ } else if (c == ',') {
+ this.list.push(this.section());
+ this.Comma();
+ } else if (!isLetter(c) && (c < '0' || c > '9') && c != '-' && c != '_')
+ this.state = this.Ignore;
+}
+parser.prototype.NameSpace = function(c) {
+ if (c == '{') this.Content();
+ else if (c == ',') this.Comma();
+ else if (!cfg.blankChar[c]) this.state = this.Ignore;
+}
+parser.prototype.Comma = function() {
+ while (cfg.blankChar[this.data[++this.i]]);
+ if (this.data[this.i] == '{') this.Content();
+ else {
+ this.start = this.i--;
+ this.state = this.Name;
+ }
+}
+parser.prototype.Content = function() {
+ this.start = ++this.i;
+ if ((this.i = this.data.indexOf('}', this.i)) == -1) this.i = this.data.length;
+ var content = this.section();
+ for (var i = 0, item; item = this.list[i++];)
+ if (this.res[item]) this.res[item] += ';' + content;
+ else this.res[item] = content;
+ this.list = [];
+ this.state = this.Space;
+}
diff --git a/hotgo-uniapp/uview-ui/components/u-parse/libs/MpHtmlParser.js b/hotgo-uniapp/uview-ui/components/u-parse/libs/MpHtmlParser.js
new file mode 100644
index 0000000..aeb0fc3
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-parse/libs/MpHtmlParser.js
@@ -0,0 +1,580 @@
+/**
+ * html 解析器
+ * @tutorial https://github.com/jin-yufeng/Parser
+ * @version 20201029
+ * @author JinYufeng
+ * @listens MIT
+ */
+const cfg = require('./config.js'),
+ blankChar = cfg.blankChar,
+ CssHandler = require('./CssHandler.js'),
+ windowWidth = uni.getSystemInfoSync().windowWidth;
+var emoji;
+
+function MpHtmlParser(data, options = {}) {
+ this.attrs = {};
+ this.CssHandler = new CssHandler(options.tagStyle, windowWidth);
+ this.data = data;
+ this.domain = options.domain;
+ this.DOM = [];
+ this.i = this.start = this.audioNum = this.imgNum = this.videoNum = 0;
+ options.prot = (this.domain || '').includes('://') ? this.domain.split('://')[0] : 'http';
+ this.options = options;
+ this.state = this.Text;
+ this.STACK = [];
+ // 工具函数
+ this.bubble = () => {
+ for (var i = this.STACK.length, item; item = this.STACK[--i];) {
+ if (cfg.richOnlyTags[item.name]) return false;
+ item.c = 1;
+ }
+ return true;
+ }
+ this.decode = (val, amp) => {
+ var i = -1,
+ j, en;
+ while (1) {
+ if ((i = val.indexOf('&', i + 1)) == -1) break;
+ if ((j = val.indexOf(';', i + 2)) == -1) break;
+ if (val[i + 1] == '#') {
+ en = parseInt((val[i + 2] == 'x' ? '0' : '') + val.substring(i + 2, j));
+ if (!isNaN(en)) val = val.substr(0, i) + String.fromCharCode(en) + val.substr(j + 1);
+ } else {
+ en = val.substring(i + 1, j);
+ if (cfg.entities[en] || en == amp)
+ val = val.substr(0, i) + (cfg.entities[en] || '&') + val.substr(j + 1);
+ }
+ }
+ return val;
+ }
+ this.getUrl = url => {
+ if (url[0] == '/') {
+ if (url[1] == '/') url = this.options.prot + ':' + url;
+ else if (this.domain) url = this.domain + url;
+ } else if (this.domain && url.indexOf('data:') != 0 && !url.includes('://'))
+ url = this.domain + '/' + url;
+ return url;
+ }
+ this.isClose = () => this.data[this.i] == '>' || (this.data[this.i] == '/' && this.data[this.i + 1] == '>');
+ this.section = () => this.data.substring(this.start, this.i);
+ this.parent = () => this.STACK[this.STACK.length - 1];
+ this.siblings = () => this.STACK.length ? this.parent().children : this.DOM;
+}
+MpHtmlParser.prototype.parse = function() {
+ if (emoji) this.data = emoji.parseEmoji(this.data);
+ for (var c; c = this.data[this.i]; this.i++)
+ this.state(c);
+ if (this.state == this.Text) this.setText();
+ while (this.STACK.length) this.popNode(this.STACK.pop());
+ return this.DOM;
+}
+// 设置属性
+MpHtmlParser.prototype.setAttr = function() {
+ var name = this.attrName.toLowerCase(),
+ val = this.attrVal;
+ if (cfg.boolAttrs[name]) this.attrs[name] = 'T';
+ else if (val) {
+ if (name == 'src' || (name == 'data-src' && !this.attrs.src)) this.attrs.src = this.getUrl(this.decode(val, 'amp'));
+ else if (name == 'href' || name == 'style') this.attrs[name] = this.decode(val, 'amp');
+ else if (name.substr(0, 5) != 'data-') this.attrs[name] = val;
+ }
+ this.attrVal = '';
+ while (blankChar[this.data[this.i]]) this.i++;
+ if (this.isClose()) this.setNode();
+ else {
+ this.start = this.i;
+ this.state = this.AttrName;
+ }
+}
+// 设置文本节点
+MpHtmlParser.prototype.setText = function() {
+ var back, text = this.section();
+ if (!text) return;
+ text = (cfg.onText && cfg.onText(text, () => back = true)) || text;
+ if (back) {
+ this.data = this.data.substr(0, this.start) + text + this.data.substr(this.i);
+ let j = this.start + text.length;
+ for (this.i = this.start; this.i < j; this.i++) this.state(this.data[this.i]);
+ return;
+ }
+ if (!this.pre) {
+ // 合并空白符
+ var flag, tmp = [];
+ for (let i = text.length, c; c = text[--i];)
+ if (!blankChar[c]) {
+ tmp.unshift(c);
+ if (!flag) flag = 1;
+ } else {
+ if (tmp[0] != ' ') tmp.unshift(' ');
+ if (c == '\n' && flag == void 0) flag = 0;
+ }
+ if (flag == 0) return;
+ text = tmp.join('');
+ }
+ this.siblings().push({
+ type: 'text',
+ text: this.decode(text)
+ });
+}
+// 设置元素节点
+MpHtmlParser.prototype.setNode = function() {
+ var node = {
+ name: this.tagName.toLowerCase(),
+ attrs: this.attrs
+ },
+ close = cfg.selfClosingTags[node.name];
+ if (this.options.nodes.length) node.type = 'node';
+ this.attrs = {};
+ if (!cfg.ignoreTags[node.name]) {
+ // 处理属性
+ var attrs = node.attrs,
+ style = this.CssHandler.match(node.name, attrs, node) + (attrs.style || ''),
+ styleObj = {};
+ if (attrs.id) {
+ if (this.options.compress & 1) attrs.id = void 0;
+ else if (this.options.useAnchor) this.bubble();
+ }
+ if ((this.options.compress & 2) && attrs.class) attrs.class = void 0;
+ switch (node.name) {
+ case 'a':
+ case 'ad': // #ifdef APP-PLUS
+ case 'iframe':
+ // #endif
+ this.bubble();
+ break;
+ case 'font':
+ if (attrs.color) {
+ styleObj['color'] = attrs.color;
+ attrs.color = void 0;
+ }
+ if (attrs.face) {
+ styleObj['font-family'] = attrs.face;
+ attrs.face = void 0;
+ }
+ if (attrs.size) {
+ var size = parseInt(attrs.size);
+ if (size < 1) size = 1;
+ else if (size > 7) size = 7;
+ var map = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];
+ styleObj['font-size'] = map[size - 1];
+ attrs.size = void 0;
+ }
+ break;
+ case 'embed':
+ // #ifndef APP-PLUS
+ var src = node.attrs.src || '',
+ type = node.attrs.type || '';
+ if (type.includes('video') || src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8'))
+ node.name = 'video';
+ else if (type.includes('audio') || src.includes('.m4a') || src.includes('.wav') || src.includes('.mp3') || src.includes(
+ '.aac'))
+ node.name = 'audio';
+ else break;
+ if (node.attrs.autostart)
+ node.attrs.autoplay = 'T';
+ node.attrs.controls = 'T';
+ // #endif
+ // #ifdef APP-PLUS
+ this.bubble();
+ break;
+ // #endif
+ case 'video':
+ case 'audio':
+ if (!attrs.id) attrs.id = node.name + (++this[`${node.name}Num`]);
+ else this[`${node.name}Num`]++;
+ if (node.name == 'video') {
+ if (this.videoNum > 3)
+ node.lazyLoad = 1;
+ if (attrs.width) {
+ styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px');
+ attrs.width = void 0;
+ }
+ if (attrs.height) {
+ styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px');
+ attrs.height = void 0;
+ }
+ }
+ if (!attrs.controls && !attrs.autoplay) attrs.controls = 'T';
+ attrs.source = [];
+ if (attrs.src) {
+ attrs.source.push(attrs.src);
+ attrs.src = void 0;
+ }
+ this.bubble();
+ break;
+ case 'td':
+ case 'th':
+ if (attrs.colspan || attrs.rowspan)
+ for (var k = this.STACK.length, item; item = this.STACK[--k];)
+ if (item.name == 'table') {
+ item.flag = 1;
+ break;
+ }
+ }
+ if (attrs.align) {
+ if (node.name == 'table') {
+ if (attrs.align == 'center') styleObj['margin-inline-start'] = styleObj['margin-inline-end'] = 'auto';
+ else styleObj['float'] = attrs.align;
+ } else styleObj['text-align'] = attrs.align;
+ attrs.align = void 0;
+ }
+ // 压缩 style
+ var styles = style.split(';');
+ style = '';
+ for (var i = 0, len = styles.length; i < len; i++) {
+ var info = styles[i].split(':');
+ if (info.length < 2) continue;
+ let key = info[0].trim().toLowerCase(),
+ value = info.slice(1).join(':').trim();
+ if (value[0] == '-' || value.includes('safe'))
+ style += `;${key}:${value}`;
+ else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import'))
+ styleObj[key] = value;
+ }
+ if (node.name == 'img') {
+ if (attrs.src && !attrs.ignore) {
+ if (this.bubble())
+ attrs.i = (this.imgNum++).toString();
+ else attrs.ignore = 'T';
+ }
+ if (attrs.ignore) {
+ style += ';-webkit-touch-callout:none';
+ styleObj['max-width'] = '100%';
+ }
+ var width;
+ if (styleObj.width) width = styleObj.width;
+ else if (attrs.width) width = attrs.width.includes('%') ? attrs.width : parseFloat(attrs.width) + 'px';
+ if (width) {
+ styleObj.width = width;
+ attrs.width = '100%';
+ if (parseInt(width) > windowWidth) {
+ styleObj.height = '';
+ if (attrs.height) attrs.height = void 0;
+ }
+ }
+ if (styleObj.height) {
+ attrs.height = styleObj.height;
+ styleObj.height = '';
+ } else if (attrs.height && !attrs.height.includes('%'))
+ attrs.height = parseFloat(attrs.height) + 'px';
+ }
+ for (var key in styleObj) {
+ var value = styleObj[key];
+ if (!value) continue;
+ if (key.includes('flex') || key == 'order' || key == 'self-align') node.c = 1;
+ // 填充链接
+ if (value.includes('url')) {
+ var j = value.indexOf('(');
+ if (j++ != -1) {
+ while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) j++;
+ value = value.substr(0, j) + this.getUrl(value.substr(j));
+ }
+ }
+ // 转换 rpx
+ else if (value.includes('rpx'))
+ value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px');
+ else if (key == 'white-space' && value.includes('pre') && !close)
+ this.pre = node.pre = true;
+ style += `;${key}:${value}`;
+ }
+ style = style.substr(1);
+ if (style) attrs.style = style;
+ if (!close) {
+ node.children = [];
+ if (node.name == 'pre' && cfg.highlight) {
+ this.remove(node);
+ this.pre = node.pre = true;
+ }
+ this.siblings().push(node);
+ this.STACK.push(node);
+ } else if (!cfg.filter || cfg.filter(node, this) != false)
+ this.siblings().push(node);
+ } else {
+ if (!close) this.remove(node);
+ else if (node.name == 'source') {
+ var parent = this.parent();
+ if (parent && (parent.name == 'video' || parent.name == 'audio') && node.attrs.src)
+ parent.attrs.source.push(node.attrs.src);
+ } else if (node.name == 'base' && !this.domain) this.domain = node.attrs.href;
+ }
+ if (this.data[this.i] == '/') this.i++;
+ this.start = this.i + 1;
+ this.state = this.Text;
+}
+// 移除标签
+MpHtmlParser.prototype.remove = function(node) {
+ var name = node.name,
+ j = this.i;
+ // 处理 svg
+ var handleSvg = () => {
+ var src = this.data.substring(j, this.i + 1);
+ node.attrs.xmlns = 'http://www.w3.org/2000/svg';
+ for (var key in node.attrs) {
+ if (key == 'viewbox') src = ` viewBox="${node.attrs.viewbox}"` + src;
+ else if (key != 'style') src = ` ${key}="${node.attrs[key]}"` + src;
+ }
+ src = '', this.i)) == -1) this.i = this.data.length;
+ if (name == 'svg') handleSvg();
+ return;
+ }
+ }
+}
+// 节点出栈处理
+MpHtmlParser.prototype.popNode = function(node) {
+ // 空白符处理
+ if (node.pre) {
+ node.pre = this.pre = void 0;
+ for (let i = this.STACK.length; i--;)
+ if (this.STACK[i].pre)
+ this.pre = true;
+ }
+ var siblings = this.siblings(),
+ len = siblings.length,
+ childs = node.children;
+ if (node.name == 'head' || (cfg.filter && cfg.filter(node, this) == false))
+ return siblings.pop();
+ var attrs = node.attrs;
+ // 替换一些标签名
+ if (cfg.blockTags[node.name]) node.name = 'div';
+ else if (!cfg.trustTags[node.name]) node.name = 'span';
+ // 处理列表
+ if (node.c && (node.name == 'ul' || node.name == 'ol')) {
+ if ((node.attrs.style || '').includes('list-style:none')) {
+ for (let i = 0, child; child = childs[i++];)
+ if (child.name == 'li')
+ child.name = 'div';
+ } else if (node.name == 'ul') {
+ var floor = 1;
+ for (let i = this.STACK.length; i--;)
+ if (this.STACK[i].name == 'ul') floor++;
+ if (floor != 1)
+ for (let i = childs.length; i--;)
+ childs[i].floor = floor;
+ } else {
+ for (let i = 0, num = 1, child; child = childs[i++];)
+ if (child.name == 'li') {
+ child.type = 'ol';
+ child.num = ((num, type) => {
+ if (type == 'a') return String.fromCharCode(97 + (num - 1) % 26);
+ if (type == 'A') return String.fromCharCode(65 + (num - 1) % 26);
+ if (type == 'i' || type == 'I') {
+ num = (num - 1) % 99 + 1;
+ var one = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
+ ten = ['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],
+ res = (ten[Math.floor(num / 10) - 1] || '') + (one[num % 10 - 1] || '');
+ if (type == 'i') return res.toLowerCase();
+ return res;
+ }
+ return num;
+ })(num++, attrs.type) + '.';
+ }
+ }
+ }
+ // 处理表格
+ if (node.name == 'table') {
+ var padding = parseFloat(attrs.cellpadding),
+ spacing = parseFloat(attrs.cellspacing),
+ border = parseFloat(attrs.border);
+ if (node.c) {
+ if (isNaN(padding)) padding = 2;
+ if (isNaN(spacing)) spacing = 2;
+ }
+ if (border) attrs.style = `border:${border}px solid gray;${attrs.style || ''}`;
+ if (node.flag && node.c) {
+ // 有 colspan 或 rowspan 且含有链接的表格转为 grid 布局实现
+ attrs.style = `${attrs.style || ''};${spacing ? `;grid-gap:${spacing}px` : ';border-left:0;border-top:0'}`;
+ var row = 1,
+ col = 1,
+ colNum,
+ trs = [],
+ children = [],
+ map = {};
+ (function f(ns) {
+ for (var i = 0; i < ns.length; i++) {
+ if (ns[i].name == 'tr') trs.push(ns[i]);
+ else f(ns[i].children || []);
+ }
+ })(node.children)
+ for (let i = 0; i < trs.length; i++) {
+ for (let j = 0, td; td = trs[i].children[j]; j++) {
+ if (td.name == 'td' || td.name == 'th') {
+ while (map[row + '.' + col]) col++;
+ var cell = {
+ name: 'div',
+ c: 1,
+ attrs: {
+ style: (td.attrs.style || '') + (border ? `;border:${border}px solid gray` + (spacing ? '' :
+ ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '')
+ },
+ children: td.children
+ }
+ if (td.attrs.colspan) {
+ cell.attrs.style += ';grid-column-start:' + col + ';grid-column-end:' + (col + parseInt(td.attrs.colspan));
+ if (!td.attrs.rowspan) cell.attrs.style += ';grid-row-start:' + row + ';grid-row-end:' + (row + 1);
+ col += parseInt(td.attrs.colspan) - 1;
+ }
+ if (td.attrs.rowspan) {
+ cell.attrs.style += ';grid-row-start:' + row + ';grid-row-end:' + (row + parseInt(td.attrs.rowspan));
+ if (!td.attrs.colspan) cell.attrs.style += ';grid-column-start:' + col + ';grid-column-end:' + (col + 1);
+ for (var k = 1; k < td.attrs.rowspan; k++) map[(row + k) + '.' + col] = 1;
+ }
+ children.push(cell);
+ col++;
+ }
+ }
+ if (!colNum) {
+ colNum = col - 1;
+ attrs.style += `;grid-template-columns:repeat(${colNum},auto)`
+ }
+ col = 1;
+ row++;
+ }
+ node.children = children;
+ } else {
+ attrs.style = `border-spacing:${spacing}px;${attrs.style || ''}`;
+ if (border || padding)
+ (function f(ns) {
+ for (var i = 0, n; n = ns[i]; i++) {
+ if (n.name == 'th' || n.name == 'td') {
+ if (border) n.attrs.style = `border:${border}px solid gray;${n.attrs.style || ''}`;
+ if (padding) n.attrs.style = `padding:${padding}px;${n.attrs.style || ''}`;
+ } else f(n.children || []);
+ }
+ })(childs)
+ }
+ if (this.options.autoscroll) {
+ var table = Object.assign({}, node);
+ node.name = 'div';
+ node.attrs = {
+ style: 'overflow:scroll'
+ }
+ node.children = [table];
+ }
+ }
+ this.CssHandler.pop && this.CssHandler.pop(node);
+ // 自动压缩
+ if (node.name == 'div' && !Object.keys(attrs).length && childs.length == 1 && childs[0].name == 'div')
+ siblings[len - 1] = childs[0];
+}
+// 状态机
+MpHtmlParser.prototype.Text = function(c) {
+ if (c == '<') {
+ var next = this.data[this.i + 1],
+ isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+ if (isLetter(next)) {
+ this.setText();
+ this.start = this.i + 1;
+ this.state = this.TagName;
+ } else if (next == '/') {
+ this.setText();
+ if (isLetter(this.data[++this.i + 1])) {
+ this.start = this.i + 1;
+ this.state = this.EndTag;
+ } else this.Comment();
+ } else if (next == '!' || next == '?') {
+ this.setText();
+ this.Comment();
+ }
+ }
+}
+MpHtmlParser.prototype.Comment = function() {
+ var key;
+ if (this.data.substring(this.i + 2, this.i + 4) == '--') key = '-->';
+ else if (this.data.substring(this.i + 2, this.i + 9) == '[CDATA[') key = ']]>';
+ else key = '>';
+ if ((this.i = this.data.indexOf(key, this.i + 2)) == -1) this.i = this.data.length;
+ else this.i += key.length - 1;
+ this.start = this.i + 1;
+ this.state = this.Text;
+}
+MpHtmlParser.prototype.TagName = function(c) {
+ if (blankChar[c]) {
+ this.tagName = this.section();
+ while (blankChar[this.data[this.i]]) this.i++;
+ if (this.isClose()) this.setNode();
+ else {
+ this.start = this.i;
+ this.state = this.AttrName;
+ }
+ } else if (this.isClose()) {
+ this.tagName = this.section();
+ this.setNode();
+ }
+}
+MpHtmlParser.prototype.AttrName = function(c) {
+ if (c == '=' || blankChar[c] || this.isClose()) {
+ this.attrName = this.section();
+ if (blankChar[c])
+ while (blankChar[this.data[++this.i]]);
+ if (this.data[this.i] == '=') {
+ while (blankChar[this.data[++this.i]]);
+ this.start = this.i--;
+ this.state = this.AttrValue;
+ } else this.setAttr();
+ }
+}
+MpHtmlParser.prototype.AttrValue = function(c) {
+ if (c == '"' || c == "'") {
+ this.start++;
+ if ((this.i = this.data.indexOf(c, this.i + 1)) == -1) return this.i = this.data.length;
+ this.attrVal = this.section();
+ this.i++;
+ } else {
+ for (; !blankChar[this.data[this.i]] && !this.isClose(); this.i++);
+ this.attrVal = this.section();
+ }
+ this.setAttr();
+}
+MpHtmlParser.prototype.EndTag = function(c) {
+ if (blankChar[c] || c == '>' || c == '/') {
+ var name = this.section().toLowerCase();
+ for (var i = this.STACK.length; i--;)
+ if (this.STACK[i].name == name) break;
+ if (i != -1) {
+ var node;
+ while ((node = this.STACK.pop()).name != name) this.popNode(node);
+ this.popNode(node);
+ } else if (name == 'p' || name == 'br')
+ this.siblings().push({
+ name,
+ attrs: {}
+ });
+ this.i = this.data.indexOf('>', this.i);
+ this.start = this.i + 1;
+ if (this.i == -1) this.i = this.data.length;
+ else this.state = this.Text;
+ }
+}
+module.exports = MpHtmlParser;
diff --git a/hotgo-uniapp/uview-ui/components/u-parse/libs/config.js b/hotgo-uniapp/uview-ui/components/u-parse/libs/config.js
new file mode 100644
index 0000000..1f772e9
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-parse/libs/config.js
@@ -0,0 +1,80 @@
+/* 配置文件 */
+var cfg = {
+ // 出错占位图
+ errorImg: null,
+ // 过滤器函数
+ filter: null,
+ // 代码高亮函数
+ highlight: null,
+ // 文本处理函数
+ onText: null,
+ // 实体编码列表
+ entities: {
+ quot: '"',
+ apos: "'",
+ semi: ';',
+ nbsp: '\xA0',
+ ensp: '\u2002',
+ emsp: '\u2003',
+ ndash: '–',
+ mdash: '—',
+ middot: '·',
+ lsquo: '‘',
+ rsquo: '’',
+ ldquo: '“',
+ rdquo: '”',
+ bull: '•',
+ hellip: '…'
+ },
+ blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'),
+ boolAttrs: makeMap('allowfullscreen,autoplay,autostart,controls,ignore,loop,muted'),
+ // 块级标签,将被转为 div
+ blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
+ // 将被移除的标签
+ ignoreTags: makeMap('area,base,canvas,frame,iframe,input,link,map,meta,param,script,source,style,svg,textarea,title,track,wbr'),
+ // 只能被 rich-text 显示的标签
+ richOnlyTags: makeMap('a,colgroup,fieldset,legend'),
+ // 自闭合的标签
+ selfClosingTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
+ // 信任的标签
+ trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
+ // 默认的标签样式
+ userAgentStyles: {
+ address: 'font-style:italic',
+ big: 'display:inline;font-size:1.2em',
+ blockquote: 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px',
+ caption: 'display:table-caption;text-align:center',
+ center: 'text-align:center',
+ cite: 'font-style:italic',
+ dd: 'margin-left:40px',
+ mark: 'background-color:yellow',
+ pre: 'font-family:monospace;white-space:pre;overflow:scroll',
+ s: 'text-decoration:line-through',
+ small: 'display:inline;font-size:0.8em',
+ u: 'text-decoration:underline'
+ }
+}
+
+function makeMap(str) {
+ var map = Object.create(null),
+ list = str.split(',');
+ for (var i = list.length; i--;)
+ map[list[i]] = true;
+ return map;
+}
+
+// #ifdef MP-WEIXIN
+if (wx.canIUse('editor')) {
+ cfg.blockTags.pre = void 0;
+ cfg.ignoreTags.rp = true;
+ Object.assign(cfg.richOnlyTags, makeMap('bdi,bdo,caption,rt,ruby'));
+ Object.assign(cfg.trustTags, makeMap('bdi,bdo,caption,pre,rt,ruby'));
+}
+// #endif
+
+// #ifdef APP-PLUS
+cfg.ignoreTags.iframe = void 0;
+Object.assign(cfg.trustTags, makeMap('embed,iframe'));
+// #endif
+
+module.exports = cfg;
diff --git a/hotgo-uniapp/uview-ui/components/u-parse/libs/handler.wxs b/hotgo-uniapp/uview-ui/components/u-parse/libs/handler.wxs
new file mode 100644
index 0000000..d3b1aaa
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-parse/libs/handler.wxs
@@ -0,0 +1,22 @@
+var inline = {
+ abbr: 1,
+ b: 1,
+ big: 1,
+ code: 1,
+ del: 1,
+ em: 1,
+ i: 1,
+ ins: 1,
+ label: 1,
+ q: 1,
+ small: 1,
+ span: 1,
+ strong: 1,
+ sub: 1,
+ sup: 1
+}
+module.exports = {
+ use: function(item) {
+ return !item.c && !inline[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1
+ }
+}
diff --git a/hotgo-uniapp/uview-ui/components/u-parse/libs/trees.vue b/hotgo-uniapp/uview-ui/components/u-parse/libs/trees.vue
new file mode 100644
index 0000000..2b24820
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-parse/libs/trees.vue
@@ -0,0 +1,505 @@
+
+
+
+
+
+
+
+
+
+ {{n.text}}
+
+ \n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{n.num}}
+
+ █
+
+ █
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-parse/u-parse.vue b/hotgo-uniapp/uview-ui/components/u-parse/u-parse.vue
new file mode 100644
index 0000000..57a105e
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-parse/u-parse.vue
@@ -0,0 +1,645 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-picker/u-picker.vue b/hotgo-uniapp/uview-ui/components/u-picker/u-picker.vue
new file mode 100644
index 0000000..68212a4
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-picker/u-picker.vue
@@ -0,0 +1,676 @@
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+ {{ item.label }}
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+ {{ item }}
+ 年
+
+
+
+
+ {{ formatNumber(item) }}
+ 月
+
+
+
+
+ {{ formatNumber(item) }}
+ 日
+
+
+
+
+ {{ formatNumber(item) }}
+ 时
+
+
+
+
+ {{ formatNumber(item) }}
+ 分
+
+
+
+
+ {{ formatNumber(item) }}
+ 秒
+
+
+
+
+
+
+ {{ getItemValue(item, 'selector') }}
+
+
+
+
+
+
+ {{ getItemValue(item1, 'multiSelector') }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-popup/u-popup.vue b/hotgo-uniapp/uview-ui/components/u-popup/u-popup.vue
new file mode 100644
index 0000000..69c0ec8
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-popup/u-popup.vue
@@ -0,0 +1,456 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-radio-group/u-radio-group.vue b/hotgo-uniapp/uview-ui/components/u-radio-group/u-radio-group.vue
new file mode 100644
index 0000000..2172eb2
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-radio-group/u-radio-group.vue
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-radio/u-radio.vue b/hotgo-uniapp/uview-ui/components/u-radio/u-radio.vue
new file mode 100644
index 0000000..1d9a439
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-radio/u-radio.vue
@@ -0,0 +1,271 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-rate/u-rate.vue b/hotgo-uniapp/uview-ui/components/u-rate/u-rate.vue
new file mode 100644
index 0000000..17eb3a8
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-rate/u-rate.vue
@@ -0,0 +1,275 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-read-more/u-read-more.vue b/hotgo-uniapp/uview-ui/components/u-read-more/u-read-more.vue
new file mode 100644
index 0000000..a77a44f
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-read-more/u-read-more.vue
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+ {{ showMore ? openText : closeText }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-row-notice/u-row-notice.vue b/hotgo-uniapp/uview-ui/components/u-row-notice/u-row-notice.vue
new file mode 100644
index 0000000..f4683f1
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-row-notice/u-row-notice.vue
@@ -0,0 +1,269 @@
+
+
+
+
+
+
+
+
+ {{showText}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-row/u-row.vue b/hotgo-uniapp/uview-ui/components/u-row/u-row.vue
new file mode 100644
index 0000000..915dfa6
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-row/u-row.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-search/u-search.vue b/hotgo-uniapp/uview-ui/components/u-search/u-search.vue
new file mode 100644
index 0000000..206f661
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-search/u-search.vue
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ actionText }}
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-section/u-section.vue b/hotgo-uniapp/uview-ui/components/u-section/u-section.vue
new file mode 100644
index 0000000..02293ce
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-section/u-section.vue
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+ {{title}}
+
+
+
+
+ {{subTitle}}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-select/u-select.vue b/hotgo-uniapp/uview-ui/components/u-select/u-select.vue
new file mode 100644
index 0000000..4c76474
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-select/u-select.vue
@@ -0,0 +1,424 @@
+
+
+
+
+
+
+
+
+
+
+ {{ item1[labelName] }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-skeleton/u-skeleton.vue b/hotgo-uniapp/uview-ui/components/u-skeleton/u-skeleton.vue
new file mode 100644
index 0000000..c8cb19e
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-skeleton/u-skeleton.vue
@@ -0,0 +1,199 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-slider/u-slider.vue b/hotgo-uniapp/uview-ui/components/u-slider/u-slider.vue
new file mode 100644
index 0000000..6d21b92
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-slider/u-slider.vue
@@ -0,0 +1,257 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-steps/u-steps.vue b/hotgo-uniapp/uview-ui/components/u-steps/u-steps.vue
new file mode 100644
index 0000000..a72cfcf
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-steps/u-steps.vue
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+ {{ index + 1 }}
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-sticky/u-sticky.vue b/hotgo-uniapp/uview-ui/components/u-sticky/u-sticky.vue
new file mode 100644
index 0000000..d9bc34c
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-sticky/u-sticky.vue
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-subsection/u-subsection.vue b/hotgo-uniapp/uview-ui/components/u-subsection/u-subsection.vue
new file mode 100644
index 0000000..b8fbd79
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-subsection/u-subsection.vue
@@ -0,0 +1,355 @@
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-swipe-action/u-swipe-action.vue b/hotgo-uniapp/uview-ui/components/u-swipe-action/u-swipe-action.vue
new file mode 100644
index 0000000..13fb33c
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-swipe-action/u-swipe-action.vue
@@ -0,0 +1,255 @@
+
+
+
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-swiper/u-swiper.vue b/hotgo-uniapp/uview-ui/components/u-swiper/u-swiper.vue
new file mode 100644
index 0000000..b6e7e81
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-swiper/u-swiper.vue
@@ -0,0 +1,340 @@
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ uCurrent + 1 }}/{{ list.length }}
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-switch/u-switch.vue b/hotgo-uniapp/uview-ui/components/u-switch/u-switch.vue
new file mode 100644
index 0000000..dd8e4bb
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-switch/u-switch.vue
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-tabbar/u-tabbar.vue b/hotgo-uniapp/uview-ui/components/u-tabbar/u-tabbar.vue
new file mode 100644
index 0000000..2e1b6a2
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-tabbar/u-tabbar.vue
@@ -0,0 +1,330 @@
+
+ {}">
+
+
+
+
+
+
+
+ {{item.text}}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-table/u-table.vue b/hotgo-uniapp/uview-ui/components/u-table/u-table.vue
new file mode 100644
index 0000000..79df16f
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-table/u-table.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-tabs-swiper/u-tabs-swiper.vue b/hotgo-uniapp/uview-ui/components/u-tabs-swiper/u-tabs-swiper.vue
new file mode 100644
index 0000000..a53e261
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-tabs-swiper/u-tabs-swiper.vue
@@ -0,0 +1,488 @@
+
+
+
+
+
+
+ {{ item[name] || item['name']}}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-tabs/u-tabs.vue b/hotgo-uniapp/uview-ui/components/u-tabs/u-tabs.vue
new file mode 100644
index 0000000..0c59658
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-tabs/u-tabs.vue
@@ -0,0 +1,369 @@
+
+
+
+
+
+
+
+
+ {{ item[name] || item['name']}}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-tag/u-tag.vue b/hotgo-uniapp/uview-ui/components/u-tag/u-tag.vue
new file mode 100644
index 0000000..90ec3f4
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-tag/u-tag.vue
@@ -0,0 +1,294 @@
+
+
+ {{text}}
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-td/u-td.vue b/hotgo-uniapp/uview-ui/components/u-td/u-td.vue
new file mode 100644
index 0000000..b00ad8b
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-td/u-td.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-th/u-th.vue b/hotgo-uniapp/uview-ui/components/u-th/u-th.vue
new file mode 100644
index 0000000..9fe5a16
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-th/u-th.vue
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-time-line-item/u-time-line-item.vue b/hotgo-uniapp/uview-ui/components/u-time-line-item/u-time-line-item.vue
new file mode 100644
index 0000000..be86fdc
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-time-line-item/u-time-line-item.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-time-line/u-time-line.vue b/hotgo-uniapp/uview-ui/components/u-time-line/u-time-line.vue
new file mode 100644
index 0000000..f3c7587
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-time-line/u-time-line.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-toast/u-toast.vue b/hotgo-uniapp/uview-ui/components/u-toast/u-toast.vue
new file mode 100644
index 0000000..a2209a5
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-toast/u-toast.vue
@@ -0,0 +1,220 @@
+
+
+
+
+
+ {{tmpConfig.title}}
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-top-tips/u-top-tips.vue b/hotgo-uniapp/uview-ui/components/u-top-tips/u-top-tips.vue
new file mode 100644
index 0000000..98d58df
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-top-tips/u-top-tips.vue
@@ -0,0 +1,121 @@
+
+ {{ title }}
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-tr/u-tr.vue b/hotgo-uniapp/uview-ui/components/u-tr/u-tr.vue
new file mode 100644
index 0000000..06aed4a
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-tr/u-tr.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-upload/u-upload.vue b/hotgo-uniapp/uview-ui/components/u-upload/u-upload.vue
new file mode 100644
index 0000000..e58bb65
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-upload/u-upload.vue
@@ -0,0 +1,660 @@
+
+
+
+
+
+
+
+ 点击重试
+
+
+
+
+
+
+
+ {{ uploadText }}
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-verification-code/u-verification-code.vue b/hotgo-uniapp/uview-ui/components/u-verification-code/u-verification-code.vue
new file mode 100644
index 0000000..b3079f4
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-verification-code/u-verification-code.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/components/u-waterfall/u-waterfall.vue b/hotgo-uniapp/uview-ui/components/u-waterfall/u-waterfall.vue
new file mode 100644
index 0000000..31964b7
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/components/u-waterfall/u-waterfall.vue
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-uniapp/uview-ui/iconfont.css b/hotgo-uniapp/uview-ui/iconfont.css
new file mode 100644
index 0000000..836c718
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/iconfont.css
@@ -0,0 +1,910 @@
+/* #ifdef APP-PLUS */
+@font-face {
+ font-family: "uicon-iconfont";
+ font-weight: normal;
+ font-style: normal;
+ font-display: auto;
+ src: url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2');
+}
+
+/* #endif */
+
+/* 支付宝,百度,头条小程序目前读取大的本地字体文件,导致无法显示图标,故用在线加载的方式-2020-05-12 */
+/* #ifndef APP-PLUS */
+@font-face {
+ font-family: "uicon-iconfont";
+ src: url('//at.alicdn.com/t/font_1529455_k4s6di1d1.eot?t=1596960292384');
+ /* IE9 */
+ src: url('//at.alicdn.com/t/font_1529455_k4s6di1d1.eot?t=1596960292384#iefix') format('embedded-opentype'),
+ /* IE6-IE8 */
+ url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
+ url('//at.alicdn.com/t/font_1529455_k4s6di1d1.woff?t=1596960292384') format('woff'),
+ url('//at.alicdn.com/t/font_1529455_k4s6di1d1.ttf?t=1596960292384') format('truetype'),
+ /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
+ url('//at.alicdn.com/t/font_1529455_k4s6di1d1.svg?t=1596960292384#iconfont') format('svg');
+}
+
+/* #endif */
+
+.u-iconfont {
+ position: relative;
+ display: flex;
+ font: normal normal normal 14px/1 "uicon-iconfont";
+ font-size: inherit;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.u-iconfont::before {
+ display: flex;
+ align-items: center;
+}
+
+.uicon-en:before {
+ content: "\e70a";
+}
+
+.uicon-zh:before {
+ content: "\e692";
+}
+
+.uicon-level:before {
+ content: "\e693";
+}
+
+.uicon-woman:before {
+ content: "\e69c";
+}
+
+.uicon-man:before {
+ content: "\e697";
+}
+
+.uicon-column-line:before {
+ content: "\e68e";
+}
+
+.uicon-empty-page:before {
+ content: "\e627";
+}
+
+.uicon-empty-data:before {
+ content: "\e62f";
+}
+
+.uicon-empty-car:before {
+ content: "\e602";
+}
+
+.uicon-empty-order:before {
+ content: "\e639";
+}
+
+.uicon-empty-address:before {
+ content: "\e646";
+}
+
+.uicon-empty-message:before {
+ content: "\e6a9";
+}
+
+.uicon-empty-search:before {
+ content: "\e664";
+}
+
+.uicon-empty-favor:before {
+ content: "\e67c";
+}
+
+.uicon-empty-coupon:before {
+ content: "\e682";
+}
+
+.uicon-empty-history:before {
+ content: "\e684";
+}
+
+.uicon-empty-permission:before {
+ content: "\e686";
+}
+
+.uicon-empty-news:before {
+ content: "\e687";
+}
+
+.uicon-empty-wifi:before {
+ content: "\e688";
+}
+
+.uicon-empty-list:before {
+ content: "\e68b";
+}
+
+.uicon-arrow-left-double:before {
+ content: "\e68c";
+}
+
+.uicon-arrow-right-double:before {
+ content: "\e68d";
+}
+
+.uicon-red-packet:before {
+ content: "\e691";
+}
+
+.uicon-red-packet-fill:before {
+ content: "\e690";
+}
+
+.uicon-order:before {
+ content: "\e68f";
+}
+
+.uicon-nav-back-arrow:before {
+ content: "\e67f";
+}
+
+.uicon-nav-back:before {
+ content: "\e683";
+}
+
+.uicon-checkbox-mark:before {
+ content: "\e6a8";
+}
+
+.uicon-arrow-up-fill:before {
+ content: "\e6b0";
+}
+
+.uicon-arrow-down-fill:before {
+ content: "\e600";
+}
+
+.uicon-backspace:before {
+ content: "\e67b";
+}
+
+.uicon-android-circle-fill:before {
+ content: "\e67e";
+}
+
+.uicon-android-fill:before {
+ content: "\e67d";
+}
+
+.uicon-question:before {
+ content: "\e715";
+}
+
+.uicon-pause:before {
+ content: "\e8fa";
+}
+
+.uicon-close:before {
+ content: "\e685";
+}
+
+.uicon-volume-up:before {
+ content: "\e633";
+}
+
+.uicon-volume-off:before {
+ content: "\e644";
+}
+
+.uicon-info:before {
+ content: "\e653";
+}
+
+.uicon-error:before {
+ content: "\e6d3";
+}
+
+.uicon-lock-opened-fill:before {
+ content: "\e974";
+}
+
+.uicon-lock-fill:before {
+ content: "\e979";
+}
+
+.uicon-lock:before {
+ content: "\e97a";
+}
+
+.uicon-photo-fill:before {
+ content: "\e98b";
+}
+
+.uicon-photo:before {
+ content: "\e98d";
+}
+
+.uicon-account-fill:before {
+ content: "\e614";
+}
+
+.uicon-minus-people-fill:before {
+ content: "\e615";
+}
+
+.uicon-plus-people-fill:before {
+ content: "\e626";
+}
+
+.uicon-account:before {
+ content: "\e628";
+}
+
+.uicon-thumb-down-fill:before {
+ content: "\e726";
+}
+
+.uicon-thumb-down:before {
+ content: "\e727";
+}
+
+.uicon-thumb-up-fill:before {
+ content: "\e72f";
+}
+
+.uicon-thumb-up:before {
+ content: "\e733";
+}
+
+.uicon-person-delete-fill:before {
+ content: "\e66a";
+}
+
+.uicon-cut:before {
+ content: "\e948";
+}
+
+.uicon-fingerprint:before {
+ content: "\e955";
+}
+
+.uicon-home-fill:before {
+ content: "\e964";
+}
+
+.uicon-home:before {
+ content: "\e965";
+}
+
+.uicon-hourglass-half-fill:before {
+ content: "\e966";
+}
+
+.uicon-hourglass:before {
+ content: "\e967";
+}
+
+.uicon-lock-open:before {
+ content: "\e973";
+}
+
+.uicon-integral-fill:before {
+ content: "\e703";
+}
+
+.uicon-integral:before {
+ content: "\e704";
+}
+
+.uicon-coupon:before {
+ content: "\e8ae";
+}
+
+.uicon-coupon-fill:before {
+ content: "\e8c4";
+}
+
+.uicon-kefu-ermai:before {
+ content: "\e656";
+}
+
+.uicon-scan:before {
+ content: "\e662";
+}
+
+.uicon-rmb:before {
+ content: "\e608";
+}
+
+.uicon-rmb-circle-fill:before {
+ content: "\e657";
+}
+
+.uicon-rmb-circle:before {
+ content: "\e677";
+}
+
+.uicon-gift:before {
+ content: "\e65b";
+}
+
+.uicon-gift-fill:before {
+ content: "\e65c";
+}
+
+.uicon-bookmark-fill:before {
+ content: "\e63b";
+}
+
+.uicon-zhuanfa:before {
+ content: "\e60b";
+}
+
+.uicon-eye-off-outline:before {
+ content: "\e62b";
+}
+
+.uicon-eye-off:before {
+ content: "\e648";
+}
+
+.uicon-pause-circle:before {
+ content: "\e643";
+}
+
+.uicon-play-circle:before {
+ content: "\e647";
+}
+
+.uicon-pause-circle-fill:before {
+ content: "\e654";
+}
+
+.uicon-play-circle-fill:before {
+ content: "\e655";
+}
+
+.uicon-grid:before {
+ content: "\e673";
+}
+
+.uicon-play-right:before {
+ content: "\e610";
+}
+
+.uicon-play-left:before {
+ content: "\e66d";
+}
+
+.uicon-calendar:before {
+ content: "\e66e";
+}
+
+.uicon-rewind-right:before {
+ content: "\e66f";
+}
+
+.uicon-rewind-left:before {
+ content: "\e671";
+}
+
+.uicon-skip-forward-right:before {
+ content: "\e672";
+}
+
+.uicon-skip-back-left:before {
+ content: "\e674";
+}
+
+.uicon-play-left-fill:before {
+ content: "\e675";
+}
+
+.uicon-play-right-fill:before {
+ content: "\e676";
+}
+
+.uicon-grid-fill:before {
+ content: "\e678";
+}
+
+.uicon-rewind-left-fill:before {
+ content: "\e679";
+}
+
+.uicon-rewind-right-fill:before {
+ content: "\e67a";
+}
+
+.uicon-pushpin:before {
+ content: "\e7e3";
+}
+
+.uicon-star:before {
+ content: "\e65f";
+}
+
+.uicon-star-fill:before {
+ content: "\e669";
+}
+
+.uicon-server-fill:before {
+ content: "\e751";
+}
+
+.uicon-server-man:before {
+ content: "\e6bc";
+}
+
+.uicon-edit-pen:before {
+ content: "\e612";
+}
+
+.uicon-edit-pen-fill:before {
+ content: "\e66b";
+}
+
+.uicon-wifi:before {
+ content: "\e667";
+}
+
+.uicon-wifi-off:before {
+ content: "\e668";
+}
+
+.uicon-file-text:before {
+ content: "\e663";
+}
+
+.uicon-file-text-fill:before {
+ content: "\e665";
+}
+
+.uicon-more-dot-fill:before {
+ content: "\e630";
+}
+
+.uicon-minus:before {
+ content: "\e618";
+}
+
+.uicon-minus-circle:before {
+ content: "\e61b";
+}
+
+.uicon-plus:before {
+ content: "\e62d";
+}
+
+.uicon-plus-circle:before {
+ content: "\e62e";
+}
+
+.uicon-minus-circle-fill:before {
+ content: "\e652";
+}
+
+.uicon-plus-circle-fill:before {
+ content: "\e661";
+}
+
+.uicon-email:before {
+ content: "\e611";
+}
+
+.uicon-email-fill:before {
+ content: "\e642";
+}
+
+.uicon-phone:before {
+ content: "\e622";
+}
+
+.uicon-phone-fill:before {
+ content: "\e64f";
+}
+
+.uicon-clock:before {
+ content: "\e60f";
+}
+
+.uicon-car:before {
+ content: "\e60c";
+}
+
+.uicon-car-fill:before {
+ content: "\e636";
+}
+
+.uicon-warning:before {
+ content: "\e694";
+}
+
+.uicon-warning-fill:before {
+ content: "\e64d";
+}
+
+.uicon-search:before {
+ content: "\e62a";
+}
+
+.uicon-baidu-circle-fill:before {
+ content: "\e680";
+}
+
+.uicon-baidu:before {
+ content: "\e681";
+}
+
+.uicon-facebook:before {
+ content: "\e689";
+}
+
+.uicon-facebook-circle-fill:before {
+ content: "\e68a";
+}
+
+.uicon-qzone:before {
+ content: "\e695";
+}
+
+.uicon-qzone-circle-fill:before {
+ content: "\e696";
+}
+
+.uicon-moments-circel-fill:before {
+ content: "\e69a";
+}
+
+.uicon-moments:before {
+ content: "\e69b";
+}
+
+.uicon-qq-circle-fill:before {
+ content: "\e6a0";
+}
+
+.uicon-qq-fill:before {
+ content: "\e6a1";
+}
+
+.uicon-weibo:before {
+ content: "\e6a4";
+}
+
+.uicon-weibo-circle-fill:before {
+ content: "\e6a5";
+}
+
+.uicon-taobao:before {
+ content: "\e6a6";
+}
+
+.uicon-taobao-circle-fill:before {
+ content: "\e6a7";
+}
+
+.uicon-twitter:before {
+ content: "\e6aa";
+}
+
+.uicon-twitter-circle-fill:before {
+ content: "\e6ab";
+}
+
+.uicon-weixin-circle-fill:before {
+ content: "\e6b1";
+}
+
+.uicon-weixin-fill:before {
+ content: "\e6b2";
+}
+
+.uicon-zhifubao-circle-fill:before {
+ content: "\e6b8";
+}
+
+.uicon-zhifubao:before {
+ content: "\e6b9";
+}
+
+.uicon-zhihu:before {
+ content: "\e6ba";
+}
+
+.uicon-zhihu-circle-fill:before {
+ content: "\e709";
+}
+
+.uicon-list:before {
+ content: "\e650";
+}
+
+.uicon-list-dot:before {
+ content: "\e616";
+}
+
+.uicon-setting:before {
+ content: "\e61f";
+}
+
+.uicon-bell:before {
+ content: "\e609";
+}
+
+.uicon-bell-fill:before {
+ content: "\e640";
+}
+
+.uicon-attach:before {
+ content: "\e632";
+}
+
+.uicon-shopping-cart:before {
+ content: "\e621";
+}
+
+.uicon-shopping-cart-fill:before {
+ content: "\e65d";
+}
+
+.uicon-tags:before {
+ content: "\e629";
+}
+
+.uicon-share:before {
+ content: "\e631";
+}
+
+.uicon-question-circle-fill:before {
+ content: "\e666";
+}
+
+.uicon-question-circle:before {
+ content: "\e625";
+}
+
+.uicon-error-circle:before {
+ content: "\e624";
+}
+
+.uicon-checkmark-circle:before {
+ content: "\e63d";
+}
+
+.uicon-close-circle:before {
+ content: "\e63f";
+}
+
+.uicon-info-circle:before {
+ content: "\e660";
+}
+
+.uicon-md-person-add:before {
+ content: "\e6e4";
+}
+
+.uicon-md-person-fill:before {
+ content: "\e6ea";
+}
+
+.uicon-bag-fill:before {
+ content: "\e617";
+}
+
+.uicon-bag:before {
+ content: "\e619";
+}
+
+.uicon-chat-fill:before {
+ content: "\e61e";
+}
+
+.uicon-chat:before {
+ content: "\e620";
+}
+
+.uicon-more-circle:before {
+ content: "\e63e";
+}
+
+.uicon-more-circle-fill:before {
+ content: "\e645";
+}
+
+.uicon-volume:before {
+ content: "\e66c";
+}
+
+.uicon-volume-fill:before {
+ content: "\e670";
+}
+
+.uicon-reload:before {
+ content: "\e788";
+}
+
+.uicon-camera:before {
+ content: "\e7d7";
+}
+
+.uicon-heart:before {
+ content: "\e7df";
+}
+
+.uicon-heart-fill:before {
+ content: "\e851";
+}
+
+.uicon-minus-square-fill:before {
+ content: "\e855";
+}
+
+.uicon-plus-square-fill:before {
+ content: "\e856";
+}
+
+.uicon-pushpin-fill:before {
+ content: "\e86e";
+}
+
+.uicon-camera-fill:before {
+ content: "\e870";
+}
+
+.uicon-setting-fill:before {
+ content: "\e872";
+}
+
+.uicon-google:before {
+ content: "\e87a";
+}
+
+.uicon-ie:before {
+ content: "\e87b";
+}
+
+.uicon-apple-fill:before {
+ content: "\e881";
+}
+
+.uicon-chrome-circle-fill:before {
+ content: "\e885";
+}
+
+.uicon-github-circle-fill:before {
+ content: "\e887";
+}
+
+.uicon-IE-circle-fill:before {
+ content: "\e889";
+}
+
+.uicon-google-circle-fill:before {
+ content: "\e88a";
+}
+
+.uicon-arrow-down:before {
+ content: "\e60d";
+}
+
+.uicon-arrow-left:before {
+ content: "\e60e";
+}
+
+.uicon-map:before {
+ content: "\e61d";
+}
+
+.uicon-man-add-fill:before {
+ content: "\e64c";
+}
+
+.uicon-tags-fill:before {
+ content: "\e651";
+}
+
+.uicon-arrow-leftward:before {
+ content: "\e601";
+}
+
+.uicon-arrow-rightward:before {
+ content: "\e603";
+}
+
+.uicon-arrow-downward:before {
+ content: "\e604";
+}
+
+.uicon-arrow-right:before {
+ content: "\e605";
+}
+
+.uicon-arrow-up:before {
+ content: "\e606";
+}
+
+.uicon-arrow-upward:before {
+ content: "\e607";
+}
+
+.uicon-bookmark:before {
+ content: "\e60a";
+}
+
+.uicon-eye:before {
+ content: "\e613";
+}
+
+.uicon-man-delete:before {
+ content: "\e61a";
+}
+
+.uicon-man-add:before {
+ content: "\e61c";
+}
+
+.uicon-trash:before {
+ content: "\e623";
+}
+
+.uicon-error-circle-fill:before {
+ content: "\e62c";
+}
+
+.uicon-calendar-fill:before {
+ content: "\e634";
+}
+
+.uicon-checkmark-circle-fill:before {
+ content: "\e635";
+}
+
+.uicon-close-circle-fill:before {
+ content: "\e637";
+}
+
+.uicon-clock-fill:before {
+ content: "\e638";
+}
+
+.uicon-checkmark:before {
+ content: "\e63a";
+}
+
+.uicon-download:before {
+ content: "\e63c";
+}
+
+.uicon-eye-fill:before {
+ content: "\e641";
+}
+
+.uicon-mic-off:before {
+ content: "\e649";
+}
+
+.uicon-mic:before {
+ content: "\e64a";
+}
+
+.uicon-info-circle-fill:before {
+ content: "\e64b";
+}
+
+.uicon-map-fill:before {
+ content: "\e64e";
+}
+
+.uicon-trash-fill:before {
+ content: "\e658";
+}
+
+.uicon-volume-off-fill:before {
+ content: "\e659";
+}
+
+.uicon-volume-up-fill:before {
+ content: "\e65a";
+}
+
+.uicon-share-fill:before {
+ content: "\e65e";
+}
diff --git a/hotgo-uniapp/uview-ui/index.js b/hotgo-uniapp/uview-ui/index.js
new file mode 100644
index 0000000..854a380
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/index.js
@@ -0,0 +1,140 @@
+// 引入全局mixin
+import mixin from './libs/mixin/mixin.js'
+// 引入关于是否mixin集成小程序分享的配置
+// import wxshare from './libs/mixin/mpShare.js'
+// 全局挂载引入http相关请求拦截插件
+import http from './libs/request'
+
+function wranning(str) {
+ // 开发环境进行信息输出,主要是一些报错信息
+ // 这个环境的来由是在程序编写时候,点击hx编辑器运行调试代码的时候,详见:
+ // https://uniapp.dcloud.io/frame?id=%e5%bc%80%e5%8f%91%e7%8e%af%e5%a2%83%e5%92%8c%e7%94%9f%e4%ba%a7%e7%8e%af%e5%a2%83
+ if (process.env.NODE_ENV === 'development') {
+ console.warn(str)
+ }
+}
+
+// 尝试判断在根目录的/store中是否有$u.mixin.js,此文件uView默认为需要挂在到全局的vuex的state变量
+// HX2.6.11版本,放到try中,控制台依然会警告,暂时不用此方式,
+// let vuexStore = {};
+// try {
+// vuexStore = require("@/store/$u.mixin.js");
+// } catch (e) {
+// //TODO handle the exception
+// }
+
+// post类型对象参数转为get类型url参数
+import queryParams from './libs/function/queryParams.js'
+// 路由封装
+import route from './libs/function/route.js'
+// 时间格式化
+import timeFormat from './libs/function/timeFormat.js'
+// 时间戳格式化,返回多久之前
+import timeFrom from './libs/function/timeFrom.js'
+// 颜色渐变相关,colorGradient-颜色渐变,hexToRgb-十六进制颜色转rgb颜色,rgbToHex-rgb转十六进制
+import colorGradient from './libs/function/colorGradient.js'
+// 生成全局唯一guid字符串
+import guid from './libs/function/guid.js'
+// 主题相关颜色,info|success|warning|primary|default|error,此颜色已在uview.scss中定义,但是为js中也能使用,故也定义一份
+import color from './libs/function/color.js'
+// 根据type获取图标名称
+import type2icon from './libs/function/type2icon.js'
+// 打乱数组的顺序
+import randomArray from './libs/function/randomArray.js'
+// 对象和数组的深度克隆
+import deepClone from './libs/function/deepClone.js'
+// 对象深度拷贝
+import deepMerge from './libs/function/deepMerge.js'
+// 添加单位
+import addUnit from './libs/function/addUnit.js'
+
+// 规则检验
+import test from './libs/function/test.js'
+// 随机数
+import random from './libs/function/random.js'
+// 去除空格
+import trim from './libs/function/trim.js'
+// toast提示,对uni.showToast的封装
+import toast from './libs/function/toast.js'
+// 获取父组件参数
+import getParent from './libs/function/getParent.js'
+// 获取整个父组件
+import $parent from './libs/function/$parent.js'
+// 获取sys()和os()工具方法
+// 获取设备信息,挂载到$u的sys()(system的缩写)属性中,
+// 同时把安卓和ios平台的名称"ios"和"android"挂到$u.os()中,方便取用
+import {sys, os} from './libs/function/sys.js'
+// 防抖方法
+import debounce from './libs/function/debounce.js'
+// 节流方法
+import throttle from './libs/function/throttle.js'
+
+// 配置信息
+import config from './libs/config/config.js'
+// 各个需要fixed的地方的z-index配置文件
+import zIndex from './libs/config/zIndex.js'
+
+const $u = {
+ queryParams: queryParams,
+ route: route,
+ timeFormat: timeFormat,
+ date: timeFormat, // 另名date
+ timeFrom,
+ colorGradient: colorGradient.colorGradient,
+ colorToRgba: colorGradient.colorToRgba,
+ guid,
+ color,
+ sys,
+ os,
+ type2icon,
+ randomArray,
+ wranning,
+ get: http.get,
+ post: http.post,
+ put: http.put,
+ 'delete': http.delete,
+ hexToRgb: colorGradient.hexToRgb,
+ rgbToHex: colorGradient.rgbToHex,
+ test,
+ random,
+ deepClone,
+ deepMerge,
+ getParent,
+ $parent,
+ addUnit,
+ trim,
+ type: ['primary', 'success', 'error', 'warning', 'info'],
+ http,
+ toast,
+ config, // uView配置信息相关,比如版本号
+ zIndex,
+ debounce,
+ throttle,
+}
+
+// $u挂载到uni对象上
+uni.$u = $u
+
+const install = Vue => {
+ Vue.mixin(mixin)
+ if (Vue.prototype.openShare) {
+ Vue.mixin(mpShare);
+ }
+ // Vue.mixin(vuexStore);
+ // 时间格式化,同时两个名称,date和timeFormat
+ Vue.filter('timeFormat', (timestamp, format) => {
+ return timeFormat(timestamp, format)
+ })
+ Vue.filter('date', (timestamp, format) => {
+ return timeFormat(timestamp, format)
+ })
+ // 将多久以前的方法,注入到全局过滤器
+ Vue.filter('timeFrom', (timestamp, format) => {
+ return timeFrom(timestamp, format)
+ })
+ Vue.prototype.$u = $u
+}
+
+export default {
+ install
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/index.scss b/hotgo-uniapp/uview-ui/index.scss
new file mode 100644
index 0000000..84daa72
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/index.scss
@@ -0,0 +1,23 @@
+// 引入公共基础类
+@import "./libs/css/common.scss";
+@import "./libs/css/color.scss";
+
+// 非nvue的样式
+/* #ifndef APP-NVUE */
+@import "./libs/css/style.vue.scss";
+/* #endif */
+
+// nvue的特有样式
+/* #ifdef APP-NVUE */
+@import "./libs/css/style.nvue.scss";
+/* #endif */
+
+// 小程序特有的样式
+/* #ifdef MP */
+@import "./libs/css/style.mp.scss";
+/* #endif */
+
+// H5特有的样式
+/* #ifdef H5 */
+@import "./libs/css/style.h5.scss";
+/* #endif */
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/config/config.js b/hotgo-uniapp/uview-ui/libs/config/config.js
new file mode 100644
index 0000000..ac3c65e
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/config/config.js
@@ -0,0 +1,15 @@
+// 此版本发布于2020-12-17
+let version = '1.8.3';
+
+export default {
+ v: version,
+ version: version,
+ // 主题名称
+ type: [
+ 'primary',
+ 'success',
+ 'info',
+ 'error',
+ 'warning'
+ ]
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/config/zIndex.js b/hotgo-uniapp/uview-ui/libs/config/zIndex.js
new file mode 100644
index 0000000..d60e5bd
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/config/zIndex.js
@@ -0,0 +1,20 @@
+// uniapp在H5中各API的z-index值如下:
+/**
+ * actionsheet: 999
+ * modal: 999
+ * navigate: 998
+ * tabbar: 998
+ * toast: 999
+ */
+
+export default {
+ toast: 10090,
+ noNetwork: 10080,
+ // popup包含popup,actionsheet,keyboard,picker的值
+ popup: 10075,
+ mask: 10070,
+ navbar: 980,
+ topTips: 975,
+ sticky: 970,
+ indexListSticky: 965,
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/css/color.scss b/hotgo-uniapp/uview-ui/libs/css/color.scss
new file mode 100644
index 0000000..279bc40
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/css/color.scss
@@ -0,0 +1,155 @@
+.u-type-primary-light {
+ color: $u-type-primary-light;
+}
+
+.u-type-warning-light {
+ color: $u-type-warning-light;
+}
+
+.u-type-success-light {
+ color: $u-type-success-light;
+}
+
+.u-type-error-light {
+ color: $u-type-error-light;
+}
+
+.u-type-info-light {
+ color: $u-type-info-light;
+}
+
+.u-type-primary-light-bg {
+ background-color: $u-type-primary-light;
+}
+
+.u-type-warning-light-bg {
+ background-color: $u-type-warning-light;
+}
+
+.u-type-success-light-bg {
+ background-color: $u-type-success-light;
+}
+
+.u-type-error-light-bg {
+ background-color: $u-type-error-light;
+}
+
+.u-type-info-light-bg {
+ background-color: $u-type-info-light;
+}
+
+.u-type-primary-dark {
+ color: $u-type-primary-dark;
+}
+
+.u-type-warning-dark {
+ color: $u-type-warning-dark;
+}
+
+.u-type-success-dark {
+ color: $u-type-success-dark;
+}
+
+.u-type-error-dark {
+ color: $u-type-error-dark;
+}
+
+.u-type-info-dark {
+ color: $u-type-info-dark;
+}
+
+.u-type-primary-dark-bg {
+ background-color: $u-type-primary-dark;
+}
+
+.u-type-warning-dark-bg {
+ background-color: $u-type-warning-dark;
+}
+
+.u-type-success-dark-bg {
+ background-color: $u-type-success-dark;
+}
+
+.u-type-error-dark-bg {
+ background-color: $u-type-error-dark;
+}
+
+.u-type-info-dark-bg {
+ background-color: $u-type-info-dark;
+}
+
+.u-type-primary-disabled {
+ color: $u-type-primary-disabled;
+}
+
+.u-type-warning-disabled {
+ color: $u-type-warning-disabled;
+}
+
+.u-type-success-disabled {
+ color: $u-type-success-disabled;
+}
+
+.u-type-error-disabled {
+ color: $u-type-error-disabled;
+}
+
+.u-type-info-disabled {
+ color: $u-type-info-disabled;
+}
+
+.u-type-primary {
+ color: $u-type-primary;
+}
+
+.u-type-warning {
+ color: $u-type-warning;
+}
+
+.u-type-success {
+ color: $u-type-success;
+}
+
+.u-type-error {
+ color: $u-type-error;
+}
+
+.u-type-info {
+ color: $u-type-info;
+}
+
+.u-type-primary-bg {
+ background-color: $u-type-primary;
+}
+
+.u-type-warning-bg {
+ background-color: $u-type-warning;
+}
+
+.u-type-success-bg {
+ background-color: $u-type-success;
+}
+
+.u-type-error-bg {
+ background-color: $u-type-error;
+}
+
+.u-type-info-bg {
+ background-color: $u-type-info;
+}
+
+.u-main-color {
+ color: $u-main-color;
+}
+
+.u-content-color {
+ color: $u-content-color;
+}
+
+.u-tips-color {
+ color: $u-tips-color;
+}
+
+.u-light-color {
+ color: $u-light-color;
+}
diff --git a/hotgo-uniapp/uview-ui/libs/css/common.scss b/hotgo-uniapp/uview-ui/libs/css/common.scss
new file mode 100644
index 0000000..29eb7f4
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/css/common.scss
@@ -0,0 +1,176 @@
+.u-relative,
+.u-rela {
+ position: relative;
+}
+
+.u-absolute,
+.u-abso {
+ position: absolute;
+}
+
+// nvue不能用标签命名样式,不能放在微信组件中,否则微信开发工具会报警告,无法使用标签名当做选择器
+/* #ifndef APP-NVUE */
+image {
+ display: inline-block;
+}
+
+// 在weex,也即nvue中,所有元素默认为border-box
+view,
+text {
+ box-sizing: border-box;
+}
+/* #endif */
+
+.u-font-xs {
+ font-size: 22rpx;
+}
+
+.u-font-sm {
+ font-size: 26rpx;
+}
+
+.u-font-md {
+ font-size: 28rpx;
+}
+
+.u-font-lg {
+ font-size: 30rpx;
+}
+
+.u-font-xl {
+ font-size: 34rpx;
+}
+
+.u-flex {
+ /* #ifndef APP-NVUE */
+ display: flex;
+ /* #endif */
+ flex-direction: row;
+ align-items: center;
+}
+
+.u-flex-wrap {
+ flex-wrap: wrap;
+}
+
+.u-flex-nowrap {
+ flex-wrap: nowrap;
+}
+
+.u-col-center {
+ align-items: center;
+}
+
+.u-col-top {
+ align-items: flex-start;
+}
+
+.u-col-bottom {
+ align-items: flex-end;
+}
+
+.u-row-center {
+ justify-content: center;
+}
+
+.u-row-left {
+ justify-content: flex-start;
+}
+
+.u-row-right {
+ justify-content: flex-end;
+}
+
+.u-row-between {
+ justify-content: space-between;
+}
+
+.u-row-around {
+ justify-content: space-around;
+}
+
+.u-text-left {
+ text-align: left;
+}
+
+.u-text-center {
+ text-align: center;
+}
+
+.u-text-right {
+ text-align: right;
+}
+
+.u-flex-col {
+ /* #ifndef APP-NVUE */
+ display: flex;
+ /* #endif */
+ flex-direction: column;
+}
+
+// 定义flex等分
+@for $i from 0 through 12 {
+ .u-flex-#{$i} {
+ flex: $i;
+ }
+}
+
+// 定义字体(px)单位,小于20都为px单位字体
+@for $i from 9 to 20 {
+ .u-font-#{$i} {
+ font-size: $i + px;
+ }
+}
+
+// 定义字体(rpx)单位,大于或等于20的都为rpx单位字体
+@for $i from 20 through 40 {
+ .u-font-#{$i} {
+ font-size: $i + rpx;
+ }
+}
+
+// 定义内外边距,历遍1-80
+@for $i from 0 through 80 {
+ // 只要双数和能被5除尽的数
+ @if $i % 2 == 0 or $i % 5 == 0 {
+ // 得出:u-margin-30或者u-m-30
+ .u-margin-#{$i}, .u-m-#{$i} {
+ margin: $i + rpx!important;
+ }
+
+ // 得出:u-padding-30或者u-p-30
+ .u-padding-#{$i}, .u-p-#{$i} {
+ padding: $i + rpx!important;
+ }
+
+ @each $short, $long in l left, t top, r right, b bottom {
+ // 缩写版,结果如: u-m-l-30
+ // 定义外边距
+ .u-m-#{$short}-#{$i} {
+ margin-#{$long}: $i + rpx!important;
+ }
+
+ // 定义内边距
+ .u-p-#{$short}-#{$i} {
+ padding-#{$long}: $i + rpx!important;
+ }
+
+ // 完整版,结果如:u-margin-left-30
+ // 定义外边距
+ .u-margin-#{$long}-#{$i} {
+ margin-#{$long}: $i + rpx!important;
+ }
+
+ // 定义内边距
+ .u-padding-#{$long}-#{$i} {
+ padding-#{$long}: $i + rpx!important;
+ }
+ }
+ }
+}
+
+// 重置nvue的默认关于flex的样式
+.u-reset-nvue {
+ flex-direction: row;
+ align-items: center;
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/css/style.components.scss b/hotgo-uniapp/uview-ui/libs/css/style.components.scss
new file mode 100644
index 0000000..6835876
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/css/style.components.scss
@@ -0,0 +1,7 @@
+// 定义混入指令,用于在非nvue环境下的flex定义,因为nvue没有display属性,会报错
+@mixin vue-flex($direction: row) {
+ /* #ifndef APP-NVUE */
+ display: flex;
+ flex-direction: $direction;
+ /* #endif */
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/css/style.h5.scss b/hotgo-uniapp/uview-ui/libs/css/style.h5.scss
new file mode 100644
index 0000000..62839eb
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/css/style.h5.scss
@@ -0,0 +1,8 @@
+/* H5的时候,隐藏滚动条 */
+::-webkit-scrollbar {
+ display: none;
+ width: 0 !important;
+ height: 0 !important;
+ -webkit-appearance: none;
+ background: transparent;
+}
diff --git a/hotgo-uniapp/uview-ui/libs/css/style.mp.scss b/hotgo-uniapp/uview-ui/libs/css/style.mp.scss
new file mode 100644
index 0000000..ca1d3e0
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/css/style.mp.scss
@@ -0,0 +1,72 @@
+/* start--微信小程序编译后页面有组件名的元素,特别处理--start */
+/* #ifdef MP-WEIXIN || MP-QQ */
+u-td, u-th {
+ flex: 1;
+ align-self: stretch;
+}
+
+.u-td {
+ height: 100%;
+}
+
+u-icon {
+ display: inline-flex;
+ align-items: center;
+}
+
+// 各家小程序宫格组件外层设置为100%,避免受到父元素display: flex;的影响
+u-grid {
+ width: 100%;
+ flex: 0 0 100%;
+}
+
+// 避免小程序线条组件因为父组件display: flex;而失效
+u-line {
+ flex: 1;
+}
+
+u-switch {
+ display: inline-flex;
+ align-items: center;
+}
+
+u-dropdown {
+ flex: 1;
+}
+/* #endif */
+/* end-微信小程序编译后页面有组件名的元素,特别处理--end */
+
+
+/* #ifdef MP-QQ || MP-TOUTIAO */
+// 需要做这一切额外的兼容,都是因为TX的无能
+u-icon {
+ line-height: 0;
+}
+/* #endif */
+
+/* start--头条小程序编译后页面有组件名的元素,特别处理--start */
+// 由于头条小程序不支持直接组件名形式写样式,目前只能在写组件的时候给组件加上对应的类名
+/* #ifdef MP-TOUTIAO */
+.u-td, .u-th, .u-tr {
+ flex: 1;
+ align-self: stretch;
+}
+
+.u-row, .u-col {
+ flex: 1;
+ align-self: stretch;
+}
+
+// 避免小程序线条组件因为父组件display: flex;而失效
+.u-line {
+ flex: 1;
+}
+
+.u-dropdown {
+ flex: 1;
+}
+/* #endif */
+/* end-头条小程序编译后页面有组件名的元素,特别处理--end */
+
+
+
diff --git a/hotgo-uniapp/uview-ui/libs/css/style.nvue.scss b/hotgo-uniapp/uview-ui/libs/css/style.nvue.scss
new file mode 100644
index 0000000..4a6192a
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/css/style.nvue.scss
@@ -0,0 +1,3 @@
+.nvue {
+ font-size: 24rpx;
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/css/style.vue.scss b/hotgo-uniapp/uview-ui/libs/css/style.vue.scss
new file mode 100644
index 0000000..1ab3707
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/css/style.vue.scss
@@ -0,0 +1,175 @@
+page {
+ color: $u-main-color;
+ font-size: 28rpx;
+}
+
+/* start--去除webkit的默认样式--start */
+.u-fix-ios-appearance {
+ -webkit-appearance:none;
+}
+/* end--去除webkit的默认样式--end */
+
+/* start--icon图标外层套一个view,让其达到更好的垂直居中的效果--start */
+.u-icon-wrap {
+ display: flex;
+ align-items: center;
+}
+/* end-icon图标外层套一个view,让其达到更好的垂直居中的效果--end */
+
+/* start--iPhoneX底部安全区定义--start */
+.safe-area-inset-bottom {
+ padding-bottom: 0;
+ padding-bottom: constant(safe-area-inset-bottom);
+ padding-bottom: env(safe-area-inset-bottom);
+}
+/* end-iPhoneX底部安全区定义--end */
+
+/* start--各种hover点击反馈相关的类名-start */
+.u-hover-class {
+ // background-color: #f7f8f9!important;
+ opacity: 0.6;
+}
+
+.u-cell-hover {
+ background-color: #f7f8f9!important;
+}
+/* end--各种hover点击反馈相关的类名--end */
+
+/* start--文本行数限制--start */
+.u-line-1 {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.u-line-2 {
+ -webkit-line-clamp: 2;
+}
+
+.u-line-3 {
+ -webkit-line-clamp: 3;
+}
+
+.u-line-4 {
+ -webkit-line-clamp: 4;
+}
+
+.u-line-5 {
+ -webkit-line-clamp: 5;
+}
+
+.u-line-2, .u-line-3, .u-line-4, .u-line-5 {
+ overflow: hidden;
+ word-break: break-all;
+ text-overflow: ellipsis;
+ display: -webkit-box; // 弹性伸缩盒
+ -webkit-box-orient: vertical; // 设置伸缩盒子元素排列方式
+}
+
+/* end--文本行数限制--end */
+
+
+/* start--Retina 屏幕下的 1px 边框--start */
+.u-border,
+.u-border-bottom,
+.u-border-left,
+.u-border-right,
+.u-border-top,
+.u-border-top-bottom {
+ position: relative
+}
+
+.u-border-bottom:after,
+.u-border-left:after,
+.u-border-right:after,
+.u-border-top-bottom:after,
+.u-border-top:after,
+.u-border:after {
+ /* #ifndef APP-NVUE */
+ content: ' ';
+ /* #endif */
+ position: absolute;
+ left: 0;
+ top: 0;
+ pointer-events: none;
+ box-sizing: border-box;
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ // 多加0.1%,能解决有时候边框缺失的问题
+ width: 199.8%;
+ height: 199.7%;
+ transform: scale(0.5, 0.5);
+ border: 0 solid $u-border-color;
+ z-index: 2;
+}
+
+.u-border-top:after {
+ border-top-width: 1px
+}
+
+.u-border-left:after {
+ border-left-width: 1px
+}
+
+.u-border-right:after {
+ border-right-width: 1px
+}
+
+.u-border-bottom:after {
+ border-bottom-width: 1px
+}
+
+.u-border-top-bottom:after {
+ border-width: 1px 0
+}
+
+.u-border:after {
+ border-width: 1px
+}
+/* end--Retina 屏幕下的 1px 边框--end */
+
+
+/* start--clearfix--start */
+.u-clearfix:after,
+.clearfix:after {
+ /* #ifndef APP-NVUE */
+ content: '';
+ /* #endif */
+ display: table;
+ clear: both
+}
+/* end--clearfix--end */
+
+/* start--高斯模糊tabbar底部处理--start */
+.u-blur-effect-inset {
+ width: 750rpx;
+ height: var(--window-bottom);
+ background-color: #FFFFFF;
+}
+/* end--高斯模糊tabbar底部处理--end */
+
+/* start--提升H5端uni.toast()的层级,避免被uView的modal等遮盖--start */
+/* #ifdef H5 */
+uni-toast {
+ z-index: 10090;
+}
+uni-toast .uni-toast {
+ z-index: 10090;
+}
+/* #endif */
+/* end--提升H5端uni.toast()的层级,避免被uView的modal等遮盖--end */
+
+/* start--去除button的所有默认样式--start */
+.u-reset-button {
+ padding: 0;
+ font-size: inherit;
+ line-height: inherit;
+ background-color: transparent;
+ color: inherit;
+}
+
+.u-reset-button::after {
+ border: none;
+}
+/* end--去除button的所有默认样式--end */
+
diff --git a/hotgo-uniapp/uview-ui/libs/function/$parent.js b/hotgo-uniapp/uview-ui/libs/function/$parent.js
new file mode 100644
index 0000000..80515c4
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/$parent.js
@@ -0,0 +1,18 @@
+// 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法
+// this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx
+// 这里默认值等于undefined有它的含义,因为最顶层元素(组件)的$parent就是undefined,意味着不传name
+// 值(默认为undefined),就是查找最顶层的$parent
+export default function $parent(name = undefined) {
+ let parent = this.$parent;
+ // 通过while历遍,这里主要是为了H5需要多层解析的问题
+ while (parent) {
+ // 父组件
+ if (parent.$options && parent.$options.name !== name) {
+ // 如果组件的name不相等,继续上一级寻找
+ parent = parent.$parent;
+ } else {
+ return parent;
+ }
+ }
+ return false;
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/function/addUnit.js b/hotgo-uniapp/uview-ui/libs/function/addUnit.js
new file mode 100644
index 0000000..247fae2
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/addUnit.js
@@ -0,0 +1,8 @@
+import validation from './test.js';
+
+// 添加单位,如果有rpx,%,px等单位结尾或者值为auto,直接返回,否则加上rpx单位结尾
+export default function addUnit(value = 'auto', unit = 'rpx') {
+ value = String(value);
+ // 用uView内置验证规则中的number判断是否为数值
+ return validation.number(value) ? `${value}${unit}` : value;
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/function/bem.js b/hotgo-uniapp/uview-ui/libs/function/bem.js
new file mode 100644
index 0000000..05d1a36
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/bem.js
@@ -0,0 +1,5 @@
+function bem(name, conf) {
+
+}
+
+module.exports.bem = bem;
diff --git a/hotgo-uniapp/uview-ui/libs/function/color.js b/hotgo-uniapp/uview-ui/libs/function/color.js
new file mode 100644
index 0000000..dafb8c1
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/color.js
@@ -0,0 +1,37 @@
+// 为了让用户能够自定义主题,会逐步弃用此文件,各颜色通过css提供
+// 为了给某些特殊场景使用和向后兼容,无需删除此文件(2020-06-20)
+let color = {
+ primary: "#2979ff",
+ primaryDark: "#2b85e4",
+ primaryDisabled: "#a0cfff",
+ primaryLight: "#ecf5ff",
+ bgColor: "#f3f4f6",
+
+ info: "#909399",
+ infoDark: "#82848a",
+ infoDisabled: "#c8c9cc",
+ infoLight: "#f4f4f5",
+
+ warning: "#ff9900",
+ warningDark: "#f29100",
+ warningDisabled: "#fcbd71",
+ warningLight: "#fdf6ec",
+
+ error: "#fa3534",
+ errorDark: "#dd6161",
+ errorDisabled: "#fab6b6",
+ errorLight: "#fef0f0",
+
+ success: "#19be6b",
+ successDark: "#18b566",
+ successDisabled: "#71d5a1",
+ successLight: "#dbf1e1",
+
+ mainColor: "#303133",
+ contentColor: "#606266",
+ tipsColor: "#909399",
+ lightColor: "#c0c4cc",
+ borderColor: "#e4e7ed"
+}
+
+export default color;
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/function/colorGradient.js b/hotgo-uniapp/uview-ui/libs/function/colorGradient.js
new file mode 100644
index 0000000..eca30a2
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/colorGradient.js
@@ -0,0 +1,134 @@
+/**
+ * 求两个颜色之间的渐变值
+ * @param {string} startColor 开始的颜色
+ * @param {string} endColor 结束的颜色
+ * @param {number} step 颜色等分的份额
+ * */
+function colorGradient(startColor = 'rgb(0, 0, 0)', endColor = 'rgb(255, 255, 255)', step = 10) {
+ let startRGB = hexToRgb(startColor, false); //转换为rgb数组模式
+ let startR = startRGB[0];
+ let startG = startRGB[1];
+ let startB = startRGB[2];
+
+ let endRGB = hexToRgb(endColor, false);
+ let endR = endRGB[0];
+ let endG = endRGB[1];
+ let endB = endRGB[2];
+
+ let sR = (endR - startR) / step; //总差值
+ let sG = (endG - startG) / step;
+ let sB = (endB - startB) / step;
+ let colorArr = [];
+ for (let i = 0; i < step; i++) {
+ //计算每一步的hex值
+ let hex = rgbToHex('rgb(' + Math.round((sR * i + startR)) + ',' + Math.round((sG * i + startG)) + ',' + Math.round((sB *
+ i + startB)) + ')');
+ colorArr.push(hex);
+ }
+ return colorArr;
+}
+
+// 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
+function hexToRgb(sColor, str = true) {
+ let reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
+ sColor = sColor.toLowerCase();
+ if (sColor && reg.test(sColor)) {
+ if (sColor.length === 4) {
+ let sColorNew = "#";
+ for (let i = 1; i < 4; i += 1) {
+ sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
+ }
+ sColor = sColorNew;
+ }
+ //处理六位的颜色值
+ let sColorChange = [];
+ for (let i = 1; i < 7; i += 2) {
+ sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
+ }
+ if(!str) {
+ return sColorChange;
+ } else {
+ return `rgb(${sColorChange[0]},${sColorChange[1]},${sColorChange[2]})`;
+ }
+ } else if (/^(rgb|RGB)/.test(sColor)) {
+ let arr = sColor.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",")
+ return arr.map(val => Number(val));
+ } else {
+ return sColor;
+ }
+};
+
+// 将rgb表示方式转换为hex表示方式
+function rgbToHex(rgb) {
+ let _this = rgb;
+ let reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
+ if (/^(rgb|RGB)/.test(_this)) {
+ let aColor = _this.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
+ let strHex = "#";
+ for (let i = 0; i < aColor.length; i++) {
+ let hex = Number(aColor[i]).toString(16);
+ hex = String(hex).length == 1 ? 0 + '' + hex : hex; // 保证每个rgb的值为2位
+ if (hex === "0") {
+ hex += hex;
+ }
+ strHex += hex;
+ }
+ if (strHex.length !== 7) {
+ strHex = _this;
+ }
+ return strHex;
+ } else if (reg.test(_this)) {
+ let aNum = _this.replace(/#/, "").split("");
+ if (aNum.length === 6) {
+ return _this;
+ } else if (aNum.length === 3) {
+ let numHex = "#";
+ for (let i = 0; i < aNum.length; i += 1) {
+ numHex += (aNum[i] + aNum[i]);
+ }
+ return numHex;
+ }
+ } else {
+ return _this;
+ }
+}
+
+
+/**
+* JS颜色十六进制转换为rgb或rgba,返回的格式为 rgba(255,255,255,0.5)字符串
+* sHex为传入的十六进制的色值
+* alpha为rgba的透明度
+*/
+function colorToRgba(color, alpha = 0.3) {
+ color = rgbToHex(color)
+ // 十六进制颜色值的正则表达式
+ var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
+ /* 16进制颜色转为RGB格式 */
+ let sColor = color.toLowerCase()
+ if (sColor && reg.test(sColor)) {
+ if (sColor.length === 4) {
+ var sColorNew = '#'
+ for (let i = 1; i < 4; i += 1) {
+ sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
+ }
+ sColor = sColorNew
+ }
+ // 处理六位的颜色值
+ var sColorChange = []
+ for (let i = 1; i < 7; i += 2) {
+ sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
+ }
+ // return sColorChange.join(',')
+ return 'rgba(' + sColorChange.join(',') + ',' + alpha + ')'
+ }
+ else {
+ return sColor
+ }
+}
+
+export default {
+ colorGradient,
+ hexToRgb,
+ rgbToHex,
+ colorToRgba
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/function/date.js b/hotgo-uniapp/uview-ui/libs/function/date.js
new file mode 100644
index 0000000..f26a18d
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/date.js
@@ -0,0 +1,173 @@
+// 格式化时间戳
+export default function formatTimestamp(format, timestamp) {
+ var a, jsdate = ((timestamp) ? new Date(timestamp * 1000) : new Date());
+ var pad = function (n, c) {
+ if ((n = n + "").length < c) {
+ return new Array(++c - n.length).join("0") + n;
+ } else {
+ return n;
+ }
+ };
+ var txt_weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
+ var txt_ordin = {1: "st", 2: "nd", 3: "rd", 21: "st", 22: "nd", 23: "rd", 31: "st"};
+ var txt_months = ["", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
+ var f = {
+ // Day
+ d: function () {
+ return pad(f.j(), 2)
+ },
+ D: function () {
+ return f.l().substr(0, 3)
+ },
+ j: function () {
+ return jsdate.getDate()
+ },
+ l: function () {
+ return txt_weekdays[f.w()]
+ },
+ N: function () {
+ return f.w() + 1
+ },
+ S: function () {
+ return txt_ordin[f.j()] ? txt_ordin[f.j()] : 'th'
+ },
+ w: function () {
+ return jsdate.getDay()
+ },
+ z: function () {
+ return (jsdate - new Date(jsdate.getFullYear() + "/1/1")) / 864e5 >> 0
+ },
+
+ // Week
+ W: function () {
+ var a = f.z(), b = 364 + f.L() - a;
+ var nd2, nd = (new Date(jsdate.getFullYear() + "/1/1").getDay() || 7) - 1;
+ if (b <= 2 && ((jsdate.getDay() || 7) - 1) <= 2 - b) {
+ return 1;
+ } else {
+ if (a <= 2 && nd >= 4 && a >= (6 - nd)) {
+ nd2 = new Date(jsdate.getFullYear() - 1 + "/12/31");
+ return date("W", Math.round(nd2.getTime() / 1000));
+ } else {
+ return (1 + (nd <= 3 ? ((a + nd) / 7) : (a - (7 - nd)) / 7) >> 0);
+ }
+ }
+ },
+
+ // Month
+ F: function () {
+ return txt_months[f.n()]
+ },
+ m: function () {
+ return pad(f.n(), 2)
+ },
+ M: function () {
+ return f.F().substr(0, 3)
+ },
+ n: function () {
+ return jsdate.getMonth() + 1
+ },
+ t: function () {
+ var n;
+ if ((n = jsdate.getMonth() + 1) == 2) {
+ return 28 + f.L();
+ } else {
+ if (n & 1 && n < 8 || !(n & 1) && n > 7) {
+ return 31;
+ } else {
+ return 30;
+ }
+ }
+ },
+
+ // Year
+ L: function () {
+ var y = f.Y();
+ return (!(y & 3) && (y % 1e2 || !(y % 4e2))) ? 1 : 0
+ },
+ //o not supported yet
+ Y: function () {
+ return jsdate.getFullYear()
+ },
+ y: function () {
+ return (jsdate.getFullYear() + "").slice(2)
+ },
+
+ // Time
+ a: function () {
+ return jsdate.getHours() > 11 ? "pm" : "am"
+ },
+ A: function () {
+ return f.a().toUpperCase()
+ },
+ B: function () {
+ // peter paul koch:
+ var off = (jsdate.getTimezoneOffset() + 60) * 60;
+ var theSeconds = (jsdate.getHours() * 3600) + (jsdate.getMinutes() * 60) + jsdate.getSeconds() + off;
+ var beat = Math.floor(theSeconds / 86.4);
+ if (beat > 1000) beat -= 1000;
+ if (beat < 0) beat += 1000;
+ if ((String(beat)).length == 1) beat = "00" + beat;
+ if ((String(beat)).length == 2) beat = "0" + beat;
+ return beat;
+ },
+ g: function () {
+ return jsdate.getHours() % 12 || 12
+ },
+ G: function () {
+ return jsdate.getHours()
+ },
+ h: function () {
+ return pad(f.g(), 2)
+ },
+ H: function () {
+ return pad(jsdate.getHours(), 2)
+ },
+ i: function () {
+ return pad(jsdate.getMinutes(), 2)
+ },
+ s: function () {
+ return pad(jsdate.getSeconds(), 2)
+ },
+ //u not supported yet
+
+ // Timezone
+ //e not supported yet
+ //I not supported yet
+ O: function () {
+ var t = pad(Math.abs(jsdate.getTimezoneOffset() / 60 * 100), 4);
+ if (jsdate.getTimezoneOffset() > 0) t = "-" + t; else t = "+" + t;
+ return t;
+ },
+ P: function () {
+ var O = f.O();
+ return (O.substr(0, 3) + ":" + O.substr(3, 2))
+ },
+ //T not supported yet
+ //Z not supported yet
+
+ // Full Date/Time
+ c: function () {
+ return f.Y() + "-" + f.m() + "-" + f.d() + "T" + f.h() + ":" + f.i() + ":" + f.s() + f.P()
+ },
+ //r not supported yet
+ U: function () {
+ return Math.round(jsdate.getTime() / 1000)
+ }
+ };
+
+ return format.replace(/[\]?([a-zA-Z])/g, function (t, s) {
+ if (t != s) {
+ // escaped
+ ret = s;
+ } else if (f[s]) {
+ // a date function exists
+ ret = f[s]();
+ } else {
+ // nothing special
+ ret = s;
+ }
+ return ret;
+ });
+}
+
diff --git a/hotgo-uniapp/uview-ui/libs/function/debounce.js b/hotgo-uniapp/uview-ui/libs/function/debounce.js
new file mode 100644
index 0000000..4f1027b
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/debounce.js
@@ -0,0 +1,29 @@
+let timeout = null;
+
+/**
+ * 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
+ *
+ * @param {Function} func 要执行的回调函数
+ * @param {Number} wait 延时的时间
+ * @param {Boolean} immediate 是否立即执行
+ * @return null
+ */
+function debounce(func, wait = 500, immediate = false) {
+ // 清除定时器
+ if (timeout !== null) clearTimeout(timeout);
+ // 立即执行,此类情况一般用不到
+ if (immediate) {
+ var callNow = !timeout;
+ timeout = setTimeout(function() {
+ timeout = null;
+ }, wait);
+ if (callNow) typeof func === 'function' && func();
+ } else {
+ // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
+ timeout = setTimeout(function() {
+ typeof func === 'function' && func();
+ }, wait);
+ }
+}
+
+export default debounce
diff --git a/hotgo-uniapp/uview-ui/libs/function/deepClone.js b/hotgo-uniapp/uview-ui/libs/function/deepClone.js
new file mode 100644
index 0000000..3db999a
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/deepClone.js
@@ -0,0 +1,23 @@
+// 判断arr是否为一个数组,返回一个bool值
+function isArray (arr) {
+ return Object.prototype.toString.call(arr) === '[object Array]';
+}
+
+// 深度克隆
+function deepClone (obj) {
+ // 对常见的“非”值,直接返回原来值
+ if([null, undefined, NaN, false].includes(obj)) return obj;
+ if(typeof obj !== "object" && typeof obj !== 'function') {
+ //原始类型直接返回
+ return obj;
+ }
+ var o = isArray(obj) ? [] : {};
+ for(let i in obj) {
+ if(obj.hasOwnProperty(i)){
+ o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
+ }
+ }
+ return o;
+}
+
+export default deepClone;
diff --git a/hotgo-uniapp/uview-ui/libs/function/deepMerge.js b/hotgo-uniapp/uview-ui/libs/function/deepMerge.js
new file mode 100644
index 0000000..81d2d18
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/deepMerge.js
@@ -0,0 +1,30 @@
+import deepClone from "./deepClone";
+
+// JS对象深度合并
+function deepMerge(target = {}, source = {}) {
+ target = deepClone(target);
+ if (typeof target !== 'object' || typeof source !== 'object') return false;
+ for (var prop in source) {
+ if (!source.hasOwnProperty(prop)) continue;
+ if (prop in target) {
+ if (typeof target[prop] !== 'object') {
+ target[prop] = source[prop];
+ } else {
+ if (typeof source[prop] !== 'object') {
+ target[prop] = source[prop];
+ } else {
+ if (target[prop].concat && source[prop].concat) {
+ target[prop] = target[prop].concat(source[prop]);
+ } else {
+ target[prop] = deepMerge(target[prop], source[prop]);
+ }
+ }
+ }
+ } else {
+ target[prop] = source[prop];
+ }
+ }
+ return target;
+}
+
+export default deepMerge;
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/function/getParent.js b/hotgo-uniapp/uview-ui/libs/function/getParent.js
new file mode 100644
index 0000000..9cb45c4
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/getParent.js
@@ -0,0 +1,47 @@
+// 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法
+// this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx
+export default function getParent(name, keys) {
+ let parent = this.$parent;
+ // 通过while历遍,这里主要是为了H5需要多层解析的问题
+ while (parent) {
+ // 父组件
+ if (parent.$options.name !== name) {
+ // 如果组件的name不相等,继续上一级寻找
+ parent = parent.$parent;
+ } else {
+ let data = {};
+ // 判断keys是否数组,如果传过来的是一个数组,那么直接使用数组元素值当做键值去父组件寻找
+ if(Array.isArray(keys)) {
+ keys.map(val => {
+ data[val] = parent[val] ? parent[val] : '';
+ })
+ } else {
+ // 历遍传过来的对象参数
+ for(let i in keys) {
+ // 如果子组件有此值则用,无此值则用父组件的值
+ // 判断是否空数组,如果是,则用父组件的值,否则用子组件的值
+ if(Array.isArray(keys[i])) {
+ if(keys[i].length) {
+ data[i] = keys[i];
+ } else {
+ data[i] = parent[i];
+ }
+ } else if(keys[i].constructor === Object) {
+ // 判断是否对象,如果是对象,且有属性,那么使用子组件的值,否则使用父组件的值
+ if(Object.keys(keys[i]).length) {
+ data[i] = keys[i];
+ } else {
+ data[i] = parent[i];
+ }
+ } else {
+ // 只要子组件有传值,即使是false值,也是“传值”了,也需要覆盖父组件的同名参数
+ data[i] = (keys[i] || keys[i] === false) ? keys[i] : parent[i];
+ }
+ }
+ }
+ return data;
+ }
+ }
+
+ return {};
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/function/guid.js b/hotgo-uniapp/uview-ui/libs/function/guid.js
new file mode 100644
index 0000000..8497664
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/guid.js
@@ -0,0 +1,41 @@
+/**
+ * 本算法来源于简书开源代码,详见:https://www.jianshu.com/p/fdbf293d0a85
+ * 全局唯一标识符(uuid,Globally Unique Identifier),也称作 uuid(Universally Unique IDentifier)
+ * 一般用于多个组件之间,给它一个唯一的标识符,或者v-for循环的时候,如果使用数组的index可能会导致更新列表出现问题
+ * 最可能的情况是左滑删除item或者对某条信息流"不喜欢"并去掉它的时候,会导致组件内的数据可能出现错乱
+ * v-for的时候,推荐使用后端返回的id而不是循环的index
+ * @param {Number} len uuid的长度
+ * @param {Boolean} firstU 将返回的首字母置为"u"
+ * @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制
+ */
+function guid(len = 32, firstU = true, radix = null) {
+ let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
+ let uuid = [];
+ radix = radix || chars.length;
+
+ if (len) {
+ // 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
+ for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
+ } else {
+ let r;
+ // rfc4122标准要求返回的uuid中,某些位为固定的字符
+ uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
+ uuid[14] = '4';
+
+ for (let i = 0; i < 36; i++) {
+ if (!uuid[i]) {
+ r = 0 | Math.random() * 16;
+ uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
+ }
+ }
+ }
+ // 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
+ if (firstU) {
+ uuid.shift();
+ return 'u' + uuid.join('');
+ } else {
+ return uuid.join('');
+ }
+}
+
+export default guid;
diff --git a/hotgo-uniapp/uview-ui/libs/function/md5.js b/hotgo-uniapp/uview-ui/libs/function/md5.js
new file mode 100644
index 0000000..8d541a1
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/md5.js
@@ -0,0 +1,385 @@
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
+var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
+function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
+function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
+function hex_hmac_md5(k, d)
+ { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function b64_hmac_md5(k, d)
+ { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function any_hmac_md5(k, d, e)
+ { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function md5_vm_test()
+{
+ return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
+}
+
+/*
+ * Calculate the MD5 of a raw string
+ */
+function rstr_md5(s)
+{
+ return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
+}
+
+/*
+ * Calculate the HMAC-MD5, of a key and some data (raw strings)
+ */
+function rstr_hmac_md5(key, data)
+{
+ var bkey = rstr2binl(key);
+ if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
+
+ var ipad = Array(16), opad = Array(16);
+ for(var i = 0; i < 16; i++)
+ {
+ ipad[i] = bkey[i] ^ 0x36363636;
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
+ }
+
+ var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
+ return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
+}
+
+/*
+ * Convert a raw string to a hex string
+ */
+function rstr2hex(input)
+{
+ try { hexcase } catch(e) { hexcase=0; }
+ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+ var output = "";
+ var x;
+ for(var i = 0; i < input.length; i++)
+ {
+ x = input.charCodeAt(i);
+ output += hex_tab.charAt((x >>> 4) & 0x0F)
+ + hex_tab.charAt( x & 0x0F);
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to a base-64 string
+ */
+function rstr2b64(input)
+{
+ try { b64pad } catch(e) { b64pad=''; }
+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ var output = "";
+ var len = input.length;
+ for(var i = 0; i < len; i += 3)
+ {
+ var triplet = (input.charCodeAt(i) << 16)
+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);
+ for(var j = 0; j < 4; j++)
+ {
+ if(i * 8 + j * 6 > input.length * 8) output += b64pad;
+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
+ }
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to an arbitrary string encoding
+ */
+function rstr2any(input, encoding)
+{
+ var divisor = encoding.length;
+ var i, j, q, x, quotient;
+
+ /* Convert to an array of 16-bit big-endian values, forming the dividend */
+ var dividend = Array(Math.ceil(input.length / 2));
+ for(i = 0; i < dividend.length; i++)
+ {
+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
+ }
+
+ /*
+ * Repeatedly perform a long division. The binary array forms the dividend,
+ * the length of the encoding is the divisor. Once computed, the quotient
+ * forms the dividend for the next step. All remainders are stored for later
+ * use.
+ */
+ var full_length = Math.ceil(input.length * 8 /
+ (Math.log(encoding.length) / Math.log(2)));
+ var remainders = Array(full_length);
+ for(j = 0; j < full_length; j++)
+ {
+ quotient = Array();
+ x = 0;
+ for(i = 0; i < dividend.length; i++)
+ {
+ x = (x << 16) + dividend[i];
+ q = Math.floor(x / divisor);
+ x -= q * divisor;
+ if(quotient.length > 0 || q > 0)
+ quotient[quotient.length] = q;
+ }
+ remainders[j] = x;
+ dividend = quotient;
+ }
+
+ /* Convert the remainders to the output string */
+ var output = "";
+ for(i = remainders.length - 1; i >= 0; i--)
+ output += encoding.charAt(remainders[i]);
+
+ return output;
+}
+
+/*
+ * Encode a string as utf-8.
+ * For efficiency, this assumes the input is valid utf-16.
+ */
+function str2rstr_utf8(input)
+{
+ var output = "";
+ var i = -1;
+ var x, y;
+
+ while(++i < input.length)
+ {
+ /* Decode utf-16 surrogate pairs */
+ x = input.charCodeAt(i);
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
+ {
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
+ i++;
+ }
+
+ /* Encode output as utf-8 */
+ if(x <= 0x7F)
+ output += String.fromCharCode(x);
+ else if(x <= 0x7FF)
+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0xFFFF)
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0x1FFFFF)
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
+ 0x80 | ((x >>> 12) & 0x3F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ }
+ return output;
+}
+
+/*
+ * Encode a string as utf-16
+ */
+function str2rstr_utf16le(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
+ (input.charCodeAt(i) >>> 8) & 0xFF);
+ return output;
+}
+
+function str2rstr_utf16be(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
+ input.charCodeAt(i) & 0xFF);
+ return output;
+}
+
+/*
+ * Convert a raw string to an array of little-endian words
+ * Characters >255 have their high-byte silently ignored.
+ */
+function rstr2binl(input)
+{
+ var output = Array(input.length >> 2);
+ for(var i = 0; i < output.length; i++)
+ output[i] = 0;
+ for(var i = 0; i < input.length * 8; i += 8)
+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
+ return output;
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2rstr(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length * 32; i += 8)
+ output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
+ return output;
+}
+
+/*
+ * Calculate the MD5 of an array of little-endian words, and a bit length.
+ */
+function binl_md5(x, len)
+{
+ /* append padding */
+ x[len >> 5] |= 0x80 << ((len) % 32);
+ x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+ var a = 1732584193;
+ var b = -271733879;
+ var c = -1732584194;
+ var d = 271733878;
+
+ for(var i = 0; i < x.length; i += 16)
+ {
+ var olda = a;
+ var oldb = b;
+ var oldc = c;
+ var oldd = d;
+
+ a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
+ d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
+ c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
+ b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+ a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
+ d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
+ c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
+ b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
+ a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
+ d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
+ c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
+ b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
+ a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
+ d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+ c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
+ b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
+
+ a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
+ d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
+ c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
+ b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
+ a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
+ d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
+ c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
+ b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+ a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
+ d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
+ c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
+ b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
+ a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
+ d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
+ c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
+ b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
+
+ a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
+ d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+ c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
+ b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
+ a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
+ d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
+ c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
+ b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
+ a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
+ d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
+ c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
+ b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
+ a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
+ d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
+ c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
+ b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
+
+ a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
+ d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
+ c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
+ b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
+ a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
+ d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+ c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
+ b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
+ a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
+ d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
+ c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
+ b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
+ a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
+ d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
+ c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
+ b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+
+ a = safe_add(a, olda);
+ b = safe_add(b, oldb);
+ c = safe_add(c, oldc);
+ d = safe_add(d, oldd);
+ }
+ return Array(a, b, c, d);
+}
+
+/*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+function md5_cmn(q, a, b, x, s, t)
+{
+ return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
+}
+function md5_ff(a, b, c, d, x, s, t)
+{
+ return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+}
+function md5_gg(a, b, c, d, x, s, t)
+{
+ return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+}
+function md5_hh(a, b, c, d, x, s, t)
+{
+ return md5_cmn(b ^ c ^ d, a, b, x, s, t);
+}
+function md5_ii(a, b, c, d, x, s, t)
+{
+ return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+ var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+ var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+ return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+ return (num << cnt) | (num >>> (32 - cnt));
+}
+
+module.exports = {
+ md5 : function(str){
+ return hex_md5(str);
+ }
+}
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/function/queryParams.js b/hotgo-uniapp/uview-ui/libs/function/queryParams.js
new file mode 100644
index 0000000..81c7e5e
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/queryParams.js
@@ -0,0 +1,58 @@
+/**
+ * 对象转url参数
+ * @param {*} data,对象
+ * @param {*} isPrefix,是否自动加上"?"
+ */
+function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') {
+ let prefix = isPrefix ? '?' : ''
+ let _result = []
+ if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets';
+ for (let key in data) {
+ let value = data[key]
+ // 去掉为空的参数
+ if (['', undefined, null].indexOf(value) >= 0) {
+ continue;
+ }
+ // 如果值为数组,另行处理
+ if (value.constructor === Array) {
+ // e.g. {ids: [1, 2, 3]}
+ switch (arrayFormat) {
+ case 'indices':
+ // 结果: ids[0]=1&ids[1]=2&ids[2]=3
+ for (let i = 0; i < value.length; i++) {
+ _result.push(key + '[' + i + ']=' + value[i])
+ }
+ break;
+ case 'brackets':
+ // 结果: ids[]=1&ids[]=2&ids[]=3
+ value.forEach(_value => {
+ _result.push(key + '[]=' + _value)
+ })
+ break;
+ case 'repeat':
+ // 结果: ids=1&ids=2&ids=3
+ value.forEach(_value => {
+ _result.push(key + '=' + _value)
+ })
+ break;
+ case 'comma':
+ // 结果: ids=1,2,3
+ let commaStr = "";
+ value.forEach(_value => {
+ commaStr += (commaStr ? "," : "") + _value;
+ })
+ _result.push(key + '=' + commaStr)
+ break;
+ default:
+ value.forEach(_value => {
+ _result.push(key + '[]=' + _value)
+ })
+ }
+ } else {
+ _result.push(key + '=' + value)
+ }
+ }
+ return _result.length ? prefix + _result.join('&') : ''
+}
+
+export default queryParams;
diff --git a/hotgo-uniapp/uview-ui/libs/function/random.js b/hotgo-uniapp/uview-ui/libs/function/random.js
new file mode 100644
index 0000000..e155279
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/random.js
@@ -0,0 +1,10 @@
+function random(min, max) {
+ if (min >= 0 && max > 0 && max >= min) {
+ let gab = max - min + 1;
+ return Math.floor(Math.random() * gab + min);
+ } else {
+ return 0;
+ }
+}
+
+export default random;
diff --git a/hotgo-uniapp/uview-ui/libs/function/randomArray.js b/hotgo-uniapp/uview-ui/libs/function/randomArray.js
new file mode 100644
index 0000000..590a048
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/randomArray.js
@@ -0,0 +1,7 @@
+// 打乱数组
+function randomArray(array = []) {
+ // 原理是sort排序,Math.random()产生0<= x < 1之间的数,会导致x-0.05大于或者小于0
+ return array.sort(() => Math.random() - 0.5);
+}
+
+export default randomArray
diff --git a/hotgo-uniapp/uview-ui/libs/function/route.js b/hotgo-uniapp/uview-ui/libs/function/route.js
new file mode 100644
index 0000000..28a81b7
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/route.js
@@ -0,0 +1,122 @@
+/**
+ * 路由跳转方法,该方法相对于直接使用uni.xxx的好处是使用更加简单快捷
+ * 并且带有路由拦截功能
+ */
+
+class Router {
+ constructor() {
+ // 原始属性定义
+ this.config = {
+ type: 'navigateTo',
+ url: '',
+ delta: 1, // navigateBack页面后退时,回退的层数
+ params: {}, // 传递的参数
+ animationType: 'pop-in', // 窗口动画,只在APP有效
+ animationDuration: 300, // 窗口动画持续时间,单位毫秒,只在APP有效
+ intercept: false, // 是否需要拦截
+ }
+ // 因为route方法是需要对外赋值给另外的对象使用,同时route内部有使用this,会导致route失去上下文
+ // 这里在构造函数中进行this绑定
+ this.route = this.route.bind(this)
+ }
+
+ // 判断url前面是否有"/",如果没有则加上,否则无法跳转
+ addRootPath(url) {
+ return url[0] === '/' ? url : `/${url}`
+ }
+
+ // 整合路由参数
+ mixinParam(url, params) {
+ url = url && this.addRootPath(url)
+
+ // 使用正则匹配,主要依据是判断是否有"/","?","="等,如“/page/index/index?name=mary"
+ // 如果有url中有get参数,转换后无需带上"?"
+ let query = ''
+ if (/.*\/.*\?.*=.*/.test(url)) {
+ // object对象转为get类型的参数
+ query = uni.$u.queryParams(params, false);
+ // 因为已有get参数,所以后面拼接的参数需要带上"&"隔开
+ return url += "&" + query
+ } else {
+ // 直接拼接参数,因为此处url中没有后面的query参数,也就没有"?/&"之类的符号
+ query = uni.$u.queryParams(params);
+ return url += query
+ }
+ }
+
+ // 对外的方法名称
+ async route(options = {}, params = {}) {
+ // 合并用户的配置和内部的默认配置
+ let mergeConfig = {}
+
+ if (typeof options === 'string') {
+ // 如果options为字符串,则为route(url, params)的形式
+ mergeConfig.url = this.mixinParam(options, params)
+ mergeConfig.type = 'navigateTo'
+ } else {
+ mergeConfig = uni.$u.deepClone(options, this.config)
+ // 否则正常使用mergeConfig中的url和params进行拼接
+ mergeConfig.url = this.mixinParam(options.url, options.params)
+ }
+
+ if(params.intercept) {
+ this.config.intercept = params.intercept
+ }
+ // params参数也带给拦截器
+ mergeConfig.params = params
+ // 合并内外部参数
+ mergeConfig = uni.$u.deepMerge(this.config, mergeConfig)
+ // 判断用户是否定义了拦截器
+ if (typeof uni.$u.routeIntercept === 'function') {
+ // 定一个promise,根据用户执行resolve(true)或者resolve(false)来决定是否进行路由跳转
+ const isNext = await new Promise((resolve, reject) => {
+ uni.$u.routeIntercept(mergeConfig, resolve)
+ })
+ // 如果isNext为true,则执行路由跳转
+ isNext && this.openPage(mergeConfig)
+ } else {
+ this.openPage(mergeConfig)
+ }
+ }
+
+ // 执行路由跳转
+ openPage(config) {
+ // 解构参数
+ const {
+ url,
+ type,
+ delta,
+ animationType,
+ animationDuration
+ } = config
+ if (config.type == 'navigateTo' || config.type == 'to') {
+ uni.navigateTo({
+ url,
+ animationType,
+ animationDuration
+ });
+ }
+ if (config.type == 'redirectTo' || config.type == 'redirect') {
+ uni.redirectTo({
+ url
+ });
+ }
+ if (config.type == 'switchTab' || config.type == 'tab') {
+ uni.switchTab({
+ url
+ });
+ }
+ if (config.type == 'reLaunch' || config.type == 'launch') {
+ uni.reLaunch({
+ url
+ });
+ }
+ if (config.type == 'navigateBack' || config.type == 'back') {
+ uni.navigateBack({
+ delta
+ });
+ }
+ }
+}
+
+export default (new Router()).route
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/function/sys.js b/hotgo-uniapp/uview-ui/libs/function/sys.js
new file mode 100644
index 0000000..00f6a28
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/sys.js
@@ -0,0 +1,9 @@
+export function os() {
+ return uni.getSystemInfoSync().platform;
+};
+
+export function sys() {
+ return uni.getSystemInfoSync();
+}
+
+
diff --git a/hotgo-uniapp/uview-ui/libs/function/test.js b/hotgo-uniapp/uview-ui/libs/function/test.js
new file mode 100644
index 0000000..fd25e18
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/test.js
@@ -0,0 +1,232 @@
+/**
+ * 验证电子邮箱格式
+ */
+function email(value) {
+ return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value);
+}
+
+/**
+ * 验证手机格式
+ */
+function mobile(value) {
+ return /^1[3-9]\d{9}$/.test(value)
+}
+
+/**
+ * 验证URL格式
+ */
+function url(value) {
+ return /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/.test(value)
+}
+
+/**
+ * 验证日期格式
+ */
+function date(value) {
+ return !/Invalid|NaN/.test(new Date(value).toString())
+}
+
+/**
+ * 验证ISO类型的日期格式
+ */
+function dateISO(value) {
+ return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
+}
+
+/**
+ * 验证十进制数字
+ */
+function number(value) {
+ return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value)
+}
+
+/**
+ * 验证整数
+ */
+function digits(value) {
+ return /^\d+$/.test(value)
+}
+
+/**
+ * 验证身份证号码
+ */
+function idCard(value) {
+ return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
+ value)
+}
+
+/**
+ * 是否车牌号
+ */
+function carNo(value) {
+ // 新能源车牌
+ const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/;
+ // 旧车牌
+ const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
+ if (value.length === 7) {
+ return creg.test(value);
+ } else if (value.length === 8) {
+ return xreg.test(value);
+ } else {
+ return false;
+ }
+}
+
+/**
+ * 金额,只允许2位小数
+ */
+function amount(value) {
+ //金额,只允许保留两位小数
+ return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value);
+}
+
+/**
+ * 中文
+ */
+function chinese(value) {
+ let reg = /^[\u4e00-\u9fa5]+$/gi;
+ return reg.test(value);
+}
+
+/**
+ * 只能输入字母
+ */
+function letter(value) {
+ return /^[a-zA-Z]*$/.test(value);
+}
+
+/**
+ * 只能是字母或者数字
+ */
+function enOrNum(value) {
+ //英文或者数字
+ let reg = /^[0-9a-zA-Z]*$/g;
+ return reg.test(value);
+}
+
+/**
+ * 验证是否包含某个值
+ */
+function contains(value, param) {
+ return value.indexOf(param) >= 0
+}
+
+/**
+ * 验证一个值范围[min, max]
+ */
+function range(value, param) {
+ return value >= param[0] && value <= param[1]
+}
+
+/**
+ * 验证一个长度范围[min, max]
+ */
+function rangeLength(value, param) {
+ return value.length >= param[0] && value.length <= param[1]
+}
+
+/**
+ * 是否固定电话
+ */
+function landline(value) {
+ let reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/;
+ return reg.test(value);
+}
+
+/**
+ * 判断是否为空
+ */
+function empty(value) {
+ switch (typeof value) {
+ case 'undefined':
+ return true;
+ case 'string':
+ if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true;
+ break;
+ case 'boolean':
+ if (!value) return true;
+ break;
+ case 'number':
+ if (0 === value || isNaN(value)) return true;
+ break;
+ case 'object':
+ if (null === value || value.length === 0) return true;
+ for (var i in value) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+/**
+ * 是否json字符串
+ */
+function jsonString(value) {
+ if (typeof value == 'string') {
+ try {
+ var obj = JSON.parse(value);
+ if (typeof obj == 'object' && obj) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (e) {
+ return false;
+ }
+ }
+ return false;
+}
+
+
+/**
+ * 是否数组
+ */
+function array(value) {
+ if (typeof Array.isArray === "function") {
+ return Array.isArray(value);
+ } else {
+ return Object.prototype.toString.call(value) === "[object Array]";
+ }
+}
+
+/**
+ * 是否对象
+ */
+function object(value) {
+ return Object.prototype.toString.call(value) === '[object Object]';
+}
+
+/**
+ * 是否短信验证码
+ */
+function code(value, len = 6) {
+ return new RegExp(`^\\d{${len}}$`).test(value);
+}
+
+
+export default {
+ email,
+ mobile,
+ url,
+ date,
+ dateISO,
+ number,
+ digits,
+ idCard,
+ carNo,
+ amount,
+ chinese,
+ letter,
+ enOrNum,
+ contains,
+ range,
+ rangeLength,
+ empty,
+ isEmpty: empty,
+ jsonString,
+ landline,
+ object,
+ array,
+ code
+}
diff --git a/hotgo-uniapp/uview-ui/libs/function/throttle.js b/hotgo-uniapp/uview-ui/libs/function/throttle.js
new file mode 100644
index 0000000..ad830b2
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/throttle.js
@@ -0,0 +1,32 @@
+let timer, flag;
+/**
+ * 节流原理:在一定时间内,只能触发一次
+ *
+ * @param {Function} func 要执行的回调函数
+ * @param {Number} wait 延时的时间
+ * @param {Boolean} immediate 是否立即执行
+ * @return null
+ */
+function throttle(func, wait = 500, immediate = true) {
+ if (immediate) {
+ if (!flag) {
+ flag = true;
+ // 如果是立即执行,则在wait毫秒内开始时执行
+ typeof func === 'function' && func();
+ timer = setTimeout(() => {
+ flag = false;
+ }, wait);
+ }
+ } else {
+ if (!flag) {
+ flag = true
+ // 如果是非立即执行,则在wait毫秒内的结束处执行
+ timer = setTimeout(() => {
+ flag = false
+ typeof func === 'function' && func();
+ }, wait);
+ }
+
+ }
+};
+export default throttle
diff --git a/hotgo-uniapp/uview-ui/libs/function/timeFormat.js b/hotgo-uniapp/uview-ui/libs/function/timeFormat.js
new file mode 100644
index 0000000..0372f2f
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/timeFormat.js
@@ -0,0 +1,51 @@
+// padStart 的 polyfill,因为某些机型或情况,还无法支持es7的padStart,比如电脑版的微信小程序
+// 所以这里做一个兼容polyfill的兼容处理
+if (!String.prototype.padStart) {
+ // 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解
+ String.prototype.padStart = function(maxLength, fillString = ' ') {
+ if (Object.prototype.toString.call(fillString) !== "[object String]") throw new TypeError(
+ 'fillString must be String')
+ let str = this
+ // 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉
+ if (str.length >= maxLength) return String(str)
+
+ let fillLength = maxLength - str.length,
+ times = Math.ceil(fillLength / fillString.length)
+ while (times >>= 1) {
+ fillString += fillString
+ if (times === 1) {
+ fillString += fillString
+ }
+ }
+ return fillString.slice(0, fillLength) + str;
+ }
+}
+
+// 其他更多是格式化有如下:
+// yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合
+function timeFormat(dateTime = null, fmt = 'yyyy-mm-dd') {
+ // 如果为null,则格式化当前时间
+ if (!dateTime) dateTime = Number(new Date());
+ // 如果dateTime长度为10或者13,则为秒和毫秒的时间戳,如果超过13位,则为其他的时间格式
+ if (dateTime.toString().length == 10) dateTime *= 1000;
+ let date = new Date(dateTime);
+ let ret;
+ let opt = {
+ "y+": date.getFullYear().toString(), // 年
+ "m+": (date.getMonth() + 1).toString(), // 月
+ "d+": date.getDate().toString(), // 日
+ "h+": date.getHours().toString(), // 时
+ "M+": date.getMinutes().toString(), // 分
+ "s+": date.getSeconds().toString() // 秒
+ // 有其他格式化字符需求可以继续添加,必须转化成字符串
+ };
+ for (let k in opt) {
+ ret = new RegExp("(" + k + ")").exec(fmt);
+ if (ret) {
+ fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
+ };
+ };
+ return fmt;
+}
+
+export default timeFormat
diff --git a/hotgo-uniapp/uview-ui/libs/function/timeFrom.js b/hotgo-uniapp/uview-ui/libs/function/timeFrom.js
new file mode 100644
index 0000000..68cd990
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/timeFrom.js
@@ -0,0 +1,47 @@
+import timeFormat from '../../libs/function/timeFormat.js';
+
+/**
+ * 时间戳转为多久之前
+ * @param String timestamp 时间戳
+ * @param String | Boolean format 如果为时间格式字符串,超出一定时间范围,返回固定的时间格式;
+ * 如果为布尔值false,无论什么时间,都返回多久以前的格式
+ */
+function timeFrom(dateTime = null, format = 'yyyy-mm-dd') {
+ // 如果为null,则格式化当前时间
+ if (!dateTime) dateTime = Number(new Date());
+ // 如果dateTime长度为10或者13,则为秒和毫秒的时间戳,如果超过13位,则为其他的时间格式
+ if (dateTime.toString().length == 10) dateTime *= 1000;
+ let timestamp = + new Date(Number(dateTime));
+
+ let timer = (Number(new Date()) - timestamp) / 1000;
+ // 如果小于5分钟,则返回"刚刚",其他以此类推
+ let tips = '';
+ switch (true) {
+ case timer < 300:
+ tips = '刚刚';
+ break;
+ case timer >= 300 && timer < 3600:
+ tips = parseInt(timer / 60) + '分钟前';
+ break;
+ case timer >= 3600 && timer < 86400:
+ tips = parseInt(timer / 3600) + '小时前';
+ break;
+ case timer >= 86400 && timer < 2592000:
+ tips = parseInt(timer / 86400) + '天前';
+ break;
+ default:
+ // 如果format为false,则无论什么时间戳,都显示xx之前
+ if(format === false) {
+ if(timer >= 2592000 && timer < 365 * 86400) {
+ tips = parseInt(timer / (86400 * 30)) + '个月前';
+ } else {
+ tips = parseInt(timer / (86400 * 365)) + '年前';
+ }
+ } else {
+ tips = timeFormat(timestamp, format);
+ }
+ }
+ return tips;
+}
+
+export default timeFrom;
diff --git a/hotgo-uniapp/uview-ui/libs/function/toast.js b/hotgo-uniapp/uview-ui/libs/function/toast.js
new file mode 100644
index 0000000..91afa73
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/toast.js
@@ -0,0 +1,9 @@
+function toast(title, duration = 1500) {
+ uni.showToast({
+ title: title,
+ icon: 'none',
+ duration: duration
+ })
+}
+
+export default toast
diff --git a/hotgo-uniapp/uview-ui/libs/function/trim.js b/hotgo-uniapp/uview-ui/libs/function/trim.js
new file mode 100644
index 0000000..72adc37
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/trim.js
@@ -0,0 +1,15 @@
+function trim(str, pos = 'both') {
+ if (pos == 'both') {
+ return str.replace(/^\s+|\s+$/g, "");
+ } else if (pos == "left") {
+ return str.replace(/^\s*/, '');
+ } else if (pos == 'right') {
+ return str.replace(/(\s*$)/g, "");
+ } else if (pos == 'all') {
+ return str.replace(/\s+/g, "");
+ } else {
+ return str;
+ }
+}
+
+export default trim
diff --git a/hotgo-uniapp/uview-ui/libs/function/type2icon.js b/hotgo-uniapp/uview-ui/libs/function/type2icon.js
new file mode 100644
index 0000000..23cb40e
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/function/type2icon.js
@@ -0,0 +1,35 @@
+/**
+ * 根据主题type值,获取对应的图标
+ * @param String type 主题名称,primary|info|error|warning|success
+ * @param String fill 是否使用fill填充实体的图标
+ */
+function type2icon(type = 'success', fill = false) {
+ // 如果非预置值,默认为success
+ if (['primary', 'info', 'error', 'warning', 'success'].indexOf(type) == -1) type = 'success';
+ let iconName = '';
+ // 目前(2019-12-12),info和primary使用同一个图标
+ switch (type) {
+ case 'primary':
+ iconName = 'info-circle';
+ break;
+ case 'info':
+ iconName = 'info-circle';
+ break;
+ case 'error':
+ iconName = 'close-circle';
+ break;
+ case 'warning':
+ iconName = 'error-circle';
+ break;
+ case 'success':
+ iconName = 'checkmark-circle';
+ break;
+ default:
+ iconName = 'checkmark-circle';
+ }
+ // 是否是实体类型,加上-fill,在icon组件库中,实体的类名是后面加-fill的
+ if (fill) iconName += '-fill';
+ return iconName;
+}
+
+export default type2icon
diff --git a/hotgo-uniapp/uview-ui/libs/mixin/mixin.js b/hotgo-uniapp/uview-ui/libs/mixin/mixin.js
new file mode 100644
index 0000000..e388986
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/mixin/mixin.js
@@ -0,0 +1,64 @@
+module.exports = {
+ data() {
+ return {}
+ },
+ onLoad() {
+ // getRect挂载到$u上,因为这方法需要使用in(this),所以无法把它独立成一个单独的文件导出
+ this.$u.getRect = this.$uGetRect
+ },
+ methods: {
+ // 查询节点信息
+ // 目前此方法在支付宝小程序中无法获取组件跟接点的尺寸,为支付宝的bug(2020-07-21)
+ // 解决办法为在组件根部再套一个没有任何作用的view元素
+ $uGetRect(selector, all) {
+ return new Promise(resolve => {
+ uni.createSelectorQuery().
+ in(this)[all ? 'selectAll' : 'select'](selector)
+ .boundingClientRect(rect => {
+ if (all && Array.isArray(rect) && rect.length) {
+ resolve(rect)
+ }
+ if (!all && rect) {
+ resolve(rect)
+ }
+ })
+ .exec()
+ })
+ },
+ getParentData(parentName = '') {
+ // 避免在created中去定义parent变量
+ if(!this.parent) this.parent = false;
+ // 这里的本质原理是,通过获取父组件实例(也即u-radio-group的this)
+ // 将父组件this中对应的参数,赋值给本组件(u-radio的this)的parentData对象中对应的属性
+ // 之所以需要这么做,是因为所有端中,头条小程序不支持通过this.parent.xxx去监听父组件参数的变化
+ this.parent = this.$u.$parent.call(this, parentName);
+ if(this.parent) {
+ // 历遍parentData中的属性,将parent中的同名属性赋值给parentData
+ Object.keys(this.parentData).map(key => {
+ this.parentData[key] = this.parent[key];
+ });
+ }
+ },
+ // 阻止事件冒泡
+ preventEvent(e) {
+ e && e.stopPropagation && e.stopPropagation()
+ }
+ },
+ onReachBottom() {
+ uni.$emit('uOnReachBottom')
+ },
+ beforeDestroy() {
+ // 判断当前页面是否存在parent和chldren,一般在checkbox和checkbox-group父子联动的场景会有此情况
+ // 组件销毁时,移除子组件在父组件children数组中的实例,释放资源,避免数据混乱
+ if(this.parent && uni.$u.test.array(this.parent.children)) {
+ // 组件销毁时,移除父组件中的children数组中对应的实例
+ const childrenList = this.parent.children
+ childrenList.map((child, index) => {
+ // 如果相等,则移除
+ if(child === this) {
+ childrenList.splice(index, 1)
+ }
+ })
+ }
+ }
+}
diff --git a/hotgo-uniapp/uview-ui/libs/mixin/mpShare.js b/hotgo-uniapp/uview-ui/libs/mixin/mpShare.js
new file mode 100644
index 0000000..057d369
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/mixin/mpShare.js
@@ -0,0 +1,18 @@
+module.exports = {
+ onLoad() {
+ // 设置默认的转发参数
+ this.$u.mpShare = {
+ title: '', // 默认为小程序名称
+ path: '', // 默认为当前页面路径
+ imageUrl: '' // 默认为当前页面的截图
+ }
+ },
+ onShareAppMessage() {
+ return this.$u.mpShare
+ },
+ // #ifdef MP-WEIXIN
+ onShareTimeline() {
+ return this.$u.mpShare
+ }
+ // #endif
+}
diff --git a/hotgo-uniapp/uview-ui/libs/request/index.js b/hotgo-uniapp/uview-ui/libs/request/index.js
new file mode 100644
index 0000000..b5e0561
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/request/index.js
@@ -0,0 +1,182 @@
+import deepMerge from "../function/deepMerge";
+import validate from "../function/test";
+
+class Request {
+ // 设置全局默认配置
+ setConfig(customConfig) {
+ // 深度合并对象,否则会造成对象深层属性丢失
+ this.config = deepMerge(this.config, customConfig);
+ }
+
+ // 主要请求部分
+ request(options = {}) {
+ // 检查请求拦截
+ if (this.interceptor.request && typeof this.interceptor.request == 'function') {
+ let tmpConfig = {};
+ let interceptorRequest = this.interceptor.request(options);
+ if (interceptorRequest === false) {
+ // 返回一个处于pending状态中的Promise,来取消原promise,避免进入then()回调
+ return new Promise(() => {
+ });
+ }
+ this.options = interceptorRequest;
+ }
+ options.dataType = options.dataType || this.config.dataType;
+ options.responseType = options.responseType || this.config.responseType;
+ options.url = options.url || '';
+ options.params = options.params || {};
+ options.header = Object.assign({}, this.config.header, options.header);
+ options.method = options.method || this.config.method;
+
+ return new Promise((resolve, reject) => {
+ options.complete = (response) => {
+ // 请求返回后,隐藏loading(如果请求返回快的话,可能会没有loading)
+ uni.hideLoading();
+ // 清除定时器,如果请求回来了,就无需loading
+ clearTimeout(this.config.timer);
+ this.config.timer = null;
+ // 判断用户对拦截返回数据的要求,如果originalData为true,返回所有的数据(response)到拦截器,否则只返回response.data
+ if (this.config.originalData) {
+ // 判断是否存在拦截器
+ if (this.interceptor.response && typeof this.interceptor.response == 'function') {
+ let resInterceptors = this.interceptor.response(response, options); // 增加请求选项,方便后续处理 ThinkGem
+ // 如果拦截器不返回false,就将拦截器返回的内容给this.$u.post的then回调
+ if (resInterceptors !== false) {
+ resolve(resInterceptors);
+ } else {
+ // 如果拦截器返回false,意味着拦截器定义者认为返回有问题,直接接入catch回调
+ reject(response);
+ }
+ } else {
+ // 如果要求返回原始数据,就算没有拦截器,也返回最原始的数据
+ resolve(response);
+ }
+ } else {
+
+ if (response.statusCode === 200) {
+ if (this.interceptor.response && typeof this.interceptor.response == 'function') {
+ this.response(response.data, options);
+ let resInterceptors = this.interceptor.response(response.data, options); // 增加请求选项,方便后续处理 ThinkGem
+ if (resInterceptors !== false) {
+ resolve(resInterceptors);
+ } else {
+ reject(response.data);
+ }
+ } else {
+ // 如果不是返回原始数据(originalData=false),且没有拦截器的情况下,返回纯数据给then回调
+ resolve(response.data);
+ }
+ } else {
+ // 不返回原始数据的情况下,服务器状态码不为200,modal弹框提示
+ // if(response.errMsg) {
+ // uni.showModal({
+ // title: response.errMsg
+ // });
+ // }
+ reject(response)
+ }
+ }
+ }
+
+ // 判断用户传递的URL是否/开头,如果不是,加上/,这里使用了uView的test.js验证库的url()方法
+ options.url = validate.url(options.url) ? options.url : (this.config.baseUrl + (options.url.indexOf('/') == 0 ?
+ options.url : '/' + options.url));
+
+ // 是否显示loading
+ // 加一个是否已有timer定时器的判断,否则有两个同时请求的时候,后者会清除前者的定时器id
+ // 而没有清除前者的定时器,导致前者超时,一直显示loading
+ if (this.config.showLoading && !this.config.timer) {
+ this.config.timer = setTimeout(() => {
+ uni.showLoading({
+ title: this.config.loadingText,
+ mask: this.config.loadingMask
+ })
+ this.config.timer = null;
+ }, this.config.loadingTime);
+ }
+ uni.request(options);
+ })
+ // .catch(res => {
+ // // 如果返回reject(),不让其进入this.$u.post().then().catch()后面的catct()
+ // // 因为很多人都会忘了写后面的catch(),导致报错捕获不到catch
+ // return new Promise(()=>{});
+ // })
+ }
+
+ constructor() {
+ this.config = {
+ baseUrl: '', // 请求的根域名
+ // 默认的请求头
+ header: {},
+ method: 'POST',
+ // 设置为json,返回后uni.request会对数据进行一次JSON.parse
+ dataType: 'json',
+ // 此参数无需处理,因为5+和支付宝小程序不支持,默认为text即可
+ responseType: 'text',
+ showLoading: true, // 是否显示请求中的loading
+ loadingText: '请求中...',
+ loadingTime: 800, // 在此时间内,请求还没回来的话,就显示加载中动画,单位ms
+ timer: null, // 定时器
+ originalData: false, // 是否在拦截器中返回服务端的原始数据,见文档说明
+ loadingMask: true, // 展示loading的时候,是否给一个透明的蒙层,防止触摸穿透
+ }
+
+ // 拦截器
+ this.interceptor = {
+ // 请求前的拦截
+ request: null,
+ // 请求后的拦截
+ response: null,
+ }
+
+ this.response = (response, options) => {
+ console.log('拦截器2response:' + JSON.stringify(response))
+ console.log('options:' + JSON.stringify(options))
+ // response.qwe = "6666"
+
+ return response;
+ }
+
+ // get请求
+ this.get = (url, data = {}, header = {}) => {
+ return this.request({
+ method: 'GET',
+ url,
+ header,
+ data
+ })
+ }
+
+ // post请求
+ this.post = (url, data = {}, header = {}) => {
+ return this.request({
+ url,
+ method: 'POST',
+ header,
+ data
+ })
+ }
+
+ // put请求,不支持支付宝小程序(HX2.6.15)
+ this.put = (url, data = {}, header = {}) => {
+ return this.request({
+ url,
+ method: 'PUT',
+ header,
+ data
+ })
+ }
+
+ // delete请求,不支持支付宝和头条小程序(HX2.6.15)
+ this.delete = (url, data = {}, header = {}) => {
+ return this.request({
+ url,
+ method: 'DELETE',
+ header,
+ data
+ })
+ }
+ }
+}
+
+export default new Request
diff --git a/hotgo-uniapp/uview-ui/libs/store/index.js b/hotgo-uniapp/uview-ui/libs/store/index.js
new file mode 100644
index 0000000..a5927b3
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/store/index.js
@@ -0,0 +1,19 @@
+// 暂时不用vuex模块方式实现,将该方法直接放入到/store/index.js中
+const module = {
+ actions: {
+ $uStore({rootState}, params) {
+ let nameArr = params.name.split('.');
+ if(nameArr.length >= 2) {
+ let obj = rootState[nameArr[0]];
+ for(let i = 1; i < nameArr.length - 1; i ++) {
+ obj = obj[nameArr[i]];
+ }
+ obj[nameArr[nameArr.length - 1]] = params.value;
+ } else {
+ rootState[params.name] = params.value;
+ }
+ }
+ }
+}
+
+export default module
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/util/area.js b/hotgo-uniapp/uview-ui/libs/util/area.js
new file mode 100644
index 0000000..0d602e9
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/util/area.js
@@ -0,0 +1 @@
+var areaData=[[[{"label":"东城区","value":"110101"},{"label":"西城区","value":"110102"},{"label":"朝阳区","value":"110105"},{"label":"丰台区","value":"110106"},{"label":"石景山区","value":"110107"},{"label":"海淀区","value":"110108"},{"label":"门头沟区","value":"110109"},{"label":"房山区","value":"110111"},{"label":"通州区","value":"110112"},{"label":"顺义区","value":"110113"},{"label":"昌平区","value":"110114"},{"label":"大兴区","value":"110115"},{"label":"怀柔区","value":"110116"},{"label":"平谷区","value":"110117"},{"label":"密云区","value":"110118"},{"label":"延庆区","value":"110119"}]],[[{"label":"和平区","value":"120101"},{"label":"河东区","value":"120102"},{"label":"河西区","value":"120103"},{"label":"南开区","value":"120104"},{"label":"河北区","value":"120105"},{"label":"红桥区","value":"120106"},{"label":"东丽区","value":"120110"},{"label":"西青区","value":"120111"},{"label":"津南区","value":"120112"},{"label":"北辰区","value":"120113"},{"label":"武清区","value":"120114"},{"label":"宝坻区","value":"120115"},{"label":"滨海新区","value":"120116"},{"label":"宁河区","value":"120117"},{"label":"静海区","value":"120118"},{"label":"蓟州区","value":"120119"}]],[[{"label":"长安区","value":"130102"},{"label":"桥西区","value":"130104"},{"label":"新华区","value":"130105"},{"label":"井陉矿区","value":"130107"},{"label":"裕华区","value":"130108"},{"label":"藁城区","value":"130109"},{"label":"鹿泉区","value":"130110"},{"label":"栾城区","value":"130111"},{"label":"井陉县","value":"130121"},{"label":"正定县","value":"130123"},{"label":"行唐县","value":"130125"},{"label":"灵寿县","value":"130126"},{"label":"高邑县","value":"130127"},{"label":"深泽县","value":"130128"},{"label":"赞皇县","value":"130129"},{"label":"无极县","value":"130130"},{"label":"平山县","value":"130131"},{"label":"元氏县","value":"130132"},{"label":"赵县","value":"130133"},{"label":"石家庄高新技术产业开发区","value":"130171"},{"label":"石家庄循环化工园区","value":"130172"},{"label":"辛集市","value":"130181"},{"label":"晋州市","value":"130183"},{"label":"新乐市","value":"130184"}],[{"label":"路南区","value":"130202"},{"label":"路北区","value":"130203"},{"label":"古冶区","value":"130204"},{"label":"开平区","value":"130205"},{"label":"丰南区","value":"130207"},{"label":"丰润区","value":"130208"},{"label":"曹妃甸区","value":"130209"},{"label":"滦县","value":"130223"},{"label":"滦南县","value":"130224"},{"label":"乐亭县","value":"130225"},{"label":"迁西县","value":"130227"},{"label":"玉田县","value":"130229"},{"label":"唐山市芦台经济技术开发区","value":"130271"},{"label":"唐山市汉沽管理区","value":"130272"},{"label":"唐山高新技术产业开发区","value":"130273"},{"label":"河北唐山海港经济开发区","value":"130274"},{"label":"遵化市","value":"130281"},{"label":"迁安市","value":"130283"}],[{"label":"海港区","value":"130302"},{"label":"山海关区","value":"130303"},{"label":"北戴河区","value":"130304"},{"label":"抚宁区","value":"130306"},{"label":"青龙满族自治县","value":"130321"},{"label":"昌黎县","value":"130322"},{"label":"卢龙县","value":"130324"},{"label":"秦皇岛市经济技术开发区","value":"130371"},{"label":"北戴河新区","value":"130372"}],[{"label":"邯山区","value":"130402"},{"label":"丛台区","value":"130403"},{"label":"复兴区","value":"130404"},{"label":"峰峰矿区","value":"130406"},{"label":"肥乡区","value":"130407"},{"label":"永年区","value":"130408"},{"label":"临漳县","value":"130423"},{"label":"成安县","value":"130424"},{"label":"大名县","value":"130425"},{"label":"涉县","value":"130426"},{"label":"磁县","value":"130427"},{"label":"邱县","value":"130430"},{"label":"鸡泽县","value":"130431"},{"label":"广平县","value":"130432"},{"label":"馆陶县","value":"130433"},{"label":"魏县","value":"130434"},{"label":"曲周县","value":"130435"},{"label":"邯郸经济技术开发区","value":"130471"},{"label":"邯郸冀南新区","value":"130473"},{"label":"武安市","value":"130481"}],[{"label":"桥东区","value":"130502"},{"label":"桥西区","value":"130503"},{"label":"邢台县","value":"130521"},{"label":"临城县","value":"130522"},{"label":"内丘县","value":"130523"},{"label":"柏乡县","value":"130524"},{"label":"隆尧县","value":"130525"},{"label":"任县","value":"130526"},{"label":"南和县","value":"130527"},{"label":"宁晋县","value":"130528"},{"label":"巨鹿县","value":"130529"},{"label":"新河县","value":"130530"},{"label":"广宗县","value":"130531"},{"label":"平乡县","value":"130532"},{"label":"威县","value":"130533"},{"label":"清河县","value":"130534"},{"label":"临西县","value":"130535"},{"label":"河北邢台经济开发区","value":"130571"},{"label":"南宫市","value":"130581"},{"label":"沙河市","value":"130582"}],[{"label":"竞秀区","value":"130602"},{"label":"莲池区","value":"130606"},{"label":"满城区","value":"130607"},{"label":"清苑区","value":"130608"},{"label":"徐水区","value":"130609"},{"label":"涞水县","value":"130623"},{"label":"阜平县","value":"130624"},{"label":"定兴县","value":"130626"},{"label":"唐县","value":"130627"},{"label":"高阳县","value":"130628"},{"label":"容城县","value":"130629"},{"label":"涞源县","value":"130630"},{"label":"望都县","value":"130631"},{"label":"安新县","value":"130632"},{"label":"易县","value":"130633"},{"label":"曲阳县","value":"130634"},{"label":"蠡县","value":"130635"},{"label":"顺平县","value":"130636"},{"label":"博野县","value":"130637"},{"label":"雄县","value":"130638"},{"label":"保定高新技术产业开发区","value":"130671"},{"label":"保定白沟新城","value":"130672"},{"label":"涿州市","value":"130681"},{"label":"定州市","value":"130682"},{"label":"安国市","value":"130683"},{"label":"高碑店市","value":"130684"}],[{"label":"桥东区","value":"130702"},{"label":"桥西区","value":"130703"},{"label":"宣化区","value":"130705"},{"label":"下花园区","value":"130706"},{"label":"万全区","value":"130708"},{"label":"崇礼区","value":"130709"},{"label":"张北县","value":"130722"},{"label":"康保县","value":"130723"},{"label":"沽源县","value":"130724"},{"label":"尚义县","value":"130725"},{"label":"蔚县","value":"130726"},{"label":"阳原县","value":"130727"},{"label":"怀安县","value":"130728"},{"label":"怀来县","value":"130730"},{"label":"涿鹿县","value":"130731"},{"label":"赤城县","value":"130732"},{"label":"张家口市高新技术产业开发区","value":"130771"},{"label":"张家口市察北管理区","value":"130772"},{"label":"张家口市塞北管理区","value":"130773"}],[{"label":"双桥区","value":"130802"},{"label":"双滦区","value":"130803"},{"label":"鹰手营子矿区","value":"130804"},{"label":"承德县","value":"130821"},{"label":"兴隆县","value":"130822"},{"label":"滦平县","value":"130824"},{"label":"隆化县","value":"130825"},{"label":"丰宁满族自治县","value":"130826"},{"label":"宽城满族自治县","value":"130827"},{"label":"围场满族蒙古族自治县","value":"130828"},{"label":"承德高新技术产业开发区","value":"130871"},{"label":"平泉市","value":"130881"}],[{"label":"新华区","value":"130902"},{"label":"运河区","value":"130903"},{"label":"沧县","value":"130921"},{"label":"青县","value":"130922"},{"label":"东光县","value":"130923"},{"label":"海兴县","value":"130924"},{"label":"盐山县","value":"130925"},{"label":"肃宁县","value":"130926"},{"label":"南皮县","value":"130927"},{"label":"吴桥县","value":"130928"},{"label":"献县","value":"130929"},{"label":"孟村回族自治县","value":"130930"},{"label":"河北沧州经济开发区","value":"130971"},{"label":"沧州高新技术产业开发区","value":"130972"},{"label":"沧州渤海新区","value":"130973"},{"label":"泊头市","value":"130981"},{"label":"任丘市","value":"130982"},{"label":"黄骅市","value":"130983"},{"label":"河间市","value":"130984"}],[{"label":"安次区","value":"131002"},{"label":"广阳区","value":"131003"},{"label":"固安县","value":"131022"},{"label":"永清县","value":"131023"},{"label":"香河县","value":"131024"},{"label":"大城县","value":"131025"},{"label":"文安县","value":"131026"},{"label":"大厂回族自治县","value":"131028"},{"label":"廊坊经济技术开发区","value":"131071"},{"label":"霸州市","value":"131081"},{"label":"三河市","value":"131082"}],[{"label":"桃城区","value":"131102"},{"label":"冀州区","value":"131103"},{"label":"枣强县","value":"131121"},{"label":"武邑县","value":"131122"},{"label":"武强县","value":"131123"},{"label":"饶阳县","value":"131124"},{"label":"安平县","value":"131125"},{"label":"故城县","value":"131126"},{"label":"景县","value":"131127"},{"label":"阜城县","value":"131128"},{"label":"河北衡水经济开发区","value":"131171"},{"label":"衡水滨湖新区","value":"131172"},{"label":"深州市","value":"131182"}]],[[{"label":"小店区","value":"140105"},{"label":"迎泽区","value":"140106"},{"label":"杏花岭区","value":"140107"},{"label":"尖草坪区","value":"140108"},{"label":"万柏林区","value":"140109"},{"label":"晋源区","value":"140110"},{"label":"清徐县","value":"140121"},{"label":"阳曲县","value":"140122"},{"label":"娄烦县","value":"140123"},{"label":"山西转型综合改革示范区","value":"140171"},{"label":"古交市","value":"140181"}],[{"label":"城区","value":"140202"},{"label":"矿区","value":"140203"},{"label":"南郊区","value":"140211"},{"label":"新荣区","value":"140212"},{"label":"阳高县","value":"140221"},{"label":"天镇县","value":"140222"},{"label":"广灵县","value":"140223"},{"label":"灵丘县","value":"140224"},{"label":"浑源县","value":"140225"},{"label":"左云县","value":"140226"},{"label":"大同县","value":"140227"},{"label":"山西大同经济开发区","value":"140271"}],[{"label":"城区","value":"140302"},{"label":"矿区","value":"140303"},{"label":"郊区","value":"140311"},{"label":"平定县","value":"140321"},{"label":"盂县","value":"140322"},{"label":"山西阳泉经济开发区","value":"140371"}],[{"label":"城区","value":"140402"},{"label":"郊区","value":"140411"},{"label":"长治县","value":"140421"},{"label":"襄垣县","value":"140423"},{"label":"屯留县","value":"140424"},{"label":"平顺县","value":"140425"},{"label":"黎城县","value":"140426"},{"label":"壶关县","value":"140427"},{"label":"长子县","value":"140428"},{"label":"武乡县","value":"140429"},{"label":"沁县","value":"140430"},{"label":"沁源县","value":"140431"},{"label":"山西长治高新技术产业园区","value":"140471"},{"label":"潞城市","value":"140481"}],[{"label":"城区","value":"140502"},{"label":"沁水县","value":"140521"},{"label":"阳城县","value":"140522"},{"label":"陵川县","value":"140524"},{"label":"泽州县","value":"140525"},{"label":"高平市","value":"140581"}],[{"label":"朔城区","value":"140602"},{"label":"平鲁区","value":"140603"},{"label":"山阴县","value":"140621"},{"label":"应县","value":"140622"},{"label":"右玉县","value":"140623"},{"label":"怀仁县","value":"140624"},{"label":"山西朔州经济开发区","value":"140671"}],[{"label":"榆次区","value":"140702"},{"label":"榆社县","value":"140721"},{"label":"左权县","value":"140722"},{"label":"和顺县","value":"140723"},{"label":"昔阳县","value":"140724"},{"label":"寿阳县","value":"140725"},{"label":"太谷县","value":"140726"},{"label":"祁县","value":"140727"},{"label":"平遥县","value":"140728"},{"label":"灵石县","value":"140729"},{"label":"介休市","value":"140781"}],[{"label":"盐湖区","value":"140802"},{"label":"临猗县","value":"140821"},{"label":"万荣县","value":"140822"},{"label":"闻喜县","value":"140823"},{"label":"稷山县","value":"140824"},{"label":"新绛县","value":"140825"},{"label":"绛县","value":"140826"},{"label":"垣曲县","value":"140827"},{"label":"夏县","value":"140828"},{"label":"平陆县","value":"140829"},{"label":"芮城县","value":"140830"},{"label":"永济市","value":"140881"},{"label":"河津市","value":"140882"}],[{"label":"忻府区","value":"140902"},{"label":"定襄县","value":"140921"},{"label":"五台县","value":"140922"},{"label":"代县","value":"140923"},{"label":"繁峙县","value":"140924"},{"label":"宁武县","value":"140925"},{"label":"静乐县","value":"140926"},{"label":"神池县","value":"140927"},{"label":"五寨县","value":"140928"},{"label":"岢岚县","value":"140929"},{"label":"河曲县","value":"140930"},{"label":"保德县","value":"140931"},{"label":"偏关县","value":"140932"},{"label":"五台山风景名胜区","value":"140971"},{"label":"原平市","value":"140981"}],[{"label":"尧都区","value":"141002"},{"label":"曲沃县","value":"141021"},{"label":"翼城县","value":"141022"},{"label":"襄汾县","value":"141023"},{"label":"洪洞县","value":"141024"},{"label":"古县","value":"141025"},{"label":"安泽县","value":"141026"},{"label":"浮山县","value":"141027"},{"label":"吉县","value":"141028"},{"label":"乡宁县","value":"141029"},{"label":"大宁县","value":"141030"},{"label":"隰县","value":"141031"},{"label":"永和县","value":"141032"},{"label":"蒲县","value":"141033"},{"label":"汾西县","value":"141034"},{"label":"侯马市","value":"141081"},{"label":"霍州市","value":"141082"}],[{"label":"离石区","value":"141102"},{"label":"文水县","value":"141121"},{"label":"交城县","value":"141122"},{"label":"兴县","value":"141123"},{"label":"临县","value":"141124"},{"label":"柳林县","value":"141125"},{"label":"石楼县","value":"141126"},{"label":"岚县","value":"141127"},{"label":"方山县","value":"141128"},{"label":"中阳县","value":"141129"},{"label":"交口县","value":"141130"},{"label":"孝义市","value":"141181"},{"label":"汾阳市","value":"141182"}]],[[{"label":"新城区","value":"150102"},{"label":"回民区","value":"150103"},{"label":"玉泉区","value":"150104"},{"label":"赛罕区","value":"150105"},{"label":"土默特左旗","value":"150121"},{"label":"托克托县","value":"150122"},{"label":"和林格尔县","value":"150123"},{"label":"清水河县","value":"150124"},{"label":"武川县","value":"150125"},{"label":"呼和浩特金海工业园区","value":"150171"},{"label":"呼和浩特经济技术开发区","value":"150172"}],[{"label":"东河区","value":"150202"},{"label":"昆都仑区","value":"150203"},{"label":"青山区","value":"150204"},{"label":"石拐区","value":"150205"},{"label":"白云鄂博矿区","value":"150206"},{"label":"九原区","value":"150207"},{"label":"土默特右旗","value":"150221"},{"label":"固阳县","value":"150222"},{"label":"达尔罕茂明安联合旗","value":"150223"},{"label":"包头稀土高新技术产业开发区","value":"150271"}],[{"label":"海勃湾区","value":"150302"},{"label":"海南区","value":"150303"},{"label":"乌达区","value":"150304"}],[{"label":"红山区","value":"150402"},{"label":"元宝山区","value":"150403"},{"label":"松山区","value":"150404"},{"label":"阿鲁科尔沁旗","value":"150421"},{"label":"巴林左旗","value":"150422"},{"label":"巴林右旗","value":"150423"},{"label":"林西县","value":"150424"},{"label":"克什克腾旗","value":"150425"},{"label":"翁牛特旗","value":"150426"},{"label":"喀喇沁旗","value":"150428"},{"label":"宁城县","value":"150429"},{"label":"敖汉旗","value":"150430"}],[{"label":"科尔沁区","value":"150502"},{"label":"科尔沁左翼中旗","value":"150521"},{"label":"科尔沁左翼后旗","value":"150522"},{"label":"开鲁县","value":"150523"},{"label":"库伦旗","value":"150524"},{"label":"奈曼旗","value":"150525"},{"label":"扎鲁特旗","value":"150526"},{"label":"通辽经济技术开发区","value":"150571"},{"label":"霍林郭勒市","value":"150581"}],[{"label":"东胜区","value":"150602"},{"label":"康巴什区","value":"150603"},{"label":"达拉特旗","value":"150621"},{"label":"准格尔旗","value":"150622"},{"label":"鄂托克前旗","value":"150623"},{"label":"鄂托克旗","value":"150624"},{"label":"杭锦旗","value":"150625"},{"label":"乌审旗","value":"150626"},{"label":"伊金霍洛旗","value":"150627"}],[{"label":"海拉尔区","value":"150702"},{"label":"扎赉诺尔区","value":"150703"},{"label":"阿荣旗","value":"150721"},{"label":"莫力达瓦达斡尔族自治旗","value":"150722"},{"label":"鄂伦春自治旗","value":"150723"},{"label":"鄂温克族自治旗","value":"150724"},{"label":"陈巴尔虎旗","value":"150725"},{"label":"新巴尔虎左旗","value":"150726"},{"label":"新巴尔虎右旗","value":"150727"},{"label":"满洲里市","value":"150781"},{"label":"牙克石市","value":"150782"},{"label":"扎兰屯市","value":"150783"},{"label":"额尔古纳市","value":"150784"},{"label":"根河市","value":"150785"}],[{"label":"临河区","value":"150802"},{"label":"五原县","value":"150821"},{"label":"磴口县","value":"150822"},{"label":"乌拉特前旗","value":"150823"},{"label":"乌拉特中旗","value":"150824"},{"label":"乌拉特后旗","value":"150825"},{"label":"杭锦后旗","value":"150826"}],[{"label":"集宁区","value":"150902"},{"label":"卓资县","value":"150921"},{"label":"化德县","value":"150922"},{"label":"商都县","value":"150923"},{"label":"兴和县","value":"150924"},{"label":"凉城县","value":"150925"},{"label":"察哈尔右翼前旗","value":"150926"},{"label":"察哈尔右翼中旗","value":"150927"},{"label":"察哈尔右翼后旗","value":"150928"},{"label":"四子王旗","value":"150929"},{"label":"丰镇市","value":"150981"}],[{"label":"乌兰浩特市","value":"152201"},{"label":"阿尔山市","value":"152202"},{"label":"科尔沁右翼前旗","value":"152221"},{"label":"科尔沁右翼中旗","value":"152222"},{"label":"扎赉特旗","value":"152223"},{"label":"突泉县","value":"152224"}],[{"label":"二连浩特市","value":"152501"},{"label":"锡林浩特市","value":"152502"},{"label":"阿巴嘎旗","value":"152522"},{"label":"苏尼特左旗","value":"152523"},{"label":"苏尼特右旗","value":"152524"},{"label":"东乌珠穆沁旗","value":"152525"},{"label":"西乌珠穆沁旗","value":"152526"},{"label":"太仆寺旗","value":"152527"},{"label":"镶黄旗","value":"152528"},{"label":"正镶白旗","value":"152529"},{"label":"正蓝旗","value":"152530"},{"label":"多伦县","value":"152531"},{"label":"乌拉盖管委会","value":"152571"}],[{"label":"阿拉善左旗","value":"152921"},{"label":"阿拉善右旗","value":"152922"},{"label":"额济纳旗","value":"152923"},{"label":"内蒙古阿拉善经济开发区","value":"152971"}]],[[{"label":"和平区","value":"210102"},{"label":"沈河区","value":"210103"},{"label":"大东区","value":"210104"},{"label":"皇姑区","value":"210105"},{"label":"铁西区","value":"210106"},{"label":"苏家屯区","value":"210111"},{"label":"浑南区","value":"210112"},{"label":"沈北新区","value":"210113"},{"label":"于洪区","value":"210114"},{"label":"辽中区","value":"210115"},{"label":"康平县","value":"210123"},{"label":"法库县","value":"210124"},{"label":"新民市","value":"210181"}],[{"label":"中山区","value":"210202"},{"label":"西岗区","value":"210203"},{"label":"沙河口区","value":"210204"},{"label":"甘井子区","value":"210211"},{"label":"旅顺口区","value":"210212"},{"label":"金州区","value":"210213"},{"label":"普兰店区","value":"210214"},{"label":"长海县","value":"210224"},{"label":"瓦房店市","value":"210281"},{"label":"庄河市","value":"210283"}],[{"label":"铁东区","value":"210302"},{"label":"铁西区","value":"210303"},{"label":"立山区","value":"210304"},{"label":"千山区","value":"210311"},{"label":"台安县","value":"210321"},{"label":"岫岩满族自治县","value":"210323"},{"label":"海城市","value":"210381"}],[{"label":"新抚区","value":"210402"},{"label":"东洲区","value":"210403"},{"label":"望花区","value":"210404"},{"label":"顺城区","value":"210411"},{"label":"抚顺县","value":"210421"},{"label":"新宾满族自治县","value":"210422"},{"label":"清原满族自治县","value":"210423"}],[{"label":"平山区","value":"210502"},{"label":"溪湖区","value":"210503"},{"label":"明山区","value":"210504"},{"label":"南芬区","value":"210505"},{"label":"本溪满族自治县","value":"210521"},{"label":"桓仁满族自治县","value":"210522"}],[{"label":"元宝区","value":"210602"},{"label":"振兴区","value":"210603"},{"label":"振安区","value":"210604"},{"label":"宽甸满族自治县","value":"210624"},{"label":"东港市","value":"210681"},{"label":"凤城市","value":"210682"}],[{"label":"古塔区","value":"210702"},{"label":"凌河区","value":"210703"},{"label":"太和区","value":"210711"},{"label":"黑山县","value":"210726"},{"label":"义县","value":"210727"},{"label":"凌海市","value":"210781"},{"label":"北镇市","value":"210782"}],[{"label":"站前区","value":"210802"},{"label":"西市区","value":"210803"},{"label":"鲅鱼圈区","value":"210804"},{"label":"老边区","value":"210811"},{"label":"盖州市","value":"210881"},{"label":"大石桥市","value":"210882"}],[{"label":"海州区","value":"210902"},{"label":"新邱区","value":"210903"},{"label":"太平区","value":"210904"},{"label":"清河门区","value":"210905"},{"label":"细河区","value":"210911"},{"label":"阜新蒙古族自治县","value":"210921"},{"label":"彰武县","value":"210922"}],[{"label":"白塔区","value":"211002"},{"label":"文圣区","value":"211003"},{"label":"宏伟区","value":"211004"},{"label":"弓长岭区","value":"211005"},{"label":"太子河区","value":"211011"},{"label":"辽阳县","value":"211021"},{"label":"灯塔市","value":"211081"}],[{"label":"双台子区","value":"211102"},{"label":"兴隆台区","value":"211103"},{"label":"大洼区","value":"211104"},{"label":"盘山县","value":"211122"}],[{"label":"银州区","value":"211202"},{"label":"清河区","value":"211204"},{"label":"铁岭县","value":"211221"},{"label":"西丰县","value":"211223"},{"label":"昌图县","value":"211224"},{"label":"调兵山市","value":"211281"},{"label":"开原市","value":"211282"}],[{"label":"双塔区","value":"211302"},{"label":"龙城区","value":"211303"},{"label":"朝阳县","value":"211321"},{"label":"建平县","value":"211322"},{"label":"喀喇沁左翼蒙古族自治县","value":"211324"},{"label":"北票市","value":"211381"},{"label":"凌源市","value":"211382"}],[{"label":"连山区","value":"211402"},{"label":"龙港区","value":"211403"},{"label":"南票区","value":"211404"},{"label":"绥中县","value":"211421"},{"label":"建昌县","value":"211422"},{"label":"兴城市","value":"211481"}]],[[{"label":"南关区","value":"220102"},{"label":"宽城区","value":"220103"},{"label":"朝阳区","value":"220104"},{"label":"二道区","value":"220105"},{"label":"绿园区","value":"220106"},{"label":"双阳区","value":"220112"},{"label":"九台区","value":"220113"},{"label":"农安县","value":"220122"},{"label":"长春经济技术开发区","value":"220171"},{"label":"长春净月高新技术产业开发区","value":"220172"},{"label":"长春高新技术产业开发区","value":"220173"},{"label":"长春汽车经济技术开发区","value":"220174"},{"label":"榆树市","value":"220182"},{"label":"德惠市","value":"220183"}],[{"label":"昌邑区","value":"220202"},{"label":"龙潭区","value":"220203"},{"label":"船营区","value":"220204"},{"label":"丰满区","value":"220211"},{"label":"永吉县","value":"220221"},{"label":"吉林经济开发区","value":"220271"},{"label":"吉林高新技术产业开发区","value":"220272"},{"label":"吉林中国新加坡食品区","value":"220273"},{"label":"蛟河市","value":"220281"},{"label":"桦甸市","value":"220282"},{"label":"舒兰市","value":"220283"},{"label":"磐石市","value":"220284"}],[{"label":"铁西区","value":"220302"},{"label":"铁东区","value":"220303"},{"label":"梨树县","value":"220322"},{"label":"伊通满族自治县","value":"220323"},{"label":"公主岭市","value":"220381"},{"label":"双辽市","value":"220382"}],[{"label":"龙山区","value":"220402"},{"label":"西安区","value":"220403"},{"label":"东丰县","value":"220421"},{"label":"东辽县","value":"220422"}],[{"label":"东昌区","value":"220502"},{"label":"二道江区","value":"220503"},{"label":"通化县","value":"220521"},{"label":"辉南县","value":"220523"},{"label":"柳河县","value":"220524"},{"label":"梅河口市","value":"220581"},{"label":"集安市","value":"220582"}],[{"label":"浑江区","value":"220602"},{"label":"江源区","value":"220605"},{"label":"抚松县","value":"220621"},{"label":"靖宇县","value":"220622"},{"label":"长白朝鲜族自治县","value":"220623"},{"label":"临江市","value":"220681"}],[{"label":"宁江区","value":"220702"},{"label":"前郭尔罗斯蒙古族自治县","value":"220721"},{"label":"长岭县","value":"220722"},{"label":"乾安县","value":"220723"},{"label":"吉林松原经济开发区","value":"220771"},{"label":"扶余市","value":"220781"}],[{"label":"洮北区","value":"220802"},{"label":"镇赉县","value":"220821"},{"label":"通榆县","value":"220822"},{"label":"吉林白城经济开发区","value":"220871"},{"label":"洮南市","value":"220881"},{"label":"大安市","value":"220882"}],[{"label":"延吉市","value":"222401"},{"label":"图们市","value":"222402"},{"label":"敦化市","value":"222403"},{"label":"珲春市","value":"222404"},{"label":"龙井市","value":"222405"},{"label":"和龙市","value":"222406"},{"label":"汪清县","value":"222424"},{"label":"安图县","value":"222426"}]],[[{"label":"道里区","value":"230102"},{"label":"南岗区","value":"230103"},{"label":"道外区","value":"230104"},{"label":"平房区","value":"230108"},{"label":"松北区","value":"230109"},{"label":"香坊区","value":"230110"},{"label":"呼兰区","value":"230111"},{"label":"阿城区","value":"230112"},{"label":"双城区","value":"230113"},{"label":"依兰县","value":"230123"},{"label":"方正县","value":"230124"},{"label":"宾县","value":"230125"},{"label":"巴彦县","value":"230126"},{"label":"木兰县","value":"230127"},{"label":"通河县","value":"230128"},{"label":"延寿县","value":"230129"},{"label":"尚志市","value":"230183"},{"label":"五常市","value":"230184"}],[{"label":"龙沙区","value":"230202"},{"label":"建华区","value":"230203"},{"label":"铁锋区","value":"230204"},{"label":"昂昂溪区","value":"230205"},{"label":"富拉尔基区","value":"230206"},{"label":"碾子山区","value":"230207"},{"label":"梅里斯达斡尔族区","value":"230208"},{"label":"龙江县","value":"230221"},{"label":"依安县","value":"230223"},{"label":"泰来县","value":"230224"},{"label":"甘南县","value":"230225"},{"label":"富裕县","value":"230227"},{"label":"克山县","value":"230229"},{"label":"克东县","value":"230230"},{"label":"拜泉县","value":"230231"},{"label":"讷河市","value":"230281"}],[{"label":"鸡冠区","value":"230302"},{"label":"恒山区","value":"230303"},{"label":"滴道区","value":"230304"},{"label":"梨树区","value":"230305"},{"label":"城子河区","value":"230306"},{"label":"麻山区","value":"230307"},{"label":"鸡东县","value":"230321"},{"label":"虎林市","value":"230381"},{"label":"密山市","value":"230382"}],[{"label":"向阳区","value":"230402"},{"label":"工农区","value":"230403"},{"label":"南山区","value":"230404"},{"label":"兴安区","value":"230405"},{"label":"东山区","value":"230406"},{"label":"兴山区","value":"230407"},{"label":"萝北县","value":"230421"},{"label":"绥滨县","value":"230422"}],[{"label":"尖山区","value":"230502"},{"label":"岭东区","value":"230503"},{"label":"四方台区","value":"230505"},{"label":"宝山区","value":"230506"},{"label":"集贤县","value":"230521"},{"label":"友谊县","value":"230522"},{"label":"宝清县","value":"230523"},{"label":"饶河县","value":"230524"}],[{"label":"萨尔图区","value":"230602"},{"label":"龙凤区","value":"230603"},{"label":"让胡路区","value":"230604"},{"label":"红岗区","value":"230605"},{"label":"大同区","value":"230606"},{"label":"肇州县","value":"230621"},{"label":"肇源县","value":"230622"},{"label":"林甸县","value":"230623"},{"label":"杜尔伯特蒙古族自治县","value":"230624"},{"label":"大庆高新技术产业开发区","value":"230671"}],[{"label":"伊春区","value":"230702"},{"label":"南岔区","value":"230703"},{"label":"友好区","value":"230704"},{"label":"西林区","value":"230705"},{"label":"翠峦区","value":"230706"},{"label":"新青区","value":"230707"},{"label":"美溪区","value":"230708"},{"label":"金山屯区","value":"230709"},{"label":"五营区","value":"230710"},{"label":"乌马河区","value":"230711"},{"label":"汤旺河区","value":"230712"},{"label":"带岭区","value":"230713"},{"label":"乌伊岭区","value":"230714"},{"label":"红星区","value":"230715"},{"label":"上甘岭区","value":"230716"},{"label":"嘉荫县","value":"230722"},{"label":"铁力市","value":"230781"}],[{"label":"向阳区","value":"230803"},{"label":"前进区","value":"230804"},{"label":"东风区","value":"230805"},{"label":"郊区","value":"230811"},{"label":"桦南县","value":"230822"},{"label":"桦川县","value":"230826"},{"label":"汤原县","value":"230828"},{"label":"同江市","value":"230881"},{"label":"富锦市","value":"230882"},{"label":"抚远市","value":"230883"}],[{"label":"新兴区","value":"230902"},{"label":"桃山区","value":"230903"},{"label":"茄子河区","value":"230904"},{"label":"勃利县","value":"230921"}],[{"label":"东安区","value":"231002"},{"label":"阳明区","value":"231003"},{"label":"爱民区","value":"231004"},{"label":"西安区","value":"231005"},{"label":"林口县","value":"231025"},{"label":"牡丹江经济技术开发区","value":"231071"},{"label":"绥芬河市","value":"231081"},{"label":"海林市","value":"231083"},{"label":"宁安市","value":"231084"},{"label":"穆棱市","value":"231085"},{"label":"东宁市","value":"231086"}],[{"label":"爱辉区","value":"231102"},{"label":"嫩江县","value":"231121"},{"label":"逊克县","value":"231123"},{"label":"孙吴县","value":"231124"},{"label":"北安市","value":"231181"},{"label":"五大连池市","value":"231182"}],[{"label":"北林区","value":"231202"},{"label":"望奎县","value":"231221"},{"label":"兰西县","value":"231222"},{"label":"青冈县","value":"231223"},{"label":"庆安县","value":"231224"},{"label":"明水县","value":"231225"},{"label":"绥棱县","value":"231226"},{"label":"安达市","value":"231281"},{"label":"肇东市","value":"231282"},{"label":"海伦市","value":"231283"}],[{"label":"加格达奇区","value":"232701"},{"label":"松岭区","value":"232702"},{"label":"新林区","value":"232703"},{"label":"呼中区","value":"232704"},{"label":"呼玛县","value":"232721"},{"label":"塔河县","value":"232722"},{"label":"漠河县","value":"232723"}]],[[{"label":"黄浦区","value":"310101"},{"label":"徐汇区","value":"310104"},{"label":"长宁区","value":"310105"},{"label":"静安区","value":"310106"},{"label":"普陀区","value":"310107"},{"label":"虹口区","value":"310109"},{"label":"杨浦区","value":"310110"},{"label":"闵行区","value":"310112"},{"label":"宝山区","value":"310113"},{"label":"嘉定区","value":"310114"},{"label":"浦东新区","value":"310115"},{"label":"金山区","value":"310116"},{"label":"松江区","value":"310117"},{"label":"青浦区","value":"310118"},{"label":"奉贤区","value":"310120"},{"label":"崇明区","value":"310151"}]],[[{"label":"玄武区","value":"320102"},{"label":"秦淮区","value":"320104"},{"label":"建邺区","value":"320105"},{"label":"鼓楼区","value":"320106"},{"label":"浦口区","value":"320111"},{"label":"栖霞区","value":"320113"},{"label":"雨花台区","value":"320114"},{"label":"江宁区","value":"320115"},{"label":"六合区","value":"320116"},{"label":"溧水区","value":"320117"},{"label":"高淳区","value":"320118"}],[{"label":"锡山区","value":"320205"},{"label":"惠山区","value":"320206"},{"label":"滨湖区","value":"320211"},{"label":"梁溪区","value":"320213"},{"label":"新吴区","value":"320214"},{"label":"江阴市","value":"320281"},{"label":"宜兴市","value":"320282"}],[{"label":"鼓楼区","value":"320302"},{"label":"云龙区","value":"320303"},{"label":"贾汪区","value":"320305"},{"label":"泉山区","value":"320311"},{"label":"铜山区","value":"320312"},{"label":"丰县","value":"320321"},{"label":"沛县","value":"320322"},{"label":"睢宁县","value":"320324"},{"label":"徐州经济技术开发区","value":"320371"},{"label":"新沂市","value":"320381"},{"label":"邳州市","value":"320382"}],[{"label":"天宁区","value":"320402"},{"label":"钟楼区","value":"320404"},{"label":"新北区","value":"320411"},{"label":"武进区","value":"320412"},{"label":"金坛区","value":"320413"},{"label":"溧阳市","value":"320481"}],[{"label":"虎丘区","value":"320505"},{"label":"吴中区","value":"320506"},{"label":"相城区","value":"320507"},{"label":"姑苏区","value":"320508"},{"label":"吴江区","value":"320509"},{"label":"苏州工业园区","value":"320571"},{"label":"常熟市","value":"320581"},{"label":"张家港市","value":"320582"},{"label":"昆山市","value":"320583"},{"label":"太仓市","value":"320585"}],[{"label":"崇川区","value":"320602"},{"label":"港闸区","value":"320611"},{"label":"通州区","value":"320612"},{"label":"海安县","value":"320621"},{"label":"如东县","value":"320623"},{"label":"南通经济技术开发区","value":"320671"},{"label":"启东市","value":"320681"},{"label":"如皋市","value":"320682"},{"label":"海门市","value":"320684"}],[{"label":"连云区","value":"320703"},{"label":"海州区","value":"320706"},{"label":"赣榆区","value":"320707"},{"label":"东海县","value":"320722"},{"label":"灌云县","value":"320723"},{"label":"灌南县","value":"320724"},{"label":"连云港经济技术开发区","value":"320771"},{"label":"连云港高新技术产业开发区","value":"320772"}],[{"label":"淮安区","value":"320803"},{"label":"淮阴区","value":"320804"},{"label":"清江浦区","value":"320812"},{"label":"洪泽区","value":"320813"},{"label":"涟水县","value":"320826"},{"label":"盱眙县","value":"320830"},{"label":"金湖县","value":"320831"},{"label":"淮安经济技术开发区","value":"320871"}],[{"label":"亭湖区","value":"320902"},{"label":"盐都区","value":"320903"},{"label":"大丰区","value":"320904"},{"label":"响水县","value":"320921"},{"label":"滨海县","value":"320922"},{"label":"阜宁县","value":"320923"},{"label":"射阳县","value":"320924"},{"label":"建湖县","value":"320925"},{"label":"盐城经济技术开发区","value":"320971"},{"label":"东台市","value":"320981"}],[{"label":"广陵区","value":"321002"},{"label":"邗江区","value":"321003"},{"label":"江都区","value":"321012"},{"label":"宝应县","value":"321023"},{"label":"扬州经济技术开发区","value":"321071"},{"label":"仪征市","value":"321081"},{"label":"高邮市","value":"321084"}],[{"label":"京口区","value":"321102"},{"label":"润州区","value":"321111"},{"label":"丹徒区","value":"321112"},{"label":"镇江新区","value":"321171"},{"label":"丹阳市","value":"321181"},{"label":"扬中市","value":"321182"},{"label":"句容市","value":"321183"}],[{"label":"海陵区","value":"321202"},{"label":"高港区","value":"321203"},{"label":"姜堰区","value":"321204"},{"label":"泰州医药高新技术产业开发区","value":"321271"},{"label":"兴化市","value":"321281"},{"label":"靖江市","value":"321282"},{"label":"泰兴市","value":"321283"}],[{"label":"宿城区","value":"321302"},{"label":"宿豫区","value":"321311"},{"label":"沭阳县","value":"321322"},{"label":"泗阳县","value":"321323"},{"label":"泗洪县","value":"321324"},{"label":"宿迁经济技术开发区","value":"321371"}]],[[{"label":"上城区","value":"330102"},{"label":"下城区","value":"330103"},{"label":"江干区","value":"330104"},{"label":"拱墅区","value":"330105"},{"label":"西湖区","value":"330106"},{"label":"滨江区","value":"330108"},{"label":"萧山区","value":"330109"},{"label":"余杭区","value":"330110"},{"label":"富阳区","value":"330111"},{"label":"临安区","value":"330112"},{"label":"桐庐县","value":"330122"},{"label":"淳安县","value":"330127"},{"label":"建德市","value":"330182"}],[{"label":"海曙区","value":"330203"},{"label":"江北区","value":"330205"},{"label":"北仑区","value":"330206"},{"label":"镇海区","value":"330211"},{"label":"鄞州区","value":"330212"},{"label":"奉化区","value":"330213"},{"label":"象山县","value":"330225"},{"label":"宁海县","value":"330226"},{"label":"余姚市","value":"330281"},{"label":"慈溪市","value":"330282"}],[{"label":"鹿城区","value":"330302"},{"label":"龙湾区","value":"330303"},{"label":"瓯海区","value":"330304"},{"label":"洞头区","value":"330305"},{"label":"永嘉县","value":"330324"},{"label":"平阳县","value":"330326"},{"label":"苍南县","value":"330327"},{"label":"文成县","value":"330328"},{"label":"泰顺县","value":"330329"},{"label":"温州经济技术开发区","value":"330371"},{"label":"瑞安市","value":"330381"},{"label":"乐清市","value":"330382"}],[{"label":"南湖区","value":"330402"},{"label":"秀洲区","value":"330411"},{"label":"嘉善县","value":"330421"},{"label":"海盐县","value":"330424"},{"label":"海宁市","value":"330481"},{"label":"平湖市","value":"330482"},{"label":"桐乡市","value":"330483"}],[{"label":"吴兴区","value":"330502"},{"label":"南浔区","value":"330503"},{"label":"德清县","value":"330521"},{"label":"长兴县","value":"330522"},{"label":"安吉县","value":"330523"}],[{"label":"越城区","value":"330602"},{"label":"柯桥区","value":"330603"},{"label":"上虞区","value":"330604"},{"label":"新昌县","value":"330624"},{"label":"诸暨市","value":"330681"},{"label":"嵊州市","value":"330683"}],[{"label":"婺城区","value":"330702"},{"label":"金东区","value":"330703"},{"label":"武义县","value":"330723"},{"label":"浦江县","value":"330726"},{"label":"磐安县","value":"330727"},{"label":"兰溪市","value":"330781"},{"label":"义乌市","value":"330782"},{"label":"东阳市","value":"330783"},{"label":"永康市","value":"330784"}],[{"label":"柯城区","value":"330802"},{"label":"衢江区","value":"330803"},{"label":"常山县","value":"330822"},{"label":"开化县","value":"330824"},{"label":"龙游县","value":"330825"},{"label":"江山市","value":"330881"}],[{"label":"定海区","value":"330902"},{"label":"普陀区","value":"330903"},{"label":"岱山县","value":"330921"},{"label":"嵊泗县","value":"330922"}],[{"label":"椒江区","value":"331002"},{"label":"黄岩区","value":"331003"},{"label":"路桥区","value":"331004"},{"label":"三门县","value":"331022"},{"label":"天台县","value":"331023"},{"label":"仙居县","value":"331024"},{"label":"温岭市","value":"331081"},{"label":"临海市","value":"331082"},{"label":"玉环市","value":"331083"}],[{"label":"莲都区","value":"331102"},{"label":"青田县","value":"331121"},{"label":"缙云县","value":"331122"},{"label":"遂昌县","value":"331123"},{"label":"松阳县","value":"331124"},{"label":"云和县","value":"331125"},{"label":"庆元县","value":"331126"},{"label":"景宁畲族自治县","value":"331127"},{"label":"龙泉市","value":"331181"}]],[[{"label":"瑶海区","value":"340102"},{"label":"庐阳区","value":"340103"},{"label":"蜀山区","value":"340104"},{"label":"包河区","value":"340111"},{"label":"长丰县","value":"340121"},{"label":"肥东县","value":"340122"},{"label":"肥西县","value":"340123"},{"label":"庐江县","value":"340124"},{"label":"合肥高新技术产业开发区","value":"340171"},{"label":"合肥经济技术开发区","value":"340172"},{"label":"合肥新站高新技术产业开发区","value":"340173"},{"label":"巢湖市","value":"340181"}],[{"label":"镜湖区","value":"340202"},{"label":"弋江区","value":"340203"},{"label":"鸠江区","value":"340207"},{"label":"三山区","value":"340208"},{"label":"芜湖县","value":"340221"},{"label":"繁昌县","value":"340222"},{"label":"南陵县","value":"340223"},{"label":"无为县","value":"340225"},{"label":"芜湖经济技术开发区","value":"340271"},{"label":"安徽芜湖长江大桥经济开发区","value":"340272"}],[{"label":"龙子湖区","value":"340302"},{"label":"蚌山区","value":"340303"},{"label":"禹会区","value":"340304"},{"label":"淮上区","value":"340311"},{"label":"怀远县","value":"340321"},{"label":"五河县","value":"340322"},{"label":"固镇县","value":"340323"},{"label":"蚌埠市高新技术开发区","value":"340371"},{"label":"蚌埠市经济开发区","value":"340372"}],[{"label":"大通区","value":"340402"},{"label":"田家庵区","value":"340403"},{"label":"谢家集区","value":"340404"},{"label":"八公山区","value":"340405"},{"label":"潘集区","value":"340406"},{"label":"凤台县","value":"340421"},{"label":"寿县","value":"340422"}],[{"label":"花山区","value":"340503"},{"label":"雨山区","value":"340504"},{"label":"博望区","value":"340506"},{"label":"当涂县","value":"340521"},{"label":"含山县","value":"340522"},{"label":"和县","value":"340523"}],[{"label":"杜集区","value":"340602"},{"label":"相山区","value":"340603"},{"label":"烈山区","value":"340604"},{"label":"濉溪县","value":"340621"}],[{"label":"铜官区","value":"340705"},{"label":"义安区","value":"340706"},{"label":"郊区","value":"340711"},{"label":"枞阳县","value":"340722"}],[{"label":"迎江区","value":"340802"},{"label":"大观区","value":"340803"},{"label":"宜秀区","value":"340811"},{"label":"怀宁县","value":"340822"},{"label":"潜山县","value":"340824"},{"label":"太湖县","value":"340825"},{"label":"宿松县","value":"340826"},{"label":"望江县","value":"340827"},{"label":"岳西县","value":"340828"},{"label":"安徽安庆经济开发区","value":"340871"},{"label":"桐城市","value":"340881"}],[{"label":"屯溪区","value":"341002"},{"label":"黄山区","value":"341003"},{"label":"徽州区","value":"341004"},{"label":"歙县","value":"341021"},{"label":"休宁县","value":"341022"},{"label":"黟县","value":"341023"},{"label":"祁门县","value":"341024"}],[{"label":"琅琊区","value":"341102"},{"label":"南谯区","value":"341103"},{"label":"来安县","value":"341122"},{"label":"全椒县","value":"341124"},{"label":"定远县","value":"341125"},{"label":"凤阳县","value":"341126"},{"label":"苏滁现代产业园","value":"341171"},{"label":"滁州经济技术开发区","value":"341172"},{"label":"天长市","value":"341181"},{"label":"明光市","value":"341182"}],[{"label":"颍州区","value":"341202"},{"label":"颍东区","value":"341203"},{"label":"颍泉区","value":"341204"},{"label":"临泉县","value":"341221"},{"label":"太和县","value":"341222"},{"label":"阜南县","value":"341225"},{"label":"颍上县","value":"341226"},{"label":"阜阳合肥现代产业园区","value":"341271"},{"label":"阜阳经济技术开发区","value":"341272"},{"label":"界首市","value":"341282"}],[{"label":"埇桥区","value":"341302"},{"label":"砀山县","value":"341321"},{"label":"萧县","value":"341322"},{"label":"灵璧县","value":"341323"},{"label":"泗县","value":"341324"},{"label":"宿州马鞍山现代产业园区","value":"341371"},{"label":"宿州经济技术开发区","value":"341372"}],[{"label":"金安区","value":"341502"},{"label":"裕安区","value":"341503"},{"label":"叶集区","value":"341504"},{"label":"霍邱县","value":"341522"},{"label":"舒城县","value":"341523"},{"label":"金寨县","value":"341524"},{"label":"霍山县","value":"341525"}],[{"label":"谯城区","value":"341602"},{"label":"涡阳县","value":"341621"},{"label":"蒙城县","value":"341622"},{"label":"利辛县","value":"341623"}],[{"label":"贵池区","value":"341702"},{"label":"东至县","value":"341721"},{"label":"石台县","value":"341722"},{"label":"青阳县","value":"341723"}],[{"label":"宣州区","value":"341802"},{"label":"郎溪县","value":"341821"},{"label":"广德县","value":"341822"},{"label":"泾县","value":"341823"},{"label":"绩溪县","value":"341824"},{"label":"旌德县","value":"341825"},{"label":"宣城市经济开发区","value":"341871"},{"label":"宁国市","value":"341881"}]],[[{"label":"鼓楼区","value":"350102"},{"label":"台江区","value":"350103"},{"label":"仓山区","value":"350104"},{"label":"马尾区","value":"350105"},{"label":"晋安区","value":"350111"},{"label":"闽侯县","value":"350121"},{"label":"连江县","value":"350122"},{"label":"罗源县","value":"350123"},{"label":"闽清县","value":"350124"},{"label":"永泰县","value":"350125"},{"label":"平潭县","value":"350128"},{"label":"福清市","value":"350181"},{"label":"长乐市","value":"350182"}],[{"label":"思明区","value":"350203"},{"label":"海沧区","value":"350205"},{"label":"湖里区","value":"350206"},{"label":"集美区","value":"350211"},{"label":"同安区","value":"350212"},{"label":"翔安区","value":"350213"}],[{"label":"城厢区","value":"350302"},{"label":"涵江区","value":"350303"},{"label":"荔城区","value":"350304"},{"label":"秀屿区","value":"350305"},{"label":"仙游县","value":"350322"}],[{"label":"梅列区","value":"350402"},{"label":"三元区","value":"350403"},{"label":"明溪县","value":"350421"},{"label":"清流县","value":"350423"},{"label":"宁化县","value":"350424"},{"label":"大田县","value":"350425"},{"label":"尤溪县","value":"350426"},{"label":"沙县","value":"350427"},{"label":"将乐县","value":"350428"},{"label":"泰宁县","value":"350429"},{"label":"建宁县","value":"350430"},{"label":"永安市","value":"350481"}],[{"label":"鲤城区","value":"350502"},{"label":"丰泽区","value":"350503"},{"label":"洛江区","value":"350504"},{"label":"泉港区","value":"350505"},{"label":"惠安县","value":"350521"},{"label":"安溪县","value":"350524"},{"label":"永春县","value":"350525"},{"label":"德化县","value":"350526"},{"label":"金门县","value":"350527"},{"label":"石狮市","value":"350581"},{"label":"晋江市","value":"350582"},{"label":"南安市","value":"350583"}],[{"label":"芗城区","value":"350602"},{"label":"龙文区","value":"350603"},{"label":"云霄县","value":"350622"},{"label":"漳浦县","value":"350623"},{"label":"诏安县","value":"350624"},{"label":"长泰县","value":"350625"},{"label":"东山县","value":"350626"},{"label":"南靖县","value":"350627"},{"label":"平和县","value":"350628"},{"label":"华安县","value":"350629"},{"label":"龙海市","value":"350681"}],[{"label":"延平区","value":"350702"},{"label":"建阳区","value":"350703"},{"label":"顺昌县","value":"350721"},{"label":"浦城县","value":"350722"},{"label":"光泽县","value":"350723"},{"label":"松溪县","value":"350724"},{"label":"政和县","value":"350725"},{"label":"邵武市","value":"350781"},{"label":"武夷山市","value":"350782"},{"label":"建瓯市","value":"350783"}],[{"label":"新罗区","value":"350802"},{"label":"永定区","value":"350803"},{"label":"长汀县","value":"350821"},{"label":"上杭县","value":"350823"},{"label":"武平县","value":"350824"},{"label":"连城县","value":"350825"},{"label":"漳平市","value":"350881"}],[{"label":"蕉城区","value":"350902"},{"label":"霞浦县","value":"350921"},{"label":"古田县","value":"350922"},{"label":"屏南县","value":"350923"},{"label":"寿宁县","value":"350924"},{"label":"周宁县","value":"350925"},{"label":"柘荣县","value":"350926"},{"label":"福安市","value":"350981"},{"label":"福鼎市","value":"350982"}]],[[{"label":"东湖区","value":"360102"},{"label":"西湖区","value":"360103"},{"label":"青云谱区","value":"360104"},{"label":"湾里区","value":"360105"},{"label":"青山湖区","value":"360111"},{"label":"新建区","value":"360112"},{"label":"南昌县","value":"360121"},{"label":"安义县","value":"360123"},{"label":"进贤县","value":"360124"}],[{"label":"昌江区","value":"360202"},{"label":"珠山区","value":"360203"},{"label":"浮梁县","value":"360222"},{"label":"乐平市","value":"360281"}],[{"label":"安源区","value":"360302"},{"label":"湘东区","value":"360313"},{"label":"莲花县","value":"360321"},{"label":"上栗县","value":"360322"},{"label":"芦溪县","value":"360323"}],[{"label":"濂溪区","value":"360402"},{"label":"浔阳区","value":"360403"},{"label":"柴桑区","value":"360404"},{"label":"武宁县","value":"360423"},{"label":"修水县","value":"360424"},{"label":"永修县","value":"360425"},{"label":"德安县","value":"360426"},{"label":"都昌县","value":"360428"},{"label":"湖口县","value":"360429"},{"label":"彭泽县","value":"360430"},{"label":"瑞昌市","value":"360481"},{"label":"共青城市","value":"360482"},{"label":"庐山市","value":"360483"}],[{"label":"渝水区","value":"360502"},{"label":"分宜县","value":"360521"}],[{"label":"月湖区","value":"360602"},{"label":"余江县","value":"360622"},{"label":"贵溪市","value":"360681"}],[{"label":"章贡区","value":"360702"},{"label":"南康区","value":"360703"},{"label":"赣县区","value":"360704"},{"label":"信丰县","value":"360722"},{"label":"大余县","value":"360723"},{"label":"上犹县","value":"360724"},{"label":"崇义县","value":"360725"},{"label":"安远县","value":"360726"},{"label":"龙南县","value":"360727"},{"label":"定南县","value":"360728"},{"label":"全南县","value":"360729"},{"label":"宁都县","value":"360730"},{"label":"于都县","value":"360731"},{"label":"兴国县","value":"360732"},{"label":"会昌县","value":"360733"},{"label":"寻乌县","value":"360734"},{"label":"石城县","value":"360735"},{"label":"瑞金市","value":"360781"}],[{"label":"吉州区","value":"360802"},{"label":"青原区","value":"360803"},{"label":"吉安县","value":"360821"},{"label":"吉水县","value":"360822"},{"label":"峡江县","value":"360823"},{"label":"新干县","value":"360824"},{"label":"永丰县","value":"360825"},{"label":"泰和县","value":"360826"},{"label":"遂川县","value":"360827"},{"label":"万安县","value":"360828"},{"label":"安福县","value":"360829"},{"label":"永新县","value":"360830"},{"label":"井冈山市","value":"360881"}],[{"label":"袁州区","value":"360902"},{"label":"奉新县","value":"360921"},{"label":"万载县","value":"360922"},{"label":"上高县","value":"360923"},{"label":"宜丰县","value":"360924"},{"label":"靖安县","value":"360925"},{"label":"铜鼓县","value":"360926"},{"label":"丰城市","value":"360981"},{"label":"樟树市","value":"360982"},{"label":"高安市","value":"360983"}],[{"label":"临川区","value":"361002"},{"label":"东乡区","value":"361003"},{"label":"南城县","value":"361021"},{"label":"黎川县","value":"361022"},{"label":"南丰县","value":"361023"},{"label":"崇仁县","value":"361024"},{"label":"乐安县","value":"361025"},{"label":"宜黄县","value":"361026"},{"label":"金溪县","value":"361027"},{"label":"资溪县","value":"361028"},{"label":"广昌县","value":"361030"}],[{"label":"信州区","value":"361102"},{"label":"广丰区","value":"361103"},{"label":"上饶县","value":"361121"},{"label":"玉山县","value":"361123"},{"label":"铅山县","value":"361124"},{"label":"横峰县","value":"361125"},{"label":"弋阳县","value":"361126"},{"label":"余干县","value":"361127"},{"label":"鄱阳县","value":"361128"},{"label":"万年县","value":"361129"},{"label":"婺源县","value":"361130"},{"label":"德兴市","value":"361181"}]],[[{"label":"历下区","value":"370102"},{"label":"市中区","value":"370103"},{"label":"槐荫区","value":"370104"},{"label":"天桥区","value":"370105"},{"label":"历城区","value":"370112"},{"label":"长清区","value":"370113"},{"label":"章丘区","value":"370114"},{"label":"平阴县","value":"370124"},{"label":"济阳县","value":"370125"},{"label":"商河县","value":"370126"},{"label":"济南高新技术产业开发区","value":"370171"}],[{"label":"市南区","value":"370202"},{"label":"市北区","value":"370203"},{"label":"黄岛区","value":"370211"},{"label":"崂山区","value":"370212"},{"label":"李沧区","value":"370213"},{"label":"城阳区","value":"370214"},{"label":"即墨区","value":"370215"},{"label":"青岛高新技术产业开发区","value":"370271"},{"label":"胶州市","value":"370281"},{"label":"平度市","value":"370283"},{"label":"莱西市","value":"370285"}],[{"label":"淄川区","value":"370302"},{"label":"张店区","value":"370303"},{"label":"博山区","value":"370304"},{"label":"临淄区","value":"370305"},{"label":"周村区","value":"370306"},{"label":"桓台县","value":"370321"},{"label":"高青县","value":"370322"},{"label":"沂源县","value":"370323"}],[{"label":"市中区","value":"370402"},{"label":"薛城区","value":"370403"},{"label":"峄城区","value":"370404"},{"label":"台儿庄区","value":"370405"},{"label":"山亭区","value":"370406"},{"label":"滕州市","value":"370481"}],[{"label":"东营区","value":"370502"},{"label":"河口区","value":"370503"},{"label":"垦利区","value":"370505"},{"label":"利津县","value":"370522"},{"label":"广饶县","value":"370523"},{"label":"东营经济技术开发区","value":"370571"},{"label":"东营港经济开发区","value":"370572"}],[{"label":"芝罘区","value":"370602"},{"label":"福山区","value":"370611"},{"label":"牟平区","value":"370612"},{"label":"莱山区","value":"370613"},{"label":"长岛县","value":"370634"},{"label":"烟台高新技术产业开发区","value":"370671"},{"label":"烟台经济技术开发区","value":"370672"},{"label":"龙口市","value":"370681"},{"label":"莱阳市","value":"370682"},{"label":"莱州市","value":"370683"},{"label":"蓬莱市","value":"370684"},{"label":"招远市","value":"370685"},{"label":"栖霞市","value":"370686"},{"label":"海阳市","value":"370687"}],[{"label":"潍城区","value":"370702"},{"label":"寒亭区","value":"370703"},{"label":"坊子区","value":"370704"},{"label":"奎文区","value":"370705"},{"label":"临朐县","value":"370724"},{"label":"昌乐县","value":"370725"},{"label":"潍坊滨海经济技术开发区","value":"370772"},{"label":"青州市","value":"370781"},{"label":"诸城市","value":"370782"},{"label":"寿光市","value":"370783"},{"label":"安丘市","value":"370784"},{"label":"高密市","value":"370785"},{"label":"昌邑市","value":"370786"}],[{"label":"任城区","value":"370811"},{"label":"兖州区","value":"370812"},{"label":"微山县","value":"370826"},{"label":"鱼台县","value":"370827"},{"label":"金乡县","value":"370828"},{"label":"嘉祥县","value":"370829"},{"label":"汶上县","value":"370830"},{"label":"泗水县","value":"370831"},{"label":"梁山县","value":"370832"},{"label":"济宁高新技术产业开发区","value":"370871"},{"label":"曲阜市","value":"370881"},{"label":"邹城市","value":"370883"}],[{"label":"泰山区","value":"370902"},{"label":"岱岳区","value":"370911"},{"label":"宁阳县","value":"370921"},{"label":"东平县","value":"370923"},{"label":"新泰市","value":"370982"},{"label":"肥城市","value":"370983"}],[{"label":"环翠区","value":"371002"},{"label":"文登区","value":"371003"},{"label":"威海火炬高技术产业开发区","value":"371071"},{"label":"威海经济技术开发区","value":"371072"},{"label":"威海临港经济技术开发区","value":"371073"},{"label":"荣成市","value":"371082"},{"label":"乳山市","value":"371083"}],[{"label":"东港区","value":"371102"},{"label":"岚山区","value":"371103"},{"label":"五莲县","value":"371121"},{"label":"莒县","value":"371122"},{"label":"日照经济技术开发区","value":"371171"},{"label":"日照国际海洋城","value":"371172"}],[{"label":"莱城区","value":"371202"},{"label":"钢城区","value":"371203"}],[{"label":"兰山区","value":"371302"},{"label":"罗庄区","value":"371311"},{"label":"河东区","value":"371312"},{"label":"沂南县","value":"371321"},{"label":"郯城县","value":"371322"},{"label":"沂水县","value":"371323"},{"label":"兰陵县","value":"371324"},{"label":"费县","value":"371325"},{"label":"平邑县","value":"371326"},{"label":"莒南县","value":"371327"},{"label":"蒙阴县","value":"371328"},{"label":"临沭县","value":"371329"},{"label":"临沂高新技术产业开发区","value":"371371"},{"label":"临沂经济技术开发区","value":"371372"},{"label":"临沂临港经济开发区","value":"371373"}],[{"label":"德城区","value":"371402"},{"label":"陵城区","value":"371403"},{"label":"宁津县","value":"371422"},{"label":"庆云县","value":"371423"},{"label":"临邑县","value":"371424"},{"label":"齐河县","value":"371425"},{"label":"平原县","value":"371426"},{"label":"夏津县","value":"371427"},{"label":"武城县","value":"371428"},{"label":"德州经济技术开发区","value":"371471"},{"label":"德州运河经济开发区","value":"371472"},{"label":"乐陵市","value":"371481"},{"label":"禹城市","value":"371482"}],[{"label":"东昌府区","value":"371502"},{"label":"阳谷县","value":"371521"},{"label":"莘县","value":"371522"},{"label":"茌平县","value":"371523"},{"label":"东阿县","value":"371524"},{"label":"冠县","value":"371525"},{"label":"高唐县","value":"371526"},{"label":"临清市","value":"371581"}],[{"label":"滨城区","value":"371602"},{"label":"沾化区","value":"371603"},{"label":"惠民县","value":"371621"},{"label":"阳信县","value":"371622"},{"label":"无棣县","value":"371623"},{"label":"博兴县","value":"371625"},{"label":"邹平县","value":"371626"}],[{"label":"牡丹区","value":"371702"},{"label":"定陶区","value":"371703"},{"label":"曹县","value":"371721"},{"label":"单县","value":"371722"},{"label":"成武县","value":"371723"},{"label":"巨野县","value":"371724"},{"label":"郓城县","value":"371725"},{"label":"鄄城县","value":"371726"},{"label":"东明县","value":"371728"},{"label":"菏泽经济技术开发区","value":"371771"},{"label":"菏泽高新技术开发区","value":"371772"}]],[[{"label":"中原区","value":"410102"},{"label":"二七区","value":"410103"},{"label":"管城回族区","value":"410104"},{"label":"金水区","value":"410105"},{"label":"上街区","value":"410106"},{"label":"惠济区","value":"410108"},{"label":"中牟县","value":"410122"},{"label":"郑州经济技术开发区","value":"410171"},{"label":"郑州高新技术产业开发区","value":"410172"},{"label":"郑州航空港经济综合实验区","value":"410173"},{"label":"巩义市","value":"410181"},{"label":"荥阳市","value":"410182"},{"label":"新密市","value":"410183"},{"label":"新郑市","value":"410184"},{"label":"登封市","value":"410185"}],[{"label":"龙亭区","value":"410202"},{"label":"顺河回族区","value":"410203"},{"label":"鼓楼区","value":"410204"},{"label":"禹王台区","value":"410205"},{"label":"祥符区","value":"410212"},{"label":"杞县","value":"410221"},{"label":"通许县","value":"410222"},{"label":"尉氏县","value":"410223"},{"label":"兰考县","value":"410225"}],[{"label":"老城区","value":"410302"},{"label":"西工区","value":"410303"},{"label":"瀍河回族区","value":"410304"},{"label":"涧西区","value":"410305"},{"label":"吉利区","value":"410306"},{"label":"洛龙区","value":"410311"},{"label":"孟津县","value":"410322"},{"label":"新安县","value":"410323"},{"label":"栾川县","value":"410324"},{"label":"嵩县","value":"410325"},{"label":"汝阳县","value":"410326"},{"label":"宜阳县","value":"410327"},{"label":"洛宁县","value":"410328"},{"label":"伊川县","value":"410329"},{"label":"洛阳高新技术产业开发区","value":"410371"},{"label":"偃师市","value":"410381"}],[{"label":"新华区","value":"410402"},{"label":"卫东区","value":"410403"},{"label":"石龙区","value":"410404"},{"label":"湛河区","value":"410411"},{"label":"宝丰县","value":"410421"},{"label":"叶县","value":"410422"},{"label":"鲁山县","value":"410423"},{"label":"郏县","value":"410425"},{"label":"平顶山高新技术产业开发区","value":"410471"},{"label":"平顶山市新城区","value":"410472"},{"label":"舞钢市","value":"410481"},{"label":"汝州市","value":"410482"}],[{"label":"文峰区","value":"410502"},{"label":"北关区","value":"410503"},{"label":"殷都区","value":"410505"},{"label":"龙安区","value":"410506"},{"label":"安阳县","value":"410522"},{"label":"汤阴县","value":"410523"},{"label":"滑县","value":"410526"},{"label":"内黄县","value":"410527"},{"label":"安阳高新技术产业开发区","value":"410571"},{"label":"林州市","value":"410581"}],[{"label":"鹤山区","value":"410602"},{"label":"山城区","value":"410603"},{"label":"淇滨区","value":"410611"},{"label":"浚县","value":"410621"},{"label":"淇县","value":"410622"},{"label":"鹤壁经济技术开发区","value":"410671"}],[{"label":"红旗区","value":"410702"},{"label":"卫滨区","value":"410703"},{"label":"凤泉区","value":"410704"},{"label":"牧野区","value":"410711"},{"label":"新乡县","value":"410721"},{"label":"获嘉县","value":"410724"},{"label":"原阳县","value":"410725"},{"label":"延津县","value":"410726"},{"label":"封丘县","value":"410727"},{"label":"长垣县","value":"410728"},{"label":"新乡高新技术产业开发区","value":"410771"},{"label":"新乡经济技术开发区","value":"410772"},{"label":"新乡市平原城乡一体化示范区","value":"410773"},{"label":"卫辉市","value":"410781"},{"label":"辉县市","value":"410782"}],[{"label":"解放区","value":"410802"},{"label":"中站区","value":"410803"},{"label":"马村区","value":"410804"},{"label":"山阳区","value":"410811"},{"label":"修武县","value":"410821"},{"label":"博爱县","value":"410822"},{"label":"武陟县","value":"410823"},{"label":"温县","value":"410825"},{"label":"焦作城乡一体化示范区","value":"410871"},{"label":"沁阳市","value":"410882"},{"label":"孟州市","value":"410883"}],[{"label":"华龙区","value":"410902"},{"label":"清丰县","value":"410922"},{"label":"南乐县","value":"410923"},{"label":"范县","value":"410926"},{"label":"台前县","value":"410927"},{"label":"濮阳县","value":"410928"},{"label":"河南濮阳工业园区","value":"410971"},{"label":"濮阳经济技术开发区","value":"410972"}],[{"label":"魏都区","value":"411002"},{"label":"建安区","value":"411003"},{"label":"鄢陵县","value":"411024"},{"label":"襄城县","value":"411025"},{"label":"许昌经济技术开发区","value":"411071"},{"label":"禹州市","value":"411081"},{"label":"长葛市","value":"411082"}],[{"label":"源汇区","value":"411102"},{"label":"郾城区","value":"411103"},{"label":"召陵区","value":"411104"},{"label":"舞阳县","value":"411121"},{"label":"临颍县","value":"411122"},{"label":"漯河经济技术开发区","value":"411171"}],[{"label":"湖滨区","value":"411202"},{"label":"陕州区","value":"411203"},{"label":"渑池县","value":"411221"},{"label":"卢氏县","value":"411224"},{"label":"河南三门峡经济开发区","value":"411271"},{"label":"义马市","value":"411281"},{"label":"灵宝市","value":"411282"}],[{"label":"宛城区","value":"411302"},{"label":"卧龙区","value":"411303"},{"label":"南召县","value":"411321"},{"label":"方城县","value":"411322"},{"label":"西峡县","value":"411323"},{"label":"镇平县","value":"411324"},{"label":"内乡县","value":"411325"},{"label":"淅川县","value":"411326"},{"label":"社旗县","value":"411327"},{"label":"唐河县","value":"411328"},{"label":"新野县","value":"411329"},{"label":"桐柏县","value":"411330"},{"label":"南阳高新技术产业开发区","value":"411371"},{"label":"南阳市城乡一体化示范区","value":"411372"},{"label":"邓州市","value":"411381"}],[{"label":"梁园区","value":"411402"},{"label":"睢阳区","value":"411403"},{"label":"民权县","value":"411421"},{"label":"睢县","value":"411422"},{"label":"宁陵县","value":"411423"},{"label":"柘城县","value":"411424"},{"label":"虞城县","value":"411425"},{"label":"夏邑县","value":"411426"},{"label":"豫东综合物流产业聚集区","value":"411471"},{"label":"河南商丘经济开发区","value":"411472"},{"label":"永城市","value":"411481"}],[{"label":"浉河区","value":"411502"},{"label":"平桥区","value":"411503"},{"label":"罗山县","value":"411521"},{"label":"光山县","value":"411522"},{"label":"新县","value":"411523"},{"label":"商城县","value":"411524"},{"label":"固始县","value":"411525"},{"label":"潢川县","value":"411526"},{"label":"淮滨县","value":"411527"},{"label":"息县","value":"411528"},{"label":"信阳高新技术产业开发区","value":"411571"}],[{"label":"川汇区","value":"411602"},{"label":"扶沟县","value":"411621"},{"label":"西华县","value":"411622"},{"label":"商水县","value":"411623"},{"label":"沈丘县","value":"411624"},{"label":"郸城县","value":"411625"},{"label":"淮阳县","value":"411626"},{"label":"太康县","value":"411627"},{"label":"鹿邑县","value":"411628"},{"label":"河南周口经济开发区","value":"411671"},{"label":"项城市","value":"411681"}],[{"label":"驿城区","value":"411702"},{"label":"西平县","value":"411721"},{"label":"上蔡县","value":"411722"},{"label":"平舆县","value":"411723"},{"label":"正阳县","value":"411724"},{"label":"确山县","value":"411725"},{"label":"泌阳县","value":"411726"},{"label":"汝南县","value":"411727"},{"label":"遂平县","value":"411728"},{"label":"新蔡县","value":"411729"},{"label":"河南驻马店经济开发区","value":"411771"}],[{"label":"济源市","value":"419001"}]],[[{"label":"江岸区","value":"420102"},{"label":"江汉区","value":"420103"},{"label":"硚口区","value":"420104"},{"label":"汉阳区","value":"420105"},{"label":"武昌区","value":"420106"},{"label":"青山区","value":"420107"},{"label":"洪山区","value":"420111"},{"label":"东西湖区","value":"420112"},{"label":"汉南区","value":"420113"},{"label":"蔡甸区","value":"420114"},{"label":"江夏区","value":"420115"},{"label":"黄陂区","value":"420116"},{"label":"新洲区","value":"420117"}],[{"label":"黄石港区","value":"420202"},{"label":"西塞山区","value":"420203"},{"label":"下陆区","value":"420204"},{"label":"铁山区","value":"420205"},{"label":"阳新县","value":"420222"},{"label":"大冶市","value":"420281"}],[{"label":"茅箭区","value":"420302"},{"label":"张湾区","value":"420303"},{"label":"郧阳区","value":"420304"},{"label":"郧西县","value":"420322"},{"label":"竹山县","value":"420323"},{"label":"竹溪县","value":"420324"},{"label":"房县","value":"420325"},{"label":"丹江口市","value":"420381"}],[{"label":"西陵区","value":"420502"},{"label":"伍家岗区","value":"420503"},{"label":"点军区","value":"420504"},{"label":"猇亭区","value":"420505"},{"label":"夷陵区","value":"420506"},{"label":"远安县","value":"420525"},{"label":"兴山县","value":"420526"},{"label":"秭归县","value":"420527"},{"label":"长阳土家族自治县","value":"420528"},{"label":"五峰土家族自治县","value":"420529"},{"label":"宜都市","value":"420581"},{"label":"当阳市","value":"420582"},{"label":"枝江市","value":"420583"}],[{"label":"襄城区","value":"420602"},{"label":"樊城区","value":"420606"},{"label":"襄州区","value":"420607"},{"label":"南漳县","value":"420624"},{"label":"谷城县","value":"420625"},{"label":"保康县","value":"420626"},{"label":"老河口市","value":"420682"},{"label":"枣阳市","value":"420683"},{"label":"宜城市","value":"420684"}],[{"label":"梁子湖区","value":"420702"},{"label":"华容区","value":"420703"},{"label":"鄂城区","value":"420704"}],[{"label":"东宝区","value":"420802"},{"label":"掇刀区","value":"420804"},{"label":"京山县","value":"420821"},{"label":"沙洋县","value":"420822"},{"label":"钟祥市","value":"420881"}],[{"label":"孝南区","value":"420902"},{"label":"孝昌县","value":"420921"},{"label":"大悟县","value":"420922"},{"label":"云梦县","value":"420923"},{"label":"应城市","value":"420981"},{"label":"安陆市","value":"420982"},{"label":"汉川市","value":"420984"}],[{"label":"沙市区","value":"421002"},{"label":"荆州区","value":"421003"},{"label":"公安县","value":"421022"},{"label":"监利县","value":"421023"},{"label":"江陵县","value":"421024"},{"label":"荆州经济技术开发区","value":"421071"},{"label":"石首市","value":"421081"},{"label":"洪湖市","value":"421083"},{"label":"松滋市","value":"421087"}],[{"label":"黄州区","value":"421102"},{"label":"团风县","value":"421121"},{"label":"红安县","value":"421122"},{"label":"罗田县","value":"421123"},{"label":"英山县","value":"421124"},{"label":"浠水县","value":"421125"},{"label":"蕲春县","value":"421126"},{"label":"黄梅县","value":"421127"},{"label":"龙感湖管理区","value":"421171"},{"label":"麻城市","value":"421181"},{"label":"武穴市","value":"421182"}],[{"label":"咸安区","value":"421202"},{"label":"嘉鱼县","value":"421221"},{"label":"通城县","value":"421222"},{"label":"崇阳县","value":"421223"},{"label":"通山县","value":"421224"},{"label":"赤壁市","value":"421281"}],[{"label":"曾都区","value":"421303"},{"label":"随县","value":"421321"},{"label":"广水市","value":"421381"}],[{"label":"恩施市","value":"422801"},{"label":"利川市","value":"422802"},{"label":"建始县","value":"422822"},{"label":"巴东县","value":"422823"},{"label":"宣恩县","value":"422825"},{"label":"咸丰县","value":"422826"},{"label":"来凤县","value":"422827"},{"label":"鹤峰县","value":"422828"}],[{"label":"仙桃市","value":"429004"},{"label":"潜江市","value":"429005"},{"label":"天门市","value":"429006"},{"label":"神农架林区","value":"429021"}]],[[{"label":"芙蓉区","value":"430102"},{"label":"天心区","value":"430103"},{"label":"岳麓区","value":"430104"},{"label":"开福区","value":"430105"},{"label":"雨花区","value":"430111"},{"label":"望城区","value":"430112"},{"label":"长沙县","value":"430121"},{"label":"浏阳市","value":"430181"},{"label":"宁乡市","value":"430182"}],[{"label":"荷塘区","value":"430202"},{"label":"芦淞区","value":"430203"},{"label":"石峰区","value":"430204"},{"label":"天元区","value":"430211"},{"label":"株洲县","value":"430221"},{"label":"攸县","value":"430223"},{"label":"茶陵县","value":"430224"},{"label":"炎陵县","value":"430225"},{"label":"云龙示范区","value":"430271"},{"label":"醴陵市","value":"430281"}],[{"label":"雨湖区","value":"430302"},{"label":"岳塘区","value":"430304"},{"label":"湘潭县","value":"430321"},{"label":"湖南湘潭高新技术产业园区","value":"430371"},{"label":"湘潭昭山示范区","value":"430372"},{"label":"湘潭九华示范区","value":"430373"},{"label":"湘乡市","value":"430381"},{"label":"韶山市","value":"430382"}],[{"label":"珠晖区","value":"430405"},{"label":"雁峰区","value":"430406"},{"label":"石鼓区","value":"430407"},{"label":"蒸湘区","value":"430408"},{"label":"南岳区","value":"430412"},{"label":"衡阳县","value":"430421"},{"label":"衡南县","value":"430422"},{"label":"衡山县","value":"430423"},{"label":"衡东县","value":"430424"},{"label":"祁东县","value":"430426"},{"label":"衡阳综合保税区","value":"430471"},{"label":"湖南衡阳高新技术产业园区","value":"430472"},{"label":"湖南衡阳松木经济开发区","value":"430473"},{"label":"耒阳市","value":"430481"},{"label":"常宁市","value":"430482"}],[{"label":"双清区","value":"430502"},{"label":"大祥区","value":"430503"},{"label":"北塔区","value":"430511"},{"label":"邵东县","value":"430521"},{"label":"新邵县","value":"430522"},{"label":"邵阳县","value":"430523"},{"label":"隆回县","value":"430524"},{"label":"洞口县","value":"430525"},{"label":"绥宁县","value":"430527"},{"label":"新宁县","value":"430528"},{"label":"城步苗族自治县","value":"430529"},{"label":"武冈市","value":"430581"}],[{"label":"岳阳楼区","value":"430602"},{"label":"云溪区","value":"430603"},{"label":"君山区","value":"430611"},{"label":"岳阳县","value":"430621"},{"label":"华容县","value":"430623"},{"label":"湘阴县","value":"430624"},{"label":"平江县","value":"430626"},{"label":"岳阳市屈原管理区","value":"430671"},{"label":"汨罗市","value":"430681"},{"label":"临湘市","value":"430682"}],[{"label":"武陵区","value":"430702"},{"label":"鼎城区","value":"430703"},{"label":"安乡县","value":"430721"},{"label":"汉寿县","value":"430722"},{"label":"澧县","value":"430723"},{"label":"临澧县","value":"430724"},{"label":"桃源县","value":"430725"},{"label":"石门县","value":"430726"},{"label":"常德市西洞庭管理区","value":"430771"},{"label":"津市市","value":"430781"}],[{"label":"永定区","value":"430802"},{"label":"武陵源区","value":"430811"},{"label":"慈利县","value":"430821"},{"label":"桑植县","value":"430822"}],[{"label":"资阳区","value":"430902"},{"label":"赫山区","value":"430903"},{"label":"南县","value":"430921"},{"label":"桃江县","value":"430922"},{"label":"安化县","value":"430923"},{"label":"益阳市大通湖管理区","value":"430971"},{"label":"湖南益阳高新技术产业园区","value":"430972"},{"label":"沅江市","value":"430981"}],[{"label":"北湖区","value":"431002"},{"label":"苏仙区","value":"431003"},{"label":"桂阳县","value":"431021"},{"label":"宜章县","value":"431022"},{"label":"永兴县","value":"431023"},{"label":"嘉禾县","value":"431024"},{"label":"临武县","value":"431025"},{"label":"汝城县","value":"431026"},{"label":"桂东县","value":"431027"},{"label":"安仁县","value":"431028"},{"label":"资兴市","value":"431081"}],[{"label":"零陵区","value":"431102"},{"label":"冷水滩区","value":"431103"},{"label":"祁阳县","value":"431121"},{"label":"东安县","value":"431122"},{"label":"双牌县","value":"431123"},{"label":"道县","value":"431124"},{"label":"江永县","value":"431125"},{"label":"宁远县","value":"431126"},{"label":"蓝山县","value":"431127"},{"label":"新田县","value":"431128"},{"label":"江华瑶族自治县","value":"431129"},{"label":"永州经济技术开发区","value":"431171"},{"label":"永州市金洞管理区","value":"431172"},{"label":"永州市回龙圩管理区","value":"431173"}],[{"label":"鹤城区","value":"431202"},{"label":"中方县","value":"431221"},{"label":"沅陵县","value":"431222"},{"label":"辰溪县","value":"431223"},{"label":"溆浦县","value":"431224"},{"label":"会同县","value":"431225"},{"label":"麻阳苗族自治县","value":"431226"},{"label":"新晃侗族自治县","value":"431227"},{"label":"芷江侗族自治县","value":"431228"},{"label":"靖州苗族侗族自治县","value":"431229"},{"label":"通道侗族自治县","value":"431230"},{"label":"怀化市洪江管理区","value":"431271"},{"label":"洪江市","value":"431281"}],[{"label":"娄星区","value":"431302"},{"label":"双峰县","value":"431321"},{"label":"新化县","value":"431322"},{"label":"冷水江市","value":"431381"},{"label":"涟源市","value":"431382"}],[{"label":"吉首市","value":"433101"},{"label":"泸溪县","value":"433122"},{"label":"凤凰县","value":"433123"},{"label":"花垣县","value":"433124"},{"label":"保靖县","value":"433125"},{"label":"古丈县","value":"433126"},{"label":"永顺县","value":"433127"},{"label":"龙山县","value":"433130"},{"label":"湖南吉首经济开发区","value":"433172"},{"label":"湖南永顺经济开发区","value":"433173"}]],[[{"label":"荔湾区","value":"440103"},{"label":"越秀区","value":"440104"},{"label":"海珠区","value":"440105"},{"label":"天河区","value":"440106"},{"label":"白云区","value":"440111"},{"label":"黄埔区","value":"440112"},{"label":"番禺区","value":"440113"},{"label":"花都区","value":"440114"},{"label":"南沙区","value":"440115"},{"label":"从化区","value":"440117"},{"label":"增城区","value":"440118"}],[{"label":"武江区","value":"440203"},{"label":"浈江区","value":"440204"},{"label":"曲江区","value":"440205"},{"label":"始兴县","value":"440222"},{"label":"仁化县","value":"440224"},{"label":"翁源县","value":"440229"},{"label":"乳源瑶族自治县","value":"440232"},{"label":"新丰县","value":"440233"},{"label":"乐昌市","value":"440281"},{"label":"南雄市","value":"440282"}],[{"label":"罗湖区","value":"440303"},{"label":"福田区","value":"440304"},{"label":"南山区","value":"440305"},{"label":"宝安区","value":"440306"},{"label":"龙岗区","value":"440307"},{"label":"盐田区","value":"440308"},{"label":"龙华区","value":"440309"},{"label":"坪山区","value":"440310"}],[{"label":"香洲区","value":"440402"},{"label":"斗门区","value":"440403"},{"label":"金湾区","value":"440404"}],[{"label":"龙湖区","value":"440507"},{"label":"金平区","value":"440511"},{"label":"濠江区","value":"440512"},{"label":"潮阳区","value":"440513"},{"label":"潮南区","value":"440514"},{"label":"澄海区","value":"440515"},{"label":"南澳县","value":"440523"}],[{"label":"禅城区","value":"440604"},{"label":"南海区","value":"440605"},{"label":"顺德区","value":"440606"},{"label":"三水区","value":"440607"},{"label":"高明区","value":"440608"}],[{"label":"蓬江区","value":"440703"},{"label":"江海区","value":"440704"},{"label":"新会区","value":"440705"},{"label":"台山市","value":"440781"},{"label":"开平市","value":"440783"},{"label":"鹤山市","value":"440784"},{"label":"恩平市","value":"440785"}],[{"label":"赤坎区","value":"440802"},{"label":"霞山区","value":"440803"},{"label":"坡头区","value":"440804"},{"label":"麻章区","value":"440811"},{"label":"遂溪县","value":"440823"},{"label":"徐闻县","value":"440825"},{"label":"廉江市","value":"440881"},{"label":"雷州市","value":"440882"},{"label":"吴川市","value":"440883"}],[{"label":"茂南区","value":"440902"},{"label":"电白区","value":"440904"},{"label":"高州市","value":"440981"},{"label":"化州市","value":"440982"},{"label":"信宜市","value":"440983"}],[{"label":"端州区","value":"441202"},{"label":"鼎湖区","value":"441203"},{"label":"高要区","value":"441204"},{"label":"广宁县","value":"441223"},{"label":"怀集县","value":"441224"},{"label":"封开县","value":"441225"},{"label":"德庆县","value":"441226"},{"label":"四会市","value":"441284"}],[{"label":"惠城区","value":"441302"},{"label":"惠阳区","value":"441303"},{"label":"博罗县","value":"441322"},{"label":"惠东县","value":"441323"},{"label":"龙门县","value":"441324"}],[{"label":"梅江区","value":"441402"},{"label":"梅县区","value":"441403"},{"label":"大埔县","value":"441422"},{"label":"丰顺县","value":"441423"},{"label":"五华县","value":"441424"},{"label":"平远县","value":"441426"},{"label":"蕉岭县","value":"441427"},{"label":"兴宁市","value":"441481"}],[{"label":"城区","value":"441502"},{"label":"海丰县","value":"441521"},{"label":"陆河县","value":"441523"},{"label":"陆丰市","value":"441581"}],[{"label":"源城区","value":"441602"},{"label":"紫金县","value":"441621"},{"label":"龙川县","value":"441622"},{"label":"连平县","value":"441623"},{"label":"和平县","value":"441624"},{"label":"东源县","value":"441625"}],[{"label":"江城区","value":"441702"},{"label":"阳东区","value":"441704"},{"label":"阳西县","value":"441721"},{"label":"阳春市","value":"441781"}],[{"label":"清城区","value":"441802"},{"label":"清新区","value":"441803"},{"label":"佛冈县","value":"441821"},{"label":"阳山县","value":"441823"},{"label":"连山壮族瑶族自治县","value":"441825"},{"label":"连南瑶族自治县","value":"441826"},{"label":"英德市","value":"441881"},{"label":"连州市","value":"441882"}],[{"label":"东莞市","value":"441900"}],[{"label":"中山市","value":"442000"}],[{"label":"湘桥区","value":"445102"},{"label":"潮安区","value":"445103"},{"label":"饶平县","value":"445122"}],[{"label":"榕城区","value":"445202"},{"label":"揭东区","value":"445203"},{"label":"揭西县","value":"445222"},{"label":"惠来县","value":"445224"},{"label":"普宁市","value":"445281"}],[{"label":"云城区","value":"445302"},{"label":"云安区","value":"445303"},{"label":"新兴县","value":"445321"},{"label":"郁南县","value":"445322"},{"label":"罗定市","value":"445381"}]],[[{"label":"兴宁区","value":"450102"},{"label":"青秀区","value":"450103"},{"label":"江南区","value":"450105"},{"label":"西乡塘区","value":"450107"},{"label":"良庆区","value":"450108"},{"label":"邕宁区","value":"450109"},{"label":"武鸣区","value":"450110"},{"label":"隆安县","value":"450123"},{"label":"马山县","value":"450124"},{"label":"上林县","value":"450125"},{"label":"宾阳县","value":"450126"},{"label":"横县","value":"450127"}],[{"label":"城中区","value":"450202"},{"label":"鱼峰区","value":"450203"},{"label":"柳南区","value":"450204"},{"label":"柳北区","value":"450205"},{"label":"柳江区","value":"450206"},{"label":"柳城县","value":"450222"},{"label":"鹿寨县","value":"450223"},{"label":"融安县","value":"450224"},{"label":"融水苗族自治县","value":"450225"},{"label":"三江侗族自治县","value":"450226"}],[{"label":"秀峰区","value":"450302"},{"label":"叠彩区","value":"450303"},{"label":"象山区","value":"450304"},{"label":"七星区","value":"450305"},{"label":"雁山区","value":"450311"},{"label":"临桂区","value":"450312"},{"label":"阳朔县","value":"450321"},{"label":"灵川县","value":"450323"},{"label":"全州县","value":"450324"},{"label":"兴安县","value":"450325"},{"label":"永福县","value":"450326"},{"label":"灌阳县","value":"450327"},{"label":"龙胜各族自治县","value":"450328"},{"label":"资源县","value":"450329"},{"label":"平乐县","value":"450330"},{"label":"荔浦县","value":"450331"},{"label":"恭城瑶族自治县","value":"450332"}],[{"label":"万秀区","value":"450403"},{"label":"长洲区","value":"450405"},{"label":"龙圩区","value":"450406"},{"label":"苍梧县","value":"450421"},{"label":"藤县","value":"450422"},{"label":"蒙山县","value":"450423"},{"label":"岑溪市","value":"450481"}],[{"label":"海城区","value":"450502"},{"label":"银海区","value":"450503"},{"label":"铁山港区","value":"450512"},{"label":"合浦县","value":"450521"}],[{"label":"港口区","value":"450602"},{"label":"防城区","value":"450603"},{"label":"上思县","value":"450621"},{"label":"东兴市","value":"450681"}],[{"label":"钦南区","value":"450702"},{"label":"钦北区","value":"450703"},{"label":"灵山县","value":"450721"},{"label":"浦北县","value":"450722"}],[{"label":"港北区","value":"450802"},{"label":"港南区","value":"450803"},{"label":"覃塘区","value":"450804"},{"label":"平南县","value":"450821"},{"label":"桂平市","value":"450881"}],[{"label":"玉州区","value":"450902"},{"label":"福绵区","value":"450903"},{"label":"容县","value":"450921"},{"label":"陆川县","value":"450922"},{"label":"博白县","value":"450923"},{"label":"兴业县","value":"450924"},{"label":"北流市","value":"450981"}],[{"label":"右江区","value":"451002"},{"label":"田阳县","value":"451021"},{"label":"田东县","value":"451022"},{"label":"平果县","value":"451023"},{"label":"德保县","value":"451024"},{"label":"那坡县","value":"451026"},{"label":"凌云县","value":"451027"},{"label":"乐业县","value":"451028"},{"label":"田林县","value":"451029"},{"label":"西林县","value":"451030"},{"label":"隆林各族自治县","value":"451031"},{"label":"靖西市","value":"451081"}],[{"label":"八步区","value":"451102"},{"label":"平桂区","value":"451103"},{"label":"昭平县","value":"451121"},{"label":"钟山县","value":"451122"},{"label":"富川瑶族自治县","value":"451123"}],[{"label":"金城江区","value":"451202"},{"label":"宜州区","value":"451203"},{"label":"南丹县","value":"451221"},{"label":"天峨县","value":"451222"},{"label":"凤山县","value":"451223"},{"label":"东兰县","value":"451224"},{"label":"罗城仫佬族自治县","value":"451225"},{"label":"环江毛南族自治县","value":"451226"},{"label":"巴马瑶族自治县","value":"451227"},{"label":"都安瑶族自治县","value":"451228"},{"label":"大化瑶族自治县","value":"451229"}],[{"label":"兴宾区","value":"451302"},{"label":"忻城县","value":"451321"},{"label":"象州县","value":"451322"},{"label":"武宣县","value":"451323"},{"label":"金秀瑶族自治县","value":"451324"},{"label":"合山市","value":"451381"}],[{"label":"江州区","value":"451402"},{"label":"扶绥县","value":"451421"},{"label":"宁明县","value":"451422"},{"label":"龙州县","value":"451423"},{"label":"大新县","value":"451424"},{"label":"天等县","value":"451425"},{"label":"凭祥市","value":"451481"}]],[[{"label":"秀英区","value":"460105"},{"label":"龙华区","value":"460106"},{"label":"琼山区","value":"460107"},{"label":"美兰区","value":"460108"}],[{"label":"海棠区","value":"460202"},{"label":"吉阳区","value":"460203"},{"label":"天涯区","value":"460204"},{"label":"崖州区","value":"460205"}],[{"label":"西沙群岛","value":"460321"},{"label":"南沙群岛","value":"460322"},{"label":"中沙群岛的岛礁及其海域","value":"460323"}],[{"label":"儋州市","value":"460400"}],[{"label":"五指山市","value":"469001"},{"label":"琼海市","value":"469002"},{"label":"文昌市","value":"469005"},{"label":"万宁市","value":"469006"},{"label":"东方市","value":"469007"},{"label":"定安县","value":"469021"},{"label":"屯昌县","value":"469022"},{"label":"澄迈县","value":"469023"},{"label":"临高县","value":"469024"},{"label":"白沙黎族自治县","value":"469025"},{"label":"昌江黎族自治县","value":"469026"},{"label":"乐东黎族自治县","value":"469027"},{"label":"陵水黎族自治县","value":"469028"},{"label":"保亭黎族苗族自治县","value":"469029"},{"label":"琼中黎族苗族自治县","value":"469030"}]],[[{"label":"万州区","value":"500101"},{"label":"涪陵区","value":"500102"},{"label":"渝中区","value":"500103"},{"label":"大渡口区","value":"500104"},{"label":"江北区","value":"500105"},{"label":"沙坪坝区","value":"500106"},{"label":"九龙坡区","value":"500107"},{"label":"南岸区","value":"500108"},{"label":"北碚区","value":"500109"},{"label":"綦江区","value":"500110"},{"label":"大足区","value":"500111"},{"label":"渝北区","value":"500112"},{"label":"巴南区","value":"500113"},{"label":"黔江区","value":"500114"},{"label":"长寿区","value":"500115"},{"label":"江津区","value":"500116"},{"label":"合川区","value":"500117"},{"label":"永川区","value":"500118"},{"label":"南川区","value":"500119"},{"label":"璧山区","value":"500120"},{"label":"铜梁区","value":"500151"},{"label":"潼南区","value":"500152"},{"label":"荣昌区","value":"500153"},{"label":"开州区","value":"500154"},{"label":"梁平区","value":"500155"},{"label":"武隆区","value":"500156"}],[{"label":"城口县","value":"500229"},{"label":"丰都县","value":"500230"},{"label":"垫江县","value":"500231"},{"label":"忠县","value":"500233"},{"label":"云阳县","value":"500235"},{"label":"奉节县","value":"500236"},{"label":"巫山县","value":"500237"},{"label":"巫溪县","value":"500238"},{"label":"石柱土家族自治县","value":"500240"},{"label":"秀山土家族苗族自治县","value":"500241"},{"label":"酉阳土家族苗族自治县","value":"500242"},{"label":"彭水苗族土家族自治县","value":"500243"}]],[[{"label":"锦江区","value":"510104"},{"label":"青羊区","value":"510105"},{"label":"金牛区","value":"510106"},{"label":"武侯区","value":"510107"},{"label":"成华区","value":"510108"},{"label":"龙泉驿区","value":"510112"},{"label":"青白江区","value":"510113"},{"label":"新都区","value":"510114"},{"label":"温江区","value":"510115"},{"label":"双流区","value":"510116"},{"label":"郫都区","value":"510117"},{"label":"金堂县","value":"510121"},{"label":"大邑县","value":"510129"},{"label":"蒲江县","value":"510131"},{"label":"新津县","value":"510132"},{"label":"都江堰市","value":"510181"},{"label":"彭州市","value":"510182"},{"label":"邛崃市","value":"510183"},{"label":"崇州市","value":"510184"},{"label":"简阳市","value":"510185"}],[{"label":"自流井区","value":"510302"},{"label":"贡井区","value":"510303"},{"label":"大安区","value":"510304"},{"label":"沿滩区","value":"510311"},{"label":"荣县","value":"510321"},{"label":"富顺县","value":"510322"}],[{"label":"东区","value":"510402"},{"label":"西区","value":"510403"},{"label":"仁和区","value":"510411"},{"label":"米易县","value":"510421"},{"label":"盐边县","value":"510422"}],[{"label":"江阳区","value":"510502"},{"label":"纳溪区","value":"510503"},{"label":"龙马潭区","value":"510504"},{"label":"泸县","value":"510521"},{"label":"合江县","value":"510522"},{"label":"叙永县","value":"510524"},{"label":"古蔺县","value":"510525"}],[{"label":"旌阳区","value":"510603"},{"label":"罗江区","value":"510604"},{"label":"中江县","value":"510623"},{"label":"广汉市","value":"510681"},{"label":"什邡市","value":"510682"},{"label":"绵竹市","value":"510683"}],[{"label":"涪城区","value":"510703"},{"label":"游仙区","value":"510704"},{"label":"安州区","value":"510705"},{"label":"三台县","value":"510722"},{"label":"盐亭县","value":"510723"},{"label":"梓潼县","value":"510725"},{"label":"北川羌族自治县","value":"510726"},{"label":"平武县","value":"510727"},{"label":"江油市","value":"510781"}],[{"label":"利州区","value":"510802"},{"label":"昭化区","value":"510811"},{"label":"朝天区","value":"510812"},{"label":"旺苍县","value":"510821"},{"label":"青川县","value":"510822"},{"label":"剑阁县","value":"510823"},{"label":"苍溪县","value":"510824"}],[{"label":"船山区","value":"510903"},{"label":"安居区","value":"510904"},{"label":"蓬溪县","value":"510921"},{"label":"射洪县","value":"510922"},{"label":"大英县","value":"510923"}],[{"label":"市中区","value":"511002"},{"label":"东兴区","value":"511011"},{"label":"威远县","value":"511024"},{"label":"资中县","value":"511025"},{"label":"内江经济开发区","value":"511071"},{"label":"隆昌市","value":"511083"}],[{"label":"市中区","value":"511102"},{"label":"沙湾区","value":"511111"},{"label":"五通桥区","value":"511112"},{"label":"金口河区","value":"511113"},{"label":"犍为县","value":"511123"},{"label":"井研县","value":"511124"},{"label":"夹江县","value":"511126"},{"label":"沐川县","value":"511129"},{"label":"峨边彝族自治县","value":"511132"},{"label":"马边彝族自治县","value":"511133"},{"label":"峨眉山市","value":"511181"}],[{"label":"顺庆区","value":"511302"},{"label":"高坪区","value":"511303"},{"label":"嘉陵区","value":"511304"},{"label":"南部县","value":"511321"},{"label":"营山县","value":"511322"},{"label":"蓬安县","value":"511323"},{"label":"仪陇县","value":"511324"},{"label":"西充县","value":"511325"},{"label":"阆中市","value":"511381"}],[{"label":"东坡区","value":"511402"},{"label":"彭山区","value":"511403"},{"label":"仁寿县","value":"511421"},{"label":"洪雅县","value":"511423"},{"label":"丹棱县","value":"511424"},{"label":"青神县","value":"511425"}],[{"label":"翠屏区","value":"511502"},{"label":"南溪区","value":"511503"},{"label":"宜宾县","value":"511521"},{"label":"江安县","value":"511523"},{"label":"长宁县","value":"511524"},{"label":"高县","value":"511525"},{"label":"珙县","value":"511526"},{"label":"筠连县","value":"511527"},{"label":"兴文县","value":"511528"},{"label":"屏山县","value":"511529"}],[{"label":"广安区","value":"511602"},{"label":"前锋区","value":"511603"},{"label":"岳池县","value":"511621"},{"label":"武胜县","value":"511622"},{"label":"邻水县","value":"511623"},{"label":"华蓥市","value":"511681"}],[{"label":"通川区","value":"511702"},{"label":"达川区","value":"511703"},{"label":"宣汉县","value":"511722"},{"label":"开江县","value":"511723"},{"label":"大竹县","value":"511724"},{"label":"渠县","value":"511725"},{"label":"达州经济开发区","value":"511771"},{"label":"万源市","value":"511781"}],[{"label":"雨城区","value":"511802"},{"label":"名山区","value":"511803"},{"label":"荥经县","value":"511822"},{"label":"汉源县","value":"511823"},{"label":"石棉县","value":"511824"},{"label":"天全县","value":"511825"},{"label":"芦山县","value":"511826"},{"label":"宝兴县","value":"511827"}],[{"label":"巴州区","value":"511902"},{"label":"恩阳区","value":"511903"},{"label":"通江县","value":"511921"},{"label":"南江县","value":"511922"},{"label":"平昌县","value":"511923"},{"label":"巴中经济开发区","value":"511971"}],[{"label":"雁江区","value":"512002"},{"label":"安岳县","value":"512021"},{"label":"乐至县","value":"512022"}],[{"label":"马尔康市","value":"513201"},{"label":"汶川县","value":"513221"},{"label":"理县","value":"513222"},{"label":"茂县","value":"513223"},{"label":"松潘县","value":"513224"},{"label":"九寨沟县","value":"513225"},{"label":"金川县","value":"513226"},{"label":"小金县","value":"513227"},{"label":"黑水县","value":"513228"},{"label":"壤塘县","value":"513230"},{"label":"阿坝县","value":"513231"},{"label":"若尔盖县","value":"513232"},{"label":"红原县","value":"513233"}],[{"label":"康定市","value":"513301"},{"label":"泸定县","value":"513322"},{"label":"丹巴县","value":"513323"},{"label":"九龙县","value":"513324"},{"label":"雅江县","value":"513325"},{"label":"道孚县","value":"513326"},{"label":"炉霍县","value":"513327"},{"label":"甘孜县","value":"513328"},{"label":"新龙县","value":"513329"},{"label":"德格县","value":"513330"},{"label":"白玉县","value":"513331"},{"label":"石渠县","value":"513332"},{"label":"色达县","value":"513333"},{"label":"理塘县","value":"513334"},{"label":"巴塘县","value":"513335"},{"label":"乡城县","value":"513336"},{"label":"稻城县","value":"513337"},{"label":"得荣县","value":"513338"}],[{"label":"西昌市","value":"513401"},{"label":"木里藏族自治县","value":"513422"},{"label":"盐源县","value":"513423"},{"label":"德昌县","value":"513424"},{"label":"会理县","value":"513425"},{"label":"会东县","value":"513426"},{"label":"宁南县","value":"513427"},{"label":"普格县","value":"513428"},{"label":"布拖县","value":"513429"},{"label":"金阳县","value":"513430"},{"label":"昭觉县","value":"513431"},{"label":"喜德县","value":"513432"},{"label":"冕宁县","value":"513433"},{"label":"越西县","value":"513434"},{"label":"甘洛县","value":"513435"},{"label":"美姑县","value":"513436"},{"label":"雷波县","value":"513437"}]],[[{"label":"南明区","value":"520102"},{"label":"云岩区","value":"520103"},{"label":"花溪区","value":"520111"},{"label":"乌当区","value":"520112"},{"label":"白云区","value":"520113"},{"label":"观山湖区","value":"520115"},{"label":"开阳县","value":"520121"},{"label":"息烽县","value":"520122"},{"label":"修文县","value":"520123"},{"label":"清镇市","value":"520181"}],[{"label":"钟山区","value":"520201"},{"label":"六枝特区","value":"520203"},{"label":"水城县","value":"520221"},{"label":"盘州市","value":"520281"}],[{"label":"红花岗区","value":"520302"},{"label":"汇川区","value":"520303"},{"label":"播州区","value":"520304"},{"label":"桐梓县","value":"520322"},{"label":"绥阳县","value":"520323"},{"label":"正安县","value":"520324"},{"label":"道真仡佬族苗族自治县","value":"520325"},{"label":"务川仡佬族苗族自治县","value":"520326"},{"label":"凤冈县","value":"520327"},{"label":"湄潭县","value":"520328"},{"label":"余庆县","value":"520329"},{"label":"习水县","value":"520330"},{"label":"赤水市","value":"520381"},{"label":"仁怀市","value":"520382"}],[{"label":"西秀区","value":"520402"},{"label":"平坝区","value":"520403"},{"label":"普定县","value":"520422"},{"label":"镇宁布依族苗族自治县","value":"520423"},{"label":"关岭布依族苗族自治县","value":"520424"},{"label":"紫云苗族布依族自治县","value":"520425"}],[{"label":"七星关区","value":"520502"},{"label":"大方县","value":"520521"},{"label":"黔西县","value":"520522"},{"label":"金沙县","value":"520523"},{"label":"织金县","value":"520524"},{"label":"纳雍县","value":"520525"},{"label":"威宁彝族回族苗族自治县","value":"520526"},{"label":"赫章县","value":"520527"}],[{"label":"碧江区","value":"520602"},{"label":"万山区","value":"520603"},{"label":"江口县","value":"520621"},{"label":"玉屏侗族自治县","value":"520622"},{"label":"石阡县","value":"520623"},{"label":"思南县","value":"520624"},{"label":"印江土家族苗族自治县","value":"520625"},{"label":"德江县","value":"520626"},{"label":"沿河土家族自治县","value":"520627"},{"label":"松桃苗族自治县","value":"520628"}],[{"label":"兴义市","value":"522301"},{"label":"兴仁县","value":"522322"},{"label":"普安县","value":"522323"},{"label":"晴隆县","value":"522324"},{"label":"贞丰县","value":"522325"},{"label":"望谟县","value":"522326"},{"label":"册亨县","value":"522327"},{"label":"安龙县","value":"522328"}],[{"label":"凯里市","value":"522601"},{"label":"黄平县","value":"522622"},{"label":"施秉县","value":"522623"},{"label":"三穗县","value":"522624"},{"label":"镇远县","value":"522625"},{"label":"岑巩县","value":"522626"},{"label":"天柱县","value":"522627"},{"label":"锦屏县","value":"522628"},{"label":"剑河县","value":"522629"},{"label":"台江县","value":"522630"},{"label":"黎平县","value":"522631"},{"label":"榕江县","value":"522632"},{"label":"从江县","value":"522633"},{"label":"雷山县","value":"522634"},{"label":"麻江县","value":"522635"},{"label":"丹寨县","value":"522636"}],[{"label":"都匀市","value":"522701"},{"label":"福泉市","value":"522702"},{"label":"荔波县","value":"522722"},{"label":"贵定县","value":"522723"},{"label":"瓮安县","value":"522725"},{"label":"独山县","value":"522726"},{"label":"平塘县","value":"522727"},{"label":"罗甸县","value":"522728"},{"label":"长顺县","value":"522729"},{"label":"龙里县","value":"522730"},{"label":"惠水县","value":"522731"},{"label":"三都水族自治县","value":"522732"}]],[[{"label":"五华区","value":"530102"},{"label":"盘龙区","value":"530103"},{"label":"官渡区","value":"530111"},{"label":"西山区","value":"530112"},{"label":"东川区","value":"530113"},{"label":"呈贡区","value":"530114"},{"label":"晋宁区","value":"530115"},{"label":"富民县","value":"530124"},{"label":"宜良县","value":"530125"},{"label":"石林彝族自治县","value":"530126"},{"label":"嵩明县","value":"530127"},{"label":"禄劝彝族苗族自治县","value":"530128"},{"label":"寻甸回族彝族自治县","value":"530129"},{"label":"安宁市","value":"530181"}],[{"label":"麒麟区","value":"530302"},{"label":"沾益区","value":"530303"},{"label":"马龙县","value":"530321"},{"label":"陆良县","value":"530322"},{"label":"师宗县","value":"530323"},{"label":"罗平县","value":"530324"},{"label":"富源县","value":"530325"},{"label":"会泽县","value":"530326"},{"label":"宣威市","value":"530381"}],[{"label":"红塔区","value":"530402"},{"label":"江川区","value":"530403"},{"label":"澄江县","value":"530422"},{"label":"通海县","value":"530423"},{"label":"华宁县","value":"530424"},{"label":"易门县","value":"530425"},{"label":"峨山彝族自治县","value":"530426"},{"label":"新平彝族傣族自治县","value":"530427"},{"label":"元江哈尼族彝族傣族自治县","value":"530428"}],[{"label":"隆阳区","value":"530502"},{"label":"施甸县","value":"530521"},{"label":"龙陵县","value":"530523"},{"label":"昌宁县","value":"530524"},{"label":"腾冲市","value":"530581"}],[{"label":"昭阳区","value":"530602"},{"label":"鲁甸县","value":"530621"},{"label":"巧家县","value":"530622"},{"label":"盐津县","value":"530623"},{"label":"大关县","value":"530624"},{"label":"永善县","value":"530625"},{"label":"绥江县","value":"530626"},{"label":"镇雄县","value":"530627"},{"label":"彝良县","value":"530628"},{"label":"威信县","value":"530629"},{"label":"水富县","value":"530630"}],[{"label":"古城区","value":"530702"},{"label":"玉龙纳西族自治县","value":"530721"},{"label":"永胜县","value":"530722"},{"label":"华坪县","value":"530723"},{"label":"宁蒗彝族自治县","value":"530724"}],[{"label":"思茅区","value":"530802"},{"label":"宁洱哈尼族彝族自治县","value":"530821"},{"label":"墨江哈尼族自治县","value":"530822"},{"label":"景东彝族自治县","value":"530823"},{"label":"景谷傣族彝族自治县","value":"530824"},{"label":"镇沅彝族哈尼族拉祜族自治县","value":"530825"},{"label":"江城哈尼族彝族自治县","value":"530826"},{"label":"孟连傣族拉祜族佤族自治县","value":"530827"},{"label":"澜沧拉祜族自治县","value":"530828"},{"label":"西盟佤族自治县","value":"530829"}],[{"label":"临翔区","value":"530902"},{"label":"凤庆县","value":"530921"},{"label":"云县","value":"530922"},{"label":"永德县","value":"530923"},{"label":"镇康县","value":"530924"},{"label":"双江拉祜族佤族布朗族傣族自治县","value":"530925"},{"label":"耿马傣族佤族自治县","value":"530926"},{"label":"沧源佤族自治县","value":"530927"}],[{"label":"楚雄市","value":"532301"},{"label":"双柏县","value":"532322"},{"label":"牟定县","value":"532323"},{"label":"南华县","value":"532324"},{"label":"姚安县","value":"532325"},{"label":"大姚县","value":"532326"},{"label":"永仁县","value":"532327"},{"label":"元谋县","value":"532328"},{"label":"武定县","value":"532329"},{"label":"禄丰县","value":"532331"}],[{"label":"个旧市","value":"532501"},{"label":"开远市","value":"532502"},{"label":"蒙自市","value":"532503"},{"label":"弥勒市","value":"532504"},{"label":"屏边苗族自治县","value":"532523"},{"label":"建水县","value":"532524"},{"label":"石屏县","value":"532525"},{"label":"泸西县","value":"532527"},{"label":"元阳县","value":"532528"},{"label":"红河县","value":"532529"},{"label":"金平苗族瑶族傣族自治县","value":"532530"},{"label":"绿春县","value":"532531"},{"label":"河口瑶族自治县","value":"532532"}],[{"label":"文山市","value":"532601"},{"label":"砚山县","value":"532622"},{"label":"西畴县","value":"532623"},{"label":"麻栗坡县","value":"532624"},{"label":"马关县","value":"532625"},{"label":"丘北县","value":"532626"},{"label":"广南县","value":"532627"},{"label":"富宁县","value":"532628"}],[{"label":"景洪市","value":"532801"},{"label":"勐海县","value":"532822"},{"label":"勐腊县","value":"532823"}],[{"label":"大理市","value":"532901"},{"label":"漾濞彝族自治县","value":"532922"},{"label":"祥云县","value":"532923"},{"label":"宾川县","value":"532924"},{"label":"弥渡县","value":"532925"},{"label":"南涧彝族自治县","value":"532926"},{"label":"巍山彝族回族自治县","value":"532927"},{"label":"永平县","value":"532928"},{"label":"云龙县","value":"532929"},{"label":"洱源县","value":"532930"},{"label":"剑川县","value":"532931"},{"label":"鹤庆县","value":"532932"}],[{"label":"瑞丽市","value":"533102"},{"label":"芒市","value":"533103"},{"label":"梁河县","value":"533122"},{"label":"盈江县","value":"533123"},{"label":"陇川县","value":"533124"}],[{"label":"泸水市","value":"533301"},{"label":"福贡县","value":"533323"},{"label":"贡山独龙族怒族自治县","value":"533324"},{"label":"兰坪白族普米族自治县","value":"533325"}],[{"label":"香格里拉市","value":"533401"},{"label":"德钦县","value":"533422"},{"label":"维西傈僳族自治县","value":"533423"}]],[[{"label":"城关区","value":"540102"},{"label":"堆龙德庆区","value":"540103"},{"label":"林周县","value":"540121"},{"label":"当雄县","value":"540122"},{"label":"尼木县","value":"540123"},{"label":"曲水县","value":"540124"},{"label":"达孜县","value":"540126"},{"label":"墨竹工卡县","value":"540127"},{"label":"格尔木藏青工业园区","value":"540171"},{"label":"拉萨经济技术开发区","value":"540172"},{"label":"西藏文化旅游创意园区","value":"540173"},{"label":"达孜工业园区","value":"540174"}],[{"label":"桑珠孜区","value":"540202"},{"label":"南木林县","value":"540221"},{"label":"江孜县","value":"540222"},{"label":"定日县","value":"540223"},{"label":"萨迦县","value":"540224"},{"label":"拉孜县","value":"540225"},{"label":"昂仁县","value":"540226"},{"label":"谢通门县","value":"540227"},{"label":"白朗县","value":"540228"},{"label":"仁布县","value":"540229"},{"label":"康马县","value":"540230"},{"label":"定结县","value":"540231"},{"label":"仲巴县","value":"540232"},{"label":"亚东县","value":"540233"},{"label":"吉隆县","value":"540234"},{"label":"聂拉木县","value":"540235"},{"label":"萨嘎县","value":"540236"},{"label":"岗巴县","value":"540237"}],[{"label":"卡若区","value":"540302"},{"label":"江达县","value":"540321"},{"label":"贡觉县","value":"540322"},{"label":"类乌齐县","value":"540323"},{"label":"丁青县","value":"540324"},{"label":"察雅县","value":"540325"},{"label":"八宿县","value":"540326"},{"label":"左贡县","value":"540327"},{"label":"芒康县","value":"540328"},{"label":"洛隆县","value":"540329"},{"label":"边坝县","value":"540330"}],[{"label":"巴宜区","value":"540402"},{"label":"工布江达县","value":"540421"},{"label":"米林县","value":"540422"},{"label":"墨脱县","value":"540423"},{"label":"波密县","value":"540424"},{"label":"察隅县","value":"540425"},{"label":"朗县","value":"540426"}],[{"label":"乃东区","value":"540502"},{"label":"扎囊县","value":"540521"},{"label":"贡嘎县","value":"540522"},{"label":"桑日县","value":"540523"},{"label":"琼结县","value":"540524"},{"label":"曲松县","value":"540525"},{"label":"措美县","value":"540526"},{"label":"洛扎县","value":"540527"},{"label":"加查县","value":"540528"},{"label":"隆子县","value":"540529"},{"label":"错那县","value":"540530"},{"label":"浪卡子县","value":"540531"}],[{"label":"那曲县","value":"542421"},{"label":"嘉黎县","value":"542422"},{"label":"比如县","value":"542423"},{"label":"聂荣县","value":"542424"},{"label":"安多县","value":"542425"},{"label":"申扎县","value":"542426"},{"label":"索县","value":"542427"},{"label":"班戈县","value":"542428"},{"label":"巴青县","value":"542429"},{"label":"尼玛县","value":"542430"},{"label":"双湖县","value":"542431"}],[{"label":"普兰县","value":"542521"},{"label":"札达县","value":"542522"},{"label":"噶尔县","value":"542523"},{"label":"日土县","value":"542524"},{"label":"革吉县","value":"542525"},{"label":"改则县","value":"542526"},{"label":"措勤县","value":"542527"}]],[[{"label":"新城区","value":"610102"},{"label":"碑林区","value":"610103"},{"label":"莲湖区","value":"610104"},{"label":"灞桥区","value":"610111"},{"label":"未央区","value":"610112"},{"label":"雁塔区","value":"610113"},{"label":"阎良区","value":"610114"},{"label":"临潼区","value":"610115"},{"label":"长安区","value":"610116"},{"label":"高陵区","value":"610117"},{"label":"鄠邑区","value":"610118"},{"label":"蓝田县","value":"610122"},{"label":"周至县","value":"610124"}],[{"label":"王益区","value":"610202"},{"label":"印台区","value":"610203"},{"label":"耀州区","value":"610204"},{"label":"宜君县","value":"610222"}],[{"label":"渭滨区","value":"610302"},{"label":"金台区","value":"610303"},{"label":"陈仓区","value":"610304"},{"label":"凤翔县","value":"610322"},{"label":"岐山县","value":"610323"},{"label":"扶风县","value":"610324"},{"label":"眉县","value":"610326"},{"label":"陇县","value":"610327"},{"label":"千阳县","value":"610328"},{"label":"麟游县","value":"610329"},{"label":"凤县","value":"610330"},{"label":"太白县","value":"610331"}],[{"label":"秦都区","value":"610402"},{"label":"杨陵区","value":"610403"},{"label":"渭城区","value":"610404"},{"label":"三原县","value":"610422"},{"label":"泾阳县","value":"610423"},{"label":"乾县","value":"610424"},{"label":"礼泉县","value":"610425"},{"label":"永寿县","value":"610426"},{"label":"彬县","value":"610427"},{"label":"长武县","value":"610428"},{"label":"旬邑县","value":"610429"},{"label":"淳化县","value":"610430"},{"label":"武功县","value":"610431"},{"label":"兴平市","value":"610481"}],[{"label":"临渭区","value":"610502"},{"label":"华州区","value":"610503"},{"label":"潼关县","value":"610522"},{"label":"大荔县","value":"610523"},{"label":"合阳县","value":"610524"},{"label":"澄城县","value":"610525"},{"label":"蒲城县","value":"610526"},{"label":"白水县","value":"610527"},{"label":"富平县","value":"610528"},{"label":"韩城市","value":"610581"},{"label":"华阴市","value":"610582"}],[{"label":"宝塔区","value":"610602"},{"label":"安塞区","value":"610603"},{"label":"延长县","value":"610621"},{"label":"延川县","value":"610622"},{"label":"子长县","value":"610623"},{"label":"志丹县","value":"610625"},{"label":"吴起县","value":"610626"},{"label":"甘泉县","value":"610627"},{"label":"富县","value":"610628"},{"label":"洛川县","value":"610629"},{"label":"宜川县","value":"610630"},{"label":"黄龙县","value":"610631"},{"label":"黄陵县","value":"610632"}],[{"label":"汉台区","value":"610702"},{"label":"南郑区","value":"610703"},{"label":"城固县","value":"610722"},{"label":"洋县","value":"610723"},{"label":"西乡县","value":"610724"},{"label":"勉县","value":"610725"},{"label":"宁强县","value":"610726"},{"label":"略阳县","value":"610727"},{"label":"镇巴县","value":"610728"},{"label":"留坝县","value":"610729"},{"label":"佛坪县","value":"610730"}],[{"label":"榆阳区","value":"610802"},{"label":"横山区","value":"610803"},{"label":"府谷县","value":"610822"},{"label":"靖边县","value":"610824"},{"label":"定边县","value":"610825"},{"label":"绥德县","value":"610826"},{"label":"米脂县","value":"610827"},{"label":"佳县","value":"610828"},{"label":"吴堡县","value":"610829"},{"label":"清涧县","value":"610830"},{"label":"子洲县","value":"610831"},{"label":"神木市","value":"610881"}],[{"label":"汉滨区","value":"610902"},{"label":"汉阴县","value":"610921"},{"label":"石泉县","value":"610922"},{"label":"宁陕县","value":"610923"},{"label":"紫阳县","value":"610924"},{"label":"岚皋县","value":"610925"},{"label":"平利县","value":"610926"},{"label":"镇坪县","value":"610927"},{"label":"旬阳县","value":"610928"},{"label":"白河县","value":"610929"}],[{"label":"商州区","value":"611002"},{"label":"洛南县","value":"611021"},{"label":"丹凤县","value":"611022"},{"label":"商南县","value":"611023"},{"label":"山阳县","value":"611024"},{"label":"镇安县","value":"611025"},{"label":"柞水县","value":"611026"}]],[[{"label":"城关区","value":"620102"},{"label":"七里河区","value":"620103"},{"label":"西固区","value":"620104"},{"label":"安宁区","value":"620105"},{"label":"红古区","value":"620111"},{"label":"永登县","value":"620121"},{"label":"皋兰县","value":"620122"},{"label":"榆中县","value":"620123"},{"label":"兰州新区","value":"620171"}],[{"label":"嘉峪关市","value":"620201"}],[{"label":"金川区","value":"620302"},{"label":"永昌县","value":"620321"}],[{"label":"白银区","value":"620402"},{"label":"平川区","value":"620403"},{"label":"靖远县","value":"620421"},{"label":"会宁县","value":"620422"},{"label":"景泰县","value":"620423"}],[{"label":"秦州区","value":"620502"},{"label":"麦积区","value":"620503"},{"label":"清水县","value":"620521"},{"label":"秦安县","value":"620522"},{"label":"甘谷县","value":"620523"},{"label":"武山县","value":"620524"},{"label":"张家川回族自治县","value":"620525"}],[{"label":"凉州区","value":"620602"},{"label":"民勤县","value":"620621"},{"label":"古浪县","value":"620622"},{"label":"天祝藏族自治县","value":"620623"}],[{"label":"甘州区","value":"620702"},{"label":"肃南裕固族自治县","value":"620721"},{"label":"民乐县","value":"620722"},{"label":"临泽县","value":"620723"},{"label":"高台县","value":"620724"},{"label":"山丹县","value":"620725"}],[{"label":"崆峒区","value":"620802"},{"label":"泾川县","value":"620821"},{"label":"灵台县","value":"620822"},{"label":"崇信县","value":"620823"},{"label":"华亭县","value":"620824"},{"label":"庄浪县","value":"620825"},{"label":"静宁县","value":"620826"},{"label":"平凉工业园区","value":"620871"}],[{"label":"肃州区","value":"620902"},{"label":"金塔县","value":"620921"},{"label":"瓜州县","value":"620922"},{"label":"肃北蒙古族自治县","value":"620923"},{"label":"阿克塞哈萨克族自治县","value":"620924"},{"label":"玉门市","value":"620981"},{"label":"敦煌市","value":"620982"}],[{"label":"西峰区","value":"621002"},{"label":"庆城县","value":"621021"},{"label":"环县","value":"621022"},{"label":"华池县","value":"621023"},{"label":"合水县","value":"621024"},{"label":"正宁县","value":"621025"},{"label":"宁县","value":"621026"},{"label":"镇原县","value":"621027"}],[{"label":"安定区","value":"621102"},{"label":"通渭县","value":"621121"},{"label":"陇西县","value":"621122"},{"label":"渭源县","value":"621123"},{"label":"临洮县","value":"621124"},{"label":"漳县","value":"621125"},{"label":"岷县","value":"621126"}],[{"label":"武都区","value":"621202"},{"label":"成县","value":"621221"},{"label":"文县","value":"621222"},{"label":"宕昌县","value":"621223"},{"label":"康县","value":"621224"},{"label":"西和县","value":"621225"},{"label":"礼县","value":"621226"},{"label":"徽县","value":"621227"},{"label":"两当县","value":"621228"}],[{"label":"临夏市","value":"622901"},{"label":"临夏县","value":"622921"},{"label":"康乐县","value":"622922"},{"label":"永靖县","value":"622923"},{"label":"广河县","value":"622924"},{"label":"和政县","value":"622925"},{"label":"东乡族自治县","value":"622926"},{"label":"积石山保安族东乡族撒拉族自治县","value":"622927"}],[{"label":"合作市","value":"623001"},{"label":"临潭县","value":"623021"},{"label":"卓尼县","value":"623022"},{"label":"舟曲县","value":"623023"},{"label":"迭部县","value":"623024"},{"label":"玛曲县","value":"623025"},{"label":"碌曲县","value":"623026"},{"label":"夏河县","value":"623027"}]],[[{"label":"城东区","value":"630102"},{"label":"城中区","value":"630103"},{"label":"城西区","value":"630104"},{"label":"城北区","value":"630105"},{"label":"大通回族土族自治县","value":"630121"},{"label":"湟中县","value":"630122"},{"label":"湟源县","value":"630123"}],[{"label":"乐都区","value":"630202"},{"label":"平安区","value":"630203"},{"label":"民和回族土族自治县","value":"630222"},{"label":"互助土族自治县","value":"630223"},{"label":"化隆回族自治县","value":"630224"},{"label":"循化撒拉族自治县","value":"630225"}],[{"label":"门源回族自治县","value":"632221"},{"label":"祁连县","value":"632222"},{"label":"海晏县","value":"632223"},{"label":"刚察县","value":"632224"}],[{"label":"同仁县","value":"632321"},{"label":"尖扎县","value":"632322"},{"label":"泽库县","value":"632323"},{"label":"河南蒙古族自治县","value":"632324"}],[{"label":"共和县","value":"632521"},{"label":"同德县","value":"632522"},{"label":"贵德县","value":"632523"},{"label":"兴海县","value":"632524"},{"label":"贵南县","value":"632525"}],[{"label":"玛沁县","value":"632621"},{"label":"班玛县","value":"632622"},{"label":"甘德县","value":"632623"},{"label":"达日县","value":"632624"},{"label":"久治县","value":"632625"},{"label":"玛多县","value":"632626"}],[{"label":"玉树市","value":"632701"},{"label":"杂多县","value":"632722"},{"label":"称多县","value":"632723"},{"label":"治多县","value":"632724"},{"label":"囊谦县","value":"632725"},{"label":"曲麻莱县","value":"632726"}],[{"label":"格尔木市","value":"632801"},{"label":"德令哈市","value":"632802"},{"label":"乌兰县","value":"632821"},{"label":"都兰县","value":"632822"},{"label":"天峻县","value":"632823"},{"label":"大柴旦行政委员会","value":"632857"},{"label":"冷湖行政委员会","value":"632858"},{"label":"茫崖行政委员会","value":"632859"}]],[[{"label":"兴庆区","value":"640104"},{"label":"西夏区","value":"640105"},{"label":"金凤区","value":"640106"},{"label":"永宁县","value":"640121"},{"label":"贺兰县","value":"640122"},{"label":"灵武市","value":"640181"}],[{"label":"大武口区","value":"640202"},{"label":"惠农区","value":"640205"},{"label":"平罗县","value":"640221"}],[{"label":"利通区","value":"640302"},{"label":"红寺堡区","value":"640303"},{"label":"盐池县","value":"640323"},{"label":"同心县","value":"640324"},{"label":"青铜峡市","value":"640381"}],[{"label":"原州区","value":"640402"},{"label":"西吉县","value":"640422"},{"label":"隆德县","value":"640423"},{"label":"泾源县","value":"640424"},{"label":"彭阳县","value":"640425"}],[{"label":"沙坡头区","value":"640502"},{"label":"中宁县","value":"640521"},{"label":"海原县","value":"640522"}]],[[{"label":"天山区","value":"650102"},{"label":"沙依巴克区","value":"650103"},{"label":"新市区","value":"650104"},{"label":"水磨沟区","value":"650105"},{"label":"头屯河区","value":"650106"},{"label":"达坂城区","value":"650107"},{"label":"米东区","value":"650109"},{"label":"乌鲁木齐县","value":"650121"},{"label":"乌鲁木齐经济技术开发区","value":"650171"},{"label":"乌鲁木齐高新技术产业开发区","value":"650172"}],[{"label":"独山子区","value":"650202"},{"label":"克拉玛依区","value":"650203"},{"label":"白碱滩区","value":"650204"},{"label":"乌尔禾区","value":"650205"}],[{"label":"高昌区","value":"650402"},{"label":"鄯善县","value":"650421"},{"label":"托克逊县","value":"650422"}],[{"label":"伊州区","value":"650502"},{"label":"巴里坤哈萨克自治县","value":"650521"},{"label":"伊吾县","value":"650522"}],[{"label":"昌吉市","value":"652301"},{"label":"阜康市","value":"652302"},{"label":"呼图壁县","value":"652323"},{"label":"玛纳斯县","value":"652324"},{"label":"奇台县","value":"652325"},{"label":"吉木萨尔县","value":"652327"},{"label":"木垒哈萨克自治县","value":"652328"}],[{"label":"博乐市","value":"652701"},{"label":"阿拉山口市","value":"652702"},{"label":"精河县","value":"652722"},{"label":"温泉县","value":"652723"}],[{"label":"库尔勒市","value":"652801"},{"label":"轮台县","value":"652822"},{"label":"尉犁县","value":"652823"},{"label":"若羌县","value":"652824"},{"label":"且末县","value":"652825"},{"label":"焉耆回族自治县","value":"652826"},{"label":"和静县","value":"652827"},{"label":"和硕县","value":"652828"},{"label":"博湖县","value":"652829"},{"label":"库尔勒经济技术开发区","value":"652871"}],[{"label":"阿克苏市","value":"652901"},{"label":"温宿县","value":"652922"},{"label":"库车县","value":"652923"},{"label":"沙雅县","value":"652924"},{"label":"新和县","value":"652925"},{"label":"拜城县","value":"652926"},{"label":"乌什县","value":"652927"},{"label":"阿瓦提县","value":"652928"},{"label":"柯坪县","value":"652929"}],[{"label":"阿图什市","value":"653001"},{"label":"阿克陶县","value":"653022"},{"label":"阿合奇县","value":"653023"},{"label":"乌恰县","value":"653024"}],[{"label":"喀什市","value":"653101"},{"label":"疏附县","value":"653121"},{"label":"疏勒县","value":"653122"},{"label":"英吉沙县","value":"653123"},{"label":"泽普县","value":"653124"},{"label":"莎车县","value":"653125"},{"label":"叶城县","value":"653126"},{"label":"麦盖提县","value":"653127"},{"label":"岳普湖县","value":"653128"},{"label":"伽师县","value":"653129"},{"label":"巴楚县","value":"653130"},{"label":"塔什库尔干塔吉克自治县","value":"653131"}],[{"label":"和田市","value":"653201"},{"label":"和田县","value":"653221"},{"label":"墨玉县","value":"653222"},{"label":"皮山县","value":"653223"},{"label":"洛浦县","value":"653224"},{"label":"策勒县","value":"653225"},{"label":"于田县","value":"653226"},{"label":"民丰县","value":"653227"}],[{"label":"伊宁市","value":"654002"},{"label":"奎屯市","value":"654003"},{"label":"霍尔果斯市","value":"654004"},{"label":"伊宁县","value":"654021"},{"label":"察布查尔锡伯自治县","value":"654022"},{"label":"霍城县","value":"654023"},{"label":"巩留县","value":"654024"},{"label":"新源县","value":"654025"},{"label":"昭苏县","value":"654026"},{"label":"特克斯县","value":"654027"},{"label":"尼勒克县","value":"654028"}],[{"label":"塔城市","value":"654201"},{"label":"乌苏市","value":"654202"},{"label":"额敏县","value":"654221"},{"label":"沙湾县","value":"654223"},{"label":"托里县","value":"654224"},{"label":"裕民县","value":"654225"},{"label":"和布克赛尔蒙古自治县","value":"654226"}],[{"label":"阿勒泰市","value":"654301"},{"label":"布尔津县","value":"654321"},{"label":"富蕴县","value":"654322"},{"label":"福海县","value":"654323"},{"label":"哈巴河县","value":"654324"},{"label":"青河县","value":"654325"},{"label":"吉木乃县","value":"654326"}],[{"label":"石河子市","value":"659001"},{"label":"阿拉尔市","value":"659002"},{"label":"图木舒克市","value":"659003"},{"label":"五家渠市","value":"659004"},{"label":"铁门关市","value":"659006"}]],[[{"label":"台北","value":"660101"}],[{"label":"高雄","value":"660201"}],[{"label":"基隆","value":"660301"}],[{"label":"台中","value":"660401"}],[{"label":"台南","value":"660501"}],[{"label":"新竹","value":"660601"}],[{"label":"嘉义","value":"660701"}],[{"label":"宜兰","value":"660801"}],[{"label":"桃园","value":"660901"}],[{"label":"苗栗","value":"661001"}],[{"label":"彰化","value":"661101"}],[{"label":"南投","value":"661201"}],[{"label":"云林","value":"661301"}],[{"label":"屏东","value":"661401"}],[{"label":"台东","value":"661501"}],[{"label":"花莲","value":"661601"}],[{"label":"澎湖","value":"661701"}]],[[{"label":"香港岛","value":"670101"}],[{"label":"九龙","value":"670201"}],[{"label":"新界","value":"670301"}]],[[{"label":"澳门半岛","value":"680101"}],[{"label":"氹仔岛","value":"680201"}],[{"label":"路环岛","value":"680301"}],[{"label":"路氹城","value":"680401"}]]];export default areaData;
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/util/async-validator.js b/hotgo-uniapp/uview-ui/libs/util/async-validator.js
new file mode 100644
index 0000000..d7215b9
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/util/async-validator.js
@@ -0,0 +1,1356 @@
+function _extends() {
+ _extends = Object.assign || function(target) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+
+ for (var key in source) {
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
+ }
+ }
+ }
+
+ return target;
+ };
+
+ return _extends.apply(this, arguments);
+}
+
+/* eslint no-console:0 */
+var formatRegExp = /%[sdj%]/g;
+var warning = function warning() {}; // don't print warning message when in production env or node runtime
+
+if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV !== 'production' && typeof window !==
+ 'undefined' && typeof document !== 'undefined') {
+ warning = function warning(type, errors) {
+ if (typeof console !== 'undefined' && console.warn) {
+ if (errors.every(function(e) {
+ return typeof e === 'string';
+ })) {
+ console.warn(type, errors);
+ }
+ }
+ };
+}
+
+function convertFieldsError(errors) {
+ if (!errors || !errors.length) return null;
+ var fields = {};
+ errors.forEach(function(error) {
+ var field = error.field;
+ fields[field] = fields[field] || [];
+ fields[field].push(error);
+ });
+ return fields;
+}
+
+function format() {
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ var i = 1;
+ var f = args[0];
+ var len = args.length;
+
+ if (typeof f === 'function') {
+ return f.apply(null, args.slice(1));
+ }
+
+ if (typeof f === 'string') {
+ var str = String(f).replace(formatRegExp, function(x) {
+ if (x === '%%') {
+ return '%';
+ }
+
+ if (i >= len) {
+ return x;
+ }
+
+ switch (x) {
+ case '%s':
+ return String(args[i++]);
+
+ case '%d':
+ return Number(args[i++]);
+
+ case '%j':
+ try {
+ return JSON.stringify(args[i++]);
+ } catch (_) {
+ return '[Circular]';
+ }
+
+ break;
+
+ default:
+ return x;
+ }
+ });
+
+ for (var arg = args[i]; i < len; arg = args[++i]) {
+ str += " " + arg;
+ }
+
+ return str;
+ }
+
+ return f;
+}
+
+function isNativeStringType(type) {
+ return type === 'string' || type === 'url' || type === 'hex' || type === 'email' || type === 'pattern';
+}
+
+function isEmptyValue(value, type) {
+ if (value === undefined || value === null) {
+ return true;
+ }
+
+ if (type === 'array' && Array.isArray(value) && !value.length) {
+ return true;
+ }
+
+ if (isNativeStringType(type) && typeof value === 'string' && !value) {
+ return true;
+ }
+
+ return false;
+}
+
+function asyncParallelArray(arr, func, callback) {
+ var results = [];
+ var total = 0;
+ var arrLength = arr.length;
+
+ function count(errors) {
+ results.push.apply(results, errors);
+ total++;
+
+ if (total === arrLength) {
+ callback(results);
+ }
+ }
+
+ arr.forEach(function(a) {
+ func(a, count);
+ });
+}
+
+function asyncSerialArray(arr, func, callback) {
+ var index = 0;
+ var arrLength = arr.length;
+
+ function next(errors) {
+ if (errors && errors.length) {
+ callback(errors);
+ return;
+ }
+
+ var original = index;
+ index = index + 1;
+
+ if (original < arrLength) {
+ func(arr[original], next);
+ } else {
+ callback([]);
+ }
+ }
+
+ next([]);
+}
+
+function flattenObjArr(objArr) {
+ var ret = [];
+ Object.keys(objArr).forEach(function(k) {
+ ret.push.apply(ret, objArr[k]);
+ });
+ return ret;
+}
+
+function asyncMap(objArr, option, func, callback) {
+ if (option.first) {
+ var _pending = new Promise(function(resolve, reject) {
+ var next = function next(errors) {
+ callback(errors);
+ return errors.length ? reject({
+ errors: errors,
+ fields: convertFieldsError(errors)
+ }) : resolve();
+ };
+
+ var flattenArr = flattenObjArr(objArr);
+ asyncSerialArray(flattenArr, func, next);
+ });
+
+ _pending["catch"](function(e) {
+ return e;
+ });
+
+ return _pending;
+ }
+
+ var firstFields = option.firstFields || [];
+
+ if (firstFields === true) {
+ firstFields = Object.keys(objArr);
+ }
+
+ var objArrKeys = Object.keys(objArr);
+ var objArrLength = objArrKeys.length;
+ var total = 0;
+ var results = [];
+ var pending = new Promise(function(resolve, reject) {
+ var next = function next(errors) {
+ results.push.apply(results, errors);
+ total++;
+
+ if (total === objArrLength) {
+ callback(results);
+ return results.length ? reject({
+ errors: results,
+ fields: convertFieldsError(results)
+ }) : resolve();
+ }
+ };
+
+ if (!objArrKeys.length) {
+ callback(results);
+ resolve();
+ }
+
+ objArrKeys.forEach(function(key) {
+ var arr = objArr[key];
+
+ if (firstFields.indexOf(key) !== -1) {
+ asyncSerialArray(arr, func, next);
+ } else {
+ asyncParallelArray(arr, func, next);
+ }
+ });
+ });
+ pending["catch"](function(e) {
+ return e;
+ });
+ return pending;
+}
+
+function complementError(rule) {
+ return function(oe) {
+ if (oe && oe.message) {
+ oe.field = oe.field || rule.fullField;
+ return oe;
+ }
+
+ return {
+ message: typeof oe === 'function' ? oe() : oe,
+ field: oe.field || rule.fullField
+ };
+ };
+}
+
+function deepMerge(target, source) {
+ if (source) {
+ for (var s in source) {
+ if (source.hasOwnProperty(s)) {
+ var value = source[s];
+
+ if (typeof value === 'object' && typeof target[s] === 'object') {
+ target[s] = _extends({}, target[s], {}, value);
+ } else {
+ target[s] = value;
+ }
+ }
+ }
+ }
+
+ return target;
+}
+
+/**
+ * Rule for validating required fields.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param source The source object being validated.
+ * @param errors An array of errors that this rule may add
+ * validation errors to.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function required(rule, value, source, errors, options, type) {
+ if (rule.required && (!source.hasOwnProperty(rule.field) || isEmptyValue(value, type || rule.type))) {
+ errors.push(format(options.messages.required, rule.fullField));
+ }
+}
+
+/**
+ * Rule for validating whitespace.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param source The source object being validated.
+ * @param errors An array of errors that this rule may add
+ * validation errors to.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function whitespace(rule, value, source, errors, options) {
+ if (/^\s+$/.test(value) || value === '') {
+ errors.push(format(options.messages.whitespace, rule.fullField));
+ }
+}
+
+/* eslint max-len:0 */
+
+var pattern = {
+ // http://emailregex.com/
+ email: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
+ url: new RegExp(
+ "^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$",
+ 'i'),
+ hex: /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i
+};
+var types = {
+ integer: function integer(value) {
+ return types.number(value) && parseInt(value, 10) === value;
+ },
+ "float": function float(value) {
+ return types.number(value) && !types.integer(value);
+ },
+ array: function array(value) {
+ return Array.isArray(value);
+ },
+ regexp: function regexp(value) {
+ if (value instanceof RegExp) {
+ return true;
+ }
+
+ try {
+ return !!new RegExp(value);
+ } catch (e) {
+ return false;
+ }
+ },
+ date: function date(value) {
+ return typeof value.getTime === 'function' && typeof value.getMonth === 'function' && typeof value.getYear ===
+ 'function';
+ },
+ number: function number(value) {
+ if (isNaN(value)) {
+ return false;
+ }
+
+ // 修改源码,将字符串数值先转为数值
+ return typeof +value === 'number';
+ },
+ object: function object(value) {
+ return typeof value === 'object' && !types.array(value);
+ },
+ method: function method(value) {
+ return typeof value === 'function';
+ },
+ email: function email(value) {
+ return typeof value === 'string' && !!value.match(pattern.email) && value.length < 255;
+ },
+ url: function url(value) {
+ return typeof value === 'string' && !!value.match(pattern.url);
+ },
+ hex: function hex(value) {
+ return typeof value === 'string' && !!value.match(pattern.hex);
+ }
+};
+/**
+ * Rule for validating the type of a value.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param source The source object being validated.
+ * @param errors An array of errors that this rule may add
+ * validation errors to.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function type(rule, value, source, errors, options) {
+ if (rule.required && value === undefined) {
+ required(rule, value, source, errors, options);
+ return;
+ }
+
+ var custom = ['integer', 'float', 'array', 'regexp', 'object', 'method', 'email', 'number', 'date', 'url', 'hex'];
+ var ruleType = rule.type;
+
+ if (custom.indexOf(ruleType) > -1) {
+ if (!types[ruleType](value)) {
+ errors.push(format(options.messages.types[ruleType], rule.fullField, rule.type));
+ } // straight typeof check
+
+ } else if (ruleType && typeof value !== rule.type) {
+ errors.push(format(options.messages.types[ruleType], rule.fullField, rule.type));
+ }
+}
+
+/**
+ * Rule for validating minimum and maximum allowed values.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param source The source object being validated.
+ * @param errors An array of errors that this rule may add
+ * validation errors to.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function range(rule, value, source, errors, options) {
+ var len = typeof rule.len === 'number';
+ var min = typeof rule.min === 'number';
+ var max = typeof rule.max === 'number'; // 正则匹配码点范围从U+010000一直到U+10FFFF的文字(补充平面Supplementary Plane)
+
+ var spRegexp = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
+ var val = value;
+ var key = null;
+ var num = typeof value === 'number';
+ var str = typeof value === 'string';
+ var arr = Array.isArray(value);
+
+ if (num) {
+ key = 'number';
+ } else if (str) {
+ key = 'string';
+ } else if (arr) {
+ key = 'array';
+ } // if the value is not of a supported type for range validation
+ // the validation rule rule should use the
+ // type property to also test for a particular type
+
+
+ if (!key) {
+ return false;
+ }
+
+ if (arr) {
+ val = value.length;
+ }
+
+ if (str) {
+ // 处理码点大于U+010000的文字length属性不准确的bug,如"𠮷𠮷𠮷".lenght !== 3
+ val = value.replace(spRegexp, '_').length;
+ }
+
+ if (len) {
+ if (val !== rule.len) {
+ errors.push(format(options.messages[key].len, rule.fullField, rule.len));
+ }
+ } else if (min && !max && val < rule.min) {
+ errors.push(format(options.messages[key].min, rule.fullField, rule.min));
+ } else if (max && !min && val > rule.max) {
+ errors.push(format(options.messages[key].max, rule.fullField, rule.max));
+ } else if (min && max && (val < rule.min || val > rule.max)) {
+ errors.push(format(options.messages[key].range, rule.fullField, rule.min, rule.max));
+ }
+}
+
+var ENUM = 'enum';
+/**
+ * Rule for validating a value exists in an enumerable list.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param source The source object being validated.
+ * @param errors An array of errors that this rule may add
+ * validation errors to.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function enumerable(rule, value, source, errors, options) {
+ rule[ENUM] = Array.isArray(rule[ENUM]) ? rule[ENUM] : [];
+
+ if (rule[ENUM].indexOf(value) === -1) {
+ errors.push(format(options.messages[ENUM], rule.fullField, rule[ENUM].join(', ')));
+ }
+}
+
+/**
+ * Rule for validating a regular expression pattern.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param source The source object being validated.
+ * @param errors An array of errors that this rule may add
+ * validation errors to.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function pattern$1(rule, value, source, errors, options) {
+ if (rule.pattern) {
+ if (rule.pattern instanceof RegExp) {
+ // if a RegExp instance is passed, reset `lastIndex` in case its `global`
+ // flag is accidentally set to `true`, which in a validation scenario
+ // is not necessary and the result might be misleading
+ rule.pattern.lastIndex = 0;
+
+ if (!rule.pattern.test(value)) {
+ errors.push(format(options.messages.pattern.mismatch, rule.fullField, value, rule.pattern));
+ }
+ } else if (typeof rule.pattern === 'string') {
+ var _pattern = new RegExp(rule.pattern);
+
+ if (!_pattern.test(value)) {
+ errors.push(format(options.messages.pattern.mismatch, rule.fullField, value, rule.pattern));
+ }
+ }
+ }
+}
+
+var rules = {
+ required: required,
+ whitespace: whitespace,
+ type: type,
+ range: range,
+ "enum": enumerable,
+ pattern: pattern$1
+};
+
+/**
+ * Performs validation for string types.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function string(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value, 'string') && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options, 'string');
+
+ if (!isEmptyValue(value, 'string')) {
+ rules.type(rule, value, source, errors, options);
+ rules.range(rule, value, source, errors, options);
+ rules.pattern(rule, value, source, errors, options);
+
+ if (rule.whitespace === true) {
+ rules.whitespace(rule, value, source, errors, options);
+ }
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Validates a function.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function method(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (value !== undefined) {
+ rules.type(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Validates a number.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function number(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (value === '') {
+ value = undefined;
+ }
+
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (value !== undefined) {
+ rules.type(rule, value, source, errors, options);
+ rules.range(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Validates a boolean.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function _boolean(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (value !== undefined) {
+ rules.type(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Validates the regular expression type.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function regexp(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (!isEmptyValue(value)) {
+ rules.type(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Validates a number is an integer.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function integer(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (value !== undefined) {
+ rules.type(rule, value, source, errors, options);
+ rules.range(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Validates a number is a floating point number.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function floatFn(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (value !== undefined) {
+ rules.type(rule, value, source, errors, options);
+ rules.range(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Validates an array.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function array(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value, 'array') && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options, 'array');
+
+ if (!isEmptyValue(value, 'array')) {
+ rules.type(rule, value, source, errors, options);
+ rules.range(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Validates an object.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function object(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (value !== undefined) {
+ rules.type(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+var ENUM$1 = 'enum';
+/**
+ * Validates an enumerable list.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function enumerable$1(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (value !== undefined) {
+ rules[ENUM$1](rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Validates a regular expression pattern.
+ *
+ * Performs validation when a rule only contains
+ * a pattern property but is not declared as a string type.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function pattern$2(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value, 'string') && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (!isEmptyValue(value, 'string')) {
+ rules.pattern(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+function date(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+
+ if (!isEmptyValue(value)) {
+ var dateObject;
+
+ if (typeof value === 'number') {
+ dateObject = new Date(value);
+ } else {
+ dateObject = value;
+ }
+
+ rules.type(rule, dateObject, source, errors, options);
+
+ if (dateObject) {
+ rules.range(rule, dateObject.getTime(), source, errors, options);
+ }
+ }
+ }
+
+ callback(errors);
+}
+
+function required$1(rule, value, callback, source, options) {
+ var errors = [];
+ var type = Array.isArray(value) ? 'array' : typeof value;
+ rules.required(rule, value, source, errors, options, type);
+ callback(errors);
+}
+
+function type$1(rule, value, callback, source, options) {
+ var ruleType = rule.type;
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value, ruleType) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options, ruleType);
+
+ if (!isEmptyValue(value, ruleType)) {
+ rules.type(rule, value, source, errors, options);
+ }
+ }
+
+ callback(errors);
+}
+
+/**
+ * Performs validation for any type.
+ *
+ * @param rule The validation rule.
+ * @param value The value of the field on the source object.
+ * @param callback The callback function.
+ * @param source The source object being validated.
+ * @param options The validation options.
+ * @param options.messages The validation messages.
+ */
+
+function any(rule, value, callback, source, options) {
+ var errors = [];
+ var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
+
+ if (validate) {
+ if (isEmptyValue(value) && !rule.required) {
+ return callback();
+ }
+
+ rules.required(rule, value, source, errors, options);
+ }
+
+ callback(errors);
+}
+
+var validators = {
+ string: string,
+ method: method,
+ number: number,
+ "boolean": _boolean,
+ regexp: regexp,
+ integer: integer,
+ "float": floatFn,
+ array: array,
+ object: object,
+ "enum": enumerable$1,
+ pattern: pattern$2,
+ date: date,
+ url: type$1,
+ hex: type$1,
+ email: type$1,
+ required: required$1,
+ any: any
+};
+
+function newMessages() {
+ return {
+ "default": 'Validation error on field %s',
+ required: '%s is required',
+ "enum": '%s must be one of %s',
+ whitespace: '%s cannot be empty',
+ date: {
+ format: '%s date %s is invalid for format %s',
+ parse: '%s date could not be parsed, %s is invalid ',
+ invalid: '%s date %s is invalid'
+ },
+ types: {
+ string: '%s is not a %s',
+ method: '%s is not a %s (function)',
+ array: '%s is not an %s',
+ object: '%s is not an %s',
+ number: '%s is not a %s',
+ date: '%s is not a %s',
+ "boolean": '%s is not a %s',
+ integer: '%s is not an %s',
+ "float": '%s is not a %s',
+ regexp: '%s is not a valid %s',
+ email: '%s is not a valid %s',
+ url: '%s is not a valid %s',
+ hex: '%s is not a valid %s'
+ },
+ string: {
+ len: '%s must be exactly %s characters',
+ min: '%s must be at least %s characters',
+ max: '%s cannot be longer than %s characters',
+ range: '%s must be between %s and %s characters'
+ },
+ number: {
+ len: '%s must equal %s',
+ min: '%s cannot be less than %s',
+ max: '%s cannot be greater than %s',
+ range: '%s must be between %s and %s'
+ },
+ array: {
+ len: '%s must be exactly %s in length',
+ min: '%s cannot be less than %s in length',
+ max: '%s cannot be greater than %s in length',
+ range: '%s must be between %s and %s in length'
+ },
+ pattern: {
+ mismatch: '%s value %s does not match pattern %s'
+ },
+ clone: function clone() {
+ var cloned = JSON.parse(JSON.stringify(this));
+ cloned.clone = this.clone;
+ return cloned;
+ }
+ };
+}
+var messages = newMessages();
+
+/**
+ * Encapsulates a validation schema.
+ *
+ * @param descriptor An object declaring validation rules
+ * for this schema.
+ */
+
+function Schema(descriptor) {
+ this.rules = null;
+ this._messages = messages;
+ this.define(descriptor);
+}
+
+Schema.prototype = {
+ messages: function messages(_messages) {
+ if (_messages) {
+ this._messages = deepMerge(newMessages(), _messages);
+ }
+
+ return this._messages;
+ },
+ define: function define(rules) {
+ if (!rules) {
+ throw new Error('Cannot configure a schema with no rules');
+ }
+
+ if (typeof rules !== 'object' || Array.isArray(rules)) {
+ throw new Error('Rules must be an object');
+ }
+
+ this.rules = {};
+ var z;
+ var item;
+
+ for (z in rules) {
+ if (rules.hasOwnProperty(z)) {
+ item = rules[z];
+ this.rules[z] = Array.isArray(item) ? item : [item];
+ }
+ }
+ },
+ validate: function validate(source_, o, oc) {
+ var _this = this;
+
+ if (o === void 0) {
+ o = {};
+ }
+
+ if (oc === void 0) {
+ oc = function oc() {};
+ }
+
+ var source = source_;
+ var options = o;
+ var callback = oc;
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ if (!this.rules || Object.keys(this.rules).length === 0) {
+ if (callback) {
+ callback();
+ }
+
+ return Promise.resolve();
+ }
+
+ function complete(results) {
+ var i;
+ var errors = [];
+ var fields = {};
+
+ function add(e) {
+ if (Array.isArray(e)) {
+ var _errors;
+
+ errors = (_errors = errors).concat.apply(_errors, e);
+ } else {
+ errors.push(e);
+ }
+ }
+
+ for (i = 0; i < results.length; i++) {
+ add(results[i]);
+ }
+
+ if (!errors.length) {
+ errors = null;
+ fields = null;
+ } else {
+ fields = convertFieldsError(errors);
+ }
+
+ callback(errors, fields);
+ }
+
+ if (options.messages) {
+ var messages$1 = this.messages();
+
+ if (messages$1 === messages) {
+ messages$1 = newMessages();
+ }
+
+ deepMerge(messages$1, options.messages);
+ options.messages = messages$1;
+ } else {
+ options.messages = this.messages();
+ }
+
+ var arr;
+ var value;
+ var series = {};
+ var keys = options.keys || Object.keys(this.rules);
+ keys.forEach(function(z) {
+ arr = _this.rules[z];
+ value = source[z];
+ arr.forEach(function(r) {
+ var rule = r;
+
+ if (typeof rule.transform === 'function') {
+ if (source === source_) {
+ source = _extends({}, source);
+ }
+
+ value = source[z] = rule.transform(value);
+ }
+
+ if (typeof rule === 'function') {
+ rule = {
+ validator: rule
+ };
+ } else {
+ rule = _extends({}, rule);
+ }
+
+ rule.validator = _this.getValidationMethod(rule);
+ rule.field = z;
+ rule.fullField = rule.fullField || z;
+ rule.type = _this.getType(rule);
+
+ if (!rule.validator) {
+ return;
+ }
+
+ series[z] = series[z] || [];
+ series[z].push({
+ rule: rule,
+ value: value,
+ source: source,
+ field: z
+ });
+ });
+ });
+ var errorFields = {};
+ return asyncMap(series, options, function(data, doIt) {
+ var rule = data.rule;
+ var deep = (rule.type === 'object' || rule.type === 'array') && (typeof rule.fields === 'object' || typeof rule.defaultField ===
+ 'object');
+ deep = deep && (rule.required || !rule.required && data.value);
+ rule.field = data.field;
+
+ function addFullfield(key, schema) {
+ return _extends({}, schema, {
+ fullField: rule.fullField + "." + key
+ });
+ }
+
+ function cb(e) {
+ if (e === void 0) {
+ e = [];
+ }
+
+ var errors = e;
+
+ if (!Array.isArray(errors)) {
+ errors = [errors];
+ }
+
+ if (!options.suppressWarning && errors.length) {
+ Schema.warning('async-validator:', errors);
+ }
+
+ if (errors.length && rule.message) {
+ errors = [].concat(rule.message);
+ }
+
+ errors = errors.map(complementError(rule));
+
+ if (options.first && errors.length) {
+ errorFields[rule.field] = 1;
+ return doIt(errors);
+ }
+
+ if (!deep) {
+ doIt(errors);
+ } else {
+ // if rule is required but the target object
+ // does not exist fail at the rule level and don't
+ // go deeper
+ if (rule.required && !data.value) {
+ if (rule.message) {
+ errors = [].concat(rule.message).map(complementError(rule));
+ } else if (options.error) {
+ errors = [options.error(rule, format(options.messages.required, rule.field))];
+ } else {
+ errors = [];
+ }
+
+ return doIt(errors);
+ }
+
+ var fieldsSchema = {};
+
+ if (rule.defaultField) {
+ for (var k in data.value) {
+ if (data.value.hasOwnProperty(k)) {
+ fieldsSchema[k] = rule.defaultField;
+ }
+ }
+ }
+
+ fieldsSchema = _extends({}, fieldsSchema, {}, data.rule.fields);
+
+ for (var f in fieldsSchema) {
+ if (fieldsSchema.hasOwnProperty(f)) {
+ var fieldSchema = Array.isArray(fieldsSchema[f]) ? fieldsSchema[f] : [fieldsSchema[f]];
+ fieldsSchema[f] = fieldSchema.map(addFullfield.bind(null, f));
+ }
+ }
+
+ var schema = new Schema(fieldsSchema);
+ schema.messages(options.messages);
+
+ if (data.rule.options) {
+ data.rule.options.messages = options.messages;
+ data.rule.options.error = options.error;
+ }
+
+ schema.validate(data.value, data.rule.options || options, function(errs) {
+ var finalErrors = [];
+
+ if (errors && errors.length) {
+ finalErrors.push.apply(finalErrors, errors);
+ }
+
+ if (errs && errs.length) {
+ finalErrors.push.apply(finalErrors, errs);
+ }
+
+ doIt(finalErrors.length ? finalErrors : null);
+ });
+ }
+ }
+
+ var res;
+
+ if (rule.asyncValidator) {
+ res = rule.asyncValidator(rule, data.value, cb, data.source, options);
+ } else if (rule.validator) {
+ res = rule.validator(rule, data.value, cb, data.source, options);
+
+ if (res === true) {
+ cb();
+ } else if (res === false) {
+ cb(rule.message || rule.field + " fails");
+ } else if (res instanceof Array) {
+ cb(res);
+ } else if (res instanceof Error) {
+ cb(res.message);
+ }
+ }
+
+ if (res && res.then) {
+ res.then(function() {
+ return cb();
+ }, function(e) {
+ return cb(e);
+ });
+ }
+ }, function(results) {
+ complete(results);
+ });
+ },
+ getType: function getType(rule) {
+ if (rule.type === undefined && rule.pattern instanceof RegExp) {
+ rule.type = 'pattern';
+ }
+
+ if (typeof rule.validator !== 'function' && rule.type && !validators.hasOwnProperty(rule.type)) {
+ throw new Error(format('Unknown rule type %s', rule.type));
+ }
+
+ return rule.type || 'string';
+ },
+ getValidationMethod: function getValidationMethod(rule) {
+ if (typeof rule.validator === 'function') {
+ return rule.validator;
+ }
+
+ var keys = Object.keys(rule);
+ var messageIndex = keys.indexOf('message');
+
+ if (messageIndex !== -1) {
+ keys.splice(messageIndex, 1);
+ }
+
+ if (keys.length === 1 && keys[0] === 'required') {
+ return validators.required;
+ }
+
+ return validators[this.getType(rule)] || false;
+ }
+};
+
+Schema.register = function register(type, validator) {
+ if (typeof validator !== 'function') {
+ throw new Error('Cannot register a validator by type, validator is not a function');
+ }
+
+ validators[type] = validator;
+};
+
+Schema.warning = warning;
+Schema.messages = messages;
+
+export default Schema;
+//# sourceMappingURL=index.js.map
diff --git a/hotgo-uniapp/uview-ui/libs/util/city.js b/hotgo-uniapp/uview-ui/libs/util/city.js
new file mode 100644
index 0000000..94169eb
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/util/city.js
@@ -0,0 +1 @@
+var cityData=[[{"label":"市辖区","value":"1101"}],[{"label":"市辖区","value":"1201"}],[{"label":"石家庄市","value":"1301"},{"label":"唐山市","value":"1302"},{"label":"秦皇岛市","value":"1303"},{"label":"邯郸市","value":"1304"},{"label":"邢台市","value":"1305"},{"label":"保定市","value":"1306"},{"label":"张家口市","value":"1307"},{"label":"承德市","value":"1308"},{"label":"沧州市","value":"1309"},{"label":"廊坊市","value":"1310"},{"label":"衡水市","value":"1311"}],[{"label":"太原市","value":"1401"},{"label":"大同市","value":"1402"},{"label":"阳泉市","value":"1403"},{"label":"长治市","value":"1404"},{"label":"晋城市","value":"1405"},{"label":"朔州市","value":"1406"},{"label":"晋中市","value":"1407"},{"label":"运城市","value":"1408"},{"label":"忻州市","value":"1409"},{"label":"临汾市","value":"1410"},{"label":"吕梁市","value":"1411"}],[{"label":"呼和浩特市","value":"1501"},{"label":"包头市","value":"1502"},{"label":"乌海市","value":"1503"},{"label":"赤峰市","value":"1504"},{"label":"通辽市","value":"1505"},{"label":"鄂尔多斯市","value":"1506"},{"label":"呼伦贝尔市","value":"1507"},{"label":"巴彦淖尔市","value":"1508"},{"label":"乌兰察布市","value":"1509"},{"label":"兴安盟","value":"1522"},{"label":"锡林郭勒盟","value":"1525"},{"label":"阿拉善盟","value":"1529"}],[{"label":"沈阳市","value":"2101"},{"label":"大连市","value":"2102"},{"label":"鞍山市","value":"2103"},{"label":"抚顺市","value":"2104"},{"label":"本溪市","value":"2105"},{"label":"丹东市","value":"2106"},{"label":"锦州市","value":"2107"},{"label":"营口市","value":"2108"},{"label":"阜新市","value":"2109"},{"label":"辽阳市","value":"2110"},{"label":"盘锦市","value":"2111"},{"label":"铁岭市","value":"2112"},{"label":"朝阳市","value":"2113"},{"label":"葫芦岛市","value":"2114"}],[{"label":"长春市","value":"2201"},{"label":"吉林市","value":"2202"},{"label":"四平市","value":"2203"},{"label":"辽源市","value":"2204"},{"label":"通化市","value":"2205"},{"label":"白山市","value":"2206"},{"label":"松原市","value":"2207"},{"label":"白城市","value":"2208"},{"label":"延边朝鲜族自治州","value":"2224"}],[{"label":"哈尔滨市","value":"2301"},{"label":"齐齐哈尔市","value":"2302"},{"label":"鸡西市","value":"2303"},{"label":"鹤岗市","value":"2304"},{"label":"双鸭山市","value":"2305"},{"label":"大庆市","value":"2306"},{"label":"伊春市","value":"2307"},{"label":"佳木斯市","value":"2308"},{"label":"七台河市","value":"2309"},{"label":"牡丹江市","value":"2310"},{"label":"黑河市","value":"2311"},{"label":"绥化市","value":"2312"},{"label":"大兴安岭地区","value":"2327"}],[{"label":"市辖区","value":"3101"}],[{"label":"南京市","value":"3201"},{"label":"无锡市","value":"3202"},{"label":"徐州市","value":"3203"},{"label":"常州市","value":"3204"},{"label":"苏州市","value":"3205"},{"label":"南通市","value":"3206"},{"label":"连云港市","value":"3207"},{"label":"淮安市","value":"3208"},{"label":"盐城市","value":"3209"},{"label":"扬州市","value":"3210"},{"label":"镇江市","value":"3211"},{"label":"泰州市","value":"3212"},{"label":"宿迁市","value":"3213"}],[{"label":"杭州市","value":"3301"},{"label":"宁波市","value":"3302"},{"label":"温州市","value":"3303"},{"label":"嘉兴市","value":"3304"},{"label":"湖州市","value":"3305"},{"label":"绍兴市","value":"3306"},{"label":"金华市","value":"3307"},{"label":"衢州市","value":"3308"},{"label":"舟山市","value":"3309"},{"label":"台州市","value":"3310"},{"label":"丽水市","value":"3311"}],[{"label":"合肥市","value":"3401"},{"label":"芜湖市","value":"3402"},{"label":"蚌埠市","value":"3403"},{"label":"淮南市","value":"3404"},{"label":"马鞍山市","value":"3405"},{"label":"淮北市","value":"3406"},{"label":"铜陵市","value":"3407"},{"label":"安庆市","value":"3408"},{"label":"黄山市","value":"3410"},{"label":"滁州市","value":"3411"},{"label":"阜阳市","value":"3412"},{"label":"宿州市","value":"3413"},{"label":"六安市","value":"3415"},{"label":"亳州市","value":"3416"},{"label":"池州市","value":"3417"},{"label":"宣城市","value":"3418"}],[{"label":"福州市","value":"3501"},{"label":"厦门市","value":"3502"},{"label":"莆田市","value":"3503"},{"label":"三明市","value":"3504"},{"label":"泉州市","value":"3505"},{"label":"漳州市","value":"3506"},{"label":"南平市","value":"3507"},{"label":"龙岩市","value":"3508"},{"label":"宁德市","value":"3509"}],[{"label":"南昌市","value":"3601"},{"label":"景德镇市","value":"3602"},{"label":"萍乡市","value":"3603"},{"label":"九江市","value":"3604"},{"label":"新余市","value":"3605"},{"label":"鹰潭市","value":"3606"},{"label":"赣州市","value":"3607"},{"label":"吉安市","value":"3608"},{"label":"宜春市","value":"3609"},{"label":"抚州市","value":"3610"},{"label":"上饶市","value":"3611"}],[{"label":"济南市","value":"3701"},{"label":"青岛市","value":"3702"},{"label":"淄博市","value":"3703"},{"label":"枣庄市","value":"3704"},{"label":"东营市","value":"3705"},{"label":"烟台市","value":"3706"},{"label":"潍坊市","value":"3707"},{"label":"济宁市","value":"3708"},{"label":"泰安市","value":"3709"},{"label":"威海市","value":"3710"},{"label":"日照市","value":"3711"},{"label":"莱芜市","value":"3712"},{"label":"临沂市","value":"3713"},{"label":"德州市","value":"3714"},{"label":"聊城市","value":"3715"},{"label":"滨州市","value":"3716"},{"label":"菏泽市","value":"3717"}],[{"label":"郑州市","value":"4101"},{"label":"开封市","value":"4102"},{"label":"洛阳市","value":"4103"},{"label":"平顶山市","value":"4104"},{"label":"安阳市","value":"4105"},{"label":"鹤壁市","value":"4106"},{"label":"新乡市","value":"4107"},{"label":"焦作市","value":"4108"},{"label":"濮阳市","value":"4109"},{"label":"许昌市","value":"4110"},{"label":"漯河市","value":"4111"},{"label":"三门峡市","value":"4112"},{"label":"南阳市","value":"4113"},{"label":"商丘市","value":"4114"},{"label":"信阳市","value":"4115"},{"label":"周口市","value":"4116"},{"label":"驻马店市","value":"4117"},{"label":"省直辖县级行政区划","value":"4190"}],[{"label":"武汉市","value":"4201"},{"label":"黄石市","value":"4202"},{"label":"十堰市","value":"4203"},{"label":"宜昌市","value":"4205"},{"label":"襄阳市","value":"4206"},{"label":"鄂州市","value":"4207"},{"label":"荆门市","value":"4208"},{"label":"孝感市","value":"4209"},{"label":"荆州市","value":"4210"},{"label":"黄冈市","value":"4211"},{"label":"咸宁市","value":"4212"},{"label":"随州市","value":"4213"},{"label":"恩施土家族苗族自治州","value":"4228"},{"label":"省直辖县级行政区划","value":"4290"}],[{"label":"长沙市","value":"4301"},{"label":"株洲市","value":"4302"},{"label":"湘潭市","value":"4303"},{"label":"衡阳市","value":"4304"},{"label":"邵阳市","value":"4305"},{"label":"岳阳市","value":"4306"},{"label":"常德市","value":"4307"},{"label":"张家界市","value":"4308"},{"label":"益阳市","value":"4309"},{"label":"郴州市","value":"4310"},{"label":"永州市","value":"4311"},{"label":"怀化市","value":"4312"},{"label":"娄底市","value":"4313"},{"label":"湘西土家族苗族自治州","value":"4331"}],[{"label":"广州市","value":"4401"},{"label":"韶关市","value":"4402"},{"label":"深圳市","value":"4403"},{"label":"珠海市","value":"4404"},{"label":"汕头市","value":"4405"},{"label":"佛山市","value":"4406"},{"label":"江门市","value":"4407"},{"label":"湛江市","value":"4408"},{"label":"茂名市","value":"4409"},{"label":"肇庆市","value":"4412"},{"label":"惠州市","value":"4413"},{"label":"梅州市","value":"4414"},{"label":"汕尾市","value":"4415"},{"label":"河源市","value":"4416"},{"label":"阳江市","value":"4417"},{"label":"清远市","value":"4418"},{"label":"东莞市","value":"4419"},{"label":"中山市","value":"4420"},{"label":"潮州市","value":"4451"},{"label":"揭阳市","value":"4452"},{"label":"云浮市","value":"4453"}],[{"label":"南宁市","value":"4501"},{"label":"柳州市","value":"4502"},{"label":"桂林市","value":"4503"},{"label":"梧州市","value":"4504"},{"label":"北海市","value":"4505"},{"label":"防城港市","value":"4506"},{"label":"钦州市","value":"4507"},{"label":"贵港市","value":"4508"},{"label":"玉林市","value":"4509"},{"label":"百色市","value":"4510"},{"label":"贺州市","value":"4511"},{"label":"河池市","value":"4512"},{"label":"来宾市","value":"4513"},{"label":"崇左市","value":"4514"}],[{"label":"海口市","value":"4601"},{"label":"三亚市","value":"4602"},{"label":"三沙市","value":"4603"},{"label":"儋州市","value":"4604"},{"label":"省直辖县级行政区划","value":"4690"}],[{"label":"市辖区","value":"5001"},{"label":"县","value":"5002"}],[{"label":"成都市","value":"5101"},{"label":"自贡市","value":"5103"},{"label":"攀枝花市","value":"5104"},{"label":"泸州市","value":"5105"},{"label":"德阳市","value":"5106"},{"label":"绵阳市","value":"5107"},{"label":"广元市","value":"5108"},{"label":"遂宁市","value":"5109"},{"label":"内江市","value":"5110"},{"label":"乐山市","value":"5111"},{"label":"南充市","value":"5113"},{"label":"眉山市","value":"5114"},{"label":"宜宾市","value":"5115"},{"label":"广安市","value":"5116"},{"label":"达州市","value":"5117"},{"label":"雅安市","value":"5118"},{"label":"巴中市","value":"5119"},{"label":"资阳市","value":"5120"},{"label":"阿坝藏族羌族自治州","value":"5132"},{"label":"甘孜藏族自治州","value":"5133"},{"label":"凉山彝族自治州","value":"5134"}],[{"label":"贵阳市","value":"5201"},{"label":"六盘水市","value":"5202"},{"label":"遵义市","value":"5203"},{"label":"安顺市","value":"5204"},{"label":"毕节市","value":"5205"},{"label":"铜仁市","value":"5206"},{"label":"黔西南布依族苗族自治州","value":"5223"},{"label":"黔东南苗族侗族自治州","value":"5226"},{"label":"黔南布依族苗族自治州","value":"5227"}],[{"label":"昆明市","value":"5301"},{"label":"曲靖市","value":"5303"},{"label":"玉溪市","value":"5304"},{"label":"保山市","value":"5305"},{"label":"昭通市","value":"5306"},{"label":"丽江市","value":"5307"},{"label":"普洱市","value":"5308"},{"label":"临沧市","value":"5309"},{"label":"楚雄彝族自治州","value":"5323"},{"label":"红河哈尼族彝族自治州","value":"5325"},{"label":"文山壮族苗族自治州","value":"5326"},{"label":"西双版纳傣族自治州","value":"5328"},{"label":"大理白族自治州","value":"5329"},{"label":"德宏傣族景颇族自治州","value":"5331"},{"label":"怒江傈僳族自治州","value":"5333"},{"label":"迪庆藏族自治州","value":"5334"}],[{"label":"拉萨市","value":"5401"},{"label":"日喀则市","value":"5402"},{"label":"昌都市","value":"5403"},{"label":"林芝市","value":"5404"},{"label":"山南市","value":"5405"},{"label":"那曲地区","value":"5424"},{"label":"阿里地区","value":"5425"}],[{"label":"西安市","value":"6101"},{"label":"铜川市","value":"6102"},{"label":"宝鸡市","value":"6103"},{"label":"咸阳市","value":"6104"},{"label":"渭南市","value":"6105"},{"label":"延安市","value":"6106"},{"label":"汉中市","value":"6107"},{"label":"榆林市","value":"6108"},{"label":"安康市","value":"6109"},{"label":"商洛市","value":"6110"}],[{"label":"兰州市","value":"6201"},{"label":"嘉峪关市","value":"6202"},{"label":"金昌市","value":"6203"},{"label":"白银市","value":"6204"},{"label":"天水市","value":"6205"},{"label":"武威市","value":"6206"},{"label":"张掖市","value":"6207"},{"label":"平凉市","value":"6208"},{"label":"酒泉市","value":"6209"},{"label":"庆阳市","value":"6210"},{"label":"定西市","value":"6211"},{"label":"陇南市","value":"6212"},{"label":"临夏回族自治州","value":"6229"},{"label":"甘南藏族自治州","value":"6230"}],[{"label":"西宁市","value":"6301"},{"label":"海东市","value":"6302"},{"label":"海北藏族自治州","value":"6322"},{"label":"黄南藏族自治州","value":"6323"},{"label":"海南藏族自治州","value":"6325"},{"label":"果洛藏族自治州","value":"6326"},{"label":"玉树藏族自治州","value":"6327"},{"label":"海西蒙古族藏族自治州","value":"6328"}],[{"label":"银川市","value":"6401"},{"label":"石嘴山市","value":"6402"},{"label":"吴忠市","value":"6403"},{"label":"固原市","value":"6404"},{"label":"中卫市","value":"6405"}],[{"label":"乌鲁木齐市","value":"6501"},{"label":"克拉玛依市","value":"6502"},{"label":"吐鲁番市","value":"6504"},{"label":"哈密市","value":"6505"},{"label":"昌吉回族自治州","value":"6523"},{"label":"博尔塔拉蒙古自治州","value":"6527"},{"label":"巴音郭楞蒙古自治州","value":"6528"},{"label":"阿克苏地区","value":"6529"},{"label":"克孜勒苏柯尔克孜自治州","value":"6530"},{"label":"喀什地区","value":"6531"},{"label":"和田地区","value":"6532"},{"label":"伊犁哈萨克自治州","value":"6540"},{"label":"塔城地区","value":"6542"},{"label":"阿勒泰地区","value":"6543"},{"label":"自治区直辖县级行政区划","value":"6590"}],[{"label":"台北","value":"6601"},{"label":"高雄","value":"6602"},{"label":"基隆","value":"6603"},{"label":"台中","value":"6604"},{"label":"台南","value":"6605"},{"label":"新竹","value":"6606"},{"label":"嘉义","value":"6607"},{"label":"宜兰","value":"6608"},{"label":"桃园","value":"6609"},{"label":"苗栗","value":"6610"},{"label":"彰化","value":"6611"},{"label":"南投","value":"6612"},{"label":"云林","value":"6613"},{"label":"屏东","value":"6614"},{"label":"台东","value":"6615"},{"label":"花莲","value":"6616"},{"label":"澎湖","value":"6617"}],[{"label":"香港岛","value":"6701"},{"label":"九龙","value":"6702"},{"label":"新界","value":"6703"}],[{"label":"澳门半岛","value":"6801"},{"label":"氹仔岛","value":"6802"},{"label":"路环岛","value":"6803"},{"label":"路氹城","value":"6804"}]];export default cityData;
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/libs/util/emitter.js b/hotgo-uniapp/uview-ui/libs/util/emitter.js
new file mode 100644
index 0000000..228016e
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/util/emitter.js
@@ -0,0 +1,51 @@
+/**
+ * 递归使用 call 方式this指向
+ * @param componentName // 需要找的组件的名称
+ * @param eventName // 事件名称
+ * @param params // 需要传递的参数
+ */
+function broadcast(componentName, eventName, params) {
+ // 循环子节点找到名称一样的子节点 否则 递归 当前子节点
+ this.$children.map(child=>{
+ if (componentName===child.$options.name) {
+ child.$emit.apply(child,[eventName].concat(params))
+ }else {
+ broadcast.apply(child,[componentName,eventName].concat(params))
+ }
+ })
+}
+export default {
+ methods: {
+ /**
+ * 派发 (向上查找) (一个)
+ * @param componentName // 需要找的组件的名称
+ * @param eventName // 事件名称
+ * @param params // 需要传递的参数
+ */
+ dispatch(componentName, eventName, params) {
+ let parent = this.$parent || this.$root;//$parent 找到最近的父节点 $root 根节点
+ let name = parent.$options.name; // 获取当前组件实例的name
+ // 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点
+ // 循环出当前名称的一样的组件实例
+ while (parent && (!name||name!==componentName)) {
+ parent = parent.$parent;
+ if (parent) {
+ name = parent.$options.name;
+ }
+ }
+ // 有节点表示当前找到了name一样的实例
+ if (parent) {
+ parent.$emit.apply(parent,[eventName].concat(params))
+ }
+ },
+ /**
+ * 广播 (向下查找) (广播多个)
+ * @param componentName // 需要找的组件的名称
+ * @param eventName // 事件名称
+ * @param params // 需要传递的参数
+ */
+ broadcast(componentName, eventName, params) {
+ broadcast.call(this,componentName, eventName, params)
+ }
+ }
+}
diff --git a/hotgo-uniapp/uview-ui/libs/util/province.js b/hotgo-uniapp/uview-ui/libs/util/province.js
new file mode 100644
index 0000000..436b190
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/libs/util/province.js
@@ -0,0 +1 @@
+var provinceData=[{"label":"北京市","value":"11"},{"label":"天津市","value":"12"},{"label":"河北省","value":"13"},{"label":"山西省","value":"14"},{"label":"内蒙古自治区","value":"15"},{"label":"辽宁省","value":"21"},{"label":"吉林省","value":"22"},{"label":"黑龙江省","value":"23"},{"label":"上海市","value":"31"},{"label":"江苏省","value":"32"},{"label":"浙江省","value":"33"},{"label":"安徽省","value":"34"},{"label":"福建省","value":"35"},{"label":"江西省","value":"36"},{"label":"山东省","value":"37"},{"label":"河南省","value":"41"},{"label":"湖北省","value":"42"},{"label":"湖南省","value":"43"},{"label":"广东省","value":"44"},{"label":"广西壮族自治区","value":"45"},{"label":"海南省","value":"46"},{"label":"重庆市","value":"50"},{"label":"四川省","value":"51"},{"label":"贵州省","value":"52"},{"label":"云南省","value":"53"},{"label":"西藏自治区","value":"54"},{"label":"陕西省","value":"61"},{"label":"甘肃省","value":"62"},{"label":"青海省","value":"63"},{"label":"宁夏回族自治区","value":"64"},{"label":"新疆维吾尔自治区","value":"65"},{"label":"台湾","value":"66"},{"label":"香港","value":"67"},{"label":"澳门","value":"68"}];export default provinceData;
\ No newline at end of file
diff --git a/hotgo-uniapp/uview-ui/package.json b/hotgo-uniapp/uview-ui/package.json
new file mode 100644
index 0000000..dc0767c
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "uview-ui",
+ "version": "1.8.3",
+ "description": "uView UI,是uni-app生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水",
+ "main": "index.js",
+ "keywords": [
+ "uview",
+ "uView",
+ "uni-app",
+ "uni-app ui",
+ "uniapp",
+ "uviewui",
+ "uview ui",
+ "uviewUI",
+ "uViewui",
+ "uViewUI",
+ "uView UI",
+ "uni ui",
+ "uni UI",
+ "uniapp ui",
+ "ui",
+ "UI框架",
+ "uniapp ui框架",
+ "uniapp UI"
+ ],
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": ""
+ },
+ "devDependencies": {
+ "node-sass": "^4.14.0",
+ "sass-loader": "^8.0.2"
+ },
+ "author": "uView",
+ "license": "MIT"
+}
diff --git a/hotgo-uniapp/uview-ui/theme.scss b/hotgo-uniapp/uview-ui/theme.scss
new file mode 100644
index 0000000..f3bb36d
--- /dev/null
+++ b/hotgo-uniapp/uview-ui/theme.scss
@@ -0,0 +1,38 @@
+// 此文件为uView的主题变量,这些变量目前只能通过uni.scss引入才有效,另外由于
+// uni.scss中引入的样式会同时混入到全局样式文件和单独每一个页面的样式中,造成微信程序包太大,
+// 故uni.scss只建议放scss变量名相关样式,其他的样式可以通过main.js或者App.vue引入
+
+$u-main-color: #303133;
+$u-content-color: #606266;
+$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/vue.config.js b/hotgo-uniapp/vue.config.js
new file mode 100644
index 0000000..dc96386
--- /dev/null
+++ b/hotgo-uniapp/vue.config.js
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2013-Now http://jeesite.com All rights reserved.
+ */
+// module.exports = {
+// configureWebpack: {
+// devServer: {
+// port : 8080,
+// disableHostCheck : true,
+// proxy : {
+// "/js" : {
+// // target : "http://127.0.0.1:8980",
+// target : "https://demo.jeesite.com",
+// changeOrigin : true,
+// secure : false
+// }
+// }
+// }
+// },
+// productionSourceMap: false,
+// }
diff --git a/hotgo-web/.browserslistrc b/hotgo-web/.browserslistrc
new file mode 100644
index 0000000..8f96043
--- /dev/null
+++ b/hotgo-web/.browserslistrc
@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not ie <= 10
diff --git a/hotgo-web/.editorconfig b/hotgo-web/.editorconfig
new file mode 100644
index 0000000..6f77dff
--- /dev/null
+++ b/hotgo-web/.editorconfig
@@ -0,0 +1,39 @@
+[*]
+charset=utf-8
+end_of_line=lf
+insert_final_newline=false
+indent_style=space
+indent_size=2
+
+[{*.ng,*.sht,*.html,*.shtm,*.shtml,*.htm}]
+indent_style=space
+indent_size=2
+
+[{*.jhm,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.tld,*.fxml,*.jrxml,*.xml,*.jnlp,*.wsdl}]
+indent_style=space
+indent_size=2
+
+[{.babelrc,.stylelintrc,jest.config,.eslintrc,.prettierrc,*.json,*.jsb3,*.jsb2,*.bowerrc}]
+indent_style=space
+indent_size=2
+
+[*.svg]
+indent_style=space
+indent_size=2
+
+[*.js.map]
+indent_style=space
+indent_size=2
+
+[*.less]
+indent_style=space
+indent_size=2
+
+[*.vue]
+indent_style=space
+indent_size=2
+
+[{.analysis_options,*.yml,*.yaml}]
+indent_style=space
+indent_size=2
+
diff --git a/hotgo-web/.env b/hotgo-web/.env
new file mode 100644
index 0000000..36a9d3d
--- /dev/null
+++ b/hotgo-web/.env
@@ -0,0 +1,3 @@
+NODE_ENV=production
+VUE_APP_PREVIEW=false
+VUE_APP_BASE_API=/admin
\ No newline at end of file
diff --git a/hotgo-web/.env.development b/hotgo-web/.env.development
new file mode 100644
index 0000000..ac40b14
--- /dev/null
+++ b/hotgo-web/.env.development
@@ -0,0 +1,3 @@
+NODE_ENV=development
+VUE_APP_PREVIEW=true
+VUE_APP_BASE_API=/admin
\ No newline at end of file
diff --git a/hotgo-web/.env.preview b/hotgo-web/.env.preview
new file mode 100644
index 0000000..9eec572
--- /dev/null
+++ b/hotgo-web/.env.preview
@@ -0,0 +1,3 @@
+NODE_ENV=production
+VUE_APP_PREVIEW=true
+VUE_APP_BASE_API=/admin
\ No newline at end of file
diff --git a/hotgo-web/.eslintrc.js b/hotgo-web/.eslintrc.js
new file mode 100644
index 0000000..3ae891b
--- /dev/null
+++ b/hotgo-web/.eslintrc.js
@@ -0,0 +1,78 @@
+module.exports = {
+ root: true,
+ env: {
+ node: true
+ },
+ 'extends': [
+ 'plugin:vue/strongly-recommended',
+ '@vue/standard'
+ ],
+ rules: {
+ 'no-console': 'off',
+ "space-before-function-paren": 0,
+ "vue/require-default-prop": "off",
+ "vue/require-prop-types":"off",
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+ 'generator-star-spacing': 'off',
+ 'no-mixed-operators': 0,
+ 'vue/max-attributes-per-line': [
+ 2,
+ {
+ 'singleline': 5,
+ 'multiline': {
+ 'max': 1,
+ 'allowFirstLine': false
+ }
+ }
+ ],
+ 'vue/attribute-hyphenation': 0,
+ 'vue/html-self-closing': 0,
+ 'vue/component-name-in-template-casing': 0,
+ 'vue/html-closing-bracket-spacing': 0,
+ 'vue/singleline-html-element-content-newline': 0,
+ 'vue/no-unused-components': 0,
+ 'vue/multiline-html-element-content-newline': 0,
+ 'vue/no-use-v-if-with-v-for': 0,
+ 'vue/html-closing-bracket-newline': 0,
+ 'vue/no-parsing-error': 0,
+ 'no-tabs': 0,
+ 'quotes': [
+ 2,
+ 'single',
+ {
+ 'avoidEscape': true,
+ 'allowTemplateLiterals': true
+ }
+ ],
+ 'semi': [
+ 2,
+ 'never',
+ {
+ 'beforeStatementContinuationChars': 'never'
+ }
+ ],
+ 'no-delete-var': 2,
+ 'prefer-const': [
+ 2,
+ {
+ 'ignoreReadBeforeAssign': false
+ }
+ ],
+ 'template-curly-spacing': 'off',
+ 'indent': 'off'
+ },
+ parserOptions: {
+ parser: 'babel-eslint'
+ },
+ overrides: [
+ {
+ files: [
+ '**/__tests__/*.{j,t}s?(x)',
+ '**/tests/unit/**/*.spec.{j,t}s?(x)'
+ ],
+ env: {
+ jest: true
+ }
+ }
+ ]
+}
diff --git a/hotgo-web/.eslintrc.json b/hotgo-web/.eslintrc.json
new file mode 100644
index 0000000..ed223c7
--- /dev/null
+++ b/hotgo-web/.eslintrc.json
@@ -0,0 +1,5 @@
+{
+ "rules": {
+ "space-before-function-paren": 0
+ }
+}
diff --git a/hotgo-web/.gitattributes b/hotgo-web/.gitattributes
new file mode 100644
index 0000000..e507319
--- /dev/null
+++ b/hotgo-web/.gitattributes
@@ -0,0 +1 @@
+public/* linguist-vendored
\ No newline at end of file
diff --git a/hotgo-web/.gitignore b/hotgo-web/.gitignore
new file mode 100644
index 0000000..a3beccd
--- /dev/null
+++ b/hotgo-web/.gitignore
@@ -0,0 +1,23 @@
+.DS_Store
+node_modules
+/dist
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw*
+package-lock.json
+yarn.lock
diff --git a/hotgo-web/.prettierrc b/hotgo-web/.prettierrc
new file mode 100644
index 0000000..b0e80f7
--- /dev/null
+++ b/hotgo-web/.prettierrc
@@ -0,0 +1,6 @@
+{
+ "printWidth": 120,
+ "semi": false,
+ "singleQuote": true,
+ "prettier.spaceBeforeFunctionParen": true
+}
diff --git a/hotgo-web/.travis.yml b/hotgo-web/.travis.yml
new file mode 100644
index 0000000..a08bfcb
--- /dev/null
+++ b/hotgo-web/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+ - 10.15.0
+cache: yarn
+script:
+ - yarn
+ - yarn run lint --no-fix && yarn run build
diff --git a/hotgo-web/LICENSE b/hotgo-web/LICENSE
new file mode 100644
index 0000000..413013a
--- /dev/null
+++ b/hotgo-web/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 扶醉
+
+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.
diff --git a/hotgo-web/README.md b/hotgo-web/README.md
new file mode 100644
index 0000000..0440922
--- /dev/null
+++ b/hotgo-web/README.md
@@ -0,0 +1,4 @@
+## HotGo-UI
+
+#####git地址:
+https://gitee.com/bufanyun/hotgo-ui/
\ No newline at end of file
diff --git a/hotgo-web/babel.config.js b/hotgo-web/babel.config.js
new file mode 100644
index 0000000..e80ad97
--- /dev/null
+++ b/hotgo-web/babel.config.js
@@ -0,0 +1,28 @@
+const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
+
+const plugins = []
+if (IS_PROD) {
+ plugins.push('transform-remove-console')
+}
+
+// lazy load ant-design-vue
+// if your use import on Demand, Use this code
+plugins.push(['import', {
+ 'libraryName': 'ant-design-vue',
+ 'libraryDirectory': 'es',
+ 'style': true // `style: true` 会加载 less 文件
+}])
+
+module.exports = {
+ presets: [
+ '@vue/cli-plugin-babel/preset',
+ [
+ '@babel/preset-env',
+ {
+ 'useBuiltIns': 'entry',
+ 'corejs': 3
+ }
+ ]
+ ],
+ plugins
+}
diff --git a/hotgo-web/bin/build.bat b/hotgo-web/bin/build.bat
new file mode 100644
index 0000000..dda590d
--- /dev/null
+++ b/hotgo-web/bin/build.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [Ϣ] Weḅdistļ
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run build:prod
+
+pause
\ No newline at end of file
diff --git a/hotgo-web/bin/package.bat b/hotgo-web/bin/package.bat
new file mode 100644
index 0000000..8281749
--- /dev/null
+++ b/hotgo-web/bin/package.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [Ϣ] װWeḅnode_modulesļ
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm install --registry=https://registry.npm.taobao.org
+
+pause
\ No newline at end of file
diff --git a/hotgo-web/bin/run-web.bat b/hotgo-web/bin/run-web.bat
new file mode 100644
index 0000000..d30deae
--- /dev/null
+++ b/hotgo-web/bin/run-web.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [Ϣ] ʹ Vue CLI Web ̡
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run dev
+
+pause
\ No newline at end of file
diff --git a/hotgo-web/config/plugin.config.js b/hotgo-web/config/plugin.config.js
new file mode 100644
index 0000000..bb51b98
--- /dev/null
+++ b/hotgo-web/config/plugin.config.js
@@ -0,0 +1,49 @@
+const ThemeColorReplacer = require('webpack-theme-color-replacer')
+const generate = require('@ant-design/colors/lib/generate').default
+
+const getAntdSerials = (color) => {
+ // 淡化(即less的tint)
+ const lightens = new Array(9).fill().map((t, i) => {
+ return ThemeColorReplacer.varyColor.lighten(color, i / 10)
+ })
+ const colorPalettes = generate(color)
+ const rgb = ThemeColorReplacer.varyColor.toNum3(color.replace('#', '')).join(',')
+ return lightens.concat(colorPalettes).concat(rgb)
+}
+
+const themePluginOption = {
+ fileName: 'css/theme-colors-[contenthash:8].css',
+ matchColors: getAntdSerials('#1890ff'), // 主色系列
+ // 改变样式选择器,解决样式覆盖问题
+ changeSelector (selector) {
+ switch (selector) {
+ case '.ant-calendar-today .ant-calendar-date':
+ return ':not(.ant-calendar-selected-date):not(.ant-calendar-selected-day)' + selector
+ case '.ant-btn:focus,.ant-btn:hover':
+ return '.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger)'
+ case '.ant-btn.active,.ant-btn:active':
+ return '.ant-btn.active:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:active:not(.ant-btn-primary):not(.ant-btn-danger)'
+ case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
+ case '.ant-steps-item-process .ant-steps-item-icon>.ant-steps-icon':
+ return ':not(.ant-steps-item-process)' + selector
+ // fixed https://github.com/vueComponent/ant-design-vue-pro/issues/876
+ case '.ant-steps-item-process .ant-steps-item-icon':
+ return ':not(.ant-steps-item-custom)' + selector
+ case '.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover':
+ case '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal > .ant-menu-submenu-selected,.ant-menu-horizontal > .ant-menu-submenu:hover':
+ return '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu:hover'
+ case '.ant-menu-horizontal > .ant-menu-item-selected > a':
+ case '.ant-menu-horizontal>.ant-menu-item-selected>a':
+ return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item-selected > a'
+ case '.ant-menu-horizontal > .ant-menu-item > a:hover':
+ case '.ant-menu-horizontal>.ant-menu-item>a:hover':
+ return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item > a:hover'
+ default :
+ return selector
+ }
+ }
+}
+
+const createThemeColorReplacerPlugin = () => new ThemeColorReplacer(themePluginOption)
+
+module.exports = createThemeColorReplacerPlugin
diff --git a/hotgo-web/config/themePluginConfig.js b/hotgo-web/config/themePluginConfig.js
new file mode 100644
index 0000000..d35ef8b
--- /dev/null
+++ b/hotgo-web/config/themePluginConfig.js
@@ -0,0 +1,115 @@
+export default {
+ theme: [
+ {
+ key: 'dark',
+ fileName: 'dark.css',
+ theme: 'dark'
+ },
+ {
+ key: '#F5222D',
+ fileName: '#F5222D.css',
+ modifyVars: {
+ '@primary-color': '#F5222D'
+ }
+ },
+ {
+ key: '#FA541C',
+ fileName: '#FA541C.css',
+ modifyVars: {
+ '@primary-color': '#FA541C'
+ }
+ },
+ {
+ key: '#FAAD14',
+ fileName: '#FAAD14.css',
+ modifyVars: {
+ '@primary-color': '#FAAD14'
+ }
+ },
+ {
+ key: '#13C2C2',
+ fileName: '#13C2C2.css',
+ modifyVars: {
+ '@primary-color': '#13C2C2'
+ }
+ },
+ {
+ key: '#52C41A',
+ fileName: '#52C41A.css',
+ modifyVars: {
+ '@primary-color': '#52C41A'
+ }
+ },
+ {
+ key: '#2F54EB',
+ fileName: '#2F54EB.css',
+ modifyVars: {
+ '@primary-color': '#2F54EB'
+ }
+ },
+ {
+ key: '#722ED1',
+ fileName: '#722ED1.css',
+ modifyVars: {
+ '@primary-color': '#722ED1'
+ }
+ },
+
+ {
+ key: '#F5222D',
+ theme: 'dark',
+ fileName: 'dark-#F5222D.css',
+ modifyVars: {
+ '@primary-color': '#F5222D'
+ }
+ },
+ {
+ key: '#FA541C',
+ theme: 'dark',
+ fileName: 'dark-#FA541C.css',
+ modifyVars: {
+ '@primary-color': '#FA541C'
+ }
+ },
+ {
+ key: '#FAAD14',
+ theme: 'dark',
+ fileName: 'dark-#FAAD14.css',
+ modifyVars: {
+ '@primary-color': '#FAAD14'
+ }
+ },
+ {
+ key: '#13C2C2',
+ theme: 'dark',
+ fileName: 'dark-#13C2C2.css',
+ modifyVars: {
+ '@primary-color': '#13C2C2'
+ }
+ },
+ {
+ key: '#52C41A',
+ theme: 'dark',
+ fileName: 'dark-#52C41A.css',
+ modifyVars: {
+ '@primary-color': '#52C41A'
+ }
+ },
+ {
+ key: '#2F54EB',
+ theme: 'dark',
+ fileName: 'dark-#2F54EB.css',
+ modifyVars: {
+ '@primary-color': '#2F54EB'
+ }
+ },
+ {
+ key: '#722ED1',
+ theme: 'dark',
+ fileName: 'dark-#722ED1.css',
+ modifyVars: {
+ '@primary-color': '#722ED1'
+ }
+ }
+ ]
+}
diff --git a/hotgo-web/jest.config.js b/hotgo-web/jest.config.js
new file mode 100644
index 0000000..29fee32
--- /dev/null
+++ b/hotgo-web/jest.config.js
@@ -0,0 +1,23 @@
+module.exports = {
+ moduleFileExtensions: [
+ 'js',
+ 'jsx',
+ 'json',
+ 'vue'
+ ],
+ transform: {
+ '^.+\\.vue$': 'vue-jest',
+ '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
+ '^.+\\.jsx?$': 'babel-jest'
+ },
+ moduleNameMapper: {
+ '^@/(.*)$': '/src/$1'
+ },
+ snapshotSerializers: [
+ 'jest-serializer-vue'
+ ],
+ testMatch: [
+ '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
+ ],
+ testURL: 'http://localhost/'
+}
diff --git a/hotgo-web/jsconfig.json b/hotgo-web/jsconfig.json
new file mode 100644
index 0000000..1bd0da4
--- /dev/null
+++ b/hotgo-web/jsconfig.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["src/*"]
+ }
+ },
+ "exclude": ["node_modules", "dist"],
+ "include": ["src/**/*"]
+}
diff --git a/hotgo-web/package.json b/hotgo-web/package.json
new file mode 100644
index 0000000..7d5ffda
--- /dev/null
+++ b/hotgo-web/package.json
@@ -0,0 +1,71 @@
+{
+ "name": "vue-antd-pro",
+ "version": "3.0.0",
+ "private": true,
+ "scripts": {
+ "dev": "vue-cli-service serve",
+ "build": "vue-cli-service build",
+ "test:unit": "vue-cli-service test:unit",
+ "lint": "vue-cli-service lint",
+ "build:preview": "vue-cli-service build --mode preview",
+ "lint:nofix": "vue-cli-service lint --no-fix"
+ },
+ "dependencies": {
+ "@tntx/nested-table": "^1.0.11",
+ "ant-design-vue": "1.7.2",
+ "axios": "^0.19.0",
+ "core-js": "^3.1.2",
+ "echarts": "^5.0.0",
+ "enquire.js": "^2.1.6",
+ "highlight.js": "^10.5.0",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.get": "^4.4.2",
+ "lodash.pick": "^4.4.0",
+ "md5": "^2.2.1",
+ "mockjs2": "1.0.8",
+ "moment": "^2.24.0",
+ "nprogress": "^0.2.0",
+ "sortablejs": "^1.10.2",
+ "store": "^2.0.12",
+ "v-viewer": "^1.5.1",
+ "vditor": "^3.7.3",
+ "vue": "^2.6.12",
+ "vue-clipboard2": "^0.2.1",
+ "vue-container-query": "^0.1.0",
+ "vue-copy-to-clipboard": "^1.0.3",
+ "vue-cropper": "0.4.9",
+ "vue-grid-layout": "^2.3.12",
+ "vue-i18n": "^8.17.4",
+ "vue-router": "^3.1.2",
+ "vue-svg-component-runtime": "^1.0.1",
+ "vue-upload-component": "^2.8.20",
+ "vuex": "^3.1.1"
+ },
+ "devDependencies": {
+ "@ant-design/colors": "^3.2.1",
+ "@vue/cli-plugin-babel": "^4.0.4",
+ "@vue/cli-plugin-eslint": "^4.0.4",
+ "@vue/cli-plugin-router": "^4.0.4",
+ "@vue/cli-plugin-unit-jest": "^4.0.4",
+ "@vue/cli-plugin-vuex": "^4.0.4",
+ "@vue/cli-service": "^4.0.4",
+ "@vue/eslint-config-standard": "^4.0.0",
+ "@vue/test-utils": "^1.0.0-beta.29",
+ "babel-eslint": "^10.0.1",
+ "babel-plugin-import": "^1.12.2",
+ "babel-plugin-transform-remove-console": "^6.9.4",
+ "compression-webpack-plugin": "^5.0.1",
+ "eslint": "^5.16.0",
+ "eslint-plugin-html": "^5.0.0",
+ "eslint-plugin-react": "^7.22.0",
+ "eslint-plugin-vue": "^5.2.3",
+ "git-revision-webpack-plugin": "^3.0.6",
+ "less": "^3.0.4",
+ "less-loader": "^5.0.0",
+ "opencollective": "^1.0.3",
+ "opencollective-postinstall": "^2.0.2",
+ "vue-svg-icon-loader": "^2.1.1",
+ "vue-template-compiler": "^2.6.12",
+ "webpack-theme-color-replacer": "^1.3.12"
+ }
+}
diff --git a/hotgo-web/postcss.config.js b/hotgo-web/postcss.config.js
new file mode 100644
index 0000000..961986e
--- /dev/null
+++ b/hotgo-web/postcss.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ plugins: {
+ autoprefixer: {}
+ }
+}
diff --git a/hotgo-web/public/index.html b/hotgo-web/public/index.html
new file mode 100644
index 0000000..81c9c06
--- /dev/null
+++ b/hotgo-web/public/index.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+ 后台管理系统
+
+
+ <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
+
+ <% } %>
+
+
+
+ 请启用JavaScript后再使用
+
+
+
+ <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
+
+ <% } %>
+
+
+
diff --git a/hotgo-web/public/logo.png b/hotgo-web/public/logo.png
new file mode 100644
index 0000000..f830d03
Binary files /dev/null and b/hotgo-web/public/logo.png differ
diff --git a/hotgo-web/pull.bat b/hotgo-web/pull.bat
new file mode 100644
index 0000000..cfa6d5f
--- /dev/null
+++ b/hotgo-web/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-web/push.bat b/hotgo-web/push.bat
new file mode 100644
index 0000000..c18d061
--- /dev/null
+++ b/hotgo-web/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-ui.git master
\ No newline at end of file
diff --git a/hotgo-web/src/App.vue b/hotgo-web/src/App.vue
new file mode 100644
index 0000000..070f28a
--- /dev/null
+++ b/hotgo-web/src/App.vue
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/api/login.js b/hotgo-web/src/api/login.js
new file mode 100644
index 0000000..0b65b7d
--- /dev/null
+++ b/hotgo-web/src/api/login.js
@@ -0,0 +1,85 @@
+import request from '@/utils/request'
+
+const userApi = {
+ Login: '/login/sign',
+ Logout: '/login/logout',
+ // get my info
+ UserInfo: '/member/info',
+ SendSms: '/system/sysSms/sendSms'
+}
+
+/**
+ * login func
+ * @param parameter
+ * @returns {*}
+ */
+export function login(parameter) {
+ return request({
+ url: userApi.Login,
+ method: 'post',
+ data: parameter
+ })
+}
+
+/**
+ * login func
+ * @param parameter
+ * @returns {*}
+ */
+export function loginBySms(parameter) {
+ return request({
+ url: '/system/sysSms/loginBySms',
+ method: 'post',
+ data: parameter
+ })
+}
+
+export function getInfo() {
+ return request({
+ url: userApi.UserInfo,
+ method: 'get',
+ headers: {
+ 'Content-Type': 'application/json;charset=UTF-8'
+ }
+ })
+}
+
+export function logout() {
+ return request({
+ url: userApi.Logout,
+ method: 'post',
+ headers: {
+ 'Content-Type': 'application/json;charset=UTF-8'
+ }
+ })
+}
+
+// 获取验证码
+export function getCodeImg() {
+ return request({
+ url: '/login/captcha',
+ method: 'get',
+ timeout: 20000
+ })
+}
+
+// 获取手机验证码
+export function getSmsCaptcha(parameter) {
+ return request({
+ url: userApi.SendSms,
+ method: 'post',
+ data: parameter
+ })
+}
+
+// 注册方法
+export function register(data) {
+ return request({
+ url: '/register',
+ headers: {
+ isToken: false
+ },
+ method: 'post',
+ data: data
+ })
+}
diff --git a/hotgo-web/src/api/manage.js b/hotgo-web/src/api/manage.js
new file mode 100644
index 0000000..46a4a41
--- /dev/null
+++ b/hotgo-web/src/api/manage.js
@@ -0,0 +1,70 @@
+import request from '@/utils/request'
+
+const api = {
+ user: '/user',
+ role: '/role',
+ service: '/service',
+ permission: '/permission',
+ permissionNoPager: '/permission/no-pager',
+ orgTree: '/org/tree'
+}
+
+export default api
+
+export function getUserList (parameter) {
+ return request({
+ url: api.user,
+ method: 'get',
+ params: parameter
+ })
+}
+
+export function getRoleList (parameter) {
+ return request({
+ url: api.role,
+ method: 'get',
+ params: parameter
+ })
+}
+
+export function getServiceList (parameter) {
+ return request({
+ url: api.service,
+ method: 'get',
+ params: parameter
+ })
+}
+
+export function getPermissions (parameter) {
+ return request({
+ url: api.permissionNoPager,
+ method: 'get',
+ params: parameter
+ })
+}
+
+export function getOrgTree (parameter) {
+ return request({
+ url: api.orgTree,
+ method: 'get',
+ params: parameter
+ })
+}
+
+// id == 0 add post
+// id != 0 update put
+export function saveService (parameter) {
+ return request({
+ url: api.service,
+ method: parameter.id === 0 ? 'post' : 'put',
+ data: parameter
+ })
+}
+
+export function saveSub (sub) {
+ return request({
+ url: '/sub',
+ method: sub.id === 0 ? 'post' : 'put',
+ data: sub
+ })
+}
diff --git a/hotgo-web/src/api/menu.js b/hotgo-web/src/api/menu.js
new file mode 100644
index 0000000..243b6a7
--- /dev/null
+++ b/hotgo-web/src/api/menu.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 获取路由
+export const getRouters = () => {
+ return request({
+ url: '/role/dynamic/',
+ method: 'get'
+ })
+}
diff --git a/hotgo-web/src/api/monitor/cache.js b/hotgo-web/src/api/monitor/cache.js
new file mode 100644
index 0000000..81b838d
--- /dev/null
+++ b/hotgo-web/src/api/monitor/cache.js
@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+// 查询缓存详细
+export function getCache () {
+ return request({
+ url: '/monitor/cache',
+ method: 'get'
+ })
+}
+
+// 查询缓存名称列表
+export function listCacheName () {
+ return request({
+ url: '/monitor/cache/listCacheName',
+ method: 'get'
+ })
+}
+
+// 删除角色
+export function clearCache (cacheId) {
+ return request({
+ url: '/monitor/cache/clearCache/' + cacheId,
+ method: 'delete'
+ })
+}
+
+// 查询缓存详细
+export function listCacheKey (cacheId) {
+ return request({
+ url: '/monitor/cache/listCacheKey/' + cacheId,
+ method: 'get'
+ })
+}
+
+// 删除角色
+export function clearCacheByKey (cacheId, cacheKey) {
+ return request({
+ url: '/monitor/cache/clearCacheByKey/' + cacheId + '/' + cacheKey,
+ method: 'delete'
+ })
+}
+
+// 查询缓存详细
+export function getCacheValue (cacheId, cacheKey) {
+ return request({
+ url: '/monitor/cache/getCacheValue/' + cacheId + '/' + cacheKey,
+ method: 'get'
+ })
+}
diff --git a/hotgo-web/src/api/monitor/job.js b/hotgo-web/src/api/monitor/job.js
new file mode 100644
index 0000000..bf4a336
--- /dev/null
+++ b/hotgo-web/src/api/monitor/job.js
@@ -0,0 +1,79 @@
+import request from '@/utils/request'
+
+// 查询定时任务调度列表
+export function listJob (query) {
+ return request({
+ url: '/monitor/job/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询定时任务调度详细
+export function getJob (jobId) {
+ return request({
+ url: '/monitor/job/' + jobId,
+ method: 'get'
+ })
+}
+
+// 新增定时任务调度
+export function addJob (data) {
+ return request({
+ url: '/monitor/job',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改定时任务调度
+export function updateJob (data) {
+ return request({
+ url: '/monitor/job',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除定时任务调度
+export function delJob (jobId) {
+ return request({
+ url: '/monitor/job/' + jobId,
+ method: 'delete'
+ })
+}
+
+// 导出定时任务调度
+export function exportJob (query) {
+ return request({
+ url: '/monitor/job/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 任务状态修改
+export function changeJobStatus (jobId, status) {
+ const data = {
+ jobId,
+ status
+ }
+ return request({
+ url: '/monitor/job/changeStatus',
+ method: 'put',
+ data: data
+ })
+}
+
+// 定时任务立即执行一次
+export function runJob (jobId, jobGroup) {
+ const data = {
+ jobId,
+ jobGroup
+ }
+ return request({
+ url: '/monitor/job/run',
+ method: 'put',
+ data: data
+ })
+}
diff --git a/hotgo-web/src/api/monitor/jobLog.js b/hotgo-web/src/api/monitor/jobLog.js
new file mode 100644
index 0000000..d00b3be
--- /dev/null
+++ b/hotgo-web/src/api/monitor/jobLog.js
@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+// 查询调度日志列表
+export function listJobLog (query) {
+ return request({
+ url: '/monitor/jobLog/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 删除调度日志
+export function delJobLog (jobLogId) {
+ return request({
+ url: '/monitor/jobLog/' + jobLogId,
+ method: 'delete'
+ })
+}
+
+// 清空调度日志
+export function cleanJobLog () {
+ return request({
+ url: '/monitor/jobLog/clean',
+ method: 'delete'
+ })
+}
+
+// 导出调度日志
+export function exportJobLog (query) {
+ return request({
+ url: '/monitor/jobLog/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/hotgo-web/src/api/monitor/loginLog.js b/hotgo-web/src/api/monitor/loginLog.js
new file mode 100644
index 0000000..ebf002e
--- /dev/null
+++ b/hotgo-web/src/api/monitor/loginLog.js
@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+// 查询登录日志列表
+export function list (query) {
+ return request({
+ url: '/monitor/loginLog/page',
+ method: 'get',
+ params: query
+ })
+}
+
+// 删除登录日志
+export function delLoginLog (infoId) {
+ return request({
+ url: '/monitor/loginLog/' + infoId,
+ method: 'delete'
+ })
+}
+
+// 清空登录日志
+export function cleanLoginLog () {
+ return request({
+ url: '/monitor/loginLog/clean',
+ method: 'delete'
+ })
+}
+
+// 导出登录日志
+export function exportLoginLog (query) {
+ return request({
+ url: '/monitor/loginLog/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/hotgo-web/src/api/monitor/online.js b/hotgo-web/src/api/monitor/online.js
new file mode 100644
index 0000000..76da959
--- /dev/null
+++ b/hotgo-web/src/api/monitor/online.js
@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+// 查询在线用户列表
+export function list (query) {
+ return request({
+ url: '/monitor/online/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 强退用户
+export function forceLogout (tokenId) {
+ return request({
+ url: '/monitor/online/' + tokenId,
+ method: 'delete'
+ })
+}
diff --git a/hotgo-web/src/api/monitor/operlog.js b/hotgo-web/src/api/monitor/operlog.js
new file mode 100644
index 0000000..db157c8
--- /dev/null
+++ b/hotgo-web/src/api/monitor/operlog.js
@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+// 查询操作日志列表
+export function list (query) {
+ return request({
+ url: '/log/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 删除操作日志
+export function delOperlog (operId) {
+ return request({
+ url: '/monitor/operlog/' + operId,
+ method: 'delete'
+ })
+}
+
+// 清空操作日志
+export function cleanOperlog () {
+ return request({
+ url: '/log/clear',
+ method: 'post'
+ })
+}
+
+// 导出操作日志
+export function exportOperlog (query) {
+ return request({
+ url: '/log/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/hotgo-web/src/api/monitor/server.js b/hotgo-web/src/api/monitor/server.js
new file mode 100644
index 0000000..f30882a
--- /dev/null
+++ b/hotgo-web/src/api/monitor/server.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 查询服务器详细
+export function getServer () {
+ return request({
+ url: '/monitor/server',
+ method: 'get'
+ })
+}
diff --git a/hotgo-web/src/api/monitor/sysDataPermissionsDefRule.js b/hotgo-web/src/api/monitor/sysDataPermissionsDefRule.js
new file mode 100644
index 0000000..efca948
--- /dev/null
+++ b/hotgo-web/src/api/monitor/sysDataPermissionsDefRule.js
@@ -0,0 +1,69 @@
+import request from '@/utils/request'
+
+// 查询默认规则维护列表
+export function listSysDataPermissionsDefRule (query) {
+ return request({
+ url: '/monitor/sysDataPermissionsDefRule/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询默认规则维护详细
+export function getSysDataPermissionsDefRule (id) {
+ return request({
+ url: '/monitor/sysDataPermissionsDefRule/' + id,
+ method: 'get'
+ })
+}
+
+// 新增默认规则维护
+export function addSysDataPermissionsDefRule (data) {
+ return request({
+ url: '/monitor/sysDataPermissionsDefRule',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改默认规则维护
+export function updateSysDataPermissionsDefRule (data) {
+ return request({
+ url: '/monitor/sysDataPermissionsDefRule',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除默认规则维护
+export function delSysDataPermissionsDefRule (id) {
+ return request({
+ url: '/monitor/sysDataPermissionsDefRule/' + id,
+ method: 'delete'
+ })
+}
+
+// 导出默认规则维护
+export function exportSysDataPermissionsDefRule (query) {
+ return request({
+ url: '/monitor/sysDataPermissionsDefRule/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询菜单同层最大排序
+export function findMaxSort () {
+ return request({
+ url: '/monitor/sysDataPermissionsDefRule/findMaxSort',
+ method: 'get'
+ })
+}
+
+// 获得全部的且已启用的默认规则
+export function getAllDefaultRule () {
+ return request({
+ url: '/monitor/sysDataPermissionsDefRule/getAllDefaultRule',
+ method: 'get'
+ })
+}
diff --git a/hotgo-web/src/api/monitor/sysDataPermissionsMethod.js b/hotgo-web/src/api/monitor/sysDataPermissionsMethod.js
new file mode 100644
index 0000000..da46ce2
--- /dev/null
+++ b/hotgo-web/src/api/monitor/sysDataPermissionsMethod.js
@@ -0,0 +1,78 @@
+import request from '@/utils/request'
+
+// 查询数据权限方法维护列表
+export function listSysDataPermissionsMethod (query) {
+ return request({
+ url: '/monitor/sysDataPermissionsMethod/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询数据权限方法维护详细
+export function getSysDataPermissionsMethod (id) {
+ return request({
+ url: '/monitor/sysDataPermissionsMethod/' + id,
+ method: 'get'
+ })
+}
+
+// 新增数据权限方法维护
+export function addSysDataPermissionsMethod (data) {
+ return request({
+ url: '/monitor/sysDataPermissionsMethod',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改数据权限方法维护
+export function updateSysDataPermissionsMethod (data) {
+ return request({
+ url: '/monitor/sysDataPermissionsMethod',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除数据权限方法维护
+export function delSysDataPermissionsMethod (id) {
+ return request({
+ url: '/monitor/sysDataPermissionsMethod/' + id,
+ method: 'delete'
+ })
+}
+
+// 导出数据权限方法维护
+export function exportSysDataPermissionsMethod (query) {
+ return request({
+ url: '/monitor/sysDataPermissionsMethod/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 新增数据权限方法维护
+export function getAllMapperData () {
+ return request({
+ url: '/monitor/sysDataPermissionsMethod/getAllMapperData',
+ method: 'get'
+ })
+}
+
+// 新增数据权限方法维护
+export function getMapperName (searchInfo) {
+ return request({
+ url: '/monitor/sysDataPermissionsMethod/getMapperName',
+ method: 'get',
+ params: searchInfo
+ })
+}
+
+export function getMethodHtml (searchInfo) {
+ return request({
+ url: '/monitor/sysDataPermissionsMethod/getMethodHtml',
+ method: 'get',
+ params: searchInfo
+ })
+}
diff --git a/hotgo-web/src/api/monitor/sysDataPermissionsRule.js b/hotgo-web/src/api/monitor/sysDataPermissionsRule.js
new file mode 100644
index 0000000..ff506f9
--- /dev/null
+++ b/hotgo-web/src/api/monitor/sysDataPermissionsRule.js
@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 查询数据权限规则维护子表列表
+export function listSysDataPermissionsRule (query) {
+ return request({
+ url: '/monitor/sysDataPermissionsRule/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询数据权限规则维护子表详细
+export function getSysDataPermissionsRule (id) {
+ return request({
+ url: '/monitor/sysDataPermissionsRule/' + id,
+ method: 'get'
+ })
+}
+
+// 新增数据权限规则维护子表
+export function addSysDataPermissionsRule (data) {
+ return request({
+ url: '/monitor/sysDataPermissionsRule',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改数据权限规则维护子表
+export function updateSysDataPermissionsRule (data) {
+ return request({
+ url: '/monitor/sysDataPermissionsRule',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除数据权限规则维护子表
+export function delSysDataPermissionsRule (id) {
+ return request({
+ url: '/monitor/sysDataPermissionsRule/' + id,
+ method: 'delete'
+ })
+}
+
+// 导出数据权限规则维护子表
+export function exportSysDataPermissionsRule (query) {
+ return request({
+ url: '/monitor/sysDataPermissionsRule/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 导出数据权限规则维护子表
+export function getDataPermissionsMethodInfo (methodId) {
+ return request({
+ url: '/monitor/sysDataPermissionsRule/getDataPermissionsMethodInfo/' + methodId,
+ method: 'get'
+ })
+}
diff --git a/hotgo-web/src/api/system/config.js b/hotgo-web/src/api/system/config.js
new file mode 100644
index 0000000..0c2655d
--- /dev/null
+++ b/hotgo-web/src/api/system/config.js
@@ -0,0 +1,70 @@
+import request from '@/utils/request'
+
+// 查询参数列表
+export function listConfig (query) {
+ return request({
+ url: '/system/config/page',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询参数详细
+export function getConfig (configId) {
+ return request({
+ url: '/system/config/' + configId,
+ method: 'get'
+ })
+}
+
+// 根据参数键名查询参数值
+export function getConfigKey (configKey) {
+ return request({
+ url: '/config/get_value/',
+ method: 'get',
+ params: { key: configKey }
+ })
+}
+
+// 新增参数配置
+export function saveConfig (data) {
+ return request({
+ url: '/system/config',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除参数配置
+export function delConfig (configId) {
+ return request({
+ url: '/system/config/' + configId,
+ method: 'delete'
+ })
+}
+
+// 清理参数缓存
+export function refreshCache () {
+ return request({
+ url: '/system/config/refreshCache',
+ method: 'delete'
+ })
+}
+
+// 导出参数
+export function exportConfig (query) {
+ return request({
+ url: '/system/config/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 参数列表唯一校验
+export function checkConfigKeyUnique (data) {
+ return request({
+ url: 'system/config/checkConfigKeyUnique',
+ method: 'get',
+ params: data
+ })
+}
diff --git a/hotgo-web/src/api/system/dept.js b/hotgo-web/src/api/system/dept.js
new file mode 100644
index 0000000..6ccad42
--- /dev/null
+++ b/hotgo-web/src/api/system/dept.js
@@ -0,0 +1,173 @@
+import request from '@/utils/request'
+
+// 查询部门列表
+export function listDept (query, deptId, expandLevel) {
+ if (deptId == null || deptId === '') {
+ deptId = '0'
+ }
+ if (expandLevel == null || expandLevel === '') {
+ expandLevel = '1'
+ }
+ // + expandLevel + '/' + deptId
+ return request({
+ url: '/dept/list/',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询部门树列表(排除节点)
+export function listDeptExcludeChild (deptId) {
+ // return request({
+ // url: '/system/dept/listTreeExcludeChild/10/0/' + deptId,
+ // method: 'get'
+ // })
+ return request({
+ url: '/dept/list/',
+ method: 'get',
+ params: { id: deptId }
+ })
+}
+
+// 查询部门树列表(排除当前节点及子节点)
+export function listDeptTree (deptId, expandLevel) {
+ // if (deptId == null || deptId === '') {
+ // deptId = '0'
+ // }
+ // if (expandLevel == null || expandLevel === '') {
+ // expandLevel = '1'
+ // }
+ // return request({
+ // url: '/system/dept/listTree/' + expandLevel + '/' + deptId,
+ // method: 'get'
+ // })
+
+ return request({
+ url: '/dept/list_tree/',
+ method: 'get',
+ params: { id: deptId }
+ })
+}
+
+// 查询部门详细
+export function getDept (deptId) {
+ return request({
+ url: '/dept/view',
+ method: 'get',
+ params: { id: deptId }
+ })
+}
+
+// 根据角色ID查询部门树结构
+export function roleDeptTreeselect (roleId) {
+ return request({
+ url: '/system/dept/roleDeptTreeselect/' + roleId,
+ method: 'get'
+ })
+}
+
+// 新增部门
+export function addDept (data) {
+ return request({
+ url: '/system/dept',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改部门
+export function updateDept (data) {
+ return request({
+ url: '/system/dept',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除部门
+export function delDept (deptId) {
+ return request({
+ url: '/system/dept/' + deptId,
+ method: 'delete'
+ })
+}
+
+// 查询部门下拉树结构
+export function findMaxSort(parentId) {
+ return request({
+ url: '/dept/max_sort',
+ method: 'get',
+ params: { id: parentId }
+ })
+}
+
+// 校验部门名称是否存在
+export function validateDeptNameUnique (deptName, parentId, id) {
+ if (id === undefined) {
+ id = ''
+ }
+ return request({
+ url: '/system/dept/validateDeptNameUnique/' + deptName + '/' + parentId + '/' + id,
+ method: 'get'
+ })
+}
+// 部门树检索
+export function searchDept (searchInfo) {
+ return request({
+ url: '/system/dept/search',
+ method: 'get',
+ params: searchInfo
+ })
+}
+// 部门树检索
+export function searchDeptList (searchInfo) {
+ // return request({
+ // url: '/system/dept/searchDeptList',
+ // method: 'get',
+ // params: searchInfo
+ // })
+ return request({
+ url: '/dept/list/',
+ method: 'get',
+ params: searchInfo
+ })
+}
+// 按部门分组人员树
+export function userSelectTree (deptId, expandLevel) {
+ if (deptId == null || deptId === '') {
+ deptId = '0'
+ }
+ if (expandLevel == null || expandLevel === '') {
+ expandLevel = '1'
+ }
+ // return request({
+ // url: '/dept/userSelectList/' + expandLevel + '/' + deptId,
+ // method: 'get'
+ // })
+ return request({
+ url: '/dept/list/',
+ method: 'get'
+ })
+}
+// 按部门树检索用户
+export function searchDeptUserList (searchInfo) {
+ return request({
+ url: '/system/dept/searchDeptUserList',
+ method: 'get',
+ params: searchInfo
+ })
+}
+
+// 查询部门详细
+export function getDeptInfoByIds (userIds) {
+ // return request({
+ // url: '/system/dept/getDeptInfoByIds',
+ // method: 'post',
+ // data: userIds
+ // })
+ return request({
+ url: '/dept/list/',
+ method: 'get',
+ params: userIds
+ })
+}
diff --git a/hotgo-web/src/api/system/dict/data.js b/hotgo-web/src/api/system/dict/data.js
new file mode 100644
index 0000000..bd4add0
--- /dev/null
+++ b/hotgo-web/src/api/system/dict/data.js
@@ -0,0 +1,83 @@
+import request from '@/utils/request'
+
+// 查询字典数据列表
+export function listData(query) {
+ return request({
+ url: '/dict_data/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询字典数据详细
+export function getData(dictCode) {
+ return request({
+ url: '/dict_data/view',
+ method: 'get',
+ params: { id: dictCode }
+ })
+}
+
+// 根据字典类型查询字典数据信息
+export function getDicts(dictType) {
+ const params = { type: dictType }
+ return request({
+ url: '/dict/attribute',
+ method: 'get',
+ params: params
+ })
+}
+
+// 根据字典类型查询字典数据信息
+export function getAllDicts(dictType) {
+ return request({
+ url: '/system/dict/data/all/type/' + dictType,
+ method: 'get'
+ })
+}
+
+// 新增字典数据
+export function saveData(data) {
+ return request({
+ url: '/dict_data/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除字典数据
+export function delData(dictCode) {
+ return request({
+ url: '/dict_data/delete',
+ method: 'post',
+ params: { id: dictCode }
+ })
+}
+
+// 导出字典数据
+export function exportData(query) {
+ return request({
+ url: '/system/dict/data/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询字典类型列表
+export function checkDictDataValueUnique(data) {
+ console.log('data:' + JSON.stringify(data))
+ return request({
+ url: '/dict_data/unique',
+ method: 'get',
+ params: data
+ })
+}
+
+// 查询最大排序
+export function findMaxSort(dictType) {
+ return request({
+ url: '/dict_data/max_sort',
+ method: 'get',
+ params: { type: dictType }
+ })
+}
diff --git a/hotgo-web/src/api/system/dict/type.js b/hotgo-web/src/api/system/dict/type.js
new file mode 100644
index 0000000..fac95b6
--- /dev/null
+++ b/hotgo-web/src/api/system/dict/type.js
@@ -0,0 +1,71 @@
+import request from '@/utils/request'
+
+// 查询字典类型列表
+export function listType(query) {
+ return request({
+ url: '/dict_type/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询字典类型详细
+export function getType(dictId) {
+ return request({
+ url: '/dict_type/view',
+ method: 'get',
+ params: { id: dictId }
+ })
+}
+
+// 新增字典类型
+export function saveType(data) {
+ return request({
+ url: '/dict_type/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除字典类型
+export function delType(dictId) {
+ return request({
+ url: '/dict_type/delete',
+ method: 'post',
+ params: { id: dictId }
+ })
+}
+
+// 刷新字典缓存
+export function refreshCache() {
+ return request({
+ url: '/dict_type/refresh_cache',
+ method: 'get'
+ })
+}
+
+// 导出字典类型
+export function exportType(query) {
+ return request({
+ url: '/dict_type/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 获取字典选择框列表
+export function optionselect() {
+ return request({
+ url: '/system/dict/type/optionselect',
+ method: 'get'
+ })
+}
+
+// 查询字典类型列表
+export function checkDictTypeUnique(data) {
+ return request({
+ url: '/dict_type/unique',
+ method: 'get',
+ params: data
+ })
+}
diff --git a/hotgo-web/src/api/system/menu.js b/hotgo-web/src/api/system/menu.js
new file mode 100644
index 0000000..c492da0
--- /dev/null
+++ b/hotgo-web/src/api/system/menu.js
@@ -0,0 +1,121 @@
+import request from '@/utils/request'
+
+// 查询菜单列表
+export function listMenu(query, menuId, expandLevel) {
+ // console.log('query:' + JSON.stringify(query))
+ if (menuId == null || menuId === '') {
+ menuId = 0
+ }
+ if (expandLevel == null || expandLevel === '') {
+ expandLevel = '2'
+ }
+ if (query === undefined) {
+ query = {}
+ }
+ query.pid = menuId
+ return request({
+ url: '/menu/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询菜单详细
+export function getMenu(menuId) {
+ return request({
+ url: '/menu/view',
+ method: 'get',
+ params: { id: menuId }
+ })
+}
+
+// 查询菜单下拉树结构
+export function treeselect(menuId, expandLevel) {
+ if (menuId == null || menuId === '') {
+ menuId = '0'
+ }
+ if (expandLevel == null || expandLevel === '') {
+ expandLevel = '2'
+ }
+ return request({
+ url: '/system/menu/treeselect/' + expandLevel + '/' + menuId,
+ method: 'get'
+ })
+}
+
+// 查询菜单下拉树结构
+export function menuTreeExcludeButton(menuId, expandLevel) {
+ if (menuId == null || menuId === '') {
+ menuId = '0'
+ }
+ if (expandLevel == null || expandLevel === '') {
+ expandLevel = '2'
+ }
+ return request({
+ url: '/system/menu/menuTreeExcludeButton/' + expandLevel + '/' + menuId,
+ method: 'get'
+ })
+}
+
+// 根据角色ID查询菜单下拉树结构
+export function roleMenuTreeselect(roleId) {
+ return request({
+ url: '/menu/role_list',
+ method: 'get',
+ params: { id: roleId }
+ })
+}
+
+// 新增菜单
+export function saveMenu(data) {
+ return request({
+ url: '/menu/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除菜单
+export function delMenu(menuId) {
+ return request({
+ url: '/menu/delete',
+ method: 'post',
+ params: { id: menuId }
+ })
+}
+
+// 菜单树检索
+export function searchMenuList(searchInfo) {
+ return request({
+ url: '/menu/search_list',
+ method: 'get',
+ params: searchInfo
+ })
+}
+
+// 菜单名称唯一校验
+export function checkMenuNameUnique(data) {
+ return request({
+ url: '/menu/name_unique',
+ method: 'get',
+ params: data
+ })
+}
+
+// 路由地址唯一校验
+export function checkMenuCodeUnique(data) {
+ return request({
+ url: '/menu/code_unique',
+ method: 'get',
+ params: data
+ })
+}
+
+// 查询菜单同层最大排序
+export function findMaxSort(parentId) {
+ return request({
+ url: '/menu/max_sort',
+ method: 'get',
+ params: { id: parentId }
+ })
+}
diff --git a/hotgo-web/src/api/system/notice.js b/hotgo-web/src/api/system/notice.js
new file mode 100644
index 0000000..5f60cb3
--- /dev/null
+++ b/hotgo-web/src/api/system/notice.js
@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 查询公告列表
+export function listNotice(query) {
+ return request({
+ url: '/notice/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询公告详细
+export function getNotice(noticeId) {
+ return request({
+ url: '/notice/view',
+ method: 'get',
+ params: { id: noticeId }
+ })
+}
+
+// 新增公告
+export function saveNotice(data) {
+ return request({
+ url: '/notice/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除公告
+export function delNotice(noticeId) {
+ return request({
+ url: '/notice/delete',
+ method: 'post',
+ params: { id: noticeId }
+ })
+}
+
+// 查看页面查询公告详细
+export function getNoticeView(noticeId) {
+ return request({
+ url: '/system/notice/getNoticeView/' + noticeId,
+ method: 'get'
+ })
+}
+
+// 查询个人公告阅读列表
+export function listNoticeByUser(query) {
+ return request({
+ url: '/system/notice/listNoticeByUser/page',
+ method: 'get',
+ params: query
+ })
+}
+
+// 新增公告
+export function updateNoticeToRead(noticeIds) {
+ return request({
+ url: '/system/notice/updateNoticeToRead/' + noticeIds,
+ method: 'put'
+ })
+}
diff --git a/hotgo-web/src/api/system/post.js b/hotgo-web/src/api/system/post.js
new file mode 100644
index 0000000..4946efe
--- /dev/null
+++ b/hotgo-web/src/api/system/post.js
@@ -0,0 +1,72 @@
+import request from '@/utils/request'
+
+// 查询岗位列表
+export function listPost (query) {
+ return request({
+ url: '/post/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询岗位详细
+export function getPost (id) {
+ return request({
+ url: '/post/view',
+ method: 'get',
+ params: { id: id }
+ })
+}
+
+// 新增岗位
+export function savePost (data) {
+ return request({
+ url: '/post/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除岗位
+export function delPost (id) {
+ return request({
+ url: '/post/delete',
+ method: 'post',
+ data: { id: id }
+ })
+}
+
+// 导出岗位
+export function exportPost (query) {
+ return request({
+ url: '/system/post/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 岗位编码唯一校验
+export function checkPostCodeUnique (data) {
+ return request({
+ url: '/post/code_unique',
+ method: 'get',
+ params: data
+ })
+}
+
+// 岗位名称唯一校验
+export function checkPostNameUnique (data) {
+ return request({
+ url: '/post/name_unique',
+ method: 'get',
+ params: data
+ })
+}
+
+// 查询岗位最大排序
+export function findMaxSort () {
+ return request({
+ url: '/post/max_sort',
+ method: 'get'
+ })
+}
diff --git a/hotgo-web/src/api/system/role.js b/hotgo-web/src/api/system/role.js
new file mode 100644
index 0000000..88ec57b
--- /dev/null
+++ b/hotgo-web/src/api/system/role.js
@@ -0,0 +1,127 @@
+import request from '@/utils/request'
+
+// 查询角色列表
+export function listRole (query) {
+ return request({
+ url: '/role/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询角色详细
+export function getRole (roleId) {
+ return request({
+ url: '/role/view' + roleId,
+ method: 'get',
+ params: { id: roleId }
+ })
+}
+
+// 新增角色
+export function addRole (data) {
+ return request({
+ url: '/role/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改角色
+export function updateRole (data) {
+ return request({
+ url: '/role/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 角色数据权限
+export function dataScope (data) {
+ return request({
+ url: '/role/dataScope',
+ method: 'post',
+ data: data
+ })
+}
+
+// 角色状态修改
+export function changeRoleStatus (id, status) {
+ const data = {
+ id,
+ status
+ }
+ return request({
+ url: '/role/changeStatus',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除角色
+export function delRole (roleId) {
+ return request({
+ url: '/role/delete',
+ method: 'post',
+ params: { id: roleId }
+ })
+}
+
+// 导出角色
+export function exportRole (query) {
+ return request({
+ url: '/role/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 校验角色名称唯一性
+export function checkRoleNameUnique (data) {
+ return request({
+ url: '/system/role/checkRoleNameUnique',
+ method: 'get',
+ params: data
+ })
+}
+
+// 校验角色名称唯一性
+export function checkRoleKeyUnique (data) {
+ return request({
+ url: '/system/role/checkRoleKeyUnique',
+ method: 'get',
+ params: data
+ })
+}
+
+// 查询最大排序
+export function findMaxSort () {
+ return request({
+ url: '/system/role/findMaxSort',
+ method: 'get'
+ })
+}
+// 新增角色
+export function batchSaveRole (data) {
+ return request({
+ url: '/system/role/batchSave',
+ method: 'post',
+ data: data
+ })
+}
+// 删除角色
+export function delRoleUser (roleId, userIds) {
+ return request({
+ url: '/system/role/delete_role_user/',
+ method: 'post',
+ params: { id: roleId, member_id: userIds }
+ })
+}
+// 给小页授权
+export function saveRolePortlet (data) {
+ return request({
+ url: '/role/saveRolePortlet',
+ method: 'post',
+ data: data
+ })
+}
diff --git a/hotgo-web/src/api/system/sysNoticeUserRead.js b/hotgo-web/src/api/system/sysNoticeUserRead.js
new file mode 100644
index 0000000..7ee519b
--- /dev/null
+++ b/hotgo-web/src/api/system/sysNoticeUserRead.js
@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询通知公告用户阅读列表
+export function listSysNoticeUserRead (query) {
+ return request({
+ url: '/system/sysNoticeUserRead/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询通知公告用户阅读详细
+export function getSysNoticeUserRead (id) {
+ return request({
+ url: '/system/sysNoticeUserRead/' + id,
+ method: 'get'
+ })
+}
+
+// 新增通知公告用户阅读
+export function addSysNoticeUserRead (data) {
+ return request({
+ url: '/system/sysNoticeUserRead',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改通知公告用户阅读
+export function updateSysNoticeUserRead (data) {
+ return request({
+ url: '/system/sysNoticeUserRead',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除通知公告用户阅读
+export function delSysNoticeUserRead (id) {
+ return request({
+ url: '/system/sysNoticeUserRead/' + id,
+ method: 'delete'
+ })
+}
+
+// 导出通知公告用户阅读
+export function exportSysNoticeUserRead (query) {
+ return request({
+ url: '/system/sysNoticeUserRead/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/hotgo-web/src/api/system/sysPortalConfig.js b/hotgo-web/src/api/system/sysPortalConfig.js
new file mode 100644
index 0000000..b080ab5
--- /dev/null
+++ b/hotgo-web/src/api/system/sysPortalConfig.js
@@ -0,0 +1,93 @@
+import request from '@/utils/request'
+
+// 查询多栏目门户配置列表
+export function listSysPortalConfig (query) {
+ return request({
+ url: '/system/sysPortalConfig/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询多栏目门户配置详细
+export function getSysPortalConfig (id) {
+ return request({
+ url: '/system/sysPortalConfig/' + id,
+ method: 'get'
+ })
+}
+
+// 新增多栏目门户配置
+export function addSysPortalConfig (data) {
+ return request({
+ url: '/system/sysPortalConfig',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改多栏目门户配置
+export function updateSysPortalConfig (data) {
+ return request({
+ url: '/system/sysPortalConfig',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除多栏目门户配置
+export function delSysPortalConfig (id) {
+ return request({
+ url: '/system/sysPortalConfig/' + id,
+ method: 'delete'
+ })
+}
+
+// 查询最大编号
+export function findMaxSort () {
+ return request({
+ url: '/system/sysPortalConfig/findMaxSort',
+ method: 'get'
+ })
+}
+// 校验小页编码是否存在
+export function checkCodeUnique (id, code) {
+ if (id === undefined) {
+ id = ''
+ }
+ return request({
+ url: '/system/sysPortalConfig/checkCodeUnique/' + code + '/' + id,
+ method: 'get'
+ })
+}
+
+// 导出多栏目门户配置
+export function exportSysPortalConfig (query) {
+ return request({
+ url: '/system/sysPortalConfig/export',
+ method: 'get',
+ params: query
+ })
+}
+// 查询多栏目门户配置详细
+export function getConfigAndPortalList (id) {
+ return request({
+ url: '/system/sysPortalConfig/getConfigAndPortalList/' + id,
+ method: 'get'
+ })
+}
+// 修改多栏目门户配置
+export function updateDefaultPortalConfig (data) {
+ return request({
+ url: '/system/sysPortalConfig/updateDefaultPortalConfig',
+ method: 'put',
+ data: data
+ })
+}
+// 查询模板列表
+export function getPortalTemplateList () {
+ return request({
+ url: '/system/sysPortalConfig/getPortalTemplateList',
+ method: 'get'
+ })
+}
diff --git a/hotgo-web/src/api/system/sysPortlet.js b/hotgo-web/src/api/system/sysPortlet.js
new file mode 100644
index 0000000..e9c7e60
--- /dev/null
+++ b/hotgo-web/src/api/system/sysPortlet.js
@@ -0,0 +1,79 @@
+import request from '@/utils/request'
+
+// 查询工作台小页管理列表
+export function listSysPortlet (query) {
+ return request({
+ url: '/system/sysPortlet/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询工作台小页管理详细
+export function getSysPortlet (id) {
+ return request({
+ url: '/system/sysPortlet/' + id,
+ method: 'get'
+ })
+}
+
+// 新增工作台小页管理
+export function addSysPortlet (data) {
+ return request({
+ url: '/system/sysPortlet',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改工作台小页管理
+export function updateSysPortlet (data) {
+ return request({
+ url: '/system/sysPortlet',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除工作台小页管理
+export function delSysPortlet (id) {
+ return request({
+ url: '/system/sysPortlet/' + id,
+ method: 'delete'
+ })
+}
+
+// 查询最大编号
+export function findMaxSort () {
+ return request({
+ url: '/system/sysPortlet/findMaxSort',
+ method: 'get'
+ })
+}
+// 校验小页编码是否存在
+export function checkCodeUnique (id, code) {
+ if (id === undefined) {
+ id = ''
+ }
+ return request({
+ url: '/system/sysPortlet/checkCodeUnique/' + code + '/' + id,
+ method: 'get'
+ })
+}
+
+// 导出工作台小页管理
+export function exportSysPortlet (query) {
+ return request({
+ url: '/system/sysPortlet/export',
+ method: 'get',
+ params: query
+ })
+}
+// 查询工作台小页管理列表
+export function listSysPortletByRoleId (query) {
+ return request({
+ url: '/system/sysPortlet/getSysPortletByRoleId',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/hotgo-web/src/api/system/sysTableConfig.js b/hotgo-web/src/api/system/sysTableConfig.js
new file mode 100644
index 0000000..f442e1b
--- /dev/null
+++ b/hotgo-web/src/api/system/sysTableConfig.js
@@ -0,0 +1,27 @@
+import request from '@/utils/request'
+
+// 查询个性化配置详细
+export function getSysTableConfig (tableKey) {
+ return request({
+ url: '/system/sysTableConfig/getInfoByTableKey/' + tableKey,
+ method: 'get'
+ })
+}
+
+// 新增个性化配置
+export function addSysTableConfig (data) {
+ return request({
+ url: '/system/sysTableConfig',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改个性化配置
+export function updateSysTableConfig (data) {
+ return request({
+ url: '/system/sysTableConfig',
+ method: 'put',
+ data: data
+ })
+}
diff --git a/hotgo-web/src/api/system/sysThemeConfig.js b/hotgo-web/src/api/system/sysThemeConfig.js
new file mode 100644
index 0000000..7f2c81b
--- /dev/null
+++ b/hotgo-web/src/api/system/sysThemeConfig.js
@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 查询用户主题信息记录列表
+export function listSysThemeConfig (query) {
+ return request({
+ url: '/sysThemeConfig/sysThemeConfig/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询用户主题信息记录详细
+export function getSysThemeConfig (id) {
+ return request({
+ url: '/sysThemeConfig/sysThemeConfig/' + id,
+ method: 'get'
+ })
+}
+
+// 新增用户主题信息记录
+export function addSysThemeConfig (data) {
+ return request({
+ url: '/sysThemeConfig/sysThemeConfig',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改用户主题信息记录
+export function updateSysThemeConfig (data) {
+ return request({
+ url: '/sysThemeConfig/sysThemeConfig',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除用户主题信息记录
+export function delSysThemeConfig (id) {
+ return request({
+ url: '/sysThemeConfig/sysThemeConfig/' + id,
+ method: 'delete'
+ })
+}
+
+// 查询最大编号
+export function findMaxSort () {
+ return request({
+ url: '/sysThemeConfig/sysThemeConfig/findMaxSort',
+ method: 'get'
+ })
+}
+// 导出用户主题信息记录
+export function exportSysThemeConfig (query) {
+ return request({
+ url: '/sysThemeConfig/sysThemeConfig/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/hotgo-web/src/api/system/upload.js b/hotgo-web/src/api/system/upload.js
new file mode 100644
index 0000000..db384b3
--- /dev/null
+++ b/hotgo-web/src/api/system/upload.js
@@ -0,0 +1,17 @@
+import request from '@/utils/request'
+// 上传附件
+export function baseUpload (data) {
+ return request({
+ url: '/common/attach/baseupload/v1',
+ method: 'post',
+ data: data
+ })
+}
+// 仅上传附件到磁盘不保存数据库
+export function uploadDisk (data) {
+ return request({
+ url: '/common/attach/uploadDisk/v1',
+ method: 'post',
+ data: data
+ })
+}
diff --git a/hotgo-web/src/api/system/user.js b/hotgo-web/src/api/system/user.js
new file mode 100644
index 0000000..308fb0e
--- /dev/null
+++ b/hotgo-web/src/api/system/user.js
@@ -0,0 +1,181 @@
+import request from '@/utils/request'
+import { praseStrEmpty } from '@/utils/aidex'
+
+// 查询用户列表
+export function listUser(query) {
+ return request({
+ url: '/member/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询用户详细
+export function getUser(userId) {
+ return request({
+ url: '/member/view',
+ method: 'get',
+ params: { id: praseStrEmpty(userId) }
+ })
+}
+
+// 新增用户
+export function addUser(data) {
+ return request({
+ url: '/member/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改用户
+export function updateUser(data) {
+ return request({
+ url: '/member/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除用户
+export function delUser(userId) {
+ return request({
+ url: '/member/delete',
+ method: 'post',
+ params: { id: praseStrEmpty(userId) }
+ })
+}
+
+// 导出用户
+export function exportUser(query) {
+ return request({
+ url: '/member/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 用户密码重置
+export function resetUserPwd(id, password) {
+ const data = {
+ id,
+ password
+ }
+ return request({
+ url: '/member/reset_pwd',
+ method: 'post',
+ data: data
+ })
+}
+
+// 用户状态修改
+export function changeUserStatus(id, status) {
+ const data = {
+ id,
+ status
+ }
+ return request({
+ url: '/member/changeStatus',
+ method: 'put',
+ data: data
+ })
+}
+
+// 查询用户个人信息
+export function getUserProfile() {
+ return request({
+ url: '/member/profile',
+ method: 'get'
+ })
+}
+
+// 修改用户个人信息
+export function updateUserProfile(data) {
+ return request({
+ url: '/member/update_profile',
+ method: 'post',
+ data: data
+ })
+}
+
+// 用户密码重置
+export function updateUserPwd(oldPassword, newPassword) {
+ const data = {
+ oldPassword,
+ newPassword
+ }
+ return request({
+ url: '/member/update_pwd',
+ method: 'post',
+ params: data
+ })
+}
+
+// 用户头像上传
+export function uploadAvatar(data) {
+ return request({
+ url: '/member/profile/avatar',
+ method: 'post',
+ data: data
+ })
+}
+
+// 下载用户导入模板
+export function importTemplate() {
+ return request({
+ url: '/system/user/importTemplate',
+ method: 'get'
+ })
+}
+
+// 校验用户名称唯一性
+export function checkUserNameUnique(data) {
+ return request({
+ url: '/member/name_unique',
+ method: 'get',
+ params: data
+ })
+}
+
+export function checkEmailUnique(data) {
+ return request({
+ url: '/member/email_unique',
+ method: 'get',
+ params: data
+ })
+}
+
+export function checkPhoneUnique(data) {
+ return request({
+ url: '/member/mobile_unique',
+ method: 'get',
+ params: data
+ })
+}
+
+// 查询用户详细
+export function getUserInfoByIds(userIds) {
+ return request({
+ url: '/member/getUserInfoByIds',
+ method: 'post',
+ data: userIds
+ })
+}
+
+// 查询角色下用户列表
+export function getRoleUserList(query) {
+ return request({
+ url: '/role/member_list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 插入角色用户
+export function saveRoleUser(data) {
+ return request({
+ url: '/member/addRoleUser',
+ method: 'post',
+ data: data
+ })
+}
diff --git a/hotgo-web/src/api/tool/gen.js b/hotgo-web/src/api/tool/gen.js
new file mode 100644
index 0000000..eefc040
--- /dev/null
+++ b/hotgo-web/src/api/tool/gen.js
@@ -0,0 +1,101 @@
+import request from '@/utils/request'
+
+// 查询生成表数据
+export function listTable (query) {
+ return request({
+ url: '/tool/gen/list',
+ method: 'get',
+ params: query
+ })
+}
+// 查询db数据库列表
+export function listDbTable (query) {
+ return request({
+ url: '/tool/gen/db/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询表详细信息
+export function getGenTable (tableId) {
+ return request({
+ url: '/tool/gen/' + tableId,
+ method: 'get'
+ })
+}
+
+// 修改代码生成信息并同步生成代码
+export function updateGenTableGenCode (data) {
+ return request({
+ url: '/tool/gen/genCode',
+ method: 'put',
+ data: data
+ })
+}
+
+// 修改代码生成信息
+export function updateGenTableNoValidated (data) {
+ return request({
+ url: '/tool/gen/editNoValidated',
+ method: 'post',
+ data: data
+ })
+}
+// 修改代码生成信息
+export function updateGenTable (data) {
+ return request({
+ url: '/tool/gen',
+ method: 'put',
+ data: data
+ })
+}
+
+// 导入表
+export function importTable (data) {
+ return request({
+ url: '/tool/gen/importTable',
+ method: 'post',
+ params: data
+ })
+}
+
+// 预览生成代码
+export function previewTable (tableId) {
+ return request({
+ url: '/tool/gen/preview/' + tableId,
+ method: 'get'
+ })
+}
+
+// 删除表数据
+export function delTable (tableId) {
+ return request({
+ url: '/tool/gen/' + tableId,
+ method: 'delete'
+ })
+}
+
+// 生成代码(自定义路径)
+export function genCode (tableName) {
+ return request({
+ url: '/tool/gen/genCode/' + tableName,
+ method: 'get'
+ })
+}
+
+// 同步数据库
+export function synchDb (tableName) {
+ return request({
+ url: '/tool/gen/synchDb/' + tableName,
+ method: 'get'
+ })
+}
+
+// 生成菜单
+export function addMenu (tableName) {
+ return request({
+ url: '/tool/gen/addMenu/' + tableName,
+ method: 'get'
+ })
+}
diff --git a/hotgo-web/src/api/tool/genConfigTemplate.js b/hotgo-web/src/api/tool/genConfigTemplate.js
new file mode 100644
index 0000000..29f6a49
--- /dev/null
+++ b/hotgo-web/src/api/tool/genConfigTemplate.js
@@ -0,0 +1,98 @@
+import request from '@/utils/request'
+
+// 查询模板配置列表
+export function listTemplate (query) {
+ return request({
+ url: '/system/template/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询模板配置详细
+export function getTemplate (id) {
+ return request({
+ url: '/system/template/' + id,
+ method: 'get'
+ })
+}
+
+// 新增模板配置
+export function addTemplate (data) {
+ return request({
+ url: '/system/template',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改模板配置
+export function updateTemplate (data) {
+ return request({
+ url: '/system/template',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除模板配置
+export function delTemplate (id) {
+ return request({
+ url: '/system/template/' + id,
+ method: 'delete'
+ })
+}
+
+// 导出模板配置
+export function exportTemplate (query) {
+ return request({
+ url: '/system/template/export',
+ method: 'get',
+ params: query
+ })
+}
+
+// 状态修改
+export function changeStatus (id, status) {
+ const data = {
+ id,
+ status
+ }
+ return request({
+ url: '/system/template/changeStatus',
+ method: 'put',
+ data: data
+ })
+}
+
+// 状态修改
+export function changeTemplateDefault (id, templateDefault) {
+ const data = {
+ id,
+ templateDefault
+ }
+ return request({
+ url: '/system/template/changeTemplateDefault',
+ method: 'put',
+ data: data
+ })
+}
+
+// 查询最大编号
+export function findMaxSort () {
+ return request({
+ url: '/system/template/findMaxSort',
+ method: 'get'
+ })
+}
+
+// 校验模板名称是否存在
+export function checkTemplateUnique (id, templateName) {
+ if (id === undefined) {
+ id = ''
+ }
+ return request({
+ url: '/system/template/checkTemplateNameUnique/' + templateName + '/' + id,
+ method: 'get'
+ })
+}
diff --git a/hotgo-web/src/assets/background.svg b/hotgo-web/src/assets/background.svg
new file mode 100644
index 0000000..89c2597
--- /dev/null
+++ b/hotgo-web/src/assets/background.svg
@@ -0,0 +1,69 @@
+
+
+
+ Group 21
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/Alipay.svg b/hotgo-web/src/assets/icons/Alipay.svg
new file mode 100644
index 0000000..06e5acd
--- /dev/null
+++ b/hotgo-web/src/assets/icons/Alipay.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/DragColumn.svg b/hotgo-web/src/assets/icons/DragColumn.svg
new file mode 100644
index 0000000..52f67ae
--- /dev/null
+++ b/hotgo-web/src/assets/icons/DragColumn.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/QRcode.svg b/hotgo-web/src/assets/icons/QRcode.svg
new file mode 100644
index 0000000..686fe0c
--- /dev/null
+++ b/hotgo-web/src/assets/icons/QRcode.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/Sina.svg b/hotgo-web/src/assets/icons/Sina.svg
new file mode 100644
index 0000000..cd0a486
--- /dev/null
+++ b/hotgo-web/src/assets/icons/Sina.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/WeChat.svg b/hotgo-web/src/assets/icons/WeChat.svg
new file mode 100644
index 0000000..06cc18a
--- /dev/null
+++ b/hotgo-web/src/assets/icons/WeChat.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/bug.svg b/hotgo-web/src/assets/icons/bug.svg
new file mode 100644
index 0000000..b7fbf75
--- /dev/null
+++ b/hotgo-web/src/assets/icons/bug.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/build.svg b/hotgo-web/src/assets/icons/build.svg
new file mode 100644
index 0000000..97c4688
--- /dev/null
+++ b/hotgo-web/src/assets/icons/build.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/button.svg b/hotgo-web/src/assets/icons/button.svg
new file mode 100644
index 0000000..ef85344
--- /dev/null
+++ b/hotgo-web/src/assets/icons/button.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/bxAnalyse.svg b/hotgo-web/src/assets/icons/bxAnalyse.svg
new file mode 100644
index 0000000..b02a8d6
--- /dev/null
+++ b/hotgo-web/src/assets/icons/bxAnalyse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/cascader.svg b/hotgo-web/src/assets/icons/cascader.svg
new file mode 100644
index 0000000..e256024
--- /dev/null
+++ b/hotgo-web/src/assets/icons/cascader.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/chart.svg b/hotgo-web/src/assets/icons/chart.svg
new file mode 100644
index 0000000..85b3e0a
--- /dev/null
+++ b/hotgo-web/src/assets/icons/chart.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/checkbox.svg b/hotgo-web/src/assets/icons/checkbox.svg
new file mode 100644
index 0000000..013fd3a
--- /dev/null
+++ b/hotgo-web/src/assets/icons/checkbox.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/clipboard.svg b/hotgo-web/src/assets/icons/clipboard.svg
new file mode 100644
index 0000000..2f290c6
--- /dev/null
+++ b/hotgo-web/src/assets/icons/clipboard.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/codeNew.svg b/hotgo-web/src/assets/icons/codeNew.svg
new file mode 100644
index 0000000..5f9c5ab
--- /dev/null
+++ b/hotgo-web/src/assets/icons/codeNew.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/color.svg b/hotgo-web/src/assets/icons/color.svg
new file mode 100644
index 0000000..44a81aa
--- /dev/null
+++ b/hotgo-web/src/assets/icons/color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/company.svg b/hotgo-web/src/assets/icons/company.svg
new file mode 100644
index 0000000..28be960
--- /dev/null
+++ b/hotgo-web/src/assets/icons/company.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/companyFill.svg b/hotgo-web/src/assets/icons/companyFill.svg
new file mode 100644
index 0000000..0dd910e
--- /dev/null
+++ b/hotgo-web/src/assets/icons/companyFill.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/component.svg b/hotgo-web/src/assets/icons/component.svg
new file mode 100644
index 0000000..29c3458
--- /dev/null
+++ b/hotgo-web/src/assets/icons/component.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/compress.svg b/hotgo-web/src/assets/icons/compress.svg
new file mode 100644
index 0000000..99b9f57
--- /dev/null
+++ b/hotgo-web/src/assets/icons/compress.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/connections.svg b/hotgo-web/src/assets/icons/connections.svg
new file mode 100644
index 0000000..a5e2f7f
--- /dev/null
+++ b/hotgo-web/src/assets/icons/connections.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/dashboardNew.svg b/hotgo-web/src/assets/icons/dashboardNew.svg
new file mode 100644
index 0000000..79065e6
--- /dev/null
+++ b/hotgo-web/src/assets/icons/dashboardNew.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/date.svg b/hotgo-web/src/assets/icons/date.svg
new file mode 100644
index 0000000..52dc73e
--- /dev/null
+++ b/hotgo-web/src/assets/icons/date.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/dateRange.svg b/hotgo-web/src/assets/icons/dateRange.svg
new file mode 100644
index 0000000..fda571e
--- /dev/null
+++ b/hotgo-web/src/assets/icons/dateRange.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/dict.svg b/hotgo-web/src/assets/icons/dict.svg
new file mode 100644
index 0000000..4849377
--- /dev/null
+++ b/hotgo-web/src/assets/icons/dict.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/dingtalk.svg b/hotgo-web/src/assets/icons/dingtalk.svg
new file mode 100644
index 0000000..f2ae3d4
--- /dev/null
+++ b/hotgo-web/src/assets/icons/dingtalk.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/documentation.svg b/hotgo-web/src/assets/icons/documentation.svg
new file mode 100644
index 0000000..ecf1bfe
--- /dev/null
+++ b/hotgo-web/src/assets/icons/documentation.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/download.svg b/hotgo-web/src/assets/icons/download.svg
new file mode 100644
index 0000000..87a04f9
--- /dev/null
+++ b/hotgo-web/src/assets/icons/download.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/dragImg.svg b/hotgo-web/src/assets/icons/dragImg.svg
new file mode 100644
index 0000000..0a5460b
--- /dev/null
+++ b/hotgo-web/src/assets/icons/dragImg.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/dragtable.svg b/hotgo-web/src/assets/icons/dragtable.svg
new file mode 100644
index 0000000..c5ce513
--- /dev/null
+++ b/hotgo-web/src/assets/icons/dragtable.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/druid.svg b/hotgo-web/src/assets/icons/druid.svg
new file mode 100644
index 0000000..a2b4b4e
--- /dev/null
+++ b/hotgo-web/src/assets/icons/druid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/edit.svg b/hotgo-web/src/assets/icons/edit.svg
new file mode 100644
index 0000000..e3cc776
--- /dev/null
+++ b/hotgo-web/src/assets/icons/edit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/expend.svg b/hotgo-web/src/assets/icons/expend.svg
new file mode 100644
index 0000000..91daeed
--- /dev/null
+++ b/hotgo-web/src/assets/icons/expend.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/eyeOpen.svg b/hotgo-web/src/assets/icons/eyeOpen.svg
new file mode 100644
index 0000000..88dcc98
--- /dev/null
+++ b/hotgo-web/src/assets/icons/eyeOpen.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/github.svg b/hotgo-web/src/assets/icons/github.svg
new file mode 100644
index 0000000..db0a0d4
--- /dev/null
+++ b/hotgo-web/src/assets/icons/github.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/guide.svg b/hotgo-web/src/assets/icons/guide.svg
new file mode 100644
index 0000000..60195f7
--- /dev/null
+++ b/hotgo-web/src/assets/icons/guide.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/input.svg b/hotgo-web/src/assets/icons/input.svg
new file mode 100644
index 0000000..ab91381
--- /dev/null
+++ b/hotgo-web/src/assets/icons/input.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/job.svg b/hotgo-web/src/assets/icons/job.svg
new file mode 100644
index 0000000..2a93a25
--- /dev/null
+++ b/hotgo-web/src/assets/icons/job.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/log.svg b/hotgo-web/src/assets/icons/log.svg
new file mode 100644
index 0000000..d879d33
--- /dev/null
+++ b/hotgo-web/src/assets/icons/log.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/loginLog.svg b/hotgo-web/src/assets/icons/loginLog.svg
new file mode 100644
index 0000000..267f844
--- /dev/null
+++ b/hotgo-web/src/assets/icons/loginLog.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/message.svg b/hotgo-web/src/assets/icons/message.svg
new file mode 100644
index 0000000..74986f3
--- /dev/null
+++ b/hotgo-web/src/assets/icons/message.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/monitor.svg b/hotgo-web/src/assets/icons/monitor.svg
new file mode 100644
index 0000000..bc308cb
--- /dev/null
+++ b/hotgo-web/src/assets/icons/monitor.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/number.svg b/hotgo-web/src/assets/icons/number.svg
new file mode 100644
index 0000000..ad5ce9a
--- /dev/null
+++ b/hotgo-web/src/assets/icons/number.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/online.svg b/hotgo-web/src/assets/icons/online.svg
new file mode 100644
index 0000000..330a202
--- /dev/null
+++ b/hotgo-web/src/assets/icons/online.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/password.svg b/hotgo-web/src/assets/icons/password.svg
new file mode 100644
index 0000000..6c64def
--- /dev/null
+++ b/hotgo-web/src/assets/icons/password.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/pdf.svg b/hotgo-web/src/assets/icons/pdf.svg
new file mode 100644
index 0000000..957aa0c
--- /dev/null
+++ b/hotgo-web/src/assets/icons/pdf.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/peoples.svg b/hotgo-web/src/assets/icons/peoples.svg
new file mode 100644
index 0000000..07bb38b
--- /dev/null
+++ b/hotgo-web/src/assets/icons/peoples.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/phone.svg b/hotgo-web/src/assets/icons/phone.svg
new file mode 100644
index 0000000..ab8e8c4
--- /dev/null
+++ b/hotgo-web/src/assets/icons/phone.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/post.svg b/hotgo-web/src/assets/icons/post.svg
new file mode 100644
index 0000000..2922c61
--- /dev/null
+++ b/hotgo-web/src/assets/icons/post.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/question.svg b/hotgo-web/src/assets/icons/question.svg
new file mode 100644
index 0000000..cf75bd4
--- /dev/null
+++ b/hotgo-web/src/assets/icons/question.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/radio.svg b/hotgo-web/src/assets/icons/radio.svg
new file mode 100644
index 0000000..0cde345
--- /dev/null
+++ b/hotgo-web/src/assets/icons/radio.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/rate.svg b/hotgo-web/src/assets/icons/rate.svg
new file mode 100644
index 0000000..aa3b14d
--- /dev/null
+++ b/hotgo-web/src/assets/icons/rate.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/redis.svg b/hotgo-web/src/assets/icons/redis.svg
new file mode 100644
index 0000000..2f1d62d
--- /dev/null
+++ b/hotgo-web/src/assets/icons/redis.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/row.svg b/hotgo-web/src/assets/icons/row.svg
new file mode 100644
index 0000000..0780992
--- /dev/null
+++ b/hotgo-web/src/assets/icons/row.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/select.svg b/hotgo-web/src/assets/icons/select.svg
new file mode 100644
index 0000000..d628382
--- /dev/null
+++ b/hotgo-web/src/assets/icons/select.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/server.svg b/hotgo-web/src/assets/icons/server.svg
new file mode 100644
index 0000000..eb287e3
--- /dev/null
+++ b/hotgo-web/src/assets/icons/server.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/swagger.svg b/hotgo-web/src/assets/icons/swagger.svg
new file mode 100644
index 0000000..05d4e7b
--- /dev/null
+++ b/hotgo-web/src/assets/icons/swagger.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/switch.svg b/hotgo-web/src/assets/icons/switch.svg
new file mode 100644
index 0000000..0ba61e3
--- /dev/null
+++ b/hotgo-web/src/assets/icons/switch.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/system.svg b/hotgo-web/src/assets/icons/system.svg
new file mode 100644
index 0000000..5992593
--- /dev/null
+++ b/hotgo-web/src/assets/icons/system.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/textarea.svg b/hotgo-web/src/assets/icons/textarea.svg
new file mode 100644
index 0000000..2709f29
--- /dev/null
+++ b/hotgo-web/src/assets/icons/textarea.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/time.svg b/hotgo-web/src/assets/icons/time.svg
new file mode 100644
index 0000000..b376e32
--- /dev/null
+++ b/hotgo-web/src/assets/icons/time.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/timeRange.svg b/hotgo-web/src/assets/icons/timeRange.svg
new file mode 100644
index 0000000..13c1202
--- /dev/null
+++ b/hotgo-web/src/assets/icons/timeRange.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/tool.svg b/hotgo-web/src/assets/icons/tool.svg
new file mode 100644
index 0000000..48e0e35
--- /dev/null
+++ b/hotgo-web/src/assets/icons/tool.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/tree.svg b/hotgo-web/src/assets/icons/tree.svg
new file mode 100644
index 0000000..5ec9429
--- /dev/null
+++ b/hotgo-web/src/assets/icons/tree.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/treeTable.svg b/hotgo-web/src/assets/icons/treeTable.svg
new file mode 100644
index 0000000..189533c
--- /dev/null
+++ b/hotgo-web/src/assets/icons/treeTable.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/upload.svg b/hotgo-web/src/assets/icons/upload.svg
new file mode 100644
index 0000000..bae49c0
--- /dev/null
+++ b/hotgo-web/src/assets/icons/upload.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/users.svg b/hotgo-web/src/assets/icons/users.svg
new file mode 100644
index 0000000..573056c
--- /dev/null
+++ b/hotgo-web/src/assets/icons/users.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/icons/validCode.svg b/hotgo-web/src/assets/icons/validCode.svg
new file mode 100644
index 0000000..b9dc3b6
--- /dev/null
+++ b/hotgo-web/src/assets/icons/validCode.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/images/dark.svg b/hotgo-web/src/assets/images/dark.svg
new file mode 100644
index 0000000..f646bd7
--- /dev/null
+++ b/hotgo-web/src/assets/images/dark.svg
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/images/light.svg b/hotgo-web/src/assets/images/light.svg
new file mode 100644
index 0000000..ab7cc08
--- /dev/null
+++ b/hotgo-web/src/assets/images/light.svg
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hotgo-web/src/assets/images/login-background.jpg b/hotgo-web/src/assets/images/login-background.jpg
new file mode 100644
index 0000000..8a89eb8
Binary files /dev/null and b/hotgo-web/src/assets/images/login-background.jpg differ
diff --git a/hotgo-web/src/assets/images/profile.jpg b/hotgo-web/src/assets/images/profile.jpg
new file mode 100644
index 0000000..b3a940b
Binary files /dev/null and b/hotgo-web/src/assets/images/profile.jpg differ
diff --git a/hotgo-web/src/assets/images/upload/excel.svg b/hotgo-web/src/assets/images/upload/excel.svg
new file mode 100644
index 0000000..79fc0ff
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/excel.svg
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/images/upload/gif.svg b/hotgo-web/src/assets/images/upload/gif.svg
new file mode 100644
index 0000000..70f8f15
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/gif.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/images/upload/jpg.svg b/hotgo-web/src/assets/images/upload/jpg.svg
new file mode 100644
index 0000000..172d731
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/jpg.svg
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/images/upload/other.svg b/hotgo-web/src/assets/images/upload/other.svg
new file mode 100644
index 0000000..9a5170e
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/other.svg
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/images/upload/pdf.svg b/hotgo-web/src/assets/images/upload/pdf.svg
new file mode 100644
index 0000000..b894769
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/pdf.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/images/upload/png.svg b/hotgo-web/src/assets/images/upload/png.svg
new file mode 100644
index 0000000..5bb882a
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/png.svg
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/images/upload/ppt.svg b/hotgo-web/src/assets/images/upload/ppt.svg
new file mode 100644
index 0000000..fba4e9a
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/ppt.svg
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/images/upload/text.svg b/hotgo-web/src/assets/images/upload/text.svg
new file mode 100644
index 0000000..77ef4a5
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/text.svg
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/images/upload/word.svg b/hotgo-web/src/assets/images/upload/word.svg
new file mode 100644
index 0000000..a98ade8
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/word.svg
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/images/upload/zip.svg b/hotgo-web/src/assets/images/upload/zip.svg
new file mode 100644
index 0000000..e0446ac
--- /dev/null
+++ b/hotgo-web/src/assets/images/upload/zip.svg
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/assets/login-bg.png b/hotgo-web/src/assets/login-bg.png
new file mode 100644
index 0000000..a9fe20b
Binary files /dev/null and b/hotgo-web/src/assets/login-bg.png differ
diff --git a/hotgo-web/src/assets/logo.png b/hotgo-web/src/assets/logo.png
new file mode 100644
index 0000000..6e994f5
Binary files /dev/null and b/hotgo-web/src/assets/logo.png differ
diff --git a/hotgo-web/src/assets/logo.svg b/hotgo-web/src/assets/logo.svg
new file mode 100644
index 0000000..9c17769
--- /dev/null
+++ b/hotgo-web/src/assets/logo.svg
@@ -0,0 +1,319 @@
+
+
+
+
diff --git a/hotgo-web/src/assets/projects/antdv.png b/hotgo-web/src/assets/projects/antdv.png
new file mode 100644
index 0000000..4ca0b60
Binary files /dev/null and b/hotgo-web/src/assets/projects/antdv.png differ
diff --git a/hotgo-web/src/assets/projects/ruoyi.png b/hotgo-web/src/assets/projects/ruoyi.png
new file mode 100644
index 0000000..755c0d8
Binary files /dev/null and b/hotgo-web/src/assets/projects/ruoyi.png differ
diff --git a/hotgo-web/src/assets/styles/antv-theme.less b/hotgo-web/src/assets/styles/antv-theme.less
new file mode 100644
index 0000000..68a937d
--- /dev/null
+++ b/hotgo-web/src/assets/styles/antv-theme.less
@@ -0,0 +1,705 @@
+@import './default.less';
+
+body {
+ font-family: 'Microsoft YaHei', 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Helvetica Neue', Helvetica, Arial,
+ sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol' !important;
+ a {
+ color: @text-color;
+ }
+ .ant-table,
+ .ant-tree,
+ .ant-select,
+ .ant-input,
+ .ant-select-selection--multiple .ant-select-selection__choice {
+ color: @text-color;
+ font-size: @font-size-base;
+ }
+ .ant-dropdown-trigger {
+ color: @text-color;
+ }
+ .ant-pro-global-header .ant-dropdown-trigger {
+ color: #fff;
+ }
+ .ant-btn > .anticon + span,
+ .ant-btn > span + .anticon {
+ margin-left: 4px;
+ }
+ .ant-tree li .ant-tree-node-content-wrapper {
+ color: @text-color;
+ }
+
+ .ant-card-body {
+ padding: 0;
+ }
+ .ant-modal-title {
+ color: @heading-color;
+ }
+ .table-page-search-wrapper .ant-form-inline .ant-form-item,
+ .table-page-search-wrapper .table-page-search-submitButtons {
+ margin-bottom: 16px;
+ }
+ .table-page-search-wrapper {
+ .ant-form-inline .ant-form-item > .ant-form-item-label {
+ line-height: @input-height-base;
+ }
+ }
+ .ant-table-default .ant-table-thead > tr > th,
+ .ant-table-default .ant-table-tbody > tr > td {
+ padding: 16px 8px;
+ }
+ .ant-table-thead > tr > th,
+ .ant-table-tbody > tr > td,
+ .ant-table-placeholder {
+
+ }
+ .ant-table-wrapper {
+ margin: 0 12px;
+ }
+ .ant-table-small > .ant-table-content > .ant-table-header > table > .ant-table-thead > tr > th,
+ .ant-table-small > .ant-table-content > .ant-table-body > table > .ant-table-thead > tr > th,
+ .ant-table-small > .ant-table-content > .ant-table-scroll > .ant-table-header > table > .ant-table-thead > tr > th,
+ .ant-table-small > .ant-table-content > .ant-table-scroll > .ant-table-body > table > .ant-table-thead > tr > th,
+ .ant-table-small
+ > .ant-table-content
+ > .ant-table-fixed-left
+ > .ant-table-header
+ > table
+ > .ant-table-thead
+ > tr
+ > th,
+ .ant-table-small
+ > .ant-table-content
+ > .ant-table-fixed-right
+ > .ant-table-header
+ > table
+ > .ant-table-thead
+ > tr
+ > th,
+ .ant-table-small
+ > .ant-table-content
+ > .ant-table-fixed-left
+ > .ant-table-body-outer
+ > .ant-table-body-inner
+ > table
+ > .ant-table-thead
+ > tr
+ > th,
+ .ant-table-small
+ > .ant-table-content
+ > .ant-table-fixed-right
+ > .ant-table-body-outer
+ > .ant-table-body-inner
+ > table
+ > .ant-table-thead
+ > tr
+ > th,
+ .ant-table-small > .ant-table-content > .ant-table-header > table > .ant-table-tbody > tr > td,
+ .ant-table-small > .ant-table-content > .ant-table-body > table > .ant-table-tbody > tr > td,
+ .ant-table-small > .ant-table-content > .ant-table-scroll > .ant-table-header > table > .ant-table-tbody > tr > td,
+ .ant-table-small > .ant-table-content > .ant-table-scroll > .ant-table-body > table > .ant-table-tbody > tr > td,
+ .ant-table-small
+ > .ant-table-content
+ > .ant-table-fixed-left
+ > .ant-table-header
+ > table
+ > .ant-table-tbody
+ > tr
+ > td,
+ .ant-table-small
+ > .ant-table-content
+ > .ant-table-fixed-right
+ > .ant-table-header
+ > table
+ > .ant-table-tbody
+ > tr
+ > td,
+ .ant-table-small
+ > .ant-table-content
+ > .ant-table-fixed-left
+ > .ant-table-body-outer
+ > .ant-table-body-inner
+ > table
+ > .ant-table-tbody
+ > tr
+ > td,
+ .ant-table-small
+ > .ant-table-content
+ > .ant-table-fixed-right
+ > .ant-table-body-outer
+ > .ant-table-body-inner
+ > table
+ > .ant-table-tbody
+ > tr
+ > td {
+ padding: 4px 4px;
+ }
+ .ant-table-middle > .ant-table-content > .ant-table-header > table > .ant-table-thead > tr > th,
+ .ant-table-middle > .ant-table-content > .ant-table-body > table > .ant-table-thead > tr > th,
+ .ant-table-middle > .ant-table-content > .ant-table-scroll > .ant-table-header > table > .ant-table-thead > tr > th,
+ .ant-table-middle > .ant-table-content > .ant-table-scroll > .ant-table-body > table > .ant-table-thead > tr > th,
+ .ant-table-middle
+ > .ant-table-content
+ > .ant-table-fixed-left
+ > .ant-table-header
+ > table
+ > .ant-table-thead
+ > tr
+ > th,
+ .ant-table-middle
+ > .ant-table-content
+ > .ant-table-fixed-right
+ > .ant-table-header
+ > table
+ > .ant-table-thead
+ > tr
+ > th,
+ .ant-table-middle
+ > .ant-table-content
+ > .ant-table-fixed-left
+ > .ant-table-body-outer
+ > .ant-table-body-inner
+ > table
+ > .ant-table-thead
+ > tr
+ > th,
+ .ant-table-middle
+ > .ant-table-content
+ > .ant-table-fixed-right
+ > .ant-table-body-outer
+ > .ant-table-body-inner
+ > table
+ > .ant-table-thead
+ > tr
+ > th,
+ .ant-table-middle > .ant-table-content > .ant-table-header > table > .ant-table-tbody > tr > td,
+ .ant-table-middle > .ant-table-content > .ant-table-body > table > .ant-table-tbody > tr > td,
+ .ant-table-middle > .ant-table-content > .ant-table-scroll > .ant-table-header > table > .ant-table-tbody > tr > td,
+ .ant-table-middle > .ant-table-content > .ant-table-scroll > .ant-table-body > table > .ant-table-tbody > tr > td,
+ .ant-table-middle
+ > .ant-table-content
+ > .ant-table-fixed-left
+ > .ant-table-header
+ > table
+ > .ant-table-tbody
+ > tr
+ > td,
+ .ant-table-middle
+ > .ant-table-content
+ > .ant-table-fixed-right
+ > .ant-table-header
+ > table
+ > .ant-table-tbody
+ > tr
+ > td,
+ .ant-table-middle
+ > .ant-table-content
+ > .ant-table-fixed-left
+ > .ant-table-body-outer
+ > .ant-table-body-inner
+ > table
+ > .ant-table-tbody
+ > tr
+ > td,
+ .ant-table-middle
+ > .ant-table-content
+ > .ant-table-fixed-right
+ > .ant-table-body-outer
+ > .ant-table-body-inner
+ > table
+ > .ant-table-tbody
+ > tr
+ > td {
+ padding: 8px 8px;
+ line-height: 24px;
+ }
+ // .ant-table-thead > tr > th {
+ // background: #f7f7f7;
+ // }
+ .ant-table-small > .ant-table-content > .ant-table-body {
+ margin: 0;
+ }
+ .table-operations {
+ margin: 0;
+ }
+ .ant-pro-global-header {
+ height: @layout-header-height;
+ }
+ .ant-pro-global-header-trigger {
+ height: @layout-header-height;
+ line-height: @layout-header-height;
+ }
+ .ant-layout-header {
+ height: @layout-header-height;
+ padding: 0 @layout-header-height;
+ line-height: @layout-header-height;
+ }
+ .ant-pro-global-header-content {
+ height: @layout-header-height;
+ line-height: @layout-header-height;
+ }
+ .ant-pro-drop-down {
+ line-height: @layout-header-height;
+ }
+ .ant-form-explain {
+ font-size: @font-size-base;
+ }
+ .ant-page-header-heading-title {
+ font-size: @spin-dot-size-sm;
+ line-height: 28px;
+ }
+ .ant-form-extra {
+ font-size: @font-size-base;
+ min-height: 18px;
+ }
+ .ant-page-header.has-breadcrumb {
+ padding: 14px 0;
+ }
+ .ant-pro-global-header-index-right .ant-pro-global-header-index-action {
+ padding: 0;
+ }
+ .ant-pro-top-nav-header-menu .ant-menu.ant-menu-horizontal,
+ .ant-pro-top-nav-header .ant-menu-submenu.ant-menu-submenu-horizontal,
+ .ant-pro-top-nav-header-logo,
+ .ant-pro-sider-menu-logo {
+ height: @layout-header-height;
+ line-height: @layout-header-height;
+ }
+ .ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab-active {
+ background: #f0f2f5;
+ border-bottom: 1px solid #f0f2f5;
+ }
+ .ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab {
+ height: 36px;
+ margin-right: 4px;
+ margin-top: 4px;
+ line-height: 36px;
+ }
+ .advanced-table .header-bar .button[data-v-7acdf686] {
+ margin-right: 8px;
+ }
+ .ant-menu-inline-collapsed {
+ width: 100%;
+ }
+ .ant-menu-inline-collapsed > .ant-menu-item,
+ .ant-menu-inline-collapsed > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item,
+ .ant-menu-inline-collapsed
+ > .ant-menu-item-group
+ > .ant-menu-item-group-list
+ > .ant-menu-submenu
+ > .ant-menu-submenu-title,
+ .ant-menu-inline-collapsed > .ant-menu-submenu > .ant-menu-submenu-title {
+ padding: 0 20px !important;
+ }
+ .ant-pro-sider-menu-logo {
+ padding-left: 10px;
+ }
+ .ant-pro-sider-menu-logo img {
+ width: 38px;
+ height: 38px;
+ }
+ .ant-layout .ant-table-pagination.ant-pagination {
+ margin: 12px 0 4px 0;
+ }
+ .ant-pagination {
+ .ant-select {
+ min-height: auto;
+ }
+ }
+ .advanced-table .header-bar .button[data-v-6ac60990] {
+ margin: 0;
+ }
+ .table-page-search-wrapper {
+ padding: 16px 32px;
+ padding-bottom: 0;
+ }
+ .table-page-search-wrapper .ant-form-inline .ant-form-item .ant-form-item-control,
+ .ant-select-selection--single,
+ .ant-input {
+ height: @input-height-base;
+ line-height: @input-height-base;
+ border-color: @border-color-base;
+ }
+
+ .advanced-table .header-bar .title[data-v-6ac60990] {
+ font-size: @font-size-base + 2;
+ font-weight: 400;
+ color: @heading-color;
+ }
+ .ant-pagination-prev,
+ .ant-pagination-next,
+ .ant-pagination-jump-prev,
+ .ant-pagination-jump-next {
+ min-width: @input-height-base;
+ height: @input-height-base;
+ }
+
+ .ant-form-item-label > label {
+ color: @text-color;
+ }
+ .ant-menu-vertical .ant-menu-item,
+ .ant-menu-vertical-left .ant-menu-item,
+ .ant-menu-vertical-right .ant-menu-item,
+ .ant-menu-inline .ant-menu-item,
+ .ant-menu-vertical .ant-menu-submenu-title,
+ .ant-menu-vertical-left .ant-menu-submenu-title,
+ .ant-menu-vertical-right .ant-menu-submenu-title,
+ .ant-menu-inline .ant-menu-submenu-title {
+ font-size: 14px;
+ color: @heading-color;
+ .anticon{
+ font-size: 16px;
+ vertical-align: middle;
+ }
+
+ }
+
+ .ant-menu-submenu-selected > .ant-menu-submenu-title {
+ color: @primary-color;
+ }
+ .ant-menu-inline-collapsed > .ant-menu-item .anticon,
+ .ant-menu-inline-collapsed > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item .anticon,
+ .ant-menu-inline-collapsed
+ > .ant-menu-item-group
+ > .ant-menu-item-group-list
+ > .ant-menu-submenu
+ > .ant-menu-submenu-title
+ .anticon,
+ .ant-menu-inline-collapsed > .ant-menu-submenu > .ant-menu-submenu-title .anticon {
+ font-size: 18px;
+ }
+ .ant-menu-item > a {
+ color: @heading-color;
+ }
+ .ant-menu-item-selected > a,
+ .ant-menu-item-selected > a:hover {
+ color: @primary-color;
+ }
+ .ant-table,
+ .ant-form {
+ font-size: @font-size-base;
+ }
+ input.ant-form {
+ font-size: @font-size-base;
+ }
+ .ant-form-item {
+ font-size: @font-size-base;
+ }
+ .has-error .ant-form-explain,
+ .has-error .ant-form-split {
+ font-size: @font-size-sm;
+ }
+ .ant-form label,
+ .ant-input,
+ .ant-select {
+ font-size: @font-size-base;
+ }
+ .ant-form-item-label {
+ line-height: 1.5;
+ padding-bottom: 6px;
+ }
+ .ant-select-selection {
+ border-top-width: 1px;
+ }
+ .ant-select-selection--multiple {
+ min-height: calc(@input-height-base - 4px);
+ padding-bottom: 2px;
+ }
+ .ant-select-selection--multiple > ul > li,
+ .ant-select-selection--multiple .ant-select-selection__rendered > ul > li {
+ margin-top: 2px;
+ height: calc(@input-height-base - 6px);
+ line-height: calc(@input-height-base - 8px);
+ }
+ .ant-radio-button-wrapper {
+ height: @input-height-base;
+ }
+ .ant-select-selection--multiple .ant-select-selection__rendered {
+ margin-left: 2px;
+ }
+ .ant-select-selection__rendered {
+ line-height: calc(@input-height-base - 2px);
+ }
+ .ant-form-sm label,
+ .ant-input-sm,
+ .ant-select-sm,
+ .ant-form-item-label-sm {
+ font-size: @font-size-base;
+ height: @input-height-sm;
+ line-height: @input-height-sm;
+ }
+ .ant-form-lg label,
+ .ant-input-lg,
+ .ant-select-lg,
+ .ant-form-item-label-lg {
+ font-size: @font-size-base;
+ height: @input-height-lg;
+ line-height: @input-height-lg;
+ }
+
+ .ant-input-number {
+ line-height: @input-height-base;
+ height: @input-height-base;
+ }
+ .ant-input-number-input {
+ height: calc(@input-height-base - 2px);
+ line-height: calc(@input-height-base - 2px);
+ }
+ .ant-form .ant-form-item .ant-form-item-control {
+ line-height: inherit;
+ }
+ .aidex-modal-size-adjust,
+ .ant-modal-close-x {
+ width: 48px;
+ height: 48px;
+ line-height: 48px;
+ }
+ .ant-modal-header {
+ .aidex-modal-size-adjust {
+ margin-right: -24px;
+ }
+ }
+ .ant-modal-footer {
+ padding: 13px 16px;
+ }
+ .ant-pro-global-header,
+ .ant-pro-sider-menu-sider.light .ant-pro-sider-menu-logo {
+ background: @primary-color;
+ box-shadow: none;
+ transform: none;
+ transition: none;
+ }
+ .ant-pro-sider-menu-sider.light .ant-pro-sider-menu-logo h1 {
+ color: #fff;
+ }
+ .ant-pro-page-header-wrap-page-header-warp {
+ background-color: inherit;
+ color: #fff;
+ }
+ .ant-space-align-center {
+ color: #fff;
+ }
+ .ant-pro-global-header .ant-pro-global-header-index-action i,
+ .ant-pro-global-header-trigger {
+ color: #fff;
+ }
+ .ant-breadcrumb {
+ color: rgba(255, 255, 255, 0.65);
+ }
+ .ant-breadcrumb a {
+ color: rgba(255, 255, 255, 0.65);
+ }
+ .ant-breadcrumb-separator {
+ color: rgba(255, 255, 255, 0.65);
+ }
+ .ant-breadcrumb > span:last-child {
+ color: rgba(255, 255, 255, 0.95);
+ }
+ .ant-list-item-meta-description a {
+ color: @text-color;
+ }
+ .ant-list-item-meta-description a:hover {
+ color: @primary-color;
+ }
+ .ant-btn.ant-btn-link {
+ border: 0;
+ height: auto;
+ padding: 0;
+ }
+ .ant-btn {
+ height: @btn-height-base;
+ padding: 0 14px;
+ font-size: @font-size-base;
+ border-radius: 2px;
+ min-width: 66px;
+ color: @text-color;
+ border-color: @border-color-base;
+ }
+ .ant-btn-primary.ant-btn {
+ border-color: @primary-color;
+ color: #fff;
+ }
+ .ant-btn-primary.ant-btn[disabled] {
+ border-color: @border-color-base;
+ color: @text-color;
+ }
+ .ant-btn-danger.ant-btn {
+ border-color: @error-color;
+ color: #fff;
+ }
+ .ant-btn-background-ghost.ant-btn-danger {
+ color: @error-color;
+ }
+ .ant-btn-danger.ant-btn[disabled] {
+ border-color: @border-color-base;
+ color: @text-color;
+ }
+ .ant-btn-background-ghost.ant-btn-primary {
+ color: @primary-color;
+ }
+ .ant-table-row i {
+ padding-right: 8px;
+ &.depIcon {
+ font-size: 20px;
+ color: @primary-color;
+ line-height: 20px;
+ height: 20px;
+ vertical-align: middle;
+ margin-top: -4px;
+ }
+ }
+ .ant-table-row-cell-break-word {
+ a {
+ color: @primary-color;
+ }
+ }
+
+ .ant-collapse-borderless > .ant-collapse-item:last-child {
+ &.ant-collapse-item-active {
+ .ant-collapse-header {
+ margin-bottom: 16px;
+ }
+ }
+ }
+ .ant-avatar {
+ font-size: @font-size-sm;
+ }
+ .ant-avatar-sm{
+ width: 32px;
+ height: 32px;
+ margin:calc((50px - 32px) / 2)!important;
+
+ }
+ /* 树形控件样式 */
+ .ant-tree {
+ li {
+ padding: 2px 0;
+ span.ant-tree-switcher,
+ .ant-tree li span.ant-tree-iconEle {
+ vertical-align: middle;
+ width: 18px;
+ line-height: 32px;
+ }
+ .ant-tree-node-content-wrapper {
+ padding: 0 4px;
+ height: 32px;
+ line-height: 32px;
+ width: calc(100% - 20px);
+ .ant-tree-iconEle {
+ vertical-align: middle;
+ }
+ .depIcon {
+ color: #2b2f36;
+ }
+ }
+ .ant-tree-node-selected {
+ .depIcon,
+ .ant-tree-title {
+ color: @primary-color;
+ }
+ }
+ .ant-tree-node-content-wrapper.ant-tree-node-selected {
+ background-color: @primary-1;
+ }
+ .ant-tree-title {
+ padding: 0 4px;
+ }
+ }
+ .ant-tree-child-tree > li:first-child {
+ padding: 0;
+ }
+ }
+ .ant-select-tree li .ant-select-tree-node-content-wrapper {
+ color: @text-color;
+ }
+ /* 导航栏修改 */
+ .ant-menu-inline .ant-menu-item {
+ margin: 0;
+ }
+ .ant-menu-vertical .ant-menu-item:not(:last-child),
+ .ant-menu-vertical-left .ant-menu-item:not(:last-child),
+ .ant-menu-vertical-right .ant-menu-item:not(:last-child),
+ .ant-menu-inline .ant-menu-item:not(:last-child) {
+ margin-bottom: 0;
+ }
+ /* 弹出form表单修改 */
+ .ant-form-vertical {
+ .ant-form-item {
+ padding-bottom: 0;
+ }
+ .ant-form-item-required::before {
+ position: absolute;
+ right: 0;
+ top: 4px;
+ }
+ .ant-form-item-required {
+ padding-right: 14px;
+ }
+ }
+ // 折叠面板样式修改
+ .ant-collapse-borderless > .ant-collapse-item:last-child .ant-collapse-header {
+ padding: 0 16px;
+ color: @primary-color;
+ }
+ .ant-collapse-content > .ant-collapse-content-box {
+ padding: 0;
+ }
+ .ant-collapse > .ant-collapse-item > .ant-collapse-header .ant-collapse-arrow {
+ left: 0;
+ }
+ // 折叠表格样式修改
+ tr.ant-table-expanded-row,
+ tr.ant-table-expanded-row:hover {
+ background: #fafafa;
+ .ant-card {
+ padding: 8px;
+ background: inherit;
+ }
+ .ant-table-wrapper {
+ margin: 0;
+ }
+ .table-operations {
+ padding-bottom: 8px;
+ text-align: right;
+ }
+ .table_title {
+ float: left;
+ padding-left: 8px;
+ font-weight: @typography-title-font-weight;
+ color: @heading-color;
+ line-height: @btn-height-base;
+ }
+ }
+ .vditor-toolbar {
+ padding: 0 8px !important;
+ }
+ .vditor-reset {
+ padding: 8px !important;
+ }
+ .selectIconBox {
+ border: 1px solid @border-color-base;
+ border-radius: @border-radius-base;
+ height: @input-height-base;
+ width: 100%;
+ .anticon {
+ color: @primary-color;
+ font-size: 16px;
+ padding: 0 12px;
+ }
+ .selectup {
+ .anticon {
+ color: @text-color;
+ font-size: @font-size-base;
+ }
+ }
+ .ant-space-item {
+ margin: 0 !important;
+ }
+ .selectup {
+ position: absolute;
+ right: 0;
+ top: -2px;
+ width: 80%;
+ text-align: right;
+ }
+ }
+}
diff --git a/hotgo-web/src/assets/styles/default.less b/hotgo-web/src/assets/styles/default.less
new file mode 100644
index 0000000..43a27eb
--- /dev/null
+++ b/hotgo-web/src/assets/styles/default.less
@@ -0,0 +1,700 @@
+@import '~ant-design-vue/lib/style/color/colors';
+
+// The prefix to use on all css classes from ant.
+@ant-prefix: ant;
+
+// An override for the html selector for theme prefixes
+@html-selector: html;
+
+// -------- Colors -----------
+@primary-color: @blue-6;
+@info-color: @blue-6;
+@success-color: @green-6;
+@processing-color: @blue-6;
+@error-color: @red-6;
+@highlight-color: @red-6;
+@warning-color: @gold-6;
+@normal-color: #d9d9d9;
+@white: #fff;
+@black: #000;
+
+// Color used by default to control hover and active backgrounds and for
+// alert info backgrounds.
+@primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%)
+@primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%)
+@primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused
+@primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused
+@primary-5: color(
+ ~`colorPalette('@{primary-color}', 5) `
+); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%)
+@primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color
+@primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%)
+@primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused
+@primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused
+@primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused
+
+// Base Scaffolding Variables
+// ---
+
+// Background color for ``
+@body-background: #fff;
+// Base background color for most components
+@component-background: #fff;
+@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB',
+ 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji',
+ 'Segoe UI Emoji', 'Segoe UI Symbol';
+@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
+@text-color:#444444;
+@text-color-secondary:#8c8c8c;
+@text-color-inverse: @white;
+@icon-color: inherit;
+@icon-color-hover: fade(@black, 75%);
+@heading-color: #222222;
+@heading-color-dark: fade(@white, 100%);
+@text-color-dark: fade(@white, 85%);
+@text-color-secondary-dark: fade(@white, 65%);
+@text-selection-bg: @primary-color;
+@font-variant-base: tabular-nums;
+@font-feature-settings-base: 'tnum';
+@font-size-base: 13px;
+@font-size-lg: @font-size-base + 2px;
+@font-size-sm: 12px;
+@heading-1-size: ceil(@font-size-base * 2.71);
+@heading-2-size: ceil(@font-size-base * 2.14);
+@heading-3-size: ceil(@font-size-base * 1.71);
+@heading-4-size: ceil(@font-size-base * 1.42);
+@line-height-base: 1.5;
+@border-radius-base: 4px;
+@border-radius-sm: 2px;
+
+// vertical paddings
+@padding-lg: 24px; // containers
+@padding-md: 16px; // small containers and buttons
+@padding-sm: 12px; // Form controls and items
+@padding-xs: 8px; // small items
+
+// vertical padding for all form controls
+@control-padding-horizontal: @padding-sm;
+@control-padding-horizontal-sm: @padding-xs;
+
+// The background colors for active and hover states for things like
+// list items or table cells.
+@item-active-bg: @primary-1;
+@item-hover-bg: @primary-1;
+
+// ICONFONT
+@iconfont-css-prefix: anticon;
+
+// LINK
+@link-color: @primary-color;
+@link-hover-color: color(~`colorPalette('@{link-color}', 5) `);
+@link-active-color: color(~`colorPalette('@{link-color}', 7) `);
+@link-decoration: none;
+@link-hover-decoration: none;
+
+// Animation
+@ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1);
+@ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7);
+@ease-out: cubic-bezier(0.215, 0.61, 0.355, 1);
+@ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+@ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1);
+@ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46);
+@ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6);
+@ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46);
+@ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1);
+@ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+@ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
+@ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+@ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);
+
+// Border color
+@border-color-base:#dee0e3; // base border outline a component
+@border-color-split: hsv(0, 0, 91%); // split border inside a component
+@border-color-inverse: @white;
+@border-width-base: 1px; // width of the border for a component
+@border-style-base: solid; // style of a components border
+
+// Outline
+@outline-blur-size: 0;
+@outline-width: 2px;
+@outline-color: @primary-color;
+
+@background-color-light: hsv(0, 0, 98%); // background of header and selected item
+@background-color-base: hsv(0, 0, 96%); // Default grey background color
+
+// Disabled states
+@disabled-color: fade(#000, 25%);
+@disabled-bg: @background-color-base;
+@disabled-color-dark: fade(#fff, 35%);
+
+// Shadow
+@shadow-color: rgba(0, 0, 0, 0.15);
+@shadow-color-inverse: @component-background;
+@box-shadow-base: @shadow-1-down;
+@shadow-1-up: 0 -2px 8px @shadow-color;
+@shadow-1-down: 0 2px 8px @shadow-color;
+@shadow-1-left: -2px 0 8px @shadow-color;
+@shadow-1-right: 2px 0 8px @shadow-color;
+@shadow-2: 0 4px 12px @shadow-color;
+
+// Buttons
+@btn-font-weight: 400;
+@btn-border-radius-base: @border-radius-base;
+@btn-border-radius-sm: @border-radius-base;
+@btn-border-width: @border-width-base;
+@btn-border-style: @border-style-base;
+@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
+@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
+@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
+
+@btn-primary-color: #fff;
+@btn-primary-bg: @primary-color;
+
+@btn-default-color: @text-color;
+@btn-default-bg: @component-background;
+@btn-default-border: @border-color-base;
+
+@btn-danger-color: #fff;
+@btn-danger-bg: color(~`colorPalette('@{error-color}', 5) `);
+@btn-danger-border: color(~`colorPalette('@{error-color}', 5) `);
+
+@btn-disable-color: @disabled-color;
+@btn-disable-bg: @disabled-bg;
+@btn-disable-border: @border-color-base;
+
+@btn-padding-base: 0 @padding-md - 1px;
+@btn-font-size-lg: @font-size-lg;
+@btn-font-size-sm: @font-size-base;
+@btn-padding-lg: @btn-padding-base;
+@btn-padding-sm: 0 @padding-xs - 1px;
+
+@btn-height-base: 30px;
+@btn-height-lg: 40px;
+@btn-height-sm: 24px;
+
+@btn-circle-size: @btn-height-base;
+@btn-circle-size-lg: @btn-height-lg;
+@btn-circle-size-sm: @btn-height-sm;
+
+@btn-square-size: @btn-height-base;
+@btn-square-size-lg: @btn-height-lg;
+@btn-square-size-sm: @btn-height-sm;
+
+@btn-group-border: @primary-5;
+
+// Checkbox
+@checkbox-size: 16px;
+@checkbox-color: @primary-color;
+@checkbox-check-color: #fff;
+@checkbox-border-width: @border-width-base;
+
+// Descriptions
+@descriptions-bg: #fafafa;
+
+// Dropdown
+@dropdown-selected-color: @primary-color;
+
+// Empty
+@empty-font-size: @font-size-base;
+
+// Radio
+@radio-size: 16px;
+@radio-dot-color: @primary-color;
+
+// Radio buttons
+@radio-button-bg: @btn-default-bg;
+@radio-button-checked-bg: @btn-default-bg;
+@radio-button-color: @btn-default-color;
+@radio-button-hover-color: @primary-5;
+@radio-button-active-color: @primary-7;
+
+// Media queries breakpoints
+// Extra small screen / phone
+@screen-xs: 480px;
+@screen-xs-min: @screen-xs;
+
+// Small screen / tablet
+@screen-sm: 576px;
+@screen-sm-min: @screen-sm;
+
+// Medium screen / desktop
+@screen-md: 768px;
+@screen-md-min: @screen-md;
+
+// Large screen / wide desktop
+@screen-lg: 992px;
+@screen-lg-min: @screen-lg;
+
+// Extra large screen / full hd
+@screen-xl: 1200px;
+@screen-xl-min: @screen-xl;
+
+// Extra extra large screen / large desktop
+@screen-xxl: 1600px;
+@screen-xxl-min: @screen-xxl;
+
+// provide a maximum
+@screen-xs-max: (@screen-sm-min - 1px);
+@screen-sm-max: (@screen-md-min - 1px);
+@screen-md-max: (@screen-lg-min - 1px);
+@screen-lg-max: (@screen-xl-min - 1px);
+@screen-xl-max: (@screen-xxl-min - 1px);
+
+// Grid system
+@grid-columns: 24;
+@grid-gutter-width: 0;
+
+// Layout
+@layout-body-background: #f0f2f5;
+@layout-header-background: #001529;
+@layout-footer-background: @layout-body-background;
+@layout-header-height: 50px;
+@layout-header-padding: 0 50px;
+@layout-footer-padding: 24px 50px;
+@layout-sider-background: @layout-header-background;
+@layout-trigger-height: 48px;
+@layout-trigger-background: #002140;
+@layout-trigger-color: #fff;
+@layout-zero-trigger-width: 36px;
+@layout-zero-trigger-height: 42px;
+// Layout light theme
+@layout-sider-background-light: #fff;
+@layout-trigger-background-light: #fff;
+@layout-trigger-color-light: @text-color;
+
+// z-index list, order by `z-index`
+@zindex-badge: 1;
+@zindex-table-fixed: 1;
+@zindex-affix: 10;
+@zindex-back-top: 10;
+@zindex-picker-panel: 10;
+@zindex-popup-close: 10;
+@zindex-modal: 1000;
+@zindex-modal-mask: 1000;
+@zindex-message: 1010;
+@zindex-notification: 1010;
+@zindex-popover: 1030;
+@zindex-dropdown: 1050;
+@zindex-picker: 1050;
+@zindex-tooltip: 1060;
+
+// Animation
+@animation-duration-slow: 0.3s; // Modal
+@animation-duration-base: 0.2s;
+@animation-duration-fast: 0.1s; // Tooltip
+
+//CollapsePanel
+@collapse-panel-border-radius: @border-radius-base;
+
+//Dropdown
+@dropdown-vertical-padding: 5px;
+@dropdown-edge-child-vertical-padding: 4px;
+@dropdown-font-size: @font-size-base;
+@dropdown-line-height: 22px;
+
+// Form
+// ---
+@label-required-color: @highlight-color;
+@label-color: @heading-color;
+@form-warning-input-bg: @input-bg;
+@form-item-margin-bottom: 24px;
+@form-item-trailing-colon: true;
+@form-vertical-label-padding: 0 0 8px;
+@form-vertical-label-margin: 0;
+@form-item-label-colon-margin-right: 8px;
+@form-item-label-colon-margin-left: 2px;
+@form-error-input-bg: @input-bg;
+
+// Input
+// ---
+@input-height-base: 30px;
+@input-height-lg: 40px;
+@input-height-sm: 24px;
+@input-padding-horizontal: @control-padding-horizontal - 1px;
+@input-padding-horizontal-base: @input-padding-horizontal;
+@input-padding-horizontal-sm: @control-padding-horizontal-sm - 1px;
+@input-padding-horizontal-lg: @input-padding-horizontal;
+@input-padding-vertical-base: 4px;
+@input-padding-vertical-sm: 1px;
+@input-padding-vertical-lg: 6px;
+@input-placeholder-color: hsv(0, 0, 75%);
+@input-color: @text-color;
+@input-border-color: @border-color-base;
+@input-bg: @component-background;
+@input-number-hover-border-color: @input-hover-border-color;
+@input-number-handler-active-bg: #f4f4f4;
+@input-number-handler-hover-bg: @primary-5;
+@input-number-handler-bg: @component-background;
+@input-number-handler-border-color: @border-color-base;
+@input-addon-bg: @background-color-light;
+@input-hover-border-color: @primary-5;
+@input-disabled-bg: @disabled-bg;
+@input-outline-offset: 0 0;
+
+// Select
+// ---
+@select-border-color: @border-color-base;
+@select-item-selected-color: @text-color;
+@select-item-selected-font-weight: 600;
+@select-dropdown-bg: @component-background;
+@select-dropdown-vertical-padding: @dropdown-vertical-padding;
+@select-dropdown-edge-child-vertical-padding: @dropdown-edge-child-vertical-padding;
+@select-dropdown-font-size: @dropdown-font-size;
+@select-dropdown-line-height: @dropdown-line-height;
+@select-item-selected-bg: @background-color-light;
+@select-item-active-bg: @item-active-bg;
+@select-background: @component-background;
+
+// Cascader
+// ----
+@cascader-dropdown-vertical-padding: @dropdown-vertical-padding;
+@cascader-dropdown-edge-child-vertical-padding: @dropdown-edge-child-vertical-padding;
+@cascader-dropdown-font-size: @dropdown-font-size;
+@cascader-dropdown-line-height: @dropdown-line-height;
+
+// Anchor
+// ---
+@anchor-border-color: @border-color-split;
+
+// Tooltip
+// ---
+// Tooltip max width
+@tooltip-max-width: 250px;
+// Tooltip text color
+@tooltip-color: #fff;
+// Tooltip background color
+@tooltip-bg: rgba(0, 0, 0, 0.75);
+// Tooltip arrow width
+@tooltip-arrow-width: 5px;
+// Tooltip distance with trigger
+@tooltip-distance: @tooltip-arrow-width - 1px + 4px;
+// Tooltip arrow color
+@tooltip-arrow-color: @tooltip-bg;
+
+// Popover
+// ---
+// Popover body background color
+@popover-bg: @component-background;
+// Popover text color
+@popover-color: @text-color;
+// Popover maximum width
+@popover-min-width: 177px;
+// Popover arrow width
+@popover-arrow-width: 6px;
+// Popover arrow color
+@popover-arrow-color: @popover-bg;
+// Popover outer arrow width
+// Popover outer arrow color
+@popover-arrow-outer-color: @popover-bg;
+// Popover distance with trigger
+@popover-distance: @popover-arrow-width + 4px;
+
+// Modal
+// --
+@modal-body-padding: 24px;
+@modal-header-bg: @component-background;
+@modal-header-border-color-split: @border-color-split;
+@modal-heading-color: @heading-color;
+@modal-footer-bg: transparent;
+@modal-footer-border-color-split: @border-color-split;
+@modal-mask-bg: fade(@black, 45%);
+
+// Progress
+// --
+@progress-default-color: @processing-color;
+@progress-remaining-color: @background-color-base;
+@progress-text-color: @text-color;
+@progress-radius: 100px;
+
+// Menu
+// ---
+@menu-inline-toplevel-item-height: 40px;
+@menu-item-height: 40px;
+@menu-collapsed-width: 80px;
+@menu-bg: @component-background;
+@menu-popup-bg: @component-background;
+@menu-item-color: @text-color;
+@menu-highlight-color: @primary-color;
+@menu-item-active-bg: @item-active-bg;
+@menu-item-active-border-width: 3px;
+@menu-item-group-title-color: @text-color-secondary;
+@menu-icon-size: @font-size-base;
+@menu-icon-size-lg: @font-size-lg;
+
+@menu-item-vertical-margin: 4px;
+@menu-item-font-size: @font-size-base;
+@menu-item-boundary-margin: 8px;
+
+// dark theme
+@menu-dark-color: @text-color-secondary-dark;
+@menu-dark-bg: @layout-header-background;
+@menu-dark-arrow-color: #fff;
+@menu-dark-submenu-bg: #000c17;
+@menu-dark-highlight-color: #fff;
+@menu-dark-item-active-bg: @primary-color;
+@menu-dark-selected-item-icon-color: @white;
+@menu-dark-selected-item-text-color: @white;
+@menu-dark-item-hover-bg: transparent;
+// Spin
+// ---
+@spin-dot-size-sm: 14px;
+@spin-dot-size: 16px;
+@spin-dot-size-lg: 32px;
+
+// Table
+// --
+@table-header-bg: @background-color-light;
+@table-header-color: @heading-color;
+@table-header-sort-bg: @background-color-base;
+@table-body-sort-bg: rgba(0, 0, 0, 0.01);
+@table-row-hover-bg: @primary-1;
+@table-selected-row-color: inherit;
+@table-selected-row-bg: #fafafa;
+@table-body-selected-sort-bg: @table-selected-row-bg;
+@table-selected-row-hover-bg: @table-selected-row-bg;
+@table-expanded-row-bg: #fbfbfb;
+@table-padding-vertical: 8px;
+@table-padding-horizontal: 8px;
+@table-border-radius-base: @border-radius-base;
+@table-footer-bg: @background-color-light;
+@table-footer-color: @heading-color;
+@table-header-bg-sm: transparent;
+
+// Tag
+// --
+@tag-default-bg: @background-color-light;
+@tag-default-color: @text-color;
+@tag-font-size: @font-size-sm;
+
+// TimePicker
+// ---
+@time-picker-panel-column-width: 56px;
+@time-picker-panel-width: @time-picker-panel-column-width * 3;
+@time-picker-selected-bg: @background-color-base;
+
+// Carousel
+// ---
+@carousel-dot-width: 16px;
+@carousel-dot-height: 3px;
+@carousel-dot-active-width: 24px;
+
+// Badge
+// ---
+@badge-height: 20px;
+@badge-dot-size: 6px;
+@badge-font-size: @font-size-sm;
+@badge-font-weight: normal;
+@badge-status-size: 6px;
+@badge-text-color: @component-background;
+
+// Rate
+// ---
+@rate-star-color: @yellow-6;
+@rate-star-bg: @border-color-split;
+
+// Card
+// ---
+@card-head-color: @heading-color;
+@card-head-background: transparent;
+@card-head-padding: 16px;
+@card-inner-head-padding: 12px;
+@card-padding-base: 24px;
+@card-actions-background: @background-color-light;
+@card-skeleton-bg: #cfd8dc;
+@card-background: @component-background;
+@card-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
+@card-radius: @border-radius-sm;
+
+// Comment
+// ---
+@comment-padding-base: 16px 0;
+@comment-nest-indent: 44px;
+@comment-font-size-base: @font-size-base;
+@comment-font-size-sm: @font-size-sm;
+@comment-author-name-color: @text-color-secondary;
+@comment-author-time-color: #ccc;
+@comment-action-color: @text-color-secondary;
+@comment-action-hover-color: #595959;
+
+// Tabs
+// ---
+@tabs-card-head-background: @background-color-light;
+@tabs-card-height: 40px;
+@tabs-card-active-color: @primary-color;
+@tabs-title-font-size: @font-size-base;
+@tabs-title-font-size-lg: @font-size-lg;
+@tabs-title-font-size-sm: @font-size-base;
+@tabs-ink-bar-color: @primary-color;
+@tabs-bar-margin: 0 0 16px 0;
+@tabs-horizontal-margin: 0 32px 0 0;
+@tabs-horizontal-padding: 12px 16px;
+@tabs-horizontal-padding-lg: 16px;
+@tabs-horizontal-padding-sm: 8px 16px;
+@tabs-vertical-padding: 8px 24px;
+@tabs-vertical-margin: 0 0 16px 0;
+@tabs-scrolling-size: 32px;
+@tabs-highlight-color: @primary-color;
+@tabs-hover-color: @primary-5;
+@tabs-active-color: @primary-7;
+@tabs-card-gutter: 2px;
+@tabs-card-tab-active-border-top: 2px solid transparent;
+
+// BackTop
+// ---
+@back-top-color: #fff;
+@back-top-bg: @text-color-secondary;
+@back-top-hover-bg: @text-color;
+
+// Avatar
+// ---
+@avatar-size-base: 32px;
+@avatar-size-lg: 40px;
+@avatar-size-sm: 24px;
+@avatar-font-size-base: 18px;
+@avatar-font-size-lg: 24px;
+@avatar-font-size-sm: 14px;
+@avatar-bg: #ccc;
+@avatar-color: #fff;
+@avatar-border-radius: @border-radius-base;
+
+// Switch
+// ---
+@switch-height: 22px;
+@switch-sm-height: 16px;
+@switch-sm-checked-margin-left: -(@switch-sm-height - 3px);
+@switch-disabled-opacity: 0.4;
+@switch-color: @primary-color;
+@switch-shadow-color: fade(#00230b, 20%);
+
+// Pagination
+// ---
+@pagination-item-size: 32px;
+@pagination-item-size-sm: 24px;
+@pagination-font-family: Arial;
+@pagination-font-weight-active: 500;
+@pagination-item-bg-active: @component-background;
+
+// PageHeader
+// ---
+@page-header-padding: 24px;
+@page-header-padding-vertical: 16px;
+@page-header-padding-breadcrumb: 12px;
+@page-header-back-color: #000;
+
+// Breadcrumb
+// ---
+@breadcrumb-base-color: @text-color-secondary;
+@breadcrumb-last-item-color: @text-color;
+@breadcrumb-font-size: @font-size-base;
+@breadcrumb-icon-font-size: @font-size-base;
+@breadcrumb-link-color: @text-color-secondary;
+@breadcrumb-link-color-hover: @primary-5;
+@breadcrumb-separator-color: @text-color-secondary;
+@breadcrumb-separator-margin: 0 @padding-xs;
+
+// Slider
+// ---
+@slider-margin: 14px 6px 10px;
+@slider-rail-background-color: @background-color-base;
+@slider-rail-background-color-hover: #e1e1e1;
+@slider-track-background-color: @primary-3;
+@slider-track-background-color-hover: @primary-4;
+@slider-handle-border-width: 2px;
+@slider-handle-background-color: @component-background;
+@slider-handle-color: @primary-3;
+@slider-handle-color-hover: @primary-4;
+@slider-handle-color-focus: tint(@primary-color, 20%);
+@slider-handle-color-focus-shadow: fade(@primary-color, 20%);
+@slider-handle-color-tooltip-open: @primary-color;
+@slider-handle-shadow: 0;
+@slider-dot-border-color: @border-color-split;
+@slider-dot-border-color-active: tint(@primary-color, 50%);
+@slider-disabled-color: @disabled-color;
+@slider-disabled-background-color: @component-background;
+
+// Tree
+// ---
+@tree-title-height: 24px;
+@tree-child-padding: 18px;
+@tree-directory-selected-color: #fff;
+@tree-directory-selected-bg: @primary-color;
+@tree-node-hover-bg: @item-hover-bg;
+@tree-node-selected-bg: @primary-2;
+
+// Collapse
+// ---
+@collapse-header-padding: 12px 16px;
+@collapse-header-padding-extra: 40px;
+@collapse-header-bg: @background-color-light;
+@collapse-content-padding: @padding-md;
+@collapse-content-bg: @component-background;
+
+// Skeleton
+// ---
+@skeleton-color: #f2f2f2;
+
+// Transfer
+// ---
+@transfer-header-height: 40px;
+@transfer-disabled-bg: @disabled-bg;
+@transfer-list-height: 200px;
+
+// Message
+// ---
+@message-notice-content-padding: 10px 16px;
+
+// Motion
+// ---
+@wave-animation-width: 6px;
+
+// Alert
+// ---
+@alert-success-border-color: ~`colorPalette('@{success-color}', 3) `;
+@alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `;
+@alert-success-icon-color: @success-color;
+@alert-info-border-color: ~`colorPalette('@{info-color}', 3) `;
+@alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `;
+@alert-info-icon-color: @info-color;
+@alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `;
+@alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `;
+@alert-warning-icon-color: @warning-color;
+@alert-error-border-color: ~`colorPalette('@{error-color}', 3) `;
+@alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `;
+@alert-error-icon-color: @error-color;
+
+// List
+// ---
+@list-header-background: transparent;
+@list-footer-background: transparent;
+@list-empty-text-padding: @padding-md;
+@list-item-padding: @padding-sm 0;
+@list-item-meta-margin-bottom: @padding-md;
+@list-item-meta-avatar-margin-right: @padding-md;
+@list-item-meta-title-margin-bottom: @padding-sm;
+
+// Statistic
+// ---
+@statistic-title-font-size: @font-size-base;
+@statistic-content-font-size: 24px;
+@statistic-unit-font-size: 16px;
+@statistic-font-family: @font-family;
+
+// Drawer
+// ---
+@drawer-header-padding: 16px 24px;
+@drawer-body-padding: 24px;
+
+// Timeline
+// ---
+@timeline-width: 2px;
+@timeline-color: @border-color-split;
+@timeline-dot-border-width: 2px;
+@timeline-dot-color: @primary-color;
+@timeline-dot-bg: @component-background;
+
+// Typography
+// ---
+@typography-title-font-weight: 600;
+@typography-title-margin-top: 1.2em;
+@typography-title-margin-bottom: 0.5em;
diff --git a/hotgo-web/src/assets/wrapper.jpg b/hotgo-web/src/assets/wrapper.jpg
new file mode 100644
index 0000000..3e70e55
Binary files /dev/null and b/hotgo-web/src/assets/wrapper.jpg differ
diff --git a/hotgo-web/src/components/ArticleListContent/ArticleListContent.vue b/hotgo-web/src/components/ArticleListContent/ArticleListContent.vue
new file mode 100644
index 0000000..8f39978
--- /dev/null
+++ b/hotgo-web/src/components/ArticleListContent/ArticleListContent.vue
@@ -0,0 +1,89 @@
+
+
+
+
+ {{ description }}
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/ArticleListContent/index.js b/hotgo-web/src/components/ArticleListContent/index.js
new file mode 100644
index 0000000..37d35c7
--- /dev/null
+++ b/hotgo-web/src/components/ArticleListContent/index.js
@@ -0,0 +1,3 @@
+import ArticleListContent from './ArticleListContent'
+
+export default ArticleListContent
diff --git a/hotgo-web/src/components/AvatarList/Item.jsx b/hotgo-web/src/components/AvatarList/Item.jsx
new file mode 100644
index 0000000..c5a69b2
--- /dev/null
+++ b/hotgo-web/src/components/AvatarList/Item.jsx
@@ -0,0 +1,24 @@
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import { Tooltip, Avatar } from 'ant-design-vue'
+import { getSlotOptions } from 'ant-design-vue/lib/_util/props-util'
+import { warning } from 'ant-design-vue/lib/vc-util/warning'
+
+export const AvatarListItemProps = {
+ tips: PropTypes.string.def(null),
+ src: PropTypes.string.def('')
+}
+
+const Item = {
+ __ANT_AVATAR_CHILDREN: true,
+ name: 'AvatarListItem',
+ props: AvatarListItemProps,
+ created () {
+ warning(getSlotOptions(this.$parent).__ANT_AVATAR_LIST, 'AvatarListItem must be a subcomponent of AvatarList')
+ },
+ render () {
+ const AvatarDom =
+ return this.tips && {AvatarDom} ||
+ }
+}
+
+export default Item
diff --git a/hotgo-web/src/components/AvatarList/List.jsx b/hotgo-web/src/components/AvatarList/List.jsx
new file mode 100644
index 0000000..74ad5ff
--- /dev/null
+++ b/hotgo-web/src/components/AvatarList/List.jsx
@@ -0,0 +1,72 @@
+import './index.less'
+
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import Avatar from 'ant-design-vue/es/avatar'
+import Item from './Item.jsx'
+import { filterEmpty } from '@/components/_util/util'
+
+/**
+ * size: `number`、 `large`、`small`、`default` 默认值: default
+ * maxLength: number
+ * excessItemsStyle: CSSProperties
+ */
+const AvatarListProps = {
+ prefixCls: PropTypes.string.def('ant-pro-avatar-list'),
+ size: {
+ validator: val => {
+ return typeof val === 'number' || ['small', 'large', 'default'].includes(val)
+ },
+ default: 'default'
+ },
+ maxLength: PropTypes.number.def(0),
+ excessItemsStyle: PropTypes.object.def({
+ color: '#f56a00',
+ backgroundColor: '#fde3cf'
+ })
+}
+
+const AvatarList = {
+ __ANT_AVATAR_LIST: true,
+ Item,
+ name: 'AvatarList',
+ props: AvatarListProps,
+ render (h) {
+ const { prefixCls, size } = this.$props
+ const className = {
+ [`${prefixCls}`]: true,
+ [`${size}`]: true
+ }
+ const items = filterEmpty(this.$slots.default)
+ const itemsDom = items && items.length ? : null
+
+ return (
+
+ {itemsDom}
+
+ )
+ },
+ methods: {
+ getItems (items) {
+ const className = {
+ [`${this.prefixCls}-item`]: true,
+ [`${this.size}`]: true
+ }
+ const totalSize = items.length
+
+ if (this.maxLength > 0) {
+ items = items.slice(0, this.maxLength)
+ items.push(({`+${totalSize - this.maxLength}`} ))
+ }
+ return items.map((item) => (
+ {item}
+ ))
+ }
+ }
+}
+
+AvatarList.install = function (Vue) {
+ Vue.component(AvatarList.name, AvatarList)
+ Vue.component(AvatarList.Item.name, AvatarList.Item)
+}
+
+export default AvatarList
diff --git a/hotgo-web/src/components/AvatarList/index.js b/hotgo-web/src/components/AvatarList/index.js
new file mode 100644
index 0000000..b047432
--- /dev/null
+++ b/hotgo-web/src/components/AvatarList/index.js
@@ -0,0 +1,9 @@
+import AvatarList from './List'
+import Item from './Item'
+
+export {
+ AvatarList,
+ Item as AvatarListItem
+}
+
+export default AvatarList
diff --git a/hotgo-web/src/components/AvatarList/index.less b/hotgo-web/src/components/AvatarList/index.less
new file mode 100644
index 0000000..9ce073f
--- /dev/null
+++ b/hotgo-web/src/components/AvatarList/index.less
@@ -0,0 +1,60 @@
+@import "../index";
+
+@avatar-list-prefix-cls: ~"@{ant-pro-prefix}-avatar-list";
+@avatar-list-item-prefix-cls: ~"@{ant-pro-prefix}-avatar-list-item";
+
+.@{avatar-list-prefix-cls} {
+ display: inline-block;
+
+ ul {
+ list-style: none;
+ display: inline-block;
+ padding: 0;
+ margin: 0 0 0 8px;
+ font-size: 0;
+ }
+}
+
+.@{avatar-list-item-prefix-cls} {
+ display: inline-block;
+ font-size: @font-size-base;
+ margin-left: -8px;
+ width: @avatar-size-base;
+ height: @avatar-size-base;
+
+ :global {
+ .ant-avatar {
+ border: 1px solid #fff;
+ cursor: pointer;
+ }
+ }
+
+ &.large {
+ width: @avatar-size-lg;
+ height: @avatar-size-lg;
+ }
+
+ &.small {
+ width: @avatar-size-sm;
+ height: @avatar-size-sm;
+ }
+
+ &.mini {
+ width: 20px;
+ height: 20px;
+
+ :global {
+ .ant-avatar {
+ width: 20px;
+ height: 20px;
+ line-height: 20px;
+
+ .ant-avatar-string {
+ font-size: 12px;
+ line-height: 18px;
+ }
+ }
+ }
+ }
+}
+
diff --git a/hotgo-web/src/components/AvatarList/index.md b/hotgo-web/src/components/AvatarList/index.md
new file mode 100644
index 0000000..75e022c
--- /dev/null
+++ b/hotgo-web/src/components/AvatarList/index.md
@@ -0,0 +1,64 @@
+# AvatarList 用户头像列表
+
+
+一组用户头像,常用在项目/团队成员列表。可通过设置 `size` 属性来指定头像大小。
+
+
+
+引用方式:
+
+```javascript
+import AvatarList from '@/components/AvatarList'
+const AvatarListItem = AvatarList.Item
+
+export default {
+ components: {
+ AvatarList,
+ AvatarListItem
+ }
+}
+```
+
+
+
+## 代码演示 [demo](https://pro.loacg.com/test/home)
+
+```html
+
+
+
+
+
+```
+或
+```html
+
+
+
+
+
+
+
+
+
+```
+
+
+
+## API
+
+### AvatarList
+
+| 参数 | 说明 | 类型 | 默认值 |
+| ---------------- | -------- | ---------------------------------- | --------- |
+| size | 头像大小 | `large`、`small` 、`mini`, `default` | `default` |
+| maxLength | 要显示的最大项目 | number | - |
+| excessItemsStyle | 多余的项目风格 | CSSProperties | - |
+
+### AvatarList.Item
+
+| 参数 | 说明 | 类型 | 默认值 |
+| ---- | ------ | --------- | --- |
+| tips | 头像展示文案 | string | - |
+| src | 头像图片连接 | string | - |
+
diff --git a/hotgo-web/src/components/Dialog.js b/hotgo-web/src/components/Dialog.js
new file mode 100644
index 0000000..78e95b2
--- /dev/null
+++ b/hotgo-web/src/components/Dialog.js
@@ -0,0 +1,113 @@
+import Modal from 'ant-design-vue/es/modal'
+export default (Vue) => {
+ function dialog (component, componentProps, modalProps) {
+ const _vm = this
+ modalProps = modalProps || {}
+ if (!_vm || !_vm._isVue) {
+ return
+ }
+ let dialogDiv = document.querySelector('body>div[type=dialog]')
+ if (!dialogDiv) {
+ dialogDiv = document.createElement('div')
+ dialogDiv.setAttribute('type', 'dialog')
+ document.body.appendChild(dialogDiv)
+ }
+
+ const handle = function (checkFunction, afterHandel) {
+ if (checkFunction instanceof Function) {
+ const res = checkFunction()
+ if (res instanceof Promise) {
+ res.then(c => {
+ c && afterHandel()
+ })
+ } else {
+ res && afterHandel()
+ }
+ } else {
+ // checkFunction && afterHandel()
+ checkFunction || afterHandel()
+ }
+ }
+
+ const dialogInstance = new Vue({
+ data () {
+ return {
+ visible: true
+ }
+ },
+ router: _vm.$router,
+ store: _vm.$store,
+ mounted () {
+ this.$on('close', (v) => {
+ this.handleClose()
+ })
+ },
+ methods: {
+ handleClose () {
+ handle(this.$refs._component.onCancel, () => {
+ this.visible = false
+ this.$refs._component.$emit('close')
+ this.$refs._component.$emit('cancel')
+ dialogInstance.$destroy()
+ })
+ },
+ handleOk () {
+ handle(this.$refs._component.onOK || this.$refs._component.onOk, () => {
+ this.visible = false
+ this.$refs._component.$emit('close')
+ this.$refs._component.$emit('ok')
+ dialogInstance.$destroy()
+ })
+ }
+ },
+ render: function (h) {
+ const that = this
+ const modalModel = modalProps && modalProps.model
+ if (modalModel) {
+ delete modalProps.model
+ }
+ const ModalProps = Object.assign({}, modalModel && { model: modalModel } || {}, {
+ attrs: Object.assign({}, {
+ ...(modalProps.attrs || modalProps)
+ }, {
+ visible: this.visible
+ }),
+ on: Object.assign({}, {
+ ...(modalProps.on || modalProps)
+ }, {
+ ok: () => {
+ that.handleOk()
+ },
+ cancel: () => {
+ that.handleClose()
+ }
+ })
+ })
+
+ const componentModel = componentProps && componentProps.model
+ if (componentModel) {
+ delete componentProps.model
+ }
+ const ComponentProps = Object.assign({}, componentModel && { model: componentModel } || {}, {
+ ref: '_component',
+ attrs: Object.assign({}, {
+ ...((componentProps && componentProps.attrs) || componentProps)
+ }),
+ on: Object.assign({}, {
+ ...((componentProps && componentProps.on) || componentProps)
+ })
+ })
+
+ return h(Modal, ModalProps, [h(component, ComponentProps)])
+ }
+ }).$mount(dialogDiv)
+ }
+
+ Object.defineProperty(Vue.prototype, '$dialog', {
+ get: () => {
+ return function () {
+ dialog.apply(this, arguments)
+ }
+ }
+ })
+}
diff --git a/hotgo-web/src/components/Ellipsis/Ellipsis.vue b/hotgo-web/src/components/Ellipsis/Ellipsis.vue
new file mode 100644
index 0000000..5d59200
--- /dev/null
+++ b/hotgo-web/src/components/Ellipsis/Ellipsis.vue
@@ -0,0 +1,64 @@
+
diff --git a/hotgo-web/src/components/Ellipsis/index.js b/hotgo-web/src/components/Ellipsis/index.js
new file mode 100644
index 0000000..91e3ff4
--- /dev/null
+++ b/hotgo-web/src/components/Ellipsis/index.js
@@ -0,0 +1,3 @@
+import Ellipsis from './Ellipsis'
+
+export default Ellipsis
diff --git a/hotgo-web/src/components/Ellipsis/index.md b/hotgo-web/src/components/Ellipsis/index.md
new file mode 100644
index 0000000..f528ac7
--- /dev/null
+++ b/hotgo-web/src/components/Ellipsis/index.md
@@ -0,0 +1,38 @@
+# Ellipsis 文本自动省略号
+
+文本过长自动处理省略号,支持按照文本长度和最大行数两种方式截取。
+
+
+
+引用方式:
+
+```javascript
+import Ellipsis from '@/components/Ellipsis'
+
+export default {
+ components: {
+ Ellipsis
+ }
+}
+```
+
+
+
+## 代码演示 [demo](https://pro.loacg.com/test/home)
+
+```html
+
+ There were injuries alleged in three cases in 2015, and a
+ fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.
+
+```
+
+
+
+## API
+
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+tooltip | 移动到文本展示完整内容的提示 | boolean | -
+length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | -
\ No newline at end of file
diff --git a/hotgo-web/src/components/FooterToolbar/FooterToolBar.vue b/hotgo-web/src/components/FooterToolbar/FooterToolBar.vue
new file mode 100644
index 0000000..ea07123
--- /dev/null
+++ b/hotgo-web/src/components/FooterToolbar/FooterToolBar.vue
@@ -0,0 +1,47 @@
+
+
+
+ {{ extra }}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/FooterToolbar/index.js b/hotgo-web/src/components/FooterToolbar/index.js
new file mode 100644
index 0000000..a0bf145
--- /dev/null
+++ b/hotgo-web/src/components/FooterToolbar/index.js
@@ -0,0 +1,4 @@
+import FooterToolBar from './FooterToolBar'
+import './index.less'
+
+export default FooterToolBar
diff --git a/hotgo-web/src/components/FooterToolbar/index.less b/hotgo-web/src/components/FooterToolbar/index.less
new file mode 100644
index 0000000..f56273f
--- /dev/null
+++ b/hotgo-web/src/components/FooterToolbar/index.less
@@ -0,0 +1,23 @@
+@import "../index";
+
+@footer-toolbar-prefix-cls: ~"@{ant-pro-prefix}-footer-toolbar";
+
+.@{footer-toolbar-prefix-cls} {
+ position: fixed;
+ width: 100%;
+ bottom: 0;
+ right: 0;
+ height: 56px;
+ line-height: 56px;
+ box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03);
+ background: #fff;
+ border-top: 1px solid #e8e8e8;
+ padding: 0 24px;
+ z-index: 9;
+
+ &:after {
+ content: "";
+ display: block;
+ clear: both;
+ }
+}
\ No newline at end of file
diff --git a/hotgo-web/src/components/FooterToolbar/index.md b/hotgo-web/src/components/FooterToolbar/index.md
new file mode 100644
index 0000000..c1aec2c
--- /dev/null
+++ b/hotgo-web/src/components/FooterToolbar/index.md
@@ -0,0 +1,48 @@
+# FooterToolbar 底部工具栏
+
+固定在底部的工具栏。
+
+
+
+## 何时使用
+
+固定在内容区域的底部,不随滚动条移动,常用于长页面的数据搜集和提交工作。
+
+
+
+引用方式:
+
+```javascript
+import FooterToolBar from '@/components/FooterToolbar'
+
+export default {
+ components: {
+ FooterToolBar
+ }
+}
+```
+
+
+
+## 代码演示
+
+```html
+
+ 提交
+
+```
+或
+```html
+
+ 提交
+
+```
+
+
+## API
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+children (slot) | 工具栏内容,向右对齐 | - | -
+extra | 额外信息,向左对齐 | String, Object | -
+
diff --git a/hotgo-web/src/components/GlobalFooter/index.vue b/hotgo-web/src/components/GlobalFooter/index.vue
new file mode 100644
index 0000000..8b246cf
--- /dev/null
+++ b/hotgo-web/src/components/GlobalFooter/index.vue
@@ -0,0 +1,21 @@
+
+
+
+
diff --git a/hotgo-web/src/components/GlobalHeader/AvatarDropdown.vue b/hotgo-web/src/components/GlobalHeader/AvatarDropdown.vue
new file mode 100644
index 0000000..2e210b3
--- /dev/null
+++ b/hotgo-web/src/components/GlobalHeader/AvatarDropdown.vue
@@ -0,0 +1,83 @@
+
+
+
+
+ {{ name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/GlobalHeader/PlatformVersion.vue b/hotgo-web/src/components/GlobalHeader/PlatformVersion.vue
new file mode 100644
index 0000000..987d717
--- /dev/null
+++ b/hotgo-web/src/components/GlobalHeader/PlatformVersion.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
平台授权信息.
+ 非常感谢您对我们产品的认可与支持!
+ {{ versionContent[0] }}
+ {{ versionContent[1] }}
+ {{ versionContent[2] }}
+ 授权产品名称:AiDex
+ 当前平台版本:V1.2.1
+
+
+ 关闭页面
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/GlobalHeader/RightContent.vue b/hotgo-web/src/components/GlobalHeader/RightContent.vue
new file mode 100644
index 0000000..dfe678e
--- /dev/null
+++ b/hotgo-web/src/components/GlobalHeader/RightContent.vue
@@ -0,0 +1,251 @@
+
+
+
+
+
+
+ 切换工作台
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
+
+
+ 控制台
+
+
+
+
+
+ 消息
+
+
+
+
+
+
+
+ 换肤
+
+
+
+
+
+ {{ fullScreen ? '退出全屏' : '切为全屏' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/GridContent/index.js b/hotgo-web/src/components/GridContent/index.js
new file mode 100644
index 0000000..a468126
--- /dev/null
+++ b/hotgo-web/src/components/GridContent/index.js
@@ -0,0 +1,44 @@
+'use strict'
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+})
+exports['default'] = void 0
+
+require('./index.less')
+
+var _vueTypes = _interopRequireDefault(require('ant-design-vue/es/_util/vue-types'))
+
+var _util = require('../../utils/util')
+
+function _interopRequireDefault (obj) { return obj && obj.__esModule ? obj : { 'default': obj } }
+
+function _defineProperty (obj, key, value) {
+ if (key in obj) {
+ Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true })
+ } else {
+ obj[key] = value
+ } return obj
+}
+
+var GridContent = {
+ name: 'GridContent',
+ functional: true,
+ props: {
+ children: _vueTypes['default'].any,
+ contentWidth: _vueTypes['default'].oneOf(['Fluid', 'Fixed']).def('Fluid')
+ },
+ render: function render (h, content) {
+ var _classNames
+
+ var contentWidth = content.props.contentWidth
+ var children = content.children
+ var propsContentWidth = (0, _util.layoutContentWidth)(contentWidth)
+ var classNames = (_classNames = {}, _defineProperty(_classNames, 'ant-pro-grid-content', true), _defineProperty(_classNames, 'wide', propsContentWidth), _classNames)
+ return h('div', {
+ 'class': classNames
+ }, [children])
+ }
+}
+var _default = GridContent
+exports['default'] = _default
diff --git a/hotgo-web/src/components/GridContent/index.less b/hotgo-web/src/components/GridContent/index.less
new file mode 100644
index 0000000..3c1a395
--- /dev/null
+++ b/hotgo-web/src/components/GridContent/index.less
@@ -0,0 +1,14 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+@grid-content-prefix-cls: ~'@{ant-prefix}-pro-grid-content';
+
+.@{grid-content-prefix-cls} {
+ width: 100%;
+ min-height: 100%;
+ transition: 0.3s;
+ &.wide {
+ max-width: 1200px;
+ margin: 0 auto;
+ }
+
+}
diff --git a/hotgo-web/src/components/IconSelector/IconDetail.vue b/hotgo-web/src/components/IconSelector/IconDetail.vue
new file mode 100644
index 0000000..7bc287e
--- /dev/null
+++ b/hotgo-web/src/components/IconSelector/IconDetail.vue
@@ -0,0 +1,187 @@
+
+
+
+
+
+ {{ v.title }}
+
+
+
+
+
+
+ {{ icon }}
+
+
+
+
+
+
+
+
+
+ {{ icon }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/IconSelector/IconSelector.vue b/hotgo-web/src/components/IconSelector/IconSelector.vue
new file mode 100644
index 0000000..dcf96b5
--- /dev/null
+++ b/hotgo-web/src/components/IconSelector/IconSelector.vue
@@ -0,0 +1,109 @@
+
+
+
+
+
+ {{ v.title }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/IconSelector/README.md b/hotgo-web/src/components/IconSelector/README.md
new file mode 100644
index 0000000..503095d
--- /dev/null
+++ b/hotgo-web/src/components/IconSelector/README.md
@@ -0,0 +1,48 @@
+IconSelector
+====
+
+> 图标选择组件,常用于为某一个数据设定一个图标时使用
+> eg: 设定菜单列表时,为每个菜单设定一个图标
+
+该组件由 [@Saraka](https://github.com/saraka-tsukai) 封装
+
+
+
+### 使用方式
+
+```vue
+
+
+
+
+
+
+
+```
+
+
+
+### 事件
+
+
+| 名称 | 说明 | 类型 | 默认值 |
+| ------ | -------------------------- | ------ | ------ |
+| change | 当改变了 `icon` 选中项触发 | String | - |
diff --git a/hotgo-web/src/components/IconSelector/icons.js b/hotgo-web/src/components/IconSelector/icons.js
new file mode 100644
index 0000000..a007242
--- /dev/null
+++ b/hotgo-web/src/components/IconSelector/icons.js
@@ -0,0 +1,36 @@
+/**
+ * 增加新的图标时,请遵循以下数据结构
+ * Adding new icon please follow the data structure below
+ */
+export default [
+ {
+ key: 'directional',
+ title: '方向性图标',
+ icons: ['step-backward', 'step-forward', 'fast-backward', 'fast-forward', 'shrink', 'arrows-alt', 'down', 'up', 'left', 'right', 'caret-up', 'caret-down', 'caret-left', 'caret-right', 'up-circle', 'down-circle', 'left-circle', 'right-circle', 'double-right', 'double-left', 'vertical-left', 'vertical-right', 'forward', 'backward', 'rollback', 'enter', 'retweet', 'swap', 'swap-left', 'swap-right', 'arrow-up', 'arrow-down', 'arrow-left', 'arrow-right', 'play-circle', 'up-square', 'down-square', 'left-square', 'right-square', 'login', 'logout', 'menu-fold', 'menu-unfold', 'border-bottom', 'border-horizontal', 'border-inner', 'border-left', 'border-right', 'border-top', 'border-verticle', 'pic-center', 'pic-left', 'pic-right', 'radius-bottomleft', 'radius-bottomright', 'radius-upleft', 'fullscreen', 'fullscreen-exit']
+ },
+ {
+ key: 'suggested',
+ title: '提示建议性图标',
+ icons: ['question', 'question-circle', 'plus', 'plus-circle', 'pause', 'pause-circle', 'minus', 'minus-circle', 'plus-square', 'minus-square', 'info', 'info-circle', 'exclamation', 'exclamation-circle', 'close', 'close-circle', 'close-square', 'check', 'check-circle', 'check-square', 'clock-circle', 'warning', 'issues-close', 'stop']
+ },
+ {
+ key: 'editor',
+ title: '编辑类图标',
+ icons: ['edit', 'form', 'copy', 'scissor', 'delete', 'snippets', 'diff', 'highlight', 'align-center', 'align-left', 'align-right', 'bg-colors', 'bold', 'italic', 'underline', 'strikethrough', 'redo', 'undo', 'zoom-in', 'zoom-out', 'font-colors', 'font-size', 'line-height', 'colum-height', 'dash', 'small-dash', 'sort-ascending', 'sort-descending', 'drag', 'ordered-list', 'radius-setting']
+ },
+ {
+ key: 'data',
+ title: '数据类图标',
+ icons: ['area-chart', 'pie-chart', 'bar-chart', 'dot-chart', 'line-chart', 'radar-chart', 'heat-map', 'fall', 'rise', 'stock', 'box-plot', 'fund', 'sliders']
+ },
+ {
+ key: 'brand_logo',
+ title: '网站通用图标',
+ icons: ['lock', 'unlock', 'bars', 'book', 'calendar', 'cloud', 'cloud-download', 'code', 'copy', 'credit-card', 'delete', 'desktop', 'download', 'ellipsis', 'file', 'file-text', 'file-unknown', 'file-pdf', 'file-word', 'file-excel', 'file-jpg', 'file-ppt', 'file-markdown', 'file-add', 'folder', 'folder-open', 'folder-add', 'hdd', 'frown', 'meh', 'smile', 'inbox', 'laptop', 'appstore', 'link', 'mail', 'mobile', 'notification', 'paper-clip', 'picture', 'poweroff', 'reload', 'search', 'setting', 'share-alt', 'shopping-cart', 'tablet', 'tag', 'tags', 'to-top', 'upload', 'user', 'video-camera', 'home', 'loading', 'loading-3-quarters', 'cloud-upload', 'star', 'heart', 'environment', 'eye', 'camera', 'save', 'team', 'solution', 'phone', 'filter', 'exception', 'export', 'customer-service', 'qrcode', 'scan', 'like', 'dislike', 'message', 'pay-circle', 'calculator', 'pushpin', 'bulb', 'select', 'switcher', 'rocket', 'bell', 'disconnect', 'database', 'compass', 'barcode', 'hourglass', 'key', 'flag', 'layout', 'printer', 'sound', 'usb', 'skin', 'tool', 'sync', 'wifi', 'car', 'schedule', 'user-add', 'user-delete', 'usergroup-add', 'usergroup-delete', 'man', 'woman', 'shop', 'gift', 'idcard', 'medicine-box', 'red-envelope', 'coffee', 'copyright', 'trademark', 'safety', 'wallet', 'bank', 'trophy', 'contacts', 'global', 'shake', 'api', 'fork', 'dashboard', 'table', 'profile', 'alert', 'audit', 'branches', 'build', 'border', 'crown', 'experiment', 'fire', 'money-collect', 'property-safety', 'read', 'reconciliation', 'rest', 'security-scan', 'insurance', 'interation', 'safety-certificate', 'project', 'thunderbolt', 'block', 'cluster', 'deployment-unit', 'dollar', 'euro', 'pound', 'file-done', 'file-exclamation', 'file-protect', 'file-search', 'file-sync', 'gateway', 'gold', 'robot', 'shopping']
+ },
+ {
+ key: 'application',
+ title: '品牌和标识',
+ icons: ['android', 'apple', 'windows', 'ie', 'chrome', 'github', 'aliwangwang', 'dingtalk', 'weibo-square', 'weibo-circle', 'taobao-circle', 'html5', 'weibo', 'twitter', 'wechat', 'youtube', 'alipay-circle', 'taobao', 'skype', 'qq', 'medium-workmark', 'gitlab', 'medium', 'linkedin', 'google-plus', 'dropbox', 'facebook', 'codepen', 'code-sandbox', 'amazon', 'google', 'codepen-circle', 'alipay', 'ant-design', 'aliyun', 'zhihu', 'slack', 'slack-square', 'behance', 'behance-square', 'dribbble', 'dribbble-square', 'instagram', 'yuque', 'alibaba', 'yahoo']
+ }
+]
diff --git a/hotgo-web/src/components/IconSelector/index.js b/hotgo-web/src/components/IconSelector/index.js
new file mode 100644
index 0000000..2d27d70
--- /dev/null
+++ b/hotgo-web/src/components/IconSelector/index.js
@@ -0,0 +1,2 @@
+import IconSelector from './IconSelector'
+export default IconSelector
diff --git a/hotgo-web/src/components/MultiTab/MultiTab.vue b/hotgo-web/src/components/MultiTab/MultiTab.vue
new file mode 100644
index 0000000..0af0dac
--- /dev/null
+++ b/hotgo-web/src/components/MultiTab/MultiTab.vue
@@ -0,0 +1,175 @@
+
diff --git a/hotgo-web/src/components/MultiTab/events.js b/hotgo-web/src/components/MultiTab/events.js
new file mode 100644
index 0000000..b0230b5
--- /dev/null
+++ b/hotgo-web/src/components/MultiTab/events.js
@@ -0,0 +1,2 @@
+import Vue from 'vue'
+export default new Vue()
diff --git a/hotgo-web/src/components/MultiTab/index.js b/hotgo-web/src/components/MultiTab/index.js
new file mode 100644
index 0000000..02a1c77
--- /dev/null
+++ b/hotgo-web/src/components/MultiTab/index.js
@@ -0,0 +1,40 @@
+import events from './events'
+import MultiTab from './MultiTab'
+import './index.less'
+
+const api = {
+ /**
+ * open new tab on route fullPath
+ * @param config
+ */
+ open: function (config) {
+ events.$emit('open', config)
+ },
+ rename: function (key, name) {
+ events.$emit('rename', { key: key, name: name })
+ },
+ /**
+ * close current page
+ */
+ closeCurrentPage: function () {
+ this.close()
+ },
+ /**
+ * close route fullPath tab
+ * @param config
+ */
+ close: function (config) {
+ events.$emit('close', config)
+ }
+}
+
+MultiTab.install = function (Vue) {
+ if (Vue.prototype.$multiTab) {
+ return
+ }
+ api.instance = events
+ Vue.prototype.$multiTab = api
+ Vue.component('multi-tab', MultiTab)
+}
+
+export default MultiTab
diff --git a/hotgo-web/src/components/MultiTab/index.less b/hotgo-web/src/components/MultiTab/index.less
new file mode 100644
index 0000000..b7fa848
--- /dev/null
+++ b/hotgo-web/src/components/MultiTab/index.less
@@ -0,0 +1,31 @@
+@import '../index';
+
+@multi-tab-prefix-cls: ~"@{ant-pro-prefix}-multi-tab";
+@multi-tab-wrapper-prefix-cls: ~"@{ant-pro-prefix}-multi-tab-wrapper";
+
+/*
+.topmenu .@{multi-tab-prefix-cls} {
+ max-width: 1200px;
+ margin: -23px auto 24px auto;
+}
+*/
+.@{multi-tab-prefix-cls} {
+ margin: -23px -24px 24px -24px;
+ background: #fff;
+}
+
+.topmenu .@{multi-tab-wrapper-prefix-cls} {
+ max-width: 1200px;
+ margin: 0 auto;
+}
+
+.topmenu.content-width-Fluid .@{multi-tab-wrapper-prefix-cls} {
+ max-width: 100%;
+ margin: 0 auto;
+}
+.@{multi-tab-wrapper-prefix-cls} > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active {
+ border-color: #fff;
+ border-top-right-radius: 0px;
+ background: #fff;
+ box-shadow: 2px 0 4px rgb(0 21 41 / 5%);
+}
\ No newline at end of file
diff --git a/hotgo-web/src/components/NProgress/nprogress.less b/hotgo-web/src/components/NProgress/nprogress.less
new file mode 100644
index 0000000..7826c0e
--- /dev/null
+++ b/hotgo-web/src/components/NProgress/nprogress.less
@@ -0,0 +1,76 @@
+@import url('../index.less');
+
+/* Make clicks pass-through */
+#nprogress {
+ pointer-events: none;
+}
+
+#nprogress .bar {
+ background: @primary-color;
+
+ position: fixed;
+ z-index: 1031;
+ top: 0;
+ left: 0;
+
+ width: 100%;
+ height: 2px;
+}
+
+/* Fancy blur effect */
+#nprogress .peg {
+ display: block;
+ position: absolute;
+ right: 0px;
+ width: 100px;
+ height: 100%;
+ box-shadow: 0 0 10px @primary-color, 0 0 5px @primary-color;
+ opacity: 1.0;
+
+ -webkit-transform: rotate(3deg) translate(0px, -4px);
+ -ms-transform: rotate(3deg) translate(0px, -4px);
+ transform: rotate(3deg) translate(0px, -4px);
+}
+
+/* Remove these to get rid of the spinner */
+#nprogress .spinner {
+ display: block;
+ position: fixed;
+ z-index: 1031;
+ top: 15px;
+ right: 15px;
+}
+
+#nprogress .spinner-icon {
+ width: 18px;
+ height: 18px;
+ box-sizing: border-box;
+
+ border: solid 2px transparent;
+ border-top-color: @primary-color;
+ border-left-color: @primary-color;
+ border-radius: 50%;
+
+ -webkit-animation: nprogress-spinner 400ms linear infinite;
+ animation: nprogress-spinner 400ms linear infinite;
+}
+
+.nprogress-custom-parent {
+ overflow: hidden;
+ position: relative;
+}
+
+.nprogress-custom-parent #nprogress .spinner,
+.nprogress-custom-parent #nprogress .bar {
+ position: absolute;
+}
+
+@-webkit-keyframes nprogress-spinner {
+ 0% { -webkit-transform: rotate(0deg); }
+ 100% { -webkit-transform: rotate(360deg); }
+}
+@keyframes nprogress-spinner {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
diff --git a/hotgo-web/src/components/NoticeIcon/NoticeIcon.vue b/hotgo-web/src/components/NoticeIcon/NoticeIcon.vue
new file mode 100644
index 0000000..8ae1c80
--- /dev/null
+++ b/hotgo-web/src/components/NoticeIcon/NoticeIcon.vue
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 123
+
+
+ 123
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/NoticeIcon/index.js b/hotgo-web/src/components/NoticeIcon/index.js
new file mode 100644
index 0000000..659b9ec
--- /dev/null
+++ b/hotgo-web/src/components/NoticeIcon/index.js
@@ -0,0 +1,2 @@
+import NoticeIcon from './NoticeIcon'
+export default NoticeIcon
diff --git a/hotgo-web/src/components/NumberInfo/NumberInfo.vue b/hotgo-web/src/components/NumberInfo/NumberInfo.vue
new file mode 100644
index 0000000..bdde3e0
--- /dev/null
+++ b/hotgo-web/src/components/NumberInfo/NumberInfo.vue
@@ -0,0 +1,54 @@
+
+
+
+ {{ typeof subTitle === 'string' ? subTitle : subTitle() }}
+
+
+ {{ total }}
+
+ {{ subTotal }}
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/NumberInfo/index.js b/hotgo-web/src/components/NumberInfo/index.js
new file mode 100644
index 0000000..659a2f3
--- /dev/null
+++ b/hotgo-web/src/components/NumberInfo/index.js
@@ -0,0 +1,3 @@
+import NumberInfo from './NumberInfo'
+
+export default NumberInfo
diff --git a/hotgo-web/src/components/NumberInfo/index.less b/hotgo-web/src/components/NumberInfo/index.less
new file mode 100644
index 0000000..719113d
--- /dev/null
+++ b/hotgo-web/src/components/NumberInfo/index.less
@@ -0,0 +1,55 @@
+@import "../index";
+
+@numberInfo-prefix-cls: ~"@{ant-pro-prefix}-number-info";
+
+.@{numberInfo-prefix-cls} {
+
+ .ant-pro-number-info-subtitle {
+ color: @text-color-secondary;
+ font-size: @font-size-base;
+ height: 22px;
+ line-height: 22px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ word-break: break-all;
+ white-space: nowrap;
+ }
+
+ .number-info-value {
+ margin-top: 4px;
+ font-size: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ word-break: break-all;
+ white-space: nowrap;
+
+ & > span {
+ color: @heading-color;
+ display: inline-block;
+ line-height: 32px;
+ height: 32px;
+ font-size: 24px;
+ margin-right: 32px;
+ }
+
+ .sub-total {
+ color: @text-color-secondary;
+ font-size: @font-size-lg;
+ vertical-align: top;
+ margin-right: 0;
+ i {
+ font-size: 12px;
+ transform: scale(0.82);
+ margin-left: 4px;
+ }
+ :global {
+ .anticon-caret-up {
+ color: @red-6;
+ }
+ .anticon-caret-down {
+ color: @green-6;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/hotgo-web/src/components/NumberInfo/index.md b/hotgo-web/src/components/NumberInfo/index.md
new file mode 100644
index 0000000..147adc4
--- /dev/null
+++ b/hotgo-web/src/components/NumberInfo/index.md
@@ -0,0 +1,43 @@
+# NumberInfo 数据文本
+
+常用在数据卡片中,用于突出展示某个业务数据。
+
+
+
+引用方式:
+
+```javascript
+import NumberInfo from '@/components/NumberInfo'
+
+export default {
+ components: {
+ NumberInfo
+ }
+}
+```
+
+
+
+## 代码演示 [demo](https://pro.loacg.com/test/home)
+
+```html
+
+```
+
+
+
+## API
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+title | 标题 | ReactNode\|string | -
+subTitle | 子标题 | ReactNode\|string | -
+total | 总量 | ReactNode\|string | -
+subTotal | 子总量 | ReactNode\|string | -
+status | 增加状态 | 'up \| down' | -
+theme | 状态样式 | string | 'light'
+gap | 设置数字和描述之间的间距(像素)| number | 8
diff --git a/hotgo-web/src/components/Other/CarbonAds.vue b/hotgo-web/src/components/Other/CarbonAds.vue
new file mode 100644
index 0000000..1e53ba6
--- /dev/null
+++ b/hotgo-web/src/components/Other/CarbonAds.vue
@@ -0,0 +1,114 @@
+
+
diff --git a/hotgo-web/src/components/PageLoading/index.jsx b/hotgo-web/src/components/PageLoading/index.jsx
new file mode 100644
index 0000000..af6d6d6
--- /dev/null
+++ b/hotgo-web/src/components/PageLoading/index.jsx
@@ -0,0 +1,106 @@
+import { Spin } from 'ant-design-vue'
+
+export const PageLoading = {
+ name: 'PageLoading',
+ props: {
+ tip: {
+ type: String,
+ default: 'Loading..'
+ },
+ size: {
+ type: String,
+ default: 'large'
+ }
+ },
+ render () {
+ const style = {
+ textAlign: 'center',
+ background: 'rgba(0,0,0,0.6)',
+ position: 'fixed',
+ top: 0,
+ bottom: 0,
+ left: 0,
+ right: 0,
+ zIndex: 1100
+ }
+ const spinStyle = {
+ position: 'absolute',
+ left: '50%',
+ top: '40%',
+ transform: 'translate(-50%, -50%)'
+ }
+ return (
+
+
)
+ }
+}
+
+const version = '0.0.1'
+const loading = {}
+
+loading.newInstance = (Vue, options) => {
+ let loadingElement = document.querySelector('body>div[type=loading]')
+ if (!loadingElement) {
+ loadingElement = document.createElement('div')
+ loadingElement.setAttribute('type', 'loading')
+ loadingElement.setAttribute('class', 'ant-loading-wrapper')
+ document.body.appendChild(loadingElement)
+ }
+
+ const cdProps = Object.assign({ visible: false, size: 'large', tip: 'Loading...' }, options)
+
+ const instance = new Vue({
+ data () {
+ return {
+ ...cdProps
+ }
+ },
+ render () {
+ const { tip } = this
+ const props = {}
+ this.tip && (props.tip = tip)
+ if (this.visible) {
+ return
+ }
+ return null
+ }
+ }).$mount(loadingElement)
+
+ function update (config) {
+ const { visible, size, tip } = { ...cdProps, ...config }
+ instance.$set(instance, 'visible', visible)
+ if (tip) {
+ instance.$set(instance, 'tip', tip)
+ }
+ if (size) {
+ instance.$set(instance, 'size', size)
+ }
+ }
+
+ return {
+ instance,
+ update
+ }
+}
+
+const api = {
+ show: function (options) {
+ this.instance.update({ ...options, visible: true })
+ },
+ hide: function () {
+ this.instance.update({ visible: false })
+ }
+}
+
+const install = function (Vue, options) {
+ if (Vue.prototype.$loading) {
+ return
+ }
+ api.instance = loading.newInstance(Vue, options)
+ Vue.prototype.$loading = api
+}
+
+export default {
+ version,
+ install
+}
diff --git a/hotgo-web/src/components/ProLayout/BasicLayout.jsx b/hotgo-web/src/components/ProLayout/BasicLayout.jsx
new file mode 100644
index 0000000..dd8b49c
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/BasicLayout.jsx
@@ -0,0 +1,187 @@
+import './BasicLayout.less'
+
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+
+import 'ant-design-vue/es/layout/style'
+import Layout from 'ant-design-vue/es/layout'
+
+import { ContainerQuery } from 'vue-container-query'
+import { SiderMenuWrapper } from './components'
+import { getComponentFromProp, isFun } from './utils/util'
+import { SiderMenuProps } from './components/SiderMenu'
+import HeaderView, { HeaderViewProps } from './Header'
+import WrapContent from './WrapContent'
+import ConfigProvider from './components/ConfigProvider'
+import PageHeaderWrapper from './components/PageHeaderWrapper'
+export const BasicLayoutProps = {
+ ...SiderMenuProps,
+ ...HeaderViewProps,
+ contentWidth: PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid'),
+ // contentWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).def('Fluid'),
+ locale: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).def('en-US'),
+ breadcrumbRender: PropTypes.func,
+ disableMobile: PropTypes.bool.def(false),
+ mediaQuery: PropTypes.object.def({}),
+ handleMediaQuery: PropTypes.func,
+ footerRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(undefined)
+}
+
+const MediaQueryEnum = {
+ 'screen-xs': {
+ maxWidth: 575
+ },
+ 'screen-sm': {
+ minWidth: 576,
+ maxWidth: 767
+ },
+ 'screen-md': {
+ minWidth: 768,
+ maxWidth: 991
+ },
+ 'screen-lg': {
+ minWidth: 992,
+ maxWidth: 1199
+ },
+ 'screen-xl': {
+ minWidth: 1200,
+ maxWidth: 1599
+ },
+ 'screen-xxl': {
+ minWidth: 1600
+ }
+}
+
+const getPaddingLeft = (
+ hasLeftPadding,
+ collapsed = undefined,
+ siderWidth
+) => {
+ if (hasLeftPadding) {
+ return collapsed ? 60 : siderWidth
+ }
+ return 0
+}
+const getLeft = (collapsed = undefined) => {
+ return collapsed ? 60 : 210
+}
+const headerRender = (h, props) => {
+ if (props.headerRender === false) {
+ return null
+ }
+ return
+}
+
+const defaultI18nRender = (key) => key
+
+const BasicLayout = {
+ name: 'BasicLayout',
+ functional: true,
+ props: BasicLayoutProps,
+ render (h, content) {
+ const { props, children } = content
+ const {
+ layout,
+ // theme,
+ isMobile,
+ collapsed,
+ mediaQuery,
+ handleMediaQuery,
+ handleCollapse,
+ siderWidth,
+ fixSiderbar,
+ i18nRender = defaultI18nRender,
+ multiTab
+ } = props
+
+ const footerRender = getComponentFromProp(content, 'footerRender')
+ const rightContentRender = getComponentFromProp(content, 'rightContentRender')
+ const collapsedButtonRender = getComponentFromProp(content, 'collapsedButtonRender')
+ const menuHeaderRender = getComponentFromProp(content, 'menuHeaderRender')
+ const breadcrumbRender = getComponentFromProp(content, 'breadcrumbRender')
+ const headerContentRender = getComponentFromProp(content, 'headerContentRender')
+ const menuRender = getComponentFromProp(content, 'menuRender')
+ const headerBottomRender = getComponentFromProp(content, 'headerBottomRender')
+ const isTopMenu = layout === 'topmenu'
+ const hasSiderMenu = !isTopMenu
+ // If it is a fix menu, calculate padding
+ // don't need padding in phone mode
+ const hasLeftPadding = fixSiderbar && !isTopMenu && !isMobile
+ const cdProps = {
+ ...props,
+ hasSiderMenu,
+ footerRender,
+ menuHeaderRender,
+ rightContentRender,
+ collapsedButtonRender,
+ breadcrumbRender,
+ headerContentRender,
+ menuRender
+ }
+ return (
+
+
+
+
+
+ {headerRender(h, {
+ ...cdProps,
+ mode: 'horizontal'
+ })}
+
+ {headerBottomRender}
+
+
+
+
+ { footerRender !== false && (
+
+ { isFun(footerRender) && footerRender(h) || footerRender }
+
+ ) || null
+ }
+
+
+
+
+ )
+ }
+}
+
+BasicLayout.install = function (Vue) {
+ Vue.component(PageHeaderWrapper.name, PageHeaderWrapper)
+ Vue.component('PageContainer', PageHeaderWrapper)
+ Vue.component('ProLayout', BasicLayout)
+}
+
+export default BasicLayout
diff --git a/hotgo-web/src/components/ProLayout/BasicLayout.less b/hotgo-web/src/components/ProLayout/BasicLayout.less
new file mode 100644
index 0000000..548446d
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/BasicLayout.less
@@ -0,0 +1,101 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+@basicLayout-prefix-cls: ~'@{ant-prefix}-pro-basicLayout';
+@sider-menu-prefix-cls: ~'@{ant-prefix}-pro-sider-menu';
+@nav-header-height: @layout-header-height;
+
+.@{basicLayout-prefix-cls} {
+
+ &:not('.ant-pro-basicLayout-mobile') {
+ ::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+ }
+ ::-webkit-scrollbar-track {
+ background: rgba(0, 0, 0, 0.06);
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
+ }
+ /* 滚动条滑块 */
+ ::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.12);
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.2);
+ }
+ }
+
+ // BFC
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ min-height: 100%;
+
+ .ant-layout-header {
+ &:not(.ant-pro-top-menu) {
+ background: @component-background;
+ }
+
+ &.ant-pro-fixed-header {
+ position: fixed;
+ top: 0;
+ }
+ }
+
+ &-content {
+ position: relative;
+ margin: 24px;
+ transition: all 0.2s;
+ .@{ant-prefix}-pro-page-header-wrap {
+ margin: -24px -24px 0;
+ }
+ &-disable-margin {
+ margin: 0;
+ > div > .@{ant-prefix}-pro-page-header-wrap {
+ margin: 0;
+ }
+ }
+ > .ant-layout {
+ max-height: 100%;
+ }
+ }
+
+ // append hook styles
+
+ .ant-layout-sider-children {
+ height: 100%;
+ }
+
+ .trigger {
+ font-size: 18px;
+ line-height: 64px;
+ padding: 0 24px;
+ cursor: pointer;
+ transition: color 0.3s;
+
+ &:hover {
+ color: #1890ff;
+ }
+ }
+
+ &-content {
+ position: relative;
+ margin: 24px;
+ transition: all 0.2s;
+ .@{ant-prefix}-pro-page-header-wrap {
+ margin: -24px -24px 0;
+ }
+ &-disable-margin {
+ margin: 0;
+ > div > .@{ant-prefix}-pro-page-header-wrap {
+ margin: 0;
+ }
+ }
+ > .ant-layout {
+ max-height: 100%;
+ }
+ }
+
+ .color-picker {
+ margin: 10px 0;
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/BlockLayout.jsx b/hotgo-web/src/components/ProLayout/BlockLayout.jsx
new file mode 100644
index 0000000..48b6157
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/BlockLayout.jsx
@@ -0,0 +1,9 @@
+const BlockLayout = {
+ name: 'BlockLayout',
+ functional: true,
+ render (createElement, content) {
+ return content.children
+ }
+}
+
+export default BlockLayout
diff --git a/hotgo-web/src/components/ProLayout/Header.jsx b/hotgo-web/src/components/ProLayout/Header.jsx
new file mode 100644
index 0000000..5b1a058
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/Header.jsx
@@ -0,0 +1,109 @@
+import './Header.less'
+
+import 'ant-design-vue/es/layout/style'
+import Layout from 'ant-design-vue/es/layout'
+
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import BaseMenu from './components/RouteMenu/BaseMenu'
+import { defaultRenderLogoAntTitle, SiderMenuProps } from './components/SiderMenu/SiderMenu'
+import GlobalHeader, { GlobalHeaderProps } from './components/GlobalHeader'
+import { VueFragment } from './components'
+import { isFun } from './utils/util'
+
+const { Header } = Layout
+
+export const HeaderViewProps = {
+ ...GlobalHeaderProps,
+ ...SiderMenuProps,
+ isMobile: PropTypes.bool.def(false),
+ collapsed: PropTypes.bool,
+ logo: PropTypes.any,
+ hasSiderMenu: PropTypes.bool,
+ autoHideHeader: PropTypes.bool,
+ menuRender: PropTypes.any,
+ headerRender: PropTypes.any,
+ rightContentRender: PropTypes.any,
+ visible: PropTypes.bool.def(true)
+}
+
+const renderContent = (h, props) => {
+ const isTop = props.layout === 'topmenu'
+ const maxWidth = 1200 - 280 - 120
+ const contentWidth = props.contentWidth === 'Fixed'
+ const baseCls = 'ant-pro-top-nav-header'
+ const { logo, title, theme, isMobile, headerRender, rightContentRender, menuHeaderRender } = props
+ const rightContentProps = { theme, isTop, isMobile }
+ let defaultDom =
+ if (isTop && !isMobile) {
+ defaultDom = (
+
+
+ {menuHeaderRender && (
+
+
+ {defaultRenderLogoAntTitle(h, { logo, title, menuHeaderRender })}
+
+
+ )}
+
+ {isFun(rightContentRender) && rightContentRender(h, rightContentProps) || rightContentRender}
+
+
+ )
+ }
+ if (headerRender) {
+ return headerRender(h, props)
+ }
+ return defaultDom
+}
+
+const HeaderView = {
+ name: 'HeaderView',
+ props: HeaderViewProps,
+ render (h) {
+ const {
+ visible,
+ isMobile,
+ layout,
+ collapsed,
+ siderWidth,
+ fixedHeader,
+ hasSiderMenu
+ } = this.$props
+ const props = this.$props
+ const isTop = layout === 'topmenu'
+
+ const needSettingWidth = fixedHeader && hasSiderMenu && !isTop && !isMobile
+
+ const className = {
+ 'ant-pro-fixed-header': fixedHeader,
+ 'ant-pro-top-menu': isTop
+ }
+
+ // 没有 <>> 暂时代替写法
+ return (
+ visible ? (
+
+ { fixedHeader && }
+
+ {renderContent(h, props)}
+
+
+ ) : null
+ )
+ }
+}
+
+export default HeaderView
diff --git a/hotgo-web/src/components/ProLayout/Header.less b/hotgo-web/src/components/ProLayout/Header.less
new file mode 100644
index 0000000..beefc71
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/Header.less
@@ -0,0 +1,91 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+@top-nav-header-prefix-cls: ~'@{ant-prefix}-pro-top-nav-header';
+@pro-layout-fixed-header-prefix-cls: ~'@{ant-prefix}-pro-fixed-header';
+
+.@{top-nav-header-prefix-cls} {
+ position: relative;
+ width: 100%;
+ height: 50px;
+ box-shadow: @box-shadow-base;
+ transition: background 0.3s, width 0.2s;
+ .ant-menu-submenu.ant-menu-submenu-horizontal {
+ height: 100%;
+ line-height: @layout-header-height;
+ .ant-menu-submenu-title {
+ height: 100%;
+ }
+ }
+
+ &.light {
+ background-color: @component-background;
+ h1 {
+ color: #002140;
+ }
+ }
+
+ &-main {
+ display: flex;
+ height: @layout-header-height;
+ padding-left: 24px;
+ &.wide {
+ max-width: 1200px;
+ margin: auto;
+ padding-left: 0;
+ }
+ .left {
+ display: flex;
+ flex: 1;
+ }
+ .right {
+ width: 324px;
+ }
+ }
+
+ &-logo {
+ position: relative;
+ width: 165px;
+ height: @layout-header-height;
+ overflow: hidden;
+ line-height: @layout-header-height;
+ transition: all 0.3s;
+ img, svg {
+ display: inline-block;
+ height: 32px;
+ width: 32px;
+ vertical-align: middle;
+ }
+ h1 {
+ display: inline-block;
+ margin: 0 0 0 12px;
+ color: @btn-primary-color;
+ font-weight: 400;
+ font-size: 16px;
+ vertical-align: top;
+ }
+ }
+ &-menu {
+ .ant-menu.ant-menu-horizontal {
+ height: @layout-header-height;
+ line-height: @layout-header-height;
+ border: none;
+ }
+ }
+}
+
+.@{pro-layout-fixed-header-prefix-cls} {
+ z-index: 9;
+ width: 100%;
+ transition: width 0.2s;
+}
+
+.drop-down {
+ &.menu {
+ .anticon {
+ margin-right: 8px;
+ }
+ .ant-dropdown-menu-item {
+ min-width: 160px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/hotgo-web/src/components/ProLayout/PageView.jsx b/hotgo-web/src/components/ProLayout/PageView.jsx
new file mode 100644
index 0000000..66ad750
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/PageView.jsx
@@ -0,0 +1,14 @@
+import { PageHeaderWrapper } from './components'
+
+const PageView = {
+ name: 'PageView',
+ render () {
+ return (
+
+
+
+ )
+ }
+}
+
+export default PageView
diff --git a/hotgo-web/src/components/ProLayout/WrapContent.jsx b/hotgo-web/src/components/ProLayout/WrapContent.jsx
new file mode 100644
index 0000000..bc0d26d
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/WrapContent.jsx
@@ -0,0 +1,44 @@
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+
+import 'ant-design-vue/es/layout/style'
+import Layout from 'ant-design-vue/es/layout'
+import ConfigProvider from 'ant-design-vue/es/config-provider'
+import GridContent from './components/GridContent'
+
+const { Content } = Layout
+
+const WrapContentProps = {
+ isChildrenLayout: PropTypes.bool,
+ location: PropTypes.any,
+ contentHeight: PropTypes.number,
+ contentWidth: PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid')
+}
+
+const WrapContent = {
+ name: 'WrapContent',
+ props: WrapContentProps,
+ render (h) {
+ const {
+ isChildrenLayout,
+ contentWidth
+ } = this.$props
+ return (
+
+ {
+ if (isChildrenLayout) {
+ return el.parentNode()
+ }
+ return document.body
+ }}
+ >
+
+ {this.$slots.default}
+
+
+
+ )
+ }
+}
+
+export default WrapContent
diff --git a/hotgo-web/src/components/ProLayout/components/ConfigProvider/index.js b/hotgo-web/src/components/ProLayout/components/ConfigProvider/index.js
new file mode 100644
index 0000000..a246071
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/ConfigProvider/index.js
@@ -0,0 +1,27 @@
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+
+const ProConfigProviderProps = {
+ i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false),
+ contentWidth: PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid'),
+ breadcrumbRender: PropTypes.func
+}
+
+const ConfigProvider = {
+ name: 'ProConfigProvider',
+ props: ProConfigProviderProps,
+ provide () {
+ const _self = this
+ return {
+ locale: _self.$props.i18nRender,
+ contentWidth: _self.$props.contentWidth,
+ breadcrumbRender: _self.$props.breadcrumbRender
+ }
+ },
+ render () {
+ const { $scopedSlots } = this
+ const children = this.children || $scopedSlots.default
+ return children()
+ }
+}
+
+export default ConfigProvider
diff --git a/hotgo-web/src/components/ProLayout/components/DocumentTitle/SideEffect/index.js b/hotgo-web/src/components/ProLayout/components/DocumentTitle/SideEffect/index.js
new file mode 100644
index 0000000..1645a08
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/DocumentTitle/SideEffect/index.js
@@ -0,0 +1,17 @@
+/* eslint-disable */
+class SideEffect {
+ constructor ({ propsToState, handleStateChange }) {
+ if (typeof propsToState !== 'function') {
+ throw new Error('Expected propsToState to be a function.')
+ }
+ if (typeof handleStateChange !== 'function') {
+ throw new Error('Expected handleStateChange to be a function.')
+ }
+ this.options = {
+ propsToState,
+ handleStateChange
+ }
+ }
+}
+
+export default SideEffect
diff --git a/hotgo-web/src/components/ProLayout/components/DocumentTitle/index.js b/hotgo-web/src/components/ProLayout/components/DocumentTitle/index.js
new file mode 100644
index 0000000..533f958
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/DocumentTitle/index.js
@@ -0,0 +1,89 @@
+// import SideEffect from './SideEffect'
+import { setDocumentTitle } from './util'
+
+// const sideEffect = new SideEffect({
+// propsToState (propsList) {
+// var innermostProps = propsList[propsList.length - 1]
+// if (innermostProps) {
+// return innermostProps.title
+// }
+// },
+// handleStateChange (title, prefix) {
+// console.log('title', title, prefix)
+// const nextTitle = `${(title || '')} - ${prefix}`
+// if (nextTitle !== document.title) {
+// setDocumentTitle(nextTitle)
+// }
+// }
+// })
+
+const handleStateChange = (title, prefix) => {
+ const nextTitle = `${(title || '')} - ${prefix}`
+ if (nextTitle !== document.title) {
+ setDocumentTitle(nextTitle)
+ }
+}
+
+const DocumentTitle = {
+ name: 'DocumentTitle',
+ functional: true,
+ props: {
+ prefix: {
+ type: String,
+ required: false,
+ default: 'Ant Design Pro'
+ },
+ title: {
+ type: String,
+ required: true
+ }
+ },
+ // { props, data, children }
+ // eslint-disable-next-line
+ render (createElement, { props, data, children }) {
+ handleStateChange(props.title, props.prefix)
+ return children
+ }
+}
+
+DocumentTitle.install = function (Vue) {
+ // const mountedInstances = []
+ // let state
+
+ // function __emit (sideEffect) {
+ // const options = sideEffect.options
+ // state = options.propsToState(mountedInstances.map(function (instance) {
+ // return instance
+ // }))
+
+ // options.handleStateChange(state)
+ // }
+
+ // Vue.mixin({
+ // beforeMount () {
+ // const sideEffect = this.$options.sideEffect
+ // if (sideEffect) {
+ // mountedInstances.push(this)
+ // __emit(sideEffect)
+ // }
+ // },
+ // updated () {
+ // const sideEffect = this.$options.sideEffect
+ // if (sideEffect) {
+ // __emit(sideEffect)
+ // }
+ // },
+ // beforeDestroy () {
+ // const sideEffect = this.$options.sideEffect
+ // if (sideEffect) {
+ // const index = mountedInstances.indexOf(this)
+ // mountedInstances.splice(index, 1)
+ // __emit(sideEffect)
+ // }
+ // }
+ // })
+
+ Vue.component(DocumentTitle.name, DocumentTitle)
+}
+
+export default DocumentTitle
diff --git a/hotgo-web/src/components/ProLayout/components/DocumentTitle/util.js b/hotgo-web/src/components/ProLayout/components/DocumentTitle/util.js
new file mode 100644
index 0000000..f820754
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/DocumentTitle/util.js
@@ -0,0 +1,17 @@
+export const setDocumentTitle = function (title) {
+ document.title = title
+ const ua = navigator.userAgent
+ // eslint-disable-next-line
+ const regex = /\bMicroMessenger\/([\d\.]+)/
+ if (regex.test(ua) && /ip(hone|od|ad)/i.test(ua)) {
+ const i = document.createElement('iframe')
+ i.src = '/favicon.ico'
+ i.style.display = 'none'
+ i.onload = function () {
+ setTimeout(function () {
+ i.remove()
+ }, 9)
+ }
+ document.body.appendChild(i)
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/components/Fragment.jsx b/hotgo-web/src/components/ProLayout/components/Fragment.jsx
new file mode 100644
index 0000000..1ed3e54
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/Fragment.jsx
@@ -0,0 +1,7 @@
+export default {
+ name: 'VueFragment',
+ functional: true,
+ render (h, ctx) {
+ return ctx.children.length > 1 ? h('div', {}, ctx.children) : ctx.children
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/components/GlobalFooter/index.jsx b/hotgo-web/src/components/ProLayout/components/GlobalFooter/index.jsx
new file mode 100644
index 0000000..2d57c04
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/GlobalFooter/index.jsx
@@ -0,0 +1,43 @@
+import './index.less'
+
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import { getComponentFromProp, hasProp } from 'ant-design-vue/lib/_util/props-util'
+
+const GlobalFooterProps = {
+ links: PropTypes.array,
+ copyright: PropTypes.any
+}
+
+const GlobalFooter = {
+ name: 'GlobalFooter',
+ props: GlobalFooterProps,
+ render () {
+ const copyright = getComponentFromProp(this, 'copyright')
+ const links = getComponentFromProp(this, 'links')
+ const linksType = hasProp(links)
+
+ return (
+
+ )
+ }
+}
+
+export default GlobalFooter
diff --git a/hotgo-web/src/components/ProLayout/components/GlobalFooter/index.less b/hotgo-web/src/components/ProLayout/components/GlobalFooter/index.less
new file mode 100644
index 0000000..67f4b17
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/GlobalFooter/index.less
@@ -0,0 +1,31 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+@global-footer-prefix-cls: ~'@{ant-prefix}-pro-global-footer';
+
+.@{global-footer-prefix-cls} {
+ margin: 48px 0 24px 0;
+ padding: 0 16px;
+ text-align: center;
+
+ &-links {
+ margin-bottom: 8px;
+
+ a {
+ color: @text-color-secondary;
+ transition: all 0.3s;
+
+ &:not(:last-child) {
+ margin-right: 40px;
+ }
+
+ &:hover {
+ color: @text-color;
+ }
+ }
+ }
+
+ &-copyright {
+ color: @text-color-secondary;
+ font-size: @font-size-base;
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/components/GlobalHeader/index.jsx b/hotgo-web/src/components/ProLayout/components/GlobalHeader/index.jsx
new file mode 100644
index 0000000..a455820
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/GlobalHeader/index.jsx
@@ -0,0 +1,81 @@
+import './index.less'
+
+import debounce from 'lodash/debounce'
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import { triggerEvent, inBrowser, isFun } from '../../utils/util'
+import 'ant-design-vue/es/icon/style'
+import Icon from 'ant-design-vue/es/icon'
+import { defaultRenderLogo } from '../SiderMenu/SiderMenu'
+
+export const GlobalHeaderProps = {
+ collapsed: PropTypes.bool,
+ handleCollapse: PropTypes.func,
+ isMobile: PropTypes.bool.def(false),
+ fixedHeader: PropTypes.bool.def(false),
+ logo: PropTypes.any,
+ menuRender: PropTypes.any,
+ collapsedButtonRender: PropTypes.any,
+ headerContentRender: PropTypes.any,
+ rightContentRender: PropTypes.any
+}
+
+const defaultRenderCollapsedButton = (h, collapsed) => (
+
+)
+
+const GlobalHeader = {
+ name: 'GlobalHeader',
+ props: GlobalHeaderProps,
+ render (h) {
+ const { isMobile, logo, rightContentRender, headerContentRender } = this.$props
+ const toggle = () => {
+ const { collapsed, handleCollapse } = this.$props
+ if (handleCollapse) handleCollapse(!collapsed)
+ this.triggerResizeEvent()
+ }
+ const renderCollapsedButton = () => {
+ const {
+ collapsed,
+ collapsedButtonRender = defaultRenderCollapsedButton,
+ menuRender
+ } = this.$props
+ if (collapsedButtonRender !== false && menuRender !== false) {
+ return (
+
+ )
+ }
+ return null
+ }
+
+ const headerCls = 'ant-pro-global-header'
+
+ return (
+
+ )
+ },
+ methods: {
+ triggerResizeEvent: debounce(() => {
+ inBrowser && triggerEvent(window, 'resize')
+ })
+ },
+ beforeDestroy () {
+ this.triggerResizeEvent.cancel && this.triggerResizeEvent.cancel()
+ }
+}
+
+export default GlobalHeader
diff --git a/hotgo-web/src/components/ProLayout/components/GlobalHeader/index.less b/hotgo-web/src/components/ProLayout/components/GlobalHeader/index.less
new file mode 100644
index 0000000..a7fb1eb
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/GlobalHeader/index.less
@@ -0,0 +1,109 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+@global-header-prefix-cls: ~'@{ant-prefix}-pro-global-header';
+
+@pro-header-bg: @component-background;
+@pro-header-hover-bg: @component-background;
+@pro-header-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
+@pro-header-hover-trigger-action-bg: rgba(0,0,0,.025);
+
+.@{global-header-prefix-cls} {
+ position: relative;
+ height: @layout-header-height;
+ padding: 0;
+ background: @pro-header-bg;
+ box-shadow: @pro-header-box-shadow;
+
+ &-index-right {
+ float: right;
+ height: 100%;
+ margin-left: auto;
+ overflow: hidden;
+
+ .@{global-header-prefix-cls}-index-action {
+ display: inline-block;
+ height: 100%;
+ padding: 0 12px;
+ cursor: pointer;
+ transition: all .3s;
+
+ &:hover {
+ background: @pro-header-hover-trigger-action-bg;
+ }
+ }
+ }
+
+ &-logo {
+ display: inline-block;
+ height: @layout-header-height;
+ padding: 0 0 0 24px;
+ font-size: 20px;
+ line-height: @layout-header-height;
+ vertical-align: top;
+ cursor: pointer;
+ img, svg {
+ display: inline-block;
+ width: 32px;
+ height: 32px;
+ vertical-align: middle;
+ }
+ }
+
+ &-menu {
+ .anticon {
+ margin-right: 8px;
+ }
+ .ant-dropdown-menu-item {
+ min-width: 160px;
+ }
+ }
+
+ &-trigger {
+ height: @layout-header-height;
+ line-height: @layout-header-height;
+ vertical-align: top;
+ padding: 0 22px;
+ display: inline-block;
+ cursor: pointer;
+ transition: all 0.3s, padding 0s;
+ .anticon {
+ font-size: 20px;
+ vertical-align: -0.225em;
+ }
+ &:hover {
+ background: @pro-header-hover-trigger-action-bg;
+ }
+ }
+
+ &-content {
+ height: @layout-header-height;
+ line-height: @layout-header-height;
+ vertical-align: top;
+ display: inline-block;
+ }
+
+ .dark {
+ height: @layout-header-height;
+ .action {
+ color: rgba(255, 255, 255, 0.85);
+ > i {
+ color: rgba(255, 255, 255, 0.85);
+ }
+ &:hover,
+ &.opened {
+ background: @primary-color;
+ }
+ .ant-badge {
+ color: rgba(255, 255, 255, 0.85);
+ }
+ }
+ }
+
+ .ant-pro-global-header-index-action {
+ i {
+ color: rgba(0,0,0,.65);
+ vertical-align: middle;
+ }
+ }
+
+}
diff --git a/hotgo-web/src/components/ProLayout/components/GridContent/index.jsx b/hotgo-web/src/components/ProLayout/components/GridContent/index.jsx
new file mode 100644
index 0000000..4038f12
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/GridContent/index.jsx
@@ -0,0 +1,27 @@
+import './index.less'
+
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import { layoutContentWidth } from '../../utils/util'
+
+const GridContent = {
+ name: 'GridContent',
+ functional: true,
+ props: {
+ children: PropTypes.any,
+ contentWidth: PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid')
+ },
+ render (h, content) {
+ const { contentWidth } = content.props
+ const children = content.children
+
+ const propsContentWidth = layoutContentWidth(contentWidth)
+ const classNames = {
+ 'ant-pro-grid-content': true,
+ 'wide': propsContentWidth
+ }
+
+ return {children}
+ }
+}
+
+export default GridContent
diff --git a/hotgo-web/src/components/ProLayout/components/GridContent/index.less b/hotgo-web/src/components/ProLayout/components/GridContent/index.less
new file mode 100644
index 0000000..9f15f75
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/GridContent/index.less
@@ -0,0 +1,13 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+@grid-content-prefix-cls: ~'@{ant-prefix}-pro-grid-content';
+
+.@{grid-content-prefix-cls} {
+ width: 100%;
+ min-height: 100%;
+ transition: 0.3s;
+ &.wide {
+ max-width: 1200px;
+ margin: 0 auto;
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/components/PageHeaderWrapper/index.jsx b/hotgo-web/src/components/ProLayout/components/PageHeaderWrapper/index.jsx
new file mode 100644
index 0000000..e4a9870
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/PageHeaderWrapper/index.jsx
@@ -0,0 +1,232 @@
+import './index.less'
+
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import { isArray } from 'ant-design-vue/lib/_util/vue-types/utils'
+import GridContent from '../GridContent'
+import 'ant-design-vue/es/page-header/style'
+import PageHeader, { PageHeaderProps } from 'ant-design-vue/es/page-header'
+import 'ant-design-vue/es/tabs/style'
+import Tabs from 'ant-design-vue/es/tabs'
+import { getComponentFromProp } from 'ant-design-vue/lib/_util/props-util'
+
+const prefixedClassName = 'ant-pro-page-header-wrap'
+
+const PageHeaderTabConfig = {
+ tabList: PropTypes.array,
+ tabActiveKey: PropTypes.string,
+ tabProps: PropTypes.object,
+ tabChange: PropTypes.func
+}
+
+const PageHeaderWrapperProps = {
+ ...PageHeaderTabConfig,
+ ...PageHeaderProps,
+ title: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ content: PropTypes.any,
+ extraContent: PropTypes.any,
+ pageHeaderRender: PropTypes.func,
+ breadcrumb: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]).def(true),
+ back: PropTypes.func,
+
+ // only use `pro-layout` in children
+ i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false)
+}
+
+const defaultI18nRender = (t) => t
+
+const useContext = (route) => {
+ return route && {
+ ...route.meta
+ } || null
+}
+
+const noop = () => {
+}
+
+// TODO :: tabList tab 支持图标 优化
+const renderFooter = (h, tabConfigProps, i18nRender) => {
+ const {
+ tabList,
+ tabActiveKey,
+ tabChange: onTabChange,
+ tabBarExtraContent,
+ tabProps
+ } = tabConfigProps
+ return tabList && tabList.length > 0 && (
+ {
+ if (onTabChange) {
+ onTabChange(key)
+ }
+ }}
+ tabBarExtraContent={tabBarExtraContent}
+ {...tabProps}
+ >
+ {tabList.map(item => (
+
+ ))}
+
+ )
+}
+
+const renderPageHeader = (h, content, extraContent) => {
+ if (!content && !extraContent) {
+ return null
+ }
+ return (
+
+
+
+ {content && (
+
{content}
+ )}
+ {extraContent && (
+
+ )}
+
+
+
+ )
+}
+
+const defaultPageHeaderRender = (h, props, pageMeta, i18nRender) => {
+ const {
+ title: propTitle,
+ tags,
+ content,
+ pageHeaderRender,
+ extra,
+ extraContent,
+ breadcrumb,
+ back: handleBack,
+ ...restProps
+ } = props
+ if (pageHeaderRender) {
+ return pageHeaderRender({ ...props })
+ }
+ let pageHeaderTitle = propTitle
+ if (!propTitle && propTitle !== false) {
+ pageHeaderTitle = pageMeta.title
+ }
+ // title props 不是 false 且不是 array 则直接渲染 title
+ // 反之认为是 VNode, 作为 render 参数直接传入到 PageHeader
+ const title = isArray(pageHeaderTitle)
+ ? pageHeaderTitle
+ : pageHeaderTitle && i18nRender(pageHeaderTitle)
+ const tabProps = {
+ breadcrumb,
+ extra,
+ tags,
+ title,
+ footer: renderFooter(h, restProps, i18nRender)
+ }
+ if (!handleBack) {
+ tabProps.backIcon = false
+ }
+
+ return (
+
+ {renderPageHeader(h, content, extraContent)}
+
+ )
+ // return
+}
+
+const PageHeaderWrapper = {
+ name: 'PageHeaderWrapper',
+ props: PageHeaderWrapperProps,
+ inject: ['locale', 'contentWidth', 'breadcrumbRender'],
+ render (h) {
+ const { $route, $listeners } = this
+ const children = this.$slots.default
+ const title = getComponentFromProp(this, 'title')
+ const tags = getComponentFromProp(this, 'tags')
+ const content = getComponentFromProp(this, 'content')
+ const extra = getComponentFromProp(this, 'extra')
+ const extraContent = getComponentFromProp(this, 'extraContent')
+
+ const pageMeta = useContext(this.$props.route || $route)
+ const i18n = this.$props.i18nRender || this.locale || defaultI18nRender
+ const contentWidth = this.$props.contentWidth || this.contentWidth || false
+ // 当未设置 back props 或未监听 @back,不显示 back
+ // props 的 back 事件优先级高于 @back,需要注意
+ const onBack = this.$props.back || $listeners.back
+ const back = onBack && (() => {
+ // this.$emit('back')
+ // call props back func
+ onBack && onBack()
+ }) || undefined
+
+ const onTabChange = this.$props.tabChange
+ const tabChange = (key) => {
+ this.$emit('tabChange', key)
+ onTabChange && onTabChange(key)
+ }
+
+ let breadcrumb = {}
+ const propsBreadcrumb = this.$props.breadcrumb
+ if (propsBreadcrumb === true) {
+ const routes = $route.matched.concat().map(route => {
+ return {
+ path: route.path,
+ breadcrumbName: i18n(route.meta.title),
+ redirect: route.redirect
+ }
+ })
+
+ const defaultItemRender = ({ route, params, routes, paths, h }) => {
+ return (route.redirect === 'noRedirect' || routes.indexOf(route) === routes.length - 1) && (
+ {route.breadcrumbName}
+ ) || (
+ {route.breadcrumbName}
+ )
+ }
+
+ // If custom breadcrumb render undefined
+ // use default breadcrumb..
+ const itemRender = this.breadcrumbRender || defaultItemRender
+ routes.splice(0, 1)
+ breadcrumb = { props: { routes, itemRender } }
+ } else {
+ breadcrumb = propsBreadcrumb || null
+ }
+
+ const props = {
+ ...this.$props,
+ title,
+ tags,
+ content,
+ extra,
+ extraContent,
+ breadcrumb,
+ tabChange,
+ back
+ }
+
+ return (
+
+ )
+ }
+}
+
+PageHeaderWrapper.install = function (Vue) {
+ Vue.component(PageHeaderWrapper.name, PageHeaderWrapper)
+ Vue.component('page-container', PageHeaderWrapper)
+}
+
+export default PageHeaderWrapper
diff --git a/hotgo-web/src/components/ProLayout/components/PageHeaderWrapper/index.less b/hotgo-web/src/components/ProLayout/components/PageHeaderWrapper/index.less
new file mode 100644
index 0000000..10c14fa
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/PageHeaderWrapper/index.less
@@ -0,0 +1,93 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+@ant-pro-page-header-wrap: ~'@{ant-prefix}-pro-page-header-wrap';
+
+.@{ant-pro-page-header-wrap}-children-content {
+ margin: 24px 24px 0;
+}
+
+.@{ant-pro-page-header-wrap}-page-header-warp {
+ background-color: @component-background;
+}
+
+.@{ant-pro-page-header-wrap}-main {
+ .@{ant-pro-page-header-wrap}-detail {
+ display: flex;
+ }
+
+ .@{ant-pro-page-header-wrap}-row {
+ display: flex;
+ width: 100%;
+ }
+
+ .@{ant-pro-page-header-wrap}-title-content {
+ margin-bottom: 16px;
+ }
+
+ .@{ant-pro-page-header-wrap}-title,
+ .@{ant-pro-page-header-wrap}-content {
+ flex: auto;
+ }
+
+ .@{ant-pro-page-header-wrap}-extraContent,
+ .@{ant-pro-page-header-wrap}-main {
+ flex: 0 1 auto;
+ }
+
+ .@{ant-pro-page-header-wrap}-main {
+ width: 100%;
+ }
+
+ .@{ant-pro-page-header-wrap}-title {
+ margin-bottom: 16px;
+ }
+
+ .@{ant-pro-page-header-wrap}-logo {
+ margin-bottom: 16px;
+ }
+
+ .@{ant-pro-page-header-wrap}-extraContent {
+ min-width: 242px;
+ margin-left: 88px;
+ text-align: right;
+ }
+}
+
+@media screen and (max-width: @screen-xl) {
+ .@{ant-pro-page-header-wrap}-main {
+ .@{ant-pro-page-header-wrap}-extraContent {
+ margin-left: 44px;
+ }
+ }
+}
+
+@media screen and (max-width: @screen-lg) {
+ .@{ant-pro-page-header-wrap}-main {
+ .@{ant-pro-page-header-wrap}-extraContent {
+ margin-left: 20px;
+ }
+ }
+}
+
+@media screen and (max-width: @screen-md) {
+ .@{ant-pro-page-header-wrap}-main {
+ .@{ant-pro-page-header-wrap}-row {
+ display: block;
+ }
+
+ .@{ant-pro-page-header-wrap}-action,
+ .@{ant-pro-page-header-wrap}-extraContent {
+ margin-left: 0;
+ text-align: left;
+ }
+ }
+}
+
+@media screen and (max-width: @screen-sm) {
+ .@{ant-pro-page-header-wrap}-detail {
+ display: block;
+ }
+ .@{ant-pro-page-header-wrap}-extraContent {
+ margin-left: 0;
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/components/RouteMenu/BaseMenu.jsx b/hotgo-web/src/components/ProLayout/components/RouteMenu/BaseMenu.jsx
new file mode 100644
index 0000000..59b1986
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/RouteMenu/BaseMenu.jsx
@@ -0,0 +1,181 @@
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+
+import 'ant-design-vue/es/menu/style'
+import Menu from 'ant-design-vue/es/menu'
+import 'ant-design-vue/es/icon/style'
+import Icon from 'ant-design-vue/es/icon'
+
+const {
+ Item: MenuItem,
+ SubMenu
+} = Menu
+
+export const RouteMenuProps = {
+ menus: PropTypes.array,
+ theme: PropTypes.string.def('dark'),
+ mode: PropTypes.string.def('inline'),
+ collapsedWidth: PropTypes.number.def('60'),
+ collapsed: PropTypes.bool.def(false),
+ i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false)
+}
+
+const httpReg = /(http|https|ftp):\/\/([\w.]+\/?)\S*/
+
+const renderMenu = (h, item, i18nRender) => {
+ if (item && !item.hidden) {
+ const bool = item.children && !item.hideChildrenInMenu
+ return bool ? renderSubMenu(h, item, i18nRender) : renderMenuItem(h, item, i18nRender)
+ }
+ return null
+}
+
+const renderSubMenu = (h, item, i18nRender) => {
+ return (
+
+ {renderIcon(h, item.meta.icon)}
+ {renderTitle(h, item.meta.title, i18nRender)}
+
+ )}>
+ {!item.hideChildrenInMenu && item.children.map(cd => renderMenu(h, cd, i18nRender))}
+
+ )
+}
+
+const renderMenuItem = (h, item, i18nRender) => {
+ const meta = Object.assign({}, item.meta)
+ const target = meta.target || null
+ const hasRemoteUrl = httpReg.test(item.path)
+ const CustomTag = target && 'a' || 'router-link'
+ const props = { to: { name: item.name } }
+ const attrs = (hasRemoteUrl || target) ? { href: item.path, target: target } : {}
+ if (item.children && item.hideChildrenInMenu) {
+ // 把有子菜单的 并且 父菜单是要隐藏子菜单的
+ // 都给子菜单增加一个 hidden 属性
+ // 用来给刷新页面时, selectedKeys 做控制用
+ item.children.forEach(cd => {
+ cd.meta = Object.assign(cd.meta || {}, { hidden: true })
+ })
+ }
+ return (
+
+
+ {renderIcon(h, meta.icon)}
+ {renderTitle(h, meta.title, i18nRender)}
+
+
+ )
+}
+
+const renderIcon = (h, icon) => {
+ if (icon === undefined || icon === 'none' || icon === null) {
+ return null
+ }
+ const props = {}
+ typeof (icon) === 'object' ? (props.component = icon) : (props.type = icon)
+ return
+}
+
+const renderTitle = (h, title, i18nRender) => {
+ return { i18nRender && i18nRender(title) || title }
+}
+
+const RouteMenu = {
+ name: 'RouteMenu',
+ props: RouteMenuProps,
+ data () {
+ return {
+ openKeys: [],
+ selectedKeys: [],
+ cachedOpenKeys: [],
+ cachedSelectedKeys: []
+ }
+ },
+ render (h) {
+ const { mode, theme, menus, i18nRender } = this
+ const handleOpenChange = (openKeys) => {
+ // 在水平模式下时,不再执行后续
+ if (mode === 'horizontal') {
+ this.openKeys = openKeys
+ return
+ }
+ const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key))
+ if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
+ this.openKeys = openKeys
+ } else {
+ this.openKeys = latestOpenKey ? [latestOpenKey] : []
+ }
+ }
+
+ const dynamicProps = {
+ props: {
+ mode,
+ theme,
+ openKeys: this.openKeys,
+ selectedKeys: this.selectedKeys
+ },
+ on: {
+ select: menu => {
+ this.$emit('select', menu)
+ if (!httpReg.test(menu.key)) {
+ this.selectedKeys = menu.selectedKeys
+ }
+ },
+ openChange: handleOpenChange
+ }
+ }
+
+ const menuItems = menus.map(item => {
+ if (item.hidden) {
+ return null
+ }
+ return renderMenu(h, item, i18nRender)
+ })
+ return {menuItems}
+ },
+ methods: {
+ updateMenu () {
+ const routes = this.$route.matched.concat()
+ const { hidden } = this.$route.meta
+ if (routes.length >= 3 && hidden) {
+ routes.pop()
+ this.selectedKeys = [routes[routes.length - 1].path]
+ } else {
+ this.selectedKeys = [routes.pop().path]
+ }
+ const openKeys = []
+ if (this.mode === 'inline') {
+ routes.forEach(item => {
+ item.path && openKeys.push(item.path)
+ })
+ }
+
+ this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
+ }
+ },
+ computed: {
+ rootSubmenuKeys: vm => {
+ const keys = []
+ vm.menus.forEach(item => keys.push(item.path))
+ return keys
+ }
+ },
+ created () {
+ this.$watch('$route', () => {
+ this.updateMenu()
+ })
+ this.$watch('collapsed', val => {
+ if (val) {
+ this.cachedOpenKeys = this.openKeys.concat()
+ this.openKeys = []
+ } else {
+ this.openKeys = this.cachedOpenKeys
+ }
+ })
+ },
+ mounted () {
+ this.updateMenu()
+ }
+}
+
+export default RouteMenu
diff --git a/hotgo-web/src/components/ProLayout/components/RouteMenu/index.js b/hotgo-web/src/components/ProLayout/components/RouteMenu/index.js
new file mode 100644
index 0000000..b6dbfee
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/RouteMenu/index.js
@@ -0,0 +1,2 @@
+import BaseMenu from './BaseMenu'
+export default BaseMenu
diff --git a/hotgo-web/src/components/ProLayout/components/SettingDrawer/BlockCheckbox.jsx b/hotgo-web/src/components/ProLayout/components/SettingDrawer/BlockCheckbox.jsx
new file mode 100644
index 0000000..51cc2eb
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SettingDrawer/BlockCheckbox.jsx
@@ -0,0 +1,69 @@
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+
+import 'ant-design-vue/es/tooltip/style'
+import Tooltip from 'ant-design-vue/es/tooltip'
+import 'ant-design-vue/es/icon/style'
+import Icon from 'ant-design-vue/es/icon'
+
+const BlockCheckboxProps = {
+ value: PropTypes.string,
+ // Item: { key, url, title }
+ list: PropTypes.array,
+
+ i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false)
+}
+
+const baseClassName = 'ant-pro-setting-drawer-block-checbox'
+const BlockCheckbox = {
+ props: BlockCheckboxProps,
+ inject: ['locale'],
+ render (h) {
+ const { value, list } = this
+ const i18n = this.$props.i18nRender || this.locale
+
+ const items = list || [
+ {
+ key: 'sidemenu',
+ url:
+ 'https://gw.alipayobjects.com/zos/antfincdn/XwFOFbLkSM/LCkqqYNmvBEbokSDscrm.svg',
+ title: i18n('app.setting.sidemenu')
+ },
+ {
+ key: 'topmenu',
+ url:
+ 'https://gw.alipayobjects.com/zos/antfincdn/URETY8%24STp/KDNDBbriJhLwuqMoxcAr.svg',
+ title: i18n('app.setting.topmenu')
+ }
+ ]
+
+ const handleChange = (key) => {
+ this.$emit('change', key)
+ }
+
+ const disableStyle = {
+ cursor: 'not-allowed'
+ }
+
+ return (
+
+ {items.map(item => (
+
+ !item.disable && handleChange(item.key)}>
+
+
+
+
+
+
+ ))}
+
+ )
+ }
+}
+
+export default BlockCheckbox
diff --git a/hotgo-web/src/components/ProLayout/components/SettingDrawer/LayoutChange.jsx b/hotgo-web/src/components/ProLayout/components/SettingDrawer/LayoutChange.jsx
new file mode 100644
index 0000000..b1915a8
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SettingDrawer/LayoutChange.jsx
@@ -0,0 +1,95 @@
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+
+import 'ant-design-vue/es/tooltip/style'
+import Tooltip from 'ant-design-vue/es/tooltip'
+import 'ant-design-vue/es/list/style'
+import List from 'ant-design-vue/es/list'
+import 'ant-design-vue/es/select/style'
+import Select from 'ant-design-vue/es/select'
+import 'ant-design-vue/es/switch/style'
+import Switch from 'ant-design-vue/es/switch'
+
+export const renderLayoutSettingItem = (h, item) => {
+ const action = { ...item.action }
+ return (
+
+
+ {item.title}
+
+
+ )
+}
+
+export const LayoutSettingProps = {
+ contentWidth: PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid'),
+ fixedHeader: PropTypes.bool,
+ fixSiderbar: PropTypes.bool,
+ layout: PropTypes.oneOf(['sidemenu', 'topmenu']),
+
+ i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false)
+}
+
+export default {
+ props: LayoutSettingProps,
+ inject: ['locale'],
+ render (h) {
+ const i18n = this.$props.i18nRender || this.locale
+ const { contentWidth, fixedHeader, layout, fixSiderbar } = this
+
+ const handleChange = (type, value) => {
+ this.$emit('change', { type, value })
+ }
+
+ return (
+ handleChange('contentWidth', value)}
+ style={{ width: '80px' }}
+ >
+ {layout === 'sidemenu' ? null : (
+
+ {i18n('app.setting.content-width.fixed')}
+
+ )}
+
+ {i18n('app.setting.content-width.fluid')}
+
+
+ )
+ },
+ {
+ title: i18n('app.setting.fixedheader'),
+ action: (
+ handleChange('fixedHeader', checked)}
+ />
+ )
+ },
+ {
+ title: i18n('app.setting.fixedsidebar'),
+ disabled: layout === 'topmenu',
+ disabledReason: i18n('app.setting.fixedsidebar.hint'),
+ action: (
+ handleChange('fixSiderbar', checked)}
+ />
+ )
+ }
+ ]}
+ renderItem={(item, index) => renderLayoutSettingItem(h, item)}
+ />
+ )
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/components/SettingDrawer/ThemeColor.jsx b/hotgo-web/src/components/ProLayout/components/SettingDrawer/ThemeColor.jsx
new file mode 100644
index 0000000..5eddbea
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SettingDrawer/ThemeColor.jsx
@@ -0,0 +1,75 @@
+import './ThemeColor.less'
+
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import { genThemeToString } from '../../utils/util'
+import 'ant-design-vue/es/tooltip/style'
+import Tooltip from 'ant-design-vue/es/tooltip'
+import 'ant-design-vue/es/icon/style'
+import Icon from 'ant-design-vue/es/icon'
+
+const baseClassName = 'theme-color'
+
+export const TagProps = {
+ color: PropTypes.string,
+ check: PropTypes.bool
+}
+
+const Tag = {
+ props: TagProps,
+ functional: true,
+ render (h, content) {
+ const { props: { color, check }, data } = content
+ return (
+
+ { check ? : null }
+
+ )
+ }
+}
+
+export const ThemeColorProps = {
+ colors: PropTypes.array,
+ title: PropTypes.string,
+ value: PropTypes.string,
+
+ i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false)
+}
+
+const ThemeColor = {
+ props: ThemeColorProps,
+ inject: ['locale'],
+ render (h) {
+ const { title, value, colors = [] } = this
+ const i18n = this.$props.i18nRender || this.locale
+ const handleChange = (key) => {
+ this.$emit('change', key)
+ }
+
+ return (
+
+
{title}
+
+ {colors.map(item => {
+ const themeKey = genThemeToString(item.key)
+ const check = value === item.key || genThemeToString(value) === item.key
+ return (
+
+ handleChange(item.key)}
+ />
+
+ )
+ })}
+
+
+ )
+ }
+}
+
+export default ThemeColor
diff --git a/hotgo-web/src/components/ProLayout/components/SettingDrawer/ThemeColor.less b/hotgo-web/src/components/ProLayout/components/SettingDrawer/ThemeColor.less
new file mode 100644
index 0000000..0d18b79
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SettingDrawer/ThemeColor.less
@@ -0,0 +1,26 @@
+@import './index.less';
+
+.@{ant-pro-setting-drawer}-content {
+ .theme-color {
+ margin-top: 24px;
+ overflow: hidden;
+
+ .theme-color-title {
+ margin-bottom: 12px;
+ font-size: 14px;
+ line-height: 22px;
+ }
+
+ .theme-color-block {
+ float: left;
+ width: 20px;
+ height: 20px;
+ margin-right: 8px;
+ color: #fff;
+ font-weight: bold;
+ text-align: center;
+ border-radius: 2px;
+ cursor: pointer;
+ }
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/components/SettingDrawer/index.jsx b/hotgo-web/src/components/ProLayout/components/SettingDrawer/index.jsx
new file mode 100644
index 0000000..dfa5eff
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SettingDrawer/index.jsx
@@ -0,0 +1,267 @@
+import './index.less'
+
+import omit from 'omit.js'
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+
+import 'ant-design-vue/es/divider/style'
+import Divider from 'ant-design-vue/es/divider'
+
+import 'ant-design-vue/es/drawer/style'
+import Drawer from 'ant-design-vue/es/drawer'
+
+import 'ant-design-vue/es/button/style'
+import Button from 'ant-design-vue/es/button'
+
+import 'ant-design-vue/es/icon/style'
+import Icon from 'ant-design-vue/es/icon'
+
+import 'ant-design-vue/es/alert/style'
+import Alert from 'ant-design-vue/es/alert'
+
+import antPortal from 'ant-design-vue/es/_util/portalDirective'
+
+import 'ant-design-vue/es/message/style'
+import message from 'ant-design-vue/es/message'
+
+import BlockCheckbox from './BlockCheckbox'
+import ThemeColor from './ThemeColor'
+import { updateTheme, updateColorWeak } from '../../utils/dynamicTheme'
+import { genStringToTheme } from '../../utils/util'
+import CopyToClipboard from 'vue-copy-to-clipboard'
+
+const baseClassName = 'ant-pro-setting-drawer'
+
+const BodyProps = {
+ title: PropTypes.string.def('')
+}
+
+const Body = {
+ props: BodyProps,
+ render (h) {
+ const { title } = this
+
+ return (
+
+
{title}
+ {this.$slots.default}
+
+ )
+ }
+}
+
+const defaultI18nRender = (t) => t
+
+const getThemeList = (i18nRender) => {
+ const list = window.umi_plugin_ant_themeVar || []
+
+ const themeList = [
+ {
+ key: 'light',
+ url: 'https://gw.alipayobjects.com/zos/antfincdn/NQ%24zoisaD2/jpRkZQMyYRryryPNtyIC.svg',
+ title: i18nRender('app.setting.pagestyle.light')
+ }
+ ]
+
+ const darkColorList = [
+ {
+ key: '#1890ff',
+ color: '#1890ff',
+ theme: 'dark'
+ }
+ ]
+
+ const lightColorList = [
+ {
+ key: '#1890ff',
+ color: '#1890ff',
+ theme: 'dark'
+ }
+ ]
+ // insert theme color List
+ list.forEach(item => {
+ const color = (item.modifyVars || {})['@primary-color']
+ if (item.theme === 'dark' && color) {
+ darkColorList.push({
+ color,
+ ...item
+ })
+ }
+ if (!item.theme || item.theme === 'light') {
+ lightColorList.push({
+ color,
+ ...item
+ })
+ }
+ })
+
+ return {
+ colorList: {
+ dark: darkColorList,
+ light: lightColorList
+ },
+ themeList
+ }
+}
+
+const handleChangeSetting = (key, value, hideMessageLoading) => {
+ if (key === 'primaryColor') {
+ // 更新主色调
+ updateTheme(value)
+ }
+ if (key === 'colorWeak') {
+ updateColorWeak(value)
+ }
+}
+
+const genCopySettingJson = (settings) =>
+ JSON.stringify(
+ omit(
+ {
+ ...settings,
+ primaryColor: genStringToTheme(settings.primaryColor)
+ },
+ ['colorWeak']
+ ),
+ null,
+ 2
+ )
+
+export const settings = {
+ theme: PropTypes.oneOf(['dark', 'light', 'realDark']),
+ primaryColor: PropTypes.string,
+ layout: PropTypes.oneOf(['sidemenu', 'topmenu']),
+ colorWeak: PropTypes.bool,
+ contentWidth: PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid'),
+ // 替换兼容 PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid')
+ // contentWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).def('Fluid'),
+ fixedHeader: PropTypes.bool,
+ fixSiderbar: PropTypes.bool,
+ hideHintAlert: PropTypes.bool.def(false),
+ hideCopyButton: PropTypes.bool.def(false)
+}
+
+export const SettingDrawerProps = {
+ getContainer: PropTypes.func,
+ settings: PropTypes.objectOf(settings),
+
+ i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false)
+}
+
+const SettingDrawer = {
+ name: 'SettingDrawer',
+ props: SettingDrawerProps,
+ inject: ['locale'],
+ data () {
+ return {
+ show: false
+ }
+ },
+ render (h) {
+ const {
+ setShow,
+ getContainer,
+ settings
+ } = this
+
+ const {
+ theme = 'dark',
+ primaryColor = 'daybreak',
+ hideHintAlert,
+ hideCopyButton
+ } = settings
+
+ const i18n = this.$props.i18nRender || this.locale || defaultI18nRender
+ const themeList = getThemeList(i18n)
+
+ const iconStyle = {
+ color: '#fff',
+ fontSize: 20
+ }
+
+ const changeSetting = (type, value) => {
+ this.$emit('change', { type, value })
+ handleChangeSetting(type, value, false)
+ }
+
+ return (
+ setShow(false)}
+ placement="right"
+ getContainer={getContainer}
+ style={{
+ zIndex: 999
+ }}
+ >
+
+ setShow(!this.show)} style="display:none;">
+ {this.show
+ ? ()
+ : ()
+ }
+
+
+
+
+
{
+ changeSetting('theme', val)
+ }} />
+
+
+ {
+ // changeSetting('primaryColor', color, null)
+ // 解决严重漏洞
+ changeSetting('primaryColor', color)
+ }}
+ />
+
+ {hideHintAlert && hideCopyButton ? null : }
+ {hideHintAlert ? null : (
+ )}
+ showIcon
+ style={{ marginBottom: '16px' }}
+ />
+ )}
+
+ {hideCopyButton ? null : (
+
+ message.success(i18n('app.setting.copyinfo'))
+ }
+ >
+
+ {i18n('app.setting.copy')}
+
+
+ )}
+
+
+
+
+ )
+ },
+ methods: {
+ setShow (flag) {
+ this.show = flag
+ }
+ }
+}
+
+SettingDrawer.install = function (Vue) {
+ Vue.use(antPortal)
+ Vue.component(SettingDrawer.name, SettingDrawer)
+}
+
+export default SettingDrawer
diff --git a/hotgo-web/src/components/ProLayout/components/SettingDrawer/index.less b/hotgo-web/src/components/ProLayout/components/SettingDrawer/index.less
new file mode 100644
index 0000000..ee836c6
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SettingDrawer/index.less
@@ -0,0 +1,90 @@
+@import "../../../../assets/styles/default.less";
+
+@ant-pro-setting-drawer: ~'@{ant-prefix}-pro-setting-drawer';
+
+.@{ant-pro-setting-drawer} {
+ &-content {
+ position: relative;
+ min-height: 100%;
+
+ .ant-list-item {
+ span {
+ flex: 1;
+ }
+ }
+ }
+
+ &-block-checbox {
+ display: flex;
+
+ &-item {
+ position: relative;
+ margin-right: 16px;
+ // box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
+ border-radius: @border-radius-base;
+ cursor: pointer;
+
+ img {
+ width: 48px;
+ }
+ }
+
+ &-selectIcon {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 100%;
+ height: 100%;
+ padding-top: 15px;
+ padding-left: 24px;
+ color: @primary-color;
+ font-weight: bold;
+ font-size: 14px;
+
+ .action {
+ color: @primary-color;
+ }
+ }
+ }
+
+ &-color_block {
+ display: inline-block;
+ width: 38px;
+ height: 22px;
+ margin: 4px;
+ margin-right: 12px;
+ vertical-align: middle;
+ border-radius: 4px;
+ cursor: pointer;
+ }
+
+ &-title {
+ margin-bottom: 12px;
+ color: @heading-color;
+ font-size: 14px;
+ line-height: 22px;
+ }
+
+ &-handle {
+ position: absolute;
+ top: 240px;
+ right: 300px;
+ z-index: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 48px;
+ height: 48px;
+ font-size: 16px;
+ text-align: center;
+ background: @primary-color;
+ border-radius: 4px 0 0 4px;
+ cursor: pointer;
+ pointer-events: auto;
+ }
+
+ &-production-hint {
+ margin-top: 16px;
+ font-size: 12px;
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/components/SettingDrawer/index原始文件勿删.jsx b/hotgo-web/src/components/ProLayout/components/SettingDrawer/index原始文件勿删.jsx
new file mode 100644
index 0000000..bc7eccc
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SettingDrawer/index原始文件勿删.jsx
@@ -0,0 +1,344 @@
+import './index.less'
+
+import omit from 'omit.js'
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+
+import 'ant-design-vue/es/divider/style'
+import Divider from 'ant-design-vue/es/divider'
+
+import 'ant-design-vue/es/drawer/style'
+import Drawer from 'ant-design-vue/es/drawer'
+
+import 'ant-design-vue/es/list/style'
+import List from 'ant-design-vue/es/list'
+
+import 'ant-design-vue/es/switch/style'
+import Switch from 'ant-design-vue/es/switch'
+
+import 'ant-design-vue/es/button/style'
+import Button from 'ant-design-vue/es/button'
+
+import 'ant-design-vue/es/icon/style'
+import Icon from 'ant-design-vue/es/icon'
+
+import 'ant-design-vue/es/alert/style'
+import Alert from 'ant-design-vue/es/alert'
+
+import antPortal from 'ant-design-vue/es/_util/portalDirective'
+
+import 'ant-design-vue/es/message/style'
+import message from 'ant-design-vue/es/message'
+
+import BlockCheckbox from './BlockCheckbox'
+import ThemeColor from './ThemeColor'
+import LayoutSetting, { renderLayoutSettingItem } from './LayoutChange'
+import { updateTheme, updateColorWeak } from '../../utils/dynamicTheme'
+import { genStringToTheme } from '../../utils/util'
+import CopyToClipboard from 'vue-copy-to-clipboard'
+
+const baseClassName = 'ant-pro-setting-drawer'
+
+const BodyProps = {
+ title: PropTypes.string.def('')
+}
+
+const Body = {
+ props: BodyProps,
+ render (h) {
+ const { title } = this
+
+ return (
+
+
{title}
+ {this.$slots.default}
+
+ )
+ }
+}
+
+const defaultI18nRender = (t) => t
+
+const getThemeList = (i18nRender) => {
+ const list = window.umi_plugin_ant_themeVar || []
+
+ const themeList = [
+ {
+ key: 'light',
+ url: 'https://gw.alipayobjects.com/zos/antfincdn/NQ%24zoisaD2/jpRkZQMyYRryryPNtyIC.svg',
+ title: i18nRender('app.setting.pagestyle.light')
+ },
+ {
+ key: 'dark',
+ url: 'https://gw.alipayobjects.com/zos/antfincdn/XwFOFbLkSM/LCkqqYNmvBEbokSDscrm.svg',
+ title: i18nRender('app.setting.pagestyle.dark')
+ }
+ ]
+
+ const darkColorList = [
+ {
+ key: '#1890ff',
+ color: '#1890ff',
+ theme: 'dark'
+ }
+ ]
+
+ const lightColorList = [
+ {
+ key: '#1890ff',
+ color: '#1890ff',
+ theme: 'dark'
+ }
+ ]
+
+ if (list.find((item) => item.theme === 'dark')) {
+ themeList.push({
+ // disable click
+ disable: true,
+ key: 'realDark',
+ url: 'https://gw.alipayobjects.com/zos/antfincdn/hmKaLQvmY2/LCkqqYNmvBEbokSDscrm.svg',
+ title: i18nRender('app.setting.pagestyle.realdark')
+ })
+ }
+ // insert theme color List
+ list.forEach(item => {
+ const color = (item.modifyVars || {})['@primary-color']
+ if (item.theme === 'dark' && color) {
+ darkColorList.push({
+ color,
+ ...item
+ })
+ }
+ if (!item.theme || item.theme === 'light') {
+ lightColorList.push({
+ color,
+ ...item
+ })
+ }
+ })
+
+ return {
+ colorList: {
+ dark: darkColorList,
+ light: lightColorList
+ },
+ themeList
+ }
+}
+
+const handleChangeSetting = (key, value, hideMessageLoading) => {
+ if (key === 'primaryColor') {
+ // 更新主色调
+ updateTheme(value)
+ }
+ if (key === 'colorWeak') {
+ updateColorWeak(value)
+ }
+}
+
+const genCopySettingJson = (settings) =>
+ JSON.stringify(
+ omit(
+ {
+ ...settings,
+ primaryColor: genStringToTheme(settings.primaryColor)
+ },
+ ['colorWeak']
+ ),
+ null,
+ 2
+ )
+
+export const settings = {
+ theme: PropTypes.oneOf(['dark', 'light', 'realDark']),
+ primaryColor: PropTypes.string,
+ layout: PropTypes.oneOf(['sidemenu', 'topmenu']),
+ colorWeak: PropTypes.bool,
+ contentWidth: PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid'),
+ // 替换兼容 PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid')
+ // contentWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).def('Fluid'),
+ fixedHeader: PropTypes.bool,
+ fixSiderbar: PropTypes.bool,
+ hideHintAlert: PropTypes.bool.def(false),
+ hideCopyButton: PropTypes.bool.def(false)
+}
+
+export const SettingDrawerProps = {
+ getContainer: PropTypes.func,
+ settings: PropTypes.objectOf(settings),
+
+ i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false)
+}
+
+const SettingDrawer = {
+ name: 'SettingDrawer',
+ props: SettingDrawerProps,
+ inject: ['locale'],
+ data () {
+ return {
+ show: false
+ }
+ },
+ render (h) {
+ const {
+ setShow,
+ getContainer,
+ settings
+ } = this
+
+ const {
+ theme = 'dark',
+ primaryColor = 'daybreak',
+ layout = 'sidemenu',
+ fixedHeader = false,
+ fixSiderbar = false,
+ contentWidth,
+ hideHintAlert,
+ hideCopyButton,
+ colorWeak
+ } = settings
+
+ const i18n = this.$props.i18nRender || this.locale || defaultI18nRender
+ const themeList = getThemeList(i18n)
+ const isTopMenu = layout === 'topmenu'
+
+ const iconStyle = {
+ color: '#fff',
+ fontSize: 20
+ }
+
+ const changeSetting = (type, value) => {
+ this.$emit('change', { type, value })
+ handleChangeSetting(type, value, false)
+ }
+
+ return (
+ setShow(false)}
+ placement="right"
+ getContainer={getContainer}
+ /* handle={
+ setShow(!this.show)}>
+ {this.show
+ ? ( )
+ : ( )
+ }
+
+ } */
+ style={{
+ zIndex: 999
+ }}
+ >
+
+ setShow(!this.show)} style="display:none;">
+ {this.show
+ ? ()
+ : ()
+ }
+
+
+
+
+
{
+ changeSetting('theme', val)
+ }} />
+
+ {
+ // changeSetting('primaryColor', color, null)
+ // 解决严重漏洞
+ changeSetting('primaryColor', color)
+ }}
+ />
+
+
+
+
+ {
+ // changeSetting('layout', value, null)
+ // 解决严重漏洞
+ changeSetting('layout', value)
+ }} />
+
+
+ {
+ changeSetting(type, value)
+ }}
+ />
+
+
+
+ renderLayoutSettingItem(h, item)}
+ dataSource={[
+ {
+ title: i18n('app.setting.weakmode'),
+ action: (
+ changeSetting('colorWeak', checked)}
+ />
+ )
+ }
+ ]}
+ />
+
+
+ {hideHintAlert && hideCopyButton ? null : }
+
+ {hideHintAlert ? null : (
+ )}
+ showIcon
+ style={{ marginBottom: '16px' }}
+ />
+ )}
+
+ {hideCopyButton ? null : (
+
+ message.success(i18n('app.setting.copyinfo'))
+ }
+ >
+
+ {i18n('app.setting.copy')}
+
+
+ )}
+
+
+
+
+ )
+ },
+ methods: {
+ setShow (flag) {
+ this.show = flag
+ }
+ }
+}
+
+SettingDrawer.install = function (Vue) {
+ Vue.use(antPortal)
+ Vue.component(SettingDrawer.name, SettingDrawer)
+}
+
+export default SettingDrawer
diff --git a/hotgo-web/src/components/ProLayout/components/SiderMenu/SiderMenu.jsx b/hotgo-web/src/components/ProLayout/components/SiderMenu/SiderMenu.jsx
new file mode 100644
index 0000000..bba1e57
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SiderMenu/SiderMenu.jsx
@@ -0,0 +1,137 @@
+import './index.less'
+
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import 'ant-design-vue/es/layout/style'
+import Layout from 'ant-design-vue/es/layout'
+import { isFun } from '../../utils/util'
+import BaseMenu from '../RouteMenu'
+
+const { Sider } = Layout
+
+export const SiderMenuProps = {
+ i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false),
+ mode: PropTypes.string.def('inline'),
+ theme: PropTypes.string.def('light '),
+ contentWidth: PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid'),
+ collapsible: PropTypes.bool,
+ collapsed: PropTypes.bool,
+ handleCollapse: PropTypes.func,
+ menus: PropTypes.array,
+ siderWidth: PropTypes.number.def(210),
+ collapsedWidth: PropTypes.number.def(60),
+ isMobile: PropTypes.bool,
+ layout: PropTypes.string.def('inline'),
+ fixSiderbar: PropTypes.bool,
+ logo: PropTypes.any,
+ title: PropTypes.string.def(''),
+ multiTab: PropTypes.bool,
+ // render function or vnode
+ menuHeaderRender: PropTypes.oneOfType([PropTypes.func, PropTypes.array, PropTypes.object, PropTypes.bool]),
+ menuRender: PropTypes.oneOfType([PropTypes.func, PropTypes.array, PropTypes.object, PropTypes.bool])
+}
+
+export const defaultRenderLogo = (h, logo) => {
+ if (typeof logo === 'string') {
+ return
+ }
+ if (typeof logo === 'function') {
+ return logo()
+ }
+ return h(logo)
+}
+
+export const defaultRenderLogoAntTitle = (h, props) => {
+ const {
+ logo = 'https://gw.alipayobjects.com/zos/antfincdn/PmY%24TNNDBI/logo.svg',
+ title,
+ menuHeaderRender
+ } = props
+
+ if (menuHeaderRender === false) {
+ return null
+ }
+ const logoDom = defaultRenderLogo(h, logo)
+ const titleDom = {title}
+
+ if (menuHeaderRender) {
+ return isFun(menuHeaderRender) &&
+ menuHeaderRender(h, logoDom, props.collapsed ? null : titleDom, props) ||
+ menuHeaderRender
+ }
+ return (
+
+ {logoDom}
+ {titleDom}
+
+ )
+}
+
+const SiderMenu = {
+ name: 'SiderMenu',
+ model: {
+ prop: 'collapsed',
+ event: 'collapse'
+ },
+ props: SiderMenuProps,
+ render (h) {
+ const {
+ collapsible,
+ collapsed,
+ siderWidth,
+ fixSiderbar,
+ collapsedWidth,
+ mode,
+ theme,
+ menus,
+ logo,
+ title,
+ onMenuHeaderClick = () => null,
+ i18nRender,
+ menuHeaderRender,
+ menuRender
+ } = this
+ const siderCls = ['ant-pro-sider-menu-sider']
+ if (fixSiderbar) siderCls.push('fix-sider-bar')
+ if (theme === 'light') siderCls.push('light')
+ //
+ // const handleCollapse = (collapsed, type) => {
+ // this.$emit('collapse', collapsed)
+ // }
+
+ const headerDom = defaultRenderLogoAntTitle(h, {
+ logo, title, menuHeaderRender, collapsed
+ })
+
+ return (
+ {headerDom && (
+
+ )}
+ {menuRender && (
+ isFun(menuRender) &&
+ menuRender(h, this.$props) ||
+ menuRender
+ ) || (
+
+ )}
+ )
+ }
+}
+
+export default SiderMenu
diff --git a/hotgo-web/src/components/ProLayout/components/SiderMenu/index.jsx b/hotgo-web/src/components/ProLayout/components/SiderMenu/index.jsx
new file mode 100644
index 0000000..2788345
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SiderMenu/index.jsx
@@ -0,0 +1,54 @@
+import './index.less'
+
+import 'ant-design-vue/es/drawer/style'
+import Drawer from 'ant-design-vue/es/drawer'
+import SiderMenu, { SiderMenuProps } from './SiderMenu'
+
+const SiderMenuWrapper = {
+ name: 'SiderMenuWrapper',
+ model: {
+ prop: 'collapsed',
+ event: 'collapse'
+ },
+ props: SiderMenuProps,
+ render (h) {
+ const {
+ layout,
+ isMobile,
+ collapsed
+ } = this
+ const isTopMenu = layout === 'topmenu'
+ const handleCollapse = (e) => {
+ this.$emit('collapse', true)
+ }
+ return isMobile ? (
+
+ ) : !isTopMenu && (
+
+ )
+ }
+}
+
+SiderMenuWrapper.install = function (Vue) {
+ Vue.component(SiderMenuWrapper.name, SiderMenuWrapper)
+}
+
+export {
+ SiderMenu,
+ SiderMenuProps
+}
+
+export default SiderMenuWrapper
diff --git a/hotgo-web/src/components/ProLayout/components/SiderMenu/index.less b/hotgo-web/src/components/ProLayout/components/SiderMenu/index.less
new file mode 100644
index 0000000..8b80625
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/SiderMenu/index.less
@@ -0,0 +1,130 @@
+@import "../../../../assets/styles/default.less";
+
+@sider-menu-prefix-cls: ~'@{ant-prefix}-pro-sider-menu';
+
+@nav-header-height: @layout-header-height;
+.@{sider-menu-prefix-cls} {
+
+ &-logo {
+ position: relative;
+ height: 64px;
+ padding-left: 24px;
+ overflow: hidden;
+ transition: all .3s;
+ line-height: @nav-header-height;
+ background: @layout-sider-background;
+
+ svg, img, h1 {
+ display: inline-block;
+ }
+
+ svg, img {
+ height: 32px;
+ width: 32px;
+ vertical-align: middle;
+ }
+
+ h1 {
+ color: @white;
+ font-size: 20px;
+ margin: 0 0 0 12px;
+ font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+ font-weight: 600;
+ vertical-align: middle;
+ }
+ }
+
+ &-sider {
+ position: relative;
+ z-index: 10;
+ min-height: 100vh;
+ box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
+
+ &.fix-sider-bar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
+
+ .ant-menu-root {
+ height: ~'calc(100vh - @{nav-header-height})';
+ overflow-y: auto;
+ }
+
+ .ant-menu-inline {
+ border-right: 0;
+
+ .ant-menu-item,
+ .ant-menu-submenu-title {
+ width: 100%;
+ }
+ }
+ }
+
+ &.light {
+ background-color: white;
+ box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
+
+ .@{sider-menu-prefix-cls}-logo {
+ background: white;
+ box-shadow: 1px 1px 0 0 @border-color-split;
+
+ h1 {
+ color: @primary-color;
+ }
+ }
+
+ .ant-menu-light {
+ border-right-color: transparent;
+ }
+ }
+ }
+
+ &-icon {
+ width: 14px;
+ vertical-align: baseline;
+ }
+
+ .top-nav-menu li.ant-menu-item {
+ height: @nav-header-height;
+ line-height: @nav-header-height;
+ }
+
+ .drawer .drawer-content {
+ background: @layout-sider-background;
+ }
+
+ .ant-menu-inline-collapsed {
+ & > .ant-menu-item .sider-menu-item-img + span,
+ &
+ > .ant-menu-item-group
+ > .ant-menu-item-group-list
+ > .ant-menu-item
+ .sider-menu-item-img
+ + span,
+ &
+ > .ant-menu-submenu
+ > .ant-menu-submenu-title
+ .sider-menu-item-img
+ + span {
+ display: inline-block;
+ max-width: 0;
+ opacity: 0;
+ }
+ }
+
+ .ant-menu-item .sider-menu-item-img + span,
+ .ant-menu-submenu-title .sider-menu-item-img + span {
+ opacity: 1;
+ transition: opacity 0.3s @ease-in-out, width 0.3s @ease-in-out;
+
+ }
+.ant-menu-item .anticon + span,
+.ant-menu-submenu-title .anticon + span{
+ line-height: 21px;
+ vertical-align: middle;
+}
+ .ant-drawer-body {
+ padding: 0;
+ }
+}
diff --git a/hotgo-web/src/components/ProLayout/components/index.js b/hotgo-web/src/components/ProLayout/components/index.js
new file mode 100644
index 0000000..bf8f679
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/components/index.js
@@ -0,0 +1,15 @@
+import RouteMenu from './RouteMenu'
+import SiderMenuWrapper, { SiderMenu, SiderMenuProps } from './SiderMenu'
+import PageHeaderWrapper from './PageHeaderWrapper'
+import GlobalFooter from './GlobalFooter'
+import VueFragment from './Fragment'
+
+export {
+ RouteMenu,
+ SiderMenu,
+ SiderMenuProps,
+ SiderMenuWrapper,
+ PageHeaderWrapper,
+ GlobalFooter,
+ VueFragment
+}
diff --git a/hotgo-web/src/components/ProLayout/index.js b/hotgo-web/src/components/ProLayout/index.js
new file mode 100644
index 0000000..a6a2ea4
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/index.js
@@ -0,0 +1,9 @@
+export { default, BasicLayoutProps } from './BasicLayout'
+export { default as BlockLayout } from './BlockLayout'
+export { default as PageHeaderWrapper } from './components/PageHeaderWrapper'
+export { default as SiderMenuWrapper } from './components/SiderMenu'
+export { default as GlobalFooter } from './components/GlobalFooter'
+export { default as SettingDrawer } from './components/SettingDrawer'
+export { default as DocumentTitle } from './components/DocumentTitle'
+export { default as BaseMenu } from './components/RouteMenu'
+export { updateTheme, updateColorWeak } from './utils/dynamicTheme'
diff --git a/hotgo-web/src/components/ProLayout/utils/dynamicTheme.js b/hotgo-web/src/components/ProLayout/utils/dynamicTheme.js
new file mode 100644
index 0000000..cf474f0
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/utils/dynamicTheme.js
@@ -0,0 +1,38 @@
+import client from 'webpack-theme-color-replacer/client'
+import generate from '@ant-design/colors/lib/generate'
+// import { message } from 'ant-design-vue'
+
+export const themeColor = {
+ getAntdSerials (color) {
+ // 淡化(即less的tint)
+ const lightens = new Array(9).fill().map((t, i) => {
+ return client.varyColor.lighten(color, i / 10)
+ })
+ // colorPalette 变换得到颜色值
+ const colorPalettes = generate(color)
+ const rgb = client.varyColor.toNum3(color.replace('#', '')).join(',')
+ return lightens.concat(colorPalettes).concat(rgb)
+ },
+ changeColor (newColor) {
+ const options = {
+ newColors: this.getAntdSerials(newColor), // new colors array, one-to-one corresponde with `matchColors`
+ changeUrl (cssUrl) {
+ return `/${cssUrl}` // while router is not `hash` mode, it needs absolute path
+ }
+ }
+ return client.changer.changeColor(options, Promise)
+ }
+}
+
+export const updateTheme = newPrimaryColor => {
+ // const hideMessage = message.loading('正在切换主题', 0)
+ themeColor.changeColor(newPrimaryColor).then(r => {
+ // hideMessage()
+ })
+}
+
+export const updateColorWeak = colorWeak => {
+ // document.body.className = colorWeak ? 'colorWeak' : '';
+ const app = document.body.querySelector('#app')
+ colorWeak ? app.classList.add('colorWeak') : app.classList.remove('colorWeak')
+}
diff --git a/hotgo-web/src/components/ProLayout/utils/request.js b/hotgo-web/src/components/ProLayout/utils/request.js
new file mode 100644
index 0000000..ff4e3c8
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/utils/request.js
@@ -0,0 +1,62 @@
+import request, { extend } from 'umi-request'
+import { notification } from 'ant-design-vue'
+
+const codeMessage = {
+ 200: '服务器成功返回请求的数据。',
+ 201: '新建或修改数据成功。',
+ 202: '一个请求已经进入后台排队(异步任务)。',
+ 204: '删除数据成功。',
+ 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
+ 401: '用户没有权限(令牌、用户名、密码错误)。',
+ 403: '用户得到授权,但是访问是被禁止的。',
+ 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
+ 406: '请求的格式不可得。',
+ 410: '请求的资源被永久删除,且不会再得到的。',
+ 422: '当创建一个对象时,发生一个验证错误。',
+ 500: '服务器发生错误,请检查服务器。',
+ 502: '网关错误。',
+ 503: '服务不可用,服务器暂时过载或维护。',
+ 504: '网关超时。'
+}
+
+const errorHandler = (error) => {
+ const { response = {} } = error
+ const errortext = codeMessage[response.status] || response.statusText
+ const { status, url } = response
+
+ notification.error({
+ message: `请求错误 ${status}: ${url}`,
+ description: errortext
+ })
+}
+
+export const BASE_URL = process.env.VUE_APP_API_URL || '/api/v1'
+
+const customRequest = extend({
+ prefix: BASE_URL,
+ timeout: 1000,
+ errorHandler
+})
+
+// request 拦截器
+customRequest.interceptors.request.use((url, options) => {
+ return (
+ {
+ url: `${url}&interceptors=yes`,
+ options: { ...options, interceptors: true }
+ }
+ )
+})
+
+// response 拦截器
+customRequest.interceptors.response.use((response, options) => {
+ response.headers.append('interceptors', 'yes yo')
+ return response
+})
+
+export {
+ request,
+ extend
+}
+
+export default customRequest
diff --git a/hotgo-web/src/components/ProLayout/utils/util.js b/hotgo-web/src/components/ProLayout/utils/util.js
new file mode 100644
index 0000000..25d3d23
--- /dev/null
+++ b/hotgo-web/src/components/ProLayout/utils/util.js
@@ -0,0 +1,64 @@
+import triggerEvent from 'ant-design-vue/es/_util/triggerEvent'
+import { inBrowser } from 'ant-design-vue/es/_util/env'
+
+const getComponentFromProp = (instance, prop) => {
+ const slots = instance.slots && instance.slots()
+ return slots[prop] || instance.props[prop]
+}
+
+const isFun = (func) => {
+ return typeof func === 'function'
+}
+
+// 兼容 0.3.4~0.3.8
+export const contentWidthCheck = (contentWidth) => {
+ return Object.prototype.toString.call(contentWidth) === '[object Boolean]'
+ ? contentWidth === true && 'Fixed' || 'Fluid'
+ : contentWidth
+}
+
+export const layoutContentWidth = (contentType) => {
+ return contentType !== 'Fluid'
+}
+
+const themeConfig = {
+ daybreak: 'geekblue',
+ '#2F54EB': 'geekblue',
+ '#1890ff': 'daybreak',
+ '#F5222D': 'dust',
+ '#FA541C': 'volcano',
+ '#FAAD14': 'sunset',
+ '#13C2C2': 'cyan',
+ '#52C41A': 'green',
+ '#722ED1': 'purple'
+}
+
+const invertKeyValues = (obj) =>
+ Object.keys(obj).reduce((acc, key) => {
+ acc[obj[key]] = key
+ return acc
+ }, {})
+
+/**
+ * #1890ff -> daybreak
+ * @param val
+ */
+export function genThemeToString (val) {
+ return val && themeConfig[val] ? themeConfig[val] : val
+}
+
+/**
+ * daybreak-> #1890ff
+ * @param val
+ */
+export function genStringToTheme (val) {
+ const stringConfig = invertKeyValues(themeConfig)
+ return val && stringConfig[val] ? stringConfig[val] : val
+}
+
+export {
+ triggerEvent,
+ inBrowser,
+ getComponentFromProp,
+ isFun
+}
diff --git a/hotgo-web/src/components/Search/GlobalSearch.jsx b/hotgo-web/src/components/Search/GlobalSearch.jsx
new file mode 100644
index 0000000..bd9e604
--- /dev/null
+++ b/hotgo-web/src/components/Search/GlobalSearch.jsx
@@ -0,0 +1,63 @@
+import { Select } from 'ant-design-vue'
+import './index.less'
+
+const GlobalSearch = {
+ name: 'GlobalSearch',
+ data () {
+ return {
+ visible: false
+ }
+ },
+ mounted () {
+ const keyboardHandle = (e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ const { ctrlKey, shiftKey, altKey, keyCode } = e
+ console.log('keyCode:', e.keyCode, e)
+ // key is `K` and hold ctrl
+ if (keyCode === 75 && ctrlKey && !shiftKey && !altKey) {
+ this.visible = !this.visible
+ }
+ }
+ document.addEventListener('keydown', keyboardHandle)
+ },
+ render () {
+ const { visible } = this
+ const handleSearch = (e) => {
+ this.$emit('search', e)
+ }
+
+ const handleChange = (e) => {
+ this.$emit('change', e)
+ }
+ if (!visible) {
+ return null
+ }
+ return (
+
+
+
+
+
Open with Ctrl/⌘ + K
+
+
+ )
+ }
+}
+
+GlobalSearch.install = function (Vue) {
+ Vue.component(GlobalSearch.name, GlobalSearch)
+}
+
+export default GlobalSearch
diff --git a/hotgo-web/src/components/Search/index.less b/hotgo-web/src/components/Search/index.less
new file mode 100644
index 0000000..d397852
--- /dev/null
+++ b/hotgo-web/src/components/Search/index.less
@@ -0,0 +1,25 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+.global-search-wrapper {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: @zindex-modal-mask;
+ background: @modal-mask-bg;
+
+ .global-search-box {
+ position: absolute;
+ top: 20%;
+ left: 50%;
+ width: 450px;
+ transform: translate(-50%, -50%);
+
+ .global-search-tips {
+ color: @white;
+ font-size: @font-size-lg;
+ text-align: right;
+ }
+ }
+}
\ No newline at end of file
diff --git a/hotgo-web/src/components/SelectLang/index.jsx b/hotgo-web/src/components/SelectLang/index.jsx
new file mode 100644
index 0000000..85a342a
--- /dev/null
+++ b/hotgo-web/src/components/SelectLang/index.jsx
@@ -0,0 +1,54 @@
+import './index.less'
+
+import { Icon, Menu, Dropdown } from 'ant-design-vue'
+import { i18nRender } from '@/locales'
+import i18nMixin from '@/store/i18n-mixin'
+
+const locales = ['zh-CN', 'en-US']
+const languageLabels = {
+ 'zh-CN': '简体中文',
+ 'en-US': 'English(暂不支持)'
+}
+// eslint-disable-next-line
+const languageIcons = {
+ 'zh-CN': '🇨🇳',
+ 'en-US': '🇺🇸'
+}
+
+const SelectLang = {
+ props: {
+ prefixCls: {
+ type: String,
+ default: 'ant-pro-drop-down'
+ }
+ },
+ name: 'SelectLang',
+ mixins: [i18nMixin],
+ render () {
+ const { prefixCls } = this
+ const changeLang = ({ key }) => {
+ this.setLang(key)
+ }
+ const langMenu = (
+
+ )
+ return (
+
+
+
+
+
+ )
+ }
+}
+
+export default SelectLang
diff --git a/hotgo-web/src/components/SelectLang/index.less b/hotgo-web/src/components/SelectLang/index.less
new file mode 100644
index 0000000..750c9c7
--- /dev/null
+++ b/hotgo-web/src/components/SelectLang/index.less
@@ -0,0 +1,31 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+@header-menu-prefix-cls: ~'@{ant-prefix}-pro-header-menu';
+@header-drop-down-prefix-cls: ~'@{ant-prefix}-pro-drop-down';
+
+.@{header-menu-prefix-cls} {
+
+ .anticon {
+ margin-right: 8px;
+ }
+ .ant-dropdown-menu-item {
+ min-width: 160px;
+ }
+}
+
+.@{header-drop-down-prefix-cls} {
+
+ line-height: @layout-header-height;
+ vertical-align: top;
+ cursor: pointer;
+
+ > i {
+ font-size: 16px !important;
+ transform: none !important;
+
+ svg {
+ position: relative;
+ top: -1px;
+ }
+ }
+}
diff --git a/hotgo-web/src/components/SettingDrawer/SettingDrawer.vue b/hotgo-web/src/components/SettingDrawer/SettingDrawer.vue
new file mode 100644
index 0000000..f041ae4
--- /dev/null
+++ b/hotgo-web/src/components/SettingDrawer/SettingDrawer.vue
@@ -0,0 +1,343 @@
+
+
+
+
+
+
+
整体风格设置
+
+
+
+
+ 暗色菜单风格1
+
+
+
+
+
+
+
+
+
+ 亮色菜单风格
+
+
+
+
+
+
+
+
+
+
+
主题色
+
+
+
+
+ {{ item.key }}
+
+
+
+
+
+
+
+
+
+
+
+
导航模式
+
+
+
+
+ 侧边栏导航
+
+
+
+
+
+
+
+
+
+ 顶部栏导航
+
+
+
+
+
+
+
+
+
+
+
+
+ 该设定仅 [顶部栏导航] 时有效
+
+
+ 固定
+ 流式
+
+
+
+ 内容区域宽度
+
+
+
+
+
+ 固定 Header
+
+
+
+
+
+
+ 固定 Header 时可配置
+ 下滑时隐藏 Header
+
+
+
+
+
+
+ 固定侧边菜单
+
+
+
+
+
+
+
+
+
其他设置
+
+
+
+
+
+ 色弱模式
+
+
+
+
+
+ 多页签模式
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/SettingDrawer/SettingItem.vue b/hotgo-web/src/components/SettingDrawer/SettingItem.vue
new file mode 100644
index 0000000..2b3b553
--- /dev/null
+++ b/hotgo-web/src/components/SettingDrawer/SettingItem.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/SettingDrawer/index.js b/hotgo-web/src/components/SettingDrawer/index.js
new file mode 100644
index 0000000..8260f2d
--- /dev/null
+++ b/hotgo-web/src/components/SettingDrawer/index.js
@@ -0,0 +1,2 @@
+import SettingDrawer from './SettingDrawer'
+export default SettingDrawer
diff --git a/hotgo-web/src/components/SettingDrawer/settingConfig.js b/hotgo-web/src/components/SettingDrawer/settingConfig.js
new file mode 100644
index 0000000..2cfab79
--- /dev/null
+++ b/hotgo-web/src/components/SettingDrawer/settingConfig.js
@@ -0,0 +1,48 @@
+import message from 'ant-design-vue/es/message'
+// import defaultSettings from '../defaultSettings';
+import themeColor from './themeColor.js'
+
+// let lessNodesAppended
+const colorList = [
+ {
+ key: '薄暮', color: '#F5222D'
+ },
+ {
+ key: '火山', color: '#FA541C'
+ },
+ {
+ key: '日暮', color: '#FAAD14'
+ },
+ {
+ key: '明青', color: '#13C2C2'
+ },
+ {
+ key: '极光绿', color: '#52C41A'
+ },
+ {
+ key: '拂晓蓝(默认)', color: '#1890FF'
+ },
+ {
+ key: '极客蓝', color: '#2F54EB'
+ },
+ {
+ key: '酱紫', color: '#722ED1'
+ }
+]
+
+const updateTheme = newPrimaryColor => {
+ const hideMessage = message.loading('正在切换主题!', 0)
+ themeColor.changeColor(newPrimaryColor).finally(() => {
+ setTimeout(() => {
+ hideMessage()
+ }, 10)
+ })
+}
+
+const updateColorWeak = colorWeak => {
+ // document.body.className = colorWeak ? 'colorWeak' : '';
+ const app = document.body.querySelector('#app')
+ colorWeak ? app.classList.add('colorWeak') : app.classList.remove('colorWeak')
+}
+
+export { updateTheme, colorList, updateColorWeak }
diff --git a/hotgo-web/src/components/SettingDrawer/themeColor.js b/hotgo-web/src/components/SettingDrawer/themeColor.js
new file mode 100644
index 0000000..10dfbd4
--- /dev/null
+++ b/hotgo-web/src/components/SettingDrawer/themeColor.js
@@ -0,0 +1,24 @@
+import client from 'webpack-theme-color-replacer/client'
+import generate from '@ant-design/colors/lib/generate'
+
+export default {
+ getAntdSerials (color) {
+ // 淡化(即less的tint)
+ const lightens = new Array(9).fill().map((t, i) => {
+ return client.varyColor.lighten(color, i / 10)
+ })
+ // colorPalette变换得到颜色值
+ const colorPalettes = generate(color)
+ const rgb = client.varyColor.toNum3(color.replace('#', '')).join(',')
+ return lightens.concat(colorPalettes).concat(rgb)
+ },
+ changeColor (newColor) {
+ var options = {
+ newColors: this.getAntdSerials(newColor), // new colors array, one-to-one corresponde with `matchColors`
+ changeUrl (cssUrl) {
+ return `/${cssUrl}` // while router is not `hash` mode, it needs absolute path
+ }
+ }
+ return client.changer.changeColor(options, Promise)
+ }
+}
diff --git a/hotgo-web/src/components/StandardFormRow/StandardFormRow.vue b/hotgo-web/src/components/StandardFormRow/StandardFormRow.vue
new file mode 100644
index 0000000..a4e261b
--- /dev/null
+++ b/hotgo-web/src/components/StandardFormRow/StandardFormRow.vue
@@ -0,0 +1,122 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/StandardFormRow/index.js b/hotgo-web/src/components/StandardFormRow/index.js
new file mode 100644
index 0000000..8155cc7
--- /dev/null
+++ b/hotgo-web/src/components/StandardFormRow/index.js
@@ -0,0 +1,3 @@
+import StandardFormRow from './StandardFormRow'
+
+export default StandardFormRow
diff --git a/hotgo-web/src/components/TagSelect/TagSelectOption.jsx b/hotgo-web/src/components/TagSelect/TagSelectOption.jsx
new file mode 100644
index 0000000..b5ae799
--- /dev/null
+++ b/hotgo-web/src/components/TagSelect/TagSelectOption.jsx
@@ -0,0 +1,45 @@
+import { Tag } from 'ant-design-vue'
+const { CheckableTag } = Tag
+
+export default {
+ name: 'TagSelectOption',
+ props: {
+ prefixCls: {
+ type: String,
+ default: 'ant-pro-tag-select-option'
+ },
+ value: {
+ type: [String, Number, Object],
+ default: ''
+ },
+ checked: {
+ type: Boolean,
+ default: false
+ }
+ },
+ data () {
+ return {
+ localChecked: this.checked || false
+ }
+ },
+ watch: {
+ 'checked' (val) {
+ this.localChecked = val
+ },
+ '$parent.items': {
+ handler: function (val) {
+ this.value && val.hasOwnProperty(this.value) && (this.localChecked = val[this.value])
+ },
+ deep: true
+ }
+ },
+ render () {
+ const { $slots, value } = this
+ const onChange = (checked) => {
+ this.$emit('change', { value, checked })
+ }
+ return (
+ {$slots.default}
+ )
+ }
+}
diff --git a/hotgo-web/src/components/TagSelect/index.jsx b/hotgo-web/src/components/TagSelect/index.jsx
new file mode 100644
index 0000000..af98ad7
--- /dev/null
+++ b/hotgo-web/src/components/TagSelect/index.jsx
@@ -0,0 +1,113 @@
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import Option from './TagSelectOption.jsx'
+import { filterEmpty } from '@/components/_util/util'
+
+export default {
+ Option,
+ name: 'TagSelect',
+ model: {
+ prop: 'checked',
+ event: 'change'
+ },
+ props: {
+ prefixCls: {
+ type: String,
+ default: 'ant-pro-tag-select'
+ },
+ defaultValue: {
+ type: PropTypes.array,
+ default: null
+ },
+ value: {
+ type: PropTypes.array,
+ default: null
+ },
+ expandable: {
+ type: Boolean,
+ default: false
+ },
+ hideCheckAll: {
+ type: Boolean,
+ default: false
+ }
+ },
+ data () {
+ return {
+ expand: false,
+ localCheckAll: false,
+ items: this.getItemsKey(filterEmpty(this.$slots.default)),
+ val: this.value || this.defaultValue || []
+ }
+ },
+ methods: {
+ onChange (checked) {
+ const key = Object.keys(this.items).filter(key => key === checked.value)
+ this.items[key] = checked.checked
+ const bool = Object.values(this.items).lastIndexOf(false)
+ if (bool === -1) {
+ this.localCheckAll = true
+ } else {
+ this.localCheckAll = false
+ }
+ },
+ onCheckAll (checked) {
+ Object.keys(this.items).forEach(v => {
+ this.items[v] = checked.checked
+ })
+ this.localCheckAll = checked.checked
+ },
+ getItemsKey (items) {
+ const totalItem = {}
+ items.forEach(item => {
+ totalItem[item.componentOptions.propsData && item.componentOptions.propsData.value] = false
+ })
+ return totalItem
+ },
+ // CheckAll Button
+ renderCheckAll () {
+ const props = {
+ on: {
+ change: (checked) => {
+ this.onCheckAll(checked)
+ checked.value = 'total'
+ this.$emit('change', checked)
+ }
+ }
+ }
+ const checkAllElement = All
+ return !this.hideCheckAll && checkAllElement || null
+ },
+ // expandable
+ renderExpandable () {
+
+ },
+ // render option
+ renderTags (items) {
+ const listeners = {
+ change: (checked) => {
+ this.onChange(checked)
+ this.$emit('change', checked)
+ }
+ }
+
+ return items.map(vnode => {
+ const options = vnode.componentOptions
+ options.listeners = listeners
+ return vnode
+ })
+ }
+ },
+ render () {
+ const { $props: { prefixCls } } = this
+ const classString = {
+ [`${prefixCls}`]: true
+ }
+ const tagItems = filterEmpty(this.$slots.default)
+ return (
+
+ {this.renderCheckAll()}
+ {this.renderTags(tagItems)}
+
+ )
+ }
+}
diff --git a/hotgo-web/src/components/TextArea/index.jsx b/hotgo-web/src/components/TextArea/index.jsx
new file mode 100644
index 0000000..00aeb2f
--- /dev/null
+++ b/hotgo-web/src/components/TextArea/index.jsx
@@ -0,0 +1,69 @@
+import './style.less'
+import { getStrFullLength, cutStrByFullLength } from '../_util/util'
+import Input from 'ant-design-vue/es/input'
+const TextArea = Input.TextArea
+
+export default {
+ name: 'LimitTextArea',
+ model: {
+ prop: 'value',
+ event: 'change'
+ },
+ props: Object.assign({}, TextArea.props, {
+ prefixCls: {
+ type: String,
+ default: 'ant-textarea-limit'
+ },
+ // eslint-disable-next-line
+ value: {
+ type: String
+ },
+ limit: {
+ type: Number,
+ default: 200
+ }
+ }),
+ data () {
+ return {
+ currentLimit: 0
+ }
+ },
+ watch: {
+ value (val) {
+ this.calcLimitNum(val)
+ }
+ },
+ created () {
+ this.calcLimitNum(this.value)
+ },
+ methods: {
+ handleChange (e) {
+ const value = e.target.value
+ const len = getStrFullLength(value)
+ if (len <= this.limit) {
+ this.currentLimit = len
+ this.$emit('change', value)
+ return
+ } else {
+ const str = cutStrByFullLength(value, this.limit)
+ this.currentLimit = getStrFullLength(str)
+ this.$emit('change', str)
+ }
+ console.error('limit out! currentLimit:', this.currentLimit)
+ },
+ calcLimitNum (val) {
+ const len = getStrFullLength(val)
+ this.currentLimit = len
+ }
+ },
+ render () {
+ const { prefixCls, ...props } = this.$props
+ return (
+
+
+ {this.currentLimit}/{this.limit}
+
+ )
+ }
+}
diff --git a/hotgo-web/src/components/TextArea/style.less b/hotgo-web/src/components/TextArea/style.less
new file mode 100644
index 0000000..6dee494
--- /dev/null
+++ b/hotgo-web/src/components/TextArea/style.less
@@ -0,0 +1,12 @@
+.ant-textarea-limit {
+ position: relative;
+
+ .limit {
+ position: absolute;
+ color: #909399;
+ background: #fff;
+ font-size: 12px;
+ bottom: 5px;
+ right: 10px;
+ }
+}
\ No newline at end of file
diff --git a/hotgo-web/src/components/Tree/Tree.jsx b/hotgo-web/src/components/Tree/Tree.jsx
new file mode 100644
index 0000000..e5a2a11
--- /dev/null
+++ b/hotgo-web/src/components/Tree/Tree.jsx
@@ -0,0 +1,124 @@
+import { Menu, Icon, Input } from 'ant-design-vue'
+
+const { Item, ItemGroup, SubMenu } = Menu
+const { Search } = Input
+
+export default {
+ name: 'Tree',
+ props: {
+ dataSource: {
+ type: Array,
+ required: true
+ },
+ openKeys: {
+ type: Array,
+ default: () => []
+ },
+ search: {
+ type: Boolean,
+ default: false
+ }
+ },
+ created () {
+ this.localOpenKeys = this.openKeys.slice(0)
+ },
+ data () {
+ return {
+ localOpenKeys: []
+ }
+ },
+ methods: {
+ handlePlus (item) {
+ this.$emit('add', item)
+ },
+ handleTitleClick (...args) {
+ this.$emit('titleClick', { args })
+ },
+
+ renderSearch () {
+ return (
+
+ )
+ },
+ renderIcon (icon) {
+ return icon && ( ) || null
+ },
+ renderMenuItem (item) {
+ return (
+ -
+ { this.renderIcon(item.icon) }
+ { item.title }
+
this.handlePlus(item) } }}>
+
+ )
+ },
+ renderItem (item) {
+ return item.children ? this.renderSubItem(item, item.key) : this.renderMenuItem(item, item.key)
+ },
+ renderItemGroup (item) {
+ const childrenItems = item.children.map(o => {
+ return this.renderItem(o, o.key)
+ })
+
+ return (
+
+
+ { item.title }
+
+
+
+ 新增
+ 合并
+ 移除
+
+
+
+ { childrenItems }
+
+ )
+ },
+ renderSubItem (item, key) {
+ const childrenItems = item.children && item.children.map(o => {
+ return this.renderItem(o, o.key)
+ })
+
+ const title = (
+
+ { this.renderIcon(item.icon) }
+ { item.title }
+
+ )
+
+ if (item.group) {
+ return this.renderItemGroup(item)
+ }
+ // titleClick={this.handleTitleClick(item)}
+ return (
+
+ { title }
+ { childrenItems }
+
+ )
+ }
+ },
+ render () {
+ const { dataSource, search } = this.$props
+
+ // this.localOpenKeys = openKeys.slice(0)
+ const list = dataSource.map(item => {
+ return this.renderItem(item)
+ })
+
+ return (
+
+ { search ? this.renderSearch() : null }
+
this.$emit('click', item), 'update:openKeys': val => { this.localOpenKeys = val } } }} openKeys={this.localOpenKeys}>
+ { list }
+
+
+ )
+ }
+}
diff --git a/hotgo-web/src/components/Trend/Trend.vue b/hotgo-web/src/components/Trend/Trend.vue
new file mode 100644
index 0000000..526e1cc
--- /dev/null
+++ b/hotgo-web/src/components/Trend/Trend.vue
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/Trend/index.js b/hotgo-web/src/components/Trend/index.js
new file mode 100644
index 0000000..9f14228
--- /dev/null
+++ b/hotgo-web/src/components/Trend/index.js
@@ -0,0 +1,3 @@
+import Trend from './Trend.vue'
+
+export default Trend
diff --git a/hotgo-web/src/components/Trend/index.less b/hotgo-web/src/components/Trend/index.less
new file mode 100644
index 0000000..8a3d24c
--- /dev/null
+++ b/hotgo-web/src/components/Trend/index.less
@@ -0,0 +1,42 @@
+@import "../index";
+
+@trend-prefix-cls: ~"@{ant-pro-prefix}-trend";
+
+.@{trend-prefix-cls} {
+ display: inline-block;
+ font-size: @font-size-base;
+ line-height: 22px;
+
+ .up,
+ .down {
+ margin-left: 4px;
+ position: relative;
+ top: 1px;
+
+ i {
+ font-size: 12px;
+ transform: scale(0.83);
+ }
+ }
+
+ .item-text {
+ display: inline-block;
+ margin-left: 8px;
+ color: rgba(0,0,0,.85);
+ }
+
+ .up {
+ color: @red-6;
+ }
+ .down {
+ color: @green-6;
+ top: -1px;
+ }
+
+ &.reverse-color .up {
+ color: @green-6;
+ }
+ &.reverse-color .down {
+ color: @red-6;
+ }
+}
\ No newline at end of file
diff --git a/hotgo-web/src/components/Trend/index.md b/hotgo-web/src/components/Trend/index.md
new file mode 100644
index 0000000..8881f0e
--- /dev/null
+++ b/hotgo-web/src/components/Trend/index.md
@@ -0,0 +1,45 @@
+# Trend 趋势标记
+
+趋势符号,标记上升和下降趋势。通常用绿色代表“好”,红色代表“不好”,股票涨跌场景除外。
+
+
+
+引用方式:
+
+```javascript
+import Trend from '@/components/Trend'
+
+export default {
+ components: {
+ Trend
+ }
+}
+```
+
+
+
+## 代码演示 [demo](https://pro.loacg.com/test/home)
+
+```html
+5%
+```
+或
+```html
+
+ 工资
+ 5%
+
+```
+或
+```html
+5%
+```
+
+
+## API
+
+| 参数 | 说明 | 类型 | 默认值 |
+|----------|------------------------------------------|-------------|-------|
+| flag | 上升下降标识:`up|down` | string | - |
+| reverseColor | 颜色反转 | Boolean | false |
+
diff --git a/hotgo-web/src/components/_util/util.js b/hotgo-web/src/components/_util/util.js
new file mode 100644
index 0000000..dd33231
--- /dev/null
+++ b/hotgo-web/src/components/_util/util.js
@@ -0,0 +1,46 @@
+/**
+ * components util
+ */
+
+/**
+ * 清理空值,对象
+ * @param children
+ * @returns {*[]}
+ */
+export function filterEmpty (children = []) {
+ return children.filter(c => c.tag || (c.text && c.text.trim() !== ''))
+}
+
+/**
+ * 获取字符串长度,英文字符 长度1,中文字符长度2
+ * @param {*} str
+ */
+export const getStrFullLength = (str = '') =>
+ str.split('').reduce((pre, cur) => {
+ const charCode = cur.charCodeAt(0)
+ if (charCode >= 0 && charCode <= 128) {
+ return pre + 1
+ }
+ return pre + 2
+ }, 0)
+
+/**
+ * 截取字符串,根据 maxLength 截取后返回
+ * @param {*} str
+ * @param {*} maxLength
+ */
+export const cutStrByFullLength = (str = '', maxLength) => {
+ let showLength = 0
+ return str.split('').reduce((pre, cur) => {
+ const charCode = cur.charCodeAt(0)
+ if (charCode >= 0 && charCode <= 128) {
+ showLength += 1
+ } else {
+ showLength += 2
+ }
+ if (showLength <= maxLength) {
+ return pre + cur
+ }
+ return pre
+ }, '')
+}
diff --git a/hotgo-web/src/components/index.js b/hotgo-web/src/components/index.js
new file mode 100644
index 0000000..62226ea
--- /dev/null
+++ b/hotgo-web/src/components/index.js
@@ -0,0 +1,37 @@
+// pro components
+import AvatarList from '@/components/AvatarList'
+import Ellipsis from '@/components/Ellipsis'
+import FooterToolbar from '@/components/FooterToolbar'
+import NumberInfo from '@/components/NumberInfo'
+import Tree from '@/components/Tree/Tree'
+import Trend from '@/components/Trend'
+import MultiTab from '@/components/MultiTab'
+import IconSelector from '@/components/IconSelector'
+import TagSelect from '@/components/TagSelect'
+import StandardFormRow from '@/components/StandardFormRow'
+import ArticleListContent from '@/components/ArticleListContent'
+
+import Dialog from '@/components/Dialog'
+
+import SettingDrawer from '@/components/SettingDrawer'
+
+import ProLayout from '@/components/ProLayout'
+
+export {
+ AvatarList,
+ Trend,
+ Ellipsis,
+ FooterToolbar,
+ NumberInfo,
+ Tree,
+ MultiTab,
+ IconSelector,
+ TagSelect,
+ StandardFormRow,
+ ArticleListContent,
+
+ Dialog,
+ SettingDrawer,
+
+ ProLayout
+}
diff --git a/hotgo-web/src/components/index.less b/hotgo-web/src/components/index.less
new file mode 100644
index 0000000..e831c41
--- /dev/null
+++ b/hotgo-web/src/components/index.less
@@ -0,0 +1,6 @@
+@import "~ant-design-vue/lib/style/index";
+
+// The prefix to use on all css classes from ant-pro.
+@ant-pro-prefix : ant-pro;
+@ant-global-sider-zindex : 106;
+@ant-global-header-zindex : 105;
\ No newline at end of file
diff --git a/hotgo-web/src/components/pt/asyncComponent/Error.vue b/hotgo-web/src/components/pt/asyncComponent/Error.vue
new file mode 100644
index 0000000..7a7ea4b
--- /dev/null
+++ b/hotgo-web/src/components/pt/asyncComponent/Error.vue
@@ -0,0 +1,3 @@
+
+ 加载失败
+
diff --git a/hotgo-web/src/components/pt/asyncComponent/Loading.vue b/hotgo-web/src/components/pt/asyncComponent/Loading.vue
new file mode 100644
index 0000000..406a545
--- /dev/null
+++ b/hotgo-web/src/components/pt/asyncComponent/Loading.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/asyncComponent/index.vue b/hotgo-web/src/components/pt/asyncComponent/index.vue
new file mode 100644
index 0000000..b06a20f
--- /dev/null
+++ b/hotgo-web/src/components/pt/asyncComponent/index.vue
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/dialog/AntModal.vue b/hotgo-web/src/components/pt/dialog/AntModal.vue
new file mode 100644
index 0000000..b114c3d
--- /dev/null
+++ b/hotgo-web/src/components/pt/dialog/AntModal.vue
@@ -0,0 +1,294 @@
+
+
+
+ {{ modalTitle }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/import/ImportExcel.vue b/hotgo-web/src/components/pt/import/ImportExcel.vue
new file mode 100644
index 0000000..d4a876b
--- /dev/null
+++ b/hotgo-web/src/components/pt/import/ImportExcel.vue
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+ 请将文件拖拽到此处上传
+
+
+ 支持单个上传,也可以点击后选择文件上传
+
+
+
+ {{ uploadMsg }}
+
+ 下载模板
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/passwordStrength/index.vue b/hotgo-web/src/components/pt/passwordStrength/index.vue
new file mode 100644
index 0000000..902b6dd
--- /dev/null
+++ b/hotgo-web/src/components/pt/passwordStrength/index.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+ 安全强度:
+ 弱
+ 中
+ 强
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/ptButtons/Delete.vue b/hotgo-web/src/components/pt/ptButtons/Delete.vue
new file mode 100644
index 0000000..03b9d0a
--- /dev/null
+++ b/hotgo-web/src/components/pt/ptButtons/Delete.vue
@@ -0,0 +1,88 @@
+
+
+
+
+ 删除
+
+
+
+
+
+
+ 删除
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/ptButtons/index.js b/hotgo-web/src/components/pt/ptButtons/index.js
new file mode 100644
index 0000000..6fabd26
--- /dev/null
+++ b/hotgo-web/src/components/pt/ptButtons/index.js
@@ -0,0 +1,2 @@
+import Delete from './Delete'
+export { Delete }
diff --git a/hotgo-web/src/components/pt/selectDept/SelectDept.vue b/hotgo-web/src/components/pt/selectDept/SelectDept.vue
new file mode 100644
index 0000000..d7d07e5
--- /dev/null
+++ b/hotgo-web/src/components/pt/selectDept/SelectDept.vue
@@ -0,0 +1,719 @@
+
+
+
+
+
+
+ >
+
+
+
+
+
+
+
+
+
+
+
+ {{ deptTitle.substr(0, deptTitle.indexOf(searchValue)) }}
+ {{ searchValue }}
+ {{ deptTitle.substr(deptTitle.indexOf(searchValue) + searchValue.length) }}
+
+
+ {{ deptTitle }}
+
+ {{ deptTitle }}
+
+
+
+
+
+
+
+
+ {{ deptTitle.substr(0, deptTitle.indexOf(searchValue)) }}
+ {{ searchValue }}
+ {{ deptTitle.substr(deptTitle.indexOf(searchValue) + searchValue.length) }}
+
+
+ {{ deptTitle }}
+
+ {{ deptTitle }}
+
+
+
+
+
+
+
+
已选({{ selectCount }})
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/selectUser/SelectUser.vue b/hotgo-web/src/components/pt/selectUser/SelectUser.vue
new file mode 100644
index 0000000..e4b7bbc
--- /dev/null
+++ b/hotgo-web/src/components/pt/selectUser/SelectUser.vue
@@ -0,0 +1,787 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ userTitle.substr(0, userTitle.indexOf(searchValue)) }}
+ {{ searchValue }}
+ {{ userTitle.substr(userTitle.indexOf(searchValue) + searchValue.length) }}
+
+
+ {{ userTitle }}
+
+ {{ userTitle }}
+
+
+
+
+
+
+
+
+
+ {{ userTitle.substr(0, userTitle.indexOf(searchValue)) }}
+ {{ searchValue }}
+ {{ userTitle.substr(userTitle.indexOf(searchValue) + searchValue.length) }}
+
+
+ {{ userTitle }}
+
+ {{ userTitle }}
+
+
+
+
+
+
+
+
+ 已选({{ selectCount }})
+
+
+
+
+
+
+
+
+ {{ item.name }}
+ ({{ item.subtitle }})
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 保存
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/split/Index.vue b/hotgo-web/src/components/pt/split/Index.vue
new file mode 100644
index 0000000..c060a78
--- /dev/null
+++ b/hotgo-web/src/components/pt/split/Index.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/switch/Index.vue b/hotgo-web/src/components/pt/switch/Index.vue
new file mode 100644
index 0000000..f6c5df4
--- /dev/null
+++ b/hotgo-web/src/components/pt/switch/Index.vue
@@ -0,0 +1,63 @@
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/table/ActionColumns.vue b/hotgo-web/src/components/pt/table/ActionColumns.vue
new file mode 100644
index 0000000..87512dc
--- /dev/null
+++ b/hotgo-web/src/components/pt/table/ActionColumns.vue
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+ onCheckChange(e, col)" />
+
+ {{ col.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/table/ActionSize.vue b/hotgo-web/src/components/pt/table/ActionSize.vue
new file mode 100644
index 0000000..2da9dec
--- /dev/null
+++ b/hotgo-web/src/components/pt/table/ActionSize.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+ 默认
+
+
+ 中等
+
+
+ 紧密
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/table/AdvanceTable.vue b/hotgo-web/src/components/pt/table/AdvanceTable.vue
new file mode 100644
index 0000000..72421f1
--- /dev/null
+++ b/hotgo-web/src/components/pt/table/AdvanceTable.vue
@@ -0,0 +1,333 @@
+
+
+
+
+
+
+ {{ title }}
+
+
+
+ 高级表格
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/table/SearchArea.vue b/hotgo-web/src/components/pt/table/SearchArea.vue
new file mode 100644
index 0000000..22e61c7
--- /dev/null
+++ b/hotgo-web/src/components/pt/table/SearchArea.vue
@@ -0,0 +1,352 @@
+
+
+
+
+
+
+ {{ col.title }}:
+
+
+
+
onCloseClick(e, col)" type="close-circle" theme="filled" />
+
+
+
+ {{ col.title }}:
+
+
+
onCalendarChange(time, timeStr, col)"
+ @openChange="open => onCalendarOpenChange(open, col)"
+ class="time-picker"
+ size="small"
+ :get-popup-container="() => $refs.root"/>
+
+
+
+ {{ col.title }}:
+
+
+
+
+
+
+ {{ col.title }}:
+
+
+
onCalendarChange(date, dateStr, col)"
+ @openChange="open => onCalendarOpenChange(open, col)"
+ class="datetime-picker"
+ size="small"
+ show-time
+ :getCalendarContainer="() => $refs.root"/>
+
+
+
+ {{ col.title }}:
+
+
+
+
+
+
+
+
+ {{ col.title }}
+
+
+ : {{ col.search.format && typeof col.search.format === 'function' ? col.search.format(col.search.value) : col.search.value }}
+
+
+
+
+
onCloseClick(e, col)" class="close" type="close-circle" theme="filled"/>
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/pt/table/index.js b/hotgo-web/src/components/pt/table/index.js
new file mode 100644
index 0000000..52b62a1
--- /dev/null
+++ b/hotgo-web/src/components/pt/table/index.js
@@ -0,0 +1,2 @@
+import AdvanceTable from './AdvanceTable'
+export default AdvanceTable
diff --git a/hotgo-web/src/components/table/ActionColumns.vue b/hotgo-web/src/components/table/ActionColumns.vue
new file mode 100644
index 0000000..b8c2062
--- /dev/null
+++ b/hotgo-web/src/components/table/ActionColumns.vue
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+ onCheckChange(e, col)"/>
+
+ {{ col.title }}:
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/table/ActionSize.vue b/hotgo-web/src/components/table/ActionSize.vue
new file mode 100644
index 0000000..a7abb94
--- /dev/null
+++ b/hotgo-web/src/components/table/ActionSize.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+ 默认
+
+
+ 中等
+
+
+ 紧密
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/table/AdvanceTable.vue b/hotgo-web/src/components/table/AdvanceTable.vue
new file mode 100644
index 0000000..861dbe1
--- /dev/null
+++ b/hotgo-web/src/components/table/AdvanceTable.vue
@@ -0,0 +1,251 @@
+
+
+
+
+
+ {{ title }}
+
+ 高级表格
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/table/SearchArea.vue b/hotgo-web/src/components/table/SearchArea.vue
new file mode 100644
index 0000000..22e61c7
--- /dev/null
+++ b/hotgo-web/src/components/table/SearchArea.vue
@@ -0,0 +1,352 @@
+
+
+
+
+
+
+ {{ col.title }}:
+
+
+
+
onCloseClick(e, col)" type="close-circle" theme="filled" />
+
+
+
+ {{ col.title }}:
+
+
+
onCalendarChange(time, timeStr, col)"
+ @openChange="open => onCalendarOpenChange(open, col)"
+ class="time-picker"
+ size="small"
+ :get-popup-container="() => $refs.root"/>
+
+
+
+ {{ col.title }}:
+
+
+
+
+
+
+ {{ col.title }}:
+
+
+
onCalendarChange(date, dateStr, col)"
+ @openChange="open => onCalendarOpenChange(open, col)"
+ class="datetime-picker"
+ size="small"
+ show-time
+ :getCalendarContainer="() => $refs.root"/>
+
+
+
+ {{ col.title }}:
+
+
+
+
+
+
+
+
+ {{ col.title }}
+
+
+ : {{ col.search.format && typeof col.search.format === 'function' ? col.search.format(col.search.value) : col.search.value }}
+
+
+
+
+
onCloseClick(e, col)" class="close" type="close-circle" theme="filled"/>
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/components/table/index.js b/hotgo-web/src/components/table/index.js
new file mode 100644
index 0000000..52b62a1
--- /dev/null
+++ b/hotgo-web/src/components/table/index.js
@@ -0,0 +1,2 @@
+import AdvanceTable from './AdvanceTable'
+export default AdvanceTable
diff --git a/hotgo-web/src/config/defaultSettings.js b/hotgo-web/src/config/defaultSettings.js
new file mode 100644
index 0000000..a630f75
--- /dev/null
+++ b/hotgo-web/src/config/defaultSettings.js
@@ -0,0 +1,30 @@
+/**
+ * 项目默认配置项
+ * primaryColor - 默认主题色, 如果修改颜色不生效,请清理 localStorage
+ * navTheme - sidebar theme ['dark', 'light'] 两种主题
+ * colorWeak - 色盲模式
+ * layout - 整体布局方式 ['sidemenu', 'topmenu'] 两种布局
+ * fixedHeader - 固定 Header : boolean
+ * fixSiderbar - 固定左侧菜单栏 : boolean
+ * contentWidth - 内容区布局: 流式 | 固定
+ *
+ * storageOptions: {} - Vue-ls 插件配置项 (localStorage/sessionStorage)
+ *
+ */
+export default {
+ navTheme: 'light', // theme for nav menu
+ primaryColor: '#2F54EB', // primary color of ant design
+ layout: 'sidemenu', // nav menu position: `sidemenu` or `topmenu`
+ contentWidth: 'Fluid', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu
+ fixedHeader: true, // sticky header
+ fixSiderbar: true, // sticky siderbar
+ colorWeak: false,
+ multiTab: true,
+ menu: {
+ locale: true
+ },
+ title: '后台管理系统',
+ pwa: false,
+ iconfontUrl: '',
+ production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true'
+}
diff --git a/hotgo-web/src/config/router.config.js b/hotgo-web/src/config/router.config.js
new file mode 100644
index 0000000..f9bf79b
--- /dev/null
+++ b/hotgo-web/src/config/router.config.js
@@ -0,0 +1,125 @@
+// eslint-disable-next-line
+import { UserLayout } from '@/layouts'
+
+/**
+ * 工作台
+ */
+export const indexRouterMap = [
+ {
+ path: '/index',
+ name: 'index',
+ component: 'DashBoard',
+ meta: { title: '工作台', keepAlive: true, icon: 'home', noCache: false }
+ },
+ // {
+ // name: 'index',
+ // path: '/',
+ // component: 'Layout',
+ // meta: { title: '首页', icon: 'home', hideHeader: true },
+ // redirect: '/index',
+ // children: [
+ // {
+ // path: '/index',
+ // name: 'index',
+ // component: 'DashBoard',
+ // meta: { title: '首页', keepAlive: true, icon: 'home', noCache: false }
+ // }
+ // ]
+ // },
+ {
+ path: '/account/center',
+ name: 'center',
+ component: 'AccountCenter',
+ meta: { title: '个人中心', keepAlive: true, noCache: false },
+ hidden: true
+ },
+ // {
+ // path: '/dashboard/console',
+ // name: 'center',
+ // component: 'Console',
+ // meta: { title: '控制台', keepAlive: true, noCache: false },
+ // hidden: true
+ // },
+ {
+ path: '/account/settings',
+ name: 'settings',
+ component: 'AccountSettings',
+ meta: { title: '个人设置', hideHeader: true },
+ redirect: '/account/settings/base',
+ hidden: true,
+ children: [
+ {
+ path: '/account/settings/base',
+ name: 'BaseSettings',
+ component: 'BaseSettings',
+ hidden: true,
+ meta: { title: '基本设置', hidden: true, keepAlive: true, noCache: false }
+ },
+ {
+ path: '/account/settings/security',
+ name: 'SecuritySettings',
+ component: 'SecuritySettings',
+ meta: { title: '安全设置', hidden: true, keepAlive: true, noCache: false }
+ }
+ ]
+ },
+ {
+ path: '/monitor/job/log',
+ name: 'JobLog',
+ component: 'JobLog',
+ meta: { title: '调度日志', keepAlive: true, noCache: false },
+ hidden: true
+ },
+ {
+ path: '/system/notice/NoticeReadIndex',
+ name: 'NoticeReadIndex',
+ component: 'NoticeReadIndex',
+ meta: { title: '通知公告阅读', keepAlive: true, noCache: false },
+ hidden: true
+ },
+ {
+ path: '/system/notice/form',
+ name: 'NoticeForm',
+ component: 'NoticeForm',
+ meta: { title: '公告编辑', keepAlive: true, noCache: false },
+ hidden: true
+ },
+ {
+ path: '/gen/edit',
+ name: 'GenEdit',
+ component: 'GenEdit',
+ meta: { title: '修改生成配置', keepAlive: true, noCache: false },
+ hidden: true
+ }
+]
+/**
+ * 基础路由
+ * @type { *[] }
+ */
+export const constantRouterMap = [
+ {
+ path: '/user',
+ component: UserLayout,
+ redirect: '/user/login',
+ hidden: true,
+ children: [
+ {
+ path: 'login',
+ name: 'login',
+ component: () => import(/* webpackChunkName: "user" */ '@/views/user/Login')
+ }
+ ]
+ },
+
+ {
+ path: '/404',
+ name: '404',
+ component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/404')
+ },
+ {
+ path: '/applyLicense',
+ name: 'applyLicense',
+ component: () => import(/* webpackChunkName: "fail" */ '@/views/applyLicense/ApplyLicense')
+ }
+
+]
diff --git a/hotgo-web/src/core/bootstrap.js b/hotgo-web/src/core/bootstrap.js
new file mode 100644
index 0000000..533f85f
--- /dev/null
+++ b/hotgo-web/src/core/bootstrap.js
@@ -0,0 +1,30 @@
+import store from '@/store'
+import storage from 'store'
+import {
+ ACCESS_TOKEN,
+ APP_LANGUAGE,
+ TOGGLE_CONTENT_WIDTH,
+ TOGGLE_FIXED_HEADER,
+ TOGGLE_FIXED_SIDEBAR, TOGGLE_HIDE_HEADER,
+ TOGGLE_LAYOUT, TOGGLE_NAV_THEME, TOGGLE_WEAK,
+ TOGGLE_COLOR, TOGGLE_MULTI_TAB
+} from '@/store/mutation-types'
+import { printANSI } from '@/utils/screenLog'
+import defaultSettings from '@/config/defaultSettings'
+
+export default function Initializer () {
+ printANSI() // 请自行移除该行. please remove this line
+ // 此处布局样式数据来自default中,后期需要调用方法获取,并修改default中的数据----zkp
+ store.commit(TOGGLE_LAYOUT, storage.get(TOGGLE_LAYOUT, defaultSettings.layout))
+ store.commit(TOGGLE_FIXED_HEADER, storage.get(TOGGLE_FIXED_HEADER, defaultSettings.fixedHeader))
+ store.commit(TOGGLE_FIXED_SIDEBAR, storage.get(TOGGLE_FIXED_SIDEBAR, defaultSettings.fixSiderbar))
+ store.commit(TOGGLE_CONTENT_WIDTH, storage.get(TOGGLE_CONTENT_WIDTH, defaultSettings.contentWidth))
+ store.commit(TOGGLE_HIDE_HEADER, storage.get(TOGGLE_HIDE_HEADER, defaultSettings.autoHideHeader))
+ store.commit(TOGGLE_NAV_THEME, storage.get(TOGGLE_NAV_THEME, defaultSettings.navTheme))
+ store.commit(TOGGLE_WEAK, storage.get(TOGGLE_WEAK, defaultSettings.colorWeak))
+ store.commit(TOGGLE_COLOR, storage.get(TOGGLE_COLOR, defaultSettings.primaryColor))
+ store.commit(TOGGLE_MULTI_TAB, storage.get(TOGGLE_MULTI_TAB, defaultSettings.multiTab))
+ store.commit('SET_TOKEN', storage.get(ACCESS_TOKEN))
+ store.dispatch('setLang', storage.get(APP_LANGUAGE, 'zh-CN'))
+ // last step
+}
diff --git a/hotgo-web/src/core/directives/action.js b/hotgo-web/src/core/directives/action.js
new file mode 100644
index 0000000..18b7584
--- /dev/null
+++ b/hotgo-web/src/core/directives/action.js
@@ -0,0 +1,34 @@
+import Vue from 'vue'
+import store from '@/store'
+
+/**
+ * Action 权限指令
+ * 指令用法:
+ * - 在需要控制 action 级别权限的组件上使用 v-action:[method] , 如下:
+ * 添加用户
+ * 删除用户
+ * 修改
+ *
+ * - 当前用户没有权限时,组件上使用了该指令则会被隐藏
+ * - 当后台权限跟 pro 提供的模式不同时,只需要针对这里的权限过滤进行修改即可
+ *
+ * @see https://github.com/vueComponent/ant-design-vue-pro/pull/53
+ */
+const action = Vue.directive('action', {
+ inserted: function (el, binding, vnode) {
+ const actionName = binding.arg
+ const roles = store.getters.roles
+ const elVal = vnode.context.$route.meta.permission
+ const permissionId = elVal instanceof String && [elVal] || elVal
+ roles.permissions.forEach(p => {
+ if (!permissionId.includes(p.permissionId)) {
+ return
+ }
+ if (p.actionList && !p.actionList.includes(actionName)) {
+ el.parentNode && el.parentNode.removeChild(el) || (el.style.display = 'none')
+ }
+ })
+ }
+})
+
+export default action
diff --git a/hotgo-web/src/core/icons.js b/hotgo-web/src/core/icons.js
new file mode 100644
index 0000000..9e3e57e
--- /dev/null
+++ b/hotgo-web/src/core/icons.js
@@ -0,0 +1,147 @@
+/**
+ * Custom icon list
+ * All icons are loaded here for easy management
+ * @see https://vue.ant.design/components/icon/#Custom-Font-Icon
+ *
+ * 自定义图标加载表
+ * 所有图标均从这里加载,方便管理
+ */
+
+import bugIcon from '@/assets/icons/bug.svg?inline'
+import buildIcon from '@/assets/icons/build.svg?inline'
+import buttonIcon from '@/assets/icons/button.svg?inline'
+import bxAnalyseIcon from '@/assets/icons/bxAnalyse.svg?inline'
+import cascaderIcon from '@/assets/icons/cascader.svg?inline'
+import chartIcon from '@/assets/icons/chart.svg?inline'
+import checkboxIcon from '@/assets/icons/checkbox.svg?inline'
+import clipboardIcon from '@/assets/icons/clipboard.svg?inline'
+import codeNewIcon from '@/assets/icons/codeNew.svg?inline'
+import colorIcon from '@/assets/icons/color.svg?inline'
+import componentIcon from '@/assets/icons/component.svg?inline'
+import dashboardNewIcon from '@/assets/icons/dashboardNew.svg?inline'
+import dateRangeIcon from '@/assets/icons/dateRange.svg?inline'
+import dateIcon from '@/assets/icons/date.svg?inline'
+import dictIcon from '@/assets/icons/dict.svg?inline'
+import documentationIcon from '@/assets/icons/documentation.svg?inline'
+import downloadIcon from '@/assets/icons/download.svg?inline'
+import dragImgIcon from '@/assets/icons/dragImg.svg?inline'
+import druidIcon from '@/assets/icons/druid.svg?inline'
+import editIcon from '@/assets/icons/edit.svg?inline'
+import eyeOpenIcon from '@/assets/icons/eyeOpen.svg?inline'
+import githubIcon from '@/assets/icons/github.svg?inline'
+import guideIcon from '@/assets/icons/guide.svg?inline'
+import inputIcon from '@/assets/icons/input.svg?inline'
+import jobIcon from '@/assets/icons/job.svg?inline'
+import logIcon from '@/assets/icons/log.svg?inline'
+import loginLogIcon from '@/assets/icons/loginLog.svg?inline'
+import messageIcon from '@/assets/icons/message.svg?inline'
+import monitorIcon from '@/assets/icons/monitor.svg?inline'
+import numberIcon from '@/assets/icons/number.svg?inline'
+import onlineIcon from '@/assets/icons/online.svg?inline'
+import passwordIcon from '@/assets/icons/password.svg?inline'
+import pdfIcon from '@/assets/icons/pdf.svg?inline'
+import peoplesIcon from '@/assets/icons/peoples.svg?inline'
+import phoneIcon from '@/assets/icons/phone.svg?inline'
+import postIcon from '@/assets/icons/post.svg?inline'
+import questionIcon from '@/assets/icons/question.svg?inline'
+import radioIcon from '@/assets/icons/radio.svg?inline'
+import rateIcon from '@/assets/icons/rate.svg?inline'
+import redisIcon from '@/assets/icons/redis.svg?inline'
+import rowIcon from '@/assets/icons/row.svg?inline'
+import selectIcon from '@/assets/icons/select.svg?inline'
+import serverIcon from '@/assets/icons/server.svg?inline'
+import swaggerIcon from '@/assets/icons/swagger.svg?inline'
+import switchIcon from '@/assets/icons/switch.svg?inline'
+import systemIcon from '@/assets/icons/system.svg?inline'
+import textareaIcon from '@/assets/icons/textarea.svg?inline'
+import timeRangeIcon from '@/assets/icons/timeRange.svg?inline'
+import timeIcon from '@/assets/icons/time.svg?inline'
+import toolIcon from '@/assets/icons/tool.svg?inline'
+import treeTableIcon from '@/assets/icons/treeTable.svg?inline'
+import treeIcon from '@/assets/icons/tree.svg?inline'
+import uploadIcon from '@/assets/icons/upload.svg?inline'
+import usersIcon from '@/assets/icons/users.svg?inline'
+import validCodeIcon from '@/assets/icons/validCode.svg?inline'
+import dingtalkIcon from '@/assets/icons/dingtalk.svg?inline'
+import WeChatIcon from '@/assets/icons/WeChat.svg?inline'
+import AlipayIcon from '@/assets/icons/Alipay.svg?inline'
+import SinaIcon from '@/assets/icons/Sina.svg?inline'
+import QRcodeIcon from '@/assets/icons/QRcode.svg?inline'
+import companyIcon from '@/assets/icons/company.svg?inline'
+import companyFillIcon from '@/assets/icons/companyFill.svg?inline'
+import connectionsIcon from '@/assets/icons/connections.svg?inline'
+import DragColumnIcon from '@/assets/icons/DragColumn.svg?inline'
+import dragtableIcon from '@/assets/icons/dragtable.svg?inline'
+import expendIcon from '@/assets/icons/expend.svg?inline'
+import compressIcon from '@/assets/icons/compress.svg?inline'
+const allIcon = {
+ expendIcon,
+ compressIcon,
+ bugIcon,
+ buildIcon,
+ buttonIcon,
+ bxAnalyseIcon,
+ cascaderIcon,
+ chartIcon,
+ checkboxIcon,
+ clipboardIcon,
+ codeNewIcon,
+ colorIcon,
+ componentIcon,
+ dashboardNewIcon,
+ dateRangeIcon,
+ dateIcon,
+ dictIcon,
+ documentationIcon,
+ downloadIcon,
+ dragImgIcon,
+ druidIcon,
+ editIcon,
+ eyeOpenIcon,
+ githubIcon,
+ guideIcon,
+ inputIcon,
+ jobIcon,
+ logIcon,
+ loginLogIcon,
+ messageIcon,
+ monitorIcon,
+ numberIcon,
+ onlineIcon,
+ passwordIcon,
+ pdfIcon,
+ peoplesIcon,
+ phoneIcon,
+ postIcon,
+ questionIcon,
+ radioIcon,
+ rateIcon,
+ redisIcon,
+ rowIcon,
+ selectIcon,
+ serverIcon,
+ swaggerIcon,
+ switchIcon,
+ systemIcon,
+ textareaIcon,
+ timeRangeIcon,
+ timeIcon,
+ toolIcon,
+ treeTableIcon,
+ treeIcon,
+ uploadIcon,
+ usersIcon,
+ validCodeIcon,
+ dingtalkIcon,
+ WeChatIcon,
+ AlipayIcon,
+ SinaIcon,
+ QRcodeIcon,
+ companyIcon,
+ companyFillIcon,
+ connectionsIcon,
+ DragColumnIcon,
+ dragtableIcon
+}
+
+export default allIcon
diff --git a/hotgo-web/src/core/lazy_use.js b/hotgo-web/src/core/lazy_use.js
new file mode 100644
index 0000000..2a26766
--- /dev/null
+++ b/hotgo-web/src/core/lazy_use.js
@@ -0,0 +1,125 @@
+import Vue from 'vue'
+
+// base library
+import {
+ ConfigProvider,
+ Layout,
+ Input,
+ InputNumber,
+ Button,
+ Switch,
+ Radio,
+ Checkbox,
+ Select,
+ TreeSelect,
+ Card,
+ Form,
+ Row,
+ Col,
+ Modal,
+ Table,
+ Tabs,
+ Icon,
+ Badge,
+ Popover,
+ Dropdown,
+ List,
+ Avatar,
+ Breadcrumb,
+ Steps,
+ Spin,
+ Menu,
+ Drawer,
+ Tooltip,
+ Alert,
+ Tag,
+ Divider,
+ DatePicker,
+ TimePicker,
+ Upload,
+ Progress,
+ Skeleton,
+ Popconfirm,
+ Pagination,
+ FormModel,
+ PageHeader,
+ Result,
+ Statistic,
+ Descriptions,
+ message,
+ notification,
+ Space,
+ Tree,
+ Collapse
+} from 'ant-design-vue'
+
+// ext library
+import VueCropper from 'vue-cropper'
+import Dialog from '@/components/Dialog'
+import MultiTab from '@/components/MultiTab'
+import PageLoading from '@/components/PageLoading'
+import PermissionHelper from '@/core/permission/permission'
+import './directives/action'
+
+Vue.use(ConfigProvider)
+Vue.use(Layout)
+Vue.use(Input)
+Vue.use(InputNumber)
+Vue.use(Button)
+Vue.use(Switch)
+Vue.use(Radio)
+Vue.use(Checkbox)
+Vue.use(Select)
+Vue.use(TreeSelect)
+Vue.use(Card)
+Vue.use(Form)
+Vue.use(Row)
+Vue.use(Col)
+Vue.use(Modal)
+Vue.use(Table)
+Vue.use(Tabs)
+Vue.use(Icon)
+Vue.use(Badge)
+Vue.use(Popover)
+Vue.use(Dropdown)
+Vue.use(List)
+Vue.use(Avatar)
+Vue.use(Breadcrumb)
+Vue.use(Steps)
+Vue.use(Spin)
+Vue.use(Menu)
+Vue.use(Drawer)
+Vue.use(Tooltip)
+Vue.use(Alert)
+Vue.use(Tag)
+Vue.use(Divider)
+Vue.use(DatePicker)
+Vue.use(TimePicker)
+Vue.use(Upload)
+Vue.use(Progress)
+Vue.use(Skeleton)
+Vue.use(Popconfirm)
+Vue.use(Pagination)
+Vue.use(FormModel)
+Vue.use(PageHeader)
+Vue.use(Result)
+Vue.use(Statistic)
+Vue.use(Descriptions)
+Vue.use(Space)
+Vue.use(Tree)
+Vue.use(Collapse)
+
+Vue.prototype.$confirm = Modal.confirm
+Vue.prototype.$message = message
+Vue.prototype.$notification = notification
+Vue.prototype.$info = Modal.info
+Vue.prototype.$success = Modal.success
+Vue.prototype.$error = Modal.error
+Vue.prototype.$warning = Modal.warning
+
+Vue.use(Dialog) // this.$dialog func
+Vue.use(MultiTab)
+Vue.use(PageLoading)
+Vue.use(PermissionHelper)
+Vue.use(VueCropper)
+process.env.NODE_ENV !== 'production' && console.warn('[antd-pro] NOTICE: Antd use lazy-load.')
diff --git a/hotgo-web/src/core/permission/permission.js b/hotgo-web/src/core/permission/permission.js
new file mode 100644
index 0000000..fb69844
--- /dev/null
+++ b/hotgo-web/src/core/permission/permission.js
@@ -0,0 +1,55 @@
+export const PERMISSION_ENUM = {
+ 'add': { key: 'add', label: '新增' },
+ 'delete': { key: 'delete', label: '删除' },
+ 'edit': { key: 'edit', label: '修改' },
+ 'query': { key: 'query', label: '查询' },
+ 'get': { key: 'get', label: '详情' },
+ 'enable': { key: 'enable', label: '启用' },
+ 'disable': { key: 'disable', label: '禁用' },
+ 'import': { key: 'import', label: '导入' },
+ 'export': { key: 'export', label: '导出' }
+}
+
+/**
+ * Button
+ * @param Vue
+ */
+function plugin (Vue) {
+ if (plugin.installed) {
+ return
+ }
+
+ !Vue.prototype.$auth && Object.defineProperties(Vue.prototype, {
+ $auth: {
+ get () {
+ const _this = this
+ return (permissions) => {
+ const [permission, action] = permissions.split('.')
+ const permissionList = _this.$store.getters.roles.permissions
+ return permissionList.find((val) => {
+ return val.permissionId === permission
+ }).actionList.findIndex((val) => {
+ return val === action
+ }) > -1
+ }
+ }
+ }
+ })
+
+ !Vue.prototype.$enum && Object.defineProperties(Vue.prototype, {
+ $enum: {
+ get () {
+ // const _this = this;
+ return (val) => {
+ let result = PERMISSION_ENUM
+ val && val.split('.').forEach(v => {
+ result = result && result[v] || null
+ })
+ return result
+ }
+ }
+ }
+ })
+}
+
+export default plugin
diff --git a/hotgo-web/src/core/use.js b/hotgo-web/src/core/use.js
new file mode 100644
index 0000000..db92c05
--- /dev/null
+++ b/hotgo-web/src/core/use.js
@@ -0,0 +1,25 @@
+import Vue from 'vue'
+
+// base library
+import Antd from 'ant-design-vue'
+import VueCropper from 'vue-cropper'
+import 'ant-design-vue/dist/antd.less'
+
+// ext library
+import VueClipboard from 'vue-clipboard2'
+import MultiTab from '@/components/MultiTab'
+import PageLoading from '@/components/PageLoading'
+import PermissionHelper from '@/core/permission/permission'
+// import '@/components/use'
+import './directives/action'
+
+VueClipboard.config.autoSetContainer = true
+
+Vue.use(Antd)
+Vue.use(MultiTab)
+Vue.use(PageLoading)
+Vue.use(VueClipboard)
+Vue.use(PermissionHelper)
+Vue.use(VueCropper)
+
+process.env.NODE_ENV !== 'production' && console.warn('[antd-pro] WARNING: Antd now use fulled imported.')
diff --git a/hotgo-web/src/directive/permission/hasPermi.js b/hotgo-web/src/directive/permission/hasPermi.js
new file mode 100644
index 0000000..bf6e175
--- /dev/null
+++ b/hotgo-web/src/directive/permission/hasPermi.js
@@ -0,0 +1,27 @@
+ /**
+ * 操作权限处理
+ * Copyright (c) 2019 aidex
+ */
+import store from '@/store'
+
+export default {
+ inserted (el, binding, vnode) {
+ const { value } = binding
+ const allPermission = '*:*:*'
+ const permissions = store.getters && store.getters.permissions
+
+ if (value && value instanceof Array && value.length > 0) {
+ const permissionFlag = value
+
+ const hasPermissions = permissions.some(permission => {
+ return allPermission === permission || permissionFlag.includes(permission)
+ })
+
+ if (!hasPermissions) {
+ el.parentNode && el.parentNode.removeChild(el)
+ }
+ } else {
+ throw new Error(`请设置操作权限标签值`)
+ }
+ }
+}
diff --git a/hotgo-web/src/directive/permission/hasRole.js b/hotgo-web/src/directive/permission/hasRole.js
new file mode 100644
index 0000000..1b2fd3e
--- /dev/null
+++ b/hotgo-web/src/directive/permission/hasRole.js
@@ -0,0 +1,27 @@
+ /**
+ * 角色权限处理
+ * Copyright (c) 2019 aidex
+ */
+import store from '@/store'
+
+export default {
+ inserted (el, binding, vnode) {
+ const { value } = binding
+ const superAdmin = 'admin'
+ const roles = store.getters && store.getters.roles
+
+ if (value && value instanceof Array && value.length > 0) {
+ const roleFlag = value
+
+ const hasRole = roles.some(role => {
+ return superAdmin === role || roleFlag.includes(role)
+ })
+
+ if (!hasRole) {
+ el.parentNode && el.parentNode.removeChild(el)
+ }
+ } else {
+ throw new Error(`请设置角色权限标签值"`)
+ }
+ }
+}
diff --git a/hotgo-web/src/directive/permission/index.js b/hotgo-web/src/directive/permission/index.js
new file mode 100644
index 0000000..6bda3f8
--- /dev/null
+++ b/hotgo-web/src/directive/permission/index.js
@@ -0,0 +1,15 @@
+import hasRole from './hasRole'
+import hasPermi from './hasPermi'
+
+const install = function (Vue) {
+ Vue.directive('hasRole', hasRole)
+ Vue.directive('hasPermi', hasPermi)
+}
+
+if (window.Vue) {
+ window['hasRole'] = hasRole
+ window['hasPermi'] = hasPermi
+ Vue.use(install); // eslint-disable-line
+}
+
+export default install
diff --git a/hotgo-web/src/global.less b/hotgo-web/src/global.less
new file mode 100644
index 0000000..6950f1f
--- /dev/null
+++ b/hotgo-web/src/global.less
@@ -0,0 +1,183 @@
+@import "assets/styles/default.less";
+html,
+body,
+#app, #root {
+ height: 100%;
+}
+
+.colorWeak {
+ filter: invert(80%);
+}
+
+.ant-layout.layout-basic {
+ height: 100vh;
+ min-height: 100vh;
+}
+
+canvas {
+ display: block;
+}
+
+body {
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+ul,
+ol {
+ list-style: none;
+}
+
+// 数据列表 样式
+.table-alert {
+ margin-bottom: 16px;
+}
+// 数据列表 操作
+.table-operator {
+ margin-bottom: 18px;
+
+ button {
+ margin-right: 8px;
+ }
+}
+// 数据列表 搜索条件
+.table-page-search-wrapper {
+
+ .ant-form-inline {
+ .ant-form-item {
+ display: flex;
+ margin-bottom: 24px;
+ margin-right: 0;
+
+ .ant-form-item-control-wrapper {
+ flex: 1 1;
+ display: inline-block;
+ vertical-align: middle;
+ }
+
+ > .ant-form-item-label {
+ line-height: 32px;
+ padding-right: 8px;
+ width: auto;
+ }
+ .ant-form-item-control {
+ height: 32px;
+ line-height: 32px;
+ }
+ }
+ }
+
+ .table-page-search-submitButtons {
+ display: block;
+ margin-bottom: 24px;
+ white-space: nowrap;
+ }
+}
+
+@media (max-width: @screen-xs) {
+ .ant-table {
+ width: 100%;
+ overflow-x: auto;
+ &-thead > tr,
+ &-tbody > tr {
+ > th,
+ > td {
+ white-space: pre;
+ > span {
+ display: block;
+ }
+ }
+ }
+ }
+ .ant-avatar-sm{
+ width: 32px;
+ height: 32px;
+ margin:calc((50px - 32px) / 2) 0;
+ border-radius:8px ;
+ }
+}
+//表格上方操作条
+.table-operations {
+ margin-bottom: 16px;
+}
+.table-operations > button,
+.table-operations .ant-input-affix-wrapper{
+ margin-right: 8px;
+}
+// 详情页底部按钮
+.bottom-control {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ border-top: 1px solid #e8e8e8;
+ padding: 10px 16px;
+ text-align: right;
+ left: 0;
+ background: #fff;
+ border-radius: 0 0 4px 4px;
+}
+.ant-drawer-body {
+ padding: 24px 24px 50px 24px;
+ font-size: 14px;
+ line-height: 1.5;
+}
+
+
+.ant-pro-multi-tab {
+ margin: 0 0 0 0;
+ background: #fff;
+}
+/* 谷歌美化滚动条 */
+*::-webkit-scrollbar {
+ width: 6px;
+ // height: 6px;
+ height: 10px;
+}
+*::-webkit-scrollbar-track {
+ background: f0f2f5;
+ border-radius: 2px;
+}
+*::-webkit-scrollbar-thumb {
+ background: #c8d2e0;
+ border-radius: 10px;
+}
+*::-webkit-scrollbar-thumb:hover {
+ background: #c8d2e0;
+}
+*::-webkit-scrollbar-corner {
+ background: #c8d2e0;
+}
+.drag-list-color {
+ background-color: @primary-1!important;
+}
+.dasboard_body{
+ .ant-statistic-title{
+ color: #97a4ba;
+ margin-bottom: 8px;
+ }
+
+}
+/* 重新label样式解决label对不齐问题 */
+.ant-form-item-label {
+ line-height: 30px !important;
+ padding-right: 8px;
+ }
+.table-card{
+ min-height:calc(100vh - 196px);
+}
+
+.table-page-search-wrapper .ant-form-item{
+ margin-bottom: 8px;
+}
+main{
+ .ant-pro-grid-content{
+ height:calc(100vh - 90px);
+ padding: 16px;
+ overflow: auto;
+ }
+}
+/* 正常引用card样式 */
+ body .padding-card .ant-card-body {
+ padding: 24px;
+ }
diff --git a/hotgo-web/src/layouts/BasicLayout.less b/hotgo-web/src/layouts/BasicLayout.less
new file mode 100644
index 0000000..0298840
--- /dev/null
+++ b/hotgo-web/src/layouts/BasicLayout.less
@@ -0,0 +1,66 @@
+@import "../assets/styles/default.less";
+.ant-pro-global-header-index-right {
+ margin-right: 8px;
+
+ &.ant-pro-global-header-index-dark {
+ .ant-pro-global-header-index-action {
+ color: hsla(0, 0%, 100%, .85);
+
+ &:hover {
+ background: #1890ff;
+ }
+ }
+ }
+
+ .ant-pro-account-avatar {
+ .antd-pro-global-header-index-avatar {
+ margin: ~'calc((@{layout-header-height} - 24px) / 2)' 0;
+ margin-right: 8px;
+ color: @primary-color;
+ vertical-align: top;
+ background: rgba(255, 255, 255, 0.85);
+ }
+ }
+
+ .menu {
+ .anticon {
+ margin-right: 8px;
+ }
+
+ .ant-dropdown-menu-item {
+ min-width: 100px;
+ }
+ }
+}
+.ant-layout-sider-children {
+ ::-webkit-scrollbar-track {
+ box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+ background-color: transparent;
+ border-radius: 10px;
+ }
+
+ ::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ ::-webkit-scrollbar-thumb {
+ border-radius: 10px;
+ background-color: #c8d2e0;
+ background-image: -webkit-linear-gradient(
+ 45deg,
+ rgba(255, 255, 255, 0.2) 25%,
+ transparent 25%,
+ transparent 50%,
+ rgba(255, 255, 255, 0.2) 50%,
+ rgba(255, 255, 255, 0.2) 75%,
+ transparent 75%,
+ transparent
+ );
+ }
+ *::-webkit-scrollbar-thumb:hover {
+ background: #c8d2e0;
+ }
+}
+.ant-layout-footer{
+ display: none;
+}
\ No newline at end of file
diff --git a/hotgo-web/src/layouts/BasicLayout.vue b/hotgo-web/src/layouts/BasicLayout.vue
new file mode 100644
index 0000000..90df9d2
--- /dev/null
+++ b/hotgo-web/src/layouts/BasicLayout.vue
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/layouts/BlankLayout.vue b/hotgo-web/src/layouts/BlankLayout.vue
new file mode 100644
index 0000000..1bfbfbf
--- /dev/null
+++ b/hotgo-web/src/layouts/BlankLayout.vue
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/layouts/PageView.vue b/hotgo-web/src/layouts/PageView.vue
new file mode 100644
index 0000000..86df485
--- /dev/null
+++ b/hotgo-web/src/layouts/PageView.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/layouts/RouteView.vue b/hotgo-web/src/layouts/RouteView.vue
new file mode 100644
index 0000000..edae19e
--- /dev/null
+++ b/hotgo-web/src/layouts/RouteView.vue
@@ -0,0 +1,32 @@
+
diff --git a/hotgo-web/src/layouts/UserLayout.vue b/hotgo-web/src/layouts/UserLayout.vue
new file mode 100644
index 0000000..b997c51
--- /dev/null
+++ b/hotgo-web/src/layouts/UserLayout.vue
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/layouts/index.js b/hotgo-web/src/layouts/index.js
new file mode 100644
index 0000000..1d62d6c
--- /dev/null
+++ b/hotgo-web/src/layouts/index.js
@@ -0,0 +1,7 @@
+import UserLayout from './UserLayout'
+import BlankLayout from './BlankLayout'
+import BasicLayout from './BasicLayout'
+import RouteView from './RouteView'
+import PageView from './PageView'
+
+export { UserLayout, BasicLayout, BlankLayout, RouteView, PageView }
diff --git a/hotgo-web/src/layouts/modules/tabs-view.vue b/hotgo-web/src/layouts/modules/tabs-view.vue
new file mode 100644
index 0000000..22bf348
--- /dev/null
+++ b/hotgo-web/src/layouts/modules/tabs-view.vue
@@ -0,0 +1,199 @@
+
+
+
+
+
+
+
+
+ {{ pane.title }}
+
+
+
+
+
+ 刷新
+
+
+
+ 关闭
+
+
+
+
+ 关闭左侧
+
+
+
+ 关闭右侧
+
+
+
+
+ 关闭其他
+
+
+
+ 关闭全部
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/locales/index.js b/hotgo-web/src/locales/index.js
new file mode 100644
index 0000000..54bd869
--- /dev/null
+++ b/hotgo-web/src/locales/index.js
@@ -0,0 +1,59 @@
+import Vue from 'vue'
+import VueI18n from 'vue-i18n'
+import storage from 'store'
+import moment from 'moment'
+
+// default lang
+import zhCn from './lang/zh-CN'
+
+Vue.use(VueI18n)
+
+export const defaultLang = 'zh-CN'
+
+const messages = {
+ 'zh-CN': {
+ ...zhCn
+ }
+}
+
+const i18n = new VueI18n({
+ silentTranslationWarn: true,
+ locale: defaultLang,
+ fallbackLocale: defaultLang,
+ messages
+})
+
+const loadedLanguages = [defaultLang]
+
+function setI18nLanguage (lang) {
+ i18n.locale = lang
+ // request.headers['Accept-Language'] = lang
+ document.querySelector('html').setAttribute('lang', lang)
+ return lang
+}
+
+export function loadLanguageAsync (lang = defaultLang) {
+ return new Promise(resolve => {
+ // 缓存语言设置
+ storage.set('lang', lang)
+ if (i18n.locale !== lang) {
+ if (!loadedLanguages.includes(lang)) {
+ return import(/* webpackChunkName: "lang-[request]" */ `./lang/${lang}`).then(msg => {
+ const locale = msg.default
+ i18n.setLocaleMessage(lang, locale)
+ loadedLanguages.push(lang)
+ moment.updateLocale(locale.momentName, locale.momentLocale)
+ return setI18nLanguage(lang)
+ })
+ }
+ return resolve(setI18nLanguage(lang))
+ }
+ return resolve(lang)
+ })
+}
+
+export function i18nRender (key) {
+ return i18n.t(`${key}`)
+}
+
+export default i18n
diff --git a/hotgo-web/src/locales/lang/en-US.js b/hotgo-web/src/locales/lang/en-US.js
new file mode 100644
index 0000000..137fc5b
--- /dev/null
+++ b/hotgo-web/src/locales/lang/en-US.js
@@ -0,0 +1,16 @@
+import antdEnUS from 'ant-design-vue/es/locale-provider/en_US'
+import momentEU from 'moment/locale/eu'
+import setting from './en-US/setting'
+
+const components = {
+ antLocale: antdEnUS,
+ momentName: 'eu',
+ momentLocale: momentEU
+}
+
+export default {
+ 'message': '-',
+
+ ...components,
+ ...setting
+}
diff --git a/hotgo-web/src/locales/lang/en-US/setting.js b/hotgo-web/src/locales/lang/en-US/setting.js
new file mode 100644
index 0000000..0a1c0f8
--- /dev/null
+++ b/hotgo-web/src/locales/lang/en-US/setting.js
@@ -0,0 +1,29 @@
+export default {
+ // 'app.setting.pagestyle': 'Page style setting',
+ // 'app.setting.pagestyle.light': 'Light style',
+ // 'app.setting.pagestyle.dark': 'Dark style',
+ // 'app.setting.pagestyle.realdark': 'RealDark style',
+ // 'app.setting.themecolor': 'Theme Color',
+ // 'app.setting.navigationmode': 'Navigation Mode',
+ // 'app.setting.content-width': 'Content Width',
+ // 'app.setting.fixedheader': 'Fixed Header',
+ // 'app.setting.fixedsidebar': 'Fixed Sidebar',
+ // 'app.setting.sidemenu': 'Side Menu Layout',
+ // 'app.setting.topmenu': 'Top Menu Layout',
+ // 'app.setting.content-width.fixed': 'Fixed',
+ // 'app.setting.content-width.fluid': 'Fluid',
+ // 'app.setting.othersettings': 'Other Settings',
+ // 'app.setting.weakmode': 'Weak Mode',
+ // 'app.setting.copy': 'Copy Setting',
+ // 'app.setting.loading': 'Loading theme',
+ // 'app.setting.copyinfo': 'copy success,please replace defaultSettings in src/config/defaultSettings.js',
+ // 'app.setting.production.hint': 'Setting panel shows in development environment only, please manually modify',
+ // 'app.setting.themecolor.daybreak': 'Daybreak Blue',
+ // 'app.setting.themecolor.dust': 'Dust Red',
+ // 'app.setting.themecolor.volcano': 'Volcano',
+ // 'app.setting.themecolor.sunset': 'Sunset Orange',
+ // 'app.setting.themecolor.cyan': 'Cyan',
+ // 'app.setting.themecolor.green': 'Polar Green',
+ // 'app.setting.themecolor.geekblue': 'Geek Blue',
+ // 'app.setting.themecolor.purple': 'Golden Purple'
+}
diff --git a/hotgo-web/src/locales/lang/zh-CN.js b/hotgo-web/src/locales/lang/zh-CN.js
new file mode 100644
index 0000000..bb1b13e
--- /dev/null
+++ b/hotgo-web/src/locales/lang/zh-CN.js
@@ -0,0 +1,16 @@
+import antd from 'ant-design-vue/es/locale-provider/zh_CN'
+import momentCN from 'moment/locale/zh-cn'
+import setting from './zh-CN/setting'
+
+const components = {
+ antLocale: antd,
+ momentName: 'zh-cn',
+ momentLocale: momentCN
+}
+
+export default {
+ 'message': '-',
+
+ ...components,
+ ...setting
+}
diff --git a/hotgo-web/src/locales/lang/zh-CN/setting.js b/hotgo-web/src/locales/lang/zh-CN/setting.js
new file mode 100644
index 0000000..c713806
--- /dev/null
+++ b/hotgo-web/src/locales/lang/zh-CN/setting.js
@@ -0,0 +1,29 @@
+export default {
+ 'app.setting.pagestyle': '整体风格设置',
+ 'app.setting.pagestyle.light': '亮色菜单风格',
+ 'app.setting.pagestyle.dark': '暗色菜单风格',
+ 'app.setting.pagestyle.realdark': '暗黑模式',
+ 'app.setting.themecolor': '主题色',
+ 'app.setting.navigationmode': '导航模式',
+ 'app.setting.content-width': '内容区域宽度',
+ 'app.setting.fixedheader': '固定 Header',
+ 'app.setting.fixedsidebar': '固定侧边栏',
+ 'app.setting.sidemenu': '侧边菜单布局',
+ 'app.setting.topmenu': '顶部菜单布局',
+ 'app.setting.content-width.fixed': 'Fixed',
+ 'app.setting.content-width.fluid': 'Fluid',
+ 'app.setting.othersettings': '其他设置',
+ 'app.setting.weakmode': '色弱模式',
+ 'app.setting.copy': '拷贝设置',
+ 'app.setting.loading': '加载主题中',
+ 'app.setting.copyinfo': '拷贝设置成功 src/config/defaultSettings.js',
+ 'app.setting.production.hint': '配置栏只在开发环境用于预览,生产环境不会展现,请拷贝后手动修改配置文件',
+ 'app.setting.themecolor.daybreak': '拂晓蓝',
+ 'app.setting.themecolor.dust': '薄暮',
+ 'app.setting.themecolor.volcano': '火山',
+ 'app.setting.themecolor.sunset': '日暮',
+ 'app.setting.themecolor.cyan': '明青',
+ 'app.setting.themecolor.green': '极光绿',
+ 'app.setting.themecolor.geekblue': '极客蓝',
+ 'app.setting.themecolor.purple': '酱紫'
+}
diff --git a/hotgo-web/src/main.js b/hotgo-web/src/main.js
new file mode 100644
index 0000000..d450880
--- /dev/null
+++ b/hotgo-web/src/main.js
@@ -0,0 +1,68 @@
+// with polyfills
+import 'core-js/stable'
+import 'regenerator-runtime/runtime'
+
+import Vue from 'vue'
+import App from './App.vue'
+import router from './router'
+import permission from './directive/permission'
+import store from './store/'
+import i18n from './locales'
+import { VueAxios } from './utils/request'
+import ProLayout, { PageHeaderWrapper } from '@/components/ProLayout'
+import FooterToolBar from '@/components/FooterToolbar'
+import themePluginConfig from '../config/themePluginConfig'
+
+// mock
+// WARNING: `mockjs` NOT SUPPORT `IE` PLEASE DO NOT USE IN `production` ENV.
+// import './mock'
+import '@/assets/styles/antv-theme.less'
+import bootstrap from './core/bootstrap'
+import './core/lazy_use' // use lazy load components
+import './permission' // permission control
+import './utils/filter' // global filter
+import draggable from '@/utils/drag'
+import './global.less' // global style
+import { getDicts, getAllDicts } from '@/api/system/dict/data'
+import { getConfigKey } from '@/api/system/config'
+import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, downloadTask, downloadByPath, handleTree, appendTreeNode, removeTreeNode, expandTree } from '@/utils/aidex'
+import Highlight from './utils/highlight'
+
+// 全局方法挂载
+Vue.prototype.getDicts = getDicts
+Vue.prototype.getAllDicts = getAllDicts
+Vue.prototype.getConfigKey = getConfigKey
+Vue.prototype.parseTime = parseTime
+Vue.prototype.resetForm = resetForm
+Vue.prototype.addDateRange = addDateRange
+Vue.prototype.selectDictLabel = selectDictLabel
+Vue.prototype.selectDictLabels = selectDictLabels
+Vue.prototype.download = download
+Vue.prototype.downloadTask = downloadTask
+Vue.prototype.downloadByPath = downloadByPath
+Vue.prototype.handleTree = handleTree
+Vue.prototype.appendTreeNode = appendTreeNode
+Vue.prototype.removeTreeNode = removeTreeNode
+Vue.prototype.expandTree = expandTree
+Vue.config.productionTip = false
+
+// mount axios to `Vue.$http` and `this.$http`
+Vue.use(VueAxios)
+// use pro-layout components
+Vue.component('pro-layout', ProLayout)
+Vue.component('page-container', PageHeaderWrapper)
+Vue.component('page-header-wrapper', PageHeaderWrapper)
+Vue.component('footer-tool-bar', FooterToolBar)
+
+Vue.use(permission)
+Vue.use(Highlight)
+Vue.use(draggable)
+window.umi_plugin_ant_themeVar = themePluginConfig.theme
+new Vue({
+ router,
+ store,
+ i18n,
+ // init localstorage, vuex
+ created: bootstrap,
+ render: h => h(App)
+}).$mount('#app')
diff --git a/hotgo-web/src/mock/index.js b/hotgo-web/src/mock/index.js
new file mode 100644
index 0000000..ebc2013
--- /dev/null
+++ b/hotgo-web/src/mock/index.js
@@ -0,0 +1,18 @@
+import { isIE } from '@/utils/util'
+
+// 判断环境不是 prod 或者 preview 是 true 时,加载 mock 服务
+if (process.env.NODE_ENV !== 'production' || process.env.VUE_APP_PREVIEW === 'true') {
+ if (isIE()) {
+ console.error('[antd-pro] ERROR: `mockjs` NOT SUPPORT `IE` PLEASE DO NOT USE IN `production` ENV.')
+ }
+ // 使用同步加载依赖
+ // 防止 vuex 中的 GetInfo 早于 mock 运行,导致无法 mock 请求返回结果
+ console.log('[antd-pro] mock mounting')
+ const Mock = require('mockjs2')
+ require('./services/user')
+
+ Mock.setup({
+ timeout: 800 // setter delay time
+ })
+ console.log('[antd-pro] mock mounted')
+}
diff --git a/hotgo-web/src/mock/services/user.js b/hotgo-web/src/mock/services/user.js
new file mode 100644
index 0000000..47fe15c
--- /dev/null
+++ b/hotgo-web/src/mock/services/user.js
@@ -0,0 +1,26 @@
+import Mock from 'mockjs2'
+import { builder } from '../util'
+
+const info = (options) => {
+ console.log('options', options)
+ const userInfo = {
+ 'id': '4291d7da9005377ec9aec4a71ea837f',
+ 'name': '天野远子',
+ 'username': 'admin',
+ 'password': '',
+ 'avatar': '/avatar2.jpg',
+ 'status': 1,
+ 'telephone': '',
+ 'lastLoginIp': '27.154.74.117',
+ 'lastLoginTime': 1534837621348,
+ 'creatorId': 'admin',
+ 'createTime': 1497160610259,
+ 'merchantCode': 'TLif2btpzg079h15bk',
+ 'deleted': 0,
+ 'roleId': 'admin',
+ 'role': {}
+ }
+ return builder(userInfo)
+}
+
+Mock.mock(/\/api\/user\/info/, 'get', info)
diff --git a/hotgo-web/src/mock/util.js b/hotgo-web/src/mock/util.js
new file mode 100644
index 0000000..a4be036
--- /dev/null
+++ b/hotgo-web/src/mock/util.js
@@ -0,0 +1,38 @@
+const responseBody = {
+ message: '',
+ timestamp: 0,
+ result: null,
+ code: 0
+}
+
+export const builder = (data, message, code = 0, headers = {}) => {
+ responseBody.result = data
+ if (message !== undefined && message !== null) {
+ responseBody.message = message
+ }
+ if (code !== undefined && code !== 0) {
+ responseBody.code = code
+ responseBody._status = code
+ }
+ if (headers !== null && typeof headers === 'object' && Object.keys(headers).length > 0) {
+ responseBody._headers = headers
+ }
+ responseBody.timestamp = new Date().getTime()
+ return responseBody
+}
+
+export const getQueryParameters = (options) => {
+ const url = options.url
+ const search = url.split('?')[1]
+ if (!search) {
+ return {}
+ }
+ return JSON.parse('{"' + decodeURIComponent(search)
+ .replace(/"/g, '\\"')
+ .replace(/&/g, '","')
+ .replace(/=/g, '":"') + '"}')
+}
+
+export const getBody = (options) => {
+ return options.body && JSON.parse(options.body)
+}
diff --git a/hotgo-web/src/permission.js b/hotgo-web/src/permission.js
new file mode 100644
index 0000000..b03bdd4
--- /dev/null
+++ b/hotgo-web/src/permission.js
@@ -0,0 +1,84 @@
+import router from './router'
+import store from './store'
+import storage from 'store'
+import NProgress from 'nprogress' // progress bar
+import '@/components/NProgress/nprogress.less' // progress bar custom style
+// import notification from 'ant-design-vue/es/notification'
+import { setDocumentTitle, domTitle } from '@/utils/domUtil'
+import { ACCESS_TOKEN } from '@/store/mutation-types'
+import { i18nRender } from '@/locales'
+
+NProgress.configure({ showSpinner: false }) // NProgress Configuration
+
+const allowList = ['login', 'applyLicense'] // no redirect allowList
+const loginRoutePath = '/user/login'
+const defaultRoutePath = '/index'
+
+router.beforeEach((to, from, next) => {
+ NProgress.start() // start progress bar
+ to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${i18nRender(to.meta.title)} - ${domTitle}`))
+ // 存储params参数到本地
+ const paramsJson = JSON.stringify(to.params)
+ if (paramsJson !== '{}') {
+ localStorage.setItem('routerParams' + to.name, paramsJson)
+ }
+ /* has token */
+ if (storage.get(ACCESS_TOKEN)) {
+ if (to.path === loginRoutePath || to.path === '/') {
+ next({ path: defaultRoutePath })
+ NProgress.done()
+ } else {
+ // check login user.roles is null
+ if (store.getters.roles.length === 0) {
+ // request login userInfo
+ store
+ .dispatch('GetInfo')
+ .then(res => {
+ // const roles = res.result && res.result.role
+ const roles = res.roles
+ // generate dynamic router
+ store.dispatch('GenerateRoutes', { roles }).then(() => {
+ // 根据roles权限生成可访问的路由表
+ // 动态添加可访问路由表
+ router.addRoutes(store.getters.addRouters)
+ // router.addRoutes(accessRoutes)
+ // 请求带有 redirect 重定向时,登录自动重定向到该地址
+ next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
+ // const redirect = decodeURIComponent(from.query.redirect || to.path)
+ // if (to.path === redirect) {
+ // // set the replace: true so the navigation will not leave a history record
+ // next({ ...to, replace: true })
+ // } else {
+ // // 跳转到目的路由
+ // next({ path: redirect })
+ // }
+ })
+ })
+ .catch(() => {
+ // notification.error({
+ // message: '错误',
+ // description: '请求用户信息失败,请重试'
+ // })
+ // 失败时,获取用户信息失败时,调用登出,来清空历史保留信息
+ store.dispatch('Logout').then(() => {
+ next({ path: '/' })
+ })
+ })
+ } else {
+ next()
+ }
+ }
+ } else {
+ if (allowList.includes(to.name)) {
+ // 在免登录名单,直接进入
+ next()
+ } else {
+ next({ path: loginRoutePath, query: { redirect: to.fullPath } })
+ NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
+ }
+ }
+})
+
+router.afterEach(() => {
+ NProgress.done() // finish progress bar
+})
diff --git a/hotgo-web/src/router/README.md b/hotgo-web/src/router/README.md
new file mode 100644
index 0000000..169db8d
--- /dev/null
+++ b/hotgo-web/src/router/README.md
@@ -0,0 +1,134 @@
+路由/菜单说明
+====
+
+
+格式和说明
+----
+
+```ecmascript 6
+const routerObject = {
+ redirect: noredirect,
+ name: 'router-name',
+ hidden: true,
+ meta: {
+ title: 'title',
+ icon: 'a-icon',
+ target: '_blank|_self|_top|_parent',
+ keepAlive: true,
+ hiddenHeaderContent: true,
+ }
+}
+```
+
+
+
+`{ Route }` 对象
+
+| 参数 | 说明 | 类型 | 默认值 |
+| -------- | ----------------------------------------- | ------- | ------ |
+| hidden | 控制路由是否显示在 sidebar | boolean | false |
+| redirect | 重定向地址, 访问这个路由时,自定进行重定向 | string | - |
+| name | 路由名称, 必须设置,且不能重名 | string | - |
+| meta | 路由元信息(路由附带扩展信息) | object | {} |
+| hideChildrenInMenu | 强制菜单显示为Item而不是SubItem(配合 meta.hidden) | boolean | - |
+
+
+`{ Meta }` 路由元信息对象
+
+| 参数 | 说明 | 类型 | 默认值 |
+| ------------------- | ------------------------------------------------------------ | ------- | ------ |
+| title | 路由标题, 用于显示面包屑, 页面标题 *推荐设置 | string | - |
+| icon | 路由在 menu 上显示的图标 | [string,svg] | - |
+| keepAlive | 缓存该路由 | boolean | false |
+| target | 菜单链接跳转目标(参考 html a 标记) | string | - |
+| hidden | 配合`hideChildrenInMenu`使用,用于隐藏菜单时,提供递归到父菜单显示 选中菜单项_(可参考 个人页 配置方式)_ | boolean | false |
+| hiddenHeaderContent | *特殊 隐藏 [PageHeader](https://github.com/vueComponent/ant-design-vue-pro/blob/master/src/components/PageHeader/PageHeader.vue#L6) 组件中的页面带的 面包屑和页面标题栏 | boolean | false |
+| permission | 与项目提供的权限拦截匹配的权限,如果不匹配,则会被禁止访问该路由页面 | array | [] |
+
+> 路由自定义 `Icon` 请引入自定义 `svg` Icon 文件,然后传递给路由的 `meta.icon` 参数即可
+
+路由构建例子方案1
+
+路由例子
+----
+
+```ecmascript 6
+const asyncRouterMap = [
+ {
+ path: '/',
+ name: 'index',
+ component: BasicLayout,
+ meta: { title: '工作台' },
+ redirect: '/dashboard/analysis',
+ children: [
+ {
+ path: '/dashboard',
+ component: RouteView,
+ name: 'dashboard',
+ redirect: '/dashboard/workplace',
+ meta: {title: '仪表盘', icon: 'dashboard', permission: ['dashboard']},
+ children: [
+ {
+ path: '/dashboard/analysis',
+ name: 'Analysis',
+ component: () => import('@/views/dashboard/Analysis'),
+ meta: {title: '分析页', permission: ['dashboard']}
+ },
+ {
+ path: '/dashboard/monitor',
+ name: 'Monitor',
+ hidden: true,
+ component: () => import('@/views/dashboard/Monitor'),
+ meta: {title: '监控页', permission: ['dashboard']}
+ },
+ {
+ path: '/dashboard/workplace',
+ name: 'Workplace',
+ component: () => import('@/views/dashboard/Workplace'),
+ meta: {title: '工作台', permission: ['dashboard']}
+ }
+ ]
+ },
+
+ // result
+ {
+ path: '/result',
+ name: 'result',
+ component: PageView,
+ redirect: '/result/success',
+ meta: { title: '结果页', icon: 'check-circle-o', permission: [ 'result' ] },
+ children: [
+ {
+ path: '/result/success',
+ name: 'ResultSuccess',
+ component: () => import(/* webpackChunkName: "result" */ '@/views/result/Success'),
+ // 该页面隐藏面包屑和页面标题栏
+ meta: { title: '成功', hiddenHeaderContent: true, permission: [ 'result' ] }
+ },
+ {
+ path: '/result/fail',
+ name: 'ResultFail',
+ component: () => import(/* webpackChunkName: "result" */ '@/views/result/Error'),
+ // 该页面隐藏面包屑和页面标题栏
+ meta: { title: '失败', hiddenHeaderContent: true, permission: [ 'result' ] }
+ }
+ ]
+ },
+ ...
+ ]
+ },
+]
+```
+
+> 1. 请注意 `component: () => import('..') ` 方式引入路由的页面组件为 懒加载模式。具体可以看 [Vue 官方文档](https://router.vuejs.org/zh/guide/advanced/lazy-loading.html)
+> 2. 增加新的路由应该增加在 '/' (index) 路由的 `children` 内
+> 3. 子路由的父级路由必须有 `router-view` 才能让子路由渲染出来,请仔细查阅 vue-router 文档
+> 4. `permission` 可以进行自定义修改,只需要对这个模块进行自定义修改即可 [src/store/modules/permission.js#L10](https://github.com/vueComponent/ant-design-vue-pro/blob/master/src/store/modules/permission.js#L10)
+
+
+附权限路由结构:
+
+
+
+
+第二种前端路由由后端动态生成的设计,可以前往官网文档 https://pro.antdv.com/docs/authority-management 参考
diff --git a/hotgo-web/src/router/generator-routers.js b/hotgo-web/src/router/generator-routers.js
new file mode 100644
index 0000000..6152399
--- /dev/null
+++ b/hotgo-web/src/router/generator-routers.js
@@ -0,0 +1,444 @@
+// eslint-disable-next-line
+import { getRouters } from '@/api/menu'
+import { UserLayout, BasicLayout, BlankLayout, PageView, RouteView } from '@/layouts'
+import { indexRouterMap } from '@/config/router.config'
+import allIcon from '@/core/icons'
+// import { validURL } from '@/utils/validate'
+// 前端路由表
+const constantRouterComponents = {
+ // 基础页面 layout 必须引入
+ BasicLayout: BasicLayout,
+ BlankLayout: BlankLayout,
+ RouteView: RouteView,
+ PageView: PageView,
+ UserLayout: UserLayout, // 登陆注册页面的通用布局
+
+ // 你需要动态引入的页面组件
+ 'Index': () => import('@/views/index'),
+ // account
+ 'AccountCenter': () => import('@/views/account/center'),
+ 'AccountSettings': () => import('@/views/account/settings/index'),
+ 'BaseSettings': () => import('@/views/account/settings/BaseSetting'),
+ 'SecuritySettings': () => import('@/views/account/settings/Security'),
+ // job log
+ 'JobLog': () => import('@/views/monitor/job/log'),
+ // 公告新增修改
+ // 修改生成配置
+ 'GenEdit': () => import('@/views/tool/gen/modules/GenEdit'),
+ 'DashBoard': () => import('@/views/dashboard/index'),
+ 'NoticeReadIndex': () => import('@/views/system/notice/NoticeReadIndex')
+}
+
+// 前端未找到页面路由(固定不用改)
+// const notFoundRouter = {
+// path: '*', redirect: '/404', hidden: true
+// }
+// 根级菜单
+const rootRouter = {
+ key: '',
+ name: 'index',
+ path: '',
+ component: 'BasicLayout',
+ redirect: '/index',
+ meta: {
+ title: '工作台'
+ },
+ children: []
+}
+
+/**
+ * 动态生成菜单
+ * @param token
+ * @returns {Promise}
+ */
+export const generatorDynamicRouter = (token) => {
+ return new Promise((resolve, reject) => {
+ // 向后端请求路由数据
+ getRouters().then(res => {
+ // eslint-disable-next-line no-unused-vars
+ const res1 = [
+ {
+ 'name': 'Org',
+ 'path': '/org',
+ 'hidden': false,
+ 'redirect': 'noRedirect',
+ 'component': 'Layout',
+ 'alwaysShow': true,
+ 'isFrame': '1',
+ 'meta': { 'title': '组织管理', 'icon': 'calculator', 'noCache': false, 'remark': '' },
+ 'children': [{
+ 'name': '小欣欣',
+ 'path': '小欣欣',
+ 'hidden': false,
+ 'component': 'ParentView',
+ 'isFrame': '1',
+ 'meta': { 'title': '学校', 'icon': 'Alipay', 'noCache': false, 'remark': null }
+ }, {
+ 'name': 'SysAuth',
+ 'path': 'sysAuth',
+ 'hidden': false,
+ 'component': 'system/role/SysRoleAuth',
+ 'isFrame': '1',
+ 'meta': { 'title': '菜单授权', 'icon': 'api', 'noCache': false, 'remark': '' }
+ }, {
+ 'name': 'SysPost',
+ 'path': 'sysPost',
+ 'hidden': false,
+ 'component': '11/syspost/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '岗位信息', 'icon': 'DragColumn', 'noCache': false, 'remark': '' }
+ }]
+ },
+ {
+ 'name': 'Auth',
+ 'path': '/auth',
+ 'hidden': false,
+ 'redirect': 'noRedirect',
+ 'component': 'Layout',
+ 'alwaysShow': true,
+ 'isFrame': '1',
+ 'meta': { 'title': '权限管理', 'icon': 'solution', 'noCache': false, 'remark': '' },
+ 'children': [{
+ 'name': 'Role',
+ 'path': 'role',
+ 'hidden': false,
+ 'component': 'system/role/QueryList',
+ 'isFrame': '1',
+ 'meta': { 'title': '角色管理', 'icon': 'contacts', 'noCache': false, 'remark': '维护平台各角色数据以及权限分配.' }
+ }]
+ }, {
+ 'name': 'Tool',
+ 'path': '/tool',
+ 'hidden': false,
+ 'redirect': 'noRedirect',
+ 'component': 'Layout',
+ 'alwaysShow': true,
+ 'isFrame': '1',
+ 'meta': { 'title': '系统工具', 'icon': 'appstore', 'noCache': false, 'remark': '系统工具目录' },
+ 'children': [{
+ 'name': 'Build',
+ 'path': 'build',
+ 'hidden': false,
+ 'component': 'tool/build/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '表单构建', 'icon': 'bars', 'noCache': false, 'remark': '表单构建菜单' }
+ }, {
+ 'name': 'Gen',
+ 'path': 'gen',
+ 'hidden': false,
+ 'component': 'tool/gen/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '代码生成', 'icon': 'code', 'noCache': false, 'remark': '代码生成菜单' }
+ }, {
+ 'name': 'Swagger',
+ 'path': 'swagger',
+ 'hidden': false,
+ 'component': 'tool/swagger/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '系统接口', 'icon': 'api', 'noCache': false, 'remark': '系统接口菜单' }
+ }, {
+ 'name': 'Template',
+ 'path': 'template',
+ 'hidden': false,
+ 'component': 'tool/gen/genconfigtemplate/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '模板配置', 'icon': 'picture', 'noCache': false, 'remark': '' }
+ }, {
+ 'name': 'BaseTreeTable',
+ 'path': 'baseTreeTable',
+ 'hidden': false,
+ 'component': '11/basetreetable/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '树基础', 'icon': '#', 'noCache': false, 'remark': '' }
+ }, {
+ 'name': 'BaseTable',
+ 'path': 'baseTable',
+ 'hidden': false,
+ 'component': 'test/basetable/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '基础', 'icon': '#', 'noCache': false, 'remark': '' }
+ }]
+ }, {
+ 'name': 'SysSetting',
+ 'path': '/sysSetting',
+ 'hidden': false,
+ 'redirect': 'noRedirect',
+ 'component': 'Layout',
+ 'alwaysShow': true,
+ 'isFrame': '1',
+ 'meta': { 'title': '系统设置', 'icon': 'setting', 'noCache': false, 'remark': '' },
+ 'children': [{
+ 'name': 'Menu',
+ 'path': 'menu',
+ 'hidden': false,
+ 'component': 'system/menu/MenuIndex',
+ 'isFrame': '1',
+ 'meta': { 'title': '菜单管理', 'icon': 'bars', 'noCache': false, 'remark': '平台所有菜单维护' }
+ }, {
+ 'name': 'Dict',
+ 'path': 'dict',
+ 'hidden': false,
+ 'component': 'system/dict/DictIndex',
+ 'isFrame': '1',
+ 'meta': { 'title': '字典管理', 'icon': 'read', 'noCache': false, 'remark': '字典管理菜单' }
+ }, {
+ 'name': 'Config',
+ 'path': 'config',
+ 'hidden': false,
+ 'component': 'system/config/ConfigIndex',
+ 'isFrame': '1',
+ 'meta': { 'title': '参数设置', 'icon': 'code', 'noCache': false, 'remark': '参数设置菜单' }
+ }, {
+ 'name': 'User',
+ 'path': 'user',
+ 'hidden': false,
+ 'component': 'system/user/SysUserIndex',
+ 'isFrame': '1',
+ 'meta': { 'title': '用户管理', 'icon': 'peoples', 'noCache': false, 'remark': null }
+ }]
+ }, {
+ 'name': 'Log',
+ 'path': '/log',
+ 'hidden': false,
+ 'redirect': 'noRedirect',
+ 'component': 'Layout',
+ 'alwaysShow': true,
+ 'isFrame': '1',
+ 'meta': { 'title': '日志管理', 'icon': 'copy', 'noCache': false, 'remark': '日志管理菜单' },
+ 'children': [{
+ 'name': 'Operlog',
+ 'path': 'operlog',
+ 'hidden': false,
+ 'component': 'monitor/operlog/OperlogIndex',
+ 'isFrame': '1',
+ 'meta': { 'title': '操作日志', 'icon': 'form', 'noCache': false, 'remark': '操作日志菜单' }
+ }, {
+ 'name': 'LoginLog',
+ 'path': 'loginLog',
+ 'hidden': false,
+ 'component': 'monitor/loginlog/LoginLogIndex',
+ 'isFrame': '1',
+ 'meta': { 'title': '登录日志', 'icon': 'loginLog', 'noCache': false, 'remark': '登录日志菜单' }
+ }, {
+ 'name': 'Joblog',
+ 'path': 'joblog',
+ 'hidden': false,
+ 'component': 'monitor/job/log',
+ 'isFrame': '1',
+ 'meta': { 'title': '调度日志', 'icon': 'bug', 'noCache': false, 'remark': '' }
+ }]
+ }, {
+ 'name': 'Monitor',
+ 'path': '/monitor',
+ 'hidden': false,
+ 'redirect': 'noRedirect',
+ 'component': 'Layout',
+ 'alwaysShow': true,
+ 'isFrame': '1',
+ 'meta': { 'title': '系统监控', 'icon': 'fund', 'noCache': false, 'remark': '系统监控目录' },
+ 'children': [{
+ 'name': 'Online',
+ 'path': 'online',
+ 'hidden': false,
+ 'component': 'monitor/online/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '在线用户', 'icon': 'dot-chart', 'noCache': false, 'remark': '在线用户菜单' }
+ }, {
+ 'name': 'Job',
+ 'path': 'job',
+ 'hidden': false,
+ 'component': 'monitor/job/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '定时任务', 'icon': 'bar-chart', 'noCache': false, 'remark': '定时任务菜单' }
+ }, {
+ 'name': 'Druid',
+ 'path': 'druid',
+ 'hidden': false,
+ 'component': 'monitor/druid/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '数据监控', 'icon': 'dashboard', 'noCache': false, 'remark': '数据监控菜单' }
+ }, {
+ 'name': 'Server',
+ 'path': 'server',
+ 'hidden': false,
+ 'component': 'monitor/server/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '服务监控', 'icon': 'pie-chart', 'noCache': false, 'remark': '服务监控菜单' }
+ }, {
+ 'name': 'Cache',
+ 'path': 'cache',
+ 'hidden': false,
+ 'component': 'monitor/cache/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '缓存监控', 'icon': 'box-plot', 'noCache': false, 'remark': '缓存监控菜单' }
+ }, {
+ 'name': 'CacheList',
+ 'path': 'cacheList',
+ 'hidden': false,
+ 'component': 'monitor/cache/indexCacheList',
+ 'isFrame': '1',
+ 'meta': { 'title': '缓存列表', 'icon': 'dashboardNew', 'noCache': false, 'remark': null }
+ }]
+ }, {
+ 'name': 'SysApp',
+ 'path': '/sysApp',
+ 'hidden': false,
+ 'redirect': 'noRedirect',
+ 'component': 'Layout',
+ 'alwaysShow': true,
+ 'isFrame': '1',
+ 'meta': { 'title': '系统应用', 'icon': 'laptop', 'noCache': false, 'remark': '' },
+ 'children': [{
+ 'name': 'Notice',
+ 'path': 'notice',
+ 'hidden': false,
+ 'component': 'system/notice/NoticeIndex',
+ 'isFrame': '1',
+ 'meta': { 'title': '通知公告', 'icon': 'notification', 'noCache': false, 'remark': '通知公告菜单' }
+ }, {
+ 'name': 'Baidu.com',
+ 'path': 'baidu.com',
+ 'hidden': false,
+ 'component': 'ParentView',
+ 'isFrame': '0',
+ 'meta': { 'title': '测试', 'icon': 'QRcode', 'noCache': false, 'remark': null }
+ }]
+ }, {
+ 'path': '/',
+ 'hidden': false,
+ 'component': 'Layout',
+ 'isFrame': '1',
+ 'meta': { 'title': '部门管理', 'icon': 'cluster', 'noCache': false, 'remark': '部门管理菜单' },
+ 'children': [{
+ 'name': 'Dept',
+ 'path': 'dept',
+ 'hidden': false,
+ 'component': 'system/dept/SysDeptIndex',
+ 'isFrame': '1',
+ 'meta': { 'title': '部门管理', 'icon': 'cluster', 'noCache': false, 'remark': '部门管理菜单' }
+ }]
+ }, {
+ 'name': '字典',
+ 'path': '/SysDictType',
+ 'hidden': false,
+ 'redirect': 'noRedirect',
+ 'component': 'Layout',
+ 'alwaysShow': true,
+ 'isFrame': '1',
+ 'meta': { 'title': '字典', 'icon': 'redis', 'noCache': false, 'remark': null },
+ 'children': [{
+ 'name': 'SysDictType',
+ 'path': 'sysDictType',
+ 'hidden': false,
+ 'component': 'sysDictType/sysdicttype/index',
+ 'isFrame': '1',
+ 'meta': { 'title': '字典类型', 'icon': 'Sina', 'noCache': false, 'remark': '' }
+ }]
+ }, {
+ 'name': '测试菜单-name',
+ 'path': '/test_path',
+ 'hidden': false,
+ 'redirect': 'noRedirect',
+ 'component': 'Layout',
+ 'alwaysShow': true,
+ 'isFrame': '1',
+ 'meta': { 'title': '测试菜单-title', 'icon': 'setting', 'noCache': false, 'remark': '' },
+ 'children': [{
+ 'name': 'Temp_children_name',
+ 'path': 'temp_children_path',
+ 'hidden': false,
+ 'component': 'test/temp/home',
+ 'isFrame': '1',
+ 'meta': { 'title': '测试页面', 'icon': 'code', 'noCache': false, 'remark': '参数设置菜单' }
+ }]
+ }]
+
+ // console.log('res2:' + res1.length)
+ // console.log('res.data:' + JSON.stringify(res))
+ const menuNav = []
+ rootRouter.children = indexRouterMap.concat(res)
+ menuNav.push(rootRouter)
+ const routers = generator(menuNav)
+ // console.log('routers', routers)
+ // routers.push(notFoundRouter)
+ resolve(routers)
+ }).catch(err => {
+ reject(err)
+ })
+ })
+}
+
+/**
+ * 格式化树形结构数据 生成 vue-router 层级路由表
+ *
+ * @param routerMap
+ * @param parent
+ * @returns {*}
+ */
+export const generator = (routerMap, parent) => {
+ return routerMap.map(item => {
+ const { title, show, hideChildren, hiddenHeaderContent, hidden, icon, noCache } = item.meta || {}
+ if (item.component) {
+ // Layout ParentView 组件特殊处理
+ if (item.component === 'Layout') {
+ item.component = 'RouteView'
+ } else if (item.component === 'ParentView') {
+ // 三级菜单处理
+ item.component = 'RouteView'
+ item.path = '/' + item.path
+ }
+ }
+ if (item.path) {
+ // item.path = '/' + item.path
+ }
+ if (item.isFrame === '2') {
+ item.target = '_blank'
+ } else {
+ item.target = ''
+ }
+ const currentRouter = {
+ // 如果路由设置了 path,则作为默认 path,否则 路由地址 动态拼接生成如 /dashboard/workplace
+ path: item.path || `${parent && parent.path || ''}/${item.path}`,
+ // 路由名称,建议唯一
+ name: item.name || item.key || '',
+ // 该路由对应页面的 组件(动态加载)
+ component: (constantRouterComponents[item.component || item.key]) || (() => import(`@/views/${item.component}`)),
+ hidden: item.hidden,
+ // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
+ meta: {
+ title: title,
+ icon: allIcon[icon + 'Icon'] || icon,
+ iconStr: icon === null ? 'profile' : icon,
+ hiddenHeaderContent: hiddenHeaderContent,
+ // 目前只能通过判断path的http链接来判断是否外链,适配若依
+ // target: validURL(item.path) ? '_blank' : '',
+ target: item.target,
+ permission: item.name,
+ keepAlive: noCache,
+ hidden: hidden,
+ remark: item.meta.remark
+ },
+ redirect: item.redirect
+ }
+ // 是否设置了隐藏菜单
+ if (show === false) {
+ currentRouter.hidden = true
+ }
+ // 适配若依,若依为缩写路径,而antdv-pro的pro-layout要求每个路径需为全路径
+ if (!constantRouterComponents[item.component || item.key]) {
+ currentRouter.path = `${parent && parent.path || ''}/${item.path}`
+ }
+ // 是否设置了隐藏子菜单
+ if (hideChildren) {
+ currentRouter.hideChildrenInMenu = true
+ }
+ // 是否有子菜单,并递归处理,并将父path传入
+ if (item.children && item.children.length > 0) {
+ // Recursion
+ currentRouter.children = generator(item.children, currentRouter)
+ }
+ // console.log('currentRouter:' + JSON.stringify(currentRouter))
+ // console.log('======================')
+ return currentRouter
+ })
+}
diff --git a/hotgo-web/src/router/index.js b/hotgo-web/src/router/index.js
new file mode 100644
index 0000000..afda622
--- /dev/null
+++ b/hotgo-web/src/router/index.js
@@ -0,0 +1,17 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+import { constantRouterMap } from '@/config/router.config'
+
+// hack router push callback
+const originalPush = Router.prototype.push
+Router.prototype.push = function push (location, onResolve, onReject) {
+ if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
+ return originalPush.call(this, location).catch(err => err)
+}
+
+Vue.use(Router)
+
+export default new Router({
+ mode: 'history',
+ routes: constantRouterMap
+})
diff --git a/hotgo-web/src/store/app-mixin.js b/hotgo-web/src/store/app-mixin.js
new file mode 100644
index 0000000..c910ae9
--- /dev/null
+++ b/hotgo-web/src/store/app-mixin.js
@@ -0,0 +1,32 @@
+import { mapState } from 'vuex'
+
+const baseMixin = {
+ computed: {
+ ...mapState({
+ layout: state => state.app.layout,
+ navTheme: state => state.app.theme,
+ primaryColor: state => state.app.color,
+ colorWeak: state => state.app.weak,
+ fixedHeader: state => state.app.fixedHeader,
+ fixedSidebar: state => state.app.fixedSidebar,
+ contentWidth: state => state.app.contentWidth,
+ autoHideHeader: state => state.app.autoHideHeader,
+
+ isMobile: state => state.app.isMobile,
+ sideCollapsed: state => state.app.sideCollapsed,
+ multiTab: state => state.app.multiTab
+ }),
+ isTopMenu () {
+ return this.layout === 'topmenu'
+ }
+ },
+ methods: {
+ isSideMenu () {
+ return !this.isTopMenu
+ }
+ }
+}
+
+export {
+ baseMixin
+}
diff --git a/hotgo-web/src/store/device-mixin.js b/hotgo-web/src/store/device-mixin.js
new file mode 100644
index 0000000..2510707
--- /dev/null
+++ b/hotgo-web/src/store/device-mixin.js
@@ -0,0 +1,11 @@
+import { mapState } from 'vuex'
+
+const deviceMixin = {
+ computed: {
+ ...mapState({
+ isMobile: state => state.app.isMobile
+ })
+ }
+}
+
+export { deviceMixin }
diff --git a/hotgo-web/src/store/getters.js b/hotgo-web/src/store/getters.js
new file mode 100644
index 0000000..3a5d517
--- /dev/null
+++ b/hotgo-web/src/store/getters.js
@@ -0,0 +1,23 @@
+const getters = {
+ isMobile: state => state.app.isMobile,
+ lang: state => state.app.lang,
+ theme: state => state.app.theme,
+ color: state => state.app.color,
+ token: state => state.user.token,
+ avatar: state => state.user.avatar,
+ nickname: state => state.user.name,
+ name: state => state.user.name,
+ userType: state => state.user.userType,
+ portalConfigs: state => state.user.portalConfigs,
+ defaultPortal: state => state.user.defaultPortal,
+ platformVersion: state => state.user.platformVersion,
+ sysNoticeList: state => state.user.sysNoticeList,
+ welcome: state => state.user.welcome,
+ roles: state => state.user.roles,
+ permissions: state => state.user.permissions,
+ userInfo: state => state.user.info,
+ addRouters: state => state.permission.addRouters,
+ multiTab: state => state.app.multiTab
+}
+
+export default getters
diff --git a/hotgo-web/src/store/i18n-mixin.js b/hotgo-web/src/store/i18n-mixin.js
new file mode 100644
index 0000000..715b0c8
--- /dev/null
+++ b/hotgo-web/src/store/i18n-mixin.js
@@ -0,0 +1,16 @@
+import { mapState } from 'vuex'
+
+const i18nMixin = {
+ computed: {
+ ...mapState({
+ currentLang: state => state.app.lang
+ })
+ },
+ methods: {
+ setLang (lang) {
+ this.$store.dispatch('setLang', lang)
+ }
+ }
+}
+
+export default i18nMixin
diff --git a/hotgo-web/src/store/index.js b/hotgo-web/src/store/index.js
new file mode 100644
index 0000000..e385bee
--- /dev/null
+++ b/hotgo-web/src/store/index.js
@@ -0,0 +1,32 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import app from './modules/app'
+import user from './modules/user'
+
+// default router permission control
+// import permission from './modules/permission'
+import permission from './modules/async-router'
+
+// dynamic router permission control (Experimental)
+// import permission from './modules/async-router'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+ modules: {
+ app,
+ user,
+ permission
+ },
+ state: {
+
+ },
+ mutations: {
+
+ },
+ actions: {
+
+ },
+ getters
+})
diff --git a/hotgo-web/src/store/modules/app.js b/hotgo-web/src/store/modules/app.js
new file mode 100644
index 0000000..a3ec761
--- /dev/null
+++ b/hotgo-web/src/store/modules/app.js
@@ -0,0 +1,99 @@
+import storage from 'store'
+import {
+ SIDEBAR_TYPE,
+ TOGGLE_MOBILE_TYPE,
+ TOGGLE_NAV_THEME,
+ TOGGLE_LAYOUT,
+ TOGGLE_FIXED_HEADER,
+ TOGGLE_FIXED_SIDEBAR,
+ TOGGLE_CONTENT_WIDTH,
+ TOGGLE_HIDE_HEADER,
+ TOGGLE_COLOR,
+ TOGGLE_WEAK,
+ TOGGLE_MULTI_TAB,
+ // i18n
+ APP_LANGUAGE
+} from '@/store/mutation-types'
+import { loadLanguageAsync } from '@/locales'
+
+const app = {
+ state: {
+ sideCollapsed: false,
+ isMobile: false,
+ theme: 'dark',
+ layout: '',
+ contentWidth: '',
+ fixedHeader: false,
+ fixedSidebar: false,
+ autoHideHeader: false,
+ color: '',
+ weak: false,
+ multiTab: true,
+ lang: 'zh-CN',
+ _antLocale: {}
+ },
+ mutations: {
+ [SIDEBAR_TYPE]: (state, type) => {
+ state.sideCollapsed = type
+ storage.set(SIDEBAR_TYPE, type)
+ },
+ [TOGGLE_MOBILE_TYPE]: (state, isMobile) => {
+ state.isMobile = isMobile
+ },
+ [TOGGLE_NAV_THEME]: (state, theme) => {
+ state.theme = theme
+ storage.set(TOGGLE_NAV_THEME, theme)
+ },
+ [TOGGLE_LAYOUT]: (state, mode) => {
+ state.layout = mode
+ storage.set(TOGGLE_LAYOUT, mode)
+ },
+ [TOGGLE_FIXED_HEADER]: (state, mode) => {
+ state.fixedHeader = mode
+ storage.set(TOGGLE_FIXED_HEADER, mode)
+ },
+ [TOGGLE_FIXED_SIDEBAR]: (state, mode) => {
+ state.fixedSidebar = mode
+ storage.set(TOGGLE_FIXED_SIDEBAR, mode)
+ },
+ [TOGGLE_CONTENT_WIDTH]: (state, type) => {
+ state.contentWidth = type
+ storage.set(TOGGLE_CONTENT_WIDTH, type)
+ },
+ [TOGGLE_HIDE_HEADER]: (state, type) => {
+ state.autoHideHeader = type
+ storage.set(TOGGLE_HIDE_HEADER, type)
+ },
+ [TOGGLE_COLOR]: (state, color) => {
+ state.color = color
+ storage.set(TOGGLE_COLOR, color)
+ },
+ [TOGGLE_WEAK]: (state, mode) => {
+ state.weak = mode
+ storage.set(TOGGLE_WEAK, mode)
+ },
+ [APP_LANGUAGE]: (state, lang, antd = {}) => {
+ state.lang = lang
+ state._antLocale = antd
+ storage.set(APP_LANGUAGE, lang)
+ },
+ [TOGGLE_MULTI_TAB]: (state, bool) => {
+ storage.set(TOGGLE_MULTI_TAB, bool)
+ state.multiTab = bool
+ }
+ },
+ actions: {
+ setLang ({ commit }, lang) {
+ return new Promise((resolve, reject) => {
+ commit(APP_LANGUAGE, lang)
+ loadLanguageAsync(lang).then(() => {
+ resolve()
+ }).catch((e) => {
+ reject(e)
+ })
+ })
+ }
+ }
+}
+
+export default app
diff --git a/hotgo-web/src/store/modules/async-router.js b/hotgo-web/src/store/modules/async-router.js
new file mode 100644
index 0000000..37f6af9
--- /dev/null
+++ b/hotgo-web/src/store/modules/async-router.js
@@ -0,0 +1,31 @@
+/**
+ * 向后端请求用户的菜单,动态生成路由
+ */
+import { constantRouterMap } from '@/config/router.config'
+import { generatorDynamicRouter } from '@/router/generator-routers'
+
+const permission = {
+ state: {
+ routers: constantRouterMap,
+ addRouters: []
+ },
+ mutations: {
+ SET_ROUTERS: (state, routers) => {
+ state.addRouters = constantRouterMap.concat(routers)
+ state.routers = constantRouterMap.concat(routers)
+ // state.routers = constantRouterMap
+ }
+ },
+ actions: {
+ GenerateRoutes ({ commit }, data) {
+ return new Promise(resolve => {
+ generatorDynamicRouter(data).then(routers => {
+ commit('SET_ROUTERS', routers)
+ resolve()
+ })
+ })
+ }
+ }
+}
+
+export default permission
diff --git a/hotgo-web/src/store/modules/permission.js b/hotgo-web/src/store/modules/permission.js
new file mode 100644
index 0000000..676905e
--- /dev/null
+++ b/hotgo-web/src/store/modules/permission.js
@@ -0,0 +1,104 @@
+import { constantRouterMap } from '@/config/router.config'
+import { getRouters } from '@/api/menu'
+import { BasicLayout } from '@/layouts'
+
+const RouteView = {
+ name: 'RouteView',
+ render: (h) => h('router-view')
+}
+// /**
+// * 过滤账户是否拥有某一个权限,并将菜单从加载列表移除
+// *
+// * @param permission
+// * @param route
+// * @returns {boolean}
+// */
+// function hasPermission (permission, route) {
+// if (route.meta && route.meta.permission) {
+// let flag = false
+// for (let i = 0, len = permission.length; i < len; i++) {
+// flag = route.meta.permission.includes(permission[i])
+// if (flag) {
+// return true
+// }
+// }
+// return false
+// }
+// return true
+// }
+
+/**
+ * 单账户多角色时,使用该方法可过滤角色不存在的菜单
+ *
+ * @param roles
+ * @param route
+ * @returns {*}
+ */
+// eslint-disable-next-line
+function hasRole(roles, route) {
+ if (route.meta && route.meta.roles) {
+ return route.meta.roles.includes(roles.id)
+ } else {
+ return true
+ }
+}
+
+function filterAsyncRouter (asyncRouterMap) {
+ const accessedRouters = asyncRouterMap.filter(route => {
+ // if (hasPermission(roles.permissionList, route)) {
+ // if (route.children && route.children.length) {
+ // route.children = filterAsyncRouter(route.children)
+ // }
+ // return true
+ // }
+ // if (route.children && route.children.length) {
+ // route.children = filterAsyncRouter(route.children)
+ // }
+ if (route.component) {
+ // Layout ParentView 组件特殊处理
+ if (route.component === 'Layout') {
+ route.component = BasicLayout
+ } else {
+ route.component = RouteView
+ }
+ }
+ if (route.children != null && route.children && route.children.length) {
+ route.children = filterAsyncRouter(route.children)
+ }
+ return true
+ })
+ return accessedRouters
+}
+
+const permission = {
+ state: {
+ routers: constantRouterMap,
+ addRouters: []
+ },
+ mutations: {
+ SET_ROUTERS: (state, routers) => {
+ state.addRouters = routers
+ state.routers = constantRouterMap.concat(routers)
+ }
+ },
+ actions: {
+ GenerateRoutes ({ commit }) {
+ return new Promise(resolve => {
+ getRouters().then(res => {
+ const accessedRoutes = filterAsyncRouter(res.data)
+ // const accessedRoutes = filterAsyncRouter(constantRouterMap)
+ // const accessedRoutes = constantRouterMap
+ // accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
+ commit('SET_ROUTERS', accessedRoutes)
+ resolve(accessedRoutes)
+ })
+ // const { roles } = data
+ // const accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
+ // commit('SET_ROUTERS', accessedRouters)
+ // resolve()
+ })
+ }
+ }
+}
+
+export default permission
diff --git a/hotgo-web/src/store/modules/user.js b/hotgo-web/src/store/modules/user.js
new file mode 100644
index 0000000..9dc6fbb
--- /dev/null
+++ b/hotgo-web/src/store/modules/user.js
@@ -0,0 +1,320 @@
+import storage from 'store'
+import { login, loginBySms, getInfo, logout } from '@/api/login'
+import { ACCESS_TOKEN } from '@/store/mutation-types'
+
+const user = {
+ state: {
+ token: '',
+ name: '',
+ userType: '',
+ welcome: '',
+ avatar: '',
+ roles: [],
+ portalConfigs: [],
+ defaultPortal: {},
+ info: {},
+ platformVersion: '',
+ sysNoticeList: []
+ },
+
+ mutations: {
+ SET_TOKEN: (state, token) => {
+ state.token = token
+ },
+ SET_NAME: (state, name) => {
+ state.name = name
+ },
+ SET_AVATAR: (state, avatar) => {
+ state.avatar = avatar
+ },
+ SET_ROLES: (state, roles) => {
+ state.roles = roles
+ },
+ SET_INFO: (state, info) => {
+ state.info = info
+ },
+ SET_PERMISSIONS: (state, permissions) => {
+ state.permissions = permissions
+ },
+ SET_USER_TYPE: (state, userType) => {
+ state.userType = userType
+ },
+ SET_PORTAL_CONFIG: (state, portalConfigs) => {
+ state.portalConfigs = portalConfigs
+ },
+ SET_DEFAULT_PORTAL: (state, defaultPortal) => {
+ state.defaultPortal = defaultPortal
+ },
+ SET_PLATFORM_VERSION: (state, platformVersion) => {
+ state.platformVersion = platformVersion
+ },
+ SET_NOTICE_LIST: (state, sysNoticeList) => {
+ state.sysNoticeList = sysNoticeList
+ }
+ },
+
+ actions: {
+ // 登录
+ Login({ commit }, userInfo) {
+ return new Promise((resolve, reject) => {
+ login(userInfo).then(res => {
+ storage.set(ACCESS_TOKEN, res.token, 7 * 24 * 60 * 60 * 1000)
+ commit('SET_TOKEN', res.token)
+ resolve()
+ })
+ .catch(error => {
+ reject(error)
+ })
+ })
+ },
+ // 根据验证码登录
+ LoginBySms({ commit }, userInfo) {
+ return new Promise((resolve, reject) => {
+ loginBySms(userInfo).then(res => {
+ storage.set(ACCESS_TOKEN, res.token, 7 * 24 * 60 * 60 * 1000)
+ commit('SET_TOKEN', res.token)
+ resolve()
+ })
+ .catch(error => {
+ reject(error)
+ })
+ })
+ },
+ // 获取用户信息
+ GetInfo({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ getInfo(state.token).then(res => {
+ // eslint-disable-next-line no-unused-vars
+ const res1 = {
+ 'msg': '操作成功',
+ 'code': 200,
+ 'lincenseInfo': null,
+ 'userPortalConfig': [{
+ 'createByName': null,
+ 'createDeptName': null,
+ 'importErrInfo': null,
+ 'id': '73c217ba0fb24945a8faef74eb10d302',
+ 'searchValue': null,
+ 'createBy': null,
+ 'createDept': null,
+ 'createTime': null,
+ 'updateBy': null,
+ 'updateTime': null,
+ 'updateIp': null,
+ 'remark': null,
+ 'version': null,
+ 'delFlag': '0',
+ 'handleType': null,
+ 'params': {},
+ 'name': '首页',
+ 'code': '6c297eb4651940edbb45c87c75be00d7',
+ 'applicationRange': 'U',
+ 'isDefault': 'Y',
+ 'resourceId': '1',
+ 'resourceName': null,
+ 'systemDefinedId': 'app1',
+ 'content': '[{"id":"4ae60dd1debe462096698e1da993317a","x":0,"y":0,"w":3,"h":262,"i":"4ae60dd1debe462096698e1da993317a","key":"kuaijierukou","isShowTitle":"N","isAllowDrag":false,"name":"快捷入口","type":"smallPage","url":"dashboard/portal/CommonUse","options":"{\\"titleRequired\\":true,\\"moreUrl\\":\\"\\",\\"refresh\\":1}","moved":false},{"id":"fd7290c27f644234b38d18faf5d75783","x":0,"y":262,"w":3,"h":1370,"i":"fd7290c27f644234b38d18faf5d75783","key":"todo","isShowTitle":"N","isAllowDrag":true,"name":"待办小页","type":"smallPage","url":"dashboard/portal/ToDo","options":"{\\"titleRequired\\":true,\\"moreUrl\\":\\"\\",\\"refresh\\":1}","moved":false}]',
+ 'sort': null,
+ 'saveType': null,
+ 'status': '0',
+ 'recordLog': true
+ }],
+ 'permissions': ['*:*:*'],
+ 'sysNoticeList': [],
+ 'roles': ['admin'],
+ 'defaultPortalConfig': {
+ 'createByName': null,
+ 'createDeptName': null,
+ 'importErrInfo': null,
+ 'id': '73c217ba0fb24945a8faef74eb10d302',
+ 'searchValue': null,
+ 'createBy': null,
+ 'createDept': null,
+ 'createTime': null,
+ 'updateBy': null,
+ 'updateTime': null,
+ 'updateIp': null,
+ 'remark': null,
+ 'version': null,
+ 'delFlag': '0',
+ 'handleType': null,
+ 'params': {},
+ 'name': '首页',
+ 'code': '6c297eb4651940edbb45c87c75be00d7',
+ 'applicationRange': 'U',
+ 'isDefault': 'Y',
+ 'resourceId': '1',
+ 'resourceName': null,
+ 'systemDefinedId': 'app1',
+ 'content': '[{"id":"4ae60dd1debe462096698e1da993317a","x":0,"y":0,"w":3,"h":262,"i":"4ae60dd1debe462096698e1da993317a","key":"kuaijierukou","isShowTitle":"N","isAllowDrag":false,"name":"快捷入口","type":"smallPage","url":"dashboard/portal/CommonUse","options":"{\\"titleRequired\\":true,\\"moreUrl\\":\\"\\",\\"refresh\\":1}","moved":false},{"id":"fd7290c27f644234b38d18faf5d75783","x":0,"y":262,"w":3,"h":1370,"i":"fd7290c27f644234b38d18faf5d75783","key":"todo","isShowTitle":"N","isAllowDrag":true,"name":"待办小页","type":"smallPage","url":"dashboard/portal/ToDo","options":"{\\"titleRequired\\":true,\\"moreUrl\\":\\"\\",\\"refresh\\":1}","moved":false}]',
+ 'sort': null,
+ 'saveType': null,
+ 'status': '0',
+ 'recordLog': true
+ },
+ 'user': {
+ 'createByName': null,
+ 'createDeptName': null,
+ 'importErrInfo': null,
+ 'id': '1',
+ 'searchValue': null,
+ 'createBy': 'admin',
+ 'createDept': null,
+ 'createTime': '2021-01-30 13:27:43',
+ 'updateBy': null,
+ 'updateTime': null,
+ 'updateIp': null,
+ 'remark': '管理员',
+ 'version': null,
+ 'delFlag': '0',
+ 'handleType': null,
+ 'params': {},
+ 'deptId': '100',
+ 'name': '管理员',
+ 'nameEn': null,
+ 'no': null,
+ 'userName': 'admin',
+ 'nickName': '111',
+ 'userType': '1',
+ 'email': '1125373330@qq.com',
+ 'phonenumber': '1125373330a',
+ 'sex': '1',
+ 'avatar': '/profile/avatar/2021/11/11/2022/01/14/74359886-5bd9-4ad2-99f6-aab2ad85a8bb.jpeg',
+ 'birthday': null,
+ 'nation': null,
+ 'birthAddress': null,
+ 'polity': null,
+ 'title': null,
+ 'officeTel': '029-03456751111',
+ 'fax': null,
+ 'workSpace': null,
+ 'sort': null,
+ 'userPinyin': null,
+ 'salt': null,
+ 'status': '0',
+ 'loginIp': '112.24.62.102',
+ 'loginDate': '2022-01-18 09:56:46',
+ 'sysDept': {
+ 'createByName': null,
+ 'createDeptName': null,
+ 'importErrInfo': null,
+ 'id': '100',
+ 'searchValue': null,
+ 'createBy': null,
+ 'createDept': null,
+ 'createTime': null,
+ 'updateBy': null,
+ 'updateTime': null,
+ 'updateIp': null,
+ 'remark': null,
+ 'version': null,
+ 'delFlag': '0',
+ 'handleType': null,
+ 'params': {},
+ 'parentId': '0',
+ 'parentIds': null,
+ 'treeSort': 10,
+ 'treeSorts': null,
+ 'treeLevel': null,
+ 'treeLeaf': null,
+ 'children': [],
+ 'deptCode': null,
+ 'deptName': '集团',
+ 'leader': '管理员',
+ 'phone': null,
+ 'email': null,
+ 'status': '0',
+ 'deptFullName': null,
+ 'deptType': null,
+ 'address': null,
+ 'zipCode': null,
+ 'deptPinyin': null,
+ 'subtitle': null,
+ 'searchText': null,
+ 'parentName': null,
+ 'parentDeptType': null,
+ 'recordLog': true
+ },
+ 'sysRoles': [{
+ 'createByName': null,
+ 'createDeptName': null,
+ 'importErrInfo': null,
+ 'id': '1',
+ 'searchValue': null,
+ 'createBy': null,
+ 'createDept': null,
+ 'createTime': null,
+ 'updateBy': null,
+ 'updateTime': null,
+ 'updateIp': null,
+ 'remark': null,
+ 'version': null,
+ 'delFlag': null,
+ 'handleType': null,
+ 'params': {},
+ 'roleName': '技术部',
+ 'roleKey': '007',
+ 'sort': '4',
+ 'dataScope': '1',
+ 'menuCheckStrictly': false,
+ 'deptCheckStrictly': false,
+ 'status': '0',
+ 'flag': false,
+ 'menuIds': null,
+ 'deptIds': null,
+ 'codeOrName': null,
+ 'option': null,
+ 'admin': true,
+ 'recordLog': true
+ }],
+ 'roleIds': null,
+ 'postIds': null,
+ 'roleId': null,
+ 'userNameOrName': null,
+ 'admin': true,
+ 'recordLog': true
+ }
+ }
+ const user = res.user
+ const avatar = (user.avatar === '' || user.avatar === null) ? require('@/assets/images/profile.jpg') : user.avatar
+ if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
+ commit('SET_ROLES', res.roles)
+ commit('SET_PERMISSIONS', res.permissions)
+ } else {
+ commit('SET_ROLES', ['ROLE_DEFAULT'])
+ }
+ commit('SET_PORTAL_CONFIG', res.userPortalConfig)
+ commit('SET_DEFAULT_PORTAL', res.defaultPortalConfig)
+ commit('SET_NAME', user.username)
+ commit('SET_AVATAR', avatar)
+ commit('SET_USER_TYPE', user.type)
+ commit('SET_PLATFORM_VERSION', res.lincenseInfo)
+ commit('SET_NOTICE_LIST', res.sysNoticeList ? res.sysNoticeList : [])
+ resolve(res)
+ }).catch(error => {
+ console.log('error:' + error)
+ reject(error)
+ })
+ })
+ },
+
+ // 登出
+ Logout({ commit, state }) {
+ return new Promise((resolve) => {
+ logout(state.token).then(() => {
+ commit('SET_TOKEN', '')
+ commit('SET_ROLES', [])
+ commit('SET_PERMISSIONS', [])
+ storage.remove(ACCESS_TOKEN)
+ resolve()
+ }).catch(() => {
+ resolve()
+ }).finally(() => {
+ })
+ })
+ }
+
+ }
+}
+
+export default user
diff --git a/hotgo-web/src/store/mutation-types.js b/hotgo-web/src/store/mutation-types.js
new file mode 100644
index 0000000..591b69e
--- /dev/null
+++ b/hotgo-web/src/store/mutation-types.js
@@ -0,0 +1,24 @@
+export const ACCESS_TOKEN = 'access_token'
+
+export const SIDEBAR_TYPE = 'sidebar_type'
+export const TOGGLE_MOBILE_TYPE = 'is_mobile'
+export const TOGGLE_NAV_THEME = 'nav_theme'
+export const TOGGLE_LAYOUT = 'layout'
+export const TOGGLE_FIXED_HEADER = 'fixed_header'
+export const TOGGLE_FIXED_SIDEBAR = 'fixed_sidebar'
+export const TOGGLE_CONTENT_WIDTH = 'content_width'
+export const TOGGLE_HIDE_HEADER = 'auto_hide_header'
+export const TOGGLE_COLOR = 'color'
+export const TOGGLE_WEAK = 'weak'
+export const TOGGLE_MULTI_TAB = 'multi_tab'
+export const APP_LANGUAGE = 'app_language'
+
+export const CONTENT_WIDTH_TYPE = {
+ Fluid: 'Fluid',
+ Fixed: 'Fixed'
+}
+
+export const NAV_THEME = {
+ LIGHT: 'light',
+ DARK: 'dark'
+}
diff --git a/hotgo-web/src/utils/aidex.js b/hotgo-web/src/utils/aidex.js
new file mode 100644
index 0000000..c5ba770
--- /dev/null
+++ b/hotgo-web/src/utils/aidex.js
@@ -0,0 +1,269 @@
+import storage from 'store'
+import { ACCESS_TOKEN } from '@/store/mutation-types'
+
+/**
+ * 通用js方法封装处理
+ * Copyright (c) 2019 aidex
+ */
+
+const baseURL = process.env.VUE_APP_BASE_API
+
+// 日期格式化
+export function parseTime (time, pattern) {
+ if (arguments.length === 0 || !time) {
+ return null
+ }
+ const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+ let date
+ if (typeof time === 'object') {
+ date = time
+ } else {
+ if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+ time = parseInt(time)
+ } else if (typeof time === 'string') {
+ time = time.replace(new RegExp(/-/gm), '/')
+ }
+ if ((typeof time === 'number') && (time.toString().length === 10)) {
+ time = time * 1000
+ }
+ date = new Date(time)
+ }
+ const formatObj = {
+ y: date.getFullYear(),
+ m: date.getMonth() + 1,
+ d: date.getDate(),
+ h: date.getHours(),
+ i: date.getMinutes(),
+ s: date.getSeconds(),
+ a: date.getDay()
+ }
+ const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+ let value = formatObj[key]
+ // Note: getDay() returns 0 on Sunday
+ if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+ if (result.length > 0 && value < 10) {
+ value = '0' + value
+ }
+ return value || 0
+ })
+ return timeStr
+}
+
+// 表单重置
+export function resetForm (refName) {
+ if (this[refName]) {
+ this[refName].resetFields()
+ }
+}
+
+// 添加日期范围
+export function addDateRange (params, dateRange, propName) {
+ var search = params
+ // search.params = {}
+ if (dateRange !== null && dateRange !== '' && dateRange.length === 2) {
+ if (typeof (propName) === 'undefined') {
+ search.start_time = dateRange[0]
+ search.end_time = dateRange[1]
+ } else {
+ const startTime = propName + '_start_time'
+ const endTime = propName + '_end_time'
+ search[startTime] = dateRange[0]
+ search[endTime] = dateRange[1]
+ }
+ }
+ return search
+}
+
+// 回显数据字典
+export function selectDictLabel (datas, value) {
+ var actions = []
+ Object.keys(datas).some((key) => {
+ if (datas[key].value === ('' + value)) {
+ actions.push(datas[key].label)
+ return true
+ }
+ })
+ return actions.join('')
+}
+
+// 回显数据字典(字符串数组)
+export function selectDictLabels (datas, value, separator) {
+ var actions = []
+ var currentSeparator = undefined === separator ? ',' : separator
+ var temp = value.split(currentSeparator)
+ Object.keys(value.split(currentSeparator)).some((val) => {
+ Object.keys(datas).some((key) => {
+ if (datas[key].value === ('' + temp[val])) {
+ actions.push(datas[key].label + currentSeparator)
+ }
+ })
+ })
+ return actions.join('').substring(0, actions.join('').length - 1)
+}
+
+// 通用导出下载
+export function exportDownload(path, params) {
+ let url = baseURL + path + '?'
+ params.authorization = storage.get(ACCESS_TOKEN)
+ for (const propName of Object.keys(params)) {
+ const value = params[propName]
+ var part = encodeURIComponent(propName) + '='
+ // 修改漏洞
+ if (value != null && typeof (value) !== 'undefined') {
+ if (typeof value === 'object') {
+ for (const key of Object.keys(value)) {
+ const params = propName + '[' + key + ']'
+ var subPart = encodeURIComponent(params) + '='
+ url += subPart + encodeURIComponent(value[key]) + '&'
+ }
+ } else {
+ url += part + encodeURIComponent(value) + '&'
+ }
+ }
+ }
+ url = url.slice(0, -1)
+ window.location.href = url
+}
+
+// 通用下载方法
+export function download (fileName, delFlag) {
+ if (delFlag === undefined) {
+ delFlag = true
+ }
+ window.location.href = baseURL + '/common/download?fileName=' + encodeURI(fileName) + '&delete=' + delFlag
+}
+// 通用下载方法
+export function downloadByPath (filePath, delFlag) {
+ if (delFlag === undefined) {
+ delFlag = true
+ }
+ window.location.href = baseURL + '/common/downloadByPath?filePath=' + encodeURI(filePath) + '&delete=' + delFlag
+}
+// 通用下载到导出任务中心
+export function downloadTask () {
+ this.$router.push({
+ name: 'SysDownloadFiles',
+ params: {
+ key: new Date().toLocaleString()
+ }
+ })
+}
+
+// 字符串格式化(%s )
+export function sprintf (str) {
+ var args = arguments
+ var flag = true
+ var i = 1
+ str = str.replace(/%s/g, function () {
+ var arg = args[i++]
+ if (typeof arg === 'undefined') {
+ flag = false
+ return ''
+ }
+ return arg
+ })
+ return flag ? str : ''
+}
+
+// 转换字符串,undefined,null等转化为''
+export function praseStrEmpty (str) {
+ if (!str || str === 'undefined' || str === 'null') {
+ return ''
+ }
+ return str
+}
+
+/**
+ * 构造树型结构数据
+ * @param {*} data 数据源
+ * @param {*} id id字段 默认 'id'
+ * @param {*} parentId 父节点字段 默认 'parentId'
+ * @param {*} children 孩子节点字段 默认 'children'
+ * @param {*} rootId 根Id 默认 0
+ */
+export function handleTree (data, id, parentId, children, rootId) {
+ id = id || 'id'
+ parentId = parentId || 'parentId'
+ children = children || 'children'
+ rootId = rootId || '0'
+ // 对源数据深度克隆
+ const cloneData = JSON.parse(JSON.stringify(data))
+ // 循环所有项
+ const treeData = cloneData.filter(father => {
+ var branchArr = cloneData.filter(child => {
+ // 返回每一项的子级数组
+ return father[id] === child[parentId]
+ })
+
+ if (branchArr.length > 0) {
+ father.children = branchArr
+ } else {
+ father.children = ''
+ }
+ // 返回第一层
+ return father[parentId] === rootId
+ })
+ return treeData !== '' && treeData == null ? treeData : data
+}
+/**
+ * 从树中移除指定节点
+ * @param {Object} list
+ * @param {Object} node
+ */
+export function removeTreeNode (list, node) {
+ console.log('node:' + JSON.stringify(node))
+ const parentList = list
+ // const parentIds = node.pid.split('/')
+ const parentIds = node.pid
+ const currentNodeId = node.id
+ deleteTreeNode(parentList, list, parentIds, currentNodeId)
+}
+export function deleteTreeNode (parentList, list, parentIds, currentNodeId) {
+ for (let s = 0; s < list.length; s++) {
+ if (list[s].id === currentNodeId) {
+ list.splice(s, 1)
+ return
+ } else if (list[s].children && list[s].children.length > 0) { // 递归条件
+ // parentIds.splice(0, 1)
+ deleteTreeNode(list[s], list[s].children, parentIds, currentNodeId)
+ } else {
+ continue
+ }
+ }
+}
+export function appendTreeNode (node, data) {
+ // if (node.treeLeaf === 'y') {
+ // // 如果节点是叶子节点则直接改为非叶子节点
+ // node.treeLeaf = 'n'
+ // node.children.push(data)
+ // } else {
+ // const children = node.children
+ // if (children.length > 0) {
+ // // 有子节点则直接push数据,否则不做操作等待异步加载
+ // node.children.push(data)
+ // }
+ // }
+ // console.log('node,' + JSON.stringify(node))
+ // console.log('data,' + JSON.stringify(data))
+ const children = node.children
+ if (children.length > 0) {
+ // 有子节点则直接push数据,否则不做操作等待异步加载
+ node.children.push(data)
+ }
+}
+/**
+ * 按展开几层展开树
+ * @param {Object} nodes
+ * @param {Object} expandLevel
+ * @param {Object} expandedRowKeys 记录展开key
+ */
+export function expandTree (nodes, expandLevel, expandedRowKeys) {
+ if (expandLevel > 1) {
+ // 最后一层不展开
+ nodes.forEach(node => {
+ expandedRowKeys.push(node.id)
+ expandLevel = expandLevel - 1
+ return expandTree(node.children, expandLevel, expandedRowKeys)
+ })
+ }
+}
diff --git a/hotgo-web/src/utils/axios.js b/hotgo-web/src/utils/axios.js
new file mode 100644
index 0000000..3b91f6b
--- /dev/null
+++ b/hotgo-web/src/utils/axios.js
@@ -0,0 +1,35 @@
+const VueAxios = {
+ vm: {},
+ // eslint-disable-next-line no-unused-vars
+ install (Vue, instance) {
+ if (this.installed) {
+ return
+ }
+ this.installed = true
+
+ if (!instance) {
+ // eslint-disable-next-line no-console
+ console.error('You have to install axios')
+ return
+ }
+
+ Vue.axios = instance
+
+ Object.defineProperties(Vue.prototype, {
+ axios: {
+ get: function get () {
+ return instance
+ }
+ },
+ $http: {
+ get: function get () {
+ return instance
+ }
+ }
+ })
+ }
+}
+
+export {
+ VueAxios
+}
diff --git a/hotgo-web/src/utils/domUtil.js b/hotgo-web/src/utils/domUtil.js
new file mode 100644
index 0000000..be93027
--- /dev/null
+++ b/hotgo-web/src/utils/domUtil.js
@@ -0,0 +1,21 @@
+import config from '@/config/defaultSettings'
+
+export const setDocumentTitle = function (title) {
+ document.title = title
+ const ua = navigator.userAgent
+ // eslint-disable-next-line
+ const regex = /\bMicroMessenger\/([\d\.]+)/
+ if (regex.test(ua) && /ip(hone|od|ad)/i.test(ua)) {
+ const i = document.createElement('iframe')
+ i.src = '/favicon.ico'
+ i.style.display = 'none'
+ i.onload = function () {
+ setTimeout(function () {
+ i.remove()
+ }, 9)
+ }
+ document.body.appendChild(i)
+ }
+}
+
+export const domTitle = config.title
diff --git a/hotgo-web/src/utils/drag.js b/hotgo-web/src/utils/drag.js
new file mode 100644
index 0000000..5eeaf9d
--- /dev/null
+++ b/hotgo-web/src/utils/drag.js
@@ -0,0 +1,95 @@
+const draggable = {
+ install (Vue) {
+ Vue.directive('drag', {
+ inserted (el, binding) {
+ if (window.Element && !Element.prototype.closest) {
+ Element.prototype.closest = function (s) {
+ const matches = (this.document || this.ownerDocument).querySelectorAll(s)
+ let i
+ let el = this
+ do {
+ i = matches.length
+ } while (i < 0 && (el = el.parentElement))
+ return el
+ }
+ }
+ let overWin = false // 拖动是否能超出屏幕,默认不能
+ if (binding.value) {
+ overWin = binding.value.over || false
+ }
+
+ const moveTitle = el.parentNode.parentNode.parentNode.querySelector('.ant-modal-header')
+
+ el.style.width = '100%'
+ el.style.height = moveTitle.offsetHeight + 'px'
+ el.style.position = 'absolute'
+ el.style.left = 0
+ el.style.top = 0
+ el.style.cursor = 'move'
+
+ const odiv = el // 获取当前元素操作区
+ const moveDom = el.closest('.ant-modal') // 位移元素,当前只对a-modal生效
+
+ odiv.onmousedown = e => {
+ const moveDomLeft = moveDom.offsetLeft // 位移元素初始横轴位置
+ const moveDomTop = moveDom.offsetTop // 位移元素初始纵轴位置
+ const moveDomW = moveDom.offsetWidth // 位移元素初始宽
+ const moveDomH = moveDom.offsetHeight // 位移元素初始高
+ const winWidth = document.body.clientWidth // 父容器初始宽
+ const winHeight = document.body.clientHeight // 父容器初始高
+
+ // 设置位移元素可移动
+ moveDom.style.position = 'absolute'
+ moveDom.style.top = moveDomTop + 'px'
+ moveDom.style.left = moveDomLeft + 'px'
+
+ // 算出鼠标相对元素的位置
+ const disX = e.clientX
+ const disY = e.clientY
+
+ document.onmousemove = e => {
+ // 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
+ const left = e.clientX - disX // X轴相对位移量
+ const top = e.clientY - disY // Y轴相对位移量
+ let toMoveTop = 0 // 纵轴最终坐标
+ let toMoveLeft = 0 // 横轴最终坐标
+
+ if (!overWin) {
+ // 不可超出屏幕时计算移动边界
+ if (moveDomTop + top + moveDomH > winHeight) {
+ toMoveTop = winHeight - moveDomH
+ } else if (moveDomTop + top < 0) {
+ // 解决漏洞toMoveTop默认为0这里无需重复赋值
+ // toMoveTop = 0
+ } else {
+ toMoveTop = moveDomTop + top
+ }
+ if (moveDomLeft + left < 0) {
+ // 解决漏洞toMoveLeft默认为0这里无需重复赋值
+ // toMoveLeft = 0
+ } else if (moveDomLeft + left + moveDomW > winWidth) {
+ toMoveLeft = winWidth - moveDomW
+ } else {
+ toMoveLeft = moveDomLeft + left
+ }
+ } else {
+ // 让弹窗飞
+ toMoveTop = moveDomTop + top
+ toMoveLeft = moveDomLeft + left
+ }
+
+ // 移动当前元素
+ moveDom.style.top = toMoveTop + 'px'
+ moveDom.style.left = toMoveLeft + 'px'
+ }
+ document.onmouseup = () => {
+ // 注销事件
+ document.onmousemove = null
+ document.onmouseup = null
+ }
+ }
+ }
+ })
+ }
+ }
+export default draggable
diff --git a/hotgo-web/src/utils/errorCode.js b/hotgo-web/src/utils/errorCode.js
new file mode 100644
index 0000000..25ae1d9
--- /dev/null
+++ b/hotgo-web/src/utils/errorCode.js
@@ -0,0 +1,7 @@
+export default {
+ '0': '操作成功!',
+ '401': '认证失败,无法访问系统资源',
+ '403': '当前操作没有权限',
+ '404': '访问资源不存在',
+ 'default': '系统未知错误,请反馈给管理员'
+}
diff --git a/hotgo-web/src/utils/filter.js b/hotgo-web/src/utils/filter.js
new file mode 100644
index 0000000..45702c6
--- /dev/null
+++ b/hotgo-web/src/utils/filter.js
@@ -0,0 +1,20 @@
+import Vue from 'vue'
+import moment from 'moment'
+import 'moment/locale/zh-cn'
+moment.locale('zh-cn')
+
+Vue.filter('NumberFormat', function (value) {
+ if (!value) {
+ return '0'
+ }
+ const intPartFormat = value.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') // 将整数部分逢三一断
+ return intPartFormat
+})
+
+Vue.filter('dayjs', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
+ return moment(dataStr).format(pattern)
+})
+
+Vue.filter('moment', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
+ return moment(dataStr).format(pattern)
+})
diff --git a/hotgo-web/src/utils/highlight.js b/hotgo-web/src/utils/highlight.js
new file mode 100644
index 0000000..c1046c8
--- /dev/null
+++ b/hotgo-web/src/utils/highlight.js
@@ -0,0 +1,29 @@
+// src/utils/highlight.js 文件路径,纯属自定义
+
+// highlight.js 代码高亮指令
+import Hljs from 'highlight.js'
+import 'highlight.js/styles/vs.css' // 代码高亮风格,选择更多风格需导入 node_modules/hightlight.js/styles/ 目录下其它css文件
+
+const Highlight = {}
+// 自定义插件
+Highlight.install = function (Vue) {
+ // 自定义指令 v-highlight
+ Vue.directive('highlight', {
+ // 被绑定元素插入父节点时调用
+ inserted: function (el) {
+ const blocks = el.querySelectorAll('pre code')
+ for (let i = 0; i < blocks.length; i++) {
+ Hljs.highlightBlock(blocks[i])
+ }
+ },
+ // 指令所在组件的 VNode 及其子 VNode 全部更新后调用
+ componentUpdated: function (el) {
+ const blocks = el.querySelectorAll('pre code')
+ for (let i = 0; i < blocks.length; i++) {
+ Hljs.highlightBlock(blocks[i])
+ }
+ }
+ })
+}
+
+export default Highlight
diff --git a/hotgo-web/src/utils/pt/layout/baseMouldStyles.js b/hotgo-web/src/utils/pt/layout/baseMouldStyles.js
new file mode 100644
index 0000000..180758c
--- /dev/null
+++ b/hotgo-web/src/utils/pt/layout/baseMouldStyles.js
@@ -0,0 +1,385 @@
+/**
+ * 控制表单列数布局
+ * @param layout 列布局: 1,2,3,4
+ */
+ const formColLayout = function (layout, colSetting, fixedSetting) {
+ if (layout && layout === '1') {
+ // 1列
+ return {
+ cols: colSetting && colSetting.cols ? colSetting.cols : { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ colSetting && colSetting.labelCol ? colSetting.labelCol : { xs: 6, sm: 6, lg: 6, xl: 6 },
+ wrapperCol:
+ colSetting && colSetting.wrapperCol
+ ? colSetting.wrapperCol
+ : { xs: 18, sm: 18, lg: 18, xl: 18 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ fixedSetting && fixedSetting.labelCol
+ ? fixedSetting.labelCol
+ : { xs: 6, sm: 6, lg: 6, xl: 6 },
+ wrapperCol:
+ fixedSetting && fixedSetting.wrapperCol
+ ? fixedSetting.wrapperCol
+ : { xs: 18, sm: 18, lg: 18, xl: 18 }
+ }
+ }
+ } else if (layout && layout === '2') {
+ // 2列
+ return {
+ cols: colSetting && colSetting.cols ? colSetting.cols : { xs: 12, sm: 12, lg: 12, xl: 12 },
+ labelCol:
+ colSetting && colSetting.labelCol ? colSetting.labelCol : { xs: 8, sm: 8, lg: 8, xl: 8 },
+ wrapperCol:
+ colSetting && colSetting.wrapperCol
+ ? colSetting.wrapperCol
+ : { xs: 16, sm: 16, lg: 16, xl: 16 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ fixedSetting && fixedSetting.labelCol
+ ? fixedSetting.labelCol
+ : { xs: 4, sm: 4, lg: 4, xl: 4 },
+ wrapperCol:
+ fixedSetting && fixedSetting.wrapperCol
+ ? fixedSetting.wrapperCol
+ : { xs: 20, sm: 20, lg: 20, xl: 20 }
+ }
+ }
+ } else if (layout && layout === '3') {
+ // 3列
+ return {
+ cols: colSetting && colSetting.cols ? colSetting.cols : { xs: 8, sm: 8, lg: 8, xl: 8 },
+ labelCol:
+ colSetting && colSetting.labelCol ? colSetting.labelCol : { xs: 9, sm: 9, lg: 9, xl: 9 },
+ wrapperCol:
+ colSetting && colSetting.wrapperCol
+ ? colSetting.wrapperCol
+ : { xs: 15, sm: 15, lg: 15, xl: 15 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ fixedSetting && fixedSetting.labelCol
+ ? fixedSetting.labelCol
+ : { xs: 3, sm: 3, lg: 3, xl: 3 },
+ wrapperCol:
+ fixedSetting && fixedSetting.wrapperCol
+ ? fixedSetting.wrapperCol
+ : { xs: 21, sm: 21, lg: 21, xl: 21 }
+ }
+ }
+ } else if (layout && layout === '4') {
+ // 4列
+ return {
+ cols: colSetting && colSetting.cols ? colSetting.cols : { xs: 6, sm: 6, lg: 6, xl: 6 },
+ labelCol:
+ colSetting && colSetting.labelCol ? colSetting.labelCol : { xs: 8, sm: 8, lg: 8, xl: 8 },
+ wrapperCol:
+ colSetting && colSetting.wrapperCol
+ ? colSetting.wrapperCol
+ : { xs: 16, sm: 16, lg: 16, xl: 16 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ fixedSetting && fixedSetting.labelCol
+ ? fixedSetting.labelCol
+ : { xs: 2, sm: 2, lg: 2, xl: 2 },
+ wrapperCol:
+ fixedSetting && fixedSetting.wrapperCol
+ ? fixedSetting.wrapperCol
+ : { xs: 22, sm: 22, lg: 22, xl: 22 }
+ }
+ }
+ } else {
+ // 默认1列
+ return {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol: { xs: 4, sm: 4, lg: 4, xl: 4 },
+ wrapperCol: { xs: 20, sm: 20, lg: 20, xl: 20 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol: { xs: 4, sm: 4, lg: 4, xl: 4 },
+ wrapperCol: { xs: 20, sm: 20, lg: 20, xl: 20 }
+ }
+ }
+ }
+ }
+
+ /**
+ * 控制详情页表单列数布局
+ * @param layout 列布局: 1,2,3,4
+ */
+ const flowformColLayout = function (layout, colSetting, fixedSetting) {
+ if (layout && layout === '1') {
+ // 1列
+ return {
+ cols: colSetting && colSetting.cols ? colSetting.cols : { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ colSetting && colSetting.labelCol
+ ? colSetting.labelCol
+ : { xs: 22, sm: 22, lg: 22, xl: 22 },
+ wrapperCol:
+ colSetting && colSetting.wrapperCol
+ ? colSetting.wrapperCol
+ : { xs: 22, sm: 22, lg: 22, xl: 22 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ fixedSetting && fixedSetting.labelCol
+ ? fixedSetting.labelCol
+ : { xs: 24, sm: 24, lg: 24, xl: 24 },
+ wrapperCol:
+ fixedSetting && fixedSetting.wrapperCol
+ ? fixedSetting.wrapperCol
+ : { xs: 20, sm: 20, lg: 20, xl: 20 }
+ }
+ }
+ } else if (layout && layout === '2') {
+ // 2列
+ return {
+ cols: colSetting && colSetting.cols ? colSetting.cols : { xs: 12, sm: 12, lg: 12, xl: 12 },
+ labelCol:
+ colSetting && colSetting.labelCol ? colSetting.labelCol : { xs: 6, sm: 6, lg: 6, xl: 6 },
+ wrapperCol:
+ colSetting && colSetting.wrapperCol
+ ? colSetting.wrapperCol
+ : { xs: 18, sm: 18, lg: 18, xl: 18 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ fixedSetting && fixedSetting.labelCol
+ ? fixedSetting.labelCol
+ : { xs: 3, sm: 3, lg: 3, xl: 3 },
+ wrapperCol:
+ fixedSetting && fixedSetting.wrapperCol
+ ? fixedSetting.wrapperCol
+ : { xs: 21, sm: 21, lg: 21, xl: 21 }
+ }
+ }
+ } else if (layout && layout === '3') {
+ // 3列
+ return {
+ cols: colSetting && colSetting.cols ? colSetting.cols : { xs: 8, sm: 8, lg: 8, xl: 8 },
+ labelCol:
+ colSetting && colSetting.labelCol ? colSetting.labelCol : { xs: 6, sm: 6, lg: 6, xl: 6 },
+ wrapperCol:
+ colSetting && colSetting.wrapperCol
+ ? colSetting.wrapperCol
+ : { xs: 18, sm: 18, lg: 18, xl: 18 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ fixedSetting && fixedSetting.labelCol
+ ? fixedSetting.labelCol
+ : { xs: 2, sm: 2, lg: 2, xl: 2 },
+ wrapperCol:
+ fixedSetting && fixedSetting.wrapperCol
+ ? fixedSetting.wrapperCol
+ : { xs: 22, sm: 22, lg: 22, xl: 22 }
+ }
+ }
+ } else if (layout && layout === '4') {
+ // 4列
+ return {
+ cols: colSetting && colSetting.cols ? colSetting.cols : { xs: 6, sm: 6, lg: 6, xl: 6 },
+ labelCol:
+ colSetting && colSetting.labelCol
+ ? colSetting.labelCol
+ : { xs: 24, sm: 24, lg: 24, xl: 24 },
+ wrapperCol:
+ colSetting && colSetting.wrapperCol
+ ? colSetting.wrapperCol
+ : { xs: 24, sm: 24, lg: 24, xl: 24 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol:
+ fixedSetting && fixedSetting.labelCol
+ ? fixedSetting.labelCol
+ : { xs: 24, sm: 24, lg: 24, xl: 24 },
+ wrapperCol:
+ fixedSetting && fixedSetting.wrapperCol
+ ? fixedSetting.wrapperCol
+ : { xs: 24, sm: 24, lg: 24, xl: 24 }
+ }
+ }
+ } else {
+ // 默认1列
+ return {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol: { xs: 4, sm: 4, lg: 4, xl: 4 },
+ wrapperCol: { xs: 20, sm: 20, lg: 20, xl: 20 },
+ fixed: {
+ cols: { xs: 24, sm: 24, lg: 24, xl: 24 },
+ labelCol: { xs: 4, sm: 4, lg: 4, xl: 4 },
+ wrapperCol: { xs: 20, sm: 20, lg: 20, xl: 20 }
+ }
+ }
+ }
+ }
+ /**
+ * 控制弹窗modal的宽高
+ * @param widthRatio 弹窗modal宽度占屏幕比例
+ * @param heightRatio 弹窗modal高度占屏幕比例
+ * @param cutHeight 弹窗modal的body的高度比整个弹窗modal少的高度
+ * @param bodyOverflowY 弹窗modal的body的overflow-y属性
+ */
+ const modalWidthAndHeight = function (
+ widthRatio = 0.7,
+ heightRatio = 0.7,
+ cutHeight = 40,
+ bodyOverflowY = 'auto',
+ backgroundColor = '#fff'
+ ) {
+ const modalStyleWidth = document.documentElement.clientWidth * widthRatio + 'px'
+ // let modalStyleHeight = document.documentElement.clientHeight * heightRatio + 'px';
+ const bodyStyleWidth = document.documentElement.clientWidth * widthRatio + 'px'
+ const bodyStyleHeight = document.documentElement.clientHeight * heightRatio - cutHeight + 'px'
+ return {
+ modalStyle: {
+ // 弹窗宽高控制
+ width: modalStyleWidth,
+ height: 'auto'
+ },
+ bodyStyle: {
+ // 弹窗body宽高控制
+ width: bodyStyleWidth,
+ height: bodyStyleHeight,
+ overflowY: bodyOverflowY,
+ backgroundColor
+ }
+ }
+ }
+ /**
+ * 根据布局列数控制弹窗modal的宽高
+ * (单列: 580*420 适用于1~6项内容时、
+ * 两列:960*500 适用于6~12项内容时、
+ * 三列:1280*600) 适用于12项以上
+ * @param layout 列数
+ * @param cutHeight 弹窗modal的body的高度比整个弹窗modal少的高度
+ * @param bodyOverflowY 弹窗modal的body的overflow-y属性
+ */
+ const modalWidthAndHeightBylayout = function (
+ layout = 1,
+ cutHeight = 40,
+ bodyOverflowY = 'auto',
+ backgroundColor = '#fff'
+ ) {
+ let modalStyleWidth = null
+ // let modalStyleHeight = document.documentElement.clientHeight * heightRatio + 'px';
+ let bodyStyleWidth = null
+ let bodyStyleHeight = null
+ let bodyStylePadding = null
+ if (layout === 1) {
+ modalStyleWidth = 580 + 'px'
+ bodyStyleWidth = 580 + 'px'
+ bodyStyleHeight = 420 - cutHeight + 'px'
+ bodyStylePadding = '20px 50px'
+ } else if (layout === 2) {
+ modalStyleWidth = 960 + 'px'
+ bodyStyleWidth = 960 + 'px'
+ bodyStyleHeight = 500 - cutHeight + 'px'
+ bodyStylePadding = '20px'
+ } else if (layout === 3) {
+ modalStyleWidth = 1280 + 'px'
+ bodyStyleWidth = 1280 + 'px'
+ bodyStyleHeight = 600 - cutHeight + 'px'
+ bodyStylePadding = '20px 40px'
+ }
+ return {
+ modalStyle: {
+ // 弹窗宽高控制
+ width: modalStyleWidth,
+ height: 'auto'
+ },
+ bodyStyle: {
+ // 弹窗body宽高控制
+ width: bodyStyleWidth,
+ height: bodyStyleHeight,
+ padding: bodyStylePadding,
+ overflowY: bodyOverflowY,
+ backgroundColor
+ }
+ }
+ }
+ /**
+ * 获取内容高度: 传入元素的父元素高度 - 父元素除去内容之外的元素的高度
+ * @param wrapId 元素的id
+ * @param cutHeight 内容与父元素相差的高度,一般包括:父元素padding,按钮高度及margin,及其他
+ */
+ const getContentHeight = function (params) {
+ // 默认值auto
+ let contentHeight = 'auto'
+ if (params) {
+ // 获取元素父元素
+ const el = document.querySelector('#' + params.wrapId)
+ if (el) {
+ // 获取父元素高度
+ const parentHeight = el.parentNode.offsetHeight
+ // 传入的元素高度设为父元素高度
+ // el.style.height = parentHeight + 'px'; 为加resize改变大小,注释掉这句.
+ // 内容高度为 父元素高度 减去 父元素除去内容之外的元素的高度
+ if (params.cutHeight) {
+ contentHeight = parentHeight - params.cutHeight + 'px'
+ } else {
+ contentHeight = parentHeight + 'px'
+ }
+ }
+ }
+ return contentHeight
+ }
+
+ /**
+ * 校验不通过,滚动到校验不通过元素位置,提示用户
+ */
+ const getFirstCheckErrorElement = function (err) {
+ for (const key in err) {
+ // return document.querySelector("div[for='" + key + "']") || document.querySelector("div[for='" + key + "Alias']") || document.querySelector("div[for='" + key + "Name']");
+ return document.querySelector('#' + key)
+ }
+ }
+ const appointModalWidthAndHeight = function (
+ height,
+ width,
+ cutHeight,
+ bodyOverflowY = 'auto',
+ backgroundColor = '#fff'
+ ) {
+ let modalStyleWidth
+ let bodyStyleWidth
+ let bodyStyleHeight
+ if (width === '100%' && height === '100%') {
+ // 全屏模式
+ modalStyleWidth = document.documentElement.clientWidth + 'px'
+ bodyStyleWidth = document.documentElement.clientWidth + 'px'
+ bodyStyleHeight = document.documentElement.clientHeight - cutHeight + 'px'
+ } else {
+ // 指定宽高
+ modalStyleWidth = width + 'px'
+ bodyStyleWidth = width + 'px'
+ bodyStyleHeight = height - cutHeight + 'px'
+ }
+ return {
+ modalStyle: {
+ // 弹窗宽高控制
+ width: modalStyleWidth,
+ height: 'auto'
+ },
+ bodyStyle: {
+ // 弹窗body宽高控制
+ width: bodyStyleWidth,
+ height: bodyStyleHeight,
+ overflowY: bodyOverflowY,
+ backgroundColor
+ }
+ }
+ }
+ export {
+ formColLayout,
+ flowformColLayout,
+ modalWidthAndHeight,
+ modalWidthAndHeightBylayout,
+ getContentHeight,
+ getFirstCheckErrorElement,
+ appointModalWidthAndHeight
+ }
diff --git a/hotgo-web/src/utils/request.js b/hotgo-web/src/utils/request.js
new file mode 100644
index 0000000..d2b4bf4
--- /dev/null
+++ b/hotgo-web/src/utils/request.js
@@ -0,0 +1,136 @@
+import axios from 'axios'
+import store from '@/store'
+import storage from 'store'
+import notification from 'ant-design-vue/es/notification'
+import { VueAxios } from './axios'
+import { ACCESS_TOKEN } from '@/store/mutation-types'
+import errorCode from '@/utils/errorCode'
+
+// 创建 axios 实例
+const request = axios.create({
+ // API 请求的默认前缀
+ baseURL: process.env.VUE_APP_BASE_API,
+ // baseURL: 'https://aidex.setworld.net',
+ timeout: 20000 // 请求超时时间
+})
+
+// 异常拦截处理器
+const errorHandler = (error) => {
+ console.log('err' + error)
+ let { message } = error
+ if (message === 'Network Error') {
+ message = '后端接口连接异常'
+ } else if (message.includes('timeout')) {
+ message = '系统接口请求超时'
+ } else if (message.includes('Request failed with status code')) {
+ message = '系统接口' + message.substr(message.length - 3) + '异常'
+ }
+ notification.error({
+ message: message,
+ duration: 5
+ })
+ // return Promise.reject(error) //注释该行,否则接口请求失败会一直请求刷新错误数据,这里保证请求一次
+}
+
+// request interceptor
+request.interceptors.request.use(config => {
+ const token = storage.get(ACCESS_TOKEN)
+ // 如果 token 存在
+ // 让每个请求携带自定义 token 请根据实际情况自行修改
+ if (token) {
+ config.headers['Authorization'] = 'Bearer ' + token // 让每个请求携带自定义token 请根据实际情况自行修改
+ // config.headers['accessAccess-Token'] = token
+ }
+ // get请求映射params参数
+ if (config.method === 'get' && config.params) {
+ let url = config.url + '?'
+ for (const propName of Object.keys(config.params)) {
+ const value = config.params[propName]
+ var part = encodeURIComponent(propName) + '='
+ // 修改漏洞
+ if (value != null && typeof (value) !== 'undefined') {
+ if (typeof value === 'object') {
+ for (const key of Object.keys(value)) {
+ const params = propName + '[' + key + ']'
+ var subPart = encodeURIComponent(params) + '='
+ url += subPart + encodeURIComponent(value[key]) + '&'
+ }
+ } else {
+ url += part + encodeURIComponent(value) + '&'
+ }
+ }
+ }
+ url = url.slice(0, -1)
+ config.params = {}
+ config.url = url
+ }
+ return config
+}, errorHandler)
+
+// response interceptor
+request.interceptors.response.use((res) => {
+ // 请求rul
+ const requestUrl = res.config.url
+ // 未设置状态码则默认成功状态
+ const code = res.data.code || 0
+ // 获取错误信息
+ const msg = errorCode[code] || res.data.message || errorCode['default']
+
+ if (code === 401) {
+ notification.open({
+ key: 'loginExpireTip',
+ message: '系统提示',
+ description: '登录状态已过期,请重新登录',
+ btn: h => {
+ return h(
+ 'a-button',
+ {
+ props: {
+ type: 'primary',
+ size: 'small'
+ },
+ on: {
+ click: () => {
+ store.dispatch('Logout').then(() => {
+ location.href = '/index'
+ })
+ }
+ }
+ },
+ '确认'
+ )
+ },
+ duration: 0,
+ onClose: close
+ })
+ } else if (code === 500) {
+ if (requestUrl !== '/login') {
+ notification.error({
+ message: msg,
+ description: msg
+ })
+ }
+ } else if (code !== 0) {
+ notification.error({
+ message: msg,
+ duration: 5
+ })
+ } else {
+ return res.data.data
+ }
+ return Promise.reject(msg)
+}, errorHandler)
+
+const installer = {
+ vm: {},
+ install(Vue) {
+ Vue.use(VueAxios, request)
+ }
+}
+
+export default request
+
+export {
+ installer as VueAxios,
+ request as axios
+}
diff --git a/hotgo-web/src/utils/requireIcons.js b/hotgo-web/src/utils/requireIcons.js
new file mode 100644
index 0000000..2705e95
--- /dev/null
+++ b/hotgo-web/src/utils/requireIcons.js
@@ -0,0 +1,9 @@
+const req = require.context('../assets/icons', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys()
+const re = /\.\/(.*)\.svg/
+
+const icons = requireAll(req).map(i => {
+ return i.match(re)[1]
+})
+
+export default icons
diff --git a/hotgo-web/src/utils/routeConvert.js b/hotgo-web/src/utils/routeConvert.js
new file mode 100644
index 0000000..e88b0d6
--- /dev/null
+++ b/hotgo-web/src/utils/routeConvert.js
@@ -0,0 +1,30 @@
+import cloneDeep from 'lodash.clonedeep'
+
+export function convertRoutes (nodes) {
+ if (!nodes) return null
+
+ nodes = cloneDeep(nodes)
+
+ let queue = Array.isArray(nodes) ? nodes.concat() : [nodes]
+
+ while (queue.length) {
+ const levelSize = queue.length
+
+ for (let i = 0; i < levelSize; i++) {
+ const node = queue.shift()
+
+ if (!node.children || !node.children.length) continue
+
+ node.children.forEach(child => {
+ // 转化相对路径
+ if (child.path[0] !== '/' && !child.path.startsWith('http')) {
+ child.path = node.path.replace(/(\w*)[/]*$/, `$1/${child.path}`)
+ }
+ })
+
+ queue = queue.concat(node.children)
+ }
+ }
+
+ return nodes
+}
diff --git a/hotgo-web/src/utils/screenLog.js b/hotgo-web/src/utils/screenLog.js
new file mode 100644
index 0000000..3a77da7
--- /dev/null
+++ b/hotgo-web/src/utils/screenLog.js
@@ -0,0 +1,5 @@
+/* eslint-disable */
+export const printANSI = () => {
+ // console.clear()
+ // 这里可以配置首次加载输出到控制台的brand
+}
diff --git a/hotgo-web/src/utils/util.js b/hotgo-web/src/utils/util.js
new file mode 100644
index 0000000..67a57e9
--- /dev/null
+++ b/hotgo-web/src/utils/util.js
@@ -0,0 +1,128 @@
+export function timeFix () {
+ const time = new Date()
+ const hour = time.getHours()
+ return hour < 9 ? '早上好' : hour <= 11 ? '上午好' : hour <= 13 ? '中午好' : hour < 20 ? '下午好' : '晚上好'
+}
+
+export function welcome () {
+ const arr = ['休息一会儿吧', '准备吃什么呢?', '要不要打一把 DOTA', '我猜你可能累了']
+ const index = Math.floor(Math.random() * arr.length)
+ return arr[index]
+}
+
+/**
+ * 触发 window.resize
+ */
+export function triggerWindowResizeEvent () {
+ const event = document.createEvent('HTMLEvents')
+ event.initEvent('resize', true, true)
+ event.eventType = 'message'
+ window.dispatchEvent(event)
+}
+
+export function handleScrollHeader (callback) {
+ let timer = 0
+
+ let beforeScrollTop = window.pageYOffset
+ callback = callback || function () {}
+ window.addEventListener(
+ 'scroll',
+ event => {
+ clearTimeout(timer)
+ timer = setTimeout(() => {
+ let direction = 'up'
+ const afterScrollTop = window.pageYOffset
+ const delta = afterScrollTop - beforeScrollTop
+ if (delta === 0) {
+ return false
+ }
+ direction = delta > 0 ? 'down' : 'up'
+ callback(direction)
+ beforeScrollTop = afterScrollTop
+ }, 50)
+ },
+ false
+ )
+}
+
+export function isIE () {
+ const bw = window.navigator.userAgent
+ const compare = (s) => bw.indexOf(s) >= 0
+ const ie11 = (() => 'ActiveXObject' in window)()
+ return compare('MSIE') || ie11
+}
+
+/**
+ * Remove loading animate
+ * @param id parent element id or class
+ * @param timeout
+ */
+export function removeLoadingAnimate (id = '', timeout = 1500) {
+ if (id === '') {
+ return
+ }
+ setTimeout(() => {
+ document.body.removeChild(document.getElementById(id))
+ }, timeout)
+}
+
+/**
+ * 随机生成数字
+ * @param min 最小值
+ * @param max 最大值
+ * @return int 生成后的数字
+ */
+export function randomNumber (min, max) {
+ return Math.floor(Math.random() * (max - min + 1) + min)
+}
+
+/**
+ * 随机生成字符串
+ * @param length 字符串的长度
+ * @param chats 可选字符串区间(只会生成传入的字符串中的字符)
+ * @return string 生成的字符串
+ */
+export function randomString (length, chats) {
+ if (!length) length = 1
+ if (!chats) chats = '0123456789qwertyuioplkjhgfdsazxcvbnm'
+ let str = ''
+ for (let i = 0; i < length; i++) {
+ const num = randomNumber(0, chats.length - 1)
+ str += chats[num]
+ }
+ return str
+}
+
+/**
+ * 随机生成uuid
+ * @return string 生成的uuid
+ */
+export function randomUUID () {
+ const chats = '0123456789abcdef'
+ return randomString(32, chats)
+}
+/**
+ * json对象单层,转换url参数
+ * @param {*} paramObj
+ */
+export function formateObjToParamStr (paramObj) {
+ const sdata = []
+ for (const attr in paramObj) {
+ sdata.push(`${attr} = ${filter(paramObj[attr])}`)
+ }
+ return sdata.join('&')
+}
+// 过滤特殊符号
+function filter (str) {
+ // 特殊字符转义
+ str += '' // 隐式转换
+ str = str.replace(/%/g, '%25')
+ str = str.replace(/\+/g, '%2B')
+ str = str.replace(/ /g, '%20')
+ str = str.replace(/\//g, '%2F')
+ str = str.replace(/\?/g, '%3F')
+ str = str.replace(/&/g, '%26')
+ str = str.replace(/=/g, '%3D')
+ str = str.replace(/#/g, '%23')
+ return str
+}
diff --git a/hotgo-web/src/utils/utils.less b/hotgo-web/src/utils/utils.less
new file mode 100644
index 0000000..ba75a67
--- /dev/null
+++ b/hotgo-web/src/utils/utils.less
@@ -0,0 +1,50 @@
+.textOverflow() {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ word-break: break-all;
+}
+
+.textOverflowMulti(@line: 3, @bg: #fff) {
+ position: relative;
+ max-height: @line * 1.5em;
+ margin-right: -1em;
+ padding-right: 1em;
+ overflow: hidden;
+ line-height: 1.5em;
+ text-align: justify;
+ &::before {
+ position: absolute;
+ right: 14px;
+ bottom: 0;
+ padding: 0 1px;
+ background: @bg;
+ content: '...';
+ }
+ &::after {
+ position: absolute;
+ right: 14px;
+ width: 1em;
+ height: 1em;
+ margin-top: 0.2em;
+ background: white;
+ content: '';
+ }
+}
+
+// mixins for clearfix
+// ------------------------
+.clearfix() {
+ zoom: 1;
+ &::before,
+ &::after {
+ display: table;
+ content: ' ';
+ }
+ &::after {
+ clear: both;
+ height: 0;
+ font-size: 0;
+ visibility: hidden;
+ }
+}
\ No newline at end of file
diff --git a/hotgo-web/src/utils/validate.js b/hotgo-web/src/utils/validate.js
new file mode 100644
index 0000000..70460b9
--- /dev/null
+++ b/hotgo-web/src/utils/validate.js
@@ -0,0 +1,83 @@
+/**
+ * @param {string} path
+ * @returns {Boolean}
+ */
+export function isExternal (path) {
+ return /^(https?:|mailto:|tel:)/.test(path)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUsername (str) {
+ const validMap = ['admin', 'editor']
+ return validMap.indexOf(str.trim()) >= 0
+}
+
+/**
+ * @param {string} url
+ * @returns {Boolean}
+ */
+export function validURL (url) {
+ const reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~/])+$/
+ return reg.test(url)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validLowerCase (str) {
+ const reg = /^[a-z]+$/
+ return reg.test(str)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUpperCase (str) {
+ const reg = /^[A-Z]+$/
+ return reg.test(str)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validAlphabets (str) {
+ const reg = /^[A-Za-z]+$/
+ return reg.test(str)
+}
+
+/**
+ * @param {string} email
+ * @returns {Boolean}
+ */
+export function validEmail (email) {
+ const reg = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+ return reg.test(email)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function isString (str) {
+ if (typeof str === 'string' || str instanceof String) {
+ return true
+ }
+ return false
+}
+
+/**
+ * @param {Array} arg
+ * @returns {Boolean}
+ */
+export function isArray (arg) {
+ if (typeof Array.isArray === 'undefined') {
+ return Object.prototype.toString.call(arg) === '[object Array]'
+ }
+ return Array.isArray(arg)
+}
diff --git a/hotgo-web/src/utils/zipdownload.js b/hotgo-web/src/utils/zipdownload.js
new file mode 100644
index 0000000..8e8f165
--- /dev/null
+++ b/hotgo-web/src/utils/zipdownload.js
@@ -0,0 +1,42 @@
+import axios from 'axios'
+import storage from 'store'
+import { ACCESS_TOKEN } from '@/store/mutation-types'
+
+const mimeMap = {
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ zip: 'application/zip'
+}
+
+const baseUrl = process.env.VUE_APP_BASE_API
+export function downLoadZip (str, filename) {
+ var url = baseUrl + str
+ axios({
+ method: 'get',
+ url: url,
+ responseType: 'blob',
+ headers: { 'Authorization': 'Bearer ' + storage.get(ACCESS_TOKEN) }
+ }).then(res => {
+ resolveBlob(res, mimeMap.zip)
+ })
+}
+/**
+ * 解析blob响应内容并下载
+ * @param {*} res blob响应内容
+ * @param {String} mimeType MIME类型
+ */
+export function resolveBlob (res, mimeType) {
+ const aLink = document.createElement('a')
+ var blob = new Blob([res.data], { type: mimeType })
+ // //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
+ var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
+ var contentDisposition = decodeURI(res.headers['content-disposition'])
+ var result = patt.exec(contentDisposition)
+ console.log(result)
+ var fileName = result[1]
+ fileName = fileName.replace(/"/g, '')
+ aLink.href = URL.createObjectURL(blob)
+ aLink.setAttribute('download', fileName) // 设置下载文件名称
+ document.body.appendChild(aLink)
+ aLink.click()
+ document.body.removeChild(aLink)
+}
diff --git a/hotgo-web/src/views/404.vue b/hotgo-web/src/views/404.vue
new file mode 100644
index 0000000..8c1d8a1
--- /dev/null
+++ b/hotgo-web/src/views/404.vue
@@ -0,0 +1,15 @@
+
+
+ 404 page
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/center/index.vue b/hotgo-web/src/views/account/center/index.vue
new file mode 100644
index 0000000..5991e8e
--- /dev/null
+++ b/hotgo-web/src/views/account/center/index.vue
@@ -0,0 +1,277 @@
+
+
+
+
+
+
+
+
+
+
{{ user.userName }}
+
{{ roleGroup }}
+
+
+
+ {{ user.phonenumber }}
+
+
+ {{ user.email }}
+
+
+ {{ user.dept.deptName }} / {{ postGroup }}
+
+
+ {{ user.createTime }}
+
+
+
+
+
+
+
+
+
+ handleTabChange(key, 'noTitleKey')"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/center/page/App.vue b/hotgo-web/src/views/account/center/page/App.vue
new file mode 100644
index 0000000..b618416
--- /dev/null
+++ b/hotgo-web/src/views/account/center/page/App.vue
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/center/page/Article.vue b/hotgo-web/src/views/account/center/page/Article.vue
new file mode 100644
index 0000000..508c36c
--- /dev/null
+++ b/hotgo-web/src/views/account/center/page/Article.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ {{ item.title }}
+
+
+ Ant Design
+ 设计语言
+ 蚂蚁金服
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/center/page/Project.vue b/hotgo-web/src/views/account/center/page/Project.vue
new file mode 100644
index 0000000..8cac067
--- /dev/null
+++ b/hotgo-web/src/views/account/center/page/Project.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/center/page/index.js b/hotgo-web/src/views/account/center/page/index.js
new file mode 100644
index 0000000..b579b6a
--- /dev/null
+++ b/hotgo-web/src/views/account/center/page/index.js
@@ -0,0 +1,5 @@
+import AppPage from './App'
+import ArticlePage from './Article'
+import ProjectPage from './Project'
+
+export { AppPage, ArticlePage, ProjectPage }
diff --git a/hotgo-web/src/views/account/settings/AvatarModal.vue b/hotgo-web/src/views/account/settings/AvatarModal.vue
new file mode 100644
index 0000000..19279f6
--- /dev/null
+++ b/hotgo-web/src/views/account/settings/AvatarModal.vue
@@ -0,0 +1,201 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 选择图片
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/settings/BaseSetting.vue b/hotgo-web/src/views/account/settings/BaseSetting.vue
new file mode 100644
index 0000000..d265345
--- /dev/null
+++ b/hotgo-web/src/views/account/settings/BaseSetting.vue
@@ -0,0 +1,222 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 男
+ 女
+
+
+
+ 保存
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/settings/Security.vue b/hotgo-web/src/views/account/settings/Security.vue
new file mode 100644
index 0000000..da0587e
--- /dev/null
+++ b/hotgo-web/src/views/account/settings/Security.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/settings/UpdataPass.vue b/hotgo-web/src/views/account/settings/UpdataPass.vue
new file mode 100644
index 0000000..66f6d61
--- /dev/null
+++ b/hotgo-web/src/views/account/settings/UpdataPass.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/settings/UpdatePassword.vue b/hotgo-web/src/views/account/settings/UpdatePassword.vue
new file mode 100644
index 0000000..2249729
--- /dev/null
+++ b/hotgo-web/src/views/account/settings/UpdatePassword.vue
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/account/settings/index.vue b/hotgo-web/src/views/account/settings/index.vue
new file mode 100644
index 0000000..eedbcc8
--- /dev/null
+++ b/hotgo-web/src/views/account/settings/index.vue
@@ -0,0 +1,312 @@
+
+
+
+
+
+
+
+
+
+
+
{{ user.username }}
+
{{ roleGroup }}
+
+
+
+ {{ user.mobile }}
+
+
+ {{ user.email }}
+
+
+ {{ user.sysDept.name }}
+
+
+ {{ user.created_at }}
+
+
+
+
+
+
+
+
+
+
+
+
+ handleTabChange(key, 'noTitleKey')"
+ >
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/applyLicense/ApplyLicense.vue b/hotgo-web/src/views/applyLicense/ApplyLicense.vue
new file mode 100644
index 0000000..e69de29
diff --git a/hotgo-web/src/views/dashboard/images/QQCode.png b/hotgo-web/src/views/dashboard/images/QQCode.png
new file mode 100644
index 0000000..22f2a74
Binary files /dev/null and b/hotgo-web/src/views/dashboard/images/QQCode.png differ
diff --git a/hotgo-web/src/views/dashboard/images/banner1.png b/hotgo-web/src/views/dashboard/images/banner1.png
new file mode 100644
index 0000000..9f69f5a
Binary files /dev/null and b/hotgo-web/src/views/dashboard/images/banner1.png differ
diff --git a/hotgo-web/src/views/dashboard/images/banner2.png b/hotgo-web/src/views/dashboard/images/banner2.png
new file mode 100644
index 0000000..9f69f5a
Binary files /dev/null and b/hotgo-web/src/views/dashboard/images/banner2.png differ
diff --git a/hotgo-web/src/views/dashboard/images/img02.png b/hotgo-web/src/views/dashboard/images/img02.png
new file mode 100644
index 0000000..dd1a2e2
Binary files /dev/null and b/hotgo-web/src/views/dashboard/images/img02.png differ
diff --git a/hotgo-web/src/views/dashboard/images/img03.png b/hotgo-web/src/views/dashboard/images/img03.png
new file mode 100644
index 0000000..cbc90b5
Binary files /dev/null and b/hotgo-web/src/views/dashboard/images/img03.png differ
diff --git a/hotgo-web/src/views/dashboard/images/wxCode.png b/hotgo-web/src/views/dashboard/images/wxCode.png
new file mode 100644
index 0000000..30f205b
Binary files /dev/null and b/hotgo-web/src/views/dashboard/images/wxCode.png differ
diff --git a/hotgo-web/src/views/dashboard/index.vue b/hotgo-web/src/views/dashboard/index.vue
new file mode 100644
index 0000000..18140ee
--- /dev/null
+++ b/hotgo-web/src/views/dashboard/index.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
diff --git a/hotgo-web/src/views/dashboard/portal/About.vue b/hotgo-web/src/views/dashboard/portal/About.vue
new file mode 100644
index 0000000..f3c4ce7
--- /dev/null
+++ b/hotgo-web/src/views/dashboard/portal/About.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 基于若依-ruoyi-vue项目扩展,前端采用Ant-Design-VUE,代码易读易懂、界面简洁美观,不仅仅是一个后台开发框架,它是一个企业级快速开发解决方案,我们将把UI交互、快速开发能力追求到极致,适配国产数据库,国产中间件,将支持多租户、flowable工作流,移动APP,更多插件正在扩展中
+
+
+ 当前版本:V3.0(后台与ruoyi-vue定期同步)
+
+
+
+
+
+
+ 访问AiDex
+
+
+
+
+ 我的B站
+
+
+
+
+ 访问若依
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/dashboard/portal/CommonUse.vue b/hotgo-web/src/views/dashboard/portal/CommonUse.vue
new file mode 100644
index 0000000..09323e2
--- /dev/null
+++ b/hotgo-web/src/views/dashboard/portal/CommonUse.vue
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/dashboard/portal/ToDo.vue b/hotgo-web/src/views/dashboard/portal/ToDo.vue
new file mode 100644
index 0000000..7b591d5
--- /dev/null
+++ b/hotgo-web/src/views/dashboard/portal/ToDo.vue
@@ -0,0 +1,837 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item }}
+
+
+ 后端
+
+
+
+
+
+
+
+
+ {{ item }}
+
+
+ 前端
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 【1】
+ 接AiDex Sharp系列架构的定制服务
+
+
+
+
+
+
+ 【2】
+ 接3个月以内工期的vue、springboot、springcloud、app、小程序等软件定制服务
+
+
+
+
+
+
+ 【3】
+ UI原型页面设计及切图服务
+
+
+
+
+
+
+ 【4】
+ 有意向请联系唯一指定联系人:皮皮大刺猬(右侧扫码)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 皮皮大刺猬
+
+
+ Some contents...
+ Some contents...
+ Some contents...
+
+
+
+ QQ号:
+ 1125373330
+
+
+ QQ群:
+ 208511180
+
+
+ 微信号:
+ big-hebgehog
+
+
+ 我的特长:
+ 专业UI设计(5年+)+VUE前端功能开发(3年+)
+
+
+ 项目:
+ 若依-Adiex Sharp快速开发平台
+
+
+
+
+
+
+
微信
+
+
+
+
+
+
QQ
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+ {{ item.data }}
+
+
+
+
+
+
+
+ {{ item.state }}
+ {{ item.txt }}
+
+
+ {{ item.hint }}
+
+
+
+ 办理
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
最近使用
+
+
+
+
+
+ {{ item.con }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item }}
+
+
+ 组件使用方法
+
+
+
+
+
+
+ {{ item }}
+
+
+ 组件使用方法
+
+
+
+
+
+
+ {{ item }}
+
+
+ 组件使用方法
+
+
+
+
+
+
+ {{ item }}
+
+
+ 组件使用方法
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.state }}{{ item.title }}
+
+
+
+ 更多
+
+
+
+
+ Content of Tab Pane 2
+
+
+ Content of Tab Pane 3
+
+
+ Content of Tab Pane 3
+
+
+ Content of Tab Pane 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ tags >= 0 ? '+' + tags+'%': tags+'%' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/dashboard/typical-home.less b/hotgo-web/src/views/dashboard/typical-home.less
new file mode 100644
index 0000000..77e12e2
--- /dev/null
+++ b/hotgo-web/src/views/dashboard/typical-home.less
@@ -0,0 +1,523 @@
+.typical-home{
+ overflow: hidden;
+ color: #666 !important;
+ background-color: #F0F2F5;
+ // 顶部列表
+ .top-list{
+ .ant-card-body{
+ height: 66px;
+ padding: 13px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ border-radius: 4px;
+ span{
+ color: #333;
+ }
+ >.anticon{
+ margin-right: 16px;
+ font-size: 24px;
+ width: 40px;
+ padding-top: 8px;
+ height: 40px;
+ vertical-align: middle;
+ text-align: center;
+ border-radius:16px;
+ background: #0081cc;
+ color: #fff;
+ }
+ }
+ .ant-col:last-child{
+ cursor: pointer;
+ .add-plus{
+ color: #abafb5;
+ border: 1px dashed #dadada;
+ background: #f3f3f3;
+ }
+ }
+ }
+ .module-list{
+ .module-in{
+ background: #fff;
+ min-height: 200px;
+ padding:0 16px;
+ .ant-page-header{
+ padding:0;
+ height: 52px;
+ line-height: 52px;
+ .ant-page-header-heading-title{
+ font-size: 16px;
+ line-height: 52px;
+ }
+ }
+ }
+
+ // 待办事项
+ .module-in01{
+ height: 370px;
+ .technology{
+ padding:0 16px;
+ background: #f7f9fa;
+ border-radius: 8px;
+ .ant-list-split{
+
+ .ant-list-item{
+
+ display: block;
+ border: 0!important;
+ padding:8px 0 ;
+ }
+ }
+
+ }
+ .list-totality{
+ .ant-card-bordered{
+ border:none;
+ }
+ .ant-list-item{
+ margin-bottom: 8px;
+ }
+ .ant-card-body{
+ height:76px;
+ padding:10px 14px;
+ background: #f7f9fa;
+ border-radius: 4px;
+ p{
+ margin-bottom: 0;
+ color: #000;
+ }
+ span{
+ font-size: 24px;
+ color: #5675EB;
+ }
+ }
+ }
+ .list-detail{
+ .module-text {
+ height: auto!important;
+ line-height: 24px!important;
+ padding:8px 14px!important;
+ margin: 8px 0;
+ span:nth-child(2){
+ white-space: break-spaces!important;
+ word-wrap: break-word!important;
+ max-width: 88%!important;
+ }
+ }
+ .ant-list-item{
+ height: 40px;
+ line-height: 40px;
+ padding:0 0 0 14px;
+ border:0;
+ background: #f7f9fa;
+ border-radius: 4px;
+ margin-bottom: 4px;
+ .ant-list-item-meta-description{
+ color: #666;
+ span,
+ .anticon,
+ a{
+ float: left;
+ font-size: 12px;
+ }
+ a{
+ color: #526ECC;
+ }
+ .anticon{
+ margin:6px 4px 0;
+ color: #b5b6b7;
+ font-size: 12px;
+ }
+ span:nth-child(2){
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ max-width: 164px;
+ color: #131415;
+ }
+
+ }
+ }
+ }
+ }
+ // 关注项目总览
+ .module-in02{
+ height: 370px;
+ .ant-table-wrapper{
+ height:auto;
+ .ant-table.ant-table-small{
+ border: none;
+ .ant-table-body{
+ margin: 0;
+ th,
+ td{
+ padding:8px ;
+ font-size: 12px;
+ line-height: 24px;
+ }
+ th{
+ color: #131415;
+ font-weight: normal;
+ background: #FAFAFA;
+ }
+ td{
+ height: 38px !important;
+ color: #666;
+ .ant-badge-status-dot{
+ width: 8px;
+ height: 8px;
+ }
+ .ant-badge-status-text{
+ font-size: 12px;
+ }
+ }
+ }
+ }
+ }
+ }
+ // 组件API搜索
+ .module-in03{
+ height:226px;
+ .ant-input{
+ margin:14px 0 10px;
+ }
+ .subtitle{
+ color: #131415;
+ padding-left: 10px;
+ margin:8px 0 26px;
+ }
+ .ant-card-bordered{
+ border: none;
+ .ant-card-body{
+ color: #333;
+ padding:0 0 0 20px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ .anticon{
+ width: 38px;
+ height: 38px;
+ line-height: 38px;
+ text-align: center;
+ border-radius: 8px;
+ background: #f3f4f9;
+ color: #5675eb;
+ font-size: 20px;
+ margin-right: 16px;
+ }
+ span{
+ }
+ }
+ }
+ }
+ // 趋势图
+ .module-in04{
+ .ant-radio-group{
+ .ant-radio-button-wrapper{
+ width: 70px;
+ height: 28px;
+ line-height: 26px;
+ text-align: center;
+ span{
+ font-size: 12px;
+ }
+ }
+ }
+ }
+ // 帮助文档
+ .module-in05{
+ height: 284px;
+ .ant-list-header{
+ font-size: 14px;
+ color: #131415;
+ border: none;
+ }
+ .ant-list-item{
+ border: none;
+ padding: 0;
+ font-size: 12px;
+ line-height: 30px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ }
+ // 公告
+ .module-in06{
+ height: 320px;
+ .ant-tabs-bar{
+ .ant-tabs-tab{
+ margin:0;
+ font-size: 12px;
+ }
+ .ant-tabs-tab-active{
+ color: #0064c8;
+ }
+ .ant-tabs-ink-bar{
+ background: #0064c8;
+ }
+ }
+ .ant-tabs-content{
+ .ant-list-item{
+ padding:0;
+ border: 0;
+ .ant-list-item-meta,
+ .ant-list-item-meta-content{
+ width: 100%;
+ }
+ .ant-list-item-meta-description{
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ a{
+ line-height: 34px;
+ font-size: 12px;
+ // color: #666;
+ }
+ }
+ }
+ }
+
+ }
+ // 个人信息
+ .module-in07{
+ height: 222px;
+ .ant-col{
+ .name{
+ span{
+ font-size: 14px;
+ color: #131415;
+ margin-right: 10px;
+ }
+ .anticon{
+ font-size: 18px;
+ color: #8098ef;
+ }
+ }
+ .ant-avatar{
+ background: #18d0d0;
+ font-size: 24px;
+ line-height: 40px;
+ width: 40px;
+ color: #fff;
+ margin:4px 10px 0 10px;
+ }
+ span{
+ font-size: 12px;
+ color: #666;
+ line-height: 28px;
+ }
+ span:nth-child(2){
+ color: #131415;
+ }
+ }
+ }
+ // 产品热度
+ .module-in08{
+ height: 222px;
+ .ant-list-item{
+ border:none;
+ padding:0;
+ .ant-list-item-meta{
+ .ant-list-item-meta-description{
+ height: 18px;
+ line-height: 18px;
+ margin:8px 0;
+ .order{
+ float: left;
+ width: 18px;
+ height: 18px;
+ line-height: 18px;
+ text-align: center;
+ border-radius: 18px;
+ font-size: 12px;
+ background: #a9a2a0;
+ color: #fff;
+ }
+ .icon{
+ float: left;
+ font-size: 16px;
+ margin:0 8px;
+ }
+ .txt{
+ // height: 18px;
+ float: left;
+ font-size: 12px;
+ color: #131415;
+ max-width: 200px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ .ant-statistic{
+ float:right;
+ .ant-statistic-content{
+ font-size: 12px;
+ .ant-statistic-content-value-decimal,
+ .ant-statistic-content-suffix{
+ font-size: 12px;
+ }
+ }
+ }
+ }
+ }
+ }
+ .ant-list-item:nth-child(1){
+ .ant-list-item-meta{
+ .ant-list-item-meta-description{
+ .order{
+ background: #ea2e2e;
+ }
+ }
+ }
+ }
+ .ant-list-item:nth-child(2){
+ .ant-list-item-meta{
+ .ant-list-item-meta-description{
+ .order{
+ background: #f38800;
+ }
+ }
+ }
+ }
+ .ant-list-item:nth-child(3){
+ .ant-list-item-meta{
+ .ant-list-item-meta-description{
+ .order{
+ background: #695fc8;
+ }
+ }
+ }
+ }
+ }
+ // 统计信息
+ .anticon-more{
+ font-size: 18px;
+ cursor: pointer;
+ }
+ .module-in09{
+ height: 526px;
+ .ant-page-header-heading-extra{
+ .ant-calendar-picker{
+ width: 140px;
+ }
+ }
+ .ant-table.ant-table-small{
+ border: none;
+ .ant-table-body{
+ margin: 0;
+ th,
+ td{
+ padding:0 16px !important;
+ font-size: 12px;
+ }
+ th{
+ color: #131415;
+ font-weight: normal
+ }
+ td{
+ height: 38px !important;
+ color: #666;
+ .ant-badge-status-dot{
+ width: 8px;
+ height: 8px;
+ }
+ .ant-badge-status-text{
+ font-size: 12px;
+ }
+ }
+ }
+ }
+ }
+ }
+ .apply{
+ .ant-page-header{
+ padding: 8px 16px;
+ font-size: 16px;
+ }
+ .ant-tabs-bar{
+ border:none;
+ .ant-tabs-extra-content{
+ line-height: 32px;
+ }
+ .ant-tabs-tab{
+ padding: 8px 0;
+ margin: 0 16px ;
+ color: #333;
+ }
+ .ant-tabs-tab::after{
+ position: absolute;
+ content: "/";
+ right: -20px;
+ color: #ccc;
+ font-size: 14px;
+ }
+ }
+ }
+}
+.top-list-modal{
+ .ant-modal{
+ width: 720px !important;
+ .ant-modal-body{
+ height: 466px;
+ .ant-tabs{
+ height:376px;
+ margin-top:16px;
+ .ant-tabs-left-bar{
+ width: 182px;
+ .ant-tabs-tab{
+ text-align: left;
+ margin-bottom: 0;
+ padding:0 20px;
+ height: 40px;
+ line-height: 40px;
+ }
+ .ant-tabs-ink-bar{
+ left: 0;
+ width: 3px;
+
+ }
+ }
+ .ant-tabs-tab-active{
+ /* background: #f9f9f9;*/
+ }
+ .ant-tabs-content{
+ .ant-list-item{
+ border:none;
+ padding:8px 0;
+ .ant-list-item-meta-title{
+ margin-bottom: 0;
+ font-weight: normal;
+ a{
+ color: #333;
+ }
+ .ant-list-item-meta-description{
+ color: #888;
+ }
+ }
+ .ant-list-item-meta-description{
+ font-size: 12px;
+ }
+ .ant-btn{
+ width: 66px;
+ height: 24px;
+ }
+ .ant-list-item-meta-avatar{
+ margin-top: 2px;
+ .ant-avatar{
+ border-radius: 4px;
+ font-size: 24px!;
+ // background: #ff8b40;
+ }
+ }
+ }
+ .ant-list-split{
+ height: 378px;
+ overflow: auto;
+ padding-right: 16px;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/hotgo-web/src/views/demo/chart/area-chart.vue b/hotgo-web/src/views/demo/chart/area-chart.vue
new file mode 100644
index 0000000..4488457
--- /dev/null
+++ b/hotgo-web/src/views/demo/chart/area-chart.vue
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/chart/chart-radar.vue b/hotgo-web/src/views/demo/chart/chart-radar.vue
new file mode 100644
index 0000000..577807c
--- /dev/null
+++ b/hotgo-web/src/views/demo/chart/chart-radar.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/chart/dashboard-chart.vue b/hotgo-web/src/views/demo/chart/dashboard-chart.vue
new file mode 100644
index 0000000..625d6d2
--- /dev/null
+++ b/hotgo-web/src/views/demo/chart/dashboard-chart.vue
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/chart/echartDashBoard.vue b/hotgo-web/src/views/demo/chart/echartDashBoard.vue
new file mode 100644
index 0000000..9d2070b
--- /dev/null
+++ b/hotgo-web/src/views/demo/chart/echartDashBoard.vue
@@ -0,0 +1,280 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
月收入
+
+
+ ¥183,827
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/chart/histogram-chart.vue b/hotgo-web/src/views/demo/chart/histogram-chart.vue
new file mode 100644
index 0000000..0277cdd
--- /dev/null
+++ b/hotgo-web/src/views/demo/chart/histogram-chart.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/chart/line-chart.vue b/hotgo-web/src/views/demo/chart/line-chart.vue
new file mode 100644
index 0000000..f490b09
--- /dev/null
+++ b/hotgo-web/src/views/demo/chart/line-chart.vue
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/chart/pie-chart.vue b/hotgo-web/src/views/demo/chart/pie-chart.vue
new file mode 100644
index 0000000..5a9fdd1
--- /dev/null
+++ b/hotgo-web/src/views/demo/chart/pie-chart.vue
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/chart/scatter-chart.vue b/hotgo-web/src/views/demo/chart/scatter-chart.vue
new file mode 100644
index 0000000..56d0aa6
--- /dev/null
+++ b/hotgo-web/src/views/demo/chart/scatter-chart.vue
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/chart/sm-pieChart.vue b/hotgo-web/src/views/demo/chart/sm-pieChart.vue
new file mode 100644
index 0000000..22c8d99
--- /dev/null
+++ b/hotgo-web/src/views/demo/chart/sm-pieChart.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/portLetCards/AmountStatistics.vue b/hotgo-web/src/views/demo/portLetCards/AmountStatistics.vue
new file mode 100644
index 0000000..3b24ac0
--- /dev/null
+++ b/hotgo-web/src/views/demo/portLetCards/AmountStatistics.vue
@@ -0,0 +1,32 @@
+
+
+
+
项目金额总览
+
+ 150032
+ +15%
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/portLetCards/DashboardChart.vue b/hotgo-web/src/views/demo/portLetCards/DashboardChart.vue
new file mode 100644
index 0000000..1eb0212
--- /dev/null
+++ b/hotgo-web/src/views/demo/portLetCards/DashboardChart.vue
@@ -0,0 +1,47 @@
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/portLetCards/TaskCompletionStatistics.vue b/hotgo-web/src/views/demo/portLetCards/TaskCompletionStatistics.vue
new file mode 100644
index 0000000..dc6a893
--- /dev/null
+++ b/hotgo-web/src/views/demo/portLetCards/TaskCompletionStatistics.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/portLetCards/TaskTotalStatistics.vue b/hotgo-web/src/views/demo/portLetCards/TaskTotalStatistics.vue
new file mode 100644
index 0000000..bb6ae5f
--- /dev/null
+++ b/hotgo-web/src/views/demo/portLetCards/TaskTotalStatistics.vue
@@ -0,0 +1,32 @@
+
+
+
+
当月任务总数统计
+
+ 150
+ -15%
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/portLetCards/TrafficStatistics.vue b/hotgo-web/src/views/demo/portLetCards/TrafficStatistics.vue
new file mode 100644
index 0000000..892e97f
--- /dev/null
+++ b/hotgo-web/src/views/demo/portLetCards/TrafficStatistics.vue
@@ -0,0 +1,38 @@
+
+
+
+
访问量
+
+
8,846
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/demo/portLetCards/icon/MtimeIcon.vue b/hotgo-web/src/views/demo/portLetCards/icon/MtimeIcon.vue
new file mode 100644
index 0000000..e8f65c5
--- /dev/null
+++ b/hotgo-web/src/views/demo/portLetCards/icon/MtimeIcon.vue
@@ -0,0 +1,18 @@
+
diff --git a/hotgo-web/src/views/demo/portLetCards/images-m/bg01.png b/hotgo-web/src/views/demo/portLetCards/images-m/bg01.png
new file mode 100644
index 0000000..e8a6d11
Binary files /dev/null and b/hotgo-web/src/views/demo/portLetCards/images-m/bg01.png differ
diff --git a/hotgo-web/src/views/demo/portLetCards/images-m/chart_sm.png b/hotgo-web/src/views/demo/portLetCards/images-m/chart_sm.png
new file mode 100644
index 0000000..d1b067b
Binary files /dev/null and b/hotgo-web/src/views/demo/portLetCards/images-m/chart_sm.png differ
diff --git a/hotgo-web/src/views/demo/portLetCards/images-m/img01.png b/hotgo-web/src/views/demo/portLetCards/images-m/img01.png
new file mode 100644
index 0000000..5eaaeca
Binary files /dev/null and b/hotgo-web/src/views/demo/portLetCards/images-m/img01.png differ
diff --git a/hotgo-web/src/views/demo/portLetCards/images-m/img02.png b/hotgo-web/src/views/demo/portLetCards/images-m/img02.png
new file mode 100644
index 0000000..74337ec
Binary files /dev/null and b/hotgo-web/src/views/demo/portLetCards/images-m/img02.png differ
diff --git a/hotgo-web/src/views/demo/portLetCards/images-m/img03.png b/hotgo-web/src/views/demo/portLetCards/images-m/img03.png
new file mode 100644
index 0000000..b4420b0
Binary files /dev/null and b/hotgo-web/src/views/demo/portLetCards/images-m/img03.png differ
diff --git a/hotgo-web/src/views/demo/portLetCards/images-m/img401.png b/hotgo-web/src/views/demo/portLetCards/images-m/img401.png
new file mode 100644
index 0000000..f1eac31
Binary files /dev/null and b/hotgo-web/src/views/demo/portLetCards/images-m/img401.png differ
diff --git a/hotgo-web/src/views/demo/portLetCards/images-m/title_left.png b/hotgo-web/src/views/demo/portLetCards/images-m/title_left.png
new file mode 100644
index 0000000..a2f4d2f
Binary files /dev/null and b/hotgo-web/src/views/demo/portLetCards/images-m/title_left.png differ
diff --git a/hotgo-web/src/views/demo/portLetCards/style/base.less b/hotgo-web/src/views/demo/portLetCards/style/base.less
new file mode 100644
index 0000000..6918450
--- /dev/null
+++ b/hotgo-web/src/views/demo/portLetCards/style/base.less
@@ -0,0 +1,619 @@
+
+.module{
+ background :#fff;
+ .module-in{
+ padding: 10px;
+ }
+ // .ant-tabs-nav-wrap{
+ // padding-left: 10px;
+ // }
+ .ant-tabs .ant-tabs-bar{
+ margin:0;
+ }
+ .ant-tabs-tab{
+ font-size: 14px;
+ padding: 12px;
+ font-weight: 600;
+ }
+
+ .ant-tabs-tab-active,
+ .ant-tabs-nav .ant-tabs-tab:hover{
+ font-size: 14px;
+ font-weight: 600;
+ }
+ .ant-tabs-nav{
+ position: relative;
+ font-size: 18px;
+ color: #67758D;
+ margin-bottom: 0;
+ border-bottom: 1px solid #e8e8e8;
+ font-weight: 900;
+ }
+ .ant-tabs-nav::after{
+ display: none;
+ position: absolute;
+ top: 12px;
+ left:0;
+ content: '';
+ width: 4px;
+ height: 24px;
+ transform: perspective(0.5em) rotateY(25deg);
+ //background: url(../images-m/title_left.png) no-repeat;
+ }
+ .panel-icon{
+ width: 28px;
+ height:28px;
+ line-height: 28px;
+ border-radius: 2px;
+ font-size: 17px;
+ cursor: pointer;
+ margin: 0 9px 0 -3px;
+ border: 1px solid #d9dee5;
+ color: #8291a9;
+ }
+ .panel-icon:hover{
+ opacity: 0.6;
+ background: #fbfbfb;
+ }
+ .ant-tabs-extra-content{
+ line-height: 46px;
+ }
+ // 首行卡片样式 start
+ .card{
+ padding: 12px 20px;
+ padding-top: 14px;
+ position: absolute;
+ top:0;
+ left:0;
+ right:0;
+ bottom: 0;
+ overflow: auto;
+ z-index: 10;
+ h3{
+ font-size: 14px;
+ color: #252b3a;
+ margin:5px 0;
+ font-weight: 600;
+ }
+ .card-inner{
+ padding: 6px 0 0 0;
+ }
+ .card-number{
+ display: inline-block;
+ font-size: 20px;
+ color: #7D899D;
+ line-height: 32px;
+ vertical-align: middle;
+ .ant-statistic-content-value-int{
+ font-size: 32px;
+ color: #7D899D;
+ }
+ }
+ .card-tag {
+ width: 74px;
+ height: 32px;
+ color: #FFF;
+ line-height: 32px;
+ text-align: center;
+ border-radius:16px ;
+ display: inline-block;
+ vertical-align: middle;
+ margin-left: 14px;
+ }
+ .card-blue{
+ background: #85c1fb;
+ }
+ .card-green{
+ background: #55d1b4;
+ }
+ .card-progress{
+ display: inline-block;
+ width: 78%;
+ float: right;
+ margin-top: 7px;
+ .ant-progress-outer{
+ padding: 0;
+ }
+ .ant-progress div .ant-progress-text{
+ position: absolute;
+ top: 2px;
+ left: -31%;
+ font-size: 20px;
+ color: #7D899D;
+ }
+ }
+ .card-chart{
+ display: inline-block;
+ width: 74%;
+ height: 32px;
+ margin-top: 2px;
+ border-radius: 6px;
+ float: right;
+ }
+ .ant-progress-inner{
+ background-color: #f3f4f9;
+ }
+ }
+ // 首行卡片样式 end
+
+ // 我的待办样式start
+ .backlog{
+ height: 100%;
+ overflow: auto;
+ .ant-list-item{
+ cursor: pointer;
+ padding: 0 16px ;
+ margin-bottom: 6px;
+ border: 1px solid #F0F2F4;
+ border-radius:2px ;
+ }
+ .ant-list-item-meta-title{
+ font-weight: normal;
+ line-height: 36px;
+ margin: 0;
+ a{
+ display: block;
+ overflow: hidden;
+ .ant-btn{
+ margin: 0;
+ padding: 0 10px;
+ }
+ }
+ }
+ .title{
+ float: left;
+ color: #252b3a;
+ max-width: 540px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ .todo-name,
+ .todo-time,
+ .todo
+ {
+ font-size: 12px;
+ float: right;
+ color: #5D6B7E;
+ width: 100px;
+ text-align: center;
+ }
+ .todo-time{
+ width: 140px;
+ }
+ .todo{
+ width: 80px;
+ text-align: right;
+ }
+ }
+ // 通知公告start
+ .module-notice{
+ .ant-list-bordered .ant-list-item,
+ .ant-list-bordered{
+ border:none;
+ }
+ .ant-list-bordered{
+ .ant-list-item{
+ height: 40px;
+ font-size: 12px;
+ color: #252b3a;
+ padding: 10px;
+ display: block;
+ span:nth-child(3),
+ span:nth-child(4),
+ span:nth-child(5){
+ float: right;
+ color:#7D899D;
+ font-size: 12px;
+ margin-left: 10px;
+ line-height: 22px;
+ }
+ .ant-badge .ant-badge-count{
+ width: 42px;
+ height:18px;
+ line-height: 18px;
+ text-align: center;
+ border-radius: 2px;
+ background: #f66;
+ margin-left: 13px;
+ }
+ }
+ .ant-list-item> span:nth-child(1){
+ max-width: 80%;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ display: inline-block;
+ a{
+ color:#252b3a;
+ }
+ }
+ }
+ }
+ // 通知公告end
+
+ // 关注项目start
+ .article{
+ .ant-progress-inner{
+ background-color: #f3f4f9;
+ }
+ .ant-list-split .ant-list-item{
+ border-bottom:1px dashed #e8e8e8 !important;
+ display: block;
+ padding:10px ;
+ .date-m{
+ font-size: 12px;
+ color: #92A0B2;
+ padding-left: 4px;
+ }
+ .ant-list-item-meta{
+ margin-bottom: 4px;
+ }
+ .ant-list-item-meta-title a{
+ color: #252b3a;
+ font-weight: normal;
+ }
+ .ant-progress{
+ display: block;
+ line-height: 1;
+ }
+ .ant-list-item-meta-avatar{
+ margin-right:16px;
+ }
+ .ant-list-item-meta-content{
+ overflow: hidden;
+ h4{
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ margin-bottom: 0;
+ margin-top: 2px;
+ }
+ .ant-list-item-meta-description{
+ font-size: 12px;
+ color: #ADB9CA;
+ span{
+ margin-right: 14px;
+ }
+ }
+ }
+
+ .ant-progress .ant-progress-text{
+ position: absolute;
+ top: -24px;
+ right: 6px;
+ font-size: 18px;
+ color: #48CFAE;
+ }
+ .ant-progress-show-info .ant-progress-outer{
+ padding-right: 0;
+ }
+ .ant-progress-bg{
+ background: #8CDECC;
+ }
+ .ant-avatar{
+ background: #EDFAF7;
+ color: #48CFAE;
+ width: 48px;
+ height: 48px;
+ position: relative;
+ }
+ .ant-avatar::after{
+ content: 'M';
+ position: absolute;
+ top: 0;
+ left: 0;
+ font-size: 20px;
+ width: 48px;
+ height: 48px;
+ text-align: center;
+ line-height: 48px;
+ }
+ }
+ .ant-list-split .ant-list-item:nth-child(2){
+
+ .ant-avatar{
+ background: #EAF2FD;
+
+ }
+ .ant-avatar::after{
+ content: 'J';
+ font-size: 20px;
+ }
+ }
+ .ant-list-split .ant-list-item:nth-child(3){
+ .ant-progress .ant-progress-text{
+ color: #F90;
+ }
+ .ant-progress-bg{
+ background: #FABE64;
+ }
+ .ant-avatar{
+ background: #FFF5E6;
+ color: #F90;
+ }
+ .ant-avatar::after{
+ content: 'M';
+ font-size: 20px;
+ }
+ }
+ }
+ // 关注项目end
+
+ // 监控start
+ .information{
+ overflow: hidden;
+ padding: 18px 0 0 0;
+ li{
+ list-style: none;
+ float: left;
+ width: 33.33%;
+ border-right: 1px dashed #E8E8E8;
+ text-align: center;
+ span{
+ font-size: 28px;
+ color: #7D899D;
+ }
+ span:nth-child(2){
+ color: #ADB9CA;
+ font-size: 12px;
+ }
+ .anticon{
+
+ margin-right: 4px;
+ }
+ p{
+ font-size: 13px;
+ color: #ADB9CA;
+ margin-top: 10px;
+ }
+ }
+ li:nth-child(3){
+ border:none;
+ }
+ }
+ // 监控end
+
+ // 仪表盘start
+ .information02{
+ overflow: hidden;
+ padding: 0;
+ li{
+ list-style: none;
+ display: inline-block;
+ width: 50%;
+ text-align: center;
+ overflow: hidden;
+ .sky{
+ width: 144px;
+ height: 126px;
+ line-height: 126px;
+ // border: 1px solid #000;
+ display: inline-block;
+ text-align: center;
+ overflow: hidden;
+ }
+ .information02-data{
+ overflow: hidden;
+ display: inline-block;
+ height: 126px;
+ padding-top: 25px;
+ span{
+ font-size: 28px;
+ color: #7D899D;
+ }
+ p{
+ font-size: 13px;
+ color: #ADB9CA;
+ margin-top: 10px;
+ }
+ }
+
+ }
+ li:nth-child(1){
+ border-right: 1px dashed #E8E8E8;
+ }
+ }
+ // 仪表盘end
+
+ // 常用流程start
+
+ .flowPath{
+ padding: 10px 16px;
+ height:100%;
+ .ant-col:nth-child(2n+2){
+ .anticon{
+ color: #48cfae;
+ }
+ }
+ .ant-col:nth-child(3n+3){
+ .anticon{
+ color: #f66;
+ }
+ }
+ .ant-col:nth-child(4n+4){
+ .anticon{
+ color: #fc0;
+ }
+ }
+ /deep/ .ant-card-bordered{
+ height: 72px;
+ border:1px solid #e8e8e8;
+ border-radius: 2px;
+ background: url(../images-m/bg01.png) center right no-repeat;
+
+ .ant-card-head{
+ min-height: auto;
+ height:34px;
+ border-bottom: 0;
+ font-size: 14px;
+ color: #252b3a;
+ padding-left: 10px;
+ padding-top: 4px;
+ font-weight: normal;
+ }
+ .ant-card-head-title{
+ padding-left:44px;
+ height: 40px;
+ line-height: 40px;
+ }
+ .ant-card-body{
+ font-size: 12px;
+ color: #ADB9CA;
+ padding: 8px 10px 0 54px;
+ word-wrap:break-word;
+ .anticon{
+ font-size: 20px;
+ position: absolute;
+ top: 20px;
+ left: 16px;
+ color: #34b3f8;
+ }
+ }
+ }
+
+ }
+ // 常用流程end
+
+ // 关注任务start
+ .task-m {
+ .sky {
+ height: 252px;
+ overflow: hidden;
+ }
+ .ant-table-small {
+ border: none;
+ }
+ .ant-table-wrapper {
+ margin-top: 10px;
+ }
+ th {
+ border: 1px solid #fff;
+ height: 36px;
+ line-height: 36px;
+ padding: 0 10px !important;
+ background-color: #edf0f5 !important;
+ text-align: center;
+ color: #484848;
+ }
+ td {
+ height: 36px;
+ line-height: 36px;
+ padding: 0 10px !important;
+ font-size: 12px;
+ color: #666;
+ border-bottom: 1px solid #edf0f5;
+ text-align: right;
+ }
+ .ant-table-tbody > tr:nth-child(2n) {
+ background: none;
+ }
+ }
+ // 关注任务end
+
+ // 快捷入口start
+ .shortcut {
+ /deep/ .ant-card-bordered{
+ border: none;
+ .ant-card-head{
+ min-height: auto;
+ padding: 0;
+ text-align: center;
+ border:none;
+ .ant-card-head-title{
+ padding:0 16px;
+ height:36px;
+ line-height: 36px;
+ border-radius: 2px;
+ font-size: 14px;
+ text-align: left;
+ font-weight:normal ;
+ a{
+ display: block;
+ }
+ }
+ }
+ }
+ .anticon{
+ color: #8291a9;
+ margin-right: 6px;
+ font-size: 16px;
+ }
+ }
+ // 快捷入口end
+
+ // 最新动态start
+ .dynamic {
+ overflow: auto;
+ padding: 10px;
+ margin-right: 0;
+ .ant-timeline-item-tail{
+ border-left: 1px solid #e8e8e8;
+ top: 15px;
+ }
+ .ant-timeline-item-head{
+ // top: 10px;
+ padding:0;
+ .anticon{
+ font-size: 18px !important;
+ border: 1px solid #e8e8e8;
+ border-radius: 22px;
+ padding: 4px;
+ }
+ }
+ .ant-timeline{
+ .ant-timeline-item{
+ padding:0 ;
+ }
+ .ant-timeline-item-content{
+ margin-left: 26px;
+ .span01{
+ font-size: 14px;
+ line-height: 24px;
+ color: #252b3a;
+ font-weight: 600;
+ margin-right: 10px;
+ vertical-align: middle;
+ }
+ .span02{
+ font-size: 12px;
+ line-height: 24px;
+ color: #252b3a;
+ vertical-align: middle;
+ }
+ p{
+ font-size: 12px;
+ line-height: 20px;
+ color: #ADB9CA;
+ }
+ }
+ }
+ }
+}
+.module01 {
+ height: 100px;
+ position: relative;
+ .card-icon {
+ position: absolute;
+ top: 10px;
+ right: 20px;
+ color: #f3f4f9;
+ font-size: 46px;
+ z-index: 1;
+ }
+}
+.module03{
+ height: 404px;
+}
+.module04{
+ height: 190px;
+}
+.module05{
+ height: 560px;
+}
+.module06{
+ height: 348px;
+}
+.module07{
+ height: 290px;
+}
diff --git a/hotgo-web/src/views/exception/403.vue b/hotgo-web/src/views/exception/403.vue
new file mode 100644
index 0000000..fb1bf36
--- /dev/null
+++ b/hotgo-web/src/views/exception/403.vue
@@ -0,0 +1,20 @@
+
+
+
+
+ Back Home
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/exception/404.vue b/hotgo-web/src/views/exception/404.vue
new file mode 100644
index 0000000..3142e7b
--- /dev/null
+++ b/hotgo-web/src/views/exception/404.vue
@@ -0,0 +1,20 @@
+
+
+
+
+ Back Home
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/exception/500.vue b/hotgo-web/src/views/exception/500.vue
new file mode 100644
index 0000000..2770b77
--- /dev/null
+++ b/hotgo-web/src/views/exception/500.vue
@@ -0,0 +1,20 @@
+
+
+
+
+ Back Home
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/index.less b/hotgo-web/src/views/index.less
new file mode 100644
index 0000000..7e0acdc
--- /dev/null
+++ b/hotgo-web/src/views/index.less
@@ -0,0 +1,107 @@
+@import "../assets/styles/default.less";
+
+.text-overflow() {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ word-break: break-all;
+}
+
+// mixins for clearfix
+// ------------------------
+.clearfix() {
+ zoom: 1;
+ &::before,
+ &::after {
+ display: table;
+ content: ' ';
+ }
+ &::after {
+ clear: both;
+ height: 0;
+ font-size: 0;
+ visibility: hidden;
+ }
+}
+
+
+.page-header-content {
+ display: flex;
+
+ .avatar {
+ flex: 0 1 72px;
+
+ & > span {
+ display: block;
+ width: 72px;
+ height: 72px;
+ border-radius: 72px;
+ }
+ }
+
+ .content {
+ position: relative;
+ top: 4px;
+ flex: 1 1 auto;
+ margin-left: 24px;
+ color: @text-color-secondary;
+ line-height: 22px;
+
+ .content-title {
+ margin-bottom: 12px;
+ color: @heading-color;
+ font-weight: 500;
+ font-size: 20px;
+ line-height: 28px;
+ }
+ }
+}
+
+.extra-content {
+ .clearfix();
+ float: right;
+ white-space: nowrap;
+
+ .stat-item {
+ position: relative;
+ display: inline-block;
+ padding: 0 32px;
+
+ > p:first-child {
+ margin-bottom: 4px;
+ color: @text-color-secondary;
+ font-size: @font-size-base;
+ line-height: 22px;
+ }
+
+ > p {
+ margin: 0;
+ color: @heading-color;
+ font-size: 30px;
+ line-height: 38px;
+
+ > span {
+ color: @text-color-secondary;
+ font-size: 20px;
+ }
+ }
+
+ &::after {
+ position: absolute;
+ top: 8px;
+ right: 0;
+ width: 1px;
+ height: 40px;
+ background-color: @border-color-split;
+ content: '';
+ }
+
+ &:last-child {
+ padding-right: 0;
+
+ &::after {
+ display: none;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/hotgo-web/src/views/index.vue b/hotgo-web/src/views/index.vue
new file mode 100644
index 0000000..96a5173
--- /dev/null
+++ b/hotgo-web/src/views/index.vue
@@ -0,0 +1,772 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+ 添加常用
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+ 移除
+
+
+
+
+ 分析工具
+
+
+ 沟通协作
+
+
+ 客户服务
+
+
+ 开发工具
+
+
+ 人力资源
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+ {{ item.data }}
+
+
+
+
+
+
+
+ {{ item.state }}
+ {{ item.txt }}
+
+
+ {{ item.hint }}
+
+
+
+ 办理
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
最近使用
+
+
+
+
+
+ {{ item.con }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 一个月
+
+
+ 三个月
+
+
+ 六个月
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item }}
+
+
+ 组件使用方法
+
+
+
+
+
+
+ {{ item }}
+
+
+ 组件使用方法
+
+
+
+
+
+
+ {{ item }}
+
+
+ 组件使用方法
+
+
+
+
+
+
+ {{ item }}
+
+
+ 组件使用方法
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.state }}{{ item.title }}
+
+
+
+ 更多
+
+
+
+
+ Content of Tab Pane 2
+
+
+ Content of Tab Pane 3
+
+
+ Content of Tab Pane 3
+
+
+ Content of Tab Pane 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Aidex
+
+
+ Some contents...
+ Some contents...
+ Some contents...
+
+
+
+ 员工编号:
+ 88888888888
+
+
+ 组织机构:
+ XXXXX
+
+
+ 所属群组:
+ XXXX
+
+
+ 所属部门:
+ 市场部
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ tags >= 0 ? '+' + tags+'%': tags+'%' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/cache/index.vue b/hotgo-web/src/views/monitor/cache/index.vue
new file mode 100644
index 0000000..37ee810
--- /dev/null
+++ b/hotgo-web/src/views/monitor/cache/index.vue
@@ -0,0 +1,299 @@
+
+
+
+
+
+
+
+
+ {{ cache.info.redis_version }}
+
+
+ {{ cache.info.redis_mode == 'standalone' ? '单机' : '集群' }}
+
+
+ {{ cache.info.tcp_port }}
+
+
+ {{ cache.info.connected_clients }}
+
+
+ {{ cache.info.uptime_in_days }}
+
+
+ {{ cache.info.used_memory_human }}
+
+
+ {{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}
+
+
+ {{ cache.info.maxmemory_human }}
+
+
+ {{ cache.info.aof_enabled == '0' ? '否' : '是' }}
+
+
+ {{ cache.info.rdb_last_bgsave_status }}
+
+
+ {{ cache.dbSize }}
+
+
+
+ {{ cache.info.instantaneous_input_kbps }}kps/{{ cache.info.instantaneous_output_kbps }}kps
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/cache/indexCacheList.vue b/hotgo-web/src/views/monitor/cache/indexCacheList.vue
new file mode 100644
index 0000000..6927464
--- /dev/null
+++ b/hotgo-web/src/views/monitor/cache/indexCacheList.vue
@@ -0,0 +1,360 @@
+
+
+
+
+
+
+
+ {{ index + 1 }}
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+ {{ index + 1 }}
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/cache/indexOld.vue b/hotgo-web/src/views/monitor/cache/indexOld.vue
new file mode 100644
index 0000000..804e295
--- /dev/null
+++ b/hotgo-web/src/views/monitor/cache/indexOld.vue
@@ -0,0 +1,229 @@
+
+
+
+
+
+
+
+
+ {{ cache.info.redis_version }}
+
+
+ {{ cache.info.redis_mode == 'standalone' ? '单机' : '集群' }}
+
+
+ {{ cache.info.tcp_port }}
+
+
+ {{ cache.info.connected_clients }}
+
+
+ {{ cache.info.uptime_in_days }}
+
+
+ {{ cache.info.used_memory_human }}
+
+
+ {{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}
+
+
+ {{ cache.info.maxmemory_human }}
+
+
+ {{ cache.info.aof_enabled == '0' ? '否' : '是' }}
+
+
+ {{ cache.info.rdb_last_bgsave_status }}
+
+
+ {{ cache.dbSize }}
+
+
+
+ {{ cache.info.instantaneous_input_kbps }}kps/{{ cache.info.instantaneous_output_kbps }}kps
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/druid/index.vue b/hotgo-web/src/views/monitor/druid/index.vue
new file mode 100644
index 0000000..03dd170
--- /dev/null
+++ b/hotgo-web/src/views/monitor/druid/index.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/job/index.vue b/hotgo-web/src/views/monitor/job/index.vue
new file mode 100644
index 0000000..1374ff7
--- /dev/null
+++ b/hotgo-web/src/views/monitor/job/index.vue
@@ -0,0 +1,377 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+
+ 删除
+
+
+ 导出
+
+
+ 日志
+
+
+
+ {{ jobGroupFormat(record) }}
+
+
+
+ 确认{{ record.status === '1' ? '开启' : '关闭' }} {{ record.jobName }}的任务吗?
+
+
+
+
+
+ 确认执行一次{{ record.jobName }}的任务吗?
+
+
+ 执行一次
+
+
+
+
+
+ 修改
+
+
+
+ 详细
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/job/log.vue b/hotgo-web/src/views/monitor/job/log.vue
new file mode 100644
index 0000000..3443551
--- /dev/null
+++ b/hotgo-web/src/views/monitor/job/log.vue
@@ -0,0 +1,325 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ jobGroupFormat(record) }}
+
+
+ {{ statusFormat(record) }}
+
+
+
+ 详细
+
+
+
+
+ 删除
+
+
+ 清空
+
+
+ 导出
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/job/modules/CreateForm.vue b/hotgo-web/src/views/monitor/job/modules/CreateForm.vue
new file mode 100644
index 0000000..b168782
--- /dev/null
+++ b/hotgo-web/src/views/monitor/job/modules/CreateForm.vue
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+ 调用方法
+
+
+ Class类调用示例:com.aidex.quartz.task.RyTask.ryParams('ry')
+ 参数说明:支持字符串,布尔类型,长整型,浮点型,整型
+
+ Bean调用示例:ryTask.ryParams('ry')
+
+
+
+
+
+
+
+
+
+
+ 允许
+ 禁止
+
+
+
+
+ 立即执行
+ 执行一次
+ 放弃执行
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/job/modules/LogViewForm.vue b/hotgo-web/src/views/monitor/job/modules/LogViewForm.vue
new file mode 100644
index 0000000..d8fff7a
--- /dev/null
+++ b/hotgo-web/src/views/monitor/job/modules/LogViewForm.vue
@@ -0,0 +1,81 @@
+
+
+
+
+ {{ form.jobLogId }}
+
+
+ {{ form.jobName }}
+
+
+ {{ jobGroupFormat(form) }}
+
+
+
+
+
+
+ {{ form.createTime }}
+
+
+ {{ form.invokeTarget }}
+
+
+ {{ form.jobMessage }}
+
+
+ {{ form.exceptionInfo }}
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/job/modules/ViewForm.vue b/hotgo-web/src/views/monitor/job/modules/ViewForm.vue
new file mode 100644
index 0000000..7dd1632
--- /dev/null
+++ b/hotgo-web/src/views/monitor/job/modules/ViewForm.vue
@@ -0,0 +1,96 @@
+
+
+
+
+ {{ form.jobId }}
+
+
+ {{ jobGroupFormat(form.jobGroup) }}
+
+
+ {{ form.jobName }}
+
+
+ {{ form.createTime }}
+
+
+ {{ parseTime(form.nextValidTime) }}
+
+
+ {{ form.invokeTarget }}
+
+
+ {{ form.cronExpression }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/loginlog/LoginLogIndex.vue b/hotgo-web/src/views/monitor/loginlog/LoginLogIndex.vue
new file mode 100644
index 0000000..7ade96e
--- /dev/null
+++ b/hotgo-web/src/views/monitor/loginlog/LoginLogIndex.vue
@@ -0,0 +1,304 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 删除
+
+
+ 清空
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/online/index.vue b/hotgo-web/src/views/monitor/online/index.vue
new file mode 100644
index 0000000..e76df19
--- /dev/null
+++ b/hotgo-web/src/views/monitor/online/index.vue
@@ -0,0 +1,213 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+ 确认强退{{ record.userName }} 的用户吗?
+ 强退
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/operlog/OperlogIndex.vue b/hotgo-web/src/views/monitor/operlog/OperlogIndex.vue
new file mode 100644
index 0000000..675424b
--- /dev/null
+++ b/hotgo-web/src/views/monitor/operlog/OperlogIndex.vue
@@ -0,0 +1,447 @@
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 删除
+
+
+ 清空
+
+
+ 导出
+
+
+
+
+ {{ typeFormat(record) }}
+
+
+
+
+ {{ moduleFormat(record) }}
+
+
+
+
+ {{ methodFormat(record) }}
+
+
+
+
+ {{ errorCodeFormat(record) }}
+
+
+
+
+ {{ takeTimeFormat(record) }}
+
+
+
+
+ 详细
+
+
+
+ {{ memberNameFormat(record) }}
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/operlog/modules/ViewForm.vue b/hotgo-web/src/views/monitor/operlog/modules/ViewForm.vue
new file mode 100644
index 0000000..4b7be90
--- /dev/null
+++ b/hotgo-web/src/views/monitor/operlog/modules/ViewForm.vue
@@ -0,0 +1,99 @@
+
+
+
+
+ {{ form.module }}
+
+
+ #{{ form.member_id }} / {{ form.member_name }} / {{ form.ip }} / {{ form.region }}
+
+
+ {{ form.method }}
+
+
+ {{ form.url }}
+
+
+ {{ form.method }}
+
+
+
+
+
+ {{ form.header_data }}
+
+
+ {{ form.get_data }}
+
+
+ {{ form.post_data }}
+
+
+
+
+
+
+ {{ parseTime(form.created_at) }}
+
+
+ {{ form.take_up_time }}毫秒
+
+
+ {{ form.error_msg }}
+
+
+ {{ form.error_data }}
+
+
+
+
+
+
+ {{ form.req_id }}
+
+
+ 无
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/monitor/server/index.vue b/hotgo-web/src/views/monitor/server/index.vue
new file mode 100644
index 0000000..7229a5b
--- /dev/null
+++ b/hotgo-web/src/views/monitor/server/index.vue
@@ -0,0 +1,499 @@
+
+
+
+
+
+
+
+ {{ server.cpu ? server.cpu.cpuNum : 0 }}
+ CPU核心数
+
+
+
+
+ {{ server.cpu ? server.cpu.sys : 0 }}%
+
+ 系统CPU使用率
+
+
+
+
+
+ {{ server.cpu ? server.cpu.used : 0 }}%
+
+ 用户CPU使用率
+
+
+
+
+
+
+ {{ server.cpu ? server.cpu.free : 0 }}%
+
+ 当前CPU空闲率
+
+
+
+
+
+
+
+
+
+
+ 内存
+
+
+
+
+ {{ item.name }}
+
+
+
+ G
+
+
+
+
+ %
+
+
+
+
+
+
+
+ M
+
+
+
+
+ %
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 磁盘状态
+
+
+
+
+
+
+
+ {{ item.dirName }}
+ 磁盘类型:{{ item.sysTypeName }}
+
+
+
+
+ {{ item.usage }}%
+
+
+
+
+
+
+ 总大小
+
+ {{ item.total }}
+
+
+ 可用大小
+
+ {{ item.free }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 服务器信息
+
+
+ {{ server.sys ? server.sys.computerName : '' }}
+ {{ server.sys ? server.sys.osName : '' }}
+ {{ server.sys ? server.sys.computerIp : '' }}
+ {{ server.sys ? server.sys.osArch : '' }}
+
+
+
+
+
+
+
+
+
+ Java虚拟机信息
+
+
+ {{ server.jvm ? server.jvm.name : '' }}
+ {{ server.jvm ? server.jvm.version : '' }}
+ {{ server.jvm ? server.jvm.startTime : '' }}
+ {{ server.jvm ? server.jvm.runTime : '' }}
+ {{ server.jvm ? server.jvm.home : '' }}
+ {{ server.jvm ? server.sys.userDir : '' }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/config/ConfigIndex.vue b/hotgo-web/src/views/system/config/ConfigIndex.vue
new file mode 100644
index 0000000..5faceee
--- /dev/null
+++ b/hotgo-web/src/views/system/config/ConfigIndex.vue
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+ 删除
+
+
+ 导出
+
+
+ 刷新缓存
+
+
+
+ {{ typeFormat(record) }}
+
+
+
+ 修改
+
+
+
+ 删除
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/config/modules/ConfigAddForm.vue b/hotgo-web/src/views/system/config/modules/ConfigAddForm.vue
new file mode 100644
index 0000000..3c948bd
--- /dev/null
+++ b/hotgo-web/src/views/system/config/modules/ConfigAddForm.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ d.dictLabel
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/config/modules/ConfigEditForm.vue b/hotgo-web/src/views/system/config/modules/ConfigEditForm.vue
new file mode 100644
index 0000000..2b4cc06
--- /dev/null
+++ b/hotgo-web/src/views/system/config/modules/ConfigEditForm.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ d.dictLabel
+ }}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/config/modules/ConfigForm.js b/hotgo-web/src/views/system/config/modules/ConfigForm.js
new file mode 100644
index 0000000..1313541
--- /dev/null
+++ b/hotgo-web/src/views/system/config/modules/ConfigForm.js
@@ -0,0 +1,117 @@
+import { getConfig, saveConfig, checkConfigKeyUnique } from '@/api/system/config'
+import AntModal from '@/components/pt/dialog/AntModal'
+export default {
+ name: 'CreateForm',
+ props: {
+ typeOptions: {
+ type: Array,
+ required: true
+ }
+ },
+ components: {
+ AntModal
+ },
+ data () {
+ return {
+ loading: false,
+ formTitle: '',
+ // 表单参数
+ form: {
+ id: undefined,
+ configName: undefined,
+ configKey: undefined,
+ configValue: undefined,
+ configType: 'Y',
+ remark: undefined
+ },
+ open: false,
+ rules: {
+ configName: [{ required: true, message: '参数名称不能为空', trigger: 'blur' }],
+ configKey: [{ required: true, message: '参数编码不能为空', trigger: 'blur' },
+ { validator: this.checkConfigKeyUnique }],
+ configValue: [{ required: true, message: '参数值不能为空', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {
+ },
+ created () {
+ },
+ computed: {
+ },
+ watch: {
+ },
+ methods: {
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ if (this.$refs.form !== undefined) {
+ this.$refs.form.resetFields()
+ }
+ },
+ /** 新增按钮操作 */
+ handleAdd () {
+ this.open = true
+ this.formTitle = '添加参数'
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row, ids) {
+ const configId = row ? row.id : ids
+ getConfig(configId).then(response => {
+ this.form = response.data
+ this.open = true
+ this.formTitle = '修改参数'
+ })
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ if (this.form.id !== undefined) {
+ saveConfig(this.form).then(response => {
+ this.$message.success(
+ '修改成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ } else {
+ saveConfig(this.form).then(response => {
+ this.$message.success(
+ '新增成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ checkConfigKeyUnique (rule, value, callback) {
+ const msg = '参数编码已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ configKey: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkConfigKeyUnique(checkData).then(response => {
+ if (response.data.code === '1') {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/dept/SysDeptIndex.vue b/hotgo-web/src/views/system/dept/SysDeptIndex.vue
new file mode 100644
index 0000000..e76074c
--- /dev/null
+++ b/hotgo-web/src/views/system/dept/SysDeptIndex.vue
@@ -0,0 +1,429 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+ 删除
+
+
+ 导入
+
+
+
+ 导出
+
+
+
+
+
+
+
+
+ {{ text.substr(0, text.indexOf(queryParam.name)) }}
+ {{ queryParam.name }}
+ {{ text.substr(text.indexOf(queryParam.name) + queryParam.name.length) }}
+
+ {{ text }}
+
+
+
+
+
+ {{ parseTime(record.created_at) }}
+
+
+
+ 修改
+
+
+
+ 添加子部门
+
+
+
+ 删除
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/dept/modules/SysDeptAddForm.vue b/hotgo-web/src/views/system/dept/modules/SysDeptAddForm.vue
new file mode 100644
index 0000000..96d7365
--- /dev/null
+++ b/hotgo-web/src/views/system/dept/modules/SysDeptAddForm.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/dept/modules/SysDeptEditForm.vue b/hotgo-web/src/views/system/dept/modules/SysDeptEditForm.vue
new file mode 100644
index 0000000..2d8b99a
--- /dev/null
+++ b/hotgo-web/src/views/system/dept/modules/SysDeptEditForm.vue
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ d.label
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/dept/modules/SysDeptForm.js b/hotgo-web/src/views/system/dept/modules/SysDeptForm.js
new file mode 100644
index 0000000..9f6a26e
--- /dev/null
+++ b/hotgo-web/src/views/system/dept/modules/SysDeptForm.js
@@ -0,0 +1,273 @@
+import { getDept, addDept, updateDept, findMaxSort, validateDeptNameUnique, listDeptTree } from '@/api/system/dept'
+import AntModal from '@/components/pt/dialog/AntModal'
+import SelectDept from '@/components/pt/selectDept/SelectDept'
+export default {
+ name: 'CreateForm',
+ props: {
+ deptTypeOptions: {
+ type: Array,
+ required: true
+ },
+ statusOptions: {
+ type: Array,
+ required: true
+ },
+ deptOptions: {
+ type: Array,
+ required: true
+ },
+ expandedKeys: {
+ type: Array,
+ required: true
+ }
+ },
+ components: {
+ AntModal,
+ SelectDept
+ },
+ data () {
+ const validateDeptName = (rule, value, callback) => {
+ if (value === '') {
+ callback(new Error('部门名不允许为空'))
+ } else {
+ validateDeptNameUnique(this.form.name, this.form.parentId.ids, this.form.id)
+ callback()
+ }
+ }
+ const validateParentId = (rule, value, callback) => {
+ if (value.ids === '') {
+ callback(new Error('上级部门不允许为空'))
+ } else {
+ callback()
+ }
+ }
+ return {
+ loading: false,
+ parentIdShow: false,
+ hasChild: false,
+ selectScope: 'all',
+ deptTypeEnableValue: [],
+ formTitle: '',
+ currentRow: undefined,
+ oldParentId: '',
+ spinning: false,
+ delayTime: 200,
+ customStyle: 'background: #fff;ssborder-radius: 4px;margin-bottom: 24px;border: 0;overflow: hidden',
+ // 表单参数
+ form: {
+ id: undefined,
+ pid: undefined,
+ name: undefined,
+ deptFullName: undefined,
+ sort: 0,
+ deptType: 'dept',
+ leader: undefined,
+ phone: undefined,
+ address: undefined,
+ zipCode: undefined,
+ email: undefined,
+ status: '0'
+ },
+ open: false,
+ rules: {
+ pid: [{ required: true, message: '上级部门不能为空', trigger: 'blur', validator: validateParentId }],
+ deptType: [{ required: true, message: '部门类型不能为空', trigger: 'blur' }],
+ name: [{ required: true, message: '部门名称不能为空', validator: validateDeptName, trigger: 'change' }],
+ sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
+ email: [
+ {
+ type: 'email',
+ message: '请输入正确的邮箱地址',
+ trigger: ['blur', 'change']
+ }
+ ],
+ phone: [
+ {
+ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+ message: '请输入正确的手机号码',
+ trigger: 'blur'
+ }
+ ]
+ }
+ }
+ },
+ filters: {
+ },
+ created () {
+ },
+ computed: {
+ },
+ watch: {
+ },
+ methods: {
+ onDeptTypeChange (item) {
+ if (item.target.value === 'company') {
+ this.selectScope = 'nonDept'
+ } else {
+ this.selectScope = 'all'
+ }
+ },
+ onSelectDept (result) {
+ this.getDeptTypeEnableValue(result.types)
+ },
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ if (this.$refs.form !== undefined) {
+ this.$refs.form.resetFields()
+ }
+ },
+ getDeptTypeEnableValue (parentDeptType) {
+ const id = this.form.id
+ /* if (parentDeptType === null) {
+ this.deptTypeEnableValue = this.deptTypeOptions.filter(function (item) { return item.dictValue === 'org' })
+ .map(function (item) { return item.dictValue })
+ } else if (this.hasChild) {
+ this.deptTypeEnableValue = this.deptTypeOptions.filter(function (item) { return item.dictValue === 'company' })
+ .map(function (item) { return item.dictValue })
+ } else if (parentDeptType === 'org' || parentDeptType === 'company' || parentDeptType === '') {
+ this.deptTypeEnableValue = this.deptTypeOptions.filter(function (item) { return item.dictValue !== 'org' })
+ .map(function (item) { return item.dictValue })
+ } else {
+ this.deptTypeEnableValue = this.deptTypeOptions.filter(function (item) { return item.dictValue === 'dept' })
+ .map(function (item) { return item.dictValue })
+ } */
+ if (parentDeptType === 'org' || parentDeptType === 'company') {
+ this.deptTypeEnableValue = this.deptTypeOptions.filter(function (item) { return item.dictValue !== 'org' })
+ .map(function (item) { return item.dictValue })
+ } else {
+ this.deptTypeEnableValue = this.deptTypeOptions.filter(function (item) { return item.dictValue === 'dept' })
+ .map(function (item) { return item.dictValue })
+ }
+ if (id !== null && id !== '' && id !== 'undefined' && id !== undefined) {
+ // 编辑页面
+ if (parentDeptType === null) {
+ this.deptTypeEnableValue = this.deptTypeOptions.filter(function (item) { return item.dictValue === 'org' })
+ .map(function (item) { return item.dictValue })
+ }
+ // 编辑页面当切换上级部门后需要判断当前部门类型是否在可选集合,如果在类型保持不变,如果不在需要重新赋值
+ const deptType = this.form.deptType
+ const selectDeptType = this.deptTypeEnableValue.filter(function (item) { return item === deptType })
+ this.form.deptType = selectDeptType.length === 0 ? this.deptTypeEnableValue[0] : deptType
+ } else {
+ // 添加页面
+ this.form.deptType = this.deptTypeEnableValue[0]
+ }
+ },
+ /** 新增按钮操作 */
+ handleAdd (row) {
+ this.parentIdShow = true
+ this.oldParentId = ''
+ this.deptTypeEnableValue = this.deptTypeOptions.map(function (item) { return item.dictValue })
+ if (row !== undefined) {
+ this.currentRow = row
+ this.oldParentId = row.id
+ this.form.pid = { ids: row.id, names: row.name }
+ this.getDeptTypeEnableValue(row.deptType)
+ }
+ /** 获取最大编号 */
+ findMaxSort(row !== undefined ? row.id : '0').then(response => {
+ this.form.treeSort = response
+ })
+ this.$emit('getTreeselect')
+ this.formTitle = '添加部门'
+ this.open = true
+ },
+ setNodeData (data) {
+ this.currentRow.name = data.name
+ this.currentRow.deptCode = data.deptCode
+ this.currentRow.leader = data.leader
+ this.currentRow.phone = data.phone
+ this.currentRow.email = data.email
+ this.currentRow.status = data.status
+ this.currentRow.treeSort = data.treeSort
+ this.currentRow.createTime = data.createTime
+ this.currentRow.deptType = data.deptType
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row) {
+ this.currentRow = row
+ this.open = true
+ this.formTitle = '修改部门'
+ this.hasChild = row.children.length > 0
+ this.spinning = !this.spinning
+ const id = row.id
+ getDept(id).then(response => {
+ this.oldParentId = response.pid
+ this.form = response
+ if (response.pid !== '0') {
+ this.parentIdShow = true
+ this.getDeptTypeEnableValue(response.parentDeptType)
+ } else {
+ this.parentIdShow = false
+ this.getDeptTypeEnableValue(null)
+ }
+ if (response.deptType === 'company') {
+ this.selectScope = 'nonDept'
+ }
+ this.form.pid = { ids: response.pid, names: response.parentName }
+ this.spinning = !this.spinning
+ })
+ this.$emit('getTreeselect', row)
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ const saveForm = JSON.parse(JSON.stringify(this.form))
+ if (this.form.pid !== undefined) {
+ saveForm.pid = this.form.pid.ids
+ }
+ if (this.form.id !== undefined) {
+ updateDept(saveForm).then(response => {
+ this.$message.success(
+ '修改成功',
+ 3
+ )
+ if (this.oldParentId !== this.form.pid.ids) {
+ // 如果修改父节点则刷新树
+ this.$emit('ok')
+ } else {
+ this.setNodeData(response)
+ }
+ this.cancel()
+ })
+ } else {
+ addDept(saveForm).then(response => {
+ this.$message.success(
+ '新增成功',
+ 3
+ )
+ // 修改父节点后刷新整个树,如果直接添加子节点不更换父节点则追加节点
+ if (this.oldParentId !== this.form.pid.ids) {
+ // 如果修改父节点则刷新树
+ this.$emit('ok')
+ } else {
+ this.appendTreeNode(this.currentRow, response)
+ }
+ this.cancel()
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ onLoadData (treeNode) {
+ return new Promise(resolve => {
+ if (treeNode.dataRef.children) {
+ resolve()
+ return
+ }
+ listDeptTree(treeNode.dataRef.id, 1).then(response => {
+ treeNode.dataRef.children = response
+ resolve()
+ })
+ })
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/dict/DictDataIndex.vue b/hotgo-web/src/views/system/dict/DictDataIndex.vue
new file mode 100644
index 0000000..46535ac
--- /dev/null
+++ b/hotgo-web/src/views/system/dict/DictDataIndex.vue
@@ -0,0 +1,279 @@
+
+
+
+
+
+
+
{{ title }}
+
+ 新增
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+ {{ parseTime(record.created_at) }}
+
+
+
+ 修改
+
+
+
+ 删除
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/dict/DictIndex.vue b/hotgo-web/src/views/system/dict/DictIndex.vue
new file mode 100644
index 0000000..181e6cf
--- /dev/null
+++ b/hotgo-web/src/views/system/dict/DictIndex.vue
@@ -0,0 +1,360 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+ 删除
+
+
+ 导出
+
+
+ 刷新缓存
+
+
+
+
+
+
+
+
+
+ {{ parseTime(record.created_at) }}
+
+
+
+ 修改
+
+
+
+ 删除
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/dict/modules/DictDataAddForm.vue b/hotgo-web/src/views/system/dict/modules/DictDataAddForm.vue
new file mode 100644
index 0000000..e5302dc
--- /dev/null
+++ b/hotgo-web/src/views/system/dict/modules/DictDataAddForm.vue
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/dict/modules/DictDataEditForm.vue b/hotgo-web/src/views/system/dict/modules/DictDataEditForm.vue
new file mode 100644
index 0000000..0815a5b
--- /dev/null
+++ b/hotgo-web/src/views/system/dict/modules/DictDataEditForm.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/dict/modules/DictDataForm.js b/hotgo-web/src/views/system/dict/modules/DictDataForm.js
new file mode 100644
index 0000000..0bec452
--- /dev/null
+++ b/hotgo-web/src/views/system/dict/modules/DictDataForm.js
@@ -0,0 +1,129 @@
+import AntModal from '@/components/pt/dialog/AntModal'
+import { checkDictDataValueUnique, getData, saveData, findMaxSort } from '@/api/system/dict/data'
+export default {
+ name: 'CreateDataForm',
+ props: {
+ type: {
+ type: String,
+ required: true
+ },
+ statusOptions: {
+ type: Array,
+ required: true
+ },
+ title: String
+ },
+ components: {
+ AntModal
+ },
+ data () {
+ return {
+ loading: false,
+ formTitle: '',
+ // 表单参数
+ form: {
+ id: undefined,
+ label: undefined,
+ value: undefined,
+ sort: 0,
+ status: '1',
+ remark: undefined
+ },
+ open: false,
+ rules: {
+ label: [{ required: true, message: '数据标签不能为空', trigger: 'blur' }],
+ value: [{ required: true, message: '数据键值不能为空', trigger: 'blur' },
+ { validator: this.checkDictDataValueUnique }],
+ sort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {
+ },
+ created () {
+ },
+ computed: {
+ },
+ watch: {
+ },
+ methods: {
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ },
+ /** 新增按钮操作 */
+ handleAdd () {
+ this.reset()
+ /** 获取最大编号 */
+ findMaxSort(this.type).then(response => {
+ this.form.sort = response.sort
+ this.open = true
+ this.formTitle = '添加【' + this.title + '】子表数据'
+ this.form.type = this.type
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row) {
+ this.reset()
+ const dictCode = row.id
+ getData(dictCode).then(response => {
+ this.form = response
+ this.form.status = '' + response.status
+ this.open = true
+ this.formTitle = '修改【' + this.title + '】子表数据'
+ })
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ if (this.form.id !== undefined) {
+ saveData(this.form).then(response => {
+ this.$message.success(
+ '修改成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ } else {
+ saveData(this.form).then(response => {
+ this.$message.success(
+ '新增成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ checkDictDataValueUnique (rule, value, callback) {
+ const msg = '数据字典值已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ value: value,
+ type: this.type,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkDictDataValueUnique(checkData).then(response => {
+ if (response.is_unique) {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/dict/modules/DictTypeAddForm.vue b/hotgo-web/src/views/system/dict/modules/DictTypeAddForm.vue
new file mode 100644
index 0000000..fe9b39f
--- /dev/null
+++ b/hotgo-web/src/views/system/dict/modules/DictTypeAddForm.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/dict/modules/DictTypeEditForm.vue b/hotgo-web/src/views/system/dict/modules/DictTypeEditForm.vue
new file mode 100644
index 0000000..7ed253f
--- /dev/null
+++ b/hotgo-web/src/views/system/dict/modules/DictTypeEditForm.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/dict/modules/DictTypeForm.js b/hotgo-web/src/views/system/dict/modules/DictTypeForm.js
new file mode 100644
index 0000000..8dfc046
--- /dev/null
+++ b/hotgo-web/src/views/system/dict/modules/DictTypeForm.js
@@ -0,0 +1,114 @@
+import AntModal from '@/components/pt/dialog/AntModal'
+import { checkDictTypeUnique, getType, saveType } from '@/api/system/dict/type'
+
+export default {
+ name: 'CreateForm',
+ props: {
+ statusOptions: {
+ type: Array,
+ required: true
+ }
+ },
+ components: {
+ AntModal
+ },
+ data() {
+ return {
+ loading: false,
+ formTitle: '',
+ // 表单参数
+ form: {
+ id: undefined,
+ name: undefined,
+ type: undefined,
+ status: '1',
+ remark: undefined
+ },
+ open: false,
+ rules: {
+ name: [{ required: true, message: '字典名称不能为空', trigger: 'blur' }],
+ type: [{ required: true, message: '字典类型不能为空', trigger: 'blur' },
+ { validator: this.checkDictTypeUnique }]
+ }
+ }
+ },
+ filters: {},
+ created() {
+ },
+ computed: {},
+ watch: {},
+ methods: {
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 表单重置
+ reset() {
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ this.open = true
+ this.formTitle = '添加字典类型'
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row, ids) {
+ this.reset()
+ const dictId = row ? row.id : ids
+ getType(dictId).then(response => {
+ this.form = response
+ this.form.status = '' + response.status
+ this.open = true
+ this.formTitle = '修改【' + this.form.name + '】类型'
+ })
+ },
+ /** 提交按钮 */
+ submitForm: function() {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ if (this.form.id !== undefined) {
+ saveType(this.form).then(response => {
+ this.$message.success(
+ '修改成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ } else {
+ saveType(this.form).then(response => {
+ this.$message.success(
+ '新增成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ checkDictTypeUnique(rule, value, callback) {
+ const msg = '数据字典类型已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ type: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkDictTypeUnique(checkData).then(response => {
+ if (response.is_unique) {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/iconSelect/IconSelect.vue b/hotgo-web/src/views/system/iconSelect/IconSelect.vue
new file mode 100644
index 0000000..6af697d
--- /dev/null
+++ b/hotgo-web/src/views/system/iconSelect/IconSelect.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/menu/MenuIndex.vue b/hotgo-web/src/views/system/menu/MenuIndex.vue
new file mode 100644
index 0000000..88fd22c
--- /dev/null
+++ b/hotgo-web/src/views/system/menu/MenuIndex.vue
@@ -0,0 +1,449 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ text.substr(0, text.indexOf(queryParam.name)) }}
+ {{ queryParam.name }}
+ {{ text.substr(text.indexOf(queryParam.name) + queryParam.name.length) }}
+
+ {{ text }}
+
+
+
+ {{ text }}
+
+
+
+
+ {{ menuTypeFormat(record) }}
+
+
+
+
+
+
+ {{ visibleFormat(record) }}
+
+
+
+ 修改
+
+
+
+ 添加子菜单
+
+
+
+ 删除
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/menu/modules/MenuAddForm.vue b/hotgo-web/src/views/system/menu/modules/MenuAddForm.vue
new file mode 100644
index 0000000..bbd0191
--- /dev/null
+++ b/hotgo-web/src/views/system/menu/modules/MenuAddForm.vue
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.menuTypeLabel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 是
+ 否
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ d.label
+ }}
+
+
+
+
+
+
+ {{
+ d.label
+ }}
+
+
+
+
+
+
+ 缓存
+ 不缓存
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/menu/modules/MenuEditForm.vue b/hotgo-web/src/views/system/menu/modules/MenuEditForm.vue
new file mode 100644
index 0000000..335acb6
--- /dev/null
+++ b/hotgo-web/src/views/system/menu/modules/MenuEditForm.vue
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+ {{ d.menuTypeLabel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 是
+ 否
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ d.label
+ }}
+
+
+
+
+ {{
+ d.label
+ }}
+
+
+
+
+ 缓存
+ 不缓存
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/menu/modules/MenuForm.js b/hotgo-web/src/views/system/menu/modules/MenuForm.js
new file mode 100644
index 0000000..809ad0c
--- /dev/null
+++ b/hotgo-web/src/views/system/menu/modules/MenuForm.js
@@ -0,0 +1,272 @@
+import { getMenu, saveMenu, checkMenuNameUnique, findMaxSort, checkMenuCodeUnique } from '@/api/system/menu'
+import allIcon from '@/core/icons'
+import icons from '@/utils/requireIcons'
+import IconSelector from '@/components/IconSelector'
+import AntModal from '@/components/pt/dialog/AntModal'
+
+export default {
+ name: 'CreateForm',
+ props: {
+ statusOptions: {
+ type: Array,
+ required: true
+ },
+ visibleOptions: {
+ type: Array,
+ required: true
+ },
+ menuOptions: {
+ type: Array,
+ required: true
+ },
+ menuTypeOptions: {
+ type: Array,
+ required: true
+ }
+ },
+ components: {
+ IconSelector,
+ AntModal
+ },
+ data () {
+ return {
+ SelectIcon: 'down',
+ allIcon,
+ iconVisible: false,
+ iconList: icons,
+ loading: false,
+ formTitle: '',
+ currentRow: undefined,
+ oldPid: '',
+ spinning: false,
+ delayTime: 200,
+ menuTypeEnableValue: [],
+ // 表单参数
+ form: {
+ id: undefined,
+ pid: 0,
+ name: undefined,
+ icon: 'smile',
+ type: 'M',
+ sort: 0,
+ is_frame: '1',
+ is_cache: '2',
+ is_visible: '2',
+ status: '1'
+ },
+ open: false,
+ rules: {
+ name: [{ required: true, message: '菜单名称不能为空', trigger: 'blur' },
+ { validator: this.checkMenuNameUnique }],
+ code: [{ required: true, message: '菜单编码不能为空', trigger: 'blur' },
+ { validator: this.checkMenuCodeUnique }],
+ sort: [{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }],
+ path: [{ required: true, message: '路由地址不能为空', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {},
+ created () {},
+ computed: {},
+ watch: {},
+ methods: {
+ onMenuTreeChange (pid, label, extra) {
+ const type = extra.triggerNode.$options.propsData.dataRef.type
+ findMaxSort(pid !== undefined ? pid : '0').then(response => {
+ this.form.sort = response.sort
+ })
+ if (type !== undefined) {
+ this.getMenuTypeEnableValue(type)
+ } else {
+ this.menuTypeEnableValue = this.menuTypeOptions.map(function (item) { return item.menuTypeValue })
+ }
+ },
+ filterIcons () {
+ this.iconList = icons
+ if (this.name) {
+ this.iconList = this.iconList.filter(item => item.includes(this.name))
+ }
+ },
+ hideIconSelect () {
+ this.iconList = icons
+ this.iconVisible = false
+ },
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.iconVisible = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ },
+ getMenuTypeEnableValue (parentMenuType) {
+ const id = this.form.id
+ // if (parentMenuType === 'M' || parentMenuType === 'C') {
+ if (parentMenuType === 'M') {
+ this.menuTypeEnableValue = this.menuTypeOptions.map(function (item) { return item.menuTypeValue })
+ } else if (parentMenuType === 'C') {
+ this.menuTypeEnableValue = this.menuTypeOptions.filter(function (item) { return item.menuTypeValue !== 'M' })
+ .map(function (item) { return item.menuTypeValue })
+ } else {
+ this.menuTypeEnableValue = this.menuTypeOptions.filter(function (item) { return item.menuTypeValue === 'F' })
+ .map(function (item) { return item.menuTypeValue })
+ }
+ if (id !== null && id !== '' && id !== 'undefined' && id !== undefined) {
+ // 编辑页面
+ if (parentMenuType === null) {
+ this.menuTypeEnableValue = this.menuTypeOptions.filter(function (item) { return item.menuTypeValue === 'M' })
+ .map(function (item) { return item.menuTypeValue })
+ }
+ // 编辑页面当切换上级部门后需要判断当前部门类型是否在可选集合,如果在类型保持不变,如果不在需要重新赋值
+ const menuType = this.form.type
+ const selectMenuType = this.menuTypeEnableValue.filter(function (item) { return item === menuType })
+ this.form.type = selectMenuType.length === 0 ? this.menuTypeEnableValue[0] : menuType
+ } else {
+ // 添加页面
+ this.form.type = this.menuTypeEnableValue[0]
+ }
+ },
+ /** 新增按钮操作 */
+ handleAdd (row) {
+ this.reset()
+ /** 获取最大编号 */
+ findMaxSort(row !== undefined ? row.id : '0').then(response => {
+ this.form.sort = response.sort
+ })
+ this.menuTypeEnableValue = this.menuTypeOptions.map(function (item) { return item.menuTypeValue })
+ this.$emit('select-tree')
+ this.oldPid = ''
+ if (row != null && row.id) {
+ this.currentRow = row
+ this.oldPid = row.id
+ this.form.pid = row.id
+ this.getMenuTypeEnableValue(row.type)
+ } else {
+ this.form.pid = 0
+ }
+ this.open = true
+ this.formTitle = '添加菜单'
+ },
+ setNodeData (data) {
+ this.currentRow.name = data.name
+ this.currentRow.code = data.code
+ this.currentRow.icon = data.icon
+ this.currentRow.sort = data.sort
+ this.currentRow.type = data.type
+ this.currentRow.is_visible = data.is_visible
+ this.currentRow.perms = data.perms
+ this.currentRow.component = data.component
+ this.currentRow.status = data.status
+ this.currentRow.created_at = data.created_at
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row) {
+ this.spinning = !this.spinning
+ this.open = true
+ this.formTitle = '修改菜单'
+ this.currentRow = row
+ this.reset()
+ this.$emit('select-tree')
+ getMenu(row.id).then(response => {
+ this.oldPid = response.pid
+ this.form = response
+ this.spinning = !this.spinning
+ this.menuTypeEnableValue = [response.type]
+ })
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ this.spinning = !this.spinning
+ if (this.form.id !== undefined) {
+ saveMenu(this.form).then(response => {
+ this.$message.success('修改成功', 3)
+ if (this.oldPid !== this.form.pid) {
+ // 如果修改父节点则刷新树
+ this.$emit('ok')
+ } else {
+ this.setNodeData(this.form)
+ }
+ this.cancel()
+ })
+ } else {
+ saveMenu(this.form).then(response => {
+ this.$message.success('新增成功', 3)
+ // 修改父节点后刷新整个树,如果直接添加子节点不更换父节点则追加节点
+ if (this.oldPid !== this.form.pid) {
+ // 如果修改父节点则刷新树
+ this.$emit('ok')
+ } else {
+ console.log('this.currentRow:' + JSON.stringify(this.currentRow))
+ console.log('this.form:' + JSON.stringify(this.form))
+ this.appendTreeNode(this.currentRow, this.form)
+ }
+ this.cancel()
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ handleIconChange (icon) {
+ this.SelectIcon = 'down'
+ this.iconVisible = false
+ this.form.icon = icon
+ },
+ changeIcon (type) {
+ this.currentSelectedIcon = type
+ },
+ selectIcon () {
+ this.iconVisible = !this.iconVisible
+ if (this.iconVisible) {
+ this.SelectIcon = 'up'
+ } else {
+ this.SelectIcon = 'down'
+ }
+ },
+ cancelSelectIcon () {
+ this.iconVisible = false
+ },
+ checkMenuNameUnique (rule, value, callback) {
+ const msg = '菜单名称已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ name: value,
+ pid: this.form.pid !== undefined ? this.form.pid : '',
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkMenuNameUnique(checkData).then(response => {
+ if (response.is_unique) {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ },
+ checkMenuCodeUnique (rule, value, callback) {
+ const msg = '路由地址已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ code: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkMenuCodeUnique(checkData).then(response => {
+ if (response.is_unique) {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/notice/NoticeIndex.vue b/hotgo-web/src/views/system/notice/NoticeIndex.vue
new file mode 100644
index 0000000..852a0ab
--- /dev/null
+++ b/hotgo-web/src/views/system/notice/NoticeIndex.vue
@@ -0,0 +1,295 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ typeFormat(record) }}
+
+
+
+
+
+
+ {{ parseTime(record.created_at, '{y}-{m}-{d}') }}
+
+
+
+ 修改
+
+
+
+ 删除
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/notice/NoticeReadIndex.vue b/hotgo-web/src/views/system/notice/NoticeReadIndex.vue
new file mode 100644
index 0000000..561dc8a
--- /dev/null
+++ b/hotgo-web/src/views/system/notice/NoticeReadIndex.vue
@@ -0,0 +1,290 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ typeFormat(record) }}
+
+
+
+
+
+
+ {{ parseTime(record.createTime, '{y}-{m}-{d}') }}
+
+
+
+ 阅读
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/notice/modules/NoticeAddForm.vue b/hotgo-web/src/views/system/notice/modules/NoticeAddForm.vue
new file mode 100644
index 0000000..11a9c8e
--- /dev/null
+++ b/hotgo-web/src/views/system/notice/modules/NoticeAddForm.vue
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 发布
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/notice/modules/NoticeEditForm.vue b/hotgo-web/src/views/system/notice/modules/NoticeEditForm.vue
new file mode 100644
index 0000000..f8223e9
--- /dev/null
+++ b/hotgo-web/src/views/system/notice/modules/NoticeEditForm.vue
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/notice/modules/NoticeForm.js b/hotgo-web/src/views/system/notice/modules/NoticeForm.js
new file mode 100644
index 0000000..1ed248b
--- /dev/null
+++ b/hotgo-web/src/views/system/notice/modules/NoticeForm.js
@@ -0,0 +1,229 @@
+import AntModal from '@/components/pt/dialog/AntModal'
+import { getNotice, saveNotice, getNoticeView } from '@/api/system/notice'
+import Vditor from 'vditor'
+import 'vditor/dist/index.css'
+export default {
+ name: 'CreateForm',
+ props: {
+ typeOptions: {
+ type: Array,
+ required: true
+ },
+ statusOptions: {
+ type: Array,
+ required: true
+ }
+ },
+ components: {
+ AntModal,
+ Vditor
+ },
+ data () {
+ return {
+ open: false,
+ attachmentRefName: 'addUploaderFile', // 标志表单是否含有附件
+ editAttachmentRefName: 'editUploaderFile',
+ attachmentUploadStatus: true, // 记录的附件的上传状态
+ uploaderButtonStatus: false, // 附件上传时按钮状态
+ formId: '',
+ labelCol: { span: 4 },
+ wrapperCol: { span: 14 },
+ loading: false,
+ total: 0,
+ id: undefined,
+ formTitle: '',
+ contentEditorEdit: '',
+ // 表单参数
+ form: {
+ id: undefined,
+ title: undefined,
+ type: undefined,
+ content: '',
+ status: '0'
+ },
+ rules: {
+ title: [{ required: true, message: '公告标题不能为空', trigger: 'blur' }],
+ type: [{ required: true, message: '公告类型不能为空', trigger: 'change' }]
+ },
+ vditorToolbar: [// 将上传图片和录音按钮隐藏
+ 'emoji',
+ 'headings',
+ 'bold',
+ 'italic',
+ 'strike',
+ 'link',
+ '|',
+ 'list',
+ 'ordered-list',
+ 'check',
+ 'outdent',
+ 'indent',
+ '|',
+ 'quote',
+ 'line',
+ 'code',
+ 'inline-code',
+ 'insert-before',
+ 'insert-after',
+ '|',
+ 'table',
+ '|',
+ 'undo',
+ 'redo',
+ '|',
+ 'fullscreen',
+ 'edit-mode',
+ {
+ 'name': 'more',
+ 'toolbar': [
+ 'both',
+ 'code-theme',
+ 'content-theme',
+ 'export',
+ 'outline',
+ 'preview',
+ 'devtools'
+ ]
+ }
+ ]
+ }
+ },
+ filters: {
+ },
+ created () {
+ },
+ computed: {
+ },
+ watch: {
+ },
+ mounted () {
+ },
+ methods: {
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ this.form = {
+ id: undefined,
+ title: undefined,
+ type: undefined,
+ content: '',
+ status: '0'
+ }
+ if (this.formId) {
+ // 清空附件的formId
+ this.formId = ''
+ }
+ },
+ handleAdd () {
+ this.reset()
+ this.open = true
+ this.formTitle = '添加公告'
+ this.$nextTick(() => {
+ if (this.contentEditorEdit === '') {
+ this.contentEditorEdit = new Vditor('vditor', {
+ height: 180,
+ toolbarConfig: {
+ pin: true
+ },
+ toolbar: this.vditorToolbar,
+ cache: {
+ enable: false
+ },
+ after: () => {
+ this.contentEditorEdit.setValue(this.form.content)
+ }
+ })
+ } else {
+ this.contentEditorEdit.setValue(this.form.content)
+ }
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row) {
+ this.reset()
+ const noticeId = row.id
+ getNotice(noticeId).then(response => {
+ this.open = true
+ this.form = response
+ this.formId = response.id
+ this.formTitle = '修改公告'
+ this.$nextTick(() => {
+ if (this.contentEditorEdit === '') {
+ this.contentEditorEdit = new Vditor('vditorEdit', {
+ height: 360,
+ toolbarConfig: {
+ pin: true
+ },
+ toolbar: this.vditorToolbar,
+ cache: {
+ enable: false
+ },
+ after: () => {
+ this.contentEditorEdit.setValue(response.content)
+ }
+ })
+ } else {
+ this.contentEditorEdit.setValue(response.content)
+ }
+ })
+ })
+ },
+ handleView (row) {
+ this.reset()
+ const noticeId = row.id
+ getNoticeView(noticeId).then(response => {
+ this.open = true
+ this.$nextTick(() => (
+ this.$refs.antModalRef.setMaxDiolog()
+ ))
+ this.form = response
+ this.form.createByName = row.createByName
+ this.formId = response.id
+ this.formTitle = '公告详情'
+ this.$emit('ok')
+ })
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ const that = this
+ this.form.content = this.contentEditorEdit.getValue()
+ this.form.contentHtml = this.contentEditorEdit.getHTML()
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ this.uploaderButtonStatus = true
+ if (this.form.id !== undefined) {
+ saveNotice(this.form).then(response => {
+ this.$message.success(
+ '修改成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ this.$emit('close')
+ })
+ } else {
+ saveNotice(this.form).then(response => {
+ that.$message.success(
+ '新增成功',
+ 3
+ )
+ that.open = false
+ that.$emit('ok')
+ this.$emit('close')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ back () {
+ this.$router.push('/system/notice')
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/notice/modules/NoticeViewForm.vue b/hotgo-web/src/views/system/notice/modules/NoticeViewForm.vue
new file mode 100644
index 0000000..502a57b
--- /dev/null
+++ b/hotgo-web/src/views/system/notice/modules/NoticeViewForm.vue
@@ -0,0 +1,65 @@
+
+
+
+
+
{{ form.noticeTitle }}({{ form.noticeType === '1' ? '通知' : '公告' }})
+ 发布人:{{ form.createByName }}
+ 发布时间:{{ form.createTime }}
+
+
+
+
+ {{ form.noticeContentHtml }}
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/post/PostIndex.vue b/hotgo-web/src/views/system/post/PostIndex.vue
new file mode 100644
index 0000000..826f593
--- /dev/null
+++ b/hotgo-web/src/views/system/post/PostIndex.vue
@@ -0,0 +1,332 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+ {{ parseTime(record.created_at) }}
+
+
+
+ 修改
+
+
+
+ 删除
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/post/modules/PostAddForm.vue b/hotgo-web/src/views/system/post/modules/PostAddForm.vue
new file mode 100644
index 0000000..3fd91b8
--- /dev/null
+++ b/hotgo-web/src/views/system/post/modules/PostAddForm.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/post/modules/PostEditForm.vue b/hotgo-web/src/views/system/post/modules/PostEditForm.vue
new file mode 100644
index 0000000..a952bd0
--- /dev/null
+++ b/hotgo-web/src/views/system/post/modules/PostEditForm.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/post/modules/PostForm.js b/hotgo-web/src/views/system/post/modules/PostForm.js
new file mode 100644
index 0000000..6d79012
--- /dev/null
+++ b/hotgo-web/src/views/system/post/modules/PostForm.js
@@ -0,0 +1,140 @@
+import { getPost, savePost, checkPostCodeUnique, findMaxSort, checkPostNameUnique } from '@/api/system/post'
+import AntModal from '@/components/pt/dialog/AntModal'
+export default {
+ name: 'CreateForm',
+ props: {
+ statusOptions: {
+ type: Array,
+ required: true
+ }
+ },
+ components: {
+ AntModal
+ },
+ data () {
+ return {
+ loading: false,
+ formTitle: '',
+ // 表单参数
+ form: {
+ id: undefined,
+ postCode: undefined,
+ postName: undefined,
+ sort: 0,
+ status: '1',
+ remark: undefined
+ },
+ open: false,
+ rules: {
+ name: [{ required: true, message: '岗位名称不能为空', trigger: 'blur' },
+ { validator: this.checkPostNameUnique }],
+ code: [{ required: true, message: '岗位编码不能为空', trigger: 'blur' },
+ { validator: this.checkPostCodeUnique }],
+ sort: [{ required: true, message: '显示顺序不能为空', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {
+ },
+ created () {
+ },
+ computed: {
+ },
+ watch: {
+ },
+ methods: {
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ },
+ /** 新增按钮操作 */
+ handleAdd () {
+ this.reset()
+ /** 获取最大编号 */
+ findMaxSort().then(response => {
+ this.form.sort = response.sort
+ this.open = true
+ this.formTitle = '添加岗位'
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row, ids) {
+ this.reset()
+ const postId = row ? row.id : ids
+ getPost(postId).then(response => {
+ this.form = response
+ this.open = true
+ this.formTitle = '修改岗位'
+ })
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ if (this.form.id !== undefined) {
+ savePost(this.form).then(response => {
+ this.$message.success(
+ '修改成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ } else {
+ savePost(this.form).then(response => {
+ this.$message.success(
+ '新增成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ checkPostCodeUnique (rule, value, callback) {
+ const msg = '岗位编码已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ code: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkPostCodeUnique(checkData).then(response => {
+ if (response.is_unique) {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ },
+ checkPostNameUnique (rule, value, callback) {
+ const msg = '岗位名称已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ name: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkPostNameUnique(checkData).then(response => {
+ if (response.is_unique) {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/role/QueryList.vue b/hotgo-web/src/views/system/role/QueryList.vue
new file mode 100644
index 0000000..16c26b4
--- /dev/null
+++ b/hotgo-web/src/views/system/role/QueryList.vue
@@ -0,0 +1,691 @@
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+ 保存
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+ 点击修改状态
+
+
+ 确认{{ record.status === '1' ? '启用' : '停用' }} 【{{ record.name }}】的角色吗?
+
+
+
+
+
+
+
+ {{ text }}
+
+
+
+
+
+ {{ text }}
+
+
+
+
+
+ {{ text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ text }}
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/role/SysRoleAuth.vue b/hotgo-web/src/views/system/role/SysRoleAuth.vue
new file mode 100644
index 0000000..1bfe95e
--- /dev/null
+++ b/hotgo-web/src/views/system/role/SysRoleAuth.vue
@@ -0,0 +1,453 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/role/SysRoleIndex.vue b/hotgo-web/src/views/system/role/SysRoleIndex.vue
new file mode 100644
index 0000000..c608761
--- /dev/null
+++ b/hotgo-web/src/views/system/role/SysRoleIndex.vue
@@ -0,0 +1,360 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+ {{ advanced ? '收起' : '展开' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+
+ {{ text }}
+
+
+
+
+ 修改
+
+
+
+ 数据权限
+
+
+
+ 删除
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/role/modules/CreateDataScopeForm.vue b/hotgo-web/src/views/system/role/modules/CreateDataScopeForm.vue
new file mode 100644
index 0000000..b48eca6
--- /dev/null
+++ b/hotgo-web/src/views/system/role/modules/CreateDataScopeForm.vue
@@ -0,0 +1,293 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.label }}
+
+
+
+
+ 展开/折叠
+
+
+ 全选/全不选
+
+
+ 父子联动
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/role/modules/DataScope.vue b/hotgo-web/src/views/system/role/modules/DataScope.vue
new file mode 100644
index 0000000..f9df981
--- /dev/null
+++ b/hotgo-web/src/views/system/role/modules/DataScope.vue
@@ -0,0 +1,324 @@
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/role/modules/PortletScope.vue b/hotgo-web/src/views/system/role/modules/PortletScope.vue
new file mode 100644
index 0000000..d072c5f
--- /dev/null
+++ b/hotgo-web/src/views/system/role/modules/PortletScope.vue
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+ 确认{{ record.menuId !== null ? '取消' : '给' }} 该小页授权吗?
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/role/modules/SysRoleAddForm.vue b/hotgo-web/src/views/system/role/modules/SysRoleAddForm.vue
new file mode 100644
index 0000000..ca9e1ec
--- /dev/null
+++ b/hotgo-web/src/views/system/role/modules/SysRoleAddForm.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+
+ 展开/折叠
+
+
+ 全选/全不选
+
+
+ 父子联动
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+ 取消
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/role/modules/SysRoleEditForm.vue b/hotgo-web/src/views/system/role/modules/SysRoleEditForm.vue
new file mode 100644
index 0000000..5751189
--- /dev/null
+++ b/hotgo-web/src/views/system/role/modules/SysRoleEditForm.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+ 展开/折叠
+
+
+ 全选/全不选
+
+
+ 父子联动
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/role/modules/SysRoleForm.js b/hotgo-web/src/views/system/role/modules/SysRoleForm.js
new file mode 100644
index 0000000..12244ce
--- /dev/null
+++ b/hotgo-web/src/views/system/role/modules/SysRoleForm.js
@@ -0,0 +1,285 @@
+import { getRole, addRole, updateRole, checkRoleNameUnique, checkRoleKeyUnique, findMaxSort } from '@/api/system/role'
+import { treeselect as menuTreeselect, roleMenuTreeselect } from '@/api/system/menu'
+import AntModal from '@/components/pt/dialog/AntModal'
+
+export default {
+ name: 'CreateForm',
+ props: {
+ statusOptions: {
+ type: Array,
+ required: true
+ }
+ },
+ components: {
+ AntModal
+ },
+ data () {
+ return {
+ loading: false,
+ spinning: false,
+ delayTime: 200,
+ menuExpandedKeys: [],
+ autoExpandParent: false,
+ menuCheckedKeys: [],
+ halfCheckedKeys: [],
+ menuOptions: [],
+ formTitle: '',
+ // 表单参数
+ form: {
+ roleId: undefined,
+ roleName: undefined,
+ roleKey: undefined,
+ sort: 0,
+ status: '0',
+ menuIds: [],
+ menuCheckStrictly: true,
+ remark: undefined
+ },
+ open: false,
+ menuExpand: false,
+ menuNodeAll: false,
+ rules: {
+ roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' },
+ { validator: this.checkRoleNameUnique }],
+ roleKey: [{ required: true, message: '角色编码不能为空', trigger: 'blur' },
+ { validator: this.checkRoleKeyUnique }],
+ sort: [{ required: true, message: '显示顺序不能为空', trigger: 'blur' }]
+ },
+ defaultProps: {
+ children: 'children',
+ title: 'label',
+ key: 'id'
+ }
+ }
+ },
+ filters: {
+ },
+ created () {
+ },
+ computed: {
+ },
+ watch: {
+ },
+ methods: {
+ onExpandMenu (expandedKeys) {
+ this.menuExpandedKeys = expandedKeys
+ this.autoExpandParent = false
+ },
+ /** 查询菜单树结构 */
+ getMenuTreeselect () {
+ return menuTreeselect(0, 10).then(response => {
+ return response
+ })
+ },
+ // 所有菜单节点数据
+ getMenuAllCheckedKeys () {
+ // 全选与半选
+ return Array.from(new Set(this.menuCheckedKeys.concat(this.halfCheckedKeys)))
+ },
+ getAllMenuNode (nodes) {
+ if (!nodes || nodes.length === 0) {
+ return []
+ }
+ nodes.forEach(node => {
+ this.menuCheckedKeys.push(node.id)
+ return this.getAllMenuNode(node.children)
+ })
+ },
+ // 回显过滤
+ selectNodefilter (nodes, parentIds) {
+ if (!nodes || nodes.length === 0) {
+ return []
+ }
+ nodes.forEach(node => {
+ // 父子关联模式且当前元素有父级
+ const currentIndex = this.menuCheckedKeys.indexOf(node.id)
+ // 当前节点存在,且父节点不存在,则说明父节点应是半选中状态
+ if (currentIndex !== -1) {
+ parentIds.forEach(parentId => {
+ if (this.halfCheckedKeys.indexOf(parentId) === -1) {
+ this.halfCheckedKeys.push(parentId)
+ }
+ })
+ parentIds = []
+ }
+ // 防重
+ const isExist = this.halfCheckedKeys.indexOf(node.id)
+ const isExistParentIds = parentIds.indexOf(node.id)
+ if (isExist === -1 && isExistParentIds === -1 && currentIndex === -1) {
+ parentIds.push(node.id)
+ }
+ return this.selectNodefilter(node.children, parentIds)
+ })
+ },
+ handleCheckedTreeNodeAll (value) {
+ this.menuNodeAll = !this.menuNodeAll
+ if (value.target.checked) {
+ this.getAllMenuNode(this.menuOptions)
+ } else {
+ this.menuCheckedKeys = []
+ this.halfCheckedKeys = []
+ }
+ },
+ handleCheckedTreeExpand (value) {
+ this.menuExpand = !this.menuExpand
+ if (value.target.checked) {
+ const treeList = this.menuOptions
+ this.treeExpandWithLevel(treeList, -1)
+ } else {
+ this.menuExpandedKeys = []
+ this.treeExpandWithLevel(this.menuOptions, 1)
+ }
+ },
+ treeExpandWithLevel (treeNodeList, level) {
+ level--
+ if (level !== 0) {
+ treeNodeList.forEach(node => {
+ this.menuExpandedKeys.push(node.id)
+ if (node.children) {
+ this.treeExpandWithLevel(node.children, level)
+ }
+ })
+ }
+ },
+ // 树权限(父子联动)
+ handleCheckedTreeConnect (value) {
+ this.form.menuCheckStrictly = !this.form.menuCheckStrictly
+ },
+ /** 根据角色ID查询菜单树结构 */
+ getRoleMenuTreeselect (roleId) {
+ return roleMenuTreeselect(roleId).then(response => {
+ return response
+ })
+ },
+ onCheck (checkedKeys, info) {
+ if (!this.form.menuCheckStrictly) {
+ let currentCheckedKeys = []
+ if (this.menuCheckedKeys.checked) {
+ currentCheckedKeys = Array.from(new Set(currentCheckedKeys.concat(this.menuCheckedKeys.checked)))
+ }
+ if (this.menuCheckedKeys.halfChecked) {
+ currentCheckedKeys = Array.from(new Set(currentCheckedKeys.concat(this.menuCheckedKeys.halfChecked)))
+ }
+ this.menuCheckedKeys = currentCheckedKeys
+ } else {
+ // 半选节点
+ this.halfCheckedKeys = info.halfCheckedKeys
+ this.menuCheckedKeys = checkedKeys
+ }
+ },
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ },
+ /** 新增按钮操作 */
+ handleAdd () {
+ this.reset()
+ /** 获取最大编号 */
+ findMaxSort().then(response => {
+ this.form.sort = response.data
+ })
+ const roleMenu = this.getMenuTreeselect()
+ roleMenu.then(res => {
+ this.menuOptions = res.data
+ this.treeExpandWithLevel(this.menuOptions, 1)
+ })
+ this.open = true
+ this.formTitle = '添加角色'
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row, ids) {
+ this.open = true
+ this.spinning = !this.spinning
+ this.reset()
+ this.menuExpand = false
+ this.menuNodeAll = false
+ const roleId = row ? row.id : ids
+ const roleMenu = this.getRoleMenuTreeselect(roleId)
+ getRole(roleId).then(response => {
+ this.form = response.data
+ })
+ roleMenu.then(res => {
+ this.menuOptions = res.data.menus
+ this.menuCheckedKeys = res.data.checkedKeys
+ // 过滤回显时的半选中node(父)
+ if (this.form.menuCheckStrictly) {
+ this.selectNodefilter(this.menuOptions, [])
+ }
+ this.treeExpandWithLevel(this.menuOptions, 1)
+ })
+ this.formTitle = '修改角色'
+ this.spinning = !this.spinning
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ if (this.form.id !== undefined) {
+ this.form.menuIds = this.getMenuAllCheckedKeys()
+ updateRole(this.form).then(response => {
+ this.$message.success(
+ '修改成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ } else {
+ this.form.menuIds = this.getMenuAllCheckedKeys()
+ addRole(this.form).then(response => {
+ this.$message.success(
+ '新增成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ checkRoleNameUnique (rule, value, callback) {
+ const msg = '角色名称已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ roleName: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkRoleNameUnique(checkData).then(response => {
+ if (response.data.code === '1') {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ },
+ checkRoleKeyUnique (rule, value, callback) {
+ const msg = '角色编码已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ roleKey: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkRoleKeyUnique(checkData).then(response => {
+ if (response.data.code === '1') {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/sysportalconfig/modules/SysPortalConfigAddForm.vue b/hotgo-web/src/views/system/sysportalconfig/modules/SysPortalConfigAddForm.vue
new file mode 100644
index 0000000..1830e04
--- /dev/null
+++ b/hotgo-web/src/views/system/sysportalconfig/modules/SysPortalConfigAddForm.vue
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.dictLabel }}
+
+
+
+
+
+
+
+
+ {{ dict.dictLabel }}
+
+
+
+
+
+
+
+
+ {{ d.roleName }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/sysportalconfig/modules/SysPortalConfigEditForm.vue b/hotgo-web/src/views/system/sysportalconfig/modules/SysPortalConfigEditForm.vue
new file mode 100644
index 0000000..3963394
--- /dev/null
+++ b/hotgo-web/src/views/system/sysportalconfig/modules/SysPortalConfigEditForm.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.dictLabel }}
+
+
+
+
+
+
+
+
+ {{ dict.dictLabel }}
+
+
+
+
+
+
+
+
+ {{ d.roleName }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/sysportalconfig/modules/SysPortalConfigForm.js b/hotgo-web/src/views/system/sysportalconfig/modules/SysPortalConfigForm.js
new file mode 100644
index 0000000..d361db7
--- /dev/null
+++ b/hotgo-web/src/views/system/sysportalconfig/modules/SysPortalConfigForm.js
@@ -0,0 +1,159 @@
+import AntModal from '@/components/pt/dialog/AntModal'
+import { getSysPortalConfig, addSysPortalConfig, updateSysPortalConfig, checkCodeUnique } from '@/api/system/sysPortalConfig'
+import SelectUser from '@/components/pt/selectUser/SelectUser'
+export default {
+ name: 'CreateForm',
+ props: {
+ applicationRangeOptions: {
+ type: Array,
+ required: true
+ },
+ isDefaultOptions: {
+ type: Array,
+ required: true
+ }
+ },
+ components: {
+ AntModal,
+ SelectUser
+ },
+ data () {
+ const validateCode = (rule, value, callback) => {
+ if (value === '' || value === undefined || value === null) {
+ callback(new Error('小页编码不允许为空'))
+ } else {
+ checkCodeUnique(this.form.id, this.form.code)
+ callback()
+ }
+ }
+ return {
+ open: false,
+ spinning: false,
+ delayTime: 100,
+ labelCol: { span: 4 },
+ wrapperCol: { span: 14 },
+ loading: false,
+ roleOptions: [],
+ isShowResourceId: true,
+ total: 0,
+ id: undefined,
+ formTitle: '添加多栏目门户配置',
+ // 表单参数
+ form: {},
+ rules: {
+ name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
+ code: [{ required: true, message: '编码不能为空', validator: validateCode, trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {},
+ created () {},
+ computed: {},
+ watch: {
+ },
+ mounted () {},
+ methods: {
+ rangeChange (e) {
+ const applicationRange = this.form.applicationRange
+ if (applicationRange === 'R' || applicationRange === 'U') {
+ this.isShowResourceId = true
+ } else {
+ this.isShowResourceId = false
+ }
+ this.form.systemDefinedId = ''
+ },
+ onClose () {
+ this.open = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ this.form = {
+ id: undefined,
+ name: undefined,
+ code: undefined,
+ applicationRange: 'R',
+ isDefault: 'N',
+ resourceId: undefined,
+ systemDefinedId: undefined,
+ content: undefined,
+ sort: undefined,
+ status: undefined
+ }
+ },
+ /** 新增按钮操作 */
+ handleAdd () {
+ this.reset()
+ this.open = true
+ this.formTitle = '添加多栏目门户配置'
+ getSysPortalConfig().then(response => {
+ this.roleOptions = response.data.roles
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row) {
+ this.reset()
+ this.open = true
+ this.spinning = !this.spinning
+ const sysPortalConfigId = row.id
+ getSysPortalConfig(sysPortalConfigId).then(response => {
+ this.form = response.data.data
+ this.rangeChange()
+ const applicationRange = this.form.applicationRange
+ if (applicationRange === 'U') {
+ let userIds = ''
+ let userNames = ''
+ response.data.listMap.forEach(node => {
+ userIds += node.id + ','
+ userNames += node.name + ','
+ })
+ userIds = userIds.substr(0, userIds.length - 1)
+ userNames = userNames.substr(0, userNames.length - 1)
+ this.form.resourceId = { ids: userIds, names: userNames }
+ }
+ this.roleOptions = response.data.roles
+ this.formTitle = '修改多栏目门户配置'
+ this.spinning = !this.spinning
+ })
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ const saveForm = JSON.parse(JSON.stringify(this.form))
+ if (this.form.resourceId !== undefined && this.form.applicationRange === 'U') {
+ saveForm.resourceId = this.form.resourceId.ids
+ }
+ if (this.form.id !== undefined) {
+ updateSysPortalConfig(saveForm).then(response => {
+ this.$message.success('新增成功', 3)
+ this.open = false
+ this.$emit('ok')
+ this.$emit('close')
+ })
+ } else {
+ addSysPortalConfig(saveForm).then(response => {
+ this.$message.success('新增成功', 3)
+ this.open = false
+ this.$emit('ok')
+ this.$emit('close')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ back () {
+ const index = '/system/sysportalconfig/index'
+ this.$router.push(index)
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/sysportlet/index.vue b/hotgo-web/src/views/system/sysportlet/index.vue
new file mode 100644
index 0000000..c6f7681
--- /dev/null
+++ b/hotgo-web/src/views/system/sysportlet/index.vue
@@ -0,0 +1,356 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+ 导出
+
+
+ 删除
+
+
+
+ {{ showTitleFormat(record) }}
+
+
+ {{ isAllowDragFormat(record) }}
+
+
+ {{ statusFormat(record) }}
+
+
+
+ 修改
+
+
+
+ 删除
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/sysportlet/modules/SysPortletAddForm.vue b/hotgo-web/src/views/system/sysportlet/modules/SysPortletAddForm.vue
new file mode 100644
index 0000000..3c193d3
--- /dev/null
+++ b/hotgo-web/src/views/system/sysportlet/modules/SysPortletAddForm.vue
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.dictLabel }}
+
+
+
+
+
+
+
+ 1行
+ 2/3行
+ 1/3行
+
+
+
+
+
+ px
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.dictLabel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/sysportlet/modules/SysPortletEditForm.vue b/hotgo-web/src/views/system/sysportlet/modules/SysPortletEditForm.vue
new file mode 100644
index 0000000..e2a9aac
--- /dev/null
+++ b/hotgo-web/src/views/system/sysportlet/modules/SysPortletEditForm.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.dictLabel }}
+
+
+
+
+
+
+
+ 1行
+ 2/3行
+ 1/3行
+
+
+
+
+
+ px
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.dictLabel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/sysportlet/modules/SysPortletForm.js b/hotgo-web/src/views/system/sysportlet/modules/SysPortletForm.js
new file mode 100644
index 0000000..59db23b
--- /dev/null
+++ b/hotgo-web/src/views/system/sysportlet/modules/SysPortletForm.js
@@ -0,0 +1,135 @@
+import AntModal from '@/components/pt/dialog/AntModal'
+import { getSysPortlet, addSysPortlet, updateSysPortlet, findMaxSort, checkCodeUnique } from '@/api/system/sysPortlet'
+
+export default {
+ name: 'CreateForm',
+ props: {
+ showTitleOptions: {
+ type: Array,
+ required: true
+ },
+ isAllowDragOptions: {
+ type: Array,
+ required: true
+ },
+ statusOptions: {
+ type: Array,
+ required: true
+ } },
+ components: {
+ AntModal },
+ data () {
+ const validateCode = (rule, value, callback) => {
+ if (value === '' || value === undefined || value === null) {
+ callback(new Error('小页编码不允许为空'))
+ } else {
+ checkCodeUnique(this.form.id, this.form.code)
+ callback()
+ }
+ }
+ return {
+ open: false,
+ spinning: false,
+ delayTime: 100,
+ labelCol: { span: 4 },
+ wrapperCol: { span: 14 },
+ loading: false,
+ total: 0,
+ id: undefined,
+ formTitle: '添加工作台小页管理',
+ // 表单参数
+ form: {
+ },
+ rules: {
+ name: [{ required: true, message: '小页名称不能为空', trigger: 'blur' }],
+ code: [{ required: true, message: '小页编码不能为空', validator: validateCode, trigger: 'blur' }],
+ status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {},
+ created () {},
+ computed: {},
+ watch: {},
+ mounted () {},
+ methods: {
+ onClose () {
+ this.open = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.reset()
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ this.form = {
+ id: undefined,
+ name: undefined,
+ code: undefined,
+ url: undefined,
+ refreshRate: undefined,
+ showTitle: 'N',
+ isAllowDrag: 'N',
+ xGridNumber: '2',
+ yGridNumber: 100,
+ sort: undefined,
+ status: '0'
+ }
+ },
+ /** 新增按钮操作 */
+ handleAdd () {
+ this.reset()
+ /** 获取最大编号 */
+ findMaxSort().then(response => {
+ this.form.sort = response.data
+ this.open = true
+ this.formTitle = '添加工作台小页管理'
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row) {
+ this.reset()
+ this.open = true
+ this.spinning = !this.spinning
+ const sysPortletId = row.id
+ getSysPortlet(sysPortletId).then(response => {
+ this.form = response.data
+ this.formTitle = '修改工作台小页管理'
+ this.spinning = !this.spinning
+ })
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ const saveForm = JSON.parse(JSON.stringify(this.form))
+ if (this.form.id !== undefined) {
+ updateSysPortlet(saveForm).then(response => {
+ this.$message.success('新增成功', 3)
+ this.open = false
+ this.$emit('ok')
+ this.$emit('close')
+ })
+ } else {
+ addSysPortlet(saveForm).then(response => {
+ this.$message.success('新增成功', 3)
+ this.open = false
+ this.$emit('ok')
+ this.$emit('close')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ back () {
+ const index = '/system/sysportlet/index'
+ this.$router.push(index)
+ }
+ }
+}
diff --git a/hotgo-web/src/views/system/user/SysUserIndex.vue b/hotgo-web/src/views/system/user/SysUserIndex.vue
new file mode 100644
index 0000000..9c4fa5b
--- /dev/null
+++ b/hotgo-web/src/views/system/user/SysUserIndex.vue
@@ -0,0 +1,497 @@
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/user/modules/DeptTree.vue b/hotgo-web/src/views/system/user/modules/DeptTree.vue
new file mode 100644
index 0000000..d185289
--- /dev/null
+++ b/hotgo-web/src/views/system/user/modules/DeptTree.vue
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+
+
+
+ {{ title.substr(0, title.indexOf(searchValue)) }}
+ {{ searchValue }}
+ {{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
+
+
+ {{ title }}
+
+ {{ title }}
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/user/modules/ImportExcel.vue b/hotgo-web/src/views/system/user/modules/ImportExcel.vue
new file mode 100644
index 0000000..1aca288
--- /dev/null
+++ b/hotgo-web/src/views/system/user/modules/ImportExcel.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+ 请将文件拖拽到此处上传❥(^_-)
+
+
+ 支持单个上传,也可以点击后选择文件上传
+
+
+
+ 是否更新已经存在的用户数据
+
+ 下载模板
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/user/modules/ResetPassword.vue b/hotgo-web/src/views/system/user/modules/ResetPassword.vue
new file mode 100644
index 0000000..cba2a63
--- /dev/null
+++ b/hotgo-web/src/views/system/user/modules/ResetPassword.vue
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/user/modules/SysUserAddForm.vue b/hotgo-web/src/views/system/user/modules/SysUserAddForm.vue
new file mode 100644
index 0000000..bd31563
--- /dev/null
+++ b/hotgo-web/src/views/system/user/modules/SysUserAddForm.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.name }}
+
+
+
+
+
+
+
+
+ {{ d.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ d.label
+ }}
+
+
+
+
+
+
+
+ {{
+ d.label
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+ 取消
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/user/modules/SysUserEditForm.vue b/hotgo-web/src/views/system/user/modules/SysUserEditForm.vue
new file mode 100644
index 0000000..d19f19e
--- /dev/null
+++ b/hotgo-web/src/views/system/user/modules/SysUserEditForm.vue
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.name }}
+
+
+
+
+
+
+
+
+ {{ d.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ d.label
+ }}
+
+
+
+
+
+
+
+ {{
+ d.label
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/system/user/modules/SysUserForm.js b/hotgo-web/src/views/system/user/modules/SysUserForm.js
new file mode 100644
index 0000000..91d1179
--- /dev/null
+++ b/hotgo-web/src/views/system/user/modules/SysUserForm.js
@@ -0,0 +1,243 @@
+import { getUser, addUser, updateUser, checkUserNameUnique, checkEmailUnique, checkPhoneUnique } from '@/api/system/user'
+import { listDeptTree } from '@/api/system/dept'
+import SelectDept from '@/components/pt/selectDept/SelectDept'
+import AntModal from '@/components/pt/dialog/AntModal'
+export default {
+ name: 'CreateForm',
+ props: {
+ deptCheckedValue: {
+ type: Object
+ },
+ statusOptions: {
+ type: Array,
+ required: true
+ },
+ sexOptions: {
+ type: Array,
+ required: true
+ },
+ userTypeOptions: {
+ type: Array,
+ required: true
+ },
+ defalutExpandedKeys: {
+ type: Array
+ }
+ },
+ components: {
+ AntModal,
+ SelectDept
+ },
+ data () {
+ const validateDeptId = (rule, value, callback) => {
+ if (value.ids === '' || value.ids === undefined || value.ids === null) {
+ callback(new Error('部门不允许为空'))
+ } else {
+ callback()
+ }
+ }
+ return {
+ expandedKeys: this.defalutExpandedKeys,
+ spinning: false,
+ delayTime: 100,
+ replaceFields: { children: 'children', title: 'label', key: 'id', value: 'id' },
+ customStyle: 'background: #fff;ssborder-radius: 4px;margin-bottom: 24px;border: 0;overflow: hidden',
+ // 岗位选项
+ postOptions: [],
+ // 角色选项
+ roleOptions: [],
+ // 默认密码
+ initPassword: undefined,
+ formTitle: '',
+ // 表单参数
+ form: {
+ id: undefined,
+ dept_id: 0,
+ username: undefined,
+ nickName: undefined,
+ mobile: undefined,
+ email: undefined,
+ sex: '2',
+ status: '1',
+ userType: '2',
+ remark: undefined,
+ postIds: [],
+ role: []
+ },
+ open: false,
+ rules: {
+ realname: [{ required: true, message: '用户名称不能为空', trigger: 'blur' }],
+ id: [{ required: true, message: '用户编号不能为空', trigger: 'blur' }],
+ username: [{ required: true, message: '登录名不能为空', trigger: 'blur' },
+ { validator: this.checkUserNameUnique, trigger: 'change' }
+ ],
+ postIds: [{ required: true, message: '岗位不能为空', trigger: 'blur' }],
+ secretLevel: [{ required: true, message: '密级不能为空', trigger: 'blur' }],
+ dept_id: [{ required: true, message: '部门不能为空', trigger: 'blur', validator: validateDeptId }],
+ email: [
+ {
+ type: 'email',
+ message: '请正确填写邮箱地址',
+ trigger: ['blur', 'change']
+ },
+ { validator: this.checkEmailUnique }
+ ],
+ mobile: [
+ {
+ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+ message: '请正确填写手机号',
+ trigger: 'blur'
+ },
+ { validator: this.checkPhoneUnique }
+ ]
+ }
+ }
+ },
+ filters: {},
+ created () {
+ this.getConfigKey('sys.user.initPassword').then(response => {
+ this.initPassword = response.value
+ })
+ },
+ computed: {},
+ watch: {},
+ methods: {
+ // 取消按钮
+ cancel () {
+ this.open = false
+ this.$emit('close')
+ },
+ // 表单重置
+ reset () {
+ if (this.$refs.form !== undefined) {
+ this.$refs.form.resetFields()
+ }
+ },
+ /** 新增按钮操作 */
+ handleAdd () {
+ // this.$emit('select-tree')
+ this.open = true
+ this.formTitle = '新增用户'
+ getUser().then(response => {
+ this.postOptions = response.posts
+ this.roleOptions = response.roles
+ this.form.dept_id = this.deptCheckedValue
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate (row, ids) {
+ this.open = true
+ this.formTitle = '修改【' + row.realname + '】信息'
+ this.spinning = !this.spinning
+ // this.$emit('select-tree')
+ const id = row ? row.id : ids
+ getUser(id).then(response => {
+ this.form = response
+ this.form.dept_id = { ids: response.dept_id, names: response.dept_name }
+ this.postOptions = response.posts
+ this.roleOptions = response.roles
+ this.form.postIds = response.postIds !== null ? response.postIds : []
+ this.form.role = response.role !== null ? response.role : []
+ this.spinning = !this.spinning
+ })
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ const saveForm = JSON.parse(JSON.stringify(this.form))
+ if (this.form.dept_id !== undefined) {
+ saveForm.dept_id = this.form.dept_id.ids
+ }
+ if (this.form.id !== undefined) {
+ updateUser(saveForm).then(response => {
+ this.$message.success(
+ '修改成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ } else {
+ addUser(saveForm).then(response => {
+ this.$message.success(
+ '新增成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ onLoadData (treeNode) {
+ return new Promise(resolve => {
+ if (treeNode.dataRef.children) {
+ resolve()
+ return
+ }
+ listDeptTree(treeNode.dataRef.id, 1).then(response => {
+ treeNode.dataRef.children = response
+ resolve()
+ })
+ })
+ },
+ checkUserNameUnique (rule, value, callback) {
+ const msg = '登陆名称已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ username: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkUserNameUnique(checkData).then(response => {
+ if (response.is_unique) {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ },
+ checkEmailUnique (rule, value, callback) {
+ const msg = '登陆名称已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ email: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkEmailUnique(checkData).then(response => {
+ if (response.is_unique) {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ },
+ checkPhoneUnique (rule, value, callback) {
+ const msg = '手机号已存在'
+ if (value === '') {
+ callback()
+ } else {
+ const checkData = {
+ mobile: value,
+ id: this.form.id !== undefined ? this.form.id : ''
+ }
+ checkPhoneUnique(checkData).then(response => {
+ if (response.is_unique) {
+ callback()
+ } else {
+ callback(msg)
+ }
+ })
+ }
+ }
+ }
+}
diff --git a/hotgo-web/src/views/test/temp/home.vue b/hotgo-web/src/views/test/temp/home.vue
new file mode 100644
index 0000000..a845076
--- /dev/null
+++ b/hotgo-web/src/views/test/temp/home.vue
@@ -0,0 +1,5 @@
+
+
+ home.............
+
+
diff --git a/hotgo-web/src/views/tool/build/index.vue b/hotgo-web/src/views/tool/build/index.vue
new file mode 100644
index 0000000..d9bbccb
--- /dev/null
+++ b/hotgo-web/src/views/tool/build/index.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ 返回工作台
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/tool/gen/genconfigtemplate/index.vue b/hotgo-web/src/views/tool/gen/genconfigtemplate/index.vue
new file mode 100644
index 0000000..4cb79d9
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/genconfigtemplate/index.vue
@@ -0,0 +1,359 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ parseTime(record.createTime, '{y}-{m}-{d}') }}
+
+
+
+ 确认{{ record.status === '1' ? '启用' : '停用' }} {{ record.templateName }}的模板吗?
+
+
+
+
+
+ 确认{{ record.templateDefault === 'N' ? '设置' : '取消' }} {{ record.templateName }}的模板为默认模板吗?
+
+
+
+
+
+ 修改
+
+
+
+ 删除
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/tool/gen/genconfigtemplate/module/GenConfigTemplateAddForm.vue b/hotgo-web/src/views/tool/gen/genconfigtemplate/module/GenConfigTemplateAddForm.vue
new file mode 100644
index 0000000..d1f27aa
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/genconfigtemplate/module/GenConfigTemplateAddForm.vue
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+ 生成模块名
+
+
+ 可理解为子系统名,例如 system
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
+
diff --git a/hotgo-web/src/views/tool/gen/genconfigtemplate/module/GenConfigTemplateEditForm.vue b/hotgo-web/src/views/tool/gen/genconfigtemplate/module/GenConfigTemplateEditForm.vue
new file mode 100644
index 0000000..24c1859
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/genconfigtemplate/module/GenConfigTemplateEditForm.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.dictLabel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/tool/gen/genconfigtemplate/module/GenConfigTemplateForm.js b/hotgo-web/src/views/tool/gen/genconfigtemplate/module/GenConfigTemplateForm.js
new file mode 100644
index 0000000..39debe5
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/genconfigtemplate/module/GenConfigTemplateForm.js
@@ -0,0 +1,169 @@
+import AntModal from '@/components/pt/dialog/AntModal'
+import {
+ getTemplate,
+ addTemplate,
+ updateTemplate,
+ findMaxSort
+} from '@/api/tool/genConfigTemplate'
+
+export default {
+ name: 'CreateForm',
+ props: {
+ statusOptions: {
+ type: Array,
+ required: true
+ },
+ templateDefaultOptions: {
+ type: Array,
+ required: true
+ }
+ },
+ components: {
+ AntModal
+ },
+ data() {
+ return {
+ open: false,
+ spinning: false,
+ labelCol: {
+ span: 4
+ },
+ wrapperCol: {
+ span: 14
+ },
+ loading: false,
+ total: 0,
+ id: undefined,
+ formTitle: '',
+ // 表单参数
+ form: {},
+ rules: {
+ templateName: [{
+ required: true,
+ message: '模板名称不能为空',
+ trigger: 'change'
+ }],
+ functionAuthor: [{
+ required: true,
+ message: '作者不能为空',
+ trigger: 'change'
+ }],
+ functionAuthorEmail: [{
+ type: 'email',
+ message: '请正确填写邮箱地址',
+ trigger: ['blur', 'change']
+ }],
+ workspacePath: [{
+ required: true,
+ message: '后端工作空间不能为空',
+ trigger: 'change'
+ }],
+ wenWorkspacePath: [{
+ required: true,
+ message: '前端工作空间不能为空',
+ trigger: 'change'
+ }],
+ moduleName: [{
+ required: true,
+ message: '模块名不能为空',
+ trigger: 'change'
+ }],
+ packageName: [{
+ required: true,
+ message: '模块路径不能为空',
+ trigger: 'change'
+ }],
+ sort: [{
+ required: true,
+ message: '排序不能为空',
+ trigger: 'change'
+ }]
+ }
+ }
+ },
+ filters: {},
+ created() {},
+ computed: {},
+ watch: {},
+ mounted() {},
+ methods: {
+ onClose() {
+ this.open = false
+ this.reset()
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ id: undefined,
+ templateName: undefined,
+ functionAuthor: undefined,
+ functionAuthorEmail: undefined,
+ workspacePath: undefined,
+ moduleName: undefined,
+ packageName: undefined,
+ webWorkspacePath: undefined,
+ templateDefault: 'N',
+ status: '0',
+ remark: undefined
+ }
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ /** 获取最大编号 */
+ findMaxSort().then(response => {
+ this.form.sort = response.data
+ this.open = true
+ this.formTitle = '添加模板'
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ this.spinning = !this.spinning
+ const templateId = row.id
+ getTemplate(templateId).then(response => {
+ this.open = true
+ this.form = response.data
+ this.formTitle = '修改模板'
+ })
+ this.spinning = !this.spinning
+ },
+ /** 提交按钮 */
+ submitForm: function () {
+ this.$refs.form.validate(valid => {
+ if (valid) {
+ if (this.form.id !== undefined) {
+ updateTemplate(this.form).then(response => {
+ this.$message.success(
+ '修改成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ } else {
+ addTemplate(this.form).then(response => {
+ this.$message.success(
+ '新增成功',
+ 3
+ )
+ this.open = false
+ this.$emit('ok')
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ },
+ back () {
+ this.$router.push('/tool/gen/genconfigtemplate/index')
+ }
+ }
+}
diff --git a/hotgo-web/src/views/tool/gen/index.vue b/hotgo-web/src/views/tool/gen/index.vue
new file mode 100644
index 0000000..8e3fe2c
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/index.vue
@@ -0,0 +1,384 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+ 导入
+
+
+ 生成
+
+
+ 修改
+
+
+ 删除
+
+
+
+ {{ parseTime(record.createTime) }}
+
+
+ {{ parseTime(record.updateTime) }}
+
+
+
+ 预览
+
+
+
+ 编辑
+
+
+
+ 删除
+
+
+
+ 同步
+
+
+
+ 生成代码
+
+
+
+ 创建菜单
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/tool/gen/modules/BasicInfoForm.vue b/hotgo-web/src/views/tool/gen/modules/BasicInfoForm.vue
new file mode 100644
index 0000000..8d0de59
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/modules/BasicInfoForm.vue
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/tool/gen/modules/GenEdit.vue b/hotgo-web/src/views/tool/gen/modules/GenEdit.vue
new file mode 100644
index 0000000..2ce2d8e
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/modules/GenEdit.vue
@@ -0,0 +1,772 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 该选项表示24栅格中 摆放控件个数
+
+ 列数
+
+
+
+
+ {{ text }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ =
+ !=
+ >
+ >=
+ <
+ <=
+ LIKE
+ BETWEEN
+
+
+
+
+
+ 居中
+ 居左
+ 居右
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 一列/24栅格
+ 两列/24栅格
+ 三列/24栅格
+ 四列/24栅格
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+ 请选择
+
+ {{ item.dictName }}
+
+
+
+
+
+
+ 请选择
+ 日期
+ 数值
+ 整数
+ 正整数
+ 手机号
+ 固定号码
+ 邮编
+ 邮箱
+ QQ号
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+ 保存并生成代码
+
+
+ 取消
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/tool/gen/modules/GenInfoForm.vue b/hotgo-web/src/views/tool/gen/modules/GenInfoForm.vue
new file mode 100644
index 0000000..ec58523
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/modules/GenInfoForm.vue
@@ -0,0 +1,491 @@
+
+
+
+
+
+
+
+ 生成模板
+
+
+ 单表(增删改查)
+ 树表(增删改查)
+ 主子表(增删改查)
+ 左树右表(增删改查)
+
+
+
+
+
+
+ 个人模板
+
+
+
+ {{ item.templateName }}
+
+
+
+
+
+
+
+
+
+ 作者
+
+
+
+
+
+
+
+ 邮箱
+
+
+
+
+
+
+
+
+
+
+ 工作空间路径
+
+
+
+
+
+
+
+ 前端工作空间路径
+
+
+
+
+
+
+
+
+
+ 生成模块名
+
+
+ 可理解为子系统名,例如 system
+
+
+
+
+
+
+
+
+
+
+ 包路径
+
+
+
+
+
+
+
+
+
+ 生成功能名
+
+
+ 用作类描述,例如 用户
+
+
+
+
+
+
+
+
+
+
+ 生成业务名
+
+
+ 可理解为功能英文名,例如 user
+
+
+
+
+
+
+
+
+
+
+
+
+ 生成代码方式
+
+
+ 默认为zip压缩包下载,也可以自定义生成路径
+
+
+
+
+
+ zip压缩包
+ 自定义路径
+
+
+
+
+
+
+ 上级菜单
+
+
+ 分配到指定菜单下,例如 系统管理
+
+
+
+
+
+
+
+
+
+
+ 菜单图标
+
+
+ 选择当前模块对应的菜单图标
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 树表信息
+
+
+
+
+
+ 树编码字段
+
+
+ 树显示的编码字段名, 如:dept_id
+
+
+
+
+
+
+
+
+
+
+
+ 树父编码字段
+
+
+ 树显示的父编码字段名, 如:parent_Id
+
+
+
+
+
+
+
+
+
+
+
+ 树名称字段
+
+
+ 树节点的显示名称字段名, 如:dept_name
+
+
+
+
+
+
+ {{ item.columnName + (item.columnComment === null ? '': ':' + item.columnComment) }}
+
+
+
+
+
+
+
+
+ 关联信息
+
+
+
+
+
+ 关联子表的表名
+
+
+ 关联子表的表名, 如:sys_user
+
+
+
+
+
+
+ {{ item.tableName + ':' + item.tableComment }}
+
+
+
+
+
+
+
+ 子表关联的外键名
+
+
+ 子表关联的外键名, 如:user_id
+
+
+
+
+
+
+ {{ item.columnName + (item.columnComment === null ? '': ':' + item.columnComment) }}
+
+
+
+
+
+
+
+
+ 其他选项
+
+
+
+
+
+ 是否可上传附件
+
+
+ 默认新增页面,编辑页面不上传附件
+
+
+
+
+
+ 是
+ 否
+
+
+
+
+
+
+ 是否有停用启用
+
+
+ 必须要包含status字段才可以
+
+
+
+
+
+ 是
+ 否
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/tool/gen/modules/ImportTable.vue b/hotgo-web/src/views/tool/gen/modules/ImportTable.vue
new file mode 100644
index 0000000..680eb36
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/modules/ImportTable.vue
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/tool/gen/modules/PreviewCode.vue b/hotgo-web/src/views/tool/gen/modules/PreviewCode.vue
new file mode 100644
index 0000000..3cfb4b3
--- /dev/null
+++ b/hotgo-web/src/views/tool/gen/modules/PreviewCode.vue
@@ -0,0 +1,71 @@
+
+
+
+
diff --git a/hotgo-web/src/views/tool/swagger/index.vue b/hotgo-web/src/views/tool/swagger/index.vue
new file mode 100644
index 0000000..49491bb
--- /dev/null
+++ b/hotgo-web/src/views/tool/swagger/index.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/src/views/user/Login.vue b/hotgo-web/src/views/user/Login.vue
new file mode 100644
index 0000000..7a075fe
--- /dev/null
+++ b/hotgo-web/src/views/user/Login.vue
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 记住密码
+
+
+
+ 确定
+
+
+
+ 其它登录方式
+
+
+
+
+
+
+
+
+
diff --git a/hotgo-web/tests/unit/.eslintrc.js b/hotgo-web/tests/unit/.eslintrc.js
new file mode 100644
index 0000000..958d51b
--- /dev/null
+++ b/hotgo-web/tests/unit/.eslintrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+ env: {
+ jest: true
+ }
+}
diff --git a/hotgo-web/vue.config.js b/hotgo-web/vue.config.js
new file mode 100644
index 0000000..03361bc
--- /dev/null
+++ b/hotgo-web/vue.config.js
@@ -0,0 +1,145 @@
+const path = require('path')
+const webpack = require('webpack')
+const GitRevisionPlugin = require('git-revision-webpack-plugin')
+const GitRevision = new GitRevisionPlugin()
+const buildDate = JSON.stringify(new Date().toLocaleString())
+const createThemeColorReplacerPlugin = require('./config/plugin.config')
+const CompressionWebpackPlugin = require('compression-webpack-plugin')
+const productionGzipExtensions = ['js', 'css']
+
+function resolve(dir) {
+ return path.join(__dirname, dir)
+}
+
+// check Git
+function getGitHash() {
+ try {
+ return GitRevision.version()
+ } catch (e) { }
+ return 'unknown'
+}
+
+const isProd = process.env.NODE_ENV === 'production'
+
+const assetsCDN = {
+ // webpack build externals
+ externals: {
+ vue: 'Vue',
+ 'vue-router': 'VueRouter',
+ vuex: 'Vuex',
+ axios: 'axios'
+ },
+ css: [],
+ // https://unpkg.com/browse/vue@2.6.10/
+ js: [
+ '//cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js',
+ '//cdn.jsdelivr.net/npm/vue-router@3.1.3/dist/vue-router.min.js',
+ '//cdn.jsdelivr.net/npm/vuex@3.1.1/dist/vuex.min.js',
+ '//cdn.jsdelivr.net/npm/axios@0.19.0/dist/axios.min.js'
+ ]
+}
+
+// vue.config.js
+const vueConfig = {
+ configureWebpack: {
+ // webpack plugins
+ plugins: [
+ // Ignore all locale files of moment.js
+ new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
+ new webpack.DefinePlugin({
+ APP_VERSION: `"${require('./package.json').version}"`,
+ GIT_HASH: JSON.stringify(getGitHash()),
+ BUILD_DATE: buildDate
+ }),
+ // 配置compression-webpack-plugin压缩
+ new CompressionWebpackPlugin({
+ algorithm: 'gzip',
+ test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
+ threshold: 10240,
+ minRatio: 0.8
+ })
+ ],
+ // if prod, add externals
+ externals: isProd ? assetsCDN.externals : {}
+ },
+
+ chainWebpack: (config) => {
+ config.resolve.alias
+ .set('@$', resolve('src'))
+ .set('@assets', resolve('src/assets'))
+ .set('@views', resolve('src/views'))
+
+ const svgRule = config.module.rule('svg')
+ svgRule.uses.clear()
+ svgRule
+ .oneOf('inline')
+ .resourceQuery(/inline/)
+ .use('vue-svg-icon-loader')
+ .loader('vue-svg-icon-loader')
+ .end()
+ .end()
+ .oneOf('external')
+ .use('file-loader')
+ .loader('file-loader')
+ .options({
+ name: 'assets/[name].[hash:8].[ext]'
+ })
+
+ // if prod is on
+ // assets require on cdn
+ if (isProd) {
+ config.plugin('html').tap(args => {
+ args[0].cdn = assetsCDN
+ return args
+ })
+ }
+ },
+
+ css: {
+ loaderOptions: {
+ less: {
+ modifyVars: {
+ // less vars,customize ant design theme
+ 'primary-color': '#2f54eb',
+ // 'link-color': '#F5222D',
+ //'border-radius-base': '2px'
+ },
+ // DO NOT REMOVE THIS LINE
+ javascriptEnabled: true
+ }
+ }
+ },
+
+ devServer: {
+ // development server port 8000
+ port: 8100,
+ // If you want to turn on the proxy, please remove the mockjs /src/main.jsL11
+ proxy: {
+ // detail: https://cli.vuejs.org/config/#devserver-proxy
+ [process.env.VUE_APP_BASE_API]: {
+ // target: `https://aidex.setworld.net`,
+ target: `http://127.0.0.1:8299/admin/`,
+ changeOrigin: true,
+ pathRewrite: {
+ ['^' + process.env.VUE_APP_BASE_API]: ''
+ }
+ }
+ },
+ disableHostCheck: true // 增加该设置是为了解决使用外网映射工具映射时报错--可以删除
+ },
+
+ // disable source map in production
+ productionSourceMap: false,
+ lintOnSave: undefined,
+ // babel-loader no-ignore node_modules/*
+ transpileDependencies: []
+}
+
+// preview.pro.loacg.com only do not use in your production;
+if (process.env.VUE_APP_PREVIEW === 'true') {
+ console.log('VUE_APP_PREVIEW', true)
+ // add `ThemeColorReplacer` plugin to webpack plugins
+ vueConfig.configureWebpack.plugins.push(createThemeColorReplacerPlugin())
+}
+
+module.exports = vueConfig
diff --git a/hotgo-web/webstorm.config.js b/hotgo-web/webstorm.config.js
new file mode 100644
index 0000000..9117455
--- /dev/null
+++ b/hotgo-web/webstorm.config.js
@@ -0,0 +1,3 @@
+'use strict'
+const webpackConfig = require('@vue/cli-service/webpack.config.js')
+module.exports = webpackConfig