Browse Source

Merge branch 'master' into yb/5.1

# Conflicts:
#	controller/community/question.go
#	models/response/community.go
#	services/community/question.go
xiexiaoyuan 2 years ago
parent
commit
16dc188a65
63 changed files with 2423 additions and 161 deletions
  1. 2 0
      controller/chart/chart_info.go
  2. 5 5
      controller/community/question.go
  3. 72 0
      controller/community/video.go
  4. 1 1
      controller/pc/pc.go
  5. 61 0
      controller/price_driven/price_driven.go
  6. 21 2
      controller/public.go
  7. 25 0
      controller/report/report.go
  8. 174 0
      controller/sandbox/sandbox.go
  9. 25 0
      controller/user/user.go
  10. 7 0
      init_serve/router.go
  11. 91 0
      logic/sandbox/sandbox.go
  12. 74 15
      logic/user/user.go
  13. 27 0
      middleware/common.go
  14. 20 7
      models/request/community.go
  15. 11 0
      models/request/price_driven.go
  16. 5 0
      models/request/public.go
  17. 9 0
      models/request/sandbox/sandbox.go
  18. 17 2
      models/response/community.go
  19. 21 18
      models/response/permission.go
  20. 13 0
      models/response/price_driven.go
  21. 17 16
      models/response/report.go
  22. 9 0
      models/response/sandbox.go
  23. 7 6
      models/tables/chart_permission/chart_permission.go
  24. 1 1
      models/tables/chart_permission_first/chart_permission_first.go
  25. 41 0
      models/tables/sandbox/query.go
  26. 58 0
      models/tables/sandbox/sandbox.go
  27. 35 0
      models/tables/variety_classify/entity.go
  28. 11 0
      models/tables/variety_classify/model.go
  29. 50 0
      models/tables/variety_tag/entity.go
  30. 11 0
      models/tables/variety_tag/model.go
  31. 31 31
      models/tables/yb_community_question/entity.go
  32. 62 0
      models/tables/yb_community_video/entity.go
  33. 41 0
      models/tables/yb_community_video/model.go
  34. 50 0
      models/tables/yb_community_video_play_log/entity.go
  35. 8 0
      models/tables/yb_community_video_play_log/model.go
  36. 45 0
      models/tables/yb_index_tab/entity.go
  37. 21 0
      models/tables/yb_index_tab/model.go
  38. 9 0
      models/tables/yb_poster_config/query.go
  39. 46 0
      models/tables/yb_poster_config/yb_poster_config.go
  40. 67 0
      models/tables/yb_price_driven/entity.go
  41. 20 0
      models/tables/yb_price_driven/model.go
  42. 35 0
      models/tables/yb_price_driven_tag/entity.go
  43. 9 0
      models/tables/yb_price_driven_tag/model.go
  44. 56 0
      models/tables/yb_price_driven_visit_log/entity.go
  45. 8 0
      models/tables/yb_price_driven_visit_log/model.go
  46. 5 0
      routers/community.go
  47. 15 0
      routers/price_driven.go
  48. 1 0
      routers/public.go
  49. 1 0
      routers/report.go
  50. 15 0
      routers/sandbox.go
  51. 1 0
      routers/user.go
  52. 7 8
      services/activity/activity.go
  53. 8 8
      services/community/question.go
  54. 94 0
      services/community/video.go
  55. 147 7
      services/company/permission.go
  56. 19 0
      services/page.go
  57. 81 0
      services/price_driven/price_driven.go
  58. 7 0
      services/report/report.go
  59. 16 0
      services/report/report_view_record.go
  60. 327 34
      services/share_poster.go
  61. 99 0
      services/variety_tag.go
  62. 111 0
      static/htm2img/price_driven.html
  63. 40 0
      static/htm2img/rddp-share.html

+ 2 - 0
controller/chart/chart_info.go

