Browse Source

init:初始化

Roc 3 years ago
parent
commit
ed026b1911

+ 12 - 0
.gitignore

@@ -0,0 +1,12 @@
+/hongze_open_api
+/lastupdate.tmp
+/swagger
+/binlog
+/rdlucklog
+/.idea
+.DS_Store
+/conf
+/tests
+go.mod
+go.sum
+routers/commentsRouter_controllers.go

+ 198 - 0
controllers/base_auth.go

@@ -0,0 +1,198 @@
+package controllers
+
+import (
+	"crypto/md5"
+	"errors"
+	"fmt"
+	"hongze/hongze_open_api/models/custom"
+	"hongze/hongze_open_api/models/tables/open_api_user"
+	"hongze/hongze_open_api/utils"
+	"math"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// BaseAuth 需要授权token的基类
+type BaseAuth struct {
+	BaseCommon
+	AdminWx *custom.AdminWx                  `description:"管理员信息"`
+	Token   string                           `description:"用户token"`
+
+	StartSize int	`description:"开始数量"`
+	StartPage int	`description:"开始页码"`
+	PageSize int	`description:"每页数量"`
+}
+
+func (c *BaseAuth) Prepare() {
+	//var requestBody string
+	signData := make(map[string]string)
+	method := c.Ctx.Input.Method()
+
+	var pageSize,currentIndex int
+	switch method {
+	case "GET":
+		//requestBody = c.Ctx.Request.RequestURI
+		params := c.Ctx.Request.URL.Query()
+		//fmt.Println(params)
+		signData = convertParam(params)
+
+		pageSize, _ = c.GetInt("_page_size")
+		currentIndex, _ = c.GetInt("_page")
+	case "POST":
+		//requestBody, _ = url.QueryUnescape(string(c.Ctx.Input.RequestBody))
+
+		//请求类型
+		contentType := c.Ctx.Request.Header.Get("content-type")
+		switch contentType {
+		case "multipart/form-data":
+			//文件最大5M
+			err := c.Ctx.Request.ParseMultipartForm(- int64(5<<20))
+			if err != nil{
+				c.FailWithMessage(fmt.Sprintf("获取参数失败,%v", err))
+				//response.FailWithMessage(fmt.Sprintf("获取参数失败,%v", err), c)
+				//c.Abort()
+				return
+			}
+		default:
+			err := c.Ctx.Request.ParseForm()
+			if err != nil{
+				c.FailWithMessage(fmt.Sprintf("获取参数失败,%v", err))
+				return
+			}
+		}
+		params := c.Ctx.Request.Form
+		signData = convertParam(params)
+	}
+
+	//页码数
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+	c.StartSize = startSize
+	c.PageSize = pageSize
+	c.StartPage = currentIndex
+
+
+	ip := c.Ctx.Input.IP()
+
+	//获取签名秘钥
+	//key := global.GVA_CONFIG.SignKey.Agent
+	////签名校验
+	err := checkSign(signData,ip)
+	if err != nil {
+		c.SignError(fmt.Sprintf("签名校验失败,%v", err))
+		return
+	}
+	uri := c.Ctx.Input.URI()
+	utils.FileLog.Info(fmt.Sprintf("URI:%s", uri))
+}
+
+//将请求传入的数据格式转换成签名需要的格式
+func convertParam(params map[string][]string)(signData map[string]string)  {
+	signData = make(map[string]string)
+	for key := range params {
+		signData[key] = params[key][0]
+	}
+	return signData
+}
+
+
+//请求参数签名校验
+func checkSign(postData map[string]string,ip string) (err error){
+	isSandbox := postData["is_sandbox"]
+	//如果是测试环境,且是沙箱环境的话,那么绕过测试
+	if utils.RunMode == "debug" && isSandbox != "" {
+		return
+	}
+
+	appid :=postData["appid"]
+	if appid == "" {
+		err = errors.New("参数异常,缺少appid")
+		return
+	}
+	openApiUserInfo,tmpErr:= open_api_user.GetByAppid(appid)
+	if tmpErr != nil{
+		if tmpErr.Error() == utils.ErrNoRow(){
+			err = errors.New("appid异常,请联系管理员")
+		}else{
+			err = errors.New("系统异常,请联系管理员")
+		}
+		return
+	}
+
+	if openApiUserInfo == nil{
+		err = errors.New("系统异常,请联系管理员")
+		return
+	}
+	//如果有ip限制,那么就添加ip
+	if openApiUserInfo.Ip != ""{
+		if !strings.Contains(openApiUserInfo.Ip,ip){
+			err = errors.New(fmt.Sprintf("无权限访问该接口,ip:%v,请联系管理员",ip))
+			return
+		}
+	}
+
+	//接口提交的签名字符串
+	ownSign := postData["sign"]
+	if ownSign == "" {
+		err = errors.New("参数异常,缺少签名字符串")
+		return
+	}
+	if postData["nonce_str"] == "" {
+		err = errors.New("参数异常,缺少随机字符串")
+		return
+	}
+	if postData["timestamp"] == "" {
+		err = errors.New("参数异常,缺少时间戳")
+		return
+	}else{
+		timeUnix := time.Now().Unix()	//当前格林威治时间,int64类型
+		//将接口传入的时间做转换
+		timestamp, timeErr := strconv.ParseInt(postData["timestamp"], 10, 64)
+		if timeErr != nil{
+			err = errors.New("参数异常,时间戳格式异常")
+			return
+		}
+		if math.Abs(float64(timeUnix - timestamp)) > 300 {
+			err = errors.New("当前时间异常,请调整设备时间与北京时间一致")
+			return
+		}
+	}
+
+	//先取出除sign外的所有的提交的参数key
+	var keys []string
+	for k, _ := range postData {
+		if k != "sign" {
+			keys = append(keys, k)
+		}
+	}
+
+	//1,根据参数名称的ASCII码表的顺序排序
+	sort.Strings(keys)
+
+	//2 根据排序后的参数名称,取出对应的值,并拼接字符串
+	var signStr string
+	for _, v := range keys {
+		signStr += v + "=" + postData[v] + "&"
+	}
+	//3,全转小写(md5(拼装的字符串后+分配给你的app_secret))
+	//sign := strings.ToLower(fmt.Sprintf("%x", md5.Sum([]byte(strings.Trim(signStr, "&")+key))))
+
+
+	//md5.Sum([]byte(signStr+"key="+key))  这是md5加密出来后的每个字符的ascall码,需要再转换成对应的字符
+	//3,全转大写(md5(拼装的字符串后+分配给你的app_secret))
+	sign := strings.ToUpper(fmt.Sprintf("%x", md5.Sum([]byte(signStr+"secret="+openApiUserInfo.Secret))))
+
+	if sign != ownSign {
+		utils.ApiLog.Println(fmt.Sprintf("签名校验异常,签名字符串:%v;服务端签名值:%v",signStr,sign))
+		return errors.New("签名校验异常,请核实签名")
+	}
+	return nil
+}

+ 103 - 0
controllers/base_common.go

@@ -0,0 +1,103 @@
+package controllers
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/beego/beego/v2/server/web"
+	"hongze/hongze_open_api/utils"
+	"net/url"
+)
+
+//不需要授权的基类
+type BaseCommon struct {
+	web.Controller
+	Response
+}
+
+type Response struct {
+	Code   int         `json:"code"`
+	Data   interface{} `json:"data"`
+	Msg    string      `json:"msg"`
+}
+
+const (
+	SUCCESS     = 200 //成功
+	ERROR       = 400 //代表业务处理失败,前端同学需要做额外逻辑处理
+	SIGN_ERROR  = 401   //签名异常
+)
+
+//返回数据
+func (c BaseCommon) Result() {
+	var content []byte
+	var err error
+	content, err = json.Marshal(c.Response)
+	ip := c.Ctx.Input.IP()
+	requestBody, err := url.QueryUnescape(string(c.Ctx.Input.RequestBody))
+	if err != nil {
+		fmt.Println("base auth url.QueryUnescape Err:", err.Error())
+		requestBody = string(c.Ctx.Input.RequestBody)
+	}
+	utils.ApiLog.Println("请求地址:", c.Ctx.Input.URI(), "RequestBody:", requestBody, "ResponseBody", string(content), "IP:", ip)
+
+	c.Controller.Data["json"] = c.Response
+	c.Controller.ServeJSON()
+	c.StopRun()
+}
+
+//没有任何信息的返回
+func (c BaseCommon) Ok() {
+	c.Response.Code = SUCCESS
+	c.Response.Msg = "操作成功"
+	c.Response.Data = map[string]interface{}{}
+	c.Result()
+}
+
+func (c BaseCommon) OkWithMessage(message string) {
+	c.Response.Code = SUCCESS
+	c.Response.Msg = message
+	c.Response.Data = map[string]interface{}{}
+	c.Result()
+}
+
+func (c BaseCommon) OkWithData(data interface{}) {
+	c.Response.Code = SUCCESS
+	c.Response.Msg = "操作成功"
+	c.Response.Data = data
+	c.Result()
+}
+
+func (c BaseCommon) OkDetailed(data interface{}, message string) {
+	c.Response.Code = SUCCESS
+	c.Response.Msg = message
+	c.Response.Data = data
+	c.Result()
+}
+
+func (c BaseCommon) Fail() {
+	c.Response.Code = ERROR
+	c.Response.Msg = "操作失败"
+	c.Response.Data = map[string]interface{}{}
+	c.Result()
+}
+
+func (c BaseCommon) FailWithMessage(message string) {
+	c.Response.Code = ERROR
+	c.Response.Msg = message
+	c.Response.Data = map[string]interface{}{}
+	c.Result()
+}
+
+func (c BaseCommon) FailWithDetailed(code int, data interface{}, message string) {
+	c.Response.Code = code
+	c.Response.Msg = message
+	c.Response.Data = data
+	c.Result()
+}
+
+// SignError 签名异常
+func (c BaseCommon) SignError(message string) {
+	c.Response.Code = SIGN_ERROR
+	c.Response.Msg = message
+	c.Response.Data = map[string]interface{}{}
+	c.Result()
+}

