Эх сурвалжийг харах

Merge branch 'feature/eta_forum3_chart_classify' of eta_server/eta_api into master

xyxie 1 сар өмнө
parent
commit
8a66dcb31d

+ 358 - 133
controllers/data_manage/chart_classify.go

@@ -8,6 +8,7 @@ import (
 	"eta/eta_api/models/system"
 	"eta/eta_api/services/data"
 	"eta/eta_api/services/data/data_manage_permission"
+	"eta/eta_api/services/eta_forum"
 	"eta/eta_api/utils"
 	"fmt"
 	"time"
@@ -381,7 +382,7 @@ func (this *ChartClassifyController) AddChartClassify() {
 	}
 
 	// 新增图表分类
-	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_DEFAULT, this.Lang, this.SysUser)
+	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_DEFAULT, req.IsSelected, this.Lang, this.SysUser)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = "添加分类失败,Err:" + err.Error()
@@ -426,18 +427,35 @@ func (this *ChartClassifyController) EditChartClassify() {
 	}
 
 	// 编辑图表分类
-	_, err, errMsg, isSendEmail := data.EditChartClassifyV2(req.ChartClassifyId, req.ParentId, utils.CHART_SOURCE_DEFAULT, req.ChartClassifyName, this.Lang)
+	classifyInfo, isDeleteForumChart, tipCode, err, errMsg, isSendEmail := data.EditChartClassifyV2(req.ChartClassifyId, req.ParentId, utils.CHART_SOURCE_DEFAULT, req.ChartClassifyName, req.IsSelected, this.Lang)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = "保存分类失败,Err:" + err.Error()
 		br.IsSendEmail = isSendEmail
 		return
 	}
+	var ret data_manage.EditChartClassifyResp
+	if tipCode != "" {
+		br.Ret = 200
+		br.Msg = "该分类下存在已上架的图表,请先将图表从资源库下架,再关闭该精选资源分类。"
+		ret.TipCode = tipCode
+		ret.TipMsg = "该分类下存在已上架的图表,请先将图表从资源库下架,再关闭该精选资源分类。"
+		br.IsSendEmail = false
+		br.Success = true
+		br.Data = ret
+		return
+	}
+
+	// 移除精选后,删除所有的图表
+	if isDeleteForumChart {
+		go eta_forum.ChartInfoDeleteBatch(classifyInfo, this.SysUser)
+	}
 
 	br.Ret = 200
 	br.Msg = "保存成功"
 	br.Success = true
 	br.IsAddLog = true
+	br.Data = ret
 }
 
 // @Title 删除图表检测接口
@@ -523,6 +541,24 @@ func (this *ChartClassifyController) DeleteChartClassifyCheck() {
 		tipsMsg = "可删除,进行删除操作"
 	}
 
+	if req.ChartInfoId > 0 {
+		chartInfo, err := data_manage.GetChartInfoById(req.ChartInfoId)
+		if err != nil {
+			if utils.IsErrNoRow(err) {
+				br.Msg = "图表已删除,请刷新页面"
+				br.ErrMsg = "指标不存在,Err:" + err.Error()
+				return
+			}
+			br.Msg = "删除失败"
+			br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+			return
+		}
+		if chartInfo.ForumChartInfoId > 0 {
+			deleteStatus = 3
+			tipsMsg = "删除后,该图表将从ETA投研资源库同步删除,影响客户的查看权限,是否确认删除?"
+		}
+	}
+
 	resp := new(data_manage.ChartClassifyDeleteCheckResp)
 	resp.DeleteStatus = deleteStatus
 	resp.TipsMsg = tipsMsg
@@ -614,6 +650,8 @@ func (this *ChartClassifyController) DeleteChartClassify() {
 			br.ErrMsg = "删除失败,Err:" + err.Error()
 			return
 		}
+
+		go eta_forum.ChartClassifySaveBatch(item.Source)
 	}
 	resp := new(data_manage.AddChartInfoResp)
 	//删除图表
@@ -699,6 +737,10 @@ func (this *ChartClassifyController) DeleteChartClassify() {
 			// 删除MY ETA 图表 es数据
 			//go data.EsDeleteMyChartInfoByChartInfoId(req.ChartInfoId)
 			go data.EsDeleteMyChartInfoByMyChartIds(myIds)
+			
+			if chartInfo.ForumChartInfoId > 0 {
+				go eta_forum.DeleteChartByForumChartInfoId(chartInfo.ForumChartInfoId)
+			}
 		}
 
 		var condition string
@@ -795,7 +837,6 @@ func (this *ChartClassifyController) ChartClassifyMove() {
 		br.Ret = 408
 		return
 	}
-
 	var req data_manage.MoveChartClassifyReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
@@ -803,141 +844,197 @@ func (this *ChartClassifyController) ChartClassifyMove() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
-
-	if req.ClassifyId <= 0 {
+	if req.ClassifyId <= 0 && req.ChartInfoId <= 0 {
 		br.Msg = "参数错误"
-		br.ErrMsg = "分类id小于等于0"
-		return
-	}
-	//判断分类是否存在
-	chartClassifyInfo, err := data_manage.GetChartClassifyById(req.ClassifyId)
-	if err != nil {
-		if utils.IsErrNoRow(err) {
-			br.Msg = "分类不存在,请刷新页面"
-			return
-		}
-		br.Msg = "移动失败"
-		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
-		return
-	}
-
-	// 校验移动的父级目录下是否有重名分类
-	exists, e := data_manage.GetChartClassifyByParentIdAndName(req.ParentClassifyId, chartClassifyInfo.ChartClassifyName, req.ClassifyId)
-	if e != nil && !utils.IsErrNoRow(e) {
-		br.Msg = "移动失败"
-		br.ErrMsg = "获取父级目录下的同名分类失败, Err: " + e.Error()
-		return
-	}
-	if exists != nil && exists.ChartClassifyId > 0 {
-		br.Msg = "移动失败,分类名称已存在"
-		return
-	}
-	// 已授权分类id
-	permissionClassifyIdList, err := data_manage_permission.GetUserChartClassifyPermissionList(this.SysUser.AdminId, chartClassifyInfo.ChartClassifyId)
-	if err != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取已授权分类id数据失败,Err:" + err.Error()
+		br.ErrMsg = "请选择拖动目标,分类目录或者指标"
 		return
 	}
