package semantic_analysis import ( "encoding/json" "eta/eta_api/controllers" "eta/eta_api/models" saModel "eta/eta_api/models/semantic_analysis" "eta/eta_api/services" "eta/eta_api/utils" "fmt" "github.com/rdlucklib/rdluck_tools/paging" "html" "strings" "time" ) // SaDocController 语义分析-文档 type SaDocController struct { controllers.BaseAuthController } // Add // @Title 新增文档 // @Description 新增文档 // @Param request body saModel.SaDocAddReq true "type json string" // @Success 200 Ret=200 操作成功 // @router /doc/add [post] func (this *SaDocController) Add() { br := new(models.BaseResponse).Init() defer func() { if br.ErrMsg == "" { br.IsSendEmail = false } this.Data["json"] = br this.ServeJSON() }() var req saModel.SaDocAddReq if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil { br.Msg = "参数解析异常!" br.ErrMsg = "参数解析失败,Err:" + e.Error() return } req.Title = strings.TrimSpace(req.Title) if req.Title == "" { br.Msg = "请输入标题" return } if req.ClassifyId <= 0 { br.Msg = "请选择分类" return } // 过滤Editor版权内容 req.Content = strings.Replace(req.Content, "Powered by Froala Editor", "", -1) req.Content = strings.Replace(req.Content, " ", "", -1) req.Content = strings.Replace(req.Content, "

Froala Editor