+ 192 - 0
controllers/company_user.go

@@ -0,0 +1,192 @@
+package controllers
+
+import (
+	"hongze/hongze_open_api/models/response/company_user"
+	"hongze/hongze_open_api/models/tables"
+	"hongze/hongze_open_api/models/tables/wx_user"
+	"hongze/hongze_open_api/utils"
+	"strconv"
+	"time"
+)
+
+// CompanyUser
+// 客户联系人模块
+type CompanyUser struct {
+	BaseAuth
+}
+
+// GetUserReportList
+// @Title 获取用户阅读数据报表
+// @Description 获取用户阅读数据报表
+// @Param   start_date   query   string  true       "开始日期,格式:2021-11-03"
+// @Param   end_date   query   string  true       "结束日期,格式:2021-11-04"
+// @Param   mobile   query   string  false       "用户手机号"
+// @Param   email   query   string  false       "用户邮箱"
+// @Success 200 {object} company_user.UserReportListResp
+// @router /user_report_list [get]
+func (c *CompanyUser) GetUserReportList()  {
+	mobile:=c.GetString("mobile","")
+	email:=c.GetString("email","")
+	startDate:=c.GetString("start_date","")
+	endDate:=c.GetString("end_date","")
+	if startDate == ""{
+		c.FailWithMessage("start_date必传")
+		return
+	}
+	if endDate == ""{
+		c.FailWithMessage("end_date必传")
+		return
+	}
+	startDateTime,err := time.Parse(utils.FormatDate,startDate)
+	if err != nil{
+		c.FailWithMessage("start_date格式异常")
+		return
+	}
+	endDateTime,err := time.Parse(utils.FormatDate,endDate)
+	if err != nil{
+		c.FailWithMessage("end_date格式异常")
+		return
+	}
+
+	pageSize := c.PageSize
+	startSize := c.StartSize
+	currentIndex := c.StartPage
+
+
+
+	total,list, err := tables.GetViewReportList(mobile,email,startDateTime.Format(utils.FormatDate)+" 00:00:00",endDateTime.Format(utils.FormatDate)+" 23:59:59",startSize,pageSize)
+	if err != nil {
+		c.FailWithMessage("获取失败")
+		return
+	}
+
+	for k, v := range list {
+		if v.ReportType == "day" {
+			list[k].MatchTypeName = "晨报"
+		} else if v.ReportType == "week" {
+			list[k].MatchTypeName = "周报"
+		} else if v.ReportType == "two_week" {
+			list[k].MatchTypeName = "双周报"
+		} else if v.ReportType == "month" {
+			list[k].MatchTypeName = "月报"
+		} else if v.ReportType == "rddp" {
+			//list[k].MatchTypeName = "日评"
+			createdTime := utils.StrTimeToTime(v.CreatedTime)
+			monthStr := createdTime.Format("01")
+			dayStr := strconv.Itoa(createdTime.Day())
+			if len(dayStr) == 1 {
+				dayStr = "0" + dayStr
+			}
+			list[k].ResearchReportName += "(" + monthStr + dayStr + ")"
+		}
+		if v.StopTime != "--" {
+			list[k].StopTime += "s"
+		}
+		//v.CompanyName = wxUserInfo.CompanyName
+		//v.UserName = wxUserInfo.RealName
+		//v.Mobile = wxUserInfo.Mobile
+	}
+	page := utils.GetPaging(currentIndex, pageSize, total)
+
+	resp := company_user.UserReportListResp{
+		List: list,
+		Paging: page,
+	}
+	c.OkDetailed(resp,"获取成功")
+}
+
+// GetUserReportListV2
+// @Title 获取用户阅读数据报表
+// @Description 合同详情接口
+// @Param   mobile   query   string  false       "用户手机号"
+// @Param   email   query   string  false       "用户邮箱"
+// @Success 200 {object} company_user.UserReportListResp
+
+func (c *CompanyUser) GetUserReportListV2()  {
+	mobile:=c.GetString("mobile","")
+	startDate:=c.GetString("start_date","")
+	endDate:=c.GetString("end_date","")
+	if startDate == ""{
+		c.FailWithMessage("start_date必传")
+		return
+	}
+	if endDate == ""{
+		c.FailWithMessage("end_date必传")
+		return
+	}
+	startDateTime,err := time.Parse(utils.FormatDate,startDate)
+	if err != nil{
+		c.FailWithMessage("start_date格式异常")
+		return
+	}
+	endDateTime,err := time.Parse(utils.FormatDate,endDate)
+	if err != nil{
+		c.FailWithMessage("end_date格式异常")
+		return
+	}
+	var wxUserInfo *wx_user.WxUserItem
+	if mobile!=""{
+		item, err :=  wx_user.GetWxUserByMobile(mobile)
+		if err != nil {
+			c.FailWithMessage("找不到该用户")
+			return
+		}
+		wxUserInfo = item
+	}
+
+	email:=c.GetString("email","")
+	if wxUserInfo == nil && email!=""{
+		item, err :=  wx_user.GetWxUserByEmail(email)
+		if err != nil {
+			c.FailWithMessage("找不到该用户")
+			return
+		}
+		wxUserInfo = item
+	}
+	if wxUserInfo == nil{
+		c.FailWithMessage("找不该用户")
+	}
+
+	pageSize := c.PageSize
+	startSize := c.StartSize
+	currentIndex := c.StartPage
+
+	total,list, err := tables.GetViewReportList(wxUserInfo.Mobile,wxUserInfo.Email,startDateTime.Format(utils.FormatDate)+" 00:00:00",endDateTime.Format(utils.FormatDate)+" 23:59:59",startSize,pageSize)
+	if err != nil {
+			c.FailWithMessage("获取失败")
+			return
+		}
+
+	for k, v := range list {
+		if v.ReportType == "day" {
+			list[k].MatchTypeName = "晨报"
+		} else if v.ReportType == "week" {
+			list[k].MatchTypeName = "周报"
+		} else if v.ReportType == "two_week" {
+			list[k].MatchTypeName = "双周报"
+		} else if v.ReportType == "month" {
+			list[k].MatchTypeName = "月报"
+		} else if v.ReportType == "rddp" {
+			//list[k].MatchTypeName = "日评"
+			createdTime := utils.StrTimeToTime(v.CreatedTime)
+			monthStr := createdTime.Format("01")
+			dayStr := strconv.Itoa(createdTime.Day())
+			if len(dayStr) == 1 {
+				dayStr = "0" + dayStr
+			}
+			list[k].ResearchReportName += "(" + monthStr + dayStr + ")"
+		}
+		if v.StopTime != "--" {
+			list[k].StopTime += "s"
+		}
+		v.CompanyName = wxUserInfo.CompanyName
+		v.Mobile = wxUserInfo.Mobile
+	}
+	page := utils.GetPaging(currentIndex, pageSize, total)
+
+	resp := company_user.UserReportListResp{
+		List: list,
+		Paging: page,
+	}
+	c.OkDetailed(resp,"获取成功")
+}

+ 54 - 0
controllers/tmp/company.go

@@ -0,0 +1,54 @@
+package tmp
+
+//万一以后用到了呢,文件保留吧
+
+//
+//import (
+//	companyResp "hongze/hongze_open_api/models/response/company"
+//	"hongze/hongze_open_api/models/tables/company"
+//	"hongze/hongze_open_api/utils"
+//)
+//
+//// Company 客户模块
+//type Company struct {
+//	BaseAuth
+//}
+//
+//// GetList
+//// @Title 获取客户数据报表
+//// @Description 客户数据接口
+//// @Param   company_name   query   string  true       "客户名称,模糊匹配"
+//// @Param   credit_code   query   string  true       "客户组织社会信用码,全等匹配"
+//// @Success 200 {object} company.CompanyListResp
+//func (c *Company) GetList()  {
+//	pageSize := c.PageSize
+//	startSize := c.StartSize
+//	currentIndex := c.StartPage
+//
+//	var condition string
+//	var pars []interface{}
+//	//客户名称
+//	companyName := c.GetString("company_name")
+//	if companyName!=""{
+//		condition += ` a.company_name like "%`+companyName+`" `
+//	}
+//	//组织社会信用码
+//	creditCode := c.GetString("credit_code")
+//	if creditCode!=""{
+//		condition += ` a.credit_code = ? `
+//		pars = append(pars,creditCode)
+//	}
+//
+//	total, list,err := company.GetList(condition,pars,startSize,pageSize)
+//	if err != nil {
+//		c.FailWithMessage("获取失败")
+//		return
+//	}
+//
+//	page := utils.GetPaging(currentIndex, pageSize, total)
+//	resp := companyResp.CompanyListResp{
+//		List: list,
+//		Paging: page,
+//	}
+//	c.OkDetailed(resp,"获取成功")
+//}

