Browse Source

Merge branch 'yb/9.2'

hsun 2 năm trước cách đây
mục cha
commit
c7915ec295

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

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

+ 155 - 133
controller/voice_broadcast/voice_broadcast.go

@@ -1,32 +1,27 @@
 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"
 	"hongze/hongze_yb/models/tables/voice_section"
 	"hongze/hongze_yb/services"
-	"hongze/hongze_yb/services/company"
 	"hongze/hongze_yb/services/user"
 	"hongze/hongze_yb/utils"
-	"io/ioutil"
-	"os"
-	"path"
 	"strconv"
-	"time"
+	"strings"
 )
 
 // BroadcastList
 // @Description 语音播报列表
-// @Param page_index			query int false "页码"
-// @Param page_size				query int false "每页数量"
-// @Param broadcast_id			query int false "语音播报id"
-// @Param section_id			query int false "板块id"
+// @Param page_index	query int false "页码"
+// @Param page_size		query int false "每页数量"
+// @Param broadcast_id	query int false "语音播报ID(分享进来的时候筛选用)"
+// @Param section_id	query int false "板块ID"
+// @Param author_id		query int false "作者ID(我的语音播报列表)"
+// @Param mine_status	query int false "语音播报状态:0-未发布 1-已发布 2-全部(我的语音播报列表)"
 // @Success 200 {object} []voiceResp.BroadcastListResp
 // @failure 400 {string} string "获取失败"
 // @Router /list [Post]
@@ -44,20 +39,8 @@ func BroadcastList(c *gin.Context) {
 	}
 
 	userinfo := user.GetInfoByClaims(c)
-	ok, checkInfo, _, err := company.CheckBaseFiccPermission(userinfo.CompanyID, int(userinfo.UserID))
+	list, err := services.GetVoiceBroadcastList(req.PageIndex, req.PageSize, req.SectionId, req.BroadcastId, req.AuthorId, req.MineStatus, userinfo)
 	if err != nil {
-		response.FailMsg("用户权限验证失败", "CheckBaseAuth-用户权限验证失败"+err.Error(), c)
-		c.Abort()
-		return
-	}
-	if !ok {
-		response.AuthError(checkInfo, "暂无权限", c)
-		c.Abort()
-		return
-	}
-	list, err := services.GetVoiceBroadcastList(req.PageIndex, req.PageSize, req.SectionId, req.BroadcastId, userinfo)
-	if err != nil {
-
 		response.FailMsg("获取语音播报列表失败,"+err.Error(), "QuestionList ErrMsg:"+err.Error(), c)
 		return
 	}
@@ -74,121 +57,157 @@ func BroadcastList(c *gin.Context) {
 }
 
 // AddBroadcast
-// @Description 新建语音播报
-// @Param file  query  string  true  "音频文件"
+// @Description 新增语音播报
+// @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 /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)
+	var req request.SaveBroadcastReq
+	if err := c.ShouldBind(&req); err != nil {
+		response.Fail("参数有误", c)
 		return
 	}
