瀏覽代碼

Merge branch 'bzq/dev' of eta_mini/eta_mini_api into master

鲍自强 10 月之前
父節點
當前提交
cef076420f
共有 68 個文件被更改,包括 4681 次插入273 次删除
  1. 1 0
      .gitignore
  2. 70 0
      controllers/banner.go
  3. 60 40
      controllers/base_auth.go
  4. 59 0
      controllers/base_common.go
  5. 177 0
      controllers/chart.go
  6. 58 0
      controllers/chart_permission.go
  7. 21 0
      controllers/error.go
  8. 84 0
      controllers/mini_config.go
  9. 335 0
      controllers/my_chart.go
  10. 232 0
      controllers/my_report.go
  11. 209 0
      controllers/report.go
  12. 580 27
      controllers/user.go
  13. 336 39
      controllers/wechat.go
  14. 2 2
      go.mod
  15. 50 2
      main.go
  16. 31 0
      models/banner.go
  17. 14 0
      models/business_conf.go
  18. 41 0
      models/chart_permission.go
  19. 12 0
      models/chart_permission_search_key_word_mapping.go
  20. 24 0
      models/classify.go
  21. 21 7
      models/db.go
  22. 70 0
      models/mini_config.go
  23. 10 3
      models/msg_code.go
  24. 60 0
      models/my_chart.go
  25. 53 0
      models/my_report.go
  26. 63 0
      models/report.go
  27. 15 0
      models/request/my_chart.go
  28. 5 0
      models/request/my_report.go
  29. 22 10
      models/request/user.go
  30. 9 0
      models/request/wechat.go
  31. 104 0
      models/response/chart.go
  32. 1 0
      models/response/chart_permission.go
  33. 6 0
      models/response/mini_config.go
  34. 26 0
      models/response/my_chart.go
  35. 16 0
      models/response/my_report.go
  36. 66 0
      models/response/report.go
  37. 24 0
      models/response/user.go
  38. 0 38
      models/sys_session.go
  39. 17 0
      models/sys_user.go
  40. 88 1
      models/user.go
  41. 16 0
      models/user_chart_permission_mapping.go
  42. 26 0
      models/user_read_permission.go
  43. 78 0
      models/user_read_record.go
  44. 59 0
      models/user_record.go
  45. 22 0
      models/user_template_record.go
  46. 42 0
      models/wx_sesssion.go
  47. 2 2
      models/wx_token.go
  48. 0 20
      models/wx_user.go
  49. 251 8
      routers/commentsRouter.go
  50. 37 1
      routers/router.go
  51. 30 0
      services/alarm_msg/alarm_msg.go
  52. 38 0
      services/base_lib.go
  53. 40 0
      services/chart.go
  54. 89 0
      services/chart_permission.go
  55. 0 5
      services/email.go
  56. 92 0
      services/go_redis/redis.go
  57. 71 0
      services/report.go
  58. 5 5
      services/sms.go
  59. 151 13
      services/user.go
  60. 10 0
      services/verify.go
  61. 177 0
      services/wechat/template_msg.go
  62. 93 21
      services/wechat/wechat.go
  63. 5 21
      services/wx_app/wx_app.go
  64. 101 0
      utils/common.go
  65. 92 0
      utils/config.go
  66. 52 2
      utils/constants.go
  67. 4 4
      utils/email.go
  68. 26 2
      utils/logs.go

+ 1 - 0
.gitignore

@@ -4,3 +4,4 @@
 *.exe
 *.exe
 *.exe~
 *.exe~
 go.sum
 go.sum
+/rdlucklog/

+ 70 - 0
controllers/banner.go

@@ -0,0 +1,70 @@
+package controllers
+
+import (
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/utils"
+)
+
+type BannerController struct {
+	BaseAuthController
+}
+
+// @Title List
+// @Description create users
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.BaseResponse
+// @router /list [get]
+func (this *BannerController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	startSize := utils.StartIndex(currentIndex, pageSize)
+	banners, err := models.GetBannerList(startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取banner列表失败"
+		br.ErrMsg = "获取banner列表失败,系统异常,Err:" + err.Error()
+		return
+	}
+	br.Data = banners
+	br.Msg = "获取banner列表成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title Detail
+// @Description banner详情
+// @Param   BannerId   query   int  true       "bannerId"
+// @Success 200 {object} models.BaseResponse
+// @router /detail [get]
+func (this *BannerController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	bannerId, _ := this.GetInt("BannerId")
+
+	banners, err := models.GetBannerById(bannerId)
+	if err != nil {
+		br.Msg = "获取banner详情失败"
+		br.ErrMsg = "获取banner详情失败,系统异常,Err:" + err.Error()
+		return
+	}
+	br.Data = banners
+	br.Msg = "获取banner列表成功"
+	br.Success = true
+	br.Ret = 200
+}

+ 60 - 40
controllers/base_auth.go

@@ -5,11 +5,7 @@ import (
 	"eta/eta_mini_api/models"
 	"eta/eta_mini_api/models"
 	"eta/eta_mini_api/utils"
 	"eta/eta_mini_api/utils"
 	"net/http"
 	"net/http"
-	"strconv"
-	"strings"
-	"time"
 
 
-	"github.com/beego/beego/v2/client/orm"
 	"github.com/beego/beego/v2/server/web"
 	"github.com/beego/beego/v2/server/web"
 )
 )
 
 
@@ -26,65 +22,86 @@ func (c *BaseAuthController) Prepare() {
 		if method == "POST" || method == "GET" {
 		if method == "POST" || method == "GET" {
 			authorization := c.Ctx.Input.Header("authorization")
 			authorization := c.Ctx.Input.Header("authorization")
 			if authorization == "" {
 			if authorization == "" {
-				c.JSON(models.BaseResponse{Ret: 408, Msg: "请重新授权!", ErrMsg: "请重新授权:Token is empty or account is empty"})
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "请重新授权!", ErrMsg: "请重新授权:Token is empty or account is empty"}, false, false)
 				c.StopRun()
 				c.StopRun()
 				return
 				return
 			}
 			}
-			tokenStr := authorization
-			tokenArr := strings.Split(tokenStr, "=")
-			token := tokenArr[1]
-
-			session, err := models.GetWxSessionByToken(token)
+			token := authorization
+			session, err := models.GetWxSessionByAccessToken(token)
 			if err != nil {
 			if err != nil {
-				if err == orm.ErrNoRows {
-					c.JSON(models.BaseResponse{Ret: 408, Msg: "信息已变更,请重新登陆!", ErrMsg: "Token 信息已变更:Token: " + token})
+				if err.Error() == utils.ErrNoRow() {
+					c.JSON(models.BaseResponse{Ret: 408, Msg: "信息已变更,请重新登陆!", ErrMsg: "Token 信息已变更:Token: " + token}, false, false)
 					c.StopRun()
 					c.StopRun()
 					return
 					return
 				}
 				}
-				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "获取用户信息异常,Eerr:" + err.Error()})
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "获取用户信息异常,Err:" + err.Error()}, false, false)
 				c.StopRun()
 				c.StopRun()
 				return
 				return
 			}
 			}
 			if session == nil {
 			if session == nil {
-				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "sesson is empty "})
-				c.StopRun()
-				return
-			}
-
-			account := utils.MD5(strconv.Itoa(session.UserId))
-			if !utils.CheckToken(account, token) {
-				c.JSON(models.BaseResponse{Ret: 408, Msg: "鉴权失败,请重新登录!", ErrMsg: "登录失效,请重新登陆!,CheckToken Fail"})
-				c.StopRun()
-				return
-			}
-			if time.Now().After(session.ExpiredTime) {
-				c.JSON(models.BaseResponse{Ret: 408, Msg: "请重新登录!", ErrMsg: "获取用户信息异常"})
-				c.StopRun()
-				return
-			}
-			user, err := models.GetUserById(session.UserId)
-			if err != nil {
-				if err == orm.ErrNoRows {
-					c.JSON(models.BaseResponse{Ret: 408, Msg: "信息已变更,请重新登陆!", ErrMsg: "获取sysUser信息失败: " + strconv.Itoa(session.UserId)})
-					c.StopRun()
-					return
-				}
-				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "获取sysUser信息异常,Err:" + err.Error()})
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "session is empty "}, false, false)
 				c.StopRun()
 				c.StopRun()
 				return
 				return
 			}
 			}
-			if user == nil {
-				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "sysUser is empty"})
+			user, err := models.GetUserByOpenId(session.OpenId)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "获取用户信息异常,Err:" + err.Error()}, false, false)
 				c.StopRun()
 				c.StopRun()
 				return
 				return
 			}
 			}
 			c.User = user
 			c.User = user
 			c.Session = session
 			c.Session = session
+		} else {
+			c.JSON(models.BaseResponse{Ret: 408, Msg: "请求异常,请联系客服!", ErrMsg: "POST之外的请求,暂不支持"}, false, false)
+			c.StopRun()
+			return
 		}
 		}
 	}
 	}
 }
 }
 
 
-func (c *BaseAuthController) JSON(data interface{}) error {
+func (c *BaseAuthController) ServeJSON(encoding ...bool) {
+	var (
+		hasIndent   = false
+		hasEncoding = false
+	)
+	if web.BConfig.RunMode == web.PROD {
+		hasIndent = false
+	}
+	if len(encoding) > 0 && encoding[0] == true {
+		hasEncoding = true
+	}
+	if c.Data["json"] == nil {
+		//go utils.SendEmail("异常提醒:", "接口:"+"URI:"+c.Ctx.Input.URI()+";无返回值", utils.EmailSendToUsers)
+		body := "接口:" + "URI:" + c.Ctx.Input.URI() + ";无返回值"
+		utils.ApiLog.Notice(body)
+		return
+	}
+	baseRes := c.Data["json"].(*models.BaseResponse)
+	if baseRes != nil && baseRes.Ret != 408 {
+		body, _ := json.Marshal(baseRes)
+		var requestBody string
+		method := c.Ctx.Input.Method()
+		if method == "GET" {
+			requestBody = c.Ctx.Request.RequestURI
+		} else {
+			//requestBody, _ = url.QueryUnescape(string(c.Ctx.Input.RequestBody))
+			requestBody = string(c.Ctx.Input.RequestBody)
+		}
+		if baseRes.Ret != 200 && baseRes.IsSendEmail && c.User != nil {
+			//go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "URI:"+c.Ctx.Input.URI()+"<br/> "+"Params"+requestBody+" <br/>"+"ErrMsg:"+baseRes.ErrMsg+";<br/>Msg:"+baseRes.Msg+";<br/> Body:"+string(body)+"<br/>"+c.SysUser.RealName, utils.EmailSendToUsers)
+			body := "URI:" + c.Ctx.Input.URI() + "<br/> " + "Params" + requestBody + " <br/>" + "ErrMsg:" + baseRes.ErrMsg + ";<br/>Msg:" + baseRes.Msg + ";<br/> Body:" + string(body) + "<br/>" + c.User.RealName
+			// go alarm_msg.SendAlarmMsg(body, 1)
+			utils.ApiLog.Notice(body)
+		}
+		if baseRes.IsAddLog && c.User != nil {
+			return
+		}
+	}
+
+	c.JSON(c.Data["json"], hasIndent, hasEncoding)
+}
+
+func (c *BaseAuthController) JSON(data interface{}, hasIndent bool, coding bool) error {
 	c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
 	c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
 	desEncrypt := utils.DesBase64Encrypt([]byte(utils.DesKey), utils.DesKeySalt)
 	desEncrypt := utils.DesBase64Encrypt([]byte(utils.DesKey), utils.DesKeySalt)
 	c.Ctx.Output.Header("Dk", string(desEncrypt)) // des3加解密key
 	c.Ctx.Output.Header("Dk", string(desEncrypt)) // des3加解密key
@@ -100,5 +117,8 @@ func (c *BaseAuthController) JSON(data interface{}) error {
 		content = utils.DesBase64Encrypt(content, utils.DesKey)
 		content = utils.DesBase64Encrypt(content, utils.DesKey)
 		content = []byte(`"` + string(content) + `"`)
 		content = []byte(`"` + string(content) + `"`)
 	}
 	}
+	if coding {
+		content = []byte(utils.StringsToJSON(string(content)))
+	}
 	return c.Ctx.Output.Body(content)
 	return c.Ctx.Output.Body(content)
 }
 }

+ 59 - 0
controllers/base_common.go

