Explorar o código

Merge branch 'yb/11.6'

hsun %!s(int64=2) %!d(string=hai) anos
pai
achega
e6b53ee8f1

+ 27 - 0
controller/chart/chart_info.go

@@ -8,11 +8,13 @@ import (
 	"hongze/hongze_yb/controller/response"
 	"hongze/hongze_yb/global"
 	"hongze/hongze_yb/models/request"
+	responseModel "hongze/hongze_yb/models/response"
 	"hongze/hongze_yb/models/response/chart_info"
 	chartEdbMappingModel "hongze/hongze_yb/models/tables/chart_edb_mapping"
 	chartInfoModel "hongze/hongze_yb/models/tables/chart_info"
 	"hongze/hongze_yb/models/tables/chart_info_log"
 	edbInfoModel "hongze/hongze_yb/models/tables/edb_info"
+	"hongze/hongze_yb/models/tables/yb_my_chart"
 	"hongze/hongze_yb/services/alarm_msg"
 	"hongze/hongze_yb/services/chart"
 	"hongze/hongze_yb/services/user"
@@ -230,11 +232,36 @@ func GetChartInfoDetail(c *gin.Context) {
 		go chart.SaveChartVisitLog(userInfo, chartInfo, myChartClassifyId)
 	}
 
+	// 用户是否有收藏该图表
+	ob := new(yb_my_chart.YbMyChart)
+	cond := `user_id = ? AND chart_info_id = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, userInfo.UserID, chartInfo.ChartInfoId)
+	exists, e := ob.FetchByCondition(cond, pars)
+	if e != nil && e != utils.ErrNoRow {
+		response.FailMsg("操作失败", "获取用户图表失败, Err: "+e.Error(), c)
+		return
+	}
+	myChartInfo := new(responseModel.MyChartItem)
+	if exists != nil && exists.MyChartID > 0 {
+		myChartInfo.MyChartID = exists.MyChartID
+		myChartInfo.MyChartClassifyID = exists.MyChartClassifyID
+		myChartInfo.ChartInfoID = exists.ChartInfoID
+		myChartInfo.ChartName = exists.ChartName
+		myChartInfo.UniqueCode = exists.UniqueCode
+		myChartInfo.ChartImage = exists.ChartImage
+		myChartInfo.UserID = exists.UserID
+		myChartInfo.ReportID = exists.ReportID
+		myChartInfo.ReportChapterID = exists.ReportChapterID
+		myChartInfo.CreateTime = utils.TimeTransferString(utils.FormatDateTime, exists.CreateTime)
+	}
+
 	resp := new(chart_info.ChartInfoDetailResp)
 	resp.ChartInfo = chartInfo
 	resp.EdbInfoList = edbList
 	resp.XEdbIdValue = xEdbIdValue
 	resp.YDataList = yDataList
+	resp.MyChartInfo = myChartInfo
 
 	response.OkData("获取成功", resp, c)
 }

+ 348 - 0
controller/my_chart/my_chart.go

@@ -0,0 +1,348 @@
+package my_chart
+
+import (
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/response"
+	"hongze/hongze_yb/models/request"
+	responseModel "hongze/hongze_yb/models/response"
+	chartInfoModel "hongze/hongze_yb/models/tables/chart_info"
+	"hongze/hongze_yb/models/tables/yb_config"
+	"hongze/hongze_yb/models/tables/yb_my_chart"
+	"hongze/hongze_yb/services"
+	userService "hongze/hongze_yb/services/user"
+	"hongze/hongze_yb/utils"
+	"strconv"
+	"time"
+)
+
+// MyChartController 用户-我的图表
+type MyChartController struct{}
+
+// List 我的图表列表
+func (this *MyChartController) List(c *gin.Context) {
+	userInfo := userService.GetInfoByClaims(c)
+	userId := int(userInfo.UserID)
+	var req request.MyChartCollectListReq
+	if c.Bind(&req) != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	cond := `user_id = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, userId)
+	if req.Keyword != "" {
+		kw := fmt.Sprint("%", req.Keyword, "%")
+		cond += ` AND chart_name LIKE ?`
+		pars = append(pars, kw)
+	}
+	if req.ClassifyId > 0 {
+		cond += ` AND my_chart_classify_id = ?`
+		pars = append(pars, req.ClassifyId)
+	}
+	pageIndex := services.GetCurrPageByClaims(c)
+	pageSize := services.GetPageSizeByClaims(c)
+
+	ob := new(yb_my_chart.YbMyChart)
+	chartTotal, e := ob.Count(cond, pars)
+	if e != nil {
+		response.FailMsg("获取失败", "获取用户图表列表总数失败, Err:"+e.Error(), c)
+		return
+	}
+	total := int(chartTotal)
+	list, e := ob.PageList(cond, pars, pageIndex, pageSize)
+	if e != nil {
+		response.FailMsg("获取失败", "获取用户图表列表失败, Err:"+e.Error(), c)
+		return
+	}
+	respList := make([]*responseModel.MyChartItem, 0)
+	for i := range list {
+		respList = append(respList, &responseModel.MyChartItem{
+			MyChartID:         list[i].MyChartID,
+			MyChartClassifyID: list[i].MyChartClassifyID,
+			ChartInfoID:       list[i].ChartInfoID,
+			ChartName:         list[i].ChartName,
+			UniqueCode:        list[i].UniqueCode,
+			ChartImage:        list[i].ChartImage,
+			UserID:            list[i].UserID,
+			ReportID:          list[i].ReportID,
+			ReportChapterID:   list[i].ReportChapterID,
+			CreateTime:        utils.TimeTransferString(utils.FormatDateTime, list[i].CreateTime),
+		})
+	}
+
+	response.OkData("获取成功", &responseModel.MyChartListResp{
+		List:   respList,
+		Paging: responseModel.GetPaging(pageIndex, pageSize, total),
+	}, c)
+}
+
+// Collect 收藏图表
+func (this *MyChartController) Collect(c *gin.Context) {
+	var req request.MyChartCollectReq
+	if c.ShouldBind(&req) != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.Authorization == "" {
+		response.Fail("用户身份有误", c)
+		return
+	}
+	if req.UniqueCode == "" {
+		response.Fail("请选择图表", c)
+		return
+	}
+	if req.ReportId <= 0 {
+		response.Fail("请选择报告", c)
+		return
+	}
+
+	// 获取用户信息
+	userInfo, e := userService.GetUserInfoByToken(req.Authorization)
+	if e != nil {
+		response.FailMsg("操作失败", "Token获取有效用户失败, Err: "+e.Error(), c)
+		return
+	}
+	if userInfo.UserID <= 0 {
+		response.FailMsg("操作失败", "Token获取有效用户失败", c)
+		return
+	}
+	userId := int(userInfo.UserID)
+
+	// 获取图表信息
+	chartInfo, e := chartInfoModel.GetChartInfoViewByUniqueCode(req.UniqueCode)
+	if e != nil {
+		response.FailMsg("操作失败", "UniqueCode获取图表信息失败, Err:"+e.Error(), c)
+		return
+	}
+	if chartInfo.ChartInfoId <= 0 {
+		response.FailMsg("操作失败", "图表信息有误", c)
+		return
+	}
+
+	// 图表收藏上限
+	ob := new(yb_my_chart.YbMyChart)
+	countCond := `user_id = ?`
+	countPars := make([]interface{}, 0)
+	countPars = append(countPars, userId)
+	count, e := ob.Count(countCond, countPars)
+	if e != nil {
+		response.FailMsg("操作失败", "获取用户图表收藏数量失败, Err: "+e.Error(), c)
+		return
+	}
+	// 获取图表收藏上限配置
+	configCond := `config_code = ?`
+	configPars := make([]interface{}, 0)
+	configPars = append(configPars, yb_config.UserChartCollectMax)
+	confOB := new(yb_config.YbConfig)
+	conf, e := confOB.Fetch(configCond, configPars)
+	if e != nil {
+		response.FailMsg("操作失败", "获取图表收藏上限配置失败, Err: "+e.Error(), c)
+		return
+	}
+	max, e := strconv.Atoi(conf.ConfigValue)
+	if e != nil {
+		response.FailMsg("操作失败", "图表收藏上限配置有误, Err: "+e.Error(), c)
+		return
+	}
+	if int(count) >= max {
+		response.Fail(fmt.Sprintf("图表最多可收藏%d张", max), c)
+		return
+	}
+
+	// 是否已收藏
+	cond := `user_id = ? AND chart_info_id = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, userId, chartInfo.ChartInfoId)
+	exists, e := ob.FetchByCondition(cond, pars)
+	if e != nil && e != utils.ErrNoRow {
+		response.FailMsg("操作失败", "获取用户图表失败, Err: "+e.Error(), c)
+		return
+	}
+	nowTime := time.Now().Local()
+	collectId := 0
+	if exists != nil && exists.MyChartID > 0 {
+		// 更新收藏信息
+		exists.ChartName = chartInfo.ChartName
+		exists.ChartImage = chartInfo.ChartImage
+		exists.ReportID = req.ReportId
+		exists.ReportChapterID = req.ReportChapterId
+		exists.ModifyTime = nowTime
+		updateCols := []string{"ChartName", "ChartImage", "ReportID", "ReportChapterID", "ModifyTime"}
+		if e = exists.Update(updateCols); e != nil {
+			response.FailMsg("操作失败", "更新收藏失败, Err: "+e.Error(), c)
+			return
+		}
+		collectId = exists.MyChartID
+	} else {
+		// 新增收藏
+		ob.ChartInfoID = chartInfo.ChartInfoId
+		ob.ChartName = chartInfo.ChartName
+		ob.UniqueCode = chartInfo.UniqueCode
+		ob.ChartImage = chartInfo.ChartImage
+		ob.UserID = userId
+		ob.ReportID = req.ReportId
+		ob.ReportChapterID = req.ReportChapterId
+		ob.CreateTime = nowTime
+		ob.ModifyTime = nowTime
+		if e = ob.Create(); e != nil {
+			response.FailMsg("操作失败", "新增收藏失败, Err: "+e.Error(), c)
+			return
+		}
+		collectId = ob.MyChartID
+	}
+	response.OkData("操作成功", collectId, c)
+}
+
+// 取消收藏 CollectCancel
+func (this *MyChartController) CollectCancel(c *gin.Context) {
+	var req request.MyChartCollectCancelReq
+	if c.ShouldBind(&req) != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.Authorization == "" {
+		response.Fail("用户身份有误", c)
+		return
+	}
+	if req.UniqueCode == "" {
+		response.Fail("请选择图表", c)
+		return
+	}
+
+	// 获取用户信息
+	userInfo, e := userService.GetUserInfoByToken(req.Authorization)
+	if e != nil {
+		response.FailMsg("操作失败", "Token获取有效用户失败, Err: "+e.Error(), c)
+		return
+	}
+	if userInfo.UserID <= 0 {
+		response.FailMsg("操作失败", "Token获取有效用户失败", c)
+		return
+	}
+	userId := int(userInfo.UserID)
+
+	// 获取图表信息
+	chartInfo, e := chartInfoModel.GetChartInfoViewByUniqueCode(req.UniqueCode)
+	if e != nil {
+		response.FailMsg("操作失败", "UniqueCode获取图表信息失败, Err:"+e.Error(), c)
+		return
+	}
+	if chartInfo.ChartInfoId <= 0 {
+		response.FailMsg("操作失败", "图表信息有误", c)
+		return
+	}
+
+	cond := `user_id = ? AND chart_info_id = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, userId, chartInfo.ChartInfoId)
+	ob := new(yb_my_chart.YbMyChart)
+	// 此处可能出现同一个报告两个同样的图表均有"取消收藏"按钮,点击第一个取消之后再点击第二个会报错,此时进行一个友好的提示"已取消收藏"
+	item, e := ob.FetchByCondition(cond, pars)
+	if e != nil {
+		response.FailMsg("已取消收藏", "获取用户图表失败, Err: "+e.Error(), c)
+		return
+	}
+	if e = item.Delete(); e != nil {
+		response.FailMsg("已取消收藏", "取消用户图表收藏失败, Err: "+e.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
+}
+
+// RelateClassify 加入分类
+func (this *MyChartController) RelateClassify(c *gin.Context) {
+	userInfo := userService.GetInfoByClaims(c)
+	userId := int(userInfo.UserID)
+	if userId <= 0 {
+		response.Fail("请登录后操作", c)
+		return
+	}
+	var req request.MyChartRelateClassifyReq
+	if c.ShouldBind(&req) != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.MyChartId <= 0 {
+		response.Fail("请选择图表", c)
+		return
+	}
+	if req.ClassifyId <= 0 {
+		response.Fail("请选择分类", c)
+		return
+	}
+
+	ob := new(yb_my_chart.YbMyChart)
+	item, e := ob.Fetch(req.MyChartId)
+	if e != nil {
+		response.FailMsg("图表信息有误", "获取用户图表失败, Err: "+e.Error(), c)
+		return
+	}
+	if item.UserID != userId {
+		response.Fail("无权操作", c)
+		return
+	}
+	item.MyChartClassifyID = req.ClassifyId
+	item.ModifyTime = time.Now().Local()
+	if e = item.Update([]string{"MyChartClassifyID", "ModifyTime"}); e != nil {
+		response.FailMsg("操作失败", "更新用户图表关联分类失败, Err: "+e.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
+}
+
+// IsCollect 是否已收藏
+func (this *MyChartController) IsCollect(c *gin.Context) {
+	var req request.MyChartIsCollectReq
+	if c.Bind(&req) != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.Authorization == "" {
+		response.Fail("用户身份有误", c)
+		return
+	}
+	if req.UniqueCode == "" {
+		response.Fail("请选择图表", c)
+		return
+	}
+
+	// 获取用户信息
+	userInfo, e := userService.GetUserInfoByToken(req.Authorization)
+	if e != nil {
+		response.FailMsg("操作失败", "Token获取有效用户失败, Err: "+e.Error(), c)
+		return
+	}
+	if userInfo.UserID <= 0 {
+		response.FailMsg("操作失败", "Token获取有效用户失败", c)
+		return
+	}
+	userId := int(userInfo.UserID)
+
+	// 获取图表信息
+	chartInfo, e := chartInfoModel.GetChartInfoViewByUniqueCode(req.UniqueCode)
+	if e != nil {
+		response.FailMsg("操作失败", "UniqueCode获取图表信息失败, Err:"+e.Error(), c)
+		return
+	}
+	if chartInfo.ChartInfoId <= 0 {
+		response.FailMsg("操作失败", "图表信息有误", c)
+		return
+	}
+
+	// 是否已收藏
+	ob := new(yb_my_chart.YbMyChart)
+	cond := `user_id = ? AND chart_info_id = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, userId, chartInfo.ChartInfoId)
+	exists, e := ob.FetchByCondition(cond, pars)
+	if e != nil && e != utils.ErrNoRow {
+		response.FailMsg("操作失败", "获取用户图表失败, Err: "+e.Error(), c)
+		return
+	}
+	isCollect := false
+	if exists != nil && exists.MyChartID > 0 {
+		isCollect = true
+	}
+	response.OkData("获取成功", isCollect, c)
+}

+ 239 - 0
controller/my_chart/my_chart_classify.go

@@ -0,0 +1,239 @@
+package my_chart
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/response"
+	"hongze/hongze_yb/models/request"
+	responseModel "hongze/hongze_yb/models/response"
+	"hongze/hongze_yb/models/tables/yb_my_chart"
+	"hongze/hongze_yb/models/tables/yb_my_chart_classify"
+	userService "hongze/hongze_yb/services/user"
+	"hongze/hongze_yb/utils"
+	"time"
+)
+
+// MyChartClassifyController 用户-我的图表分类
+type MyChartClassifyController struct{}
+
+func (this *MyChartClassifyController) List(c *gin.Context) {
+	userInfo := userService.GetInfoByClaims(c)
+	userId := int(userInfo.UserID)
+	if userId <= 0 {
+		response.Fail("请登录后查看", c)
+		return
+	}
+
+	cond := `user_id = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, userId)
+	ob := new(yb_my_chart_classify.YbMyChartClassify)
+	list, e := ob.List(cond, pars)
+	if e != nil {
+		response.FailMsg("获取失败", "获取用户图表分类失败, Err: "+e.Error(), c)
+		return
+	}
+	respList := make([]*responseModel.MyChartClassifyItem, 0)
+	for i := range list {
+		respList = append(respList, &responseModel.MyChartClassifyItem{
+			MyChartClassifyID:   list[i].MyChartClassifyID,
+			MyChartClassifyName: list[i].MyChartClassifyName,
+			Sort:                list[i].Sort,
+			UserID:              list[i].UserID,
+			CreateTime:          utils.TimeTransferString(utils.FormatDateTime, list[i].CreateTime),
+		})
+	}
+	response.OkData("获取成功", respList, c)
+}
+
+func (this *MyChartClassifyController) Add(c *gin.Context) {
+	userInfo := userService.GetInfoByClaims(c)
+	userId := int(userInfo.UserID)
+	if userId <= 0 {
+		response.Fail("请登录后操作", c)
+		return
+	}
+	var req request.MyChartClassifyAddReq
+	if c.ShouldBind(&req) != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.ClassifyName == "" {
+		response.Fail("请输入分类名称", c)
+		return
+	}
+	if len([]rune(req.ClassifyName)) > 10 {
+		response.Fail("分类名称不可超过10个字符", c)
+		return
+	}
+
+	cond := `my_chart_classify_name = ? AND user_id = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, req.ClassifyName, userId)
+	ob := new(yb_my_chart_classify.YbMyChartClassify)
+	exists, e := ob.FetchByCondition(cond, pars)
+	if e != nil && e != utils.ErrNoRow {
+		response.FailMsg("操作失败", "获取用户同名图表分类失败, Err: "+e.Error(), c)
+		return
+	}
+	if exists != nil && exists.MyChartClassifyID > 0 {
+		response.Fail("分类名称已存在", c)
+		return
+	}
+
+	nowTime := time.Now().Local()
+	ob.MyChartClassifyName = req.ClassifyName
+	ob.UserID = userId
+	ob.CreateTime = nowTime
+	ob.ModifyTime = nowTime
+	if e = ob.Create(); e != nil {
+		response.FailMsg("操作失败", "新增用户图表分类失败, Err: "+e.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
+}
+
+func (this *MyChartClassifyController) Edit(c *gin.Context) {
+	userInfo := userService.GetInfoByClaims(c)
+	userId := int(userInfo.UserID)
+	if userId <= 0 {
+		response.Fail("请登录后操作", c)
+		return
+	}
+	var req request.MyChartClassifyEditReq
+	if c.ShouldBind(&req) != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.ClassifyId <= 0 {
+		response.Fail("请选择分类", c)
+		return
+	}
+	if req.ClassifyName == "" {
+		response.Fail("请输入分类名称", c)
+		return
+	}
+	if len([]rune(req.ClassifyName)) > 10 {
+		response.Fail("分类名称不可超过10个字符", c)
+		return
+	}
+
+	cond := `my_chart_classify_name = ? AND user_id = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, req.ClassifyName, userId)
+	ob := new(yb_my_chart_classify.YbMyChartClassify)
+	exists, e := ob.FetchByCondition(cond, pars)
+	if e != nil && e != utils.ErrNoRow {
+		response.FailMsg("操作失败", "获取用户同名图表分类失败, Err: "+e.Error(), c)
+		return
+	}
+	if exists != nil && exists.MyChartClassifyID > 0 && exists.MyChartClassifyID != req.ClassifyId {
+		response.Fail("分类名称已存在", c)
+		return
+	}
+
+	item, e := ob.Fetch(req.ClassifyId)
+	if e != nil {
+		response.FailMsg("信息有误", "获取用户图表分类失败, Err: "+e.Error(), c)
+		return
+	}
+	item.MyChartClassifyName = req.ClassifyName
+	item.ModifyTime = time.Now().Local()
+	if e = item.Update([]string{"MyChartClassifyName", "ModifyTime"}); e != nil {
+		response.FailMsg("操作失败", "编辑用户图表分类失败, Err: "+e.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
+}
+
+func (this *MyChartClassifyController) Del(c *gin.Context) {
+	userInfo := userService.GetInfoByClaims(c)
+	userId := int(userInfo.UserID)
+	if userId <= 0 {
+		response.Fail("请登录后操作", c)
+		return
+	}
+	var req request.MyChartClassifyDelReq
+	if c.ShouldBind(&req) != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if req.ClassifyId <= 0 {
+		response.Fail("请选择分类", c)
+		return
+	}
+
+	ob := new(yb_my_chart_classify.YbMyChartClassify)
+	item, e := ob.Fetch(req.ClassifyId)
+	if e != nil {
+		response.FailMsg("分类不存在或已被删除", "获取用户图表分类失败, Err: "+e.Error(), c)
+		return
+	}
+	if item.UserID != userId {
+		response.Fail("无权操作", c)
+		return
+	}
+	// 是否存在关联图表
+	condRelate := `my_chart_classify_id = ?`
+	parsRelate := make([]interface{}, 0)
+	parsRelate = append(parsRelate, req.ClassifyId)
+	chartOB := new(yb_my_chart.YbMyChart)
+	count, e := chartOB.Count(condRelate, parsRelate)
+	if e != nil {
+		response.FailMsg("操作失败", "获取用户图表分类关联数失败, Err: "+e.Error(), c)
+		return
+	}
+	if count > 0 {
+		response.SpecificFail("", "删除失败, 该分类下有图表", c)
+		return
+	}
+	if e = item.Delete(); e != nil {
+		response.FailMsg("操作失败", "删除分类失败, Err: "+e.Error(), c)
+		return
+	}
+	response.Ok("操作成功", c)
+}
+
+func (this *MyChartClassifyController) Sort(c *gin.Context) {
+	userInfo := userService.GetInfoByClaims(c)
+	userId := int(userInfo.UserID)
+	if userId <= 0 {
+		response.Fail("请登录后操作", c)
+		return
+	}
+	var req []request.MyChartClassifySortReq
+	if c.ShouldBind(&req) != nil {
+		response.Fail("参数有误", c)
+		return
+	}
+	if len(req) == 0 {
+		response.Fail("请选择排序分类", c)
+		return
+	}
+	sortMap := make(map[int]int)
+	classifyIds := make([]int, 0)
+	for i := range req {
+		classifyIds = append(classifyIds, req[i].ClassifyId)
+		sortMap[req[i].ClassifyId] = req[i].Sort
+	}
+
+	cond := `my_chart_classify_id IN ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, classifyIds)
+	ob := new(yb_my_chart_classify.YbMyChartClassify)
+	list, e := ob.List(cond, pars)
+	if e != nil {
+		response.FailMsg("操作失败", "获取用户分类列表失败, Err: "+e.Error(), c)
+		return
+	}
+	nowTime := time.Now().Local()
+	updateCols := []string{"Sort", "ModifyTime"}
+	for i := range list {
+		list[i].Sort = sortMap[list[i].MyChartClassifyID]
+		list[i].ModifyTime = nowTime
+		if e = list[i].Update(updateCols); e != nil {
+			response.FailMsg("操作失败", "更新用户分类排序失败, Err: "+e.Error(), c)
+			return
+		}
+	}
+	response.Ok("操作成功", c)
+}

+ 2 - 0
init_serve/router.go

@@ -77,5 +77,7 @@ func InitRouter() (r *gin.Engine) {
 	routers.InitCollection(r)
 	// 弹幕路由
 	routers.InitBulletChat(r)
+	// 我的图表
+	routers.InitMyChart(r)
 	return
 }

+ 50 - 0
models/request/my_chart.go

@@ -0,0 +1,50 @@
+package request
+
+type MyChartClassifyAddReq struct {
+	ClassifyName string `json:"classify_name"`
+}
+
+type MyChartClassifyEditReq struct {
+	ClassifyId   int    `json:"classify_id"`
+	ClassifyName string `json:"classify_name"`
+}
+
+type MyChartClassifyDelReq struct {
+	ClassifyId int `json:"classify_id"`
+}
+
+type MyChartClassifySortReq struct {
+	ClassifyId int `json:"classify_id"`
+	Sort       int `json:"sort"`
+}
+
+type MyChartRelateClassifyReq struct {
+	MyChartId  int `json:"my_chart_id"`
+	ClassifyId int `json:"classify_id"`
+}
+
+type MyChartCollectReq struct {
+	Authorization   string `json:"authorization" form:"authorization"`
+	UniqueCode      string `json:"unique_code" form:"unique_code"`
+	ReportId        int    `json:"report_id" form:"report_id"`
+	ReportChapterId int    `json:"report_chapter_id" form:"report_chapter_id"`
+}
+
+type MyChartCollectCancelReq struct {
+	Authorization string `json:"authorization" form:"authorization"`
+	UniqueCode    string `json:"unique_code" form:"unique_code"`
+}
+
+type MyChartIsCollectReq struct {
+	Authorization string `json:"authorization" form:"authorization"`
+	UniqueCode    string `json:"unique_code" form:"unique_code"`
+	//ReportId        int    `json:"report_id" form:"report_id"`
+	//ReportChapterId int    `json:"report_chapter_id" form:"report_chapter_id"`
+}
+
+type MyChartCollectListReq struct {
+	Keyword    string `json:"keyword" form:"keyword" description:"关键词"`
+	ClassifyId int    `json:"classify_id" form:"classify_id" description:"图表分类ID"`
+	CurrPage   int    `json:"curr_page" form:"curr_page"`
+	PageSize   int    `json:"page_size" form:"page_size"`
+}

+ 2 - 0
models/response/chart_info/chart_info.go

@@ -1,6 +1,7 @@
 package chart_info
 
 import (
+	responseModel "hongze/hongze_yb/models/response"
 	"hongze/hongze_yb/models/tables/chart_edb_mapping"
 	"hongze/hongze_yb/models/tables/chart_info"
 )
@@ -10,6 +11,7 @@ type ChartInfoDetailResp struct {
 	EdbInfoList []*chart_edb_mapping.ChartEdbInfoMappingList
 	XEdbIdValue []int   `description:"柱方图的x轴数据,指标id"`
 	YDataList   []YData `description:"柱方图的y轴数据"`
+	MyChartInfo *responseModel.MyChartItem
 }
 
 // YData 柱方图的y轴数据

+ 29 - 0
models/response/my_chart.go

@@ -0,0 +1,29 @@
+package response
+
+// MyChartClassifyItem 用户图表分类
+type MyChartClassifyItem struct {
+	MyChartClassifyID   int    `json:"my_chart_classify_id"`
+	MyChartClassifyName string `json:"my_chart_classify_name"`
+	Sort                int    `json:"sort"`
+	UserID              int    `json:"user_id"`
+	CreateTime          string `json:"create_time"`
+}
+
+// MyChartItem 用户图表
+type MyChartItem struct {
+	MyChartID         int    `json:"my_chart_id"`
+	MyChartClassifyID int    `json:"my_chart_classify_id"`
+	ChartInfoID       int    `json:"chart_info_id"`
+	ChartName         string `json:"chart_name"`
+	UniqueCode        string `json:"unique_code"`
+	ChartImage        string `json:"chart_image"`
+	UserID            int    `json:"user_id"`
+	ReportID          int    `json:"report_id"`
+	ReportChapterID   int    `json:"report_chapter_id"`
+	CreateTime        string `json:"create_time"`
+}
+
+type MyChartListResp struct {
+	List   []*MyChartItem `json:"list"`
+	Paging *PagingItem    `json:"paging"`
+}

+ 7 - 0
models/tables/chart_info/query.go

@@ -101,3 +101,10 @@ func GetChartInfoById(chartInfoId int) (item *ChartInfo, err error) {
 	err = global.MYSQL["data"].Model(ChartInfo{}).Where("chart_info_id = ?", chartInfoId).First(&item).Error
 	return
 }
+
+// GetChartInfoViewByUniqueCode 通过唯一编码获取图表展示信息
+func GetChartInfoViewByUniqueCode(uniqueCode string) (item *ChartInfoView, err error) {
+	sql := `SELECT * FROM chart_info WHERE unique_code = ? LIMIT 1`
+	err = global.MYSQL["data"].Raw(sql, uniqueCode).First(&item).Error
+	return
+}

+ 1 - 1
models/tables/rddp/session/session.go

@@ -4,7 +4,7 @@ import "time"
 
 // Session [...]
 type Session struct {
-	SessionID       int64     `gorm:"primaryKey;column:session_id;type:bigint(12);not null" json:"-"`
+	SessionID       int64     `gorm:"primaryKey;column:session_id;type:bigint(12);not null" json:"sessionId"`
 	UserID          int64     `gorm:"index:session_user;column:user_id;type:bigint(20);not null" json:"userId"`
 	OpenID          string    `gorm:"column:open_id;type:varchar(32);not null" json:"openId"` // openid
 	AccessToken     string    `gorm:"index:session_token;column:access_token;type:varchar(64);not null" json:"accessToken"`

+ 4 - 0
models/tables/yb_config/entity.go

@@ -15,3 +15,7 @@ type YbConfig struct {
 func (m *YbConfig) TableName() string {
 	return "yb_config"
 }
+
+const (
+	UserChartCollectMax = "user_chart_collect_max" // 用户图表收藏上限
+)

+ 53 - 0
models/tables/yb_my_chart/entity.go

@@ -0,0 +1,53 @@
+package yb_my_chart
+
+import "time"
+
+// YbMyChart 研报-我的图表
+type YbMyChart struct {
+	MyChartID         int       `gorm:"primaryKey;column:my_chart_id;type:int(10) unsigned;not null" json:"myChartId"`
+	MyChartClassifyID int       `gorm:"index:idx_classify_id;column:my_chart_classify_id;type:int(10) unsigned;not null;default:0" json:"myChartClassifyId"` // 图表分类ID
+	ChartInfoID       int       `gorm:"column:chart_info_id;type:int(10) unsigned;not null;default:0" json:"chartInfoId"`                                    // 图表ID
+	ChartName         string    `gorm:"column:chart_name;type:varchar(255);not null;default:''" json:"chartName"`                                            // 图表名称
+	UniqueCode        string    `gorm:"column:unique_code;type:varchar(64);not null;default:''" json:"uniqueCode"`                                           // 图表唯一编码
+	ChartImage        string    `gorm:"column:chart_image;type:varchar(255);not null;default:''" json:"chartImage"`                                          // 图表图片
+	UserID            int       `gorm:"index:idx_user_id;column:user_id;type:int(10) unsigned;not null;default:0" json:"userId"`                             // 用户ID
+	ReportID          int       `gorm:"column:report_id;type:int(10) unsigned;not null;default:0" json:"reportId"`                                           // 报告ID(从哪个报告收藏的)
+	ReportChapterID   int       `gorm:"column:report_chapter_id;type:int(10) unsigned;not null;default:0" json:"reportChapterId"`                            // 报告章节ID
+	Source            int       `gorm:"column:source;type:tinyint(4) unsigned;not null;default:1" json:"source"`                                             // 1-ETA图库;2-ETA表格
+	CreateTime        time.Time `gorm:"column:create_time;type:datetime" json:"createTime"`
+	ModifyTime        time.Time `gorm:"column:modify_time;type:datetime" json:"modifyTime"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbMyChart) TableName() string {
+	return "yb_my_chart"
+}
+
+// YbMyChartColumns get sql column name.获取数据库列名
+var YbMyChartColumns = struct {
+	MyChartID         string
+	MyChartClassifyID string
+	ChartInfoID       string
+	ChartName         string
+	UniqueCode        string
+	ChartImage        string
+	UserID            string
+	ReportID          string
+	ReportChapterID   string
+	Source            string
+	CreateTime        string
+	ModifyTime        string
+}{
+	MyChartID:         "my_chart_id",
+	MyChartClassifyID: "my_chart_classify_id",
+	ChartInfoID:       "chart_info_id",
+	ChartName:         "chart_name",
+	UniqueCode:        "unique_code",
+	ChartImage:        "chart_image",
+	UserID:            "user_id",
+	ReportID:          "report_id",
+	ReportChapterID:   "report_chapter_id",
+	Source:            "source",
+	CreateTime:        "create_time",
+	ModifyTime:        "modify_time",
+}

+ 56 - 0
models/tables/yb_my_chart/model.go

@@ -0,0 +1,56 @@
+package yb_my_chart
+
+import "hongze/hongze_yb/global"
+
+func (m *YbMyChart) Count(condition string, pars []interface{}) (num int64, err error) {
+	err = global.DEFAULT_MYSQL.Model(m).
+		Where(condition, pars...).
+		Count(&num).Error
+	return
+}
+
+func (m *YbMyChart) Create() (err error) {
+	err = global.DEFAULT_MYSQL.Create(m).Error
+	return
+}
+
+func (m *YbMyChart) Update(updateCols []string) (err error) {
+	err = global.DEFAULT_MYSQL.Model(m).Select(updateCols).Updates(m).Error
+	return
+}
+
+func (m *YbMyChart) List(condition string, pars []interface{}) (list []*YbMyChart, err error) {
+	list = make([]*YbMyChart, 0)
+	err = global.DEFAULT_MYSQL.Model(m).
+		Where(condition, pars...).
+		Order("create_time DESC").
+		Find(&list).Error
+	return
+}
+
+func (m *YbMyChart) PageList(condition string, pars []interface{}, pageIndex, pageSize int) (list []*YbMyChart, err error) {
+	offset := (pageIndex - 1) * pageSize
+	err = global.DEFAULT_MYSQL.Model(m).
+		Where(condition, pars...).
+		Offset(offset).Limit(pageSize).
+		Order("create_time DESC").
+		Scan(&list).Error
+	return
+}
+
+func (m *YbMyChart) Fetch(id int) (item *YbMyChart, err error) {
+	err = global.DEFAULT_MYSQL.Model(m).Where("my_chart_id = ?", id).First(&item).Error
+	return
+}
+
+func (m *YbMyChart) FetchByCondition(condition string, pars []interface{}) (item *YbMyChart, err error) {
+	err = global.DEFAULT_MYSQL.Model(m).
+		Where(condition, pars...).
+		First(&item).Error
+	return
+}
+
+func (m *YbMyChart) Delete() (err error) {
+	err = global.DEFAULT_MYSQL.Delete(m).Error
+	return
+}

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

@@ -0,0 +1,35 @@
+package yb_my_chart_classify
+
+import "time"
+
+// YbMyChartClassify 研报-我的图表分类
+type YbMyChartClassify struct {
+	MyChartClassifyID   int       `gorm:"primaryKey;column:my_chart_classify_id;type:int(10) unsigned;not null" json:"my_chart_classify_id"`
+	MyChartClassifyName string    `gorm:"column:my_chart_classify_name;type:varchar(255);not null;default:''" json:"my_chart_classify_name"` // 分类名称
+	UserID              int       `gorm:"index:idx_user_id;column:user_id;type:int(10) unsigned;not null;default:0" json:"user_id"`          // 用户ID
+	Sort                int       `gorm:"column:sort;type:int(10) unsigned;not null;default:0" json:"sort"`                                  // 排序
+	CreateTime          time.Time `gorm:"column:create_time;type:datetime" json:"create_time"`
+	ModifyTime          time.Time `gorm:"column:modify_time;type:datetime" json:"modify_time"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *YbMyChartClassify) TableName() string {
+	return "yb_my_chart_classify"
+}
+
+// YbMyChartClassifyColumns get sql column name.获取数据库列名
+var YbMyChartClassifyColumns = struct {
+	MyChartClassifyID   string
+	MyChartClassifyName string
+	UserID              string
+	Sort                string
+	CreateTime          string
+	ModifyTime          string
+}{
+	MyChartClassifyID:   "my_chart_classify_id",
+	MyChartClassifyName: "my_chart_classify_name",
+	UserID:              "user_id",
+	Sort:                "sort",
+	CreateTime:          "create_time",
+	ModifyTime:          "modify_time",
+}

+ 39 - 0
models/tables/yb_my_chart_classify/model.go

@@ -0,0 +1,39 @@
+package yb_my_chart_classify
+
+import "hongze/hongze_yb/global"
+
+func (m *YbMyChartClassify) Create() (err error) {
+	err = global.DEFAULT_MYSQL.Create(m).Error
+	return
+}
+
+func (m *YbMyChartClassify) Update(updateCols []string) (err error) {
+	err = global.DEFAULT_MYSQL.Model(m).Select(updateCols).Updates(m).Error
+	return
+}
+
+func (m *YbMyChartClassify) List(condition string, pars []interface{}) (list []*YbMyChartClassify, err error) {
+	list = make([]*YbMyChartClassify, 0)
+	err = global.DEFAULT_MYSQL.Model(m).
+		Where(condition, pars...).
+		Order("sort ASC, my_chart_classify_id ASC").
+		Find(&list).Error
+	return
+}
+
+func (m *YbMyChartClassify) Fetch(id int) (item *YbMyChartClassify, err error) {
+	err = global.DEFAULT_MYSQL.Model(m).Where("my_chart_classify_id = ?", id).First(&item).Error
+	return
+}
+
+func (m *YbMyChartClassify) FetchByCondition(condition string, pars []interface{}) (item *YbMyChartClassify, err error) {
+	err = global.DEFAULT_MYSQL.Model(m).
+		Where(condition, pars...).
+		First(&item).Error
+	return
+}
+
+func (m *YbMyChartClassify) Delete() (err error) {
+	err = global.DEFAULT_MYSQL.Delete(m).Error
+	return
+}

+ 35 - 0
routers/my_chart.go

@@ -0,0 +1,35 @@
+package routers
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/hongze_yb/controller/chart"
+	"hongze/hongze_yb/controller/my_chart"
+	"hongze/hongze_yb/middleware"
+)
+
+func InitMyChart(r *gin.Engine) {
+	rg := r.Group("api/")
+	// 图表分类
+	mcc := new(my_chart.MyChartClassifyController)
+	mccGroup := rg.Group("my_chart_classify/").Use(middleware.Token())
+	mccGroup.GET("list", mcc.List)
+	mccGroup.POST("add", mcc.Add)
+	mccGroup.POST("edit", mcc.Edit)
+	mccGroup.POST("sort", mcc.Sort)
+	mccGroup.POST("del", mcc.Del)
+
+	// 我的图表
+	mc := new(my_chart.MyChartController)
+	mcGroup := rg.Group("my_chart/").Use(middleware.Token())
+	mcGroup.GET("list", mc.List)
+	mcGroup.POST("relate_classify", mc.RelateClassify)
+
+	//mcGroupAuth := rg.Group("my_chart/").Use(middleware.Token(), middleware.CheckBaseAuth())
+	mcGroup.GET("detail", chart.GetChartInfoDetail)
+
+	// 以下接口可能是从iframe发出请求, 所以token被放在入参中处理而不是header里
+	mcGroupNo := rg.Group("my_chart/")
+	mcGroupNo.POST("collect", mc.Collect)
+	mcGroupNo.POST("collect_cancel", mc.CollectCancel)
+	mcGroupNo.GET("is_collect", mc.IsCollect)
+}

+ 30 - 0
services/user/user.go

@@ -478,3 +478,33 @@ func GetResearcherByUserInfo(userInfo UserInfo) (ok bool, adminInfo *admin2.Admi
 
 	return
 }
+
+// GetUserInfoByToken 通过token获取用户信息
+func GetUserInfoByToken(token string) (userInfo UserInfo, err error) {
+	sessionInfo, e := session.GetTokenByToken(token)
+	if e != nil {
+		err = errors.New("找不到对应session")
+		return
+	}
+	if sessionInfo.SessionID <= 0 {
+		err = errors.New("找不到对应session")
+		return
+	}
+	if sessionInfo.OpenID != "" {
+		u, e := GetWxUserItemByOpenId(sessionInfo.OpenID)
+		if e != nil {
+			err = errors.New("用户记录不存在或未绑定")
+			return
+		}
+		userInfo = u
+	} else {
+		// PC端
+		u, e := GetWxUserItemByUserId(int(sessionInfo.UserID), utils.USER_RECORD_PLATFORM_PC)
+		if e != nil {
+			err = errors.New("用户PC记录不存在或未绑定")
+			return
+		}
+		userInfo = u
+	}
+	return
+}

+ 9 - 0
utils/common.go

@@ -1076,3 +1076,12 @@ func (ms MapSorter) Less(i, j int) bool {
 func (ms MapSorter) Swap(i, j int) {
 	ms[i], ms[j] = ms[j], ms[i]
 }
+
+func TimeTransferString(format string, t time.Time) string {
+	str := t.Format(format)
+	var emptyT time.Time
+	if str == emptyT.Format(format) {
+		return ""
+	}
+	return str
+}