Răsfoiți Sursa

init project

rdluck 4 ani în urmă
comite
03e85a3896
13 a modificat fișierele cu 1225 adăugiri și 0 ștergeri
  1. 132 0
      controllers/base_auth.go
  2. 124 0
      controllers/base_common.go
  3. 5 0
      controllers/home.go
  4. 84 0
      controllers/wechat.go
  5. 31 0
      models/base.go
  6. 25 0
      models/db.go
  7. 5 0
      services/task.go
  8. 552 0
      utils/common.go
  9. 73 0
      utils/config.go
  10. 81 0
      utils/constants.go
  11. 56 0
      utils/email.go
  12. 45 0
      utils/jwt.go
  13. 12 0
      utils/logs.go

+ 132 - 0
controllers/base_auth.go

@@ -0,0 +1,132 @@
+package controllers
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/astaxie/beego"
+	"net/http"
+	"net/url"
+
+	"hongze/hongze_cygx/models"
+	"hongze/hongze_cygx/utils"
+
+	"rdluck_tools/log"
+)
+
+var apiLog *log.Log
+
+func init() {
+	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 == "" {
+				cookie := this.Ctx.GetCookie("rddp_access_token")
+				utils.FileLog.Info("authorization:%s,cookie:%s", authorization, cookie)
+				authorization = cookie
+			}
+			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 := 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
+		} 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)
+		go utils.SendEmail(utils.APPNAME+" "+utils.RunMode+" 失败提醒", "URI:"+c.Ctx.Input.URI()+"<br/> ErrMsg:"+baseRes.ErrMsg+";<br/>Msg:"+baseRes.Msg+";<br/> Body:"+string(body), 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)
+}

+ 124 - 0
controllers/base_common.go

@@ -0,0 +1,124 @@
+package controllers
+
+import (
+	"encoding/json"
+	"net/http"
+	"net/url"
+	"strings"
+
+	"github.com/astaxie/beego"
+
+	"hongze/hongze_cygx/models"
+	"hongze/hongze_cygx/utils"
+)
+
+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)
+}

+ 5 - 0
controllers/home.go

@@ -0,0 +1,5 @@
+package controllers
+
+type HomeController struct {
+	BaseCommonController
+}

+ 84 - 0
controllers/wechat.go

@@ -0,0 +1,84 @@
+package controllers
+
+import (
+	"hongze/hongze_cygx/models"
+)
+
+type WechatController struct {
+	BaseAuthController
+}
+
+type WechatCommonController struct {
+	BaseCommonController
+}
+
+// @Title 微信登录接口
+// @Description 微信登录接口
+// @Param   Code   query   string  true       "微信唯一编码code"
+// @Success 200 {object} models.WxLoginResp
+// @router /login [get]
+func (this *WechatCommonController) WechatLogin() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "登录成功"
+	//登录日志
+	//{
+	//	returnResult, err := json.Marshal(br)
+	//	if err != nil {
+	//		utils.FileLog.Info(this.Ctx.Input.URI() + " Err:%s" + err.Error())
+	//	}
+	//	utils.FileLog.Info(this.Ctx.Input.URI()+" code: %s , return data: %s", code, string(returnResult))
+	//}
+}
+
+// @Title 微信获取签名接口
+// @Description 微信获取签名接口
+// @Param   Url   query   string  true       "url地址"
+// @Success 200 {object} models.WechatSign
+// @router /getWxSign [get]
+func (this *WechatController) GetWxSign() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	//getUrl := this.GetString("Url")
+
+	//accessToken, err := services.WxGetAccessToken()
+	//if err != nil {
+	//	br.Msg = "获取用户信息失败"
+	//	br.ErrMsg = "获取access_token失败,err:" + err.Error()
+	//	return
+	//}
+	//
+	//ticket, err := services.GetWxTicket(accessToken)
+	//if err != nil {
+	//	br.Msg = "获取Ticket失败,请联系客服"
+	//	br.ErrMsg = "获取Ticket失败,Err" + err.Error()
+	//	return
+	//}
+	//if ticket == "" {
+	//	br.Msg = "获取Ticket失败,请联系客服"
+	//	br.ErrMsg = "ticket为空" + ticket
+	//	return
+	//}
+	//nonceStr := utils.GetRandStringNoSpecialChar(16)
+	//signature, nonceString, timestamp := services.GetWxSignature(ticket, getUrl, nonceStr)
+	//
+	//resp := new(models.WechatSign)
+	//resp.AppId = utils.WxAppId
+	//resp.NonceStr = nonceString
+	//resp.Timestamp = timestamp
+	//resp.Url = getUrl
+	//resp.Signature = signature
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取签名成功"
+	//br.Data = resp
+}

+ 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}
+}

+ 25 - 0
models/db.go

@@ -0,0 +1,25 @@
+package models
+
+import (
+	"hongze/hongze_cygx/utils"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+
+	"rdluck_tools/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(
+
+	)
+}

+ 5 - 0
services/task.go

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

+ 552 - 0
utils/common.go

@@ -0,0 +1,552 @@
+package utils
+
+import (
+	"crypto/md5"
+	"crypto/sha1"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"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
+}

+ 73 - 0
utils/config.go

