Selaa lähdekoodia

报告审批流管理

hsun 1 vuosi sitten
vanhempi
commit
13c6cf862a

+ 6 - 5
controllers/base_auth.go

@@ -208,11 +208,12 @@ func (c *BaseAuthController) Prepare() {
 			for _, s := range apis {
 				apiMap[s] = true
 			}
-			if !apiMap[uri] {
-				c.JSON(models.BaseResponse{Ret: 403, Msg: "无权访问!", ErrMsg: "无权访问!"}, false, false)
-				c.StopRun()
-				return
-			}
+			// TODO: 关闭调试
+			//if !apiMap[uri] {
+			//	c.JSON(models.BaseResponse{Ret: 403, Msg: "无权访问!", ErrMsg: "无权访问!"}, false, false)
+			//	c.StopRun()
+			//	return
+			//}
 		} else {
 			c.JSON(models.BaseResponse{Ret: 408, Msg: "请求异常,请联系客服!", ErrMsg: "POST之外的请求,暂不支持"}, false, false)
 			c.StopRun()

+ 1 - 0
controllers/report_approve/report_approve.go

@@ -0,0 +1 @@
+package report_approve

+ 507 - 198
controllers/report_approve/report_approve_flow.go

@@ -5,10 +5,7 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/report_approve"
-	"eta/eta_api/models/smart_report"
-	"eta/eta_api/models/system"
 	"eta/eta_api/services"
-	smartReportService "eta/eta_api/services/smart_report"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
@@ -22,11 +19,140 @@ type ReportApproveFlowController struct {
 	controllers.BaseAuthController
 }
 
+// List
+// @Title 报告列表
+// @Description 报告列表
+// @Param   PageSize			query	int		true	"每页数据条数"
+// @Param   CurrentIndex		query	int		true	"当前页页码"
+// @Param   ReportType			query   int     false	"报告类型:1-中文研报;2-英文研报;3-智能研报"
+// @Param   ClassifyIdFirst		query	int		false	"一级分类ID"
+// @Param   ClassifyIdSecond	query	int		false	"二级分类ID"
+// @Param   Keyword				query	string	false	"搜索关键词"
+// @Param   SortRule			query	int		false	"排序方式: 1-正序; 2-倒序(默认)"
+// @Success 200 {object} report_approve.ReportApproveFlowListResp
+// @router /list [get]
+func (this *ReportApproveFlowController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	params := new(report_approve.ReportApproveFlowListReq)
+	if e := this.ParseForm(params); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "入参解析失败, Err: " + e.Error()
+		return
+	}
+
+	var cond, orderRule string
+	var pars []interface{}
+	// 筛选项
+	{
+		keyword := strings.TrimSpace(params.Keyword)
+		if keyword != "" {
+			kw := fmt.Sprint("%", keyword, "%")
+			cond += fmt.Sprintf(` AND %s LIKE ?`, report_approve.ReportApproveFlowCols.FlowName)
+			pars = append(pars, kw)
+		}
+		if params.ReportType > 0 && params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifySecondId)
+			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		}
+		if params.SortRule > 0 {
+			orderMap := map[int]string{1: "ASC", 2: "DESC"}
+			orderRule = fmt.Sprintf("%s %s", report_approve.ReportApproveFlowCols.CreateTime, orderMap[params.SortRule])
+		}
+	}
+
+	resp := new(report_approve.ReportApproveFlowListResp)
+	flowOb := new(report_approve.ReportApproveFlow)
+	total, e := flowOb.GetCountByCondition(cond, pars)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批流总数失败, Err:" + e.Error()
+		return
+	}
+	if total <= 0 {
+		page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
+		resp.Paging = page
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
+		return
+	}
+
+	// 分页列表
+	var startSize int
+	if params.PageSize <= 0 {
+		params.PageSize = utils.PageSize20
+	}
+	if params.CurrentIndex <= 0 {
+		params.CurrentIndex = 1
+	}
+	startSize = utils.StartIndex(params.CurrentIndex, params.PageSize)
+
+	list, e := flowOb.GetPageItemsByCondition(cond, pars, []string{}, orderRule, startSize, params.PageSize)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批流分页列表失败, Err:" + e.Error()
+		return
+	}
+
+	// 指标分类
+	cnClassifyIdName, enClassifyIdName := make(map[int]string), make(map[int]string)
+	cnClassify, e := models.GetAllClassify()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取中文分类失败, Err: " + e.Error()
+		return
+	}
+	for _, v := range cnClassify {
+		cnClassifyIdName[v.Id] = v.ClassifyName
+	}
+	enClassify, e := models.GetAllEnglishClassify()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取英文分类失败, Err: " + e.Error()
+		return
+	}
+	for _, v := range enClassify {
+		enClassifyIdName[v.Id] = v.ClassifyName
+	}
+
+	for _, v := range list {
+		t := report_approve.FormatReportApproveFlow2Item(v)
+		if v.ReportType == report_approve.FlowReportTypeEnglish {
+			t.ReportClassify = fmt.Sprintf("%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], enClassifyIdName[v.ClassifyFirstId], enClassifyIdName[v.ClassifySecondId])
+		} else {
+			t.ReportClassify = fmt.Sprintf("%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], cnClassifyIdName[v.ClassifyFirstId], cnClassifyIdName[v.ClassifySecondId])
+		}
+		resp.List = append(resp.List, t)
+	}
+
+	page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
+	resp.Paging = page
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
 // Add
-// @Title 新增
-// @Description 新增
-// @Param	request	body smart_report.SmartReportAddReq true "type json string"
-// @Success 200 {object} smart_report.SmartReportItem
+// @Title 新增审批流
+// @Description 新增审批流
+// @Param	request	body report_approve.ReportApproveFlowAddReq true "type json string"
+// @Success 200 {object} report_approve.ReportApproveDetailItem
 // @router /add [post]
 func (this *ReportApproveFlowController) Add() {
 	br := new(models.BaseResponse).Init()
@@ -44,120 +170,117 @@ func (this *ReportApproveFlowController) Add() {
 		br.Ret = 408
 		return
 	}
-	var req smart_report.SmartReportAddReq
-	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
-	if err != nil {
-		br.Msg = "参数解析异常!"
-		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+	var req report_approve.ReportApproveFlowAddReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	req.FlowName = strings.TrimSpace(req.FlowName)
+	if req.FlowName == "" {
+		br.Msg = "请输入审批流名称"
 		return
 	}
-	if req.AddType != 1 && req.AddType != 2 {
-		br.Msg = "请选择新增方式"
+	if len([]rune(req.FlowName)) > 20 {
+		br.Msg = "审批流名称最多输入20个字符"
 		return
 	}
-	if req.ClassifyIdFirst <= 0 || req.ClassifyIdSecond <= 0 {
-		br.Msg = "请选择分类"
+	reportTypes := []int{report_approve.FlowReportTypeChinese, report_approve.FlowReportTypeEnglish, report_approve.FlowReportTypeSmart}
+	if !utils.InArrayByInt(reportTypes, req.ReportType) {
+		br.Msg = "审批流报告类型有误"
+		br.ErrMsg = fmt.Sprintf("审批流报告类型有误, ReportType: %d", req.ReportType)
 		return
 	}
-	req.Title = strings.TrimSpace(req.Title)
-	if req.Title == "" {
-		br.Msg = "请输入标题"
+	if req.ClassifyFirstId <= 0 || req.ClassifySecondId <= 0 {
+		br.Msg = "请选择报告分类"
 		return
 	}
+	if len(req.Nodes) <= 0 {
+		br.Msg = "请添加审批流程"
+		return
+	}
+	approveTypes := []int{report_approve.NodeApproveTypeRoll, report_approve.NodeApproveTypeAll, report_approve.NodeApproveTypeAny}
+	approveUserTypes := []string{report_approve.NodeUserTypeNormal, report_approve.NodeUserTypeRole}
+	for _, v := range req.Nodes {
+		if !utils.InArrayByInt(approveTypes, v.ApproveType) {
+			br.Msg = "审批流类型有误"
+			br.ErrMsg = fmt.Sprintf("审批流类型有误, ApproveType: %d", v.ApproveType)
+			return
+		}
+		for _, v2 := range v.Users {
+			if !utils.InArrayByStr(approveUserTypes, v2.UserType) {
+				br.Msg = "审批流用户类型有误"
+				br.ErrMsg = fmt.Sprintf("审批流用户类型有误, UserType: %d", v2.UserType)
+				return
+			}
+		}
+	}
 
-	reportOB := new(smart_report.SmartReport)
-	stageMax, e := reportOB.GetMaxStageByClassifyId(req.ClassifyIdSecond)
-	if e != nil {
-		br.Msg = "操作失败"
-		br.ErrMsg = "获取期数失败, Err: " + e.Error()
-		return
-	}
-	stageMax += 1
-
-	item := new(smart_report.SmartReport)
-	item.AddType = req.AddType
-	item.ClassifyIdFirst = req.ClassifyIdFirst
-	item.ClassifyNameFirst = req.ClassifyNameFirst
-	item.ClassifyIdSecond = req.ClassifyIdSecond
-	item.ClassifyNameSecond = req.ClassifyNameSecond
-	item.Title = req.Title
-	item.Abstract = req.Abstract
-	item.Author = req.Author
-	item.Frequency = req.Frequency
-	item.Stage = stageMax
-	item.AdminId = sysUser.AdminId
-	item.AdminRealName = sysUser.RealName
-	item.LastModifyAdminId = sysUser.AdminId
-	item.LastModifyAdminName = sysUser.RealName
-	item.State = smart_report.SmartReportStateWaitPublish
-	item.CreateTime = time.Now().Local()
-	item.ModifyTime = time.Now().Local()
-	// 继承报告
-	if req.AddType == 2 {
-		ob := new(smart_report.SmartReport)
-		cond := ` AND classify_id_first = ? AND classify_id_second = ?`
-		pars := make([]interface{}, 0)
-		pars = append(pars, req.ClassifyIdFirst, req.ClassifyIdSecond)
-		lastReport, e := ob.GetItemByCondition(cond, pars, "stage DESC")
+	// 审批流是否已存在
+	{
+		flowOb := new(report_approve.ReportApproveFlow)
+		existCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId)
+		existPars := make([]interface{}, 0)
+		existPars = append(existPars, req.ReportType, req.ClassifyFirstId, req.ClassifySecondId)
+		exist, e := flowOb.GetItemByCondition(existCond, existPars, "")
 		if e != nil && e.Error() != utils.ErrNoRow() {
 			br.Msg = "获取失败"
-			br.ErrMsg = "获取往期研报失败, Err: " + e.Error()
+			br.ErrMsg = "获取审批流是否已存在失败, Err: " + e.Error()
 			return
 		}
-		if lastReport != nil {
-			item.Content = lastReport.Content
-			item.ContentSub = lastReport.ContentSub
-			item.ContentStruct = lastReport.ContentStruct
+		if exist != nil {
+			br.Msg = "该分类已有审批流, 请勿重复添加"
+			return
 		}
 	}
-	if e = item.Create(); e != nil {
-		br.Msg = "操作失败"
-		br.ErrMsg = "新增研报失败, Err: " + e.Error()
-		return
+
+	flowItem := new(report_approve.ReportApproveFlow)
+	flowItem.FlowName = req.FlowName
+	flowItem.ReportType = req.ReportType
+	flowItem.ClassifyFirstId = req.ClassifyFirstId
+	flowItem.ClassifySecondId = req.ClassifySecondId
+	flowItem.CurrVersion = 1
+	flowItem.CreateTime = time.Now().Local()
+	flowItem.ModifyTime = time.Now().Local()
+
+	nodeItems := make([]*report_approve.ReportApproveNode, 0)
+	for _, v := range req.Nodes {
+		n := new(report_approve.ReportApproveNode)
+		n.ApproveType = v.ApproveType
+		n.CurrVersion = flowItem.CurrVersion
+		j, _ := json.Marshal(v.Users)
+		n.Users = string(j)
+		n.CreateTime = time.Now().Local()
+		nodeItems = append(nodeItems, n)
 	}
-	uniqueCode := utils.MD5(fmt.Sprint("smart_", item.SmartReportId))
-	item.ReportCode = uniqueCode
-	if e = item.Update([]string{"ReportCode"}); e != nil {
+
+	// 新增审批流和节点
+	if e := flowItem.CreateFlowAndNodes(flowItem, nodeItems); e != nil {
 		br.Msg = "操作失败"
-		br.ErrMsg = "更新研报编码失败, Err: " + e.Error()
+		br.ErrMsg = "新增审批流和节点失败, Err: " + e.Error()
 		return
 	}
-	resp := smart_report.FormatSmartReport2Item(item)
 
-	recordItem := &models.ReportStateRecord{
-		ReportId:   item.SmartReportId,
-		ReportType: 2,
-		State:      smart_report.SmartReportStateWaitPublish,
-		AdminId:    this.SysUser.AdminId,
-		AdminName:  this.SysUser.AdminName,
-		CreateTime: time.Now(),
+	// 返回详情
+	detail, e := report_approve.FormatFlowAndNodesItem2Detail(flowItem, nodeItems)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批详情失败, Err: " + e.Error()
+		return
 	}
-	go func() {
-		_, _ = models.AddReportStateRecord(recordItem)
-	}()
-
+	br.Data = detail
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "操作成功"
-	br.Data = resp
 }
 
-// List
-// @Title 报告列表
-// @Description 报告列表
-// @Param   PageSize			query	int		true	"每页数据条数"
-// @Param   CurrentIndex		query	int		true	"当前页页码"
-// @Param   TimeType			query	string	false	"筛选的时间类别: publish_time-发布时间, modify_time-更新时间"
-// @Param   StartDate			query   string  false	"开始时间"
-// @Param   EndDate				query   string  false	"结束时间"
-// @Param   Frequency			query   string  false	"频度"
-// @Param   ClassifyIdFirst		query	int		false	"一级分类ID"
-// @Param   ClassifyIdSecond	query	int		false	"二级分类ID"
-// @Param   State				query	int		false	"发布状态: 1-待发布; 2-已发布"
-// @Param   Keyword				query	string	false	"搜索关键词"
-// @Success 200 {object} smart_report.SmartReportListResp
-// @router /list [get]
-func (this *ReportApproveFlowController) List() {
+// Edit
+// @Title 编辑审批流
+// @Description 编辑审批流
+// @Param	request	body report_approve.ReportApproveFlowEditReq true "type json string"
+// @Success 200 {object} report_approve.ReportApproveDetailItem
+// @router /edit [post]
+func (this *ReportApproveFlowController) Edit() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
 		if br.ErrMsg == "" {
@@ -173,151 +296,277 @@ func (this *ReportApproveFlowController) List() {
 		br.Ret = 408
 		return
 	}
-	type SmartReportListReq struct {
-		PageSize         int    `form:"PageSize"`
-		CurrentIndex     int    `form:"CurrentIndex"`
-		TimeType         string `form:"TimeType"`
-		StartDate        string `form:"StartDate"`
-		EndDate          string `form:"EndDate"`
-		Frequency        string `form:"Frequency"`
-		ClassifyIdFirst  int    `form:"ClassifyIdFirst"`
-		ClassifyIdSecond int    `form:"ClassifyIdSecond"`
-		State            int    `form:"State"`
-		Keyword          string `form:"Keyword"`
+	var req report_approve.ReportApproveFlowEditReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
 	}
-	params := new(SmartReportListReq)
-	if e := this.ParseForm(params); e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "入参解析失败, Err: " + e.Error()
+	if req.ReportApproveFlowId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveFlowId: %d", req.ReportApproveFlowId)
 		return
 	}
-	if params.TimeType == "" {
-		params.TimeType = "publish_time"
+	req.FlowName = strings.TrimSpace(req.FlowName)
+	if req.FlowName == "" {
+		br.Msg = "请输入审批流名称"
+		return
 	}
-	if params.TimeType != "publish_time" && params.TimeType != "modify_time" {
-		br.Msg = "请选择正确的时间类型"
+	if len([]rune(req.FlowName)) > 20 {
+		br.Msg = "审批流名称最多输入20个字符"
 		return
 	}
-	// 更新时间指的是内容更新时间
-	if params.TimeType == "modify_time" {
-		params.TimeType = "content_modify_time"
+	reportTypes := []int{report_approve.FlowReportTypeChinese, report_approve.FlowReportTypeEnglish, report_approve.FlowReportTypeSmart}
+	if !utils.InArrayByInt(reportTypes, req.ReportType) {
+		br.Msg = "审批流报告类型有误"
+		br.ErrMsg = fmt.Sprintf("审批流报告类型有误, ReportType: %d", req.ReportType)
+		return
 	}
-
-	var condition string
-	var pars []interface{}
-	// 筛选项
-	{
-		keyword := strings.TrimSpace(params.Keyword)
-		if keyword != "" {
-			kw := fmt.Sprint("%", keyword, "%")
-			condition += fmt.Sprintf(` AND (title LIKE ? OR admin_real_name LIKE ? OR last_modify_admin_name LIKE ?)`)
-			pars = append(pars, kw, kw, kw)
+	if req.ClassifyFirstId <= 0 || req.ClassifySecondId <= 0 {
+		br.Msg = "请选择报告分类"
+		return
+	}
+	if len(req.Nodes) <= 0 {
+		br.Msg = "请添加审批流程"
+		return
+	}
+	approveTypes := []int{report_approve.NodeApproveTypeRoll, report_approve.NodeApproveTypeAll, report_approve.NodeApproveTypeAny}
+	approveUserTypes := []string{report_approve.NodeUserTypeNormal, report_approve.NodeUserTypeRole}
+	for _, v := range req.Nodes {
+		if !utils.InArrayByInt(approveTypes, v.ApproveType) {
+			br.Msg = "审批流类型有误"
+			br.ErrMsg = fmt.Sprintf("审批流类型有误, ApproveType: %d", v.ApproveType)
+			return
 		}
-		if params.StartDate != "" && params.EndDate != "" {
-			st := fmt.Sprintf("%s 00:00:00", params.StartDate)
-			ed := fmt.Sprintf("%s 23:59:59", params.EndDate)
-			condition += fmt.Sprintf(` AND %s >= ? AND %s <= ?`, params.TimeType, params.TimeType)
-			pars = append(pars, st, ed)
+		for _, v2 := range v.Users {
+			if !utils.InArrayByStr(approveUserTypes, v2.UserType) {
+				br.Msg = "审批流用户类型有误"
+				br.ErrMsg = fmt.Sprintf("审批流用户类型有误, UserType: %d", v2.UserType)
+				return
+			}
 		}
-		if params.Frequency != "" {
-			condition += ` AND frequency = ?`
-			pars = append(pars, params.Frequency)
+	}
+
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowItem, e := flowOb.GetItemById(req.ReportApproveFlowId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批流已被删除, 请刷新页面"
+			return
 		}
-		if params.ClassifyIdFirst > 0 {
-			condition += ` AND classify_id_first = ?`
-			pars = append(pars, params.ClassifyIdFirst)
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取审批流信息失败, Err: " + e.Error()
+		return
+	}
+
+	// 审批流是否已存在
+	{
+		existCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ? AND %s <> ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId, report_approve.ReportApproveFlowCols.ReportApproveFlowId)
+		existPars := make([]interface{}, 0)
+		existPars = append(existPars, req.ReportType, req.ClassifyFirstId, req.ClassifySecondId, req.ReportApproveFlowId)
+		exist, e := flowOb.GetItemByCondition(existCond, existPars, "")
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取审批流是否已存在失败, Err: " + e.Error()
+			return
 		}
-		if params.ClassifyIdSecond > 0 {
-			condition += ` AND classify_id_second = ?`
-			pars = append(pars, params.ClassifyIdSecond)
+		if exist != nil {
+			br.Msg = "该分类已有审批流, 请勿重复添加"
+			return
 		}
-		if params.State > 0 {
-			condition += ` AND state = ?`
-			pars = append(pars, params.State)
+	}
+
+	// 变更了报告分类时, 判断是否允许变更
+	if req.ReportType != flowItem.ReportType || req.ClassifyFirstId != flowItem.ClassifyFirstId || req.ClassifySecondId != flowItem.ClassifySecondId {
+		checkOk, e := services.CheckReportApproveFlowChange(flowItem.ReportType, flowItem.ClassifyFirstId, flowItem.ClassifySecondId)
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "校验审批流是否可变更失败, Err: " + e.Error()
+			return
+		}
+		if !checkOk {
+			br.Msg = "当前有未走完流程的报告, 请走完流程后再做变更!"
+			return
 		}
 	}
 
-	resp := new(smart_report.SmartReportListResp)
-	reportOB := new(smart_report.SmartReport)
-	total, e := reportOB.GetCountByCondition(condition, pars)
-	if e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取报告总数失败, Err:" + e.Error()
+	flowItem.FlowName = req.FlowName
+	flowItem.ReportType = req.ReportType
+	flowItem.ClassifyFirstId = req.ClassifyFirstId
+	flowItem.ClassifySecondId = req.ClassifySecondId
+	flowItem.CurrVersion += 1
+	flowItem.ModifyTime = time.Now().Local()
+
+	nodeItems := make([]*report_approve.ReportApproveNode, 0)
+	for _, v := range req.Nodes {
+		n := new(report_approve.ReportApproveNode)
+		n.ApproveType = v.ApproveType
+		n.CurrVersion = flowItem.CurrVersion
+		j, _ := json.Marshal(v.Users)
+		n.Users = string(j)
+		n.CreateTime = time.Now().Local()
+		nodeItems = append(nodeItems, n)
+	}
+
+	// 更新审批流和节点
+	if e := flowItem.UpdateFlowAndNodes(flowItem, nodeItems); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新审批流和节点失败, Err: " + e.Error()
 		return
 	}
-	if total <= 0 {
-		page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
-		resp.Paging = page
-		br.Ret = 200
-		br.Success = true
-		br.Msg = "获取成功"
-		br.Data = resp
+
+	// 返回详情
+	detail, e := report_approve.FormatFlowAndNodesItem2Detail(flowItem, nodeItems)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批详情失败, Err: " + e.Error()
 		return
 	}
+	br.Data = detail
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
 
-	// 分页列表
-	var startSize int
-	if params.PageSize <= 0 {
-		params.PageSize = utils.PageSize20
+// Detail
+// @Title 审批流详情
+// @Description 审批流详情
+// @Param   ReportApproveFlowId  query  int  true  "审批流ID"
+// @Success 200 {object} report_approve.ReportApproveDetailItem
+// @router /detail [get]
+func (this *ReportApproveFlowController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
 	}
-	if params.CurrentIndex <= 0 {
-		params.CurrentIndex = 1
+	flowId, _ := this.GetInt("ReportApproveFlowId")
+	if flowId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveFlowId: %d", flowId)
+		return
 	}
-	startSize = utils.StartIndex(params.CurrentIndex, params.PageSize)
 
-	// 列表查询过滤掉富文本内容
-	fields := []string{
-		"smart_report_id", "report_code", "classify_id_first", "classify_name_first", "classify_id_second", "classify_name_second", "add_type",
-		"title", "abstract", "author", "frequency", "stage", "video_url", "video_name", "video_play_seconds", "video_size", "detail_img_url", "detail_pdf_url",
-		"admin_id", "admin_real_name", "state", "publish_time", "pre_publish_time", "pre_msg_send", "msg_is_send", "msg_send_time", "create_time", "modify_time",
-		"last_modify_admin_id", "last_modify_admin_name", "content_modify_time", "pv", "uv",
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowItem, e := flowOb.GetItemById(flowId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批流已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批流信息失败, Err: " + e.Error()
+		return
 	}
-	list, e := reportOB.GetPageItemsByCondition(condition, pars, fields, "", startSize, params.PageSize)
+
+	// 审批节点
+	nodeOb := new(report_approve.ReportApproveNode)
+	nodeCond := fmt.Sprintf(` AND %s = ? AND %s = ?`, report_approve.ReportApproveNodeCols.ReportApproveFlowId, report_approve.ReportApproveNodeCols.CurrVersion)
+	nodePars := make([]interface{}, 0)
+	nodePars = append(nodePars, flowItem.ReportApproveFlowId, flowItem.CurrVersion)
+	nodes, e := nodeOb.GetItemsByCondition(nodeCond, nodePars, []string{}, "")
 	if e != nil {
 		br.Msg = "获取失败"
-		br.ErrMsg = "获取报告分页列表失败, Err:" + e.Error()
+		br.ErrMsg = "获取审批节点失败, Err: " + e.Error()
 		return
 	}
 
-	// 获取系统用户列表-用于匹配编辑中的用户
-	adminIdName := make(map[int]string)
-	admins, e := system.GetSysAdminList(``, make([]interface{}, 0), []string{}, "")
+	detail, e := report_approve.FormatFlowAndNodesItem2Detail(flowItem, nodes)
 	if e != nil {
 		br.Msg = "获取失败"
-		br.ErrMsg = "获取系统用户列表失败, Err: " + e.Error()
+		br.ErrMsg = "获取审批详情失败, Err: " + e.Error()
 		return
 	}
-	for _, ad := range admins {
-		adminIdName[ad.AdminId] = ad.RealName
+	br.Data = detail
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Remove
+// @Title 删除审批流
+// @Description 删除审批流
+// @Param	request	body report_approve.ReportApproveFlowRemoveReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /remove [post]
+func (this *ReportApproveFlowController) Remove() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req report_approve.ReportApproveFlowRemoveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	if req.ReportApproveFlowId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveFlowId: %d", req.ReportApproveFlowId)
+		return
 	}
 
-	for _, v := range list {
-		item := smart_report.FormatSmartReport2Item(v)
-		mark, e := smartReportService.UpdateSmartReportEditing(v.SmartReportId, 2, sysUser.AdminId, sysUser.RealName, adminIdName)
-		if e != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = "查询编辑中标记失败, Err:" + e.Error()
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowItem, e := flowOb.GetItemById(req.ReportApproveFlowId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批流已被删除, 请刷新页面"
 			return
 		}
-		if mark.Status == 0 {
-			item.CanEdit = true
-		} else {
-			item.Editor = mark.Editor
-		}
-		resp.List = append(resp.List, item)
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取审批流信息失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验是否允许删除
+	checkOk, e := services.CheckReportApproveFlowChange(flowItem.ReportType, flowItem.ClassifyFirstId, flowItem.ClassifySecondId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验审批流是否可变更失败, Err: " + e.Error()
+		return
+	}
+	if !checkOk {
+		br.Msg = "当前有未走完流程的报告, 请走完流程后再做删除!"
+		return
+	}
+
+	// 删除审批流, 保留审批节点, 历史审批回显会用得到
+	if e = flowItem.Del(); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "删除审批流失败, Err: " + e.Error()
+		return
 	}
 
-	page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
-	resp.Paging = page
 	br.Ret = 200
 	br.Success = true
-	br.Msg = "获取成功"
-	br.Data = resp
+	br.Msg = "操作成功"
 }
 
 // ReportClassifyTree
 // @Title 报告分类树
 // @Description 报告分类树
+// @Param   ReportApproveFlowId  query  int  false  "审批流ID"
 // @Success 200 {object} report_approve.ReportClassifyTreeItem
 // @router /report/classify_tree [get]
 func (this *ReportApproveFlowController) ReportClassifyTree() {
@@ -336,8 +585,44 @@ func (this *ReportApproveFlowController) ReportClassifyTree() {
 		br.Ret = 408
 		return
 	}
+	flowId, _ := this.GetInt("ReportApproveFlowId")
+
+	// 获取审批流信息, 用于查询分类是否可选
+	var flowKey string
+	if flowId > 0 {
+		flowOb := new(report_approve.ReportApproveFlow)
+		flowItem, e := flowOb.GetItemById(flowId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "审批流已被删除, 请刷新页面"
+				return
+			}
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取审批流信息失败, Err: " + e.Error()
+			return
+		}
+		flowKey = fmt.Sprintf("%d-%d-%d", flowItem.ReportType, flowItem.ClassifyFirstId, flowItem.ClassifySecondId)
+	}
+
+	// 获取审批流列表
+	flowOb := new(report_approve.ReportApproveFlow)
+	flows, e := flowOb.GetItemsByCondition(``, make([]interface{}, 0), []string{}, "")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批流列表失败, Err: " + e.Error()
+		return
+	}
+	hasFlowMap := make(map[string]bool)
+	for _, v := range flows {
+		k := fmt.Sprintf("%d-%d-%d", v.ReportType, v.ClassifyFirstId, v.ClassifySecondId)
+		if k == flowKey {
+			// 当前审批流对应的分类标记为可选状态
+			continue
+		}
+		hasFlowMap[k] = true
+	}
 
-	resp, cnTree, enTree := make([]*report_approve.ReportClassifyTreeItem, 0), make([]*report_approve.ReportClassifyTreeItem, 0), make([]*report_approve.ReportClassifyTreeItem, 0)
+	resp, cnTree, smartTree, enTree := make([]*report_approve.ReportClassifyTreeItem, 0), make([]*report_approve.ReportClassifyTreeItem, 0), make([]*report_approve.ReportClassifyTreeItem, 0), make([]*report_approve.ReportClassifyTreeItem, 0)
 
 	var cnErr, enErr error
 	wg := sync.WaitGroup{}
@@ -345,7 +630,9 @@ func (this *ReportApproveFlowController) ReportClassifyTree() {
 
 	// 中文/智能研报分类
 	go func() {
-		wg.Done()
+		defer func() {
+			wg.Done()
+		}()
 
 		classify, e := models.GetAllClassify()
 		if e != nil {
@@ -353,11 +640,27 @@ func (this *ReportApproveFlowController) ReportClassifyTree() {
 			return
 		}
 		cnTree = services.GetReportClassifyTreeRecursive(classify, 0)
+		for _, v := range cnTree {
+			for _, v2 := range v.Children {
+				k := fmt.Sprintf("%d-%d-%d", report_approve.FlowReportTypeChinese, v.ClassifyId, v2.ClassifyId)
+				v2.HasFlow = hasFlowMap[k]
+			}
+		}
+
+		smartTree = services.GetReportClassifyTreeRecursive(classify, 0)
+		for _, v := range smartTree {
+			for _, v2 := range v.Children {
+				k := fmt.Sprintf("%d-%d-%d", report_approve.FlowReportTypeSmart, v.ClassifyId, v2.ClassifyId)
+				v2.HasFlow = hasFlowMap[k]
+			}
+		}
 	}()
 
 	// 英文研报分类
 	go func() {
-		wg.Done()
+		defer func() {
+			wg.Done()
+		}()
 
 		classify, e := models.GetAllEnglishClassify()
 		if e != nil {
@@ -365,6 +668,12 @@ func (this *ReportApproveFlowController) ReportClassifyTree() {
 			return
 		}
 		enTree = services.GetReportClassifyTreeRecursive(classify, 0)
+		for _, v := range enTree {
+			for _, v2 := range v.Children {
+				k := fmt.Sprintf("%d-%d-%d", report_approve.FlowReportTypeEnglish, v.ClassifyId, v2.ClassifyId)
+				v2.HasFlow = hasFlowMap[k]
+			}
+		}
 	}()
 
 	wg.Wait()
@@ -391,7 +700,7 @@ func (this *ReportApproveFlowController) ReportClassifyTree() {
 	}, &report_approve.ReportClassifyTreeItem{
 		ClassifyId:   report_approve.FlowReportTypeSmart,
 		ClassifyName: "智能研报",
-		Children:     cnTree,
+		Children:     smartTree,
 	})
 
 	br.Data = resp

+ 13 - 6
models/business_conf.go

@@ -9,12 +9,19 @@ import (
 )
 
 const (
-	BusinessConfUseXf          = "UseXf"
-	BusinessConfXfAppid        = "XfAppid"
-	BusinessConfXfApiKey       = "XfApiKey"
-	BusinessConfXfApiSecret    = "XfApiSecret"
-	BusinessConfXfVcn          = "XfVcn"
-	BusinessConfEnPptCoverImgs = "EnPptCoverImgs"
+	BusinessConfUseXf             = "UseXf"
+	BusinessConfXfAppid           = "XfAppid"
+	BusinessConfXfApiKey          = "XfApiKey"
+	BusinessConfXfApiSecret       = "XfApiSecret"
+	BusinessConfXfVcn             = "XfVcn"
+	BusinessConfEnPptCoverImgs    = "EnPptCoverImgs"
+	BusinessConfIsReportApprove   = "IsReportApprove"
+	BusinessConfReportApproveType = "ReportApproveType"
+)
+
+const (
+	BusinessConfReportApproveTypeEta   = "eta"
+	BusinessConfReportApproveTypeOther = "other"
 )
 
 // BusinessConf 商户配置表

+ 12 - 0
models/db.go

@@ -8,6 +8,7 @@ import (
 	"eta/eta_api/models/data_manage/supply_analysis"
 	"eta/eta_api/models/eta_trial"
 	"eta/eta_api/models/ppt_english"
+	"eta/eta_api/models/report_approve"
 	"eta/eta_api/models/sandbox"
 	"eta/eta_api/models/semantic_analysis"
 	"eta/eta_api/models/smart_report"
@@ -153,6 +154,9 @@ func init() {
 	// 初始化EXCEL的表
 	initExcel()
 
+	// 报告审批
+	initReportApprove()
+
 	// 初始化部分数据表变量(直接init会有顺序问题=_=!)
 	data_manage.InitEdbSourceVar()
 }
@@ -456,3 +460,11 @@ func initSmartReport() {
 		new(smart_report.SmartReportSaveLog), // 智能研报-保存记录表
 	)
 }
+
+// initReportApprove 报告审批相关表
+func initReportApprove() {
+	orm.RegisterModel(
+		new(report_approve.ReportApproveFlow), // 审批流表
+		new(report_approve.ReportApproveNode), // 审批节点表
+	)
+}

+ 11 - 1
models/report.go

@@ -8,6 +8,16 @@ import (
 	"time"
 )
 
+// 报告状态
+const (
+	ReportStateUnpublished = 1 // 未发布
+	ReportStatePublished   = 2 // 已发布
+	ReportStateWaitSubmit  = 3 // 待提交
+	ReportStateWaitApprove = 4 // 审批中
+	ReportStateRefused     = 5 // 已驳回
+	ReportStatePass        = 6 // 已通过
+)
+
 type Report struct {
 	Id                 int       `orm:"column(id)" description:"报告Id"`
 	AddType            int       `description:"新增方式:1:新增报告,2:继承报告"`
@@ -1049,4 +1059,4 @@ func SetPrePublishReportById(reportId int, prePublishTime string, preMsgSend int
 	sql := `UPDATE report SET pre_publish_time=?, pre_msg_send=? WHERE id = ? and state = 1 `
 	_, err = o.Raw(sql, prePublishTime, preMsgSend, reportId).Exec()
 	return
-}
+}

+ 234 - 90
models/report_approve/report_approve_flow.go

@@ -4,16 +4,23 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"strings"
 	"time"
 )
 
 const (
-	FlowReportTypeChinese = iota + 1
-	FlowReportTypeEnglish
-	FlowReportTypeSmart
+	FlowReportTypeChinese = 1
+	FlowReportTypeEnglish = 2
+	FlowReportTypeSmart   = 3
 )
 
+var FlowReportTypeMap = map[int]string{
+	FlowReportTypeChinese: "中文研报",
+	FlowReportTypeEnglish: "英文研报",
+	FlowReportTypeSmart:   "智能研报",
+}
+
 // ReportApproveFlow 报告审批流表
 type ReportApproveFlow struct {
 	ReportApproveFlowId int       `orm:"column(report_approve_flow_id);pk" description:"审批流ID"`
@@ -26,12 +33,32 @@ type ReportApproveFlow struct {
 	ModifyTime          time.Time `description:"修改时间"`
 }
 
+var ReportApproveFlowCols = struct {
+	ReportApproveFlowId string
+	FlowName            string
+	ReportType          string
+	ClassifyFirstId     string
+	ClassifySecondId    string
+	CurrVersion         string
+	CreateTime          string
+	ModifyTime          string
+}{
+	ReportApproveFlowId: "report_approve_flow_id",
+	FlowName:            "flow_name",
+	ReportType:          "report_type",
+	ClassifyFirstId:     "classify_first_id",
+	ClassifySecondId:    "classify_second_id",
+	CurrVersion:         "curr_version",
+	CreateTime:          "create_time",
+	ModifyTime:          "modify_time",
+}
+
 func (m *ReportApproveFlow) TableName() string {
 	return "report_approve_flow"
 }
 
 func (m *ReportApproveFlow) PrimaryId() string {
-	return "report_approve_flow_id"
+	return ReportApproveFlowCols.ReportApproveFlowId
 }
 
 func (m *ReportApproveFlow) Create() (err error) {
@@ -138,7 +165,7 @@ type ReportApproveFlowItem struct {
 	ReportType          int    `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
 	ClassifyFirstId     int    `description:"一级分类ID"`
 	ClassifySecondId    int    `description:"二级分类ID"`
-	CurrVersion         int    `description:"当前版本号"`
+	ReportClassify      string `description:"报告类型: XX研报/一级分类/二级分类"`
 	CreateTime          string `description:"创建时间"`
 	ModifyTime          string `description:"修改时间"`
 }
@@ -161,95 +188,212 @@ func FormatReportApproveFlow2Item(origin *ReportApproveFlow) (item *ReportApprov
 
 // ReportApproveFlowAddReq 新增报告审批流请求体
 type ReportApproveFlowAddReq struct {
-	FlowName         string `description:"审批流名称"`
-	ReportType       int    `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
-	ClassifyFirstId  int    `description:"一级分类ID"`
-	ClassifySecondId int    `description:"二级分类ID"`
-}
-
-//
-//// ReportApproveFlowEditReq 编辑报告审批流请求体
-//type ReportApproveFlowEditReq struct {
-//	ReportApproveFlowAddReq
-//	ReportApproveFlowId int    `description:"报告审批流ID"`
-//	Content             string `description:"内容"`
-//	ContentStruct       string `description:"内容结构"`
-//}
-//
-//// ReportApproveFlowRemoveReq 删除报告审批流请求体
-//type ReportApproveFlowRemoveReq struct {
-//	ReportApproveFlowId int `description:"报告审批流ID"`
-//}
-//
-//// ReportApproveFlowPublishReq 发布报告审批流请求体
-//type ReportApproveFlowPublishReq struct {
-//	ReportApproveFlowId int `description:"报告审批流ID"`
-//	PublishState        int `description:"1-取消发布; 2-发布"`
-//}
-//
-//// ReportApproveFlowPrePublishReq 预发布报告审批流请求体
-//type ReportApproveFlowPrePublishReq struct {
-//	ReportApproveFlowId int    `description:"报告审批流ID"`
-//	PrePublishTime      string `description:"预发布时间"`
-//	PreMsgSend          int    `description:"定时发布成功后是否立即推送模版消息:0否,1是"`
-//}
-//
-//// ReportApproveFlowSaveContentReq 保存草稿请求体
-//type ReportApproveFlowSaveContentReq struct {
-//	ReportApproveFlowId int    `description:"报告审批流ID"`
-//	Content             string `description:"内容"`
-//	ContentStruct       string `description:"内容结构"`
-//	NoChange            int    `description:"内容是否未改变:1:内容未改变"`
-//}
-//
-//// ReportApproveFlowSaveContentResp 保存草稿响应体
-//type ReportApproveFlowSaveContentResp struct {
-//	ReportApproveFlowId int `description:"报告审批流ID"`
-//}
-//
-//// ReportApproveFlowSendMsgReq 消息推送请求体
-//type ReportApproveFlowSendMsgReq struct {
-//	ReportApproveFlowId int `description:"报告审批流ID"`
-//}
-//
-//// ReportApproveFlowMarkEditReq 标记编辑英文研报的请求数据
-//type ReportApproveFlowMarkEditReq struct {
-//	ReportApproveFlowId int `description:"报告审批流ID"`
-//	Status              int `description:"标记状态: 1-编辑中; 2-编辑完成"`
-//}
-//
-//// ReportApproveFlowListResp 报告审批流
-//type ReportApproveFlowListResp struct {
-//	List   []*ReportApproveFlowItem
-//	Paging *paging.PagingItem `description:"分页数据"`
-//}
-//
-//// ElasticReportApproveFlow 报告审批流es
-//type ElasticReportApproveFlow struct {
-//	ReportApproveFlowId int    `description:"报告审批流ID"`
-//	Title               string `description:"标题"`
-//	Abstract            string `description:"摘要"`
-//	BodyContent         string `description:"内容"`
-//	PublishTime         string `description:"发布时间"`
-//	PublishState        int    `description:"发布状态 1-未发布 2-已发布"`
-//	Author              string `description:"作者"`
-//	ClassifyIdFirst     int    `description:"一级分类ID"`
-//	ClassifyNameFirst   string `description:"一级分类名称"`
-//	ClassifyIdSecond    int    `description:"二级分类ID"`
-//	ClassifyNameSecond  string `description:"二级分类名称"`
-//	StageStr            string `description:"报告期数"`
-//	Frequency           string `description:"频度"`
-//}
-//
-//// Report2ImgQueueReq 报告详情生成长图队列请求体
-//type Report2ImgQueueReq struct {
-//	ReportType int    `description:"报告类型: 1-研报; 2-报告审批流"`
-//	ReportCode string `description:"报告唯一编码"`
-//}
+	FlowName         string                     `description:"审批流名称"`
+	ReportType       int                        `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
+	ClassifyFirstId  int                        `description:"一级分类ID"`
+	ClassifySecondId int                        `description:"二级分类ID"`
+	Nodes            []ReportApproveNodeSaveReq `description:"审批节点信息"`
+}
+
+// ReportApproveFlowEditReq 编辑报告审批流请求体
+type ReportApproveFlowEditReq struct {
+	ReportApproveFlowId int `description:"审批流ID"`
+	ReportApproveFlowAddReq
+}
+
+// ReportApproveFlowRemoveReq 删除报告审批流请求体
+type ReportApproveFlowRemoveReq struct {
+	ReportApproveFlowId int `description:"报告审批流ID"`
+}
 
 type ReportClassifyTreeItem struct {
 	ClassifyId   int                       `description:"分类ID"`
 	ClassifyName string                    `description:"分类名称"`
 	ParentId     int                       `description:"父级ID"`
+	HasFlow      bool                      `description:"是否已配置审批流"`
 	Children     []*ReportClassifyTreeItem `description:"子分类"`
 }
+
+// CreateFlowAndNodes 新增审批流和节点
+func (m *ReportApproveFlow) CreateFlowAndNodes(flowItem *ReportApproveFlow, nodeItems []*ReportApproveNode) (err error) {
+	if flowItem == nil {
+		err = fmt.Errorf("flow is nil")
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	tx, e := o.Begin()
+	if e != nil {
+		err = fmt.Errorf("orm begin err: %s", e.Error())
+		return
+	}
+	prevNodes := make([]*ReportApproveNode, 0)
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+			return
+		}
+		_ = tx.Commit()
+		// 更新每个节点的下一个节点信息, 放在事务中会更新失败
+		if e = m.UpdateNextNodes(prevNodes); e != nil {
+			err = fmt.Errorf("UpdatePrevNodes err: %s", e.Error())
+			return
+		}
+	}()
+
+	lastId, e := tx.Insert(flowItem)
+	if e != nil {
+		err = fmt.Errorf("insert flow err: %s", e.Error())
+		return
+	}
+	flowItem.ReportApproveFlowId = int(lastId)
+
+	nodesLen := len(nodeItems)
+	if nodesLen == 0 {
+		return
+	}
+	prevId := 0
+	prevNode := new(ReportApproveNode)
+	for k, v := range nodeItems {
+		v.ReportApproveFlowId = flowItem.ReportApproveFlowId
+		v.PrevNodeId = prevId
+		id, e := tx.Insert(v)
+		if e != nil {
+			err = fmt.Errorf("insert node err: %s", e.Error())
+			return
+		}
+		v.ReportApproveNodeId = int(id)
+		prevId = v.ReportApproveNodeId
+
+		// 下一个节点
+		if prevNode != nil && k > 0 && k < nodesLen {
+			prevNode.NextNodeId = int(id)
+			prevNodes = append(prevNodes, prevNode)
+		}
+		prevNode = v
+	}
+	return
+}
+
+func (m *ReportApproveFlow) UpdateNextNodes(nodes []*ReportApproveNode) (err error) {
+	if len(nodes) == 0 {
+		return
+	}
+	updateCols := []string{"NextNodeId"}
+	for _, v := range nodes {
+		e := v.Update(updateCols)
+		if e != nil {
+			err = fmt.Errorf("prev node update err: %s", e.Error())
+			return
+		}
+	}
+	return
+}
+
+// UpdateFlowAndNodes 更新审批流和节点
+func (m *ReportApproveFlow) UpdateFlowAndNodes(flowItem *ReportApproveFlow, nodeItems []*ReportApproveNode) (err error) {
+	if flowItem == nil {
+		err = fmt.Errorf("flow is nil")
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	tx, e := o.Begin()
+	if e != nil {
+		err = fmt.Errorf("orm begin err: %s", e.Error())
+		return
+	}
+	prevNodes := make([]*ReportApproveNode, 0)
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+			return
+		}
+		_ = tx.Commit()
+		// 更新每个节点的下一个节点信息, 放在事务中会更新失败
+		if e = m.UpdateNextNodes(prevNodes); e != nil {
+			err = fmt.Errorf("UpdatePrevNodes err: %s", e.Error())
+			return
+		}
+	}()
+
+	// 更新审批流
+	updateCols := []string{"FlowName", "ReportType", "ClassifyFirstId", "ClassifySecondId", "CurrVersion", "ModifyTime"}
+	if e = flowItem.Update(updateCols); e != nil {
+		err = fmt.Errorf("update flow err: %s", e.Error())
+		return
+	}
+
+	// 新增节点(旧版的节点不删除, 根据版本号区分)
+	nodesLen := len(nodeItems)
+	if nodesLen == 0 {
+		return
+	}
+	prevId := 0
+	prevNode := new(ReportApproveNode)
+	for k, v := range nodeItems {
+		v.ReportApproveFlowId = flowItem.ReportApproveFlowId
+		v.PrevNodeId = prevId
+		id, e := tx.Insert(v)
+		if e != nil {
+			err = fmt.Errorf("insert node err: %s", e.Error())
+			return
+		}
+		v.ReportApproveNodeId = int(id)
+		prevId = v.ReportApproveNodeId
+
+		// 下一个节点
+		if prevNode != nil && k > 0 && k < nodesLen {
+			prevNode.NextNodeId = int(id)
+			prevNodes = append(prevNodes, prevNode)
+		}
+		prevNode = v
+	}
+	return
+}
+
+// ReportApproveDetailItem 报告审批流详情信息
+type ReportApproveDetailItem struct {
+	ReportApproveFlowItem `description:"审批流信息"`
+	Nodes                 []*ReportApproveNodeItem `description:"节点信息"`
+}
+
+// FormatFlowAndNodesItem2Detail 格式化审批流详情
+func FormatFlowAndNodesItem2Detail(flowItem *ReportApproveFlow, nodeItems []*ReportApproveNode) (detail *ReportApproveDetailItem, err error) {
+	if flowItem == nil {
+		return
+	}
+	detail = new(ReportApproveDetailItem)
+	detail.ReportApproveFlowId = flowItem.ReportApproveFlowId
+	detail.FlowName = flowItem.FlowName
+	detail.ReportType = flowItem.ReportType
+	detail.ClassifyFirstId = flowItem.ClassifyFirstId
+	detail.ClassifySecondId = flowItem.ClassifySecondId
+	detail.CreateTime = utils.TimeTransferString(utils.FormatDateTime, flowItem.CreateTime)
+	detail.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, flowItem.ModifyTime)
+	detail.Nodes = make([]*ReportApproveNodeItem, 0)
+	for _, v := range nodeItems {
+		t, e := FormatReportApproveNode2Item(v)
+		if e != nil {
+			err = fmt.Errorf("format node err: %s", e.Error())
+			return
+		}
+		detail.Nodes = append(detail.Nodes, t)
+	}
+	return
+}
+
+// ReportApproveFlowListReq 审批流列表请求体
+type ReportApproveFlowListReq struct {
+	PageSize         int    `form:"PageSize"`
+	CurrentIndex     int    `form:"CurrentIndex"`
+	ReportType       int    `form:"ReportType" description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
+	ClassifyFirstId  int    `form:"ClassifyFirstId" description:"一级分类ID"`
+	ClassifySecondId int    `form:"ClassifySecondId" description:"二级分类ID"`
+	Keyword          string `form:"Keyword" description:"关键词"`
+	SortRule         int    `form:"SortRule" description:"排序方式: 1-正序; 2-倒序(默认)"`
+}
+
+// ReportApproveFlowListResp 审批流列表响应体
+type ReportApproveFlowListResp struct {
+	List   []*ReportApproveFlowItem
+	Paging *paging.PagingItem `description:"分页数据"`
+}

+ 73 - 109
models/report_approve/report_approve_node.go

@@ -1,6 +1,7 @@
 package report_approve
 
 import (
+	"encoding/json"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
@@ -9,9 +10,14 @@ import (
 )
 
 const (
-	NodeApproveTypeRoll = iota + 1
-	NodeApproveTypeAll
-	NodeApproveTypeAny
+	NodeApproveTypeRoll = 1
+	NodeApproveTypeAll  = 2
+	NodeApproveTypeAny  = 3
+)
+
+const (
+	NodeUserTypeNormal = "user"
+	NodeUserTypeRole   = "role"
 )
 
 // ReportApproveNode 报告审批节点表
@@ -22,11 +28,33 @@ type ReportApproveNode struct {
 	NextNodeId          int       `description:"下一个节点ID(0为结束节点)"`
 	NodeType            int       `description:"节点类型:0-审批;1-抄送"`
 	ApproveType         int       `description:"审批类型:1-依次审批;2-会签;3-或签"`
-	users               string    `description:"审批人信息-JSON,user_type:user-用户;role-角色,user_id:用户/角色ID"`
+	Users               string    `description:"审批人信息-JSON,user_type:user-用户;role-角色,user_id:用户/角色ID"`
 	CurrVersion         int       `description:"当前版本号"`
 	CreateTime          time.Time `description:"创建时间"`
 }
 
+var ReportApproveNodeCols = struct {
+	ReportApproveNodeId string
+	ReportApproveFlowId string
+	PrevNodeId          string
+	NextNodeId          string
+	NodeType            string
+	ApproveType         string
+	Users               string
+	CurrVersion         string
+	CreateTime          string
+}{
+	ReportApproveNodeId: "report_approve_node_id",
+	ReportApproveFlowId: "report_approve_flow_id",
+	PrevNodeId:          "prev_node_id",
+	NextNodeId:          "next_node_id",
+	NodeType:            "node_type",
+	ApproveType:         "approve_type",
+	Users:               "users",
+	CurrVersion:         "curr_version",
+	CreateTime:          "create_time",
+}
+
 func (m *ReportApproveNode) TableName() string {
 	return "report_approve_node"
 }
@@ -108,7 +136,7 @@ func (m *ReportApproveNode) GetItemsByCondition(condition string, pars []interfa
 	if len(fieldArr) == 0 {
 		fields = `*`
 	}
-	order := `ORDER BY create_time DESC`
+	order := `ORDER BY create_time DESC, report_approve_node_id ASC`
 	if orderRule != "" {
 		order = ` ORDER BY ` + orderRule
 	}
@@ -132,114 +160,50 @@ func (m *ReportApproveNode) GetPageItemsByCondition(condition string, pars []int
 	return
 }
 
-// ReportApproveNodeItem 报告审批节点信息
+// ReportApproveNodeSaveReq 报告审批节点保存请求体
+type ReportApproveNodeSaveReq struct {
+	ApproveType int                        `description:"审批类型:1-依次审批;2-会签;3-或签"`
+	Users       []ReportApproveNodeUserReq `description:"审批人信息"`
+}
+
+// ReportApproveNodeUserReq 报告审批节点用户请求体
+type ReportApproveNodeUserReq struct {
+	UserType string `description:"审批人类型: user-用户; role-角色"`
+	UserId   int    `description:"用户/角色ID"`
+	UserName string `description:"用户/角色姓名"`
+	Sort     int    `description:"排序"`
+}
+
+// ReportApproveNodeItem 报告审批节点详情信息
 type ReportApproveNodeItem struct {
-	ReportApproveNodeId int    `orm:"column(report_approve_node_id);pk" description:"报告审批节点ID"`
-	ReportApproveFlowId int    `description:"报告审批流ID"`
-	PrevNodeId          int    `description:"上一个节点ID(0为开始节点)"`
-	NextNodeId          int    `description:"下一个节点ID(0为结束节点)"`
-	NodeType            int    `description:"节点类型:0-审批;1-抄送"`
-	ApproveType         int    `description:"审批类型:1-依次审批;2-会签;3-或签"`
-	users               string `description:"审批人信息-JSON,user_type:user-用户;role-角色,user_id:用户/角色ID"`
-	CurrVersion         int    `description:"当前版本号"`
-	CreateTime          string `description:"创建时间"`
-}
-
-// FormatReportApproveNode2Item 格式化报告审批节点
-func FormatReportApproveNode2Item(origin *ReportApproveNode) (item *ReportApproveNodeItem) {
-	item = new(ReportApproveNodeItem)
+	ReportApproveNodeId int                         `description:"报告审批节点ID"`
+	ReportApproveFlowId int                         `description:"报告审批流ID"`
+	PrevNodeId          int                         `description:"上一个节点ID(0为开始节点)"`
+	NextNodeId          int                         `description:"下一个节点ID(0为结束节点)"`
+	NodeType            int                         `description:"节点类型:0-审批;1-抄送"`
+	ApproveType         int                         `description:"审批类型:1-依次审批;2-会签;3-或签"`
+	Users               []*ReportApproveNodeUserReq `description:"审批人信息"`
+}
+
+// FormatReportApproveNode2Item 格式化报告审批节点信息
+func FormatReportApproveNode2Item(origin *ReportApproveNode) (item *ReportApproveNodeItem, err error) {
 	if origin == nil {
 		return
 	}
+	item = new(ReportApproveNodeItem)
 	item.ReportApproveNodeId = origin.ReportApproveNodeId
-	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
+	item.ReportApproveFlowId = origin.ReportApproveFlowId
+	item.PrevNodeId = origin.PrevNodeId
+	item.NextNodeId = origin.NextNodeId
+	item.NodeType = origin.NodeType
+	item.ApproveType = origin.ApproveType
+	item.Users = make([]*ReportApproveNodeUserReq, 0)
+	if origin.Users != "" {
+		e := json.Unmarshal([]byte(origin.Users), &item.Users)
+		if e != nil {
+			err = fmt.Errorf("node users unmarshal err: %s", e.Error())
+			return
+		}
+	}
 	return
 }
-
-// ReportApproveNodeAddReq 新增报告审批节点请求体
-type ReportApproveNodeAddReq struct {
-	FlowName         string `description:"审批流名称"`
-	ReportType       int    `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
-	ClassifyFirstId  int    `description:"一级分类ID"`
-	ClassifySecondId int    `description:"二级分类ID"`
-}
-
-//
-//// ReportApproveNodeEditReq 编辑报告审批节点请求体
-//type ReportApproveNodeEditReq struct {
-//	ReportApproveNodeAddReq
-//	ReportApproveNodeId int    `description:"报告审批节点ID"`
-//	Content             string `description:"内容"`
-//	ContentStruct       string `description:"内容结构"`
-//}
-//
-//// ReportApproveNodeRemoveReq 删除报告审批节点请求体
-//type ReportApproveNodeRemoveReq struct {
-//	ReportApproveNodeId int `description:"报告审批节点ID"`
-//}
-//
-//// ReportApproveNodePublishReq 发布报告审批节点请求体
-//type ReportApproveNodePublishReq struct {
-//	ReportApproveNodeId int `description:"报告审批节点ID"`
-//	PublishState        int `description:"1-取消发布; 2-发布"`
-//}
-//
-//// ReportApproveNodePrePublishReq 预发布报告审批节点请求体
-//type ReportApproveNodePrePublishReq struct {
-//	ReportApproveNodeId int    `description:"报告审批节点ID"`
-//	PrePublishTime      string `description:"预发布时间"`
-//	PreMsgSend          int    `description:"定时发布成功后是否立即推送模版消息:0否,1是"`
-//}
-//
-//// ReportApproveNodeSaveContentReq 保存草稿请求体
-//type ReportApproveNodeSaveContentReq struct {
-//	ReportApproveNodeId int    `description:"报告审批节点ID"`
-//	Content             string `description:"内容"`
-//	ContentStruct       string `description:"内容结构"`
-//	NoChange            int    `description:"内容是否未改变:1:内容未改变"`
-//}
-//
-//// ReportApproveNodeSaveContentResp 保存草稿响应体
-//type ReportApproveNodeSaveContentResp struct {
-//	ReportApproveNodeId int `description:"报告审批节点ID"`
-//}
-//
-//// ReportApproveNodeSendMsgReq 消息推送请求体
-//type ReportApproveNodeSendMsgReq struct {
-//	ReportApproveNodeId int `description:"报告审批节点ID"`
-//}
-//
-//// ReportApproveNodeMarkEditReq 标记编辑英文研报的请求数据
-//type ReportApproveNodeMarkEditReq struct {
-//	ReportApproveNodeId int `description:"报告审批节点ID"`
-//	Status              int `description:"标记状态: 1-编辑中; 2-编辑完成"`
-//}
-//
-//// ReportApproveNodeListResp 报告审批节点
-//type ReportApproveNodeListResp struct {
-//	List   []*ReportApproveNodeItem
-//	Paging *paging.PagingItem `description:"分页数据"`
-//}
-//
-//// ElasticReportApproveNode 报告审批节点es
-//type ElasticReportApproveNode struct {
-//	ReportApproveNodeId int    `description:"报告审批节点ID"`
-//	Title               string `description:"标题"`
-//	Abstract            string `description:"摘要"`
-//	BodyContent         string `description:"内容"`
-//	PublishTime         string `description:"发布时间"`
-//	PublishState        int    `description:"发布状态 1-未发布 2-已发布"`
-//	Author              string `description:"作者"`
-//	ClassifyIdFirst     int    `description:"一级分类ID"`
-//	ClassifyNameFirst   string `description:"一级分类名称"`
-//	ClassifyIdSecond    int    `description:"二级分类ID"`
-//	ClassifyNameSecond  string `description:"二级分类名称"`
-//	StageStr            string `description:"报告期数"`
-//	Frequency           string `description:"频度"`
-//}
-//
-//// Report2ImgQueueReq 报告详情生成长图队列请求体
-//type Report2ImgQueueReq struct {
-//	ReportType int    `description:"报告类型: 1-研报; 2-报告审批节点"`
-//	ReportCode string `description:"报告唯一编码"`
-//}

+ 54 - 0
routers/commentsRouter.go

@@ -4363,6 +4363,60 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"],
+        beego.ControllerComments{
+            Method: "Edit",
+            Router: `/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"],
+        beego.ControllerComments{
+            Method: "Remove",
+            Router: `/remove`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveFlowController"],
+        beego.ControllerComments{
+            Method: "ReportClassifyTree",
+            Router: `/report/classify_tree`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/roadshow:CalendarController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/roadshow:CalendarController"],
         beego.ControllerComments{
             Method: "ResearcherList",

+ 6 - 0
routers/router.go

@@ -18,6 +18,7 @@ import (
 	"eta/eta_api/controllers/data_manage/supply_analysis"
 	"eta/eta_api/controllers/english_report"
 	"eta/eta_api/controllers/eta_trial"
+	"eta/eta_api/controllers/report_approve"
 	"eta/eta_api/controllers/roadshow"
 	"eta/eta_api/controllers/sandbox"
 	"eta/eta_api/controllers/semantic_analysis"
@@ -305,6 +306,11 @@ func init() {
 				&smart_report.SmartReportController{},
 			),
 		),
+		web.NSNamespace("/report_approve",
+			web.NSInclude(
+				&report_approve.ReportApproveFlowController{},
+			),
+		),
 	)
 	web.AddNamespace(ns)
 }

+ 41 - 0
services/report_approve.go

@@ -3,6 +3,8 @@ package services
 import (
 	"eta/eta_api/models"
 	"eta/eta_api/models/report_approve"
+	"eta/eta_api/models/smart_report"
+	"fmt"
 )
 
 // GetReportClassifyTreeRecursive 递归获取报告分类树
@@ -20,3 +22,42 @@ func GetReportClassifyTreeRecursive(list []*models.Classify, parentId int) []*re
 	}
 	return res
 }
+
+// CheckReportApproveFlowChange 校验是否可变更分类
+func CheckReportApproveFlowChange(reportType, classifyFirstId, classifySecondId int) (ok bool, err error) {
+	var count int
+	cond := ` AND classify_first_id = ? AND classify_second_id = ? AND state = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, classifyFirstId, classifySecondId, models.ReportStateWaitApprove)
+	switch reportType {
+	case report_approve.FlowReportTypeChinese:
+		ct, e := models.GetReportListCount(cond, pars, "")
+		if e != nil {
+			err = fmt.Errorf("GetReportListCount err: %s", e.Error())
+			return
+		}
+		count = ct
+	case report_approve.FlowReportTypeEnglish:
+		ct, e := models.GetEnglishReportListCount(cond, pars, "")
+		if e != nil {
+			err = fmt.Errorf("GetEnglishReportListCount err: %s", e.Error())
+			return
+		}
+		count = ct
+	case report_approve.FlowReportTypeSmart:
+		ob := new(smart_report.SmartReport)
+		ct, e := ob.GetCountByCondition(cond, pars)
+		if e != nil {
+			err = fmt.Errorf("SmartReport GetCountByCondition err: %s", e.Error())
+			return
+		}
+		count = ct
+	default:
+		err = fmt.Errorf("报告类型有误")
+		return
+	}
+	if count <= 0 {
+		ok = true
+	}
+	return
+}