+ 58 - 0
main.go

@@ -0,0 +1,58 @@
+package main
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/adapter/logs"
+	"github.com/beego/beego/v2/server/web/context"
+	"hongze/hongze_open_api/models"
+	_ "hongze/hongze_open_api/routers"
+	"hongze/hongze_open_api/utils"
+	"runtime"
+	"time"
+
+	"github.com/beego/beego/v2/server/web"
+)
+
+func main() {
+	if web.BConfig.RunMode == "dev" {
+		web.BConfig.WebConfig.DirectoryIndex = true
+		web.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
+	}
+
+	web.BConfig.RecoverFunc = Recover
+	//数据库初始化
+	models.InitDb()
+	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
+}

+ 38 - 0
models/custom/admin.go

@@ -0,0 +1,38 @@
+package custom
+
+//管理员账户信息结构体(包含微信信息)
+type AdminWx struct {
+	AdminId                 int    `json:"admin_id"`
+	AdminName               string `json:"admin_name"`
+	RealName                string `json:"real_name"`
+	Password                string `json:"password"`
+	LastUpdatedPasswordTime string `json:"last_updated_password_time"`
+	Enabled                 int    `json:"enabled"` // 1:有效,0:禁用
+	Email                   string `json:"email"`
+	LastLoginTime           string `json:"last_login_time"` // 最近登陆时间
+	CreatedTime             string `json:"created_time"`    // 创建时间
+	LastUpdatedTime         string `json:"last_updated_time"`
+	Role                    string `json:"role"`            // 用户角色
+	Mobile                  string `json:"mobile"`          // 手机号
+	RoleType                int    `json:"role_type"`       // 角色类型:1需要录入指标,0:不需要
+	RoleId                  int    `json:"role_id"`         // 角色id
+	RoleName                string `json:"role_name"`       // 角色名称
+	RoleTypeCode            string `json:"role_type_code"`  // 角色编码
+	DepartmentId            int    `json:"department_id"`   // 部门id
+	DepartmentName          string `json:"department_name"` // 部门名称
+	GroupId                 int    `json:"group_id"`        // 分组id
+	GroupName               string `json:"group_name"`      // 分组名称
+	Authority               int    `json:"authority"`       // 管理权限,0:无,1:部门负责人,2:小组负责人,3:超级管理员
+	Position                string `json:"position"`        // 职位
+
+	OpenId      string `json:"open_id"` // open_id
+	UnionId     string `json:"union_id"`
+	Subscribe   int    `json:"subscribe"`    // 是否关注
+	NickName    string `json:"nick_name"`    // 用户昵称
+	BindAccount string `json:"bind_account"` // 绑定时的账号
+	Sex         int    `json:"sex"`          // 普通用户性别,1为男性,2为女性
+	Province    string `json:"province"`     // 普通用户个人资料填写的省份
+	City        string `json:"city"`         // 普通用户个人资料填写的城市
+	Country     string `json:"country"`      // 国家,如中国为CN
+	Headimgurl  string `json:"headimgurl"`
+}

+ 40 - 0
models/custom/contract/contract_service.go

@@ -0,0 +1,40 @@
+package contract
+
+import (
+	"hongze/hongze_open_api/models/tables/contract_service_detail"
+	"rdluck_tools/orm"
+	"time"
+)
+
+//合同的服务内容
+type ContractService struct {
+	ContractServiceId int       `orm:"column(contract_service_id);pk"`
+	ContractId        int       `description:"合同id"`
+	ProductId         int       `description:"产品id,1:ficc;2:权益"`
+	ServiceTemplateId int       `description:"合同服务模板id"`
+	Title             string    `description:"套餐名称"`
+	Value             string    `description:"套餐的值"`
+	HasDetail         string    `description:"是否有详情,枚举值:是、否;默认:否"`
+	CreateTime        time.Time `description:"合同添加时间"`
+}
+
+//合同的服务内容
+type ContractServiceAndDetail struct {
+	ContractServiceId int    `orm:"column(contract_service_id);pk"`
+	ContractId        int    `description:"合同id"`
+	ProductId         int    `description:"产品id,1:ficc;2:权益"`
+	ServiceTemplateId int    `description:"合同服务模板id"`
+	Title             string `description:"套餐标题"`
+	Value             string `description:"套餐的值"`
+	HasDetail         string `description:"是否有详情,枚举值:是、否;默认:否"`
+	ChartPermissionId int    `description:"权限id"`
+	DetailList        []*contract_service_detail.ContractServiceDetail
+}
+
+//获取合同列表数据
+func GetContractServiceAndDetailList(contractId int) (list []*ContractServiceAndDetail, err error) {
+	o := orm.NewOrm()
+	sql := "select * from contract_service where contract_id = ?  "
+	_, err = o.Raw(sql, contractId).QueryRows(&list)
+	return
+}

+ 25 - 0
models/custom/wechat.go

@@ -0,0 +1,25 @@
+package custom
+
+import "rdluck_tools/orm"
+
+type WechatSign struct {
+	AppId     string
+	NonceStr  string
+	Timestamp int64
+	Url       string
+	Signature string
+	RawString string
+}
+
+type WxTicket struct {
+	Errcode int    `json:"errcode"`
+	Errmsg  string `json:"errmsg"`
+	Ticket  string `json:"ticket"`
+}
+
+func ModifyWxUserInfo(nickName, headimgUrl, city, province, country string, sex, userId int) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE wx_user SET nick_name=?,headimgurl=?,sex=?,city=?,province=?,country=? WHERE user_id=? `
+	_, err = o.Raw(sql, nickName, headimgUrl, sex, city, province, country, userId).Exec()
+	return
+}

+ 34 - 0
models/db_init.go

@@ -0,0 +1,34 @@
+package models
+
+import (
+	_ "github.com/go-sql-driver/mysql"
+	"hongze/hongze_open_api/models/tables/open_api_user"
+	"hongze/hongze_open_api/utils"
+	"rdluck_tools/orm"
+	"time"
+)
+
+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)
+
+	//rddp数据库
+	_ = orm.RegisterDataBase("rddp", "mysql", utils.MYSQL_URL_RDDP)
+	orm.SetMaxIdleConns("rddp", 50)
+	orm.SetMaxOpenConns("rddp", 100)
+
+	report_db, _ := orm.GetDB("rddp")
+	report_db.SetConnMaxLifetime(10 * time.Minute)
+
+	//注册对象
+	orm.RegisterModel(
+		new(open_api_user.OpenApiUser), //开放API用户表
+	)
+
+}
+
+func InitDb() {}

+ 6 - 0
models/request/admin/admin.go

@@ -0,0 +1,6 @@
+package admin
+
+type LoginReq struct {
+	Username string `description:"账号"`
+	Password string `description:"密码"`
+}

+ 12 - 0
models/response/company/company.go

@@ -0,0 +1,12 @@
+package company
+
+import (
+	"hongze/hongze_open_api/models/tables/company"
+	"hongze/hongze_open_api/utils"
+)
+
+// CompanyListResp 客户列表列表返回结构体
+type CompanyListResp struct {
+	Paging *utils.PagingItem `description:"分页数据" json:"paging"`
+	List   []*company.CompanyList `description:"数据列表" json:"list"`
+}

+ 12 - 0
models/response/company_user/user_report.go

@@ -0,0 +1,12 @@
+package company_user
+
+import (
+	"hongze/hongze_open_api/models/tables"
+	"hongze/hongze_open_api/utils"
+)
+
+// UserReportListResp 用户阅读数据列表返回结构体
+type UserReportListResp struct {
+	Paging *utils.PagingItem `description:"分页数据" json:"paging"`
+	List   []*tables.ViewReportList `description:"数据列表" json:"list"`
+}

+ 16 - 0
models/response/wechat/wechat.go

@@ -0,0 +1,16 @@
+package wechat
+
+import (
+	"hongze/hongze_open_api/models/response/admin"
+	"time"
+)
+
+type WxLoginResp struct {
+	Code          int
+	Authorization string
+	AdminId       int
+	Expires       time.Time
+	Headimgurl    string          `description:"用户头像"`
+	RealName      string          `description:"用户名称"`
+	UserInfo      admin.LoginResp `description:"用户信息"`
+}

+ 65 - 0
models/tables/company/company.go

@@ -0,0 +1,65 @@
+package company
+
+import (
+	"rdluck_tools/orm"
+	"time"
+)
+
+type Company struct {
+	CompanyId       int       `orm:"column(company_id);pk"`
+	CompanyName     string    `description:"客户名称"`
+	CompanyType     int       `orm:"column(type)"`
+	CreditCode      string    `description:"社会统一信用码"`
+	CompanyCode     string    `description:"客户编码"`
+	Sort            int       `description:"优先级"`
+	IsFeeCustomer   int       `description:"是否付费用户"`
+	Country         string    `description:"国家编码"`
+	Province        string    `description:"省"`
+	City            string    `description:"市"`
+	Address         string    `description:"详细地址"`
+	Enabled         int       `description:"用户状态"`
+	CreatedTime     time.Time `description:"创建时间"`
+	LastUpdatedTime time.Time `description:"最后一次阅读时间"`
+	Seller          string    `description:"销售员"`
+	SellsId         int       `description:"销售员id"`
+	CompanyBelong   string    `description:"客户所属,ficc:ficc客户,public_offering:公募客户,partner:合作伙伴"`
+	StartDate       string    `description:"合同开始日期"`
+	EndDate         string    `description:"合同结束日期"`
+	LastType        int       `description:"原客户标签"`
+	IsVip           int       `description:"0:普通用户,1:大客户"`
+	FirstStartDate  string    `description:"首次设置为试用客户开始时间"`
+	FirstEndDate    string    `description:"首次设置为试用客户结束时间"`
+	DateType        int       `description:"设置流失类型,1:1个月,2:2个月,3:3个月"`
+	Remark          string    `description:"备注信息"`
+	RegionType      string    `description:"地区类型,国内,国外"`
+}
+
+type CompanyList struct {
+	CompanyId       int       `description:"客户id" json:"company_id"`
+	CompanyName     string    `description:"客户名称" json:"company_name"`
+	CreditCode      string    `description:"社会统一信用码" json:"credit_code"`
+	Status      string    `description:"客户状态" json:"status"`
+}
+
+// GetList 获取客户列表
+func GetList(condition string,pars []interface{},startSize, pageSize  int) (total int,list []*CompanyList,err error){
+	o := orm.NewOrm()
+	sql := `SELECT a.company_id,a.company_name,a.credit_code,b.status
+			FROM company AS a
+			INNER JOIN company_product AS b ON a.company_id=b.company_id
+			WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` GROUP BY a.company_id ORDER BY  a.last_updated_time DESC `
+
+	totalSql := `select count(*) count from (`+sql+`) g`
+
+	err = o.Raw(totalSql, pars).QueryRow(&total)
+	if err != nil{
+		return
+	}
+	sql += ` limit ?,?`
+	_, err = o.Raw(sql, pars,startSize,pageSize).QueryRows(&list)
+	return
+}