@@ -1,7 +1,11 @@
 package controllers
 package controllers
 
 
 import (
 import (
+	"encoding/json"
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/services"
 	"eta/eta_mini_api/utils"
 	"eta/eta_mini_api/utils"
+	"net/http"
 	"net/url"
 	"net/url"
 
 
 	"github.com/beego/beego/v2/server/web"
 	"github.com/beego/beego/v2/server/web"
@@ -23,3 +27,58 @@ func (c *BaseCommonController) Prepare() {
 	ip := c.Ctx.Input.IP()
 	ip := c.Ctx.Input.IP()
 	utils.ApiLog.Info("uri:%s, requestBody:%s, ip:%s", c.Ctx.Input.URI(), requestBody, ip)
 	utils.ApiLog.Info("uri:%s, requestBody:%s, ip:%s", c.Ctx.Input.URI(), requestBody, ip)
 }
 }
+
+func (c *BaseCommonController) ServeJSON(encoding ...bool) {
+	var (
+		hasIndent   = false
+		hasEncoding = false
+	)
+	if web.BConfig.RunMode == web.PROD {
+		hasIndent = false
+	}
+	if len(encoding) > 0 && encoding[0] == true {
+		hasEncoding = true
+	}
+	if c.Data["json"] == nil {
+		// go utils.SendEmail(utils.APPNAME+" "+utils.RunMode+"异常提醒", "接口:"+"URI:"+c.Ctx.Input.URI()+";无返回值", utils.EmailSendToUsers)
+		utils.ApiLog.Notice(utils.APPNAME+" "+utils.RunMode+"异常提醒", "接口:"+"URI:"+c.Ctx.Input.URI()+";无返回值")
+		return
+	}
+	baseRes := c.Data["json"].(*models.BaseResponse)
+	if baseRes != nil && !baseRes.Success && baseRes.IsSendEmail {
+		utils.ApiLog.Notice("接口:"+"URI:"+c.Ctx.Input.URI()+";ErrMsg:"+baseRes.ErrMsg+";Msg"+baseRes.Msg, utils.EmailSendToUsers)
+		// go utils.SendEmail(utils.APPNAME+" "+utils.RunMode+" 失败提醒", "URI:"+c.Ctx.Input.URI()+" ErrMsg:"+baseRes.ErrMsg+";Msg"+baseRes.Msg, utils.EmailSendToUsers)
+	}
+	c.JSON(c.Data["json"], hasIndent, hasEncoding)
+}
+
+func (c *BaseCommonController) JSON(data interface{}, hasIndent bool, coding bool) error {
+	c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
+	var content []byte
+	var err error
+	if hasIndent {
+		content, err = json.MarshalIndent(data, "", "  ")
+	} else {
+		content, err = json.Marshal(data)
+	}
+	if err != nil {
+		http.Error(c.Ctx.Output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
+		return err
+	}
+	ip := c.Ctx.Input.IP()
+	requestBody, _ := url.QueryUnescape(string(c.Ctx.Input.RequestBody))
+	utils.ApiLog.Info("请求地址:", c.Ctx.Input.URI(), "Authorization:", c.Ctx.Input.Header("Authorization"), "RequestBody:", requestBody, "ResponseBody", string(content), "IP:", ip)
+
+	if coding {
+		content = []byte(utils.StringsToJSON(string(content)))
+	}
+
+	// 数据加密
+	if services.CheckEncryption() {
+		content = utils.DesBase64Encrypt(content, utils.DesKey)
+		// get请求时,不加双引号就获取不到数据,不知道什么原因,所以还是在前后加上双引号吧
+		content = []byte(`"` + string(content) + `"`)
+	}
+
+	return c.Ctx.Output.Body(content)
+}

+ 177 - 0
controllers/chart.go

@@ -0,0 +1,177 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/models/response"
+	"eta/eta_mini_api/services"
+	"eta/eta_mini_api/services/alarm_msg"
+	"eta/eta_mini_api/utils"
+	"fmt"
+)
+
+type ChartController struct {
+	BaseAuthController
+}
+
+// @Title List
+// @Description create users
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.BaseResponse
+// @router /list [get]
+func (this *ChartController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	result, err := services.GetChartList(currentIndex, pageSize)
+	if err != nil {
+		br.Msg = "查询图表失败"
+		br.ErrMsg = "查询图表失败,系统异常,Err:" + err.Error()
+		return
+	}
+	if result.Ret != 200 {
+		br.Msg = "查询图表失败"
+		br.ErrMsg = result.ErrMsg
+		return
+	}
+	resp := new(response.ChartListResp)
+	resp.List = result.Data.List
+	resp.Paging = result.Data.Paging
+
+	br.Msg = "查询图表成功"
+	br.Data = result.Data
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title Detail
+// @Description 图表详情
+// @Param   ChartInfoId   query   int  true       "图表详情id"
+// @Success 200 {object} models.BaseResponse
+// @router /detail [get]
+func (this *ChartController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.Ret != 200 {
+			errb, _ := json.Marshal(br)
+			alarm_msg.SendAlarmMsg(fmt.Sprintf("获得图表详情失败:%s, user:%d", string(errb), this.User.UserId), 1)
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有权限查看图表"
+		return
+	}
+
+	chartInfoId, _ := this.GetInt("ChartInfoId")
+	if chartInfoId <= 0 {
+		br.Msg = "图表id错误"
+		return
+	}
+
+	result, err := services.GetChartDetail(chartInfoId, "")
+	if err != nil {
+		br.Msg = "获取图表详情失败"
+		br.ErrMsg = "获取图表详情失败,Err:" + err.Error()
+		return
+	}
+	if result.Ret == 200 && result.Data.UniqueCode == "" {
+		// 说明后台删除了这个图表,那么尝试将收藏的图表也删除
+		alarm_msg.SendAlarmMsg(fmt.Sprintf("图表不存在,删除图表,id:%d", chartInfoId), 1)
+		models.DeleteMyChartByUserIdAndChartInfoId(user.UserId, chartInfoId)
+		br.Msg = "图表已删除或不存在"
+		return
+	}
+	count, err := models.GetMyChartCount(user.UserId, result.Data.UniqueCode)
+	if err != nil {
+		br.Msg = "获取图表详情失败"
+		br.ErrMsg = "获取图表详情失败,Err:" + err.Error()
+	}
+	if count > 0 {
+		result.Data.IsCollect = true
+	}
+	br.Data = result.Data
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title Locate
+// @Description create users
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.BaseResponse
+// @router /locate [get]
+func (this *ChartController) Locate() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	if pageSize <= 0 {
+		pageSize = 2
+	}
+	result, err := services.GetChartList(currentIndex, pageSize)
+	if err != nil {
+		br.Msg = "查询图表失败"
+		br.ErrMsg = "查询图表失败,系统异常,Err:" + err.Error()
+		return
+	}
+	if result.Ret != 200 {
+		br.Msg = result.Msg
+		br.ErrMsg = result.ErrMsg
+		return
+	}
+	total := len(result.Data.List)
+	charts := make([]*response.ChartLocateItem, 0)
+
+	items := result.Data.List
+	for k, v := range items {
+		var prevChartInfoId, nextChartInfoId int
+		switch k {
+		case 0:
+			prevChartInfoId = -1
+			if k < total-1 {
+				nextChartInfoId = items[k+1].ChartInfoId
+			} else {
+				nextChartInfoId = -1
+			}
+		case total - 1:
+			nextChartInfoId = -1
+			if k > 0 {
+				prevChartInfoId = items[k-1].ChartInfoId
+			}
+		default:
+			prevChartInfoId = items[k-1].ChartInfoId
+			nextChartInfoId = items[k+1].ChartInfoId
+
+		}
+		tmpLocate := &response.ChartLocateItem{
+			ChartInfoId:     v.ChartInfoId,
+			ChartName:       v.ChartName,
+			UniqueCode:      v.UniqueCode,
+			PrevChartInfoId: prevChartInfoId,
+			NextChartInfoId: nextChartInfoId,
+		}
+		charts = append(charts, tmpLocate)
+	}
+
+	br.Data = charts
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+}

+ 58 - 0
controllers/chart_permission.go

@@ -0,0 +1,58 @@
+package controllers
+
+import (
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/services"
+)
+
+type ChartPermissionController struct {
+	BaseAuthController
+}
+
+// List
+// @Title 系统品种列表
+// @Description 系统品种列表
+// @Param   UserId   query   int  true       "角色ID"
+// @Success 200 {object} models.LoginResp
+// @router /list [get]
+func (this *ChartPermissionController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	id, _ := this.GetInt("chartPermissonId", 0)
+
+	var resp *models.ChartPermissionResp[[]models.ChartPermission]
+	var err error
+	if id == 0 {
+		resp, err = services.GetChartPermissionList()
+	} else if id > 0 {
+		resp, err = services.GetChartPermissionSecondList(id)
+	}
+	if err != nil {
+		br.Msg = "权限列表获取失败"
+		br.ErrMsg = "权限列表获取失败,系统错误,Err:" + err.Error()
+		return
+	}
+	if resp.Ret != 200 {
+		br.Msg = resp.Msg
+		br.ErrMsg = resp.ErrMsg
+		return
+	}
+	chartPermissionList := make([]models.ChartPermissionView, 0)
+	for _, item := range resp.Data {
+		chartPermissionList = append(chartPermissionList, models.ChartPermissionView{
+			ChartPermissionId:   item.ChartPermissionId,
+			ChartPermissionName: item.ChartPermissionName,
+			PermissionName:      item.PermissionName,
+			Remark:              item.Remark,
+			ImageUrl:            item.ImageUrl,
+		})
+	}
+
+	br.Ret = 200
+	br.Data = chartPermissionList
+	br.Msg = "列表获取成功"
+	br.Success = true
+}

+ 21 - 0
controllers/error.go

@@ -0,0 +1,21 @@
+package controllers
+
+import "eta/eta_mini_api/models"
+
+// ErrorController
+// @Description: 该控制器处理页面错误请求
+type ErrorController struct {
+	BaseCommonController
+}
+
+func (c *ErrorController) Error404() {
+	c.Data["content"] = "很抱歉您访问的地址或者方法不存在"
+	//c.TplName = "error/404.html"
+
+	br := new(models.BaseResponse).Init()
+
+	br.Msg = "您访问的资源不存在"
+	br.Ret = 404
+	c.Data["json"] = br
+	c.ServeJSON()
+}

+ 84 - 0
controllers/mini_config.go

@@ -0,0 +1,84 @@
+package controllers
+
+import (
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/models/response"
+)
+
+type MiniConfigController struct {
+	BaseCommonController
+}
+
+// @Title 获取小程序配置项
+// @Description 获取小程序配置项
+// @Param   ReportId   query   int  true       "报告id"
+// @Param   chartPermissionId   query   int  true       "品种ID"
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.ReportDetailResp
+// @router /config [get]
+func (this *MiniConfigController) MiniConfig() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	list := make([]response.MiniConfigResp, 0)
+	miniConf, err := models.GetMiniConf()
+	if err != nil {
+		br.Msg = "获取小程序配置项失败"
+		br.ErrMsg = "获取小程序配置项失败,系统异常,Err:" + err.Error()
+		return
+	}
+	etaConf, err := models.GetEtaConf()
+	if err != nil {
+		br.Msg = "获取小程序配置项失败"
+		br.ErrMsg = "获取程序配置项失败,系统异常,Err:" + err.Error()
+		return
+	}
+
+	list = append(list, response.MiniConfigResp{
+		ConfKey: "ChartViewUrl",
+		ConfVal: etaConf["ChartViewUrl"],
+	}, response.MiniConfigResp{
+		ConfKey: "H5Url",
+		ConfVal: miniConf["H5Url"],
+	}, response.MiniConfigResp{
+		ConfKey: "Disclaimers",
+		ConfVal: miniConf["Disclaimers"],
+	}, response.MiniConfigResp{
+		ConfKey: "ServiceAgreement",
+		ConfVal: miniConf["ServiceAgreement"],
+	}, response.MiniConfigResp{
+		ConfKey: "MostReport",
+		ConfVal: miniConf["MostReport"],
+	}, response.MiniConfigResp{
+		ConfKey: "ServicePhone",
+		ConfVal: miniConf["ServicePhone"],
+	}, response.MiniConfigResp{
+		ConfKey: "Colors",
+		ConfVal: miniConf["Colors"],
+	}, response.MiniConfigResp{
+		ConfKey: "EmptyImg",
+		ConfVal: miniConf["EmptyImg"],
+	}, response.MiniConfigResp{
+		ConfKey: "Logo",
+		ConfVal: miniConf["Logo"],
+	}, response.MiniConfigResp{
+		ConfKey: "WxAppId",
+		ConfVal: miniConf["WxAppId"],
+	}, response.MiniConfigResp{
+		ConfKey: "BindImg",
+		ConfVal: miniConf["BindImg"],
+	})
+
+	br.Data = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+
+}

+ 335 - 0
controllers/my_chart.go

@@ -0,0 +1,335 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/models/request"
+	"eta/eta_mini_api/models/response"
+	"eta/eta_mini_api/services"
+	"eta/eta_mini_api/utils"
+	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type MyChartController struct {
+	BaseAuthController
+}
+
+// @Title 收藏图表
+// @Description 收藏图表
+// @Success 200 {object} models.BaseResponse
+// @router /collect [post]
+func (this *MyChartController) Collect() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MyChartCollectReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有权限收藏"
+		return
+	}
+	if req.ChartInfoId == 0 {
+		chartResp, err := services.GetChartDetail(req.ChartInfoId, req.UniqueCode)
+		if err != nil {
+			br.Msg = "收藏失败"
+			br.Msg = "获取图表信息失败,系统错误,Err:" + err.Error()
+			return
+		}
+		if chartResp.Ret != 200 {
+			br.Msg = chartResp.Msg
+			br.ErrMsg = chartResp.ErrMsg
+			return
+		}
+		req.ChartInfoId = chartResp.Data.ChartInfoId
+	}
+	count, err := models.GetMyChartCount(user.UserId, req.UniqueCode)
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "该图表已收藏,请重新刷新页面"
+		return
+	}
+	myChart := &models.MyChart{
+		UserId:       user.UserId,
+		UserRealName: user.RealName,
+		UniqueCode:   req.UniqueCode,
+		ChartImage:   req.ChartImage,
+		ChartName:    req.ChartName,
+		ChartInfoId:  req.ChartInfoId,
+		CreateTime:   time.Now(),
+		ModifyTime:   time.Now(),
+	}
+	err = myChart.Insert()
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "收藏失败,Err:" + err.Error()
+		return
+	}
+
+	br.Msg = "收藏成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title 取消收藏
+// @Description 取消收藏
+// @Success 200 {object} models.BaseResponse
+// @router /collectCancel [post]
+func (this *MyChartController) CollectCancel() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MyChartCollectCancelReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有权限收藏"
+		return
+	}
+	count, err := models.GetMyChartCount(user.UserId, req.UniqueCode)
+	if err != nil {
+		br.Msg = "取消收藏失败"
+		br.ErrMsg = "获取收藏信息失败,Err:" + err.Error()
+		return
+	}
+	if count == 0 {
+		br.Msg = "该图表已取消收藏,请重新刷新页面"
+		return
+	}
+	err = models.DeleteMyChart(user.UserId, req.UniqueCode)
+	if err != nil {
+		br.Msg = "取消收藏失败"
+		br.ErrMsg = "取消收藏失败,Err:" + err.Error()
+		return
+	}
+
+	br.Msg = "取消收藏成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title List
+// @Description create users
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.BaseResponse
+// @router /list [get]
+func (this *MyChartController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	if pageSize <= 0 {
+		pageSize = 30
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有收藏权限"
+		return
+	}
+	total, err := models.GetMyChartListCountById(user.UserId)
+	if err != nil {
+		br.Msg = "查询收藏数量失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+
+	resp := new(response.MyChartListResp)
+	startSize := utils.StartIndex(currentIndex, pageSize)
+	items, err := models.GetMyChartListById(user.UserId, startSize, pageSize)
+	if err != nil {
+		br.Msg = "查询收藏失败"
+		br.ErrMsg = "查询收藏失败,Err:" + err.Error()
+		return
+	}
+
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp.List = items
+	resp.Paging = page
+
+	br.Data = resp
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title Locate
+// @Description create users
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.BaseResponse
+// @router /locate [get]
+func (this *MyChartController) Locate() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	user := this.User
+	total, err := models.GetMyChartListCountById(user.UserId)
+	if err != nil {
+		br.Msg = "查询收藏数量失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+	charts := make([]*response.MyChartLocateItem, 0)
+	items, err := models.GetMyChartListById(user.UserId, 0, total)
+	if err != nil {
+		br.Msg = "查询收藏失败"
+		br.ErrMsg = "查询收藏失败,Err:" + err.Error()
+		return
+	}
+	for k, v := range items {
+		var prevChartInfoId, nextChartInfoId int
+		switch k {
+		case 0:
+			prevChartInfoId = -1
+			if k < total-1 {
+				nextChartInfoId = items[k+1].ChartInfoId
+			} else {
+				nextChartInfoId = -1
+			}
+		case total - 1:
+			nextChartInfoId = -1
+			if k > 0 {
+				prevChartInfoId = items[k-1].ChartInfoId
+			}
+		default:
+			prevChartInfoId = items[k-1].ChartInfoId
+			nextChartInfoId = items[k+1].ChartInfoId
+
+		}
+		tmpChart := &response.MyChartLocateItem{
+			MyChartId:       v.MyChartId,
+			ChartInfoId:     v.ChartInfoId,
+			ChartName:       v.ChartName,
+			UniqueCode:      v.UniqueCode,
+			PrevChartInfoId: prevChartInfoId,
+			NextChartInfoId: nextChartInfoId,
+		}
+		charts = append(charts, tmpChart)
+	}
+
+	br.Data = charts
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title Detail
+// @Description 图表详情
+// @Param   ChartInfoId   query   int  true       "图表详情id"
+// @Success 200 {object} models.BaseResponse
+// @router /detail [get]
+func (this *MyChartController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	user := this.User
+	chartInfoId, _ := this.GetInt("ChartInfoId")
+	if chartInfoId <= 0 {
+		br.Msg = "图表id错误"
+		return
+	}
+
+	result, err := services.GetChartDetail(chartInfoId, "")
+	if err != nil {
+		br.Msg = "获取图表详情失败"
+		br.ErrMsg = "获取图表详情失败,Err:" + err.Error()
+		return
+	}
+	if result.Ret != 200 {
+		br.Msg = result.Msg
+		br.ErrMsg = result.ErrMsg
+		return
+	}
+	if result.Ret == 200 && result.Data.UniqueCode == "" {
+		// 说明后台删除了这个图表,那么尝试将收藏的图表也删除
+		models.DeleteMyChartByUserIdAndChartInfoId(user.UserId, chartInfoId)
+		br.Msg = "图表已删除或不存在,请刷新页面"
+		return
+	}
+
+	count, err := models.GetMyChartCount(user.UserId, result.Data.UniqueCode)
+	if err != nil {
+		br.Msg = "图表已删除或不存在"
+		br.ErrMsg = "获取图表详情失败,Err:" + err.Error()
+	}
+	if count > 0 {
+		result.Data.IsCollect = true
+	}
+
+	br.Data = result.Data
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title IsCollect
+// @Description create users
+// @Success 200 {object} models.BaseResponse
+// @router /isCollect [post]
+func (this *MyChartController) IsCollect() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MyChartIsCollectReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	user := this.User
+	count, err := models.GetMyChartCount(user.UserId, req.UniqueCode)
+	if err != nil {
+		br.Msg = "查询收藏数量失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+	resp := new(response.MyChartIsCollectResp)
+	if count > 0 {
+		resp.IsCollect = true
+	} else {
+		resp.IsCollect = false
+	}
+	br.Data = resp
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+}

+ 232 - 0
controllers/my_report.go

@@ -0,0 +1,232 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/models/request"
+	"eta/eta_mini_api/models/response"
+	"eta/eta_mini_api/services"
+	"eta/eta_mini_api/utils"
+	"fmt"
+	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type MyReportController struct {
+	BaseAuthController
+}
+
+// @Title 获取我的报告列表
+// @Description 获取我的报告列表
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.MyReportResp
+// @router /list [get]
+func (this *MyReportController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if err := recover(); err != nil {
+			fmt.Println(err)
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	user := this.User
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	if pageSize <= 0 {
+		pageSize = utils.PageSize30
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "该用户没有收藏权限"
+		return
+	}
+	total, err := models.GetMyReportListCountByUserId(user.UserId)
+	if err != nil {
+		br.Msg = "获取我的报告列表失败"
+		br.ErrMsg = "获取我的报告列表失败,系统异常,Err:" + err.Error()
+		return
+	}
+	resp := new(response.MyReportListResp)
+	startSize := utils.StartIndex(currentIndex, pageSize)
+	reportList, err := models.GetMyReportListByUserId(user.UserId, startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取我的报告列表失败"
+		br.ErrMsg = "获取我的报告列表失败,系统异常,Err:" + err.Error()
+		return
+	}
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp.List = reportList
+	resp.Paging = page
+
+	br.Data = resp
+	br.Success = true
+	br.Msg = "获取我的报告列表成功"
+	br.Ret = 200
+}
+
+// @Title 收藏研报
+// @Description 收藏研报
+// @Success 200 {object} models.BaseResponse
+// @Failure 403 {object} models.BaseResponse
+// @router /collect [post]
+func (this *MyReportController) Collect() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MyReportCollectReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有权限收藏"
+		return
+	}
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportId)
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "该研报已收藏,请重新刷新页面"
+		return
+	}
+	reportResp, err := services.GetReportDetail(req.ReportId, user.UserId)
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "获取研报详情失败,Err:" + err.Error()
+
+	}
+	if reportResp.Ret != 200 {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "获取研报详情失败,Err:" + reportResp.ErrMsg
+		return
+	}
+	report := reportResp.Data.Report
+	publishTime, err := time.Parse(utils.FormatDateTime, report.PublishTime)
+	if err != nil {
+		br.Msg = "时间格式不对"
+		return
+	}
+	myChart := &models.MyReport{
+		UserId:      user.UserId,
+		ReportId:    req.ReportId,
+		Title:       report.Title,
+		Abstract:    report.Abstract,
+		Author:      report.Author,
+		PublishTime: publishTime,
+		Stage:       report.Stage,
+		CreateTime:  time.Now(),
+	}
+	err = myChart.Insert()
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "收藏失败,Err:" + err.Error()
+		return
+	}
+
+	br.Msg = "收藏成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title 取消收藏
+// @Description 取消收藏
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.BaseResponse
+// @Failure 403 {object} models.BaseResponse
+// @router /collectCancel [post]
+func (this *MyReportController) CollectCancel() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MyReportCollectReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有权限收藏"
+		return
+	}
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportId)
+	if err != nil {
+		br.Msg = "取消收藏失败"
+		br.ErrMsg = "获取收藏信息失败,Err:" + err.Error()
+		return
+	}
+	if count == 0 {
+		br.Msg = "该研报已取消收藏,请重新刷新页面"
+		return
+	}
+	err = models.DeleteMyReportByUserIdAndReportId(user.UserId, req.ReportId)
+	if err != nil {
+		br.Msg = "取消收藏失败"
+		br.ErrMsg = "取消收藏失败,Err:" + err.Error()
+		return
+	}
+
+	br.Msg = "取消收藏成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title 是否收藏研报
+// @Description 是否收藏研报
+// @Param	request	body request.MyReportCollectReq true "type json string"
+// @Success 200 {object} models.BaseResponse
+// @router /isCollect [post]
+func (this *MyReportController) IsCollect() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MyReportCollectReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有权限收藏"
+		return
+	}
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportId)
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+	resp := new(response.MyReportIsCollectResp)
+	if count > 0 {
+		resp.IsCollect = true
+	} else {
+		resp.IsCollect = false
+	}
+
+	br.Data = resp
+	br.Msg = "收藏成功"
+	br.Success = true
+	br.Ret = 200
+}

+ 209 - 0
controllers/report.go

@@ -0,0 +1,209 @@
+package controllers
+
+import (
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/models/response"
+	"eta/eta_mini_api/services"
+	"eta/eta_mini_api/utils"
+)
+
+type ReportController struct {
+	BaseAuthController
+}
+
+// @Title 研报详情
+// @Description 研报详情接口
+// @Param   ReportId   query   int  true       "报告id"
+// @Success 200 {object} models.ReportDetailResp
+// @router /detail [get]
+func (this *ReportController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	reportId, _ := this.GetInt("ReportId")
+	if reportId <= 0 {
+		br.Msg = "报告不存在"
+		return
+	}
+	user := this.User
+
+	result, err := services.GetReportDetail(reportId, user.UserId)
+	if err != nil {
+		br.Msg = "查询报告详情失败"
+		br.ErrMsg = "查询报告失败,系统异常,Err:" + err.Error()
+		return
+	}
+
+	if result.Ret == 403 {
+		br.Msg = result.Msg
+		br.ErrMsg = result.ErrMsg
+		return
+	}
+	if result.Ret == 200 && result.Data.Report == nil {
+		// 后台没有这个报告,那么尝试删除我的收藏
+		models.DeleteMyReportByUserIdAndReportId(user.UserId, reportId)
+		br.Msg = "该报告已删除或不存在,请刷新页面"
+		return
+	}
+
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, reportId)
+	if err != nil {
+		br.Msg = "查询收藏数量失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		result.Data.IsCollect = true
+	} else {
+		result.Data.IsCollect = false
+	}
+
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+	br.Data = result.Data
+}
+
+// @Title 研报列表
+// @Description 研报列表
+// @Param   ChartPermissionId   query   int  true       "品种ID"
+// @Param   Level   query   int  true       "品种层级"
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   RangeType   query   string  true       "范围类型,1-一天内,2-一周内,3-半年内"
+// @Success 200 {object} response.ReportList
+// @router /list [get]
+func (this *ReportController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	chartPermissionId, _ := this.GetInt("ChartPermissionId")
+	level, _ := this.GetInt("Level")
+	rangeType, _ := this.GetInt("RangeType")
+	reports, err := services.GetReportList(chartPermissionId, level, rangeType, currentIndex, pageSize)
+	if err != nil {
+		br.Msg = "研报列表查询失败"
+		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
+		return
+	}
+	if reports.Ret != 200 {
+		br.Msg = reports.Msg
+		br.ErrMsg = reports.ErrMsg
+		return
+	}
+
+	br.Data = reports.Data
+	br.Msg = "查询成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// @Title 研报列表
+// @Description 研报列表
+// @Param   ReportId   query   int  true       "报告id"
+// @Param   chartPermissionId   query   int  true       "品种ID"
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.ReportDetailResp
+// @router /daily/list [get]
+func (this *ReportController) DailyList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	if pageSize <= 0 {
+		pageSize = 3
+	}
+
+	reports, err := services.GetReportDailyList(currentIndex, pageSize)
+	if err != nil {
+		br.Msg = "研报列表查询失败"
+		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
+		return
+	}
+
+	br.Data = reports.Data
+	br.Msg = "查询成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// @Title 研报列表
+// @Description 研报列表
+// @Param   ReportId   query   int  true       "报告id"
+// @Param   chartPermissionId   query   int  true       "品种ID"
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} models.ReportDetailResp
+// @router /search [get]
+func (this *ReportController) Search() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	keyWord := this.GetString("KeyWord")
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	if pageSize <= 0 {
+		pageSize = utils.PageSize30
+	}
+
+	if keyWord == "" {
+		br.Msg = "请输入关键字"
+		return
+	}
+
+	reports, err := services.SearchReport(keyWord, currentIndex, pageSize)
+	if err != nil {
+		br.Msg = "研报列表查询失败"
+		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
+		return
+	}
+	if reports.Ret != 200 {
+		br.Msg = reports.Msg
+		br.ErrMsg = reports.ErrMsg
+		return
+	}
+	resp := new(response.ReportSearchViewResp)
+	list := make([]*response.ReportSearchListView, 0)
+	for _, v := range reports.Data.List {
+		tmpReport := &response.ReportSearchListView{
+			ReportId:            v.ReportId,
+			ReportChapterId:     v.ReportChapterId,
+			ClassifyIdFirst:     v.ClassifyIdFirst,
+			ClassifyNameFirst:   v.ClassifyNameFirst,
+			ClassifyIdSecond:    v.ClassifyIdSecond,
+			ClassifyNameSecond:  v.ClassifyNameSecond,
+			ReportChapterTypeId: v.ReportChapterTypeId,
+			PublishTime:         v.PublishTime.Format(utils.FormatDate),
+			Title:               v.Title,
+			ContentSub:          v.ContentSub,
+			Abstract:            v.Abstract,
+			Stage:               v.Stage,
+			Author:              v.Author,
+		}
+		if v.PublishTime.IsZero() {
+			tmpReport.PublishTime = ""
+		}
+		list = append(list, tmpReport)
+	}
+	resp.List = list
+	resp.Paging = reports.Data.Paging
+	br.Data = resp
+	br.Msg = "查询成功"
+	br.Ret = 200
+	br.Success = true
+}

+ 580 - 27
controllers/user.go

@@ -4,26 +4,35 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"eta/eta_mini_api/models"
 	"eta/eta_mini_api/models"
 	"eta/eta_mini_api/models/request"
 	"eta/eta_mini_api/models/request"
+	"eta/eta_mini_api/models/response"
 	"eta/eta_mini_api/services"
 	"eta/eta_mini_api/services"
+	"eta/eta_mini_api/services/go_redis"
 	"eta/eta_mini_api/utils"
 	"eta/eta_mini_api/utils"
 	"fmt"
 	"fmt"
+	"strings"
+	"time"
 )
 )
 
 
 type UserController struct {
 type UserController struct {
 	BaseCommonController
 	BaseCommonController
 }
 }
 
 
+type UserAuthController struct {
+	BaseAuthController
+}
+
 // @Title 用户登录接口
 // @Title 用户登录接口
 // @Description 用户登录
 // @Description 用户登录
 // @Param	request	body models.LoginReq true "type json string"
 // @Param	request	body models.LoginReq true "type json string"
 // @Success 200 {object} models.LoginResp
 // @Success 200 {object} models.LoginResp
 // @router /login [post]
 // @router /login [post]
-func (this *UserController) Login() {
+func (this *UserAuthController) Login() {
 	br := new(models.BaseResponse).Init()
 	br := new(models.BaseResponse).Init()
 	defer func() {
 	defer func() {
 		this.Data["json"] = br
 		this.Data["json"] = br
 		this.ServeJSON()
 		this.ServeJSON()
 	}()
 	}()
+	session := this.Session
 
 
 	var req request.LoginReq
 	var req request.LoginReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
@@ -32,33 +41,73 @@ func (this *UserController) Login() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 		return
 	}
 	}
+
 	switch req.LoginType {
 	switch req.LoginType {
 	case 1:
 	case 1:
-		if req.Mobile == "" {
+		if req.Phone == "" {
 			br.Msg = "请输入手机号"
 			br.Msg = "请输入手机号"
+			br.ErrMsg = "请输入手机号"
 			return
 			return
 		}
 		}
-		if req.VerifyCode == "" {
+		if req.SmsCode == "" {
 			br.Msg = "请输入验证码"
 			br.Msg = "请输入验证码"
+			br.ErrMsg = "请输入验证码"
 			return
 			return
 		}
 		}
-		code := utils.GetRandDigit(6)
-		ok := services.SendSmsCode(req.Mobile, code)
-		if !ok {
-			br.Msg = "短信验证码发送失败"
+		phone := req.AreaCode + req.Phone
+		item, err := models.GetMsgCode(phone, req.SmsCode)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "验证码错误,请重新输入"
+				br.ErrMsg = "校验验证码失败,Err:" + err.Error()
+				return
+			} else {
+				br.Msg = "验证码错误,请重新输入"
+				br.ErrMsg = "校验验证码失败,Err:" + err.Error()
+				return
+			}
+		}
+		if item == nil {
+			br.Msg = "验证码错误,请重新输入"
 			return
 			return
 		}
 		}
 
 
 	case 2:
 	case 2:
 		if req.Email == "" {
 		if req.Email == "" {
 			br.Msg = "请输入邮箱"
 			br.Msg = "请输入邮箱"
+			br.ErrMsg = "请输入邮箱"
 			return
 			return
 		}
 		}
-		if req.VerifyCode == "" {
+		if req.SmsCode == "" {
 			br.Msg = "请输入验证码"
 			br.Msg = "请输入验证码"
+			br.ErrMsg = "请输入验证码"
 			return
 			return
 		}
 		}
-
+		item, err := models.GetMsgCode(req.Email, req.SmsCode)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "验证码错误,请重新输入"
+				br.ErrMsg = "校验验证码失败,Err:" + err.Error()
+				return
+			} else {
+				br.Msg = "验证码错误,请重新输入"
+				br.ErrMsg = "校验验证码失败,Err:" + err.Error()
+				return
+			}
+		}
+		if item == nil {
+			br.Msg = "验证码错误,请重新输入"
+			return
+		}
+	}
+	_, errMsg, err := services.BindUser(session.UnionId, session.OpenId, req.Phone, req.Email, req.AreaCode)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "登录失败,系统处理中,请稍后重试"
+		if errMsg != "" {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "登录失败:" + err.Error()
+		return
 	}
 	}
 
 
 	br.Msg = "登录成功"
 	br.Msg = "登录成功"
@@ -66,12 +115,11 @@ func (this *UserController) Login() {
 	br.Ret = 200
 	br.Ret = 200
 }
 }
 
 
-// GetVerifyCode
 // @Title 获取短信/邮箱验证码
 // @Title 获取短信/邮箱验证码
