Ver Fonte

Merge branch 'bzq/knowledge_report_add' of eta_gn_server/eta_report into debug

baoziqiang há 3 meses atrás
pai
commit
73cb07f1b3

+ 239 - 4
controllers/report_open.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"eta_gn/eta_report/models"
 	"eta_gn/eta_report/services"
+	"eta_gn/eta_report/services/knowledge"
 	"eta_gn/eta_report/utils"
 	"fmt"
 	"strconv"
@@ -140,6 +141,7 @@ func (this *ReportOpenController) ReportCreate() {
 		br.Msg = "请输入课题结束时间"
 		return
 	}
+	req.Abstract = strings.TrimSpace(req.Abstract)
 	topicTime, e := time.ParseInLocation(utils.FormatDateTime, req.EndTime, time.Local)
 	if e != nil {
 		br.Msg = "课题结束时间格式有误"
@@ -188,7 +190,7 @@ func (this *ReportOpenController) ReportCreate() {
 	// 研报类型
 	var reportId int
 	if classify.ClassifyType == utils.ReportTypeDefault {
-		reportId, e = services.CreateReport(req.ReportId, req.ClassifyId, req.Title, topicTime, req.Creator, req.Authors)
+		reportId, e = services.CreateReport(req.ReportId, req.ClassifyId, req.Title, req.Abstract, topicTime, req.Creator, req.Authors)
 		if e != nil {
 			br.Msg = "操作失败"
 			br.ErrMsg = fmt.Sprintf("新增报告失败, %v", e)
@@ -198,7 +200,7 @@ func (this *ReportOpenController) ReportCreate() {
 
 	// PPT类型
 	if classify.ClassifyType == utils.ReportTypePPT {
-		reportId, e = services.CreatePptReport(req.ReportId, req.ClassifyId, req.Title, topicTime, req.Creator, req.Authors)
+		reportId, e = services.CreatePptReport(req.ReportId, req.ClassifyId, req.Title, req.Abstract, topicTime, req.Creator, req.Authors)
 		if e != nil {
 			br.Msg = "操作失败"
 			br.ErrMsg = fmt.Sprintf("新增PPT报告失败, %v", e)
@@ -242,6 +244,7 @@ func (this *ReportOpenController) ReportModify() {
 		br.ErrMsg = fmt.Sprintf("智力共享报告ID有误, %d", req.ReportId)
 		return
 	}
+	req.Abstract = strings.TrimSpace(req.Abstract)
 	req.Title = strings.TrimSpace(req.Title)
 	if req.Title == "" {
 		br.Msg = "请输入报告标题"
@@ -270,7 +273,7 @@ func (this *ReportOpenController) ReportModify() {
 			br.Msg = "报告已发布,不可编辑"
 			return
 		}
-		if e = services.EditReport(reportExist, req.Title, topicTime, req.Authors); e != nil {
+		if e = services.EditReport(reportExist, req.Title, req.Abstract, topicTime, req.Authors); e != nil {
 			br.Msg = "操作失败"
 			br.ErrMsg = fmt.Sprintf("编辑报告失败, %v", e)
 			return
@@ -283,7 +286,7 @@ func (this *ReportOpenController) ReportModify() {
 			br.Msg = "报告已发布,不可编辑"
 			return
 		}
-		if e = services.EditPptReport(pptExist, req.Title, topicTime, req.Authors); e != nil {
+		if e = services.EditPptReport(pptExist, req.Title, req.Abstract, topicTime, req.Authors); e != nil {
 			br.Msg = "操作失败"
 			br.ErrMsg = fmt.Sprintf("编辑PPT报告失败, %v", e)
 			return
@@ -396,6 +399,42 @@ func (this *ReportOpenController) ReportApprove() {
 				br.ErrMsg = fmt.Sprintf("更新报告状态失败, %v", e)
 				return
 			}
+			if req.ApproveType == 1 {
+				// 审批通过,将PPT或研报加入报告库中
+				go func() {
+					msg, err := knowledge.ReportKnowledgeResourceAdd(v.Title, []string{v.DetailPdfUrl}, v.AdminId, v.AdminRealName, "市场研究报告/内部报告/日常报告", "市场信息研究所", time.Now())
+					if err != nil {
+						utils.FileLog.Error(fmt.Sprintf("ReportKnowledgeResourceAdd-报告知识资源库添加失败,reportId:%d,msg:%s,err: %v", v.Id, msg, err))
+						return
+					}
+				}()
+				go func() {
+					// 审批通过,将摘要加入知识资源库观点中
+					var classifyId int
+					if v.ClassifyIdThird > 0 {
+						classifyId = v.ClassifyIdThird
+					} else if v.ClassifyIdSecond > 0 {
+						classifyId = v.ClassifyIdSecond
+					} else {
+						classifyId = v.ClassifyIdFirst
+					}
+					v.Abstract = strings.TrimSpace(v.Abstract)
+					if v.Abstract == "" {
+						return
+					}
+					classifyId, err := knowledge.ReportKnowledgeResourceClassifyCheckAndSave(classifyId)
+					if err != nil {
+						utils.FileLog.Error(fmt.Sprintf("ReportKnowledgeResourceClassifyCheckAndSave-报告分类保存失败,reportId:%d,classifyId:%d,err: %v", v.Id, classifyId, err))
+						return
+					}
+					msg, err := knowledge.ViewPointSave(0, v.AdminId, v.AdminRealName, v.Title, v.Abstract, "市场信息研究所", "", classifyId, &v.ApproveTime)
+					if err != nil {
+						utils.FileLog.Error(fmt.Sprintf("ViewPointSave-报告摘要知识资源库添加失败,reportId:%d,msg:%s,err: %v", v.Id, msg, err))
+						return
+					}
+				}()
+			}
+
 			if req.ApproveType == 3 || req.ApproveType == 4 {
 				// 撤回/提审暂不发消息
 				continue
@@ -478,6 +517,35 @@ func (this *ReportOpenController) ReportApprove() {
 				br.ErrMsg = fmt.Sprintf("更新报告状态失败, %v", e)
 				return
 			}
+
+			if req.ApproveType == 1 {
+				// 审批通过,将PPT或研报加入报告库中
+				go func() {
+					msg, err := knowledge.ReportKnowledgeResourceAdd(v.Title, []string{v.PptxUrl}, v.AdminId, v.AdminRealName, "市场研究报告/内部报告/日常报告", "市场信息研究所", time.Now())
+					if err != nil {
+						utils.FileLog.Error(fmt.Sprintf("ReportKnowledgeResourceAdd-PPT知识资源报告库添加失败,pptId:%d,msg:%s,err: %v", v.PptId, msg, err))
+						return
+					}
+				}()
+				go func() {
+					// 审批通过,将摘要加入知识资源库观点中
+					v.Abstract = strings.TrimSpace(v.Abstract)
+					if v.Abstract == "" {
+						return
+					}
+					classifyId, err := knowledge.ReportKnowledgeResourceClassifyCheckAndSave(v.ClassifyId)
+					if err != nil {
+						utils.FileLog.Error(fmt.Sprintf("ReportKnowledgeResourceClassifyCheckAndSave-PPT分类保存失败,pptId:%d,classifyId:%d,err: %v", v.PptId, v.ClassifyId, err))
+						return
+					}
+					msg, err := knowledge.ViewPointSave(0, v.AdminId, v.AdminRealName, v.Title, v.Abstract, "市场信息研究所", "", classifyId, &v.ApproveTime)
+					if err != nil {
+						utils.FileLog.Error(fmt.Sprintf("ViewPointSave-ppt摘要知识库添加失败,pptId:%d,msg:%s,err: %v", v.PptId, msg, err))
+						return
+					}
+				}()
+			}
+
 			if req.ApproveType == 3 || req.ApproveType == 4 {
 				// 撤回/提审暂不发消息
 				continue
@@ -611,3 +679,170 @@ func (this *ReportOpenController) ReportRemove() {
 	br.Success = true
 	br.Msg = "操作成功"
 }
+
+// ViewPointSave
+// @Title 观点保存
+// @Description 观点保存
+// @Param request body models.ReportViewPointReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /viewpoint/save [post]
+func (this *ReportOpenController) ViewPointSave() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req *models.ReportViewPointSaveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常"
+		br.ErrMsg = fmt.Sprintf("参数解析失败,%v", e)
+		return
+	}
+	req.Content = strings.TrimSpace(req.Content)
+	req.Title = strings.TrimSpace(req.Title)
+	req.Category = strings.TrimSpace(req.Category)
+	if req.Title == "" {
+		br.Msg = "观点标题不能为空"
+		return
+	}
+	if req.Content == "" {
+		br.Msg = "观点内容不能为空"
+		return
+	}
+	if req.Category == "" {
+		br.Msg = "观点分类不能为空"
+		return
+	}
+	if req.DataDate == "" {
+		br.Msg = "观点日期不能为空"
+		return
+	}
+	dataDate, err := time.ParseInLocation(utils.FormatDateTime, req.DataDate, time.Local)
+	if err != nil {
+		br.Msg = "观点日期格式不正确"
+		return
+	}
+	msg, err := knowledge.ViewPointSave(req.Id, 0, "", req.Title, req.Content, req.DataSource, req.Category, 0, &dataDate)
+	if err != nil {
+		if msg == "" {
+			msg = "保存观点失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = fmt.Sprintf("保存观点失败, %v", err)
+		return
+	}
+
+	br.Msg = "保存观点成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title 观点删除
+// @Description 观点删除
+// @Param request body models.ReportViewPointReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /viewpoint/delete [post]
+func (this *ReportOpenController) ViewPointDelete() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req *models.ReportViewPointDeleteRep
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常"
+		br.ErrMsg = fmt.Sprintf("参数解析失败,%v", e)
+		return
+	}
+	if req.Id == nil {
+		br.Msg = "观点ID不能为空"
+		return
+	}
+
+	obj := new(models.KnowledgeResource)
+	obj, err := obj.GetKnowledgeResourceByOutId(*req.Id)
+	if err != nil {
+		if utils.IsErrNoRow(err) {
+			br.Msg = "观点不存在"
+			return
+		}
+		br.Msg = "删除观点失败"
+		br.ErrMsg = fmt.Sprintf("删除观点失败, %v", err)
+		return
+	}
+	obj.IsDelete = 1
+	if err = obj.Update([]string{"IsDelete"}); err != nil {
+		br.Msg = "删除观点失败"
+		br.ErrMsg = fmt.Sprintf("删除观点失败, %v", err)
+		return
+	}
+	updateMap := map[string]interface{}{
+		"IsDelete": "1",
+	}
+	err = knowledge.UpdateEsKnowledgeResource(obj.KnowledgeResourceId, updateMap)
+	if err != nil {
+		br.Msg = "删除观点失败"
+		br.ErrMsg = fmt.Sprintf("es删除观点失败, %v", err)
+		return
+	}
+
+	br.Msg = "删除观点成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title 知识资源报告库上传
+// @Description 知识资源报告库上传
+// @Param request body string/int true/false "Description"
+// @Success 200 string "操作成功"
+// @router /report/knowledge/upload [post]
+func (this *ReportOpenController) ReportKnowledgeUpload() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req models.ReportKnowledgeUploadRep
+	if e := this.BindForm(&req); e != nil {
+		br.Msg = "参数解析异常"
+		br.ErrMsg = fmt.Sprintf("参数解析失败,%v", e)
+		return
+	}
+	pushTime, err := time.Parse(utils.FormatDateTime, req.PushTime)
+	if err != nil {
+		br.Msg = "发布时间格式不正确"
+		return
+	}
+	fileUrls, msg, err := knowledge.UploadFormFile(this.Ctx.Request.MultipartForm.File)
+	if err != nil {
+		if msg == "" {
+			msg = "上传失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = fmt.Sprintf("上传失败, %v", err)
+		return
+	}
+	msg, err = knowledge.ReportKnowledgeResourceAdd(req.Title, fileUrls, 0, "", req.ClassifyPath, req.Source, pushTime)
+	if err != nil {
+		if msg == "" {
+			msg = "保存失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = fmt.Sprintf("保存失败, %v", err)
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "上传成功"
+	br.Success = true
+}

+ 5 - 0
go.mod

@@ -3,6 +3,7 @@ module eta_gn/eta_report
 go 1.21.7
 
 require (
+	github.com/PuerkitoBio/goquery v1.9.1
 	github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
 	github.com/aws/aws-sdk-go v1.51.2
 	github.com/beego/beego/v2 v2.1.0
@@ -10,12 +11,14 @@ require (
 	github.com/go-redis/redis/v8 v8.11.5
 	github.com/go-sql-driver/mysql v1.7.0
 	github.com/minio/minio-go/v7 v7.0.69
+	github.com/olivere/elastic/v7 v7.0.32
 	github.com/rdlucklib/rdluck_tools v1.0.3
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
 	gorm.io/gorm v1.25.12
 )
 
 require (
+	github.com/andybalholm/cascadia v1.3.2 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -27,10 +30,12 @@ require (
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/klauspost/compress v1.17.6 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.6 // indirect
 	github.com/kr/text v0.2.0 // indirect
+	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/minio/md5-simd v1.1.2 // indirect
 	github.com/minio/sha256-simd v1.0.1 // indirect

+ 41 - 0
go.sum

@@ -1,5 +1,7 @@
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI=
+github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -8,6 +10,8 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn
 github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
+github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
+github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
 github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
 github.com/aws/aws-sdk-go v1.51.2 h1:Ruwgz5aqIXin5Yfcgc+PCzoqW5tEGb9aDL/JWDsre7k=
 github.com/aws/aws-sdk-go v1.51.2/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
@@ -44,6 +48,8 @@ github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox
 github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
 github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -99,6 +105,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -121,6 +129,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
@@ -144,6 +154,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
+github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
@@ -206,23 +218,34 @@ github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2K
 github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
 github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
 github.com/ylywyn/jpush-api-go-client v0.0.0-20190906031852-8c4466c6e369/go.mod h1:Nv7wKD2/bCdKUFNKcJRa99a+1+aSLlCRJFriFYdjz/I=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
 golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -232,14 +255,32 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
 golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=

+ 9 - 0
models/classify.go

@@ -60,6 +60,15 @@ func (m *Classify) GetItemById(id int) (item *Classify, err error) {
 	return
 }
 
+func (m *Classify) GetItemsByIds(ids []int) (items []*Classify, err error) {
+	if len(ids) == 0 {
+		return
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s IN (?) ORDER BY level ASC`, m.TableName(), "id")
+	err = global.DEFAULT_DmSQL.Raw(sql, ids).Find(&items).Error
+	return
+}
+
 func (m *Classify) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*Classify, err error) {
 	fields := strings.Join(fieldArr, ",")
 	if len(fieldArr) == 0 {

+ 151 - 0
models/knowledge_resource.go

@@ -0,0 +1,151 @@
+package models
+
+import (
+	"eta_gn/eta_report/global"
+	"eta_gn/eta_report/utils"
+	"time"
+)
+
+const (
+	// 事件类型-事件库
+	KnowledgeResourceTypeEvent = iota
+	// 事件-政策库
+	KnowledgeResourceTypePolicy
+	// 事件-报告库
+	KnowledgeResourceTypeReport
+	// 事件类型-知识库
+	KnowledgeResourceTypeKnow
+	// 事件-观点库
+	KnowledgeResourceTypeOpinion
+)
+
+const (
+	// 未发布
+	KnowledgeResourceStateUnpublished = iota
+	// 已发布
+	KnowledgeResourceStatePublished
+	// 待审批
+	KnowledgeResourceStatePending
+	// 已驳回
+	KnowledgeResourceStateRejected
+	// 已通过
+	KnowledgeResourceStateApproved
+)
+
+type KnowledgeResourceFile struct {
+	KnowledgeResourceFileId int    `gorm:"column:knowledge_resource_file_id;primaryKey;autoIncrement"`
+	KnowledgeResourceId     int    `gorm:"column:knowledge_resource_id"`
+	FileUrl                 string `gorm:"column:file_url"`
+}
+
+func (k KnowledgeResourceFile) TableName() string {
+	return "knowledge_resource_file"
+}
+
+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          time.Time  `gorm:"column:create_time" description:"创建时间"`
+	ModifyTime          time.Time  `gorm:"column:modify_time;autoUpdateTime" description:"修改时间"`
+	State               int        `gorm:"column:state" description:"0:未发布;1:已发布;2:待审批;3:已驳回;4:已通过"`
+	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           *time.Time `gorm:"column:start_time"`
+	EndTime             *time.Time `gorm:"column:end_time"`
+	IsFile              int        `gorm:"column:is_file;default:0;NOT NULL"`
+	FileUrl             string     `gorm:"column:file_url"`
+	OutId               int        `gorm:"column:out_id" description:"外部系统ID"`
+	IsDelete            int        `gorm:"column:is_delete;default:0;NOT NULL"`
+}
+
+func (k KnowledgeResource) TableName() string {
+	return "knowledge_resource"
+}
+
+func (k *KnowledgeResource) Create(fileUrl []string) (err error) {
+	tx := global.DEFAULT_DmSQL.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	err = tx.Create(k).Error
+	if len(fileUrl) > 0 {
+		addFile := make([]*KnowledgeResourceFile, 0, len(fileUrl))
+		for _, url := range fileUrl {
+			file := new(KnowledgeResourceFile)
+			file.KnowledgeResourceId = k.KnowledgeResourceId
+			file.FileUrl = url
+			addFile = append(addFile, file)
+		}
+		err = tx.CreateInBatches(addFile, utils.MultiAddNum).Error
+	}
+	return
+}
+
+func (k *KnowledgeResource) Update(cols []string) error {
+	return global.DEFAULT_DmSQL.Model(k).Select(cols).Updates(k).Error
+}
+
+// GetKnowledgeResourceByOutId 根据外部系统ID获取知识资源
+func (k *KnowledgeResource) GetKnowledgeResourceByOutId(outId int) (item *KnowledgeResource, err error) {
+	sql := "SELECT * FROM knowledge_resource WHERE out_id = ?"
+	err = global.DEFAULT_DmSQL.Raw(sql, outId).First(&item).Error
+	return
+}
+
+type KnowledgeClassify struct {
+	ClassifyId   int       `gorm:"primaryKey;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"`
+}
+
+func (k KnowledgeClassify) TableName() string {
+	return "knowledge_classify"
+}
+
+func (k *KnowledgeClassify) Create() error {
+	return global.DEFAULT_DmSQL.Create(k).Error
+}
+
+func (k *KnowledgeClassify) GetClassifyByNameTypeAndParentId(classifyName string, resourceType, parentId int) (items *KnowledgeClassify, err error) {
+	sql := "SELECT * FROM knowledge_classify WHERE classify_name = ? AND resource_type = ? AND parent_id = ?"
+	err = global.DEFAULT_DmSQL.Raw(sql, classifyName, resourceType, parentId).First(&items).Error
+	return
+}
+
+func (k *KnowledgeClassify) GetClassifysByNameAndType(classifyName string, resourceType int) (item *KnowledgeClassify, err error) {
+	sql := "SELECT * FROM knowledge_classify WHERE classify_name = ? AND resource_type = ?"
+	err = global.DEFAULT_DmSQL.Raw(sql, classifyName, resourceType).Find(&item).Error
+	return
+}
+
+func (k *KnowledgeClassify) GetChildClassifyIdByNamePath(classifyNameFirst string, classifyNameSecond string, classifyNameThird string) (id int, err error) {
+	sql := `SELECT 
+    c3.classify_id AS id
+	FROM knowledge_classify c1 
+	JOIN knowledge_classify c2 ON c2.parent_id = c1.classify_id 
+					AND c2.classify_name = ? 
+					AND c2.level = 2
+	JOIN knowledge_classify c3 ON c3.parent_id = c2.classify_id 
+					AND c3.classify_name = ?
+					AND c3.level = 3
+	WHERE c1.classify_name = ?
+	AND c1.level = 1 `
+	err = global.DEFAULT_DmSQL.Raw(sql, classifyNameSecond, classifyNameThird, classifyNameFirst).Scan(&id).Error
+	return
+}

+ 1 - 0
models/ppt_v2.go

@@ -15,6 +15,7 @@ type PptV2 struct {
 	Title            string    `gorm:"column:title" description:"标题"`
 	ReportType       string    `gorm:"column:report_type" description:"报告类型"`
 	PptDate          string    `gorm:"column:ppt_date" description:"选择日期"`
+	Abstract         string    `gorm:"column:abstract" description:"摘要"`
 	Content          string    `gorm:"column:content" description:"ppt内容"`
 	PptUrl           string    `gorm:"column:ppt_url" description:"ppt下载地址"`
 	PptxUrl          string    `gorm:"column:pptx_url" description:"pptx下载地址"`

+ 23 - 0
models/report_open.go

@@ -5,6 +5,7 @@ type ReportCreateReq struct {
 	ReportId   int      `description:"智力共享报告ID"`
 	ClassifyId int      `description:"分类ID"`
 	Title      string   `description:"报告标题"`
+	Abstract   string   `description:"报告摘要"`
 	EndTime    string   `description:"课题结束时间"`
 	Creator    string   `description:"创建人工号"`
 	Authors    []string `description:"作者工号"`
@@ -20,6 +21,7 @@ type ReportCreateResp struct {
 type ReportModifyReq struct {
 	ReportId int      `description:"智力共享报告ID"`
 	Title    string   `description:"报告标题"`
+	Abstract string   `description:"报告摘要"`
 	EndTime  string   `description:"课题结束时间"`
 	Authors  []string `description:"作者工号"`
 	Operator string   `description:"操作人工号"`
@@ -38,3 +40,24 @@ type ReportRemoveReq struct {
 	ReportIds []int  `description:"智力共享报告ID"`
 	Operator  string `description:"操作人工号"`
 }
+
+type ReportViewPointSaveReq struct {
+	Id         int    `description:"观点库外部id"`
+	Title      string `description:"观点标题"`
+	Category   string `description:"观点分类"`
+	Content    string `description:"观点内容"`
+	DataSource string `description:"数据来源名称"`
+	DataDate   string `description:"数据日期"`
+	UpdateTime string `description:"更新时间"`
+}
+
+type ReportViewPointDeleteRep struct {
+	Id *int `description:"观点库外部id"`
+}
+
+type ReportKnowledgeUploadRep struct {
+	Title        string `form:"title" description:"文件标题"`
+	Source       string `form:"source" description:"文件来源"`
+	ClassifyPath string `form:"classify_path" description:"文件分类路径"`
+	PushTime     string `form:"push_time" description:"上传时间"`
+}

+ 27 - 0
routers/commentsRouter.go

@@ -70,6 +70,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportOpenController"] = append(beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportOpenController"],
+        beego.ControllerComments{
+            Method: "ReportKnowledgeUpload",
+            Router: `/report/knowledge/upload`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportOpenController"] = append(beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportOpenController"],
         beego.ControllerComments{
             Method: "ReportModify",
@@ -88,6 +97,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportOpenController"] = append(beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportOpenController"],
+        beego.ControllerComments{
+            Method: "ViewPointDelete",
+            Router: `/viewpoint/delete`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportOpenController"] = append(beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportOpenController"],
+        beego.ControllerComments{
+            Method: "ViewPointSave",
+            Router: `/viewpoint/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportShareController"] = append(beego.GlobalControllerRouter["eta_gn/eta_report/controllers:ReportShareController"],
         beego.ControllerComments{
             Method: "Detail",

+ 86 - 0
services/knowledge/es.go

@@ -0,0 +1,86 @@
+package knowledge
+
+import (
+	"context"
+	"encoding/json"
+	"eta_gn/eta_report/models"
+	"eta_gn/eta_report/utils"
+	"fmt"
+	"html"
+	"strconv"
+	"strings"
+
+	"github.com/PuerkitoBio/goquery"
+)
+
+// EsAddOrEditKnowledgeResource 新增/修改es中的知识资源数据
+func EsAddOrEditKnowledgeResource(item *models.KnowledgeResource) (err error) {
+	defer func() {
+		if err != nil {
+			fmt.Println("EsAddOrEditData Err:", err.Error())
+			utils.FileLog.Info("EsAddOrEditKnowledgeResource err:", err)
+		}
+	}()
+	indexName := utils.EsKnowledgeResourceIndexName
+	client := utils.EsClient
+	if item.IsFile == 0 {
+		content := ExtractTextFromResourceContent(item.Content)
+		contentRunes := []rune(content)
+		if len(contentRunes) > 60 {
+			item.Content = string(contentRunes[:60])
+		} else {
+			item.Content = content
+		}
+	}
+	request := client.Index().Index(indexName).Id(strconv.Itoa(item.KnowledgeResourceId)).BodyJson(item)
+	response, err := request.Do(context.Background())
+	if err != nil {
+		jsonBytes, _ := json.Marshal(item)
+		utils.FileLog.Info("add json:%s,EsAddOrEditKnowledgeResource err:%s", string(jsonBytes), err.Error())
+		return
+	}
+	if response.Status == 0 {
+		err = nil
+	} else {
+		fmt.Println("EsAddOrEditKnowledgeResource:", response.Status, response.Result)
+	}
+	return
+}
+
+func ExtractTextFromResourceContent(content string) (text string) {
+	content = html.UnescapeString(content)
+	doc, err := goquery.NewDocumentFromReader(strings.NewReader(content))
+	if err != nil {
+		return
+	}
+	text = doc.Text()
+	text = strings.ReplaceAll(text, "\n", "")
+	return
+}
+
+func UpdateEsKnowledgeResource(docId int, docFields map[string]interface{}) (err error) {
+	defer func() {
+		if err != nil {
+			fmt.Println("EsAddOrEditData Err:", err.Error())
+			utils.FileLog.Info("EsAddOrEditKnowledgeResource err:", err)
+		}
+	}()
+	indexName := utils.EsKnowledgeResourceIndexName
+	client := utils.EsClient
+
+	res, err := client.Update().
+		Index(indexName).
+		Id(strconv.Itoa(docId)).
+		Doc(docFields).
+		Do(context.Background())
+	if err != nil {
+		utils.FileLog.Info("update docId:%d,UpdateEsKnowledgeResource err:%s", docId, err.Error())
+		return
+	}
+	if res.Result == "updated" {
+		err = nil
+	} else {
+		fmt.Println("UpdateEsKnowledgeResource:", res.Result)
+	}
+	return
+}

+ 310 - 0
services/knowledge/knowledge_resource.go

@@ -0,0 +1,310 @@
+package knowledge
+
+import (
+	"eta_gn/eta_report/models"
+	"eta_gn/eta_report/services"
+	"eta_gn/eta_report/utils"
+	"fmt"
+	"html"
+	"io/ioutil"
+	"mime/multipart"
+	"os"
+	"path"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func ReportKnowledgeResourceAdd(title string, fileUrl []string, adminId int, adminRealName, classifyPath, sourceFrom string, pushTime time.Time) (msg string, err error) {
+	classifyObj := new(models.KnowledgeClassify)
+	var childClassifyId int
+	if classifyPath != "" {
+		classifyPathArr := strings.Split(classifyPath, "/")
+		var classifyFirst, classifySecond, classifyThird string
+		switch len(classifyPathArr) {
+		case 1:
+			classifyFirst = classifyPathArr[0]
+		case 2:
+			classifyFirst = classifyPathArr[0]
+			classifySecond = classifyPathArr[1]
+		case 3:
+			classifyFirst = classifyPathArr[0]
+			classifySecond = classifyPathArr[1]
+			classifyThird = classifyPathArr[2]
+		}
+		childClassifyId, err = classifyObj.GetChildClassifyIdByNamePath(classifyFirst, classifySecond, classifyThird)
+		if err != nil {
+			if utils.IsErrNoRow(err) {
+				msg = "分类不存在,请检查知识资源-报告库中是否存在-" + classifyPath
+				return
+			}
+			msg = "报告库添加失败"
+			return
+		}
+	} else {
+		msg = "分类不能为空"
+		return
+	}
+	obj := new(models.KnowledgeResource)
+	obj.ResourceType = models.KnowledgeResourceTypeReport
+	obj.ClassifyId = childClassifyId
+	obj.Title = title
+	obj.CreateTime = time.Now()
+	obj.ModifyTime = time.Now()
+	obj.State = models.KnowledgeResourceStatePublished
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	obj.ResourceCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp)
+	obj.AdminId = adminId
+	obj.AdminRealName = adminRealName
+	obj.SourceFrom = sourceFrom
+	obj.StartTime = &pushTime
+	// 此处传入的url会在入库时存入knowledge_resource_file表中
+	if len(fileUrl) != 0 {
+		obj.IsFile = 1
+	}
+	err = obj.Create(fileUrl)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func ReportKnowledgeResourceClassifyCheckAndSave(reportClassifyId int) (classifyId int, err error) {
+	classifyObj := new(models.Classify)
+	classifyObj, err = classifyObj.GetItemById(reportClassifyId)
+	if err != nil {
+		if !utils.IsErrNoRow(err) {
+			return
+		}
+	}
+	levelPath := classifyObj.LevelPath
+	classifyIdStrs := strings.Split(levelPath, ",")
+	classifyIds := make([]int, 0, len(classifyIdStrs))
+	for _, classifyIdStr := range classifyIdStrs {
+		classifyId, _ := strconv.Atoi(classifyIdStr)
+		classifyIds = append(classifyIds, classifyId)
+	}
+	classifyList, err := classifyObj.GetItemsByIds(classifyIds)
+	if err != nil {
+		return
+	}
+	knowledgeClassifyObj := new(models.KnowledgeClassify)
+	var parentId int
+	for i, classify := range classifyList {
+		knowledgeClassifyObj, err = knowledgeClassifyObj.GetClassifyByNameTypeAndParentId(classify.ClassifyName, models.KnowledgeResourceTypeOpinion, parentId)
+		if err != nil {
+			if !utils.IsErrNoRow(err) {
+				return
+			}
+			for j := i; j < len(classifyList); j++ {
+				tmp := &models.KnowledgeClassify{
+					ClassifyName: classifyList[j].ClassifyName,
+					Sort:         1,
+					ParentId:     parentId,
+					CreateTime:   time.Now(),
+					ModifyTime:   time.Now(),
+					Enabled:      1,
+					Level:        classifyList[j].Level,
+					ResourceType: models.KnowledgeResourceTypeOpinion,
+				}
+				err = tmp.Create()
+				if err != nil {
+					return
+				}
+				parentId = tmp.ClassifyId
+			}
+			classifyId = parentId
+			return
+		}
+		parentId = knowledgeClassifyObj.ClassifyId
+	}
+	classifyId = parentId
+	return
+}
+
+// ViewPointSave 知识资源观点库保存
+func ViewPointSave(outId, adminId int, adminRealName, title, content, sourceFrom, classifyName string, classifyId int, startTime *time.Time) (msg string, err error) {
+	if classifyId <= 0 {
+		tmpClassifyId, er := ViewPointKnowledgeResourceClassifyCheckAndSave(classifyName, models.KnowledgeResourceTypeOpinion)
+		if er != nil {
+			msg = "观点保存失败"
+			err = er
+			return
+		}
+		classifyId = tmpClassifyId
+	}
+	obj := new(models.KnowledgeResource)
+	knowledgeResource, err := obj.GetKnowledgeResourceByOutId(outId)
+	esObj := new(models.KnowledgeResource)
+	if err != nil && !utils.IsErrNoRow(err) {
+		msg = "观点保存失败"
+		return
+	}
+	if outId <= 0 || utils.IsErrNoRow(err) {
+		// 创建新的知识资源库
+		err = nil
+		obj.ResourceType = models.KnowledgeResourceTypeOpinion
+		obj.ClassifyId = classifyId
+		obj.Title = title
+		obj.CreateTime = time.Now()
+		obj.ModifyTime = time.Now()
+		obj.State = models.KnowledgeResourceStateApproved
+		obj.Content = html.EscapeString(content)
+		timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+		obj.ResourceCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp)
+		obj.AdminId = adminId
+		if adminRealName == "" || obj.AdminId == 0 {
+			obj.AdminRealName = "无"
+		} else {
+			obj.AdminRealName = adminRealName
+		}
+		obj.SourceFrom = sourceFrom
+		obj.StartTime = startTime
+		obj.IsFile = 0
+		err = obj.Create([]string{})
+		if err != nil {
+			msg = "观点保存失败"
+			return
+		}
+		esObj = obj
+	} else {
+		// 更新知识资源库的状态
+		var updateCols []string
+		if knowledgeResource.Title != title {
+			knowledgeResource.Title = title
+			updateCols = append(updateCols, "title")
+		}
+		if knowledgeResource.Content != content {
+			knowledgeResource.Content = content
+			updateCols = append(updateCols, "content")
+		}
+		if !knowledgeResource.StartTime.Equal(*startTime) {
+			knowledgeResource.StartTime = startTime
+			updateCols = append(updateCols, "start_time")
+		}
+		if knowledgeResource.SourceFrom != sourceFrom {
+			knowledgeResource.SourceFrom = sourceFrom
+			updateCols = append(updateCols, "source_from")
+		}
+
+		if len(updateCols) > 0 {
+			knowledgeResource.ModifyTime = time.Now()
+			updateCols = append(updateCols, "modify_time")
+			err = knowledgeResource.Update(updateCols)
+			if err != nil {
+				msg = "观点保存失败"
+				return
+			}
+		}
+		esObj = knowledgeResource
+	}
+
+	go func() {
+		er := EsAddOrEditKnowledgeResource(esObj)
+		if er != nil {
+			utils.FileLog.Info("es ViewPointSave error:%v", er)
+		}
+	}()
+	return
+}
+
+func ViewPointKnowledgeResourceClassifyCheckAndSave(classifyName string, resourceType int) (classifyId int, err error) {
+	obj := new(models.KnowledgeClassify)
+	obj, err = obj.GetClassifyByNameTypeAndParentId(classifyName, resourceType, 0)
+	if err != nil {
+		if !utils.IsErrNoRow(err) {
+			return
+		}
+		// 创建新的分类
+		err = nil
+		obj.ClassifyName = classifyName
+		obj.ResourceType = resourceType
+		obj.CreateTime = time.Now()
+		obj.ModifyTime = time.Now()
+		obj.Enabled = 1
+		obj.Level = 1
+		obj.Sort = 1
+		err = obj.Create()
+		if err != nil {
+			return
+		}
+		classifyId = obj.ClassifyId
+	} else {
+		classifyId = obj.ClassifyId
+	}
+	return
+}
+
+func UploadFormFile(multipartFile map[string][]*multipart.FileHeader) (fileUrl []string, msg string, err error) {
+	client := services.NewOssClient()
+
+	// 定义允许的文件格式
+	allowedExtensions := map[string]bool{
+		".pdf":  true,
+		".doc":  true,
+		".docx": true,
+		".ppt":  true,
+		".pptx": true,
+	}
+	for _, file := range multipartFile {
+		for _, f := range file {
+			if f.Filename == "" {
+				continue
+			}
+			ext := path.Ext(f.Filename)
+			if !allowedExtensions[ext] {
+				msg = "文件格式不正确"
+				err = fmt.Errorf("文件格式不正确")
+				return
+			}
+			saveName := fmt.Sprint(utils.MD5(f.Filename), time.Now().Format(utils.FormatDateTimeUnSpace), time.Now().Nanosecond(), ext)
+			dataDir := time.Now().Format(utils.FormatDate)
+			filePath := utils.StaticDir + "files/" + dataDir + "/" + saveName
+			ok, _ := utils.PathExists(filePath)
+			if !ok {
+				err = os.MkdirAll(filePath, utils.DIR_MOD)
+				if err != nil {
+					msg = "目录创建失败"
+					return
+				}
+			}
+			fileContent, er := f.Open()
+			if er != nil {
+				msg = "文件打开失败"
+				err = er
+				return
+			}
+			fileContentBytes, er := ioutil.ReadAll(fileContent)
+			if er != nil {
+				msg = "文件读取失败"
+				err = er
+				return
+			}
+			// 保存到本地
+			er = utils.SaveToFile(fileContentBytes, filePath)
+			if er != nil {
+				msg = "文件保存失败"
+				err = er
+				return
+			}
+			_, er = os.Stat(filePath)
+			if er != nil {
+				msg = "文件信息获取失败"
+				err = er
+				return
+			}
+			randStr := utils.GetRandStringNoSpecialChar(28)
+			fileName := randStr + ext
+
+			savePath := fmt.Sprintf("%s%s%s", utils.UploadFileDir, time.Now().Format("200601/20060102/"), fileName)
+			resourceUrl, er := client.UploadFile(fileName, filePath, savePath)
+			if er != nil {
+				msg = "文件上传失败"
+				err = er
+				return
+			}
+			fileUrl = append(fileUrl, resourceUrl)
+		}
+	}
+	return
+}

+ 10 - 6
services/report_open.go

@@ -62,7 +62,7 @@ func GetReportByOutReportId(outReportId int) (reportItem *models.Report, pptItem
 }
 
 // CreatePptReport 创建PPT报告
-func CreatePptReport(outReportId, classifyId int, title string, topicEndTime time.Time, creator string, authors []string) (reportId int, err error) {
+func CreatePptReport(outReportId, classifyId int, title, abstract string, topicEndTime time.Time, creator string, authors []string) (reportId int, err error) {
 	defer func() {
 		if err != nil {
 			utils.FileLog.Info(fmt.Sprintf("创建外部PPT报告失败, OutReportId: %d, %v", outReportId, err))
@@ -94,6 +94,7 @@ func CreatePptReport(outReportId, classifyId int, title string, topicEndTime tim
 	// 新建PPT基础信息
 	newItem := new(models.PptV2)
 	newItem.Title = title
+	newItem.Abstract = abstract
 	newItem.AddType = utils.ReportAddTypeInherit
 	newItem.ClassifyId = classifyId
 	newItem.CollaborateType = utils.ReportWriteTypeGroup
@@ -287,7 +288,7 @@ func CountParentClassifyReportNumRecursive(list []*models.Classify, parentId int
 }
 
 // CreateReport 创建报告
-func CreateReport(outReportId, classifyId int, title string, topicEndTime time.Time, creator string, authors []string) (reportId int, err error) {
+func CreateReport(outReportId, classifyId int, title, abstract string, topicEndTime time.Time, creator string, authors []string) (reportId int, err error) {
 	defer func() {
 		if err != nil {
 			utils.FileLog.Info(fmt.Sprintf("创建外部报告失败, OutReportId: %d, %v", outReportId, err))
@@ -372,6 +373,7 @@ func CreateReport(outReportId, classifyId int, title string, topicEndTime time.T
 
 	// 新报告信息
 	newItem := new(models.Report)
+	newItem.Abstract = abstract
 	newItem.AddType = utils.ReportAddTypeInherit // 固定继承
 	newItem.ReportVersion = 2                    // 固定新版报告
 	newItem.ClassifyIdFirst = classifyIdFirst
@@ -545,7 +547,7 @@ func CreateReport(outReportId, classifyId int, title string, topicEndTime time.T
 }
 
 // EditReport 编辑报告
-func EditReport(reportItem *models.Report, title string, topicEndTime time.Time, authors []string) (err error) {
+func EditReport(reportItem *models.Report, title, abstract string, topicEndTime time.Time, authors []string) (err error) {
 	if reportItem == nil {
 		err = fmt.Errorf("报告信息有误")
 		return
@@ -629,10 +631,11 @@ func EditReport(reportItem *models.Report, title string, topicEndTime time.Time,
 	}
 
 	// 更新报告和移除授权
+	reportItem.Abstract = abstract
 	reportItem.Title = title
 	reportItem.TopicEndTime = topicEndTime
 	reportItem.ModifyTime = time.Now()
-	updateCols := []string{"Title", "TopicEndTime", "ModifyTime"}
+	updateCols := []string{"Title", "Abstract", "TopicEndTime", "ModifyTime"}
 	if e := reportItem.EditReportAndClearGrant(reportItem, updateCols, chapterIds, removePartner); e != nil {
 		err = fmt.Errorf("更新报告失败, %v", e)
 		return
@@ -641,7 +644,7 @@ func EditReport(reportItem *models.Report, title string, topicEndTime time.Time,
 }
 
 // EditPptReport 编辑PPT报告
-func EditPptReport(pptItem *models.PptV2, title string, topicEndTime time.Time, authors []string) (err error) {
+func EditPptReport(pptItem *models.PptV2, title, abstract string, topicEndTime time.Time, authors []string) (err error) {
 	if pptItem == nil {
 		err = fmt.Errorf("PPT报告信息有误")
 		return
@@ -672,6 +675,7 @@ func EditPptReport(pptItem *models.PptV2, title string, topicEndTime time.Time,
 	// 新建PPT基础信息
 	pptItem.Title = title
 	pptItem.TopicEndTime = topicEndTime
+	pptItem.Abstract = abstract
 	if len(authors) > 0 {
 		var partnerArr []string
 		for _, v := range authors {
@@ -684,7 +688,7 @@ func EditPptReport(pptItem *models.PptV2, title string, topicEndTime time.Time,
 		}
 		pptItem.CollaborateUsers = strings.Trim(strings.Join(partnerArr, ","), `"`)
 	}
-	updateCols := []string{"Title", "TopicEndTime", "CollaborateUsers"}
+	updateCols := []string{"Title", "Abstract", "TopicEndTime", "CollaborateUsers"}
 	if e := pptItem.Update(updateCols); e != nil {
 		err = fmt.Errorf("更新PPT报告失败, %v", e)
 		return

+ 26 - 1
utils/common.go

@@ -10,7 +10,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"gorm.io/gorm"
 	"image"
 	"image/png"
 	"math"
@@ -22,6 +21,8 @@ import (
 	"strconv"
 	"strings"
 	"time"
+
+	"gorm.io/gorm"
 )
 
 func GetRandString(size int) string {
@@ -613,3 +614,27 @@ func InArrayByStr(idStrList []string, searchId string) (has bool) {
 	}
 	return
 }
+
+// SaveToFile
+// @Description: 将字节内容保存到本地文件
+// @author: Roc
+// @datetime 2024-09-05 18:12:55
+// @param content []byte
+// @param fileName string
+// @return error
+func SaveToFile(content []byte, fileName string) error {
+	file, err := os.Create(fileName)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		_ = file.Close()
+	}()
+
+	_, err = file.Write(content)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}

+ 33 - 1
utils/config.go

@@ -2,8 +2,9 @@ package utils
 
 import (
 	"fmt"
-	"github.com/beego/beego/v2/server/web"
 	"strconv"
+
+	"github.com/beego/beego/v2/server/web"
 )
 
 var (
@@ -59,12 +60,17 @@ var (
 	ResourceProxyUrl    string // 代理资源地址
 )
 
+var (
+	StaticDir string //静态文件目录
+)
+
 // 阿里云配置
 var (
 	Bucketname       string
 	Endpoint         string
 	Imghost          string
 	UploadDir        string
+	UploadFileDir    string
 	Upload_Audio_Dir string
 	AccessKeyId      string
 	AccessKeySecret  string
@@ -100,6 +106,17 @@ var (
 	S3OpenAcl         string
 )
 
+// ES配置
+var (
+	ES_URL      string // ES服务器地址
+	ES_USERNAME string // ES账号
+	ES_PASSWORD string // ES密码
+)
+
+var (
+	EsKnowledgeResourceIndexName string //ES知识资源库索引
+)
+
 var (
 	AppId  string
 	Secret string
@@ -201,12 +218,15 @@ func init() {
 	ObjectStorageClient = config["object_storage_client"]
 	// 代理资源地址
 	ResourceProxyUrl = config["resource_proxy_url"]
+	// 静态资源目录
+	StaticDir = config["static_dir"]
 	// OSS相关
 	{
 		Endpoint = config["endpoint"]
 		Bucketname = config["bucket_name"]
 		Imghost = config["img_host"]
 		UploadDir = config["upload_dir"]
+		UploadFileDir = config["upload_file_dir"]
 		Upload_Audio_Dir = config["upload_audio_dir"]
 		AccessKeyId = config["access_key_id"]
 		AccessKeySecret = config["access_key_secret"]
@@ -241,7 +261,19 @@ func init() {
 		S3DisableSSL = config["s3_disable_ssl"]
 		S3OpenAcl = config["s3_open_acl"]
 	}
+	// ES配置
+	{
+		ES_URL = config["es_url"]
+		ES_USERNAME = config["es_username"]
+		ES_PASSWORD = config["es_password"]
+	}
+
+	{
+		// ES知识资源库索引
+		EsKnowledgeResourceIndexName = config["es_knowledge_resource_index_name"]
+	}
 
 	AppId = config["appid"]
 	Secret = config["secret"]
+	initEs()
 }

+ 5 - 1
utils/constants.go

@@ -1,5 +1,7 @@
 package utils
 
+import "io/fs"
+
 // 常量定义
 const (
 	FormatTime            = "15:04:05"                //时间格式
@@ -20,13 +22,15 @@ const (
 const (
 	APPNAME = "ETA报告服务"
 )
-
+const DIR_MOD fs.FileMode = 0766 // Unix permission bits
 // 手机号,电子邮箱正则
 const (
 	RegularMobile = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0-9])|(17[0-9])|(16[0-9])|(19[0-9]))\\d{8}$" //手机号码
 	RegularEmail  = `\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`                                             //匹配电子邮箱
 )
 
+const CHART_PREFIX = "hz_chart"
+
 // 缓存key
 const (
 	CACHE_KEY_USER_VIEW = "user_view_record" //用户阅读数据

+ 21 - 0
utils/elastic.go

@@ -0,0 +1,21 @@
+package utils
+
+import (
+	"github.com/olivere/elastic/v7"
+)
+
+// EsClient es客户端
+var EsClient *elastic.Client
+
+func initEs() {
+	client, err := elastic.NewClient(
+		elastic.SetURL(ES_URL),
+		elastic.SetBasicAuth(ES_USERNAME, ES_PASSWORD),
+		elastic.SetSniff(false))
+	EsClient = client
+	if err != nil {
+		panic("ElasticSearch连接失败,err:" + err.Error())
+		//go alarm_msg.SendAlarmMsg("ElasticSearch连接失败", 2)
+	}
+	return
+}