瀏覽代碼

Merge branch 'bzq/dev' of eta_mini/eta_mini_api into master

鲍自强 8 月之前
父節點
當前提交
162a528837

+ 2 - 1
.gitignore

@@ -4,4 +4,5 @@
 *.exe
 *.exe~
 go.sum
-/rdlucklog/
+/rdlucklog/
+*_test.go

+ 3 - 6
controllers/base_auth.go

@@ -101,13 +101,10 @@ func (c *BaseAuthController) ServeJSON(encoding ...bool) {
 			requestBody = string(c.Ctx.Input.RequestBody)
 		}
 		if baseRes.Ret != 200 && c.User != nil {
-			//go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "URI:"+c.Ctx.Input.URI()+"<br/> "+"Params"+requestBody+" <br/>"+"ErrMsg:"+baseRes.ErrMsg+";<br/>Msg:"+baseRes.Msg+";<br/> Body:"+string(body)+"<br/>"+c.SysUser.RealName, utils.EmailSendToUsers)
-			body := "URI:" + c.Ctx.Input.URI() + "<br/> " + "Params" + requestBody + " <br/>" + "ErrMsg:" + baseRes.ErrMsg + ";<br/>Msg:" + baseRes.Msg + ";<br/> Body:" + string(body) + "<br/>" + c.User.RealName
+			//go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "URI:"+c.Ctx.Input.URI()+"<br/> "+"Params"+requestBody+" <br/>"+"ErrMsg:"+baseRes.ErrMsg+";<br/>Msg:"+baseRes.Msg+";<br/> Body:"+string(content)+"<br/>"+c.SysUser.RealName, utils.EmailSendToUsers)
+			content := "URI:" + c.Ctx.Input.URI() + "<br/> " + "Params" + requestBody + " <br/>" + "ErrMsg:" + baseRes.ErrMsg + ";<br/>Msg:" + baseRes.Msg + ";<br/> Body:" + string(body) + "<br/>" + c.User.RealName
 			// go alarm_msg.SendAlarmMsg(body, 1)
-			utils.ApiLog.Notice(body)
-		}
-		if baseRes.IsAddLog && c.User != nil {
-			return
+			utils.ApiLog.Notice(content)
 		}
 	}
 

+ 0 - 61
controllers/chart.go

@@ -1,13 +1,9 @@
 package controllers
 
 import (
-	"encoding/json"
 	"eta/eta_mini_api/models"
 	"eta/eta_mini_api/models/response"
 	"eta/eta_mini_api/services"
-	"eta/eta_mini_api/services/alarm_msg"
-	"eta/eta_mini_api/utils"
-	"fmt"
 )
 
 type ChartController struct {
@@ -41,9 +37,6 @@ func (this *ChartController) List() {
 		br.ErrMsg = result.ErrMsg
 		return
 	}
-	resp := new(response.ChartListResp)
-	resp.List = result.Data.List
-	resp.Paging = result.Data.Paging
 
 	br.Msg = "查询图表成功"
 	br.Data = result.Data
@@ -51,60 +44,6 @@ func (this *ChartController) List() {
 	br.Ret = 200
 }
 
-// @Title Detail
-// @Description 图表详情
-// @Param   ChartInfoId   query   int  true       "图表详情id"
-// @Success 200 {object} models.BaseResponse
-// @router /detail [get]
-func (this *ChartController) Detail() {
-	br := new(models.BaseResponse).Init()
-	defer func() {
-		if br.Ret != 200 {
-			errb, _ := json.Marshal(br)
-			alarm_msg.SendAlarmMsg(fmt.Sprintf("获得图表详情失败:%s, user:%d", string(errb), this.User.UserId), 1)
-		}
-		this.Data["json"] = br
-		this.ServeJSON()
-	}()
-	user := this.User
-	if user.Status != utils.UserStatusFormal {
-		br.Msg = "用户没有权限查看图表"
-		return
-	}
-
-	chartInfoId, _ := this.GetInt("ChartInfoId")
-	if chartInfoId <= 0 {
-		br.Msg = "图表id错误"
-		return
-	}
-
-	result, err := services.GetChartDetail(chartInfoId, "")
-	if err != nil {
-		br.Msg = "获取图表详情失败"
-		br.ErrMsg = "获取图表详情失败,Err:" + err.Error()
-		return
-	}
-	if result.Ret == 200 && result.Data.UniqueCode == "" {
-		// 说明后台删除了这个图表,那么尝试将收藏的图表也删除
-		alarm_msg.SendAlarmMsg(fmt.Sprintf("图表不存在,删除图表,id:%d", chartInfoId), 1)
-		models.DeleteMyChartByUserIdAndChartInfoId(user.UserId, chartInfoId)
-		br.Msg = "图表已删除或不存在"
-		return
-	}
-	count, err := models.GetMyChartCount(user.UserId, result.Data.UniqueCode)
-	if err != nil {
-		br.Msg = "获取图表详情失败"
-		br.ErrMsg = "获取图表详情失败,Err:" + err.Error()
-	}
-	if count > 0 {
-		result.Data.IsCollect = true
-	}
-	br.Data = result.Data
-	br.Msg = "查询成功"
-	br.Success = true
-	br.Ret = 200
-}
-
 // @Title Locate
 // @Description create users
 // @Param   PageSize   query   int  true       "每页数据条数"

+ 54 - 5
controllers/chart_permission.go

@@ -3,6 +3,7 @@ package controllers
 import (
 	"eta/eta_mini_api/models"
 	"eta/eta_mini_api/services"
+	"eta/eta_mini_api/utils"
 )
 
 type ChartPermissionController struct {
@@ -12,7 +13,7 @@ type ChartPermissionController struct {
 // List
 // @Title 系统品种列表
 // @Description 系统品种列表
-// @Param   UserId   query   int  true       "角色ID"
+// @Param   chartPermissonId   query   int  true       "品种权限id"
 // @Success 200 {object} models.LoginResp
 // @router /list [get]
 func (this *ChartPermissionController) List() {
@@ -23,7 +24,7 @@ func (this *ChartPermissionController) List() {
 	}()
 	id, _ := this.GetInt("chartPermissonId", 0)
 
-	var resp *models.ChartPermissionResp[[]models.ChartPermission]
+	var resp *models.ChartPermissionResp[[]*models.ChartPermission]
 	var err error
 	if id == 0 {
 		resp, err = services.GetChartPermissionList()
@@ -40,15 +41,27 @@ func (this *ChartPermissionController) List() {
 		br.ErrMsg = resp.ErrMsg
 		return
 	}
-	chartPermissionList := make([]models.ChartPermissionView, 0)
+	chartPermissionList := make([]*models.ChartPermissionView, 0)
 	for _, item := range resp.Data {
-		chartPermissionList = append(chartPermissionList, models.ChartPermissionView{
+		chartPermissionList = append(chartPermissionList, &models.ChartPermissionView{
 			ChartPermissionId:   item.ChartPermissionId,
-			ChartPermissionName: item.ChartPermissionName,
 			PermissionName:      item.PermissionName,
 			Remark:              item.Remark,
 			ImageUrl:            item.ImageUrl,
+			ChartPermissionType: utils.PermissionTypeEta,
 		})
+
+	}
+	// 如果id != 0, 则只返回二级品种权限,并且需要附加pdf报告品种
+	if id != 0 {
+		chartPermissionList = append(chartPermissionList, &models.ChartPermissionView{
+			ChartPermissionId:   -1,
+			PermissionName:      utils.MINI_CUSTOM_PERMISSION_NAME,
+			Remark:              "",
+			ImageUrl:            "",
+			ChartPermissionType: utils.PermissionTypeMini,
+		})
+
 	}
 
 	br.Ret = 200
@@ -56,3 +69,39 @@ func (this *ChartPermissionController) List() {
 	br.Msg = "列表获取成功"
 	br.Success = true
 }
+
+// ClassifyTree
+// @Title 获取品种下的分类权限列表
+// @Description 获取研报的品种权限列表
+// @Param   ChartPermissionId   query   int  true       "品种权限id"
+// @Success 200 {object} []models.ChartPermission
+// @router /classify/tree [get]
+func (this *ChartPermissionController) ClassifyTree() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	chartPermissionId, _ := this.GetInt("ChartPermissionId")
+	if chartPermissionId <= 0 {
+		br.Msg = "品种权限不能为空"
+		return
+	}
+	resp, err := services.GetClassifyTreeByChartPermission(chartPermissionId)
+	if err != nil {
+		br.Msg = "获取分类失败"
+		br.ErrMsg = "品种权限获取失败,系统错误,Err:" + err.Error()
+		return
+	}
+	if resp.Ret != 200 {
+		br.Msg = resp.Msg
+		br.ErrMsg = resp.ErrMsg
+		return
+	}
+	classifyList := resp.Data
+
+	br.Data = classifyList
+	br.Msg = "获取成功"
+	br.Success = true
+	br.Ret = 200
+}

+ 1 - 7
controllers/mini_config.go

@@ -34,16 +34,10 @@ func (this *MiniConfigController) MiniConfig() {
 		br.ErrMsg = "获取小程序配置项失败,系统异常,Err:" + err.Error()
 		return
 	}
-	etaConf, err := models.GetEtaConf()
-	if err != nil {
-		br.Msg = "获取小程序配置项失败"
-		br.ErrMsg = "获取程序配置项失败,系统异常,Err:" + err.Error()
-		return
-	}
 
 	list = append(list, response.MiniConfigResp{
 		ConfKey: "ChartViewUrl",
-		ConfVal: etaConf["ChartViewUrl"],
+		ConfVal: miniConf["ChartViewUrl"],
 	}, response.MiniConfigResp{
 		ConfKey: "H5Url",
 		ConfVal: miniConf["H5Url"],

+ 210 - 5
controllers/my_report.go

@@ -93,7 +93,7 @@ func (this *MyReportController) Collect() {
 		br.Msg = "用户没有权限收藏"
 		return
 	}
-	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportId)
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportId, utils.ReportTypeEta)
 	if err != nil {
 		br.Msg = "收藏失败"
 		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
@@ -137,6 +137,7 @@ func (this *MyReportController) Collect() {
 		PublishTime: publishTime,
 		Stage:       report.Stage,
 		CreateTime:  time.Now(),
+		ReportType:  utils.ReportTypeEta,
 	}
 	err = myChart.Insert()
 	if err != nil {
@@ -150,6 +151,168 @@ func (this *MyReportController) Collect() {
 	br.Ret = 200
 }
 
+// @Title 收藏pdf研报
+// @Description 收藏pdf研报
+// @Success 200 {object} models.BaseResponse
+// @Failure 403 {object} models.BaseResponse
+// @router /pdf/collect [post]
+func (this *MyReportController) PdfCollect() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MyReportPdfCollectReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有权限收藏"
+		return
+	}
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportPdfId, utils.ReportTypePdf)
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "该研报已收藏,请重新刷新页面"
+		return
+	}
+	reportPdf, err := models.GetReportPdfById(req.ReportPdfId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "研报不存在或已删除"
+			return
+		}
+		br.Msg = "收藏失败"
+		br.ErrMsg = "获取研报详情失败,Err:" + err.Error()
+		return
+	}
+	reportClassifyId := services.GetReportPdfClassify(reportPdf)
+	chartPermissionResp, err := services.GetChartPermissionListByClassifyId(reportClassifyId, 0)
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "获取研报详情失败,Err:" + err.Error()
+		return
+	}
+	if chartPermissionResp.Ret != 200 {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "获取研报详情失败,Err:" + chartPermissionResp.ErrMsg
+		return
+	}
+	var IsPublic bool
+	var permissionMap = make(map[int]struct{})
+	for _, v := range chartPermissionResp.Data {
+		if v.IsPublic == 1 {
+			IsPublic = true
+		}
+		permissionMap[v.ChartPermissionId] = struct{}{}
+	}
+	// 校验是否有收藏权限
+	var IsHas bool
+	if !IsPublic {
+		chartPermissionIds, err := models.GetUserChartPermissionIdByUserId(user.UserId)
+		if err != nil {
+			br.Msg = "收藏失败"
+			br.ErrMsg = "获取用户权限失败,Err:" + err.Error()
+			return
+		}
+		if len(chartPermissionIds) == 0 {
+			br.Msg = "用户没有权限收藏"
+			return
+		}
+		for _, v := range chartPermissionIds {
+			if _, ok := permissionMap[v]; ok {
+				IsHas = true
+				break
+			}
+		}
+		if !IsHas {
+			br.Msg = "用户没有权限收藏"
+			return
+		}
+	}
+
+	publishTime, err := time.Parse(utils.FormatDateTime, reportPdf.PublishTime)
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "时间格式不对, err:" + err.Error()
+		return
+	}
+	myChart := &models.MyReport{
+		UserId:      user.UserId,
+		ReportId:    req.ReportPdfId,
+		Title:       reportPdf.Title,
+		Abstract:    reportPdf.Abstract,
+		Author:      reportPdf.Author,
+		PublishTime: publishTime,
+		Stage:       reportPdf.Stage,
+		CreateTime:  time.Now(),
+		ReportType:  utils.ReportTypePdf,
+	}
+	err = myChart.Insert()
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "收藏失败,Err:" + err.Error()
+		return
+	}
+
+	br.Msg = "收藏成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// @Title 收藏pdf研报
+// @Description 收藏pdf研报
+// @Success 200 {object} models.BaseResponse
+// @Failure 403 {object} models.BaseResponse
+// @router /pdf/collectCancel [post]
+func (this *MyReportController) PdfCollectCancel() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MyReportPdfCollectReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有权限收藏"
+		return
+	}
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportPdfId, utils.ReportTypePdf)
+	if err != nil {
+		br.Msg = "取消收藏失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+	if count == 0 {
+		br.Msg = "该研报已取消收藏,请重新刷新页面"
+		return
+	}
+	err = models.DeleteMyReportByUserIdAndReportId(user.UserId, req.ReportPdfId, utils.ReportTypePdf)
+	if err != nil {
+		br.Msg = "取消收藏失败"
+		br.ErrMsg = "取消收藏失败,Err:" + err.Error()
+		return
+	}
+
+	br.Msg = "取消收藏成功"
+	br.Success = true
+	br.Ret = 200
+}
+
 // @Title 取消收藏
 // @Description 取消收藏
 // @Param   PageSize   query   int  true       "每页数据条数"
