Browse Source

temp commit

hsun 2 years ago
parent
commit
1b1e232f7e

+ 5 - 4
controller/pc/pc.go

@@ -453,16 +453,17 @@ func GetSunCode(c *gin.Context) {
 	var sunCodeUrl string
 	//先查,查不到再去生成上传
 	item, err := yb_pc_suncode.GetYbPcSunCode(req.CodeScene, req.CodePage)
-	sunCodeUrl = item.SuncodeURL
 	if err != nil && err != utils.ErrNoRow {
-		response.Fail(err.Error(), c)
+		response.FailMsg("获取太阳码失败", err.Error(), c)
 		return
 	}
-
+	if item != nil && item.SuncodeURL != "" {
+		sunCodeUrl = item.SuncodeURL
+	}
 	if sunCodeUrl == "" {
 		sunCodeUrl, err = services.PcCreateAndUploadSunCode(req.CodeScene, req.CodePage)
 		if err != nil {
-			response.Fail(err.Error(), c)
+			response.FailMsg("生成太阳码失败", err.Error(), c)
 			return
 		}
 	}

+ 159 - 100
controller/voice_broadcast/voice_broadcast.go

@@ -1,11 +1,8 @@
 package voice_broadcast
 
 import (
-	"encoding/json"
-	"fmt"
 	"github.com/gin-gonic/gin"
 	"hongze/hongze_yb/controller/response"
-	"hongze/hongze_yb/global"
 	"hongze/hongze_yb/models/request"
 	voiceResp "hongze/hongze_yb/models/response"
 	"hongze/hongze_yb/models/tables/voice_broadcast"
@@ -14,11 +11,8 @@ import (
 	"hongze/hongze_yb/services/company"
 	"hongze/hongze_yb/services/user"
 	"hongze/hongze_yb/utils"
-	"io/ioutil"
-	"os"
-	"path"
 	"strconv"
-	"time"
+	"strings"
 )
 
 // BroadcastList
@@ -79,116 +73,181 @@ func BroadcastList(c *gin.Context) {
 // @Success 200 {string} string "发布成功"
 // @failure 400 {string} string "发布失败"
 // @Router /add [post]
-func AddBroadcast(c *gin.Context) {
-	broadcastName := c.PostForm("broadcast_name")
-	nsectionId := c.PostForm("section_id")
-	sectionId, _ := strconv.Atoi(nsectionId)
-	sectionName := c.PostForm("section_name")
-	nvarietyId := c.PostForm("variety_id")
-	varietyId, _ := strconv.Atoi(nvarietyId)
-	varietyName := c.PostForm("variety_name")
-	nauthorId := c.PostForm("author_id")
-	authorId, _ := strconv.Atoi(nauthorId)
-	author := c.PostForm("author")
-	imgUrl := c.PostForm("img_url")
-	file, err := c.FormFile("file")
-	if err != nil {
-		response.FailMsg("获取资源失败", "获取资源失败, Err:"+err.Error(), c)
-		return
-	}
-	if imgUrl == "" {
-		response.Fail("图片不能为空", c)
-		return
-	}
-	// 生成动态分享图
-	createTimeStr := time.Now().Local().Format(utils.FormatDate)
-	pars := services.VoiceBroadcastShareImgPars{
-		BackgroundImg: imgUrl,
-		Title:         sectionName,
-		CreateTime:    createTimeStr,
-	}
-	parsByte, e := json.Marshal(pars)
-	if e != nil {
-		response.Fail("分享图参数有误", c)
-		return
-	}
-	shareImg, e := services.GetDynamicShareImg(services.VoiceBroadcastShareImgSource, string(parsByte))
-	if e != nil {
-		response.Fail("生成分享图失败", c)
-		return
-	}
+//func AddBroadcast(c *gin.Context) {
+//	broadcastName := c.PostForm("broadcast_name")
+//	nsectionId := c.PostForm("section_id")
+//	sectionId, _ := strconv.Atoi(nsectionId)
+//	sectionName := c.PostForm("section_name")
+//	nvarietyId := c.PostForm("variety_id")
+//	varietyId, _ := strconv.Atoi(nvarietyId)
+//	varietyName := c.PostForm("variety_name")
+//	nauthorId := c.PostForm("author_id")
+//	authorId, _ := strconv.Atoi(nauthorId)
+//	author := c.PostForm("author")
+//	imgUrl := c.PostForm("img_url")
+//	file, err := c.FormFile("file")
+//	if err != nil {
+//		response.FailMsg("获取资源失败", "获取资源失败, Err:"+err.Error(), c)
+//		return
+//	}
+//	if imgUrl == "" {
+//		response.Fail("图片不能为空", c)
+//		return
+//	}
+//	// 生成动态分享图
+//	createTimeStr := time.Now().Local().Format(utils.FormatDate)
+//	pars := services.VoiceBroadcastShareImgPars{
+//		BackgroundImg: imgUrl,
+//		Title:         sectionName,
+//		CreateTime:    createTimeStr,
+//	}
+//	parsByte, e := json.Marshal(pars)
+//	if e != nil {
+//		response.Fail("分享图参数有误", c)
+//		return
+//	}
+//	shareImg, e := services.GetDynamicShareImg(services.VoiceBroadcastShareImgSource, string(parsByte))
+//	if e != nil {
+//		response.Fail("生成分享图失败", c)
+//		return
+//	}
+//
+//	ext := path.Ext(file.Filename)
+//	if ext != ".mp3" {
+//		response.Fail("暂仅支持mp3格式", c)
+//		return
+//	}
+//	dateDir := time.Now().Format("20060102")
+//	localDir := global.CONFIG.Serve.StaticDir + "hongze/" + dateDir
+//	if err := os.MkdirAll(localDir, 0766); err != nil {
+//		response.FailMsg("存储目录创建失败", "QuestionUploadAudio 存储目录创建失败, Err:"+err.Error(), c)
+//		return
+//	}
+//	randStr := utils.GetRandStringNoSpecialChar(28)
+//	filtName := randStr + ext
+//	fpath := localDir + "/" + filtName
+//	defer func() {
+//		_ = os.Remove(fpath)
+//	}()
+//	// 生成文件至指定目录
+//	if err := c.SaveUploadedFile(file, fpath); err != nil {
+//		response.FailMsg("文件生成失败", "QuestionUploadAudio 文件生成失败, Err:"+err.Error(), c)
+//		return
+//	}
+//	// 获取音频文件时长
+//	fByte, err := ioutil.ReadFile(fpath)
+//	if err != nil {
+//		response.FailMsg("读取本地文件失败", "QuestionUploadAudio 读取本地文件失败", c)
+//		return
+//	}
+//	if len(fByte) <= 0 {
+//		response.FailMsg("文件大小有误", "QuestionUploadAudio 文件大小有误", c)
+//		return
+//	}
+//	seconds, err := services.GetMP3PlayDuration(fByte)
+//	if err != nil {
+//		response.FailMsg("读取文件时长失败", "QuestionUploadAudio 读取文件时长失败", c)
+//		return
+//	}
+//	// 音频大小MB
+//	fi, err := os.Stat(fpath)
+//	if err != nil {
+//		response.FailMsg("读取文件大小失败", "QuestionUploadAudio 读取文件大小失败", c)
+//		return
+//	}
+//	mb := utils.Bit2MB(fi.Size(), 2)
+//	// 上传文件至阿里云
+//	ossDir := "yb_wx/voice_broadcast/"
+//	resourceUrl, err := services.UploadAliyunToDir(filtName, fpath, ossDir)
+//	if err != nil {
+//		response.FailMsg("文件上传失败", "QuestionUploadAudio 文件上传失败, Err:"+err.Error(), c)
+//		return
+//	}
+//
+//	voiceBroadcast := voice_broadcast.VoiceBroadcast{
+//		BroadcastName:    broadcastName,
+//		SectionId:        sectionId,
+//		SectionName:      sectionName,
+//		VarietyId:        varietyId,
+//		VarietyName:      varietyName,
+//		AuthorId:         authorId,
+//		Author:           author,
+//		ImgUrl:           shareImg,
+//		VoiceUrl:         resourceUrl,
+//		VoicePlaySeconds: fmt.Sprint(seconds),
+//		VoiceSize:        fmt.Sprint(mb),
+//		CreateTime:       time.Now().Format(utils.FormatDateTime),
+//	}
+//	err = voiceBroadcast.AddVoiceBroadcast()
+//	if err != nil {
+//		fmt.Println("AddUserViewHistory err", err.Error())
+//	}
+//	response.OkData("发布成功", voiceBroadcast.BroadcastId, c)
+//}
 
-	ext := path.Ext(file.Filename)
-	if ext != ".mp3" {
-		response.Fail("暂仅支持mp3格式", c)
+// PublishBroadcast
+// @Description 发布语音播报
+// @Param broadcast_id		query  int  	false  	"语音播报ID"
+// @Param broadcast_name	query  string  	true  	"语音标题"
+// @Param section_id		query  int  	true  	"板块ID"
+// @Param section_name		query  string  	true  	"板块名称"
+// @Param variety_id		query  int		true  	"品种ID"
+// @Param variety_name		query  string	true  	"品种名称"
+// @Param author_id			query  int		true  	"作者ID"
+// @Param author			query  string  	true  	"作者名称"
+// @Param img_url			query  string  	true  	"分享图背景"
+// @Param Imgs				query  string  	true  	"图片,英文逗号拼接"
+// @Param publish_type		query  string  	true  	"发布类型: 0-仅发布 1-发布并推送 2-定时发布"
+// @Param pre_publish_time	query  string  	false	"预发布时间"
+// @Param file				query  string  	true	"音频文件"
+// @Success 200 {string} string "发布成功"
+// @failure 400 {string} string "发布失败"
+// @Router /add [post]
+func PublishBroadcast(c *gin.Context) {
+	var req request.SaveBroadcastReq
+	if err := c.Bind(&req); err != nil {
+		response.Fail("参数有误", c)
 		return
 	}
-	dateDir := time.Now().Format("20060102")
-	localDir := global.CONFIG.Serve.StaticDir + "hongze/" + dateDir
-	if err := os.MkdirAll(localDir, 0766); err != nil {
-		response.FailMsg("存储目录创建失败", "QuestionUploadAudio 存储目录创建失败, Err:"+err.Error(), c)
+	// 参数校验
+	if req.BroadcastName == "" {
+		response.Fail("请输入标题", c)
 		return
 	}
-	randStr := utils.GetRandStringNoSpecialChar(28)
-	filtName := randStr + ext
-	fpath := localDir + "/" + filtName
-	defer func() {
-		_ = os.Remove(fpath)
-	}()
-	// 生成文件至指定目录
-	if err := c.SaveUploadedFile(file, fpath); err != nil {
-		response.FailMsg("文件生成失败", "QuestionUploadAudio 文件生成失败, Err:"+err.Error(), c)
+	if req.SectionId <= 0 || req.SectionName == "" {
+		response.Fail("请选择品种", c)
 		return
 	}
-	// 获取音频文件时长
-	fByte, err := ioutil.ReadFile(fpath)
-	if err != nil {
-		response.FailMsg("读取本地文件失败", "QuestionUploadAudio 读取本地文件失败", c)
+	if req.SectionId <= 0 || req.SectionName == "" {
+		response.Fail("请选择板块", c)
 		return
 	}
-	if len(fByte) <= 0 {
-		response.FailMsg("文件大小有误", "QuestionUploadAudio 文件大小有误", c)
+	if req.File == nil {
+		response.Fail("请上传音频", c)
 		return
 	}
-	seconds, err := services.GetMP3PlayDuration(fByte)
-	if err != nil {
-		response.FailMsg("读取文件时长失败", "QuestionUploadAudio 读取文件时长失败", c)
+	if req.ImgUrl == "" {
+		response.Fail("分享图背景不能为空", c)
 		return
 	}
-	// 音频大小MB
-	fi, err := os.Stat(fpath)
-	if err != nil {
-		response.FailMsg("读取文件大小失败", "QuestionUploadAudio 读取文件大小失败", c)
+	if req.PublishType == 2 && req.PrePublishTime == "" {
+		response.Fail("定时发布请选择发布时间", c)
 		return
 	}
-	mb := utils.Bit2MB(fi.Size(), 2)
-	// 上传文件至阿里云
-	ossDir := "yb_wx/voice_broadcast/"
-	resourceUrl, err := services.UploadAliyunToDir(filtName, fpath, ossDir)
-	if err != nil {
-		response.FailMsg("文件上传失败", "QuestionUploadAudio 文件上传失败, Err:"+err.Error(), c)
-		return
+	if req.Imgs != "" {
+		imgList := strings.Split(req.Imgs, ",")
+		if len(imgList) > 5 {
+			response.Fail("最多插入五张图片", c)
+			return
+		}
 	}
-
-	voiceBroadcast := voice_broadcast.VoiceBroadcast{
-		BroadcastName:    broadcastName,
-		SectionId:        sectionId,
-		SectionName:      sectionName,
-		VarietyId:        varietyId,
-		VarietyName:      varietyName,
-		AuthorId:         authorId,
-		Author:           author,
-		ImgUrl:           shareImg,
-		VoiceUrl:         resourceUrl,
-		VoicePlaySeconds: fmt.Sprint(seconds),
-		VoiceSize:        fmt.Sprint(mb),
-		CreateTime:       time.Now().Format(utils.FormatDateTime),
-	}
-	err = voiceBroadcast.AddVoiceBroadcast()
-	if err != nil {
-		fmt.Println("AddUserViewHistory err", err.Error())
+	// 发布语音
+	if msg, e := services.PublishVoiceBroadcast(req.BroadcastId, req.SectionId, req.VarietyId, req.AuthorId, req.PublishType, req.BroadcastName,
+		req.SectionName, req.VarietyName, req.Author, req.ImgUrl, req.PrePublishTime, req.Imgs, req.File); e != nil {
+		response.FailMsg(msg, e.Error(), c)
+		return
 	}
-	response.OkData("发布成功", voiceBroadcast.BroadcastId, c)
+	response.Ok("发布成功", c)
 }
 
 // SectionList

+ 19 - 26
models/request/voice_broadcast.go

@@ -1,6 +1,8 @@
 package request
 
-import "mime/multipart"
+import (
+	"mime/multipart"
+)
 
 type BroadcastListReq struct {
 	PageIndex   int `json:"page_index" form:"page_index"`
@@ -9,31 +11,6 @@ type BroadcastListReq struct {
 	SectionId   int `json:"section_id" form:"section_id"`
 }
 
-type AddBroadcastReq struct {
-	BroadcastName string                `json:"broadcast_name" `
-	SectionId     int                   `json:"section_id" `
-	SectionName   string                `json:"section_name"`
-	VarietyId     int                   `json:"variety_id"`
-	VarietyName   string                `json:"variety_name"`
-	AuthorId      int                   `json:"author_id"`
-	Author        string                `json:"author"`
-	File          *multipart.FileHeader `json:"file"`
-}
-
-//type AddBroadcastReq struct {
-//	BroadcastName    string `json:"page_index" `
-//	SectionId        int    `json:"section_id" `
-//	SectionName      string `json:"section_name"`
-//	VarietyId        int    `json:"variety_id"`
-//	VarietyName      string `json:"variety_name"`
-//	AuthorId         int    `json:"author_id"`
-//	Author           string `json:"author"`
-//	VoiceUrl         string `json:"voice_url"`
-//	VoicePlaySeconds string `json:"voice_play_seconds"`
-//	VoiceSize        string `json:"voice_size"`
-//	CreateTime       string `json:"create_time" `
-//}
-
 type AddBroadcastStatisticsReq struct {
 	Source      int `json:"source" description:"点击来源,1手机小程序,2pc小程序,3web端"`
 	BroadcastId int `json:"broadcast_id" `
@@ -46,3 +23,19 @@ type BroadcastDetailReq struct {
 type BroadcastMsgSendReq struct {
 	BroadcastId int `json:"broadcast_id" description:"语音播报ID"`
 }
+
+type SaveBroadcastReq struct {
+	BroadcastId      int                   `form:"broadcast_id" description:"语音播报ID"`
+	BroadcastName    string                `form:"broadcast_name" description:"语音标题"`
+	SectionId        int                   `form:"section_id" description:"板块ID"`
+	SectionName      string                `form:"section_name" description:"板块名称"`
+	VarietyId        int                   `form:"variety_id" description:"品种ID"`
+	VarietyName      string                `form:"variety_name" description:"品种名称"`
+	AuthorId         int                   `form:"author_id" description:"作者ID"`
+	Author           string                `form:"author" description:"作者名称"`
+	ImgUrl           string                `form:"img_url" description:"分享图背景"`
+	File             *multipart.FileHeader `form:"file" description:"语音文件"`
+	Imgs             string                `form:"imgs" description:"图片,英文逗号拼接"`
+	PublishType      int                   `form:"publish_type" description:"发布类型: 0-仅发布 1-发布并推送 2-定时发布"`
+	PrePublishTime   string                `form:"pre_publish_time" description:"预发布时间"`
+}

+ 53 - 1
models/tables/voice_broadcast/create.go

@@ -1,6 +1,9 @@
 package voice_broadcast
 
-import "hongze/hongze_yb/global"
+import (
+	"hongze/hongze_yb/global"
+	"hongze/hongze_yb/models/tables/voice_broadcast_img"
+)
 
 // AddVoiceBroadcast 新增记录
 func (voiceBroadcast *VoiceBroadcast) AddVoiceBroadcast() (err error) {
@@ -12,4 +15,53 @@ func (voiceBroadcast *VoiceBroadcast) AddVoiceBroadcast() (err error) {
 func (voiceBroadcast *VoiceBroadcast) Update(updateCols []string) (err error) {
 	err = global.DEFAULT_MYSQL.Model(voiceBroadcast).Select(updateCols).Updates(*voiceBroadcast).Error
 	return
+}
+
+// CreateVoiceBroadcastAndImgs 新增语音播报及图片
+func CreateVoiceBroadcastAndImgs(item *VoiceBroadcast, imgs []*voice_broadcast_img.YbVoiceBroadcastImg) (err error) {
+	tx := global.DEFAULT_MYSQL.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	if err = tx.Create(item).Error; err != nil {
+		return
+	}
+	imgLen := len(imgs)
+	if imgLen > 0 {
+		for i := 0; i < imgLen; i++ {
+			imgs[i].BroadcastId = item.BroadcastId
+		}
+		if err = tx.Model(voice_broadcast_img.YbVoiceBroadcastImg{}).CreateInBatches(imgs, len(imgs)).Error; err != nil {
+			return
+		}
+	}
+	return
+}
+
+// UpdateVoiceBroadcastAndImgs 更新语音播报及图片
+func UpdateVoiceBroadcastAndImgs(item *VoiceBroadcast, updateCols []string, imgs []*voice_broadcast_img.YbVoiceBroadcastImg) (err error) {
+	tx := global.DEFAULT_MYSQL.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	if err = tx.Model(item).Select(updateCols).Where("broadcast_id = ?", item.BroadcastId).Updates(*item).Error; err != nil {
+		return
+	}
+	if err = tx.Where("broadcast_id = ?", item.BroadcastId).Delete(voice_broadcast_img.YbVoiceBroadcastImg{}).Error; err != nil {
+		return
+	}
+	if len(imgs) > 0 {
+		if err = tx.Model(voice_broadcast_img.YbVoiceBroadcastImg{}).CreateInBatches(imgs, len(imgs)).Error; err != nil {
+			return
+		}
+	}
+	return
 }

+ 2 - 2
models/tables/voice_broadcast/query.go

@@ -20,8 +20,8 @@ func GetBroadcast(pageIndex, pageSize int) (list []*VoiceBroadcast, err error) {
 	return
 }
 
-func GetBroadcastById(broadcastId int) (list *VoiceBroadcast, err error) {
-	err = global.DEFAULT_MYSQL.Model(VoiceBroadcast{}).Where("broadcast_id=?", broadcastId).First(&list).Error
+func GetBroadcastById(broadcastId int) (item *VoiceBroadcast, err error) {
+	err = global.DEFAULT_MYSQL.Model(VoiceBroadcast{}).Where("broadcast_id=?", broadcastId).First(&item).Error
 	return
 }
 

+ 5 - 1
models/tables/voice_broadcast/voice_broadcast.go

@@ -1,7 +1,7 @@
 package voice_broadcast
 
 type VoiceBroadcast struct {
-	BroadcastId      int    `gorm:"primaryKey;column:broadcast_id;type:int(11)" description:"语音ID"`
+	BroadcastId      int    `gorm:"primaryKey;column:broadcast_id;type:int(11)" description:"语音ID" json:"BroadcastId"`
 	BroadcastName    string `description:"语音名称"`
 	SectionId        int    `description:"语音分类ID"`
 	SectionName      string `description:"语音分类名称"`
@@ -14,6 +14,10 @@ type VoiceBroadcast struct {
 	VoicePlaySeconds string `description:"音频时长"`
 	VoiceSize        string `description:"音频大小"`
 	CreateTime       string `description:"创建时间"`
+	ModifyTime       string `description:"更新时间"`
+	PublishState     int    `description:"发布状态:0-未发布 1-已发布"`
+	PublishTime      string `description:"发布时间"`
+	PrePublishTime   string `description:"预发布时间"`
 	MsgState         int    `description:"消息推送状态:0-待推送 1-已推送"`
 	MsgTime          string `description:"消息推送时间"`
 }

+ 29 - 0
models/tables/voice_broadcast_img/entity.go

@@ -0,0 +1,29 @@
+package voice_broadcast_img
+
+import "time"
+
+// YbVoiceBroadcastImg 语音播报图片表
+type YbVoiceBroadcastImg struct {
+	Id          int       `gorm:"primaryKey;column:id;type:int(10) unsigned;not null" json:"-"`
+	BroadcastId int       `gorm:"index:idx_broadcast_id;column:broadcast_id;type:int(10) unsigned;not null;default:0" json:"broadcastId"` // 语音播报ID
+	ImgUrl      string    `gorm:"column:img_url;type:varchar(255);not null;default:''" json:"imgUrl"`                                     // 图片
+	CreateTime  time.Time `gorm:"column:create_time;type:datetime" json:"createTime"`                                                     // 创建时间
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbVoiceBroadcastImg) TableName() string {
+	return "yb_voice_broadcast_img"
+}
+
+// YbVoiceBroadcastImgColumns get sql column name.获取数据库列名
+var YbVoiceBroadcastImgColumns = struct {
+	ID          string
+	BroadcastID string
+	ImgURL      string
+	CreateTime  string
+}{
+	ID:          "id",
+	BroadcastID: "broadcast_id",
+	ImgURL:      "img_url",
+	CreateTime:  "create_time",
+}

+ 1 - 0
models/tables/voice_broadcast_img/model.go

@@ -0,0 +1 @@
+package voice_broadcast_img

+ 1 - 1
routers/voice_broadcast.go

@@ -9,7 +9,7 @@ import (
 func InitVoiceBroadcast(r *gin.Engine)  {
 	rGroup := r.Group("api/voice/broadcast").Use(middleware.Token())
 	rGroup.POST("/list", voice_broadcast.BroadcastList)
-	rGroup.POST("/add", voice_broadcast.AddBroadcast)
+	rGroup.POST("/add", voice_broadcast.PublishBroadcast)
 	rGroup.GET("/section/list", voice_broadcast.SectionList)
 	rGroup.GET("/delete", voice_broadcast.DelBroadcast)
 	rGroup.POST("/statistics/add", voice_broadcast.AddStatistics)

+ 29 - 0
services/file.go

@@ -0,0 +1,29 @@
+package services
+
+import (
+	"io"
+	"mime/multipart"
+	"os"
+)
+
+// SaveUploadedFile 保存上传的本地文件
+func SaveUploadedFile(file *multipart.FileHeader, fpath string) (err error) {
+	src, err := file.Open()
+	if err != nil {
+		return err
+	}
+	defer func() {
+		_ = src.Close()
+	}()
+
+	out, err := os.Create(fpath)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		_ = out.Close()
+	}()
+
+	_, err = io.Copy(out, src)
+	return
+}

+ 199 - 0
services/voice_broadcast.go

@@ -10,11 +10,17 @@ import (
 	"hongze/hongze_yb/models/tables/company_product"
 	"hongze/hongze_yb/models/tables/sys_role_admin"
 	"hongze/hongze_yb/models/tables/voice_broadcast"
+	"hongze/hongze_yb/models/tables/voice_broadcast_img"
 	"hongze/hongze_yb/models/tables/voice_broadcast_statistics"
 	"hongze/hongze_yb/models/tables/voice_section"
 	"hongze/hongze_yb/services/user"
 	"hongze/hongze_yb/services/wechat"
 	"hongze/hongze_yb/utils"
+	"io/ioutil"
+	"mime/multipart"
+	"os"
+	"path"
+	"strings"
 	"time"
 )
 
@@ -327,3 +333,196 @@ func UpdateVoiceBroadcastImgUrl() (err error) {
 	}
 	return
 }
+
+// PublishVoiceBroadcast 发布语音播报
+func PublishVoiceBroadcast(broadcastId, sectionId, varietyId, authorId, publishType int, broadcastName, sectionName, varietyName, author,
+	imgUrl, prePublishTime, imgs string, voiceFile *multipart.FileHeader) (errMsg string, err error) {
+	// broadcastId > 0为编辑
+	var e error
+	item := new(voice_broadcast.VoiceBroadcast)
+	if broadcastId > 0 {
+		// 语音播报
+		// TODO:主键
+		item, e := voice_broadcast.GetBroadcastById(broadcastId)
+		fmt.Println(broadcastId)
+		if e != nil || item.BroadcastId == 0 {
+			errMsg = "语音播报信息有误"
+			err = errors.New("语音播报信息有误\n")
+			return
+		}
+	}
+	fmt.Println(item.BroadcastId)
+	return
+	item.CreateTime = time.Now().Local().Format(utils.FormatDateTime)
+	item.PublishTime = ""
+	item.PrePublishTime = ""
+	updateCols := []string{"BroadcastName", "SectionId", "SectionName", "VarietyId", "VarietyName", "AuthorId", "Author", "ImgUrl", "VoiceUrl",
+		"VoicePlaySeconds", "VoiceSize", "ModifyTime", "PublisState"}
+
+	// publishType: 0-仅发布 1-发布并推送 2-定时发布; 发布类型为定时发送时, 分享图时间取预发布时间
+	publishTime := time.Now().Local()
+	if publishType == 2 {
+		updateCols = append(updateCols, "PrePublishTime")
+		item.PublishState = 0
+		item.PrePublishTime = prePublishTime
+		publishTime, e = time.ParseInLocation(utils.FormatDateTime, prePublishTime, time.Local)
+		if e != nil {
+			errMsg = "预发布时间有误"
+			err = errors.New("预发布时间有误, Err:" + "\n" + e.Error())
+			return
+		}
+	} else {
+		// TODO:新增时为定时发布,编辑时为仅发布是否需要重置定时发布时间
+		updateCols = append(updateCols, "PublishTime", "PrePublishTime")
+		item.PublishState = 1
+		item.PublishTime = publishTime.Format(utils.FormatDateTime)
+		item.PrePublishTime = ""
+		if publishType == 1 {
+			updateCols = append(updateCols, "MsgState", "MsgTime")
+			item.MsgState = 1
+			item.MsgTime = time.Now().Format(utils.FormatDateTime)
+		}
+	}
+	shareTime := publishTime.Format(utils.FormatDate)
+	shareImg, e := createVoiceBroadcastShareImg(imgUrl, sectionName, shareTime)
+	if e != nil {
+		errMsg = "生成分享图失败"
+		err = errors.New("生成分享图失败, Err: " + "\n" + e.Error())
+		return
+	}
+
+	// 上传音频
+	fileSeconds, fileSize, resourceUrl, e := handleVoiceBroadcastFile(voiceFile)
+	if e != nil {
+		errMsg = "语音信息有误"
+		err = errors.New("上传音频失败, Err: " + "\n" + e.Error())
+		return
+	}
+
+	// 语音播报及图片
+	item.BroadcastName = broadcastName
+	item.SectionId = sectionId
+	item.SectionName = sectionName
+	item.VarietyId = varietyId
+	item.VarietyName = varietyName
+	item.AuthorId = authorId
+	item.Author = author
+	item.ImgUrl = shareImg
+	item.VoiceUrl = resourceUrl
+	item.VoicePlaySeconds = fmt.Sprint(fileSeconds)
+	item.VoiceSize = fmt.Sprint(fileSize)
+	item.ModifyTime = time.Now().Local().Format(utils.FormatDateTime)
+
+	imgList := make([]*voice_broadcast_img.YbVoiceBroadcastImg, 0)
+	imgArr := strings.Split(imgs, ",")
+	imgLen := len(imgList)
+	nowTime := time.Now().Local()
+	for i := 0; i < imgLen; i++ {
+		imgList = append(imgList, &voice_broadcast_img.YbVoiceBroadcastImg{
+			BroadcastId: item.BroadcastId,
+			ImgUrl: imgArr[i],
+			CreateTime: nowTime,
+		})
+	}
+	// 新增/更新
+	if broadcastId > 0 {
+		if e := voice_broadcast.UpdateVoiceBroadcastAndImgs(item, updateCols, imgList); e != nil {
+			errMsg = "发布失败"
+			err = errors.New("更新语音播报及图片失败, Err: " + "\n" + e.Error())
+			return
+		}
+	} else {
+		if e := voice_broadcast.CreateVoiceBroadcastAndImgs(item, imgList); e != nil {
+			errMsg = "发布失败"
+			err = errors.New("新增语音播报及图片失败, Err: " + "\n" + e.Error())
+			return
+		}
+	}
+
+	// 推送模板及客群消息
+	if publishType == 1 {
+		go func() {
+			_ = wechat.SendVoiceBroadcastWxMsg(item.BroadcastId, item.SectionName, item.BroadcastName)
+		}()
+		go func() {
+			_ = SendVoiceBroadcastToThs(item)
+		}()
+	}
+	return
+}
+
+// createVoiceBroadcastShareImg 生成动态分享图
+func createVoiceBroadcastShareImg(baseImg, sectionName, createTime string) (shareImg string, err error) {
+	pars := VoiceBroadcastShareImgPars{
+		BackgroundImg: baseImg,
+		Title:         sectionName,
+		CreateTime:    createTime,
+	}
+	parsByte, e := json.Marshal(pars)
+	if e != nil {
+		err = e
+		return
+	}
+	shareImg, e = GetDynamicShareImg(VoiceBroadcastShareImgSource, string(parsByte))
+	if e != nil {
+		err = e
+		return
+	}
+	return
+}
+
+// handleVoiceBroadcastFile 语音播报音频
+func handleVoiceBroadcastFile(voiceFile *multipart.FileHeader) (fileSeconds int, fileSize float64, resourceUrl string, err error) {
+	ext := path.Ext(voiceFile.Filename)
+	if ext != ".mp3" {
+		err = errors.New("暂仅支持mp3格式\n")
+		return
+	}
+	dateDir := time.Now().Format("20060102")
+	localDir := global.CONFIG.Serve.StaticDir + "hongze/" + dateDir
+	if e := os.MkdirAll(localDir, 0766); e != nil {
+		err = errors.New("创建目录失败, Err: " + "\n" + e.Error())
+		return
+	}
+	randStr := utils.GetRandStringNoSpecialChar(28)
+	filtName := randStr + ext
+	fpath := localDir + "/" + filtName
+	defer func() {
+		_ = os.Remove(fpath)
+	}()
+	// 生成文件至指定目录
+	if e := SaveUploadedFile(voiceFile, fpath); e != nil {
+		err = errors.New("本地文件生成失败, Err: " + "\n" + e.Error())
+		return
+	}
+	// 获取音频文件时长
+	fByte, e := ioutil.ReadFile(fpath)
+	if e != nil {
+		err = errors.New("读取本地文件失败, Err: " + "\n" + e.Error())
+		return
+	}
+	if len(fByte) <= 0 {
+		err = errors.New("文件大小有误\n")
+		return
+	}
+	fileSeconds, e = GetMP3PlayDuration(fByte)
+	if e != nil {
+		err = errors.New("读取文件时长失败, Err:" + "\n" + e.Error())
+		return
+	}
+	// 音频大小MB
+	fi, e := os.Stat(fpath)
+	if e != nil {
+		err = errors.New("读取文件大小失败, Err:" + "\n" + e.Error())
+		return
+	}
+	fileSize = utils.Bit2MB(fi.Size(), 2)
+	// 上传文件至阿里云
+	ossDir := "yb_wx/voice_broadcast/"
+	resourceUrl, e = UploadAliyunToDir(filtName, fpath, ossDir)
+	if e != nil {
+		err = errors.New("文件上传失败, Err:" + "\n" + e.Error())
+		return
+	}
+	return
+}