-// @Description 获取短信/邮箱验证码
-// @Param	request	body VerifyCodeReq true "type json string"
-// @Success 200 Ret=200 获取成功
-// @Router /getSmsCode [get]
+// @Description 用户登录
+// @Param	request	body models.LoginReq true "type json string"
+// @Success 200 {object} models.LoginResp
+// @router /getVerifyCode [post]
 func (this *UserController) GetVerifyCode() {
 func (this *UserController) GetVerifyCode() {
 	br := new(models.BaseResponse).Init()
 	br := new(models.BaseResponse).Init()
 	defer func() {
 	defer func() {
@@ -91,24 +139,57 @@ func (this *UserController) GetVerifyCode() {
 		br.ErrMsg = fmt.Sprintf("验证方式异常<%d>", req.VerifyType)
 		br.ErrMsg = fmt.Sprintf("验证方式异常<%d>", req.VerifyType)
 	}
 	}
 
 
+	code := utils.GetRandDigit(6)
+	fmt.Println(code)
 	switch req.VerifyType {
 	switch req.VerifyType {
 	case 1:
 	case 1:
-		if req.TelAreaCode == "" {
+		if req.AreaCode == "" {
 			br.Msg = "请选择区号"
 			br.Msg = "请选择区号"
 			return
 			return
 		}
 		}
-		if req.Mobile == "" {
+		if req.Phone == "" {
 			br.Msg = "请输入手机号"
 			br.Msg = "请输入手机号"
 			return
 			return
 		}
 		}
-		if req.TelAreaCode == utils.TelAreaCodeHome && !utils.ValidateMobileFormatat(req.Mobile) {
+		if req.AreaCode == utils.TelAreaCodeHome && !utils.ValidateMobileFormatat(req.Phone) {
 			br.Msg = "您的手机号输入有误, 请检查"
 			br.Msg = "您的手机号输入有误, 请检查"
 			return
 			return
 		}
 		}
-		ok := services.SendSmsCode(req.Mobile, req.TelAreaCode)
+		phoneKey := utils.CACHE_ACCESS_PHONE_LOGIN_CODE + req.AreaCode + req.Phone
+		res, _ := go_redis.RedisInt(phoneKey)
+		if res > 5 {
+			br.Msg = "验证码发送太频繁,请稍后重试"
+			return
+		}
+		var ok bool
+		if req.AreaCode == "86" {
+			ok = services.SendSmsCode(req.Phone, code)
+		} else {
+			ok = services.SendSmsCodeGj(req.Phone, code, req.AreaCode)
+		}
 		if !ok {
 		if !ok {
-			br.ErrMsg = "短信验证码发送错误" + err.Error()
+			br.ErrMsg = "短信验证码发送失败"
 			return
 			return
+		} else {
+			item := new(models.MsgCode)
+			item.OpenId = ""
+			item.Code = code
+			item.Mobile = req.AreaCode + req.Phone
+			item.ExpiredIn = time.Now().Add(15 * time.Minute).Unix()
+			item.CreateTime = time.Now()
+			err = item.Insert()
+			if err != nil {
+				br.Msg = "发送失败"
+				br.ErrMsg = "发送失败,Err:" + err.Error()
+				return
+			}
+			br.Msg = "发送成功"
+			isExist := go_redis.IsExist(phoneKey)
+			if isExist {
+				go_redis.Incr(phoneKey)
+			} else {
+				go_redis.SetNX(phoneKey, 1, time.Minute*15)
+			}
 		}
 		}
 	case 2:
 	case 2:
 		if req.Email == "" {
 		if req.Email == "" {
@@ -118,7 +199,46 @@ func (this *UserController) GetVerifyCode() {
 			br.Msg = "您的邮箱格式输入有误, 请检查"
 			br.Msg = "您的邮箱格式输入有误, 请检查"
 			return
 			return
 		}
 		}
-		// err := services.SendEmailCode(req.Email)
+
+		emailKey := utils.CACHE_ACCESS_EMAIL_LOGIN_CODE + req.Email
+		res, _ := go_redis.RedisInt(emailKey)
+		if res > 5 {
+			br.Msg = "验证码发送太频繁,请稍后重试"
+			return
+		}
+
+		date := time.Now()
+		content := "尊敬的用户:</br>本次请求的验证码为:" + code + "(为了保障您账号的安全性,请在15分钟内完成验证。)</br>东吴期货研究团队 </br>" + fmt.Sprintf("%d年%02d月%02d日", date.Year(), date.Month(), date.Day())
+		title := "东吴期货登录验证"
+		result, err := utils.SendEmailByDw(title, content, req.Email)
+		if err != nil {
+			br.Msg = "发送失败"
+			br.ErrMsg = "发送失败,Err:" + err.Error()
+			return
+		}
+		if result {
+			item := new(models.MsgCode)
+			item.OpenId = ""
+			item.Code = code
+			item.Mobile = req.Email
+			item.ExpiredIn = time.Now().Add(15 * time.Minute).Unix()
+			item.CreateTime = time.Now()
+			err = item.Insert()
+			if err != nil {
+				br.Msg = "发送失败"
+				br.ErrMsg = "发送失败,Err:" + err.Error()
+				return
+			}
+			br.Msg = "发送成功"
+			isExist := go_redis.IsExist(emailKey)
+			if isExist {
+				go_redis.Incr(emailKey)
+			} else {
+				go_redis.SetNX(emailKey, 1, time.Minute*15)
+			}
+		} else {
+			br.Msg = "发送失败"
+		}
 	}
 	}
 
 
 	br.Ret = 200
 	br.Ret = 200
@@ -126,13 +246,446 @@ func (this *UserController) GetVerifyCode() {
 	br.Msg = "发送成功"
 	br.Msg = "发送成功"
 }
 }
 
 
-// SendEmail
-// @Title 获取短信/邮箱验证码
-// @Description 获取短信/邮箱验证码
-// @Param	request	body VerifyCodeReq true "type json string"
+// @Title 新增报告浏览记录
+// @Description 新增报告浏览记录接口
+// @Param	request	body models.ReportRecordReq true "type json string"
+// @Success 200 新增成功
+// @router /addReportRecord [post]
+func (this *UserAuthController) AddReportRecord() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	user := this.User
+	if user == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,用户信息为空"
+		br.Ret = 408
+		return
+	}
+	var req request.ReportRecordReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ReportId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,报告id小于等于0"
+		return
+	}
+	reportResp, err := services.GetReportDetail(req.ReportId, user.UserId)
+	if err != nil {
+		br.Msg = "添加阅读记录失败"
+		br.ErrMsg = "获取研报错误,Err:" + err.Error()
+		return
+	}
+	if reportResp.Ret != 200 {
+		br.Msg = reportResp.Msg
+		br.ErrMsg = reportResp.ErrMsg
+		return
+	}
+	reportDetail := reportResp.Data.Report
+	reportPermissionResp, err := services.GetReportChartPermissionList(req.ReportId)
+	if err != nil {
+		br.Msg = "添加阅读记录失败"
+		br.ErrMsg = "获取研报品种错误,Err:" + err.Error()
+		return
+	}
+	if reportPermissionResp.Ret != 200 {
+		br.Msg = reportPermissionResp.Msg
+		br.ErrMsg = reportPermissionResp.ErrMsg
+		return
+	}
+	reportPermissionList := reportPermissionResp.Data
+	chartPermissionList, err := services.GetChartPermissionAllList()
+	if err != nil {
+		br.Msg = "添加阅读记录失败"
+		br.ErrMsg = "获取研报品种列表失败,Err:" + err.Error()
+		return
+	}
+	chartMap := make(map[int]*models.ChartPermission)
+	for _, permission := range chartPermissionList.Data {
+		chartMap[permission.ChartPermissionId] = permission
+	}
+	curTime := time.Now()
+	var insertId int64
+	if req.RecordId == 0 {
+		// 如果不存在就新增一条记录
+		permission1Ids := make([]int, 0)
+		permission2Ids := make([]int, 0)
+		permissionNames := make([]string, 0)
+		for _, item := range reportPermissionList {
+			curPermission := chartMap[item.ChartPermissionId]
+			permission1Ids = append(permission1Ids, curPermission.ParentId)
+			permission2Ids = append(permission2Ids, curPermission.ChartPermissionId)
+			permissionNames = append(permissionNames, curPermission.PermissionName)
+		}
+		permission1Ids = utils.Unique(permission1Ids)
+		permission2Ids = utils.Unique(permission2Ids)
+		permissionNames = utils.Unique(permissionNames)
+		userReadRecord := &models.UserReadRecord{
+			UserId:              user.UserId,
+			ReportId:            req.ReportId,
+			ReportTitle:         reportDetail.Title,
+			ChartPermissionName: strings.Join(permissionNames, ","),
+			ClassifyId1:         reportDetail.ClassifyIdFirst,
+			ClassifyName1:       reportDetail.ClassifyNameFirst,
+			ClassifyId2:         reportDetail.ClassifyIdSecond,
+			ClassifyName2:       reportDetail.ClassifyNameSecond,
+			Timestamp:           int(curTime.Unix()),
+			CreateTime:          curTime,
+			CreateDate:          curTime.Format(utils.FormatDate),
+		}
+		insertId, err = userReadRecord.Insert()
+		if err != nil {
+			br.Msg = "添加阅读记录失败"
+			br.ErrMsg = "添加阅读记录失败,Err:" + err.Error()
+			return
+		}
+
+		userReadPermission1 := make([]*models.UserReadPermission1, 0)
+		for _, id := range permission1Ids {
+			userReadPermission1 = append(userReadPermission1, &models.UserReadPermission1{
+				UserReadRecordId:  int(insertId),
+				ChartPermissionId: id,
+				PermissionName:    chartMap[id].PermissionName,
+			})
+		}
+		err = models.UserReadPermission1MultiInsert(userReadPermission1)
+		if err != nil {
+			br.Msg = "添加阅读记录失败"
+			br.ErrMsg = "添加阅读记录失败,Err:" + err.Error()
+			return
+		}
+		userReadPermission2 := make([]*models.UserReadPermission2, 0)
+		for _, id := range permission2Ids {
+			userReadPermission2 = append(userReadPermission2, &models.UserReadPermission2{
+				UserReadRecordId:  int(insertId),
+				ChartPermissionId: id,
+			})
+		}
+		err = models.UserReadPermission2MultiInsert(userReadPermission2)
+		if err != nil {
+			br.Msg = "添加阅读记录失败"
+			br.ErrMsg = "添加阅读记录失败,Err:" + err.Error()
+			return
+		}
+	} else {
+		// 如果存在就计算停留时间
+		userRecord, err := models.GetUserReadRecordListById(req.RecordId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "更新阅读记录不存在"
+				return
+			}
+			br.Msg = "更新阅读记录失败"
+			br.ErrMsg = "更新阅读记录失败,Err:" + err.Error()
+			return
+		}
+		stayTime := curTime.Unix() - int64(userRecord.Timestamp)
+		stayTimeStr := utils.SecondsToHMS(stayTime)
+		err = models.UpdateUserReadRecordById(req.RecordId, int(curTime.Unix()), int(stayTime), stayTimeStr)
+		if err != nil {
+			br.Msg = "更新阅读记录失败"
+			br.ErrMsg = "更新阅读记录失败,Err:" + err.Error()
+			return
+		}
+	}
+	resp := new(response.UserReadRecordResp)
+	resp.RecordId = insertId
+
+	br.Msg = "添加阅读记录成功"
+	br.Ret = 200
+	br.Success = true
+	br.Data = resp
+}
+
+// AreaCodeList
+// @Title 手机号区号列表
+// @Description 手机号区号列表
+// @Success 200 Ret=200 获取成功
+// @router /area_code/list [get]
+func (this *UserController) AreaCodeList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	resp := make([]response.AreaCodeListResp, 0)
+	confValue, e := models.GetConfigDetailByCode(models.ConfAreaCodeListKey)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取手机号区号配置失败, Err: " + e.Error()
+		return
+	}
+	if confValue == "" {
+		br.Msg = "获取失败"
+		br.ErrMsg = "手机号区号配置为空"
+		return
+	}
+	if e := json.Unmarshal([]byte(confValue), &resp); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "手机号区号配置有误"
+		return
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// 用户品种信息
+// @Title 用户信息
+// @Description 用户信息
 // @Success 200 Ret=200 获取成功
 // @Success 200 Ret=200 获取成功
-// @Router /sendEmail [get]
-func (this *UserController) SendEmail() {
-	utils.SendEmailByHz("测试邮箱", "测试内容", "564693862@qq.com")
+// @router /info [get]
+func (this *UserAuthController) Info() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	user := this.User
 
 
+	if user == nil {
+		user = &models.User{}
+	}
+	seller, err := models.GetSellerById(user.SellerId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败,系统异常,Err:" + err.Error()
+		return
+	}
+	private, err := services.GetPrivateChartPermissionList()
+	if err != nil {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败,系统异常,Err:" + err.Error()
+		return
+	}
+	if private.Ret != 200 {
+		br.Msg = private.Msg
+		br.ErrMsg = private.ErrMsg
+		return
+	}
+	userPermissionIds, err := models.GetChartPermissionIdByUserId(user.UserId)
+	if err != nil {
+		br.Msg = "查看权限失败"
+		br.ErrMsg = "查看权限失败,系统异常,Err:" + err.Error()
+		return
+	}
+	userPermissionMap := make(map[int]struct{})
+	for _, v := range userPermissionIds {
+		userPermissionMap[v] = struct{}{}
+	}
+	if seller == nil {
+		// 添加默认的销售电话
+		seller = &models.SysUser{
+			Phone:    utils.DefaultPhone,
+			AreaCode: utils.DefaultAreaCode,
+		}
+	}
+	var hasPermission string
+	for _, v := range private.Data {
+		for _, vv := range v.Child {
+			if _, ok := userPermissionMap[vv.ChartPermissionId]; ok {
+				hasPermission = "私有权限"
+				break
+			}
+		}
+	}
+	if hasPermission == "" || user.Status == utils.UserStatusNo {
+		hasPermission = "公有权限"
+	}
+	miniconf, err := models.GetMiniConf()
+	if err != nil {
+		br.Msg = "获取配置失败"
+		br.ErrMsg = "获取配置失败,系统异常,Err:" + err.Error()
+		return
+	}
+
+	userView := &models.UserView{
+		Headimgurl:     miniconf["Logo"],
+		RealName:       user.RealName,
+		Phone:          user.Phone,
+		AreaCode:       user.AreaCode,
+		SellerName:     seller.SysRealName,
+		SellerPhone:    seller.Phone,
+		SellerAreaCode: seller.AreaCode,
+		HasPermission:  hasPermission,
+		Email:          user.Email,
+		Componey:       user.Company,
+		IsRegistered:   user.IsRegistered,
+		Status:         user.Status,
+		ValidEndTime:   user.ValidEndTime.Format(utils.FormatDate),
+	}
+
+	if user.ValidEndTime.IsZero() {
+		userView.ValidEndTime = ""
+	}
+	br.Data = userView
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// PermissionList
+// @Title 用户个人权限列表
+// @Description 用户个人权限列表
+// @Param	request	body models.LoginReq true "type json string"
+// @Success 200 {object} []models.ChartPermissionTreeView
+// @router /permission/list [get]
+func (this *UserAuthController) PermissionList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	user := this.User
+	permissionIds, err := models.GetChartPermissionIdByUserId(user.UserId)
+	if err != nil {
+		br.Msg = "查询用户权限失败"
+		br.ErrMsg = "查询用户权限失败,系统异常,Err:" + err.Error()
+		return
+	}
+	userPermissionMap := make(map[int]struct{})
+	for _, v := range permissionIds {
+		userPermissionMap[v] = struct{}{}
+	}
+	// 查询公有权限
+	var publicView []*models.ChartPermissionTreeView
+	publicResp, err := services.GetPublicChartPermissionList()
+	if err != nil {
+		br.Msg = "查询公有权限失败"
+		br.ErrMsg = "查询私有权限失败,系统异常,Err:" + err.Error()
+	}
+	if publicResp.Ret != 200 {
+		br.Msg = publicResp.Msg
+		br.ErrMsg = publicResp.ErrMsg
+		return
+	}
+	publicView = publicResp.Data
+
+	// 如果是正式用户,则查询私有权限
+	var privateView []*models.ChartPermissionTreeView
+	if user.Status == utils.UserStatusFormal {
+		privateResp, err := services.GetPrivateChartPermissionList()
+		if err != nil {
+			br.Msg = "查询私有权限失败"
+			br.ErrMsg = "查询私有权限失败,系统异常,Err:" + err.Error()
+		}
+		if privateResp.Ret != 200 {
+			br.Msg = privateResp.Msg
+			br.ErrMsg = privateResp.ErrMsg
+			return
+		}
+
+		for _, v := range privateResp.Data {
+			IsAdd := false
+			curPermissionView := &models.ChartPermissionTreeView{
+				ChartPermissionId: v.ChartPermissionId,
+				PermissionName:    v.PermissionName,
+				IsPublic:          v.IsPublic,
+				Sort:              v.Sort,
+				Child:             make([]*models.ChartPermissionTreeView, 0),
+			}
+			for _, vv := range v.Child {
+				if _, ok := userPermissionMap[vv.ChartPermissionId]; ok {
+					curPermissionView.Child = append(curPermissionView.Child, vv)
+					IsAdd = true
+				}
+			}
+			if IsAdd {
+				privateView = append(privateView, curPermissionView)
+			}
+		}
+	}
+	privateAloneView := make([]*models.ChartPermissionTreeView, 0)
+	for _, vi := range privateView {
+		isHas := false
+		for _, vb := range publicView {
+			if vi.ChartPermissionId == vb.ChartPermissionId {
+				isHas = true
+				vb.Child = append(vb.Child, vi.Child...)
+				break
+			}
+		}
+		if !isHas {
+			privateAloneView = append(privateAloneView, vi)
+		}
+	}
+	publicView = append(publicView, privateAloneView...)
+
+	br.Data = publicView
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// PermissionList
+// @Title 用户已购权限列表
+// @Description 用户已购权限列表
+// @Param	request	body models.LoginReq true "type json string"
+// @Success 200 {object} []models.ChartPermissionTreeView
+// @router /purchased/list [get]
+func (this *UserAuthController) PurchasedPermission() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	user := this.User
+	permissionIds, err := models.GetChartPermissionIdByUserId(user.UserId)
+	if err != nil {
+		br.Msg = "查询用户权限失败"
+		br.ErrMsg = "查询用户权限失败,系统异常,Err:" + err.Error()
+		return
+	}
+	permissionMap := make(map[int]struct{})
+	for _, v := range permissionIds {
+		permissionMap[v] = struct{}{}
+	}
+	// 查询私有权限
+	privateResp, err := services.GetPrivateChartPermissionList()
+	if err != nil {
+		br.Msg = "查询私有权限失败"
+		br.ErrMsg = "查询私有权限失败,系统异常,Err:" + err.Error()
+	}
+	if privateResp.Ret != 200 {
+		br.Msg = privateResp.Msg
+		br.ErrMsg = privateResp.ErrMsg
+		return
+	}
+
+	var privateView []*models.ChartPermissionTreeView
+	for _, v := range privateResp.Data {
+		IsAdd := false
+		curPermissionView := &models.ChartPermissionTreeView{
+			ChartPermissionId: v.ChartPermissionId,
+			PermissionName:    v.PermissionName,
+			IsPublic:          v.IsPublic,
+			Sort:              v.Sort,
+			Child:             make([]*models.ChartPermissionTreeView, 0),
+		}
+		for _, vv := range v.Child {
+			if _, ok := permissionMap[vv.ChartPermissionId]; ok && vv.ParentId != 0 {
+				curPermissionView.Child = append(curPermissionView.Child, vv)
+				IsAdd = true
+			}
+		}
+		if IsAdd {
+			privateView = append(privateView, curPermissionView)
+		}
+	}
+
+	br.Data = privateView
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
 }
 }

+ 336 - 39
controllers/wechat.go

@@ -1,86 +1,383 @@
 package controllers
 package controllers
 
 
 import (
 import (
+	"encoding/json"
+	"encoding/xml"
 	"eta/eta_mini_api/models"
 	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/models/request"
+	"eta/eta_mini_api/models/response"
+	"eta/eta_mini_api/services/alarm_msg"
 	"eta/eta_mini_api/services/wechat"
 	"eta/eta_mini_api/services/wechat"
 	"eta/eta_mini_api/services/wx_app"
 	"eta/eta_mini_api/services/wx_app"
 	"eta/eta_mini_api/utils"
 	"eta/eta_mini_api/utils"
 	"fmt"
 	"fmt"
+	"strconv"
+	"time"
 )
 )
 
 
 type WechatController struct {
 type WechatController struct {
 	BaseCommonController
 	BaseCommonController
 }
 }
 
 