-	// 权限校验
-	{
-		haveOperaAuth := data_manage_permission.CheckEdbClassifyPermissionByPermissionIdList(chartClassifyInfo.IsJoinPermission, chartClassifyInfo.ChartClassifyId, permissionClassifyIdList)
 
-		button := data.GetChartClassifyOpButton(this.SysUser, chartClassifyInfo.SysUserId, haveOperaAuth)
-		if !button.OpButton {
-			br.Msg = "无操作权限"
+	err, errMsg := data.MoveChartClassify(req, sysUser, utils.CHART_SOURCE_DEFAULT)
+	if errMsg != `` {
+		br.Msg = errMsg
+		br.ErrMsg = errMsg
+		if err != nil {
+			br.ErrMsg = err.Error()
+		} else {
 			br.IsSendEmail = false
-			return
 		}
-	}
-
-	if chartClassifyInfo.Source != utils.CHART_SOURCE_DEFAULT {
-		br.Msg = "分类异常"
-		br.ErrMsg = "分类异常,不是ETA图库的分类"
 		return
 	}
-	updateCol := make([]string, 0)
-
-	//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
-	if chartClassifyInfo.ParentId != req.ParentClassifyId && req.ParentClassifyId != 0 {
-		parentChartClassifyInfo, err := data_manage.GetChartClassifyById(req.ParentClassifyId)
-		if err != nil {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取上级分类信息失败,Err:" + err.Error()
-			return
-		}
-		chartClassifyInfo.ParentId = parentChartClassifyInfo.ChartClassifyId
-		chartClassifyInfo.Level = parentChartClassifyInfo.Level + 1
-		chartClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
-	}
-
-	//如果有传入 上一个兄弟节点分类id
-	if req.PrevClassifyId > 0 {
-		//上一个兄弟节点
-		prevClassify, err := data_manage.GetChartClassifyById(req.PrevClassifyId)
-		if err != nil {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
-			return
-		}
-
-		//如果是移动在两个兄弟节点之间
-		if req.NextClassifyId > 0 {
-			//下一个兄弟节点
-			nextClassify, err := data_manage.GetChartClassifyById(req.NextClassifyId)
-			if err != nil {
-				br.Msg = "移动失败"
-				br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
-				return
-			}
-			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
-			if prevClassify.Sort == nextClassify.Sort || prevClassify.Sort == chartClassifyInfo.Sort {
-				//变更兄弟节点的排序
-				updateSortStr := `sort + 2`
-				_ = data_manage.UpdateChartClassifySortByParentId(prevClassify.ParentId, prevClassify.ChartClassifyId, prevClassify.Sort, updateSortStr)
-			} else {
-				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
-				if nextClassify.Sort-prevClassify.Sort == 1 {
-					//变更兄弟节点的排序
-					updateSortStr := `sort + 1`
-					_ = data_manage.UpdateChartClassifySortByParentId(prevClassify.ParentId, 0, prevClassify.Sort, updateSortStr)
-				}
-			}
-		}
-
-		chartClassifyInfo.Sort = prevClassify.Sort + 1
-		chartClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
-
-	} else {
-		firstClassify, err := data_manage.GetFirstChartClassifyByParentId(chartClassifyInfo.ParentId)
-		if err != nil && !utils.IsErrNoRow(err) {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
-			return
-		}
-
-		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
-		if firstClassify != nil && firstClassify.Sort == 0 {
-			updateSortStr := ` sort + 1 `
-			_ = data_manage.UpdateChartClassifySortByParentId(firstClassify.ParentId, firstClassify.ChartClassifyId-1, 0, updateSortStr)
-		}
-
-		chartClassifyInfo.Sort = 0 //那就是排在第一位
-		chartClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
-	}
-
-	//更新
-	if len(updateCol) > 0 {
-		err = chartClassifyInfo.Update(updateCol)
-		if err != nil {
-			br.Msg = "移动失败"
-			br.ErrMsg = "修改失败,Err:" + err.Error()
-			return
-		}
-	}
+	// var req data_manage.MoveChartClassifyReq
+	// err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	// if err != nil {
+	// 	br.Msg = "参数解析异常!"
+	// 	br.ErrMsg = "参数解析失败,Err:" + err.Error()
+	// 	return
+	// }
+
+	// if req.ClassifyId <= 0 {
+	// 	br.Msg = "参数错误"
+	// 	br.ErrMsg = "分类id小于等于0"
+	// 	return
+	// }
+	// //判断分类是否存在
+	// chartClassifyInfo, err := data_manage.GetChartClassifyById(req.ClassifyId)
+	// if err != nil {
+	// 	if utils.IsErrNoRow(err) {
+	// 		br.Msg = "分类不存在,请刷新页面"
+	// 		return
+	// 	}
+	// 	br.Msg = "移动失败"
+	// 	br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+	// 	return
+	// }
+	// oldParentId := chartClassifyInfo.ParentId
+	// oldLevelPath := chartClassifyInfo.LevelPath
+	// oldSelected := chartClassifyInfo.IsSelected
+
+	// // 校验移动的父级目录下是否有重名分类
+	// exists, e := data_manage.GetChartClassifyByParentIdAndName(req.ParentClassifyId, chartClassifyInfo.ChartClassifyName, req.ClassifyId)
+	// if e != nil && !utils.IsErrNoRow(e) {
+	// 	br.Msg = "移动失败"
+	// 	br.ErrMsg = "获取父级目录下的同名分类失败, Err: " + e.Error()
+	// 	return
+	// }
+	// if exists != nil && exists.ChartClassifyId > 0 {
+	// 	br.Msg = "移动失败,分类名称已存在"
+	// 	return
+	// }
+	// // 已授权分类id
+	// permissionClassifyIdList, err := data_manage_permission.GetUserChartClassifyPermissionList(this.SysUser.AdminId, chartClassifyInfo.ChartClassifyId)
+	// if err != nil {
+	// 	br.Msg = "获取失败"
+	// 	br.ErrMsg = "获取已授权分类id数据失败,Err:" + err.Error()
+	// 	return
+	// }
+	// // 权限校验
+	// {
+	// 	haveOperaAuth := data_manage_permission.CheckEdbClassifyPermissionByPermissionIdList(chartClassifyInfo.IsJoinPermission, chartClassifyInfo.ChartClassifyId, permissionClassifyIdList)
+
+	// 	button := data.GetChartClassifyOpButton(this.SysUser, chartClassifyInfo.SysUserId, haveOperaAuth)
+	// 	if !button.OpButton {
+	// 		br.Msg = "无操作权限"
+	// 		br.IsSendEmail = false
+	// 		return
+	// 	}
+	// }
+
+	// if chartClassifyInfo.Source != utils.CHART_SOURCE_DEFAULT {
+	// 	br.Msg = "分类异常"
+	// 	br.ErrMsg = "分类异常,不是ETA图库的分类"
+	// 	return
+	// }
+	// updateCol := make([]string, 0)
+
+	// var parentChartClassifyInfo *data_manage.ChartClassify
+	// if req.ParentClassifyId > 0 {
+	// 	parentChartClassifyInfo, err = data_manage.GetChartClassifyById(req.ParentClassifyId)
+	// 	if err != nil {
+	// 		br.Msg = "移动失败"
+	// 		br.ErrMsg = "获取上级分类信息失败,Err:" + err.Error()
+	// 		return
+	// 	}
+	// }
+	// //判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
+	// if chartClassifyInfo.ParentId != req.ParentClassifyId && req.ParentClassifyId != 0 {
+	// 	if chartClassifyInfo.Level != parentChartClassifyInfo.Level+1 { //禁止层级调整
+	// 		br.Msg = "移动失败"
+	// 		br.ErrMsg = "不支持目录层级变更"
+	// 		return
+	// 	}
+	// 	chartClassifyInfo.ParentId = parentChartClassifyInfo.ChartClassifyId
+	// 	chartClassifyInfo.Level = parentChartClassifyInfo.Level + 1
+	// 	chartClassifyInfo.ModifyTime = time.Now()
+	// 	updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
+	// }else if chartClassifyInfo.ParentId != req.ParentClassifyId && req.ParentClassifyId == 0 {
+	// 	br.Msg = "移动失败"
+	// 	br.ErrMsg = "不支持目录层级变更"
+	// 	return
+	// }
+
+	// //如果有传入 上一个兄弟节点分类id
+	// if req.PrevClassifyId > 0 {
+	// 	//上一个兄弟节点
+	// 	prevClassify, err := data_manage.GetChartClassifyById(req.PrevClassifyId)
+	// 	if err != nil {
+	// 		br.Msg = "移动失败"
+	// 		br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
+	// 		return
+	// 	}
+
+	// 	//如果是移动在两个兄弟节点之间
+	// 	if req.NextClassifyId > 0 {
+	// 		//下一个兄弟节点
+	// 		nextClassify, err := data_manage.GetChartClassifyById(req.NextClassifyId)
+	// 		if err != nil {
+	// 			br.Msg = "移动失败"
+	// 			br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+	// 			return
+	// 		}
+	// 		//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+	// 		if prevClassify.Sort == nextClassify.Sort || prevClassify.Sort == chartClassifyInfo.Sort {
+	// 			//变更兄弟节点的排序
+	// 			updateSortStr := `sort + 2`
+	// 			_ = data_manage.UpdateChartClassifySortByParentId(prevClassify.ParentId, prevClassify.ChartClassifyId, prevClassify.Sort, updateSortStr)
+	// 		} else {
+	// 			//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+	// 			if nextClassify.Sort-prevClassify.Sort == 1 {
+	// 				//变更兄弟节点的排序
+	// 				updateSortStr := `sort + 1`
+	// 				_ = data_manage.UpdateChartClassifySortByParentId(prevClassify.ParentId, 0, prevClassify.Sort, updateSortStr)
+	// 			}
+	// 		}
+	// 	}
+
+	// 	chartClassifyInfo.Sort = prevClassify.Sort + 1
+	// 	chartClassifyInfo.ModifyTime = time.Now()
+	// 	updateCol = append(updateCol, "Sort", "ModifyTime")
+
+	// } else {
+	// 	firstClassify, err := data_manage.GetFirstChartClassifyByParentId(chartClassifyInfo.ParentId)
+	// 	if err != nil && !utils.IsErrNoRow(err) {
+	// 		br.Msg = "移动失败"
+	// 		br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
+	// 		return
+	// 	}
+
+	// 	//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+	// 	if firstClassify != nil && firstClassify.Sort == 0 {
+	// 		updateSortStr := ` sort + 1 `
+	// 		_ = data_manage.UpdateChartClassifySortByParentId(firstClassify.ParentId, firstClassify.ChartClassifyId-1, 0, updateSortStr)
+	// 	}
+
+	// 	chartClassifyInfo.Sort = 0 //那就是排在第一位
+	// 	chartClassifyInfo.ModifyTime = time.Now()
+	// 	updateCol = append(updateCol, "Sort", "ModifyTime")
+	// }
+
+	// //更新
+	// if len(updateCol) > 0 {
+	// 	err = chartClassifyInfo.Update(updateCol)
+	// 	if err != nil {
+	// 		br.Msg = "移动失败"
+	// 		br.ErrMsg = "修改失败,Err:" + err.Error()
+	// 		return
+	// 	}
+	// }
+	// if oldParentId != req.ParentClassifyId {
+	// 	if err = data.UpdateChartClassifyLevelPathWithChildren(chartClassifyInfo, parentChartClassifyInfo, oldParentId, oldLevelPath); err != nil {
+	// 		br.Msg = "修改分类失败"
+	// 		br.ErrMsg = "更新分类level_path失败,Err:" + err.Error()
+	// 		return
+	// 	}
+	// }
+	// // 如果是精选目录,则需要同步到ETA资源库
+	// if chartClassifyInfo.Source == utils.CHART_SOURCE_DEFAULT {
+	// 	// 如果当前目录的精选标识发生变化,需要同步更新子目录的精选标识
+	// 	if err = data.UpdateChildClassifySelection(chartClassifyInfo, parentChartClassifyInfo, oldSelected); err != nil {
+	// 		br.Msg = "修改分类失败"
+	// 		br.ErrMsg = "更新子目录精选标识失败,Err:" + err.Error()
+	// 		return
+	// 	}
+	// 	go eta_forum.ChartClassifySaveBatch(chartClassifyInfo.Source)
+	// }
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "移动成功"
@@ -1095,7 +1192,7 @@ func (this *ChartClassifyController) ChartClassifyChartListV3() {
 		br.Msg = "参数错误"
 		return
 	}
-
+	
 	// 获取当前账号的不可见指标
 	noPermissionChartIdMap := make(map[int]bool)
 	{
@@ -1111,9 +1208,20 @@ func (this *ChartClassifyController) ChartClassifyChartListV3() {
 		}
 	}
 	var allNodes []*data_manage.ChartClassifyItems
+	// 获取是否精选资源标识
+	isSelected, _ := this.GetInt("IsSelected")
+	if chartClassifyId > 0 {
+		chartClassifyInfo, err := data_manage.GetChartClassifyById(chartClassifyId)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+			return
+		}
+		isSelected = chartClassifyInfo.IsSelected
+	}
 	isShowMe, _ := this.GetBool("IsShowMe")
 	if isShowMe {
-		allChartInfo, err := data_manage.GetChartClassifyAndInfoByParentIdForMe(chartClassifyId, sysUser.AdminId)
+		allChartInfo, err := data_manage.GetChartClassifyAndInfoByParentIdForMe(chartClassifyId, sysUser.AdminId, isSelected)
 		if err != nil && !utils.IsErrNoRow(err) {
 			br.Msg = "获取失败"
 			br.ErrMsg = "获取数据失败,Err:" + err.Error()
@@ -1136,7 +1244,7 @@ func (this *ChartClassifyController) ChartClassifyChartListV3() {
 		//fmt.Println("source my classify")
 		//return
 	} else {
-		allChartInfo, err := data_manage.GetChartClassifyAndInfoByParentId(chartClassifyId)
+		allChartInfo, err := data_manage.GetChartClassifyAndInfoByParentId(chartClassifyId, isSelected)
 		if err != nil && err.Error() != utils.ErrNoRow() {
 			br.Msg = "获取失败"
 			br.ErrMsg = "获取数据失败,Err:" + err.Error()
@@ -1194,3 +1302,120 @@ func (this *ChartClassifyController) ChartClassifyChartListV3() {
 	br.Msg = "获取成功"
 	br.Data = resp
 }
+
+// SetChartClassifyResourceStatus
+// @Title 一键从资源库上架/下架
+// @Description 一键从资源库上架/下架
+// @Param   ChartClassifyId   query   bool  true       "图片分类id"
+// @Param   ResourceStatus   query   bool  true       "资源状态"
+// @Success 200 {object} models.BaseResponse
+// @router /chart_classify/resource_status [post]
+func (this *ChartClassifyController) SetChartClassifyResourceStatus() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req data_manage.SetChartClassifyResourceStatusReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	chartClassifyId := req.ChartClassifyId	
+	if chartClassifyId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	resourceStatus := req.ResourceStatus
+	if resourceStatus <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+
+	chartClassifyInfo, err := data_manage.GetChartClassifyById(chartClassifyId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+		return
+	}
+	if resourceStatus == utils.ChartClassifyResourceStatusDown {
+		errMsg, err := eta_forum.SetChartClassifyResourceStatusDown(chartClassifyInfo, this.SysUser)
+		if err != nil {
+			if errMsg != "" {
+				br.Msg = errMsg
+				br.ErrMsg = err.Error()
+				return
+			}
+			br.Msg = "操作失败"
+			br.ErrMsg = err.Error()
+			return
+		}
+	} else if resourceStatus == utils.ChartClassifyResourceStatusUp {
+		errMsg, err := eta_forum.SetChartClassifyResourceStatusUp(chartClassifyInfo, this.SysUser)
+		if err != nil {
+			if errMsg != "" {
+				br.Msg = errMsg
+				br.ErrMsg = err.Error()
+				return
+			}
+			br.Msg = "操作失败"
+			br.ErrMsg = err.Error()
+			return
+		}
+	}
+	
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+
+// 一键更新至资源库
+// @Title 一键更新至资源库
+// @Description 一键更新至资源库
+// @Param   ChartClassifyId   query   bool  true       "图片分类id"
+// @Success 200 {object} models.BaseResponse
+// @router /chart_classify/forum_chart/update [post]
+func (this *ChartClassifyController) UpdateChartClassifyResource() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req data_manage.ChartClassifyResourceUpdate
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	
+	chartClassifyInfo, err := data_manage.GetChartClassifyById(req.ChartClassifyId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+		return
+	}
+	if chartClassifyInfo.Source != utils.CHART_SOURCE_DEFAULT {
+		br.Msg = "分类来源错误"
+		return
+	}
+	if chartClassifyInfo.IsSelected != utils.ChartClassifyIsSelected {
+		br.Msg = "该分类不是精选分类"
+		return
+	}
+
+	err = eta_forum.ChartBatchUpdateAndUpload(chartClassifyInfo, this.SysUser)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+	
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 151 - 3
controllers/data_manage/chart_info.go

@@ -783,7 +783,7 @@ func (this *ChartInfoController) ChartInfoMove() {
 			return
 		}
 	}
-
+	oldClassifyId := chartInfo.ChartClassifyId
 	//如果改变了分类,那么移动该图表数据
 	if chartInfo.ChartClassifyId != req.ChartClassifyId {
 		//查询需要修改的分类下是否存在同一个图表名称
@@ -874,6 +874,20 @@ func (this *ChartInfoController) ChartInfoMove() {
 		}
 		//添加es数据
 		go data.EsAddOrEditChartInfo(chartInfo.ChartInfoId)
+
+		// 判断是否为精选目录
+			// 如果该目录不是精选目录,且该图表已经上架,则需撤回该图表
+			if oldClassifyId != req.ChartClassifyId {
+				parentChartClassifyInfo, err := data_manage.GetChartClassifyById(req.ChartClassifyId)
+				if err != nil {
+					br.Msg = "移动失败"
+					br.ErrMsg = "获取上级分类信息失败,Err:" + err.Error()
+					return
+				}
+				if parentChartClassifyInfo.IsSelected == 0 && chartInfo.ForumChartInfoId > 0 {
+					go eta_forum.DeleteChart(chartInfo.ChartInfoId)
+				}
+			}
 	}
 
 	if err != nil {
@@ -1601,6 +1615,7 @@ func (this *ChartInfoController) ChartInfoDetailV2() {
 	}
 
 	resp := new(data_manage.ChartInfoDetailResp)
+	isSelected := 0
 	// 图表数据权限
 	{
 		// 图表分类
@@ -1610,7 +1625,7 @@ func (this *ChartInfoController) ChartInfoDetailV2() {
 			br.ErrMsg = "获取图表分类信息失败,Err:" + err.Error()
 			return
 		}
-
+		isSelected = chartClassify.IsSelected
 		// 已授权分类id
 		permissionChartIdList, permissionClassifyIdList, err := data_manage_permission.GetUserChartAndClassifyPermissionList(this.SysUser.AdminId, chartInfo.ChartInfoId, chartInfo.ChartClassifyId)
 		if err != nil {
@@ -1818,6 +1833,7 @@ func (this *ChartInfoController) ChartInfoDetailV2() {
 	}
 
 	// 图表当前分类的分类树
+	
 	classifyLevels := make([]string, 0)
 	{
 		list, e := data_manage.GetChartClassifyAllBySource(utils.CHART_SOURCE_DEFAULT)
@@ -1836,6 +1852,7 @@ func (this *ChartInfoController) ChartInfoDetailV2() {
 	}
 
 	resp.ClassifyLevels = classifyLevels
+	resp.IsSelected = isSelected
 
 	//图表操作权限
 	chartInfo.IsEdit = data.CheckOpChartPermission(sysUser, chartInfo.SysUserId, chartInfo.HaveOperaAuth)
@@ -2358,7 +2375,7 @@ func (this *ChartInfoController) ChartInfoSearchByEs() {
 		}
 		// 当前列表中的分类map
 		chartClassifyMap := make(map[int]*data_manage.ChartClassify)
-
+		isSelectClassifyMap := make(map[int]bool)
 		// 图表分类
 		{
 			chartClassifyList, err := data_manage.GetChartClassifyByIdList(classifyIdList)
@@ -2369,6 +2386,9 @@ func (this *ChartInfoController) ChartInfoSearchByEs() {
 			}
 			for _, v := range chartClassifyList {
 				chartClassifyMap[v.ChartClassifyId] = v
+				if v.IsSelected == 1 {
+					isSelectClassifyMap[v.ChartClassifyId] = true
+				}
 			}
 		}
 		// 图表
@@ -2418,6 +2438,9 @@ func (this *ChartInfoController) ChartInfoSearchByEs() {
 			if tmp.SearchText == "" {
 				tmp.SearchText = v.ChartName
 			}
+			if _, ok := isSelectClassifyMap[v.ChartClassifyId]; ok {
+				tmp.IsSelected = 1
+			}
 			finalList = append(finalList, tmp)
 		}
 	}
@@ -4449,6 +4472,9 @@ func (this *ChartInfoController) UpdateToForum() {
 		return
 	}
 
+	// 更新指标数据
+	utils.Rc.LPush(utils.CACHE_KEY_EDB_DATA_UPDATE_LOG, []byte("1"))
+	
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "保存成功"
@@ -5115,8 +5141,130 @@ func (this *ChartInfoController) ModifyChartList() {
 		br.ErrMsg = "更新图表分类失败,Err:" + err.Error()
 		return
 	}
+	
+	go eta_forum.ChartInfoDeleteBatchByChartInfoIds(chartIds, req.ChartClassifyId)
 
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "操作成功"
 }
+
+// 查询图表简介列表
+// @Title 查询图表简介列表
+// @Description 查询图表简介列表
+// @Param   ChartInfoId   query   int  true       "图表id"
+// @Success 200 {object} models.ChartDescriptionListResponse
+// @router /chart_info/description/list [get]
+func (this *ChartInfoController) GetChartDescriptionList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	chartInfoId, _ := this.GetInt("ChartInfoId")
+	if chartInfoId <= 0 {
+		br.Msg = "请选择图表"
+		return
+	}
+
+	chartDescriptionList, err := data_manage.GetChartDescriptionByChartInfoId(chartInfoId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表简介失败,Err:" + err.Error()
+		return
+	}
+	list := make([]*data_manage.ChartDescriptionList, 0)
+	response := new(data_manage.ChartDescriptionListResponse)
+	for _, v := range chartDescriptionList {
+		list = append(list, &data_manage.ChartDescriptionList{
+			Id:               v.Id,
+			Description:      v.Description,
+			ChartInfoId:      v.ChartInfoId,
+			SysUserId:        v.SysUserId,
+			SysUserRealName:  v.SysUserRealName,
+			CreateTime:       v.CreateTime.Format(utils.FormatDateTime),
+		})
+	}
+	response.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = response
+}
+
+// 添加图表简介
+// @Title 添加图表简介
+// @Description 添加图表简介
+// @Param   ChartInfoId   query   int  true       "图表id"
+// @Success 200 {object} models.ChartDescriptionListResponse
+// @router /chart_info/description/add [post]
+func (this *ChartInfoController) AddChartDescription() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}	
+
+	var req data_manage.ChartDescriptionAddReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ChartInfoId <= 0 {
+		br.Msg = "请选择图表"
+		return
+	}
+	if req.Description == "" {
+		br.Msg = "请输入简介"
+		return
+	}
+	// 判断图表是否存在
+	_, err = data_manage.GetChartInfoById(req.ChartInfoId)
+	if err != nil {
+		if !utils.IsErrNoRow(err) {
+			br.Msg = "图表不存在"
+			return
+		}
+		br.Msg = "获取图表信息失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+	item := &data_manage.ChartDescription{
+		ChartInfoId: req.ChartInfoId,
+		Description: req.Description,
+		SysUserId: sysUser.AdminId,
+		SysUserRealName: sysUser.RealName,
+		ModifyTime: time.Now(),
+		CreateTime: time.Now(),
+	}
+	err = data_manage.AddChartDescription(item)
+	if err != nil {
+		br.Msg = "添加失败"
+		br.ErrMsg = "添加图表简介失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "添加成功"
+}
+

+ 1 - 1
controllers/data_manage/correlation/correlation_chart_classify.go

@@ -263,7 +263,7 @@ func (this *CorrelationChartClassifyController) AddChartClassify() {
 	}
 
 	// 新增图表分类
-	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_CORRELATION, this.Lang, this.SysUser)
+	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_CORRELATION, 0,this.Lang, this.SysUser)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = "添加分类失败,Err:" + err.Error()

+ 1 - 1
controllers/data_manage/future_good/future_good_chart_classify.go

@@ -203,7 +203,7 @@ func (this *FutureGoodChartClassifyController) AddChartClassify() {
 	}
 
 	// 新增图表分类
-	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, 0, req.Level, utils.CHART_SOURCE_FUTURE_GOOD, this.Lang, this.SysUser)
+	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, 0, req.Level, utils.CHART_SOURCE_FUTURE_GOOD, 0, this.Lang, this.SysUser)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = "添加分类失败,Err:" + err.Error()