", "", -1) if req.Content == "" { br.Msg = "请输入文档内容" return } // 重名校验、内容重复校验 contentMd5 := utils.MD5(req.Content) existItem := new(saModel.SaDoc) existCond := ` AND %s = ? OR %s = ?` existCond = fmt.Sprintf(existCond, saModel.SaDocColumns.Title, saModel.SaDocColumns.ContentMd5) existPars := make([]interface{}, 0) existPars = append(existPars, req.Title, contentMd5) if e := existItem.GetItemByCondition(existCond, existPars); e != nil && e.Error() != utils.ErrNoRow() { br.Msg = "操作失败" br.ErrMsg = "获取重复文档失败, Err: " + e.Error() return } if existItem != nil && existItem.SaDocId > 0 { if existItem.Title == req.Title { br.Msg = "文档名称已存在" } if existItem.ContentMd5 == contentMd5 { br.Msg = "该文档内容已上传" } return } // 拆分文档成段落, 分段读取 sections, e := services.LoadSaDocContent2Section(req.Content) if e != nil || len(sections) == 0 { br.Msg = "内容段落信息有误" br.ErrMsg = "读取内容段落失败, Err: " + e.Error() return } // 分类 classifyItem := new(saModel.SaDocClassify) if e = classifyItem.GetItemById(req.ClassifyId); e != nil { br.Msg = "分类信息有误" br.ErrMsg = "获取文档分类信息失败, Err: " + e.Error() return } // 新增 newDoc := new(saModel.SaDoc) newDoc.ClassifyId = req.ClassifyId newDoc.ClassifyName = classifyItem.ClassifyName newDoc.Title = req.Title newDoc.CoverImg = classifyItem.CoverImg newDoc.ContentMd5 = contentMd5 newDoc.SysAdminId = this.SysUser.AdminId newDoc.SysAdminName = this.SysUser.RealName newDoc.CreateTime = time.Now().Local() newDoc.ModifyTime = time.Now().Local() newSections := make([]*saModel.SaDocSection, 0) for i := range sections { newSections = append(newSections, &saModel.SaDocSection{ Content: html.EscapeString(sections[i]), Sort: i + 1, }) } if e = saModel.InsertSaDocAndSections(newDoc, newSections); e != nil { br.Msg = "操作失败" br.ErrMsg = "新增文档和段落失败, Err: " + e.Error() return } // 新增ES文档 go func() { _ = services.HandleElasticSaDocAndSection(newDoc, newSections, []int{}) }() br.Ret = 200 br.Success = true br.Msg = "操作成功" br.Data = newDoc.SaDocId } // Edit // @Title 编辑文档 // @Description 编辑文档 // @Param request body saModel.SaDocEditReq true "type json string" // @Success 200 Ret=200 操作成功 // @router /doc/edit [post] func (this *SaDocController) Edit() { br := new(models.BaseResponse).Init() defer func() { if br.ErrMsg == "" { br.IsSendEmail = false } this.Data["json"] = br this.ServeJSON() }() var req saModel.SaDocEditReq if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil { br.Msg = "参数解析异常!" br.ErrMsg = "参数解析失败,Err:" + e.Error() return } if req.SaDocId <= 0 { br.Msg = "参数异常" return } req.Title = strings.TrimSpace(req.Title) if req.Title == "" { br.Msg = "请输入标题" return } if req.ClassifyId <= 0 { br.Msg = "请选择分类" return } if len(req.SectionList) == 0 { br.Msg = "段落不可为空" return } sectionIds := make([]int, 0) for i := range req.SectionList { if req.SectionList[i].Content == "" { br.Msg = "段落不可为空" return } if req.SectionList[i].SaDocSectionId > 0 { sectionIds = append(sectionIds, req.SectionList[i].SaDocSectionId) } } item := new(saModel.SaDoc) e := item.GetItemById(req.SaDocId) if e != nil { if e.Error() == utils.ErrNoRow() { br.Msg = "文档已被删除, 请刷新页面" return } br.Msg = "获取失败" br.ErrMsg = "获取文档信息失败, Err: " + e.Error() return } // 获取原段落 sectionOB := new(saModel.SaDocSection) sectionCond := fmt.Sprintf(` AND %s = ?`, saModel.SaDocSectionColumns.DocId) sectionPars := make([]interface{}, 0) sectionPars = append(sectionPars, item.SaDocId) originSections, e := sectionOB.GetItemsByCondition(sectionCond, sectionPars, []string{saModel.SaDocSectionColumns.SaDocSectionId}, "") if e != nil { br.Msg = "获取失败" br.ErrMsg = "获取段落信息失败, Err: " + e.Error() return } originSectionIds := make([]int, 0) for i := range originSections { originSectionIds = append(originSectionIds, originSections[i].SaDocSectionId) } // 比对原段落, 判断段落SQL操作类型 insertSecs := make([]*saModel.SaDocSection, 0) updateSecs := make([]*saModel.SaDocSection, 0) delSecIds := utils.MinusInt(originSectionIds, sectionIds) for i, v := range req.SectionList { v.Content = html.EscapeString(v.Content) v.Sort = i + 1 // 新增 if v.SaDocSectionId == 0 { insertSecs = append(insertSecs, v) continue } if utils.InArrayByInt(originSectionIds, v.SaDocSectionId) { updateSecs = append(updateSecs, v) } } // 分类 classifyItem := new(saModel.SaDocClassify) if e = classifyItem.GetItemById(req.ClassifyId); e != nil { br.Msg = "分类信息有误" br.ErrMsg = "获取文档分类信息失败, Err: " + e.Error() return } item.Title = req.Title item.ClassifyId = req.ClassifyId item.ClassifyName = classifyItem.ClassifyName item.ModifyTime = time.Now().Local() updateCols := []string{ saModel.SaDocColumns.Title, saModel.SaDocColumns.Theme, saModel.SaDocColumns.ClassifyId, saModel.SaDocColumns.ClassifyName, saModel.SaDocColumns.ModifyTime, } // 保存文档和段落 updateSecCols := []string{saModel.SaDocSectionColumns.Content, saModel.SaDocSectionColumns.Sort} if e = saModel.UpdateSaDocAndSections(item, insertSecs, updateSecs, delSecIds, updateCols, updateSecCols); e != nil { br.Msg = "操作失败" br.ErrMsg = "更新文档段落失败, Err: " + e.Error() return } // 编辑ES文档 go func() { sections := make([]*saModel.SaDocSection, 0) sections = append(sections, insertSecs...) sections = append(sections, updateSecs...) _ = services.HandleElasticSaDocAndSection(item, sections, delSecIds) }() br.Ret = 200 br.Success = true br.Msg = "操作成功" br.Data = item.SaDocId } // Del // @Title 删除文档 // @Description 删除文档 // @Param request body saModel.SaDocDelReq true "type json string" // @Success 200 Ret=200 操作成功 // @router /doc/del [post] func (this *SaDocController) Del() { br := new(models.BaseResponse).Init() defer func() { if br.ErrMsg == "" { br.IsSendEmail = false } this.Data["json"] = br this.ServeJSON() }() var req saModel.SaDocDelReq if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil { br.Msg = "参数解析异常!" br.ErrMsg = "参数解析失败,Err:" + e.Error() return } if req.SaDocId <= 0 { br.Msg = "参数有误" return } item := new(saModel.SaDoc) e := item.GetItemById(req.SaDocId) if e != nil { if e.Error() == utils.ErrNoRow() { br.Msg = "文档已被删除, 请刷新页面" return } br.Msg = "操作失败" br.ErrMsg = "获取文档信息失败, Err: " + e.Error() return } secOB := new(saModel.SaDocSection) secCond := fmt.Sprintf(` AND %s = ?`, saModel.SaDocSectionColumns.DocId) secPars := make([]interface{}, 0) secPars = append(secPars, item.SaDocId) sections, e := secOB.GetItemsByCondition(secCond, secPars, []string{saModel.SaDocSectionColumns.SaDocSectionId}, "") if e != nil { br.Msg = "操作失败" br.ErrMsg = "获取文档段落信息失败, Err: " + e.Error() return } secIds := make([]int, 0) for i := range sections { secIds = append(secIds, sections[i].SaDocSectionId) } // 校验文档引用数 useCond := fmt.Sprintf(` AND %s = ?`, saModel.SaCompareLabelColumns.DocId) usePars := make([]interface{}, 0) usePars = append(usePars, item.SaDocId) useOB := new(saModel.SaCompareLabel) count, e := useOB.GetCountByCondition(useCond, usePars) if e != nil { br.Msg = "操作失败" br.ErrMsg = "获取文档引用数失败, Err: " + e.Error() return } if count > 0 { br.Msg = "文档已被引用, 不可删除" return } // 删除文档及段落 if e = saModel.DelSaDocAndSections(item.SaDocId); e != nil { br.Msg = "操作失败" br.ErrMsg = "删除文档失败, Err: " + e.Error() return } // 删除ES文档 go func() { _ = services.DeleteElasticSaDocAndSection(item.SaDocId, secIds) }() br.Ret = 200 br.Success = true br.Msg = "操作成功" } // Detail // @Title 文档详情 // @Description 文档详情 // @Param DocId query string true "文档ID" // @Success 200 Ret=200 获取成功 // @router /doc/detail [get] func (this *SaDocController) Detail() { br := new(models.BaseResponse).Init() defer func() { if br.ErrMsg == "" { br.IsSendEmail = false } this.Data["json"] = br this.ServeJSON() }() docId, _ := this.GetInt("DocId", 0) if docId <= 0 { br.Msg = "参数异常" return } item := new(saModel.SaDoc) e := item.GetItemById(docId) if e != nil { if e.Error() == utils.ErrNoRow() { br.Msg = "文档已被删除, 请刷新页面" return } br.Msg = "获取失败" br.ErrMsg = "获取文档信息失败, Err: " + e.Error() return } // 获取段落 sectionOB := new(saModel.SaDocSection) sectionCond := fmt.Sprintf(` AND %s = ?`, saModel.SaDocSectionColumns.DocId) sectionPars := make([]interface{}, 0) sectionPars = append(sectionPars, item.SaDocId) sectionList, e := sectionOB.GetItemsByCondition(sectionCond, sectionPars, []string{}, "") if e != nil { br.Msg = "获取失败" br.ErrMsg = "获取段落信息失败, Err: " + e.Error() return } secIds := make([]int, 0) for _, s := range sectionList { secIds = append(secIds, s.SaDocSectionId) } // 段落引用数 useMap := make(map[int]int) usePartMap := make(map[int]int) if len(secIds) > 0 { // 整段 useOB := new(saModel.SaCompareLabel) useCond := fmt.Sprintf(` AND %s IN (%s) AND %s = 0`, saModel.SaCompareLabelColumns.SectionId, utils.GetOrmInReplace(len(secIds)), saModel.SaCompareLabelColumns.IsPart) usePars := make([]interface{}, 0) usePars = append(usePars, secIds) countList, e := useOB.GetGroupCountByCondition(useCond, usePars, saModel.SaCompareLabelColumns.SectionId) if e != nil && e.Error() != utils.ErrNoRow() { br.Msg = "获取失败" br.ErrMsg = "获取标签段落引用数失败, Err: " + e.Error() return } for i := range countList { useMap[countList[i].SectionId] = countList[i].UseNum } // 片段 usePartCond := fmt.Sprintf(` AND %s IN (%s) AND %s = 1`, saModel.SaCompareLabelColumns.SectionId, utils.GetOrmInReplace(len(secIds)), saModel.SaCompareLabelColumns.IsPart) usePartPars := make([]interface{}, 0) usePartPars = append(usePartPars, secIds) countPartList, e := useOB.GetGroupCountByCondition(usePartCond, usePartPars, saModel.SaCompareLabelColumns.SectionId) for i := range countPartList { usePartMap[countPartList[i].SectionId] = countPartList[i].UseNum } } secList := make([]*saModel.SaDocSectionItem, 0) for _, s := range sectionList { c := html.UnescapeString(s.Content) c = strings.ReplaceAll(c, `