-// Login
-// @Title 微信用户登录
-// @Description 用户登录
-// @Param	request	body UserLoginReq true "type json string"
+// @Title 微信获取签名接口
+// @Description 微信获取签名接口
+// @Param   Url   query   string  true       "url地址"
+// @Success 200 {object} models.WechatSign
+// @router /notify [get,post]
+func (this *WechatController) Notify() {
+	echostr := this.GetString("echostr")
+	method := this.Ctx.Input.Method()
+
+	type Notify struct {
+		ToUserName   string `xml:"ToUserName"`
+		FromUserName string `xml:"FromUserName"`
+		CreateTime   int    `xml:"CreateTime"`
+		MsgType      string `xml:"MsgType"`
+		Event        string `xml:"Event"`
+		EventKey     string `xml:"EventKey"`
+		Content      string `xml:"Content"`
+	}
+	if method == "POST" {
+		body := this.Ctx.Input.RequestBody
+		utils.FileLog.Info("wechat notify:" + string(body))
+		item := new(Notify)
+		err := xml.Unmarshal(body, &item)
+		if err != nil {
+			utils.FileLog.Info("xml.Unmarshal:" + err.Error())
+		}
+		contactMsg := "感谢关注东吴期货研究所\r\n公司地址:上海市黄浦区西藏南路1208号东吴证券大厦19楼\r\n\r\n业务合作:\r\n电话:021-6312 3065\r\n邮箱:lvan@dwqh88.com\r\n邮编:200001"
+
+		var openId, returnResult string
+		if item.MsgType != "" {
+			openId = item.FromUserName
+		}
+		xmlTpl := `<xml>
+		<ToUserName><![CDATA[%s]]></ToUserName>
+		<FromUserName><![CDATA[%s]]></FromUserName>
+		<CreateTime>%s</CreateTime>
+		<MsgType><![CDATA[text]]></MsgType>
+		<Content><![CDATA[%s]]></Content>
+		</xml>`
+		createTime := strconv.FormatInt(time.Now().Unix(), 10)
+		// WxId := "gh_5dc508325c6f" // 弘则投研公众号原始id
+		xmlTpl = fmt.Sprintf(xmlTpl, openId, utils.DW_WX_Id, createTime, contactMsg)
+
+		if item.MsgType == "event" {
+			switch item.Event {
+			case "subscribe":
+				fmt.Println("关注")
+				go subscribe(openId)
+			case "unsubscribe":
+				fmt.Println("取消关注")
+				go unsubscribe(openId)
+			case "CLICK":
+				returnResult = xmlTpl
+			default:
+				utils.FileLog.Info("wechat notify event:" + item.Event)
+			}
+			this.Ctx.WriteString(xmlTpl)
+		} else {
+			returnResult = xmlTpl
+		}
+		this.Ctx.WriteString(returnResult)
+	} else {
+		this.Ctx.WriteString(echostr)
+	}
+}
+
+// subscribe 关注后的处理逻辑
+func subscribe(openId string) {
+	userRecord, err := models.GetUserRecordByOpenId(openId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		fmt.Println("通过openid获取user_record记录失败,err:" + err.Error())
+		return
+	}
+	err = nil
+
+	// openId已存在
+	if userRecord != nil {
+		if userRecord.UserId > 0 && userRecord.UnionId != "" { //已经绑定了的话,那么就去修改用户状态
+			models.UserSubscribe(1, openId)
+		} else {
+			// 没有绑定的话,那么校验下unionid,然后再去修改
+			unionId := userRecord.UnionId
+			if unionId == `` {
+				wxUserItem, err := wechat.GetUserInfo(openId)
+				if err != nil {
+					fmt.Println("获取用户信息失败,err:" + err.Error())
+					return
+				}
+				if wxUserItem.UnionID != `` {
+					unionId = wxUserItem.UnionID
+				}
+			}
+			userRecord.UnionId = unionId
+			userRecord.Subscribe = 1
+			userRecord.SubscribeTime = time.Now()
+			err = userRecord.Update([]string{"union_id", "subscribe", "subscribe_time"})
+			if err != nil {
+				fmt.Println("关注后,通过openid更新user_record异常,err:", err)
+				return
+			}
+			user, err := models.GetUserByUnionId(unionId)
+			if err != nil {
+				fmt.Println("关注后,通过unionid获取user记录失败,err:" + err.Error())
+				return
+			}
+			if user != nil {
+				user.IsSubscribed = true
+				user.ModifyTime = time.Now()
+				err = user.Update([]string{"modify_time", "is_subscribed"})
+				if err != nil {
+					fmt.Println("关注后,修改绑定用户状态异常,err:", err)
+					return
+				}
+				userRecord.UserId = user.UserId
+				userRecord.Update([]string{"user_id"})
+			}
+		}
+		return
+	}
+
+	// 没有记录,那么需要获取下unionid
+	wxUserItem, err := wechat.GetUserInfo(openId)
+	if err != nil {
+		fmt.Println("获取用户信息失败,err:" + err.Error())
+		return
+	}
+	newUserRecord := &models.UserRecord{
+		OpenId:        openId,
+		UnionId:       wxUserItem.UnionID,
+		Subscribe:     1,
+		SubscribeTime: time.Now(),
+		NickName:      wxUserItem.Nickname,
+		Sex:           int(wxUserItem.Sex),
+		Province:      wxUserItem.Province,
+		City:          wxUserItem.City,
+		Country:       wxUserItem.Country,
+		Headimgurl:    wxUserItem.Headimgurl,
+		CreateTime:    time.Now(),
+	}
+	insertId, err := newUserRecord.Insert()
+	newUserRecord.UserRecordId = int(insertId)
+	if err != nil {
+		fmt.Println("关注后,添加user_record信息失败,err:" + err.Error())
+		return
+	}
+	// 检测用户是否绑定小程序,如果绑定修改用户状态
+	user, err := models.GetUserByUnionId(newUserRecord.UnionId)
+	if err != nil {
+		fmt.Println("修改绑定用户状态异常,ERR:", err)
+		return
+	}
+	if user != nil {
+		user.IsRegistered = true
+		user.ModifyTime = time.Now()
+		err = user.Update([]string{"is_registered", "modify_time"})
+		if err != nil {
+			fmt.Println("关注后,修改绑定用户状态异常,ERR:", err)
+			return
+		}
+		newUserRecord.UserId = user.UserId
+		newUserRecord.Update([]string{"user_id"})
+	}
+
+}
+
+// unsubscribe 取消关注后的处理逻辑
+func unsubscribe(openId string) {
+	userRecord, err := models.GetUserRecordByOpenId(openId)
+	if err != nil {
+		return
+	}
+	userRecord.Subscribe = 0
+	err = userRecord.Update([]string{"subscribe"})
+	if err != nil {
+		return
+	}
+	if userRecord.UnionId != "" {
+		user, err := models.GetUserByUnionId(userRecord.UnionId)
+		if err != nil {
+			return
+		}
+		if user != nil {
+			user.IsSubscribed = false
+			user.ModifyTime = time.Now()
+			err = user.Update([]string{"is_subscribed", "modify_time"})
+			if err != nil {
+				return
+			}
+		}
+	}
+}
+
+// @Title 微信登录
+// @Description 微信登录
+// @Param	request	body models.LoginReq true "type json string"
 // @Success 200 {object} models.LoginResp
 // @Success 200 {object} models.LoginResp
-// @router /login [get]
+// @router /login [post]
 func (this *WechatController) Login() {
 func (this *WechatController) Login() {
 	br := new(models.BaseResponse).Init()
 	br := new(models.BaseResponse).Init()
 	defer func() {
 	defer func() {
+		if err := recover(); err != nil {
+			fmt.Println(err)
+		}
 		this.Data["json"] = br
 		this.Data["json"] = br
 		this.ServeJSON()
 		this.ServeJSON()
 	}()
 	}()
 
 
-	code := this.GetString("code")
-	wxUserInfo, err := wx_app.GetSession(code)
+	var req request.WeChatLoginReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
 	if err != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取失败,Err:" + err.Error()
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.Code == "" {
+		br.Msg = "授权码不存在"
 		return
 		return
 	}
 	}
 
 
-	fmt.Println("openid", wxUserInfo.OpenID)
-	user, err := wechat.GetUserInfo(wxUserInfo.OpenID)
+	userInfo, err := wx_app.GetSession(req.Code)
 	if err != nil {
 	if err != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取失败,Err:" + err.Error()
+		br.Msg = "登录失败,请重新尝试"
+		br.ErrMsg = "用户信息获取失败,系统错误,Err:" + err.Error()
 		return
 		return
 	}
 	}
-	fmt.Println("user----", user)
-	fmt.Println(wxUserInfo)
-	fmt.Println("openid", wxUserInfo.OpenID)
-	fmt.Println("unionid", wxUserInfo.UnionID)
-	// token, userId, isBind, err := services.WxLogin(wxUserInfo)
+	session, err := models.GetWxSessionByOpenId(userInfo.OpenID)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "登录失败,请重新尝试"
+		br.ErrMsg = "用户信息获取失败,系统错误,Err:" + err.Error()
+		return
+	}
+	if session == nil {
+		session = &models.WxSession{
+			OpenId:     userInfo.OpenID,
+			UnionId:    userInfo.UnionID,
+			CreateTime: time.Now(),
+		}
+		insertId, er := session.Insert()
+		session.WxSessionId = int(insertId)
+		if er != nil {
+			br.Msg = "用户登录失败"
+			br.ErrMsg = "用户登录获取失败,系统错误,Err:" + er.Error()
+			return
+		}
+	}
+	var token string
+	timeUnix := time.Now().Unix()
+	timeUnixStr := strconv.FormatInt(timeUnix, 10)
+	token = utils.MD5(session.OpenId) + utils.MD5(timeUnixStr)
+	session.AccessToken = token
+	session.LastUpdateTime = time.Now()
+	err = session.Update([]string{"access_token", "last_update_time"})
+	if err != nil {
+		br.Msg = "微信登录失败"
+		br.ErrMsg = "微信登录失败,更新用户信息失败:" + err.Error()
+		return
+	}
+	token = session.AccessToken
+	resp := new(response.WeChatLoginResp)
+	resp.Authorization = token
+
+	br.Data = resp
+	br.Msg = "登录成功"
+	br.Success = true
+	br.Ret = 200
 }
 }
 
 
-// GetUserInfo
-// @Title 获取微信用户信息
-// @Description 获取微信用户信息
-// @Param	request	body UserLoginReq true "type json string"
+// @Title 公众号绑定
+// @Description 公众号绑定
+// @Param	request	body request.WeChatLoginReq true "type json string"
 // @Success 200 {object} models.LoginResp
 // @Success 200 {object} models.LoginResp
-// @router /userInfo [get]
-func (this *WechatController) UserInfo() {
+// @router /subscribe [post]
+func (this *WechatController) Subscribe() {
 	br := new(models.BaseResponse).Init()
 	br := new(models.BaseResponse).Init()
 	defer func() {
 	defer func() {
+		if br.Ret != 200 {
+			b, _ := json.Marshal(br)
+			alarm_msg.SendAlarmMsg(string(b), 1)
+		}
 		this.Data["json"] = br
 		this.Data["json"] = br
 		this.ServeJSON()
 		this.ServeJSON()
 	}()
 	}()
 
 
-	openid := `oxgGc63ul7XT_kkxijd5mQI_6agg`
-	userInfo, err := wechat.GetUserInfo(openid)
+	var req request.WeChatLoginReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.Code == "" {
+		br.Msg = "授权码不存在"
+		return
+	}
+	info, err := wechat.GetWxUserInfo(req.Code)
 	if err != nil {
 	if err != nil {
 		br.Msg = "获取失败"
 		br.Msg = "获取失败"
-		br.ErrMsg = "获取失败,系统错误,Err:" + err.Error()
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	if info.ErrCode != 0 {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + info.ErrMsg
 		return
 		return
 	}
 	}
+	userRecord, err := models.GetUserRecordByOpenId(info.OpenId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取用户关注记录失败"
+		br.ErrMsg = "获取用户关注记录失败,Err:" + err.Error()
+		return
+	}
+	// 如果不存在就新增一条记录
+	if userRecord == nil {
+		userRecord := &models.UserRecord{
+			OpenId: info.OpenId,
+		}
+		insertId, err := userRecord.Insert()
+		if err != nil {
+			br.Msg = "新增失败"
+			br.ErrMsg = "新增失败,Err:" + err.Error()
+			return
+		}
+		userRecord.UserRecordId = int(insertId)
+	}
+	if userRecord.UnionId == "" {
+		wxInfo, er := wechat.GetUserInfo(userRecord.OpenId)
+		if er != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败,Err:" + er.Error()
+			return
+		}
+		userRecord.UnionId = wxInfo.UnionID
+		er = userRecord.Update([]string{"union_id"})
+		if er != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败,Err:" + er.Error()
+			return
+		}
+
+	}
+	user, err := models.GetUserByUnionId(userRecord.UnionId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取用户信息失败"
+		br.ErrMsg = "获取用户信息失败,Err:" + err.Error()
+		return
+	}
+	if user != nil {
+		user.IsSubscribed = true
+		err := user.Update([]string{"is_subscribed"})
+		if err != nil {
+			br.Msg = "更新用户信息失败"
+			br.ErrMsg = "更新用户信息失败,Err:" + err.Error()
+			return
+		}
+		userRecord.UserId = user.UserId
+		userRecord.Update([]string{"user_id"})
+	}
 
 
-	br.Data = userInfo
 	br.Msg = "获取成功"
 	br.Msg = "获取成功"
 	br.Success = true
 	br.Success = true
 	br.Ret = 200
 	br.Ret = 200
 }
 }
-
-// SendEmail
-// @Title 获取微信用户信息
-// @Description 获取微信用户信息
-// @Param	request	body UserLoginReq true "type json string"
-// @Success 200 {object} models.LoginResp
-// @router /SendEmail [get]
-func (this *WechatController) SendEmail() {
-	utils.SendEmailByHz("测试邮箱", "测试内容", "564693862@qq.com")
-
-}

+ 2 - 2
go.mod

@@ -7,7 +7,9 @@ require github.com/beego/beego/v2 v2.1.0
 require (
 require (
 	github.com/beego/bee/v2 v2.1.0
 	github.com/beego/bee/v2 v2.1.0
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
+	github.com/go-redis/redis/v8 v8.11.5
 	github.com/go-sql-driver/mysql v1.7.0
 	github.com/go-sql-driver/mysql v1.7.0
+	github.com/rdlucklib/rdluck_tools v1.0.3
 	github.com/silenceper/wechat/v2 v2.1.6
 	github.com/silenceper/wechat/v2 v2.1.6
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
 )
 )