@@ -175,7 +338,7 @@ func (this *MyReportController) CollectCancel() {
 		br.Msg = "用户没有权限收藏"
 		return
 	}
-	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportId)
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportId, utils.ReportTypeEta)
 	if err != nil {
 		br.Msg = "取消收藏失败"
 		br.ErrMsg = "获取收藏信息失败,Err:" + err.Error()
@@ -185,7 +348,7 @@ func (this *MyReportController) CollectCancel() {
 		br.Msg = "该研报已取消收藏,请重新刷新页面"
 		return
 	}
-	err = models.DeleteMyReportByUserIdAndReportId(user.UserId, req.ReportId)
+	err = models.DeleteMyReportByUserIdAndReportId(user.UserId, req.ReportId, utils.ReportTypeEta)
 	if err != nil {
 		br.Msg = "取消收藏失败"
 		br.ErrMsg = "取消收藏失败,Err:" + err.Error()
@@ -197,6 +360,48 @@ func (this *MyReportController) CollectCancel() {
 	br.Ret = 200
 }
 
+// @Title 是否收藏pdf研报
+// @Description 是否收藏pdf研报
+// @Param	request	body request.MyReportCollectReq true "type json string"
+// @Success 200 {object} models.BaseResponse
+// @router /pdf/isCollect [post]
+func (this *MyReportController) IsPdfCollect() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MyReportPdfCollectReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	user := this.User
+	if user.Status != utils.UserStatusFormal {
+		br.Msg = "用户没有权限收藏"
+		return
+	}
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportPdfId, utils.ReportTypePdf)
+	if err != nil {
+		br.Msg = "收藏失败"
+		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
+		return
+	}
+	resp := new(response.MyReportIsCollectResp)
+	if count > 0 {
+		resp.IsCollect = true
+	} else {
+		resp.IsCollect = false
+	}
+
+	br.Data = resp
+	br.Msg = "获取成功"
+	br.Success = true
+	br.Ret = 200
+}
+
 // @Title 是否收藏研报
 // @Description 是否收藏研报
 // @Param	request	body request.MyReportCollectReq true "type json string"
@@ -220,7 +425,7 @@ func (this *MyReportController) IsCollect() {
 		br.Msg = "用户没有权限收藏"
 		return
 	}
-	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportId)
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, req.ReportId, utils.ReportTypeEta)
 	if err != nil {
 		br.Msg = "收藏失败"
 		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
@@ -234,7 +439,7 @@ func (this *MyReportController) IsCollect() {
 	}
 
 	br.Data = resp
-	br.Msg = "收藏成功"
+	br.Msg = "获取成功"
 	br.Success = true
 	br.Ret = 200
 }

+ 494 - 8
controllers/report.go