+ 1 - 1
controllers/data_manage/line_equation/line_chart_classify.go

@@ -208,7 +208,7 @@ func (this *LineEquationChartClassifyController) AddChartClassify() {
 	}
 
 	// 新增图表分类
-	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_LINE_EQUATION, this.Lang, this.SysUser)
+	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_LINE_EQUATION, 0, this.Lang, this.SysUser)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = "添加分类失败,Err:" + err.Error()

+ 1 - 1
controllers/data_manage/line_feature/classify.go

@@ -208,7 +208,7 @@ func (this *LineFeaturesChartClassifyController) AddChartClassify() {
 	}
 
 	// 新增图表分类
-	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_LINE_FEATURE_STANDARD_DEVIATION, this.Lang, this.SysUser)
+	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_LINE_FEATURE_STANDARD_DEVIATION, 0, this.Lang, this.SysUser)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = "添加分类失败,Err:" + err.Error()

+ 26 - 14
controllers/data_manage/my_chart.go

@@ -70,30 +70,42 @@ func (this *MyChartController) ChartList() {
 	condition += ` AND source = ? `
 	pars = append(pars, utils.CHART_SOURCE_DEFAULT)
 
-	chartClassifyIds := make([]int, 0)
-	if chartClassifyId > 0 {
+	// 是否显示精选资源
+	isSelected, _ := this.GetInt("IsSelected", -1)
 
-		list, e := data_manage.GetChartClassifyAllBySource(utils.CHART_SOURCE_DEFAULT)
-		if e != nil {
+	chartClassifyIds := make([]int, 0)
+	var classifyList []*data_manage.ChartClassifyItems
+	var err error
+	if isSelected >= 0 {
+		classifyList, err = data_manage.GetChartClassifyAllBySourceIsSelected(utils.CHART_SOURCE_DEFAULT, isSelected)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = fmt.Sprintf("获取图表分类失败, Err: %v", err)
+			return
+		}
+	} else {
+		classifyList, err = data_manage.GetChartClassifyAllBySource(utils.CHART_SOURCE_DEFAULT)
+		if err != nil {
 			br.Msg = "获取失败"
-			br.ErrMsg = fmt.Sprintf("获取图表分类失败, Err: %v", e)
+			br.ErrMsg = fmt.Sprintf("获取图表分类失败, Err: %v", err)
 			return
 		}
-		parents := data.GetChartClassifyChildrenRecursive(list, chartClassifyId)
+	}
+	if chartClassifyId > 0 {
+		parents := data.GetChartClassifyChildrenRecursive(classifyList, chartClassifyId)
 		sort.Slice(parents, func(i, j int) bool {
 			return parents[i].Level < parents[i].Level
 		})
 		for _, v := range parents {
 			chartClassifyIds = append(chartClassifyIds, v.ChartClassifyId)
 		}
-
-		//chartClassifyId, err := data_manage.GetChartClassify(chartClassifyId)
-		//if err != nil && err.Error() != utils.ErrNoRow() {
-		//	br.Msg = "获取图表信息失败"
-		//	br.ErrMsg = "获取信息失败,GetChartClassify,Err:" + err.Error()
-		//	return
-		//}
-		condition += " AND chart_classify_id IN(" + utils.GetOrmInReplace(len(chartClassifyIds)) + ") "
+		condition += " AND chart_classify_id IN (" + utils.GetOrmInReplace(len(chartClassifyIds)) + ") "
+		pars = append(pars, chartClassifyIds)
+	} else if isSelected >= 0 {
+		for _, v := range classifyList {
+			chartClassifyIds = append(chartClassifyIds, v.ChartClassifyId)
+		}
+		condition += " AND chart_classify_id IN (" + utils.GetOrmInReplace(len(chartClassifyIds)) + ") "
 		pars = append(pars, chartClassifyIds)
 	}
 

+ 1 - 1
controllers/data_manage/range_analysis/chart_classify.go

@@ -262,7 +262,7 @@ func (this *RangeChartClassifyController) AddChartClassify() {
 	}
 
 	// 新增图表分类
-	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_RANGE_ANALYSIS, this.Lang, this.SysUser)
+	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_RANGE_ANALYSIS, 0, this.Lang, this.SysUser)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = "添加分类失败,Err:" + err.Error()

+ 1 - 1
controllers/trade_analysis/warehouse_classify.go

@@ -219,7 +219,7 @@ func (this *WarehouseClassifyController) AddChartClassify() {
 	}
 
 	// 新增图表分类
-	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_TRADE_ANALYSIS_PROCESS, this.Lang, this.SysUser)
+	_, err, errMsg, isSendEmail := data.AddChartClassify(req.ChartClassifyName, req.ParentId, req.Level, utils.CHART_SOURCE_TRADE_ANALYSIS_PROCESS, 0, this.Lang, this.SysUser)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = "添加分类失败,Err:" + err.Error()

+ 88 - 10
models/data_manage/chart_classify.go

@@ -25,6 +25,9 @@ type ChartClassify struct {
 	IsJoinPermission    int       `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
 	ChartClassifyNameEn string    `description:"英文分类名称"`
 	RootId              int       `description:"顶级ID"`
+	IsSelected          int       `description:"是否精选资源,0:否;1:是"`
+	ResourceStatus      int       `description:"在ETA投研资源库中的状态,0:初始状态,1上架,2下架"`
+	LevelPath           string    `description:"所有的父级分类id"`
 }
 
 func AddChartClassify(item *ChartClassify) (lastId int64, err error) {
@@ -37,6 +40,7 @@ type AddChartClassifyReq struct {
 	ChartClassifyName string `description:"分类名称"`
 	ParentId          int    `description:"父级id,第一级传0"`
 	Level             int    `description:"层级,第一级传0,其余传上一级的层级"`
+	IsSelected        int    `description:"是否精选资源,0:否;1:是"`
 }
 
 // GetChartClassifyCount
@@ -77,6 +81,7 @@ type EditChartClassifyReq struct {
 	ChartClassifyName string `description:"分类名称"`
 	ChartClassifyId   int    `description:"分类id"`
 	ParentId          int    `description:"父级分类id"`
+	IsSelected        int    `description:"是否精选资源,0:否;1:是"`
 }
 
 func GetChartClassifyById(classifyId int) (item *ChartClassify, err error) {
@@ -269,6 +274,8 @@ type ChartClassifyItems struct {
 	IsJoinPermission    int                      `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
 	HaveOperaAuth       bool                     `description:"是否有数据权限,默认:false"`
 	Disable             bool                     `description:"勾选是否禁用"`
+	IsSelected          int                      `description:"是否精选资源,0:否;1:是"`
+	ResourceStatus      int                      `description:"在ETA投研资源库中的状态,0:初始状态,1上架,2下架"`
 }
 
 // ChartClassifyItemsButton 操作按钮
@@ -347,6 +354,16 @@ func GetChartClassifyByCondition(condition string, pars []interface{}) (item *Ch
 	return
 }
 