@@ -18,11 +20,9 @@ require (
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/fatih/structs v1.1.0 // indirect
 	github.com/fatih/structs v1.1.0 // indirect
-	github.com/go-redis/redis/v8 v8.11.5 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/kr/text v0.2.0 // indirect
 	github.com/kr/text v0.2.0 // indirect
-	github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pkg/errors v0.9.1 // indirect

+ 50 - 2
main.go

@@ -1,11 +1,59 @@
 package main
 package main
 
 
 import (
 import (
+	"eta/eta_mini_api/controllers"
 	_ "eta/eta_mini_api/routers"
 	_ "eta/eta_mini_api/routers"
-	beego "github.com/beego/beego/v2/server/web"
+	"fmt"
+	"runtime"
+
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context"
 )
 )
 
 
 func main() {
 func main() {
-	beego.Run()
+	if web.BConfig.RunMode == "dev" {
+		web.BConfig.WebConfig.DirectoryIndex = true
+		web.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
+	}
+
+	web.ErrorController(&controllers.ErrorController{})
+	// 内存调整
+	web.BConfig.MaxMemory = 1024 * 1024 * 128
+
+	web.BConfig.RecoverFunc = Recover
+	web.Run()
+
 }
 }
 
 
+func Recover(ctx *context.Context, conf *web.Config) {
+	if err := recover(); err != nil {
+		if err == web.ErrAbort {
+			return
+		}
+		if !web.BConfig.RecoverPanic {
+			panic(err)
+		}
+		stack := ""
+		msg := fmt.Sprintf("The request url is  %v", ctx.Input.URL())
+		stack += msg + "</br>"
+		logs.Critical(msg)
+		msg = fmt.Sprintf("The request data is %v", string(ctx.Input.RequestBody))
+		stack += msg + "</br>"
+		logs.Critical(msg)
+		msg = fmt.Sprintf("Handler crashed with error %v", err)
+		stack += msg + "</br>"
+		logs.Critical(msg)
+		for i := 1; ; i++ {
+			_, file, line, ok := runtime.Caller(i)
+			if !ok {
+				break
+			}
+			logs.Critical(fmt.Sprintf("%s:%d", file, line))
+			stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d</br>", file, line))
+		}
+		//go utils.SendEmail(utils.APPNAME+"崩了"+time.Now().Format("2006-01-02 15:04:05"), stack, utils.EmailSendToUsers)
+		// go alarm_msg.SendAlarmMsg(utils.APPNAME+"崩了"+time.Now().Format("2006-01-02 15:04:05")+"<br/>"+stack, 3)
+	}
+	return
+}

+ 31 - 0
models/banner.go

@@ -0,0 +1,31 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type Banner struct {
+	BannerId   int       `orm:"pk" description:"id"`
+	ImageUrl   string    `description:"图片地址"`
+	CreateTime time.Time `description:"创建时间"`
+	ModifyTime time.Time `description:"修改时间"`
+	JumpUrl    string    `description:"跳转路径"`
+	Remake     string    `description:"备注"`
+	ImageUrlPc string    `description:"pc端图片地址"`
+}
+
+func GetBannerList(startSize, pageSize int) (items []*Banner, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM banner LIMIT ?,?`
+	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func GetBannerById(bannerId int) (items *Banner, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM banner WHERE banner_id = ?`
+	err = o.Raw(sql, bannerId).QueryRow(&items)
+	return
+}

+ 14 - 0
models/business_conf.go

@@ -0,0 +1,14 @@
+package models
+
+import "time"
+
+// BusinessConf 商户配置表
+type BusinessConf struct {
+	Id         int    `orm:"column(id);pk"`
+	ConfKey    string `description:"配置Key"`
+	ConfVal    string `description:"配置值"`
+	ValType    int    `description:"1-字符串;2-数值;3-字符串数组;4-富文本;"`
+	Necessary  int    `description:"是否必填:0-否;1-是"`
+	Remark     string `description:"备注"`
+	CreateTime time.Time
+}

+ 41 - 0
models/chart_permission.go

@@ -0,0 +1,41 @@
+package models
+
+import "time"
+
+type ChartPermissionView struct {
+	ChartPermissionId   int    `description:"权限ID"`
+	ChartPermissionName string `description:"名称"`
+	PermissionName      string `description:"权限名"`
+	Remark              string `description:"备注"`
+	ImageUrl            string `description:"图片地址"`
+}
+
+type ChartPermission struct {
+	ChartPermissionId   int       `description:"问题ID"`
+	ChartPermissionName string    `description:"名称"`
+	PermissionName      string    `description:"权限名"`
+	Sort                int       `description:"排序"`
+	Enabled             int       `description:"是否可用"`
+	CreatedTime         time.Time `description:"创建时间"`
+	LastUpdatedTime     time.Time `description:"更新时间"`
+	Remark              string    `description:"备注"`
+	ImageUrl            string    `description:"图片地址"`
+	ParentId            int       `description:"父级权限id"`
+	IsPublic            int       `description:"是否是公有权限1:公有权限,0私有权限"`
+}
+
+type ChartPermissionResp[T any] struct {
+	Ret    int
+	Data   T
+	Msg    string
+	ErrMsg string
+}
+
+type ChartPermissionTreeView struct {
+	ChartPermissionId int                        `description:"权限ID"`
+	PermissionName    string                     `description:"权限名"`
+	Child             []*ChartPermissionTreeView `description:"子权限"`
+	IsPublic          int                        `description:"是否是公有权限1:公有权限,0私有权限"`
+	ParentId          int                        `description:"父级权限id"`
+	Sort              int                        `description:"排序" json:"-"`
+}

+ 12 - 0
models/chart_permission_search_key_word_mapping.go

@@ -0,0 +1,12 @@
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+func GetClassifyIdsList(chartPermissionId int) (classifyIds []int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT classify_id
+		FROM chart_permission_search_key_word_mapping	
+		WHERE chart_permission_id = ? `
+	_, err = o.Raw(sql, chartPermissionId).QueryRows(&classifyIds)
+	return
+}

+ 24 - 0
models/classify.go

@@ -0,0 +1,24 @@
+package models
+
+import (
+	"time"
+)
+
+type ClassifyDetail struct {
+	ClassifyId     int       `description:"分类id"`
+	ClassifyName   string    `description:"分类名称"`
+	Sort           int       `json:"-"`
+	ParentId       int       `description:"父级分类id"`
+	CreateTime     time.Time `description:"创建时间"`
+	ModifyTime     time.Time `description:"修改时间"`
+	Abstract       string    `description:"栏目简介"`
+	Descript       string    `description:"分享描述"`
+	ReportAuthor   string    `description:"栏目作者"`
+	AuthorDescript string    `description:"作者简介"`
+	ColumnImgUrl   string    `description:"栏目配图"`
+	HeadImgUrl     string    `description:"头部banner"`
+	AvatarImgUrl   string    `description:"头像"`
+	ReportImgUrl   string    `description:"报告配图"`
+	HomeImgUrl     string    `description:"首页配图"`
+	Stage          int       `description:"最新期数"`
+}

+ 21 - 7
models/db.go

@@ -9,6 +9,13 @@ import (
 )
 )
 
 
 func init() {
 func init() {
+	_ = orm.RegisterDataBase("default", "mysql", utils.MYSQL_URL_MASTER)
+	orm.SetMaxIdleConns("default", 50)
+	orm.SetMaxOpenConns("default", 100)
+
+	master_db, _ := orm.GetDB("default")
+	master_db.SetConnMaxLifetime(10 * time.Minute)
+
 	_ = orm.RegisterDataBase("rddp", "mysql", utils.MYSQL_URL_RDDP)
 	_ = orm.RegisterDataBase("rddp", "mysql", utils.MYSQL_URL_RDDP)
 	orm.SetMaxIdleConns("rddp", 50)
 	orm.SetMaxIdleConns("rddp", 50)
 	orm.SetMaxOpenConns("rddp", 100)
 	orm.SetMaxOpenConns("rddp", 100)
@@ -16,22 +23,29 @@ func init() {
 	report_db, _ := orm.GetDB("rddp")
 	report_db, _ := orm.GetDB("rddp")
 	report_db.SetConnMaxLifetime(10 * time.Minute)
 	report_db.SetConnMaxLifetime(10 * time.Minute)
 
 
-	_ = orm.RegisterDataBase("master", "mysql", utils.MYSQL_URL_MASTER)
-	orm.SetMaxIdleConns("master", 50)
-	orm.SetMaxOpenConns("master", 100)
-
-	master_db, _ := orm.GetDB("master")
-	master_db.SetConnMaxLifetime(10 * time.Minute)
+	_ = orm.RegisterDataBase("eta", "mysql", utils.MYSQL_URL)
+	orm.SetMaxIdleConns("eta", 50)
+	orm.SetMaxOpenConns("eta", 100)
 
 
+	db, _ := orm.GetDB("eta")
+	db.SetConnMaxLifetime(10 * time.Minute)
 	orm.Debug = true
 	orm.Debug = true
 	orm.DebugLog = orm.NewLog(utils.BinLog)
 	orm.DebugLog = orm.NewLog(utils.BinLog)
 
 
 	// register model
 	// register model
 	orm.RegisterModel(
 	orm.RegisterModel(
-		new(WxSession),
 		new(MsgCode),
 		new(MsgCode),
+		new(MyChart),
+		new(MyReport),
 		new(User),
 		new(User),
 		new(WxToken),
 		new(WxToken),
+		new(Banner),
+		new(WxSession),
+		new(UserRecord),
+		new(UserTemplateRecord),
+		new(UserReadRecord),
+		new(UserReadPermission1),
+		new(UserReadPermission2),
 	)
 	)
 
 
 }
 }

+ 70 - 0
models/mini_config.go

@@ -0,0 +1,70 @@
+package models
+
+import (
+	"html"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+const ConfAreaCodeListKey = "AreaCodeList" // 手机号区号列表
+
+type MiniConfig struct {
+	ConfigID    int       `description:"配置id"`
+	ConfigCode  string    `description:"配置编码"` // 配置编码
+	ConfigValue string    `description:"配置值"`  // 配置值
+	ValType     int       `description:"配置类型"` // 配置类型
+	Remark      string    `description:"备注信息"` // 备注信息
+	CreateTime  time.Time `description:"创建时间"` // 创建时间
+}
+
+func GetConfigDetailByCode(configCode string) (config_value string, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT config_value FROM mini_config WHERE config_code=? `
+	err = o.Raw(sql, configCode).QueryRow(&config_value)
+	return
+}
+
+// GetMiniConf 获取小程序配置
+func GetMiniConf() (list map[string]string, err error) {
+	list = make(map[string]string)
+
+	var items []*MiniConfig
+	o := orm.NewOrm()
+	sql := `SELECT * FROM mini_config `
+	_, err = o.Raw(sql).QueryRows(&items)
+	if err != nil {
+		return
+	}
+
+	for _, v := range items {
+		if v.ValType == 4 {
+			list[v.ConfigCode] = html.UnescapeString(v.ConfigValue)
+			continue
+		}
+		list[v.ConfigCode] = v.ConfigValue
+	}
+	return
+}
+
+// GetMiniConf 获取eta的服务的配置
+func GetEtaConf() (list map[string]string, err error) {
+	list = make(map[string]string)
+
+	var items []*BusinessConf
+	o := orm.NewOrmUsingDB("eta")
+	sql := `SELECT * FROM  business_conf`
+	_, err = o.Raw(sql).QueryRows(&items)
+	if err != nil {
+		return
+	}
+
+	for _, v := range items {
+		if v.ValType == 4 {
+			list[v.ConfKey] = html.UnescapeString(v.ConfVal)
+			continue
+		}
+		list[v.ConfKey] = v.ConfVal
+	}
+	return
+}

+ 10 - 3
models/msg_code.go

@@ -8,8 +8,8 @@ import (
 
 
 // MsgCode 验证码列表
 // MsgCode 验证码列表
 type MsgCode struct {
 type MsgCode struct {
-	MsgCodeID  int64     `orm:"pk" description:"id"` // 短信验证码id
-	OpenID     string    `description:"用户openId"`    // 用户id
+	MsgCodeId  int64     `orm:"pk" description:"id"` // 短信验证码id
+	OpenId     string    `description:"用户openId"`    // 用户id
 	Mobile     string    `description:"手机号/邮箱"`      // 手机号/邮箱
 	Mobile     string    `description:"手机号/邮箱"`      // 手机号/邮箱
 	Code       string    `description:"验证码"`         // 验证码
 	Code       string    `description:"验证码"`         // 验证码
 	ExpiredIn  int64     `description:"过期时间"`        // 过期时间
 	ExpiredIn  int64     `description:"过期时间"`        // 过期时间
@@ -17,7 +17,14 @@ type MsgCode struct {
 }
 }
 
 
 func (m *MsgCode) Insert() (err error) {
 func (m *MsgCode) Insert() (err error) {
-	o := orm.NewOrmUsingDB("master")
+	o := orm.NewOrm()
 	_, err = o.Insert(m)
 	_, err = o.Insert(m)
 	return
 	return
 }
 }
+
+func GetMsgCode(mobile, code string) (item *MsgCode, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM msg_code WHERE mobile=? AND code=? AND FROM_UNIXTIME(expired_in)>=NOW() `
+	err = o.Raw(sql, mobile, code).QueryRow(&item)
+	return
+}

+ 60 - 0
models/my_chart.go

@@ -0,0 +1,60 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type MyChart struct {
+	MyChartId    int       `orm:"pk" description:"我的图表ID"`
+	ChartName    string    `description:"图表名称"`   // 图表名称
+	UniqueCode   string    `description:"图表唯一编码"` // 图表唯一编码
+	ChartImage   string    `description:"图表图片"`   // 图表图片
+	ChartInfoId  int       `description:"图表id"`   // 图表图片
+	UserId       int       `description:"用户ID"`
+	UserRealName string    `description:"用户真实姓名"` // 真实姓名
+	CreateTime   time.Time `description:"创建时间"`
+	ModifyTime   time.Time `description:"修改时间"`
+}
+
+func (m *MyChart) Insert() (err error) {
+	o := orm.NewOrm()
+	_, err = o.Insert(m)
+	return
+}
+
+func GetMyChartCount(userId int, uniqueCode string) (count int, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT COUNT(*) AS count FROM my_chart WHERE user_id=? AND unique_code=?`
+	err = o.Raw(sql, userId, uniqueCode).QueryRow(&count)
+	return
+}
+
+func GetMyChartListCountById(userId int) (count int, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT COUNT(*) AS count FROM my_chart WHERE user_id=? `
+	err = o.Raw(sql, userId).QueryRow(&count)
+	return
+}
+
+func GetMyChartListById(userId int, startSize, pageSize int) (items []*MyChart, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM my_chart WHERE user_id=? ORDER BY create_time DESC LIMIT ?,?`
+	_, err = o.Raw(sql, userId, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func DeleteMyChart(userId int, uniqueCode string) (err error) {
+	o := orm.NewOrm()
+	sql := `DELETE FROM my_chart WHERE user_id=? AND unique_code=?`
+	_, err = o.Raw(sql, userId, uniqueCode).Exec()
+	return
+}
+
+func DeleteMyChartByUserIdAndChartInfoId(userId int, chartInfoId int) (err error) {
+	o := orm.NewOrm()
+	sql := `DELETE FROM my_chart WHERE user_id=? AND chart_info_id=?`
+	_, err = o.Raw(sql, userId, chartInfoId).Exec()
+	return
+}

+ 53 - 0
models/my_report.go

@@ -0,0 +1,53 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type MyReport struct {
+	MyReportId  int       `orm:"pk" description:"id"`
+	ReportId    int       `description:"报告id"`
+	UserId      int       `description:"用户id"`
+	Title       string    `description:"标题"`
+	Abstract    string    `description:"摘要"`
+	Author      string    `description:"作者"`
+	PublishTime time.Time `description:"发布时间"`
+	Stage       int       `description:"期数"`
+	CreateTime  time.Time `description:"创建时间"`
+}
+
+func (m *MyReport) Insert() (err error) {
+	o := orm.NewOrm()
+	_, err = o.Insert(m)
+	return
+}
+
+func GetMyReportCountByUserIdAndReportId(userId, reportId int) (count int, err error) {
+	o := orm.NewOrm()
+	sql := "SELECT COUNT(*) AS count FROM my_report WHERE user_id = ? AND report_id = ?"
+	err = o.Raw(sql, userId, reportId).QueryRow(&count)
+	return
+}
+
+func DeleteMyReportByUserIdAndReportId(userId, reportId int) (err error) {
+	o := orm.NewOrm()
+	sql := "DELETE FROM my_report WHERE user_id = ? AND report_id = ?"
+	_, err = o.Raw(sql, userId, reportId).Exec()
+	return
+}
+
+func GetMyReportListCountByUserId(userId int) (count int, err error) {
+	o := orm.NewOrm()
+	sql := "SELECT COUNT(*) AS count FROM my_report WHERE user_id = ?"
+	err = o.Raw(sql, userId).QueryRow(&count)
+	return
+}
+
+func GetMyReportListByUserId(userId, startSize, pageSize int) (items []*MyReport, err error) {
+	o := orm.NewOrm()
+	sql := "SELECT * FROM my_report WHERE user_id = ? ORDER BY create_time DESC LIMIT ?, ?"
+	_, err = o.Raw(sql, userId, startSize, pageSize).QueryRows(&items)
+	return
+}

+ 63 - 0
models/report.go

@@ -0,0 +1,63 @@
+package models
+
+import "time"
+
+type ReportList struct {
+	Id                 int       `description:"报告Id"`
+	AddType            int       `description:"新增方式:1:新增报告,2:继承报告"`
+	ClassifyIdFirst    int       `description:"一级分类id"`
+	ClassifyNameFirst  string    `description:"一级分类名称"`
+	ClassifyIdSecond   int       `description:"二级分类id"`
+	ClassifyNameSecond string    `description:"二级分类名称"`
+	PermissionNames    []string  `description:"二级分类名称"`
+	Title              string    `description:"标题"`
+	Abstract           string    `description:"摘要"`
+	Author             string    `description:"作者"`
+	Frequency          string    `description:"频度"`
+	CreateTime         string    `description:"创建时间"`
+	ModifyTime         time.Time `description:"修改时间"`
+	State              int       `description:"1:未发布,2:已发布"`
+	PublishTime        string    `description:"发布时间"`
+	Stage              int       `description:"期数"`
+	MsgIsSend          int       `description:"消息是否已发送,0:否,1:是"`
+	Content            string    `description:"内容"`
+	VideoUrl           string    `description:"音频文件URL"`
+	VideoName          string    `description:"音频文件名称"`
+	VideoPlaySeconds   string    `description:"音频播放时长"`
+	VideoSize          string    `description:"音频文件大小,单位M"`
+	HasPermission      int       `description:"是否拥有报告权限,1:拥有,0:没有"`
+	TitleType          string    `description:"标题类型,FICC或者权益"`
+	IsCurrentDate      int       `description:"是否当前日期:1是,0不是"`
+	IsPublic           bool      `description:"是否是公共报告"`
+	ClassifyDetail
+}
+
+type ReportDetail struct {
+	Id                 int    `description:"报告Id"`
+	AddType            int    `description:"新增方式:1:新增报告,2:继承报告"`
+	ClassifyIdFirst    int    `description:"一级分类id"`
+	ClassifyNameFirst  string `description:"一级分类名称"`
+	ClassifyIdSecond   int    `description:"二级分类id"`
+	ClassifyNameSecond string `description:"二级分类名称"`
+	Title              string `description:"标题"`
+	Abstract           string `description:"摘要"`
+	Author             string `description:"作者"`
+	Frequency          string `description:"频度"`
+	CreateTime         string `description:"创建时间"`
+	ModifyTime         string `description:"修改时间"`
+	State              int    `description:"1:未发布,2:已发布"`
+	PublishTime        string `description:"发布时间"`
+	Stage              int    `description:"期数"`
+	MsgIsSend          int    `description:"消息是否已发送,0:否,1:是"`
+	Content            string `description:"内容"`
+	VideoUrl           string `description:"音频文件URL"`
+	VideoName          string `description:"音频文件名称"`
+	VideoPlaySeconds   string `description:"音频播放时长"`
+	VideoSize          string `description:"音频文件大小,单位M"`
+	ContentSub         string `description:"内容前两个章节"`
+	IsShowNewLabel     int    `description:"是否显示新标签"`
+	IsCurrentDate      int    `description:"是否当前日期"`
+	ClassifyName       string `description:"分类名称"`
+	TitleType          string `description:"标题类型,FICC或者权益"`
+	IsPublic           bool   `description:"是否是公共报告"`
+}

+ 15 - 0
models/request/my_chart.go

@@ -0,0 +1,15 @@
+package request
+
+type MyChartCollectReq struct {
+	ChartName   string `description:"图表名称"`   // 图表名称
+	UniqueCode  string `description:"图表唯一编码"` // 图表唯一编码
+	ChartImage  string `description:"图表图片"`   // 图表图片
+	ChartInfoId int    `description:"图表id"`   // 图表id
+}
+type MyChartCollectCancelReq struct {
+	UniqueCode string `description:"图表唯一编码"` // 图表唯一编码
+}
+
+type MyChartIsCollectReq struct {
+	UniqueCode string `description:"图表唯一编码"` // 图表唯一编码
+}

+ 5 - 0
models/request/my_report.go

@@ -0,0 +1,5 @@
+package request
+
+type MyReportCollectReq struct {
+	ReportId int `description:"报告id"`
+}

+ 22 - 10
models/request/user.go

@@ -1,17 +1,29 @@
 package request
 package request
 
 
+// type LoginReq struct {
+// 	WxCode     string `description:"用户code"`
+// 	LoginType  int    `description:"登录方式:1:手机,2:邮箱"`
+// 	Mobile     string `description:"手机号"`
+// 	Email      string `description:"邮箱"`
+// 	AreaNum    int    `description:"国际区号"`
+// 	VerifyCode string `description:"短信/邮箱 验证码"`
+// }
 type LoginReq struct {
 type LoginReq struct {
-	WxCode     string `description:"用户code"`
-	LoginType  int    `description:"登录方式:1:手机,2:邮箱"`
-	Mobile     string `description:"手机号"`
-	Email      string `description:"邮箱"`
-	AreaNum    int    `description:"国际区号"`
-	VerifyCode string `description:"短信/邮箱 验证码"`
+	LoginType int    `description:"登录方式:1:手机,2:邮箱"`
+	Phone     string `description:"手机号"`
+	Email     string `description:"邮箱"`
+	AreaCode  string `description:"国际区号"`
+	SmsCode   string `description:"短信/邮箱验证码"`
 }
 }
 
 
 type VerifyCodeReq struct {
 type VerifyCodeReq struct {
-	VerifyType  int    `description:"验证方式: 1-手机号; 2-邮箱"`
-	Mobile      string `description:"手机号"`
-	TelAreaCode string `description:"手机区号"`
-	Email       string `description:"邮箱"`
+	VerifyType int    `description:"验证方式: 1-手机号; 2-邮箱"`
+	Phone      string `description:"手机号"`
+	AreaCode   string `description:"手机区号"`
+	Email      string `description:"邮箱"`
+}
+
+type ReportRecordReq struct {
+	RecordId int `description:"记录Id"`
+	ReportId int `description:"报告Id"`
 }
 }

+ 9 - 0
models/request/wechat.go

@@ -0,0 +1,9 @@
+package request
+
+type SendTemplateMsgRep struct {
+	ReportId int
+}
+
+type WeChatLoginReq struct {
+	Code string `description:"用户code"`
+}

+ 104 - 0
models/response/chart.go

@@ -0,0 +1,104 @@
+package response
+
+import (
+	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type ChartListResp struct {
+	List   []*ChartInfoView
+	Paging *paging.PagingItem
+}
+
+type ChartInfoView struct {
+	ChartInfoId       int    `orm:"column(chart_info_id);pk"`
+	ChartName         string `description:"来源名称"`
+	ChartNameEn       string `description:"英文图表名称"`
+	Unit              string `description:"中文单位名称"`
+	UnitEn            string `description:"英文单位名称"`
+	ChartClassifyId   int    `description:"图表分类id"`
+	ChartClassifyName string `description:"图表名称"`
+	SysUserId         int
+	SysUserRealName   string
+	UniqueCode        string `description:"图表唯一编码"`
+	CreateTime        time.Time
+	ModifyTime        time.Time
+	DateType          int    `description:"日期类型:1:00年至今,2:10年至今,3:15年至今,4:年初至今,5:自定义时间"`
+	StartDate         string `description:"自定义开始日期"`
+	EndDate           string `description:"自定义结束日期"`
+	IsSetName         int    `description:"设置名称"`
+	EdbInfoIds        string `description:"指标id"`
+	ChartType         int    `description:"生成样式:1:曲线图,2:季节性图"`
+	Calendar          string `description:"公历/农历"`
+	SeasonStartDate   string `description:"季节性图开始日期"`
+	SeasonEndDate     string `description:"季节性图开始日期"`
+	ChartImage        string `description:"图表图片"`
+	Sort              int    `description:"排序字段,数字越小越排前面"`
+	IsAdd             bool   `description:"true:已加入我的图库,false:未加入我的图库"`
+	MyChartId         int
+	MyChartClassifyId string `description:"我的图表分类,多个用逗号隔开"`
+	ChartClassify     []*ChartClassifyView
+	EdbEndDate        string `description:"指标最新更新日期"`
+	XMin              string `description:"图表X轴最小值"`
+	XMax              string `description:"图表X轴最大值"`
+	LeftMin           string `description:"图表左侧最小值"`
+	LeftMax           string `description:"图表左侧最大值"`
+	RightMin          string `description:"图表右侧最小值"`
+	RightMax          string `description:"图表右侧最大值"`
+	Right2Min         string `description:"图表右侧最小值"`
+	Right2Max         string `description:"图表右侧最大值"`
+	MinMaxSave        int    `description:"是否手动保存过上下限:0-否;1-是"`
+	IsEdit            bool   `description:"是否有编辑权限"`
+	IsEnChart         bool   `description:"是否展示英文标识"`
+	WarnMsg           string `description:"错误信息"`
+	Disabled          int    `description:"是否禁用,0:启用,1:禁用,默认:0"`
+	BarConfig         string `description:"柱方图的配置,json数据" json:"-"`
+	Source            int    `description:"1:ETA图库;2:商品价格曲线;3:相关性图表"`
+	//CorrelationLeadUnit string `description:"相关性图表-领先单位"`
+	ExtraConfig       string          `description:"图表额外配置,json数据"`
+	ChartSource       string          `description:"图表来源str"`
+	ChartSourceEn     string          `description:"图表来源(英文)"`
+	Button            ChartViewButton `description:"操作按钮"`
+	SeasonExtraConfig string          `description:"季节性图表中的配置,json数据"`
+	StartYear         int             `description:"当选择的日期类型为最近N年类型时,即date_type=20, 用start_year表示N"`
+	ChartThemeId      int             `description:"图表应用主题ID"`
+	ChartThemeStyle   string          `description:"图表应用主题样式"`
+	SourcesFrom       string          `description:"图表来源"`
+	Instructions      string          `description:"图表说明"`
+	MarkersLines      string          `description:"标识线"`
+	MarkersAreas      string          `description:"标识区"`
+	IsJoinPermission  int             `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
+	HaveOperaAuth     bool            `description:"是否有数据权限,默认:false"`
+	ForumChartInfoId  int             `description:"社区的图表ID"`
+	IsCollect         bool            `description:"是否收藏"`
+}
+
+type ChartClassifyView struct {
+	ChartClassifyId   int    `orm:"column(chart_classify_id);pk"`
+	ChartClassifyName string `description:"分类名称"`
+	ParentId          int    `description:"父级id"`
+}
+
+type ChartViewButton struct {
+	IsEdit    bool `description:"是否有编辑权限"`
+	IsEnChart bool `description:"是否展示英文标识"`
+	IsAdd     bool `description:"true:已加入我的图库,false:未加入我的图库"`
+	IsCopy    bool `description:"是否有另存为按钮"`
+	IsSetName int  `description:"设置名称"`
+}
+
+type ChartResp[T any] struct {
+	Ret    int
+	Data   T
+	Msg    string
+	ErrMsg string
+}
+
+type ChartLocateItem struct {
+	ChartInfoId     int
+	ChartName       string
+	UniqueCode      string
+	PrevChartInfoId int
+	NextChartInfoId int
+}

+ 1 - 0
models/response/chart_permission.go

@@ -0,0 +1 @@
+package response

+ 6 - 0
models/response/mini_config.go

@@ -0,0 +1,6 @@
+package response
+
+type MiniConfigResp struct {
+	ConfKey string `description:"配置Key"`
+	ConfVal string `description:"配置值"`
+}

+ 26 - 0
models/response/my_chart.go

@@ -0,0 +1,26 @@
+package response
+
+import (
+	"eta/eta_mini_api/models"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type MyChartIsCollectResp struct {
+	IsCollect bool `description:"是否收藏"`
+}
+
+type MyChartListResp struct {
+	List   []*models.MyChart  `description:"图表列表"`
+	Paging *paging.PagingItem `description:"分页信息"`
+}
+
+// MyChartLocateItem 用户图表定位
+type MyChartLocateItem struct {
+	MyChartId       int
+	ChartInfoId     int
+	ChartName       string
+	UniqueCode      string
+	PrevChartInfoId int
+	NextChartInfoId int
+}

+ 16 - 0
models/response/my_report.go

@@ -0,0 +1,16 @@
+package response
+
+import (
+	"eta/eta_mini_api/models"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type MyReportListResp struct {
+	List   []*models.MyReport
+	Paging *paging.PagingItem
+}
+
+type MyReportIsCollectResp struct {
+	IsCollect bool
+}

+ 66 - 0
models/response/report.go

@@ -0,0 +1,66 @@
+package response
+
+import (
+	"eta/eta_mini_api/models"
+	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type ReportList struct {
+	List   []*models.ReportList
+	Paging *paging.PagingItem
+}
+
+type ReportResp[T any] struct {
+	Ret    int
+	Data   T
+	Msg    string
+	ErrMsg string
+}
+type ReportDetailResp struct {
+	Report    *models.ReportDetail `description:"报告"`
+	Status    int                  `description:"报告状态"`
+	IsCollect bool                 `description:"报告是否收藏"`
+}
+
+type ReportCollectListItem struct {
+	ReportId            int       `description:"报告Id"`
+	ReportChapterId     int       `description:"报告章节Id"`
+	ClassifyIdFirst     int       `description:"一级分类id"`
+	ClassifyNameFirst   string    `description:"一级分类名称"`
+	ClassifyIdSecond    int       `description:"二级分类id"`
+	ClassifyNameSecond  string    `description:"二级分类名称"`
+	ReportChapterTypeId int       `decription:"报告章节类型id"`
+	PublishTime         time.Time `description:"发布时间"`
+	Title               string    `description:"标题"`
+	ContentSub          string    `description:"内容前两个章节"`
+	Abstract            string    `description:"摘要"`
+	Stage               string    `description:"期数"`
+	Author              string    `description:"作者"`
+}
+
+type ReportSearchListView struct {
+	ReportId            int    `description:"报告Id"`
+	ReportChapterId     int    `description:"报告章节Id"`
+	ClassifyIdFirst     int    `description:"一级分类id"`
+	ClassifyNameFirst   string `description:"一级分类名称"`
+	ClassifyIdSecond    int    `description:"二级分类id"`
+	ClassifyNameSecond  string `description:"二级分类名称"`
+	ReportChapterTypeId int    `decription:"报告章节类型id"`
+	PublishTime         string `description:"发布时间"`
+	Title               string `description:"标题"`
+	ContentSub          string `description:"内容前两个章节"`
+	Abstract            string `description:"摘要"`
+	Stage               string `description:"期数"`
+	Author              string `description:"作者"`
+}
+
+type ReportSearchResp struct {
+	Paging *paging.PagingItem
+	List   []*ReportCollectListItem
+}
+type ReportSearchViewResp struct {
+	Paging *paging.PagingItem
+	List   []*ReportSearchListView
+}

+ 24 - 0
models/response/user.go

@@ -0,0 +1,24 @@
+package response
+
+type LoginResp struct {
+	UserId        int    `description:"用户id"`
+	Authorization string `description:"Token"`
+	Headimgurl    string `description:"用户头像"`
+	Phone         string `description:"手机号"`
+	Email         string `description:"邮箱"`
+	CompanyName   string `description:"客户名称"`
+	EndDate       string `description:"到期日期"`
+}
+
+type WeChatLoginResp struct {
+	Authorization string `description:"Token"`
+}
+
+type UserReadRecordResp struct {
+	RecordId int64
+}
+
+type AreaCodeListResp struct {
+	Name  string `description:"地区"`
+	Value string `description:"区号"`
+}

+ 0 - 38
models/sys_session.go

@@ -1,38 +0,0 @@
-package models
-
-import (
-	"time"
-
-	"github.com/beego/beego/v2/client/orm"
-)
-
-type WxSession struct {
-	WxSessionId     int `orm:"pk"`
-	UserId          int
-	OpenId          string
-	AccessToken     string
-	ExpiredTime     time.Time
-	CreatedTime     time.Time
-	LastUpdatedTime time.Time
-}
-
-func (s *WxSession) AddWxSession() (err error) {
-	o := orm.NewOrmUsingDB("master")
-	_, err = o.Insert(s)
-	return
-}
-
-func GetWxSessionByToken(token string) (item *WxSession, err error) {
-	sql := `SELECT * FROM wx_session WHERE access_token=? AND expired_time> NOW() ORDER BY expired_time DESC LIMIT 1 `
-	o := orm.NewOrmUsingDB("master")
-	err = o.Raw(sql, token).QueryRow(&item)
-	return
-}
-
-// ExpiredWxSessionByUserId 过期掉用户token
-func ExpiredWxSessionByUserId(UserId int) (err error) {
-	sql := `UPDATE wx_session SET expired_time = NOW()  WHERE user_id=? AND expired_time > NOW()`
-	o := orm.NewOrmUsingDB("master")
-	_, err = o.Raw(sql, UserId).Exec()
-	return
-}

+ 17 - 0
models/sys_user.go

@@ -0,0 +1,17 @@
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+type SysUser struct {
+	SysUserId   int    `description:"系统用户id"`
+	SysRealName string `description:"系统用户姓名"`
+	Phone       string `description:"手机号"`
+	AreaCode    string `description:"区号"`
+}
+
+func GetSellerById(sysUserId int) (items *SysUser, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM sys_user WHERE sys_user_id=?`
+	err = o.Raw(sql, sysUserId).QueryRow(&items)
+	return
+}

+ 88 - 1
models/user.go

@@ -8,6 +8,9 @@ import (
 
 
 type User struct {
 type User struct {
 	UserId         int       `orm:"pk" description:"用户id"`
 	UserId         int       `orm:"pk" description:"用户id"`
+	OpenId         string    `description:"openid"`
+	UnionId        string    `description:"unionid"`
+	NickName       string    `description:"用户昵称"`
 	RealName       string    `description:"姓名"`
 	RealName       string    `description:"姓名"`
 	Phone          string    `description:"手机号"`
 	Phone          string    `description:"手机号"`
 	AreaCode       string    `description:"区号"`
 	AreaCode       string    `description:"区号"`
@@ -22,11 +25,95 @@ type User struct {
 	RegisterTime   time.Time `description:"用户首次登录小程序的时间"`
 	RegisterTime   time.Time `description:"用户首次登录小程序的时间"`
 	IsSubscribed   bool      `description:"是否关注公众号: 0表示没有关注,1表示关注"`
 	IsSubscribed   bool      `description:"是否关注公众号: 0表示没有关注,1表示关注"`
 	IsRegistered   bool      `description:"是否注册: 0表示没有注册,1表示注册"`
 	IsRegistered   bool      `description:"是否注册: 0表示没有注册,1表示注册"`
+	AccessToken    string    `description:"用户token"`
+	Headimgurl     string    `description:"用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空"`
+}
+
+func (u *User) Insert() (insertId int64, err error) {
+	o := orm.NewOrm()
+	insertId, err = o.Insert(u)
+	return
+}
+
+func (u *User) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(u, cols...)
+	return
+}
+
+type UserView struct {
+	Headimgurl     string `description:"用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空"`
+	RealName       string `description:"用户实际名称"`
+	Phone          string `description:"手机号码"`
+	AreaCode       string `description:"区号"`
+	SellerName     string `description:"销售名称"`
+	SellerPhone    string `description:"销售电话"`
+	SellerAreaCode string `description:"销售电话区号"`
+	Email          string `description:"邮箱"`
+	Componey       string `description:"所属公司"`
+	HasPermission  string `description:"拥有权限"`
+	ValidEndTime   string `description:"服务截至时间"`
+	IsRegistered   bool   `description:"是否注册:1:已注册,0:未注册"`
+	Status         int    `description:"用户类型: 0表示禁用,1表示潜在客户,2表示正式客户"`
+}
+
+func GetUserByToken(token string) (item *User, err error) {
+	sql := `SELECT * FROM user WHERE access_token=? `
+	o := orm.NewOrm()
+	err = o.Raw(sql, token).QueryRow(&item)
+	return
+}
+
+// 根据openid获取用户关系
+func GetUserByOpenId(openId string) (item *User, err error) {
+	sql := `SELECT * FROM user WHERE open_id=? `
+	o := orm.NewOrm()
+	err = o.Raw(sql, openId).QueryRow(&item)
+	return
+}
+
+// 根据unionid获取用户关系
+func GetUserByUnionId(unionId string) (item *User, err error) {
+	sql := `SELECT * FROM user WHERE union_id=? `
+	o := orm.NewOrm()
+	err = o.Raw(sql, unionId).QueryRow(&item)
+	return
+}
+
+// 变更联系人是否已注册状态
+func ModifyUserRegisterStatus(userId int, status bool, registerTime, modifyTime time.Time) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE user SET is_registered=?, register_time=?, modify_time=? WHERE user_id = ? `
+	_, err = o.Raw(sql, status, registerTime, modifyTime, userId).Exec()
+	return
 }
 }
 
 
 func GetUserById(userId int) (item *User, err error) {
 func GetUserById(userId int) (item *User, err error) {
-	o := orm.NewOrmUsingDB("master")
+	o := orm.NewOrm()
 	sql := `SELECT * FROM user WHERE user_id=? `
 	sql := `SELECT * FROM user WHERE user_id=? `
 	err = o.Raw(sql, userId).QueryRow(&item)
 	err = o.Raw(sql, userId).QueryRow(&item)
 	return
 	return
 }
 }
+
+func GetUserList(condition string, pars []interface{}) (items []*User, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM user WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	_, err = o.Raw(sql, pars...).QueryRows(&items)
+	return
+}
+
+func GetUserByPhone(phone string) (item *User, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM user WHERE phone=? `
+	err = o.Raw(sql, phone).QueryRow(&item)
+	return
+}
+
+func GetUserByEmail(email string) (item *User, err error) {
+	sql := `SELECT * FROM user WHERE email=? `
+	err = orm.NewOrm().Raw(sql, email).QueryRow(&item)
+	return
+}

+ 16 - 0
models/user_chart_permission_mapping.go

@@ -0,0 +1,16 @@
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+type UserChartPermissionMapping struct {
+	UserChartPermissionMappingId int `orm:"pk" description:"id"`
+	UserId                       int `description:"用户id"`
+	ChartPermissionId            int `description:"品种id"`
+}
+
+func GetChartPermissionIdByUserId(UserId int) (items []int, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT chart_permission_id FROM user_chart_permission_mapping WHERE user_id=?`
+	_, err = o.Raw(sql, UserId).QueryRows(&items)
+	return
+}

+ 26 - 0
models/user_read_permission.go

@@ -0,0 +1,26 @@
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+type UserReadPermission1 struct {
+	UserReadPermissionId int    `orm:"pk" description:"用户阅读记录品种映射id"`
+	UserReadRecordId     int    `description:"用户阅读记录id"`
+	ChartPermissionId    int    `description:"品种id"`
+	PermissionName       string `description:"品种名称"`
+}
+type UserReadPermission2 struct {
+	UserReadPermissionId int `orm:"pk" description:"用户阅读记录品种映射id"`
+	UserReadRecordId     int `description:"用户阅读记录id"`
+	ChartPermissionId    int `description:"品种id"`
+}
+
+func UserReadPermission1MultiInsert(items []*UserReadPermission1) (err error) {
+	o := orm.NewOrm()
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+func UserReadPermission2MultiInsert(items []*UserReadPermission2) (err error) {
+	o := orm.NewOrm()
+	_, err = o.InsertMulti(len(items), items)
+	return
+}

+ 78 - 0
models/user_read_record.go

@@ -0,0 +1,78 @@
+package models
+
+import (
+	"strings"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type UserReadRecord struct {
+	UserReadRecordId int    `orm:"pk" description:"id"`
+	UserId           int    `description:"用户id"`
+	ReportId         int    `description:"报告id"`
+	ReportTitle      string `description:"报告标题"`
+	// ChartPermissionId1  string    `description:"一级品种id"`
+	// ChartPermissionId2  string    `description:"二级品种id"`
+	ChartPermissionName string    `description:"二级品种名称"`
+	ClassifyId1         int       `description:"一级级分类id"`
+	ClassifyName1       string    `description:"一级分类名称"`
+	ClassifyId2         int       `description:"二级分类id"`
+	ClassifyName2       string    `description:"二级分类名称"`
+	Timestamp           int       `description:"阅读开始时间戳"`
+	EndTimestamp        int       `description:"阅读结束时间戳"`
+	CreateTime          time.Time `description:"创建时间"`
+	CreateDate          string    `description:"创建日期"`
+	StayTime            string    `description:"停留时间"`
+	StayTimestamp       string    `description:"停留时间戳"`
+}
+
+func (u *UserReadRecord) Insert() (insertId int64, err error) {
+	o := orm.NewOrm()
+	insertId, err = o.Insert(u)
+	return
+}
+
+func (u *UserReadRecord) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(u, cols...)
+	return
+}
+
+func GetUserReadRecordListById(recordId int) (items *UserReadRecord, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM user_read_record WHERE 1=1 AND user_read_record_id = ?`
+	err = o.Raw(sql, recordId).QueryRow(&items)
+	return
+}
+
+func GetUserReadRecordListByRcordIds(recordIds []string) (items []*UserReadRecord, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM user_read_record WHERE 1=1  `
+	var stringIds string
+	if len(recordIds) > 0 {
+		sql += ` AND user_read_record_id in (?) `
+		stringIds = strings.Join(recordIds, ",")
+	}
+	_, err = o.Raw(sql, stringIds).QueryRows(&items)
+	return
+}
+
+func UpdateUserReadRecordById(recordId, endTimeStamp, stayTime int, stayTimeStr string) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE user_read_record SET end_timestamp=?, stay_timestamp=?, stay_time=? WHERE 1=1 AND user_read_record_id = ? `
+	_, err = o.Raw(sql, endTimeStamp, stayTime, stayTimeStr, recordId).Exec()
+	return
+}
+
+func UpdateUserReadRecordByRecordIds(recordIds []string, endTimeStamp, stayTime int, stayTimeStr string) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE user_read_record SET end_timestamp=?, stay_timestamp=?, stay_time=? WHERE 1=1 `
+	var stringIds string
+	if len(recordIds) > 0 {
+		sql += ` AND user_read_record_id in (?) `
+		stringIds = strings.Join(recordIds, ",")
+	}
+	_, err = o.Raw(sql, endTimeStamp, stayTime, stayTimeStr, stringIds).Exec()
+	return
+}

+ 59 - 0
models/user_record.go

@@ -0,0 +1,59 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type UserRecord struct {
+	UserRecordId  int       `orm:"pk"`
+	OpenId        string    `description:"用户openid,最大长度:32"`
+	UnionId       string    `description:"用户unionid,最大长度:64"`
+	Subscribe     int       `description:"是否关注"`
+	SubscribeTime time.Time `description:""`
+	NickName      string    `descritpion:"用户昵称,最大长度:32"`
+	RealName      string    `descritpion:"用户实际名称,最大长度:32"`
+	Sex           int       `descritpion:"普通用户性别,1为男性,2为女性"`
+	Province      string    `description:"普通用户个人资料填写的省份,最大长度:30"`
+	City          string    `description:"普通用户个人资料填写的城市,最大长度:30"`
+	Country       string    `description:"国家,如中国为CN,最大长度:30"`
+	Headimgurl    string    `description:"用户第三方(微信)头像,最大长度:512"`
+	CreateTime    time.Time `description:"创建时间,关系添加时间、用户授权时间"`
+	SessionKey    string    `description:"微信小程序会话密钥,最大长度:255"`
+	UserId        int       `description:"用户id"`
+}
+
+func (item *UserRecord) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(item, cols...)
+	return
+}
+
+func (item *UserRecord) Insert() (insertId int64, err error) {
+	o := orm.NewOrm()
+	insertId, err = o.Insert(item)
+	return
+}
+
+// 根据openid获取用户关系
+func GetUserRecordByOpenId(openId string) (item *UserRecord, err error) {
+	sql := `SELECT * FROM user_record WHERE open_id=? `
+	o := orm.NewOrm()
+	err = o.Raw(sql, openId).QueryRow(&item)
+	return
+}
+
+func UserSubscribe(subscribeType int, openId string) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE user_record SET subscribe=?,subscribe_time=NOW() WHERE open_id = ? `
+	_, err = o.Raw(sql, subscribeType, openId).Exec()
+	return
+}
+
+// GetUserRecordByUnionId 通过unionid获取已绑定用户的user_record信息
+func GetUserRecordByUnionId(unionId string) (item *UserRecord, err error) {
+	sql := `SELECT * FROM user_record WHERE union_id=? `
+	err = orm.NewOrm().Raw(sql, unionId).QueryRow(&item)
+	return
+}

+ 22 - 0
models/user_template_record.go

@@ -0,0 +1,22 @@
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+type UserTemplateRecord struct {
+	ID         int    `description:"id"`
+	UserID     int    `description:"用户id"`
+	OpenID     string `description:"用户openid"`
+	Resource   string `description:"openid"` // 资源:报告id/手机号/活动id
+	SendData   string `description:"发送内容"`
+	Result     string `description:"响应结果"`
+	CreateDate string `description:"创建日期"`
+	CreateTime string `description:"创建时间"`
+	SendStatus int    `description:"发送状态"`   // 1:发送成功,0:发送失败
+	SendType   int    `description:"发送消息类型"` // 1:报告模板消息
+}
+
+func (u *UserTemplateRecord) Insert() (err error) {
+	o := orm.NewOrm()
+	_, err = o.Insert(u)
+	return
+}

+ 42 - 0
models/wx_sesssion.go

@@ -0,0 +1,42 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type WxSession struct {
+	WxSessionId    int       `orm:"pk" description:"id"`
+	OpenId         string    `description:"openId"`
+	UnionId        string    `description:"unionId"`
+	AccessToken    string    `description:"微信token"`
+	CreateTime     time.Time `description:"创建时间"`
+	LastUpdateTime time.Time `description:"最后更新时间"`
+}
+
+func (w *WxSession) Insert() (insertId int64, err error) {
+	o := orm.NewOrm()
+	insertId, err = o.Insert(w)
+	return
+}
+
+func (w *WxSession) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(w, cols...)
+	return
+}
+
+func GetWxSessionByAccessToken(accessToken string) (item *WxSession, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM wx_session WHERE access_token = ?`
+	err = o.Raw(sql, accessToken).QueryRow(&item)
+	return
+}
+
+func GetWxSessionByOpenId(openId string) (item *WxSession, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM wx_session WHERE open_id = ?`
+	err = o.Raw(sql, openId).QueryRow(&item)
+	return
+}

+ 2 - 2
models/wx_token.go

@@ -12,14 +12,14 @@ type WxToken struct {
 
 
 // Update 更新对应字段数据
 // Update 更新对应字段数据
 func (w *WxToken) Update(cols []string) (err error) {
 func (w *WxToken) Update(cols []string) (err error) {
-	o := orm.NewOrmUsingDB("master")
+	o := orm.NewOrm()
 	_, err = o.Update(w, cols...)
 	_, err = o.Update(w, cols...)
 	return
 	return
 }
 }
 
 
 // GetById 根据id获取accessToken信息
 // GetById 根据id获取accessToken信息
 func GetWxTokenById() (info WxToken, err error) {
 func GetWxTokenById() (info WxToken, err error) {
-	o := orm.NewOrmUsingDB("master")
+	o := orm.NewOrm()
 	sql := `SELECT * FROM wx_token WHERE id = ?`
 	sql := `SELECT * FROM wx_token WHERE id = ?`
 	err = o.Raw(sql, 0).QueryRow(&info)
 	err = o.Raw(sql, 0).QueryRow(&info)
 	return
 	return

+ 0 - 20
models/wx_user.go

@@ -1,20 +0,0 @@
-package models
-
-type WxUser struct {
-	Id             int64
-	OpenId         string
-	UnionId        string
-	NickName       string
-	Sex            int
-	Language       string
-	City           string
-	Province       string
-	Country        string
-	HeadImgUrl     string
-	SubscribeTime  int64
-	SubscribeScene string
-	QrScene        int
-	QrSceneStr     string
-	CreateTime     int64
-	UpdateTime     int64
-}

+ 251 - 8
routers/commentsRouter.go

@@ -7,7 +7,214 @@ import (
 
 
 func init() {
 func init() {
 
 
-    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserController"],
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:BannerController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:BannerController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:BannerController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:BannerController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"],
+        beego.ControllerComments{
+            Method: "Locate",
+            Router: `/locate`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartPermissionController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartPermissionController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MiniConfigController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MiniConfigController"],
+        beego.ControllerComments{
+            Method: "MiniConfig",
+            Router: `/config`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"],
+        beego.ControllerComments{
+            Method: "Collect",
+            Router: `/collect`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"],
+        beego.ControllerComments{
+            Method: "CollectCancel",
+            Router: `/collectCancel`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"],
+        beego.ControllerComments{
+            Method: "IsCollect",
+            Router: `/isCollect`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyChartController"],
+        beego.ControllerComments{
+            Method: "Locate",
+            Router: `/locate`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"],
+        beego.ControllerComments{
+            Method: "Collect",
+            Router: `/collect`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"],
+        beego.ControllerComments{
+            Method: "CollectCancel",
+            Router: `/collectCancel`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"],
+        beego.ControllerComments{
+            Method: "IsCollect",
+            Router: `/isCollect`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "DailyList",
+            Router: `/daily/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "Search",
+            Router: `/search`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"],
+        beego.ControllerComments{
+            Method: "AddReportRecord",
+            Router: `/addReportRecord`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"],
+        beego.ControllerComments{
+            Method: "Info",
+            Router: `/info`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"],
         beego.ControllerComments{
         beego.ControllerComments{
             Method: "Login",
             Method: "Login",
             Router: `/login`,
             Router: `/login`,
@@ -16,29 +223,65 @@ func init() {
             Filters: nil,
             Filters: nil,
             Params: nil})
             Params: nil})
 
 
-    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"],
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"],
+        beego.ControllerComments{
+            Method: "PermissionList",
+            Router: `/permission/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"],
+        beego.ControllerComments{
+            Method: "PurchasedPermission",
+            Router: `/purchased/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserController"],
         beego.ControllerComments{
         beego.ControllerComments{
-            Method: "SendEmail",
-            Router: `/SendEmail`,
+            Method: "AreaCodeList",
+            Router: `/area_code/list`,
             AllowHTTPMethods: []string{"get"},
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             MethodParams: param.Make(),
             Filters: nil,
             Filters: nil,
             Params: nil})
             Params: nil})
 
 
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserController"],
+        beego.ControllerComments{
+            Method: "GetVerifyCode",
+            Router: `/getVerifyCode`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"],
     beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"],
         beego.ControllerComments{
         beego.ControllerComments{
             Method: "Login",
             Method: "Login",
             Router: `/login`,
             Router: `/login`,
-            AllowHTTPMethods: []string{"get"},
+            AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             MethodParams: param.Make(),
             Filters: nil,
             Filters: nil,
             Params: nil})
             Params: nil})
 
 
     beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"],
     beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"],
         beego.ControllerComments{
         beego.ControllerComments{
-            Method: "UserInfo",
-            Router: `/userInfo`,
-            AllowHTTPMethods: []string{"get"},
+            Method: "Notify",
+            Router: `/notify`,
+            AllowHTTPMethods: []string{"get","post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:WechatController"],
+        beego.ControllerComments{
+            Method: "Subscribe",
+            Router: `/subscribe`,
+            AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             MethodParams: param.Make(),
             Filters: nil,
             Filters: nil,
             Params: nil})
             Params: nil})

+ 37 - 1
routers/router.go

@@ -16,10 +16,11 @@ func init() {
 		AllowCredentials: true,
 		AllowCredentials: true,
 	}))
 	}))
 	// beego.Router("/", &controllers.MainController{})
 	// beego.Router("/", &controllers.MainController{})
-	ns := beego.NewNamespace("api",
+	ns := beego.NewNamespace("/api",
 		beego.NSNamespace("/user",
 		beego.NSNamespace("/user",
 			beego.NSInclude(
 			beego.NSInclude(
 				&controllers.UserController{},
 				&controllers.UserController{},
+				&controllers.UserAuthController{},
 			),
 			),
 		),
 		),
 		beego.NSNamespace("/wechat",
 		beego.NSNamespace("/wechat",
@@ -27,6 +28,41 @@ func init() {
 				&controllers.WechatController{},
 				&controllers.WechatController{},
 			),
 			),
 		),
 		),
+		beego.NSNamespace("/report",
+			beego.NSInclude(
+				&controllers.ReportController{},
+			),
+		),
+		beego.NSNamespace("/chart",
+			beego.NSInclude(
+				&controllers.ChartController{},
+			),
+		),
+		beego.NSNamespace("/mychart",
+			beego.NSInclude(
+				&controllers.MyChartController{},
+			),
+		),
+		beego.NSNamespace("/myreport",
+			beego.NSInclude(
+				&controllers.MyReportController{},
+			),
+		),
+		beego.NSNamespace("/chart_perimission",
+			beego.NSInclude(
+				&controllers.ChartPermissionController{},
+			),
+		),
+		beego.NSNamespace("/system",
+			beego.NSInclude(
+				&controllers.MiniConfigController{},
+			),
+		),
+		beego.NSNamespace("/banner",
+			beego.NSInclude(
+				&controllers.BannerController{},
+			),
+		),
 	)
 	)
 	beego.AddNamespace(ns)
 	beego.AddNamespace(ns)
 }
 }

+ 30 - 0
services/alarm_msg/alarm_msg.go

@@ -0,0 +1,30 @@
+package alarm_msg
+
+import (
+	"encoding/json"
+	"eta/eta_mini_api/utils"
+
+	"github.com/rdlucklib/rdluck_tools/http"
+)
+
+// SendAlarmMsg
+// projectName-项目名称
+// runMode-运行模式
+// msgBody-消息内容
+// level:消息基本,1:提示消息,2:警告消息,3:严重错误信息,默认为1 提示消息
+func SendAlarmMsg(msgBody string, level int) {
+	if utils.AlarmMsgUrl == `` {
+		return
+	}
+	params := make(map[string]interface{})
+	params["ProjectName"] = utils.APPNAME
+	params["RunMode"] = utils.RunMode
+	params["MsgBody"] = msgBody
+	params["Level"] = level
+	param, err := json.Marshal(params)
+	if err != nil {
+		utils.FileLog.Info("SendAlarmMsg json.Marshal Err:" + err.Error())
+		return
+	}
+	http.Post(utils.AlarmMsgUrl, string(param), "application/json")
+}

+ 38 - 0
services/base_lib.go

@@ -0,0 +1,38 @@
+package services
+
+import (
+	"eta/eta_mini_api/utils"
+	"io"
+	"net/http"
+	"time"
+)
+
+func HttpGet(url string) (body []byte, err error) {
+	client := &http.Client{}
+	req, err := http.NewRequest("GET", url, nil)
+	if err != nil {
+		return
+	}
+	nonce := utils.GetRandStringNoSpecialChar(16)
+	timestamp := time.Now().Format(utils.FormatDateTimeUnSpace)
+	signature := utils.GetSign(nonce, timestamp, utils.ETA_MINI_APPID, utils.ETA_MINI_APP_SECRET)
+	//增加header选项
+	req.Header.Add("Nonce", nonce)
+	req.Header.Add("Timestamp", timestamp)
+	req.Header.Add("Appid", utils.ETA_MINI_APPID)
+	req.Header.Add("Signature", signature)
+	req.Header.Set("Content-Type", "application/json")
+
+	response, err := client.Do(req)
+	if err != nil {
+		return
+	}
+	defer response.Body.Close()
+
+	body, err = io.ReadAll(response.Body)
+	if err != nil {
+		return
+	}
+	utils.FileLog.Info("result:" + string(body))
+	return
+}

+ 40 - 0
services/chart.go

@@ -0,0 +1,40 @@
+package services
+
+import (
+	"encoding/json"
+	"eta/eta_mini_api/utils"
+	"fmt"
+
+	resp2 "eta/eta_mini_api/models/response"
+)
+
+func GetChartList(currentIndex, pageSize int) (resp *resp2.ChartResp[resp2.ChartListResp], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart/list?"
+	url += fmt.Sprintf("PageSize=%d&CurrentIndex=%d", pageSize, currentIndex)
+	fmt.Println(url)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return resp, err
+	}
+	return resp, nil
+
+}
+
+func GetChartDetail(chartInfoId int, uniqueCode string) (resp *resp2.ChartResp[resp2.ChartInfoView], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart/detail?"
+	url += fmt.Sprintf("ChartInfoId=%d&UniqueCode=%s", chartInfoId, uniqueCode)
+	fmt.Println(url)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}

+ 89 - 0
services/chart_permission.go

@@ -0,0 +1,89 @@
+package services
+
+import (
+	"encoding/json"
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/utils"
+	"fmt"
+)
+
+func GetChartPermissionSecondList(chartPermissionId int) (resp *models.ChartPermissionResp[[]models.ChartPermission], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/second/list"
+	url += fmt.Sprintf("?chartPermissonId=%d", chartPermissionId)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+
+}
+
+func GetChartPermissionList() (resp *models.ChartPermissionResp[[]models.ChartPermission], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/list"
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func GetPublicChartPermissionList() (resp *models.ChartPermissionResp[[]*models.ChartPermissionTreeView], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/public/list"
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func GetPrivateChartPermissionList() (resp *models.ChartPermissionResp[[]*models.ChartPermissionTreeView], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/private/list"
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func GetChartPermissionAllList() (resp *models.ChartPermissionResp[[]*models.ChartPermission], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/allList"
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func GetReportChartPermissionList(reportId int) (resp *models.ChartPermissionResp[[]*models.ChartPermission], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/detail"
+	url += fmt.Sprintf("?ReportId=%d", reportId)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}

+ 0 - 5
services/email.go

@@ -1,5 +0,0 @@
-package services
-
-func SendEmail() {
-
-}

+ 92 - 0
services/go_redis/redis.go

@@ -0,0 +1,92 @@
+package go_redis
+
+import (
+	"context"
+	"encoding/json"
+	"eta/eta_mini_api/utils"
+	"fmt"
+	"time"
+)
+
+// IsExist 检测redis中存在该key
+func IsExist(key string) (ok bool) {
+	result, err := utils.Redis.Exists(context.TODO(), key).Result()
+	if err != nil {
+		fmt.Println("err:", err)
+		return
+	}
+	if result > 0 {
+		ok = true
+	}
+
+	return
+}
+
+// SetNX 给key设置值,并设置过期时间
+func SetNX(key string, val interface{}, timeout time.Duration) (ok bool) {
+	result, err := utils.Redis.SetEX(context.TODO(), key, val, timeout).Result()
+	if err != nil {
+		return false
+	}
+	if result == "OK" {
+		ok = true
+	}
+	return
+}
+
+// RedisInt 获取int的值
+func RedisInt(key string) (result int, err error) {
+	result, err = utils.Redis.Get(context.TODO(), key).Int()
+	return
+}
+
+// RedisString 获取string的值
+func RedisString(key string) (result string, err error) {
+	result, err = utils.Redis.Get(context.TODO(), key).Result()
+	return
+}
+
+// Delete 删除key
+func Delete(key string) (err error) {
+	err = utils.Redis.Del(context.TODO(), key).Err()
+	return
+}
+
+// LPush 从列表左侧push数据
+func LPush(key string, val interface{}) (err error) {
+	data, _ := json.Marshal(val)
+	err = utils.Redis.LPush(context.TODO(), key, data).Err()
+	return err
+}
+
+// BRPop 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
+func BRPop(key string) (data string, err error) {
+	result, err := utils.Redis.BRPop(context.TODO(), 1*time.Second, key).Result()
+	if err != nil {
+		//fmt.Println("err:", err)
+		return
+	}
+	if len(result) == 2 {
+		data = result[1]
+	} else {
+		fmt.Println("result异常:", result)
+	}
+	return
+}
+
+// BRPop2Func 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
+func BRPop2Func(key string, callback func([]byte)) {
+	result, err := BRPop(key)
+	if err != nil {
+		//fmt.Println("err:", err)
+		return
+	}
+	resultByte := []byte(result)
+	callback(resultByte)
+	return
+}
+
+func Incr(key string) (err error) {
+	err = utils.Redis.Incr(context.TODO(), key).Err()
+	return
+}

+ 71 - 0
services/report.go

@@ -0,0 +1,71 @@
+package services
+
+import (
+	"encoding/json"
+	"eta/eta_mini_api/utils"
+	"fmt"
+
+	resp2 "eta/eta_mini_api/models/response"
+)
+
+func GetReportList(chartPermissionId, level, rangeType, currentIndex, pageSize int) (resp *resp2.ReportResp[resp2.ReportList], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/report/list?"
+	url += fmt.Sprintf("RangeType=%d&ChartPermissionId=%d&Level=%d&PageSize=%d&CurrentIndex=%d", rangeType, chartPermissionId, level, pageSize, currentIndex)
+	fmt.Println(url)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func GetReportDetail(reportId, userId int) (resp *resp2.ReportResp[resp2.ReportDetailResp], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/report/detail?"
+	url += fmt.Sprintf("ReportId=%d&UserId=%d", reportId, userId)
+	fmt.Println(url)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func GetReportDailyList(currentIndex, pageSize int) (resp *resp2.ReportResp[resp2.ReportList], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/report/daily/list?"
+	url += fmt.Sprintf("PageSize=%d&CurrentIndex=%d", pageSize, currentIndex)
+	fmt.Println(url)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+
+}
+
+func SearchReport(keyWord string, currentIndex, pageSize int) (resp *resp2.ReportResp[resp2.ReportSearchResp], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/report/search?"
+	url += fmt.Sprintf("KeyWord=%s&PageSize=%d&CurrentIndex=%d", keyWord, pageSize, currentIndex)
+	fmt.Println(url)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+
+}

+ 5 - 5
services/sms.go

@@ -92,11 +92,11 @@ func sendSmsGj(mobile, code, areaNum string) (rs []byte, err error) {
 	//初始化参数
 	//初始化参数
 	param := url.Values{}
 	param := url.Values{}
 	//配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
 	//配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
-	param.Set("mobile", mobile)           //接受短信的用户手机号码
-	param.Set("tplId", "10054")           //您申请的短信模板ID,根据实际情况修改
-	param.Set("tplValue", "#code#="+code) //您设置的模板变量,根据实际情况
-	param.Set("key", utils.JhGjAppKey)    //应用APPKEY(应用详细页查询)
-	param.Set("areaNum", areaNum)         //应用APPKEY(应用详细页查询)
+	param.Set("mobile", mobile)                    //接受短信的用户手机号码
+	param.Set("tplId", "262642")                   //您申请的短信模板ID,根据实际情况修改
+	param.Set("tplValue", "#code#="+code+"#m#=15") //您设置的模板变量,根据实际情况
+	param.Set("key", utils.JhGjAppKey)             //应用APPKEY(应用详细页查询)
+	param.Set("areaNum", areaNum)                  //应用APPKEY(应用详细页查询)
 
 
 	Url, err = url.Parse(apiURL)
 	Url, err = url.Parse(apiURL)
 	if err != nil {
 	if err != nil {

+ 151 - 13
services/user.go

@@ -1,19 +1,157 @@
 package services
 package services
 
 
-import "github.com/silenceper/wechat/v2/miniprogram/auth"
+import (
+	"errors"
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/services/go_redis"
+	"eta/eta_mini_api/utils"
+	"time"
+)
 
 
-type UserInfo struct {
-}
-
-func WxLogin(wxSession auth.ResCode2Session) (token string, userId int, isBind bool, err error) {
-	// openId := wxSession.OpenID
-	// unionId := wxSession.UnionID
-	// sessionKey := wxSession.SessionKey
-
-	return
-}
+// BindUser 用户绑定
+func BindUser(unionId, openId, phone, email, areaCode string) (userItem *models.User, errMsg string, err error) {
+	if phone == "" && email == "" {
+		err = errors.New("手机号或邮箱必填一个")
+		return
+	}
+	// 根据openid获取用户信息
+	if openId == "" {
+		err = errors.New("openid不能为空")
+		return
+	}
+	userItem, err = models.GetUserByOpenId(openId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		return
+	}
+	var userId int
+	curTime := time.Now()
+	if userItem != nil {
+		userId = userItem.UserId
+		if userItem.Phone != "" && userItem.Phone != phone && phone != "" {
+			errMsg = "该手机号已绑定其他微信号"
+			return
+		}
+		if userItem.Email != "" && userItem.Email != email && email != "" {
+			errMsg = "该邮箱已绑定其他微信号"
+			return
+		}
+		if userItem.Phone == "" && phone != "" {
+			user := &models.User{
+				UserId:       userItem.UserId,
+				Phone:        phone,
+				AreaCode:     areaCode,
+				RegisterTime: curTime,
+				ModifyTime:   curTime,
+			}
+			updateUserErr := user.Update([]string{"phone", "area_code", "register_time", "modify_time"})
+			err = updateUserErr
+		}
+		if userItem.Email == "" && email != "" {
+			user := &models.User{
+				UserId:       userItem.UserId,
+				Email:        email,
+				RegisterTime: curTime,
+				ModifyTime:   curTime,
+			}
+			updateUserErr := user.Update([]string{"email", "modify_time", "register_time"})
+			err = updateUserErr
+		}
+	} else {
+		//根据手机号获取用户信息
+		var phoneUser, emailUser *models.User
+		if phone != "" {
+			tmpUser, userErr := models.GetUserByPhone(phone)
+			if userErr != nil && userErr.Error() != utils.ErrNoRow() {
+				err = userErr
+				return
+			}
+			phoneUser = tmpUser
+		}
+		//根据邮箱获取用户信息
+		if email != "" {
+			tmpUser, userErr := models.GetUserByEmail(email)
+			if userErr != nil && userErr.Error() != utils.ErrNoRow() {
+				err = userErr
+				return
+			}
+			emailUser = tmpUser
+		}
+		// 理论上来说不会同时出现手机号和邮箱同时存在的情况
+		if phoneUser != nil && emailUser != nil && phoneUser.UserId != emailUser.UserId {
+			errMsg = "该手机号和邮箱已绑定其他微信号"
+			err = errors.New("该手机号和邮箱已绑定其他微信号")
+			return
+		}
+		if phoneUser != nil {
+			userItem = phoneUser
+		}
+		if emailUser != nil {
+			userItem = emailUser
+		}
+		//如果查询出来的用户是nil,那么需要新增用户
+		if userItem == nil {
+			key := utils.CACHE_ACCESS_WX_BIND + phone + ":" + email
+			isHas := go_redis.IsExist(key)
+			if isHas {
+				err = errors.New("多次提交,请关闭页面重新进入")
+				return
+			}
+			go_redis.SetNX(key, "ok", time.Second*300)
+			user := &models.User{
+				Phone:    phone,
+				AreaCode: areaCode,
+				Email:    email,
+				Status:   utils.UserStatusPotential,
+				OpenId:   openId,
+				UnionId:  unionId,
+			}
+			tmpUserId, addUserErr := user.Insert()
+			//添加完成,清除缓存
+			_ = go_redis.Delete(key)
+			if addUserErr != nil {
+				err = addUserErr
+				return
+			}
+			user.UserId = int(tmpUserId)
+			userId = int(tmpUserId)
+			userItem, err = models.GetUserById(userId)
+		} else {
+			userItem.OpenId = openId
+			userItem.UnionId = unionId
+			err = userItem.Update([]string{"open_id", "union_id"})
+			if err != nil {
+				errMsg = "用户绑定失败"
+				return
+			}
+			userId = userItem.UserId
+		}
+	}
 
 
-// GetWxUserItemByOpenId 通过openid获取用户信息
-func GetWxUserItemByOpenId(openid string) (userInfo UserInfo, err error) {
+	//如果该用户 绑定注册状态 字段处于 未注册 的情况下,那么去修改该数据
+	if !userItem.IsRegistered {
+		err = models.ModifyUserRegisterStatus(userId, true, curTime, curTime)
+		if err != nil {
+			return
+		}
+	}
+	userRecord, er := models.GetUserRecordByUnionId(userItem.UnionId)
+	if er != nil && er.Error() != utils.ErrNoRow() {
+		err = errors.New("获取用户关注记录失败")
+		return
+	}
+	if !userItem.IsSubscribed && userRecord != nil {
+		userRecord.UserId = userId
+		er = userRecord.Update([]string{"user_id"})
+		if er != nil {
+			err = errors.New("获取用户关注记录失败")
+			return
+		}
+		userItem.IsSubscribed = true
+		er = userItem.Update([]string{"is_subscribed"})
+		if er != nil {
+			err = errors.New("获取用户关注记录失败")
+			return
+		}
+	}
 	return
 	return
 }
 }

+ 10 - 0
services/verify.go

@@ -0,0 +1,10 @@
+package services
+
+import "eta/eta_mini_api/utils"
+
+func CheckEncryption() (ok bool) {
+	if utils.RunMode == "release" {
+		ok = true
+	}
+	return
+}

+ 177 - 0
services/wechat/template_msg.go

@@ -0,0 +1,177 @@
+package wechat
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"errors"
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/utils"
+	"fmt"
+	"io"
+	"net/http"
+	"time"
+)
+
+var (
+	TemplateMsgSendUrl       = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s"
+	TemplateMsgClearQuotaUrl = "https://api.weixin.qq.com/cgi-bin/clear_quota?access_token=%s"
+)
+
+type TemplateMsgSendClient struct {
+	AccessToken string
+	Data        []byte
+}
+
+type SendTemplateResponse struct {
+	Errcode int    `json:"errcode"`
+	Errmsg  string `json:"errmsg"`
+	MsgID   int    `json:"msgid"`
+}
+
+type ClearQuotaResponse struct {
+	Errcode int    `json:"errcode"`
+	Errmsg  string `json:"errmsg"`
+}
+
+type OpenIdList struct {
+	OpenId string
+	UserId int
+}
+
+// TemplateMsgSendClient.ClearQuota 清除发送超过当日10万次限制
+func (c *TemplateMsgSendClient) ClearQuota() (result *ClearQuotaResponse, err error) {
+	key := "CACHE_SendTemplateMsg_ERR"
+	exists, _ := utils.Redis.Exists(context.TODO(), key).Result()
+	if exists == 1 {
+		return
+	}
+	_ = utils.Redis.SetEX(context.TODO(), key, 1, 6*time.Minute)
+
+	sendUrl := fmt.Sprintf(TemplateMsgClearQuotaUrl, c.AccessToken)
+	client := http.Client{}
+	clearData := make(map[string]interface{})
+	clearData["appid"] = WxAppId
+	clearJson, _ := json.Marshal(clearData)
+	resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(clearJson))
+	if err != nil {
+		return
+	}
+	defer func() {
+		_ = resp.Body.Close()
+	}()
+	clearBody, err := io.ReadAll(resp.Body)
+	err = json.Unmarshal(clearBody, &result)
+	return
+}
+
+// TemplateMsgSendClient.SendMsg 推送消息
+func (c *TemplateMsgSendClient) SendMsg() (sendRes *SendTemplateResponse, err error) {
+	// 请求接口
+	sendUrl := fmt.Sprintf(TemplateMsgSendUrl, c.AccessToken)
+	client := http.Client{}
+	resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(c.Data))
+	if err != nil {
+		return
+	}
+	defer func() {
+		_ = resp.Body.Close()
+	}()
+	body, _ := io.ReadAll(resp.Body)
+	if err = json.Unmarshal(body, &sendRes); err != nil {
+		return
+	}
+	// 模板消息发送超过当日10万次限制错误处理
+	if sendRes.Errcode == 45009 {
+		// 发送提示邮件
+		// go alarm_msg.SendAlarmMsg("模板消息发送超过当日10万次限制, SendTemplateResponse: "+string(body), 3)
+		// 清理限制
+		clearRes, e := c.ClearQuota()
+		if e != nil {
+			err = e
+			return
+		}
+		if clearRes.Errcode != 0 {
+			clearJson, er := json.Marshal(clearRes)
+			if er != nil {
+				return nil, er
+			}
+			fmt.Println("自动清理模板消息限制接口, 调用失败, ClearQuotaResponse: " + string(clearJson))
+			// go alarm_msg.SendAlarmMsg("自动清理模板消息限制接口, 调用失败, ClearQuotaResponse: "+string(clearJson), 3)
+			return
+		}
+		// 发送成功邮件
+		// go alarm_msg.SendAlarmMsg("自动清理模板消息限制接口, 调用成功", 1)
+		// 重新推送
+		go func() {
+			_, e := c.SendMsg()
+			if e != nil {
+				return
+				// reSendJson, _ := json.Marshal(reSend)
+				// alarm_msg.SendAlarmMsg("重新推送模板消息失败, SendTemplateResponse: "+string(reSendJson), 3)
+			}
+		}()
+	}
+	if sendRes.Errcode != 0 {
+		err = errors.New("推送模板消息失败, SendTemplateResponse: " + string(body))
+	}
+	return
+}
+
+// AddUserTemplateRecord 新增模板消息推送记录
+func AddUserTemplateRecord(userId, sendStatus, sendType int, openid, resource, sendData, result string) (err error) {
+	item := &models.UserTemplateRecord{
+		UserID:     userId,
+		OpenID:     openid,
+		Resource:   resource,
+		SendData:   sendData,
+		Result:     result,
+		CreateDate: time.Now().Format(utils.FormatDate),
+		CreateTime: time.Now().Format(utils.FormatDateTime),
+		SendStatus: sendStatus,
+		SendType:   sendType,
+	}
+	err = item.Insert()
+	return
+}
+
+// SendMultiTemplateMsg 推送模板消息至多个用户
+func SendMultiTemplateMsg(sendMap map[string]interface{}, items []*OpenIdList, resource string, sendType int) (err error) {
+	ws := GetWxChat()
+	accessToken, err := ws.GetAccessToken()
+	if err != nil {
+		return
+	}
+	for _, item := range items {
+		sendMap["touser"] = item.OpenId
+		data, e := json.Marshal(sendMap)
+		if e != nil {
+			err = e
+			return
+		}
+		ts := &TemplateMsgSendClient{
+			AccessToken: accessToken,
+			Data:        data,
+		}
+		result, e := ts.SendMsg()
+		if result == nil {
+			return
+		}
+		// 推送消息记录
+		{
+			go func(v *OpenIdList) {
+				sendStatus := 1
+				if e != nil {
+					sendStatus = 0
+				}
+				resultJson, _ := json.Marshal(result)
+				_ = AddUserTemplateRecord(v.UserId, sendStatus, sendType, v.OpenId, resource, string(data), string(resultJson))
+			}(item)
+		}
+		if e != nil {
+			err = e
+			return
+		}
+	}
+	return
+}

+ 93 - 21
services/wechat/wechat.go

@@ -1,10 +1,18 @@
 package wechat
 package wechat
 
 
 import (
 import (
+	"context"
+	"encoding/json"
+	"errors"
 	"eta/eta_mini_api/models"
 	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/services/alarm_msg"
+	"eta/eta_mini_api/utils"
 	"fmt"
 	"fmt"
+	"io"
+	"net/http"
 	"time"
 	"time"
 
 
+	"github.com/go-redis/redis/v8"
 	"github.com/silenceper/wechat/v2"
 	"github.com/silenceper/wechat/v2"
 	"github.com/silenceper/wechat/v2/cache"
 	"github.com/silenceper/wechat/v2/cache"
 	"github.com/silenceper/wechat/v2/credential"
 	"github.com/silenceper/wechat/v2/credential"
@@ -19,20 +27,18 @@ var (
 	WxAppSecret string
 	WxAppSecret string
 )
 )
 
 
-func init() {
-	WxAppId = `wx1c6d59a9ca4b42b3`
-	WxAppSecret = `090716fa7b7fd89172cb26065fa4e6af`
-}
-
 type WechatAccessToken struct {
 type WechatAccessToken struct {
 }
 }
 
 
 func GetWxChat() (officialAccount *officialaccount.OfficialAccount) {
 func GetWxChat() (officialAccount *officialaccount.OfficialAccount) {
 	wc := wechat.NewWechat()
 	wc := wechat.NewWechat()
+	// minConf, _ := models.GetMiniConf()
 	memory := cache.NewMemory()
 	memory := cache.NewMemory()
 	conf := &config.Config{
 	conf := &config.Config{
-		AppID:          WxAppId,
-		AppSecret:      WxAppSecret,
+		AppID:     utils.DW_WX_APPID,
+		AppSecret: utils.DW_WX_APP_SECRET,
+		// AppID:          minConf["WxAppId"],
+		// AppSecret:      minConf["WxAppSecret"],
 		Token:          "",
 		Token:          "",
 		EncodingAESKey: "",
 		EncodingAESKey: "",
 		Cache:          memory,
 		Cache:          memory,
@@ -43,27 +49,50 @@ func GetWxChat() (officialAccount *officialaccount.OfficialAccount) {
 	return
 	return
 }
 }
 
 
+var DefaultKey = "zcmRedis"
+
 // GetAccessToken 获取accessToken
 // GetAccessToken 获取accessToken
 func (wechat WechatAccessToken) GetAccessToken() (accessToken string, err error) {
 func (wechat WechatAccessToken) GetAccessToken() (accessToken string, err error) {
-	wxToken, err := models.GetWxTokenById()
+	accessToken, err = utils.Redis.Get(context.TODO(), utils.CACHE_WX_ACCESS_TOKEN_DW).Result()
+	// wxToken, err := models.GetWxTokenById()
+	if err != nil && err != redis.Nil {
+		return
+	}
+
+	minConf, _ := models.GetMiniConf()
+	// 缓存中没有取到数据,那么就需要强制刷新的accessToken
+	tmpAccessToken, expires, tmpErr := getTokenFromServer(minConf["WxAppId"], minConf["WxAppSecret"])
+	if tmpAccessToken == "" {
+		err = errors.New("获取微信token失败,Err:" + tmpErr.Error())
+		return
+	}
+	redisTimeExpire := time.Duration(expires-600) * time.Second
+	err = utils.Redis.SetEX(context.TODO(), utils.CACHE_WX_ACCESS_TOKEN_DW, tmpAccessToken, redisTimeExpire).Err()
 	if err != nil {
 	if err != nil {
 		return
 		return
 	}
 	}
-	//如果300s就要过期了,那么就去刷新accessToken
-	if wxToken.ExpiresIn < time.Now().Unix()+300 {
-		tmpAccessToken, expires, tmpErr := getTokenFromServer(WxAppId, WxAppSecret)
-		if tmpErr != nil {
-			err = tmpErr
-			return
-		}
-
-		var updateCols = []string{"access_token", "expires_in"}
-		wxToken.AccessToken = tmpAccessToken
-		wxToken.ExpiresIn = expires - 600 //快过期前10分钟就刷新掉
-		wxToken.Update(updateCols)
+	err = utils.Redis.HSet(context.TODO(), DefaultKey, utils.CACHE_WX_ACCESS_TOKEN_DW, true).Err()
+	// err = utils.Redis.Put(utils.CACHE_WX_ACCESS_TOKEN_HZ, tmpAccessToken, redisTimeExpire)
+	if err != nil {
+		err = errors.New("更新微信token失败")
+		return
 	}
 	}
-	accessToken = wxToken.AccessToken
 	return
 	return
+	// //如果300s就要过期了,那么就去刷新accessToken
+	// if wxToken.ExpiresIn < time.Now().Unix()+300 {
+	// 	tmpAccessToken, expires, tmpErr := getTokenFromServer(utils.HZ_WX_APPID, utils.HZ_WX_APP_SECRET)
+	// 	if tmpErr != nil {
+	// 		err = tmpErr
+	// 		return
+	// 	}
+
+	// 	var updateCols = []string{"access_token", "expires_in"}
+	// 	wxToken.AccessToken = tmpAccessToken
+	// 	wxToken.ExpiresIn = expires - 600 //快过期前10分钟就刷新掉
+	// 	wxToken.Update(updateCols)
+	// }
+	// accessToken = wxToken.AccessToken
+	// return
 }
 }
 
 
 // getTokenFromServer 服务端获取accessToken
 // getTokenFromServer 服务端获取accessToken
@@ -87,6 +116,14 @@ func GetUserInfo(openid string) (userInfo *user.Info, err error) {
 	return
 	return
 }
 }
 
 
+// GetSession 获取用户详情
+// func GetSession(code string) (userInfo auth.ResCode2Session, err error) {
+// 	wechatClient := GetWxChat()
+// 	userClient := wechatClient.GetUser()
+// 	userInfo, err = authClient.Code2Session(code)
+// 	return
+// }
+
 // GetJsConfig 获取公众号jsConfig
 // GetJsConfig 获取公众号jsConfig
 func GetJsConfig(signUrl string) (jsConf *js.Config, err error) {
 func GetJsConfig(signUrl string) (jsConf *js.Config, err error) {
 	wechatClient := GetWxChat()
 	wechatClient := GetWxChat()
@@ -94,3 +131,38 @@ func GetJsConfig(signUrl string) (jsConf *js.Config, err error) {
 	jsConf, err = j.GetConfig(signUrl)
 	jsConf, err = j.GetConfig(signUrl)
 	return
 	return
 }
 }
+
+type WxUserInfo struct {
+	OpenId       string `json:"openid"`
+	AccessToken  string `json:"access_token"`
+	RefreshToken string `json:"refresh_token"`
+	Scope        string `json:"scope"`
+	ErrCode      int
+	ErrMsg       string
+}
+
+func GetWxUserInfo(code string) (info *WxUserInfo, err error) {
+	httpUrl := `https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code`
+
+	httpUrl = fmt.Sprintf(httpUrl, utils.DW_WX_APPID, utils.DW_WX_APP_SECRET, code)
+
+	client := http.Client{}
+	wxReq, err := http.NewRequest("GET", httpUrl, nil)
+	if err != nil {
+		return
+	}
+	response, err := client.Do(wxReq)
+	if err != nil {
+		return
+	}
+	defer response.Body.Close()
+	body, err := io.ReadAll(response.Body)
+	if err != nil {
+		return
+	}
+	alarm_msg.SendAlarmMsg(string(body), 1)
+	if err = json.Unmarshal(body, &info); err != nil {
+		return
+	}
+	return
+}

+ 5 - 21
services/wx_app/wx_app.go

@@ -1,6 +1,8 @@
 package wx_app
 package wx_app
 
 
 import (
 import (
+	"eta/eta_mini_api/utils"
+
 	wechat "github.com/silenceper/wechat/v2"
 	wechat "github.com/silenceper/wechat/v2"
 	"github.com/silenceper/wechat/v2/cache"
 	"github.com/silenceper/wechat/v2/cache"
 	"github.com/silenceper/wechat/v2/miniprogram"
 	"github.com/silenceper/wechat/v2/miniprogram"
@@ -9,31 +11,13 @@ import (
 	"github.com/silenceper/wechat/v2/miniprogram/encryptor"
 	"github.com/silenceper/wechat/v2/miniprogram/encryptor"
 )
 )
 
 
-// 微信小程序配置信息
-var (
-	WxId                 string //微信原始ID
-	WxAppId              string
-	WxAppSecret          string
-	WxPlatform           int    //用户来源,需要入库,用来保存该用户来自哪个平台,默认是:1
-	EnvVersion           string // 小程序版本, release-正式版; trial-体验版; develop-开发版
-	SendWxTemplateMsgUrl string
-)
-
-func init() {
-	WxAppId = `wx1c6d59a9ca4b42b3`
-	// WxId = `gh_75abb562a946`
-	WxAppSecret = `090716fa7b7fd89172cb26065fa4e6af`
-	EnvVersion = "trial"
-	SendWxTemplateMsgUrl = "http://127.0.0.1:8086/v1/wechat/send_template_msg"
-}
-
 func GetWxApp() (miniprogram *miniprogram.MiniProgram) {
 func GetWxApp() (miniprogram *miniprogram.MiniProgram) {
 	wc := wechat.NewWechat()
 	wc := wechat.NewWechat()
 	memory := cache.NewMemory()
 	memory := cache.NewMemory()
-	//memory := cache.NewRedis(global.Redis)
+	// memory := cache.NewRedis(utils.Redis)
 	cfg := &config.Config{
 	cfg := &config.Config{
-		AppID:     WxAppId,
-		AppSecret: WxAppSecret,
+		AppID:     utils.WX_MINI_APPID,
+		AppSecret: utils.WX_MINI_APP_SECRET,
 		Cache:     memory,
 		Cache:     memory,
 	}
 	}
 
 

+ 101 - 0
utils/common.go

@@ -1,13 +1,18 @@
 package utils
 package utils
 
 
 import (
 import (
+	"crypto/hmac"
 	"crypto/md5"
 	"crypto/md5"
+	"crypto/sha256"
+	"encoding/base64"
 	"encoding/hex"
 	"encoding/hex"
 	"fmt"
 	"fmt"
 	"math"
 	"math"
 	"math/rand"
 	"math/rand"
 	"regexp"
 	"regexp"
+	"sort"
 	"strconv"
 	"strconv"
+	"strings"
 	"time"
 	"time"
 )
 )
 
 
@@ -19,6 +24,11 @@ const (
 
 
 const TelAreaCodeHome = "86" // 大陆区号
 const TelAreaCodeHome = "86" // 大陆区号
 
 
+// 数据没有记录
+func ErrNoRow() string {
+	return "<QuerySeter> no row found"
+}
+
 var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
 var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
 
 
 // ValidateMobileFormatat 校验手机格式
 // ValidateMobileFormatat 校验手机格式
@@ -78,3 +88,94 @@ func GetRandString(size int) string {
 	}
 	}
 	return randomSb
 	return randomSb
 }
 }
+
+// HmacSha256 计算HmacSha256
+// key 是加密所使用的key
+// data 是加密的内容
+func HmacSha256(key string, data string) []byte {
+	mac := hmac.New(sha256.New, []byte(key))
+	_, _ = mac.Write([]byte(data))
+	return mac.Sum(nil)
+}
+
+// HmacSha256ToBase64 将加密后的二进制转Base64字符串
+func HmacSha256ToBase64(key string, data string) string {
+	return base64.URLEncoding.EncodeToString(HmacSha256(key, data))
+}
+
+func GetSign(nonce, timestamp, appId, secret string) (sign string) {
+	signStrMap := map[string]string{
+		"nonce":     nonce,
+		"timestamp": timestamp,
+		"appid":     appId,
+	}
+	keys := make([]string, 0, len(signStrMap))
+	for k := range signStrMap {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	var signStr string
+	for _, k := range keys {
+		signStr += k + "=" + signStrMap[k] + "&"
+	}
+	signStr = strings.Trim(signStr, "&")
+	fmt.Println("signStr:" + signStr)
+	sign = HmacSha256ToBase64(secret, signStr)
+	return
+}
+
+func GetRandStringNoSpecialChar(size int) string {
+	allLetterDigit := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
+	randomSb := ""
+	digitSize := len(allLetterDigit)
+	for i := 0; i < size; i++ {
+		randomSb += allLetterDigit[rnd.Intn(digitSize)]
+	}
+	return randomSb
+}
+
+func StringsToJSON(str string) string {
+	rs := []rune(str)
+	jsons := ""
+	for _, r := range rs {
+		rint := int(r)
+		if rint < 128 {
+			jsons += string(r)
+		} else {
+			jsons += "\\u" + strconv.FormatInt(int64(rint), 16) // json
+		}
+	}
+	return jsons
+}
+
+func SecondsToHMS(seconds int64) string {
+	duration := time.Duration(seconds) * time.Second
+	hours := int64(duration.Hours())
+	minutes := int64(duration.Minutes()) % 60
+	secs := int64(duration.Seconds()) % 60
+
+	var result string
+	if hours > 0 {
+		result += fmt.Sprintf("%d时", hours)
+	}
+	if minutes > 0 || (hours > 0 && secs > 0) {
+		result += fmt.Sprintf("%d分", minutes)
+	}
+	if secs > 0 || (hours == 0 && minutes == 0) {
+		result += fmt.Sprintf("%d秒", secs)
+	}
+	return result
+}
+
+func Unique[T comparable](slice []T) []T {
+	seen := make(map[T]struct{})
+	var unique []T
+
+	for _, v := range slice {
+		if _, exists := seen[v]; !exists {
+			unique = append(unique, v)
+			seen[v] = struct{}{}
+		}
+	}
+	return unique
+}

+ 92 - 0
utils/config.go

@@ -1,10 +1,14 @@
 package utils
 package utils
 
 
 import (
 import (
+	"context"
+	"encoding/json"
 	"fmt"
 	"fmt"
+	"strconv"
 
 
 	beeLogger "github.com/beego/bee/v2/logger"
 	beeLogger "github.com/beego/bee/v2/logger"
 	"github.com/beego/beego/v2/server/web"
 	"github.com/beego/beego/v2/server/web"
+	"github.com/go-redis/redis/v8"
 )
 )
 
 
 // 数据库配置
 // 数据库配置
@@ -12,9 +16,16 @@ var (
 	RunMode          string
 	RunMode          string
 	MYSQL_URL_MASTER string
 	MYSQL_URL_MASTER string
 	MYSQL_URL_RDDP   string
 	MYSQL_URL_RDDP   string
+	MYSQL_URL        string //数据库连接
+
+	REDIS_CACHE string        //缓存地址
+	Redis       *redis.Client //redis链接
 )
 )
 
 
+// 日志配置
 var (
 var (
+	LogPath    string //调用过程中的日志存放地址
+	LogFile    string
 	ApiLogPath string // 接口请求地址和接口返回值日志存放地址
 	ApiLogPath string // 接口请求地址和接口返回值日志存放地址
 	ApiLogFile string
 	ApiLogFile string
 	BinLogPath string // 数据库相关的日志存放地址
 	BinLogPath string // 数据库相关的日志存放地址
@@ -22,6 +33,28 @@ var (
 	LogMaxDays int // 日志最大保留天数
 	LogMaxDays int // 日志最大保留天数
 )
 )
 
 
+var (
+	SMS_TPLID string // 短信模板
+)
+
+var AlarmMsgUrl string // 报警地址
+
+// 微信相关
+var (
+	WX_MINI_APPID          string
+	WX_MINI_APP_SECRET     string
+	DW_WX_Id               string //微信原始ID
+	DW_WX_APPID            string // 东吴公众号appid
+	DW_WX_APP_SECRET       string
+	TEMPLATE_ID_BY_PRODUCT string
+)
+
+// 桥接服务
+var (
+	ETA_MINI_BRIDGE_URL string
+	ETA_MINI_APPID      string
+	ETA_MINI_APP_SECRET string
+)
 var DesKey string // 接口返回加密KEY
 var DesKey string // 接口返回加密KEY
 
 
 func init() {
 func init() {
@@ -31,13 +64,72 @@ func init() {
 	}
 	}
 	RunMode = tmpRunMode
 	RunMode = tmpRunMode
 	fmt.Println("RunMode:", RunMode)
 	fmt.Println("RunMode:", RunMode)
+	if RunMode == "" {
+		RunMode = "debug"
+		configPath := `/home/code/config/eta_mini_api/conf/app.conf`
+		fmt.Println("configPath:", configPath)
+		err = web.LoadAppConfig("ini", configPath)
+		if err != nil {
+			fmt.Println("web.LoadAppConfig Err:" + err.Error())
+		}
+	}
 
 
 	config, err := web.AppConfig.GetSection(RunMode)
 	config, err := web.AppConfig.GetSection(RunMode)
 	if err != nil {
 	if err != nil {
 		panic(any("配置文件读取错误 " + err.Error()))
 		panic(any("配置文件读取错误 " + err.Error()))
 	}
 	}
 	beeLogger.Log.Info(RunMode + " 模式")
 	beeLogger.Log.Info(RunMode + " 模式")
+	MYSQL_URL = config["mysql_url"]
 	MYSQL_URL_RDDP = config["mysql_url_rddp"]
 	MYSQL_URL_RDDP = config["mysql_url_rddp"]
 	MYSQL_URL_MASTER = config["mysql_url_master"]
 	MYSQL_URL_MASTER = config["mysql_url_master"]
 
 
+	SMS_TPLID = config["sms_tplId"]
+	DesKey = config["des_key"]
+
+	WX_MINI_APPID = config["wx_appid"]
+	WX_MINI_APP_SECRET = config["wx_app_secret"]
+	DW_WX_Id = config["dw_wx_id"]
+	DW_WX_APPID = config["dw_wx_appid"]
+	DW_WX_APP_SECRET = config["dw_wx_app_secret"]
+	TEMPLATE_ID_BY_PRODUCT = config["template_id_by_product"]
+
+	ETA_MINI_BRIDGE_URL = config["eta_mini_bridge_url"]
+	ETA_MINI_APPID = config["eta_mini_appid"]
+	ETA_MINI_APP_SECRET = config["eta_mini_app_secret"]
+	initRedis(config)
+}
+
+// initRedis 初始化redis配置
+func initRedis(config map[string]string) {
+	REDIS_CACHE = config["beego_cache"]
+	if len(REDIS_CACHE) <= 0 {
+		panic("redis链接参数没有配置")
+	}
+
+	var redisConf map[string]string
+	err := json.Unmarshal([]byte(REDIS_CACHE), &redisConf)
+	if err != nil {
+		panic("redis 配置异常失败:" + err.Error())
+	}
+
+	redisDb := 0 //默认使用redis的0库
+	if dbStr, ok := redisConf["db"]; ok {
+		redisDb, err = strconv.Atoi(dbStr)
+		if err != nil {
+			panic("redis 操作db库配置异常,db:" + dbStr)
+		}
+	}
+	client := redis.NewClient(&redis.Options{
+		Addr:     redisConf["conn"],
+		Password: redisConf["password"],
+		DB:       redisDb,
+		//PoolSize: 10, //连接池最大socket连接数,默认为10倍CPU数, 10 * runtime.NumCPU(暂不配置)
+	})
+	_, err = client.Ping(context.TODO()).Result()
+	if err != nil {
+		panic("redis 链接失败:" + err.Error())
+	}
+
+	//全局赋值redis链接
+	Redis = client
 }
 }

+ 52 - 2
utils/constants.go

@@ -6,16 +6,66 @@ const (
 	VerifyCodeExpireMinute = 15                // 短信/邮箱验证码过期时间-分钟
 	VerifyCodeExpireMinute = 15                // 短信/邮箱验证码过期时间-分钟
 )
 )
 
 
+// 报告权限状态定义
+const (
+	ReportPermissionStatusExpired      = 1 //已过期
+	ReportPermissionStatusNoPermission = 2 //没有该品种权限
+	ReportPermissionStatusNo           = 3 //没有权限
+	ReportPermissionStatusHas          = 4 //有该品种权限
+)
+
+// 用户状态定义
+const (
+	UserStatusNo        = 0 //禁用
+	UserStatusPotential = 1 //潜在用户
+	UserStatusFormal    = 2 //正式用户
+)
+
+// 常量定义
+const (
+	FormatTime            = "15:04:05"                //时间格式
+	FormatDate            = "2006-01-02"              //日期格式
+	FormatDateCN          = "2006年01月02日"             //日期格式(中文)
+	FormatDateUnSpace     = "20060102"                //日期格式
+	FormatDateTime        = "2006-01-02 15:04:05"     //完整时间格式
+	HlbFormatDateTime     = "2006-01-02_15:04:05.999" //完整时间格式
+	FormatDateTimeUnSpace = "20060102150405"          //完整时间格式
+	PageSize15            = 15                        //列表页每页数据量
+	PageSize5             = 5
+	PageSize10            = 10
+	PageSize20            = 20
+	PageSize30            = 30
+)
+
 const (
 const (
 	UserLoginSalt = "kOld9YUdf89T2uIH"         // 用户登录盐值
 	UserLoginSalt = "kOld9YUdf89T2uIH"         // 用户登录盐值
 	DesKeySalt    = "odNMloUrTAmyRd9fb0TtlrPk" // DesKey盐值
 	DesKeySalt    = "odNMloUrTAmyRd9fb0TtlrPk" // DesKey盐值
 )
 )
 
 
 const (
 const (
-	APPNAME          = "弘则-日度点评"
-	EmailSendToUsers = "glji@hzinsights.com;pyan@hzinsights.com"
+	DefaultPhone    = "021-6312 3067" //默认销售电话号
+	DefaultAreaCode = "86"
 )
 )
+
 const (
 const (
 	JhGnAppKey = "4c8504c49dd335e99cfd7b6a3a9e2415" //聚合国内AppKey
 	JhGnAppKey = "4c8504c49dd335e99cfd7b6a3a9e2415" //聚合国内AppKey
 	JhGjAppKey = "3326ad2c1047a4cd92ace153e6044ca3"
 	JhGjAppKey = "3326ad2c1047a4cd92ace153e6044ca3"
 )
 )
+
+const (
+	APPNAME          = "东吴研报小程序"
+	EmailSendToUsers = "glji@hzinsights.com;pyan@hzinsights.com"
+)
+
+const (
+	CACHE_ACCESS_TOKEN_LOGIN          = "pc_eta_min_crm:login:"          //管理后台登录
+	CACHE_ACCESS_TOKEN_LOGIN_NO_TRUST = "pc_eta_min_crm:login:no_trust:" //管理后台登录(不可信登录态)
+	CACHE_ACCESS_WX_BIND              = "eta_mini_api:phone:email:"      //管理后台登录(不可信登录态)
+	CACHE_ACCESS_EMAIL_LOGIN_CODE     = "eta_mini_api:login:email:"      //邮箱验证码防攻击key
+	CACHE_ACCESS_PHONE_LOGIN_CODE     = "eta_mini_api:login:phone:"      //手机验证码防攻击key
+)
+
+// 缓存key
+const (
+	CACHE_WX_ACCESS_TOKEN_DW = "wx:accesstoken:dw" //东吴公众号 微信accessToken
+)

+ 4 - 4
utils/email.go

@@ -19,11 +19,11 @@ func SendEmail(title, content string, touser string) bool {
 		arr = append(arr, touser)
 		arr = append(arr, touser)
 	}
 	}
 	m := gomail.NewMessage()
 	m := gomail.NewMessage()
-	m.SetHeader("From", "317699326@qq.com ")
+	m.SetHeader("From", "")
 	m.SetHeader("To", arr...)
 	m.SetHeader("To", arr...)
 	m.SetHeader("Subject", title+" "+GetRandString(16))
 	m.SetHeader("Subject", title+" "+GetRandString(16))
 	m.SetBody("text/html", content)
 	m.SetBody("text/html", content)
-	d := gomail.NewDialer("smtp.qq.com", 587, "317699326@qq.com", "oqdypwfcvruwcbea")
+	d := gomail.NewDialer("smtp.qq.com", 587, "", "")
 	if err := d.DialAndSend(m); err != nil {
 	if err := d.DialAndSend(m); err != nil {
 		return false
 		return false
 	}
 	}
@@ -31,7 +31,7 @@ func SendEmail(title, content string, touser string) bool {
 }
 }
 
 
 // 发送邮件
 // 发送邮件
-func SendEmailByHz(title, content string, touser string) (result bool, err error) {
+func SendEmailByDw(title, content string, touser string) (result bool, err error) {
 	var arr []string
 	var arr []string
 	sub := strings.Index(touser, ";")
 	sub := strings.Index(touser, ";")
 	if sub >= 0 {
 	if sub >= 0 {
@@ -48,7 +48,7 @@ func SendEmailByHz(title, content string, touser string) (result bool, err error
 	m.SetHeader("To", arr...)
 	m.SetHeader("To", arr...)
 	m.SetHeader("Subject", title)
 	m.SetHeader("Subject", title)
 	m.SetBody("text/html", content)
 	m.SetBody("text/html", content)
-	d := gomail.NewDialer("smtp.mxhichina.com", 465, "lvan@dwqh88.com", "Dwqh20248888")
+	d := gomail.NewDialer("mail.dwqh88.com", 465, "lvan@dwqh88.com", "Dwqh20248888")
 	if err := d.DialAndSend(m); err != nil {
 	if err := d.DialAndSend(m); err != nil {
 		result = false
 		result = false
 		return result, err
 		return result, err

+ 26 - 2
utils/logs.go

@@ -9,16 +9,40 @@ import (
 )
 )
 
 
 const (
 const (
+	DefaultLogPath    = "./etalogs/filelog"
 	DefaultBinlogPath = "./etalogs/binlog"
 	DefaultBinlogPath = "./etalogs/binlog"
 	DefaultApiLogPath = "./etalogs/apilog"
 	DefaultApiLogPath = "./etalogs/apilog"
 )
 )
 
 
 var (
 var (
-	BinLog *logs.BeeLogger
-	ApiLog *logs.BeeLogger
+	BinLog  *logs.BeeLogger
+	ApiLog  *logs.BeeLogger
+	FileLog *logs.BeeLogger
 )
 )
 
 
 func init() {
 func init() {
+	if LogMaxDays == 0 {
+		LogMaxDays = 30
+	}
+	logPath := LogPath
+	if logPath == "" {
+		logPath = DefaultLogPath
+	}
+	logFile := LogFile
+	if logFile == "" {
+		logFile = "filelog.log"
+	}
+	os.MkdirAll(logPath, os.ModePerm)
+
+	// 打开文件
+	logFileName := path.Join(logPath, logFile)
+	FileLog = logs.NewLogger(1000000)
+	logConf := getDefaultLogConfig()
+
+	logConf.FileName = logFileName
+	b, _ := json.Marshal(logConf)
+	FileLog.SetLogger(logs.AdapterFile, string(b))
+	FileLog.EnableFuncCallDepth(true)
 	initApiLog()
 	initApiLog()
 	initBinLog()
 	initBinLog()
 }
 }