+ 413 - 0
models/tables/company_user.go

@@ -0,0 +1,413 @@
+package tables
+
+import (
+	"fmt"
+	"hongze/hongze_open_api/utils"
+	"rdluck_tools/orm"
+)
+
+type ViewReportList struct {
+	CompanyName string `description:"公司名称" json:"company_name"`
+	RealName string `description:"用户名称" json:"user_name"`
+	Mobile string `description:"手机号" json:"mobile"`
+	Email string `description:"邮箱" json:"email"`
+	ResearchReportName string `description:"报告标题" json:"report_name"`
+	CreatedTime        string `description:"创建时间" json:"created_time"`
+	ReportType         string `description:"报告类型 'day 晨报'、'week 周报'、'twoweek 双周报'、'month 月报'、'rddp 日度点评'、'cygx 查研观向'、'advisory 每日商品聚焦'" json:"-"`
+	TxtType            string `description:"类型 ficc:ficc  、 rights:权益"  json:"-"`
+	MatchTypeName      string `description:"匹配类型"  json:"-"`
+	StopTime           string `description:"停留时间" json:"-"`
+}
+
+type ViewReportListResp struct {
+	Total int `description:"数量"`
+	List  []*ViewReportList
+}
+
+func GetViewReportListByMobile(mobile string, txtType int) (items []*ViewReportList, err error) {
+	dataName := ""
+	sql := ``
+	if utils.RunMode == "debug" {
+		dataName = "test_v2_hongze_rddp"
+	} else {
+		dataName = "hongze_rddp"
+	}
+
+	ficcSql := `SELECT
+	rr.research_report_name,
+		rr.type AS report_type,
+		'ficc' AS txt_type,
+		'--' AS match_type_name,
+		'--' AS stop_time,
+	uvh.created_time AS created_time
+	FROM
+	user_view_history uvh
+	LEFT JOIN research_report rr ON rr.research_report_id = uvh.research_report_id
+	WHERE
+	uvh.mobile = ?
+	UNION ALL
+	SELECT
+	r.title AS research_report_name,
+		'rddp' AS report_type,
+		'ficc' AS txt_type,
+		r.classify_name_first AS match_type_name,
+		'--' AS stop_time,
+		rvr.create_time AS created_time
+	FROM %s.report_view_record rvr
+	LEFT JOIN %s.report r ON r.id = rvr.report_id
+	WHERE
+	rvr.mobile=?
+	UNION ALL
+	SELECT
+	cha.permission_name AS research_report_name,
+		'advisory' AS report_type,
+		'ficc' AS txt_type,
+		cha.classify_name AS match_type_name,
+		'--' AS stop_time,
+		auc.create_time AS created_time
+	FROM
+	advisory_user_chart_article_record auc
+	LEFT JOIN chart_permission cha ON cha.chart_permission_id = auc.chart_permission_id
+	WHERE
+	auc.mobile = ?`
+
+	rightsSql := `SELECT
+		art.title AS research_report_name,
+		'cygx' AS report_type,
+		'rights' AS txt_type,
+		art.match_type_name,
+		h.stop_time,
+		h.create_time AS created_time 
+	FROM
+		cygx_article_history_record h
+		LEFT JOIN cygx_article art ON art.article_id = h.article_id
+	WHERE
+		h.mobile = ? `
+
+	if txtType == 1 {
+		sql = ` SELECT * FROM ( ` + rightsSql + `
+	      )AS t ORDER BY t.created_time DESC`
+	} else if txtType == 2 {
+		sql = ` SELECT * FROM ( ` + ficcSql + `
+	      )AS t ORDER BY t.created_time DESC`
+	} else {
+		sql = ` SELECT * FROM ( ` + ficcSql + " UNION ALL " + rightsSql + `
+	      )AS t ORDER BY t.created_time DESC`
+	}
+
+	//报告统计删除晨报部分统计加入每日资讯 2021-4-9
+	//sql := ` SELECT * FROM (
+	//					SELECT
+	//							r.title AS research_report_name,
+	//							'rddp' AS report_type,
+	//							rvr.create_time AS created_time
+	//						FROM %s.report_view_record rvr
+	//						INNER JOIN %s.report r ON r.id = rvr.report_id
+	//						WHERE
+	//							rvr.mobile=?
+	//					UNION ALL
+	//					SELECT
+	//					cha.permission_name AS research_report_name,
+	//					'advisory' AS report_type,
+	//					auc.create_time AS created_time
+	//				FROM
+	//					advisory_user_chart_article_record auc
+	//					INNER JOIN chart_permission cha ON cha.chart_permission_id = auc.chart_permission_id
+	//				WHERE
+	//					auc.mobile = ?
+	//       )AS t ORDER BY t.created_time DESC
+	//    `
+
+	o := orm.NewOrm()
+
+	if txtType == 1 {
+		_, err = o.Raw(sql, mobile).QueryRows(&items)
+	} else if txtType == 2 {
+		sql = fmt.Sprintf(sql, dataName, dataName)
+		_, err = o.Raw(sql, mobile, mobile, mobile).QueryRows(&items)
+	} else {
+		sql = fmt.Sprintf(sql, dataName, dataName)
+		_, err = o.Raw(sql, mobile, mobile, mobile, mobile).QueryRows(&items)
+	}
+
+	return
+}
+
+func GetViewReportListByEmail2(email string, txtType int) (items []*ViewReportList, err error) {
+	dataName := ""
+	sql := ``
+	if utils.RunMode == "debug" {
+		dataName = "test_hongze_rddp"
+	} else {
+		dataName = "hongze_rddp"
+	}
+
+	ficcSql := `SELECT
+	rr.research_report_name,
+		rr.type AS report_type,
+		'ficc' AS txt_type,
+		'--' AS match_type_name,
+		'--' AS stop_time,
+	uvh.created_time AS created_time
+	FROM
+	user_view_history uvh
+	INNER JOIN research_report rr ON rr.research_report_id = uvh.research_report_id
+	WHERE
+	uvh.email = ?
+	UNION ALL
+	SELECT
+	r.title AS research_report_name,
+		'rddp' AS report_type,
+		'ficc' AS txt_type,
+		r.classify_name_first AS match_type_name,
+		'--' AS stop_time,
+		rvr.create_time AS created_time
+	FROM %s.report_view_record rvr
+	INNER JOIN %s.report r ON r.id = rvr.report_id
+	WHERE
+	rvr.email=?
+	UNION ALL
+	SELECT
+	cha.permission_name AS research_report_name,
+		'advisory' AS report_type,
+		'ficc' AS txt_type,
+		cha.classify_name AS match_type_name,
+		'--' AS stop_time,
+		auc.create_time AS created_time
+	FROM
+	advisory_user_chart_article_record auc
+	INNER JOIN chart_permission cha ON cha.chart_permission_id = auc.chart_permission_id
+	WHERE
+	auc.email = ?`
+
+	rightsSql := `SELECT
+		art.title AS research_report_name,
+		'cygx' AS report_type,
+		'rights' AS txt_type,
+		art.match_type_name,
+		h.stop_time,
+		h.create_time AS created_time 
+	FROM
+		cygx_article_history_record h
+		INNER JOIN cygx_article art ON art.article_id = h.article_id
+	WHERE
+		h.email = ? `
+
+	if txtType == 1 {
+		sql = ` SELECT * FROM ( ` + rightsSql + `
+	      )AS t ORDER BY t.created_time DESC`
+	} else if txtType == 2 {
+		sql = ` SELECT * FROM ( ` + ficcSql + `
+	      )AS t ORDER BY t.created_time DESC`
+	} else {
+		sql = ` SELECT * FROM ( ` + ficcSql + " UNION ALL " + rightsSql + `
+	      )AS t ORDER BY t.created_time DESC`
+	}
+
+	//报告统计删除晨报部分统计加入每日资讯 2021-4-9
+	//sql := ` SELECT * FROM (
+	//					SELECT
+	//							r.title AS research_report_name,
+	//							'rddp' AS report_type,
+	//							rvr.create_time AS created_time
+	//						FROM %s.report_view_record rvr
+	//						INNER JOIN %s.report r ON r.id = rvr.report_id
+	//						WHERE
+	//							rvr.mobile=?
+	//					UNION ALL
+	//					SELECT
+	//					cha.permission_name AS research_report_name,
+	//					'advisory' AS report_type,
+	//					auc.create_time AS created_time
+	//				FROM
+	//					advisory_user_chart_article_record auc
+	//					INNER JOIN chart_permission cha ON cha.chart_permission_id = auc.chart_permission_id
+	//				WHERE
+	//					auc.mobile = ?
+	//       )AS t ORDER BY t.created_time DESC
+	//    `
+
+	o := orm.NewOrm()
+	if txtType == 1 {
+		_, err = o.Raw(sql, email).QueryRows(&items)
+	} else if txtType == 2 {
+		sql = fmt.Sprintf(sql, dataName, dataName)
+		_, err = o.Raw(sql, email, email, email).QueryRows(&items)
+	} else {
+		sql = fmt.Sprintf(sql, dataName, dataName)
+		_, err = o.Raw(sql, email, email, email, email).QueryRows(&items)
+	}
+
+	return
+}
+
+// GetViewReportCount 获取报告列表
+func GetViewReportList(mobile,email,startDate,endDate string, startSize, pageSize int) (total int,items []*ViewReportList, err error) {
+	dataName := ""
+	sql := ``
+
+	var sql1,sql2,sql3 string
+	var pars []interface{}
+	if mobile != "" && email !=""{
+		sql1 = ` and ( uvh.mobile = ? or uvh.email = ? ) `
+		sql2 = ` and ( rvr.mobile = ? or rvr.email = ? `
+		sql3 = ` and ( auc.mobile = ? or auc.email = ? `
+		pars = append(pars,mobile,email,mobile,email,mobile,email)
+	}else if mobile != ""{
+		sql1 = ` and ( uvh.mobile = ? ) `
+		sql2 = ` and ( rvr.mobile = ? ) `
+		sql3 = ` and ( auc.mobile = ? ) `
+		pars = append(pars,mobile,mobile,mobile)
+	}else if email != ""{
+		sql1 = ` and ( uvh.email = ? ) `
+		sql2 = ` and ( rvr.email = ? ) `
+		sql3 = ` and ( auc.email = ? ) `
+		pars = append(pars,email,email,email)
+	}
+
+	sql1 = ` and uvh.created_time >= ? and uvh.created_time <= ?  `
+	pars = append(pars,startDate,endDate)
+	sql2 = ` and rvr.create_time >= ? and rvr.create_time <= ?  `
+	pars = append(pars,startDate,endDate)
+	sql3 = ` and auc.create_time >= ? and auc.create_time <= ?  `
+	pars = append(pars,startDate,endDate)
+
+	if utils.RunMode == "debug" {
+		dataName = "test_v2_hongze_rddp"
+	} else {
+		dataName = "hongze_rddp"
+	}
+
+	ficcSql := `SELECT
+	rr.research_report_name,
+		rr.type AS report_type,
+		'ficc' AS txt_type,
+		'--' AS match_type_name,
+		'--' AS stop_time,
+	uvh.created_time AS created_time,uvh.mobile,uvh.email,uvh.real_name,uvh.company_name
+	FROM
+	user_view_history uvh
+	LEFT JOIN research_report rr ON rr.research_report_id = uvh.research_report_id
+	WHERE 1=1 
+	`+ sql1 +`
+	UNION ALL
+	SELECT
+	r.title AS research_report_name,
+		'rddp' AS report_type,
+		'ficc' AS txt_type,
+		r.classify_name_first AS match_type_name,
+		'--' AS stop_time,
+		rvr.create_time AS created_time,rvr.mobile,rvr.email,rvr.real_name,rvr.company_name
+	FROM %s.report_view_record rvr
+	LEFT JOIN %s.report r ON r.id = rvr.report_id
+	WHERE 1=1 `+ sql2 +`
+	UNION ALL
+	SELECT
+	cha.permission_name AS research_report_name,
+		'advisory' AS report_type,
+		'ficc' AS txt_type,
+		cha.classify_name AS match_type_name,
+		'--' AS stop_time,
+		auc.create_time AS created_time,auc.mobile,auc.email,auc.real_name,auc.company_name
+	FROM
+	advisory_user_chart_article_record auc
+	LEFT JOIN chart_permission cha ON cha.chart_permission_id = auc.chart_permission_id
+	WHERE 1=1 `+sql3
+
+
+	sql = ` SELECT * FROM ( ` + ficcSql + ` )AS t ORDER BY t.created_time DESC`
+
+
+	o := orm.NewOrm()
+
+	sql = fmt.Sprintf(sql, dataName, dataName)
+	totalSql := `SELECT count(*) total FROM ( ` + sql + ` )AS z `
+	err = o.Raw(totalSql, pars).QueryRow(&total)
+	if err != nil{
+		return
+	}
+
+	sql += ` limit ?,?`
+	_, err = o.Raw(sql, pars,startSize,pageSize).QueryRows(&items)
+
+	return
+}
+
+// GetViewReportCount 获取报告列表总数
+func GetViewReportCount(mobile,email string) (total int, err error) {
+	dataName := ""
+	sql := ``
+
+	var sql1,sql2,sql3 string
+	var pars []interface{}
+	if mobile != "" && email !=""{
+		sql1 = `uvh.mobile = ? or uvh.email = ? `
+		sql2 = `rvr.mobile = ? or rvr.email = ? `
+		sql3 = `auc.mobile = ? or auc.email = ? `
+		pars = append(pars,mobile,email,mobile,email,mobile,email)
+	}else if mobile != ""{
+		sql1 = `uvh.mobile = ? `
+		sql2 = `rvr.mobile = ? `
+		sql3 = `auc.mobile = ? `
+		pars = append(pars,mobile,mobile,mobile)
+	}else if email != ""{
+		sql1 = `uvh.email = ? `
+		sql2 = `rvr.email = ? `
+		sql3 = `auc.email = ? `
+		pars = append(pars,email,email,email)
+	}
+
+	if utils.RunMode == "debug" {
+		dataName = "test_v2_hongze_rddp"
+	} else {
+		dataName = "hongze_rddp"
+	}
+
+	ficcSql := `SELECT
+	rr.research_report_name,
+		rr.type AS report_type,
+		'ficc' AS txt_type,
+		'--' AS match_type_name,
+		'--' AS stop_time,
+	uvh.created_time AS created_time
+	FROM
+	user_view_history uvh
+	LEFT JOIN research_report rr ON rr.research_report_id = uvh.research_report_id
+	WHERE
+	`+ sql1 +`
+	UNION ALL
+	SELECT
+	r.title AS research_report_name,
+		'rddp' AS report_type,
+		'ficc' AS txt_type,
+		r.classify_name_first AS match_type_name,
+		'--' AS stop_time,
+		rvr.create_time AS created_time
+	FROM %s.report_view_record rvr
+	LEFT JOIN %s.report r ON r.id = rvr.report_id
+	WHERE `+ sql2 +`
+	UNION ALL
+	SELECT
+	cha.permission_name AS research_report_name,
+		'advisory' AS report_type,
+		'ficc' AS txt_type,
+		cha.classify_name AS match_type_name,
+		'--' AS stop_time,
+		auc.create_time AS created_time
+	FROM
+	advisory_user_chart_article_record auc
+	LEFT JOIN chart_permission cha ON cha.chart_permission_id = auc.chart_permission_id
+	WHERE `+sql3
+
+
+	sql = ` SELECT count(*) total FROM ( ` + ficcSql + `
+	      )AS t ORDER BY t.created_time DESC`
+
+
+	o := orm.NewOrm()
+
+	sql = fmt.Sprintf(sql, dataName, dataName)
+	err = o.Raw(sql, pars).QueryRow(&total)
+
+	return
+}

