hsun před 2 roky
rodič
revize
639e6b0af6

+ 75 - 1
controller/public.go

@@ -7,10 +7,12 @@ import (
 	"hongze/hongze_yb/global"
 	"hongze/hongze_yb/logic"
 	"hongze/hongze_yb/models/request"
+	respond "hongze/hongze_yb/models/response"
 	"hongze/hongze_yb/models/tables/yb_suncode_pars"
 	"hongze/hongze_yb/services"
 	"hongze/hongze_yb/services/alarm_msg"
 	"hongze/hongze_yb/utils"
+	"io/ioutil"
 	"os"
 	"path"
 	"time"
@@ -181,4 +183,76 @@ func WechatWarning(c *gin.Context) {
 		go alarm_msg.SendAlarmMsg(tips, 2)
 	}
 	response.Ok("操作成功", c)
-}
+}
+
+// UploadAudio 上传音频文件
+// @Tags 公共模块
+// @Description 上传音频文件
+// @Param file  query  string  true  "音频文件"
+// @Success 200 {string} string "上传成功"
+// @failure 400 {string} string "上传失败"
+// @Router /public/upload_audio [post]
+func UploadAudio(c *gin.Context) {
+	file, err := c.FormFile("file")
+	if err != nil {
+		response.FailMsg("获取资源失败", "获取资源失败, Err:"+err.Error(), 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("存储目录创建失败", "UploadAudio 存储目录创建失败, 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("文件生成失败", "UploadAudio 文件生成失败, Err:"+err.Error(), c)
+		return
+	}
+	// 获取音频文件时长
+	fByte, err := ioutil.ReadFile(fpath)
+	if err != nil {
+		response.FailMsg("读取本地文件失败", "UploadAudio 读取本地文件失败", c)
+		return
+	}
+	if len(fByte) <= 0 {
+		response.FailMsg("文件大小有误", "UploadAudio 文件大小有误", c)
+		return
+	}
+	seconds, err := services.GetMP3PlayDuration(fByte)
+	if err != nil {
+		response.FailMsg("读取文件时长失败", "UploadAudio 读取文件时长失败", c)
+		return
+	}
+	// 音频大小MB
+	fi, err := os.Stat(fpath)
+	if err != nil {
+		response.FailMsg("读取文件大小失败", "UploadAudio 读取文件大小失败", c)
+		return
+	}
+	mb := utils.Bit2MB(fi.Size(), 2)
+	// 上传文件至阿里云
+	ossDir := "yb_wx/audio/"
+	resourceUrl, err := services.UploadAliyunToDir(filtName, fpath, ossDir)
+	if err != nil {
+		response.FailMsg("文件上传失败", "UploadAudio 文件上传失败, Err:"+err.Error(), c)
+		return
+	}
+	resp := &respond.CommunityQuestionAudioUpload{
+		AudioURL:         resourceUrl,
+		AudioPlaySeconds: fmt.Sprint(seconds),
+		AudioSize:        fmt.Sprint(mb),
+	}
+	response.OkData("上传成功", resp, c)
+}

+ 110 - 20
controller/voice_broadcast/voice_broadcast.go

@@ -56,9 +56,8 @@ func BroadcastList(c *gin.Context) {
 	response.OkData("获取成功", resp, c)
 }
 
-// PublishBroadcast
-// @Description 发布语音播报
-// @Param broadcast_id		query  int  	false  	"语音播报ID"
+// AddBroadcast
+// @Description 新增语音播报
 // @Param broadcast_name	query  string  	true  	"语音标题"
 // @Param section_id		query  int  	true  	"板块ID"
 // @Param section_name		query  string  	true  	"板块名称"
@@ -66,17 +65,16 @@ func BroadcastList(c *gin.Context) {
 // @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	"音频文件"
+// @Param Imgs				query  string  	false  	"图片,英文逗号拼接"
+// @Param voice_seconds		query  string  	true	"音频时长"
+// @Param voice_size		query  string  	true	"音频大小"
+// @Param voice_url			query  string  	true	"音频文件地址"
 // @Success 200 {string} string "发布成功"
 // @failure 400 {string} string "发布失败"
 // @Router /add [post]
-func PublishBroadcast(c *gin.Context) {
+func AddBroadcast(c *gin.Context) {
 	var req request.SaveBroadcastReq
-	if err := c.Bind(&req); err != nil {
+	if err := c.ShouldBind(&req); err != nil {
 		response.Fail("参数有误", c)
 		return
 	}
@@ -93,16 +91,68 @@ func PublishBroadcast(c *gin.Context) {
 		response.Fail("请选择板块", c)
 		return
 	}
-	if req.File == nil {
+	if req.VoiceUrl == "" || req.VoiceSeconds == "" || req.VoiceSize == "" {
 		response.Fail("请上传音频", c)
 		return
 	}
-	if req.ImgUrl == "" {
-		response.Fail("分享图背景不能为空", c)
+	if req.Imgs != "" {
+		imgList := strings.Split(req.Imgs, ",")
+		if len(imgList) > 5 {
+			response.Fail("最多插入五张图片", c)
+			return
+		}
+	}
+	// 新增
+	if e := services.CreateVoiceBroadcast(req.SectionId, req.VarietyId, req.AuthorId, req.BroadcastName, req.SectionName, req.VarietyName,
+		req.Author, req.VoiceSeconds, req.VoiceSize, req.VoiceUrl, req.Imgs); e != nil {
+		response.FailMsg("新增失败", e.Error(), c)
 		return
 	}
-	if req.PublishType == 2 && req.PrePublishTime == "" {
-		response.Fail("定时发布请选择发布时间", c)
+	response.Ok("操作成功", c)
+}
+
+// EditBroadcast
+// @Description 编辑语音播报
+// @Param broadcast_id		query  int  	true  	"语音播报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 Imgs				query  string  	false  	"图片,英文逗号拼接"
+// @Param voice_seconds		query  string  	true	"音频时长"
+// @Param voice_size		query  string  	true	"音频大小"
+// @Param voice_url			query  string  	true	"音频文件地址"
+// @Success 200 {string} string "发布成功"
+// @failure 400 {string} string "发布失败"
+// @Router /edit [post]
+func EditBroadcast(c *gin.Context) {
+	var req request.SaveBroadcastReq
+	if err := c.ShouldBind(&req); err != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	// 参数校验
+	if req.BroadcastId <= 0 {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.BroadcastName == "" {
+		response.Fail("请输入标题", c)
+		return
+	}
+	if req.SectionId <= 0 || req.SectionName == "" {
+		response.Fail("请选择品种", c)
+		return
+	}
+	if req.SectionId <= 0 || req.SectionName == "" {
+		response.Fail("请选择板块", c)
+		return
+	}
+	if req.VoiceUrl == "" || req.VoiceSeconds == "" || req.VoiceSize == "" {
+		response.Fail("请上传音频", c)
 		return
 	}
 	if req.Imgs != "" {
@@ -112,13 +162,53 @@ func PublishBroadcast(c *gin.Context) {
 			return
 		}
 	}
-	// 发布语音
-	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)
+	// 编辑
+	if e := services.EditVoiceBroadcast(req.BroadcastId, req.SectionId, req.VarietyId, req.AuthorId, req.BroadcastName, req.SectionName, req.VarietyName,
+		req.Author, req.VoiceSeconds, req.VoiceSize, req.VoiceUrl, req.Imgs); e != nil {
+		response.FailMsg("编辑失败", e.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
+}
+
+// PublishBroadcast
+// @Description 发布语音播报
+// @Param broadcast_id		query  int  	true  	"语音播报ID"
+// @Param publish_type		query  int  	true  	"发布类型: 1-发布 2-定时发布"
+// @Param img_url			query  string  	true  	"分享背景图"
+// @Param pre_publish_time	query  string  	false  	"预发布时间"
+// @Success 200 {string} string "发布成功"
+// @failure 400 {string} string "发布失败"
+// @Router /publish [post]
+func PublishBroadcast(c *gin.Context) {
+	var req request.PublishBroadcastReq
+	if err := c.ShouldBind(&req); err != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	// 参数校验
+	if req.BroadcastId <= 0 {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.PublishType <= 0 {
+		response.Fail("请选择发布类型", c)
 		return
 	}
-	response.Ok("发布成功", c)
+	if req.ImgUrl == "" {
+		response.Fail("分享图有误", c)
+		return
+	}
+	if req.PublishType == 2 && req.PrePublishTime == "" {
+		response.Fail("定时发布请选择发布时间", c)
+		return
+	}
+	// 发布
+	if e := services.PublishVoiceBroadcast(req.BroadcastId, req.PublishType, req.ImgUrl, req.PrePublishTime); e != nil {
+		response.FailMsg("发布失败", e.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
 }
 
 // SectionList

+ 19 - 17
models/request/voice_broadcast.go

@@ -1,9 +1,5 @@
 package request
 
-import (
-	"mime/multipart"
-)
-
 type BroadcastListReq struct {
 	PageIndex   int `json:"page_index" form:"page_index"`
 	PageSize    int `json:"page_size" form:"page_size"`
@@ -27,17 +23,23 @@ type BroadcastMsgSendReq struct {
 }
 
 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:"预发布时间"`
+	BroadcastId   int    `json:"broadcast_id" form:"broadcast_id" description:"语音播报ID"`
+	BroadcastName string `json:"broadcast_name" description:"语音标题"`
+	SectionId     int    `json:"section_id" form:"section_id" description:"板块ID"`
+	SectionName   string `json:"section_name" form:"section_name" description:"板块名称"`
+	VarietyId     int    `json:"variety_id" form:"variety_id" description:"品种ID"`
+	VarietyName   string `json:"variety_name" form:"variety_name" description:"品种名称"`
+	AuthorId      int    `json:"author_id" form:"author_id" description:"作者ID"`
+	Author        string `json:"author" form:"author" description:"作者名称"`
+	Imgs          string `json:"imgs" form:"imgs" description:"图片,英文逗号拼接"`
+	VoiceSeconds  string `json:"voice_seconds" form:"voice_seconds" description:"音频时长"`
+	VoiceSize     string `json:"voice_size" form:"voice_size" description:"音频大小"`
+	VoiceUrl      string `json:"voice_url" form:"voice_url" description:"音频文件地址"`
+}
+
+type PublishBroadcastReq struct {
+	BroadcastId    int    `json:"broadcast_id" form:"broadcast_id" description:"语音播报ID"`
+	PublishType    int    `json:"publish_type" form:"publish_type" description:"发布类型: 1-发布 2-定时发布"`
+	ImgUrl         string `json:"img_url" form:"img_url" description:"分享背景图"`
+	PrePublishTime string `json:"pre_publish_time" form:"pre_publish_time" description:"预发布时间"`
 }

+ 1 - 0
models/response/voice_broadcast.go

@@ -20,6 +20,7 @@ type Broadcast struct {
 	VoicePlaySeconds string   `description:"音频时长"`
 	VoiceSize        string   `description:"音频大小"`
 	CreateTime       string   `description:"创建时间"`
+	ModifyTime       string   `description:"更新时间"`
 	IsAuthor         bool     `description:"是否为作者"`
 	CouldSendMsg     bool     `description:"是否可推送消息"`
 	PublishState     int      `description:"发布状态:0-未发布 1-已发布"`

+ 1 - 0
routers/public.go

@@ -27,5 +27,6 @@ func initPublic(r *gin.Engine) {
 		rGroup.GET("/get_suncode_scene", controller.GetSuncodeScene)
 		rGroup.GET("/get_variety_tag_tree", controller.GetVarietyTagTree)
 		rGroup.POST("/wechat_warning", controller.WechatWarning)
+		rGroup.POST("/upload_audio", controller.UploadAudio)
 	}
 }

+ 4 - 3
routers/voice_broadcast.go

@@ -6,9 +6,11 @@ import (
 	"hongze/hongze_yb/middleware"
 )
 
-func InitVoiceBroadcast(r *gin.Engine)  {
+func InitVoiceBroadcast(r *gin.Engine) {
 	rGroup := r.Group("api/voice/broadcast").Use(middleware.Token())
-	rGroup.POST("/add", voice_broadcast.PublishBroadcast)
+	rGroup.POST("/add", voice_broadcast.AddBroadcast)
+	rGroup.POST("/edit", voice_broadcast.EditBroadcast)
+	rGroup.POST("/publish", voice_broadcast.PublishBroadcast)
 	rGroup.GET("/section/list", voice_broadcast.SectionList)
 	rGroup.GET("/delete", voice_broadcast.DelBroadcast)
 	rGroup.POST("/statistics/add", voice_broadcast.AddStatistics)
@@ -18,4 +20,3 @@ func InitVoiceBroadcast(r *gin.Engine)  {
 	rGroup2.GET("/detail", voice_broadcast.BroadcastDetail)
 	rGroup2.POST("/msg_send", voice_broadcast.MsgSend)
 }
-

+ 103 - 153
services/voice_broadcast.go

@@ -15,10 +15,6 @@ import (
 	"hongze/hongze_yb/services/user"
 	"hongze/hongze_yb/services/wechat"
 	"hongze/hongze_yb/utils"
-	"io/ioutil"
-	"mime/multipart"
-	"os"
-	"path"
 	"strings"
 	"time"
 )
@@ -29,15 +25,10 @@ func GetVoiceBroadcastList(pageIndex, pageSize, sectionId, broadcastId, authorId
 	var pars []interface{}
 	// 分享进来的指定语音播报
 	if broadcastId > 0 {
-		condition += ` AND broadcast_id = ?`
+		condition += ` AND broadcast_id = ? AND publish_state = 1`
 		pars = append(pars, broadcastId)
 	} else {
-		// 板块
-		if sectionId > 0 {
-			condition += ` AND section_id = ?`
-			pars = append(pars, sectionId)
-		}
-		// 我的
+		// 我的-非我的只能看到已发布
 		if authorId > 0 {
 			condition += ` AND author_id = ?`
 			pars = append(pars, authorId)
@@ -46,6 +37,13 @@ func GetVoiceBroadcastList(pageIndex, pageSize, sectionId, broadcastId, authorId
 				condition += ` AND publish_state = ?`
 				pars = append(pars, mineStatus)
 			}
+		} else {
+			condition += ` AND publish_state = 1`
+		}
+		// 板块
+		if sectionId > 0 {
+			condition += ` AND section_id = ?`
+			pars = append(pars, sectionId)
 		}
 	}
 	voiceList, e := voice_broadcast.GetPageListByCondition(condition, pars, pageIndex, pageSize)
@@ -183,6 +181,11 @@ func SendBroadcastMsg(broadcastId, userId int) (errMsg string, err error) {
 		err = errors.New("获取语音播报信息失败, Err: " + e.Error())
 		return
 	}
+	if broadcast.PublishState != 1 {
+		errMsg = "报告未发布, 不可推送"
+		err = errors.New("报告未发布, 不可推送")
+		return
+	}
 	if broadcast.AuthorId != userId {
 		errMsg = "仅语音播报创建人可推送"
 		err = errors.New("仅语音播报创建人可推送")
@@ -213,74 +216,54 @@ func SendBroadcastMsg(broadcastId, userId int) (errMsg string, 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 {
-		// 语音播报
-		exists, e := voice_broadcast.GetBroadcastById(broadcastId)
-		if e != nil || exists.BroadcastId == 0 {
-			errMsg = "语音播报信息有误"
-			err = errors.New("语音播报信息有误\n")
-			return
-		}
-		if exists.PublishState == 1 {
-			errMsg = "请勿重复发布"
-			err = errors.New("该语音播报已发布\n")
-			return
-		}
-		item = exists
+// CreateVoiceBroadcast 新增语音播报
+func CreateVoiceBroadcast(sectionId, varietyId, authorId int, broadcastName, sectionName, varietyName, author, voiceSeconds, voiceSize, voiceUrl, imgs string) (err error) {
+	nowTime := time.Now().Local()
+	item := &voice_broadcast.VoiceBroadcast{
+		BroadcastName:    broadcastName,
+		SectionId:        sectionId,
+		SectionName:      sectionName,
+		VarietyId:        varietyId,
+		VarietyName:      varietyName,
+		AuthorId:         authorId,
+		Author:           author,
+		VoiceUrl:         voiceUrl,
+		VoicePlaySeconds: voiceSeconds,
+		VoiceSize:        voiceSize,
+		CreateTime:       nowTime.Format(utils.FormatDateTime),
+		ModifyTime:       nowTime.Format(utils.FormatDateTime),
 	}
-	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", "PublishState"}
-
-	// 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 {
-		// 非定时发布时重置预发布时间
-		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)
-		}
+	// 图片
+	imgList := make([]*voice_broadcast_img.YbVoiceBroadcastImg, 0)
+	imgArr := strings.Split(imgs, ",")
+	imgLen := len(imgArr)
+	for i := 0; i < imgLen; i++ {
+		imgList = append(imgList, &voice_broadcast_img.YbVoiceBroadcastImg{
+			BroadcastId: item.BroadcastId,
+			ImgUrl:      imgArr[i],
+			CreateTime:  nowTime,
+		})
 	}
-	shareTime := publishTime.Format(utils.FormatDate)
-	shareImg, e := createVoiceBroadcastShareImg(imgUrl, sectionName, shareTime)
-	if e != nil {
-		errMsg = "生成分享图失败"
-		err = errors.New("生成分享图失败, Err: " + "\n" + e.Error())
+	if e := voice_broadcast.CreateVoiceBroadcastAndImgs(item, imgList); e != nil {
+		err = errors.New("新增语音播报及图片失败, Err: " + e.Error())
 		return
 	}
+	return
+}
 
-	// 上传音频
-	fileSeconds, fileSize, resourceUrl, e := handleVoiceBroadcastFile(voiceFile)
+// EditVoiceBroadcast 编辑语音播报
+func EditVoiceBroadcast(broadcastId, sectionId, varietyId, authorId int, broadcastName, sectionName, varietyName, author, voiceSeconds, voiceSize, voiceUrl, imgs string) (err error) {
+	if broadcastId <= 0 {
+		return
+	}
+	item, e := voice_broadcast.GetBroadcastById(broadcastId)
 	if e != nil {
-		errMsg = "语音信息有误"
-		err = errors.New("上传音频失败, Err: " + "\n" + e.Error())
+		err = errors.New("语音播报信息有误")
 		return
 	}
-
-	// 语音播报及图片
+	nowTime := time.Now().Local()
+	updateCols := []string{"BroadcastName", "SectionId", "SectionName", "VarietyId", "VarietyName", "AuthorId", "Author", "VoiceUrl",
+		"VoicePlaySeconds", "VoiceSize", "ModifyTime"}
 	item.BroadcastName = broadcastName
 	item.SectionId = sectionId
 	item.SectionName = sectionName
@@ -288,16 +271,14 @@ func PublishVoiceBroadcast(broadcastId, sectionId, varietyId, authorId, publishT
 	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)
-
+	item.VoiceUrl = voiceUrl
+	item.VoicePlaySeconds = voiceSeconds
+	item.VoiceSize = voiceSize
+	item.ModifyTime = nowTime.Format(utils.FormatDateTime)
+	// 图片
 	imgList := make([]*voice_broadcast_img.YbVoiceBroadcastImg, 0)
 	imgArr := strings.Split(imgs, ",")
 	imgLen := len(imgArr)
-	nowTime := time.Now().Local()
 	for i := 0; i < imgLen; i++ {
 		imgList = append(imgList, &voice_broadcast_img.YbVoiceBroadcastImg{
 			BroadcastId: item.BroadcastId,
@@ -305,29 +286,53 @@ func PublishVoiceBroadcast(broadcastId, sectionId, varietyId, authorId, publishT
 			CreateTime:  nowTime,
 		})
 	}
-	// 新增/更新
-	if broadcastId > 0 {
-		if e := voice_broadcast.UpdateVoiceBroadcastAndImgs(item, updateCols, imgList); e != nil {
-			errMsg = "发布失败"
-			err = errors.New("更新语音播报及图片失败, Err: " + "\n" + e.Error())
+	if e := voice_broadcast.UpdateVoiceBroadcastAndImgs(item, updateCols, imgList); e != nil {
+		err = errors.New("更新语音播报及图片失败, Err: " + e.Error())
+		return
+	}
+	return
+}
+
+// PublishVoiceBroadcast 发布语音播报
+func PublishVoiceBroadcast(broadcastId, publishType int, imgUrl, prePublishTime string) (err error) {
+	item, e := voice_broadcast.GetBroadcastById(broadcastId)
+	if e != nil {
+		err = errors.New("语音播报信息有误")
+		return
+	}
+	if item.PublishState == 1 {
+		err = errors.New("不可重复发布")
+		return
+	}
+	// publishType: 0-仅发布 1-发布并推送 2-定时发布; 发布类型为定时发送时, 分享图时间取预发布时间
+	updateCols := []string{"ImgUrl", "PublishState", "PublishTime", "PrePublishTime", "ModifyTime"}
+	publishTime := time.Now().Local()
+	if publishType == 2 {
+		item.PublishState = 0
+		item.PrePublishTime = prePublishTime
+		publishTime, e = time.ParseInLocation(utils.FormatDateTime, prePublishTime, time.Local)
+		if e != nil {
+			err = errors.New("预发布时间有误, Err: " + e.Error())
 			return
 		}
 	} else {
-		if e := voice_broadcast.CreateVoiceBroadcastAndImgs(item, imgList); e != nil {
-			errMsg = "发布失败"
-			err = errors.New("新增语音播报及图片失败, Err: " + "\n" + e.Error())
-			return
-		}
+		// 非定时发布时重置预发布时间
+		item.PublishState = 1
+		item.PublishTime = publishTime.Format(utils.FormatDateTime)
+		item.PrePublishTime = ""
 	}
-
-	// 推送模板及客群消息
-	if publishType == 1 {
-		go func() {
-			_ = wechat.SendVoiceBroadcastWxMsg(item.BroadcastId, item.SectionName, item.BroadcastName)
-		}()
-		go func() {
-			_ = SendVoiceBroadcastToThs(item)
-		}()
+	// 分享图
+	shareTime := publishTime.Format(utils.FormatDate)
+	shareImg, e := createVoiceBroadcastShareImg(imgUrl, item.SectionName, shareTime)
+	if e != nil {
+		err = errors.New("生成分享图失败, Err: " + e.Error())
+		return
+	}
+	item.ImgUrl = shareImg
+	// 发布
+	if e = item.Update(updateCols); e != nil {
+		err = errors.New("发布语音播报失败, Err: " + e.Error())
+		return
 	}
 	return
 }
@@ -359,62 +364,6 @@ func createVoiceBroadcastShareImg(baseImg, sectionName, createTime string) (shar
 	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
-}
-
 // GetVoiceBroadcastDetail 获取语音播报详情
 func GetVoiceBroadcastDetail(broadcastId, userId int) (detail response.Broadcast, err error) {
 	item, e := voice_broadcast.GetBroadcastById(broadcastId)
@@ -450,6 +399,7 @@ func handleBroadcastItem(userId int, item *voice_broadcast.VoiceBroadcast, imgs
 	resp.VoicePlaySeconds = item.VoicePlaySeconds
 	resp.VoiceSize = item.VoiceSize
 	resp.CreateTime = item.CreateTime
+	resp.ModifyTime = item.ModifyTime
 	resp.PublishState = item.PublishState
 	resp.PublishTime = item.PublishTime
 	resp.PrePublishTime = item.PrePublishTime