+func GetChartClassifyListByCondition(condition string, pars []interface{}) (items []*ChartClassify, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := ` SELECT * FROM chart_classify WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	err = o.Raw(sql, pars...).Find(&items).Error
+	return
+}
+
 // MoveChartClassifyReq 移动图表分类请求参数
 type MoveChartClassifyReq struct {
 	ClassifyId       int `description:"分类id"`
@@ -560,6 +577,20 @@ func GetChartClassifyAllBySource(source int) (items []*ChartClassifyItems, err e
 	return
 }
 
+// GetChartClassifyAllBySourceIsSelected 根据来源获取所有精选分类
+func GetChartClassifyAllBySourceIsSelected(source int, isSelected int) (items []*ChartClassifyItems, err error) {
+	sql := ` SELECT * FROM chart_classify WHERE source = ? AND is_selected = ? ORDER BY parent_id ASC, sort ASC, chart_classify_id ASC`
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, source, isSelected).Find(&items).Error
+	return
+}
+
+// GetChartClassifyInfoSelectedBySource 获取所有的精选目录
+func GetChartClassifyInfoSelectedBySource(source int) (items []*ChartClassify, err error) {
+	sql := ` SELECT * FROM chart_classify WHERE source = ? AND is_selected = ? ORDER BY parent_id ASC, sort ASC, chart_classify_id ASC`
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, source, utils.ChartClassifyIsSelected).Find(&items).Error
+	return
+}
+
 // GetChartClassifyIdListByAdminId
 // @Description: 根据用户id和指标类型获取其关联的所有指标分类id列表
 // @author: Roc
@@ -579,7 +610,7 @@ func GetChartClassifyIdListByAdminId(adminId, source int) (chartClassifyIdList [
 }
 
 // GetChartClassifyAndInfoByParentId
-func GetChartClassifyAndInfoByParentId(parentId int) (items []*ChartClassifyItems, err error) {
+func GetChartClassifyAndInfoByParentId(parentId int, isSelected int) (items []*ChartClassifyItems, err error) {
 	sql := ` SELECT
 	0 AS chart_info_id,
 	chart_classify_id,
@@ -600,11 +631,13 @@ func GetChartClassifyAndInfoByParentId(parentId int) (items []*ChartClassifyItem
 	0 as chart_type,
 	'' as calendar,
 	'' as season_start_date,
-	'' as season_end_date
+	'' as season_end_date,
+	is_selected,
+	resource_status
 FROM
 	chart_classify 
 WHERE
-	parent_id = ? and source = 1 UNION ALL
+	parent_id = ? and source = 1 AND is_selected = ?  UNION ALL
 SELECT
 	chart_info_id,
 	chart_classify_id,
@@ -625,7 +658,9 @@ SELECT
 	chart_type,
 	calendar,
 	season_start_date,
-	season_end_date
+	season_end_date,
+	0 as is_selected,
+	resource_status
 FROM
 	chart_info 
 WHERE
@@ -633,12 +668,12 @@ WHERE
 ORDER BY
 	sort ASC,
 	chart_classify_id ASC`
-	err = global.DbMap[utils.DbNameIndex].Raw(sql, parentId, parentId).Find(&items).Error
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, parentId, isSelected, parentId).Find(&items).Error
 	return
 }
 
 // GetChartClassifyAndInfoByParentId
-func GetChartClassifyAndInfoByParentIdForMe(parentId, adminId int) (items []*ChartClassifyItems, err error) {
+func GetChartClassifyAndInfoByParentIdForMe(parentId, adminId, isSelected int) (items []*ChartClassifyItems, err error) {
 	sql := ` SELECT
 	0 AS chart_info_id,
 	chart_classify_id,
@@ -651,11 +686,13 @@ func GetChartClassifyAndInfoByParentIdForMe(parentId, adminId int) (items []*Cha
 	sys_user_real_name,
 	sort,
 	level,
-	unique_code
+	unique_code,
+	is_selected,
+	resource_status
 FROM
 	chart_classify 
 WHERE
-	parent_id = ? and source = 1 UNION ALL
+	parent_id = ? and source = 1 AND is_selected = ? UNION ALL
 SELECT
 	chart_info_id,
 	chart_classify_id,
@@ -668,7 +705,9 @@ SELECT
 	sys_user_real_name,
 	sort,
 	0 AS level,
-	unique_code
+	unique_code,
+	0 as is_selected,
+	resource_status
 FROM
 	chart_info 
 WHERE
@@ -676,7 +715,7 @@ WHERE
 ORDER BY
 	sort ASC,
 	chart_classify_id ASC`
-	err = global.DbMap[utils.DbNameIndex].Raw(sql, parentId, parentId, adminId).Find(&items).Error
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, parentId, isSelected, parentId, adminId).Find(&items).Error
 	return
 }
 
@@ -694,3 +733,42 @@ func GetChartClassifiesById(chartClassifyId int) (items []*ChartClassifyItems, e
 	err = global.DbMap[utils.DbNameIndex].Raw(sql, chartClassifyId, chartClassifyId, chartClassifyId).Find(&items).Error
 	return
 }
+
+func GetChartClassifyByLevelPath(levelPath string, source int) (items []*ChartClassify, err error) {
+	sql := `SELECT * FROM chart_classify where level_path like '` + levelPath + `%' and source = ?`
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, source).Find(&items).Error
+	return
+}
+
+func UpdateChartClassifyIsSelected(source int, isSelected int, levelPath string) (err error) {
+	sql := `UPDATE chart_classify SET is_selected = ? WHERE source = ? AND level_path LIKE '` + levelPath + `%'`
+	err = global.DbMap[utils.DbNameIndex].Exec(sql, isSelected, source).Error
+	return
+}
+
+func UpdateChartClassifyResourceStatus(source int, resourceStatus int, levelPath string) (err error) {
+	sql := `UPDATE chart_classify SET resource_status = ? WHERE source = ? AND level_path LIKE '` + levelPath + `%'`
+	err = global.DbMap[utils.DbNameIndex].Exec(sql, resourceStatus, source).Error
+	return
+}
+
+// 查询存在已经上架的图表的分类
+func GetChartClassifyHasUpChartBySource(source int, levelPath string) (count int, err error) {
+	sql := `SELECT count(1) FROM chart_info WHERE source = ? AND resource_status = ? and chart_classify_id in (SELECT chart_classify_id FROM chart_classify WHERE level_path like '` + levelPath + `%')`
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, source, utils.ChartClassifyResourceStatusUp).Scan(&count).Error
+	return
+}
+
+type SetChartClassifyResourceStatusReq struct {
+	ChartClassifyId int `description:"分类id"`
+	ResourceStatus  int `description:"资源状态"`
+}
+
+type ChartClassifyResourceUpdate struct {
+	ChartClassifyId int `description:"分类id"`
+}
+
+type EditChartClassifyResp struct {
+	TipCode          string `description:"提示码"`
+	TipMsg           string `description:"提示信息"`
+}

+ 81 - 0
models/data_manage/chart_description.go

@@ -0,0 +1,81 @@
+package data_manage
+
+import (
+	"eta/eta_api/global"
+	"eta/eta_api/utils"
+	"time"
+)
+
+type ChartDescription struct {
+	Id               int       `gorm:"column:id;primaryKey"`
+	Description      string    `gorm:"column:description"`
+	ChartInfoId      int       `gorm:"column:chart_info_id"` // 图表id
+	SysUserId        int       `gorm:"column:sys_user_id"`     // 创建人id
+	SysUserRealName  string    `gorm:"column:sys_user_real_name"` // 创建人姓名
+	ModifyTime       time.Time `gorm:"column:modify_time"`     // 变更时间
+	CreateTime       time.Time `gorm:"column:create_time"`     // 关系建立时间
+}
+
+// AddChartDescription 添加图表简介
+func AddChartDescription(item *ChartDescription) (err error) {
+	err = global.DbMap[utils.DbNameIndex].Create(item).Error
+	return
+}
+
+// GetChartDescriptionByChartInfoId 根据图表ID获取图表简介
+func GetChartDescriptionByChartInfoId(chartInfoId int) (item []*ChartDescription, err error) {
+	sql := `SELECT * FROM chart_description WHERE chart_info_id = ? order by create_time desc, id desc`
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, chartInfoId).Find(&item).Error
+	return
+}
+
+// GetChartDescriptionById 根据ID获取图表简介
+func GetChartDescriptionById(id int) (item *ChartDescription, err error) {
+	sql := `SELECT * FROM chart_description WHERE id = ?`
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, id).First(&item).Error
+	return
+}
+
+// DeleteChartDescription 删除图表简介
+func DeleteChartDescription(id int) (err error) {
+	sql := `DELETE FROM chart_description WHERE id = ?`
+	err = global.DbMap[utils.DbNameIndex].Exec(sql, id).Error
+	return
+}
+
+// DeleteChartDescriptionByChartInfoId 根据图表ID删除图表简介
+func DeleteChartDescriptionByChartInfoId(chartInfoId int) (err error) {
+	sql := `DELETE FROM chart_description WHERE chart_info_id = ?`
+	err = global.DbMap[utils.DbNameIndex].Exec(sql, chartInfoId).Error
+	return
+} 
+
+type ChartDescriptionList struct {
+	Id               int       `gorm:"column:id;primaryKey"`
+	Description      string    `gorm:"column:description"`
+	ChartInfoId      int       `gorm:"column:chart_info_id"` // 图表id
+	SysUserId        int       `gorm:"column:sys_user_id"`     // 创建人id
+	SysUserRealName  string    `gorm:"column:sys_user_real_name"` // 创建人姓名
+	CreateTime       string	   `gorm:"column:create_time"`     // 创建时间
+}
+
+type ChartDescriptionListResponse struct {
+	List []*ChartDescriptionList
+}
+
+type ChartDescriptionAddReq struct {
+	ChartInfoId int `description:"图表id"`
+	Description string `description:"简介"`
+}
+
+
+type ChartDescriptionReq struct {
+	Id               int       
+	Description      string      // 图表id
+	ChartInfoId      int       
+	SysUserId        int         // 创建人id
+	SysUserRealName  string    	 // 创建人姓名
+	AdminName        string   	 // 创建人姓名
+	ModifyTime       time.Time 	 // 变更时间
+	CreateTime       time.Time 	 // 关系建立时间  
+}

+ 6 - 0
models/data_manage/chart_edb_mapping.go

@@ -70,6 +70,12 @@ func GetChartMappingList(chartInfoId int) (list []*ChartEdbMapping, err error) {
 	err = o.Raw(sql, chartInfoId).Find(&list).Error
 	return
 }
+func GetChartMappingListOrderByEdbInfoId(chartInfoId int) (list []*ChartEdbMapping, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := `SELECT * FROM chart_edb_mapping WHERE chart_info_id = ? ORDER BY edb_info_id ASC`
+	err = o.Raw(sql, chartInfoId).Find(&list).Error
+	return
+}
 
 func GetChartEdbMappingListByChartInfoIds(chartInfoIds string) (list []*ChartEdbInfoMapping, err error) {
 	o := global.DbMap[utils.DbNameIndex]

+ 7 - 4
models/data_manage/chart_info.go

@@ -62,6 +62,7 @@ type ChartInfo struct {
 	ForumChartInfoId  int    `description:"社区的图表ID"`
 	ChartAlias        string `description:"图表别名"`
 	DateTypeNum       int    `description:"date_type=25(N月前)时的N值,其他N值可复用此字段"`
+	ResourceStatus    int    `description:"资源状态,0默认, 1上架,2下架"`
 }
 
 // AreaExtraConf 面积图配置
@@ -77,6 +78,7 @@ type ChartInfoMore struct {
 	IsEnChart     bool   `description:"是否展示英文标识"`
 	HaveOperaAuth bool   `description:"是否有数据权限,默认:false"`
 	SearchText    string `description:"搜索结果(含高亮)"`
+	IsSelected    int    `description:"是否是精选目录下的图表"`
 }
 
 func AddChartInfo(item *ChartInfo) (lastId int64, err error) {
@@ -378,14 +380,15 @@ func ModifyChartInfo(item *EditChartInfoReq) (err error) {
 	err = o.Exec(sql, item.ChartName, item.ChartClassifyId, item.ChartInfoId).Error
 	return
 }
-func SetForumChartInfoId(chartInfoId, forumChartInfoId int) (err error) {
+func SetForumChartInfoId(chartInfoId, forumChartInfoId int, resourceStatus int) (err error) {
 	o := global.DbMap[utils.DbNameIndex]
 	sql := ` UPDATE  chart_info
 			SET
               forum_chart_info_id=?,
-			  modify_time = NOW()
+			  modify_time = NOW(),
+			  resource_status = ?
 			WHERE chart_info_id = ?`
-	err = o.Exec(sql, forumChartInfoId, chartInfoId).Error
+	err = o.Exec(sql, forumChartInfoId, resourceStatus, chartInfoId).Error
 	return
 }
 
@@ -815,6 +818,7 @@ type ChartInfoDetailResp struct {
 	CorrelationChartInfo *CorrelationInfo `description:"相关性图表信息"`
 	DataResp             interface{}      `description:"图表数据,根据图的类型而定的,没有确定的数据格式"`
 	ClassifyLevels       []string         `description:"图表分类的UniqueCode-从最顶级到当前分类(给前端回显定位用的=_=!)"`
+	IsSelected        int             `description:"是否为精选目录下的图表,0:否;1:是;默认:0"`
 }
 
 type FutureGoodChartInfoDetailResp struct {
@@ -1780,7 +1784,6 @@ func ChartInfoSearchByEmptyKeyWord(showSysId int, sourceList []int, noPermission
 		baseSql += ` AND chart_info_id not in (` + utils.GetOrmInReplace(lenNoPermissionChartIdList) + `) `
 		basePars = append(basePars, noPermissionChartIdList)
 	}
-
 	// 查找数量
 	totalSql := " SELECT count(1) as total " + baseSql
 	err = o.Raw(totalSql, basePars...).Scan(&total).Error

+ 48 - 0
models/data_manage/forum_chart_edb_mapping.go

@@ -0,0 +1,48 @@
+package data_manage
+
+import (
+	"time"
+
+	"eta/eta_api/global"
+	"eta/eta_api/utils"
+)
+
+type ForumChartEdbMapping struct {
+	ID int `gorm:"column:id;primaryKey" description:"主键"`
+	ChartInfoId int 
+	EdbInfoIds string 
+	CreateTime time.Time 
+	ModifyTime time.Time 
+}
+
+// 根据chartInfoId获取edbInfoIds
+func GetForumEdbInfoIdsByChartInfoId(chartInfoId int) (edbInfoIds string, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := `SELECT edb_info_ids FROM forum_chart_edb_mapping WHERE chart_info_id = ?`
+	err = o.Raw(sql, chartInfoId).Scan(&edbInfoIds).Error
+	return
+}
+
+// 新增
+func AddForumChartEdbMapping(chartInfoId int, edbInfoIds string) (err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := `INSERT INTO forum_chart_edb_mapping (chart_info_id, edb_info_ids, create_time, modify_time) VALUES (?, ?, ?, ?)`
+	err = o.Exec(sql, chartInfoId, edbInfoIds, time.Now(), time.Now()).Error
+	return
+}
+
+// 更新
+func UpdateForumChartEdbMapping(chartInfoId int, edbInfoIds string) (err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := `UPDATE forum_chart_edb_mapping SET edb_info_ids = ?, modify_time = ? WHERE chart_info_id = ?`
+	err = o.Exec(sql, edbInfoIds, time.Now(), chartInfoId).Error
+	return
+}
+
+// 删除
+func DeleteForumChartEdbMapping(chartInfoId int) (err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := `DELETE FROM forum_chart_edb_mapping WHERE chart_info_id = ?`
+	err = o.Exec(sql, chartInfoId).Error
+	return
+}

+ 36 - 0
routers/commentsRouter.go

@@ -3598,6 +3598,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"],
+        beego.ControllerComments{
+            Method: "UpdateChartClassifyResource",
+            Router: `/chart_classify/forum_chart/update`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"],
         beego.ControllerComments{
             Method: "ChartClassifyItems",
@@ -3625,6 +3634,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"],
+        beego.ControllerComments{
+            Method: "SetChartClassifyResourceStatus",
+            Router: `/chart_classify/resource_status`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"],
         beego.ControllerComments{
             Method: "AddManualClassify",
@@ -3805,6 +3823,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "AddChartDescription",
+            Router: `/chart_info/description/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "GetChartDescriptionList",
+            Router: `/chart_info/description/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "ChartInfoDetail",

+ 157 - 15
services/data/chart_classify.go

@@ -5,9 +5,11 @@ import (
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services/data/data_manage_permission"
+	"eta/eta_api/services/eta_forum"
 	"eta/eta_api/utils"
 	"fmt"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -269,7 +271,7 @@ func HandleNoPermissionChart(allNodes []*data_manage.ChartClassifyItems, noPermi
 // @return err error
 // @return errMsg string
 // @return isSendEmail bool
-func AddChartClassify(chartClassifyName string, parentId, level, source int, lang string, sysUser *system.Admin) (classifyInfo *data_manage.ChartClassify, err error, errMsg string, isSendEmail bool) {
+func AddChartClassify(chartClassifyName string, parentId, level, source int, isSelected int, lang string, sysUser *system.Admin) (classifyInfo *data_manage.ChartClassify, err error, errMsg string, isSendEmail bool) {
 	isSendEmail = true
 	errMsg = "保存分类失败"
 
@@ -308,6 +310,7 @@ func AddChartClassify(chartClassifyName string, parentId, level, source int, lan
 	}
 	//查询顶级rootId
 	rootId := 0
+	levelPath := ""
 	if parentId > 0 {
 		parentClassify, tErr := data_manage.GetChartClassifyById(parentId)
 		if tErr != nil {
@@ -321,6 +324,8 @@ func AddChartClassify(chartClassifyName string, parentId, level, source int, lan
 			return
 		}
 		rootId = parentClassify.RootId
+		levelPath = parentClassify.LevelPath
+		isSelected = parentClassify.IsSelected
 	}
 
 	classifyInfo = new(data_manage.ChartClassify)
@@ -338,23 +343,34 @@ func AddChartClassify(chartClassifyName string, parentId, level, source int, lan
 	classifyInfo.Sort = maxSort + 1
 	classifyInfo.Source = source
 	classifyInfo.RootId = rootId
-
+	classifyInfo.IsSelected = isSelected
 	newId, err := data_manage.AddChartClassify(classifyInfo)
 	if err != nil {
 		return
 	}
+	updateCols := make([]string, 0)
 	if parentId == 0 { //一级目录的rootId等于自己本身
 		classifyInfo.RootId = int(newId)
-		err = classifyInfo.Update([]string{"RootId"})
-		if err != nil {
-			errMsg = "更新分类失败"
-			return
-		}
+		updateCols = append(updateCols, "RootId")
+	}
+	if parentId > 0 {
+		levelPath = fmt.Sprintf("%s%d,", levelPath, newId)
+	} else {
+		levelPath = fmt.Sprintf("%d,", newId)
+	}
+	updateCols = append(updateCols, "LevelPath")
+	classifyInfo.LevelPath = levelPath
+	err = classifyInfo.Update(updateCols)
+	if err != nil {
+		errMsg = "更新分类失败"
+		return
 	}
-
 	// 目前只有ETA图库需要继承分类权限
 	if classifyInfo.Source == utils.CHART_SOURCE_DEFAULT {
 		go data_manage_permission.InheritParentClassify(5, classifyInfo.Source, classifyInfo.ChartClassifyId, classifyInfo.ParentId, classifyInfo.ChartClassifyName)
+		if isSelected == utils.ChartClassifyIsSelected { // 如果分类设置为精选资源,则需要同步到ETA资源库
+			go eta_forum.ChartClassifySave(classifyInfo.ChartClassifyId)
+		}
 	}
 
 	return
@@ -621,7 +637,9 @@ func moveChartClassify(parentChartClassifyInfo, chartClassifyInfo, prevClassify,
 	// 移动对象为分类, 判断分类是否存在
 	if chartClassifyInfo != nil {
 		oldParentId := chartClassifyInfo.ParentId
+		oldLevelPath := chartClassifyInfo.LevelPath
 		oldLevel := chartClassifyInfo.Level
+		oldSelected := chartClassifyInfo.IsSelected
 		var classifyIds []int
 		if oldParentId != parentClassifyId {
 			//更新子分类对应的level
@@ -779,6 +797,23 @@ func moveChartClassify(parentChartClassifyInfo, chartClassifyInfo, prevClassify,
 					}
 				}
 			}
+
+			//更新分类的level_path
+			if oldParentId != parentClassifyId {
+				if err = UpdateChartClassifyLevelPathWithChildren(chartClassifyInfo, parentChartClassifyInfo, oldParentId, oldLevelPath); err != nil {
+					errMsg = "移动失败"
+					err = errors.New("更新分类level_path失败,Err:" + err.Error())
+					return
+				}
+			}
+			if source == utils.CHART_SOURCE_DEFAULT {
+				if err = UpdateChildClassifySelection(chartClassifyInfo, parentChartClassifyInfo, oldSelected); err != nil {
+					errMsg = "移动失败"
+					err = errors.New("更新子目录精选标识失败,Err:" + err.Error())
+					return
+				}
+				go eta_forum.ChartClassifySaveBatch(chartClassifyInfo.Source)
+			}
 		}
 	} else {
 		if chartInfo == nil {
@@ -898,11 +933,47 @@ func moveChartClassify(parentChartClassifyInfo, chartClassifyInfo, prevClassify,
 				err = errors.New("修改失败,Err:" + err.Error())
 				return
 			}
+
+			// 判断是否为精选目录
+			// 如果该目录不是精选目录,且该图表已经上架,则需撤回该图表
+			if parentChartClassifyInfo.IsSelected == 0 && chartInfo.ForumChartInfoId > 0 {
+				go eta_forum.DeleteChart(chartInfo.ChartInfoId)
+			}
 		}
 	}
 	return
 }
 
+// 新增内部函数
+func UpdateChartClassifyLevelPathWithChildren(chartClassifyInfo *data_manage.ChartClassify, parentChartClassifyInfo *data_manage.ChartClassify, oldParentId int, oldLevelPath string) error {
+	levelPath := fmt.Sprintf("%d,", chartClassifyInfo.ChartClassifyId)
+	if parentChartClassifyInfo != nil {
+		levelPath = fmt.Sprintf("%s%d,", parentChartClassifyInfo.LevelPath, chartClassifyInfo.ChartClassifyId)
+	}
+	chartClassifyInfo.LevelPath = levelPath
+	if err := chartClassifyInfo.Update([]string{"LevelPath"}); err != nil {
+		return fmt.Errorf("修改失败,Err:" + err.Error())
+	}
+
+	// 更新子分类的levelpath
+	tmpList, err := data_manage.GetChartClassifyByLevelPath(oldLevelPath, chartClassifyInfo.Source)
+	if err != nil {
+		return fmt.Errorf("保存分类失败,Err:" + err.Error())
+	}
+    // 把原先的父级levePath,替换成最新的父级序列
+	for _, tmp := range tmpList {
+		after, _ := strings.CutPrefix(tmp.LevelPath, oldLevelPath)
+		if after != "" {
+			tmp.LevelPath = levelPath + after
+			tmp.ModifyTime = time.Now()
+			if e := tmp.Update([]string{"LevelPath", "ModifyTime"}); e != nil {
+				return fmt.Errorf("修改子分类,Err:" + e.Error())
+			}
+		}
+	}
+	return nil
+}
+
 func GetChildChartClassifyByClassifyId(targetClassifyId int) (targetList []*data_manage.ChartClassifyIdItems, err error, errMsg string) {
 	//判断是否是挂在顶级目录下
 	targetClassify, err := data_manage.GetChartClassifyById(targetClassifyId)
@@ -996,8 +1067,35 @@ func GetChartClassifyParentRecursive(list []*data_manage.ChartClassifyItems, cla
 	return res
 }
 
+// 新增处理子分类精选状态的函数
+func UpdateChildClassifySelection(classifyInfo *data_manage.ChartClassify, parentClassifyInfo *data_manage.ChartClassify, oldSelected int) error {
+	// 处理一级目录
+	if classifyInfo.ParentId == 0 {
+		if oldSelected != classifyInfo.IsSelected {
+			return data_manage.UpdateChartClassifyIsSelected(
+				classifyInfo.Source,
+				classifyInfo.IsSelected,
+				classifyInfo.LevelPath,
+			)
+		}
+		return nil
+	}else {
+		// 处理二级及以上目录
+		if classifyInfo.IsSelected != parentClassifyInfo.IsSelected {
+			return data_manage.UpdateChartClassifyIsSelected(
+				classifyInfo.Source,
+				parentClassifyInfo.IsSelected,
+				classifyInfo.LevelPath,
+			)
+		}
+	}
+
+	
+	return nil
+}
+
 // 修改图表分类,可以修改父级
-func EditChartClassifyV2(chartClassifyId, parentId, source int, chartClassifyName, lang string) (classifyInfo *data_manage.ChartClassify, err error, errMsg string, isSendEmail bool) {
+func EditChartClassifyV2(chartClassifyId, parentId, source int, chartClassifyName string, isSelected int, lang string) (classifyInfo *data_manage.ChartClassify, isDeleteForumChart bool, tipCode string, err error, errMsg string, isSendEmail bool) {
 	isSendEmail = true
 	errMsg = "保存失败"
 
@@ -1006,19 +1104,40 @@ func EditChartClassifyV2(chartClassifyId, parentId, source int, chartClassifyNam
 	if err != nil {
 		return
 	}
-
-	if parentId != classifyInfo.ParentId {
-		parentClassifyInfo, e := data_manage.GetChartClassifyById(parentId)
-		if e != nil {
-			err = e
+	oldSelected := classifyInfo.IsSelected
+	var parentClassifyInfo *data_manage.ChartClassify
+	if parentId > 0 {
+		parentClassifyInfo, err= data_manage.GetChartClassifyById(parentId)
+		if err != nil {
 			return
 		}
+	}
+	if parentId != classifyInfo.ParentId {
 		if classifyInfo.Level != parentClassifyInfo.Level+1 {
 			err = errors.New("父级分类层级异常")
 			return
 		}
 	}
 
+	// 判断取消精选的情况
+	if classifyInfo.Source == utils.CHART_SOURCE_DEFAULT && parentId == 0 && oldSelected == 1 && isSelected == 0 {
+		// 取消精选,如果存在已经上架的分类,则提示用户下架所有的分类
+		count, e := data_manage.GetChartClassifyHasUpChartBySource(classifyInfo.Source, classifyInfo.LevelPath)
+		if e != nil {
+			errMsg = "查询是否存在已经上架的分类失败"
+			err = fmt.Errorf("查询是否存在已经上架的分类失败,Err:%w", e)
+			isSendEmail = false
+			return
+		}
+		if count > 0 {
+			// errMsg = "该分类下存在已经上架的分类,请先下架所有的分类,再取消精选"
+			// err = fmt.Errorf("",errMsg)
+			tipCode = "CHART_CLASSIFY_HAS_UP_CHART"
+			return
+		}
+		isDeleteForumChart = true
+	}
+
 	// 分类来源校验
 	if classifyInfo.Source != source {
 		errMsg = "图表分类异常"
@@ -1029,12 +1148,17 @@ func EditChartClassifyV2(chartClassifyId, parentId, source int, chartClassifyNam
 
 	// 需要变更的字段
 	updateCols := make([]string, 0)
-
+	oldParentId := classifyInfo.ParentId
+	oldLevelPath := classifyInfo.LevelPath
 	if parentId != classifyInfo.ParentId {
 		classifyInfo.ParentId = parentId
 		classifyInfo.ModifyTime = time.Now()
 		updateCols = append(updateCols, "ParentId")
 	}
+	if isSelected != classifyInfo.IsSelected && classifyInfo.Source == utils.CHART_SOURCE_DEFAULT && classifyInfo.ParentId == 0 {
+		classifyInfo.IsSelected = isSelected
+		updateCols = append(updateCols, "IsSelected")
+	}
 
 	// 语言版本校验
 	switch lang {
@@ -1082,6 +1206,24 @@ func EditChartClassifyV2(chartClassifyId, parentId, source int, chartClassifyNam
 		err = classifyInfo.Update(updateCols)
 	}
 
+	if oldParentId != parentId {
+		if err = UpdateChartClassifyLevelPathWithChildren(classifyInfo, parentClassifyInfo, oldParentId, oldLevelPath); err != nil {
+			errMsg = "修改分类失败"
+			err = errors.New("更新分类level_path失败,Err:" + err.Error())
+			return
+		}
+	}
+	// 如果是精选目录,则需要同步到ETA资源库
+	if classifyInfo.Source == utils.CHART_SOURCE_DEFAULT {
+		// 如果当前目录的精选标识发生变化,需要同步更新子目录的精选标识
+		if err = UpdateChildClassifySelection(classifyInfo, parentClassifyInfo, oldSelected); err != nil {
+			errMsg = "修改分类失败"
+			err = fmt.Errorf("更新子目录精选标识失败,Err:%w", err)
+			return
+		}
+		go eta_forum.ChartClassifySaveBatch(classifyInfo.Source)
+	}
+
 	return
 }
 

+ 7 - 0
services/data/chart_info.go

@@ -9,6 +9,7 @@ import (
 	"eta/eta_api/models/system"
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/services/data/data_manage_permission"
+	"eta/eta_api/services/eta_forum"
 	"eta/eta_api/utils"
 	"fmt"
 	"math"
@@ -3040,6 +3041,12 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 	//修改my eta es数据
 	go EsAddOrEditMyChartInfoByChartInfoId(chartItem.ChartInfoId)
 
+	// 移出精选分类,从资源库下架
+	// 判断是否为精选目录
+	// 如果该目录不是精选目录,且该图表已经上架,则需撤回该图表
+	if chartClassify.IsSelected == 0 && chartItem.ForumChartInfoId > 0 {
+		go eta_forum.DeleteChart(chartItem.ChartInfoId)
+	}
 	return
 }
 

+ 1 - 1
services/data/cross_variety/chart.go

@@ -644,7 +644,7 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin, lang string) (
 		// 分类没有,需要创建新的分类,那么err置空
 		err = nil
 
-		_, err, errMsg, isSendEmail = data.AddChartClassify(sysUser.RealName, 0, 1, source, lang, sysUser)
+		_, err, errMsg, isSendEmail = data.AddChartClassify(sysUser.RealName, 0, 1, source, 0, lang, sysUser)
 		if err != nil {
 			return
 		}

+ 80 - 0
services/eta_forum/chart_classify.go

@@ -0,0 +1,80 @@
+package eta_forum
+
+import (
+	"encoding/json"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/utils"
+	"fmt"
+)
+
+// ChartClassifySave 上传图表分类信息
+func ChartClassifySave(chartClassifyId int) (err error) {
+	if utils.BusinessCode == "" || (utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeDebug && utils.BusinessCode != utils.BusinessCodeSandbox) {
+		return
+	}
+	//查询分类信息
+	chartClassifyInfo, err := data_manage.GetChartClassifyById(chartClassifyId)
+	if err != nil {
+		if utils.IsErrNoRow(err) {
+			err = fmt.Errorf("分类不存在")
+			return
+		}
+		err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
+		return
+	}
+	if chartClassifyInfo.IsSelected != utils.ChartClassifyIsSelected {
+		return
+	}
+
+	reqJson, err := json.Marshal(chartClassifyInfo) 
+	if err != nil {
+		err = fmt.Errorf("参数解析异常,Err:" + err.Error())
+		return
+	}
+	respItem, err := ChartClassifySaveLib(string(reqJson))
+	if err != nil {
+		err = fmt.Errorf("上传图表分类信息失败,Err:" + err.Error())
+		return
+	}
+	if respItem.Ret != 200 {
+		err = fmt.Errorf("上传图表分类信息失败,Err:%v,errMsg:%v", respItem.Msg, respItem.ErrMsg)
+		return
+	}
+	return
+}
+
+type ChartClassifySaveBatchReq struct {
+	List []*data_manage.ChartClassify
+}
+
+//批量上传图表分类信息
+func ChartClassifySaveBatch(source int) (err error) {
+	if utils.BusinessCode == "" || (utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeDebug && utils.BusinessCode != utils.BusinessCodeSandbox) {
+		return
+	}
+
+	//查询分类信息
+	chartClassifyList, err := data_manage.GetChartClassifyInfoSelectedBySource(source)
+	if err != nil {
+		err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
+		return
+	}
+	req := ChartClassifySaveBatchReq{
+		List: chartClassifyList,
+	}
+	reqJson, err := json.Marshal(req)
+	if err != nil {
+		err = fmt.Errorf("参数解析异常,Err:" + err.Error())
+		return
+	}
+	respItem, err := ChartClassifySaveBatchLib(string(reqJson))
+	if err != nil {
+		err = fmt.Errorf("上传图表分类信息失败,Err:" + err.Error())
+		return
+	}	
+	if respItem.Ret != 200 {
+		err = fmt.Errorf("上传图表分类信息失败,Err:%v,errMsg:%v", respItem.Msg, respItem.ErrMsg)
+		return
+	}
+	return
+}

+ 516 - 27
services/eta_forum/eta_forum_hub.go

@@ -8,6 +8,8 @@ import (
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/utils"
 	"fmt"
+	"strconv"
+	"time"
 )
 
 type UploadChartToForumReq struct {
@@ -21,7 +23,7 @@ type UpdateChartToForumReq struct {
 
 type ChartSaveLibReq struct {
 	ChartInfo               *data_manage.ChartInfo
-	Description             string `description:"逻辑简述"`
+	Description             []*data_manage.ChartDescriptionReq `description:"逻辑简述"`
 	EdbInfoList             []*data_manage.EdbInfo
 	ChartThemeList          []*chart_theme.ChartTheme
 	EdbInfoDataList         []*AddEdbDataReq
@@ -45,6 +47,7 @@ type ChartSaveLibResp struct {
 }
 
 type AddEdbDataReq struct {
+	EdbInfoId int
 	EdbCode  string
 	EdbType  int
 	DataList []*data_manage.EdbDataBase
@@ -56,10 +59,18 @@ type DeleteChartReq struct {
 
 // UploadChart 上传图表接口
 func UploadChart(chartInfoId int, description string, uploaderInfo *system.Admin) (err error, errMsg string) {
+	// 设置缓存 防止重复上传
+	cacheKey := "eta_forum_task:UploadChart:" + strconv.Itoa(chartInfoId)
+	if utils.Rc.Get(cacheKey) != nil {
+		err = fmt.Errorf("系统处理中,请稍后重试!")
+		return
+	}
+	utils.Rc.SetNX(cacheKey, 1, 10*time.Minute)
 	defer func() {
 		if err != nil {
 			go alarm_msg.SendAlarmMsg(fmt.Sprintf("上传图表至社区失败:Err:%v,ErrMsg:%s", err, errMsg), 3)
 		}
+		utils.Rc.Delete(cacheKey)
 	}()
 	// 查询图表信息
 	chartInfo, err := data_manage.GetChartInfoById(chartInfoId)
@@ -82,15 +93,17 @@ func UploadChart(chartInfoId int, description string, uploaderInfo *system.Admin
 
 	//查询图表指标
 	//获取原图表关联的指标信息列表
-	chartMappingList, err := data_manage.GetChartMappingList(chartInfoId)
+	chartMappingList, err := data_manage.GetChartMappingListOrderByEdbInfoId(chartInfoId)
 	if err != nil {
 		errMsg = "获取图表关联的指标信息失败"
 		err = fmt.Errorf("获取图表关联的指标信息失败,Err:" + err.Error())
 		return
 	}
 	edbIds := make([]int, 0)
+	edbInfoStr := ""
 	for _, v := range chartMappingList {
 		edbIds = append(edbIds, v.EdbInfoId)
+		edbInfoStr += strconv.Itoa(v.EdbInfoId) + ","
 	}
 	chartSeriesList := make([]*data_manage.ChartSeries, 0)
 	chartSeriesEdbList := make([]*data_manage.ChartSeriesEdbMapping, 0)
@@ -116,20 +129,27 @@ func UploadChart(chartInfoId int, description string, uploaderInfo *system.Admin
 		edbInfoDataList []*AddEdbDataReq
 	)
 	//查询指标详情
-	edbInfoList, edbMappingList, edbInfoDataList, err = GetEdbListByEdbInfoId(edbIds)
+	edbInfoList, edbMappingList, edbInfoDataList, err = GetEdbListByEdbInfoId(edbIds, true)
 	if err != nil {
 		errMsg = "获取指标详情失败"
 		err = fmt.Errorf("获取指标详情失败,Err:" + err.Error())
 		return
 	}
 
+	descriptionList, err, errMsg := getChartDescriptionWithAdminNameByChartInfoId(chartInfoId)
+	if err != nil {
+		errMsg = "获取图表简介失败"
+		err = fmt.Errorf("获取图表简介失败,Err:" + err.Error())
+		return
+	}
+
 	req := new(ChartSaveLibReq)
 	req.ChartInfo = chartInfo
 	req.ChartEdbMapping = chartMappingList
 	req.EdbInfoList = edbInfoList
 	req.EdbInfoDataList = edbInfoDataList
 	req.EdbInfoCalculateMapping = edbMappingList
-	req.Description = description
+	req.Description = descriptionList
 	req.ChartSeries = chartSeriesList
 	req.ChartSeriesEdbMapping = chartSeriesEdbList
 
@@ -161,12 +181,19 @@ func UploadChart(chartInfoId int, description string, uploaderInfo *system.Admin
 
 	if respItem.Data != nil && respItem.Data.ChartInfoId != 0 {
 		// 更新社区返回的图表ID
-		err = data_manage.SetForumChartInfoId(chartInfoId, respItem.Data.ChartInfoId)
+		err = data_manage.SetForumChartInfoId(chartInfoId, respItem.Data.ChartInfoId, utils.ChartClassifyResourceStatusUp)
 		if err != nil {
 			errMsg = "更新图表ID失败"
 			err = fmt.Errorf("更新图表ID失败,Err:" + err.Error())
 			return
 		}
+		// 新增投研资源库里的图表和指标绑定关系
+		err = data_manage.AddForumChartEdbMapping(chartInfoId, edbInfoStr)
+		if err != nil {
+			errMsg = "新增投研资源库里的图表和指标绑定关系失败"
+			err = fmt.Errorf("新增投研资源库里的图表和指标绑定关系失败,Err:" + err.Error())
+			return
+		}
 	}
 
 	return
@@ -174,10 +201,18 @@ func UploadChart(chartInfoId int, description string, uploaderInfo *system.Admin
 
 // UpdateChart 更新社区里的图表接口
 func UpdateChart(chartInfoId int) (err error, errMsg string) {
+	// 设置缓存 防止重复更新
+	cacheKey := "eta_forum_task:UpdateChart:" + strconv.Itoa(chartInfoId)
+	if utils.Rc.Get(cacheKey) != nil {
+		err = fmt.Errorf("系统处理中,请稍后重试!")
+		return
+	}
+	utils.Rc.SetNX(cacheKey, 1, 10*time.Minute)
 	defer func() {
 		if err != nil {
 			go alarm_msg.SendAlarmMsg(fmt.Sprintf("同步图表信息至社区失败:Err:%v,ErrMsg:%s", err, errMsg), 3)
 		}
+		utils.Rc.Delete(cacheKey)
 	}()
 	// 查询图表信息
 	chartInfo, err := data_manage.GetChartInfoById(chartInfoId)
@@ -201,15 +236,17 @@ func UpdateChart(chartInfoId int) (err error, errMsg string) {
 
 	//查询图表指标
 	//获取原图表关联的指标信息列表
-	chartMappingList, err := data_manage.GetChartMappingList(chartInfoId)
+	chartMappingList, err := data_manage.GetChartMappingListOrderByEdbInfoId(chartInfoId)
 	if err != nil {
 		errMsg = "获取图表关联的指标信息失败"
 		err = fmt.Errorf("获取图表关联的指标信息失败,Err:" + err.Error())
 		return
 	}
 	edbIds := make([]int, 0)
+	edbInfoStr := ""
 	for _, v := range chartMappingList {
 		edbIds = append(edbIds, v.EdbInfoId)
+		edbInfoStr += strconv.Itoa(v.EdbInfoId) + ","
 	}
 	chartSeriesList := make([]*data_manage.ChartSeries, 0)
 	chartSeriesEdbList := make([]*data_manage.ChartSeriesEdbMapping, 0)
@@ -234,12 +271,30 @@ func UpdateChart(chartInfoId int) (err error, errMsg string) {
 		edbInfoDataList []*AddEdbDataReq
 	)
 	//查询指标详情
-	edbInfoList, edbMappingList, edbInfoDataList, err = GetEdbListByEdbInfoId(edbIds)
+	isGetEdbData := false
+	// 查询投研资源库里的图表和指标绑定关系
+	oldEdbInfoStr, err := data_manage.GetForumEdbInfoIdsByChartInfoId(chartInfoId)
+	if err != nil {
+		errMsg = "获取投研资源库里的图表和指标绑定关系失败"
+		err = fmt.Errorf("获取投研资源库里的图表和指标绑定关系失败,Err:" + err.Error())
+		return
+	}
+	if oldEdbInfoStr != edbInfoStr { // 图表更换过指标需要重新获取指标数据
+		isGetEdbData = true
+	}
+	//查询指标详情
+	edbInfoList, edbMappingList, edbInfoDataList, err = GetEdbListByEdbInfoId(edbIds, isGetEdbData)
 	if err != nil {
 		errMsg = "获取指标详情失败"
 		err = fmt.Errorf("获取指标详情失败,Err:" + err.Error())
 		return
 	}
+	descriptionList, err, errMsg := getChartDescriptionWithAdminNameByChartInfoId(chartInfoId)
+	if err != nil {
+		errMsg = "获取图表简介失败"
+		err = fmt.Errorf("获取图表简介失败,Err:" + err.Error())
+		return
+	}
 	req := new(ChartSaveLibReq)
 	req.ChartInfo = chartInfo
 	req.ChartInfo.ChartInfoId = chartInfo.ForumChartInfoId
@@ -249,6 +304,7 @@ func UpdateChart(chartInfoId int) (err error, errMsg string) {
 	req.EdbInfoCalculateMapping = edbMappingList
 	req.ChartSeries = chartSeriesList
 	req.ChartSeriesEdbMapping = chartSeriesEdbList
+	req.Description = descriptionList
 	// 查询创建者信息
 	creatorInfo, _ := system.GetSysAdminById(chartInfo.SysUserId)
 	if creatorInfo != nil {
@@ -274,20 +330,29 @@ func UpdateChart(chartInfoId int) (err error, errMsg string) {
 		return
 	}
 
+	// 更新投研资源库里的图表和指标绑定关系
+	err = data_manage.UpdateForumChartEdbMapping(chartInfoId, edbInfoStr)
+	if err != nil {
+		errMsg = "更新投研资源库里的图表和指标绑定关系失败"
+		err = fmt.Errorf("更新投研资源库里的图表和指标绑定关系失败,Err:" + err.Error())
+		return
+	}
 	return
 }
 
-func GetEdbListByEdbInfoId(edbInfoIds []int) (edbInfoList []*data_manage.EdbInfo, edbMappingList []*data_manage.EdbInfoCalculateMapping, edbInfoDataList []*AddEdbDataReq, err error) {
+func GetEdbListByEdbInfoId(edbInfoIds []int, isGetEdbData bool) (edbInfoList []*data_manage.EdbInfo, edbMappingList []*data_manage.EdbInfoCalculateMapping, edbInfoDataList []*AddEdbDataReq, err error) {
 	//查询指标信息
 	//查询指标映射
 	//查询所有指标数据
 	//查询这个指标相关的mapping信息放到数组里,
 	//将得到的指标ID信息放到数组里
+	chartEdbInfoIdMap := make(map[int]struct{}) //只查询图表上直接相关的指标数据
 	hasFindMap := make(map[int]struct{})
 	edbInfoIdMap := make(map[int]struct{})
 	edbMappingList = make([]*data_manage.EdbInfoCalculateMapping, 0)
 	edbMappingMap := make(map[int]struct{})
 	for _, edbInfoId := range edbInfoIds {
+		chartEdbInfoIdMap[edbInfoId] = struct{}{}
 		edbMappingList, err = traceEdbInfoByEdbInfoId(edbInfoId, hasFindMap, edbInfoIdMap, edbMappingList, edbMappingMap)
 		if err != nil {
 			err = fmt.Errorf(" traceEdbInfoByEdbInfoId err: %s", err.Error())
@@ -305,27 +370,32 @@ func GetEdbListByEdbInfoId(edbInfoIds []int) (edbInfoList []*data_manage.EdbInfo
 		err = fmt.Errorf(" GetEdbInfoByIdList err: %s", err.Error())
 		return
 	}
+	if isGetEdbData {
+		for _, v := range edbInfoList {
+			if _, ok := chartEdbInfoIdMap[v.EdbInfoId]; !ok {
+				continue
+			}
+			var dataList []*data_manage.EdbDataBase
+			if v.Source == utils.DATA_SOURCE_BUSINESS && utils.UseMongo {
+				dataList, err = data_manage.GetEdbDataBaseMongoByEdbInfoId(v.EdbInfoId, v.Source, v.SubSource)
+			} else if v.Source == utils.DATA_SOURCE_THS && v.SubSource == utils.DATA_SUB_SOURCE_HIGH_FREQUENCY && utils.UseMongo {
+				dataList, err = data_manage.GetThsHfEdbDataBaseMongoByEdbInfoId(v.EdbInfoId, v.Source, v.SubSource)
+			} else {
+				dataList, err = data_manage.GetEdbDataBaseByEdbInfoId(v.EdbInfoId, v.Source, v.SubSource)
+			}
 
-	for _, v := range edbInfoList {
-		var dataList []*data_manage.EdbDataBase
-		if v.Source == utils.DATA_SOURCE_BUSINESS && utils.UseMongo {
-			dataList, err = data_manage.GetEdbDataBaseMongoByEdbInfoId(v.EdbInfoId, v.Source, v.SubSource)
-		} else if v.Source == utils.DATA_SOURCE_THS && v.SubSource == utils.DATA_SUB_SOURCE_HIGH_FREQUENCY && utils.UseMongo {
-			dataList, err = data_manage.GetThsHfEdbDataBaseMongoByEdbInfoId(v.EdbInfoId, v.Source, v.SubSource)
-		} else {
-			dataList, err = data_manage.GetEdbDataBaseByEdbInfoId(v.EdbInfoId, v.Source, v.SubSource)
-		}
+			if err != nil {
+				err = fmt.Errorf("查询指标数据失败 Err: %s", err.Error())
+				return
+			}
 
-		if err != nil {
-			err = fmt.Errorf("查询指标数据失败 Err: %s", err.Error())
-			return
+			tmp := new(AddEdbDataReq)
+			tmp.EdbInfoId = v.EdbInfoId
+			tmp.EdbCode = v.EdbCode
+			tmp.EdbType = v.EdbType
+			tmp.DataList = dataList
+			edbInfoDataList = append(edbInfoDataList, tmp)
 		}
-
-		tmp := new(AddEdbDataReq)
-		tmp.EdbCode = v.EdbCode
-		tmp.EdbType = v.EdbType
-		tmp.DataList = dataList
-		edbInfoDataList = append(edbInfoDataList, tmp)
 	}
 	return
 }
@@ -397,6 +467,19 @@ func traceEdbInfoByEdbInfoId(edbInfoId int, hasFindMap map[int]struct{}, edbInfo
 
 // DeleteChart 上传图表接口
 func DeleteChart(chartInfoId int) (err error, errMsg string) {
+	// 设置缓存 防止重复撤回
+	cacheKey := "eta_forum_task:DeleteChart:" + strconv.Itoa(chartInfoId)
+	if utils.Rc.Get(cacheKey) != nil {
+		err = fmt.Errorf("系统处理中,请稍后重试!")
+		return
+	}
+	utils.Rc.SetNX(cacheKey, 1, 30*time.Second)
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg(fmt.Sprintf("撤回图表失败:%v,ErrMsg:%s", err, errMsg), 3)
+		}
+		utils.Rc.Delete(cacheKey)
+	}()
 	// 查询图表信息
 	chartInfo, err := data_manage.GetChartInfoById(chartInfoId)
 	if err != nil {
@@ -438,12 +521,46 @@ func DeleteChart(chartInfoId int) (err error, errMsg string) {
 	}
 
 	// 更新社区返回的图表ID
-	err = data_manage.SetForumChartInfoId(chartInfoId, 0)
+	err = data_manage.SetForumChartInfoId(chartInfoId, 0, utils.ChartClassifyResourceStatusDown)
 	if err != nil {
 		errMsg = "撤回失败"
 		err = fmt.Errorf("更新图表ID失败,Err:" + err.Error())
 		return
 	}
+	// 删除投研资源库里的图表和指标绑定关系
+	err = data_manage.DeleteForumChartEdbMapping(chartInfoId)
+	if err != nil {
+		errMsg = "删除投研资源库里的图表和指标绑定关系失败"
+		err = fmt.Errorf("删除投研资源库里的图表和指标绑定关系失败,Err:" + err.Error())
+		return
+	}
+	return
+}
+
+// DeleteChart 上传图表接口
+func DeleteChartByForumChartInfoId(forumChartInfoId int) (err error, errMsg string) {
+	// 查询图表信息
+	req := new(DeleteChartReq)
+	req.ChartInfoId = forumChartInfoId
+
+	// 添加计算指标
+	reqJson, err := json.Marshal(req)
+	if err != nil {
+		errMsg = "参数解析异常"
+		err = fmt.Errorf("参数解析异常,Err:" + err.Error())
+		return
+	}
+	respItem, err := ChartDeleteLib(string(reqJson))
+	if err != nil {
+		errMsg = "撤回失败"
+		err = fmt.Errorf("撤回失败,Err:" + err.Error())
+		return
+	}
+	if respItem.Ret != 200 {
+		errMsg = "撤回失败"
+		err = fmt.Errorf(respItem.ErrMsg)
+		return
+	}
 
 	return
 }
@@ -570,3 +687,375 @@ func ChartThemeTypeSave(theme *chart_theme.ChartThemeType) (err error) {
 	}
 	return
 }
+
+// ChartBatchUpdate 批量上传和更新图表信息
+func ChartBatchUpdateAndUpload(chartClassifyInfo *data_manage.ChartClassify, sysUser *system.Admin) (err error) {
+	if utils.BusinessCode == "" || (utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeDebug && utils.BusinessCode != utils.BusinessCodeSandbox) {
+		return
+	}
+	var tmpErr []error
+	deleteCache := true
+	cacheKey := "eta_forum_task:EtaForumChartUpdateByClassifyId:" + strconv.Itoa(chartClassifyInfo.ChartClassifyId)
+	defer func() {
+		if deleteCache {
+			_ = utils.Rc.Delete(cacheKey)
+		}
+		stack := ""
+		if err != nil {
+			stack = fmt.Sprintln(stack + err.Error())
+		}
+		if len(tmpErr) > 0 {
+			for _, v := range tmpErr {
+				stack = fmt.Sprintln(stack + v.Error())
+			}
+		}
+		if stack != "" {
+			utils.FileLog.Error("批量更新资源库图表信息失败"+"<br/>"+stack)
+			go alarm_msg.SendAlarmMsg("批量更新资源库图表信息失败"+"<br/>"+stack, 3)
+		}
+	}()
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		deleteCache = false
+		err = fmt.Errorf("系统处理中,请稍后重试!")
+		return
+	}
+	chartClassifyInfoList, err := data_manage.GetChartClassifyByLevelPath(chartClassifyInfo.LevelPath, chartClassifyInfo.Source)
+	if err != nil {
+		return
+	}
+	chartClassifyIdList := make([]string, 0)
+	upChartClassifyIdList := make([]string, 0)
+	for _, v := range chartClassifyInfoList {
+		chartClassifyIdList = append(chartClassifyIdList, strconv.Itoa(v.ChartClassifyId))
+		if v.ResourceStatus == utils.ChartClassifyResourceStatusUp {
+			upChartClassifyIdList = append(upChartClassifyIdList, strconv.Itoa(v.ChartClassifyId))
+		}
+	}
+	condition := " and forum_chart_info_id > 0 and source=1 and chart_classify_id in ?"
+	// 查询需要更新的图表信息总数
+	total, err := data_manage.GetChartInfoCountByCondition(condition, []interface{}{chartClassifyIdList})
+	if err != nil {
+		return
+	}
+	if total > 0 {
+		// 更新图表数据
+		offset := 0
+		pageSize := 100
+		success := 0
+
+		// 循环更新100个图表数据
+		for i := 0; offset < total; i++ {
+			// 查询需要更新的图表信息
+			chartInfos, e := data_manage.GetChartInfoListByCondition(condition, []interface{}{chartClassifyIdList}, offset, pageSize)
+			if e != nil {
+				err = fmt.Errorf("查询需要更新的图表信息失败: %v", e)
+				return
+			}
+			if len(chartInfos) == 0 {
+				break
+			}
+			// 循环更新图表数据
+			for _, chartInfo := range chartInfos {
+				// 更新图表数据
+				er, msg := UpdateChart(chartInfo.ChartInfoId)
+				if er != nil {
+					er = fmt.Errorf("图表ID %d, 更新图表数据失败: %s, %v", chartInfo.ChartInfoId, msg, er)
+					tmpErr = append(tmpErr, er)
+					continue
+				}
+				success += 1
+			}
+
+			offset += pageSize
+		}
+		utils.FileLog.Info("更新图表数据完成, 更新图表数据总数:", success)
+	}
+	// 更新指标数据
+	utils.Rc.LPush(utils.CACHE_KEY_EDB_DATA_UPDATE_LOG, []byte("1"))
+
+	// 批量上传已经上架的分类下的图表到资源库中
+	// 查询需要新增的图表ID
+	condition = " and source=1 and forum_chart_info_id=0 and resource_status !=2 and chart_classify_id in ?"
+	total, err = data_manage.GetChartInfoCountByCondition(condition, []interface{}{upChartClassifyIdList})
+	if err != nil {
+		return
+	}
+	if total == 0 {
+		return
+	}
+	offset := 0
+	pageSize := 100
+	success := 0
+	for i := 0; offset < total; i++ {
+		chartInfos, e := data_manage.GetChartInfoListByCondition(condition, []interface{}{upChartClassifyIdList}, offset, pageSize)
+		if e != nil {
+			err = fmt.Errorf("查询需要新增的图表信息失败: %v", e)
+			return
+		}
+		if len(chartInfos) == 0 {
+			break
+		}
+		// 循环更新图表数据
+		for _, chartInfo := range chartInfos {
+			// 更新图表数据
+			er, msg := UploadChart(chartInfo.ChartInfoId, "", sysUser)
+			if er != nil {
+				er = fmt.Errorf("图表ID %d, 上传图表数据失败: %s, %v", chartInfo.ChartInfoId, msg, er)
+				tmpErr = append(tmpErr, er)
+				continue
+			}
+			success += 1
+		}
+
+		offset += pageSize
+	}
+	utils.FileLog.Info("批量上传已经上架的分类下的图表到资源库中完成, 新增图表数据总数:", success)
+	
+	return
+}
+
+// 批量删除资源库图表信息
+func ChartInfoDeleteBatch(chartClassifyInfo *data_manage.ChartClassify, sysUser *system.Admin) (err error) {
+	if utils.BusinessCode == "" || (utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeDebug && utils.BusinessCode != utils.BusinessCodeSandbox) {
+		return
+	}
+	var tmpErr []error
+	deleteCache := true
+	cacheKey := "eta_forum_task:ChartInfoDeleteBatch:" + strconv.Itoa(chartClassifyInfo.ChartClassifyId)
+	defer func() {
+		if deleteCache {
+			_ = utils.Rc.Delete(cacheKey)
+		}
+		stack := ""
+		if err != nil {
+			stack = fmt.Sprintln(stack + err.Error())
+		}
+		if len(tmpErr) > 0 {
+			for _, v := range tmpErr {
+				stack = fmt.Sprintln(stack + v.Error())
+			}
+		}
+		if stack != "" {
+			utils.FileLog.Error("批量删除资源库图表信息失败"+"<br/>"+stack)
+			go alarm_msg.SendAlarmMsg("批量删除资源库图表信息失败"+"<br/>"+stack, 3)
+		}
+	}()
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		deleteCache = false
+		err = fmt.Errorf("系统处理中,请稍后重试!")
+		return
+	}
+	// 查询所有子分类
+	chartClassifyInfoList, err := data_manage.GetChartClassifyByLevelPath(chartClassifyInfo.LevelPath, chartClassifyInfo.Source)
+	if err != nil {
+		return
+	}
+	if len(chartClassifyInfoList) == 0 {
+		return
+	}
+	chartClassifyIdList := make([]string, 0)
+	for _, v := range chartClassifyInfoList {
+		chartClassifyIdList = append(chartClassifyIdList, strconv.Itoa(v.ChartClassifyId))
+	}
+	// 批量删除图表信息
+	condition := " AND source=? AND chart_classify_id in ? AND forum_chart_info_id > 0"
+	total, err := data_manage.GetChartInfoCountByCondition(condition, []interface{}{chartClassifyInfo.Source, chartClassifyIdList})
+	if err != nil {
+		return
+	}	
+	if total == 0 {
+		return
+	}
+	
+	offset := 0
+	pageSize := 100
+	success := 0
+
+	// 循环更新100个图表数据
+	for i := 0; offset < total; i++ {
+		// 查询需要更新的图表信息
+		chartInfos, e := data_manage.GetChartInfoListByCondition(condition, []interface{}{chartClassifyInfo.Source, chartClassifyIdList}, offset, pageSize)
+		if e != nil {
+			err = fmt.Errorf("查询需要更新的图表信息失败: %v", e)
+			return
+		}
+		if len(chartInfos) == 0 {
+			break
+		}
+		// 循环更新图表数据
+		for _, chartInfo := range chartInfos {
+			// 删除图表数据
+			er, msg := DeleteChart(chartInfo.ChartInfoId)
+			if er != nil {
+				er = fmt.Errorf("图表ID %d, 删除图表数据失败: %s, %v", chartInfo.ChartInfoId, msg, er)
+				tmpErr = append(tmpErr, er)
+				continue
+			}
+			success += 1
+		}
+
+		offset += pageSize
+	}
+	fmt.Println("删除图表数据完成, 删除图表数据总数:", success)
+	return	
+}
+
+// 批量删除资源库图表信息
+func ChartInfoDeleteBatchByChartInfoIds(chartInfoIds []int, chartClassifyId int) (err error) {
+	if utils.BusinessCode == "" || (utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeDebug && utils.BusinessCode != utils.BusinessCodeSandbox) {
+		return
+	}
+	var tmpErr []error
+	defer func() {
+		stack := ""
+		if err != nil {
+			stack = fmt.Sprintln(stack + err.Error())
+		}
+		if len(tmpErr) > 0 {
+			for _, v := range tmpErr {
+				stack = fmt.Sprintln(stack + v.Error())
+			}
+		}
+		if stack != "" {
+			utils.FileLog.Error("批量删除资源库图表信息失败"+"<br/>"+stack)
+			go alarm_msg.SendAlarmMsg("批量删除资源库图表信息失败"+"<br/>"+stack, 3)
+		}
+	}()
+	// 查询是否精选分类
+	chartClassifyInfo, err := data_manage.GetChartClassifyById(chartClassifyId)
+	if err != nil {
+		return
+	}
+	if chartClassifyInfo.IsSelected == 1 {
+		utils.FileLog.Info("精选分类,不需要删除图表信息")
+		return
+	}
+	// 非精选,需要下架图表,批量删除图表信息
+	condition := " AND source=1 AND chart_info_id in ? AND forum_chart_info_id > 0"
+	total, err := data_manage.GetChartInfoCountByCondition(condition, []interface{}{chartInfoIds})
+	if err != nil {
+		return
+	}	
+	if total == 0 {
+		utils.FileLog.Info("没有需要下架的图表")
+		return
+	}
+	
+	offset := 0
+	pageSize := 100
+	success := 0
+
+	// 循环更新100个图表数据
+	for i := 0; offset < total; i++ {
+		// 查询需要更新的图表信息
+		chartInfos, e := data_manage.GetChartInfoListByCondition(condition, []interface{}{chartInfoIds}, offset, pageSize)
+		if e != nil {
+			err = fmt.Errorf("查询需要更新的图表信息失败: %v", e)
+			return
+		}
+		if len(chartInfos) == 0 {
+			break
+		}
+		// 循环更新图表数据
+		for _, chartInfo := range chartInfos {
+			// 删除图表数据
+			er, msg := DeleteChart(chartInfo.ChartInfoId)
+			if er != nil {
+				er = fmt.Errorf("图表ID %d, 删除图表数据失败: %s, %v", chartInfo.ChartInfoId, msg, er)
+				tmpErr = append(tmpErr, er)
+				continue
+			}
+			success += 1
+		}
+
+		offset += pageSize
+	}
+	fmt.Println("删除图表数据完成, 删除图表数据总数:", success)
+	return	
+}
+
+// 修改分类状态,一键上架至资源库
+func SetChartClassifyResourceStatusUp(chartClassifyInfo *data_manage.ChartClassify, sysUser *system.Admin) (errMsg string, err error) {
+	if chartClassifyInfo.ResourceStatus == utils.ChartClassifyResourceStatusUp {
+		errMsg = "分类状态已为已上架, 无需重复操作"
+		err = fmt.Errorf("%s", errMsg)
+		return
+	}
+	// 判断是否是精选资源
+	if chartClassifyInfo.IsSelected != utils.ChartClassifyIsSelected {
+		errMsg = "分类状态已为已上架, 无需重复操作"
+		err = fmt.Errorf("%s", errMsg)
+		return
+	}
+	// 查询分类下的所有图表信息
+	err = data_manage.UpdateChartClassifyResourceStatus(chartClassifyInfo.Source, utils.ChartClassifyResourceStatusUp, chartClassifyInfo.LevelPath)
+	if err != nil {
+		errMsg = "更新分类状态失败"
+		err = fmt.Errorf("更新分类状态失败,Err:%w", err)
+		return
+	}
+
+	go ChartBatchUpdateAndUpload(chartClassifyInfo, sysUser)
+	
+	return
+}
+
+// 修改分类,一键从资源库下架
+func SetChartClassifyResourceStatusDown(chartClassifyInfo *data_manage.ChartClassify, sysUser *system.Admin) (errMsg string, err error) {
+	if chartClassifyInfo.ResourceStatus == utils.ChartClassifyResourceStatusDown {
+		errMsg = "分类状态已为已下架, 无需重复操作"
+		err = fmt.Errorf("%s", errMsg)
+		return
+	}
+	// 查询分类下的所有图表信息
+	err = data_manage.UpdateChartClassifyResourceStatus(chartClassifyInfo.Source, utils.ChartClassifyResourceStatusDown, chartClassifyInfo.LevelPath)
+	if err != nil {
+		errMsg = "更新分类状态失败"
+		err = fmt.Errorf("更新分类状态失败,Err:%w", err)
+		return
+	}
+
+	go ChartInfoDeleteBatch(chartClassifyInfo, sysUser)
+	
+	return
+}
+
+func getChartDescriptionWithAdminNameByChartInfoId(chartInfoId int) (list []*data_manage.ChartDescriptionReq, err error, errMsg string) {
+	descriptionList, err := data_manage.GetChartDescriptionByChartInfoId(chartInfoId)
+	if err != nil {
+		errMsg = "获取图表简介失败"
+		err = fmt.Errorf("获取图表简介失败,Err:" + err.Error())
+		return
+	}
+	// 查询创建者信息
+	adminIdList := make([]int, 0)
+	for _, v := range descriptionList {
+		adminIdList = append(adminIdList, v.SysUserId)
+	}
+	adminList, err := system.GetAdminListByIdList(adminIdList)
+	if err != nil {
+		errMsg = "获取创建者信息失败"
+		err = fmt.Errorf("获取创建者信息失败,Err:" + err.Error())
+		return
+	}
+	adminMap := make(map[int]string)
+	for _, v := range adminList {
+		adminMap[v.AdminId] = v.AdminName
+	}
+	for _, v := range descriptionList {
+		adminName, ok := adminMap[v.SysUserId]
+		if !ok {
+			adminName = ""
+		}
+		list = append(list, &data_manage.ChartDescriptionReq{
+			ChartInfoId: v.ChartInfoId,
+			Description: v.Description,
+			AdminName:   adminName,
+			SysUserId:   v.SysUserId,
+			SysUserRealName: v.SysUserRealName,
+			ModifyTime: v.ModifyTime,
+			CreateTime: v.CreateTime,
+		})
+	}
+	return
+}

+ 20 - 1
services/eta_forum/eta_forum_hub_lib.go

@@ -189,7 +189,26 @@ func GroupDeleteLib(req string) (resp *models.BaseResponse, err error) {
 	return
 }
 
-// post
+// ChartClassifySaveLib 上传图表分类信息
+func ChartClassifySaveLib(req string) (resp *models.BaseResponse, err error) {
+	_, resultByte, err := post(req, "/v1/chart_classify/save")
+	err = json.Unmarshal(resultByte, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+// ChartClassifySaveBatchLib 批量上传图表分类信息
+func ChartClassifySaveBatchLib(req string) (resp *models.BaseResponse, err error) {
+	_, resultByte, err := post(req, "/v1/chart_classify/batch_save")
+	err = json.Unmarshal(resultByte, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
 func post(paramStr string, urlStr string) (resp *models.BaseResponse, result []byte, err error) {
 	if utils.ETA_FORUM_HUB_URL == "" {
 		err = fmt.Errorf("ETA社区桥接服务地址为空")

+ 11 - 0
utils/constants.go

@@ -579,6 +579,17 @@ const (
 	DbNameWeekly      = "weekly_report"
 )
 
+// 图表分类设置精选资源分类
+const (
+	ChartClassifyIsSelected = 1 // 图表分类设置精选资源分类
+	ChartClassifyResourceStatusUp = 1 // 图表分类上架状态
+	ChartClassifyResourceStatusDown = 2 // 图表分类下架状态
+	ChartClassifyResourceStatusDefault = 0 // 图表分类默认状态
+)
+
+const (
+	CACHE_KEY_EDB_DATA_UPDATE_LOG = "eta_forum:edb_data_update_log" // 经济数据库数据更新日志
+)
 const (
 	DATA_SOURCE_NAME_RADISH_RESEARCH = "萝卜投研" // 萝卜投研 -> 105
 )