+ 22 - 0
models/tables/open_api_user/open_api_user.go

@@ -0,0 +1,22 @@
+package open_api_user
+
+import (
+	"rdluck_tools/orm"
+)
+
+type OpenApiUser struct {
+	Appid                 string    `orm:"column(appid);pk" json:"appid" description:"开放平台appid"`
+	Secret               string `orm:"column(secret);" json:"secret" description:"开放平台秘钥"`
+	Ip                string `orm:"column(ip);" json:"ip" description:"限制请求来源ip,多个ip用英文,隔开"`
+	Remark                string `orm:"column(remark);" json:"remark" description:"备注信息"`
+	CreateTime             string `orm:"column(create_time);" json:"create_time" description:"创建时间"`
+	ModifyTime         string `orm:"column(modify_time);" json:"modify_time" description:"最近一次更新时间"`
+}
+
+// GetByAppid 根据appid获取开放api用户信息
+func GetByAppid(appid string) (item *OpenApiUser, err error) {
+	sql := `SELECT * FROM open_api_user WHERE appid=? LIMIT 1`
+	o := orm.NewOrm()
+	err = o.Raw(sql, appid).QueryRow(&item)
+	return
+}

+ 80 - 0
models/tables/wx_user/wx_user.go

@@ -0,0 +1,80 @@
+package wx_user
+
+import (
+	"rdluck_tools/orm"
+	"time"
+)
+
+type WxUser struct {
+	UserId           int64 `orm:"column(user_id);pk"`
+	Mobile           string
+	Email            string
+	CompanyId        int
+	RealName         string `description:"姓名"`
+	CreatedTime      time.Time
+	MobileTwo        string `description:"备用手机号"`
+	BusinessCardUrl  string `description:"名片"`
+	IsMaker          int    `description:"是否决策人,1:是,0:否"`
+	Position         string `description:"职位"`
+	Sex              int    `description:"普通用户性别,1为男性,2为女性"`
+	DepartmentName   string `description:"联系人部门"`
+	RegisterTime     time.Time
+	RegisterPlatform int
+}
+
+type OpenIdList struct {
+	OpenId string
+}
+
+//获取所有的用户openid列表
+func GetOpenIdList(openIdStr string) (items []*OpenIdList, err error) {
+	sql := `SELECT DISTINCT ur.open_id FROM wx_user AS wu 
+          INNER JOIN company AS c ON c.company_id = wu.company_id 
+          INNER JOIN company_product AS d ON c.company_id=d.company_id
+		INNER join user_record  as ur on wu.user_id=ur.user_id
+          WHERE ur.open_id != "" and ur.create_platform=1 AND  d.status IN('正式','试用','永续') `
+	if openIdStr != "" {
+		sql += ` AND ur.open_id in (` + openIdStr + `) `
+	}
+	_, err = orm.NewOrm().Raw(sql).QueryRows(&items)
+	return
+}
+
+//根据手机号获取用户的openid列表
+func GetOpenIdListByMobile(mobile, openIdStr string) (items []*OpenIdList, err error) {
+	sql := `SELECT DISTINCT ur.open_id FROM wx_user AS wu 
+          INNER JOIN company AS c ON c.company_id = wu.company_id 
+          INNER join user_record  as ur on wu.user_id=ur.user_id
+          WHERE ur.open_id != "" and ur.create_platform=1 AND wu.mobile=? `
+	if openIdStr != "" {
+		sql += ` AND ur.open_id in (` + openIdStr + `) `
+	}
+	_, err = orm.NewOrm().Raw(sql, mobile).QueryRows(&items)
+	return
+}
+
+type WxUserItem struct {
+	UserId int
+	RealName string
+	Mobile string
+	Email string
+	CompanyName string
+}
+
+// GetWxUserByMobile 根据手机号获取用户信息
+func GetWxUserByMobile(mobile string) (item *WxUserItem, err error) {
+	sql := `SELECT a.user_id,a.real_name,a.mobile,b.company_name FROM wx_user AS a 
+          INNER JOIN company AS b ON a.company_id = b.company_id 
+          WHERE a.mobile=? `
+	err = orm.NewOrm().Raw(sql, mobile).QueryRow(&item)
+	return
+}
+
+// GetWxUserByEmail 根据邮箱获取用户信息
+func GetWxUserByEmail(email string) (item *WxUserItem, err error) {
+	sql := `SELECT a.user_id,a.real_name,a.mobile,b.company_name FROM wx_user AS a 
+          INNER JOIN company AS b ON a.company_id = b.company_id 
+          WHERE a.email=? `
+	err = orm.NewOrm().Raw(sql, email).QueryRow(&item)
+	return
+}