@@ -116,6 +116,8 @@ func GetChartInfoDetail(c *gin.Context) {
 		startDate = "2019-01-01"
 	case 9:
 		startDate = "2020-01-01"
+	case 11:
+		startDate = "2022-01-01"
 	}
 
 	if chartType == 2 {

+ 5 - 5
controller/community/question.go

@@ -25,8 +25,8 @@ import (
 // @Param page_index			query int false "页码"
 // @Param page_size				query int false "每页数量"
 // @Param only_mine				query int false "只看我的"
-// @Param chart_permission_id	query int false "品种权限ID"
-// @Param reply_status			query int false "回复状态 0-全部 2-回答 3-已回答,4-待回答(研究员)"
+// @Param variety_tag_id		query int false "标签ID"
+// @Param reply_status			query int false "回复状态 0-全部 2-回答 3-已回答,4-待回答(研究员)"
 // @Success 200 {object} []respond.CommunityQuestionItem
 // @failure 400 {string} string "获取失败"
 // @Router /question/list [get]
@@ -43,7 +43,7 @@ func QuestionList(c *gin.Context) {
 		req.PageSize = utils.PageSize20
 	}
 	userinfo := user.GetInfoByClaims(c)
-	list, err := community.GetQuestionList(req.PageIndex, req.PageSize, req.OnlyMine, req.ChartPermissionId, req.ReplyStatus, req.GroupId, userinfo)
+	list, err := community.GetQuestionList(req.PageIndex, req.PageSize, req.OnlyMine, req.VarietyTagId, req.ReplyStatus, req.GroupId, userinfo)
 	if err != nil {
 		response.FailMsg("获取失败", "QuestionList ErrMsg:"+err.Error(), c)
 		return
@@ -285,7 +285,7 @@ func QuestionUnread(c *gin.Context) {
 // @Success 200 {int} int "获取成功"
 // @failure 400 {string} string "获取失败"
 // @Router /question/research_group [get]
-func ResearchGroupList(c *gin.Context)  {
+func ResearchGroupList(c *gin.Context) {
 	list, err := community.GetResearchGroupTree()
 	if err != nil {
 		fmt.Println(err.Error())
@@ -323,4 +323,4 @@ func AddAudioLog(c *gin.Context) {
 		return
 	}
 	response.Ok("操作成功", c)
-}
+}

+ 72 - 0
controller/community/video.go

@@ -0,0 +1,72 @@
+package community
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/response"
+	"hongze/hongze_yb/models/request"
+	"hongze/hongze_yb/services/community"
+	"hongze/hongze_yb/services/user"
+	"hongze/hongze_yb/utils"
+)
+
+// VideoList 视频列表
+// @Tags 视频社区模块
+// @Description 获取视频社区列表
+// @Param page_index			query int false "页码"
+// @Param page_size				query int false "每页数量"
+// @Param keywords				query string false "只看我的"
+// @Param video_id				query int false "视频ID"
+// @Param variety_tag_id		query int false "标签ID"
+// @Success 200 {object}
+// @failure 400 {string} string "获取失败"
+// @Router /video/list [get]
+func VideoList(c *gin.Context) {
+	var req request.VideoListReq
+	if err := c.Bind(&req); err != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.PageIndex == 0 {
+		req.PageIndex = 1
+	}
+	if req.PageSize == 0 {
+		req.PageSize = utils.PageSize20
+	}
+	list, err := community.GetVideoList(req.PageIndex, req.PageSize, req.VideoId, req.VarietyTagId, req.Keywords)
+	if err != nil {
+		response.FailMsg("获取失败", "VideoList ErrMsg:"+err.Error(), c)
+		return
+	}
+	response.OkData("获取成功", list, c)
+}
+
+// VideoPlayLog 记录视频播放日志
+// @Tags 视频社区模块
+// @Description 记录视频播放日志
+// @Param video_id		query  int  true  "音频ID"
+// @Param source_agent	query  int  true  "操作来源,1:小程序,2:小程序 pc 3:弘则研究公众号,4:web pc"
+// @Success 200 {string} string "操作成功"
+// @failure 400 {string} string "操作失败"
+// @Router /video/play_log [post]
+func VideoPlayLog(c *gin.Context) {
+	var req request.VideoPlayLogReq
+	if err := c.ShouldBind(&req); err != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.VideoId == 0 {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.SourceAgent == 0 {
+		response.Fail("参数有误", c)
+		return
+	}
+	userinfo := user.GetInfoByClaims(c)
+	errMsg, err := community.SaveVideoPlayLog(userinfo, req.VideoId, req.SourceAgent)
+	if err != nil {
+		response.FailMsg(errMsg, "VideoPlayLog ErrMsg:"+err.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
+}

+ 1 - 1
controller/pc/pc.go

@@ -318,7 +318,7 @@ func ClassifyDetailBanner(c *gin.Context) {
 		"王艺滢": utils.ALIYUN_YBIMG_HOST + "wyy.png",
 		"姚昕泽": utils.ALIYUN_YBIMG_HOST + "yxz.png",
 		"章左昊": utils.ALIYUN_YBIMG_HOST + "zzh.png",
-		"李晓": utils.ALIYUN_YBIMG_HOST + "lxt.png",
+		"李晓": utils.ALIYUN_YBIMG_HOST + "lxt.png",
 		"弘则FICC无锡调研团队": utils.ALIYUN_YBIMG_HOST + "qp.png",
 		"弘则能化组": utils.ALIYUN_YBIMG_HOST + "qmz.png",
 		"弘则有色团队": utils.ALIYUN_YBIMG_HOST + "qp.png",

+ 61 - 0
controller/price_driven/price_driven.go

@@ -0,0 +1,61 @@
+package price_driven
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/response"
+	"hongze/hongze_yb/models/request"
+	"hongze/hongze_yb/services/price_driven"
+	"hongze/hongze_yb/services/user"
+)
+
+// PriceDrivenDetail 价格驱动详情
+// @Tags 价格驱动模块
+// @Description 获取价格驱动详情
+// @Param variety_tag_id  query  int  true  "标签ID"
+// @Success 200 {object} response.PriceDrivenItem
+// @failure 400 {string} string "获取失败"
+// @Router /price_driven/detail [get]
+func PriceDrivenDetail(c *gin.Context) {
+	var req request.PriceDrivenDetailReq
+	if err := c.Bind(&req); err != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.VarietyTagId <= 0 {
+		response.Fail("参数有误", c)
+		return
+	}
+	item, errMsg, err := price_driven.GetPriceDrivenDetail(req.VarietyTagId)
+	if err != nil {
+		response.FailMsg(errMsg, "GetPriceDrivenDetail ErrMsg:"+err.Error(), c)
+		return
+	}
+	response.OkData("获取成功", item, c)
+}
+
+// PriceDrivenVisitLog 价格驱动访问记录
+// @Tags 价格驱动模块
+// @Description 价格驱动访问记录
+// @Param price_driven_id	query  int  true  "价格驱动ID"
+// @Param source_agent  	query  int  true  "来源"
+// @Success 200 {string} string "操作成功"
+// @failure 400 {string} string "操作失败"
+// @Router /price_driven/visit_log [post]
+func PriceDrivenVisitLog(c *gin.Context) {
+	var req request.PriceDrivenVisitReq
+	if err := c.Bind(&req); err != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.PriceDrivenId <= 0 {
+		response.Fail("参数有误", c)
+		return
+	}
+	userInfo := user.GetInfoByClaims(c)
+	errMsg, err := price_driven.SavePriceDrivenVisitLog(req.PriceDrivenId, req.SourceAgent, userInfo)
+	if err != nil {
+		response.FailMsg(errMsg, "PriceDrivenVisitLog ErrMsg:"+err.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
+}

+ 21 - 2
controller/public.go

@@ -106,7 +106,7 @@ func GetSharePoster(c *gin.Context) {
 		response.Fail("来源有误", c)
 		return
 	}
-	imgUrl, err := services.CreatePosterFromSource(req.CodePage, req.CodeScene, req.Source, req.Version, req.Pars)
+	imgUrl, err := services.CreatePosterFromSourceV2(req.CodePage, req.CodeScene, req.Source, req.Version, req.Pars)
 	if err != nil {
 		response.FailData("获取分享海报失败", "获取分享海报失败, Err: "+err.Error(), c)
 		return
@@ -131,7 +131,7 @@ func GetSuncodeScene(c *gin.Context) {
 	}
 	pars, err := yb_suncode_pars.GetSceneByKey(reqKey)
 	if err != nil && err != utils.ErrNoRow {
-		response.FailMsg("获取失败", "GetSuncodeScene获取失败, Err: " + err.Error(), c)
+		response.FailMsg("获取失败", "GetSuncodeScene获取失败, Err: "+err.Error(), c)
 		return
 	}
 	scene := ""
@@ -140,3 +140,22 @@ func GetSuncodeScene(c *gin.Context) {
 	}
 	response.OkData("获取成功", scene, c)
 }
+
+// GetVarietyTagTree 标签树
+// @Tags 公共模块
+// @Summary  标签树
+// @Description 标签树
+// @Security ApiKeyAuth
+// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
+// @Param scene_key query string true "scene_key值"
+// @Success 200 {string} string "获取成功"
+// @failure 400 {string} string "获取失败"
+// @Router /public/get_variety_tag_tree [get]
+func GetVarietyTagTree(c *gin.Context) {
+	list, err := services.GetTagTree()
+	if err != nil {
+		response.FailMsg("获取标签树失败", "获取标签树失败, Err: "+err.Error(), c)
+		return
+	}
+	response.OkData("获取成功", list, c)
+}

+ 25 - 0
controller/report/report.go

@@ -3,6 +3,8 @@ package report
 import (
 	"github.com/gin-gonic/gin"
 	"hongze/hongze_yb/controller/response"
+	"hongze/hongze_yb/models/request"
+	"hongze/hongze_yb/services"
 	"hongze/hongze_yb/services/report"
 	userService "hongze/hongze_yb/services/user"
 	"hongze/hongze_yb/utils"
@@ -195,4 +197,27 @@ func TickerData(c *gin.Context)  {
 	}
 	response.OkData("查询成功", chapterDetail, c )
 	return
+}
+
+// RddpShareImg 日度点评分享图(要得急,先这么写吧=_=!)
+func RddpShareImg(c *gin.Context)  {
+	var req request.RddpReportShareImgReq
+	if c.ShouldBind(&req) != nil {
+		response.Fail("参数异常", c)
+		return
+	}
+	defaultImg := "https://hzstatic.hzinsights.com/static/icon/hzyb/rddp-share-bg.png"
+	if req.Title == "" {
+		response.OkData("获取成功", defaultImg, c)
+		return
+	}
+	imgUrl, err := services.GetRddpShareImg(req.Title)
+	if err != nil {
+		response.FailData("获取分享海报失败", "获取分享海报失败, Err: "+err.Error(), c)
+		return
+	}
+	if imgUrl == "" {
+		imgUrl = defaultImg
+	}
+	response.OkData("获取成功", imgUrl, c)
 }

+ 174 - 0
controller/sandbox/sandbox.go

@@ -0,0 +1,174 @@
+package sandbox
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/response"
+	sandboxLogic "hongze/hongze_yb/logic/sandbox"
+	sandboxReq "hongze/hongze_yb/models/request/sandbox"
+	responseModel "hongze/hongze_yb/models/response"
+	sandboxModel "hongze/hongze_yb/models/tables/sandbox"
+	"hongze/hongze_yb/services"
+	"hongze/hongze_yb/services/company"
+	"hongze/hongze_yb/services/user"
+	"strconv"
+	"strings"
+)
+
+// List 获取沙盘逻辑图列表
+// @Tags 沙盘模块
+// @Summary  获取沙盘逻辑图列表
+// @Description 获取沙盘逻辑图列表
+// @Security ApiKeyAuth
+// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
+// @Accept  json
+// @Product json
+// @Param chart_permission query int false "品种权限id"
+// @Param keyword query string false "关键字"
+// @Param is_high_light query bool false "是否高亮显示"
+// @Param curr_page query int false "当前页码"
+// @Param page_size query int false "每页返回数据"
+// @Success 200 {object} sandbox.SandboxListResp
+// @failure 400 {string} string "获取失败"
+// @Router /sandbox/list [get]
+func List(c *gin.Context) {
+	var req sandboxReq.ListReq
+	if err := c.Bind(&req); err != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	// 品种id
+	chartPermissionId := req.ChartPermissionId
+
+	// 关键字
+	keyword := req.Keyword
+	// 是否高亮
+	isHighLight := req.IsHighLight
+
+	page := services.GetCurrPageByClaims(c)
+	pageSize := services.GetPageSizeByClaims(c)
+
+	userInfo := user.GetInfoByClaims(c)
+
+	//权限验证
+	checkOk, companyPermissionIdList, permissionCheckInfo, tempErr := company.CheckUserSandboxPermission(userInfo.CompanyID, int(userInfo.UserID), chartPermissionId)
+	if tempErr != nil {
+		response.FailMsg("沙盘权限验证失败", "沙盘权限验证失败:"+tempErr.Error(), c)
+		c.Abort()
+		return
+	}
+	if !checkOk {
+		response.AuthError(permissionCheckInfo, "暂无权限", c)
+		c.Abort()
+		return
+	}
+
+	//获取指标信息
+	total, list, err, errMsg := sandboxLogic.GetList(chartPermissionId, companyPermissionIdList, keyword, page, pageSize)
+	if err != nil {
+		response.FailMsg(errMsg, err.Error(), c)
+		return
+	}
+
+	// 如果要高亮,且有输入关键字搜索,那么就返回高亮显示字符串
+	if isHighLight && keyword != `` {
+		for index, v := range list {
+			tmpKeyword := `<span style="color:#E3B377">` + keyword + `</span>`
+			list[index].Name = strings.Replace(v.Name, keyword, tmpKeyword, -1)
+		}
+	}
+
+	resp := responseModel.SandboxListResp{
+		List:   list,
+		Paging: responseModel.GetPaging(page, pageSize, int(total)),
+	}
+	response.OkData("获取成功", resp, c)
+}
+
+// Detail 获取沙盘逻辑图详情
+// @Tags 沙盘模块
+// @Summary  获取沙盘逻辑图详情
+// @Description 获取沙盘逻辑图详情
+// @Security ApiKeyAuth
+// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
+// @Accept  json
+// @Product json
+// @Param sandbox_id query int false "沙盘逻辑id"
+// @Success 200 {object} sandbox.SandboxItem
+// @failure 400 {string} string "获取失败"
+// @Router /sandbox/detail [get]
+func Detail(c *gin.Context) {
+	// 沙盘id
+	sandboxIdStr := c.DefaultQuery("sandbox_id", "0")
+	sandboxId, _ := strconv.Atoi(sandboxIdStr)
+
+	userInfo := user.GetInfoByClaims(c)
+
+	sandboxInfo, err := sandboxModel.GetBySandboxId(uint32(sandboxId))
+	if err != nil {
+		response.FailMsg("获取沙盘失败", "获取沙盘失败:"+err.Error(), c)
+		c.Abort()
+		return
+	}
+	//权限验证
+	checkOk, _, permissionCheckInfo, tempErr := company.CheckUserSandboxPermission(userInfo.CompanyID, int(userInfo.UserID), int(sandboxInfo.ChartPermissionID))
+	if tempErr != nil {
+		response.FailMsg("沙盘权限验证失败", "沙盘权限验证失败:"+tempErr.Error(), c)
+		c.Abort()
+		return
+	}
+	if !checkOk {
+		response.AuthError(permissionCheckInfo, "暂无权限", c)
+		c.Abort()
+		return
+	}
+
+	response.OkData("获取成功", sandboxLogic.SandboxItem{
+		SandboxID:           sandboxInfo.SandboxID,
+		Name:                sandboxInfo.Name,
+		ChartPermissionID:   sandboxInfo.ChartPermissionID,
+		ChartPermissionName: sandboxInfo.ChartPermissionName,
+		CurrVersion:         sandboxInfo.CurrVersion,
+		Code:                sandboxInfo.Code,
+		PicURL:              sandboxInfo.PicURL,
+		OpUserName:          sandboxInfo.OpUserName,
+		ModifyTime:          sandboxInfo.ModifyTime,
+	}, c)
+}
+
+// PermissionCountList 获取各个品种下的沙盘图数量列表
+// @Tags 沙盘模块
+// @Summary  获取各个品种下的沙盘图数量列表
+// @Description 获取各个品种下的沙盘图数量列表
+// @Security ApiKeyAuth
+// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
+// @Accept  json
+// @Product json
+// @Param sandbox_id query int false "沙盘逻辑id"
+// @Success 200 {object} []sandboxModel.PermissionSandboxCount
+// @failure 400 {string} string "获取失败"
+// @Router /sandbox/permission_count [get]
+func PermissionCountList(c *gin.Context) {
+	userInfo := user.GetInfoByClaims(c)
+
+	//权限验证
+	checkOk, companyPermissionIdList, permissionCheckInfo, tempErr := company.CheckUserSandboxPermission(userInfo.CompanyID, int(userInfo.UserID), 0)
+	if tempErr != nil {
+		response.FailMsg("沙盘权限验证失败", "沙盘权限验证失败:"+tempErr.Error(), c)
+		c.Abort()
+		return
+	}
+	if !checkOk {
+		response.AuthError(permissionCheckInfo, "暂无权限", c)
+		c.Abort()
+		return
+	}
+
+	//获取指标信息
+	list, err, errMsg := sandboxLogic.GetPermissionCountList(companyPermissionIdList)
+	if err != nil {
+		response.FailMsg(errMsg, err.Error(), c)
+		return
+	}
+
+	response.OkData("获取成功", list, c)
+}

+ 25 - 0
controller/user/user.go

@@ -292,4 +292,29 @@ func SetUserInfo(c *gin.Context) {
 		return
 	}
 	response.Ok("更新成功", c)
+}
+
+// GetTopTab 获取首页顶部Tab
+// @Tags 用户模块
+// @Summary  获取首页顶部Tab
+// @Description 获取首页顶部Tab
+// @Security ApiKeyAuth
+// @securityDefinitions.basic BasicAuth
+// @Param Authorization	header string true "微信登录后获取到的token"
+// @Accept  json
+// @Product json
+// @Success 200 {object} []string "获取成功"
+// @failure 400 {string} string "获取失败"
+// @Router /user/get_top_tab [get]
+func GetTopTab(c *gin.Context) {
+	userInfo := userService.GetInfoByClaims(c)
+	version := c.Request.Header.Get("version")
+	tabBarList, err := userLogic.GetTopTab(userInfo, version)
+
+	if err != nil {
+		response.Fail("获取失败", c)
+		return
+	}
+
+	response.OkData("获取成功", tabBarList, c)
 }

+ 7 - 0
init_serve/router.go

@@ -21,6 +21,9 @@ func InitRouter() (r *gin.Engine) {
 	//r.Use(gin.Recovery())
 	r.Use(middleware.Recover())
 
+	// 公共的中间件
+	r.Use(middleware.Common())
+
 	//swagger界面访问地址
 	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
 
@@ -62,5 +65,9 @@ func InitRouter() (r *gin.Engine) {
 	routers.InitMessage(r)
 	//pc相关路由
 	routers.InitPc(r)
+	// 价格驱动相关路由
+	routers.InitPriceDriven(r)
+	//沙盘逻辑推演路由
+	routers.InitSandbox(r)
 	return
 }

+ 91 - 0
logic/sandbox/sandbox.go

@@ -0,0 +1,91 @@
+package sandbox
+
+import (
+	sandboxModel "hongze/hongze_yb/models/tables/sandbox"
+	"time"
+)
+
+// SandboxItem 沙盘图
+type SandboxItem struct {
+	SandboxID           uint32    `gorm:"primaryKey;column:sandbox_id;type:int(9) unsigned;not null" json:"sandbox_id"`                                                   // 沙盘id
+	Name                string    `gorm:"index:idx_name;column:name;type:varchar(64);not null;default:''" json:"name"`                                                    // 沙盘名称
+	ChartPermissionID   uint32    `gorm:"column:chart_permission_id;type:int(9) unsigned;not null;default:0" json:"chart_permission_id"`                                  // 品种id
+	ChartPermissionName string    `gorm:"index:idx_chart_permission_name;column:chart_permission_name;type:varchar(32);not null;default:''" json:"chart_permission_name"` // 品种名称(冗余字段,避免列表页查询时再去关联表查询)
+	CurrVersion         uint32    `gorm:"column:curr_version;type:int(9) unsigned;not null;default:0" json:"curr_version"`                                                // 当前版本
+	Code                string    `gorm:"column:code;type:varchar(255);not null" json:"code"`                                                                             // 沙盘code
+	PicURL              string    `gorm:"column:pic_url;type:varchar(255);not null;default:''" json:"pic_url"`                                                            // 沙盘图片
+	OpUserName          string    `gorm:"index:idx_op_user_name;column:op_user_name;type:varchar(32);not null;default:''" json:"op_user_name"`                            // 最近一次编辑的用户名称(冗余字段,避免查表)
+	ModifyTime          time.Time `gorm:"column:modify_time;type:timestamp;default:CURRENT_TIMESTAMP" json:"modify_time"`                                                 // 最近一次更新时间
+}
+
+// GetList 获取沙盘列表数据
+func GetList(chartPermissionId int, companyPermissionIdList []int, keyword string, page, pageSize int) (total int64, list []SandboxItem, err error, errMsg string) {
+	errMsg = `获取失败`
+	var condition string
+	var pars []interface{}
+
+	condition = ` is_delete = ? `
+	pars = append(pars, 0)
+
+	// 客户拥有的品种权限
+	if len(companyPermissionIdList) > 0 {
+		condition += " AND chart_permission_id in (?) "
+		pars = append(pars, companyPermissionIdList)
+	}
+
+	if chartPermissionId > 0 {
+		condition += " AND chart_permission_id=? "
+		pars = append(pars, chartPermissionId)
+	}
+
+	if keyword != "" {
+		//condition += ` AND  ( name LIKE '%` + keyword + `%'  OR  chart_permission_name LIKE '%` + keyword + `%' )`
+		condition += ` AND  ( name LIKE '%` + keyword + `%' )`
+	}
+
+	//获取指标信息
+	tmpTotal, tmpList, tmpErr := sandboxModel.GetPageListByWhere(condition, pars, (page-1)*pageSize, pageSize)
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+
+	total = tmpTotal
+
+	for _, v := range tmpList {
+		tmpSandBox := SandboxItem{
+			SandboxID:           v.SandboxID,
+			Name:                v.Name,
+			ChartPermissionID:   v.ChartPermissionID,
+			ChartPermissionName: v.ChartPermissionName,
+			CurrVersion:         v.CurrVersion,
+			Code:                v.Code,
+			PicURL:              v.PicURL,
+			OpUserName:          v.OpUserName,
+			ModifyTime:          v.ModifyTime,
+			//CreateTime:          time.Time{},
+		}
+		list = append(list, tmpSandBox)
+	}
+	return
+}
+
+// GetPermissionCountList 获取沙盘列表数据
+func GetPermissionCountList(companyPermissionIdList []int) (list []*sandboxModel.PermissionSandboxCount, err error, errMsg string) {
+	errMsg = `获取失败`
+	var condition string
+	var pars []interface{}
+
+	condition = ` is_delete = ? `
+	pars = append(pars, 0)
+
+	// 客户拥有的品种权限
+	if len(companyPermissionIdList) > 0 {
+		condition += " AND chart_permission_id in (?) "
+		pars = append(pars, companyPermissionIdList)
+	}
+
+	//获取指标信息
+	list, err = sandboxModel.GetPermissionCountListByWhere(condition, pars)
+	return
+}

+ 74 - 15
logic/user/user.go

@@ -11,6 +11,7 @@ import (
 	"hongze/hongze_yb/models/tables/research_group_relation"
 	"hongze/hongze_yb/models/tables/wx_user"
 	"hongze/hongze_yb/models/tables/yb_apply_record"
+	"hongze/hongze_yb/models/tables/yb_index_tab"
 	"hongze/hongze_yb/models/tables/yb_message"
 	"hongze/hongze_yb/services"
 	companyService "hongze/hongze_yb/services/company"
@@ -399,24 +400,34 @@ func Apply(userId int, companyId int64, mobile, email string, applyInfo userReq.
 
 // GetUserTabBar 获取用户小程序TabBar
 func GetUserTabBar(userInfo user.UserInfo, version string) (list []string, err error) {
-	// user-我的; activity-活动; chart-图表; report-研报; buy-已购; question-问答;
-	list = []string{"activity", "user", "chart"}
-	if version == "yb3.0" {
-		list = []string{"activity", "user", "chart", "report"}
+	where := make(map[string]interface{})
+	where["version"] = version
+	where["position"] = 2
+	where["is_show"] = 1
+	tabs, e := yb_index_tab.GetListByCondition(where)
+	if e != nil {
+		err = errors.New("获取TabBar失败, Err: " + e.Error())
+		return
 	}
-	if version == "yb5.0" {
-		list = []string{"activity", "question", "chart", "report"}
+	if len(tabs) == 0 {
+		return
 	}
-	companyProduct, tmpErr := company_product.GetByCompany2ProductId(userInfo.CompanyID, 1)
-	if tmpErr != nil {
-		if tmpErr == utils.ErrNoRow {
-			err = nil
-		}
+	authOk := false
+	companyProduct, e := company_product.GetByCompany2ProductId(userInfo.CompanyID, 1)
+	if e != nil && e != utils.ErrNoRow {
+		err = errors.New("获取客户信息失败, Err: " + e.Error())
 		return
 	}
-	// 已购仅付费用户可见
-	if strings.Contains("永续,正式", companyProduct.Status) {
-		list = append(list, "buy")
+	if companyProduct != nil {
+		if strings.Contains("永续,正式", companyProduct.Status) {
+			authOk = true
+		}
+	}
+	for _, v := range tabs {
+		if v.AuthCheck == 1 && !authOk {
+			continue
+		}
+		list = append(list, v.Mark)
 	}
 	return
 }
@@ -480,8 +491,56 @@ func PcSendEmailCode(email string) (err error, errMsg string) {
 		}
 		err = item.Create()
 	} else {
-		err = errors.New("发送失败,Err:" + err.Error())
+		err = errors.New("发送失败")
 	}
 
 	return
 }
+
+// TopTab
+type TopTab struct {
+	Tab  string `json:"tab" description:"选项卡名称"`
+	Mark string `json:"mark" description:"选项卡标识"`
+	Icon string `json:"icon" description:"icon图标"`
+	Sort int    `json:"sort" description:"排序"`
+}
+
+// GetTopTab 获取小程序首页顶部选项卡
+func GetTopTab(userInfo user.UserInfo, version string) (list []*TopTab, err error) {
+	where := make(map[string]interface{})
+	where["version"] = version
+	where["position"] = 1
+	where["is_show"] = 1
+	tabs, e := yb_index_tab.GetListByCondition(where)
+	if e != nil {
+		err = errors.New("获取TabBar失败, Err: " + e.Error())
+		return
+	}
+	if len(tabs) == 0 {
+		return
+	}
+	authOk := false
+	companyProduct, e := company_product.GetByCompany2ProductId(userInfo.CompanyID, 1)
+	if e != nil && e != utils.ErrNoRow {
+		err = errors.New("获取客户信息失败, Err: " + e.Error())
+		return
+	}
+	if companyProduct != nil {
+		if strings.Contains("永续,正式", companyProduct.Status) {
+			authOk = true
+		}
+	}
+	list = make([]*TopTab, 0)
+	for _, v := range tabs {
+		if v.AuthCheck == 1 && !authOk {
+			continue
+		}
+		list = append(list, &TopTab{
+			Tab: v.Tab,
+			Mark: v.Mark,
+			Icon: v.DefaultIcon,
+			Sort: v.Sort,
+		})
+	}
+	return
+}

+ 27 - 0
middleware/common.go

@@ -0,0 +1,27 @@
+package middleware
+
+import (
+	"github.com/gin-gonic/gin"
+	"strconv"
+)
+
+// Common 公共中间件
+func Common() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var currPage, pageSize int
+		reqPage := c.DefaultQuery("curr_page", "0")
+		currPage, _ = strconv.Atoi(reqPage)
+		if currPage <= 0 {
+			currPage = 1
+		}
+
+		reqPageSize := c.DefaultQuery("page_size", "0")
+		pageSize, _ = strconv.Atoi(reqPageSize)
+		if pageSize <= 0 {
+			pageSize = 20
+		}
+		c.Set("curr_page", currPage)
+		c.Set("page_size", pageSize)
+		c.Next()
+	}
+}

+ 20 - 7
models/request/community.go

@@ -1,12 +1,12 @@
 package request
 
 type QuestionListReq struct {
-	PageIndex         int `json:"page_index" form:"page_index"`
-	PageSize          int `json:"page_size" form:"page_size"`
-	OnlyMine          int `json:"only_mine" form:"only_mine"`
-	ChartPermissionId int `json:"chart_permission_id" form:"chart_permission_id"`
-	ReplyStatus       int `json:"reply_status" form:"reply_status"`
-	GroupId           int `json:"group_id" form:"group_id"`
+	PageIndex    int `json:"page_index" form:"page_index"`
+	PageSize     int `json:"page_size" form:"page_size"`
+	OnlyMine     int `json:"only_mine" form:"only_mine"`
+	VarietyTagId int `json:"variety_tag_id" form:"variety_tag_id"`
+	ReplyStatus  int `json:"reply_status" form:"reply_status"`
+	GroupId      int `json:"group_id" form:"group_id"`
 }
 
 type QuestionDetailReq struct {
@@ -40,4 +40,17 @@ type ReplyListTotalReq struct {
 type CommunityAudioListenLogReq struct {
 	CommunityQuestionAudioID int `json:"community_question_audio_id"` //音频ID
 	SourceAgent              int `json:"source_agent"`                //操作来源,1:小程序,2:小程序 pc 3:弘则研究公众号,4:web pc
-}
+}
+
+type VideoListReq struct {
+	PageIndex    int    `json:"page_index" form:"page_index"`
+	PageSize     int    `json:"page_size" form:"page_size"`
+	Keywords     string `json:"keywords" form:"keywords"`
+	VideoId      int    `json:"video_id" form:"video_id"`
+	VarietyTagId int    `json:"variety_tag_id" form:"variety_tag_id"`
+}
+
+type VideoPlayLogReq struct {
+	VideoId     int `json:"video_id" description:"视频ID"`
+	SourceAgent int `json:"source_agent" description:"来源:1-小程序 2-小程序PC 3-公众号 4-Web官网"`
+}

+ 11 - 0
models/request/price_driven.go

@@ -0,0 +1,11 @@
+package request
+
+type PriceDrivenDetailReq struct {
+	//ChartPermissionId int `json:"chart_permission_id" form:"chart_permission_id"`
+	VarietyTagId int `json:"variety_tag_id" form:"variety_tag_id"`
+}
+
+type PriceDrivenVisitReq struct {
+	PriceDrivenId int `json:"price_driven_id" description:"价格驱动ID"`
+	SourceAgent   int `json:"source_agent" description:"来源:1-小程序 2-小程序PC 3-公众号 4-Web官网"`
+}

+ 5 - 0
models/request/public.go

@@ -0,0 +1,5 @@
+package request
+
+type RddpReportShareImgReq struct {
+	Title string `description:"标题" json:"title"`
+}

+ 9 - 0
models/request/sandbox/sandbox.go

@@ -0,0 +1,9 @@
+package sandbox
+
+type ListReq struct {
+	ChartPermissionId int    `json:"chart_permission_id" form:"chart_permission_id" description:"品种id"`
+	Keyword           string `json:"keyword" form:"keyword" description:"关键字"`
+	IsHighLight       bool   `json:"is_high_light" form:"is_high_light" description:"是否高亮显示"`
+	CurrPage          int    `json:"curr_page" form:"curr_page"`
+	PageSize          int    `json:"page_size" form:"page_size"`
+}

+ 17 - 2
models/response/community.go

@@ -7,8 +7,8 @@ type CommunityQuestionItem struct {
 	ReplierRealName         string `json:"replier_real_name"`
 	ReplierRank             string `json:"replier_rank"`
 	ReplierAvatar           string `json:"replier_avatar"`
-	ChartPermissionID       int    `json:"chart_permission_id"`
-	ChartPermissionName     string `json:"chart_permission_name"`
+	VarietyTagId            int    `json:"variety_tag_id"`
+	VarietyTagName          string `json:"variety_tag_name"`
 	ResearchGroupSecondId   int    `json:"research_group_second_id"`
 	ResearchGroupSecondName string `json:"research_group_second_name"`
 	IsRead                  int    `json:"is_read"`
@@ -61,3 +61,18 @@ type ResearchGroupMember struct {
 	AdminId   int    `json:"admin_id"`
 	AdminName string `json:"admin_name"`
 }
+
+// CommunityVideoItem 视频社区
+type CommunityVideoItem struct {
+	CommunityVideoID int    `json:"community_video_id"`
+	Title            string `json:"title"`
+	VarietyTagId     int    `json:"variety_tag_id"`
+	VarietyTagName   string `json:"variety_tag_name"`
+	CoverImgUrl      string `json:"cover_img_url"`
+	VideoUrl         string `json:"video_url"`
+	VideoSeconds     string `json:"video_seconds"`
+	PublishState     int    `json:"publish_state"`
+	PublishTime      string `json:"publish_time"`
+	CreateTime       string `json:"create_time"`
+	ModifyTime       string `json:"modify_time"`
+}

+ 21 - 18
models/response/permission.go

@@ -1,33 +1,36 @@
 package response
 
 type PermissionFirstItem struct {
-	AuthOk     bool
-	Sort       int
-	IsCheck    bool
-	List       PermissionFiccSecondList
+	Id          int `description:"一级品种ID"`
+	AuthOk      bool
+	Sort        int
+	IsCheck     bool
+	List        PermissionFiccSecondList
 	YbIndexName string
 	YbIndexIcon string
 }
 
 type PermissionFiccItem struct {
-	ClassifyName    string   `json:"classify_name"`
-	List            PermissionFiccSecondList   `json:"list"`
-	Sort           int       `json:"sort"`
-	IconUrl       string     `json:"icon_url"`
-	SelectIconUrl     string     `json:"select_icon_url"`
+	Id            int                      `json:"id"`
+	ClassifyName  string                   `json:"classify_name"`
+	List          PermissionFiccSecondList `json:"list"`
+	Sort          int                      `json:"sort"`
+	IconUrl       string                   `json:"icon_url"`
+	SelectIconUrl string                   `json:"select_icon_url"`
 }
 
 type PermissionFiccSecondItem struct {
-	ChartPermissionName string    `json:"chart_permission_name"`
+	ChartPermissionName string `json:"chart_permission_name"`
 	ChartPermissionID   int    `json:"chart_permission_id"`
-	Sort           int 	`json:"sort"`
-	AuthOk     bool   `json:"auth_ok"`
+	Sort                int    `json:"sort"`
+	AuthOk              bool   `json:"auth_ok"`
+	PirceDrivenState    int    `json:"pirce_driven_state" description:"价格驱动品种状态:0-关闭 1-开启"`
 }
 
 type PermissionFiccResp struct {
-	PermissionList 	PermissionFiccList `json:"permission_list"`
-	ContactInfo     PermissionCheckContactInfo    `json:"contact_info"`
-	CheckFlag    bool        `json:"check_flag"`
+	PermissionList PermissionFiccList         `json:"permission_list"`
+	ContactInfo    PermissionCheckContactInfo `json:"contact_info"`
+	CheckFlag      bool                       `json:"check_flag"`
 }
 type PermissionFiccList []*PermissionFiccItem
 
@@ -68,8 +71,8 @@ type PermissionCheckInfo struct {
 
 // PermissionCheckInfoContact 权限校验完成后的结果
 type PermissionCheckContactInfo struct {
-	Name         string       `json:"name" description:"销售名称"`
-	Mobile       string       `json:"mobile" description:"手机号"`
+	Name   string `json:"name" description:"销售名称"`
+	Mobile string `json:"mobile" description:"手机号"`
 }
 
 // CustomerInfo 客户信息
@@ -80,4 +83,4 @@ type CustomerInfo struct {
 	Status      string `json:"status" description:"状态"`
 	IsSuspend   int8   `json:"is_suspend" description:"启用与否字段:1:暂停,0:启用"`
 	HasApply    bool   `json:"has_apply" description:"是否有申请过"`
-}
+}

+ 13 - 0
models/response/price_driven.go

@@ -0,0 +1,13 @@
+package response
+
+// PriceDrivenItem 价格驱动详情
+type PriceDrivenItem struct {
+	PriceDrivenID     int    `json:"price_driven_id" description:"价格驱动ID"`
+	VarietyTagID      int    `json:"variety_tag_id" description:"标签ID"`
+	MainVariable      string `json:"main_variable" description:"关键变量"`
+	CoreDrivenType    int    `json:"core_driven_type" description:"核心驱动类型 0-多 1-空"`
+	CoreDrivenContent string `json:"core_driven_content" description:"核心驱动内容"`
+	CoreContent       string `json:"core_content" description:"核心内容"`
+	CreateTime        string `json:"create_time" description:"创建时间"`
+	ModifyTime        string `json:"modify_time" description:"更新时间"`
+}

+ 17 - 16
models/response/report.go

@@ -11,6 +11,7 @@ type ReportDetail struct {
 	AuthOk            bool                     `json:"auth_ok"`
 	LikeNum           int64                    `description:"点赞总数" json:"like_num"`
 	LikeEnabled       int8                     `description:"是否已点赞: 0-未点赞 1-已点赞" json:"like_enabled"`
+	ReportShowType    int                      `descritpion:"展示形式:1-列表 2-专栏" json:"report_show_type"`
 }
 
 type ReportChapterListItem struct {
@@ -36,22 +37,22 @@ type ReportItem struct {
 	Author             string    `description:"作者" json:"author"`
 	Frequency          string    `description:"频度" json:"frequency"`
 	PublishTime        time.Time `description:"发布时间" json:"publish_time"`
-	Stage              int    `description:"期数" json:"stage"`
-	Content            string `description:"内容" json:"content"`
-	VideoUrl           string `description:"音频文件URL" json:"video_url"`
-	VideoName          string `description:"音频文件名称" json:"video_name"`
-	VideoSize          string `description:"音频文件大小,单位M" json:"video_size"`
-	VideoPlaySeconds   string `description:"音频播放时长" json:"video_play_seconds"`
+	Stage              int       `description:"期数" json:"stage"`
+	Content            string    `description:"内容" json:"content"`
+	VideoUrl           string    `description:"音频文件URL" json:"video_url"`
+	VideoName          string    `description:"音频文件名称" json:"video_name"`
+	VideoSize          string    `description:"音频文件大小,单位M" json:"video_size"`
+	VideoPlaySeconds   string    `description:"音频播放时长" json:"video_play_seconds"`
 	VideoImg           string    `description:"音频播放条的图片" json:"video_img"`
-	ContentSub         string `description:"内容前两个章节" json:"content_sub"`
-	BannerUrl          string `description:"详情页banner" json:"banner_url"`
+	ContentSub         string    `description:"内容前两个章节" json:"content_sub"`
+	BannerUrl          string    `description:"详情页banner" json:"banner_url"`
 }
 
 type ReportChapterItem struct {
 	ReportChapterId       int       `json:"report_chapter_id"`
 	ReportId              int       `json:"report_id"`
 	Title                 string    `json:"title"`
-	Abstract string `json:"abstract"`
+	Abstract              string    `json:"abstract"`
 	TypeId                int       `json:"type_id"`
 	TypeName              string    `json:"type_name"`
 	Trend                 string    `json:"trend"`
@@ -80,13 +81,13 @@ type ReportChapterDetail struct {
 }
 
 type ReportChapterMenu struct {
-	ReportChapterId    int    `json:"report_chapter_id"`
-	ReportId        int    `json:"report_id"`
-	ReportChapterTypeName   string       `json:"report_chapter_type_name"`
-	ReportChapterTypeThumb  string	    `json:"report_chapter_type_thumb"`
-	PcSelectedThumb  string	    `json:"pc_selected_thumb"`
-	PcUnselectedThumb  string	    `json:"pc_unselected_thumb"`
-	Sort             int  `json:"sort"`
+	ReportChapterId        int    `json:"report_chapter_id"`
+	ReportId               int    `json:"report_id"`
+	ReportChapterTypeName  string `json:"report_chapter_type_name"`
+	ReportChapterTypeThumb string `json:"report_chapter_type_thumb"`
+	PcSelectedThumb        string `json:"pc_selected_thumb"`
+	PcUnselectedThumb      string `json:"pc_unselected_thumb"`
+	Sort                   int    `json:"sort"`
 }
 
 type ReportListItem struct {

+ 9 - 0
models/response/sandbox.go

@@ -0,0 +1,9 @@
+package response
+
+import "hongze/hongze_yb/logic/sandbox"
+
+// SandboxListResp 沙盘逻辑数据反馈
+type SandboxListResp struct {
+	List   []sandbox.SandboxItem `json:"list"`
+	Paging *PagingItem           `json:"paging"`
+}

+ 7 - 6
models/tables/chart_permission/chart_permission.go

@@ -16,12 +16,13 @@ type ChartPermission struct {
 	ClassifyName        string    `gorm:"column:classify_name;type:varchar(50)" json:"classifyName"`
 	ProductName         string    `gorm:"column:product_name;type:varchar(50);default:''" json:"productName"`
 	ProductID           int       `gorm:"column:product_id;type:int(11);default:0" json:"productId"`
-	ImageURL            string    `gorm:"column:image_url;type:varchar(255)" json:"imageUrl"`                                  // 图片地址
-	ShowType            int8      `gorm:"column:show_type;type:tinyint(4);default:0" json:"showType"`                          // 1:查研观向小程序展示
-	IsOther             int8      `gorm:"column:is_other;type:tinyint(2);not null;default:0" json:"isOther"`                   // 是否是其他,用于查研观向小程序后台展示
-	IsReport            int8      `gorm:"index:is_report;column:is_report;type:tinyint(4);not null;default:0" json:"isReport"` // 是否是报告,用于查研观向小程序前台报告展示
-	CygxAuth            int8      `gorm:"column:cygx_auth;type:tinyint(4);not null;default:0" json:"cygxAuth"`                 // 是否是权限,用于查研观向小程序前台权限校验
-	YbImgUrl            string      `gorm:"column:yb_img_url;type:varchar(255)" json:"yb_img_url"`                            // 研报小程序报告列表icon
+	ImageURL            string    `gorm:"column:image_url;type:varchar(255)" json:"imageUrl"`                                     // 图片地址
+	ShowType            int8      `gorm:"column:show_type;type:tinyint(4);default:0" json:"showType"`                             // 1:查研观向小程序展示
+	IsOther             int8      `gorm:"column:is_other;type:tinyint(2);not null;default:0" json:"isOther"`                      // 是否是其他,用于查研观向小程序后台展示
+	IsReport            int8      `gorm:"index:is_report;column:is_report;type:tinyint(4);not null;default:0" json:"isReport"`    // 是否是报告,用于查研观向小程序前台报告展示
+	CygxAuth            int8      `gorm:"column:cygx_auth;type:tinyint(4);not null;default:0" json:"cygxAuth"`                    // 是否是权限,用于查研观向小程序前台权限校验
+	YbImgUrl            string    `gorm:"column:yb_img_url;type:varchar(255)" json:"yb_img_url"`                                  // 研报小程序报告列表icon
+	PriceDrivenState    int       `gorm:"column:price_driven_state;type:tinyint(4);not null;default:0" json:"price_driven_state"` // 品种价格驱动状态:0-关闭 1-开启
 }
 
 // TableName get sql table name.获取数据库表名

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

@@ -4,7 +4,7 @@ import "time"
 
 // ChartPermissionFirst 报告权限一级分类表
 type ChartPermissionFirst struct {
-	Id           uint64    `gorm:"primaryKey;column:id;type:bigint(20) unsigned;not null" json:"-"`
+	Id           uint64    `gorm:"primaryKey;column:id;type:bigint(20) unsigned;not null" json:"id"`
 	ClassifyName string    `gorm:"column:classify_name;type:varchar(50)"`                                        // 权限一级分类名称,与chart_permission的classify_name一致
 	YbIndexName  string    `gorm:"column:yb_index_name;type:varchar(50);default:''" `                            // 研报小程序首页简称
 	YbIndexSort  int      `gorm:"column:yb_index_sort;type:tinyint(4);default:0"`                               // 研报小程序首页排序

+ 41 - 0
models/tables/sandbox/query.go

@@ -0,0 +1,41 @@
+package sandbox
+
+import (
+	"hongze/hongze_yb/global"
+)
+
+// GetBySandboxId 根据沙盘ID查询详情
+func GetBySandboxId(id uint32) (item *Sandbox, err error) {
+	err = global.DEFAULT_MYSQL.Where("sandbox_id = ? and is_delete=0 ", id).Order("sandbox_id desc").First(&item).Error
+	return
+}
+
+// GetPageListByWhere 分页获取活动列表
+func GetPageListByWhere(condition string, pars []interface{}, startSize, pageSize int) (total int64, list []*Sandbox, err error) {
+	// 获取查询总数量
+	err = global.DEFAULT_MYSQL.Model(Sandbox{}).Where(condition, pars...).Count(&total).Error
+	if err != nil {
+		return
+	}
+
+	// 获取列表数据
+	err = global.DEFAULT_MYSQL.Model(Sandbox{}).Where(condition, pars...).Order("modify_time desc,sandbox_id desc").Offset(startSize).Limit(pageSize).Find(&list).Error
+	return
+}
+
+// PermissionSandboxCount 品种下沙盘数
+type PermissionSandboxCount struct {
+	ChartPermissionID   uint32 `gorm:"column:chart_permission_id;type:int(9) unsigned;not null;default:0" json:"chart_permission_id"`                                  // 品种id
+	ChartPermissionName string `gorm:"index:idx_chart_permission_name;column:chart_permission_name;type:varchar(32);not null;default:''" json:"chart_permission_name"` // 品种名称(冗余字段,避免列表页查询时再去关联表查询)
+	Total               int64  `json:"total"`                                                                                                                          // 汇总数
+}
+
+// GetPermissionCountListByWhere 获取各品种的沙盘数
+func GetPermissionCountListByWhere(condition string, pars []interface{}) (list []*PermissionSandboxCount, err error) {
+
+	//err = global.DEFAULT_MYSQL.Model(ResearchReport{}).Where("research_report_id IN (?)", ids).Scan(&list).Error
+
+	// 获取列表数据
+	err = global.DEFAULT_MYSQL.Model(Sandbox{}).Select("chart_permission_id,chart_permission_name,count(1) total").Where(condition, pars...).Order("modify_time desc,sandbox_id desc").Group("chart_permission_id").Scan(&list).Error
+	return
+}

+ 58 - 0
models/tables/sandbox/sandbox.go

@@ -0,0 +1,58 @@
+package sandbox
+
+import (
+	"time"
+)
+
+// Sandbox 沙盘推演主表
+type Sandbox struct {
+	SandboxID           uint32    `gorm:"primaryKey;column:sandbox_id;type:int(9) unsigned;not null" json:"-"`                                                          // 沙盘id
+	Name                string    `gorm:"index:idx_name;column:name;type:varchar(64);not null;default:''" json:"name"`                                                  // 沙盘名称
+	ChartPermissionID   uint32    `gorm:"column:chart_permission_id;type:int(9) unsigned;not null;default:0" json:"chartPermissionId"`                                  // 品种id
+	ChartPermissionName string    `gorm:"index:idx_chart_permission_name;column:chart_permission_name;type:varchar(32);not null;default:''" json:"chartPermissionName"` // 品种名称(冗余字段,避免列表页查询时再去关联表查询)
+	CurrVersion         uint32    `gorm:"column:curr_version;type:int(9) unsigned;not null;default:0" json:"currVersion"`                                               // 当前版本
+	Code                string    `gorm:"column:code;type:varchar(255);not null" json:"code"`                                                                           // 沙盘code
+	Content             string    `gorm:"column:content;type:text;not null" json:"content"`                                                                             // 沙盘内容
+	PicURL              string    `gorm:"column:pic_url;type:varchar(255);not null;default:''" json:"picUrl"`                                                           // 沙盘图片
+	OpUserID            uint32    `gorm:"column:op_user_id;type:int(10) unsigned;not null;default:0" json:"opUserId"`                                                   // 最近一次编辑操作的用户id
+	OpUserName          string    `gorm:"index:idx_op_user_name;column:op_user_name;type:varchar(32);not null;default:''" json:"opUserName"`                            // 最近一次编辑的用户名称(冗余字段,避免查表)
+	IsDelete            uint8     `gorm:"column:is_delete;type:tinyint(9) unsigned;not null;default:0" json:"isDelete"`                                                 // 是否删除,0:未删除,1:已删除
+	ModifyTime          time.Time `gorm:"column:modify_time;type:timestamp;default:CURRENT_TIMESTAMP" json:"modifyTime"`                                                // 最近一次更新时间
+	CreateTime          time.Time `gorm:"column:create_time;type:timestamp;default:CURRENT_TIMESTAMP" json:"createTime"`                                                // 沙盘创建时间
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *Sandbox) TableName() string {
+	return "sandbox"
+}
+
+// SandboxColumns get sql column name.获取数据库列名
+var SandboxColumns = struct {
+	SandboxID           string
+	Name                string
+	ChartPermissionID   string
+	ChartPermissionName string
+	CurrVersion         string
+	Code                string
+	Content             string
+	PicURL              string
+	OpUserID            string
+	OpUserName          string
+	IsDelete            string
+	ModifyTime          string
+	CreateTime          string
+}{
+	SandboxID:           "sandbox_id",
+	Name:                "name",
+	ChartPermissionID:   "chart_permission_id",
+	ChartPermissionName: "chart_permission_name",
+	CurrVersion:         "curr_version",
+	Code:                "code",
+	Content:             "content",
+	PicURL:              "pic_url",
+	OpUserID:            "op_user_id",
+	OpUserName:          "op_user_name",
+	IsDelete:            "is_delete",
+	ModifyTime:          "modify_time",
+	CreateTime:          "create_time",
+}

+ 35 - 0
models/tables/variety_classify/entity.go

@@ -0,0 +1,35 @@
+package variety_classify
+
+import "time"
+
+// VarietyClassify 标签库分类表
+type VarietyClassify struct {
+	VarietyClassifyID int       `gorm:"primaryKey;column:variety_classify_id;type:int(10) unsigned;not null" json:"-"`  // 品种分类ID
+	ClassifyName      string    `gorm:"column:classify_name;type:varchar(100);not null;default:''" json:"classifyName"` // 品种分类名称
+	Sort              int       `gorm:"column:sort;type:int(10) unsigned;not null;default:0" json:"sort"`               // 排序
+	State             int       `gorm:"column:state;type:tinyint(4) unsigned;not null;default:1" json:"state"`          // 状态:0-禁用 1-开启
+	CreateTime        time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`
+	ModifyTime        time.Time `gorm:"column:modify_time;type:datetime;default:CURRENT_TIMESTAMP" json:"modifyTime"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *VarietyClassify) TableName() string {
+	return "variety_classify"
+}
+
+// VarietyClassifyColumns get sql column name.获取数据库列名
+var VarietyClassifyColumns = struct {
+	VarietyClassifyID string
+	ClassifyName      string
+	Sort              string
+	State             string
+	CreateTime        string
+	ModifyTime        string
+}{
+	VarietyClassifyID: "variety_classify_id",
+	ClassifyName:      "classify_name",
+	Sort:              "sort",
+	State:             "state",
+	CreateTime:        "create_time",
+	ModifyTime:        "modify_time",
+}

+ 11 - 0
models/tables/variety_classify/model.go

@@ -0,0 +1,11 @@
+package variety_classify
+
+import "hongze/hongze_yb/global"
+
+func GetVarietyClassifyList() (list []*VarietyClassify, err error) {
+	err = global.DEFAULT_MYSQL.Model(VarietyClassify{}).
+		Where("state = 1").
+		Order("sort ASC").
+		Scan(&list).Error
+	return
+}

+ 50 - 0
models/tables/variety_tag/entity.go

@@ -0,0 +1,50 @@
+package variety_tag
+
+import "time"
+
+// VarietyTag 品种标签库
+type VarietyTag struct {
+	VarietyTagID                int       `gorm:"primaryKey;column:variety_tag_id;type:int(10) unsigned;not null" json:"-"`                                                   // 品种标签ID
+	VarietyClassifyID           int       `gorm:"index:idx_variety_classify_id;column:variety_classify_id;type:int(10) unsigned;not null;default:0" json:"varietyClassifyId"` // 分类ID
+	VarietyClassifyName         string    `gorm:"column:variety_classify_name;type:varchar(100);not null;default:''" json:"varietyClassifyName"`                              // 品种分类名称
+	TagName                     string    `gorm:"column:tag_name;type:varchar(100);not null;default:''" json:"tagName"`                                                       // 标签名
+	ChartPermissionClassifyName string    `gorm:"column:chart_permission_classify_name;type:varchar(100);not null;default:''" json:"chartPermissionClassifyName"`             // 品种权限分类名
+	ChartPermissionID           int       `gorm:"index:idx_chart_permission_id;column:chart_permission_id;type:int(10) unsigned;not null;default:0" json:"chartPermissionId"` // 品种权限ID
+	ChartPermissionName         string    `gorm:"column:chart_permission_name;type:varchar(100);not null;default:''" json:"chartPermissionName"`                              // 品种权限名称
+	Sort                        int       `gorm:"column:sort;type:int(10) unsigned;not null;default:0" json:"sort"`                                                           // 排序
+	State                       int       `gorm:"column:state;type:tinyint(4) unsigned;not null;default:1" json:"state"`                                                      // 状态:0-禁用 1-启用
+	CreateTime                  time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`
+	ModifyTime                  time.Time `gorm:"column:modify_time;type:datetime;default:CURRENT_TIMESTAMP" json:"modifyTime"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *VarietyTag) TableName() string {
+	return "variety_tag"
+}
+
+// VarietyTagColumns get sql column name.获取数据库列名
+var VarietyTagColumns = struct {
+	VarietyTagID                string
+	VarietyClassifyID           string
+	VarietyClassifyName         string
+	TagName                     string
+	ChartPermissionClassifyName string
+	ChartPermissionID           string
+	ChartPermissionName         string
+	Sort                        string
+	State                       string
+	CreateTime                  string
+	ModifyTime                  string
+}{
+	VarietyTagID:                "variety_tag_id",
+	VarietyClassifyID:           "variety_classify_id",
+	VarietyClassifyName:         "variety_classify_name",
+	TagName:                     "tag_name",
+	ChartPermissionClassifyName: "chart_permission_classify_name",
+	ChartPermissionID:           "chart_permission_id",
+	ChartPermissionName:         "chart_permission_name",
+	Sort:                        "sort",
+	State:                       "state",
+	CreateTime:                  "create_time",
+	ModifyTime:                  "modify_time",
+}

+ 11 - 0
models/tables/variety_tag/model.go

@@ -0,0 +1,11 @@
+package variety_tag
+
+import "hongze/hongze_yb/global"
+
+func GetVarietyTagList() (list []*VarietyTag, err error) {
+	err = global.DEFAULT_MYSQL.Model(VarietyTag{}).
+		Where("state = 1").
+		Order("sort ASC").
+		Scan(&list).Error
+	return
+}

+ 31 - 31
models/tables/yb_community_question/entity.go

@@ -7,33 +7,33 @@ import (
 // YbCommunityQuestion 研报-问答社区表
 type YbCommunityQuestion struct {
 	CommunityQuestionID     int       `gorm:"primaryKey;column:community_question_id;type:int(10) unsigned;not null" json:"-"`
-	UserID                  int       `gorm:"index:idx_user_id;column:user_id;type:int(10) unsigned;not null;default:0" json:"userId"`                                    // 提问用户ID
-	UserOpenid              string    `gorm:"column:user_openid;type:varchar(32);not null;default:''" json:"userOpenid"`                                                  // 提问人openid
-	Mobile                  string    `gorm:"column:mobile;type:varchar(20);not null;default:''" json:"mobile"`                                                           // 用户手机号
-	RealName                string    `gorm:"column:real_name;type:varchar(100);not null;default:''" json:"realName"`                                                     // 用户名
-	QuestionContent         string    `gorm:"column:question_content;type:varchar(255);not null;default:''" json:"questionContent"`                                       // 问题描述
-	ReplierUserID           int       `gorm:"index:idx_replier_user_id;column:replier_user_id;type:int(10) unsigned;not null;default:0" json:"replierUserId"`             // 回复人的user_id
-	ReplierOpenid           string    `gorm:"column:replier_openid;type:varchar(32);not null;default:''" json:"replierOpenid"`                                            // 回复人openid
-	ReplierAdminID          int       `gorm:"column:replier_admin_id;type:int(10) unsigned;not null;default:0" json:"replierAdminId"`                                     // 回复人关联的admin_id
-	ReplierRealName         string    `gorm:"column:replier_real_name;type:varchar(30);not null;default:''" json:"replierRealName"`                                       // 回复人姓名
-	ReplierAvatar           string    `gorm:"column:replier_avatar;type:varchar(255);not null;default:''" json:"replierAvatar"`                                           // 回复人头像
-	ResearchGroupFirstID    int       `gorm:"column:research_group_first_id;type:int(10) unsigned;not null;default:0" json:"researchGroupFirstId"`                        // 回复人研究方向一级分组ID
-	ResearchGroupSecondID   int       `gorm:"column:research_group_second_id;type:int(10) unsigned;not null;default:0" json:"researchGroupSecondId"`                      // 回复人研究方向二级分组ID
-	ResearchGroupFirstName  string    `gorm:"column:research_group_first_name;type:varchar(100);not null;default:''" json:"researchGroupFirstName"`                       // 研究方向一级分组名称
-	ResearchGroupSecondName string    `gorm:"column:research_group_second_name;type:varchar(100);not null;default:''" json:"researchGroupSecondName"`                     // 研究方向二级分组名称
-	DistributeAdminID       int       `gorm:"column:distribute_admin_id;type:int(10) unsigned;not null;default:0" json:"distributeAdminId"`                               // 分配人admin_id
-	DistributeTime          time.Time `gorm:"column:distribute_time;type:datetime" json:"distributeTime"`                                                                 // 分配时间
-	ChartPermissionID       int       `gorm:"index:idx_chart_permission_id;column:chart_permission_id;type:int(10) unsigned;not null;default:0" json:"chartPermissionId"` // 关联权限ID
-	ChartPermissionName     string    `gorm:"column:chart_permission_name;type:varchar(100);not null;default:''" json:"chartPermissionName"`                              // 关联权限name
-	IsRead                  int       `gorm:"column:is_read;type:tinyint(4) unsigned;not null;default:0" json:"isRead"`                                                   // 用户是否已读 0-未读 1-已读
-	ReplierIsRead           int       `gorm:"column:replier_is_read;type:tinyint(4) unsigned;not null;default:0" json:"replierIsRead"`                                    // 回复人是否已读 0-未读 1-已读
-	ReplyStatus             int       `gorm:"column:reply_status;type:tinyint(4) unsigned;not null;default:0" json:"replyStatus"`                                         // 回复状态 1-待分配 2-待回答 3-已回答
-	MsgSendStatus           int       `gorm:"column:msg_send_status;type:tinyint(4) unsigned;not null;default:0" json:"msgSendStatus"`                                    // 消息推送进度 0-待推送 1-已推送回答人 2-已推送提问人
-	ReplyTime               time.Time `gorm:"column:reply_time;type:datetime" json:"replyTime"`                                                                           // 回复时间
-	CreateTime              time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`                                               // 提问时间
-	ModifyTime              time.Time `gorm:"column:modify_time;type:datetime;default:CURRENT_TIMESTAMP" json:"modifyTime"`                                               // 修改时间
-	IsDeleted               int       `gorm:"column:is_deleted;type:tinyint(4) unsigned;not null;default:0" json:"isDeleted"`                                             // 是否已删除 0-否 1-是
-	DeleteTime              time.Time `gorm:"column:delete_time;type:datetime" json:"deleteTime"`                                                                         // 删除时间
+	UserID                  int       `gorm:"index:idx_user_id;column:user_id;type:int(10) unsigned;not null;default:0" json:"userId"`                        // 提问用户ID
+	UserOpenid              string    `gorm:"column:user_openid;type:varchar(32);not null;default:''" json:"userOpenid"`                                      // 提问人openid
+	Mobile                  string    `gorm:"column:mobile;type:varchar(20);not null;default:''" json:"mobile"`                                               // 用户手机号
+	RealName                string    `gorm:"column:real_name;type:varchar(100);not null;default:''" json:"realName"`                                         // 用户名
+	QuestionContent         string    `gorm:"column:question_content;type:varchar(255);not null;default:''" json:"questionContent"`                           // 问题描述
+	ReplierUserID           int       `gorm:"index:idx_replier_user_id;column:replier_user_id;type:int(10) unsigned;not null;default:0" json:"replierUserId"` // 回复人的user_id
+	ReplierOpenid           string    `gorm:"column:replier_openid;type:varchar(32);not null;default:''" json:"replierOpenid"`                                // 回复人openid
+	ReplierAdminID          int       `gorm:"column:replier_admin_id;type:int(10) unsigned;not null;default:0" json:"replierAdminId"`                         // 回复人关联的admin_id
+	ReplierRealName         string    `gorm:"column:replier_real_name;type:varchar(30);not null;default:''" json:"replierRealName"`                           // 回复人姓名
+	ReplierAvatar           string    `gorm:"column:replier_avatar;type:varchar(255);not null;default:''" json:"replierAvatar"`                               // 回复人头像
+	ResearchGroupFirstID    int       `gorm:"column:research_group_first_id;type:int(10) unsigned;not null;default:0" json:"researchGroupFirstId"`            // 回复人研究方向一级分组ID
+	ResearchGroupSecondID   int       `gorm:"column:research_group_second_id;type:int(10) unsigned;not null;default:0" json:"researchGroupSecondId"`          // 回复人研究方向二级分组ID
+	ResearchGroupFirstName  string    `gorm:"column:research_group_first_name;type:varchar(100);not null;default:''" json:"researchGroupFirstName"`           // 研究方向一级分组名称
+	ResearchGroupSecondName string    `gorm:"column:research_group_second_name;type:varchar(100);not null;default:''" json:"researchGroupSecondName"`         // 研究方向二级分组名称
+	DistributeAdminID       int       `gorm:"column:distribute_admin_id;type:int(10) unsigned;not null;default:0" json:"distributeAdminId"`                   // 分配人admin_id
+	DistributeTime          time.Time `gorm:"column:distribute_time;type:datetime" json:"distributeTime"`                                                     // 分配时间
+	VarietyTagID            int       `gorm:"index:idx_variety_tag_id;column:variety_tag_id;type:int(10) unsigned;not null;default:0" json:"varietyTagId"`    // 标签ID
+	VarietyTagName          string    `gorm:"column:variety_tag_name;type:varchar(100);not null;default:''" json:"varietyTagName"`                            // 标签名称
+	IsRead                  int       `gorm:"column:is_read;type:tinyint(4) unsigned;not null;default:0" json:"isRead"`                                       // 用户是否已读 0-未读 1-已读
+	ReplierIsRead           int       `gorm:"column:replier_is_read;type:tinyint(4) unsigned;not null;default:0" json:"replierIsRead"`                        // 回复者是否已读  0-未读 1-已读
+	ReplyStatus             int       `gorm:"column:reply_status;type:tinyint(4) unsigned;not null;default:0" json:"replyStatus"`                             // 回复状态 1-待分配 2-待回答 3-已回答
+	MsgSendStatus           int       `gorm:"column:msg_send_status;type:tinyint(4) unsigned;not null;default:0" json:"msgSendStatus"`                        // 消息推送进度 0-待推送 1-已推送回答人 2-已推送提问人
+	ReplyTime               time.Time `gorm:"column:reply_time;type:datetime" json:"replyTime"`                                                               // 回复时间
+	CreateTime              time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`                                   // 提问时间
+	ModifyTime              time.Time `gorm:"column:modify_time;type:datetime;default:CURRENT_TIMESTAMP" json:"modifyTime"`                                   // 修改时间
+	IsDeleted               int       `gorm:"column:is_deleted;type:tinyint(4) unsigned;not null;default:0" json:"isDeleted"`                                 // 是否已删除 0-否 1-是
+	DeleteTime              time.Time `gorm:"column:delete_time;type:datetime" json:"deleteTime"`                                                             // 删除时间
 }
 
 // TableName get sql table name.获取数据库表名
@@ -60,8 +60,8 @@ var YbCommunityQuestionColumns = struct {
 	ResearchGroupSecondName string
 	DistributeAdminID       string
 	DistributeTime          string
-	ChartPermissionID       string
-	ChartPermissionName     string
+	VarietyTagID            string
+	VarietyTagName          string
 	IsRead                  string
 	ReplierIsRead           string
 	ReplyStatus             string
@@ -89,8 +89,8 @@ var YbCommunityQuestionColumns = struct {
 	ResearchGroupSecondName: "research_group_second_name",
 	DistributeAdminID:       "distribute_admin_id",
 	DistributeTime:          "distribute_time",
-	ChartPermissionID:       "chart_permission_id",
-	ChartPermissionName:     "chart_permission_name",
+	VarietyTagID:            "variety_tag_id",
+	VarietyTagName:          "variety_tag_name",
 	IsRead:                  "is_read",
 	ReplierIsRead:           "replier_is_read",
 	ReplyStatus:             "reply_status",

+ 62 - 0
models/tables/yb_community_video/entity.go

@@ -0,0 +1,62 @@
+package yb_community_video
+
+import "time"
+
+// YbCommunityVideo 研报-视频社区表
+type YbCommunityVideo struct {
+	CommunityVideoID int       `gorm:"primaryKey;column:community_video_id;type:int(10) unsigned;not null" json:"-"`
+	Title            string    `gorm:"column:title;type:varchar(255);not null;default:''" json:"title"`                                             // 视频标题
+	VarietyTagId     int       `gorm:"index:idx_variety_tag_id;column:variety_tag_id;type:int(10) unsigned;not null;default:0" json:"varietyTagId"` // 品种权限ID
+	VarietyTagName   string    `gorm:"column:variety_tag_name;type:varchar(30);not null;default:''" json:"varietyTagName"`                          // 品种权限名称
+	CoverImgURL      string    `gorm:"column:cover_img_url;type:varchar(255);not null;default:''" json:"coverImgUrl"`                               // 封面图地址
+	VideoURL         string    `gorm:"column:video_url;type:varchar(255);not null;default:''" json:"videoUrl"`                                      // 视频地址
+	VideoSeconds     string    `gorm:"column:video_seconds;type:varchar(30);not null;default:''" json:"videoSeconds"`                               // 视频时长
+	PublishState     int       `gorm:"column:publish_state;type:tinyint(4) unsigned;not null;default:0" json:"publishState"`                        // 发布状态:0-未发布 1-已发布
+	SendThsState     int       `gorm:"column:send_ths_state;type:tinyint(4) unsigned;not null;default:0" json:"sendThsState"`                       // 推送客群状态:0-未推送 1-已推送
+	IsDeleted        int       `gorm:"column:is_deleted;type:tinyint(4) unsigned;not null;default:0" json:"isDeleted"`                              // 是否已删除:0-未删除 1-已删除
+	PublishTime      time.Time `gorm:"column:publish_time;type:datetime" json:"publishTime"`                                                        // 发布时间
+	SendThsTime      time.Time `gorm:"column:send_ths_time;type:datetime" json:"sendThsTime"`                                                       // 推送客群时间
+	CreateTime       time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`                                // 创建时间
+	ModifyTime       time.Time `gorm:"column:modify_time;type:datetime;default:CURRENT_TIMESTAMP" json:"modifyTime"`                                // 更新时间
+	DeleteTime       time.Time `gorm:"column:delete_time;type:datetime" json:"deleteTime"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbCommunityVideo) TableName() string {
+	return "yb_community_video"
+}
+
+// YbCommunityVideoColumns get sql column name.获取数据库列名
+var YbCommunityVideoColumns = struct {
+	CommunityVideoID string
+	Title            string
+	varietyTagId     string
+	varietyTagName   string
+	CoverImgURL      string
+	VideoURL         string
+	VideoSeconds     string
+	PublishState     string
+	SendThsState     string
+	IsDeleted        string
+	PublishTime      string
+	SendThsTime      string
+	CreateTime       string
+	ModifyTime       string
+	DeleteTime       string
+}{
+	CommunityVideoID: "community_video_id",
+	Title:            "title",
+	varietyTagId:     "variety_tag_id",
+	varietyTagName:   "variety_tag_name",
+	CoverImgURL:      "cover_img_url",
+	VideoURL:         "video_url",
+	VideoSeconds:     "video_seconds",
+	PublishState:     "publish_state",
+	SendThsState:     "send_ths_state",
+	IsDeleted:        "is_deleted",
+	PublishTime:      "publish_time",
+	SendThsTime:      "send_ths_time",
+	CreateTime:       "create_time",
+	ModifyTime:       "modify_time",
+	DeleteTime:       "delete_time",
+}

+ 41 - 0
models/tables/yb_community_video/model.go

@@ -0,0 +1,41 @@
+package yb_community_video
+
+import (
+	"errors"
+	"hongze/hongze_yb/global"
+	"hongze/hongze_yb/utils"
+)
+
+func (item *YbCommunityVideo) Create() (err error) {
+	err = global.DEFAULT_MYSQL.Create(item).Error
+	return
+}
+
+func (item *YbCommunityVideo) Update(updateCols []string) (err error) {
+	err = global.DEFAULT_MYSQL.Model(item).Select(updateCols).Updates(*item).Error
+	return
+}
+
+// GetPageListByCondition 分页获取视频列表
+func GetPageListByCondition(where map[string]interface{}, pageIndex, pageSize int) (list []*YbCommunityVideo, err error) {
+	cond, vals, e := utils.WhereBuild(where)
+	if e != nil {
+		err = errors.New("系统异常,生成查询语句失败")
+		return
+	}
+	offset := (pageIndex - 1) * pageSize
+	err = global.DEFAULT_MYSQL.Model(YbCommunityVideo{}).
+		Where(cond, vals...).
+		Where("is_deleted = 0 AND publish_state = 1").
+		Offset(offset).Limit(pageSize).
+		Order("publish_time DESC").Scan(&list).Error
+	return
+}
+
+// GetItemById 主键获取已发布的视频
+func GetItemById(videoId int) (item *YbCommunityVideo, err error) {
+	err = global.DEFAULT_MYSQL.Model(YbCommunityVideo{}).
+		Where("community_video_id = ? AND is_deleted = 0 AND publish_state = 1", videoId).
+		First(&item).Error
+	return
+}

+ 50 - 0
models/tables/yb_community_video_play_log/entity.go

@@ -0,0 +1,50 @@
+package yb_community_video_play_log
+
+import "time"
+
+// YbCommunityVideoPlayLog 研报视频社区播放记录表
+type YbCommunityVideoPlayLog struct {
+	ID               int       `gorm:"primaryKey;column:id;type:bigint(20) unsigned;not null" json:"-"`
+	CommunityVideoID int       `gorm:"index:idx_community_video_id;column:community_video_id;type:int(10) unsigned;not null" json:"communityVideoId"` // 回答音频ID
+	UserID           int       `gorm:"index:idx_user_id;column:user_id;type:int(10) unsigned;not null;default:0" json:"userId"`                       // 点击音频的用户ID
+	Mobile           string    `gorm:"column:mobile;type:varchar(30);not null;default:''" json:"mobile"`                                              // 手机号
+	RealName         string    `gorm:"column:real_name;type:varchar(100);not null;default:''" json:"realName"`                                        // 真实姓名
+	NickName         string    `gorm:"column:nick_name;type:varchar(100);not null;default:''" json:"nickName"`                                        // 昵称
+	CompanyID        int       `gorm:"column:company_id;type:int(10) unsigned;not null;default:0" json:"companyId"`                                   // 客户ID
+	CompanyName      string    `gorm:"column:company_name;type:varchar(100);not null;default:''" json:"companyName"`                                  // 客户名称
+	CompanyStatus    string    `gorm:"column:company_status;type:varchar(30);not null;default:''" json:"companyStatus"`                               // 客户状态
+	SourceAgent      int       `gorm:"column:source_agent;type:tinyint(4) unsigned;not null;default:1" json:"sourceAgent"`                            // 操作来源,1:小程序,2:小程序 pc 3:弘则研究公众号,4:web pc
+	CreateTime       time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`                                  // 创建时间
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbCommunityVideoPlayLog) TableName() string {
+	return "yb_community_video_play_log"
+}
+
+// YbCommunityVideoPlayLogColumns get sql column name.获取数据库列名
+var YbCommunityVideoPlayLogColumns = struct {
+	ID               string
+	CommunityVideoID string
+	UserID           string
+	Mobile           string
+	RealName         string
+	NickName         string
+	CompanyID        string
+	CompanyName      string
+	CompanyStatus    string
+	SourceAgent      string
+	CreateTime       string
+}{
+	ID:               "id",
+	CommunityVideoID: "community_video_id",
+	UserID:           "user_id",
+	Mobile:           "mobile",
+	RealName:         "real_name",
+	NickName:         "nick_name",
+	CompanyID:        "company_id",
+	CompanyName:      "company_name",
+	CompanyStatus:    "company_status",
+	SourceAgent:      "source_agent",
+	CreateTime:       "create_time",
+}

+ 8 - 0
models/tables/yb_community_video_play_log/model.go

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

+ 45 - 0
models/tables/yb_index_tab/entity.go

@@ -0,0 +1,45 @@
+package yb_index_tab
+
+// YbIndexTab 研报-首页选项卡
+type YbIndexTab struct {
+	ID           int    `gorm:"primaryKey;column:id;type:int(10) unsigned;not null" json:"-"`
+	Tab          string `gorm:"column:tab;type:varchar(30);not null;default:''" json:"tab"`                     // 选项卡名
+	Mark         string `gorm:"column:mark;type:varchar(30);not null;default:''" json:"mark"`                   // 枚举值
+	DefaultIcon  string `gorm:"column:default_icon;type:varchar(255);not null;default:''" json:"defaultIcon"`   // 默认icon
+	SelectedIcon string `gorm:"column:selected_icon;type:varchar(255);not null;default:''" json:"selectedIcon"` // 选中icon
+	Sort         int    `gorm:"column:sort;type:int(10) unsigned;not null;default:0" json:"sort"`               // 排序
+	IsShow       int    `gorm:"column:is_show;type:tinyint(4) unsigned;not null;default:0" json:"isShow"`       // 是否显示:0-隐藏 1-显示
+	AuthCheck    int    `gorm:"column:auth_check;type:tinyint(4) unsigned;not null;default:0" json:"authCheck"` // 是否需要检验权限:0-否 1-是
+	Position     int    `gorm:"column:position;type:tinyint(4) unsigned;not null;default:0" json:"position"`    // 位置:1-顶部 2-底部
+	Version      string `gorm:"column:version;type:varchar(30);not null;default:''" json:"version"`             // 版本号
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbIndexTab) TableName() string {
+	return "yb_index_tab"
+}
+
+// YbIndexTabColumns get sql column name.获取数据库列名
+var YbIndexTabColumns = struct {
+	ID           string
+	Tab          string
+	Mark         string
+	DefaultIcon  string
+	SelectedIcon string
+	Sort         string
+	IsShow       string
+	AuthCheck    string
+	Position     string
+	Version      string
+}{
+	ID:           "id",
+	Tab:          "tab",
+	Mark:         "mark",
+	DefaultIcon:  "default_icon",
+	SelectedIcon: "selected_icon",
+	Sort:         "sort",
+	IsShow:       "is_show",
+	AuthCheck:    "auth_check",
+	Position:     "position",
+	Version:      "version",
+}

+ 21 - 0
models/tables/yb_index_tab/model.go

@@ -0,0 +1,21 @@
+package yb_index_tab
+
+import (
+	"errors"
+	"hongze/hongze_yb/global"
+	"hongze/hongze_yb/utils"
+)
+
+// GetListByCondition 条件获取列表
+func GetListByCondition(where map[string]interface{}) (list []*YbIndexTab, err error) {
+	cond, vals, e := utils.WhereBuild(where)
+	if e != nil {
+		err = errors.New("系统异常,生成查询语句失败")
+		return
+	}
+	err = global.DEFAULT_MYSQL.Model(YbIndexTab{}).
+		Where(cond, vals...).
+		Order("sort ASC").
+		Scan(&list).Error
+	return
+}

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

@@ -0,0 +1,9 @@
+package yb_poster_config
+
+import "hongze/hongze_yb/global"
+
+// GetBySource 根据来源查询配置
+func GetBySource(source string) (item *YbPosterConfig, err error) {
+	err = global.DEFAULT_MYSQL.Where("source = ? ", source).Order("id desc").First(&item).Error
+	return
+}

+ 46 - 0
models/tables/yb_poster_config/yb_poster_config.go

@@ -0,0 +1,46 @@
+package yb_poster_config
+
+import (
+	"time"
+)
+
+// YbPosterConfig 研报海报生成配置
+type YbPosterConfig struct {
+	ID                 uint32    `gorm:"primaryKey;column:id;type:int(9) unsigned;not null" json:"-"`
+	Source             string    `gorm:"index:idx_source;column:source;type:varchar(64);default:''" json:"source"` // 来源
+	Hight              float64   `gorm:"column:hight;type:double(9,2) unsigned;default:0.00" json:"hight"`         // 海报高度
+	Width              float64   `gorm:"column:width;type:double(9,2) unsigned;default:0.00" json:"width"`         // 海报宽度
+	HTMLTemplate       string    `gorm:"column:html_template;type:text" json:"htmlTemplate"`                       // html代码模板
+	HTMLReplaceConfig  string    `gorm:"column:html_replace_config;type:text" json:"htmlReplaceConfig"`            // 模板中的变量替换规则
+	DefaultValueConfig string    `gorm:"column:default_value_config;type:text" json:"defaultValueConfig"`          // 默认值的配置
+	Remark             string    `gorm:"column:remark;type:varchar(255);default:''" json:"remark"`                 // 备注
+	CreateTime         time.Time `gorm:"column:create_time;type:timestamp;default:CURRENT_TIMESTAMP" json:"createTime"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbPosterConfig) TableName() string {
+	return "yb_poster_config"
+}
+
+// YbPosterConfigColumns get sql column name.获取数据库列名
+var YbPosterConfigColumns = struct {
+	ID                 string
+	Source             string
+	Hight              string
+	Width              string
+	HTMLTemplate       string
+	HTMLReplaceConfig  string
+	DefaultValueConfig string
+	Remark             string
+	CreateTime         string
+}{
+	ID:                 "id",
+	Source:             "source",
+	Hight:              "hight",
+	Width:              "width",
+	HTMLTemplate:       "html_template",
+	HTMLReplaceConfig:  "html_replace_config",
+	DefaultValueConfig: "default_value_config",
+	Remark:             "remark",
+	CreateTime:         "create_time",
+}

+ 67 - 0
models/tables/yb_price_driven/entity.go

@@ -0,0 +1,67 @@
+package yb_price_driven
+
+import (
+	"time"
+)
+
+// YbPriceDriven 研报-价格驱动表
+type YbPriceDriven struct {
+	PriceDrivenID       int       `gorm:"primaryKey;column:price_driven_id;type:int(10) unsigned;not null" json:"-"`
+	VarietyTagID        int       `gorm:"index:idx_variety_tag_id;column:variety_tag_id;type:int(10) unsigned;not null;default:0" json:"varietyTagId"` // 标签ID
+	VarietyTagName      string    `gorm:"column:variety_tag_name;type:varchar(10);not null;default:''" json:"varietyTagName"`                          // 标签名称
+	MainVariable        string    `gorm:"column:main_variable;type:varchar(255);not null;default:''" json:"mainVariable"`                              // 关键变量
+	CoreDrivenType      int       `gorm:"column:core_driven_type;type:tinyint(4) unsigned;not null;default:0" json:"coreDrivenType"`                   // 核心驱动类型 0-多 1-空
+	CoreDrivenContent   string    `gorm:"column:core_driven_content;type:varchar(255);not null;default:''" json:"coreDrivenContent"`                   // 核心驱动内容
+	CoreContent         string    `gorm:"column:core_content;type:longtext" json:"coreContent"`                                                        // 核心内容
+	LastUpdateAdminID   int       `gorm:"column:last_update_admin_id;type:int(10) unsigned;not null;default:0" json:"lastUpdateAdminId"`               // 最后一次更新人ID
+	LastUpdateAdminName string    `gorm:"column:last_update_admin_name;type:varchar(30);not null;default:''" json:"lastUpdateAdminName"`               // 最后一次更新人姓名
+	SendThsMsgTime      time.Time `gorm:"column:send_ths_msg_time;type:datetime" json:"sendThsMsgTime"`                                                // 最后一次推送客群消息的时间
+	SendTemplateMsgTime time.Time `gorm:"column:send_template_msg_time;type:datetime" json:"sendTemplateMsgTime"`                                      // 最后一次推送模板消息的时间
+	ThsMsgState         int       `gorm:"column:ths_msg_state;type:tinyint(4) unsigned;not null;default:0" json:"thsMsgState"`                         // 同花顺推送状态:0-未推送 1-已推送
+	TemplateMsgState    int       `gorm:"column:template_msg_state;type:tinyint(4) unsigned;not null;default:0" json:"templateMsgState"`               // 模板消息推送状态:0-未推送 1-已推送
+	PublishState        int       `gorm:"column:publish_state;type:tinyint(4) unsigned;not null;default:0" json:"publishState"`                        // 发布状态:0-未发布 1-已发布
+	CreateTime          time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`                                // 创建时间
+	ModifyTime          time.Time `gorm:"column:modify_time;type:datetime;default:CURRENT_TIMESTAMP" json:"modifyTime"`                                // 修改时间
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbPriceDriven) TableName() string {
+	return "yb_price_driven"
+}
+
+// YbPriceDrivenColumns get sql column name.获取数据库列名
+var YbPriceDrivenColumns = struct {
+	PriceDrivenID       string
+	VarietyTagID        string
+	VarietyTagName      string
+	MainVariable        string
+	CoreDrivenType      string
+	CoreDrivenContent   string
+	CoreContent         string
+	LastUpdateAdminID   string
+	LastUpdateAdminName string
+	SendThsMsgTime      string
+	SendTemplateMsgTime string
+	ThsMsgState         string
+	TemplateMsgState    string
+	PublishState        string
+	CreateTime          string
+	ModifyTime          string
+}{
+	PriceDrivenID:       "price_driven_id",
+	VarietyTagID:        "variety_tag_id",
+	VarietyTagName:      "variety_tag_name",
+	MainVariable:        "main_variable",
+	CoreDrivenType:      "core_driven_type",
+	CoreDrivenContent:   "core_driven_content",
+	CoreContent:         "core_content",
+	LastUpdateAdminID:   "last_update_admin_id",
+	LastUpdateAdminName: "last_update_admin_name",
+	SendThsMsgTime:      "send_ths_msg_time",
+	SendTemplateMsgTime: "send_template_msg_time",
+	ThsMsgState:         "ths_msg_state",
+	TemplateMsgState:    "template_msg_state",
+	PublishState:        "publish_state",
+	CreateTime:          "create_time",
+	ModifyTime:          "modify_time",
+}

+ 20 - 0
models/tables/yb_price_driven/model.go

@@ -0,0 +1,20 @@
+package yb_price_driven
+
+import "hongze/hongze_yb/global"
+
+// GetPriceDrivenByVarietyTagId 通过标签获取价格驱动
+func GetPriceDrivenByVarietyTagId(varietyTagId int) (item *YbPriceDriven, err error) {
+	err = global.DEFAULT_MYSQL.
+		Where("variety_tag_id = ? AND publish_state = 1", varietyTagId).
+		Order("create_time DESC").
+		First(&item).Error
+	return
+}
+
+// GetPriceDrivenById 主键获取价格驱动
+func GetPriceDrivenById(priceDrivenId int) (item *YbPriceDriven, err error) {
+	err = global.DEFAULT_MYSQL.
+		Where("price_driven_id = ? AND publish_state = 1", priceDrivenId).
+		First(&item).Error
+	return
+}

+ 35 - 0
models/tables/yb_price_driven_tag/entity.go

@@ -0,0 +1,35 @@
+package yb_price_driven_tag
+
+import "time"
+
+// YbPriceDrivenTag 研报价格驱动标签表
+type YbPriceDrivenTag struct {
+	ID             int       `gorm:"primaryKey;column:id;type:int(10) unsigned;not null" json:"-"`
+	VarietyTagID   int       `gorm:"unique;column:variety_tag_id;type:int(10) unsigned;not null;default:0" json:"varietyTagId"` // 标签ID
+	VarietyTagName string    `gorm:"column:variety_tag_name;type:varchar(100);not null;default:''" json:"varietyTagName"`       // 标签名称
+	State          int       `gorm:"column:state;type:tinyint(4) unsigned;not null;default:1" json:"state"`                     // 状态:0-禁用 1-开启
+	CreateTime     time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`
+	ModifyTime     time.Time `gorm:"column:modify_time;type:datetime;default:CURRENT_TIMESTAMP" json:"modifyTime"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbPriceDrivenTag) TableName() string {
+	return "yb_price_driven_tag"
+}
+
+// YbPriceDrivenTagColumns get sql column name.获取数据库列名
+var YbPriceDrivenTagColumns = struct {
+	ID             string
+	VarietyTagID   string
+	VarietyTagName string
+	State          string
+	CreateTime     string
+	ModifyTime     string
+}{
+	ID:             "id",
+	VarietyTagID:   "variety_tag_id",
+	VarietyTagName: "variety_tag_name",
+	State:          "state",
+	CreateTime:     "create_time",
+	ModifyTime:     "modify_time",
+}

+ 9 - 0
models/tables/yb_price_driven_tag/model.go

@@ -0,0 +1,9 @@
+package yb_price_driven_tag
+
+import "hongze/hongze_yb/global"
+
+// GetPriceDrivenTagList 获取价格驱动标签列表
+func GetPriceDrivenTagList() (list []*YbPriceDrivenTag, err error) {
+	err = global.DEFAULT_MYSQL.Model(YbPriceDrivenTag{}).Scan(&list).Error
+	return
+}

+ 56 - 0
models/tables/yb_price_driven_visit_log/entity.go

@@ -0,0 +1,56 @@
+package yb_price_driven_visit_log
+
+import "time"
+
+// YbPriceDrivenVisitLog 研报-价格驱动访问记录表
+type YbPriceDrivenVisitLog struct {
+	ID             int       `gorm:"primaryKey;column:id;type:bigint(20) unsigned;not null" json:"-"`
+	PriceDrivenID  int       `gorm:"index:idx_price_driven_id;column:price_driven_id;type:int(10) unsigned;not null" json:"priceDrivenId"`        // 价格驱动ID
+	VarietyTagID   int       `gorm:"index:idx_variety_tag_id;column:variety_tag_id;type:int(10) unsigned;not null;default:0" json:"varietyTagId"` // 标签ID
+	VarietyTagName string    `gorm:"column:variety_tag_name;type:varchar(100);not null;default:''" json:"varietyTagName"`                         // 标签名称
+	UserID         int       `gorm:"index:idx_user_id;column:user_id;type:int(10) unsigned;not null;default:0" json:"userId"`                     // 用户ID
+	Mobile         string    `gorm:"column:mobile;type:varchar(30);not null;default:''" json:"mobile"`                                            // 手机号
+	RealName       string    `gorm:"column:real_name;type:varchar(100);not null;default:''" json:"realName"`                                      // 真实姓名
+	NickName       string    `gorm:"column:nick_name;type:varchar(100);not null;default:''" json:"nickName"`                                      // 昵称
+	CompanyID      int       `gorm:"column:company_id;type:int(10) unsigned;not null;default:0" json:"companyId"`                                 // 客户ID
+	CompanyName    string    `gorm:"column:company_name;type:varchar(100);not null;default:''" json:"companyName"`                                // 客户名称
+	CompanyStatus  string    `gorm:"column:company_status;type:varchar(30);not null;default:''" json:"companyStatus"`                             // 客户状态
+	SourceAgent    int       `gorm:"column:source_agent;type:tinyint(4) unsigned;not null;default:1" json:"sourceAgent"`                          // 来源:1-小程序 2-小程序 PC 3-弘则研究公众号 4-Web PC
+	CreateTime     time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`                                // 创建时间
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbPriceDrivenVisitLog) TableName() string {
+	return "yb_price_driven_visit_log"
+}
+
+// YbPriceDrivenVisitLogColumns get sql column name.获取数据库列名
+var YbPriceDrivenVisitLogColumns = struct {
+	ID             string
+	PriceDrivenID  string
+	VarietyTagID   string
+	VarietyTagName string
+	UserID         string
+	Mobile         string
+	RealName       string
+	NickName       string
+	CompanyID      string
+	CompanyName    string
+	CompanyStatus  string
+	SourceAgent    string
+	CreateTime     string
+}{
+	ID:             "id",
+	PriceDrivenID:  "price_driven_id",
+	VarietyTagID:   "variety_tag_id",
+	VarietyTagName: "variety_tag_name",
+	UserID:         "user_id",
+	Mobile:         "mobile",
+	RealName:       "real_name",
+	NickName:       "nick_name",
+	CompanyID:      "company_id",
+	CompanyName:    "company_name",
+	CompanyStatus:  "company_status",
+	SourceAgent:    "source_agent",
+	CreateTime:     "create_time",
+}

+ 8 - 0
models/tables/yb_price_driven_visit_log/model.go

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

+ 5 - 0
routers/community.go

@@ -8,6 +8,7 @@ import (
 
 func InitCommunity(r *gin.Engine)  {
 	rGroup := r.Group("api/community").Use(middleware.Token(), middleware.CheckBaseAuth())
+	// 问答社区
 	rGroup.GET("/question/list", community.QuestionList)
 	rGroup.GET("/question/detail", community.QuestionDetail)
 	rGroup.POST("/question/ask", community.QuestionAsk)
@@ -18,4 +19,8 @@ func InitCommunity(r *gin.Engine)  {
 	rGroup.GET("/question/unread", community.QuestionUnread)
 	rGroup.GET("/question/research_group", community.ResearchGroupList)
 	rGroup.POST("/question/audio/log", community.AddAudioLog)
+	// 视频社区
+	noAuthGroup := r.Group("api/community").Use(middleware.Token())
+	noAuthGroup.GET("/video/list", community.VideoList)
+	noAuthGroup.POST("/video/play_log", community.VideoPlayLog)
 }

+ 15 - 0
routers/price_driven.go

@@ -0,0 +1,15 @@
+package routers
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/company"
+	"hongze/hongze_yb/controller/price_driven"
+	"hongze/hongze_yb/middleware"
+)
+
+func InitPriceDriven(r *gin.Engine) {
+	rGroup := r.Group("api/price_driven").Use(middleware.Token(), middleware.CheckBaseAuth())
+	rGroup.GET("/tab", company.GetHomeFiccPermissions)
+	rGroup.GET("/detail", price_driven.PriceDrivenDetail)
+	rGroup.POST("/visit_log", price_driven.PriceDrivenVisitLog)
+}

+ 1 - 0
routers/public.go

@@ -25,5 +25,6 @@ func initPublic(r *gin.Engine) {
 		rGroup.POST("/upload", controller.Upload)
 		rGroup.POST("/get_share_poster", controller.GetSharePoster)
 		rGroup.GET("/get_suncode_scene", controller.GetSuncodeScene)
+		rGroup.GET("/get_variety_tag_tree", controller.GetVarietyTagTree)
 	}
 }

+ 1 - 0
routers/report.go

@@ -14,6 +14,7 @@ func InitReport(r *gin.Engine)  {
 	rGroup.GET("/list", report.List)
 	rGroup.GET("/collect", report.CollectReportList)
 	rGroup.GET("/search", report.Search)
+	rGroup.POST("/detail/rddp_share_img", report.RddpShareImg)
 
 	rGroup2 := r.Group("api/classify").Use(middleware.Token())
 	rGroup2.GET("/ficc", report.ClassifyFirstList)

+ 15 - 0
routers/sandbox.go

@@ -0,0 +1,15 @@
+package routers
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/sandbox"
+	"hongze/hongze_yb/middleware"
+)
+
+func InitSandbox(r *gin.Engine) {
+	rGroup := r.Group("api/sandbox").Use(middleware.Token())
+	rGroup.GET("/list", sandbox.List)
+	rGroup.GET("/detail", sandbox.Detail)
+	rGroup.GET("/permission_count", sandbox.PermissionCountList)
+
+}

+ 1 - 0
routers/user.go

@@ -41,6 +41,7 @@ func initUser(r *gin.Engine) {
 		rGroup2.GET("/get_last_apply_record", user.GetLastApplyRecord)
 		rGroup2.POST("/apply", user.Apply)
 		rGroup2.GET("/get_tab_bar", user.GetTabBar)
+		rGroup2.GET("/get_top_tab", user.GetTopTab)
 		rGroup2.POST("/set", user.SetUserInfo)
 	}
 

+ 7 - 8
services/activity/activity.go

@@ -23,8 +23,8 @@ import (
 
 // ActivityList 活动列表
 type ActivityList struct {
-	yb_activity.ActivityItem							// 活动信息
-	VoiceList	[]*yb_activity_voice.YbActivityVoice	// 音频列表
+	yb_activity.ActivityItem                                      // 活动信息
+	VoiceList                []*yb_activity_voice.YbActivityVoice // 音频列表
 }
 
 // PageList 活动分页列表
@@ -79,7 +79,7 @@ func PageList(condition string, pars []interface{}, page, limit int, order strin
 			for _, voice := range voices {
 				if temp.ActivityID == int(voice.ActivityID) {
 					voiceMap = append(voiceMap, voice)
-					temp.HasPlayBack = 1	// 有回放
+					temp.HasPlayBack = 1 // 有回放
 				}
 			}
 			temp.VoiceList = voiceMap
@@ -203,7 +203,7 @@ func GetUserAuthActivityIds(userInfo user.UserInfo) (acrivityIds []int, err erro
 }
 
 // GetLatestActivity 从用户有权限参与的活动中,筛选出最新的活动
-func GetLatestActivity(permissionIds []int, userId uint64) (purchaseItem *purchase.PurchaseListItem, err error)  {
+func GetLatestActivity(permissionIds []int, userId uint64) (purchaseItem *purchase.PurchaseListItem, err error) {
 	var errMsg string
 	defer func() {
 		if sysErr := recover(); sysErr != nil {
@@ -232,7 +232,7 @@ func GetLatestActivity(permissionIds []int, userId uint64) (purchaseItem *purcha
 	}
 	//统计未读数
 	unRead, err := GetUnRead(activityIds, userId)
-	if err != nil{
+	if err != nil {
 		errMsg = err.Error()
 		err = errors.New("查询活动未读数错误")
 		return
@@ -250,9 +250,8 @@ func GetLatestActivity(permissionIds []int, userId uint64) (purchaseItem *purcha
 	return
 }
 
-
 // GetList 从用户有权限参与的活动中,筛选出最新的活动
-func GetPurchaseDetail(permissionIds []int, userId uint64,  pageIndex, pageSize int) (ret *purchase.DetailResp, err error)  {
+func GetPurchaseDetail(permissionIds []int, userId uint64, pageIndex, pageSize int) (ret *purchase.DetailResp, err error) {
 	// 获取用户权限可参与的活动ID
 	var activityIds []int
 	permissions, err := yb_activity_permission.GetPermissionsByPermissionIds(permissionIds)
@@ -310,4 +309,4 @@ func GetPurchaseDetail(permissionIds []int, userId uint64,  pageIndex, pageSize
 		return
 	}
 	return
-}
+}

+ 8 - 8
services/community/question.go

@@ -19,7 +19,7 @@ import (
 )
 
 // GetQuestionList 获取问答列表
-func GetQuestionList(pageIndex, pageSize, onlyMine, chartPermissionId, replyStatus, groupId int, userInfo user.UserInfo) (resp []*response.CommunityQuestionItem, err error) {
+func GetQuestionList(pageIndex, pageSize, onlyMine, varietyTagId, replyStatus, groupId int, userInfo user.UserInfo) (resp []*response.CommunityQuestionItem, err error) {
 	condition := " is_deleted = 0"
 	var pars []interface{}
 	// 用户身份
@@ -58,9 +58,9 @@ func GetQuestionList(pageIndex, pageSize, onlyMine, chartPermissionId, replyStat
 		}
 	}
 
-	if chartPermissionId > 0 {
-		condition += " and chart_permission_id =?"
-		pars = append(pars, chartPermissionId)
+	if varietyTagId > 0 {
+		condition += " and variety_tag_id =?"
+		pars = append(pars, varietyTagId)
 	}
 	if groupId > 0 {
 		condition += " and research_group_second_id =?"
@@ -121,8 +121,8 @@ func GetQuestionList(pageIndex, pageSize, onlyMine, chartPermissionId, replyStat
 			ReplierRealName:         v.ReplierRealName,
 			ReplierRank:             replierRank,
 			ReplierAvatar:           avatar,
-			ChartPermissionID:       v.CommunityQuestionID,
-			ChartPermissionName:     v.ChartPermissionName,
+			VarietyTagId:       v.VarietyTagID,
+			VarietyTagName:     v.VarietyTagName,
 			ResearchGroupSecondId:   v.ResearchGroupSecondID,
 			ResearchGroupSecondName: v.ResearchGroupSecondName,
 			IsRead:                  v.IsRead,
@@ -188,8 +188,8 @@ func GetQuestionDetail(questionId int, userInfo user.UserInfo) (item *response.C
 		ReplierRealName:         detail.ReplierRealName,
 		ReplierRank:             replierRank,
 		ReplierAvatar:           detail.ReplierAvatar,
-		ChartPermissionID:       detail.ChartPermissionID,
-		ChartPermissionName:     detail.ChartPermissionName,
+		VarietyTagId:       detail.VarietyTagID,
+		VarietyTagName:     detail.VarietyTagName,
 		ResearchGroupSecondId:   detail.ResearchGroupSecondID,
 		ResearchGroupSecondName: detail.ResearchGroupSecondName,
 		IsRead:                  detail.IsRead,

+ 94 - 0
services/community/video.go

@@ -0,0 +1,94 @@
+package community
+
+import (
+	"errors"
+	"hongze/hongze_yb/models/response"
+	"hongze/hongze_yb/models/tables/company_product"
+	"hongze/hongze_yb/models/tables/yb_community_video"
+	"hongze/hongze_yb/models/tables/yb_community_video_play_log"
+	"hongze/hongze_yb/services/user"
+	"hongze/hongze_yb/utils"
+	"time"
+)
+
+// GetVideoList 获取视频列表
+func GetVideoList(pageIndex, pageSize, videoId, varietyTagId int, keywords string) (resp []*response.CommunityVideoItem, err error) {
+	condition := make(map[string]interface{})
+	// 分享点进来的直接定位到具体视频
+	if videoId > 0 {
+		condition["community_video_id ="] = videoId
+	} else {
+		if varietyTagId > 0 {
+			condition["variety_tag_id ="] = varietyTagId
+		}
+		if keywords != "" {
+			condition["title like"] = "%" + keywords + "%"
+		}
+	}
+	resp = make([]*response.CommunityVideoItem, 0)
+	list, e := yb_community_video.GetPageListByCondition(condition, pageIndex, pageSize)
+	if e != nil {
+		err = errors.New("获取视频列表失败, Err:" + e.Error())
+		return
+	}
+	if len(list) <= 0 {
+		return
+	}
+	for _, v := range list {
+		item := &response.CommunityVideoItem{
+			CommunityVideoID: v.CommunityVideoID,
+			Title:            v.Title,
+			VarietyTagId:     v.VarietyTagId,
+			VarietyTagName:   v.VarietyTagName,
+			CoverImgUrl:      v.CoverImgURL,
+			VideoUrl:         v.VideoURL,
+			VideoSeconds:     v.VideoSeconds,
+			PublishState:     v.PublishState,
+			PublishTime:      v.PublishTime.Format(utils.FormatDateTime),
+			CreateTime:       v.CreateTime.Format(utils.FormatDateTime),
+			ModifyTime:       v.ModifyTime.Format(utils.FormatDateTime),
+		}
+		resp = append(resp, item)
+	}
+	return
+}
+
+// SaveVideoPlayLog 记录用户播放视频日志
+func SaveVideoPlayLog(userInfo user.UserInfo, videoId, sourceAgent int) (errMsg string, err error) {
+	video, e := yb_community_video.GetItemById(videoId)
+	if e != nil {
+		errMsg = "视频不存在或未发布"
+		err = errors.New("获取视频信息失败, Err: " + e.Error())
+		return
+	}
+	companyInfo, e := company_product.GetByCompany2ProductId(userInfo.CompanyID, 1)
+	if e != nil && e != utils.ErrNoRow {
+		errMsg = "保存失败"
+		err = errors.New("获取客户信息失败, Err: " + e.Error())
+		return
+	}
+	companyName := "潜在客户"
+	companyStatus := "潜在"
+	if companyInfo != nil && companyInfo.CompanyID > 0 {
+		companyName = companyInfo.CompanyName
+		companyStatus = companyInfo.Status
+	}
+	item := &yb_community_video_play_log.YbCommunityVideoPlayLog{
+		CommunityVideoID: video.CommunityVideoID,
+		UserID:           int(userInfo.UserID),
+		Mobile:           userInfo.Mobile,
+		RealName:         userInfo.RealName,
+		NickName:         userInfo.NickName,
+		CompanyID:        int(userInfo.CompanyID),
+		CompanyName:      companyName,
+		CompanyStatus:    companyStatus,
+		SourceAgent:      sourceAgent,
+		CreateTime:       time.Now().Local(),
+	}
+	if e = item.Create(); e != nil {
+		errMsg = "操作失败"
+		err = errors.New("新增播放视频日志失败, Err:" + e.Error())
+		return
+	}
+	return
+}

+ 147 - 7
services/company/permission.go

@@ -124,16 +124,16 @@ func CheckBaseFiccPermission(companyId int64, userId int) (ok bool, checkInfo re
 		err = errors.New("获取用户FICC权限失败 Err:" + e.Error())
 		return
 	}
-	// 客户状态是否为流失
-	if productInfo.Status == "流失" {
-		checkInfo.Type = CheckTypeApply
+	wxUser, e := wx_user.GetByUserId(userId)
+	if e != nil {
+		err = errors.New("不存在当前用户, Err:" + e.Error())
 		return
 	}
 	// 是否为弘则研究已禁用的联系人
 	if companyId == 16 {
 		userInfo, e := wx_user.GetByUserId(userId)
 		if e != nil {
-			err = errors.New("用户信息异常 Err:" + e.Error())
+			err = errors.New("用户信息异常, Err:" + e.Error())
 			return
 		}
 		if userInfo.Enabled != 1 {
@@ -141,6 +141,19 @@ func CheckBaseFiccPermission(companyId int64, userId int) (ok bool, checkInfo re
 			return
 		}
 	}
+	customerInfo := response.CustomerInfo{
+		CompanyName: productInfo.CompanyName,
+		Status:      productInfo.Status,
+		Name:        wxUser.RealName,
+		IsSuspend:   productInfo.IsSuspend,
+		Mobile:      wxUser.Mobile,
+	}
+	checkInfo.CustomerInfo = customerInfo
+	// 客户状态是否为流失
+	if productInfo.Status == "流失" {
+		checkInfo.Type = CheckTypeApply
+		return
+	}
 	// 客户对应的销售信息
 	sellerInfo, e := admin.GetByAdminId(productInfo.SellerID)
 	if e != nil {
@@ -599,9 +612,9 @@ func CheckUserChartPermission(companyId int64, userId int) (ok bool, permissionC
 }
 
 type FiccPermissionList struct {
-	ClassifyName  string            `description:"分类"`
+	ClassifyName string `description:"分类"`
 	//HasPermission bool              `description:"是否有权限"`
-	Items         []*PermissionItem `description:"子类"`
+	Items []*PermissionItem `description:"子类"`
 }
 
 type PermissionItem struct {
@@ -664,7 +677,8 @@ func GetHomeFiccPermissions(user user.UserInfo) (ret response.PermissionFiccResp
 	}
 	for _, v := range permissionFirstList {
 		permissionFirstMap[v.ClassifyName] = &response.PermissionFirstItem{
-			Sort: v.YbIndexSort+1000,
+			Id:          int(v.Id),
+			Sort:        v.YbIndexSort + 1000,
 			YbIndexName: v.YbIndexName,
 			YbIndexIcon: v.YbIndexIcon,
 		}
@@ -692,6 +706,7 @@ func GetHomeFiccPermissions(user user.UserInfo) (ret response.PermissionFiccResp
 		temp.ChartPermissionID = int(v.ChartPermissionID)
 		temp.ChartPermissionName = v.PermissionName
 		temp.AuthOk = permissionMap[v.ChartPermissionID]
+		temp.PirceDrivenState = v.PriceDrivenState
 		if _, ok := permissionFirstMap[v.ClassifyName]; ok {
 			permissionFirstMap[v.ClassifyName].List = append(permissionFirstMap[v.ClassifyName].List, temp)
 		} else {
@@ -704,6 +719,7 @@ func GetHomeFiccPermissions(user user.UserInfo) (ret response.PermissionFiccResp
 	var list response.PermissionFiccList
 	for _, v := range permissionFirstMap {
 		temp := new(response.PermissionFiccItem)
+		temp.Id = v.Id
 		temp.Sort = v.Sort
 		temp.ClassifyName = v.YbIndexName
 		temp.IconUrl = v.YbIndexIcon
@@ -763,3 +779,127 @@ func GetHomeFiccPermissions(user user.UserInfo) (ret response.PermissionFiccResp
 	ret.ContactInfo = contactInfo
 	return
 }
+
+// CheckUserSandboxPermission 验证用户/联系人的沙盘权限
+func CheckUserSandboxPermission(companyId int64, userId, permissionId int) (ok bool, companyPermissionIdList []int, permissionCheckInfo ChartPermissionCheckInfo, err error) {
+	defer func() {
+		// 如果无权限,那么就去查询是否申请过
+		if ok == false && permissionCheckInfo.Type == CheckTypeApply {
+			_, err = yb_apply_record.GetLastNotOpRecordByUserId(userId) // 图库申请
+			// 查询是否有申请过,如果有申请过的话,那么err是nil
+			if err != nil {
+				if err == utils.ErrNoRow {
+					err = nil
+					return
+				}
+				return
+			}
+			permissionCheckInfo.CustomerInfo.HasApply = true
+		}
+	}()
+
+	var productId int64
+	productId = 1
+	if companyId > 1 {
+		// 查询是否开通FICC
+		companyProductInfo, tmpErr := company_product.GetByCompany2ProductId(companyId, productId)
+		if tmpErr != nil {
+			// 没有开通FICC
+			if tmpErr == utils.ErrNoRow {
+				permissionCheckInfo.Type = CheckTypeApply
+				return
+			}
+			err = tmpErr
+			return
+		}
+
+		wxUser, tmpErr := wx_user.GetByUserId(userId)
+		if tmpErr != nil {
+			permissionCheckInfo.Type = CheckTypeApply
+			err = tmpErr
+			return
+		}
+
+		// 查询用户是否为弘则研究已禁用的联系人
+		if companyId == 16 {
+			if wxUser.Enabled != 1 {
+				permissionCheckInfo.Type = CheckTypeApply
+				return
+			}
+		}
+
+		// 客户信息
+		companyInfo, tmpErr := company.GetByCompanyId(companyId)
+		if tmpErr != nil {
+			// 没有开通FICC
+			if tmpErr == utils.ErrNoRow {
+				permissionCheckInfo.Type = CheckTypeApply
+				return
+			}
+			err = tmpErr
+			return
+		}
+		customerInfo := CustomerInfo{
+			CompanyName: companyInfo.CompanyName,
+			Status:      companyProductInfo.Status,
+			Name:        wxUser.RealName,
+			IsSuspend:   companyProductInfo.IsSuspend,
+			Mobile:      wxUser.Mobile,
+		}
+		permissionCheckInfo.CustomerInfo = customerInfo
+
+		// 如果客户FICC产品的状态是流失-申请
+		if companyProductInfo.Status == "流失" {
+			permissionCheckInfo.Type = CheckTypeApply
+			return
+		}
+
+		// 查找对应客户的销售信息
+		adminInfo, tmpErr := admin.GetByAdminId(companyProductInfo.SellerID)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		// 客户状态为冻结/试用暂停-联系销售
+		permissionCheckInfo.Name = adminInfo.RealName
+		permissionCheckInfo.Mobile = adminInfo.Mobile
+		if companyProductInfo.Status == "冻结" || (companyProductInfo.Status == "试用" && companyProductInfo.IsSuspend == 1) {
+			permissionCheckInfo.Type = CheckTypeContact
+			return
+		}
+
+		// 验证用户的沙盘权限
+
+		//获取所有的权限分类列表
+		companyPermissionList, tmpErr := GetValidPermissionByCompany2ProductId(companyId, productId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		//客户品种权限赋值
+		for _, chartPermission := range companyPermissionList {
+			companyPermissionIdList = append(companyPermissionIdList, chartPermission.ChartPermissionID)
+		}
+		if permissionId > 0 {
+			for _, chartPermission := range companyPermissionList {
+				if chartPermission.ChartPermissionID == permissionId {
+					ok = true
+				}
+			}
+		} else {
+			// 不校验品种权限的话,那么就是认为有权限的
+			if len(companyPermissionList) > 0 {
+				ok = true
+			}
+		}
+
+		// 都不是默认联系销售
+		permissionCheckInfo.Type = CheckTypeContact
+	} else {
+		permissionCheckInfo.Type = CheckTypeApply
+	}
+
+	return
+}

+ 19 - 0
services/page.go

@@ -0,0 +1,19 @@
+package services
+
+import "github.com/gin-gonic/gin"
+
+// GetCurrPageByClaims 从Claims中获取当前页码
+func GetCurrPageByClaims(c *gin.Context) (currPage int) {
+	//获取jwt数据失败
+	claims, _ := c.Get("curr_page")
+	currPage = claims.(int)
+	return
+}
+
+// GetPageSizeByClaims 从Claims中获取当前每页数据量
+func GetPageSizeByClaims(c *gin.Context) (pageSize int) {
+	//获取jwt数据失败
+	claims, _ := c.Get("page_size")
+	pageSize = claims.(int)
+	return
+}

+ 81 - 0
services/price_driven/price_driven.go

@@ -0,0 +1,81 @@
+package price_driven
+
+import (
+	"errors"
+	"hongze/hongze_yb/models/response"
+	"hongze/hongze_yb/models/tables/company_product"
+	"hongze/hongze_yb/models/tables/yb_price_driven"
+	"hongze/hongze_yb/models/tables/yb_price_driven_visit_log"
+	"hongze/hongze_yb/services/user"
+	"hongze/hongze_yb/utils"
+)
+
+// GetPriceDrivenDetail 获取价格驱动详情
+func GetPriceDrivenDetail(varietyTagId int) (resp *response.PriceDrivenItem, errMsg string, err error) {
+	resp = new(response.PriceDrivenItem)
+	// 获取详情
+	item, e := yb_price_driven.GetPriceDrivenByVarietyTagId(varietyTagId)
+	if e != nil && e != utils.ErrNoRow {
+		errMsg = "获取失败"
+		err = errors.New("获取价格驱动信息失败, Err:" + e.Error())
+		return
+	}
+	if item != nil {
+		resp.PriceDrivenID = item.PriceDrivenID
+		resp.VarietyTagID = item.VarietyTagID
+		resp.MainVariable = item.MainVariable
+		resp.CoreDrivenType = item.CoreDrivenType
+		resp.CoreDrivenContent = item.CoreDrivenContent
+		resp.CoreContent = item.CoreContent
+		resp.CreateTime = item.CreateTime.Format(utils.FormatDateTime)
+		resp.ModifyTime = item.ModifyTime.Format(utils.FormatDateTime)
+	}
+	return
+}
+
+// SavePriceDrivenVisitLog 保存价格驱动访问记录
+func SavePriceDrivenVisitLog(priceDrivenId, sourceAgent int, userInfo user.UserInfo) (errMsg string, err error) {
+	companyInfo, e := company_product.GetByCompany2ProductId(userInfo.CompanyID, 1)
+	if e != nil && e != utils.ErrNoRow {
+		errMsg = "保存失败"
+		err = errors.New("获取客户信息失败, Err: " + e.Error())
+		return
+	}
+	companyName := "潜在客户"
+	companyStatus := "潜在"
+	if companyInfo != nil && companyInfo.CompanyID > 0 {
+		companyName = companyInfo.CompanyName
+		companyStatus = companyInfo.Status
+	}
+	item, e := yb_price_driven.GetPriceDrivenById(priceDrivenId)
+	if e != nil && e != utils.ErrNoRow {
+		errMsg = "保存失败"
+		err = errors.New("获取价格驱动信息失败, Err:" + e.Error())
+		return
+	}
+	tagId := 0
+	tagName := ""
+	if item != nil && item.PriceDrivenID > 0 {
+		tagId = item.VarietyTagID
+		tagName = item.VarietyTagName
+	}
+	logItem := &yb_price_driven_visit_log.YbPriceDrivenVisitLog{
+		PriceDrivenID:  priceDrivenId,
+		VarietyTagID:   tagId,
+		VarietyTagName: tagName,
+		UserID:         int(userInfo.UserID),
+		Mobile:         userInfo.Mobile,
+		RealName:       userInfo.RealName,
+		NickName:       userInfo.NickName,
+		CompanyID:      int(userInfo.CompanyID),
+		CompanyName:    companyName,
+		CompanyStatus:  companyStatus,
+		SourceAgent:    sourceAgent,
+	}
+	if e := logItem.Create(); e != nil {
+		errMsg = "保存失败"
+		err = errors.New("新增价格驱动访问记录失败, Err: " + e.Error())
+		return
+	}
+	return
+}

+ 7 - 0
services/report/report.go

@@ -393,6 +393,12 @@ func GetReportDetail(userinfo user.UserInfo, reportId int) (reportDetail respons
 		err = errors.New("报告未发布")
 		return
 	}
+	// 判断报告是否属于专栏报告
+	firstClassify, e := classify.GetByClassifyId(reportInfo.ClassifyIdFirst)
+	if e != nil {
+		err = errors.New("报告一级分类有误")
+		return
+	}
 
 	//判断权限
 
@@ -486,6 +492,7 @@ func GetReportDetail(userinfo user.UserInfo, reportId int) (reportDetail respons
 	reportDetail.AuthOk = authOk
 	reportDetail.LikeNum = likeNum
 	reportDetail.LikeEnabled = likeEnabled
+	reportDetail.ReportShowType = int(firstClassify.ShowType)
 	return
 }
 

+ 16 - 0
services/report/report_view_record.go

@@ -1,10 +1,13 @@
 package report
 
 import (
+	"errors"
 	"fmt"
 	companyCache "hongze/hongze_yb/cache/company"
 	"hongze/hongze_yb/global"
+	"hongze/hongze_yb/logic/report"
 	"hongze/hongze_yb/models/tables/rddp/report_view_record"
+	"hongze/hongze_yb/models/tables/user_view_history"
 	"hongze/hongze_yb/services/user"
 	"time"
 )
@@ -37,5 +40,18 @@ func AddViewRecord(userInfo user.UserInfo, reportId int, classifyName string, re
 	}
 	//修改联系人最后一次阅读报告时间
 	err = userInfo.WxUser.SetWxUserReportLastViewTime()
+
+	//新增redis阅读记录
+	userViewHistory := &user_view_history.UserViewHistory{
+		Mobile:      userInfo.Mobile,
+		Email:       userInfo.Email,
+		RealName:    userInfo.RealName,
+		CompanyName: companyInfo.CompanyName,
+		CreatedTime: time.Now(),
+	}
+	ret := report.PushViewRecordNewRedisData(userViewHistory, int(userInfo.CompanyID))
+	if !ret {
+		err = errors.New("缓存添加阅读记录失败")
+	}
 	return
 }

+ 327 - 34
services/share_poster.go

@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"github.com/PuerkitoBio/goquery"
 	"hongze/hongze_yb/global"
+	"hongze/hongze_yb/models/tables/yb_poster_config"
 	"hongze/hongze_yb/models/tables/yb_poster_resource"
 	"hongze/hongze_yb/models/tables/yb_suncode_pars"
 	"hongze/hongze_yb/services/alarm_msg"
@@ -51,7 +52,7 @@ func CreatePosterFromSource(codePage, codeScene, source, version, pars string) (
 	}
 	path := fmt.Sprint(codePage, "?", codeScene)
 	// 非列表来源获取历史图片,无则生成
-	if !strings.Contains(source, "list") {
+	if !strings.Contains(source, "list") && source != "price_driven" {
 		poster, tmpErr := yb_poster_resource.GetPosterByCondition(path, "poster", version)
 		if tmpErr != nil && tmpErr != utils.ErrNoRow {
 			err = tmpErr
@@ -72,6 +73,7 @@ func CreatePosterFromSource(codePage, codeScene, source, version, pars string) (
 		"chart_list":            1352,
 		"report_detail":         1420,
 		"report_list":           1344,
+		"price_driven":          1344,
 	}
 	widthMap := map[string]int{
 		"activity_detail":       1280,
@@ -82,6 +84,7 @@ func CreatePosterFromSource(codePage, codeScene, source, version, pars string) (
 		"chart_list":            1176,
 		"report_detail":         1176,
 		"report_list":           1176,
+		"price_driven":          1176,
 	}
 	width := widthMap[source]
 	height := heightMap[source]
@@ -245,37 +248,41 @@ func CreateAndUploadSunCode(page, scene, version string) (imgUrl string, err err
 }
 
 type PosterParsReq struct {
-	ActivityTitle   string `json:"activity_title"`
-	ActivityAvatar  string `json:"activity_avatar"`
-	ActivitySpeaker string `json:"activity_speaker"`
-	ActivityTime    string `json:"activity_time"`
-	ChartName       string `json:"chart_name"`
-	ChartImage      string `json:"chart_image"`
-	ReportType      string `json:"report_type"`
-	ReportAvatar    string `json:"report_avatar"`
-	ReportTitle     string `json:"report_title"`
-	ReportAbstract  string `json:"report_abstract"`
-	Stage1          string `json:"stage_1"`
-	Avatar1         string `json:"avatar_1"`
-	Title1          string `json:"title_1"`
-	Author1         string `json:"author_1"`
-	Tag1            string `json:"tag_1"`
-	Img1            string `json:"img_1"`
-	Time1           string `json:"time_1"`
-	Abstract1       string `json:"abstract_1"`
-	Status1         string `json:"status_1"`
-	Speaker1        string `json:"speaker_1"`
-	Stage2          string `json:"stage_2"`
-	Avatar2         string `json:"avatar_2"`
-	Title2          string `json:"title_2"`
-	Author2         string `json:"author_2"`
-	Tag2            string `json:"tag_2"`
-	Img2            string `json:"img_2"`
-	Abstract2       string `json:"abstract_2"`
-	Time2           string `json:"time_2"`
-	Status2         string `json:"status_2"`
-	Speaker2        string `json:"speaker_2"`
-	ListTitle       string `json:"list_title"`
+	ActivityTitle     string `json:"activity_title"`
+	ActivityAvatar    string `json:"activity_avatar"`
+	ActivitySpeaker   string `json:"activity_speaker"`
+	ActivityTime      string `json:"activity_time"`
+	ChartName         string `json:"chart_name"`
+	ChartImage        string `json:"chart_image"`
+	ReportType        string `json:"report_type"`
+	ReportAvatar      string `json:"report_avatar"`
+	ReportTitle       string `json:"report_title"`
+	ReportAbstract    string `json:"report_abstract"`
+	Stage1            string `json:"stage_1"`
+	Avatar1           string `json:"avatar_1"`
+	Title1            string `json:"title_1"`
+	Author1           string `json:"author_1"`
+	Tag1              string `json:"tag_1"`
+	Img1              string `json:"img_1"`
+	Time1             string `json:"time_1"`
+	Abstract1         string `json:"abstract_1"`
+	Status1           string `json:"status_1"`
+	Speaker1          string `json:"speaker_1"`
+	Stage2            string `json:"stage_2"`
+	Avatar2           string `json:"avatar_2"`
+	Title2            string `json:"title_2"`
+	Author2           string `json:"author_2"`
+	Tag2              string `json:"tag_2"`
+	Img2              string `json:"img_2"`
+	Abstract2         string `json:"abstract_2"`
+	Time2             string `json:"time_2"`
+	Status2           string `json:"status_2"`
+	Speaker2          string `json:"speaker_2"`
+	ListTitle         string `json:"list_title"`
+	CoreDrivenType    string `json:"core_driven_type"`
+	CoreDrivenContent string `json:"core_driven_content"`
+	MainVariable      string `json:"main_variable"`
+	UpdateTime        string `json:"update_time"`
 }
 
 // fillContent2Html 填充HTML动态内容
@@ -382,12 +389,12 @@ func fillContent2Html(source, pars, sunCodeUrl string, height int) (contentStr s
 		contentStr = strings.Replace(contentStr, "{{REPORT_ABSTRACT}}", abstract, 1)
 	case "special_column_list":
 		contentStr = strings.Replace(contentStr, "{{LIST_TITLE}}", params.ListTitle, 1)
-		contentStr = strings.Replace(contentStr, "{{STAGE_1}}", "第" + params.Stage1 + "期", 1)
+		contentStr = strings.Replace(contentStr, "{{STAGE_1}}", "第"+params.Stage1+"期", 1)
 		contentStr = strings.Replace(contentStr, "{{AVATAR_1}}", params.Avatar1, 1)
 		contentStr = strings.Replace(contentStr, "{{TITLE_1}}", params.Title1, 1)
 		contentStr = strings.Replace(contentStr, "{{AUTHOR_1}}", params.Author1, 1)
 		contentStr = strings.Replace(contentStr, "{{TAG_1}}", params.Tag1, 1)
-		contentStr = strings.Replace(contentStr, "{{STAGE_2}}", "第" + params.Stage2 + "期", 1)
+		contentStr = strings.Replace(contentStr, "{{STAGE_2}}", "第"+params.Stage2+"期", 1)
 		contentStr = strings.Replace(contentStr, "{{AVATAR_2}}", params.Avatar2, 1)
 		contentStr = strings.Replace(contentStr, "{{TITLE_2}}", params.Title2, 1)
 		contentStr = strings.Replace(contentStr, "{{AUTHOR_2}}", params.Author2, 1)
@@ -408,6 +415,12 @@ func fillContent2Html(source, pars, sunCodeUrl string, height int) (contentStr s
 		contentStr = strings.Replace(contentStr, "{{ABSTRACT_2}}", params.Abstract2, 1)
 		contentStr = strings.Replace(contentStr, "{{IMG_2}}", params.Img2, 1)
 		contentStr = strings.Replace(contentStr, "{{TIME_2}}", params.Time2, 1)
+	case "price_driven":
+		contentStr = strings.Replace(contentStr, "{{LIST_TITLE}}", params.ListTitle, 1)
+		contentStr = strings.Replace(contentStr, "{{CORE_DRIVEN_TYPE}}", params.CoreDrivenType, 1)
+		contentStr = strings.Replace(contentStr, "{{CORE_DRIVEN_CONTENT}}", params.CoreDrivenContent, 1)
+		contentStr = strings.Replace(contentStr, "{{MAIN_VARIABLE}}", params.MainVariable, 1)
+		contentStr = strings.Replace(contentStr, "{{UPDATE_TIME}}", params.UpdateTime, 1)
 	case "activity_list":
 		bgColorMap := map[string]string{
 			"未开始": "#E3B377",
@@ -464,3 +477,283 @@ func fillContent2Html(source, pars, sunCodeUrl string, height int) (contentStr s
 	contentStr = strings.Replace(contentStr, "{{SUN_CODE}}", sunCodeUrl, 1)
 	return
 }
+
+// GetRddpShareImg 获取日度点评分享图
+func GetRddpShareImg(title string) (imgUrl string, err error) {
+	if title == "" {
+		return
+	}
+	template := fmt.Sprint("static/htm2img/rddp-share.html")
+	contentByte, e := ioutil.ReadFile(template)
+	if e != nil {
+		err = errors.New("读取模板失败, Err: " + e.Error())
+		return
+	}
+	contentStr := string(contentByte)
+	contentStr = strings.Replace(contentStr, "{{TITLE}}", title, 1)
+	htm2ImgReq := make(map[string]interface{})
+	htm2ImgReq["html_content"] = contentStr
+	htm2ImgReq["width"] = 1000
+	htm2ImgReq["height"] = 800
+	res, e := postHtml2Img(htm2ImgReq)
+	if e != nil || res == nil {
+		err = errors.New("html转图片请求失败")
+		return
+	}
+	if res.Code != 200 {
+		err = errors.New("html转图片请求失败: " + res.Msg)
+		return
+	}
+	imgUrl = res.Data
+	return
+}
+
+// CreatePosterFromSourceV2 生成分享海报(通过配置获取相关信息)
+func CreatePosterFromSourceV2(codePage, codeScene, source, version, pars string) (imgUrl string, err error) {
+	var errMsg string
+	defer func() {
+		if err != nil {
+			global.LOG.Critical(fmt.Sprintf("CreatePosterFromSource: source=%s, pars:%s, errMsg:%s", source, pars, errMsg))
+			reqSlice := make([]string, 0)
+			reqSlice = append(reqSlice, fmt.Sprint("CodePage:", codePage, "\n"))
+			reqSlice = append(reqSlice, fmt.Sprint("CodeScene:", codeScene, "\n"))
+			reqSlice = append(reqSlice, fmt.Sprint("Source:", source, "\n"))
+			reqSlice = append(reqSlice, fmt.Sprint("Version:", version, "\n"))
+			reqSlice = append(reqSlice, fmt.Sprint("Pars:", pars, "\n"))
+			go alarm_msg.SendAlarmMsg("CreatePosterFromSource生成分享海报失败, Msg:"+errMsg+";Err:"+err.Error()+"\n;Req:\n"+strings.Join(reqSlice, ";"), 3)
+		}
+	}()
+	if codePage == "" || source == "" || pars == "" {
+		errMsg = "参数有误"
+		err = errors.New(errMsg)
+		return
+	}
+	path := fmt.Sprint(codePage, "?", codeScene)
+	// 非列表来源获取历史图片,无则生成
+	if !strings.Contains(source, "list") && source != "price_driven" {
+		poster, tmpErr := yb_poster_resource.GetPosterByCondition(path, "poster", version)
+		if tmpErr != nil && tmpErr != utils.ErrNoRow {
+			err = tmpErr
+			return
+		}
+		if poster != nil && poster.ImgURL != "" {
+			imgUrl = poster.ImgURL
+			return
+		}
+	}
+	ybPosterConfig, err := yb_poster_config.GetBySource(source)
+	if err != nil {
+		return
+	}
+	// 图片长宽
+	//heightMap := map[string]int{
+	//	"activity_detail":       1210,
+	//	"activity_list":         1948,
+	//	"special_column_detail": 1480,
+	//	"special_column_list":   1548,
+	//	"chart_detail":          1536,
+	//	"chart_list":            1352,
+	//	"report_detail":         1420,
+	//	"report_list":           1344,
+	//}
+	//widthMap := map[string]int{
+	//	"activity_detail":       1280,
+	//	"activity_list":         1280,
+	//	"special_column_detail": 1176,
+	//	"special_column_list":   1176,
+	//	"chart_detail":          1176,
+	//	"chart_list":            1176,
+	//	"report_detail":         1176,
+	//	"report_list":           1176,
+	//}
+
+	width := ybPosterConfig.Width
+	height := ybPosterConfig.Hight
+	//生成太阳码
+	sunCodeUrl, err := CreateAndUploadSunCode(codePage, codeScene, version)
+	if err != nil {
+		return
+	}
+	//sunCodeUrl := ``
+	// 填充html内容
+	contentStr, newHeight, err := fillContent2HtmlV2(source, pars, sunCodeUrl, height, *ybPosterConfig)
+	if err != nil {
+		errMsg = "html内容有误"
+		return
+	}
+	global.LOG.Critical(contentStr)
+	//return
+	// 请求python服务htm2img
+	htm2ImgReq := make(map[string]interface{})
+	htm2ImgReq["html_content"] = contentStr
+	htm2ImgReq["width"] = width
+	htm2ImgReq["height"] = newHeight
+	res, err := postHtml2Img(htm2ImgReq)
+	if err != nil || res == nil {
+		errMsg = "html转图片请求失败"
+		return
+	}
+	if res.Code != 200 {
+		errMsg = "html转图片请求失败"
+		err = errors.New("html转图片失败: " + res.Msg)
+		return
+	}
+	imgUrl = res.Data
+	// 记录海报信息
+	newPoster := &yb_poster_resource.YbPosterResource{
+		Path:       path,
+		ImgURL:     imgUrl,
+		Type:       "poster",
+		Version:    version,
+		CreateTime: time.Now(),
+	}
+	err = newPoster.Create()
+	return
+}
+
+// HtmlReplaceConfig html替换配置
+type HtmlReplaceConfig struct {
+	TemplateStr string `json:"template_str"`
+	ReplaceStr  string `json:"replace_str"`
+}
+
+// DefaultValueConfig 默认值的配置
+type DefaultValueConfig struct {
+	Key          string `json:"key"`
+	UseOtherKey  string `json:"use_other_key"`
+	Value        string `json:"value"`
+	ConditionKey string `json:"condition_key"`
+}
+
+// fillContent2Html 填充HTML动态内容
+func fillContent2HtmlV2(source, pars, sunCodeUrl string, height float64, ybPosterConfig yb_poster_config.YbPosterConfig) (contentStr string, newHeight float64, err error) {
+	paramsMap := make(map[string]string)
+	if err = json.Unmarshal([]byte(pars), &paramsMap); err != nil {
+		return
+	}
+
+	//fmt.Println(paramsMap)
+
+	//html替换规则
+	htmlReplaceConfigList := make([]HtmlReplaceConfig, 0)
+	if err = json.Unmarshal([]byte(ybPosterConfig.HTMLReplaceConfig), &htmlReplaceConfigList); err != nil {
+		return
+	}
+
+	newHeight = height
+	contentStr = ybPosterConfig.HTMLTemplate
+
+	// 默认数据替换
+	defaultValueConfigMap := make([]DefaultValueConfig, 0)
+	if ybPosterConfig.DefaultValueConfig != `` {
+		if err = json.Unmarshal([]byte(ybPosterConfig.DefaultValueConfig), &defaultValueConfigMap); err != nil {
+			return
+		}
+	}
+	// 列表的动态内容不完整的用默认内容的填充
+	//var emptyTime1, emptyTime2 bool
+	conditionKeyValMap := make(map[string]string)
+	for _, v := range defaultValueConfigMap {
+		if v.ConditionKey == `` {
+			continue
+		}
+		conditionKeyVal, ok := conditionKeyValMap[v.ConditionKey]
+		if !ok {
+			conditionKeyVal = paramsMap[v.ConditionKey]
+			conditionKeyValMap[v.ConditionKey] = conditionKeyVal
+		}
+		if conditionKeyVal == `` {
+			paramsMap[v.Key] = v.Value
+			if v.UseOtherKey != `` {
+				if tmpVal, ok := paramsMap[v.UseOtherKey]; ok {
+					paramsMap[v.Key] = tmpVal
+				}
+			}
+
+		}
+	}
+
+	// 填充指定内容
+	switch source {
+	case "report_detail": //需要将简介处理下
+		reportAbstract := paramsMap["report_abstract"]
+		doc, tmpErr := goquery.NewDocumentFromReader(strings.NewReader(reportAbstract))
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		abstract := ""
+		doc.Find("p").Each(func(i int, s *goquery.Selection) {
+			phtml, tmpErr := s.Html()
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			st := s.Text()
+			if st != "" && st != "<br>" && st != "<br style=\"max-width: 100%;\">" && !strings.Contains(phtml, "iframe") {
+				abstract = abstract + "<p>" + phtml + "</p>"
+			}
+		})
+		paramsMap["report_abstract"] = abstract
+	case "activity_list":
+		bgColorMap := map[string]string{
+			"未开始": "#E3B377",
+			"进行中": "#3385FF",
+			"已结束": "#A2A2A2",
+		}
+		statusItemMap := map[string]string{
+			"未开始": "block",
+			"进行中": "none",
+			"已结束": "none",
+		}
+		offlineMap := map[string]string{
+			"线上会议": "none",
+			"线下沙龙": "block",
+		}
+		onlineMap := map[string]string{
+			"线上会议": "block",
+			"线下沙龙": "none",
+		}
+
+		listTitle := paramsMap["list_title"]
+		status1 := paramsMap["status_1"]
+		if status1 != "未开始" {
+			newHeight = 1715
+		}
+		status2 := paramsMap["status_2"]
+		paramsMap["list_title"] = "弘则FICC周度电话会安排"
+		paramsMap["bg_color_1"] = bgColorMap[status1]
+		paramsMap["show_item_1"] = statusItemMap[status1]
+		paramsMap["show_offline_1"] = offlineMap[listTitle]
+		paramsMap["show_online_1"] = onlineMap[listTitle]
+
+		paramsMap["bg_color_2"] = bgColorMap[status2]
+		paramsMap["show_item_2"] = statusItemMap[status2]
+		paramsMap["show_offline_2"] = offlineMap[listTitle]
+		paramsMap["show_online_2"] = onlineMap[listTitle]
+
+		// 用默认内容填充的活动时间字体颜色调至看不见
+		color1 := "#999"
+		color2 := "#999"
+
+		if paramsMap["empty_time_1"] == "true" {
+			color1 = "#fff"
+		}
+		if paramsMap["empty_time_2"] == "true" {
+			color2 = "#fff"
+		}
+		paramsMap["time_color_1"] = color1
+		paramsMap["time_color_2"] = color2
+	}
+
+	contentStr = strings.Replace(contentStr, "{{SUN_CODE}}", sunCodeUrl, 1)
+
+	for _, v := range htmlReplaceConfigList {
+		tmpVal, ok := paramsMap[v.ReplaceStr]
+		if !ok {
+			tmpVal = ``
+		}
+		contentStr = strings.Replace(contentStr, v.TemplateStr, tmpVal, 1)
+	}
+	return
+}

+ 99 - 0
services/variety_tag.go

@@ -0,0 +1,99 @@
+package services
+
+import (
+	"errors"
+	"hongze/hongze_yb/models/tables/variety_classify"
+	"hongze/hongze_yb/models/tables/variety_tag"
+	"hongze/hongze_yb/models/tables/yb_price_driven_tag"
+)
+
+// TagTreeItem 标签树
+type TagTreeItem struct {
+	ClassifyId   int    `json:"classify_id" description:"分类ID"`
+	ClassifyName string `json:"classify_name" description:"分类名称"`
+	//TagId        int        `json:"tag_id" description:"分类ID(用于前端组件)"`
+	//TagName      string     `json:"tag_name" description:"分类名称(用于前端组件)"`
+	Sort int        `json:"sort" description:"排序"`
+	Tags []*TagItem `json:"tags" description:"标签"`
+}
+
+// TagItem 标签
+type TagItem struct {
+	TagId             int    `json:"tag_id" description:"标签ID"`
+	TagName           string `json:"tag_name" description:"标签名称"`
+	Sort              int    `json:"sort" description:"排序"`
+	ClassifyId        int    `json:"classify_id" description:"分类ID"`
+	ChartPermissionId int    `json:"chart_permission_id" description:"品种权限ID"`
+	PriceDrivenState  int    `json:"price_driven_state" description:"价格驱动状态:0-关闭 1-开启"`
+	//ResearcherList    []*TagResearcher `json:"researcher_list" description:"研究员列表"`
+}
+
+// TagResearcher 研究员信息
+type TagResearcher struct {
+	AdminId   int    `json:"admin_id"`
+	AdminName string `json:"admin_name"`
+}
+
+// 获取标签树
+func GetTagTree() (respList []*TagTreeItem, err error) {
+	respList = make([]*TagTreeItem, 0)
+	// 获取标签分类
+	classifyList, e := variety_classify.GetVarietyClassifyList()
+	if e != nil {
+		err = errors.New("获取标签分类列表失败, Err: " + e.Error())
+		return
+	}
+	classifyLen := len(classifyList)
+	if classifyLen == 0 {
+		return
+	}
+	// 获取标签列表
+	tagList, e := variety_tag.GetVarietyTagList()
+	if e != nil {
+		err = errors.New("获取标签列表失败, Err: " + e.Error())
+		return
+	}
+	// 价格驱动标签
+	priceTagList, e := yb_price_driven_tag.GetPriceDrivenTagList()
+	if e != nil {
+		err = errors.New("获取价格驱动标签列表失败, Err:" + e.Error())
+		return
+	}
+	priceTagLen := len(priceTagList)
+	priceTagMap := make(map[int]int, 0)
+	for i := 0; i < priceTagLen; i++ {
+		priceTagMap[priceTagList[i].VarietyTagID] = priceTagList[i].State
+	}
+	// 价格驱动状态
+	tagsArr := make([]*TagItem, 0)
+	tagLen := len(tagList)
+	for i := 0; i < tagLen; i++ {
+		item := tagList[i]
+		priceState := priceTagMap[item.VarietyTagID]
+		tagsArr = append(tagsArr, &TagItem{
+			TagId:             item.VarietyTagID,
+			TagName:           item.TagName,
+			Sort:              item.Sort,
+			ClassifyId:        item.VarietyClassifyID,
+			ChartPermissionId: item.ChartPermissionID,
+			PriceDrivenState:  priceState,
+		})
+	}
+	// 分类标签
+	for i := 0; i < classifyLen; i++ {
+		classifyItem := new(TagTreeItem)
+		classifyItem.ClassifyId = classifyList[i].VarietyClassifyID
+		classifyItem.ClassifyName = classifyList[i].ClassifyName
+		//classifyItem.TagId = classifyList[i].VarietyClassifyID
+		//classifyItem.TagName = classifyList[i].ClassifyName
+		classifyItem.Sort = classifyList[i].Sort
+		classifyItem.Tags = make([]*TagItem, 0)
+		for _, t := range tagsArr {
+			if classifyItem.ClassifyId == t.ClassifyId {
+				classifyItem.Tags = append(classifyItem.Tags, t)
+			}
+		}
+		respList = append(respList, classifyItem)
+	}
+	return
+}

+ 111 - 0
static/htm2img/price_driven.html

@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Document</title>
+    <style>
+        html,body{
+            margin: 0;
+            padding: 0;
+        }
+        div{
+            box-sizing: border-box;
+        }
+        .box{
+            /* width: 294px;
+            height: 336px; */
+            width: 1176px;
+            height: 1344px;
+            background-color: #fff;
+            padding: 100px 64px 64px 60px;
+            border-radius: 16px;
+            border: 1px solid #ECECEC;
+            background-image: url('https://hzstatic.hzinsights.com/static/icon/hzyb/yb-bg-hzlogo.png');
+            background-position: top right;
+            background-size: 300px 300px;
+            background-repeat: no-repeat;
+        }
+        .title{
+            font-size: 64px;
+            font-weight: bold;
+            margin-bottom: 40px;
+        }
+        .flex{
+            height: 256x;
+            margin-top: 40px;
+            font-size: 56px;
+        }
+        .content-box{
+            height: 500px;
+            margin: 80px 0;
+            overflow: hidden;
+            font-size: 56px;
+        }
+        .text-one{
+            overflow: hidden;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+        }
+        .item-img{
+            width: 188px;
+            height: 252px;
+            float: left;
+            object-fit: cover;
+            border-radius: 16px;
+            margin-right: 20px;
+        }
+        .item-title{
+            font-size: 52px;
+        }
+        .item-des{
+            height: 80px;
+            font-size: 44px;
+        }
+        .audio-box{
+            width: 200px;
+            height: 80px;
+            background: #E3B377;
+            border-radius: 40px;
+            color: #fff;
+            font-size: 48px;
+            float: right;
+            text-align: center;
+            line-height: 80px;
+        }
+        .audio-box img{
+            width: 60px;
+            height: 60px;
+            object-fit: cover;
+            position: relative;
+            top: 12px;
+        }
+        
+        
+        .xcx-img{
+            width: 256px;
+            height: 256px;
+            float: right;
+        }
+    </style>
+</head>
+<body>
+    <div class="box">
+        <div class="title">{{LIST_TITLE}}</div>
+        <div class="content-box">
+            <div style="margin-bottom: 40px;line-height: 80px">核心驱动({{CORE_DRIVEN_TYPE}}):{{CORE_DRIVEN_CONTENT}}</div>
+            <div style="margin-bottom: 40px;">关键变量: {{MAIN_VARIABLE}}</div>
+            <div>更新时间:{{UPDATE_TIME}}</div>
+        </div>
+        <div style="text-align:center;font-size:56px;color:#999">长按图片分享</div>
+        <div class="flex">
+            <div style="float: left;">
+                <div>长按识别小程序码</div>
+                <div style="color:#999">查看更多</div>
+            </div>
+            <img class="xcx-img" src="{{SUN_CODE}}" alt="">
+        </div>
+    </div>
+</body>
+</html>

+ 40 - 0
static/htm2img/rddp-share.html

@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Document</title>
+    <style>
+        html,body{
+            margin: 0;
+            padding: 0;
+        }
+        div{
+            box-sizing: border-box;
+        }
+        .box{
+            width: 1000px;
+            height: 800px;
+            background-color: #ccc;
+            background-image: url('https://hzstatic.hzinsights.com/static/icon/hzyb/rddp-share-bg.png');
+            background-repeat: no-repeat;
+            background-size: cover;
+            display: table-cell;
+            vertical-align: middle;
+        }
+        .text{
+            color: #fff;
+            font-size: 80px;
+            line-height: 1.5;
+            text-align: center;
+            padding: 0 100px;
+        }
+    </style>
+</head>
+<body>
+    <div class="box">
+        <div class="text">{{TITLE}}</div>
+    </div>
+</body>
+</html>