@@ -5,6 +5,10 @@ import (
 	"eta/eta_mini_api/models/response"
 	"eta/eta_mini_api/services"
 	"eta/eta_mini_api/utils"
+	"sort"
+	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 type ReportController struct {
@@ -61,12 +65,12 @@ func (this *ReportController) Detail() {
 	}
 	if result.Ret == 200 && result.Data.Report == nil {
 		// 后台没有这个报告,那么尝试删除我的收藏
-		models.DeleteMyReportByUserIdAndReportId(user.UserId, reportId)
+		models.DeleteMyReportByUserIdAndReportId(user.UserId, reportId, utils.ReportTypeEta)
 		br.Msg = "该报告已删除或不存在,请刷新页面"
 		return
 	}
 
-	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, reportId)
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, reportId, utils.ReportTypeEta)
 	if err != nil {
 		br.Msg = "查询收藏数量失败"
 		br.ErrMsg = "查询收藏数量失败,Err:" + err.Error()
@@ -94,6 +98,7 @@ func (this *ReportController) Detail() {
 // @Param   PageSize   query   int  true       "每页数据条数"
 // @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
 // @Param   RangeType   query   string  true       "范围类型,1-一天内,2-一周内,3-半年内"
+// @Param   ClassifyId   query   int  true       "分类id"
 // @Success 200 {object} response.ReportList
 // @router /list [get]
 func (this *ReportController) List() {
@@ -108,7 +113,8 @@ func (this *ReportController) List() {
 	chartPermissionId, _ := this.GetInt("ChartPermissionId")
 	level, _ := this.GetInt("Level")
 	rangeType, _ := this.GetInt("RangeType")
-	reports, err := services.GetReportList(chartPermissionId, level, rangeType, currentIndex, pageSize)
+	classifyId, _ := this.GetInt("ClassifyId")
+	reports, err := services.GetReportList(chartPermissionId, level, rangeType, classifyId, currentIndex, pageSize)
 	if err != nil {
 		br.Msg = "研报列表查询失败"
 		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
@@ -126,6 +132,314 @@ func (this *ReportController) List() {
 	br.Success = true
 }
 
+// @Title pdf研报列表
+// @Description pdf研报列表
+// @Param   ChartPermissionId   query   int  true       "品种ID"
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   RangeType   query   int  true       "范围类型,1-一天内,2-一周内,3-半年内"
+// @Param   ClassifyId   query   int  true       "二级分类id"
+// @Success 200 {object} response.ReportList
+// @router /pdf/list [get]
+func (this *ReportController) PdfList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	chartPermissionId, _ := this.GetInt("ChartPermissionId")
+	classifyId, _ := this.GetInt("ClassifyId")
+	rangeType, _ := this.GetInt("RangeType")
+
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	if chartPermissionId <= 0 {
+		br.Msg = "请输入品种ID"
+		return
+	}
+	var condition string
+	switch rangeType {
+	case 1:
+		condition += ` AND DATE(publish_time)=DATE(NOW()) `
+	case 2:
+		condition += ` AND DATE(publish_time) BETWEEN DATE_SUB(NOW(),INTERVAL 1 WEEK) AND NOW() `
+	case 3:
+		condition += ` AND DATE(publish_time) BETWEEN DATE_SUB(NOW(),INTERVAL 6 MONTH) AND NOW() `
+	}
+
+	startSize := utils.StartIndex(currentIndex, pageSize)
+	var leafClassifyIds []int
+	var leafClassifyIdMap map[int]struct{}
+	var classifyMap map[int]*models.ClassifyView
+	classifyResp, err := services.GetAllClassify()
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	if classifyResp.Ret != 200 {
+		br.Msg = classifyResp.Msg
+		br.ErrMsg = classifyResp.ErrMsg
+		return
+	}
+	classifyList := classifyResp.Data
+	classifyMap = make(map[int]*models.ClassifyView)
+	isHas := false
+	for _, v := range classifyList {
+		if v.Id == classifyId && classifyId != 0 {
+			isHas = true
+		}
+		classifyMap[v.Id] = v
+	}
+	if !isHas && classifyId != 0 {
+		br.Msg = "分类不存在"
+		return
+	}
+	if classifyId != 0 {
+		leafClassifyIds = getLeafClassifyIds(classifyMap, classifyId)
+		leafClassifyIdMap = make(map[int]struct{})
+		for _, v := range leafClassifyIds {
+			leafClassifyIdMap[v] = struct{}{}
+		}
+	}
+	var permissionClassifyList []int
+	if chartPermissionId != 0 {
+		resp, err := services.GetClassifyListByChartPermission(chartPermissionId)
+		if err != nil {
+			br.Msg = "获取分类失败"
+			br.ErrMsg = "获取分类失败,系统异常,Err:" + err.Error()
+			return
+		}
+		if resp.Ret != 200 {
+			br.Msg = resp.Msg
+			br.ErrMsg = resp.ErrMsg
+			return
+		}
+		classifyList := resp.Data
+		if len(classifyList) == 0 {
+			resp := new(response.ReportPdfResp)
+			br.Msg = "查询成功"
+			br.Ret = 200
+			br.Success = true
+			br.Data = resp
+			return
+		}
+		for _, item := range classifyList {
+			permissionClassifyList = append(permissionClassifyList, item.Id)
+		}
+	}
+	queryClassifyIds := make([]int, 0)
+	if classifyId > 0 {
+		for _, v := range permissionClassifyList {
+			if _, ok := leafClassifyIdMap[v]; ok {
+				queryClassifyIds = append(queryClassifyIds, v)
+			}
+		}
+	} else {
+		queryClassifyIds = permissionClassifyList
+	}
+	firstClassifyIds := make([]int, 0)
+	secondClassifyIds := make([]int, 0)
+	thirdClassifyIds := make([]int, 0)
+	for _, v := range queryClassifyIds {
+		switch classifyMap[v].Level {
+		case 1:
+			firstClassifyIds = append(firstClassifyIds, v)
+		case 2:
+			secondClassifyIds = append(secondClassifyIds, v)
+		case 3:
+			thirdClassifyIds = append(thirdClassifyIds, v)
+		}
+	}
+
+	total, err := models.GetReportPdfCountByCondition(firstClassifyIds, secondClassifyIds, thirdClassifyIds, condition)
+	if err != nil {
+		br.Msg = "研报列表查询失败"
+		br.ErrMsg = "研报列表统计查询失败,系统异常,Err:" + err.Error()
+		return
+
+	}
+	reportPdfList, err := models.GetReportPdfListByCondition(firstClassifyIds, secondClassifyIds, thirdClassifyIds, condition, startSize, pageSize)
+	if err != nil {
+		br.Msg = "研报列表查询失败"
+		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
+		return
+	}
+	page := paging.GetPaging(currentIndex, pageSize, total)
+
+	resp := new(response.ReportPdfResp)
+	resp.List = reportPdfList
+	resp.Paging = page
+
+	br.Msg = "查询成功"
+	br.Ret = 200
+	br.Success = true
+	br.Data = resp
+}
+
+func getLeafClassifyIds(classifyMap map[int]*models.ClassifyView, keyId int) []int {
+	var leafClassifyIds []int
+	curClassify := classifyMap[keyId]
+	if curClassify.HasChild == 0 {
+		leafClassifyIds = append(leafClassifyIds, curClassify.Id)
+		return leafClassifyIds
+	}
+	for _, v := range classifyMap {
+		if v.ParentId == curClassify.Id {
+			if v.HasChild == 0 {
+				leafClassifyIds = append(leafClassifyIds, v.Id)
+			} else {
+				leafClassifyIds = append(leafClassifyIds, getLeafClassifyIds(classifyMap, v.Id)...)
+			}
+		}
+	}
+	return leafClassifyIds
+}
+
+// @Title pdf研报详情
+// @Description pdf研报详情
+// @Param   ReportPdfId   query   int  true       "品种ID"
+// @Success 200 {object} response.ReportList
+// @router /pdf/detail [get]
+func (this *ReportController) PdfDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	user := this.User
+
+	// 有效期是否到期
+	var vailStatus int
+	if user.Status == utils.UserStatusFormal {
+		if user.ValidEndTime.After(time.Now()) && user.ValidStartTime.Before(time.Now()) {
+			vailStatus = 2
+		} else {
+			// 不在有效期时间则设置为过期, 将用户状态禁用
+			vailStatus = 1
+			user.Status = utils.UserStatusNo
+		}
+	}
+	reportPdfId, _ := this.GetInt("ReportPdfId")
+
+	if reportPdfId <= 0 {
+		br.Msg = "研报不存在或已删除"
+		return
+	}
+
+	reportPdf, err := models.GetReportPdfById(reportPdfId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "研报不存在或已删除"
+		br.ErrMsg = "研报不存在或已删除,系统异常,Err:" + err.Error()
+		return
+	}
+	if reportPdf == nil {
+		// 尝试删除收藏列表的记录
+		models.DeleteMyReportByUserIdAndReportId(user.UserId, reportPdfId, utils.ReportTypePdf)
+		br.Msg = "研报不存在或已删除"
+		return
+	}
+	reportClassifyId := services.GetReportPdfClassify(reportPdf)
+
+	permissionResp, err := services.GetChartPermissionListByClassifyId(reportClassifyId, 0)
+	if err != nil {
+		br.Msg = "研报不存在或已删除"
+		br.ErrMsg = "获取权限失败,系统异常,Err:" + err.Error()
+		return
+	}
+	if permissionResp.Ret != 200 {
+		br.Msg = permissionResp.Msg
+		br.ErrMsg = permissionResp.ErrMsg
+		return
+	}
+	var IsHas bool
+	var IsPublic bool
+	permissionMap := make(map[int]struct{})
+	for _, v := range permissionResp.Data {
+		if v.IsPublic == 1 {
+			IsPublic = true
+		}
+		permissionMap[v.ChartPermissionId] = struct{}{}
+	}
+	resp := new(response.ReportPdfDetailResp)
+	if !IsPublic {
+		// 如果是私有报告,用户权限过期直接返回有效期已过
+		if vailStatus == 1 {
+			resp.Report = reportPdf
+			resp.Status = utils.ReportPermissionStatusExpired
+			br.Ret = 200
+			br.Data = resp
+			br.Msg = "用户权限不足"
+			return
+		}
+		// 如果被禁用或是潜在用户,直接返回无阅读报告权限
+		if user.Status == utils.UserStatusNo || user.Status == utils.UserStatusPotential {
+			resp.Report = reportPdf
+			resp.Status = utils.ReportPermissionStatusNo
+			br.Ret = 200
+			br.Data = resp
+			br.Msg = "用户权限不足"
+			return
+		}
+		userChartPermissionIds, err := models.GetUserChartPermissionIdByUserId(user.UserId)
+		if err != nil {
+			br.Msg = "获取用户权限失败"
+			br.ErrMsg = "获取用户权限失败,Err:" + err.Error()
+			return
+		}
+		if len(userChartPermissionIds) == 0 {
+			resp.Report = reportPdf
+			resp.Status = utils.ReportPermissionStatusNo
+			br.Ret = 200
+			br.Data = resp
+			br.Msg = "用户权限不足"
+			return
+		}
+		for _, v := range userChartPermissionIds {
+			if _, ok := permissionMap[v]; ok {
+				IsHas = true
+				break
+			}
+		}
+		if !IsHas {
+			resp.Report = reportPdf
+			resp.Status = utils.ReportPermissionStatusNoPermission
+			br.Ret = 200
+			br.Data = resp
+			br.Msg = "用户权限不足"
+			return
+		}
+	} else {
+		reportPdf.IsPublic = IsPublic
+	}
+
+	count, err := models.GetMyReportCountByUserIdAndReportId(user.UserId, reportPdf.ReportPdfId, utils.ReportTypePdf)
+	if err != nil {
+		br.Msg = "获取研报详情失败"
+		br.ErrMsg = "获取用户收藏记录失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		reportPdf.IsCollect = true
+	} else {
+		reportPdf.IsCollect = false
+	}
+
+	resp.Report = reportPdf
+	resp.Status = utils.ReportPermissionStatusHas
+
+	br.Msg = "查询成功"
+	br.Ret = 200
+	br.Success = true
+	br.Data = resp
+}
+
 // @Title 今日研报列表
 // @Description 今日研报列表
 // @Param   PageSize   query   int  true       "每页数据条数"
@@ -138,21 +452,107 @@ func (this *ReportController) DailyList() {
 		this.Data["json"] = br
 		this.ServeJSON()
 	}()
-
+	// 暂不使用分页
 	pageSize, _ := this.GetInt("PageSize")
 	currentIndex, _ := this.GetInt("CurrentIndex")
 	if pageSize <= 0 {
 		pageSize = utils.PageSize20
 	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	resp, err := services.GetReportDailyList()
+	if err != nil {
+		br.Msg = "研报列表查询失败"
+		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
+		return
+	}
+	if resp.Ret != 200 {
+		br.Msg = resp.Msg
+		br.ErrMsg = resp.ErrMsg
+		return
+	}
+	reportList := resp.Data
+	for _, v := range reportList.List {
+		v.ReportType = utils.ReportTypeEta
+	}
 
-	reports, err := services.GetReportDailyList(currentIndex, pageSize)
+	reportPdfList, err := models.GetReportPdfDailyList()
 	if err != nil {
 		br.Msg = "研报列表查询失败"
 		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
 		return
 	}
+	var classifyIds []int
+	for _, v := range reportPdfList {
+		var reportClassifyId int
+		if v.ClassifyIdFirst != 0 {
+			reportClassifyId = v.ClassifyIdFirst
+		}
+		if v.ClassifyIdSecond != 0 {
+			reportClassifyId = v.ClassifyIdSecond
+		}
+		if v.ClassifyIdThird != 0 {
+			reportClassifyId = v.ClassifyIdThird
+		}
+		classifyIds = append(classifyIds, reportClassifyId)
+	}
 
-	br.Data = reports.Data
+	if len(classifyIds) > 0 {
+		classifyResp, err := services.GetFirstChartPermission(classifyIds)
+		if err != nil {
+			br.Msg = "研报列表查询失败"
+			br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
+			return
+		}
+		if classifyResp.Ret != 200 {
+			br.Msg = classifyResp.Msg
+			br.ErrMsg = classifyResp.ErrMsg
+			return
+		}
+		classifyPermissionMap := make(map[int][]string)
+		for _, v := range classifyResp.Data {
+			classifyPermissionMap[v.ClassifyId] = v.PermissionNames
+		}
+		for _, v := range reportPdfList {
+			var reportClassifyId int
+			if v.ClassifyIdFirst != 0 {
+				reportClassifyId = v.ClassifyIdFirst
+			}
+			if v.ClassifyIdSecond != 0 {
+				reportClassifyId = v.ClassifyIdSecond
+			}
+			if v.ClassifyIdThird != 0 {
+				reportClassifyId = v.ClassifyIdThird
+			}
+			// 过滤没有绑定品种的研报
+			if classifyPermissionMap[reportClassifyId] == nil {
+				continue
+			}
+			reportList.List = append(reportList.List, &models.ReportView{
+				Id:                 v.ReportPdfId,
+				ClassifyIdFirst:    v.ClassifyIdFirst,
+				ClassifyNameFirst:  v.ClassifyNameFirst,
+				ClassifyIdSecond:   v.ClassifyIdSecond,
+				ClassifyNameSecond: v.ClassifyNameSecond,
+				ClassifyIdThird:    v.ClassifyIdThird,
+				ClassifyNameThird:  v.ClassifyNameThird,
+				PermissionNames:    classifyPermissionMap[reportClassifyId],
+				PdfUrl:             v.PdfUrl,
+				Title:              v.Title,
+				Abstract:           v.Abstract,
+				Stage:              v.Stage,
+				Author:             v.Author,
+				ReportType:         utils.ReportTypePdf,
+				PublishTime:        v.PublishTime.Format(utils.FormatDateTime),
+				ModifyTime:         v.ModifyTime,
+			})
+		}
+	}
+
+	sort.Sort(models.ByPublishTimeReportView(reportList.List))
+
+	br.Data = reportList
 	br.Msg = "查询成功"
 	br.Ret = 200
 	br.Success = true
@@ -171,20 +571,102 @@ func (this *ReportController) RecentList() {
 		this.ServeJSON()
 	}()
 
+	// 暂不使用分页
 	pageSize, _ := this.GetInt("PageSize")
 	currentIndex, _ := this.GetInt("CurrentIndex")
 	if pageSize <= 0 {
 		pageSize = 3
 	}
 
-	reports, err := services.GetReportRecentList(currentIndex, pageSize)
+	resp, err := services.GetReportRecentList(currentIndex, pageSize)
+	if err != nil {
+		br.Msg = "研报列表查询失败"
+		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
+		return
+	}
+	// 查询已发布的pdf
+	reportPdfList, err := models.GetRecentReportPdfList(0, 3)
+	if err != nil {
+		br.Msg = "研报列表查询失败"
+		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
+		return
+	}
+
+	reportList := resp.Data
+	for _, v := range reportList.List {
+		v.ReportType = utils.ReportTypeEta
+	}
+	var classifyIds []int
+	for _, v := range reportPdfList {
+		var reportClassifyId int
+		if v.ClassifyIdFirst != 0 {
+			reportClassifyId = v.ClassifyIdFirst
+		}
+		if v.ClassifyIdSecond != 0 {
+			reportClassifyId = v.ClassifyIdSecond
+		}
+		if v.ClassifyIdThird != 0 {
+			reportClassifyId = v.ClassifyIdThird
+		}
+		classifyIds = append(classifyIds, reportClassifyId)
+	}
+	classifyResp, err := services.GetFirstChartPermission(classifyIds)
 	if err != nil {
 		br.Msg = "研报列表查询失败"
 		br.ErrMsg = "研报列表查询失败,系统异常,Err:" + err.Error()
 		return
 	}
+	if classifyResp.Ret != 200 {
+		br.Msg = classifyResp.Msg
+		br.ErrMsg = classifyResp.ErrMsg
+		return
+	}
+	classifyPermissionMap := make(map[int][]string)
+	for _, v := range classifyResp.Data {
+		classifyPermissionMap[v.ClassifyId] = v.PermissionNames
+	}
+	for _, v := range reportPdfList {
+		var reportClassifyId int
+		if v.ClassifyIdFirst != 0 {
+			reportClassifyId = v.ClassifyIdFirst
+		}
+		if v.ClassifyIdSecond != 0 {
+			reportClassifyId = v.ClassifyIdSecond
+		}
+		if v.ClassifyIdThird != 0 {
+			reportClassifyId = v.ClassifyIdThird
+		}
+		// 过滤没有绑定品种的研报
+		if classifyPermissionMap[reportClassifyId] == nil {
+			continue
+		}
+		reportList.List = append(reportList.List, &models.ReportView{
+			Id:                 v.ReportPdfId,
+			ClassifyIdFirst:    v.ClassifyIdFirst,
+			ClassifyNameFirst:  v.ClassifyNameFirst,
+			ClassifyIdSecond:   v.ClassifyIdSecond,
+			ClassifyNameSecond: v.ClassifyNameSecond,
+			ClassifyIdThird:    v.ClassifyIdThird,
+			ClassifyNameThird:  v.ClassifyNameThird,
+			PermissionNames:    classifyPermissionMap[reportClassifyId],
+			PdfUrl:             v.PdfUrl,
+			Title:              v.Title,
+			Abstract:           v.Abstract,
+			Stage:              v.Stage,
+			Author:             v.Author,
+			ReportType:         utils.ReportTypePdf,
+			PublishTime:        v.PublishTime.Format(utils.FormatDateTime),
+			ModifyTime:         v.ModifyTime,
+		})
+	}
+	sort.Sort(models.ByPublishTimeReportView(reportList.List))
+	endIdx := len(reportList.List)
+	if endIdx > 3 {
+		endIdx = 3
+	}
+	reportList.List = reportList.List[:endIdx]
 
-	br.Data = reports.Data
+	br.Data = reportList
 	br.Msg = "查询成功"
 	br.Ret = 200
 	br.Success = true
@@ -238,6 +720,8 @@ func (this *ReportController) Search() {
 			ClassifyNameFirst:   v.ClassifyNameFirst,
 			ClassifyIdSecond:    v.ClassifyIdSecond,
 			ClassifyNameSecond:  v.ClassifyNameSecond,
+			ClassifyIdThird:     v.ClassifyIdThird,
+			ClassifyNameThird:   v.ClassifyNameThird,
 			ReportChapterTypeId: v.ReportChapterTypeId,
 			PublishTime:         v.PublishTime.Format(utils.FormatDate),
 			Title:               v.Title,
@@ -245,6 +729,8 @@ func (this *ReportController) Search() {
 			Abstract:            v.Abstract,
 			Stage:               v.Stage,
 			Author:              v.Author,
+			PdfUrl:              v.PdfUrl,
+			ReportType:          v.ReportType,
 		}
 		if v.PublishTime.IsZero() {
 			tmpReport.PublishTime = ""

+ 205 - 8
controllers/user.go

@@ -333,9 +333,12 @@ func (this *UserAuthController) AddReportRecord() {
 			ClassifyName1:       reportDetail.ClassifyNameFirst,
 			ClassifyId2:         reportDetail.ClassifyIdSecond,
 			ClassifyName2:       reportDetail.ClassifyNameSecond,
+			ClassifyId3:         reportDetail.ClassifyIdThird,
+			ClassifyName3:       reportDetail.ClassifyNameThird,
 			Timestamp:           int(curTime.Unix()),
 			CreateTime:          curTime,
 			CreateDate:          curTime.Format(utils.FormatDate),
+			ReportType:          utils.ReportTypeEta,
 		}
 		insertId, err = userReadRecord.Insert()
 		if err != nil {
@@ -401,6 +404,183 @@ func (this *UserAuthController) AddReportRecord() {
 	br.Data = resp
 }
 
+// @Title 新增pdf报告浏览记录
+// @Description 新增pdf报告浏览记录接口
+// @Param	request	body models.ReportPdfRecordReq true "type json string"
+// @Success 200 新增成功
+// @router /pdf/addReportRecord [post]
+func (this *UserAuthController) AddReportPdfRecord() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	user := this.User
+	if user == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,用户信息为空"
+		br.Ret = 403
+		return
+	}
+	var req request.ReportPdfRecordReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ReportPdfId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,报告id小于等于0"
+		return
+	}
+	reportPdf, err := models.GetReportPdfById(req.ReportPdfId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "报告不存在或已删除"
+			return
+		}
+		br.Msg = "添加阅读记录失败"
+		br.ErrMsg = "获取研报错误,Err:" + err.Error()
+		return
+	}
+	reportClassifyId := services.GetReportPdfClassify(reportPdf)
+	reportPermissionResp, err := services.GetChartPermissionListByClassifyId(reportClassifyId, 0)
+	if err != nil {
+		br.Msg = "添加阅读记录失败"
+		br.ErrMsg = "获取研报品种错误,Err:" + err.Error()
+		return
+	}
+	if reportPermissionResp.Ret != 200 {
+		br.Msg = reportPermissionResp.Msg
+		br.ErrMsg = reportPermissionResp.ErrMsg
+		return
+	}
+	reportPermissionList := reportPermissionResp.Data
+	chartPermissionList, err := services.GetChartPermissionAllList()
+	if err != nil {
+		br.Msg = "添加阅读记录失败"
+		br.ErrMsg = "获取研报品种列表失败,Err:" + err.Error()
+		return
+	}
+	chartMap := make(map[int]*models.ChartPermission)
+	for _, permission := range chartPermissionList.Data {
+		chartMap[permission.ChartPermissionId] = permission
+	}
+	curTime := time.Now()
+	var insertId int64
+	if req.RecordId == 0 {
+		// 如果不存在就新增一条记录
+		permission1Ids := make([]int, 0)
+		permission2Ids := make([]int, 0)
+		permissionNames := make([]string, 0)
+		for _, item := range reportPermissionList {
+			curPermission := chartMap[item.ChartPermissionId]
+			permission1Ids = append(permission1Ids, curPermission.ParentId)
+			permission2Ids = append(permission2Ids, curPermission.ChartPermissionId)
+			permissionNames = append(permissionNames, curPermission.PermissionName)
+		}
+		permission1Ids = utils.Unique(permission1Ids)
+		permission2Ids = utils.Unique(permission2Ids)
+		permissionNames = utils.Unique(permissionNames)
+		userReadRecord := &models.UserReadRecord{
+			UserId:              user.UserId,
+			ReportId:            reportPdf.ReportPdfId,
+			ReportTitle:         reportPdf.Title,
+			ChartPermissionName: strings.Join(permissionNames, ","),
+			ClassifyId1:         reportPdf.ClassifyIdFirst,
+			ClassifyName1:       reportPdf.ClassifyNameFirst,
+			ClassifyId2:         reportPdf.ClassifyIdSecond,
+			ClassifyName2:       reportPdf.ClassifyNameSecond,
+			Timestamp:           int(curTime.Unix()),
+			CreateTime:          curTime,
+			CreateDate:          curTime.Format(utils.FormatDate),
+			ReportType:          utils.ReportTypePdf,
+		}
+		insertId, err = userReadRecord.Insert()
+		if err != nil {
+			br.Msg = "添加阅读记录失败"
+			br.ErrMsg = "添加阅读记录失败,Err:" + err.Error()
+			return
+		}
+
+		userReadPermission1 := make([]*models.UserReadPermission1, 0)
+		for _, id := range permission1Ids {
+			userReadPermission1 = append(userReadPermission1, &models.UserReadPermission1{
+				UserReadRecordId:  int(insertId),
+				ChartPermissionId: id,
+				PermissionName:    chartMap[id].PermissionName,
+			})
+		}
+		err = models.UserReadPermission1MultiInsert(userReadPermission1)
+		if err != nil {
+			br.Msg = "添加阅读记录失败"
+			br.ErrMsg = "添加阅读记录失败,Err:" + err.Error()
+			return
+		}
+		userReadPermission2 := make([]*models.UserReadPermission2, 0)
+		for _, id := range permission2Ids {
+			userReadPermission2 = append(userReadPermission2, &models.UserReadPermission2{
+				UserReadRecordId:  int(insertId),
+				ChartPermissionId: id,
+			})
+		}
+		err = models.UserReadPermission2MultiInsert(userReadPermission2)
+		if err != nil {
+			br.Msg = "添加阅读记录失败"
+			br.ErrMsg = "添加阅读记录失败,Err:" + err.Error()
+			return
+		}
+		count, err := models.GetUserReadRecordCountByReportPdfIdAndUserId(req.ReportPdfId, user.UserId)
+		if err != nil {
+			br.Msg = "添加阅读记录失败"
+			br.ErrMsg = "获取阅读记录失败,Err:" + err.Error()
+			return
+		}
+		if count > 1 {
+			err = models.UpdateReportPdfPv(req.ReportPdfId)
+			if err != nil {
+				br.Msg = "添加研报阅读记录失败"
+				br.ErrMsg = "更新阅读记录失败,Err:" + err.Error()
+				return
+			}
+		} else {
+			err = models.UpdateReportPdfUvAndPv(req.ReportPdfId)
+			if err != nil {
+				br.Msg = "添加研报阅读记录失败"
+				br.ErrMsg = "更新阅读记录失败,Err:" + err.Error()
+				return
+			}
+		}
+	} else {
+		// 如果存在就计算停留时间
+		userRecord, err := models.GetUserReadRecordListById(req.RecordId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "更新阅读记录不存在"
+				return
+			}
+			br.Msg = "更新阅读记录失败"
+			br.ErrMsg = "更新阅读记录失败,Err:" + err.Error()
+			return
+		}
+		stayTime := curTime.Unix() - int64(userRecord.Timestamp)
+		stayTimeStr := utils.SecondsToHMS(stayTime)
+		err = models.UpdateUserReadRecordById(req.RecordId, int(curTime.Unix()), int(stayTime), stayTimeStr)
+		if err != nil {
+			br.Msg = "更新阅读记录失败"
+			br.ErrMsg = "更新阅读记录失败,Err:" + err.Error()
+			return
+		}
+	}
+	resp := new(response.UserReadRecordResp)
+	resp.RecordId = insertId
+
+	br.Msg = "添加阅读记录成功"
+	br.Ret = 200
+	br.Success = true
+	br.Data = resp
+}
+
 // AreaCodeList
 // @Title 手机号区号列表
 // @Description 手机号区号列表
@@ -473,7 +653,7 @@ func (this *UserAuthController) Info() {
 		br.ErrMsg = private.ErrMsg
 		return
 	}
-	userPermissionIds, err := models.GetChartPermissionIdByUserId(user.UserId)
+	userPermissionIds, err := models.GetUserChartPermissionIdByUserId(user.UserId)
 	if err != nil {
 		br.Msg = "查看权限失败"
 		br.ErrMsg = "查看权限失败,系统异常,Err:" + err.Error()
@@ -547,7 +727,7 @@ func (this *UserAuthController) PermissionList() {
 		this.ServeJSON()
 	}()
 	user := this.User
-	permissionIds, err := models.GetChartPermissionIdByUserId(user.UserId)
+	permissionIds, err := models.GetUserChartPermissionIdByUserId(user.UserId)
 	if err != nil {
 		br.Msg = "查询用户权限失败"
 		br.ErrMsg = "查询用户权限失败,系统异常,Err:" + err.Error()
@@ -620,6 +800,12 @@ func (this *UserAuthController) PermissionList() {
 		}
 	}
 	publicView = append(publicView, privateAloneView...)
+	for _, vi := range publicView {
+		vi.ChartPermissionType = utils.PermissionTypeEta
+		for _, vi := range vi.Child {
+			vi.ChartPermissionType = utils.PermissionTypeEta
+		}
+	}
 
 	br.Data = publicView
 	br.Msg = "查询成功"
@@ -640,7 +826,7 @@ func (this *UserAuthController) PurchasedPermission() {
 		this.ServeJSON()
 	}()
 	user := this.User
-	permissionIds, err := models.GetChartPermissionIdByUserId(user.UserId)
+	permissionIds, err := models.GetUserChartPermissionIdByUserId(user.UserId)
 	if err != nil {
 		br.Msg = "查询用户权限失败"
 		br.ErrMsg = "查询用户权限失败,系统异常,Err:" + err.Error()
@@ -666,14 +852,16 @@ func (this *UserAuthController) PurchasedPermission() {
 	for _, v := range privateResp.Data {
 		IsAdd := false
 		curPermissionView := &models.ChartPermissionTreeView{
-			ChartPermissionId: v.ChartPermissionId,
-			PermissionName:    v.PermissionName,
-			IsPublic:          v.IsPublic,
-			Sort:              v.Sort,
-			Child:             make([]*models.ChartPermissionTreeView, 0),
+			ChartPermissionId:   v.ChartPermissionId,
+			PermissionName:      v.PermissionName,
+			IsPublic:            v.IsPublic,
+			Sort:                v.Sort,
+			Child:               make([]*models.ChartPermissionTreeView, 0),
+			ChartPermissionType: utils.PermissionTypeEta,
 		}
 		for _, vv := range v.Child {
 			if _, ok := permissionMap[vv.ChartPermissionId]; ok && vv.ParentId != 0 {
+				vv.ChartPermissionType = utils.PermissionTypeEta
 				curPermissionView.Child = append(curPermissionView.Child, vv)
 				IsAdd = true
 			}
@@ -682,6 +870,15 @@ func (this *UserAuthController) PurchasedPermission() {
 			privateView = append(privateView, curPermissionView)
 		}
 	}
+	for _, vi := range privateView {
+		vi.Child = append(vi.Child, &models.ChartPermissionTreeView{
+			ChartPermissionId:   -1,
+			PermissionName:      utils.MINI_CUSTOM_PERMISSION_NAME,
+			IsPublic:            0,
+			Sort:                0,
+			ChartPermissionType: utils.ReportTypePdf,
+		})
+	}
 
 	br.Data = privateView
 	br.Msg = "查询成功"

+ 8 - 0
models/base.go

@@ -14,3 +14,11 @@ type BaseResponse struct {
 func (r *BaseResponse) Init() *BaseResponse {
 	return &BaseResponse{Ret: 403, IsSendEmail: true}
 }
+
+type BaseResponseT[T any] struct {
+	Ret     int
+	Msg     string
+	ErrMsg  string
+	ErrCode string
+	Data    T
+}

+ 9 - 8
models/chart_permission.go

@@ -4,14 +4,14 @@ import "time"
 
 type ChartPermissionView struct {
 	ChartPermissionId   int    `description:"权限ID"`
-	ChartPermissionName string `description:"名称"`
 	PermissionName      string `description:"权限名"`
 	Remark              string `description:"备注"`
 	ImageUrl            string `description:"图片地址"`
+	ChartPermissionType int    `description:"权限类型:1-eta权限;2-小程序权限"`
 }
 
 type ChartPermission struct {
-	ChartPermissionId   int       `description:"问题ID"`
+	ChartPermissionId   int       `description:"品种ID"`
 	ChartPermissionName string    `description:"名称"`
 	PermissionName      string    `description:"权限名"`
 	Sort                int       `description:"排序"`
@@ -32,10 +32,11 @@ type ChartPermissionResp[T any] struct {
 }
 
 type ChartPermissionTreeView struct {
-	ChartPermissionId int                        `description:"权限ID"`
-	PermissionName    string                     `description:"权限名"`
-	Child             []*ChartPermissionTreeView `description:"子权限"`
-	IsPublic          int                        `description:"是否是公有权限1:公有权限,0私有权限"`
-	ParentId          int                        `description:"父级权限id"`
-	Sort              int                        `description:"排序" json:"-"`
+	ChartPermissionId   int                        `description:"权限ID"`
+	PermissionName      string                     `description:"权限名"`
+	Child               []*ChartPermissionTreeView `description:"子权限"`
+	IsPublic            int                        `description:"是否是公有权限1:公有权限,0私有权限"`
+	ParentId            int                        `description:"父级权限id"`
+	Sort                int                        `description:"排序" json:"-"`
+	ChartPermissionType int                        `description:"权限类型:1-eta权限;2-小程序权限"`
 }

+ 20 - 0
models/classify.go

@@ -4,6 +4,26 @@ import (
 	"time"
 )
 
+type Classify struct {
+	Id           int       `description:"分类id"`
+	ClassifyName string    `description:"分类名称"`
+	Sort         int       `json:"-"`
+	ParentId     int       `description:"父级分类id"`
+	CreateTime   time.Time `description:"创建时间"`
+	ModifyTime   time.Time `description:"修改时间"`
+	Level        int       `description:"分类层级"`
+}
+
+type ClassifyView struct {
+	Id           int             `description:"分类id"`
+	ClassifyName string          `description:"分类名称"`
+	Sort         int             `json:"-"`
+	ParentId     int             `description:"父级分类id"`
+	Level        int             `description:"分类层级"`
+	HasChild     int             `description:"是否有子分类0:下面没有子分类,1:下面有子分类"`
+	Child        []*ClassifyView `description:"子分类"`
+}
+
 type ClassifyDetail struct {
 	ClassifyId     int       `description:"分类id"`
 	ClassifyName   string    `description:"分类名称"`

+ 7 - 6
models/my_report.go

@@ -16,6 +16,7 @@ type MyReport struct {
 	PublishTime time.Time `description:"发布时间"`
 	Stage       int       `description:"期数"`
 	CreateTime  time.Time `description:"创建时间"`
+	ReportType  int       `description:"报告类型:1-普通研报;2-pdf研报"`
 }
 
 func (m *MyReport) Insert() (err error) {
@@ -24,17 +25,17 @@ func (m *MyReport) Insert() (err error) {
 	return
 }
 
-func GetMyReportCountByUserIdAndReportId(userId, reportId int) (count int, err error) {
+func GetMyReportCountByUserIdAndReportId(userId, reportId, reportType int) (count int, err error) {
 	o := orm.NewOrm()
-	sql := "SELECT COUNT(*) AS count FROM my_report WHERE user_id = ? AND report_id = ?"
-	err = o.Raw(sql, userId, reportId).QueryRow(&count)
+	sql := `SELECT COUNT(*) AS count FROM my_report WHERE user_id = ? AND report_id = ? AND report_type = ? `
+	err = o.Raw(sql, userId, reportId, reportType).QueryRow(&count)
 	return
 }
 
-func DeleteMyReportByUserIdAndReportId(userId, reportId int) (err error) {
+func DeleteMyReportByUserIdAndReportId(userId, reportId, reportType int) (err error) {
 	o := orm.NewOrm()
-	sql := "DELETE FROM my_report WHERE user_id = ? AND report_id = ?"
-	_, err = o.Raw(sql, userId, reportId).Exec()
+	sql := "DELETE FROM my_report WHERE user_id = ? AND report_id = ? AND report_type = ?"
+	_, err = o.Raw(sql, userId, reportId, reportType).Exec()
 	return
 }
 

+ 110 - 55
models/report.go

@@ -1,63 +1,118 @@
 package models
 
-import "time"
+import (
+	"eta/eta_mini_api/utils"
+	"time"
+)
 
-type ReportList struct {
-	Id                 int       `description:"报告Id"`
-	AddType            int       `description:"新增方式:1:新增报告,2:继承报告"`
-	ClassifyIdFirst    int       `description:"一级分类id"`
-	ClassifyNameFirst  string    `description:"一级分类名称"`
-	ClassifyIdSecond   int       `description:"二级分类id"`
-	ClassifyNameSecond string    `description:"二级分类名称"`
-	PermissionNames    []string  `description:"二级分类名称"`
-	Title              string    `description:"标题"`
-	Abstract           string    `description:"摘要"`
-	Author             string    `description:"作者"`
-	Frequency          string    `description:"频度"`
-	CreateTime         string    `description:"创建时间"`
-	ModifyTime         time.Time `description:"修改时间"`
-	State              int       `description:"1:未发布,2:已发布"`
-	PublishTime        string    `description:"发布时间"`
-	Stage              int       `description:"期数"`
-	MsgIsSend          int       `description:"消息是否已发送,0:否,1:是"`
-	Content            string    `description:"内容"`
-	VideoUrl           string    `description:"音频文件URL"`
-	VideoName          string    `description:"音频文件名称"`
-	VideoPlaySeconds   string    `description:"音频播放时长"`
-	VideoSize          string    `description:"音频文件大小,单位M"`
-	HasPermission      int       `description:"是否拥有报告权限,1:拥有,0:没有"`
-	TitleType          string    `description:"标题类型,FICC或者权益"`
-	IsCurrentDate      int       `description:"是否当前日期:1是,0不是"`
-	IsPublic           bool      `description:"是否是公共报告"`
+type ReportView struct {
+	Id                 int                  `description:"报告Id"`
+	AddType            int                  `description:"新增方式:1:新增报告,2:继承报告"`
+	ClassifyIdFirst    int                  `description:"一级分类id"`
+	ClassifyNameFirst  string               `description:"一级分类名称"`
+	ClassifyIdSecond   int                  `description:"二级分类id"`
+	ClassifyNameSecond string               `description:"二级分类名称"`
+	ClassifyIdThird    int                  `description:"三级分类id"`
+	ClassifyNameThird  string               `description:"三级分类名称"`
+	PermissionNames    []string             `description:"二级分类名称"`
+	Title              string               `description:"标题"`
+	Abstract           string               `description:"摘要"`
+	Author             string               `description:"作者"`
+	Frequency          string               `description:"频度"`
+	CreateTime         string               `description:"创建时间"`
+	ModifyTime         time.Time            `description:"修改时间"`
+	State              int                  `description:"1:未发布,2:已发布"`
+	PublishTime        string               `description:"发布时间"`
+	Stage              int                  `description:"期数"`
+	MsgIsSend          int                  `description:"消息是否已发送,0:否,1:是"`
+	Content            string               `description:"内容"`
+	ChapterContent     []*ReportChapter     `description:"章节内容"`
+	VideoUrl           string               `description:"音频文件URL"`
+	VideoName          string               `description:"音频文件名称"`
+	VideoPlaySeconds   string               `description:"音频播放时长"`
+	VideoSize          string               `description:"音频文件大小,单位M"`
+	HasPermission      int                  `description:"是否拥有报告权限,1:拥有,0:没有"`
+	TitleType          string               `description:"标题类型,FICC或者权益"`
+	IsCurrentDate      int                  `description:"是否当前日期:1是,0不是"`
+	IsPublic           bool                 `description:"是否是公共报告"`
+	ReportType         int                  `description:"报告类型,1:eta报告,2:pdf报告"`
+	PdfUrl             string               `description:"pdf文件URL"`
+	CollaborateType    int                  `description:"合作类型, 1:个人,2:多人协作"`
+	ReportLayout       int                  `description:"报告布局, 1:常规布局,2:智能布局"`
+	HasChapter         int                  `description:"是否有章节: 0-否 1-是"`
+	HeadResource       *SmartReportResource `description:"版头资源库"`
+	EndResource        *SmartReportResource `description:"版尾资源库"`
 	ClassifyDetail
 }
 
 type ReportDetail struct {
-	Id                 int    `description:"报告Id"`
-	AddType            int    `description:"新增方式:1:新增报告,2:继承报告"`
-	ClassifyIdFirst    int    `description:"一级分类id"`
-	ClassifyNameFirst  string `description:"一级分类名称"`
-	ClassifyIdSecond   int    `description:"二级分类id"`
-	ClassifyNameSecond string `description:"二级分类名称"`
-	Title              string `description:"标题"`
-	Abstract           string `description:"摘要"`
-	Author             string `description:"作者"`
-	Frequency          string `description:"频度"`
-	CreateTime         string `description:"创建时间"`
-	ModifyTime         string `description:"修改时间"`
-	State              int    `description:"1:未发布,2:已发布"`
-	PublishTime        string `description:"发布时间"`
-	Stage              int    `description:"期数"`
-	MsgIsSend          int    `description:"消息是否已发送,0:否,1:是"`
-	Content            string `description:"内容"`
-	VideoUrl           string `description:"音频文件URL"`
-	VideoName          string `description:"音频文件名称"`
-	VideoPlaySeconds   string `description:"音频播放时长"`
-	VideoSize          string `description:"音频文件大小,单位M"`
-	ContentSub         string `description:"内容前两个章节"`
-	IsShowNewLabel     int    `description:"是否显示新标签"`
-	IsCurrentDate      int    `description:"是否当前日期"`
-	ClassifyName       string `description:"分类名称"`
-	TitleType          string `description:"标题类型,FICC或者权益"`
-	IsPublic           bool   `description:"是否是公共报告"`
+	Id                 int                 `description:"报告Id"`
+	AddType            int                 `description:"新增方式:1:新增报告,2:继承报告"`
+	ClassifyIdFirst    int                 `description:"一级分类id"`
+	ClassifyNameFirst  string              `description:"一级分类名称"`
+	ClassifyIdSecond   int                 `description:"二级分类id"`
+	ClassifyNameSecond string              `description:"二级分类名称"`
+	ClassifyIdThird    int                 `description:"三级分类id"`
+	ClassifyNameThird  string              `description:"三级分类名称"`
+	Title              string              `description:"标题"`
+	Abstract           string              `description:"摘要"`
+	Author             string              `description:"作者"`
+	Frequency          string              `description:"频度"`
+	CreateTime         string              `description:"创建时间"`
+	ModifyTime         string              `description:"修改时间"`
+	State              int                 `description:"1:未发布,2:已发布"`
+	PublishTime        string              `description:"发布时间"`
+	Stage              int                 `description:"期数"`
+	MsgIsSend          int                 `description:"消息是否已发送,0:否,1:是"`
+	Content            string              `description:"内容"`
+	ChapterContent     []*ReportChapter    `description:"章节内容"`
+	VideoUrl           string              `description:"音频文件URL"`
+	VideoName          string              `description:"音频文件名称"`
+	VideoPlaySeconds   string              `description:"音频播放时长"`
+	VideoSize          string              `description:"音频文件大小,单位M"`
+	ContentSub         string              `description:"内容前两个章节"`
+	IsShowNewLabel     int                 `description:"是否显示新标签"`
+	IsCurrentDate      int                 `description:"是否当前日期"`
+	ClassifyName       string              `description:"分类名称"`
+	TitleType          string              `description:"标题类型,FICC或者权益"`
+	IsPublic           bool                `description:"是否是公共报告"`
+	CollaborateType    int                 `description:"合作类型, 1:个人,2:多人协作"`
+	ReportLayout       int                 `description:"报告布局, 1:常规布局,2:智能布局"`
+	HasChapter         int                 `description:"是否有章节: 0-否 1-是"`
+	HeadResource       SmartReportResource `description:"版头资源库"`
+	EndResource        SmartReportResource `description:"版尾资源库"`
 }
+
+type ReportChapter struct {
+	Title   string `description:"章节标题"`
+	Content string `description:"章节内容"`
+}
+
+type SmartReportResource struct {
+	ResourceId int    `description:"资源库id"`
+	ImgUrl     string `description:"图片url"`
+	Type       int    `description:"资源类型:1-版头 2-版尾"`
+	Style      string `description:"版图样式"`
+}
+
+type ByPublishTimeReportView []*ReportView
+
+func (a ByPublishTimeReportView) Len() int { return len(a) }
+func (a ByPublishTimeReportView) Less(i, j int) bool {
+	if a[i].PublishTime == "" {
+		return true
+	}
+	if a[j].PublishTime == "" {
+		return false
+	}
+	aiTime, err := time.Parse(utils.FormatDateTime, a[i].PublishTime)
+	if err != nil {
+		return true
+	}
+	ajTime, err := time.Parse(utils.FormatDateTime, a[j].PublishTime)
+	if err != nil {
+		return false
+	}
+	return aiTime.After(ajTime)
+}
+func (a ByPublishTimeReportView) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

+ 147 - 0
models/report_pdf.go

@@ -0,0 +1,147 @@
+package models
+
+import (
+	"eta/eta_mini_api/utils"
+	"fmt"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type ReportPdf struct {
+	ReportPdfId        int       `orm:"pk" description:"id"`
+	PdfUrl             string    `description:"pdf文件URL"`
+	Title              string    `description:"pdf文件标题"`
+	Author             string    `description:"作者"`
+	Abstract           string    `description:"摘要"`
+	ClassifyIdFirst    int       `description:"一级分类id"`
+	ClassifyNameFirst  string    `description:"一级分类名称"`
+	ClassifyIdSecond   int       `description:"二级分类id"`
+	ClassifyNameSecond string    `description:"二级分类名称"`
+	ClassifyIdThird    int       `description:"三级分类id"`
+	ClassifyNameThird  string    `description:"三级分类名称"`
+	Stage              int       `description:"期数"`
+	PublishTime        time.Time `description:"发布时间"`
+	ModifyTime         time.Time `description:"更新时间"`
+	Pv                 int       `description:"pv"`
+	Uv                 int       `description:"uv"`
+	SysUserId          int       `description:"创建人id"`
+	SysRealName        string    `description:"创建人姓名"`
+	State              int       `description:"状态:1-已发布;2-未发布"`
+}
+
+type ReportPdfView struct {
+	ReportPdfId        int    `orm:"pk" description:"id"`
+	PdfUrl             string `description:"pdf文件URL"`
+	Title              string `description:"pdf文件标题"`
+	Author             string `description:"作者"`
+	Abstract           string `description:"摘要"`
+	ClassifyIdFirst    int    `description:"一级分类id"`
+	ClassifyNameFirst  string `description:"一级分类名称"`
+	ClassifyIdSecond   int    `description:"二级分类id"`
+	ClassifyNameSecond string `description:"二级分类名称"`
+	ClassifyIdThird    int    `description:"三级分类id"`
+	ClassifyNameThird  string `description:"三级分类名称"`
+	Stage              int    `description:"期数"`
+	PublishTime        string `description:"发布时间"`
+	ModifyTime         string `description:"更新时间"`
+	Pv                 int    `description:"pv"`
+	Uv                 int    `description:"uv"`
+	SysUserId          int    `description:"创建人id"`
+	SysRealName        string `description:"创建人姓名"`
+	State              int    `description:"状态:1-已发布;2-未发布"`
+	IsPublic           bool   `description:"是否公开"`
+	IsCollect          bool   `description:"是否收藏"`
+}
+
+func GetRecentReportPdfList(startSize, pageSize int) (items []*ReportPdf, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT * FROM report_pdf WHERE state=1 ORDER BY publish_time DESC LIMIT ?,?`
+	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func GetReportPdfListByCondition(firstClassifyIds, secondClassifyIds, thirdClassifyIds []int, condition string, startSize, pageSize int) (reportPdfs []*ReportPdf, err error) {
+	if len(firstClassifyIds) == 0 && len(secondClassifyIds) == 0 && len(thirdClassifyIds) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	sql := `SELECT * FROM report_pdf WHERE 1=1 AND (1=2`
+	if len(firstClassifyIds) > 0 {
+		sql += fmt.Sprintf(" OR classify_id_first IN (%s) ", utils.GetOrmReplaceHolder(len(firstClassifyIds)))
+	}
+	if len(secondClassifyIds) > 0 {
+		sql += fmt.Sprintf(" OR classify_id_second IN (%s) ", utils.GetOrmReplaceHolder(len(secondClassifyIds)))
+	}
+	if len(thirdClassifyIds) > 0 {
+		sql += fmt.Sprintf(" OR classify_id_third IN (%s) ", utils.GetOrmReplaceHolder(len(thirdClassifyIds)))
+	}
+	sql += ")"
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY publish_time DESC LIMIT ?,?`
+	_, err = o.Raw(sql, firstClassifyIds, secondClassifyIds, thirdClassifyIds, startSize, pageSize).QueryRows(&reportPdfs)
+	return
+}
+
+func GetReportPdfDailyList() (reportPdfs []*ReportPdf, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM report_pdf WHERE 1=1 AND state=1 AND DATE(publish_time) = DATE(NOW()) ORDER BY publish_time DESC `
+	_, err = o.Raw(sql).QueryRows(&reportPdfs)
+	return
+}
+
+func GetReportPdfCountByCondition(firstClassifyIds, secondClassifyIds, thirdClassifyIds []int, condition string) (count int, err error) {
+	if len(firstClassifyIds) == 0 && len(secondClassifyIds) == 0 && len(thirdClassifyIds) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	sql := `SELECT COUNT(*) AS count FROM report_pdf WHERE 1=1 AND (1=2 `
+
+	if len(firstClassifyIds) > 0 {
+		sql += fmt.Sprintf(" OR classify_id_first IN (%s) ", utils.GetOrmReplaceHolder(len(firstClassifyIds)))
+	}
+	if len(secondClassifyIds) > 0 {
+		sql += fmt.Sprintf(" OR classify_id_second IN (%s) ", utils.GetOrmReplaceHolder(len(secondClassifyIds)))
+	}
+	if len(thirdClassifyIds) > 0 {
+		sql += fmt.Sprintf(" OR classify_id_third IN (%s) ", utils.GetOrmReplaceHolder(len(thirdClassifyIds)))
+	}
+	sql += ` )`
+	if condition != "" {
+		sql += condition
+	}
+	err = o.Raw(sql, firstClassifyIds, secondClassifyIds, thirdClassifyIds).QueryRow(&count)
+	return
+}
+
+func GetReportPdfCountById(id int) (count int, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT COUNT(*) AS count FROM report_pdf WHERE report_pdf_id = ? `
+	err = o.Raw(sql, id).QueryRow(&count)
+	return
+}
+
+func GetReportPdfById(id int) (item *ReportPdfView, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM report_pdf WHERE report_pdf_id = ? `
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// 更新pv
+func UpdateReportPdfPv(id int) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE report_pdf SET pv = pv + 1 WHERE report_pdf_id = ?`
+	_, err = o.Raw(sql, id).Exec()
+	return
+}
+
+// 更新uv和pv
+func UpdateReportPdfUvAndPv(id int) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE report_pdf SET uv = uv + 1, pv = pv + 1 WHERE report_pdf_id = ?`
+	_, err = o.Raw(sql, id).Exec()
+	return
+}

+ 4 - 0
models/request/my_report.go

@@ -3,3 +3,7 @@ package request
 type MyReportCollectReq struct {
 	ReportId int `description:"报告id"`
 }
+
+type MyReportPdfCollectReq struct {
+	ReportPdfId int `description:"报告id"`
+}

+ 5 - 0
models/request/user.go

@@ -27,3 +27,8 @@ type ReportRecordReq struct {
 	RecordId int `description:"记录Id"`
 	ReportId int `description:"报告Id"`
 }
+
+type ReportPdfRecordReq struct {
+	RecordId    int `description:"记录Id"`
+	ReportPdfId int `description:"报告Id"`
+}

+ 19 - 1
models/response/report.go

@@ -8,7 +8,7 @@ import (
 )
 
 type ReportList struct {
-	List   []*models.ReportList
+	List   []*models.ReportView
 	Paging *paging.PagingItem
 }
 
@@ -32,6 +32,8 @@ type ReportCollectListItem struct {
 	ClassifyNameFirst   string    `description:"一级分类名称"`
 	ClassifyIdSecond    int       `description:"二级分类id"`
 	ClassifyNameSecond  string    `description:"二级分类名称"`
+	ClassifyIdThird     int       `description:"三级分类id"`
+	ClassifyNameThird   string    `description:"三级分类名称"`
 	ReportChapterTypeId int       `decription:"报告章节类型id"`
 	PublishTime         time.Time `description:"发布时间"`
 	Title               string    `description:"标题"`
@@ -39,6 +41,8 @@ type ReportCollectListItem struct {
 	Abstract            string    `description:"摘要"`
 	Stage               string    `description:"期数"`
 	Author              string    `description:"作者"`
+	PdfUrl              string    `description:"pdf文件url"`
+	ReportType          int       `description:"报告类型:1:eta报告,2:小程序pdf报告"`
 }
 
 type ReportSearchListView struct {
@@ -48,6 +52,8 @@ type ReportSearchListView struct {
 	ClassifyNameFirst   string `description:"一级分类名称"`
 	ClassifyIdSecond    int    `description:"二级分类id"`
 	ClassifyNameSecond  string `description:"二级分类名称"`
+	ClassifyIdThird     int    `description:"三级分类id"`
+	ClassifyNameThird   string `description:"三级分类名称"`
 	ReportChapterTypeId int    `decription:"报告章节类型id"`
 	PublishTime         string `description:"发布时间"`
 	Title               string `description:"标题"`
@@ -55,6 +61,8 @@ type ReportSearchListView struct {
 	Abstract            string `description:"摘要"`
 	Stage               string `description:"期数"`
 	Author              string `description:"作者"`
+	PdfUrl              string `description:"pdf文件url"`
+	ReportType          int    `description:"报告类型:1:eta报告,2:小程序pdf报告"`
 }
 
 type ReportSearchResp struct {
@@ -65,3 +73,13 @@ type ReportSearchViewResp struct {
 	Paging *paging.PagingItem
 	List   []*ReportSearchListView
 }
+
+type ReportPdfResp struct {
+	Paging *paging.PagingItem
+	List   []*models.ReportPdf
+}
+
+type ReportPdfDetailResp struct {
+	Report *models.ReportPdfView `description:"报告"`
+	Status int                   `description:"报告状态"`
+}

+ 1 - 1
models/user_chart_permission_mapping.go

@@ -8,7 +8,7 @@ type UserChartPermissionMapping struct {
 	ChartPermissionId            int `description:"品种id"`
 }
 
-func GetChartPermissionIdByUserId(UserId int) (items []int, err error) {
+func GetUserChartPermissionIdByUserId(UserId int) (items []int, err error) {
 	o := orm.NewOrm()
 	sql := `SELECT chart_permission_id FROM user_chart_permission_mapping WHERE user_id=?`
 	_, err = o.Raw(sql, UserId).QueryRows(&items)

+ 10 - 0
models/user_read_record.go

@@ -19,12 +19,15 @@ type UserReadRecord struct {
 	ClassifyName1       string    `description:"一级分类名称"`
 	ClassifyId2         int       `description:"二级分类id"`
 	ClassifyName2       string    `description:"二级分类名称"`
+	ClassifyId3         int       `description:"三级分类id"`
+	ClassifyName3       string    `description:"三级分类名称"`
 	Timestamp           int       `description:"阅读开始时间戳"`
 	EndTimestamp        int       `description:"阅读结束时间戳"`
 	CreateTime          time.Time `description:"创建时间"`
 	CreateDate          string    `description:"创建日期"`
 	StayTime            string    `description:"停留时间"`
 	StayTimestamp       string    `description:"停留时间戳"`
+	ReportType          int       `description:"报告类型:1-普通研报;2-pdf研报"`
 }
 
 func (u *UserReadRecord) Insert() (insertId int64, err error) {
@@ -46,6 +49,13 @@ func GetUserReadRecordListById(recordId int) (items *UserReadRecord, err error)
 	return
 }
 
+func GetUserReadRecordCountByReportPdfIdAndUserId(reportId, userId int) (count int, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT COUNT(*) AS count FROM user_read_record WHERE 1=1 AND report_id=? AND user_id = ? AND report_type = 2`
+	err = o.Raw(sql, reportId, userId).QueryRow(&count)
+	return
+}
+
 func GetUserReadRecordListByRcordIds(recordIds []string) (items []*UserReadRecord, err error) {
 	o := orm.NewOrm()
 	sql := `SELECT * FROM user_read_record WHERE 1=1  `

+ 61 - 7
routers/commentsRouter.go

@@ -27,8 +27,8 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"],
         beego.ControllerComments{
-            Method: "Detail",
-            Router: `/detail`,
+            Method: "List",
+            Router: `/list`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -36,17 +36,17 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"],
         beego.ControllerComments{
-            Method: "List",
-            Router: `/list`,
+            Method: "Locate",
+            Router: `/locate`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})
 
-    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartController"],
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartPermissionController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ChartPermissionController"],
         beego.ControllerComments{
-            Method: "Locate",
-            Router: `/locate`,
+            Method: "ClassifyTree",
+            Router: `/classify/tree`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -160,6 +160,33 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"],
+        beego.ControllerComments{
+            Method: "PdfCollect",
+            Router: `/pdf/collect`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"],
+        beego.ControllerComments{
+            Method: "PdfCollectCancel",
+            Router: `/pdf/collectCancel`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:MyReportController"],
+        beego.ControllerComments{
+            Method: "IsPdfCollect",
+            Router: `/pdf/isCollect`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"],
         beego.ControllerComments{
             Method: "DailyList",
@@ -187,6 +214,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "PdfDetail",
+            Router: `/pdf/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "PdfList",
+            Router: `/pdf/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:ReportController"],
         beego.ControllerComments{
             Method: "RecentList",
@@ -232,6 +277,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"],
+        beego.ControllerComments{
+            Method: "AddReportPdfRecord",
+            Router: `/pdf/addReportRecord`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"] = append(beego.GlobalControllerRouter["eta/eta_mini_api/controllers:UserAuthController"],
         beego.ControllerComments{
             Method: "PermissionList",

+ 31 - 0
services/base_lib.go

@@ -1,6 +1,7 @@
 package services
 
 import (
+	"bytes"
 	"eta/eta_mini_api/utils"
 	"io"
 	"net/http"
@@ -36,3 +37,33 @@ func HttpGet(url string) (body []byte, err error) {
 	utils.FileLog.Info("result:" + string(body))
 	return
 }
+
+func HttpPost(url string, postBody []byte) (body []byte, err error) {
+	client := &http.Client{}
+	req, err := http.NewRequest("POST", url, bytes.NewReader(postBody))
+	if err != nil {
+		return
+	}
+	nonce := utils.GetRandStringNoSpecialChar(16)
+	timestamp := time.Now().Format(utils.FormatDateTimeUnSpace)
+	signature := utils.GetSign(nonce, timestamp, utils.ETA_MINI_APPID, utils.ETA_MINI_APP_SECRET)
+	//增加header选项
+	req.Header.Add("Nonce", nonce)
+	req.Header.Add("Timestamp", timestamp)
+	req.Header.Add("Appid", utils.ETA_MINI_APPID)
+	req.Header.Add("Signature", signature)
+	req.Header.Set("Content-Type", "application/json")
+
+	response, err := client.Do(req)
+	if err != nil {
+		return
+	}
+	defer response.Body.Close()
+
+	body, err = io.ReadAll(response.Body)
+	if err != nil {
+		return
+	}
+	utils.FileLog.Info("result:" + string(body))
+	return
+}

+ 53 - 2
services/chart_permission.go

@@ -7,7 +7,8 @@ import (
 	"fmt"
 )
 
-func GetChartPermissionSecondList(chartPermissionId int) (resp *models.ChartPermissionResp[[]models.ChartPermission], err error) {
+// GetChartPermissionSecondList 获取二级品种权限
+func GetChartPermissionSecondList(chartPermissionId int) (resp *models.ChartPermissionResp[[]*models.ChartPermission], err error) {
 	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/second/list"
 	url += fmt.Sprintf("?chartPermissonId=%d", chartPermissionId)
 	body, err := HttpGet(url)
@@ -22,7 +23,8 @@ func GetChartPermissionSecondList(chartPermissionId int) (resp *models.ChartPerm
 
 }
 
-func GetChartPermissionList() (resp *models.ChartPermissionResp[[]models.ChartPermission], err error) {
+// GetChartPermissionList 获取一级品种权限
+func GetChartPermissionList() (resp *models.ChartPermissionResp[[]*models.ChartPermission], err error) {
 	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/list"
 	body, err := HttpGet(url)
 	if err != nil {
@@ -35,6 +37,7 @@ func GetChartPermissionList() (resp *models.ChartPermissionResp[[]models.ChartPe
 	return
 }
 
+// GetPublicChartPermissionList 获取公共品种权限列表
 func GetPublicChartPermissionList() (resp *models.ChartPermissionResp[[]*models.ChartPermissionTreeView], err error) {
 	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/public/list"
 	body, err := HttpGet(url)
@@ -48,6 +51,7 @@ func GetPublicChartPermissionList() (resp *models.ChartPermissionResp[[]*models.
 	return
 }
 
+// GetPrivateChartPermissionList 获取私有品种权限列表
 func GetPrivateChartPermissionList() (resp *models.ChartPermissionResp[[]*models.ChartPermissionTreeView], err error) {
 	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/private/list"
 	body, err := HttpGet(url)
@@ -61,6 +65,7 @@ func GetPrivateChartPermissionList() (resp *models.ChartPermissionResp[[]*models
 	return
 }
 
+// GetChartPermissionAllList 获取所有品种权限列表
 func GetChartPermissionAllList() (resp *models.ChartPermissionResp[[]*models.ChartPermission], err error) {
 	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/allList"
 	body, err := HttpGet(url)
@@ -74,6 +79,7 @@ func GetChartPermissionAllList() (resp *models.ChartPermissionResp[[]*models.Cha
 	return
 }
 
+// GetReportChartPermissionList 获取研报的权限列表
 func GetReportChartPermissionList(reportId int) (resp *models.ChartPermissionResp[[]*models.ChartPermission], err error) {
 	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/detail"
 	url += fmt.Sprintf("?ReportId=%d", reportId)
@@ -87,3 +93,48 @@ func GetReportChartPermissionList(reportId int) (resp *models.ChartPermissionRes
 	}
 	return
 }
+
+// GetChartPermissionListByClassifyId 根据分类id获取权限列表 scope 0:二级品种权限,1:一级品种权限,2:所有权限
+func GetChartPermissionListByClassifyId(classifyId, scope int) (resp *models.ChartPermissionResp[[]*models.ChartPermission], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/classify/detail"
+	url += fmt.Sprintf("?ClassifyId=%d&Scope=%d", classifyId, scope)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+// GetClassifyTreeByChartPermission 获取绑定该品种的分类树
+func GetClassifyTreeByChartPermission(chartPermissionId int) (resp *models.ChartPermissionResp[[]*models.ClassifyView], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/classify/tree"
+	url += fmt.Sprintf("?ChartPermissionId=%d", chartPermissionId)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+// GetClassifyListByChartPermission 获取绑定该品种的分类列表
+func GetClassifyListByChartPermission(chartPermissionId int) (resp *models.ChartPermissionResp[[]*models.ClassifyView], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/chart_permission/classify/list"
+	url += fmt.Sprintf("?ChartPermissionId=%d", chartPermissionId)
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}

+ 48 - 0
services/classify.go

@@ -0,0 +1,48 @@
+package services
+
+import (
+	"encoding/json"
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/utils"
+)
+
+type ClassifyReq struct {
+	ClassifyIds []int
+}
+
+type ClassifyPermissionItemResp struct {
+	ClassifyId      int      `description:"二级分类id"`
+	PermissionNames []string `description:"权限名称列表"`
+}
+
+func GetFirstChartPermission(classifyIds []int) (resp *models.ChartPermissionResp[[]*ClassifyPermissionItemResp], err error) {
+
+	classifyReq := ClassifyReq{classifyIds}
+	postBody, err := json.Marshal(classifyReq)
+	if err != nil {
+		return
+	}
+	url := utils.ETA_MINI_BRIDGE_URL + "/classify/chart_permission/first"
+	body, err := HttpPost(url, postBody)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func GetAllClassify() (resp *models.BaseResponseT[[]*models.ClassifyView], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/classify/list"
+	body, err := HttpGet(url)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return
+	}
+	return
+}

+ 20 - 5
services/report.go

@@ -2,15 +2,31 @@ package services
 
 import (
 	"encoding/json"
+	"eta/eta_mini_api/models"
 	"eta/eta_mini_api/utils"
 	"fmt"
 
 	resp2 "eta/eta_mini_api/models/response"
 )
 
-func GetReportList(chartPermissionId, level, rangeType, currentIndex, pageSize int) (resp *resp2.ReportResp[resp2.ReportList], err error) {
+// GetReportPdfClassify 获取pdf研报的最小分类
+func GetReportPdfClassify(report *models.ReportPdfView) int {
+	var res int
+	if report.ClassifyIdFirst != 0 {
+		res = report.ClassifyIdFirst
+	}
+	if report.ClassifyIdSecond != 0 {
+		res = report.ClassifyIdSecond
+	}
+	if report.ClassifyIdThird != 0 {
+		res = report.ClassifyIdThird
+	}
+	return res
+}
+
+func GetReportList(chartPermissionId, level, rangeType, classifyId, currentIndex, pageSize int) (resp *resp2.ReportResp[resp2.ReportList], err error) {
 	url := utils.ETA_MINI_BRIDGE_URL + "/report/list?"
-	url += fmt.Sprintf("RangeType=%d&ChartPermissionId=%d&Level=%d&PageSize=%d&CurrentIndex=%d", rangeType, chartPermissionId, level, pageSize, currentIndex)
+	url += fmt.Sprintf("RangeType=%d&ChartPermissionId=%d&Level=%d&PageSize=%d&CurrentIndex=%d&ClassifyId=%d", rangeType, chartPermissionId, level, pageSize, currentIndex, classifyId)
 	fmt.Println(url)
 	body, err := HttpGet(url)
 	if err != nil {
@@ -53,9 +69,8 @@ func GetReportDetailNoUser(reportId int) (resp *resp2.ReportResp[resp2.ReportDet
 	return
 }
 
-func GetReportDailyList(currentIndex, pageSize int) (resp *resp2.ReportResp[resp2.ReportList], err error) {
-	url := utils.ETA_MINI_BRIDGE_URL + "/report/daily/list?"
-	url += fmt.Sprintf("PageSize=%d&CurrentIndex=%d", pageSize, currentIndex)
+func GetReportDailyList() (resp *resp2.ReportResp[resp2.ReportList], err error) {
+	url := utils.ETA_MINI_BRIDGE_URL + "/report/daily/list"
 	fmt.Println(url)
 	body, err := HttpGet(url)
 	if err != nil {

+ 11 - 0
utils/common.go

@@ -179,3 +179,14 @@ func Unique[T comparable](slice []T) []T {
 	}
 	return unique
 }
+
+func GetOrmReplaceHolder(num int) string {
+	var stringBuffer strings.Builder
+	for i := 0; i < num; i++ {
+		stringBuffer.WriteString("?")
+		if i != num-1 {
+			stringBuffer.WriteString(",")
+		}
+	}
+	return stringBuffer.String()
+}

+ 11 - 1
utils/config.go

@@ -57,6 +57,11 @@ var (
 )
 var DesKey string // 接口返回加密KEY
 
+// 小程序自定义的品种名称
+var (
+	MINI_CUSTOM_PERMISSION_NAME string
+)
+
 func init() {
 	tmpRunMode, err := web.AppConfig.String("run_mode")
 	if err != nil {
@@ -89,7 +94,6 @@ func init() {
 
 	WX_MINI_APPID = config["wx_mini_appid"]
 	WX_MINI_APP_SECRET = config["wx_mini_app_secret"]
-	// 仅测试
 
 	DW_WX_Id = config["dw_wx_id"]
 	DW_WX_APPID = config["dw_wx_appid"]
@@ -99,6 +103,12 @@ func init() {
 	ETA_MINI_BRIDGE_URL = config["eta_mini_bridge_url"]
 	ETA_MINI_APPID = config["eta_mini_appid"]
 	ETA_MINI_APP_SECRET = config["eta_mini_app_secret"]
+
+	MINI_CUSTOM_PERMISSION_NAME = config["mini_custom_permission_name"]
+	if MINI_CUSTOM_PERMISSION_NAME == "" {
+		MINI_CUSTOM_PERMISSION_NAME = "PDF报告"
+	}
+
 	initRedis(config)
 }
 

+ 12 - 0
utils/constants.go

@@ -22,6 +22,18 @@ const (
 	UserStatusFormal    = 2 //正式用户
 )
 
+// 权限类型
+const (
+	PermissionTypeEta  = 1 // eta的品种权限
+	PermissionTypeMini = 2 // 小程序的品种权限
+)
+
+// 报告类型
+const (
+	ReportTypeEta = 1 // eta的研报
+	ReportTypePdf = 2 // pdf的研报
+)
+
 // 常量定义
 const (
 	FormatTime            = "15:04:05"                //时间格式