File diff suppressed because it is too large
+ 2 - 0
routers/router.go


+ 91 - 0
services/oss.go

@@ -0,0 +1,91 @@
+package services
+
+import (
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"os"
+	"time"
+
+	"hongze/hongze_open_api/utils"
+)
+
+/*
+上传demo
+func init() {
+	fmt.Println("start")
+	randStr := utils.GetRandStringNoSpecialChar(28)
+	fileName :=  randStr + ".jpg"
+	fmt.Println("fileName:",fileName)
+	fpath:="./1.png"
+	resourceUrl,err:=UploadAliyun(fileName,fpath)
+	if err!=nil {
+		fmt.Println("UploadAliyun Err:",err.Error())
+		return
+	}
+	fmt.Println("resourceUrl:",resourceUrl)
+	fmt.Println("end")
+}
+*/
+
+//图片上传到阿里云
+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
+}

+ 693 - 0
utils/common.go

@@ -0,0 +1,693 @@
+package utils
+
+import (
+	"crypto/md5"
+	"crypto/sha1"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"image"
+	"image/png"
+	"math"
+	"math/rand"
+	"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 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
+}
+
+//人民币小写转大写
+func ConvertNumToCny(num float64) (str string, err error) {
+	strNum := strconv.FormatFloat(num*100, 'f', 0, 64)
+	sliceUnit := []string{"仟", "佰", "拾", "亿", "仟", "佰", "拾", "万", "仟", "佰", "拾", "元", "角", "分"}
+	// log.Println(sliceUnit[:len(sliceUnit)-2])
+	s := sliceUnit[len(sliceUnit)-len(strNum):]
+	upperDigitUnit := map[string]string{"0": "零", "1": "壹", "2": "贰", "3": "叁", "4": "肆", "5": "伍", "6": "陆", "7": "柒", "8": "捌", "9": "玖"}
+	for k, v := range strNum[:] {
+		str = str + upperDigitUnit[string(v)] + s[k]
+	}
+	reg, err := regexp.Compile(`零角零分$`)
+	str = reg.ReplaceAllString(str, "整")
+
+	reg, err = regexp.Compile(`零角`)
+	str = reg.ReplaceAllString(str, "零")
+
+	reg, err = regexp.Compile(`零分$`)
+	str = reg.ReplaceAllString(str, "整")
+
+	reg, err = regexp.Compile(`零[仟佰拾]`)
+	str = reg.ReplaceAllString(str, "零")
+
+	reg, err = regexp.Compile(`零{2,}`)
+	str = reg.ReplaceAllString(str, "零")
+
+	reg, err = regexp.Compile(`零亿`)
+	str = reg.ReplaceAllString(str, "亿")
+
+	reg, err = regexp.Compile(`零万`)
+	str = reg.ReplaceAllString(str, "万")
+
+	reg, err = regexp.Compile(`零*元`)
+	str = reg.ReplaceAllString(str, "元")
+
+	reg, err = regexp.Compile(`亿零{0, 3}万`)
+	str = reg.ReplaceAllString(str, "^元")
+
+	reg, err = regexp.Compile(`零元`)
+	str = reg.ReplaceAllString(str, "零")
+	return
+}
+
+// CalculationDate 计算两个日期之间相差n年m月y天
+func CalculationDate(startDate, endDate time.Time) (beetweenDay string, err error) {
+	//startDate := time.Date(2021, 3, 28, 0, 0, 0, 0, time.Now().Location())
+	//endDate := time.Date(2022, 3, 31, 0, 0, 0, 0, time.Now().Location())
+	numYear := endDate.Year() - startDate.Year()
+
+	numMonth := int(endDate.Month()) - int(startDate.Month())
+
+	numDay := 0
+	//获取截止月的总天数
+	endDateDays := getMonthDay(endDate.Year(), int(endDate.Month()))
+
+	//获取截止月的前一个月
+	endDatePrevMonthDate := endDate.AddDate(0, -1, 0)
+	//获取截止日期的上一个月的总天数
+	endDatePrevMonthDays := getMonthDay(endDatePrevMonthDate.Year(), int(endDatePrevMonthDate.Month()))
+	//获取开始日期的的月份总天数
+	startDateMonthDays := getMonthDay(startDate.Year(), int(startDate.Month()))
+
+	//判断,截止月是否完全被选中,如果相等,那么代表截止月份全部天数被选择
+	if endDate.Day() == endDateDays {
+		numDay = startDateMonthDays - startDate.Day() + 1
+
+		//如果剩余天数正好与开始日期的天数是一致的,那么月份加1
+		if numDay == startDateMonthDays {
+			numMonth++
+			numDay = 0
+			//超过月份了,那么年份加1
+			if numMonth == 12 {
+				numYear++
+				numMonth = 0
+			}
+		}
+	} else {
+		numDay = endDate.Day() - startDate.Day() + 1
+	}
+
+	//天数小于0,那么向月份借一位
+	if numDay < 0 {
+		//向上一个月借一个月的天数
+		numDay += endDatePrevMonthDays
+
+		//总月份减去一个月
+		numMonth = numMonth - 1
+	}
+
+	//月份小于0,那么向年份借一位
+	if numMonth < 0 {
+		//向上一个年借12个月
+		numMonth += 12
+
+		//总年份减去一年
+		numYear = numYear - 1
+	}
+	if numYear < 0 {
+		err = errors.New("日期异常")
+		return
+	}
+
+	if numYear > 0 {
+		beetweenDay += fmt.Sprint(numYear, "年")
+	}
+	if numMonth > 0 {
+		beetweenDay += fmt.Sprint(numMonth, "个月")
+	}
+	if numDay > 0 {
+		beetweenDay += fmt.Sprint(numDay, "天")
+	}
+	return
+}
+
+// getMonthDay 获取某年某月有多少天
+func getMonthDay(year, month int) (days int) {
+	if month != 2 {
+		if month == 4 || month == 6 || month == 9 || month == 11 {
+			days = 30
+
+		} else {
+			days = 31
+		}
+	} else {
+		if ((year%4) == 0 && (year%100) != 0) || (year%400) == 0 {
+			days = 29
+		} else {
+			days = 28
+		}
+	}
+	return
+}
+
+//字符串转换为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
+}

