Przeglądaj źródła

项目初始化

xingzai 2 lat temu
commit
22125c1aff

+ 16 - 0
.gitignore

@@ -0,0 +1,16 @@
+/*.exe
+/*.tmp
+/.idea
+/routers/.DS_Store
+/rdlucklog
+/conf/*.conf
+/binlog/*.log
+/*.pdf
+/static/
+/hongze_clpt.tar.gz
+/hongze_clpt
+/static/searchKeywordCount.xlsx
+.DS_Store
+/doc/
+*DS_Store
+

+ 37 - 0
README.md

@@ -0,0 +1,37 @@
+# hongze_clpt
+
+#### 介绍
+查研观向->小程序端
+
+#### 软件架构
+软件架构说明
+
+
+#### 安装教程
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 使用说明
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 参与贡献
+
+1.  Fork 本仓库
+2.  新建 Feat_xxx 分支
+3.  提交代码
+4.  新建 Pull Request
+
+
+#### 特技
+
+1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
+2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
+3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
+4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
+5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
+6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 134 - 0
controllers/base_auth.go

@@ -0,0 +1,134 @@
+package controllers
+
+import (
+	"encoding/json"
+	"fmt"
+	beego "github.com/beego/beego/v2/adapter"
+	"hongze/hongze_clpt/services"
+	"net/http"
+	"net/url"
+	"strconv"
+
+	"hongze/hongze_clpt/models"
+	"hongze/hongze_clpt/utils"
+
+	"github.com/rdlucklib/rdluck_tools/log"
+)
+
+var apiLog *log.Log
+
+func init() {
+	if utils.RunMode == "release" {
+		logDir := `/data/rdlucklog/hongze_clpt`
+		apiLog = log.Init("20060102.api", logDir)
+	} else {
+		apiLog = log.Init("20060102.api")
+	}
+}
+
+type BaseAuthController struct {
+	beego.Controller
+	User  *models.WxUserItem
+	Token string
+}
+
+func (this *BaseAuthController) Prepare() {
+	fmt.Println("enter prepare")
+	method := this.Ctx.Input.Method()
+	uri := this.Ctx.Input.URI()
+	fmt.Println("Url:", uri)
+	if method != "HEAD" {
+		if method == "POST" || method == "GET" {
+			authorization := this.Ctx.Input.Header("Authorization")
+			if authorization == "" {
+				authorization = this.GetString("Authorization")
+			}
+			this.Token = authorization
+			if authorization == "" {
+				this.JSON(models.BaseResponse{Ret: 408, Msg: "请重新授权!", ErrMsg: "请重新授权:Token is empty or account is empty"}, false, false)
+				this.StopRun()
+				return
+			}
+			session, err := models.GetSessionByToken(authorization)
+			if err != nil {
+				if err.Error() == utils.ErrNoRow() {
+					this.JSON(models.BaseResponse{Ret: 408, Msg: "信息已变更,请重新登陆!", ErrMsg: "Token 信息已变更:Token: " + authorization}, false, false)
+					this.StopRun()
+					return
+				}
+				this.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "获取用户信息异常,Eerr:" + err.Error()}, false, false)
+				this.StopRun()
+				return
+			}
+			if session == nil {
+				this.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "sesson is empty "}, false, false)
+				this.StopRun()
+				return
+			}
+			wxUser, err := services.GetWxUserItemByOpenId(session.UnionId)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				this.JSON(models.BaseResponse{Ret: 408, Msg: "信息已变更,请重新登陆!", ErrMsg: "获取信息失败 " + strconv.Itoa(session.UserId)}, false, false)
+				this.StopRun()
+				return
+			}
+
+			if wxUser == nil {
+				this.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "admin is empty "}, false, false)
+				this.StopRun()
+				return
+			}
+			this.User = wxUser
+		} else {
+			this.JSON(models.BaseResponse{Ret: 408, Msg: "请求异常,请联系客服!", ErrMsg: "POST之外的请求,暂不支持"}, false, false)
+			this.StopRun()
+			return
+		}
+	}
+}
+
+func (c *BaseAuthController) ServeJSON(encoding ...bool) {
+	var (
+		hasIndent   = false
+		hasEncoding = false
+	)
+	if beego.BConfig.RunMode == beego.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)
+		return
+	}
+	baseRes := c.Data["json"].(*models.BaseResponse)
+	if baseRes != nil && baseRes.Ret != 200 && baseRes.Ret != 408 && baseRes.IsSendEmail {
+		body, _ := json.Marshal(baseRes)
+		msgBody := "URI:" + c.Ctx.Input.URI() + "<br/> ErrMsg:" + baseRes.ErrMsg + ";<br/>Msg:" + baseRes.Msg + ";<br/> Body:" + string(body) + ";<br/>" + c.Token
+		go utils.SendEmail(utils.APPNAME+" "+utils.RunMode+" 失败提醒", msgBody, utils.EmailSendToUsers)
+	}
+
+	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")
+	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))
+	apiLog.Println("请求地址:", 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)))
+	}
+	return c.Ctx.Output.Body(content)
+}

+ 122 - 0
controllers/base_common.go

@@ -0,0 +1,122 @@
+package controllers
+
+import (
+	"encoding/json"
+	beego "github.com/beego/beego/v2/adapter"
+	"hongze/hongze_clpt/models"
+	"hongze/hongze_clpt/utils"
+	"net/http"
+	"net/url"
+	"strings"
+)
+
+type BaseCommonController struct {
+	beego.Controller
+	//User  *models.WxUserItem
+	Token string
+}
+
+func (this *BaseCommonController) Prepare() {
+	var requestBody string
+	method := this.Ctx.Input.Method()
+	if method == "GET" {
+		requestBody = this.Ctx.Request.RequestURI
+	} else {
+		requestBody, _ = url.QueryUnescape(string(this.Ctx.Input.RequestBody))
+	}
+	ip := this.Ctx.Input.IP()
+	apiLog.Println("请求地址:", this.Ctx.Input.URI(), "RequestBody:", requestBody, "IP:", ip)
+
+	authorization := this.Ctx.Input.Header("Authorization")
+	if authorization == "" {
+		cookie := this.Ctx.GetCookie("rddp_access_token")
+		utils.FileLog.Info("authorization:%s,cookie:%s", authorization, cookie)
+		authorization = cookie
+	}
+	uri := this.Ctx.Input.URI()
+	utils.FileLog.Info("URI:%s", uri)
+	if strings.Contains(uri, "/api/wechat/login") {
+		authorization = ""
+	}
+	if authorization != "" {
+		//session, err := models.GetSessionByToken(authorization)
+		//if err != nil {
+		//	if err.Error() == utils.ErrNoRow() {
+		//		this.JSON(models.BaseResponse{Ret: 408, Msg: "信息已变更,请重新登陆!", ErrMsg: "Token 信息已变更:Token: " + authorization}, false, false)
+		//		this.StopRun()
+		//		return
+		//	}
+		//	this.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "获取用户信息异常,Eerr:" + err.Error()}, false, false)
+		//	this.StopRun()
+		//	return
+		//}
+		//if session == nil {
+		//	this.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "sesson is empty "}, false, false)
+		//	this.StopRun()
+		//	return
+		//}
+		//wxUser, err := models.GetWxUserItemByUserId(session.UserId)
+		//if err != nil {
+		//	if err.Error() == utils.ErrNoRow() {
+		//		this.JSON(models.BaseResponse{Ret: 408, Msg: "信息已变更,请重新登陆!", ErrMsg: "获取admin 信息失败 " + strconv.Itoa(session.UserId)}, false, false)
+		//		this.StopRun()
+		//		return
+		//	}
+		//	this.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "获取wx_user信息异常,Eerr:" + err.Error()}, false, false)
+		//	this.StopRun()
+		//	return
+		//}
+		//if wxUser == nil {
+		//	this.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "admin is empty "}, false, false)
+		//	this.StopRun()
+		//	return
+		//}
+		//this.User = wxUser
+	}
+	//this.Token = authorization
+}
+
+func (c *BaseCommonController) ServeJSON(encoding ...bool) {
+	var (
+		hasIndent   = false
+		hasEncoding = false
+	)
+	if beego.BConfig.RunMode == beego.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)
+		return
+	}
+	baseRes := c.Data["json"].(*models.BaseResponse)
+	if baseRes != nil && !baseRes.Success && baseRes.IsSendEmail {
+		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))
+	apiLog.Println("请求地址:", 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)))
+	}
+	return c.Ctx.Output.Body(content)
+}

+ 44 - 0
controllers/chart_permission.go

@@ -0,0 +1,44 @@
+package controllers
+
+import (
+	"hongze/hongze_clpt/models"
+	"hongze/hongze_clpt/utils"
+	"strconv"
+)
+
+//品种
+type ChartPermissionController struct {
+	BaseCommonController
+}
+
+type ChartPermissionAuthController struct {
+	BaseAuthController
+}
+
+// @Title 获取所有品种
+// @Description 获取用户详情接口
+// @Success 200 {object} models.ChartPermissionListResp
+// @router /list [get]
+func (this *ChartPermissionController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var condition string
+	var chartPermissionId string
+	chartPermissionId = strconv.Itoa(utils.YI_YAO_ID) + "," + strconv.Itoa(utils.XIAO_FEI_ID) + "," + strconv.Itoa(utils.KE_JI_ID) + "," + strconv.Itoa(utils.ZHI_ZAO_ID) + "," + strconv.Itoa(utils.CHART_PERMISSION_ID_YANXUAN)
+	condition += ` AND  chart_permission_id IN ( ` + chartPermissionId + `)`
+	list, err := models.GetChartPermissionReportAll(condition)
+	if err != nil {
+		br.Msg = "获取信息失败"
+		br.ErrMsg = "获取品种信息失败,Err:" + err.Error()
+		return
+	}
+	resp := new(models.ChartPermissionListResp)
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 9 - 0
controllers/user.go

@@ -0,0 +1,9 @@
+package controllers
+
+type UserController struct {
+	BaseAuthController
+}
+
+type UserCommonController struct {
+	BaseCommonController
+}

+ 9 - 0
controllers/wechat.go

@@ -0,0 +1,9 @@
+package controllers
+
+type WechatController struct {
+	BaseAuthController
+}
+
+type WechatCommonController struct {
+	BaseCommonController
+}

+ 55 - 0
main.go

@@ -0,0 +1,55 @@
+package main
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/adapter/logs"
+	_ "hongze/hongze_clpt/routers"
+	"hongze/hongze_clpt/utils"
+	"runtime"
+	"time"
+
+	"github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context"
+)
+
+func main() {
+	if web.BConfig.RunMode == "dev" {
+		web.BConfig.WebConfig.DirectoryIndex = true
+		web.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
+	}
+	//go services.Task()
+
+	web.BConfig.RecoverFunc = Recover
+	web.Run()
+}
+
+func Recover(ctx *context.Context, config *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)
+	}
+	return
+}

+ 31 - 0
models/base.go

@@ -0,0 +1,31 @@
+package models
+
+type BaseResponse struct {
+	Ret     int
+	Msg     string
+	ErrMsg  string
+	ErrCode string
+	Data    interface{}
+	Success bool `description:"true 执行成功,false 执行失败"`
+	IsSendEmail bool `json:"-"`
+}
+
+type BaseResponseRef struct {
+	Ret     int
+	Msg     string
+	ErrMsg  string
+	ErrCode string
+	Data    string
+}
+
+type BaseResponseResult struct {
+	Ret     int    `description:"状态:200 成功,408 重新登录,403:为失败"`
+	Msg     string `description:"提示信息,对用户展示"`
+	ErrMsg  string `description:"错误信息,供开发定位问题"`
+	ErrCode string `description:"错误编码,预留"`
+	Data    string `description:"返回数据,json格式字符串"`
+}
+
+func (r *BaseResponse) Init() *BaseResponse {
+	return &BaseResponse{Ret: 403,IsSendEmail: true}
+}

+ 21 - 0
models/chart_permission.go

@@ -0,0 +1,21 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type ChartPermissionResp struct {
+	ChartPermissionId int    `description:"权限id"`
+	PermissionName    string `description:"权限名称"`
+}
+
+type ChartPermissionListResp struct {
+	List []*ChartPermissionResp
+}
+
+func GetChartPermissionReportAll(condition string) (items []*ChartPermissionResp, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM chart_permission WHERE product_id=2 AND is_report=1 AND permission_type!=2 ` + condition + ` ORDER BY sort ASC `
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}

+ 50 - 0
models/cygx_user_record.go

@@ -0,0 +1,50 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type CygxUserRecord struct {
+	UserRecordId int       `orm:"column(user_record_id);pk"`
+	OpenId       string    `description:"用户openid,最大长度:32"`
+	UnionId      string    `description:"用户unionid,最大长度:64"`
+	NickName     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:"创建时间,关系添加时间、用户授权时间"`
+}
+
+//添加
+func AddCygxUserRecord(item *CygxUserRecord) (lastId int64, err error) {
+	o := orm.NewOrm()
+	lastId, err = o.Insert(item)
+	return
+}
+
+//获取数量
+func GetCygxUserRecordCount(openId string) (count int, err error) {
+	o := orm.NewOrm()
+	sqlCount := ` SELECT COUNT(1) AS count  FROM cygx_user_record WHERE open_id=? `
+	err = o.Raw(sqlCount, openId).QueryRow(&count)
+	return
+}
+
+//修改
+func UpdateCygxUserRecord(item *CygxUserRecord) (err error) {
+	o := orm.NewOrm()
+	msql := ` UPDATE cygx_user_record SET nick_name = ?,sex=?,province=?,city=? ,country=? ,headimgurl=?  WHERE open_id = ? `
+	_, err = o.Raw(msql, item.NickName, item.Sex, item.Province, item.City, item.Country, item.Headimgurl, item.OpenId).Exec()
+	return
+}
+
+//修改
+func UpdateUserRecord(item *CygxUserRecord) (err error) {
+	o := orm.NewOrm()
+	msql := ` UPDATE user_record SET nick_name = ?,sex=?,province=?,city=? ,country=? ,headimgurl=?  WHERE union_id = ? AND create_platform = 4  `
+	_, err = o.Raw(msql, item.NickName, item.Sex, item.Province, item.City, item.Country, item.Headimgurl, item.UnionId).Exec()
+	return
+}

+ 33 - 0
models/db.go

@@ -0,0 +1,33 @@
+package models
+
+import (
+	_ "github.com/go-sql-driver/mysql"
+	"hongze/hongze_clpt/utils"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+func init() {
+
+	_ = orm.RegisterDataBase("default", "mysql", utils.MYSQL_URL)
+	orm.SetMaxIdleConns("default", 50)
+	orm.SetMaxOpenConns("default", 100)
+
+	db, _ := orm.GetDB("default")
+	db.SetConnMaxLifetime(10 * time.Minute)
+
+	//注册对象
+	orm.RegisterModel(
+		new(WxUser),
+		new(WxUserCode),
+		new(UserRecord),
+		new(CygxUserRecord),
+		new(CygxXzsSession),
+		new(CygxIndustryFllow),
+	)
+	// 记录ORM查询日志
+	orm.Debug = true
+	orm.DebugLog = orm.NewLog(utils.BinLog)
+
+}

+ 71 - 0
models/db_base.go

@@ -0,0 +1,71 @@
+// @Time : 2020/10/29 8:31 下午
+// @Author : bingee
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+)
+
+// 是否存在
+func IsExistByExpr(ptrStructOrTableName interface{}, where map[string]interface{}) bool {
+	o := orm.NewOrm()
+	qs := o.QueryTable(ptrStructOrTableName)
+	for expr, exprV := range where {
+		qs = qs.Filter(expr, exprV)
+	}
+	return qs.Exist()
+}
+
+// 获取条数
+func GetCountByExpr(ptrStructOrTableName interface{}, where map[string]interface{}) (count int64, err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(ptrStructOrTableName)
+	for expr, exprV := range where {
+		qs = qs.Filter(expr, exprV)
+	}
+	count, err = qs.Count()
+	return
+}
+
+// 更新
+func UpdateByExpr(ptrStructOrTableName interface{}, where, updateParams map[string]interface{}) error {
+	o := orm.NewOrm()
+	qs := o.QueryTable(ptrStructOrTableName)
+	for expr, exprV := range where {
+		qs = qs.Filter(expr, exprV)
+	}
+	_, err := qs.Update(updateParams)
+	return err
+}
+
+// 删除
+func DeleteByExpr(ptrStructOrTableName interface{}, where map[string]interface{}) error {
+	o := orm.NewOrm()
+	qs := o.QueryTable(ptrStructOrTableName)
+	for expr, exprV := range where {
+		qs = qs.Filter(expr, exprV)
+	}
+	_, err := qs.Delete()
+	return err
+}
+
+// 插入
+func InsertData(ptrStructOrTableName interface{}) error {
+	o := orm.NewOrm()
+	_, err := o.Insert(ptrStructOrTableName)
+	return err
+}
+
+// 获取数据
+func GetDataByExpr(ptrStructOrTableName interface{}, where map[string]interface{}, data interface{}, page ...int64) (err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(ptrStructOrTableName)
+	for expr, exprV := range where {
+		qs = qs.Filter(expr, exprV)
+	}
+	if len(page) > 1 {
+		qs = qs.Limit(page[1], page[0])
+	}
+	_, err = qs.All(data)
+	return err
+}

+ 33 - 0
models/industry_fllow.go

@@ -0,0 +1,33 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type CygxIndustryFllow struct {
+	Id                     int       `orm:"column(id);pk"`
+	IndustrialManagementId int       `description:"产业D"`
+	UserId                 int       `description:"用户ID"`
+	Mobile                 string    `description:"手机号"`
+	Email                  string    `description:"邮箱"`
+	CompanyId              int       `description:"公司id"`
+	CompanyName            string    `description:"公司名称"`
+	Type                   int       `description:"操作方式,1报名,2取消报名"`
+	CreateTime             time.Time `description:"创建时间"`
+	ModifyTime             time.Time `description:"更新时间"`
+	RealName               string    `description:"用户实际名称"`
+	Source                 int       `description:"来源1查研观向,2查研观向小助手"`
+}
+
+type CygxIndustryFllowRep struct {
+	IndustrialManagementId int `description:"产业D"`
+}
+
+//根据手机号获取用户关注的产业
+func GetCygxIndustryFllowList(mobile string) (items []*CygxIndustryFllow, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM cygx_industry_fllow WHERE mobile = ?`
+	_, err = o.Raw(sql, mobile).QueryRows(&items)
+	return
+}

+ 54 - 0
models/session.go

@@ -0,0 +1,54 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+func GetSessionByToken(token string) (item *CygxXzsSession, err error) {
+	sql := `SELECT * FROM cygx_xzs_session WHERE access_token=? AND expire_time> NOW() ORDER BY session_id DESC LIMIT 1 `
+	o := orm.NewOrm()
+	err = o.Raw(sql, token).QueryRow(&item)
+	return
+}
+
+type CygxXzsSession struct {
+	SessionId       int `orm:"column(session_id);pk"`
+	UnionId         string
+	UserId          int
+	OpenId          string
+	AccessToken     string
+	ExpireTime      time.Time
+	CreatedTime     time.Time
+	LastUpdatedTime time.Time
+}
+
+//添加用户session信息
+func AddCygxXzsSession(item *CygxXzsSession) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Insert(item)
+	return
+}
+
+func GetXzsSessionCountByToken(token string) (count int, err error) {
+	sql := `SELECT COUNT(1) AS count FROM cygx_xzs_session WHERE access_token=? LIMIT 1 `
+	o := orm.NewOrm()
+	err = o.Raw(sql, token).QueryRow(&count)
+	return
+}
+
+//获取用户token详情
+func GetUnionidByToken(token string) (item *CygxXzsSession, err error) {
+	sql := `SELECT * FROM cygx_xzs_session WHERE access_token=?  LIMIT 1 `
+	o := orm.NewOrm()
+	err = o.Raw(sql, token).QueryRow(&item)
+	return
+}
+
+//根据用户openid获取token
+func GetTokenByOpenId(openId string) (item *CygxXzsSession, err error) {
+	sql := `SELECT * FROM cygx_xzs_session WHERE open_id=? AND expire_time> NOW() ORDER BY session_id DESC LIMIT 1 `
+	o := orm.NewOrm()
+	err = o.Raw(sql, openId).QueryRow(&item)
+	return
+}

+ 215 - 0
models/user.go

@@ -0,0 +1,215 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"hongze/hongze_clpt/utils"
+	"time"
+)
+
+type UserDetail struct {
+	Headimgurl          string `description:"用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空"`
+	Mobile              string `description:"手机号码"`
+	Email               string `description:"邮箱"`
+	NickName            string `description:"用户昵称"`
+	RealName            string `description:"用户实际名称"`
+	CompanyName         string `description:"公司名称"`
+	PermissionName      string `description:"拥有权限分类,多个用英文逗号分隔"`
+	HasPermission       int    `description:"1:无该行业权限,不存在权益客户下,2:潜在客户,未提交过申请,3:潜在客户,已提交过申请"`
+	SellerMobile        string `description:"销售手机号"`
+	SellerName          string `description:"销售名称"`
+	Note                string `json:"-" description:"申请提交时,公司名称"`
+	CountryCode         string `description:"区号"`
+	OutboundMobile      string `description:"外呼手机号"`
+	OutboundCountryCode string `description:"外呼手机号区号"`
+}
+
+func GetUserDetailByUserId(userId int) (item *UserDetail, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM wx_user WHERE user_id = ? `
+	err = o.Raw(sql, userId).QueryRow(&item)
+	return
+}
+
+type UserPermission struct {
+	CompanyName         string `description:"公司名称"`
+	ChartPermissionName string `description:"权限"`
+}
+
+type LoginReq struct {
+	LoginType   int    `description:"登录方式:1:微信手机,2:邮箱,3:自定义手机登录"`
+	Mobile      string `description:"手机号"`
+	Email       string `description:"邮箱"`
+	VCode       string `description:"验证码"`
+	CountryCode string `description:"区号"`
+}
+
+func PcBindMobile(unionId, mobile string, userId, loginType int) (wxUserId int, err error) {
+	//loginType  登录方式:1:手机,2:邮箱
+	sql := ``
+	if loginType == 1 {
+		sql = `SELECT * FROM wx_user WHERE mobile = ? `
+	} else {
+		sql = "SELECT * FROM wx_user WHERE email = ? "
+	}
+	user := new(WxUser)
+	o := orm.NewOrm()
+	err = o.Raw(sql, mobile).QueryRow(&user)
+
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		return
+	}
+
+	if user == nil || (err != nil && err.Error() == utils.ErrNoRow()) {
+		msql := ``
+		if loginType == 1 {
+			msql = "UPDATE wx_user SET mobile = ?,bind_account = ? WHERE union_id = ? "
+		} else {
+			msql = "UPDATE wx_user SET email = ?,bind_account = ? WHERE union_id = ?  "
+		}
+		_, err = o.Raw(msql, mobile, mobile, unionId).Exec()
+		wxUserId = userId
+	} else {
+		if user.UnionId == "" {
+			sql = `SELECT * FROM wx_user WHERE union_id = ? `
+			userInfo := new(WxUser)
+			o := orm.NewOrm()
+			err = o.Raw(sql, unionId).QueryRow(&userInfo)
+			if err != nil {
+				return
+			}
+			var maxRegisterTime time.Time
+			if user.RegisterTime.Before(userInfo.RegisterTime) {
+				maxRegisterTime = user.RegisterTime
+			} else {
+				maxRegisterTime = userInfo.RegisterTime
+			}
+			wxUserId = user.UserId
+			dsql := ` DELETE FROM wx_user WHERE union_id = ? `
+			_, err = o.Raw(dsql, unionId).Exec()
+			if err != nil {
+				return wxUserId, err
+			}
+			msql := ` UPDATE wx_user SET union_id=?,register_time=?,province=?,city=?,country=?,headimgurl=?,unionid=?,sex=?  WHERE user_id = ?  `
+			_, err = o.Raw(msql, unionId, maxRegisterTime, userInfo.Province, userInfo.City, userInfo.Country, userInfo.Headimgurl, unionId, userInfo.Sex, user.UserId).Exec()
+			wxUserId = user.UserId
+		} else {
+			sql = `SELECT * FROM wx_user WHERE user_id = ? `
+			userInfo := new(WxUser)
+			o := orm.NewOrm()
+			err = o.Raw(sql, userId).QueryRow(&userInfo)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				return
+			}
+			if user.UserId != userId {
+				dsql := ` DELETE FROM wx_user WHERE user_id = ? `
+				_, err = o.Raw(dsql, userId).Exec()
+				if err != nil {
+					return user.UserId, err
+				}
+			}
+			msql := ` UPDATE wx_user SET union_id=?,province=?,city=?,country=?,headimgurl=?,unionid=?,sex=?  WHERE user_id = ?  `
+			_, err = o.Raw(msql, unionId, userInfo.Province, userInfo.City, userInfo.Country, userInfo.Headimgurl, unionId, userInfo.Sex, user.UserId).Exec()
+			wxUserId = userId
+		}
+	}
+	return
+}
+
+type LoginResp struct {
+	UserId        int    `description:"用户id"`
+	Authorization string `description:"Token"`
+	Headimgurl    string `description:"用户头像"`
+	Mobile        string `description:"手机号"`
+	Email         string `description:"邮箱"`
+	CompanyName   string `description:"客户名称"`
+	Status        string `description:"状态"`
+	EndDate       string `description:"到期日期"`
+	ProductName   string `description:"客户类型名称"`
+}
+
+type CheckStatusResp struct {
+	IsBind         bool   `description:"true:需要绑定手机号或邮箱,false:不需要绑定手机号或邮箱"`
+	IsAuth         bool   `description:"true:需要授权,false:不需要授权"`
+	PermissionName string `description:"拥有权限分类,多个用英文逗号分隔"`
+}
+
+type ApplyTryReq struct {
+	BusinessCardUrl string `description:"名片地址"`
+	RealName        string `description:"姓名"`
+	CompanyName     string `description:"公司名称"`
+	ApplyMethod     int    `description:"1:已付费客户申请试用,2:非客户申请试用,3:非客户申请试用(ficc下,不需要进行数据校验)"`
+}
+
+type CountryCode struct {
+	IsNeedAddCountryCode bool `description:"是否需要填写区号:需要填写,false:不需要填写"`
+}
+
+type OutboundMobile struct {
+	IsNeedAddOutboundMobile bool `description:"是否需要填写外呼手机号:需要填写,false:不需要填写"`
+}
+
+type CountryCodeItem struct {
+	CountryCode string `description:"区号"`
+}
+
+//修改外呼手机号
+type OutboundMobileItem struct {
+	OutboundMobile      string `description:"外呼手机号"`
+	OutboundCountryCode string `description:"外呼手机号区号"`
+	ActivityId          int    `description:"活动ID"`
+}
+
+type UserWhiteList struct {
+	Mobile      string `description:"手机号码"`
+	RealName    string `description:"用户实际名称"`
+	CompanyName string `description:"公司名称"`
+	Permission  string `description:"拥有权限分类,多个用英文逗号分隔"`
+	CountryCode string `description:"区号"`
+	SellerName  string `description:"销售姓名"`
+	CreatedTime time.Time
+	Status      string `description:"客户状态'试用','永续','冻结','流失','正式','潜在'"`
+}
+
+type UserWhiteListRep struct {
+	List []*UserWhiteList
+}
+
+type UserDetailByUserLogin struct {
+	Headimgurl    string `description:"头像"`
+	Mobile        string `description:"手机号码"`
+	RealName      string `description:"用户实际名称"`
+	CompanyName   string `description:"公司名称"`
+	Permission    string `description:"拥有权限分类,多个用英文逗号分隔"`
+	HasPermission int    `description:"1:有该行业权限,正常展示,2:无权限,非潜在客户,3:未在小程序授权用户信息 等"`
+	Token         string `description:"Token"`
+}
+
+func GetCompanyPermission(companyId int) (permission string, err error) {
+	sql := ` SELECT GROUP_CONCAT(DISTINCT b.chart_permission_name  ORDER BY b.sort ASC SEPARATOR ',') AS permission
+			FROM company_report_permission AS a
+			INNER JOIN chart_permission AS b ON a.chart_permission_id=b.chart_permission_id
+			INNER JOIN company_product AS c ON a.company_id=c.company_id AND a.product_id=c.product_id
+			WHERE  a.company_id=?
+			AND c.is_suspend=0
+            AND b.cygx_auth=1
+			AND c.status IN('正式','试用','永续')
+			AND a.status IN('正式','试用','永续') `
+	o := orm.NewOrm()
+	err = o.Raw(sql, companyId).QueryRow(&permission)
+	return
+}
+
+func GetCompanyPermissionId(companyId int) (permissionId string, err error) {
+	sql := ` SELECT GROUP_CONCAT(DISTINCT b.chart_permission_id  ORDER BY b.sort ASC SEPARATOR ',') AS permissionId
+			FROM company_report_permission AS a
+			INNER JOIN chart_permission AS b ON a.chart_permission_id=b.chart_permission_id
+			INNER JOIN company_product AS c ON a.company_id=c.company_id AND a.product_id=c.product_id
+			WHERE  a.company_id=?
+			AND c.is_suspend=0
+            AND b.cygx_auth=1
+			AND c.status IN('正式','试用','永续')
+			AND a.status IN('正式','试用','永续') `
+	o := orm.NewOrm()
+	err = o.Raw(sql, companyId).QueryRow(&permissionId)
+	return
+}

+ 48 - 0
models/user_record.go

@@ -0,0 +1,48 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type UserRecord struct {
+	UserRecordId   int       `orm:"column(user_record_id);pk"`
+	OpenId         string    `description:"用户openid,最大长度:32"`
+	UnionId        string    `description:"用户unionid,最大长度:64"`
+	Subscribe      int       `description:"是否关注"`
+	NickName       string    `descritpion:"用户昵称,最大长度:32"`
+	RealName       string    `descritpion:"用户实际名称,最大长度:32"`
+	BindAccount    string    `descritpion:"绑定时的账号,最大长度:128"`
+	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:"创建时间,关系添加时间、用户授权时间"`
+	CreatePlatform int       `description:"注册平台,1:日度点评公众号,2:管理后台,3:pc端网站,4:查研观向小程序;默认:1"`
+	SessionKey     string    `description:"微信小程序会话密钥,最大长度:255"`
+	UserId         int       `description:"用户id"`
+}
+
+//根据openid获取用户关系
+func GetUserRecordByOpenId(openId string) (item *UserRecord, err error) {
+	sql := `SELECT * FROM user_record WHERE open_id=? `
+	err = orm.NewOrm().Raw(sql, openId).QueryRow(&item)
+	return
+}
+
+//根据openid获取用户关系
+//4是查研观向   create_platform
+func GetUserRecordByUnionId(unionId string) (item *UserRecord, err error) {
+	sql := `SELECT * FROM user_record WHERE union_id=? AND create_platform = 4  `
+	err = orm.NewOrm().Raw(sql, unionId).QueryRow(&item)
+	return
+}
+
+//根据openid解除绑定用户关系
+func UnBindUserRecordByOpenid(openId string) (err error) {
+	o := orm.NewOrm()
+	msql := ` UPDATE user_record SET user_id = 0,bind_account="" WHERE open_id = ? `
+	_, err = o.Raw(msql, openId).Exec()
+	return
+}

+ 57 - 0
models/wechat.go

@@ -0,0 +1,57 @@
+package models
+
+type WxLoginReq struct {
+	Code string `description:"微信code"`
+}
+
+type WxToken struct {
+	AccessToken string
+	ExpiresIn   int64
+	Id          int64
+}
+
+type WxTicket struct {
+	Errcode int    `json:"errcode"`
+	Errmsg  string `json:"errmsg"`
+	Ticket  string `json:"ticket"`
+}
+
+type WechatSign struct {
+	AppId     string
+	NonceStr  string
+	Timestamp int64
+	Url       string
+	Signature string
+	RawString string
+}
+
+type WxAccessToken struct {
+	AccessToken  string `json:"access_token"`
+	ExpiresIn    int    `json:"expires_in"`
+	RefreshToken string `json:"refresh_token"`
+	Openid       string `json:"openid"`
+	Unionid      string `json:"unionid"`
+	Scope        string `json:"scope"`
+	Errcode      int    `json:"errcode"`
+	Errmsg       string `json:"errmsg"`
+}
+
+type WxUsers struct {
+	Total int
+	Count int
+	Data  struct {
+		Openid []string
+	}
+	NextOpenid string
+}
+
+type WxCheckContentJson struct {
+	AccessToken  string `json:"access_token"`
+	ExpiresIn    int    `json:"expires_in"`
+	RefreshToken string `json:"refresh_token"`
+	Openid       string `json:"openid"`
+	Unionid      string `json:"unionid"`
+	Scope        string `json:"scope"`
+	Errcode      int    `json:"errcode"`
+	Errmsg       string `json:"errmsg"`
+}

+ 162 - 0
models/wx_user.go

@@ -0,0 +1,162 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type WxUser struct {
+	UserId              int       `orm:"column(user_id);pk"`
+	OpenId              string    `description:"open_id"`
+	UnionId             string    `description:"union_id"`
+	Subscribe           string    `description:"是否关注"`
+	CompanyId           int       `description:"客户id"`
+	NickName            string    `description:"用户昵称"`
+	RealName            string    `description:"用户实际名称"`
+	UserCode            string    `description:"用户编码"`
+	Mobile              string    `description:"手机号码"`
+	BindAccount         string    `description:"绑定时的账号"`
+	WxCode              string    `description:"微信号"`
+	Profession          string    `description:"职业"`
+	Email               string    `description:"邮箱"`
+	Telephone           string    `description:"座机"`
+	Sex                 int       `description:"普通用户性别,1为男性,2为女性"`
+	Province            string    `description:"普通用户个人资料填写的省份"`
+	City                string    `description:"普通用户个人资料填写的城市"`
+	Country             string    `description:"国家,如中国为CN"`
+	SubscribeTime       int       `description:"关注时间"`
+	Remark              string    `description:"备注"`
+	Headimgurl          string    `description:"用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空"`
+	Privilege           string    `description:"用户特权信息,json数组,如微信沃卡用户为(chinaunicom)"`
+	Unionid             string    `description:"用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。"`
+	FirstLogin          int       `description:"是否第一次登陆"`
+	Enabled             int       `description:"是否可用"`
+	CreatedTime         time.Time `description:"创建时间"`
+	LastUpdatedTime     time.Time `description:"最新一次修改时间"`
+	Seller              string    `description:"销售员"`
+	Note                string    `description:"客户备份信息"`
+	IsNote              int       `description:"是否备注过信息"`
+	FromType            string    `description:"report' COMMENT 'report:研报,teleconference:电话会"`
+	ApplyMethod         int       `description:"0:未申请,1:已付费客户申请试用,2:非客户申请试用"`
+	RegisterTime        time.Time `description:"注册时间"`
+	RegisterPlatform    int       `description:"注册平台,1:微信端,2:PC网页端"`
+	IsFreeLogin         bool      `description:"是否免登陆,true:免登陆,false:非免登陆"`
+	LoginTime           time.Time `description:"最近一次登录时间"`
+	SessionKey          string    `description:"微信小程序会话密钥"`
+	IsRegister          int       `description:"是否注册:1:已注册,0:未注册"`
+	Source              int       `description:"绑定来源,1:微信端,2:pc网页端,3:查研观向小程序,4:每日咨询"`
+	CountryCode         string    `description:"区号"`
+	OutboundMobile      string    `description:"外呼手机号"`
+	OutboundCountryCode string    `description:"外呼手机号区号"`
+}
+
+type WxUserItem struct {
+	UserId              int       `description:"用户id"`
+	OpenId              string    `description:"open_id"`
+	UnionId             string    `description:"union_id"`
+	CompanyId           int       `description:"客户id"`
+	NickName            string    `description:"用户昵称"`
+	RealName            string    `description:"用户实际名称"`
+	Mobile              string    `description:"手机号码"`
+	BindAccount         string    `description:"绑定时的账号"`
+	Email               string    `description:"邮箱"`
+	Headimgurl          string    `description:"用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空"`
+	HeadimgurlRecord    string    `description:"用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空"`
+	ApplyMethod         int       `description:"0:未申请,1:已付费客户申请试用,2:非客户申请试用"`
+	FirstLogin          int       `description:"是否第一次登陆"`
+	IsFreeLogin         int       `description:"是否免登陆,true:免登陆,false:非免登陆"`
+	LoginTime           time.Time `description:"登录时间"`
+	CreatedTime         time.Time `description:"创建时间"`
+	LastUpdatedTime     time.Time `description:"最近一次修改时间"`
+	SessionKey          string    `description:"微信小程序会话密钥"`
+	CompanyName         string    `description:"公司名称"`
+	IsRegister          int       `description:"是否注册:1:已注册,0:未注册"`
+	CountryCode         string    `description:"手机国家区号"`
+	OutboundMobile      string    `description:"外呼手机号"`
+	OutboundCountryCode string    `description:"外呼手机号区号"`
+	IsMsgOutboundMobile int       `description:"是否弹窗过绑定外呼手机号区号"`
+	Source              int
+}
+
+func GetWxUserItemByUserId(userId int) (item *WxUserItem, err error) {
+	sql := `SELECT a.*,b.company_name FROM wx_user AS a
+			LEFT JOIN company AS b on a.company_id=b.company_id
+			WHERE a.user_id=? `
+	err = orm.NewOrm().Raw(sql, userId).QueryRow(&item)
+	return
+}
+
+type WxLoginResp struct {
+	Authorization string
+	UserId        int
+	FirstLogin    int
+	Headimgurl    string `description:"用户头像"`
+	Mobile        string `description:"手机号"`
+	Email         string `description:"邮箱"`
+	CompanyName   string `description:"客户名称"`
+	Status        string `description:"状态"`
+	EndDate       string `description:"到期日期"`
+	ProductName   string `description:"客户类型名称"`
+}
+
+type WxGetUserInfoReq struct {
+	RawData       string `description:"rawData"`
+	Signature     string `description:"signature"`
+	EncryptedData string `description:"encryptedData"`
+	Iv            string `description:"iv"`
+}
+
+func GetWxUserItemByUserUnionId(unionId string) (item *WxUserItem, err error) {
+	sql := `SELECT a.*,r.headimgurl as headimgurl_record, b.company_name FROM wx_user AS a
+			INNER JOIN company AS b on a.company_id=b.company_id
+			INNER JOIN user_record  as  r ON r.user_id = a.user_id 
+			WHERE r.union_id=?
+			GROUP BY a.user_id`
+	err = orm.NewOrm().Raw(sql, unionId).QueryRow(&item)
+	return
+}
+
+//根据用户UnionId取相关信息
+func GetWxUserAouthByUnionId(UnionId string) (item *WxUserItem, err error) {
+	sql := `SELECT
+			a.*,
+			s.union_id,
+			b.company_name 
+		FROM
+			cygx_xzs_session  AS s
+			INNER JOIN  user_record as  r ON r.union_id = s.union_id 
+			LEFT JOIN wx_user AS a ON a.mobile = r.bind_account
+			LEFT JOIN company AS b ON a.company_id = b.company_id 
+		WHERE
+			s.union_id = ?
+		ORDER BY
+			a.company_id DESC 
+			LIMIT 1`
+	err = orm.NewOrm().Raw(sql, UnionId).QueryRow(&item)
+	return
+}
+
+//根据用户手机号获取相关信息
+func GetWxUserItemByUserMobile(mobile string) (item *WxUserItem, err error) {
+	sql := `SELECT
+			a.user_id,
+			a.real_name,
+			a.headimgurl,
+			a.company_id,
+			a.mobile,
+			a.email,
+			c.union_id,
+			c.open_id,
+			b.company_name 
+		FROM
+			wx_user AS a
+			INNER JOIN company AS b ON a.company_id = b.company_id
+			INNER JOIN user_record AS r ON r.bind_account = a.mobile
+			INNER JOIN cygx_user_record AS c ON c.union_id = r.union_id 
+		WHERE
+			a.mobile = ? 
+		GROUP BY
+			a.mobile `
+	err = orm.NewOrm().Raw(sql, mobile).QueryRow(&item)
+	return
+}

+ 31 - 0
models/wx_user_code.go

@@ -0,0 +1,31 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type WxUserCode struct {
+	Id             int `orm:"column(id);pk"`
+	WxCode         string
+	UserId         int
+	Code           int
+	FirstLogin     int
+	Authorization  string
+	UserPermission int
+	CreateTime     time.Time
+}
+
+//添加联系人日志信息
+func AddWxUserCode(item *WxUserCode) (lastId int64, err error) {
+	o := orm.NewOrm()
+	lastId, err = o.Insert(item)
+	return
+}
+
+func GetWxUserCode(wxCode string) (item *WxUserCode, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM wx_user_code WHERE wx_code=? `
+	err = o.Raw(sql, wxCode).QueryRow(&item)
+	return
+}

+ 19 - 0
routers/commentsRouter.go

@@ -0,0 +1,19 @@
+package routers
+
+import (
+	beego "github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context/param"
+)
+
+func init() {
+
+    beego.GlobalControllerRouter["hongze/hongze_clpt/controllers:ChartPermissionController"] = append(beego.GlobalControllerRouter["hongze/hongze_clpt/controllers:ChartPermissionController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+}

+ 46 - 0
routers/router.go

@@ -0,0 +1,46 @@
+// @APIVersion 1.0.0
+// @Title beego Test API
+// @Description beego has a very cool tools to autogenerate documents for your API
+// @Contact astaxie@gmail.com
+// @TermsOfServiceUrl http://beego.me/
+// @License Apache 2.0
+// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html
+package routers
+
+import (
+	"github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/filter/cors"
+	"hongze/hongze_clpt/controllers"
+)
+
+func init() {
+	web.InsertFilter("*", web.BeforeRouter, cors.Allow(&cors.Options{
+		AllowAllOrigins:  true,
+		AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
+		AllowHeaders:     []string{"Origin", "Account", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
+		ExposeHeaders:    []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type", "Sign"},
+		AllowCredentials: true,
+	}))
+
+	ns := web.NewNamespace("/api",
+		web.NSNamespace("/wechat",
+			web.NSInclude(
+				&controllers.WechatController{},
+				&controllers.WechatCommonController{},
+			),
+		),
+		web.NSNamespace("/user",
+			web.NSInclude(
+				&controllers.UserController{},
+				&controllers.UserCommonController{},
+			),
+		),
+		web.NSNamespace("/permission",
+			web.NSInclude(
+				&controllers.ChartPermissionController{},
+				&controllers.ChartPermissionAuthController{},
+			),
+		),
+	)
+	web.AddNamespace(ns)
+}

+ 122 - 0
services/oss.go

@@ -0,0 +1,122 @@
+package services
+
+import (
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"os"
+	"time"
+
+	"hongze/hongze_clpt/utils"
+)
+
+//图片上传到阿里云
+func UploadAliyun(filename, filepath string) (string, error) {
+	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+	if err != nil {
+		return "1", err
+	}
+	bucket, err := client.Bucket(utils.Bucketname)
+	if err != nil {
+		return "2", err
+	}
+	path := utils.Upload_dir + time.Now().Format("200601/20060102/")
+	path += filename
+	err = bucket.PutObjectFromFile(path, filepath)
+	if err != nil {
+		return "3", err
+	}
+	path = utils.Imghost + path
+	return path, err
+}
+
+//音频上传到阿里云
+func UploadAudioAliyun(filename, filepath string) (string, error) {
+	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+	if err != nil {
+		return "1", err
+	}
+	bucket, err := client.Bucket(utils.Bucketname)
+	if err != nil {
+		return "2", err
+	}
+	path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+	path += filename
+	err = bucket.PutObjectFromFile(path, filepath)
+	if err != nil {
+		return "3", err
+	}
+	path = utils.Imghost + path
+	return path, err
+}
+
+//视频上传到阿里云
+func UploadVideoAliyun(filename, filepath, savePath string) error {
+	defer func() {
+		os.Remove(filepath)
+	}()
+	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+	if err != nil {
+		return err
+	}
+	bucket, err := client.Bucket(utils.Bucketname)
+	if err != nil {
+		return err
+	}
+	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+	//path += filename
+	err = bucket.PutObjectFromFile(savePath, filepath)
+	if err != nil {
+		return err
+	}
+	//path = utils.Imghost + path
+	//return path,err
+	return err
+}
+
+//PDF上传到阿里云
+func UploadPdfAliyun(filename, filepath string) (string, error) {
+	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+	if err != nil {
+		return "1", err
+	}
+	bucket, err := client.Bucket(utils.Bucketname)
+	if err != nil {
+		return "2", err
+	}
+	path := utils.Upload_Pdf_Dir + time.Now().Format("200601/20060102/")
+	path += filename
+	err = bucket.PutObjectFromFile(path, filepath)
+	if err != nil {
+		return "3", err
+	}
+	path = utils.Imghost + path
+	return path, err
+}
+
+const (
+	HzEndpoint          = "oss-cn-shanghai.aliyuncs.com"
+	HzBucketName string = "hzchart"
+)
+
+//上传文件到阿里云
+func UploadFileToAliyun(filename, filepath, savePath string) error {
+	defer func() {
+		os.Remove(filepath)
+	}()
+	client, err := oss.New(HzEndpoint, utils.AccessKeyId, utils.AccessKeySecret)
+	if err != nil {
+		return err
+	}
+	bucket, err := client.Bucket(HzBucketName)
+	if err != nil {
+		return err
+	}
+	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+	//path += filename
+	err = bucket.PutObjectFromFile(savePath, filepath)
+	if err != nil {
+		return err
+	}
+	//path = utils.Imghost + path
+	//return path,err
+	return err
+}

+ 114 - 0
services/sms.go

@@ -0,0 +1,114 @@
+package services
+
+import (
+	"encoding/json"
+	"fmt"
+	"hongze/hongze_clpt/utils"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+)
+
+func SendSmsCode(mobile, vcode string) bool {
+	flag := false
+	tplId := "65692"
+	result, err := sendSms(mobile, tplId, vcode)
+	if err != nil {
+		fmt.Println("发送短信失败")
+		return false
+	}
+	fmt.Println("result", string(result))
+	var netReturn map[string]interface{}
+	err = json.Unmarshal(result, &netReturn)
+	if err != nil {
+		go utils.SendEmail("短信验证码发送失败", "err:"+err.Error()+" result"+string(result), utils.EmailSendToUsers)
+		flag = false
+	}
+	if netReturn["error_code"].(float64) == 0 {
+		fmt.Printf("接口返回result字段是:\r\n%v", netReturn["result"])
+		flag = true
+	} else {
+		go utils.SendEmail("短信验证码发送失败", " result"+string(result), utils.EmailSendToUsers)
+		flag = false
+	}
+	return flag
+}
+
+func sendSms(mobile, tplId, code string) (rs []byte, err error) {
+	var Url *url.URL
+	apiURL := "http://v.juhe.cn/sms/send"
+	//初始化参数
+	param := url.Values{}
+	//配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
+	param.Set("mobile", mobile)            //接受短信的用户手机号码
+	param.Set("tpl_id", tplId)             //您申请的短信模板ID,根据实际情况修改
+	param.Set("tpl_value", "#code#="+code) //您设置的模板变量,根据实际情况
+	param.Set("key", utils.JhGnAppKey)     //应用APPKEY(应用详细页查询)
+
+	Url, err = url.Parse(apiURL)
+	if err != nil {
+		fmt.Printf("解析url错误:\r\n%v", err)
+		return nil, err
+	}
+	//如果参数中有中文参数,这个方法会进行URLEncode
+	Url.RawQuery = param.Encode()
+	resp, err := http.Get(Url.String())
+	if err != nil {
+		fmt.Println("err:", err)
+		return nil, err
+	}
+	defer resp.Body.Close()
+	return ioutil.ReadAll(resp.Body)
+}
+
+func SendSmsCodeGj(mobile, vcode, areaNum string) bool {
+	flag := false
+	result, err := sendSmsGj(mobile, vcode, areaNum)
+	if err != nil {
+		fmt.Println("发送短信失败")
+		return false
+	}
+	fmt.Println("result", string(result))
+	var netReturn map[string]interface{}
+	err = json.Unmarshal(result, &netReturn)
+	if err != nil {
+		go utils.SendEmail("短信验证码发送失败", "err:"+err.Error()+" result"+string(result), utils.EmailSendToUsers)
+		flag = false
+	}
+	if netReturn["error_code"].(float64) == 0 {
+		fmt.Printf("接口返回result字段是:\r\n%v", netReturn["result"])
+		flag = true
+	} else {
+		go utils.SendEmail("短信验证码发送失败", " result"+string(result), utils.EmailSendToUsers)
+		flag = false
+	}
+	return flag
+}
+
+func sendSmsGj(mobile, code, areaNum string) (rs []byte, err error) {
+	var Url *url.URL
+	apiURL := "http://v.juhe.cn/smsInternational/send.php"
+	//初始化参数
+	param := url.Values{}
+	//配置请求参数,方法内部已处理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(应用详细页查询)
+
+	Url, err = url.Parse(apiURL)
+	if err != nil {
+		fmt.Printf("解析url错误:\r\n%v", err)
+		return nil, err
+	}
+	//如果参数中有中文参数,这个方法会进行URLEncode
+	Url.RawQuery = param.Encode()
+	resp, err := http.Get(Url.String())
+	if err != nil {
+		fmt.Println("err:", err)
+		return nil, err
+	}
+	defer resp.Body.Close()
+	return ioutil.ReadAll(resp.Body)
+}

+ 46 - 0
services/user.go

@@ -0,0 +1,46 @@
+package services
+
+import (
+	"errors"
+	"hongze/hongze_clpt/models"
+	"hongze/hongze_clpt/utils"
+)
+
+var ERR_NO_USER_RECORD = errors.New("用户关系没有入库")
+var ERR_USER_NOT_BIND = errors.New("用户没有绑定")
+
+//通过用户 关系表记录  和  用户记录  格式化返回 用户数据
+func formatWxUserAndUserRecord(wxUser *models.WxUserItem, userRecord *models.UserRecord) {
+	wxUser.OpenId = userRecord.OpenId
+	wxUser.UnionId = userRecord.UnionId
+	wxUser.NickName = userRecord.NickName
+	//wxUser.RealName = userRecord.RealName
+	//wxUser.BindAccount = userRecord.BindAccount
+	wxUser.Headimgurl = userRecord.Headimgurl
+	wxUser.SessionKey = userRecord.SessionKey
+}
+
+func GetWxUserItemByOpenId(unionId string) (item *models.WxUserItem, err error) {
+	//通过openid获取用户关联信息
+	item = new(models.WxUserItem)
+	item.UnionId = unionId // 先写入 unionId
+	userRecord, userRecordErr := models.GetUserRecordByUnionId(unionId)
+	if userRecordErr != nil && userRecordErr.Error() != utils.ErrNoRow() {
+		err = userRecordErr
+		return
+	}
+	//如果 userRecord 表中的手机号不为空,那么就通过手机号来获取详情
+	if userRecord != nil {
+		if userRecord.BindAccount != "" {
+			user, userErr := models.GetWxUserItemByUserMobile(userRecord.BindAccount)
+			if userErr != nil && userErr.Error() != utils.ErrNoRow() {
+				err = userErr
+				return
+			}
+			if user != nil {
+				item = user
+			}
+		}
+	}
+	return
+}

+ 220 - 0
services/wechat.go

@@ -0,0 +1,220 @@
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/http"
+	"hongze/hongze_clpt/models"
+	"hongze/hongze_clpt/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type WxAccessToken struct {
+	AccessToken  string `json:"access_token"`
+	ExpiresIn    int    `json:"expires_in"`
+	RefreshToken string `json:"refresh_token"`
+	Openid       string `json:"openid"`
+	Unionid      string `json:"unionid"`
+	Scope        string `json:"scope"`
+	Errcode      int    `json:"errcode"`
+	Errmsg       string `json:"errmsg"`
+}
+
+type WxUserInfo struct {
+	Openid         string `json:"openid"`
+	Nickname       string `json:"nickname"`
+	Sex            int    `json:"sex"`
+	Language       string `json:"language"`
+	City           string `json:"city"`
+	Province       string `json:"province"`
+	Country        string `json:"country"`
+	Headimgurl     string `json:"headimgurl"`
+	SubscribeTime  int    `json:"subscribe_time"`
+	Unionid        string `json:"unionid"`
+	Remark         string `json:"remark"`
+	Groupid        int    `json:"groupid"`
+	SubscribeScene string `json:"subscribe_scene"`
+	Errcode        int    `json:"errcode"`
+	Errmsg         string `json:"errmsg"`
+	SessionKey     string `json:"session_key"`
+}
+
+type WxToken struct {
+	AccessToken string
+	ExpiresIn   int64
+	Id          int64
+}
+
+func WxGetUserOpenIdByCode(code string) (item *WxAccessToken, err error) {
+	if code == "" {
+		err = errors.New("code is empty")
+		return nil, err
+	}
+	requestUrl := `https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code`
+	requestUrl = fmt.Sprintf(requestUrl, utils.WxAppId, utils.WxAppSecret, code)
+	result, err := http.Get(requestUrl)
+	if err != nil {
+		return nil, err
+	}
+	err = json.Unmarshal(result, &item)
+	return
+}
+
+//小助手
+func WxGetUserOpenIdByCodeXzs(code string) (item *WxAccessToken, err error) {
+	if code == "" {
+		err = errors.New("code is empty")
+		return nil, err
+	}
+	requestUrl := `https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code`
+	requestUrl = fmt.Sprintf(requestUrl, utils.WxPublicAppId, utils.WxPublicAppSecret, code)
+	result, err := http.Get(requestUrl)
+	if err != nil {
+		return nil, err
+	}
+	err = json.Unmarshal(result, &item)
+	return
+}
+
+func WxGetToken() (item *WxAccessToken, err error) {
+	requestUrl := `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s`
+	requestUrl = fmt.Sprintf(requestUrl, utils.WxPublicAppId, utils.WxPublicAppSecret)
+	result, err := http.Get(requestUrl)
+	if err != nil {
+		utils.FileLog.Info("获取wxToken失败,Err:%s", err.Error())
+		return nil, err
+	}
+	err = json.Unmarshal(result, &item)
+	if err != nil {
+		fmt.Println(fmt.Sprintf("GetWxToken Unmarshal Err:%s", err.Error()))
+		return
+	}
+	if item.Errmsg != "" {
+		err = fmt.Errorf(item.Errmsg)
+		utils.FileLog.Info(fmt.Sprintf("GetWxToken fail result:%s", string(result)))
+	}
+	return
+}
+
+func WxGetUserInfo(openId, accessToken string) (item *WxUserInfo, err error) {
+	requestUrl := `https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s`
+	requestUrl = fmt.Sprintf(requestUrl, accessToken, openId)
+	result, err := http.Get(requestUrl)
+	if err != nil {
+		return
+	}
+	//fmt.Println("result:", string(result))
+	utils.FileLog.Info("WxGetUserInfo:%s openId:%s,accessToken:%s ", string(result), openId, accessToken)
+	utils.FileLog.Info("WxGetUserInfo Result:%s ", string(result))
+	err = json.Unmarshal(result, &item)
+	return
+}
+
+func GetWxSignature(ticket, url, noncestr string) (string, string, int64) {
+	timestamp := time.Now().Unix()
+	signStr := strings.Join([]string{"jsapi_ticket=", ticket,
+		"&noncestr=", noncestr,
+		"&timestamp=", strconv.FormatInt(timestamp, 10), "&url=", url}, "")
+	signature := utils.Sha1(signStr)
+	fmt.Println("signStr", signStr)
+	return signature, noncestr, timestamp
+}
+
+type WxUserDetail struct {
+	Unionid    string
+	Headimgurl string
+	Nickname   string
+}
+
+func GetWxAccessTokenByXzs() (accessTokenStr string, err error) {
+	//缓存校验
+	if utils.RunMode == "release" {
+		cacheKey := "xygxxzs_wxtoken"
+		accessTokenStr, _ = utils.Rc.RedisString(cacheKey)
+		if accessTokenStr != "" {
+			return
+		} else {
+			WxAccessToken, errWx := WxGetToken()
+			if errWx != nil {
+				err = errWx
+				return
+			}
+			accessTokenStr = WxAccessToken.AccessToken
+			utils.Rc.Put(cacheKey, WxAccessToken.AccessToken, time.Second*7000)
+		}
+	} else {
+		accessTokenStr, err = GetWxAccessToken()
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+func GetWxTicket(accessToken string) (string, error) {
+	Url := strings.Join([]string{"https://api.weixin.qq.com/cgi-bin/ticket/getticket",
+		"?access_token=", accessToken,
+		"&type=jsapi"}, "")
+	infoBody, err := http.Get(Url)
+	if err != nil {
+		return "", err
+	}
+	atr := models.WxTicket{}
+	err = json.Unmarshal(infoBody, &atr)
+	fmt.Println("ticket result:", string(infoBody))
+	if err != nil {
+		return atr.Errmsg, err
+	} else {
+		return atr.Ticket, nil
+	}
+}
+
+//获取测试环境的AccessToken
+func GetWxAccessToken() (accessTokenStr string, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM wx_token LIMIT 1`
+	wxToken := new(WxToken)
+	err = o.Raw(sql).QueryRow(&wxToken)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		return
+	}
+	//Token不存在
+	if wxToken == nil {
+		fmt.Println("wxToken is empty")
+		accessToken, err := WxGetToken()
+		if err != nil {
+			return "", err
+		}
+		if accessToken.AccessToken != "" {
+			expiresIn := time.Now().Add(time.Duration(accessToken.ExpiresIn) * time.Second).Unix()
+			addSql := "insert into wx_token (access_token,expires_in) values (?,?)"
+			_, err = o.Raw(addSql, accessToken.AccessToken, expiresIn).Exec()
+			accessTokenStr = accessToken.AccessToken
+		}
+		return accessTokenStr, err
+	} else {
+		//判断token是否过期
+		if time.Now().Unix() > wxToken.ExpiresIn {
+
+			accessToken, err := WxGetToken()
+			fmt.Println(accessToken)
+			if err != nil {
+				return "", err
+			}
+			if accessToken.AccessToken != "" {
+				expiresIn := time.Now().Add(time.Duration(accessToken.ExpiresIn) * time.Second).Unix()
+				updateSql := "update wx_token set access_token = ?,expires_in = ? "
+				_, err = o.Raw(updateSql, accessToken.AccessToken, expiresIn).Exec()
+				accessTokenStr = accessToken.AccessToken
+				fmt.Println("更新 TOKEN:", err)
+			}
+			return accessTokenStr, err
+		} else {
+			return wxToken.AccessToken, nil
+		}
+	}
+}

+ 653 - 0
utils/common.go

@@ -0,0 +1,653 @@
+package utils
+
+import (
+	"crypto/md5"
+	"crypto/sha1"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"image"
+	"image/png"
+	"math"
+	"math/rand"
+	"net"
+	"os"
+	"os/exec"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+)
+
+//随机数种子
+var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+func GetRandString(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 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 ToString(v interface{}) string {
+	data, _ := json.Marshal(v)
+	return string(data)
+}
+
+//md5加密
+func MD5(data string) string {
+	m := md5.Sum([]byte(data))
+	return hex.EncodeToString(m[:])
+}
+
+// 获取数字随机字符
+func GetRandDigit(n int) string {
+	return fmt.Sprintf("%0"+strconv.Itoa(n)+"d", rnd.Intn(int(math.Pow10(n))))
+}
+
+// 获取随机数
+func GetRandNumber(n int) int {
+	return rnd.Intn(n)
+}
+
+func GetRandInt(min, max int) int {
+	if min >= max || min == 0 || max == 0 {
+		return max
+	}
+	return rand.Intn(max-min) + min
+}
+
+func GetToday(format string) string {
+	today := time.Now().Format(format)
+	return today
+}
+
+//获取今天剩余秒数
+func GetTodayLastSecond() time.Duration {
+	today := GetToday(FormatDate) + " 23:59:59"
+	end, _ := time.ParseInLocation(FormatDateTime, today, time.Local)
+	return time.Duration(end.Unix()-time.Now().Local().Unix()) * time.Second
+}
+
+// 处理出生日期函数
+func GetBrithDate(idcard string) string {
+	l := len(idcard)
+	var s string
+	if l == 15 {
+		s = "19" + idcard[6:8] + "-" + idcard[8:10] + "-" + idcard[10:12]
+		return s
+	}
+	if l == 18 {
+		s = idcard[6:10] + "-" + idcard[10:12] + "-" + idcard[12:14]
+		return s
+	}
+	return GetToday(FormatDate)
+}
+
+//处理性别
+func WhichSexByIdcard(idcard string) string {
+	var sexs = [2]string{"女", "男"}
+	length := len(idcard)
+	if length == 18 {
+		sex, _ := strconv.Atoi(string(idcard[16]))
+		return sexs[sex%2]
+	} else if length == 15 {
+		sex, _ := strconv.Atoi(string(idcard[14]))
+		return sexs[sex%2]
+	}
+	return "男"
+}
+
+//截取小数点后几位
+func SubFloatToString(f float64, m int) string {
+	n := strconv.FormatFloat(f, 'f', -1, 64)
+	if n == "" {
+		return ""
+	}
+	if m >= len(n) {
+		return n
+	}
+	newn := strings.Split(n, ".")
+	if m == 0 {
+		return newn[0]
+	}
+	if len(newn) < 2 || m >= len(newn[1]) {
+		return n
+	}
+	return newn[0] + "." + newn[1][:m]
+}
+
+//截取小数点后几位
+func SubFloatToFloat(f float64, m int) float64 {
+	newn := SubFloatToString(f, m)
+	newf, _ := strconv.ParseFloat(newn, 64)
+	return newf
+}
+
+//获取相差时间-年
+func GetYearDiffer(start_time, end_time string) int {
+	t1, _ := time.ParseInLocation("2006-01-02", start_time, time.Local)
+	t2, _ := time.ParseInLocation("2006-01-02", end_time, time.Local)
+	age := t2.Year() - t1.Year()
+	if t2.Month() < t1.Month() || (t2.Month() == t1.Month() && t2.Day() < t1.Day()) {
+		age--
+	}
+	return age
+}
+
+//获取相差时间-秒
+func GetSecondDifferByTime(start_time, end_time time.Time) int64 {
+	diff := end_time.Unix() - start_time.Unix()
+	return diff
+}
+
+func FixFloat(f float64, m int) float64 {
+	newn := SubFloatToString(f+0.00000001, m)
+	newf, _ := strconv.ParseFloat(newn, 64)
+	return newf
+}
+
+// 将字符串数组转化为逗号分割的字符串形式  ["str1","str2","str3"] >>> "str1,str2,str3"
+func StrListToString(strList []string) (str string) {
+	if len(strList) > 0 {
+		for k, v := range strList {
+			if k == 0 {
+				str = v
+			} else {
+				str = str + "," + v
+			}
+		}
+		return
+	}
+	return ""
+}
+
+//Token
+func GetToken() string {
+	randStr := GetRandString(64)
+	token := MD5(randStr + Md5Key)
+	tokenLen := 64 - len(token)
+	return strings.ToUpper(token + GetRandString(tokenLen))
+}
+
+//数据没有记录
+func ErrNoRow() string {
+	return "<QuerySeter> no row found"
+}
+
+//校验邮箱格式
+func ValidateEmailFormatat(email string) bool {
+	reg := regexp.MustCompile(RegularEmail)
+	return reg.MatchString(email)
+}
+
+//验证是否是手机号
+func ValidateMobileFormatat(mobileNum string) bool {
+	reg := regexp.MustCompile(RegularMobile)
+	return reg.MatchString(mobileNum)
+}
+
+//验证是否是固定电话
+func ValidateFixedTelephoneFormatat(mobileNum string) bool {
+	reg := regexp.MustCompile(RegularFixedTelephone)
+	return reg.MatchString(mobileNum)
+}
+
+//判断文件是否存在
+func FileIsExist(filePath string) bool {
+	_, err := os.Stat(filePath)
+	return err == nil || os.IsExist(err)
+}
+
+//获取图片扩展名
+func GetImgExt(file string) (ext string, err error) {
+	var headerByte []byte
+	headerByte = make([]byte, 8)
+	fd, err := os.Open(file)
+	if err != nil {
+		return "", err
+	}
+	defer fd.Close()
+	_, err = fd.Read(headerByte)
+	if err != nil {
+		return "", err
+	}
+	xStr := fmt.Sprintf("%x", headerByte)
+	switch {
+	case xStr == "89504e470d0a1a0a":
+		ext = ".png"
+	case xStr == "0000010001002020":
+		ext = ".ico"
+	case xStr == "0000020001002020":
+		ext = ".cur"
+	case xStr[:12] == "474946383961" || xStr[:12] == "474946383761":
+		ext = ".gif"
+	case xStr[:10] == "0000020000" || xStr[:10] == "0000100000":
+		ext = ".tga"
+	case xStr[:8] == "464f524d":
+		ext = ".iff"
+	case xStr[:8] == "52494646":
+		ext = ".ani"
+	case xStr[:4] == "4d4d" || xStr[:4] == "4949":
+		ext = ".tiff"
+	case xStr[:4] == "424d":
+		ext = ".bmp"
+	case xStr[:4] == "ffd8":
+		ext = ".jpg"
+	case xStr[:2] == "0a":
+		ext = ".pcx"
+	default:
+		ext = ""
+	}
+	return ext, nil
+}
+
+//保存图片
+func SaveImage(path string, img image.Image) (err error) {
+	//需要保持的文件
+	imgfile, err := os.Create(path)
+	defer imgfile.Close()
+	// 以PNG格式保存文件
+	err = png.Encode(imgfile, img)
+	return err
+}
+
+//保存base64数据为文件
+func SaveBase64ToFile(content, path string) error {
+	data, err := base64.StdEncoding.DecodeString(content)
+	if err != nil {
+		return err
+	}
+	f, err := os.Create(path)
+	defer f.Close()
+	if err != nil {
+		return err
+	}
+	f.Write(data)
+	return nil
+}
+
+func SaveBase64ToFileBySeek(content, path string) (err error) {
+	data, err := base64.StdEncoding.DecodeString(content)
+	exist, err := PathExists(path)
+	if err != nil {
+		return
+	}
+	if !exist {
+		f, err := os.Create(path)
+		if err != nil {
+			return err
+		}
+		n, _ := f.Seek(0, 2)
+		// 从末尾的偏移量开始写入内容
+		_, err = f.WriteAt([]byte(data), n)
+		defer f.Close()
+	} else {
+		f, err := os.OpenFile(path, os.O_WRONLY, 0644)
+		if err != nil {
+			return err
+		}
+		n, _ := f.Seek(0, 2)
+		// 从末尾的偏移量开始写入内容
+		_, err = f.WriteAt([]byte(data), n)
+		defer f.Close()
+	}
+
+	return nil
+}
+
+func PathExists(path string) (bool, error) {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
+
+func StartIndex(page, pagesize int) int {
+	if page > 1 {
+		return (page - 1) * pagesize
+	}
+	return 0
+}
+func PageCount(count, pagesize int) int {
+	if count%pagesize > 0 {
+		return count/pagesize + 1
+	} else {
+		return count / pagesize
+	}
+}
+
+func TrimHtml(src string) string {
+	//将HTML标签全转换成小写
+	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
+	src = re.ReplaceAllStringFunc(src, strings.ToLower)
+
+	re, _ = regexp.Compile("\\<img[\\S\\s]+?\\>")
+	src = re.ReplaceAllString(src, "[图片]")
+
+	re, _ = regexp.Compile("class[\\S\\s]+?>")
+	src = re.ReplaceAllString(src, "")
+	re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
+	src = re.ReplaceAllString(src, "")
+	return strings.TrimSpace(src)
+}
+
+//1556164246  ->  2019-04-25 03:50:46 +0000
+//timestamp
+
+func TimeToTimestamp() {
+	fmt.Println(time.Unix(1556164246, 0).Format("2006-01-02 15:04:05"))
+}
+
+func ToUnicode(text string) string {
+	textQuoted := strconv.QuoteToASCII(text)
+	textUnquoted := textQuoted[1 : len(textQuoted)-1]
+	return textUnquoted
+}
+
+func VersionToInt(version string) int {
+	version = strings.Replace(version, ".", "", -1)
+	n, _ := strconv.Atoi(version)
+	return n
+}
+func IsCheckInList(list []int, s int) bool {
+	for _, v := range list {
+		if v == s {
+			return true
+		}
+	}
+	return false
+
+}
+
+func round(num float64) int {
+	return int(num + math.Copysign(0.5, num))
+}
+
+func toFixed(num float64, precision int) float64 {
+	output := math.Pow(10, float64(precision))
+	return float64(round(num*output)) / output
+}
+
+// GetWilsonScore returns Wilson Score
+func GetWilsonScore(p, n float64) float64 {
+	if p == 0 && n == 0 {
+		return 0
+	}
+
+	return toFixed(((p+1.9208)/(p+n)-1.96*math.Sqrt(p*n/(p+n)+0.9604)/(p+n))/(1+3.8416/(p+n)), 2)
+}
+
+//将中文数字转化成数字,比如 第三百四十五章,返回第345章 不支持一亿及以上
+func ChangeWordsToNum(str string) (numStr string) {
+	words := ([]rune)(str)
+	num := 0
+	n := 0
+	for i := 0; i < len(words); i++ {
+		word := string(words[i : i+1])
+		switch word {
+		case "万":
+			if n == 0 {
+				n = 1
+			}
+			n = n * 10000
+			num = num*10000 + n
+			n = 0
+		case "千":
+			if n == 0 {
+				n = 1
+			}
+			n = n * 1000
+			num += n
+			n = 0
+		case "百":
+			if n == 0 {
+				n = 1
+			}
+			n = n * 100
+			num += n
+			n = 0
+		case "十":
+			if n == 0 {
+				n = 1
+			}
+			n = n * 10
+			num += n
+			n = 0
+		case "一":
+			n += 1
+		case "二":
+			n += 2
+		case "三":
+			n += 3
+		case "四":
+			n += 4
+		case "五":
+			n += 5
+		case "六":
+			n += 6
+		case "七":
+			n += 7
+		case "八":
+			n += 8
+		case "九":
+			n += 9
+		case "零":
+		default:
+			if n > 0 {
+				num += n
+				n = 0
+			}
+			if num == 0 {
+				numStr += word
+			} else {
+				numStr += strconv.Itoa(num) + word
+				num = 0
+			}
+		}
+	}
+	if n > 0 {
+		num += n
+		n = 0
+	}
+	if num != 0 {
+		numStr += strconv.Itoa(num)
+	}
+	return
+}
+
+func Sha1(data string) string {
+	sha1 := sha1.New()
+	sha1.Write([]byte(data))
+	return hex.EncodeToString(sha1.Sum([]byte("")))
+}
+
+func GetVideoPlaySeconds(videoPath string) (playSeconds float64, err error) {
+	cmd := `ffmpeg -i ` + videoPath + `  2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//`
+	out, err := exec.Command("bash", "-c", cmd).Output()
+	if err != nil {
+		return
+	}
+	outTimes := string(out)
+	fmt.Println("outTimes:", outTimes)
+	if outTimes != "" {
+		timeArr := strings.Split(outTimes, ":")
+		h := timeArr[0]
+		m := timeArr[1]
+		s := timeArr[2]
+		hInt, err := strconv.Atoi(h)
+		if err != nil {
+			return playSeconds, err
+		}
+
+		mInt, err := strconv.Atoi(m)
+		if err != nil {
+			return playSeconds, err
+		}
+		s = strings.Trim(s, " ")
+		s = strings.Trim(s, "\n")
+		sInt, err := strconv.ParseFloat(s, 64)
+		if err != nil {
+			return playSeconds, err
+		}
+		playSeconds = float64(hInt)*3600 + float64(mInt)*60 + float64(sInt)
+	}
+	return
+}
+
+func GetMaxTradeCode(tradeCode string) (maxTradeCode string, err error) {
+	tradeCode = strings.Replace(tradeCode, "W", "", -1)
+	tradeCode = strings.Trim(tradeCode, " ")
+	tradeCodeInt, err := strconv.Atoi(tradeCode)
+	if err != nil {
+		return
+	}
+	tradeCodeInt = tradeCodeInt + 1
+	maxTradeCode = fmt.Sprintf("W%06d", tradeCodeInt)
+	return
+}
+
+// excel日期字段格式化 yyyy-mm-dd
+func ConvertToFormatDay(excelDaysString string) string {
+	// 2006-01-02 距离 1900-01-01的天数
+	baseDiffDay := 38719 //在网上工具计算的天数需要加2天,什么原因没弄清楚
+	curDiffDay := excelDaysString
+	b, _ := strconv.Atoi(curDiffDay)
+	// 获取excel的日期距离2006-01-02的天数
+	realDiffDay := b - baseDiffDay
+	//fmt.Println("realDiffDay:",realDiffDay)
+	// 距离2006-01-02 秒数
+	realDiffSecond := realDiffDay * 24 * 3600
+	//fmt.Println("realDiffSecond:",realDiffSecond)
+	// 2006-01-02 15:04:05距离1970-01-01 08:00:00的秒数 网上工具可查出
+	baseOriginSecond := 1136185445
+	resultTime := time.Unix(int64(baseOriginSecond+realDiffSecond), 0).Format("2006-01-02")
+	return resultTime
+}
+
+//字符串转换为time
+func StrTimeToTime(strTime string) time.Time {
+	timeLayout := "2006-01-02 15:04:05"  //转化所需模板
+	loc, _ := time.LoadLocation("Local") //重要:获取时区
+	resultTime, _ := time.ParseInLocation(timeLayout, strTime, loc)
+	return resultTime
+}
+
+//时间格式去掉时分秒
+func TimeRemoveHms(strTime string) string {
+	var Ymd string
+	var resultTime = StrTimeToTime(strTime)
+	year := resultTime.Year()
+	month := resultTime.Format("01")
+	day1 := resultTime.Day()
+	if day1 < 10 {
+		Ymd = strconv.Itoa(year) + "." + month + ".0" + strconv.Itoa(day1)
+	} else {
+		Ymd = strconv.Itoa(year) + "." + month + "." + strconv.Itoa(day1)
+	}
+	return Ymd
+}
+
+//判断时间是当年的第几周
+func WeekByDate(t time.Time) string {
+	var resultSAtr string
+	t = t.AddDate(0, 0, -8) // 减少八天跟老数据标题统一
+	yearDay := t.YearDay()
+	yearFirstDay := t.AddDate(0, 0, -yearDay+1)
+	firstDayInWeek := int(yearFirstDay.Weekday())
+	//今年第一周有几天
+	firstWeekDays := 1
+	if firstDayInWeek != 0 {
+		firstWeekDays = 7 - firstDayInWeek + 1
+	}
+	var week int
+	if yearDay <= firstWeekDays {
+		week = 1
+	} else {
+		week = (yearDay-firstWeekDays)/7 + 2
+	}
+	resultSAtr = "(" + strconv.Itoa(t.Year()) + "年第" + strconv.Itoa(week) + "周" + ")"
+	return resultSAtr
+}
+
+func Mp3Time(videoPlaySeconds string) string {
+	var d int
+	var timeStr string
+	a, _ := strconv.ParseFloat(videoPlaySeconds, 32)
+	b := int(a)
+	c := b % 60
+	d = b / 60
+	if b <= 60 {
+		timeStr = "00:" + strconv.Itoa(b)
+	} else {
+		if d < 10 {
+			timeStr = "0" + strconv.Itoa(d) + ":" + strconv.Itoa(c)
+		} else {
+			timeStr = strconv.Itoa(d) + ":" + strconv.Itoa(c)
+		}
+	}
+	return timeStr
+}
+
+func GetLocalIP() (ip string, err error) {
+	addrs, err := net.InterfaceAddrs()
+	if err != nil {
+		return
+	}
+	for _, addr := range addrs {
+		ipAddr, ok := addr.(*net.IPNet)
+		if !ok {
+			continue
+		}
+		if ipAddr.IP.IsLoopback() {
+			continue
+		}
+		if !ipAddr.IP.IsGlobalUnicast() {
+			continue
+		}
+		return ipAddr.IP.String(), nil
+	}
+	return
+}
+
+// GetOrmInReplace 获取orm的in查询替换?的方法
+func GetOrmInReplace(num int) string {
+	template := make([]string, num)
+	for i := 0; i < num; i++ {
+		template[i] = "?"
+	}
+	return strings.Join(template, ",")
+}

+ 81 - 0
utils/config.go

@@ -0,0 +1,81 @@
+package utils
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/server/web"
+	"github.com/rdlucklib/rdluck_tools/cache"
+)
+
+var (
+	RunMode           string //运行模式
+	MYSQL_URL         string //数据库连接
+	MYSQL_URL_RDDP    string //数据库连接
+	MYSQL_URL_TACTICS string
+
+	REDIS_CACHE string       //缓存地址
+	Rc          *cache.Cache //redis缓存
+	Re          error        //redis错误
+)
+
+//微信配置信息
+var (
+	WxId        string //微信原始ID
+	WxAppId     string //查研观向小程序
+	WxAppSecret string //查研观向小程序
+
+	WxPublicAppId     string //查研观向小助手公众号
+	WxPublicAppSecret string //查研观向小助手公众号
+	HeadimgurlDefault string //默认头像
+)
+
+func init() {
+	tmpRunMode, err := web.AppConfig.String("run_mode")
+	if err != nil {
+		panic("配置文件读取run_mode错误 " + err.Error())
+	}
+	RunMode = tmpRunMode
+	if RunMode == "" {
+		localIp, err := GetLocalIP()
+		fmt.Println("localIp:", localIp)
+		if localIp == "10.0.0.123" {
+			RunMode = "debug"
+		} else {
+			RunMode = "release"
+		}
+		configPath := `/home/code/config/hongze_clpt/conf/app.conf`
+		err = web.LoadAppConfig("ini", configPath)
+		if err != nil {
+			fmt.Println("web.LoadAppConfig Err:" + err.Error())
+		}
+	}
+	config, err := web.AppConfig.GetSection(RunMode)
+	if err != nil {
+		panic("配置文件读取错误 " + err.Error())
+	}
+	fmt.Println(RunMode + " 模式")
+	MYSQL_URL = config["mysql_url"]
+	MYSQL_URL_RDDP = config["mysql_url_rddp"]
+	MYSQL_URL_TACTICS = config["mysql_url_tactics"]
+
+	REDIS_CACHE = config["beego_cache"]
+	if len(REDIS_CACHE) <= 0 {
+		panic("redis链接参数没有配置")
+	}
+	Rc, Re = cache.NewCache(REDIS_CACHE) //初始化缓存
+	if Re != nil {
+		fmt.Println(Re)
+		panic(Re)
+	}
+	if RunMode == "release" {
+		WxPublicAppId = "wxb7cb8a15abad5b8e"                   //查研观向小助手
+		WxPublicAppSecret = "f425ba2863084249722af1e2a5cfffd3" //查研观向小助手
+	} else {
+		WxPublicAppId = "wx9b5d7291e581233a"                   //弘则投研公众号 开发者ID(AppID)
+		WxPublicAppSecret = "f4d52e34021eee262dce9682b31f8861" //弘则投研公众号秘钥
+	}
+	HeadimgurlDefault = "https://hongze.oss-cn-shanghai.aliyuncs.com/static/images/202202/20220225/XFBBOUmDC5AXkfxnHiuqKpPtoofH.png"
+}
+
+//http://webapi.brilliantstart.cn/api/
+//http://webapi.brilliantstart.cn/swagger/
+//http://139.196.122.219:8603/swagger/

+ 71 - 0
utils/constants.go

@@ -0,0 +1,71 @@
+package utils
+
+const (
+	Md5Key = "Ks@h64WJ#tcVgG8$&WlNfqvLAtMgpxWN"
+)
+
+//常量定义
+const (
+	FormatTime             = "15:04:05"                //时间格式
+	FormatDate             = "2006-01-02"              //日期格式
+	FormatDateTime         = "2006-01-02 15:04:05"     //完整时间格式
+	HlbFormatDateTime      = "2006-01-02_15:04:05.999" //完整时间格式
+	FormatDateTimeNoSecond = "2006-01-02 15:04"        //完整时间格式
+	FormatDateTimeUnSpace  = "20060102150405"          //完整时间格式
+	PageSize15             = 15                        //列表页每页数据量
+	PageSize5              = 5
+	PageSize10             = 10
+	PageSize20             = 20
+	PageSize30             = 30
+)
+
+const (
+	APPNAME          = "弘则-策略平台网页版"
+	EmailSendToUsers = "cxzhang@hzinsights.com"
+)
+
+//手机号,电子邮箱正则
+const (
+	RegularMobile         = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0-9])|(17[0-9])|(16[0-9])|(19[0-9]))\\d{8}$" //手机号码
+	RegularFixedTelephone = "^(\\(\\d{3,4}\\)|\\d{3,4}-|\\s)?\\d{7,14}$"                                              //手机号码
+	RegularEmail          = `\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`                                             //匹配电子邮箱
+)
+
+//聚合短信
+var (
+	JhGnTplId = "65692" //聚合国内模板编码
+	JhGjTplId = "10054" //聚合国内模板编码
+
+	JhGnAppKey = "4c8504c49dd335e99cfd7b6a3a9e2415" //聚合国内AppKey
+	JhGjAppKey = "3326ad2c1047a4cd92ace153e6044ca3"
+)
+
+//OSS
+var (
+	Endpoint   string = "oss-cn-shanghai.aliyuncs.com"
+	Bucketname string = "hongze"
+
+	Imghost          string = "https://hongze.oss-cn-shanghai.aliyuncs.com/"
+	Upload_dir       string = "static/images/"
+	Upload_Audio_Dir string = "static/audio/"
+	Upload_Pdf_Dir   string = "static/pdf/"
+
+	AccessKeyId     string = "LTAIFMZYQhS2BTvW"
+	AccessKeySecret string = "12kk1ptCHoGWedhBnKRVW5hRJzq9Fq"
+)
+
+const (
+	CE_LUE_NAME                      string = "策略"
+	CE_LUE_ID                        int    = 23
+	CHART_PERMISSION_NAME_YANXUAN    string = "研选"
+	CHART_PERMISSION_NAME_MF_YANXUAN string = "买方研选"
+	CHART_PERMISSION_ID_YANXUAN      int    = 31
+	YI_YAO_NAME                      string = "医药"
+	YI_YAO_ID                        int    = 22
+	XIAO_FEI_NAME                    string = "消费"
+	XIAO_FEI_ID                      int    = 21
+	KE_JI_NAME                       string = "科技"
+	KE_JI_ID                         int    = 20
+	ZHI_ZAO_NAME                     string = "智造"
+	ZHI_ZAO_ID                       int    = 19
+)

+ 127 - 0
utils/email.go

@@ -0,0 +1,127 @@
+package utils
+
+import (
+	"fmt"
+	"gopkg.in/gomail.v2"
+	"mime"
+	"strings"
+)
+
+//发送邮件
+func SendEmail(title, content string, touser string) bool {
+	if RunMode == "debug" {
+		return false
+	}
+	var arr []string
+	sub := strings.Index(touser, ";")
+	if sub >= 0 {
+		spArr := strings.Split(touser, ";")
+		for _, v := range spArr {
+			arr = append(arr, v)
+		}
+	} else {
+		arr = append(arr, touser)
+	}
+	m := gomail.NewMessage()
+	m.SetHeader("From", "317699326@qq.com ")
+	m.SetHeader("To", arr...)
+	m.SetHeader("Subject", title+" "+GetRandString(16))
+	m.SetBody("text/html", content)
+	d := gomail.NewDialer("smtp.qq.com", 587, "317699326@qq.com", "oqdypwfcvruwcbea")
+	if err := d.DialAndSend(m); err != nil {
+		return false
+	}
+	return true
+}
+
+//发送邮件
+func SendEmailByHz(title, content string, touser string) (result bool, err error) {
+	//if RunMode == "debug" {
+	//	result = false
+	//	return result, err
+	//}
+	var arr []string
+	sub := strings.Index(touser, ";")
+	if sub >= 0 {
+		spArr := strings.Split(touser, ";")
+		for _, v := range spArr {
+			arr = append(arr, v)
+		}
+	} else {
+		arr = append(arr, touser)
+	}
+	m := gomail.NewMessage()
+	m.SetHeader("From", "public@hzinsights.com")
+	m.SetHeader("To", arr...)
+	m.SetHeader("Subject", title)
+	m.SetBody("text/html", content)
+	d := gomail.NewDialer("smtp.mxhichina.com", 465, "public@hzinsights.com", "Hzinsights2018")
+	if err := d.DialAndSend(m); err != nil {
+		result = false
+		return result, err
+	}
+	result = true
+	return
+}
+
+//发送带有文件的邮件
+func SendEmailHaveFile(title, content string, fileName, touser string) bool {
+	var arr []string
+	sub := strings.Index(touser, ";")
+	if sub >= 0 {
+		spArr := strings.Split(touser, ";")
+		for _, v := range spArr {
+			arr = append(arr, v)
+		}
+	} else {
+		arr = append(arr, touser)
+	}
+	m := gomail.NewMessage()
+	m.SetHeader("From", "317699326@qq.com ")
+	m.SetHeader("To", arr...)
+	m.SetHeader("Subject", title)
+	m.Attach(fileName)
+	m.SetBody("text/html", content)
+	d := gomail.NewDialer("smtp.qq.com", 587, "317699326@qq.com", "oqdypwfcvruwcbea")
+	if err := d.DialAndSend(m); err != nil {
+		return false
+	}
+	return true
+}
+
+//发送邮件
+func SendEmailByHongze(title, content string, touser, attachPath, attachName string) bool {
+	var arr []string
+	sub := strings.Index(touser, ";")
+	if sub >= 0 {
+		spArr := strings.Split(touser, ";")
+		for _, v := range spArr {
+			arr = append(arr, v)
+		}
+	} else {
+		arr = append(arr, touser)
+	}
+	m := gomail.NewMessage()
+
+	m.SetHeader("From", "public@hzinsights.com")
+	m.SetHeader("To", arr...)
+	m.SetHeader("Subject", title)
+	m.SetBody("text/html", content)
+
+	//body := new(bytes.Buffer)
+	if attachPath != "" {
+		m.Attach(attachPath,
+			gomail.Rename(attachName),
+			gomail.SetHeader(map[string][]string{
+				"Content-Disposition": []string{
+					fmt.Sprintf(`attachment; filename="%s"`, mime.QEncoding.Encode("UTF-8", attachName)),
+				},
+			}))
+	}
+	d := gomail.NewDialer("smtp.mxhichina.com", 465, "public@hzinsights.com", "Hzinsights2018")
+	if err := d.DialAndSend(m); err != nil {
+		fmt.Println("send err:", err.Error())
+		return false
+	}
+	return true
+}

+ 45 - 0
utils/jwt.go

@@ -0,0 +1,45 @@
+package utils
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/beego/beego/v2/adapter/logs"
+	"github.com/dgrijalva/jwt-go"
+)
+
+var (
+	KEY = []byte("5Mb5Gdmb5x")
+)
+
+// 发放token
+func GenToken(account string) string {
+	token := jwt.New(jwt.SigningMethodHS256)
+	token.Claims = &jwt.StandardClaims{
+		NotBefore: int64(time.Now().Unix()),
+		ExpiresAt: int64(time.Now().Unix() + 90*24*60*60),
+		Issuer:    "hongze_clpt",
+		Subject:   account,
+	}
+	ss, err := token.SignedString(KEY)
+	if err != nil {
+		logs.Error(err)
+		return ""
+	}
+	return ss
+}
+
+// 校验token
+func CheckToken(account, token string) bool {
+	t, err := jwt.Parse(token, func(*jwt.Token) (interface{}, error) {
+		return KEY, nil
+	})
+	if err != nil {
+		fmt.Println(err.Error())
+		return false
+	}
+	if account != t.Claims.(jwt.MapClaims)["sub"] {
+		return false
+	}
+	return t.Valid
+}

+ 20 - 0
utils/logs.go

@@ -0,0 +1,20 @@
+package utils
+
+import (
+	"github.com/beego/beego/v2/adapter/logs"
+	"os"
+	"time"
+)
+
+var FileLog *logs.BeeLogger
+var BinLog *logs.BeeLogger
+
+func init() {
+	FileLog = logs.NewLogger(1000000)
+	FileLog.SetLogger(logs.AdapterFile, `{"filename":"./rdlucklog/hongze_clpt.log"}`)
+
+	binLogDir := `./binlog`
+	os.MkdirAll(binLogDir, os.ModePerm)
+	BinLog = logs.NewLogger(1000000)
+	BinLog.SetLogger(logs.AdapterMultiFile, `{"filename":"./binlog/binlog.`+time.Now().Format(FormatDate)+`.log","maxdays":30}`)
+}