Forráskód Böngészése

知识库分类管理

xyxie 5 hónapja
szülő
commit
6f5abcd443

+ 445 - 0
controllers/knowledge_classify.go

@@ -0,0 +1,445 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta_gn/eta_api/models"
+	"eta_gn/eta_api/models/knowledge"
+	knowledgeServ "eta_gn/eta_api/services/knowledge"
+)
+
+// 分类
+type KnowledgeClassifyController struct {
+	BaseAuthController
+}
+
+// @Title 新增分类接口
+// @Description 新增分类
+// @Param	request	body knowledge.ClassifyAddReq true "type json string"
+// @Success 200 新增成功
+// @router /classify/add [post]
+func (this *KnowledgeClassifyController) Add() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req knowledge.ClassifyAddReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ClassifyName == "" {
+		br.Msg = "分类名称不可为空"
+		return
+	}
+
+	// 新增分类
+	err, errMsg, isSentEmail := knowledgeServ.AddKnowledgeClassify(req.ClassifyName, req.ParentId, req.ResourceType)
+	if err != nil {
+		br.Msg = "添加失败"
+		if errMsg != "" {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "添加失败,Err:" + err.Error()
+		br.IsSendEmail = isSentEmail
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "新增成功"
+}
+
+// @Title 删除分类-检测接口
+// @Description 删除分类-信息检测,是否符合删除条件
+// @Param   ClassifyId   query   int  true       "分类ID"
+// @Success 200 {object} knowledge.CheckDeleteClassifyResp
+// @router /classify/checkDelete [get]
+func (this *KnowledgeClassifyController) CheckDeleteClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	classifyId, err := this.GetInt("ClassifyId")
+	if classifyId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	classify, err := knowledgeObj.GetClassifyById(classifyId)
+	if err != nil {
+		br.Msg = "获取信息失败"
+		br.ErrMsg = "获取信息失败,Err:" + err.Error()
+		return
+	}
+	resp := new(knowledge.CheckDeleteClassifyResp)
+	if classify == nil {
+		br.Msg = "分类不存在"
+		resp.Code = 1
+		resp.Msg = "分类不存在"
+		br.Data = resp
+		br.Ret = 200
+		br.Success = true
+		return
+	}
+
+	//判断分类是否关联了报告
+	if classify.ParentId > 0 {
+		count, err := knowledgeObj.GetReportCountByClassifyId(classifyId)
+		if err != nil {
+			br.Msg = "获取信息失败"
+			br.ErrMsg = "获取信息失败,Err:" + err.Error()
+			return
+		}
+		if count > 0 {
+			resp.Code = 2
+			resp.Msg = "该分类有关联报告,不允许删除"
+			br.Data = resp
+			br.Ret = 200
+			br.Msg = "该分类有关联报告,不允许删除"
+			br.Success = true
+			return
+		}
+	} else {
+		subCount, err := knowledgeObj.GetClassifySubCountByClassifyId(classifyId)
+		if err != nil {
+			br.Msg = "获取信息失败"
+			br.ErrMsg = "获取信息失败,Err:" + err.Error()
+			return
+		}
+		if subCount > 0 {
+			resp.Code = 3
+			resp.Msg = "二级分类有关联报告,不允许删除"
+			br.Data = resp
+			br.Ret = 200
+			br.Msg = "二级分类有关联报告,不允许删除"
+			br.Success = true
+			return
+		}
+		subTotal, err := knowledgeObj.GetClassifySubCountByParentId(classifyId)
+		if err != nil {
+			br.Msg = "获取信息失败"
+			br.ErrMsg = "获取信息失败,Err:" + err.Error()
+			return
+		}
+		if subTotal > 0 {
+			resp.Code = 4
+			resp.Msg = "请先删除该分类下关联分类"
+			br.Data = resp
+			br.Ret = 200
+			br.Msg = "请先删除该分类下关联分类"
+			br.Success = true
+			return
+		}
+	}
+
+	resp.Code = 0
+	resp.Msg = "检测完成,可进行删除操作"
+	br.Ret = 200
+	br.Data = resp
+	br.Success = true
+	br.Msg = "检测成功"
+}
+
+// @Title 删除分类接口
+// @Description 删除分类
+// @Param	request	body knowledge.DeleteClassifyReq true "type json string"
+// @Success 200 Ret=200,删除成功
+// @router /classify/delete [post]
+func (this *KnowledgeClassifyController) Delete() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req knowledge.DeleteClassifyReq
+	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 = "参数错误"
+		return
+	}
+	//todo 是否需要删除接口
+	/*br.Msg = "报告分类不允许删除"
+	br.IsSendEmail = false
+	return*/
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	item, err := knowledgeObj.GetClassifyById(req.ClassifyId)
+	if err != nil {
+		br.Msg = "获取信息失败"
+		br.ErrMsg = "获取信息失败,Err:" + err.Error()
+		return
+	}
+	if item == nil {
+		br.Msg = "分类不存在"
+		return
+	}
+	err = knowledgeObj.Delete(req.ClassifyId)
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+
+	// 被删除是二级分类且关联电话会时, 同步FICC活动分类
+	//if item.ParentId > 0 && item.RelateTel == 1 {
+	//	go func() {
+	//		_ = yb.SyncClassifyAndFiccActivityType()
+	//	}()
+	//}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "删除成功"
+}
+
+// @Title 修改分类接口
+// @Description 修改分类
+// @Param	request	body knowledge.EditClassifyReq true "type json string"
+// @Success 200 Ret=200,修改成功
+// @router /classify/edit [post]
+func (this *KnowledgeClassifyController) Edit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req knowledge.EditClassifyReq
+	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 = "参数错误"
+		return
+	}
+	if req.ClassifyName == "" {
+		br.Msg = "分类名称不可为空"
+		return
+	}
+
+	// 修改分类
+	err, errMsg, isSentEmail := knowledgeServ.EditKnowledgeClassify(req.ClassifyId, req.ParentId, req.ClassifyName)
+	if err != nil {
+		br.Msg = "修改失败"
+		if errMsg != "" {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "修改失败,Err:" + err.Error()
+		br.IsSendEmail = isSentEmail
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "修改成功"
+}
+
+// ParentClassify
+// @Title 获取父级分类接口
+// @Description 获取父级分类
+// @Success 200 {object} knowledge.Classify
+// @router /classify/parent [get]
+func (this *KnowledgeClassifyController) ParentClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	items, err := knowledgeObj.GetAllClassify()
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+
+	classifyIds := make([]int, 0)
+	for i := range items {
+		classifyIds = append(classifyIds, items[i].ClassifyId)
+	}
+	classifyLen := len(classifyIds)
+	if classifyLen == 0 {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		return
+	}
+
+	resp := make([]*knowledge.KnowledgeClassifyItem, 0)
+	for i := range items {
+		resp = append(resp, &knowledge.KnowledgeClassifyItem{
+			KnowledgeClassify: *items[i],
+		})
+	}
+
+	resp = knowledgeServ.GetClassifyTreeRecursive(resp, 0)
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// @Title 根据id获取分类详情接口
+// @Description 根据id获取分类详情
+// @Param	request	body knowledge.FindByIdClassifyReq true "type json string"
+// @Success 200 {object} knowledge.Classify
+// @router /classify/findById [get]
+func (this *KnowledgeClassifyController) FindByIdClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req knowledge.FindByIdClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	items, err := knowledgeObj.GetClassifyById(req.ClassifyId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	br.Data = items
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// @Title 获取分类列表
+// @Description 获取分类列表
+// @Param   KeyWord   query   string  true       "检索关键词"
+// @Param   CompanyType   query   string  false       "产品类型,枚举值:'ficc','权益';不传默认返回全部"
+// @Param   HideDayWeek   query   int  false       "是否隐藏晨周报"
+// @Success 200 {object} knowledge.Classify
+// @router /classify/list [get]
+func (this *KnowledgeClassifyController) ListClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	keyWord := this.GetString("KeyWord")
+	reqEnabled, _ := this.GetInt("Enabled", -1)
+
+	enabled := -1
+	if reqEnabled == 1 {
+		enabled = reqEnabled
+	}
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	list, err := knowledgeObj.GetClassifyListByKeyword(keyWord, enabled)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+
+	if keyWord != `` {
+		idMap := make(map[int]bool)
+
+		currParentClassifyIdList := make([]int, 0)
+		for _, v := range list {
+			idMap[v.ClassifyId] = true
+			if v.ParentId > 0 {
+				currParentClassifyIdList = append(currParentClassifyIdList, v.ParentId)
+			}
+		}
+
+		findList := list
+		list = make([]*knowledge.KnowledgeClassifyItem, 0)
+
+		tmpList, tmpErr := knowledgeServ.GetParentClassifyListByParentIdList(currParentClassifyIdList)
+		if tmpErr != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取上级分类信息失败,Err:" + tmpErr.Error()
+			return
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.ClassifyId]; !ok {
+				list = append(list, v)
+			}
+		}
+
+		list = append(list, findList...)
+	}
+
+	classifyIdList := make([]int, 0)
+	for i := range list {
+		classifyIdList = append(classifyIdList, list[i].ClassifyId)
+	}
+	parentIdLen := len(classifyIdList)
+	if parentIdLen == 0 {
+		resp := &knowledge.KnowledgeClassifyListResp{
+			List: list,
+		}
+		br.Data = resp
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		return
+	}
+
+	// 先将分类列表排序
+	knowledgeServ.SortClassifyListBySortAndCreateTime(list)
+	// 接着转换结构
+	list = knowledgeServ.GetClassifyListTreeRecursive(list, 0)
+
+	resp := new(knowledge.KnowledgeClassifyListResp)
+	resp.List = list
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Move
+// @Title 移动分类接口
+// @Description 移动分类
+// @Param	request	body knowledge.ClassifyMoveReq true "type json string"
+// @Success 200 新增成功
+// @router /classify/move [post]
+func (this *KnowledgeClassifyController) Move() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req knowledge.ClassifyMoveReq
+	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 = "请选择分类"
+		return
+	}
+	e, msg := knowledgeServ.MoveKnowledgeClassify(req)
+	if e != nil {
+		br.Msg = msg
+		br.ErrMsg = "移动分类失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 465 - 0
models/knowledge/knowledge_classify.go

@@ -0,0 +1,465 @@
+package knowledge
+
+import (
+	"eta_gn/eta_api/global"
+	"eta_gn/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+type KnowledgeClassify struct {
+	ClassifyId   int       `gorm:"primaryKey;autoIncrement;column:classify_id"`
+	ClassifyName string    `gorm:"column:classify_name;default:'';type:varchar(125);not null"` // 注意:varchar的默认长度可能需要根据实际情况调整
+	Sort         int       `gorm:"column:sort;default:0;type:tinyint"`
+	ParentId     int       `gorm:"column:parent_id;default:0;type:int"`
+	CreateTime   time.Time `gorm:"column:create_time;default:CURRENT_TIMESTAMP"`
+	ModifyTime   time.Time `gorm:"column:modify_time;default:CURRENT_TIMESTAMP"`
+	Enabled      int       `gorm:"column:enabled;default:1;type:tinyint"`
+	Level        int       `gorm:"column:level;default:0;type:bigint"`
+	ResourceType int       `gorm:"column:resource_type;default:0;not null;type:tinyint"`
+	HasChild     int       `gorm:"column:has_child;default:0;type:int"`
+}
+
+func (k *KnowledgeClassify) TableName() string {
+	return "knowledge_classify"
+}
+
+func (k *KnowledgeClassify) GetPrimaryKey() string {
+	return "classify_id"
+}
+
+func (k *KnowledgeClassify) GetClassifyByName(classifyName string, parentId, resourceType int) (item *KnowledgeClassify, err error) {
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE classify_name=? AND parent_id=? AND resource_type=?`, k.TableName())
+	err = global.DmSQL["rddp"].Raw(sql, classifyName, parentId, resourceType).First(&item).Error
+	return
+}
+
+func (k *KnowledgeClassify) GetClassifyById(classifyId int) (item *KnowledgeClassify, err error) {
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s=? `, k.TableName(), k.GetPrimaryKey())
+	err = global.DmSQL["rddp"].Raw(sql, classifyId).First(&item).Error
+	return
+}
+
+// 添加分类
+func (k *KnowledgeClassify) Add(item *KnowledgeClassify) (err error) {
+	err = global.DmSQL["rddp"].Create(item).Error
+	return
+}
+
+func (k *KnowledgeClassify) GetReportCountByClassifyId(classifyId int) (count int, err error) {
+	sql := `SELECT COUNT(1) as num FROM knowledge_resource WHERE classify_id=? `
+	err = global.DmSQL["rddp"].Raw(sql, classifyId).First(&count).Error
+	return
+}
+
+func (k *KnowledgeClassify) GetClassifySubCountByClassifyId(classifyId int) (count int, err error) {
+
+	sql := `SELECT COUNT(1) as num FROM knowledge_classify AS a
+        INNER JOIN knowledge_resource AS b ON a.id=b.classify_id_second
+        WHERE a.parent_id=? `
+	//o := orm.NewOrmUsingDB("rddp")
+	//err = o.Raw(sql, classifyId).QueryRow(&count)
+	err = global.DmSQL["rddp"].Raw(sql, classifyId).First(&count).Error
+	return
+}
+
+func (k *KnowledgeClassify) GetClassifySubCountByParentId(classifyId int) (count int, err error) {
+	sqlCount := `
+	SELECT COUNT(1) as num FROM knowledge_classify AS a
+	WHERE a.parent_id=? `
+	//o := orm.NewOrmUsingDB("rddp")
+	//err = o.Raw(sqlCount, classifyId).QueryRow(&count)
+	err = global.DmSQL["rddp"].Raw(sqlCount, classifyId).Scan(&count).Error
+	return
+}
+
+// 删除分类
+func (k *KnowledgeClassify) Delete(classifyId int) (err error) {
+	sql := `DELETE FROM knowledge_classify WHERE classify_id =? `
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Raw(sql, classifyId).Exec()
+	err = global.DmSQL["rddp"].Exec(sql, classifyId).Error
+	if err != nil {
+		return
+	}
+	return
+}
+
+type KnowledgeClassifyItem struct {
+	KnowledgeClassify
+	Child []*KnowledgeClassifyItem `gorm:"-"`
+}
+
+type KnowledgeClassifyListResp struct {
+	List []*KnowledgeClassifyItem
+}
+
+type ClassifyPermissionListResp struct {
+	List   []*KnowledgeClassifyItem
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+// 获取分类列表
+func (k *KnowledgeClassify) GetClassifyList(keyWord string, enabled int) (items []*KnowledgeClassifyItem, err error) {
+	sql := ``
+	companyTypeSqlStr := ``
+	if enabled == 1 {
+		companyTypeSqlStr += ` AND enabled = 1 `
+	}
+	pars := make([]interface{}, 0)
+	if keyWord != "" {
+		sql = `SELECT * FROM (
+                   SELECT * FROM classify
+                   WHERE parent_id=0 ` + companyTypeSqlStr + `  AND classify_name LIKE ?
+                   UNION
+                   SELECT * FROM classify
+                   WHERE classify_id IN( SELECT parent_id FROM classify
+                   WHERE parent_id>0 ` + companyTypeSqlStr + `  AND classify_name LIKE ? )
+                   )AS t
+                   ORDER BY sort ASC,create_time ASC`
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 2)
+	} else {
+		sql = `SELECT * FROM knowledge_classify WHERE parent_id=0 ` + companyTypeSqlStr
+
+		sql += ` ORDER BY sort ASC, create_time ASC`
+	}
+	pars = append(pars)
+
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Raw(sql, pars...).QueryRows(&items)
+	err = global.DmSQL["rddp"].Raw(sql, pars).Find(&items).Error
+	return
+}
+
+func (k *KnowledgeClassify) GetClassifyListCount(keyWord, companyType string, hideDayWeek int) (count int, err error) {
+	sqlCount := ``
+	pars := make([]interface{}, 0)
+
+	if keyWord != "" {
+		sqlCount = `SELECT  COUNT(1) AS count FROM (
+               SELECT * FROM classify
+               WHERE parent_id=0  AND classify_name LIKE ?
+               UNION
+               SELECT * FROM classify
+               WHERE classify_id IN(SELECT parent_id FROM classify
+               WHERE parent_id>0 AND classify_name LIKE ? )
+               )AS t `
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 2)
+	} else {
+		sqlCount = `SELECT COUNT(1) AS count FROM knowledge_classify WHERE parent_id=0 `
+		if hideDayWeek == 1 {
+			sqlCount += ` AND classify_name <> '晨报' AND classify_name <> '周报' `
+		}
+	}
+	//o := orm.NewOrmUsingDB("rddp")
+	//err = o.Raw(sqlCount, pars...).QueryRow(&count)
+	err = global.DmSQL["rddp"].Raw(sqlCount, pars...).Scan(&count).Error
+	return
+}
+
+type CheckDeleteClassifyReq struct {
+	ClassifyId int `description:"分类ID"`
+}
+
+type CheckDeleteClassifyResp struct {
+	Code int    `description:"编码:0:检测成功,可进行删除,1:分类不存在,2:该分类有关联报告,不允许删除,3:二级分类有关联报告,不允许删除,4:该分类下有关联分类,是否确认全部删除"`
+	Msg  string `description:"描述信息"`
+}
+
+type ClassifyAddReq struct {
+	ClassifyName string `description:"分类名称"`
+	ParentId     int    `description:"父级分类id,没有父级分类传0"`
+	ResourceType int    `description:"分类类型:0事件库,1政策库,2观点库,3知识库"`
+}
+
+type DeleteClassifyReq struct {
+	ClassifyId int `description:"分类ID"`
+}
+
+type EditClassifyReq struct {
+	ClassifyId int `description:"分类ID"`
+	ClassifyAddReq
+}
+
+type FindByIdClassifyReq struct {
+	ClassifyId int `description:"分类ID"`
+}
+
+func (k *KnowledgeClassify) GetClassifyChild(parentId int, keyWord string) (items []*KnowledgeClassify, err error) {
+	sql := ``
+	pars := make([]interface{}, 0)
+	if keyWord != "" {
+		sql = `SELECT * FROM knowledge_classify WHERE classify_name LIKE ? AND parent_id=? ORDER BY create_time ASC `
+		pars = append(pars, utils.GetLikeKeyword(keyWord))
+	} else {
+		sql = `SELECT * FROM knowledge_classify WHERE parent_id=? ORDER BY create_time ASC `
+	}
+	pars = append(pars, parentId)
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Raw(sql, pars...).QueryRows(&items)
+	err = global.DmSQL["rddp"].Raw(sql, pars...).Find(&items).Error
+	return
+}
+
+func (k *KnowledgeClassify) GetClassifyChildByParentIds(parentId []int, keyWord string, enabled int) (items []*KnowledgeClassify, err error) {
+	parentIdLen := len(parentId)
+	if parentIdLen == 0 {
+		return
+	}
+
+	sql := ``
+	pars := make([]interface{}, 0)
+	pars = append(pars, parentId)
+	if keyWord != "" {
+		sql = `SELECT * FROM knowledge_classify WHERE parent_id IN (` + utils.GetOrmInReplace(parentIdLen) + `) AND classify_name LIKE ? `
+		pars = append(pars, utils.GetLikeKeyword(keyWord))
+	} else {
+		sql = `SELECT * FROM knowledge_classify WHERE parent_id IN (` + utils.GetOrmInReplace(parentIdLen) + `) `
+	}
+
+	if enabled == 1 {
+		sql += ` AND enabled=1 `
+	}
+	sql += ` ORDER BY create_time ASC `
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Raw(sql, pars...).QueryRows(&items)
+	err = global.DmSQL["rddp"].Raw(sql, pars...).Find(&items).Error
+	return
+}
+
+// EditClassifyPermissionReq 编辑分类权限请求
+type EditClassifyPermissionReq struct {
+	ClassifyId            int   `description:"分类ID"`
+	ChartPermissionIdList []int `description:"权限id数组"`
+}
+
+// GetAllClassify 获取所有分类
+func (k *KnowledgeClassify) GetAllClassify() (list []*KnowledgeClassify, err error) {
+	//o := orm.NewOrmUsingDB("rddp")
+	//sql := ` SELECT * FROM classify `
+	//_, err = o.Raw(sql).QueryRows(&list)
+	sql := ` SELECT * FROM knowledge_classify `
+	err = global.DmSQL["rddp"].Raw(sql).Find(&list).Error
+	return
+}
+
+// GetClassifyByKeyword 名称获取分类
+func (k *KnowledgeClassify) GetClassifyByKeyword(keyword string) (item *KnowledgeClassify, err error) {
+	//o := orm.NewOrmUsingDB("rddp")
+	//sql := ` SELECT * FROM knowledge_classify WHERE classify_name = ? LIMIT 1 `
+	//err = o.Raw(sql, keyword).QueryRow(&item)
+	sql := ` SELECT * FROM knowledge_classify WHERE classify_name = ? LIMIT 1 `
+	err = global.DmSQL["rddp"].Raw(sql, keyword).Find(&item).Error
+	return
+}
+
+// UpdateClassify 更新分类
+func (k *KnowledgeClassify) Update(cols []string) (err error) {
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Update(classifyInfo, cols...)
+	err = global.DmSQL["rddp"].Select(cols).Updates(k).Error
+	return
+}
+
+// SimpleClassifyList 简版分类列表
+type SimpleClassifyList struct {
+	Id           int    `description:"分类ID"`
+	ClassifyName string `description:"分类名称"`
+	ParentId     int    `description:"父级ID"`
+	Sort         int    `description:"排序"`
+	Child        []*SimpleClassifyList
+}
+
+// GetClassifyByCondition 获取分类列表
+func (k *KnowledgeClassify) GetClassifyByCondition(condition, orderRule string, pars []interface{}) (items []*SimpleClassifyList, err error) {
+
+	sql := `SELECT * FROM knowledge_classify WHERE 1 = 1 `
+	if condition != `` {
+		sql += condition
+	}
+	order := `sort ASC, create_time ASC`
+	if orderRule != `` {
+		order = orderRule
+	}
+	sql += ` ORDER BY ` + order
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Raw(sql, pars).QueryRows(&items)
+	err = global.DmSQL["rddp"].Raw(sql, pars...).Find(&items).Error
+	return
+}
+
+// UpdateChildClassifyRelateSetting 更新子分类关联设置
+func (k *KnowledgeClassify) UpdateChildClassifyRelateSetting(parentId, relateTel, relateVideo int) (err error) {
+	//o := orm.NewOrmUsingDB("rddp")
+	//sql := `UPDATE knowledge_classify SET relate_tel = ?, relate_video = ? WHERE parent_id = ?`
+	//_, err = o.Raw(sql, relateTel, relateVideo, parentId).Exec()
+	sql := `UPDATE knowledge_classify SET relate_tel = ?, relate_video = ? WHERE parent_id = ?`
+	err = global.DmSQL["rddp"].Exec(sql, relateTel, relateVideo, parentId).Error
+	return
+}
+
+// RelateTelSecClassifyWithPermissions 关联了电话会的二级分类及权限
+type RelateTelSecClassifyWithPermissions struct {
+	Id                 int    `description:"分类ID"`
+	ClassifyName       string `description:"分类名称"`
+	ChartPermissionIds string `description:"权限IDs"`
+}
+
+// UpdateClassifySortByParentId 根据父类id更新排序
+func (k *KnowledgeClassify) UpdateClassifySortByParentId(parentId, permissionId, nowSort int, updateSort string) (err error) {
+
+	sql := ` update knowledge_classify set sort = ` + updateSort + ` WHERE parent_id=? AND sort > ? `
+	if permissionId > 0 {
+		sql += ` or ( classify_id > ` + fmt.Sprint(permissionId) + ` and sort = ` + fmt.Sprint(nowSort) + `)`
+	}
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Raw(sql, parentId, nowSort).Exec()
+	err = global.DmSQL["rddp"].Exec(sql, parentId, nowSort).Error
+	return
+}
+
+// GetMaxSortByParentId 获取最大的排序值
+func (k *KnowledgeClassify) GetMaxSortByParentId(parentId int) (maxSort int, err error) {
+	//o := orm.NewOrmUsingDB("rddp")
+	//sql := `SELECT max(sort) AS sort FROM knowledge_classify WHERE parent_id = ? `
+	//err = o.Raw(sql, parentId).QueryRow(&maxSort)
+	sql := `SELECT max(sort) AS sort FROM knowledge_classify WHERE parent_id = ? `
+	err = global.DmSQL["rddp"].Raw(sql, parentId).Scan(&maxSort).Error
+	return
+}
+
+// GetMaxSort 获取最大的排序值
+func (k *KnowledgeClassify) GetMaxSort() (maxSort int, err error) {
+	//o := orm.NewOrmUsingDB("rddp")
+	//sql := `SELECT max(sort) AS sort FROM classify`
+	//err = o.Raw(sql).QueryRow(&maxSort)
+	sql := `SELECT max(sort) AS sort FROM classify`
+	err = global.DmSQL["rddp"].Raw(sql).Scan(&maxSort).Error
+	return
+}
+
+// GetFirstClassifyByParentId 获取当前父级分类下,且排序数相同 的排序第一条的数据
+func (k *KnowledgeClassify) GetFirstClassifyByParentId(parentId int) (item *KnowledgeClassify, err error) {
+	sql := `SELECT * FROM knowledge_classify WHERE parent_id = ? order by sort asc, classify_id asc limit 1`
+	err = global.DmSQL["rddp"].Raw(sql, parentId).First(&item).Error
+	return
+}
+
+type ClassifyMoveReq struct {
+	ClassifyId     int `description:"分类ID"`
+	PrevClassifyId int `description:"上一个兄弟节点分类id"`
+	NextClassifyId int `description:"下一个兄弟节点分类id"`
+}
+
+type ClassifySetEnabledReq struct {
+	ClassifyId int `description:"分类ID"`
+	Enabled    int `description:"是否可用,1可用,0禁用"`
+}
+
+func (k *KnowledgeClassify) SetEnabled(id, enabled int) (err error) {
+	to := global.DmSQL["rddp"].Begin()
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	sql := ` UPDATE knowledge_classify SET enabled =?  WHERE classify_id = ?`
+	err = to.Exec(sql, enabled, id).Error
+	if err != nil {
+		return
+	}
+	sql = ` UPDATE knowledge_classify SET enabled =?  WHERE parent_id = ?`
+	err = to.Exec(sql, enabled, id).Error
+	if err != nil {
+		return
+	}
+	return
+}
+
+// GetCountClassifyChildByParentId
+// @Description: 获取父级分类下子分类数量
+// @author: Roc
+// @datetime 2024-06-17 10:58:46
+// @param parentId int
+// @return total int
+// @return err error
+func (k *KnowledgeClassify) GetCountClassifyChildByParentId(parentId int) (total int, err error) {
+	//o := orm.NewOrmUsingDB("rddp")
+	//sql := `SELECT count(1) AS total FROM knowledge_classify WHERE parent_id = ? `
+	//err = o.Raw(sql, parentId).QueryRow(&total)
+	sql := fmt.Sprintf(`SELECT count(1) AS total FROM %s WHERE parent_id = ? `, k.TableName())
+	err = global.DmSQL["rddp"].Raw(sql, parentId).Scan(&total).Error
+	return
+}
+
+// GetClassifyListByKeyword
+// @Description: 获取分类列表
+// @author: Roc
+// @datetime 2024-06-19 09:49:33
+// @param keyWord string
+// @param enabled int
+// @return items []*KnowledgeClassifyList
+// @return err error
+func (k *KnowledgeClassify) GetClassifyListByKeyword(keyWord string, enabled int) (items []*KnowledgeClassifyItem, err error) {
+	sql := ``
+	pars := make([]interface{}, 0)
+
+	sql = `SELECT * FROM knowledge_classify WHERE 1=1 `
+	if enabled == 1 {
+		sql += ` AND enabled = 1 `
+	}
+
+	if keyWord != `` {
+		sql += ` AND classify_name LIKE ? `
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 1)
+	}
+	sql += ` ORDER BY sort ASC, create_time ASC`
+
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Raw(sql, pars).QueryRows(&items)
+	err = global.DmSQL["rddp"].Raw(sql, pars...).Find(&items).Error
+	return
+}
+
+// GetClassifyListByParentIdList
+// @Description: 获取分类列表
+// @author: Roc
+// @datetime 2024-06-19 09:49:33
+// @param keyWord string
+// @param enabled int
+// @return items []*KnowledgeClassifyList
+// @return err error
+func (k *KnowledgeClassify) GetClassifyListByParentIdList(parentClassifyIdList []int) (items []*KnowledgeClassifyItem, err error) {
+	num := len(parentClassifyIdList)
+	if num <= 0 {
+		return
+	}
+	sql := `SELECT * FROM knowledge_classify WHERE classify_id in (` + utils.GetOrmInReplace(num) + `) ORDER BY sort ASC, create_time ASC`
+
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Raw(sql, parentClassifyIdList).QueryRows(&items)
+	err = global.DmSQL["rddp"].Raw(sql, parentClassifyIdList).Find(&items).Error
+	return
+}
+
+// GetClassifyListByIdList
+// @Description: 根据指标ID列表,获取分类列表
+// @author: Roc
+// @datetime 2024-06-27 15:23:57
+// @param classifyIdList []int
+// @return items []*KnowledgeClassify
+// @return err error
+func (k *KnowledgeClassify) GetClassifyListByIdList(classifyIdList []int) (items []*KnowledgeClassify, err error) {
+	num := len(classifyIdList)
+	if num <= 0 {
+		return
+	}
+	sql := `SELECT * FROM knowledge_classify WHERE classify_id IN (` + utils.GetOrmInReplace(num) + `) `
+	//o := orm.NewOrmUsingDB("rddp")
+	//_, err = o.Raw(sql, classifyIdList).QueryRows(&items)
+	err = global.DmSQL["rddp"].Raw(sql, classifyIdList).Find(&items).Error
+	return
+}