@@ -0,0 +1,73 @@
+package utils
+
+import (
+	"github.com/astaxie/beego"
+)
+
+var (
+	RunMode        string //运行模式
+	MYSQL_URL      string //数据库连接
+	MYSQL_URL_RDDP string //数据库连接
+	MYSQL_URL_EDB  string
+)
+
+var (
+	STATIC_DIR string
+)
+
+//微信配置信息
+var (
+	WxId                string //微信原始ID
+	WxAppId             string
+	WxAppSecret         string
+	TemplateIdByProduct string //产品运行报告通知-模板ID
+	TemplateRedirectUrl string //模板消息跳转地址
+)
+
+//pc端微信配置信息
+var (
+	PcWxId                string //微信原始ID
+	PcWxAppId             string
+	PcWxAppSecret         string
+	PcTemplateIdByProduct string //产品运行报告通知-模板ID
+	PcTemplateRedirectUrl string //模板消息跳转地址
+)
+
+func init() {
+	RunMode = beego.AppConfig.String("run_mode")
+	config, err := beego.AppConfig.GetSection(RunMode)
+	if err != nil {
+		panic("配置文件读取错误 " + err.Error())
+	}
+	beego.Info(RunMode + " 模式")
+	MYSQL_URL = config["mysql_url"]
+	MYSQL_URL_RDDP = config["mysql_url_rddp"]
+	MYSQL_URL_EDB = config["mysql_url_edb"]
+
+	if RunMode == "release" {
+		WxAppId = "wx4a844c734d8c8e56"
+		WxAppSecret = "26c586e7ccb3c575433f0f37797b3eeb"
+		WxId = "gh_b67e0049fb8c"
+		TemplateIdByProduct = "Cp2wF8gvBtxyWV4DeYuI172oqwyYXVRSm3AyJO42d84"
+		TemplateRedirectUrl = "https://ficc.hzinsights.com/reportdtl?id="
+
+		PcWxAppId = "wx615472d6874eeb7f"
+		PcWxAppSecret="97fe374fb0cc90ef58c4b49d431366f1"
+		STATIC_DIR = "/home/static/imgs/"
+	} else {
+		WxAppId = "wx9b5d7291e581233a"
+		WxAppSecret = "f4d52e34021eee262dce9682b31f8861"
+		WxId = "gh_5dc508325c6f"
+		TemplateIdByProduct = "-YjuPOB7Fqd-S3ilabYa6wvjDY9aXmeEfPN6DCiy-EY"
+		TemplateRedirectUrl = "http://rddpweb.brilliantstart.cn/reportdtl?id="
+
+		PcWxAppId = "wx7c8084f6e5b1d85a"
+		PcWxAppSecret="9e4210cd5a363aa1f316b7c4b8898418"
+
+		STATIC_DIR = "/home/static/imgs/"
+	}
+}
+
+//http://webapi.brilliantstart.cn/api/
+//http://webapi.brilliantstart.cn/swagger/
+//http://139.196.122.219:8603/swagger/

+ 81 - 0
utils/constants.go

@@ -0,0 +1,81 @@
+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" //完整时间格式
+	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+)*`                                             //匹配电子邮箱
+)
+
+//验证码code
+const (
+	REGISTER_CODE = iota + 1 //注册
+	LOGIN_CODE               //登录
+)
+
+//聚合短信
+var (
+	JhGnTplId = "65692" //聚合国内模板编码
+	JhGjTplId = "10054" //聚合国内模板编码
+
+	JhGnAppKey = "4c8504c49dd335e99cfd7b6a3a9e2415" //聚合国内AppKey
+	JhGjAppKey = "3326ad2c1047a4cd92ace153e6044ca3"
+)
+
+//科大讯飞--语音合成
+const (
+	XfSTATUS_FIRST_FRAME    = 0 //第一帧标识
+	XfSTATUS_CONTINUE_FRAME = 1 //中间帧标识
+	XfSTATUS_LAST_FRAME     = 2 //最后一帧标识
+	XfAPPID                 = "5ed70e9d"
+	XfAPIKey                = "d580509ca262e9586fb65a7064d5ce77"
+	XfAPISecret             = "a085720dc55850c720fa5576335f847a"
+	XfHostUrl               = "wss://tts-api.xfyun.cn/v2/tts"
+	XfOrigin                = "http://tts-api.xfyun.cn/"
+	XfHost                  = "tts-api.xfyun.cn"
+)
+
+//OSS
+var (
+	Endpoint   string = "oss-cn-shanghai.aliyuncs.com"
+	Bucketname string = "hongze"
+
+	Imghost          string = "http://hongze.oss-cn-shanghai.aliyuncs.com/"
+	Upload_dir       string = "static/images/"
+	Upload_Audio_Dir string = "static/audio/"
+
+	AccessKeyId     string = "LTAIFMZYQhS2BTvW"
+	AccessKeySecret string = "12kk1ptCHoGWedhBnKRVW5hRJzq9Fq"
+)
+
+//客户状态
+const (
+	COMPANY_STATUS_TRY_OUT   = "试用"
+	COMPANY_STATUS_FOREVER   = "永续"
+	COMPANY_STATUS_FREEZE    = "冻结"
+	COMPANY_STATUS_LOSE      = "流失"
+	COMPANY_STATUS_FORMAL    = "正式"
+	COMPANY_STATUS_POTENTIAL = "潜在"
+)

+ 56 - 0
utils/email.go

@@ -0,0 +1,56 @@
+package utils
+
+import (
+	"gopkg.in/gomail.v2"
+	"strings"
+)
+
+//发送邮件
+func SendEmail(title, content string, 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+" "+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) {
+	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
+}

+ 45 - 0
utils/jwt.go

@@ -0,0 +1,45 @@
+package utils
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/astaxie/beego/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_cygx",
+		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
+}

+ 12 - 0
utils/logs.go

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