+ 55 - 0
utils/config.go

@@ -0,0 +1,55 @@
+package utils
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/beego/beego/v2/server/web"
+	"rdluck_tools/log"
+)
+
+var (
+	RunMode        string //运行模式
+	MYSQL_URL      string //数据库连接
+	MYSQL_URL_RDDP string //数据库连接
+)
+
+var ApiLog *log.Log
+
+
+var (
+	Bucketname       string = "hongze"
+	Endpoint         string
+	Imghost          string = "https://hongze.oss-accelerate.aliyuncs.com/"
+	Upload_dir       string = "static/images/"
+	Upload_Audio_Dir string = "static/audio/"
+	AccessKeyId      string = "LTAIFMZYQhS2BTvW"
+	AccessKeySecret  string = "12kk1ptCHoGWedhBnKRVW5hRJzq9Fq"
+)
+
+func init() {
+	tmpRunMode, err := web.AppConfig.String("run_mode")
+	if err != nil {
+		panic("配置文件读取run_mode错误 " + err.Error())
+	}
+	RunMode = tmpRunMode
+	fmt.Println(RunMode, "模式")
+	config, err := web.AppConfig.GetSection(RunMode)
+	if err != nil {
+		panic("配置文件读取错误 " + err.Error())
+	}
+	logs.Info(RunMode + " 模式")
+	MYSQL_URL = config["mysql_url"]
+	MYSQL_URL_RDDP = config["mysql_url_rddp"]
+
+	//日志类
+	if RunMode == "release" {
+		logDir := `/data/rdlucklog/hongze_open_api`
+		ApiLog = log.Init("20060102.api", logDir)
+	} else {
+		ApiLog = log.Init("20060102.api")
+	}
+}
+
+//http://webapi.brilliantstart.cn/api/
+//http://webapi.brilliantstart.cn/swagger/
+//http://139.196.122.219:8603/swagger/

+ 92 - 0
utils/constants.go

