package services import ( "errors" "eta_gn/eta_api/models" "eta_gn/eta_api/models/report_approve" "eta_gn/eta_api/utils" "fmt" "sort" "time" ) // MoveReportClassify 移动分类 func MoveReportClassify(req models.ClassifyMoveReq) (err error, errMsg string) { classifyId := req.ClassifyId prevClassifyId := req.PrevClassifyId nextClassifyId := req.NextClassifyId //如果有传入 上一个兄弟节点分类id var ( classifyInfo *models.Classify prevClassify *models.Classify nextClassify *models.Classify prevSort int nextSort int ) // 移动对象为分类, 判断权限 classifyInfo, err = models.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.Id == 0 { errMsg = "分类不存在, 请刷新页面" err = fmt.Errorf("获取分类信息失败,Err:" + err.Error()) return } parentClassifyId := classifyInfo.ParentId if prevClassifyId > 0 { prevClassify, err = models.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 = models.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 = moveReportClassify(classifyInfo, prevClassify, nextClassify, parentClassifyId, prevSort, nextSort) return } // moveReportClassify 移动分类 func moveReportClassify(classifyInfo, prevClassify, nextClassify *models.Classify, parentId, prevSort, nextSort int) (err error, errMsg string) { ob := new(models.Classify) 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 { _ = models.UpdateClassifySortByParentId(parentId, prevClassify.Id, prevClassify.Sort, updateSortStr) } else { _ = models.UpdateClassifySortByParentId(parentId, 0, prevSort, updateSortStr) } } else { //如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了 if nextSort-prevSort == 1 { //变更兄弟节点的排序 updateSortStr := `sort + 1` //变更分类 if prevClassify != nil { _ = models.UpdateClassifySortByParentId(parentId, prevClassify.Id, prevSort, updateSortStr) } else { _ = models.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 = ob.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 := ob.GetFirstClassifyByParentId(parentId) if tmpErr != nil && !utils.IsErrNoRow(tmpErr) { errMsg = "移动失败" err = fmt.Errorf("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tmpErr.Error()) return } //如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序 if firstPermission != nil && firstPermission.Id > 0 && firstPermission.Sort == 0 { updateSortStr := ` sort + 1 ` _ = models.UpdateClassifySortByParentId(parentId, firstPermission.Id-1, 0, updateSortStr) } classifyInfo.Sort = 0 //那就是排在第一位 classifyInfo.ModifyTime = time.Now() updateCol = append(updateCol, "Sort", "ModifyTime") } //更新 if len(updateCol) > 0 { err = classifyInfo.UpdateClassify(updateCol) if err != nil { errMsg = "移动失败" err = fmt.Errorf("修改失败,Err:" + err.Error()) return } } return } // AddReportClassify // @Description: 添加报告分类 // @author: Roc // @datetime 2024-06-17 11:01:21 // @param classifyName string // @param parentId int // @param isRemind int // @param remindTime string // @return err error // @return errMsg string // @return isSendEmail bool func AddReportClassify(classifyName string, parentId int, classifyType, isRemind int, remindTime string) (err error, errMsg string, isSendEmail bool) { isSendEmail = true errMsg = `添加失败` item, err := models.GetClassifyByName(classifyName, parentId) if err != nil && !utils.IsErrNoRow(err) { errMsg = "获取分类信息失败" if utils.IsErrNoRow(err) { errMsg = "分类名称:" + classifyName + "已存在" isSendEmail = false } return } if item != nil && item.Id > 0 { errMsg = "分类名称:" + classifyName + "已存在" isSendEmail = false err = errors.New(errMsg) return } level := 1 // 父级分类 var parentClassifyItem *models.Classify // 父级分类下的子分类数量 var childClassifyCount int if parentId > 0 { // 获取父级分类信息 parentClassifyItem, err = models.GetClassifyById(parentId) if err != nil { errMsg = "获取父级分类信息失败" if utils.IsErrNoRow(err) { errMsg = "父级分类不存在" } return } level = parentClassifyItem.Level + 1 if level > 3 { errMsg = "分类层级不可超过三级" isSendEmail = false return } // 判断是否分类存在待操作的审批单 //err, errMsg = checkClassifyApprove(parentClassifyItem) //if err != nil { // return //} // 获取父级分类下的子分类数量 childClassifyCount, err = models.GetCountClassifyChildByParentId(parentId) if err != nil { errMsg = "获取父级分类的子分类信息失败" return } } nowTime := time.Now().Local() classify := new(models.Classify) 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.ShowType = 1 //默认列表格式 classify.ReportDetailShowType = 1 //默认列表格式 classify.IsShow = 1 classify.Level = level classify.ClassifyType = classifyType classify.IsRemind = isRemind classify.RemindTime = remindTime err = models.AddClassify(classify) if err != nil { return } // 如果父级分类不为空的话,那么就标记有子级分类,同时 if parentClassifyItem != nil { parentClassifyItem.HasChild = 1 parentClassifyItem.UpdateClassify([]string{"HasChild"}) // 如果以前没有子级分类,那么就继承父级分类下的章节类型(创建新的章节与分类的关系) if childClassifyCount <= 0 { // 继承父级分类下的章节类型(创建新的章节与分类的关系) tmpErr := inheritReportChapterType(parentId, classify.Id) if tmpErr != nil { return } // 继承父级分类审批流 //go inheritReportApproveFlow(parentClassifyItem, classify) moveReportByAddClassify(parentClassifyItem, classify) } } return } // checkClassifyApprove // @Description: 判断分类是否存在待操作的审批单 // @author: Roc // @datetime 2024-06-27 13:19:15 // @param currClassify *models.Classify // @return err error // @return errMsg string func checkClassifyApprove(currClassify *models.Classify) (err error, errMsg string) { errMsg = `判断是否有审批流关联失败` var firstClassifyId, secondClassifyId int if currClassify.ParentId > 0 { parentClassifyItem, tmpErr := models.GetClassifyById(currClassify.ParentId) if tmpErr != nil { err = tmpErr errMsg = "获取父级分类信息失败" if utils.IsErrNoRow(tmpErr) { errMsg = "父级分类不存在" } return } firstClassifyId = parentClassifyItem.Id secondClassifyId = currClassify.Id } else { firstClassifyId = currClassify.Id } // 校验审批流是否关联了进行中的审批 { flowOb := new(report_approve.ReportApproveFlow) existCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId, report_approve.ReportApproveFlowCols.ClassifyThirdId) existPars := make([]interface{}, 0) existPars = append(existPars, report_approve.FlowReportTypeChinese, firstClassifyId, secondClassifyId, 0) flowItem, e := flowOb.GetItemByCondition(existCond, existPars, "") if e != nil { // 父级分类如果没有审批流,那么就正常进行就好了 if !utils.IsErrNoRow(e) { err = errors.New("获取审批流是否已存在失败, Err: " + e.Error()) return } err = nil return } if flowItem == nil { return } approvingOb := new(report_approve.ReportApprove) approvingCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveCols.FlowId, report_approve.ReportApproveCols.FlowVersion, report_approve.ReportApproveCols.State) approvingPars := make([]interface{}, 0) approvingPars = append(approvingPars, flowItem.ReportApproveFlowId, flowItem.CurrVersion, report_approve.ReportApproveStateApproving) count, e := approvingOb.GetCountByCondition(approvingCond, approvingPars) if e != nil { err = errors.New("获取审批流关联进行中的审批数失败. Err: " + e.Error()) return } if count > 0 { errMsg = "当前有未走完流程的报告,请走完流程后再做变更" err = errors.New(errMsg) return } } return } // 关于研报分类,因只允许报告或品种关联在最小分类下,所以当某个父分类(非三级分类)已关联报告或品种,需要在该父分类下增加子分类,则第一个子分类添加成功时,默认把该父分类关联的品种和报告转移至新创建的子分类(第一个子分类)下 // moveReportByAddClassify // @Description: 报告和章节的转移 // @author: Roc // @datetime 2024-06-17 16:29:56 // @param parentClassifyInfo *models.Classify // @param currClassifyInfo *models.Classify // @return err error func moveReportByAddClassify(parentClassifyInfo, currClassifyInfo *models.Classify) (err error) { defer func() { if err != nil { utils.FileLog.Error(fmt.Sprint("历史报告更改分类失败,父级分类ID:", parentClassifyInfo.Id, ";当前分类ID:", currClassifyInfo.Id, ";错误信息:", 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.Id, currClassifyInfo.ClassifyName, parentClassifyInfo.Id) // 获取当前分类下的所有章节类型 currReportChapterTypeList, err := models.GetAllReportChapterTypeListByClassifyId(currClassifyInfo.Id) 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 = models.ModifyReportClassifyAndReportChapterTypeByCondition(condition, pars, updateStr, chapterTypeIdMap, parentClassifyInfo.Id, currClassifyInfo.Id, currClassifyInfo.ClassifyName) if err != nil { return } return } // inheritReportChapterType // @Description: 继承父级分类下的章节类型 // @author: Roc // @datetime 2024-06-17 14:41:04 // @param parentClassifyId int // @param currClassifyId int // @return err error func inheritReportChapterType(parentClassifyId, currClassifyId int) (err error) { defer func() { if err != nil { utils.FileLog.Error(fmt.Sprint("继承父级分类下的章节类型失败,父级分类ID:", parentClassifyId, ";当前分类ID:", currClassifyId, ";错误信息:", err.Error())) } }() parentReportChapterTypeList, err := models.GetAllReportChapterTypeListByClassifyId(parentClassifyId) if err != nil { return } // 如果没有章节类型,那么就直接返回 if len(parentReportChapterTypeList) <= 0 { return } addList := make([]*models.ReportChapterType, 0) for _, v := range parentReportChapterTypeList { addList = append(addList, &models.ReportChapterType{ //ReportChapterTypeId: 0, ReportChapterTypeKey: v.ReportChapterTypeKey, ReportChapterTypeThumb: v.ReportChapterTypeThumb, BannerUrl: v.BannerUrl, ReportChapterTypeName: v.ReportChapterTypeName, Sort: v.Sort, Enabled: v.Enabled, CreatedTime: time.Now(), LastUpdatedTime: time.Now(), ResearchType: v.ResearchType, SelectedImage: v.SelectedImage, UnselectedImage: v.UnselectedImage, PcSelectedImage: v.PcSelectedImage, PcUnselectedImage: v.PcUnselectedImage, EditImgUrl: v.EditImgUrl, TickerTitle: v.TickerTitle, IsShow: v.IsShow, PauseStartTime: v.PauseStartTime, PauseEndTime: v.PauseEndTime, IsSet: v.IsSet, YbIconUrl: v.YbIconUrl, YbBottomIcon: v.YbBottomIcon, ReportClassifyId: currClassifyId, InheritReportChapterTypeId: v.ReportChapterTypeId, }) } obj := models.ReportChapterType{} err = obj.MultiCreate(addList) // 修改CRM权限 go func() { var syncReq ChapterTypeSyncReq _, _ = ReportChapterTypeSync(&syncReq) }() return } // inheritReportApproveFlow // @Description: 继承父级分类下的审批流 // @author: Roc // @datetime 2024-06-17 14:41:04 // @param parentClassifyId int // @param currClassifyId int // @return err error func inheritReportApproveFlow(parentClassifyItem, currClassifyItem *models.Classify) (err error) { defer func() { if err != nil { utils.FileLog.Error(fmt.Sprint("继承父级分类下的审批流失败,父级分类ID:", parentClassifyItem.Id, ";当前分类ID:", currClassifyItem.Id, ";错误信息:", err.Error())) } }() var firstClassify, secondClassify, thirdClassify *models.Classify if parentClassifyItem.ParentId > 0 { // 获取父级分类信息 firstClassify, err = models.GetClassifyById(parentClassifyItem.ParentId) if err != nil { return } secondClassify = parentClassifyItem thirdClassify = currClassifyItem } else { firstClassify = parentClassifyItem secondClassify = currClassifyItem } flowObj := report_approve.ReportApproveFlow{} // 获取父级的审批流 existCond := fmt.Sprintf(` AND %s = ? AND %s = ? `, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId) existPars := make([]interface{}, 0) existPars = append(existPars, report_approve.FlowReportTypeChinese, firstClassify.Id) // 如果这是第三级,那么说明只需要查找第二级的审批配置就好了 if thirdClassify != nil { existCond = fmt.Sprintf(`%s AND %s = ?`, existCond, report_approve.ReportApproveFlowCols.ClassifySecondId) existPars = append(existPars, secondClassify.Id) } parentFlow, err := flowObj.GetItemByCondition(existCond, existPars, "") if err != nil { // 如果没有配置审批流,那么就直接返回 if utils.IsErrNoRow(err) { err = nil } return } // 获取父级的审批节点 nodeObj := report_approve.ReportApproveNode{} nodeCond := fmt.Sprintf(` AND %s = ? AND %s = ?`, report_approve.ReportApproveNodeCols.ReportApproveFlowId, report_approve.ReportApproveNodeCols.CurrVersion) nodePars := make([]interface{}, 0) nodePars = append(nodePars, parentFlow.ReportApproveFlowId, parentFlow.CurrVersion) parentNodeList, err := nodeObj.GetItemsByCondition(nodeCond, nodePars, []string{}, "") if err != nil { return } // 新审批流 currFlow := &report_approve.ReportApproveFlow{ ReportApproveFlowId: 0, FlowName: currClassifyItem.ClassifyName, ReportType: parentFlow.ReportType, ClassifyFirstId: firstClassify.Id, ClassifySecondId: secondClassify.Id, //ClassifyThirdId: 0, CurrVersion: 1, Enabled: 1, CreateTime: time.Now().Local(), ModifyTime: time.Now().Local(), } if thirdClassify != nil { currFlow.ClassifyThirdId = thirdClassify.Id } // 新审批流的节点 nodeItems := make([]*report_approve.ReportApproveNode, 0) for _, v := range parentNodeList { n := &report_approve.ReportApproveNode{ //ReportApproveNodeId: 0, //ReportApproveFlowId: 0, PrevNodeId: 0, NextNodeId: 0, NodeType: v.NodeType, ApproveType: v.ApproveType, Users: v.Users, CurrVersion: 1, CreateTime: time.Now().Local(), } nodeItems = append(nodeItems, n) } // 新增审批流和节点 err = flowObj.CreateFlowAndNodes(currFlow, nodeItems) if err != nil { return } parentFlow.Enabled = 0 err = parentFlow.Update([]string{"Enabled"}) return } // EditReportClassify // @Description: 编辑报告分类 // @author: Roc // @datetime 2024-06-17 13:31:33 // @param classifyId int // @param classifyName string // @param isRemind int // @param remindTime string // @return err error // @return errMsg string // @return isSendEmail bool func EditReportClassify(classifyId int, classifyName string, isRemind int, remindTime string) (err error, errMsg string, isSendEmail bool) { isSendEmail = true errMsg = `修改失败` item, err := models.GetClassifyById(classifyId) if err != nil { errMsg = "获取分类信息失败" if utils.IsErrNoRow(err) { errMsg = "分类不存在, 或已被删除" isSendEmail = false } return } //originName := item.ClassifyName // 重名校验 existName, e := models.GetClassifyByName(classifyName, item.ParentId) if e != nil && !utils.IsErrNoRow(e) { errMsg = "获取信息失败" err = errors.New("获取重名分类失败, Err: " + err.Error()) return } if existName != nil && existName.Id > 0 && existName.Id != item.Id { errMsg = "分类名称:" + classifyName + "已存在" err = errors.New(errMsg) isSendEmail = false return } item.ClassifyName = classifyName item.IsRemind = isRemind item.RemindTime = remindTime item.ModifyTime = time.Now().Local() cols := make([]string, 0) cols = append(cols, "ClassifyName", "IsRemind", "RemindTime", "ModifyTime") err = item.UpdateClassify(cols) if err != nil { return } return } // GetClassifyTreeRecursive 递归获取分类树形结构 func GetClassifyTreeRecursive(list []*models.ClassifyItem, parentId int) []*models.ClassifyItem { res := make([]*models.ClassifyItem, 0) for _, v := range list { if v.ParentId == parentId { v.Child = GetClassifyTreeRecursive(list, v.Id) res = append(res, v) } } return res } // GetParentClassifyListByParentIdList // @Description: 递归获取父级分类信息,正常来讲只有三次 // @author: Roc // @datetime 2024-06-19 13:23:33 // @param parentClassifyIdList []int // @return list []*models.ClassifyList // @return err error func GetParentClassifyListByParentIdList(parentClassifyIdList []int) (list []*models.ClassifyList, err error) { num := len(parentClassifyIdList) if num <= 0 { return } list, err = models.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 []*models.ClassifyList // @param parentId int // @return []*models.ClassifyList func GetClassifyListTreeRecursive(list []*models.ClassifyList, parentId int) []*models.ClassifyList { res := make([]*models.ClassifyList, 0) for _, v := range list { if v.ParentId == parentId { v.Child = GetClassifyListTreeRecursive(list, v.Id) res = append(res, v) } } // 前端的JP需要我这么返回 if len(res) <= 0 { res = nil } return res } // BySortAndCreateTime 用来排序,先按Sort字段升序排序,若Sort相同,则按照CreateTime字段升序排序。 type BySortAndCreateTime []*models.ClassifyList 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 []*models.ClassifyList) { sort.Sort(BySortAndCreateTime(classifyList)) } // GetClassifyChildIdsTreeRecursive 递归获取分类所有子分类ID func GetClassifyChildIdsTreeRecursive(list []*models.Classify, parentId int) []int { var res []int for _, v := range list { if v.ParentId == parentId { res = append(res, v.Id) // 子分类的子类 childIds := GetClassifyChildIdsTreeRecursive(list, v.Id) if len(childIds) > 0 { res = append(res, childIds...) } } } return res }