-	if imgUrl == "" {
-		response.Fail("图片不能为空", c)
+	// 参数校验
+	if req.BroadcastName == "" {
+		response.Fail("请输入标题", c)
 		return
 	}
-	// 生成动态分享图
-	createTimeStr := time.Now().Local().Format(utils.FormatDate)
-	pars := services.VoiceBroadcastShareImgPars{
-		BackgroundImg: imgUrl,
-		Title:         sectionName,
-		CreateTime:    createTimeStr,
+	if req.SectionId <= 0 || req.SectionName == "" {
+		response.Fail("请选择品种", c)
+		return
 	}
-	parsByte, e := json.Marshal(pars)
-	if e != nil {
-		response.Fail("分享图参数有误", c)
+	if req.SectionId <= 0 || req.SectionName == "" {
+		response.Fail("请选择板块", c)
+		return
+	}
+	if req.VoiceUrl == "" || req.VoiceSeconds == "" || req.VoiceSize == "" {
+		response.Fail("请上传音频", c)
 		return
 	}
-	shareImg, e := services.GetDynamicShareImg(services.VoiceBroadcastShareImgSource, string(parsByte))
+	if req.Imgs != "" {
+		imgList := strings.Split(req.Imgs, ",")
+		if len(imgList) > 5 {
+			response.Fail("最多插入五张图片", c)
+			return
+		}
+	}
+	userInfo := user.GetInfoByClaims(c)
+	// 新增
+	resp, e := services.CreateVoiceBroadcast(req.SectionId, req.VarietyId, req.AuthorId, int(userInfo.UserID), req.BroadcastName, req.SectionName, req.VarietyName,
+		req.Author, req.VoiceSeconds, req.VoiceSize, req.VoiceUrl, req.Imgs)
 	if e != nil {
-		response.Fail("生成分享图失败", c)
+		response.FailMsg("新增失败", e.Error(), c)
 		return
 	}
+	response.OkData("操作成功", resp, c)
+}
 
-	ext := path.Ext(file.Filename)
-	if ext != ".mp3" {
-		response.Fail("暂仅支持mp3格式", 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
 	}
-	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.BroadcastId <= 0 {
+		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.BroadcastName == "" {
+		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.SectionId <= 0 || req.SectionName == "" {
+		response.Fail("请选择板块", c)
 		return
 	}
-	seconds, err := services.GetMP3PlayDuration(fByte)
-	if err != nil {
-		response.FailMsg("读取文件时长失败", "QuestionUploadAudio 读取文件时长失败", c)
+	if req.VoiceUrl == "" || req.VoiceSeconds == "" || req.VoiceSize == "" {
+		response.Fail("请上传音频", c)
 		return
 	}
-	// 音频大小MB
-	fi, err := os.Stat(fpath)
-	if err != nil {
-		response.FailMsg("读取文件大小失败", "QuestionUploadAudio 读取文件大小失败", c)
-		return
+	if req.Imgs != "" {
+		imgList := strings.Split(req.Imgs, ",")
+		if len(imgList) > 5 {
+			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)
+	userInfo := user.GetInfoByClaims(c)
+	// 编辑
+	resp, e := services.EditVoiceBroadcast(req.BroadcastId, req.SectionId, req.VarietyId, req.AuthorId, int(userInfo.UserID), req.BroadcastName, req.SectionName, req.VarietyName,
+		req.Author, req.VoiceSeconds, req.VoiceSize, req.VoiceUrl, req.Imgs)
+	if e != nil {
+		response.FailMsg("新增失败", e.Error(), c)
 		return
 	}
+	response.OkData("操作成功", resp, c)
+}
 
-	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())
+// PublishBroadcast
+// @Description 发布语音播报
+// @Param broadcast_id		query  int  	true  	"语音播报ID"
+// @Param publish_type		query  int  	true  	"发布类型: 1-发布 2-定时发布"
+// @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.OkData("发布成功", voiceBroadcast.BroadcastId, c)
+	if req.PublishType == 2 && req.PrePublishTime == "" {
+		response.Fail("定时发布请选择发布时间", c)
+		return
+	}
+	// 发布
+	if e := services.PublishVoiceBroadcast(req.BroadcastId, req.PublishType, req.PrePublishTime); e != nil {
+		response.FailMsg("发布失败", e.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
 }
 
 // SectionList
@@ -337,8 +356,8 @@ func AddStatistics(c *gin.Context) {
 // BroadcastDetail 获取语音播报详情
 // @Tags 语音播报模块
 // @Description 获取语音播报详情
-// @Param variety_tag_id  query  int  true  "标签ID"
-// @Success 200 {object} response.PriceDrivenItem
+// @Param broadcast_id  query  int  true  "语音播报ID"
+// @Success 200 {object} voiceResp.Broadcast
 // @failure 400 {string} string "获取失败"
 // @Router /detail [get]
 func BroadcastDetail(c *gin.Context) {
@@ -352,33 +371,11 @@ func BroadcastDetail(c *gin.Context) {
 		return
 	}
 	userInfo := user.GetInfoByClaims(c)
-	item, e := voice_broadcast.GetBroadcastById(req.BroadcastId)
+	resp, e := services.GetVoiceBroadcastDetail(req.BroadcastId, int(userInfo.UserID))
 	if e != nil {
 		response.FailMsg("获取失败", "BroadcastDetail ErrMsg:"+e.Error(), c)
 		return
 	}
-	resp := &voiceResp.Broadcast{
-		BroadcastId:      item.BroadcastId,
-		BroadcastName:    item.BroadcastName,
-		SectionId:        item.SectionId,
-		SectionName:      item.SectionName,
-		VarietyId:        item.VarietyId,
-		VarietyName:      item.VarietyName,
-		AuthorId:         item.AuthorId,
-		Author:           item.Author,
-		ImgUrl:           item.ImgUrl,
-		VoiceUrl:         item.VoiceUrl,
-		VoicePlaySeconds: item.VoicePlaySeconds,
-		VoiceSize:        item.VoiceSize,
-		CreateTime:       item.CreateTime,
-	}
-	// 是否为作者、是否可以推送消息
-	if int(userInfo.UserID) == item.AuthorId {
-		resp.IsAuthor = true
-		if item.MsgState == 0 {
-			resp.CouldSendMsg = true
-		}
-	}
 	response.OkData("获取成功", resp, c)
 }
 
@@ -407,3 +404,28 @@ func MsgSend(c *gin.Context) {
 	}
 	response.Ok("操作成功", c)
 }
+
+// BroadcastDetail 获取语音播报详情
+// @Tags 语音播报模块
+// @Description 获取语音播报详情
+// @Param broadcast_id  query  int  true  "语音播报ID"
+// @Success 200 {object} voiceResp.Broadcast
+// @failure 400 {string} string "获取失败"
+// @Router /detail [get]
+func MyVoiceBroadcastListCount(c *gin.Context) {
+	var req request.BroadcastListCountReq
+	if err := c.Bind(&req); err != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.AuthorId <= 0 {
+		response.Fail("参数有误", c)
+		return
+	}
+	resp, e := services.GetMyVoiceBroadcastListCount(req.AuthorId, req.SectionId)
+	if e != nil {
+		response.FailMsg("获取失败", "BroadcastDetail ErrMsg:"+e.Error(), c)
+		return
+	}
+	response.OkData("获取成功", resp, c)
+}

+ 56 - 25
logic/user/user.go

@@ -9,6 +9,7 @@ import (
 	"hongze/hongze_yb/models/tables/company_product"
 	"hongze/hongze_yb/models/tables/rddp/msg_code"
 	"hongze/hongze_yb/models/tables/research_variety_tag_relation"
+	"hongze/hongze_yb/models/tables/sys_role_admin"
 	"hongze/hongze_yb/models/tables/wx_user"
 	"hongze/hongze_yb/models/tables/yb_apply_record"
 	"hongze/hongze_yb/models/tables/yb_index_tab"
@@ -112,6 +113,7 @@ type Detail struct {
 	PermissionList []CompanyPermission `json:"permission_list" description:"权限列表"`
 	IsInner        int                 `json:"is_inner" description:"是否为内部员工"`
 	IsResearcher   int                 `json:"is_researcher" description:"是否为研究员"`
+	IsVoiceAdmin   int                 `json:"is_voice_admin" description:"是否为语音管理员"`
 	AdminInfo      *admin2.Admin       `json:"admin_info" description:"系统管理员信息"`
 	UnRead         int64               `json:"un_read" description:"消息未读数"`
 	NickName       string              `json:"nick_name" description:"用户昵称"`
@@ -201,17 +203,6 @@ func GetUserInfo(userInfo user.UserInfo) (userDetail Detail, err error, errMsg s
 		}
 
 	}
-	// 是否为内部员工
-	isInner := 0
-	ok, adminInfo, err := user.GetAdminByUserInfo(userInfo)
-	if err != nil {
-		err = errors.New("获取用户系统管理员信息失败")
-		errMsg = "系统异常4002"
-		return
-	}
-	if ok {
-		isInner = 1
-	}
 
 	// 查询消息未读数
 	unRead, err := yb_message.GetUnreadByUserId(userInfo.UserID)
@@ -223,18 +214,11 @@ func GetUserInfo(userInfo user.UserInfo) (userDetail Detail, err error, errMsg s
 	if headimgurl == "" {
 		headimgurl = utils.DEFAULT_HONGZE_USER_LOGO
 	}
-	// 查询是否为研究员
-	isResearcher := 0
-	if isInner == 1 {
-		researchGroupList, e := research_variety_tag_relation.GetResearchVarietyTagRelationByAdminId(int(adminInfo.AdminID))
-		if e != nil {
-			errMsg = "查询是否为研究员失败"
-			err = errors.New("用户身份信息有误")
-			return
-		}
-		if len(researchGroupList) > 0 {
-			isResearcher = 1
-		}
+
+	// 查询是否为内部员工、研究员、语音管理员
+	isInner, isResearcher, isVoiceAdmin, adminInfo, e := GetUserIdentity(int(userInfo.CompanyID), userInfo.Mobile, userInfo.Email)
+	if e != nil {
+		return
 	}
 
 	userDetail = Detail{
@@ -249,6 +233,7 @@ func GetUserInfo(userInfo user.UserInfo) (userDetail Detail, err error, errMsg s
 		PermissionList: list,         //权限列表
 		IsInner:        isInner,      // 是否为内部员工
 		IsResearcher:   isResearcher, // 是否为研究员
+		IsVoiceAdmin:   isVoiceAdmin, // 语音管理员
 		AdminInfo:      adminInfo,    // 系统管理员信息
 		UnRead:         unRead,
 		NickName:       userInfo.NickName,
@@ -536,11 +521,57 @@ func GetTopTab(userInfo user.UserInfo, version string) (list []*TopTab, err erro
 			continue
 		}
 		list = append(list, &TopTab{
-			Tab: v.Tab,
+			Tab:  v.Tab,
 			Mark: v.Mark,
 			Icon: v.DefaultIcon,
 			Sort: v.Sort,
 		})
 	}
 	return
-}
+}
+
+// GetUserIdentity 获取用户身份(内部员工、研究员、语音管理员)
+func GetUserIdentity(companyId int, mobile, email string) (isInner, isResearcher, isVoiceAdmin int, adminInfo *admin2.Admin, err error) {
+	if companyId != utils.HzCompanyId {
+		return
+	}
+	if mobile == "" && email == "" {
+		return
+	}
+	var e error
+	// 通过手机号/邮箱获取管理员信息
+	if mobile != "" {
+		adminInfo, e = admin2.GetAdminByMobile(mobile)
+		if e != nil && e != utils.ErrNoRow {
+			return
+		}
+	} else {
+		adminInfo, e = admin2.GetAdminByEmail(email)
+		if e != nil && e != utils.ErrNoRow {
+			return
+		}
+	}
+	// 仅内部员工才判断研究员、语音管理员身份
+	if adminInfo != nil && adminInfo.AdminID > 0 && adminInfo.Enabled == 1 {
+		isInner = 1
+		// 研究员
+		researchGroupList, e := research_variety_tag_relation.GetResearchVarietyTagRelationByAdminId(int(adminInfo.AdminID))
+		if e != nil {
+			err = errors.New("用户研究员信息有误")
+			return
+		}
+		if len(researchGroupList) > 0 {
+			isResearcher = 1
+		}
+		// 语音管理员
+		voiceAdmin, e := sys_role_admin.GetVoiceAdmin(int(adminInfo.AdminID))
+		if e != nil && e != utils.ErrNoRow {
+			err = errors.New("用户语音管理员信息有误")
+			return
+		}
+		if voiceAdmin != nil && voiceAdmin.Id > 0 {
+			isVoiceAdmin = 1
+		}
+	}
+	return
+}

+ 29 - 27
models/request/voice_broadcast.go

@@ -1,39 +1,14 @@
 package request
 
-import "mime/multipart"
-
 type BroadcastListReq struct {
 	PageIndex   int `json:"page_index" form:"page_index"`
 	PageSize    int `json:"page_size" form:"page_size"`
 	BroadcastId int `json:"broadcast_id" form:"broadcast_id"`
 	SectionId   int `json:"section_id" form:"section_id"`
+	AuthorId    int `json:"author_id" form:"author_id" description:"我的语音播报作者ID"`
+	MineStatus  int `json:"mine_status" form:"mine_status" description:"我的语音播报状态:0-未发布 1-已发布 2-全部"`
 }
 
-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 +21,30 @@ type BroadcastDetailReq struct {
 type BroadcastMsgSendReq struct {
 	BroadcastId int `json:"broadcast_id" description:"语音播报ID"`
 }
+
+type SaveBroadcastReq struct {
+	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:"预发布时间"`
+}
+
+type BroadcastListCountReq struct {
+	AuthorId  int `json:"author_id" form:"author_id" description:"作者ID"`
+	SectionId int `json:"section_id" form:"section_id" description:"板块ID"`
+}

+ 27 - 18
models/response/voice_broadcast.go

@@ -7,34 +7,43 @@ type BroadcastListResp struct {
 }
 
 type Broadcast struct {
-	BroadcastId      int    `description:"语音ID"`
-	BroadcastName    string `description:"语音名称"`
-	SectionId        int    `description:"语音分类ID"`
-	SectionName      string `description:"语音分类名称"`
-	VarietyId        int    `description:"品种id"`
-	VarietyName      string `description:"品种名称"`
-	AuthorId         int    `description:"作者id"`
-	Author           string `description:"作者"`
-	ImgUrl           string `description:"背景图url"`
-	VoiceUrl         string `description:"音频url"`
-	VoicePlaySeconds string `description:"音频时长"`
-	VoiceSize        string `description:"音频大小"`
-	CreateTime       string `description:"创建时间"`
-	IsAuthor         bool   `description:"是否为作者"`
-	CouldSendMsg     bool   `description:"是否可推送消息"`
+	BroadcastId      int      `description:"语音ID"`
+	BroadcastName    string   `description:"语音名称"`
+	SectionId        int      `description:"语音分类ID"`
+	SectionName      string   `description:"语音分类名称"`
+	VarietyId        int      `description:"品种id"`
+	VarietyName      string   `description:"品种名称"`
+	AuthorId         int      `description:"作者id"`
+	Author           string   `description:"作者"`
+	ImgUrl           string   `description:"背景图url"`
+	VoiceUrl         string   `description:"音频url"`
+	VoicePlaySeconds string   `description:"音频时长"`
+	VoiceSize        string   `description:"音频大小"`
+	CreateTime       string   `description:"创建时间"`
+	ModifyTime       string   `description:"更新时间"`
+	IsAuthor         bool     `description:"是否为作者"`
+	CouldSendMsg     bool     `description:"是否可推送消息"`
+	PublishState     int      `description:"发布状态:0-未发布 1-已发布"`
+	PublishTime      string   `description:"发布时间"`
+	PrePublishTime   string   `description:"定时发布时间"`
+	Imgs             []string `description:"图片"`
 }
 
-//type SectionListResp struct {
-//	List []VarietyList
-//}
 type VarietyList struct {
 	VarietyId   int
 	VarietyName string
 	Children    []SectionList
 }
+
 type SectionList struct {
 	ImgUrl      string
 	SectionId   int
 	SectionName string
 	Status      int
 }
+
+type BroadcastListStatusCount struct {
+	Unpublished int `description:"未发布"`
+	Published   int `description:"已发布"`
+	All         int `description:"全部"`
+}

+ 1 - 1
models/tables/admin/admin.go

@@ -4,7 +4,7 @@ import "time"
 
 // Admin [...]
 type Admin struct {
-	AdminID                 int64     `gorm:"primaryKey;column:admin_id;type:bigint(20);not null" json:"-"`
+	AdminID                 int64     `gorm:"primaryKey;column:admin_id;type:bigint(20);not null" json:"adminId"`
 	AdminName               string    `gorm:"uniqueIndex:un;index:name;index:admin_pass;column:admin_name;type:varchar(60);not null" json:"adminName"`
 	AdminAvatar             string    `gorm:"column:admin_avatar;type:varchar(255)" json:"adminAvatar"`
 	RealName                string    `gorm:"column:real_name;type:varchar(60)" json:"realName"`

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

+ 28 - 3
models/tables/voice_broadcast/query.go

@@ -20,12 +20,37 @@ 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
 }
 
 func GetBroadcastList() (list []*VoiceBroadcast, err error) {
 	err = global.DEFAULT_MYSQL.Model(VoiceBroadcast{}).Scan(&list).Error
 	return
-}
+}
+
+func GetPageListByCondition(condition string, pars []interface{}, pageIndex, pageSize int) (list []*VoiceBroadcast, err error) {
+	offset := (pageIndex - 1) * pageSize
+	err = global.DEFAULT_MYSQL.Model(VoiceBroadcast{}).
+		Where(condition, pars...).
+		Offset(offset).Limit(pageSize).
+		Order("create_time DESC").
+		Scan(&list).Error
+	return
+}
+
+type VoiceBroadcastListStatusCount struct {
+	Num   int `json:"num" description:"计数"`
+	State int `json:"state" description:"状态:0-未发布 1-已发布"`
+}
+
+// GetVoiceBroadcastListStatusCount 获取语音播报列表计数-根据状态分组
+func GetVoiceBroadcastListStatusCount(condition string, pars []interface{}) (list []*VoiceBroadcastListStatusCount, err error) {
+	err = global.DEFAULT_MYSQL.Model(VoiceBroadcast{}).
+		Where(condition, pars...).
+		Select("COUNT(1) AS num, publish_state AS state").
+		Group("state").
+		Scan(&list).Error
+	return
+}

+ 4 - 0
models/tables/voice_broadcast/voice_broadcast.go

@@ -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",
+}

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

@@ -0,0 +1,27 @@
+package voice_broadcast_img
+
+import "hongze/hongze_yb/global"
+
+// GetVoiceImgListByVoiceIds 通过语音播报IDs获取图片列表
+func GetVoiceImgListByVoiceIds(idArr []int) (list []*YbVoiceBroadcastImg, err error) {
+	if len(idArr) == 0 {
+		return
+	}
+	err = global.DEFAULT_MYSQL.
+		Model(YbVoiceBroadcastImg{}).
+		Select("broadcast_id, img_url").
+		Where("broadcast_id IN ?", idArr).
+		Order("broadcast_id ASC, create_time ASC").
+		Scan(&list).Error
+	return
+}
+
+// GetVoiceImgListByVoiceId 通过语音播报ID获取图片列表
+func GetVoiceImgListByVoiceId(voiceId int) (list []*YbVoiceBroadcastImg, err error) {
+	err = global.DEFAULT_MYSQL.
+		Model(YbVoiceBroadcastImg{}).
+		Select("broadcast_id, img_url").
+		Where("broadcast_id = ?", voiceId).
+		Scan(&list).Error
+	return
+}

+ 8 - 0
models/tables/voice_section/query.go

@@ -21,4 +21,12 @@ func GetVoiceVariety() (list []*VoiceSection, err error) {
 func GetVoiceSectionFromBroadcast(bannedIds []int) (list []*voice_broadcast.VoiceBroadcast, err error) {
 	err = global.DEFAULT_MYSQL.Where("section_id IN (?)", bannedIds).Group("section_id").Find(&list).Error
 	return
+}
+
+// GetVoiceSectionById 主键获取板块信息
+func GetVoiceSectionById(sectionId int) (item *VoiceSection, err error) {
+	err = global.DEFAULT_MYSQL.Model(VoiceSection{}).
+		Where("section_id = ?", sectionId).
+		First(&item).Error
+	return
 }

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

+ 5 - 3
routers/voice_broadcast.go

@@ -6,16 +6,18 @@ 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("/list", voice_broadcast.BroadcastList)
 	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)
 	// 权限校验
 	rGroup2 := r.Group("api/voice/broadcast").Use(middleware.Token(), middleware.CheckBaseAuth())
+	rGroup2.POST("/list", voice_broadcast.BroadcastList)
 	rGroup2.GET("/detail", voice_broadcast.BroadcastDetail)
 	rGroup2.POST("/msg_send", voice_broadcast.MsgSend)
+	rGroup2.GET("/list_count", voice_broadcast.MyVoiceBroadcastListCount)
 }
-

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

+ 291 - 150
services/voice_broadcast.go

@@ -10,118 +10,74 @@ 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"
+	"strings"
 	"time"
 )
 
-func GetVoiceBroadcastList(pageindex, pagesize, sectionId, broadcastId int, userInfo user.UserInfo) (list []response.Broadcast, err error) {
-	if broadcastId == 0 {
-		if sectionId == 0 {
-			broadList, e := voice_broadcast.GetBroadcast(pageindex, pagesize)
-			if e != nil {
-				e = errors.New("获取语音播报列表失败 Err:" + e.Error())
-			}
-			for _, item := range broadList {
-				var respItem response.Broadcast
-				respItem = response.Broadcast{
-					BroadcastId:      item.BroadcastId,
-					BroadcastName:    item.BroadcastName,
-					SectionId:        item.SectionId,
-					SectionName:      item.SectionName,
-					VarietyId:        item.VarietyId,
-					VarietyName:      item.VarietyName,
-					AuthorId:         item.AuthorId,
-					Author:           item.Author,
-					ImgUrl:           item.ImgUrl,
-					VoiceUrl:         item.VoiceUrl,
-					VoicePlaySeconds: item.VoicePlaySeconds,
-					VoiceSize:        item.VoiceSize,
-					CreateTime:       item.CreateTime,
-					IsAuthor:         false,
-				}
-				if int(userInfo.UserID) == item.AuthorId {
-					respItem.IsAuthor = true
-					// 是否可以推送消息
-					if item.MsgState == 0 {
-						respItem.CouldSendMsg = true
-					}
-				}
-				list = append(list, respItem)
-
+// GetVoiceBroadcastList 获取语音播报列表
+func GetVoiceBroadcastList(pageIndex, pageSize, sectionId, broadcastId, authorId, mineStatus int, userInfo user.UserInfo) (resp []response.Broadcast, err error) {
+	condition := ` 1=1`
+	var pars []interface{}
+	// 分享进来的指定语音播报
+	if broadcastId > 0 {
+		condition += ` AND broadcast_id = ? AND publish_state = 1`
+		pars = append(pars, broadcastId)
+	} else {
+		// 我的-非我的只能看到已发布
+		if authorId > 0 {
+			condition += ` AND author_id = ?`
+			pars = append(pars, authorId)
+			// 我的语音播报状态: 0-未发布 1-已发布 2-全部
+			if mineStatus != 2 {
+				condition += ` AND publish_state = ?`
+				pars = append(pars, mineStatus)
 			}
-			err = e
-			return
+		} else {
+			condition += ` AND publish_state = 1`
 		}
-		broadList, e := voice_broadcast.GetBroadcastByCondition(pageindex, pagesize, sectionId)
-		if e != nil {
-			e = errors.New("获取语音播报列表失败 Err:" + e.Error())
+		// 板块
+		if sectionId > 0 {
+			condition += ` AND section_id = ?`
+			pars = append(pars, sectionId)
 		}
-		for _, item := range broadList {
-			var respItem response.Broadcast
-			respItem = response.Broadcast{
-				BroadcastId:      item.BroadcastId,
-				BroadcastName:    item.BroadcastName,
-				SectionId:        item.SectionId,
-				SectionName:      item.SectionName,
-				VarietyId:        item.VarietyId,
-				VarietyName:      item.VarietyName,
-				AuthorId:         item.AuthorId,
-				Author:           item.Author,
-				ImgUrl:           item.ImgUrl,
-				VoiceUrl:         item.VoiceUrl,
-				VoicePlaySeconds: item.VoicePlaySeconds,
-				VoiceSize:        item.VoiceSize,
-				CreateTime:       item.CreateTime,
-				IsAuthor:         false,
-			}
-			if int(userInfo.UserID) == item.AuthorId {
-				respItem.IsAuthor = true
-				// 是否可以推送消息
-				if item.MsgState == 0 {
-					respItem.CouldSendMsg = true
-				}
-			}
-			list = append(list, respItem)
-
-		}
-		err = e
+	}
+	voiceList, e := voice_broadcast.GetPageListByCondition(condition, pars, pageIndex, pageSize)
+	if e != nil {
+		err = errors.New("获取语音播报列表失败, Err: " + e.Error())
 		return
-	} else {
-		broadList, e := voice_broadcast.GetBroadcastByIdAndPage(pageindex, pagesize, broadcastId)
-		if e != nil {
-			e = errors.New("获取语音播报列表失败 Err:" + e.Error())
-		}
-		for _, item := range broadList {
-			var respItem response.Broadcast
-			respItem = response.Broadcast{
-				BroadcastId:      item.BroadcastId,
-				BroadcastName:    item.BroadcastName,
-				SectionId:        item.SectionId,
-				SectionName:      item.SectionName,
-				VarietyId:        item.VarietyId,
-				VarietyName:      item.VarietyName,
-				AuthorId:         item.AuthorId,
-				Author:           item.Author,
-				ImgUrl:           item.ImgUrl,
-				VoiceUrl:         item.VoiceUrl,
-				VoicePlaySeconds: item.VoicePlaySeconds,
-				VoiceSize:        item.VoiceSize,
-				CreateTime:       item.CreateTime,
-				IsAuthor:         false,
-			}
-			if int(userInfo.UserID) == item.AuthorId {
-				respItem.IsAuthor = true
-			}
-			list = append(list, respItem)
-
-		}
-		err = e
+	}
+	listLen := len(voiceList)
+	if listLen == 0 {
+		return
+	}
+	// 图片
+	voiceIds := make([]int, 0)
+	for i := 0; i < listLen; i++ {
+		voiceIds = append(voiceIds, voiceList[i].BroadcastId)
+	}
+	imgList, e := voice_broadcast_img.GetVoiceImgListByVoiceIds(voiceIds)
+	if e != nil {
+		err = errors.New("获取语音播报列表图片失败, Err: " + e.Error())
 		return
 	}
+	imgMap := make(map[int][]*voice_broadcast_img.YbVoiceBroadcastImg, 0)
+	imgListLen := len(imgList)
+	for i := 0; i < imgListLen; i++ {
+		imgMap[imgList[i].BroadcastId] = append(imgMap[imgList[i].BroadcastId], imgList[i])
+	}
+	// 响应数据
+	userId := int(userInfo.UserID)
+	for i := 0; i < listLen; i++ {
+		r := handleBroadcastItem(userId, voiceList[i], imgMap[voiceList[i].BroadcastId])
+		resp = append(resp, r)
+	}
+	return
 }
 
 // GetVoiceAdminByUserInfo 判断当前用户是否为语音管理员
@@ -226,6 +182,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("仅语音播报创建人可推送")
@@ -256,6 +217,144 @@ func SendBroadcastMsg(broadcastId, userId int) (errMsg string, err error) {
 	return
 }
 
+// CreateVoiceBroadcast 新增语音播报
+func CreateVoiceBroadcast(sectionId, varietyId, authorId, userId int, broadcastName, sectionName, varietyName, author, voiceSeconds, voiceSize, voiceUrl, imgs string) (resp response.Broadcast, 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),
+	}
+	// 图片
+	imgList := make([]*voice_broadcast_img.YbVoiceBroadcastImg, 0)
+	if imgs != "" {
+		imgArr := strings.Split(imgs, ",")
+		imgLen := len(imgArr)
+		for i := 0; i < imgLen; i++ {
+			if imgArr[i] == "" {
+				continue
+			}
+			imgList = append(imgList, &voice_broadcast_img.YbVoiceBroadcastImg{
+				BroadcastId: item.BroadcastId,
+				ImgUrl:      imgArr[i],
+				CreateTime:  nowTime,
+			})
+		}
+	}
+	if e := voice_broadcast.CreateVoiceBroadcastAndImgs(item, imgList); e != nil {
+		err = errors.New("新增语音播报及图片失败, Err: " + e.Error())
+		return
+	}
+	resp = handleBroadcastItem(userId, item, imgList)
+	return
+}
+
+// EditVoiceBroadcast 编辑语音播报
+func EditVoiceBroadcast(broadcastId, sectionId, varietyId, authorId, userId int, broadcastName, sectionName, varietyName, author, voiceSeconds, voiceSize, voiceUrl, imgs string) (resp response.Broadcast, err error) {
+	if broadcastId <= 0 {
+		return
+	}
+	item, e := voice_broadcast.GetBroadcastById(broadcastId)
+	if e != nil {
+		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
+	item.VarietyId = varietyId
+	item.VarietyName = varietyName
+	item.AuthorId = authorId
+	item.Author = author
+	item.VoiceUrl = voiceUrl
+	item.VoicePlaySeconds = voiceSeconds
+	item.VoiceSize = voiceSize
+	item.ModifyTime = nowTime.Format(utils.FormatDateTime)
+	// 图片
+	imgList := make([]*voice_broadcast_img.YbVoiceBroadcastImg, 0)
+	if imgs != "" {
+		imgArr := strings.Split(imgs, ",")
+		imgLen := len(imgArr)
+		for i := 0; i < imgLen; i++ {
+			if imgArr[i] == "" {
+				continue
+			}
+			imgList = append(imgList, &voice_broadcast_img.YbVoiceBroadcastImg{
+				BroadcastId: item.BroadcastId,
+				ImgUrl:      imgArr[i],
+				CreateTime:  nowTime,
+			})
+		}
+	}
+	if e := voice_broadcast.UpdateVoiceBroadcastAndImgs(item, updateCols, imgList); e != nil {
+		err = errors.New("更新语音播报及图片失败, Err: " + e.Error())
+		return
+	}
+	resp = handleBroadcastItem(userId, item, imgList)
+	return
+}
+
+// PublishVoiceBroadcast 发布语音播报
+func PublishVoiceBroadcast(broadcastId, publishType int, 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 {
+		// 非定时发布时重置预发布时间
+		item.PublishState = 1
+		item.PublishTime = publishTime.Format(utils.FormatDateTime)
+		item.PrePublishTime = ""
+	}
+	// 分享背景图-取板块的图
+	section, e := voice_section.GetVoiceSectionById(item.SectionId)
+	if e != nil {
+		err = errors.New("获取板块信息失败, Err: " + e.Error())
+		return
+	}
+	shareTime := publishTime.Format(utils.FormatDate)
+	shareImg, e := createVoiceBroadcastShareImg(section.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
+}
+
 // VoiceBroadcastShareImgPars 语音播报分享图参数
 type VoiceBroadcastShareImgPars struct {
 	BackgroundImg string `json:"background_img"`
@@ -263,67 +362,109 @@ type VoiceBroadcastShareImgPars struct {
 	CreateTime    string `json:"create_time"`
 }
 
-// UpdateVoiceBroadcastImgUrl 更新历史语音播报分享图
-func UpdateVoiceBroadcastImgUrl() (err error) {
-	defer func() {
-		if err != nil {
-			fmt.Println(err.Error())
-		}
-	}()
-	// 获取语音播报列表
-	list, e := voice_broadcast.GetBroadcastList()
+// 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
+}
+
+// GetVoiceBroadcastDetail 获取语音播报详情
+func GetVoiceBroadcastDetail(broadcastId, userId int) (detail response.Broadcast, err error) {
+	item, e := voice_broadcast.GetBroadcastById(broadcastId)
 	if e != nil {
-		err = errors.New("获取语音播报列表失败")
+		err = errors.New("获取语音播报详情失败, Err: " + e.Error())
 		return
 	}
-	// 获取语音播报板块分享图
-	sectionList, e := voice_section.GetVoiceSection()
+	// 语音播报图
+	imgList, e := voice_broadcast_img.GetVoiceImgListByVoiceId(broadcastId)
 	if e != nil {
-		err = errors.New("获取语音播报列表失败")
+		err = errors.New("获取语音播报图片失败, Err: " + e.Error())
 		return
 	}
-	sectionMap := make(map[int]string, 0)
-	sectionNameMap := make(map[int]string, 0)
-	for _, s := range sectionList {
-		sectionMap[s.SectionId] = s.ImgUrl
-		sectionNameMap[s.SectionId] = s.SectionName
+	detail = handleBroadcastItem(userId, item, imgList)
+	return
+}
+
+// handleBroadcastItem 语音播报响应数据处理
+func handleBroadcastItem(userId int, item *voice_broadcast.VoiceBroadcast, imgs []*voice_broadcast_img.YbVoiceBroadcastImg) (resp response.Broadcast) {
+	if item == nil {
+		return
 	}
-	// 生成语音分享图并更新
-	listLen := len(list)
-	fmt.Println("待更新数:", listLen)
-	updateCols := []string{"ImgUrl"}
-	for i := 0; i < listLen; i++ {
-		item := list[i]
-		fmt.Println("正在更新-Id:", item.BroadcastId)
-		imgUrl := sectionMap[item.SectionId]
-		if imgUrl == "" {
-			fmt.Println("背景图为空-Id:", item.BroadcastId)
-			continue
+	resp.BroadcastId = item.BroadcastId
+	resp.BroadcastName = item.BroadcastName
+	resp.SectionId = item.SectionId
+	resp.SectionName = item.SectionName
+	resp.VarietyId = item.VarietyId
+	resp.VarietyName = item.VarietyName
+	resp.AuthorId = item.AuthorId
+	resp.Author = item.Author
+	resp.ImgUrl = item.ImgUrl
+	resp.VoiceUrl = item.VoiceUrl
+	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
+	// 是否为作者、是否可推送消息
+	if userId == item.AuthorId {
+		resp.IsAuthor = true
+		if item.MsgState == 0 {
+			resp.CouldSendMsg = true
 		}
-		sectionName := sectionNameMap[item.SectionId]
-		timeDate := item.CreateTime[0:10]
-		pars := VoiceBroadcastShareImgPars{
-			BackgroundImg: imgUrl,
-			Title:         sectionName,
-			CreateTime:    timeDate,
-		}
-		parsByte, e := json.Marshal(pars)
-		if e != nil {
-			err = errors.New("分享图参数有误")
-			return
-		}
-		shareImg, e := GetDynamicShareImg(VoiceBroadcastShareImgSource, string(parsByte))
-		//fmt.Println(shareImg)
-		if e != nil {
-			err = errors.New("生成分享图失败")
-			return
+	}
+	imgLen := len(imgs)
+	imgArr := make([]string, 0)
+	for i := 0; i < imgLen; i++ {
+		imgArr = append(imgArr, imgs[i].ImgUrl)
+	}
+	resp.Imgs = imgArr
+	return
+}
+
+// GetMyVoiceBroadcastListCount 获取我的语音播报列表计数
+func GetMyVoiceBroadcastListCount(authorId, sectionId int) (resp response.BroadcastListStatusCount, err error) {
+	condition := ` 1=1 `
+	var pars []interface{}
+	// 我的-非我的只能看到已发布
+	if authorId > 0 {
+		condition += ` AND author_id = ?`
+		pars = append(pars, authorId)
+	}
+	// 板块
+	if sectionId > 0 {
+		condition += ` AND section_id = ?`
+		pars = append(pars, sectionId)
+	}
+	counts, e := voice_broadcast.GetVoiceBroadcastListStatusCount(condition, pars)
+	if e != nil {
+		err = errors.New("获取语音播报列表计数失败, Err: " + e.Error())
+		return
+	}
+	for _, v := range counts {
+		if v.State == 0 {
+			resp.Unpublished = v.Num
+			continue
 		}
-		item.ImgUrl = shareImg
-		if e = item.Update(updateCols); e != nil {
-			err = errors.New("更新语音播报失败")
-			return
+		if v.State == 1 {
+			resp.Published = v.Num
 		}
-		fmt.Println("更新成功-Id:", item.BroadcastId)
 	}
+	resp.All = resp.Unpublished + resp.Published
 	return
-}
+}

+ 20 - 14
utils/constants.go

@@ -125,18 +125,23 @@ const HZPHONE = "057187186319" //弘则电话
 
 //模板消息推送类型
 const (
-	TEMPLATE_MSG_REPORT               = iota + 1 //日度点评报告推送
-	TEMPLATE_MSG_INDEX                           //指标更新
-	TEMPLATE_MSG_APPLY                           //审批通知
-	TEMPLATE_MSG_RECEIVE                         //销售领取客户通知
-	TEMPLATE_MSG_CYGX_ACTIVITY_CACLE             //查研观向活动取消通知
-	TEMPLATE_MSG_CYGX_ACTIVITY_UPDATE            //查研观向活动更改时间通知
-	TEMPLATE_MSG_CYGX_ARTICLE                    //关注的作者发布报告通知
-	TEMPLATE_MSG_CYGX_DAY_REPORT                 //发送日报(周报、双周报、月报)
-	TEMPLATE_MSG_ACTIVITY_APPOINTMENT            //活动预约/报名时间通知
-	_
-	TEMPLATE_MSG_YB_COMMUNITY_QUESTION // 研报小程序-问答社区通知
-	TEMPLATE_MSG_YB_VOICE_BROADCAST    // 研报小程序-语音播报
+	TEMPLATE_MSG_REPORT                = iota + 1 //日度点评报告推送
+	TEMPLATE_MSG_INDEX                            //指标更新
+	TEMPLATE_MSG_APPLY                            //审批通知
+	TEMPLATE_MSG_RECEIVE                          //销售领取客户通知
+	TEMPLATE_MSG_CYGX_ACTIVITY_CACLE              //查研观向活动取消通知
+	TEMPLATE_MSG_CYGX_ACTIVITY_UPDATE             //查研观向活动更改时间通知
+	TEMPLATE_MSG_CYGX_ARTICLE                     //关注的作者发布报告通知
+	TEMPLATE_MSG_CYGX_DAY_REPORT                  //发送日报(周报、双周报、月报)
+	TEMPLATE_MSG_ACTIVITY_APPOINTMENT             //活动预约/报名时间通知
+	TEMPLATE_MSG_RECEIVE_PERMISSION               //销售"添加客户/领取客户"权限变更通知
+	TEMPLATE_MSG_YB_COMMUNITY_QUESTION            //研报问答社区
+	TEMPLATE_MSG_CYGX_ACTIVITY_ADD                //查研观向小程序活动更新推送 12
+	TEMPLATE_MSG_CYGX_ARTICLE_ADD                 //查研观向报告更新推送  13
+	TEMPLATE_MSG_YB_PRICE_DRIVEN                  //研报价格驱动 14
+	TEMPLATE_MSG_SEAL_FINISHED                    //用印申请已迁回通知 15
+	TEMPLATE_MSG_YB_COMMUNITY_VIDEO               //研报视频社区 16
+	TEMPLATE_MSG_YB_VOICE_BROADCAST               //研报语音播报 17
 )
 
 // 微信用户user_record注册平台
@@ -155,8 +160,9 @@ const (
 )
 
 const (
-	AdminId  = 11      //系统操作的用户id
-	RealName = "超级管理员" //系统操作的用户名称
+	AdminId     = 11      //系统操作的用户id
+	RealName    = "超级管理员" //系统操作的用户名称
+	HzCompanyId = 16      // 弘则研究公司ID
 )
 
 // 报告