@@ -0,0 +1,92 @@
+package utils
+
+const (
+	Md5Key = ""
+)
+
+//常量定义
+const (
+	FormatTime            = "15:04:05"                //时间格式
+	FormatDate            = "2006-01-02"              //日期格式
+	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 (
+	APPNAME          = "弘则官网"
+	EmailSendToUsers = "glji@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}$" //手机号码
+	RegularEmail  = `\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`                                             //匹配电子邮箱
+)
+
+//客户状态
+const (
+	COMPANY_STATUS_TRY_OUT       = "试用"
+	COMPANY_STATUS_FOREVER       = "永续"
+	COMPANY_STATUS_FREEZE        = "冻结"
+	COMPANY_STATUS_LOSE          = "流失"
+	COMPANY_STATUS_FORMAL        = "正式"
+	COMPANY_STATUS_POTENTIAL     = "潜在"
+	COMPANY_STATUS_TRY_OUT_COUNT = 30
+
+	COMPANY_APPROVE_STATUS = "待审批"
+)
+
+//管理员,ficc管理员,ficc销售,权益管理员,权益销售。
+//角色类型/类型编码
+const (
+	ROLE_TYPE_ADMIN       = "管理员"
+	ROLE_TYPE_FICC_ADMIN  = "ficc管理员"
+	ROLE_TYPE_FICC_SELLER = "ficc销售"
+	ROLE_TYPE_RAI_ADMIN   = "权益管理员"
+	ROLE_TYPE_RAI_SELLER  = "权益销售"
+
+	ROLE_TYPE_FICC_GROUP      = "ficc组长"
+	ROLE_TYPE_RAI_GROUP       = "权益组长"
+	ROLE_TYPE_FICC_DEPARTMENT = "ficc部门经理"
+	ROLE_TYPE_RAI_DEPARTMENT  = "权益部门经理"
+	ROLE_TYPE_FICC_RESEARCHR  = "ficc研究员"
+	ROLE_TYPE_RAI_RESEARCHR   = "权益研究员"
+
+	ROLE_TYPE_CODE_ADMIN           = "admin"           //管理员
+	ROLE_TYPE_CODE_FICC_ADMIN      = "ficc_admin"      //ficc管理员
+	ROLE_TYPE_CODE_FICC_SELLER     = "ficc_seller"     //ficc销售
+	ROLE_TYPE_CODE_RAI_ADMIN       = "rai_admin"       //权益管理员
+	ROLE_TYPE_CODE_RAI_SELLER      = "rai_seller"      //权益销售
+	ROLE_TYPE_CODE_FICC_GROUP      = "ficc_group"      //ficc组长
+	ROLE_TYPE_CODE_RAI_GROUP       = "rai_group"       //ficc组长
+	ROLE_TYPE_CODE_FICC_DEPARTMENT = "ficc_department" //ficc部门经理
+	ROLE_TYPE_CODE_RAI_DEPARTMENT  = "rai_department"  //权益部门经理
+	ROLE_TYPE_CODE_FICC_RESEARCHR  = "ficc_researcher" //ficc研究员
+	ROLE_TYPE_CODE_RAI_RESEARCHR   = "rai_researcher"  //权益研究员
+	ROLE_TYPE_CODE_COMPLIANCE      = "compliance"      //合规角色
+
+	ROLE_TYPE_SELLERS = "'ficc_admin','ficc_seller','rai_admin','rai_seller','ficc_group','rai_group','ficc_department','rai_department','compliance'"
+)
+
+//客户类型
+const (
+	COMPANY_CLASSIFY_FICC    = "ficc"
+	COMPANY_CLASSIFY_RAI     = "权益"
+	COMPANY_CLASSIFY_PARTNER = "合作伙伴"
+)
+
+const (
+	COMPANY_PRODUCT_FICC_ID   = 1
+	COMPANY_PRODUCT_FICC_NAME = "ficc"
+	COMPANY_PRODUCT_RAI_ID    = 2
+	COMPANY_PRODUCT_RAI_NAME  = "权益"
+)
+
+var PermissionFiccClassifyArr = [...]string{"宏观经济", "化工产业", "黑色产业", "有色产业"}
+var PermissionAllClassifyArr = [...]string{"宏观经济", "化工产业", "黑色产业", "有色产业", "权益"}

+ 34 - 0
utils/email.go

@@ -0,0 +1,34 @@
+package utils
+
+import (
+	"gopkg.in/gomail.v2"
+	"strings"
+)
+
+//发送邮件
+func SendEmail(title, content string, touser string) bool {
+	if RunMode == "debug" {
+		ApiLog.Println("title:", title, "content:", content)
+		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
+}

+ 12 - 0
utils/logs.go

@@ -0,0 +1,12 @@
+package utils
+
+import (
+	"github.com/beego/beego/v2/adapter/logs"
+)
+
+var FileLog *logs.BeeLogger
+
+func init() {
+	FileLog = logs.NewLogger(1000000)
+	FileLog.SetLogger(logs.AdapterFile, `{"filename":"./rdlucklog/hongze_open_api.log"}`)
+}

+ 80 - 0
utils/paging.go

@@ -0,0 +1,80 @@
+package utils
+
+
+type PagingReq struct {
+	CurrentIndex  int  `description:"当前页码" json:"_page"`
+	PageSize      int  `description:"每页数据条数,如果不传,默认每页20条" json:"_page_size"`
+}
+
+type PagingItem struct {
+	IsStart       bool `description:"是否首页" json:"is_start"`
+	IsEnd         bool `description:"是否最后一页" json:"is_end"`
+	PreviousIndex int  `description:"上一页页码" json:"previous_index"`
+	NextIndex     int  `description:"下一页页码" json:"next_index"`
+	CurrentIndex  int  `description:"当前页页码" json:"current_index"`
+	Pages         int  `description:"总页数" json:"pages"`
+	Totals        int  `description:"总数据量" json:"totals"`
+	PageSize      int  `description:"每页数据条数" json:"page_size"`
+}
+
+func GetPaging(currentIndex,pageSize,total int)(item *PagingItem)  {
+	if pageSize<=0 {
+		pageSize=PageSize20
+	}
+	if currentIndex<=0 {
+		currentIndex=1
+	}
+	item=new(PagingItem)
+	item.PageSize=pageSize
+	item.Totals=total
+	item.CurrentIndex=currentIndex
+
+	if total<=0 {
+		item.IsStart=true
+		item.IsEnd=true
+		return
+	}
+	pages:=PageCount(total,pageSize)
+	item.Pages=pages
+	if pages<=1 {
+		item.IsStart=true
+		item.IsEnd=true
+		item.PreviousIndex=1
+		item.NextIndex=1
+		return
+	}
+	if pages == currentIndex {
+		item.IsStart=false
+		item.IsEnd=true
+		item.PreviousIndex=currentIndex-1
+		item.NextIndex=currentIndex
+		return
+	}
+	if currentIndex==1 {
+		item.IsStart=true
+		item.IsEnd=false
+		item.PreviousIndex=1
+		item.NextIndex=currentIndex+1
+		return
+	}
+	item.IsStart=false
+	item.IsEnd=false
+	item.PreviousIndex=currentIndex-1
+	item.NextIndex=currentIndex+1
+	return
+}
+
+
+func StartIndex2(page, pagesize int) int {
+	if page > 1 {
+		return (page - 1) * pagesize
+	}
+	return 0
+}
+func PageCount2(count, pagesize int) int {
+	if count%pagesize > 0 {
+		return count/pagesize + 1
+	} else {
+		return count / pagesize
+	}
+}

+ 244 - 0
utils/validator.go

@@ -0,0 +1,244 @@
+package utils
+
+import (
+	"errors"
+	"reflect"
+	"strconv"
+	"strings"
+)
+
+type Rules map[string][]string
+
+type RulesMap map[string]Rules
+
+var CustomizeMap = make(map[string]Rules)
+
+var (
+	LANG_CN = "cn"	//中文
+	LANG_EN = "english" //英文
+)
+
+var (
+	VERIFY_NOT_EMPTY = "notEmpty"	//不为空,必填
+	VERIFY_LENGTH_NOT_LEGA = "lengthNotLega"	//长度不合规
+)
+
+// 注册自定义规则方案建议在路由初始化层即注册
+func RegisterRule(key string, rule Rules) (err error) {
+	if CustomizeMap[key] != nil {
+		return errors.New(key + "已注册,无法重复注册")
+	} else {
+		CustomizeMap[key] = rule
+		return nil
+	}
+}
+
+// 非空 不能为其对应类型的0值
+func NotEmpty() string {
+	return "notEmpty"
+}
+
+// 小于入参(<) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
+func Lt(mark string) string {
+	return "lt=" + mark
+}
+
+// 小于等于入参(<=) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
+func Le(mark string) string {
+	return "le=" + mark
+}
+
+// 等于入参(==) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
+func Eq(mark string) string {
+	return "eq=" + mark
+}
+
+// 不等于入参(!=)  如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
+func Ne(mark string) string {
+	return "ne=" + mark
+}
+
+// 大于等于入参(>=) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
+func Ge(mark string) string {
+	return "ge=" + mark
+}
+
+// 大于入参(>) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
+func Gt(mark string) string {
+	return "gt=" + mark
+}
+
+// 校验方法 接收两个参数  入参实例,规则map
+func Verify(st interface{}, roleMap Rules,lang string) (err error) {
+	compareMap := map[string]bool{
+		"lt": true,
+		"le": true,
+		"eq": true,
+		"ne": true,
+		"ge": true,
+		"gt": true,
+	}
+
+	typ := reflect.TypeOf(st)
+	val := reflect.ValueOf(st) // 获取reflect.Type类型
+
+	kd := val.Kind() // 获取到st对应的类别
+	if kd != reflect.Struct {
+		return errors.New("expect struct")
+	}
+	num := val.NumField()
+	// 遍历结构体的所有字段
+	for i := 0; i < num; i++ {
+		tagVal := typ.Field(i)
+		val := val.Field(i)
+
+		//如果有填写form字段的话,那么返回提示使用该字段
+		tagName := tagVal.Tag.Get("form")
+		if tagName == ""{
+			tagName = tagVal.Name
+		}
+
+		if len(roleMap[tagVal.Name]) > 0 {
+			for _, v := range roleMap[tagVal.Name] {
+				switch {
+				case v == "notEmpty":
+					if isBlank(val) {
+						return errors.New(tagName + getVerifyErrInfo(VERIFY_NOT_EMPTY,lang))
+					}
+				case compareMap[strings.Split(v, "=")[0]]:
+					if !compareVerify(val, v) {
+						return errors.New(tagName + getVerifyErrInfo(VERIFY_LENGTH_NOT_LEGA,lang) + v)
+					}
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// 长度和数字的校验方法 根据类型自动校验
+func compareVerify(value reflect.Value, VerifyStr string) bool {
+	switch value.Kind() {
+	case reflect.String, reflect.Slice, reflect.Array:
+		return compare(value.Len(), VerifyStr)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return compare(value.Uint(), VerifyStr)
+	case reflect.Float32, reflect.Float64:
+		return compare(value.Float(), VerifyStr)
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return compare(value.Int(), VerifyStr)
+	default:
+		return false
+	}
+}
+
+// 非空校验
+func isBlank(value reflect.Value) bool {
+	switch value.Kind() {
+	case reflect.String:
+		return value.Len() == 0
+	case reflect.Bool:
+		return !value.Bool()
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return value.Int() == 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return value.Uint() == 0
+	case reflect.Float32, reflect.Float64:
+		return value.Float() == 0
+	case reflect.Interface, reflect.Ptr:
+		return value.IsNil()
+	}
+	return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
+}
+
+func compare(value interface{}, VerifyStr string) bool {
+	VerifyStrArr := strings.Split(VerifyStr, "=")
+	val := reflect.ValueOf(value)
+	switch val.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		VInt, VErr := strconv.ParseInt(VerifyStrArr[1], 10, 64)
+		if VErr != nil {
+			return false
+		}
+		switch {
+		case VerifyStrArr[0] == "lt":
+			return val.Int() < VInt
+		case VerifyStrArr[0] == "le":
+			return val.Int() <= VInt
+		case VerifyStrArr[0] == "eq":
+			return val.Int() == VInt
+		case VerifyStrArr[0] == "ne":
+			return val.Int() != VInt
+		case VerifyStrArr[0] == "ge":
+			return val.Int() >= VInt
+		case VerifyStrArr[0] == "gt":
+			return val.Int() > VInt
+		default:
+			return false
+		}
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		VInt, VErr := strconv.Atoi(VerifyStrArr[1])
+		if VErr != nil {
+			return false
+		}
+		switch {
+		case VerifyStrArr[0] == "lt":
+			return val.Uint() < uint64(VInt)
+		case VerifyStrArr[0] == "le":
+			return val.Uint() <= uint64(VInt)
+		case VerifyStrArr[0] == "eq":
+			return val.Uint() == uint64(VInt)
+		case VerifyStrArr[0] == "ne":
+			return val.Uint() != uint64(VInt)
+		case VerifyStrArr[0] == "ge":
+			return val.Uint() >= uint64(VInt)
+		case VerifyStrArr[0] == "gt":
+			return val.Uint() > uint64(VInt)
+		default:
+			return false
+		}
+	case reflect.Float32, reflect.Float64:
+		VFloat, VErr := strconv.ParseFloat(VerifyStrArr[1], 64)
+		if VErr != nil {
+			return false
+		}
+		switch {
+		case VerifyStrArr[0] == "lt":
+			return val.Float() < VFloat
+		case VerifyStrArr[0] == "le":
+			return val.Float() <= VFloat
+		case VerifyStrArr[0] == "eq":
+			return val.Float() == VFloat
+		case VerifyStrArr[0] == "ne":
+			return val.Float() != VFloat
+		case VerifyStrArr[0] == "ge":
+			return val.Float() >= VFloat
+		case VerifyStrArr[0] == "gt":
+			return val.Float() > VFloat
+		default:
+			return false
+		}
+	default:
+		return false
+	}
+}
+
+//获取错误信息(中文文)
+func getVerifyErrInfo(errType string,lang string) (errInfo string) {
+	if lang == LANG_EN{
+		switch errType {
+		case VERIFY_NOT_EMPTY:
+			errInfo = " Cannot be empty"
+		case VERIFY_LENGTH_NOT_LEGA:
+			errInfo = " Length or value is not in legal range,"
+		}
+	}else{
+		switch errType {
+		case VERIFY_NOT_EMPTY:
+			errInfo = " 值不能为空"
+		case VERIFY_LENGTH_NOT_LEGA:
+			errInfo = " 长度或值不在合法范围,"
+		}
+	}
+	return
+}

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