Explorar el Código

Merge branch 'yb/1.1' of hongze/hongze_yb into master

颜鹏 hace 3 años
padre
commit
93633f1730

+ 2 - 1
.gitignore

@@ -5,4 +5,5 @@ latest_log
 .DS_Store
 go.sum
 /binlog
-latest_binlog
+latest_binlog
+hongze_yb

+ 135 - 3
controller/activity/activity.go

@@ -1,11 +1,15 @@
 package activity
 
 import (
+	"fmt"
 	"github.com/gin-gonic/gin"
 	"hongze/hongze_yb/controller/response"
+	"hongze/hongze_yb/models/tables/yb_activity"
 	"hongze/hongze_yb/services/activity"
 	"hongze/hongze_yb/services/user"
 	"hongze/hongze_yb/utils"
+	"io/ioutil"
+	"os"
 	"strconv"
 	"time"
 )
@@ -21,16 +25,17 @@ import (
 // @Param title query string false "活动类别/标题"
 // @Param active_state query int false "活动状态 1-本周预告 2-进行中 3-已结束"
 // @Param activity_type query int false "活动类型 1-线上会议 3-线下沙龙"
+// @Param has_permission query int false "是否查看仅有权限的 0-否 1-是"
 // @Param page query int false "当前页码"
 // @Param limit query int false "每页数量"
-// @Success 200 {object} []yb_activity.ActivityItem
+// @Success 200 {object} []activity.ActivityList
 // @failure 400 {string} string "活动获取失败"
 // @Router /activity/getPageList [get]
 func GetPageList(c *gin.Context) {
 	page, _ := strconv.Atoi(c.Query("page"))
 	limit, _ := strconv.Atoi(c.Query("limit"))
-	condition, pars, order := _handleListQuery(c)
 	userInfo := user.GetInfoByClaims(c)
+	condition, pars, order := _handleListQuery(c, userInfo)
 	listData, err := activity.PageList(condition, pars, page, limit, order, userInfo)
 	if err != nil {
 		response.Fail("活动获取失败", c)
@@ -39,7 +44,7 @@ func GetPageList(c *gin.Context) {
 	response.OkData("获取成功", listData, c)
 }
 
-func _handleListQuery(c *gin.Context) (string, []interface{}, string) {
+func _handleListQuery(c *gin.Context, userInfo user.UserInfo) (string, []interface{}, string) {
 	condition := "is_delete = 0 AND publish_status = 1"
 	pars := make([]interface{}, 0)
 	// 活动类别/标题
@@ -75,6 +80,14 @@ func _handleListQuery(c *gin.Context) (string, []interface{}, string) {
 		condition += ` AND first_activity_type_id = ?`
 		pars = append(pars, activityTypeId)
 	}
+	// 是否仅查看有权限的
+	reqHasPermission := c.DefaultQuery("has_permission", "0")
+	if reqHasPermission != "0" {
+		activityIds, _ := activity.GetUserAuthActivityIds(userInfo)
+		condition += ` AND activity_id IN (?)`
+		pars = append(pars, activityIds)
+	}
+
 	return condition, pars, order
 }
 
@@ -130,10 +143,129 @@ func GetActivityVoices(c *gin.Context) {
 		return
 	}
 	activityId, _ := strconv.Atoi(reqActivityId)
+	userInfo := user.GetInfoByClaims(c)
+	ok, permissionCheckInfo, err := activity.CheckActivityPermission(userInfo, activityId)
+	if !ok {
+		response.AuthError(permissionCheckInfo, "暂无权限", c)
+		return
+	}
 	listData, err := activity.GetVoicesByActivity(activityId)
 	if err != nil {
 		response.Fail("录音获取失败", c)
 		return
 	}
 	response.OkData("获取成功", listData, c)
+}
+
+// GetActivityShareImg 生成活动分享图片
+// @Tags 活动模块
+// @Summary  生成活动分享图片
+// @Description 生成活动分享图片
+// @Security ApiKeyAuth
+// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
+// @Accept  json
+// @Product json
+// @Param activity_id query int true "活动ID"
+// @Success 200 {string} string "获取成功"
+// @failure 400 {string} string "获取失败"
+// @Router /activity/getActivityShareImg [get]
+func GetActivityShareImg(c *gin.Context)  {
+	reqActivityId := c.DefaultQuery("activity_id", "0")
+	if reqActivityId == "0" {
+		response.Fail("参数异常", c)
+		return
+	}
+	activityId, _ := strconv.Atoi(reqActivityId)
+	activityInfo, err := yb_activity.GetDetailById(activityId)
+	if err != nil {
+		if err == utils.ErrNoRow {
+			response.Fail("获取活动信息失败", c)
+		}
+		return
+	}
+
+	// 获取原分享图
+	originShareUrl := "static/img/report_share.png"
+	if activityInfo.FirstActivityTypeID == 3 {
+		originShareUrl = "static/img/report_share_sl.png"
+	}
+	fp, err := os.OpenFile(originShareUrl, os.O_CREATE|os.O_APPEND, 6)
+	if err != nil {
+		response.Fail("读取封面图失败", c)
+		return
+	}
+	defer fp.Close()
+	bytes, err := ioutil.ReadAll(fp)
+	if err != nil {
+		response.Fail("读取封面图失败", c)
+		return
+	}
+
+	// 处理文字x轴y轴点
+	drawText := activityInfo.ActivityTypeName
+	fontSize := 40
+	fontWidth := 50
+	x, y, newSize, err := calcuDrawXandY(drawText, fontSize, 500, 400)
+	if err != nil {
+		response.Fail("生成新封面图失败", c)
+		return
+	}
+
+	// 生成新分享图
+	var drawInfo []*utils.DrawTextInfo
+	text := &utils.DrawTextInfo{
+		Text: drawText, X: x, Y: y,
+	}
+	drawInfo = append(drawInfo, text)
+	var colorRGBA = utils.FontRGBA{
+		R: 255, G: 255, B: 255, A: 255,
+	}
+	picByte, err := utils.DrawStringOnImage(bytes, drawInfo, colorRGBA, float64(newSize), fontWidth)
+	if err != nil {
+		response.Fail("生成新封面图失败", c)
+		return
+	}
+
+	c.Header("Content-Type", "image/png")
+	c.Header("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", "图片地址"))
+	c.Writer.WriteString(picByte.String())
+}
+
+// calcuDrawXandY 计算写入文字的x轴和y轴
+func calcuDrawXandY(drawText string, fontSize, canvasLength, canvasWidth int) (x, y, newSize int, err error) {
+	// y轴取画布宽度的一半
+	y = canvasWidth / 2
+	// 文字所占总宽度
+	lenText := len(drawText)
+	textUnit := float64(lenText) / 3
+	textWidth := int(textUnit * float64(fontSize))
+	// x轴上的起点位置
+	newSize = fontSize
+	doubleX := canvasLength - textWidth
+	if doubleX < 50 {
+		// 文字总宽太长则调整文字大小
+		maxTextWidth := float64(canvasLength - 50)
+		newSize = int(maxTextWidth / textUnit)
+		x = 25
+	} else {
+		x = doubleX / 2
+	}
+
+	return
+}
+
+// SyncOldActivityData 同步三个月前电话会数据
+func SyncOldActivityData(c *gin.Context) {
+	authCode := c.DefaultQuery("auth_code", "0")
+	if authCode != "10086" {
+		response.Fail("无权操作", c)
+		return
+	}
+	countTotal, countSuccess, err := activity.SyncTeleconferenceOldData()
+	if err != nil {
+		response.Fail("同步失败" + err.Error(), c)
+		return
+	}
+	tips := "同步总数:" + strconv.Itoa(countTotal) + ", 同步成功数:" + strconv.Itoa(countSuccess)
+	response.OkData("同步成功", tips, c)
 }

+ 9 - 7
go.mod

@@ -3,19 +3,20 @@ module hongze/hongze_yb
 go 1.15
 
 require (
+	github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
 	github.com/aliyun/aliyun-oss-go-sdk v1.9.8
 	github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
-	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
 	github.com/fsnotify/fsnotify v1.5.1
 	github.com/gin-gonic/gin v1.7.4
-	github.com/go-openapi/spec v0.20.4 // indirect
 	github.com/go-playground/validator/v10 v10.9.0 // indirect
 	github.com/go-redis/redis/v8 v8.11.4
+	github.com/go-sql-driver/mysql v1.6.0 // indirect
+	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
+	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/jonboulle/clockwork v0.2.2 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
 	github.com/lestrrat-go/strftime v1.0.5 // indirect
-	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
@@ -23,14 +24,15 @@ require (
 	github.com/silenceper/wechat/v2 v2.0.9
 	github.com/spf13/viper v1.9.0
 	github.com/swaggo/gin-swagger v1.3.3
-	github.com/swaggo/swag v1.7.6 // indirect
+	github.com/swaggo/swag v1.7.4
 	golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
-	golang.org/x/net v0.0.0-20211205041911-012df41ee64c // indirect
-	golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
+	golang.org/x/image v0.0.0-20190802002840-cff245a6509b
+	golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 // indirect
 	golang.org/x/text v0.3.7 // indirect
-	golang.org/x/tools v0.1.8 // indirect
+	google.golang.org/protobuf v1.27.1 // indirect
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
+	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gorm.io/driver/mysql v1.1.3
 	gorm.io/gorm v1.22.2
 )

+ 6 - 0
models/tables/chart_permission/query.go

@@ -28,3 +28,9 @@ func GetByWhereMap(where map[string]interface{}) (list []*ChartPermission, err e
 	err = global.DEFAULT_MYSQL.Where(cond, whereVal...).Find(&list).Error
 	return
 }
+
+// GetListByIds 通过IDs获取图表权限集合
+func GetListByIds(permissionIds []int) (list []*ChartPermission, err error) {
+	err = global.DEFAULT_MYSQL.Model(ChartPermission{}).Where("chart_permission_id IN (?)", permissionIds).Scan(&list).Error
+	return
+}

+ 6 - 0
models/tables/research_report/query.go

@@ -22,3 +22,9 @@ func GetByWhereMap(where map[string]interface{}) (item *ResearchReport, err erro
 	err = global.DEFAULT_MYSQL.Where(cond, whereVal...).First(&item).Error
 	return
 }
+
+// GetListByResearchReportIds 根据ids获取报告集合
+func GetListByResearchReportIds(ids []int) (list []*ResearchReport, err error) {
+	err = global.DEFAULT_MYSQL.Model(ResearchReport{}).Where("research_report_id IN (?)", ids).Scan(&list).Error
+	return
+}

+ 9 - 0
models/tables/teleconference/query.go

@@ -0,0 +1,9 @@
+package teleconference
+
+import "hongze/hongze_yb/global"
+
+// GetTeleconferenceList 获取电话会列表
+func GetTeleconferenceList(condition string, pars []interface{}) (list []*Teleconference, err error) {
+	err = global.DEFAULT_MYSQL.Model(Teleconference{}).Where(condition, pars...).Scan(&list).Error
+	return
+}

+ 76 - 0
models/tables/teleconference/teleconference.go

@@ -0,0 +1,76 @@
+package teleconference
+
+import (
+	"time"
+)
+
+// Teleconference 电话会
+type Teleconference struct {
+	TeleconferenceID      uint64    `gorm:"primaryKey;column:teleconference_id;type:bigint(20) unsigned;not null" json:"-"`                     // 电话会id
+	TeleconferenceTitle   string    `gorm:"index:teleconference_title;column:teleconference_title;type:varchar(32)" json:"teleconferenceTitle"` // 电话会标题
+	Type                  string    `gorm:"index:type;column:type;type:varchar(30);not null" json:"type"`                                       // 电话会类型
+	Speaker               string    `gorm:"column:speaker;type:varchar(30)" json:"speaker"`
+	Telephone             string    `gorm:"column:telephone;type:varchar(30)" json:"telephone"`                                                // 拨入电话
+	Password              string    `gorm:"column:password;type:varchar(30)" json:"password"`                                                  // 参会人密码
+	StartTime             time.Time `gorm:"column:start_time;type:datetime" json:"startTime"`                                                  // 会议开始时间
+	EndTime               time.Time `gorm:"column:end_time;type:datetime" json:"endTime"`                                                      // 会议结束时间
+	ReferResearchReportID int64     `gorm:"column:refer_research_report_id;type:bigint(20)" json:"referResearchReportId"`                      // 关联研报id
+	Enabled               int8      `gorm:"index:enabled;column:enabled;type:tinyint(1);default:1" json:"enabled"`                             // 是否删除,1表示已删除,0表示未删除
+	CreatedTime           time.Time `gorm:"index:created_time;column:created_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createdTime"` // 创建时间
+	LastUpdatedTime       time.Time `gorm:"index:last_updated_time;column:last_updated_time;type:timestamp;not null;default:CURRENT_TIMESTAMP" json:"lastUpdatedTime"`
+	ReportPermissionID    int       `gorm:"column:report_permission_id;type:int(10);default:1" json:"reportPermissionId"`   // 权限id,用来查询分类
+	SingaporeTelephone    string    `gorm:"column:singapore_telephone;type:varchar(30)" json:"singaporeTelephone"`          // 新加坡拨入电话
+	VideoURL              string    `gorm:"column:video_url;type:varchar(500)" json:"videoUrl"`                             // 音频文件URL
+	VideoName             string    `gorm:"column:video_name;type:varchar(125);default:''" json:"videoName"`                // 音频文件名称
+	VideoPlaySeconds      string    `gorm:"column:video_play_seconds;type:varchar(255);default:''" json:"videoPlaySeconds"` // 音频播放时长
+	Remark                string    `gorm:"column:remark;type:varchar(255);default:''" json:"remark"`                       // 简介
+	HkTelephone           string    `gorm:"column:hk_telephone;type:varchar(30)" json:"hkTelephone"`                        // 香港拨入电话
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *Teleconference) TableName() string {
+	return "teleconference"
+}
+
+// TeleconferenceColumns get sql column name.获取数据库列名
+var TeleconferenceColumns = struct {
+	TeleconferenceID      string
+	TeleconferenceTitle   string
+	Type                  string
+	Speaker               string
+	Telephone             string
+	Password              string
+	StartTime             string
+	EndTime               string
+	ReferResearchReportID string
+	Enabled               string
+	CreatedTime           string
+	LastUpdatedTime       string
+	ReportPermissionID    string
+	SingaporeTelephone    string
+	VideoURL              string
+	VideoName             string
+	VideoPlaySeconds      string
+	Remark                string
+	HkTelephone           string
+}{
+	TeleconferenceID:      "teleconference_id",
+	TeleconferenceTitle:   "teleconference_title",
+	Type:                  "type",
+	Speaker:               "speaker",
+	Telephone:             "telephone",
+	Password:              "password",
+	StartTime:             "start_time",
+	EndTime:               "end_time",
+	ReferResearchReportID: "refer_research_report_id",
+	Enabled:               "enabled",
+	CreatedTime:           "created_time",
+	LastUpdatedTime:       "last_updated_time",
+	ReportPermissionID:    "report_permission_id",
+	SingaporeTelephone:    "singapore_telephone",
+	VideoURL:              "video_url",
+	VideoName:             "video_name",
+	VideoPlaySeconds:      "video_play_seconds",
+	Remark:                "remark",
+	HkTelephone:           "hk_telephone",
+}

+ 9 - 0
models/tables/teleconference_video/query.go

@@ -0,0 +1,9 @@
+package teleconference_video
+
+import "hongze/hongze_yb/global"
+
+// GetListByTeleconferenceIds 通过电话会IDs获取集合
+func GetListByTeleconferenceIds(ids []int) (list []*TeleconferenceVideo, err error) {
+	err = global.DEFAULT_MYSQL.Model(TeleconferenceVideo{}).Where("teleconference_id IN (?)", ids).Scan(&list).Error
+	return
+}

+ 37 - 0
models/tables/teleconference_video/teleconference_video.go

@@ -0,0 +1,37 @@
+package teleconference_video
+
+import (
+	"time"
+)
+
+// TeleconferenceVideo [...]
+type TeleconferenceVideo struct {
+	TeleconferenceVideoID int       `gorm:"primaryKey;column:teleconference_video_id;type:int(11);not null" json:"-"`
+	TeleconferenceID      int       `gorm:"index:idx_teleconference_id;column:teleconference_id;type:int(11);default:0" json:"teleconferenceId"`
+	VideoURL              string    `gorm:"unique;column:video_url;type:varchar(500);default:''" json:"videoUrl"`
+	VideoName             string    `gorm:"column:video_name;type:varchar(255);default:''" json:"videoName"`
+	VideoPlaySeconds      string    `gorm:"column:video_play_seconds;type:varchar(255);default:''" json:"videoPlaySeconds"`
+	CreateTime            time.Time `gorm:"column:create_time;type:datetime" json:"createTime"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *TeleconferenceVideo) TableName() string {
+	return "teleconference_video"
+}
+
+// TeleconferenceVideoColumns get sql column name.获取数据库列名
+var TeleconferenceVideoColumns = struct {
+	TeleconferenceVideoID string
+	TeleconferenceID      string
+	VideoURL              string
+	VideoName             string
+	VideoPlaySeconds      string
+	CreateTime            string
+}{
+	TeleconferenceVideoID: "teleconference_video_id",
+	TeleconferenceID:      "teleconference_id",
+	VideoURL:              "video_url",
+	VideoName:             "video_name",
+	VideoPlaySeconds:      "video_play_seconds",
+	CreateTime:            "create_time",
+}

+ 9 - 0
models/tables/user_record/update.go

@@ -46,3 +46,12 @@ func ModifySessionKeyByOpenid(openId, sessionKey string) (err error) {
 	}).Error
 	return
 }
+
+// UnBindUserRecordByUnionId 根据unionId和平台信息解除绑定用户关系
+func UnBindUserRecordByUnionId(unionId string, platform int) (err error) {
+	err = global.DEFAULT_MYSQL.Model(UserRecord{}).Select("UserID", "BindAccount").Where("union_id = ? AND create_platform = ?", unionId, platform).Updates(UserRecord{
+		UserID:      0,
+		BindAccount: "",
+	}).Error
+	return
+}

+ 9 - 0
models/tables/yb_activity/create.go

@@ -0,0 +1,9 @@
+package yb_activity
+
+import "hongze/hongze_yb/global"
+
+func (activityInfo *YbActivity) Create() (activityId int, err error) {
+	err = global.DEFAULT_MYSQL.Create(activityInfo).Error
+	activityId = activityInfo.ActivityID
+	return
+}

+ 8 - 0
models/tables/yb_activity_permission/create.go

@@ -0,0 +1,8 @@
+package yb_activity_permission
+
+import "hongze/hongze_yb/global"
+
+func (item *YbActivityPermission) Create() (err error) {
+	err = global.DEFAULT_MYSQL.Create(item).Error
+	return
+}

+ 6 - 0
models/tables/yb_activity_permission/query.go

@@ -7,3 +7,9 @@ func GetPermissionsByActivityId(activityId int) (permissions []*YbActivityPermis
 	err = global.DEFAULT_MYSQL.Model(YbActivityPermission{}).Where("activity_id", activityId).Scan(&permissions).Error
 	return
 }
+
+// GetPermissionsByPermissionIds根据权限IDs获取权限集合
+func GetPermissionsByPermissionIds(permissionIds []int) (permissions []*YbActivityPermission, err error) {
+	err = global.DEFAULT_MYSQL.Model(YbActivityPermission{}).Where("permission_id IN (?)", permissionIds).Group("activity_id").Scan(&permissions).Error
+	return
+}

+ 6 - 0
models/tables/yb_activity_type/query.go

@@ -6,4 +6,10 @@ import "hongze/hongze_yb/global"
 func GetTypeByPid(pid int) (typeList []*YbActivityType, err error) {
 	err = global.DEFAULT_MYSQL.Model(YbActivityType{}).Where("pid", pid).Scan(&typeList).Error
 	return
+}
+
+// GetTypeList 获取活动类型列表
+func GetTypeList() (typeList []*YbActivityType, err error) {
+	err = global.DEFAULT_MYSQL.Model(YbActivityType{}).Scan(&typeList).Error
+	return
 }

+ 8 - 0
models/tables/yb_activity_voice/create.go

@@ -0,0 +1,8 @@
+package yb_activity_voice
+
+import "hongze/hongze_yb/global"
+
+func (item *YbActivityVoice) Create() (err error) {
+	err = global.DEFAULT_MYSQL.Create(item).Error
+	return
+}

+ 9 - 0
models/tables/yb_speaker/query.go

@@ -0,0 +1,9 @@
+package yb_speaker
+
+import "hongze/hongze_yb/global"
+
+// GetSpeakerList 获取主讲人列表
+func GetSpeakerList() (list []*YbSpeaker, err error) {
+	err = global.DEFAULT_MYSQL.Model(YbSpeaker{}).Scan(&list).Error
+	return
+}

+ 27 - 0
models/tables/yb_speaker/yb_speaker.go

@@ -0,0 +1,27 @@
+package yb_speaker
+
+type YbSpeaker struct {
+	SpeakerID            uint32 `gorm:"primaryKey;column:speaker_id;type:int(9) unsigned;not null" json:"speakerId"`                    // 主讲人id
+	SpeakerName          string `gorm:"column:speaker_name;type:varchar(255)" json:"speakerName"`                               // 主讲人名称
+	SpeakerHeadPic       string `gorm:"column:speaker_head_pic;type:varchar(255);default:''" json:"speakerHeadPic"`             // 主讲人头像
+	SpeakerBackgroundPic string `gorm:"column:speaker_background_pic;type:varchar(255);default:''" json:"speakerBackgroundPic"` // 主讲人背景图
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbSpeaker) TableName() string {
+	return "yb_speaker"
+}
+
+// YbSpeakerColumns get sql column name.获取数据库列名
+var YbSpeakerColumns = struct {
+	SpeakerID            string
+	SpeakerName          string
+	SpeakerHeadPic       string
+	SpeakerBackgroundPic string
+}{
+	SpeakerID:            "speaker_id",
+	SpeakerName:          "speaker_name",
+	SpeakerHeadPic:       "speaker_head_pic",
+	SpeakerBackgroundPic: "speaker_background_pic",
+}
+

+ 8 - 1
routers/activity.go

@@ -7,8 +7,8 @@ import (
 )
 
 func InitActivity(r *gin.Engine) {
+	// 需要Token
 	rGroup := r.Group("activity").Use(middleware.Token())
-
 	{
 		rGroup.GET("/getPageList", activity.GetPageList)
 		rGroup.GET("/getActivityDetail", activity.GetActivityDetail)
@@ -18,4 +18,11 @@ func InitActivity(r *gin.Engine) {
 		rGroup.POST("/registerActivity", activity.RegisterActivity)
 		rGroup.POST("/cancelRegister", activity.CancelRegister)
 	}
+	// 不需要Token
+	rGroup2 := r.Group("activity")
+	{
+		rGroup2.GET("/getActivityShareImg", activity.GetActivityShareImg)
+		// 同步三个月前活动
+		rGroup2.GET("/syncOldActivity", activity.SyncOldActivityData)
+	}
 }

+ 263 - 17
services/activity/activity.go

@@ -1,23 +1,38 @@
 package activity
 
 import (
+	"errors"
 	"gorm.io/gorm"
+	"hongze/hongze_yb/global"
+	"hongze/hongze_yb/models/tables/chart_permission"
+	"hongze/hongze_yb/models/tables/company_product"
+	"hongze/hongze_yb/models/tables/research_report"
+	"hongze/hongze_yb/models/tables/teleconference"
+	"hongze/hongze_yb/models/tables/teleconference_video"
 	"hongze/hongze_yb/models/tables/yb_activity"
 	"hongze/hongze_yb/models/tables/yb_activity_permission"
 	"hongze/hongze_yb/models/tables/yb_activity_register"
 	"hongze/hongze_yb/models/tables/yb_activity_remind"
+	"hongze/hongze_yb/models/tables/yb_activity_type"
 	"hongze/hongze_yb/models/tables/yb_activity_voice"
+	"hongze/hongze_yb/models/tables/yb_speaker"
 	"hongze/hongze_yb/services/company"
 	"hongze/hongze_yb/services/user"
 	"hongze/hongze_yb/utils"
 	"log"
+	"strconv"
+	"strings"
 	"time"
 )
 
-var WeekDay = [7]string{"周日", "周一", "周二", "周三", "周四", "周五", "周六"}
+// ActivityList 活动列表
+type ActivityList struct {
+	yb_activity.ActivityItem							// 活动信息
+	VoiceList	[]*yb_activity_voice.YbActivityVoice	// 音频列表
+}
 
 // PageList 活动分页列表
-func PageList(condition string, pars []interface{}, page, limit int, order string, userInfo user.UserInfo) (list []yb_activity.ActivityItem, err error) {
+func PageList(condition string, pars []interface{}, page, limit int, order string, userInfo user.UserInfo) (list []ActivityList, err error) {
 	activities, err := yb_activity.GetPageListByWhere(condition, pars, page, limit, order, int(userInfo.UserID))
 	if err != nil {
 		log.Print(err.Error())
@@ -35,10 +50,6 @@ func PageList(condition string, pars []interface{}, page, limit int, order strin
 			log.Print(queryErr.Error())
 			return
 		}
-		voiceMap := make(map[int]int, 0)
-		for _, voice := range voices {
-			voiceMap[int(voice.ActivityID)] = 1
-		}
 		// 提醒
 		reminds, queryErr := yb_activity_remind.GetRemindsByUserIdAndActivityIds(int(userInfo.UserID), activityIds)
 		if queryErr != nil {
@@ -62,24 +73,27 @@ func PageList(condition string, pars []interface{}, page, limit int, order strin
 			}
 		}
 
-		var temp yb_activity.ActivityItem
+		var temp ActivityList
 		for _, activity := range activities {
-			temp = activity
-			temp.WeekString = WeekDay[activity.StartTime.Weekday()]
+			temp.ActivityItem = activity
+			temp.WeekString = utils.StrDateTimeToWeek(activity.StartTime.Weekday().String())
 			temp.ActivityState = getActivityStateByTime(activity.StartTime, activity.EndTime)
-			// 是否有回放
-			tempActivity := activity
-			_, ok := voiceMap[tempActivity.ActivityID]
-			if ok {
-				temp.HasPlayBack = 1
+			// 音频列表
+			var voiceMap []*yb_activity_voice.YbActivityVoice
+			for _, voice := range voices {
+				if temp.ActivityID == int(voice.ActivityID) {
+					voiceMap = append(voiceMap, voice)
+					temp.HasPlayBack = 1	// 有回放
+				}
 			}
+			temp.VoiceList = voiceMap
 			// 是否有提醒
-			_, ok = remindMap[tempActivity.ActivityID]
+			_, ok := remindMap[temp.ActivityID]
 			if ok {
 				temp.HasRemind = 1
 			}
 			// 是否已报名
-			_, ok = registerMap[tempActivity.ActivityID]
+			_, ok = registerMap[temp.ActivityID]
 			if ok {
 				temp.RegisterState = 1
 			}
@@ -123,7 +137,7 @@ func GetActivityDetail(activityId, userId int) (detail *yb_activity.ActivityDeta
 		return
 	}
 	detail.RegisteredNum = int(registeredNum)
-	detail.WeekString = WeekDay[detail.StartTime.Weekday()]
+	detail.WeekString = utils.StrDateTimeToWeek(detail.StartTime.Weekday().String())
 	detail.ActivityState = getActivityStateByTime(detail.StartTime, detail.EndTime)
 	_, remindErr := yb_activity_remind.RemindExist(userId, activityId)
 	if remindErr != gorm.ErrRecordNotFound {
@@ -161,3 +175,235 @@ func CheckActivityPermission(userInfo user.UserInfo, activityId int) (ok bool, p
 	ok, permissionCheckInfo, err = company.CheckPermissionByPermissionIdList2Ficc(companyId, int(userInfo.UserID), permissionIds)
 	return
 }
+
+// GetUserAuthActivityIds 获取用户有权限参与的活动Ids
+func GetUserAuthActivityIds(userInfo user.UserInfo) (acrivityIds []int, err error) {
+	productId := 1
+	// 查询用户产品状态是否正常
+	companyProduct, err := company_product.GetByCompany2ProductId(userInfo.CompanyID, int64(productId))
+	if err != nil {
+		return
+	}
+	statusMatch := "正式,试用,永续"
+	if !strings.Contains(statusMatch, companyProduct.Status) || companyProduct.IsSuspend == 1 {
+		acrivityIds = append(acrivityIds, 0)
+		return
+	}
+	// 获取用户有效权限
+	validPermissionIdList, err := company.GetValidPermissionIdListByCompany2ProductId(userInfo.CompanyID, int64(productId))
+	if err != nil {
+		return
+	}
+	// 获取用户权限可参与的活动ID
+	permissions, err := yb_activity_permission.GetPermissionsByPermissionIds(validPermissionIdList)
+	if err != nil {
+		return
+	}
+	for _, v := range permissions {
+		acrivityIds = append(acrivityIds, int(v.ActivityID))
+	}
+
+	return
+}
+
+// SyncTeleconferenceOldData 同步旧数据
+func SyncTeleconferenceOldData() (countTotal, countSuccess int, err error) {
+	// 查询所有前三个月的电话会
+	condition := "enabled = 1"
+	pars := make([]interface{}, 0)
+	nowTime := time.Now()
+	threeMonth := nowTime.AddDate(0, -3, 0).Format(utils.FormatDateTime)
+	condition += " AND created_time >= ? AND created_time <= ?"
+	pars = append(pars, threeMonth, nowTime)
+	teleconferenceList, err := teleconference.GetTeleconferenceList(condition, pars)
+	if err != nil {
+		return
+	}
+	countTotal = len(teleconferenceList)
+	
+	// 取出电话会IDs和报告Ids
+	var teleconferenceIds, reportIds, chartPermissionIds []int
+	for i := 0; i < len(teleconferenceList); i++ {
+		teleconferenceIds = append(teleconferenceIds, int(teleconferenceList[i].TeleconferenceID))
+		reportIds = append(reportIds, int(teleconferenceList[i].ReferResearchReportID))
+		chartPermissionIds = append(chartPermissionIds, teleconferenceList[i].ReportPermissionID)
+	}
+
+	// 报告名称map
+	var reportIdNameMap = make(map[int]string, 0)
+	reportList, err := research_report.GetListByResearchReportIds(reportIds)
+	if err != nil {
+		return
+	}
+	for i := 0; i < len(reportList); i++ {
+		reportIdNameMap[int(reportList[i].ResearchReportID)] = reportList[i].ResearchReportName
+	}
+
+	// 活动类型map
+	var typeNameIdMap = make(map[string]int, 0)
+	var typeFirstMap = make(map[int]int, 0)
+	var typeIdNameMap = make(map[int]string, 0)
+	activityTypeList, err := yb_activity_type.GetTypeList()
+	if err != nil {
+		return
+	}
+	for _, activityType := range activityTypeList {
+		typeNameIdMap[activityType.ActivityTypeName] = activityType.ActivityTypeID
+		typeFirstMap[activityType.ActivityTypeID] = activityType.Pid
+		typeIdNameMap[activityType.ActivityTypeID] = activityType.ActivityTypeName
+	}
+
+	// 主讲人map
+	speakerList, err := yb_speaker.GetSpeakerList()
+	if err != nil {
+		return
+	}
+	var speakerNamePicMap = make(map[string]string, 0)
+	for i := 0; i < len(speakerList); i++ {
+		speakerNamePicMap[speakerList[i].SpeakerName] = speakerList[i].SpeakerHeadPic
+	}
+
+	// 音频列表
+	voicesList, err := teleconference_video.GetListByTeleconferenceIds(teleconferenceIds)
+	if err != nil {
+		return
+	}
+
+	// 图片权限map
+	chartPermissionList, err := chart_permission.GetListByIds(chartPermissionIds)
+	if err != nil {
+		return
+	}
+	var chartPermissionIdNameMap = make(map[int]string, 0)
+	for i := 0; i < len(chartPermissionList); i++ {
+		chartPermissionIdNameMap[int(chartPermissionList[i].ChartPermissionID)] = chartPermissionList[i].PermissionName
+	}
+
+	// 开启事务
+	tx := global.DEFAULT_MYSQL.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	// 遍历数据
+	for _, item := range teleconferenceList {
+
+		// 匹配报告名称和link
+		reportId := int(item.ReferResearchReportID)
+		linkUrl := `https://details.hzinsights.com/ficcReportDetail?research_report_id=`
+		if global.CONFIG.Serve.RunMode == `debug` {
+			linkUrl = `http://advisoryadmin.brilliantstart.cn/xcx_h5/ficcReportDetail?research_report_id=`
+		}
+		reportLink := linkUrl + strconv.Itoa(reportId)
+		reportName := reportIdNameMap[reportId]
+
+		// 匹配活动类型-中文匹配ID
+		var firstActivityTypeId, activityTypeId int
+		var firstActivityTypeName, activityTypeName string
+		activityTypeId = typeNameIdMap[item.Type]
+		if activityTypeId > 0 {
+			// 类型匹配到了
+			activityTypeName = typeIdNameMap[activityTypeId]
+			firstActivityTypeId = typeFirstMap[activityTypeId]
+			firstActivityTypeName = typeIdNameMap[firstActivityTypeId]
+		}
+
+		// 匹配主讲人头像
+		speakerName := item.Speaker
+		if speakerName == "" {
+			continue
+		} else if speakerName == "全体FICC研究员" || speakerName == "弘则FICC研究员" {
+			speakerName = "FICC研究员"
+		}
+		speakerPic := "https://hzstatic.hzinsights.com/static/images/202112/20211210/wn6c3oYKTfT4NbTZgRGflRuIBZaa.png"
+		for i := 0; i < len(speakerList); i++ {
+			if strings.Contains(speakerName, speakerList[i].SpeakerName) {
+				speakerName = speakerList[i].SpeakerName	// 存在多个人的情况,则以新表数据为准
+				speakerPic = speakerNamePicMap[speakerList[i].SpeakerName]
+				break
+			}
+		}
+
+		backgroundPic := ""
+		if firstActivityTypeId == 1 {
+			// 电话会议
+			backgroundPic = `https://hongze.oss-accelerate.aliyuncs.com/static/images/202112/20211214/nNSTxmH6lxlT0PAp7xcfJJTGX9Gu.png`
+		} else {
+			// 线下沙龙
+			backgroundPic = `https://hongze.oss-accelerate.aliyuncs.com/static/images/202112/20211214/k77gDxvFvuAnYUhF6PU1FOVDHI8O.png`
+		}
+
+		// 新增活动数据
+		activityInfo := &yb_activity.YbActivity{
+			FirstActivityTypeID: firstActivityTypeId,
+			FirstActivityTypeName: firstActivityTypeName,
+			ActivityTypeID: activityTypeId,
+			ActivityTypeName: activityTypeName,
+			ActivityName: item.TeleconferenceTitle,
+			StartTime: item.StartTime,
+			EndTime: item.EndTime,
+			Speaker: speakerName,
+			SpeakerHeadPic: speakerPic,
+			SpeakerBackgroundPic: backgroundPic,
+			SingaporeTel: item.SingaporeTelephone,
+			ParticipationCode: item.Password,
+			MainlandTel: item.Telephone,
+			HongKongTel: item.HkTelephone,
+			ReportID: reportId,
+			ReportLink: reportLink,
+			ReportName: reportName,
+			Remarks: item.Remark,
+			PublishStatus: 1,
+			IsSendWxMsg: 1,
+			IsSendSalonWxMsg: 1,
+			ModifyTime: nowTime,
+			CreateTime: nowTime,
+		}
+
+		// 开启事务之后的操作要使用tx
+		activityCreate := tx.Debug().Create(activityInfo)
+		if activityCreate.Error != nil {
+			err = errors.New("新增活动失败")
+			return
+		}
+		activityId := activityInfo.ActivityID
+
+		// 5.新增活动音频-音频列表
+		for _, voice := range voicesList {
+			if int(item.TeleconferenceID) == voice.TeleconferenceID {
+				activityVoice := &yb_activity_voice.YbActivityVoice{
+					ActivityVoiceID: activityId,
+					VoiceURL: voice.VideoURL,
+					VoiceName: voice.VideoName,
+					VoicePlaySeconds: voice.VideoPlaySeconds,
+					CreateTime: nowTime,
+				}
+				activityVoiceCreate := tx.Debug().Create(activityVoice)
+				if activityVoiceCreate.Error != nil {
+					err = errors.New("新增活动音频失败")
+					return
+				}
+			}
+		}
+
+		// 6.新增活动关联权限-源数据权限仅一个
+		activityPermission := &yb_activity_permission.YbActivityPermission{
+			ActivityID: uint32(activityId),
+			PermissionID: uint32(item.ReportPermissionID),
+			PermissionName: chartPermissionIdNameMap[item.ReportPermissionID],
+			CreateTime: nowTime,
+		}
+		activityPermissionCreate := tx.Debug().Create(activityPermission)
+		if activityPermissionCreate.Error != nil {
+			err = errors.New("新增活动权限失败")
+			return
+		}
+		countSuccess += 1
+	}
+
+	return
+}

+ 67 - 21
services/user/user.go

@@ -116,17 +116,57 @@ func GetWxUserItemByMobile(mobile string, platform int) (userInfo UserInfo, err
 
 // GetWxUserItemByUnionId 根据用户unionid和平台id获取用户信息
 func GetWxUserItemByUnionId(unionId string, platform int) (userInfo UserInfo, err error) {
-	//获取用户信息
-	userRecord, err := user_record.GetByUnionID(unionId, platform)
-	if err != nil {
+	// 获取用户信息
+	userRecord, userRecordErr := user_record.GetByUnionID(unionId, platform)
+	if userRecordErr != nil {
+		if userRecordErr == utils.ErrNoRow {
+			err = ERR_NO_USER_RECORD
+			return
+		} else {
+			err = userRecordErr
+			return
+		}
+	}
+
+	// 该union在系统中没有关联关系
+	if userRecord == nil {
+		err = ERR_NO_USER_RECORD
 		return
 	}
-	wxUser, err := wx_user.GetByUserId(userRecord.UserID)
-	if err != nil {
+
+	// 该openid没有绑定用户
+	if userRecord.UserID <= 0 {
+		err = ERR_USER_NOT_BIND
+		item := new(wx_user.WxUser)
+		//格式化返回用户数据
+		userInfo = formatWxUserAndUserRecord(item, userRecord)
 		return
 	}
-	//格式化返回用户数据
-	userInfo = formatWxUserAndUserRecord(wxUser, userRecord)
+
+	item, wxUserErr := wx_user.GetByUserId(userRecord.UserID)
+	if wxUserErr != nil {
+		err = wxUserErr
+
+		// 如果是找不到数据,那么可能是该用户被删除了,但是user_record没有删除对应的关系
+		if wxUserErr == utils.ErrNoRow {
+			// 用户被删除了,但是user_record没有删除对应的关系,那么去解除绑定
+			userUnbindErr := user_record.UnBindUserRecordByUnionId(unionId, platform)
+			if userUnbindErr != nil {
+				err = userUnbindErr
+				return
+			}
+			// 返回状态为用户未绑定
+			err = ERR_USER_NOT_BIND
+			item := new(wx_user.WxUser)
+			// 格式化返回用户数据
+			userInfo = formatWxUserAndUserRecord(item, userRecord)
+			return
+		}
+		return
+	}
+	// 格式化返回用户数据
+	userInfo = formatWxUserAndUserRecord(item, userRecord)
+
 	return
 }
 
@@ -173,6 +213,7 @@ func WxLogin(wxPlatform int, wxSession auth.ResCode2Session) (token string, user
 	sessionKey := wxSession.SessionKey
 
 	needUpdateSessionKey := true //是否更新sessionKey
+
 QUERY_WX_USER:
 	wxUser, wxUserErr := GetWxUserItemByOpenId(openId)
 	if wxUserErr == ERR_NO_USER_RECORD { //没有用户openid记录
@@ -187,7 +228,24 @@ QUERY_WX_USER:
 		//插入成功后,需要重新查询该用户,并进入下面的逻辑
 		goto QUERY_WX_USER
 	} else if wxUserErr == ERR_USER_NOT_BIND {
-		//没有用户信息
+		// 未绑定则去查询是否为弘则研究公众号用户,有相应的手机号邮箱信息则自动绑定
+		platformUser, platformErr := GetWxUserItemByUnionId(unionId, 1)
+		if platformErr == nil {
+			// 当公众号用户存在时
+			if platformUser.Mobile != "" || platformUser.Email != "" {
+				// 有手机号或邮箱则绑定信息则自动绑定并新增wx_user
+				countryCode := 0
+				if platformUser.CountryCode != "" {
+					countryCode, _ = strconv.Atoi(platformUser.CountryCode)
+				}
+				_, _, tempErr, errMsg := BindWxUser(openId, platformUser.Mobile, platformUser.Email, "", 3, countryCode, 1)
+				if tempErr != nil {
+					err = errors.New("自动绑定公众号用户失败" + errMsg)
+					return
+				}
+				isBind = true
+			}
+		}
 	} else if wxUserErr != nil {
 		err = wxUserErr
 		return
@@ -198,14 +256,10 @@ QUERY_WX_USER:
 		_ = user_record.ModifySessionKeyByOpenid(openId, sessionKey)
 	}
 
-	//如果已经登录注册绑定的情况下
+	// 如果已经登录注册绑定的情况下/或者首次登录且为弘则研究公众号用户
 	if wxUserErr == nil {
 		userId = int(wxUser.UserID)
 
-		//if wxUserInfo != nil {
-		//	go models.ModifyUserRecordInfo(openId, wxUserInfo.Nickname, wxUserInfo.Headimgurl, wxUserInfo.City, wxUserInfo.Province, wxUserInfo.Country, wxUserInfo.Sex, userId)
-		//}
-
 		// 如果账户有绑定了手机号或者邮箱,那么标记为已绑定
 		if wxUser.Mobile != "" || wxUser.Email != "" {
 			isBind = true
@@ -225,14 +279,6 @@ QUERY_WX_USER:
 		token = utils.MD5(openId) + utils.MD5(timeUnixStr)
 		//新增session
 		{
-			//session := new(session.Session)
-			//session.OpenID = openId
-			//session.UserID = int64(userId)
-			//session.CreatedTime = time.Now()
-			//session.LastUpdatedTime = time.Now()
-			//session.ExpireTime = time.Now().AddDate(0, 3, 0)
-			//session.AccessToken = token
-
 			sessionItem := &session.Session{
 				OpenID:          openId,
 				UserID:          int64(userId),

BIN
static/img/report_share.png


BIN
static/img/report_share_sl.png


BIN
static/img/reportdetail_share.png


BIN
static/ttf/songti.ttf


+ 296 - 0
utils/drawtext.go

@@ -0,0 +1,296 @@
+package utils
+
+import (
+	"bytes"
+	"fmt"
+	"image"
+	"image/color"
+	"image/draw"
+	"image/gif"
+	"image/jpeg"
+	"image/png"
+	"io/ioutil"
+	"net/http"
+	"os"
+
+	"github.com/golang/freetype"
+	"github.com/golang/freetype/truetype"
+	"golang.org/x/image/font"
+)
+
+//DrawTextInfo 图片绘字信息
+type DrawTextInfo struct {
+	Text string
+	X    int
+	Y    int
+}
+
+//DrawRectInfo 图片画框信息
+type DrawRectInfo struct {
+	X1 int
+	Y1 int
+	X2 int
+	Y2 int
+}
+
+//TextBrush 字体相关
+type TextBrush struct {
+	FontType  *truetype.Font
+	FontSize  float64
+	FontColor *image.Uniform
+	TextWidth int
+}
+
+//NewTextBrush 新生成笔刷
+func NewTextBrush(FontFilePath string, FontSize float64, FontColor *image.Uniform, textWidth int) (*TextBrush, error) {
+	fontFile, err := ioutil.ReadFile(FontFilePath)
+	if err != nil {
+		return nil, err
+	}
+	fontType, err := truetype.Parse(fontFile)
+	if err != nil {
+		return nil, err
+	}
+	if textWidth <= 0 {
+		textWidth = 20
+	}
+	return &TextBrush{FontType: fontType, FontSize: FontSize, FontColor: FontColor, TextWidth: textWidth}, nil
+}
+
+//DrawFontOnRGBA 图片插入文字
+func (fb *TextBrush) DrawFontOnRGBA(rgba *image.RGBA, pt image.Point, content string) {
+
+	c := freetype.NewContext()
+	c.SetDPI(72)
+	c.SetFont(fb.FontType)
+	c.SetHinting(font.HintingFull)
+	c.SetFontSize(fb.FontSize)
+	c.SetClip(rgba.Bounds())
+	c.SetDst(rgba)
+	c.SetSrc(fb.FontColor)
+
+	c.DrawString(content, freetype.Pt(pt.X, pt.Y))
+
+}
+
+//Image2RGBA Image2RGBA
+func Image2RGBA(img image.Image) *image.RGBA {
+
+	baseSrcBounds := img.Bounds().Max
+
+	newWidth := baseSrcBounds.X
+	newHeight := baseSrcBounds.Y
+
+	des := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight)) // 底板
+	//首先将一个图片信息存入jpg
+	draw.Draw(des, des.Bounds(), img, img.Bounds().Min, draw.Over)
+
+	return des
+}
+
+type FontRGBA struct {
+	R uint8
+	G uint8
+	B uint8
+	A uint8
+}
+
+//DrawStringOnImageAndSave 图片上写文字
+func DrawStringOnImageAndSave(imagePath string, imageData []byte, infos []*DrawTextInfo, colorRGBA FontRGBA) (err error) {
+	//判断图片类型
+	var backgroud image.Image
+	filetype := http.DetectContentType(imageData)
+	switch filetype {
+	case "image/jpeg", "image/jpg":
+		backgroud, err = jpeg.Decode(bytes.NewReader(imageData))
+		if err != nil {
+			fmt.Println("jpeg error")
+			return err
+		}
+
+	case "image/gif":
+		backgroud, err = gif.Decode(bytes.NewReader(imageData))
+		if err != nil {
+			return err
+		}
+
+	case "image/png":
+		backgroud, err = png.Decode(bytes.NewReader(imageData))
+		if err != nil {
+			return err
+		}
+	default:
+		return err
+	}
+	des := Image2RGBA(backgroud)
+
+	//新建笔刷
+	ttfPath := "static/ttf/songti.ttf"
+	textBrush, _ := NewTextBrush(ttfPath, 25, image.Black, 50)
+
+	//Px Py 绘图开始坐标 text要绘制的文字
+	//调整颜色
+	c := freetype.NewContext()
+	c.SetDPI(72)
+	c.SetFont(textBrush.FontType)
+	c.SetHinting(font.HintingFull)
+	c.SetFontSize(textBrush.FontSize)
+	c.SetClip(des.Bounds())
+	c.SetDst(des)
+	textBrush.FontColor = image.NewUniform(color.RGBA{
+		R: colorRGBA.R,
+		G: colorRGBA.G,
+		B: colorRGBA.B,
+		A: colorRGBA.A,
+	})
+	c.SetSrc(textBrush.FontColor)
+
+	for _, info := range infos {
+		c.DrawString(info.Text, freetype.Pt(info.X, info.Y))
+	}
+
+	//保存图片
+	fSave, err := os.Create(imagePath)
+	if err != nil {
+		return err
+	}
+	defer fSave.Close()
+
+	err = jpeg.Encode(fSave, des, nil)
+
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+//DrawRectOnImageAndSave 图片上画多个框
+func DrawRectOnImageAndSave(imagePath string, imageData []byte, infos []*DrawRectInfo) (err error) {
+	//判断图片类型
+	var backgroud image.Image
+	filetype := http.DetectContentType(imageData)
+	switch filetype {
+	case "image/jpeg", "image/jpg":
+		backgroud, err = jpeg.Decode(bytes.NewReader(imageData))
+		if err != nil {
+			fmt.Println("jpeg error")
+			return err
+		}
+
+	case "image/gif":
+		backgroud, err = gif.Decode(bytes.NewReader(imageData))
+		if err != nil {
+			return err
+		}
+
+	case "image/png":
+		backgroud, err = png.Decode(bytes.NewReader(imageData))
+		if err != nil {
+			return err
+		}
+	default:
+		return err
+	}
+	des := Image2RGBA(backgroud)
+	//新建笔刷
+	textBrush, _ := NewTextBrush("arial.ttf", 15, image.Black, 15)
+	for _, info := range infos {
+		var c *freetype.Context
+		c = freetype.NewContext()
+		c.SetDPI(72)
+		c.SetFont(textBrush.FontType)
+		c.SetHinting(font.HintingFull)
+		c.SetFontSize(textBrush.FontSize)
+		c.SetClip(des.Bounds())
+		c.SetDst(des)
+		cGreen := image.NewUniform(color.RGBA{
+			R: 0,
+			G: 0xFF,
+			B: 0,
+			A: 255,
+		})
+
+		c.SetSrc(cGreen)
+		for i := info.X1; i < info.X2; i++ {
+			c.DrawString("·", freetype.Pt(i, info.Y1))
+			c.DrawString("·", freetype.Pt(i, info.Y2))
+		}
+		for j := info.Y1; j < info.Y2; j++ {
+			c.DrawString("·", freetype.Pt(info.X1, j))
+			c.DrawString("·", freetype.Pt(info.X2, j))
+		}
+	}
+
+	//保存图片
+	fSave, err := os.Create(imagePath)
+	if err != nil {
+		return err
+	}
+	defer fSave.Close()
+
+	err = jpeg.Encode(fSave, des, nil)
+
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+//DrawStringOnImage 生成图片
+func DrawStringOnImage(imageData []byte, infos []*DrawTextInfo, colorRGBA FontRGBA, fontSize float64, fontWidth int) (picBytes bytes.Buffer, err error) {
+	//判断图片类型
+	var backgroud image.Image
+	filetype := http.DetectContentType(imageData)
+	switch filetype {
+	case "image/jpeg", "image/jpg":
+		backgroud, err = jpeg.Decode(bytes.NewReader(imageData))
+		if err != nil {
+			fmt.Println("jpeg error")
+			return
+		}
+
+	case "image/gif":
+		backgroud, err = gif.Decode(bytes.NewReader(imageData))
+		if err != nil {
+			return
+		}
+
+	case "image/png":
+		backgroud, err = png.Decode(bytes.NewReader(imageData))
+		if err != nil {
+			return
+		}
+	default:
+		return
+	}
+	des := Image2RGBA(backgroud)
+
+	//新建笔刷
+	ttfPath := "static/ttf/songti.ttf"
+	textBrush, _ := NewTextBrush(ttfPath, fontSize, image.Black, fontWidth)
+
+	//Px Py 绘图开始坐标 text要绘制的文字
+	//调整颜色
+	c := freetype.NewContext()
+	c.SetDPI(72)
+	c.SetFont(textBrush.FontType)
+	c.SetHinting(font.HintingFull)
+	c.SetFontSize(textBrush.FontSize)
+	c.SetClip(des.Bounds())
+	c.SetDst(des)
+	textBrush.FontColor = image.NewUniform(color.RGBA{
+		R: colorRGBA.R,
+		G: colorRGBA.G,
+		B: colorRGBA.B,
+		A: colorRGBA.A,
+	})
+	c.SetSrc(textBrush.FontColor)
+
+	for _, info := range infos {
+		c.DrawString(info.Text, freetype.Pt(info.X, info.Y))
+	}
+
+	err = jpeg.Encode(&picBytes, des, nil)
+
+	return
+}