+ 30 - 0
models/knowledge/knowledge_resource.go

@@ -0,0 +1,30 @@
+package knowledge
+
+import "time"
+
+type KnowledgeResource struct {
+	KnowledgeResourceId int       `gorm:"column:knowledge_resource_id;;primaryKey;autoIncrement"`
+	ResourceType        int       `gorm:"column:resource_type;"`
+	ClassifyId          int       `gorm:"column:classify_id"`
+	title               string    `gorm:"column:title;"`
+	CreateTime          string    `gorm:"column:create_time" description:"创建时间"`
+	ModifyTime          time.Time `gorm:"column:modify_time;autoUpdateTime" description:"修改时间"`
+	State               int       `gorm:"column:state" description:"1:未发布;2:已发布;3-待提交;4-待审批;5-已驳回;6-已通过"`
+	Content             string    `gorm:"column:content"`
+	ResourceCode        string    `gorm:"column:resource_code"`
+	AdminId             int       `gorm:"column:admin_id" description:"创建者账号"`
+	AdminRealName       string    `gorm:"column:admin_real_name" description:"创建者姓名"`
+	SourceFrom          string    `gorm:"column:source_from"`
+	TagId               int       `gorm:"column:tag_id;default:0;NOT NULL"`
+	StartTime           string    `gorm:"column:start_time"`
+	EndTime             string    `gorm:"column:end_time"`
+}
+
+func (k *KnowledgeResource) TableName() string {
+	return "knowledge_resource"
+}
+
+// 查询列表
+func (k *KnowledgeResource) QueryList(condition string, pars []interface{}) (items []*KnowledgeResource, err error) {
+	return
+}