`, "") c = strings.ReplaceAll(c, `

`, "") s.Content = c v := new(saModel.SaDocSectionItem) v.SaDocSection = *s v.UseNum = useMap[s.SaDocSectionId] v.UsePartNum = usePartMap[s.SaDocSectionId] secList = append(secList, v) } detail := new(saModel.SaDocDetail) detail.SaDocId = item.SaDocId detail.ClassifyId = item.ClassifyId detail.ClassifyName = item.ClassifyName detail.Title = item.Title detail.Theme = item.Theme detail.CoverImg = item.CoverImg detail.SysAdminId = item.SysAdminId detail.SysAdminName = item.SysAdminName detail.CreateTime = item.CreateTime.Format(utils.FormatDateTime) detail.SectionList = secList br.Data = detail br.Ret = 200 br.Success = true br.Msg = "获取成功" } // PageList // @Title 文档列表 // @Description 文档列表 // @Param Keyword query string false "文档关键词" // @Param ClassifyId query int false "文档分类ID" // @Success 200 Ret=200 获取成功 // @router /doc/page_list [get] func (this *SaDocController) PageList() { br := new(models.BaseResponse).Init() defer func() { if br.ErrMsg == "" { br.IsSendEmail = false } this.Data["json"] = br this.ServeJSON() }() keyword := this.GetString("Keyword", "") classifyId, _ := this.GetInt("ClassifyId", 0) var startSize int pageSize, _ := this.GetInt("PageSize") currentIndex, _ := this.GetInt("CurrentIndex") if pageSize <= 0 { pageSize = utils.PageSize20 } if currentIndex <= 0 { currentIndex = 1 } startSize = paging.StartIndex(currentIndex, pageSize) itemOB := new(saModel.SaDoc) cond := `` pars := make([]interface{}, 0) if keyword != "" { kw := "%" + keyword + "%" cond += fmt.Sprintf(` AND %s LIKE ?`, saModel.SaDocColumns.Title) pars = append(pars, kw) } if classifyId > 0 { cond += fmt.Sprintf(` AND %s = ?`, saModel.SaDocColumns.ClassifyId) pars = append(pars, classifyId) } total, list, e := itemOB.GetPageItemsByCondition(startSize, pageSize, cond, pars, []string{}, "sort ASC, create_time DESC, sa_doc_id ASC") if e != nil { br.Msg = "获取失败" br.ErrMsg = "获取文档列表失败, Err: " + e.Error() return } respList := make([]*saModel.SaDocItem, 0) for i := range list { v := new(saModel.SaDocItem) v.SaDocId = list[i].SaDocId v.ClassifyId = list[i].ClassifyId v.ClassifyName = list[i].ClassifyName v.CoverImg = list[i].CoverImg v.Title = list[i].Title v.Theme = list[i].Theme v.SysAdminId = list[i].SysAdminId v.SysAdminName = list[i].SysAdminName v.Sort = list[i].Sort v.CreateTime = list[i].CreateTime.Format(utils.FormatDateTime) respList = append(respList, v) } page := paging.GetPaging(currentIndex, pageSize, total) resp := &saModel.SaDocPageListResp{ Paging: page, List: respList, } br.Data = resp br.Ret = 200 br.Success = true br.Msg = "获取成功" } // Move // @Title 移动文档 // @Description 移动文档 // @Param request body saModel.SaDocEditReq true "type json string" // @Success 200 Ret=200 操作成功 // @router /doc/move [post] func (this *SaDocController) Move() { br := new(models.BaseResponse).Init() defer func() { if br.ErrMsg == "" { br.IsSendEmail = false } this.Data["json"] = br this.ServeJSON() }() var req saModel.SaDocMoveReq if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil { br.Msg = "参数解析异常!" br.ErrMsg = "参数解析失败,Err:" + e.Error() return } if req.SaDocClassifyId <= 0 { br.Msg = "请选择分类" return } if req.SaDocId <= 0 { br.Msg = "参数异常" return } item := new(saModel.SaDoc) e := item.GetItemById(req.SaDocId) if e != nil { if e.Error() == utils.ErrNoRow() { br.Msg = "文档已被删除, 请刷新页面" return } br.Msg = "操作失败" br.ErrMsg = "获取文档信息失败, Err: " + e.Error() return } originClassifyId := item.ClassifyId // 分类 classifyItem := new(saModel.SaDocClassify) if e = classifyItem.GetItemById(req.SaDocClassifyId); e != nil { br.Msg = "分类信息有误" br.ErrMsg = "获取文档分类信息失败, Err: " + e.Error() return } // CV的指标库指标的移动, 没有技术, 全是感情~ if req.PrevSaDocId > 0 { prevDoc := new(saModel.SaDoc) if e = prevDoc.GetItemById(req.PrevSaDocId); e != nil { if e.Error() == utils.ErrNoRow() { br.Msg = "上一个文档已被删除, 请刷新页面" return } br.Msg = "操作失败" br.ErrMsg = "获取上一个文档信息失败, Err: " + e.Error() return } // 如果是在两个文档之间 if req.NextSaDocId > 0 { nextDoc := new(saModel.SaDoc) if e = nextDoc.GetItemById(req.NextSaDocId); e != nil { if e.Error() == utils.ErrNoRow() { br.Msg = "下一个文档已被删除, 请刷新页面" return } br.Msg = "操作失败" br.ErrMsg = "获取下一个文档信息失败, Err: " + e.Error() return } // 判断上一个文档与当前文档/下一个文档的位置 if prevDoc.Sort == item.Sort || prevDoc.Sort == nextDoc.Sort { _ = saModel.UpdateSaDocSort(prevDoc.ClassifyId, prevDoc.Sort, prevDoc.SaDocId, `sort + 2`) } else { if nextDoc.Sort-prevDoc.Sort == 1 { _ = saModel.UpdateSaDocSort(prevDoc.ClassifyId, prevDoc.Sort, prevDoc.SaDocId, `sort + 1`) } } } item.Sort = prevDoc.Sort + 1 } else { firstDoc, e := saModel.GetFirstSortSaDoc(req.SaDocClassifyId) if e != nil && e.Error() != utils.ErrNoRow() { br.Msg = "操作失败" br.ErrMsg = "获取首个文档失败, Err: " + e.Error() return } if firstDoc != nil && firstDoc.Sort == 0 { _ = saModel.UpdateSaDocSort(firstDoc.ClassifyId, 0, firstDoc.SaDocId-1, `sort + 1`) } item.Sort = 0 } // 更新 item.ClassifyId = classifyItem.SaDocClassifyId item.ClassifyName = classifyItem.ClassifyName item.ModifyTime = time.Now().Local() updateCols := []string{ saModel.SaDocColumns.ClassifyId, saModel.SaDocColumns.ClassifyName, saModel.SaDocColumns.Sort, saModel.SaDocColumns.ModifyTime, } if e = item.Update(updateCols); e != nil { br.Msg = "操作失败" br.ErrMsg = "移动文档失败, Err: " + e.Error() return } // 若更改了分类-则更新ES文档 if originClassifyId != req.SaDocClassifyId { go func() { sectionOB := new(saModel.SaDocSection) sectionCond := fmt.Sprintf(` AND %s = ?`, saModel.SaDocSectionColumns.DocId) sectionPars := make([]interface{}, 0) sectionPars = append(sectionPars, item.SaDocId) sections, e := sectionOB.GetItemsByCondition(sectionCond, sectionPars, []string{}, "") if e != nil { return } _ = services.HandleElasticSaDocAndSection(item, sections, []int{}) }() } br.Ret = 200 br.Success = true br.Msg = "操作成功" br.Data = item.SaDocId }