+ 9 - 0
models/knowledge/knowledge_tags.go

@@ -0,0 +1,9 @@
+package knowledge
+
+type KnowledgeTags struct {
+	TagsId       int    `gorm:"primaryKey;autoIncrement;column:tags_id"`
+	TagsName     string `gorm:"column:tags_name;default:'';type:varchar(100);not null"`
+	TagsType     int    `gorm:"column:tags_type;default:0;type:tinyint"`
+	Sort         int    `gorm:"column:sort;default:0;type:tinyint"`
+	ResourceType int    `gorm:"column:resource_type;default:0;not null;type:tinyint"`
+}

+ 72 - 0
routers/commentsRouter.go

@@ -8449,6 +8449,78 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/classify/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"],
+        beego.ControllerComments{
+            Method: "CheckDeleteClassify",
+            Router: `/classify/checkDelete`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"],
+        beego.ControllerComments{
+            Method: "Delete",
+            Router: `/classify/delete`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"],
+        beego.ControllerComments{
+            Method: "Edit",
+            Router: `/classify/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"],
+        beego.ControllerComments{
+            Method: "FindByIdClassify",
+            Router: `/classify/findById`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"],
+        beego.ControllerComments{
+            Method: "ListClassify",
+            Router: `/classify/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"],
+        beego.ControllerComments{
+            Method: "Move",
+            Router: `/classify/move`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:KnowledgeClassifyController"],
+        beego.ControllerComments{
+            Method: "ParentClassify",
+            Router: `/classify/parent`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta_gn/eta_api/controllers:MeetingProbabilitiesController"] = append(beego.GlobalControllerRouter["eta_gn/eta_api/controllers:MeetingProbabilitiesController"],
         beego.ControllerComments{
             Method: "Detail",

+ 5 - 0
routers/router.go

@@ -387,6 +387,11 @@ func init() {
 				&range_analysis.RangeChartChartInfoController{},
 			),
 		),
+		web.NSNamespace("/knowledge",
+			web.NSInclude(
+				&controllers.KnowledgeClassifyController{},
+			),
+		),
 	)
 	web.AddNamespace(ns)
 }

+ 507 - 0
services/knowledge/classify.go

@@ -0,0 +1,507 @@
+package knowledge
+
+import (
+	"errors"
+	"eta_gn/eta_api/models/knowledge"
+	"eta_gn/eta_api/utils"
+	"fmt"
+	"sort"
+	"time"
+)
+
+// MoveKnowledgeClassify 移动分类
+func MoveKnowledgeClassify(req knowledge.ClassifyMoveReq) (err error, errMsg string) {
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	classifyId := req.ClassifyId
+	prevClassifyId := req.PrevClassifyId
+	nextClassifyId := req.NextClassifyId
+
+	//如果有传入 上一个兄弟节点分类id
+	var (
+		classifyInfo *knowledge.KnowledgeClassify
+		prevClassify *knowledge.KnowledgeClassify
+		nextClassify *knowledge.KnowledgeClassify
+
+		prevSort int
+		nextSort int
+	)
+
+	// 移动对象为分类, 判断权限
+	classifyInfo, err = knowledgeObj.GetClassifyById(classifyId)
+	if err != nil {
+		if utils.IsErrNoRow(err) {
+			errMsg = "分类不存在, 请刷新页面"
+			err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
+			return
+		}
+		errMsg = "移动失败"
+		err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
+		return
+	} else if classifyInfo.ClassifyId == 0 {
+		errMsg = "分类不存在, 请刷新页面"
+		err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
+		return
+	}
+
+	parentClassifyId := classifyInfo.ParentId
+	if prevClassifyId > 0 {
+		prevClassify, err = knowledgeObj.GetClassifyById(prevClassifyId)
+		if err != nil {
+			if utils.IsErrNoRow(err) {
+				errMsg = "上一个分类不存在, 请刷新页面"
+				err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = fmt.Errorf("获取上一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		if prevClassify.ParentId != parentClassifyId {
+			errMsg = "禁止拖动到其他节点"
+			err = fmt.Errorf(errMsg)
+			return
+		}
+		prevSort = prevClassify.Sort
+	}
+
+	if nextClassifyId > 0 {
+		//下一个兄弟节点
+		nextClassify, err = knowledgeObj.GetClassifyById(nextClassifyId)
+		if err != nil {
+			if utils.IsErrNoRow(err) {
+				errMsg = "下一个分类不存在, 请刷新页面"
+				err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = fmt.Errorf("获取下一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		if nextClassify.ParentId != parentClassifyId {
+			errMsg = "禁止拖动到其他节点"
+			err = fmt.Errorf(errMsg)
+			return
+		}
+		nextSort = nextClassify.Sort
+	}
+
+	err, errMsg = moveKnowledgeClassify(classifyInfo, prevClassify, nextClassify, parentClassifyId, prevSort, nextSort)
+	return
+}
+
+// moveKnowledgeClassify 移动分类
+func moveKnowledgeClassify(classifyInfo, prevClassify, nextClassify *knowledge.KnowledgeClassify, parentId, prevSort, nextSort int) (err error, errMsg string) {
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	updateCol := make([]string, 0)
+
+	//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
+	if classifyInfo.ParentId != parentId {
+		errMsg = "移动失败"
+		err = fmt.Errorf("不支持目录层级变更")
+		return
+	}
+
+	if prevSort > 0 {
+		//如果是移动在两个兄弟节点之间
+		if nextSort > 0 {
+			//下一个兄弟节点
+			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+			if prevSort == nextSort || prevSort == classifyInfo.Sort {
+				//变更兄弟节点的排序
+				updateSortStr := `sort + 2`
+
+				//变更分类
+				if prevClassify != nil {
+					_ = knowledgeObj.UpdateClassifySortByParentId(parentId, prevClassify.ClassifyId, prevClassify.Sort, updateSortStr)
+				} else {
+					_ = knowledgeObj.UpdateClassifySortByParentId(parentId, 0, prevSort, updateSortStr)
+				}
+
+			} else {
+				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+				if nextSort-prevSort == 1 {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 1`
+
+					//变更分类
+					if prevClassify != nil {
+						_ = knowledgeObj.UpdateClassifySortByParentId(parentId, prevClassify.ClassifyId, prevSort, updateSortStr)
+					} else {
+						_ = knowledgeObj.UpdateClassifySortByParentId(parentId, 0, prevSort, updateSortStr)
+					}
+
+				}
+			}
+		}
+
+		classifyInfo.Sort = prevSort + 1
+		classifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	} else if prevClassify == nil && nextClassify == nil && parentId > 0 {
+		//处理只拖动到目录里,默认放到目录底部的情况
+		var maxSort int
+		maxSort, err = knowledgeObj.GetMaxSortByParentId(parentId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = fmt.Errorf("查询组内排序信息失败,Err:" + err.Error())
+			return
+		}
+		classifyInfo.Sort = maxSort + 1 //那就是排在组内最后一位
+		classifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	} else {
+		// 拖动到父级分类的第一位
+		firstPermission, tmpErr := knowledgeObj.GetFirstClassifyByParentId(parentId)
+		if tmpErr != nil && !utils.IsErrNoRow(tmpErr) {
+			errMsg = "移动失败"
+			err = fmt.Errorf("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tmpErr.Error())
+			return
+		}
+
+		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+		if firstPermission != nil && firstPermission.ClassifyId != 0 && firstPermission.Sort == 0 {
+			updateSortStr := ` sort + 1 `
+			_ = knowledgeObj.UpdateClassifySortByParentId(parentId, firstPermission.ClassifyId-1, 0, updateSortStr)
+		}
+
+		classifyInfo.Sort = 0 //那就是排在第一位
+		classifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	}
+
+	//更新
+	if len(updateCol) > 0 {
+		err = classifyInfo.Update(updateCol)
+		if err != nil {
+			errMsg = "移动失败"
+			err = fmt.Errorf("修改失败,Err:" + err.Error())
+			return
+		}
+	}
+	return
+}
+
+// AddKnowledgeClassify
+// @Description: 添加报告分类
+// @author: Roc
+// @datetime 2024-06-17 11:01:21
+// @param classifyName string
+// @param parentId int
+// @param chartPermissionIdList []int
+// @return err error
+// @return errMsg string
+// @return isSendEmail bool
+func AddKnowledgeClassify(classifyName string, parentId, resourceType int) (err error, errMsg string, isSendEmail bool) {
+	isSendEmail = true
+	errMsg = `添加失败`
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	item, err := knowledgeObj.GetClassifyByName(classifyName, parentId, resourceType)
+	if err != nil && !utils.IsErrNoRow(err) {
+		errMsg = "获取分类信息失败"
+		if utils.IsErrNoRow(err) {
+			errMsg = "分类名称:" + classifyName + "已存在"
+			isSendEmail = false
+		}
+		return
+	}
+	if item != nil {
+		errMsg = "分类名称:" + classifyName + "已存在"
+		isSendEmail = false
+		err = errors.New(errMsg)
+		return
+	}
+
+	level := 1
+	// 父级分类
+	var parentClassifyItem *knowledge.KnowledgeClassify
+	// 父级分类下的子分类数量
+	var childClassifyCount int
+
+	if parentId > 0 {
+		// 获取父级分类信息
+		parentClassifyItem, err = knowledgeObj.GetClassifyById(parentId)
+		if err != nil {
+			errMsg = "获取父级分类信息失败"
+			if utils.IsErrNoRow(err) {
+				errMsg = "父级分类不存在"
+			}
+			return
+		}
+		if parentClassifyItem.ResourceType != resourceType {
+			errMsg = "父级分类与当前分类类型不一致"
+			err = fmt.Errorf(errMsg)
+			return
+		}
+		level = parentClassifyItem.Level + 1
+
+		if level > 3 {
+			errMsg = "分类层级不可超过三级"
+			isSendEmail = false
+			return
+		}
+		// 获取父级分类下的子分类数量
+		childClassifyCount, err = knowledgeObj.GetCountClassifyChildByParentId(parentId)
+		if err != nil {
+			errMsg = "获取父级分类的子分类信息失败"
+			return
+		}
+	}
+
+	nowTime := time.Now().Local()
+	classify := new(knowledge.KnowledgeClassify)
+
+	maxSort, err := classify.GetMaxSort()
+	if err != nil {
+		errMsg = "操作失败"
+		err = errors.New("查询品种排序失败, Err: " + err.Error())
+		return
+	}
+	classify.ClassifyName = classifyName
+	classify.ParentId = parentId
+	classify.CreateTime = nowTime
+	classify.ModifyTime = nowTime
+	classify.Sort = maxSort + 1
+	classify.Enabled = 1
+	classify.Level = level
+	classify.ResourceType = resourceType
+
+	err = knowledgeObj.Add(classify)
+	if err != nil {
+		return
+	}
+	// 如果父级分类不为空的话,那么就标记有子级分类,同时
+	if parentClassifyItem != nil {
+		parentClassifyItem.HasChild = 1
+		err = parentClassifyItem.Update([]string{"HasChild"})
+		if err != nil {
+			return
+		}
+
+		// 如果以前没有子级分类,那么就继承父级分类下的章节类型(创建新的章节与分类的关系)
+		if childClassifyCount <= 0 {
+			// todo 修改分类下的资源报告
+			moveResourceByAddClassify(parentClassifyItem, classify)
+		}
+	}
+	return
+}
+
+// 关于研报分类,因只允许报告或品种关联在最小分类下,所以当某个父分类(非三级分类)已关联报告或品种,需要在该父分类下增加子分类,则第一个子分类添加成功时,默认把该父分类关联的品种和报告转移至新创建的子分类(第一个子分类)下
+// moveReportByAddClassify
+// @Description: 报告和章节的转移
+// @author: Roc
+// @datetime 2024-06-17 16:29:56
+// @param parentClassifyInfo *knowledge.KnowledgeClassify
+// @param currClassifyInfo *knowledge.KnowledgeClassify
+// @return err error
+func moveResourceByAddClassify(parentClassifyInfo, currClassifyInfo *knowledge.KnowledgeClassify) (err error) {
+	/*defer func() {
+		if err != nil {
+			utils.FileLog.Error(fmt.Sprint("历史报告更改分类失败,父级分类ID:", parentClassifyInfo.ClassifyId, ";当前分类ID:", currClassifyInfo.ClassifyId, ";错误信息:", err.Error()))
+		}
+	}()
+	if currClassifyInfo.Level > 3 {
+		err = errors.New("父级分类不支持三级分类以上")
+		return
+	}
+
+	// 报告的分类归属调整,转为下一级的分类
+
+	var condition, updateStr string
+	pars := make([]interface{}, 0)
+	switch currClassifyInfo.Level {
+	case 3: // 当前分类是3级分类
+		updateStr += ` classify_id_third = ?,classify_name_third = ?`
+		condition += ` AND classify_id_second = ? `
+	case 2: // 当前分类是2级分类
+		updateStr += ` classify_id_second = ?,classify_name_second = ?`
+		condition += ` AND classify_id_first = ? `
+	default:
+		err = errors.New("错误的分类层级")
+		return
+	}
+
+	pars = append(pars, currClassifyInfo.ClassifyId, currClassifyInfo.ClassifyName, parentClassifyInfo.ClassifyId)
+
+	// 获取当前分类下的所有章节类型
+	currReportChapterTypeList, err := knowledgeObj.GetAllReportChapterTypeListByClassifyId(currClassifyInfo.ClassifyId)
+	if err != nil {
+		return
+	}
+	// 当前的章节类型ID ---> 继承的章节类型ID
+	chapterTypeIdMap := make(map[int]int)
+	for _, v := range currReportChapterTypeList {
+		chapterTypeIdMap[v.ReportChapterTypeId] = v.InheritReportChapterTypeId
+	}
+
+	// 报告转移后,历史章节报告中的type_id也要修复成最新的type_id
+	err = knowledgeObj.ModifyKnowledgeClassifyAndReportChapterTypeByCondition(condition, pars, updateStr, chapterTypeIdMap, parentClassifyInfo.ClassifyId, currClassifyInfo.ClassifyId, currClassifyInfo.ClassifyName)
+	if err != nil {
+		return
+	}*/
+
+	return
+}
+
+func EditKnowledgeClassify(classifyId, parentId int, classifyName string) (err error, errMsg string, isSendEmail bool) {
+	isSendEmail = true
+	errMsg = `修改失败`
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	item, err := knowledgeObj.GetClassifyById(classifyId)
+	if err != nil {
+		errMsg = "获取分类信息失败"
+		if utils.IsErrNoRow(err) {
+			errMsg = "分类不存在, 或已被删除"
+			isSendEmail = false
+		}
+		return
+	}
+	if (parentId == 0 && item.ParentId > 0) || (parentId > 0 && item.ParentId == 0) {
+		err = errors.New("不允许修改分类层级")
+		errMsg = "不允许修改分类层级"
+		return
+	}
+	if parentId > 0 {
+		parentClassifyItem, e := knowledgeObj.GetClassifyById(parentId)
+		if e != nil {
+			errMsg = "获取父级分类失败"
+			err = errors.New("获取父级分类失败, Err: " + e.Error())
+			return
+		}
+		if parentClassifyItem.Level != item.Level {
+			errMsg = "不允许修改分类层级"
+			err = errors.New("不允许修改分类层级")
+			return
+		}
+	}
+	//originName := item.ClassifyName
+
+	// 重名校验
+	existName, e := knowledgeObj.GetClassifyByName(classifyName, parentId, item.ResourceType)
+	if e != nil && !utils.IsErrNoRow(e) {
+		errMsg = "分类名称已存在"
+		err = errors.New("获取重名分类失败, Err: " + err.Error())
+		return
+	}
+	if existName != nil && existName.ClassifyId != item.ClassifyId {
+		errMsg = "分类名称:" + classifyName + "已存在"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+	item.ClassifyName = classifyName
+
+	// ETA1.8.3:不允许修改上级分类  2024-6-17 13:21:01
+	//
+	// todo 修改父级,修改level,只允许修改同级别
+	item.ParentId = parentId
+	item.ModifyTime = time.Now().Local()
+	cols := make([]string, 0)
+	cols = append(cols, "ParentId", "ClassifyName", "ModifyTime")
+	err = item.Update(cols)
+	if err != nil {
+		return
+	}
+	// todo 修改父级分类下相关的事件,找到当前分类的最小分类,把上一级的报告挪到最小分类上
+
+	return
+}
+
+// GetClassifyTreeRecursive 递归获取分类树形结构
+func GetClassifyTreeRecursive(list []*knowledge.KnowledgeClassifyItem, parentId int) []*knowledge.KnowledgeClassifyItem {
+	res := make([]*knowledge.KnowledgeClassifyItem, 0)
+	for _, v := range list {
+		if v.ParentId == parentId {
+			v.Child = GetClassifyTreeRecursive(list, v.ClassifyId)
+			res = append(res, v)
+		}
+	}
+	return res
+}
+
+// GetParentClassifyListByParentIdList
+// @Description: 递归获取父级分类信息,正常来讲只有三次
+// @author: Roc
+// @datetime 2024-06-19 13:23:33
+// @param parentClassifyIdList []int
+// @return list []*knowledge.KnowledgeClassifyItem
+// @return err error
+func GetParentClassifyListByParentIdList(parentClassifyIdList []int) (list []*knowledge.KnowledgeClassifyItem, err error) {
+	knowledgeObj := new(knowledge.KnowledgeClassify)
+	num := len(parentClassifyIdList)
+	if num <= 0 {
+		return
+	}
+	list, err = knowledgeObj.GetClassifyListByParentIdList(parentClassifyIdList)
+	if err != nil {
+		return
+	}
+
+	// 是否还有上级
+	{
+		currParentClassifyIdList := make([]int, 0)
+		for _, v := range list {
+			if v.ParentId > 0 {
+				currParentClassifyIdList = append(currParentClassifyIdList, v.ParentId)
+			}
+		}
+
+		if len(currParentClassifyIdList) > 0 {
+			tmpList, tmpErr := GetParentClassifyListByParentIdList(currParentClassifyIdList)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			list = append(tmpList, list...)
+		}
+	}
+
+	return
+}
+
+// GetClassifyListTreeRecursive
+// @Description: 递归获取分类树形结构
+// @author: Roc
+// @datetime 2024-06-19 13:23:28
+// @param list []*knowledge.KnowledgeClassifyItem
+// @param parentId int
+// @return []*knowledge.KnowledgeClassifyItem
+func GetClassifyListTreeRecursive(list []*knowledge.KnowledgeClassifyItem, parentId int) []*knowledge.KnowledgeClassifyItem {
+	res := make([]*knowledge.KnowledgeClassifyItem, 0)
+	for _, v := range list {
+		if v.ParentId == parentId {
+			v.Child = GetClassifyListTreeRecursive(list, v.ClassifyId)
+			res = append(res, v)
+		}
+	}
+
+	// 前端的JP需要我这么返回
+	if len(res) <= 0 {
+		res = nil
+	}
+
+	return res
+}
+
+// BySortAndCreateTime 用来排序,先按Sort字段升序排序,若Sort相同,则按照CreateTime字段升序排序。
+type BySortAndCreateTime []*knowledge.KnowledgeClassifyItem
+
+func (a BySortAndCreateTime) Len() int {
+	return len(a)
+}
+
+func (a BySortAndCreateTime) Swap(i, j int) {
+	a[i], a[j] = a[j], a[i]
+}
+
+func (a BySortAndCreateTime) Less(i, j int) bool {
+	if a[i].Sort == a[j].Sort {
+		return a[i].CreateTime.Before(a[j].CreateTime)
+	}
+	return a[i].Sort < a[j].Sort
+}
+
+// SortClassifyListBySortAndCreateTime sorts the ClassifyList slice by Sort and then CreateTime in ascending order.
+func SortClassifyListBySortAndCreateTime(classifyList []*knowledge.KnowledgeClassifyItem) {
+	sort.Sort(BySortAndCreateTime(classifyList))
+}