Browse Source

报告审批列表部分接口

hsun 1 year ago
parent
commit
2b7f28e88b

+ 191 - 2
controllers/report.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"eta/eta_api/models"
 	"eta/eta_api/models/company"
+	"eta/eta_api/models/report_approve"
 	"eta/eta_api/services"
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/utils"
@@ -508,7 +509,13 @@ func (this *ReportController) Add() {
 		return
 	}
 
-	// TODO:根据审批开关及对应分类审批流判断当前报告初始状态
+	// 根据审批开关及审批流判断当前报告状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeChinese, req.ClassifyIdFirst, req.ClassifyIdSecond, models.ReportOperateAdd)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
+		return
+	}
 
 	item := new(models.Report)
 	item.AddType = req.AddType
@@ -520,7 +527,7 @@ func (this *ReportController) Add() {
 	item.Abstract = req.Abstract
 	item.Author = req.Author
 	item.Frequency = req.Frequency
-	item.State = req.State
+	item.State = state
 	item.Content = html.EscapeString(req.Content)
 	item.Stage = maxStage + 1
 	item.ContentSub = html.EscapeString(contentSub)
@@ -3348,3 +3355,185 @@ func (this *ReportController) PrePublishReport() {
 	br.Success = true
 	br.Msg = "定时发布成功"
 }
+
+// SubmitApprove
+// @Title 提交审批
+// @Description 提交审批接口
+// @Param	request	body models.ReportSubmitApproveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /approve/submit [post]
+func (this *ReportController) SubmitApprove() {
+	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"
+		return
+	}
+	var req models.ReportSubmitApproveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	reportId := req.ReportId
+	if reportId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportId: %d", req.ReportId)
+		return
+	}
+
+	reportOb := new(models.Report)
+	reportItem, e := reportOb.GetItemById(reportId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验当前审批配置, 返回下一个状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeChinese, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateSubmitApprove)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	// 下一个状态不为待审批时, 仅更新状态
+	if state != models.ReportStateWaitApprove {
+		reportItem.State = state
+		e = reportItem.UpdateReport([]string{"State"})
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+
+	// 提交审批
+	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeChinese, reportItem.Id, reportItem.Title, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "提交审批失败, Err: " + e.Error()
+		return
+	}
+	reportItem.ApproveId = approveId
+	reportItem.State = models.ReportStateWaitApprove
+	reportItem.ModifyTime = time.Now().Local()
+	e = reportItem.UpdateReport([]string{"ApproveId", "State", "ModifyTime"})
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// CancelApprove
+// @Title 撤销审批
+// @Description 撤销审批
+// @Param	request	body models.ReportCancelApproveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /approve/cancel [post]
+func (this *ReportController) CancelApprove() {
+	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"
+		return
+	}
+	var req models.ReportCancelApproveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	reportId := req.ReportId
+	if reportId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportId: %d", req.ReportId)
+		return
+	}
+
+	reportOb := new(models.Report)
+	reportItem, e := reportOb.GetItemById(reportId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验当前审批配置, 返回下一个状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeChinese, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateCancelApprove)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	// 下一个状态不为待提交时, 仅更新状态
+	if state != models.ReportStateWaitSubmit {
+		reportItem.State = state
+		e = reportItem.UpdateReport([]string{"State"})
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+
+	// 撤销审批
+	e = services.CancelReportApprove(reportItem.ApproveId, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "撤销审批失败, Err: " + e.Error()
+		return
+	}
+	reportItem.ApproveId = 0
+	reportItem.State = models.ReportStateWaitSubmit
+	reportItem.ModifyTime = time.Now().Local()
+	e = reportItem.UpdateReport([]string{"ApproveId", "State", "ModifyTime"})
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 627 - 0
controllers/report_approve/report_approve.go

@@ -1 +1,628 @@
 package report_approve
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/report_approve"
+	"eta/eta_api/models/smart_report"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"html"
+	"strings"
+	"time"
+)
+
+// ReportApproveController 报告审批
+type ReportApproveController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 审批列表
+// @Description 审批列表
+// @Param   PageSize			query	int		true	"每页数据条数"
+// @Param   CurrentIndex		query	int		true	"当前页页码"
+// @Param   ListType			query   int     true	"列表类型:1-待处理;2-已处理;3-我发起的"
+// @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   ApproveState		query	int		false	"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"
+// @Param   TimeType			query	int		false	"时间类型:1-提交时间;2-处理时间;3-审批时间"
+// @Param   StartTime			query	string	false	"开始时间"
+// @Param   EndTime				query	string	false	"结束时间"
+// @Param   SortField			query	int		false	"排序字段:1-提交时间;2-处理时间;3-审批时间"
+// @Param   SortRule			query	int		false	"排序方式: 1-正序; 2-倒序(默认)"
+// @Success 200 {object} report_approve.ReportApproveListResp
+// @router /list [get]
+func (this *ReportApproveController) 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.ReportApproveListReq)
+	if e := this.ParseForm(params); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "入参解析失败, Err: " + e.Error()
+		return
+	}
+	if params.ListType != 1 && params.ListType != 2 && params.ListType != 3 {
+		br.Msg = "列表类型有误"
+		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
+	}
+	enRootIdMap := make(map[int]int) // 英文分类的一级分类ID
+	for _, v := range enClassify {
+		enClassifyIdName[v.Id] = v.ClassifyName
+		enRootIdMap[v.Id] = v.RootId
+	}
+
+	// 分页
+	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)
+
+	resp := new(report_approve.ReportApproveListResp)
+	respTotal := 0
+	respList := make([]*report_approve.ReportApproveItem, 0)
+	timeField := map[int]string{1: fmt.Sprintf("a.%s", report_approve.ReportApproveCols.CreateTime), 2: fmt.Sprintf("b.%s", report_approve.ReportApproveRecordCols.ApproveTime), 3: fmt.Sprintf("b.%s", report_approve.ReportApproveCols.ApproveTime)}
+	orderRules := map[int]string{1: "ASC", 2: "DESC"}
+	ormList := make([]*report_approve.ReportApproveItemOrm, 0)
+
+	// 待处理
+	if params.ListType == 1 {
+		cond := fmt.Sprintf(` AND a.%s = ? AND b.%s = ? AND b.%s = ?`, report_approve.ReportApproveCols.State, report_approve.ReportApproveRecordCols.ApproveUserId, report_approve.ReportApproveRecordCols.State)
+		pars := make([]interface{}, 0)
+		pars = append(pars, report_approve.ReportApproveStateApproving, sysUser.AdminId, report_approve.ReportApproveStateApproving)
+		order := ""
+
+		// 筛选条件
+		if params.ReportType > 0 && params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ? AND a.%s = ?`, report_approve.ReportApproveCols.ReportType, report_approve.ReportApproveCols.ClassifySecondId)
+			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		}
+		if params.TimeType <= 0 {
+			params.TimeType = 1
+		}
+		if params.TimeType == 1 && params.StartTime != "" && params.EndTime != "" {
+			_, e := time.Parse(utils.FormatDate, params.StartTime)
+			if e != nil {
+				br.Msg = "开始时间格式有误"
+				return
+			}
+			_, e = time.Parse(utils.FormatDate, params.EndTime)
+			if e != nil {
+				br.Msg = "结束时间格式有误"
+				return
+			}
+			st := fmt.Sprintf("%s %s", params.StartTime, "00:00:00")
+			ed := fmt.Sprintf("%s %s", params.EndTime, "23:59:59")
+			cond += fmt.Sprintf(` AND (a.%s BETWEEN ? AND ?)`, report_approve.ReportApproveCols.CreateTime)
+			pars = append(pars, st, ed)
+		}
+		params.Keyword = strings.TrimSpace(params.Keyword)
+		if params.Keyword != "" {
+			kw := fmt.Sprint("%", params.Keyword, "%")
+			cond += fmt.Sprintf(` AND a.%s LIKE ?`, report_approve.ReportApproveCols.ReportTitle)
+			pars = append(pars, kw)
+		}
+		if params.SortField > 0 && params.SortRule > 0 {
+			orderField := timeField[params.SortField]
+			if orderField == "" {
+				br.Msg = "时间排序字段有误"
+				return
+			}
+			orderRule := orderRules[params.SortRule]
+			if orderRule == "" {
+				br.Msg = "时间排序方式有误"
+				return
+			}
+			order = fmt.Sprintf("%s %s", orderField, orderRule)
+		}
+		total, e := report_approve.GetApprovingReportApproveCount(cond, pars)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApprovingReportApproveCount err: " + e.Error()
+			return
+		}
+		respTotal = total
+		list, e := report_approve.GetApprovingReportApprovePageList(cond, pars, order, startSize, params.PageSize)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApprovingReportApprovePageList err: " + e.Error()
+			return
+		}
+		ormList = list
+	}
+
+	// 已处理
+	if params.ListType == 2 {
+		cond := fmt.Sprintf(` AND b.%s = ? AND b.%s IN (%s)`, report_approve.ReportApproveRecordCols.ApproveUserId, report_approve.ReportApproveRecordCols.State, utils.GetOrmInReplace(2))
+		pars := make([]interface{}, 0)
+		pars = append(pars, sysUser.AdminId, []int{report_approve.ReportApproveStatePass, report_approve.ReportApproveStateRefuse})
+		order := ""
+
+		// 筛选条件
+		if params.ReportType > 0 && params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ? AND a.%s = ?`, report_approve.ReportApproveCols.ReportType, report_approve.ReportApproveCols.ClassifySecondId)
+			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		}
+		if params.TimeType > 0 && params.StartTime != "" && params.EndTime != "" {
+			_, e := time.Parse(utils.FormatDate, params.StartTime)
+			if e != nil {
+				br.Msg = "开始时间格式有误"
+				return
+			}
+			_, e = time.Parse(utils.FormatDate, params.EndTime)
+			if e != nil {
+				br.Msg = "结束时间格式有误"
+				return
+			}
+			st := fmt.Sprintf("%s %s", params.StartTime, "00:00:00")
+			ed := fmt.Sprintf("%s %s", params.EndTime, "23:59:59")
+			cond += fmt.Sprintf(` AND (a.%s BETWEEN ? AND ?)`, timeField[params.TimeType])
+			pars = append(pars, st, ed)
+		}
+		params.Keyword = strings.TrimSpace(params.Keyword)
+		if params.Keyword != "" {
+			kw := fmt.Sprint("%", params.Keyword, "%")
+			cond += fmt.Sprintf(` AND a.%s LIKE ?`, report_approve.ReportApproveCols.ReportTitle)
+			pars = append(pars, kw)
+		}
+		if params.SortField > 0 && params.SortRule > 0 {
+			orderField := timeField[params.SortField]
+			if orderField == "" {
+				br.Msg = "时间排序字段有误"
+				return
+			}
+			orderRule := orderRules[params.SortRule]
+			if orderRule == "" {
+				br.Msg = "时间排序方式有误"
+				return
+			}
+			order = fmt.Sprintf("%s %s", orderField, orderRule)
+		}
+		if params.ApproveState > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveRecordCols.State)
+			pars = append(pars, params.ApproveState)
+		}
+		total, e := report_approve.GetApprovedReportApproveCount(cond, pars)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApprovedReportApproveCount err: " + e.Error()
+			return
+		}
+		respTotal = total
+		list, e := report_approve.GetApprovedReportApprovePageList(cond, pars, order, startSize, params.PageSize)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApprovedReportApprovePageList err: " + e.Error()
+			return
+		}
+		ormList = list
+	}
+
+	// 我发起的
+	if params.ListType == 3 {
+		cond := fmt.Sprintf(` AND a.%s = ?`, report_approve.ReportApproveCols.ApplyUserId)
+		pars := make([]interface{}, 0)
+		pars = append(pars, sysUser.AdminId)
+		order := ""
+
+		// 筛选条件
+		if params.ReportType > 0 && params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ? AND a.%s = ?`, report_approve.ReportApproveCols.ReportType, report_approve.ReportApproveCols.ClassifySecondId)
+			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		}
+		if params.TimeType > 0 && params.StartTime != "" && params.EndTime != "" {
+			_, e := time.Parse(utils.FormatDate, params.StartTime)
+			if e != nil {
+				br.Msg = "开始时间格式有误"
+				return
+			}
+			_, e = time.Parse(utils.FormatDate, params.EndTime)
+			if e != nil {
+				br.Msg = "结束时间格式有误"
+				return
+			}
+			st := fmt.Sprintf("%s %s", params.StartTime, "00:00:00")
+			ed := fmt.Sprintf("%s %s", params.EndTime, "23:59:59")
+			cond += fmt.Sprintf(` AND (a.%s BETWEEN ? AND ?)`, timeField[params.TimeType])
+			pars = append(pars, st, ed)
+		}
+		params.Keyword = strings.TrimSpace(params.Keyword)
+		if params.Keyword != "" {
+			kw := fmt.Sprint("%", params.Keyword, "%")
+			cond += fmt.Sprintf(` AND a.%s LIKE ?`, report_approve.ReportApproveCols.ReportTitle)
+			pars = append(pars, kw)
+		}
+		if params.SortField > 0 && params.SortRule > 0 {
+			orderField := timeField[params.SortField]
+			if orderField == "" {
+				br.Msg = "时间排序字段有误"
+				return
+			}
+			orderRule := orderRules[params.SortRule]
+			if orderRule == "" {
+				br.Msg = "时间排序方式有误"
+				return
+			}
+			order = fmt.Sprintf("%s %s", orderField, orderRule)
+		}
+		if params.ApproveState > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveRecordCols.State)
+			pars = append(pars, params.ApproveState)
+		}
+		total, e := report_approve.GetApplyReportApproveCount(cond, pars)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApplyReportApproveCount err: " + e.Error()
+			return
+		}
+		respTotal = total
+		list, e := report_approve.GetApplyReportApprovePageList(cond, pars, order, startSize, params.PageSize)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApplyReportApprovePageList err: " + e.Error()
+			return
+		}
+		ormList = list
+	}
+
+	// 格式化列表
+	for _, v := range ormList {
+		t := report_approve.FormatReportApproveOrm2Item(v)
+		if v.ReportType == report_approve.FlowReportTypeEnglish {
+			t.ReportClassify = fmt.Sprintf("%s/%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], enClassifyIdName[enRootIdMap[v.ClassifySecondId]], 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])
+		}
+		respList = append(respList, t)
+	}
+
+	page := paging.GetPaging(params.CurrentIndex, params.PageSize, respTotal)
+	resp.Paging = page
+	resp.List = respList
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Detail
+// @Title 审批详情
+// @Description 审批详情
+// @Param   ReportApproveId  query  int  true  "审批ID"
+// @Success 200 {object} report_approve.ReportApproveListResp
+// @router /detail [get]
+func (this *ReportApproveController) 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
+	}
+	approveId, _ := this.GetInt("ReportApproveId")
+	if approveId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveId: %d", approveId)
+		return
+	}
+
+	approveOb := new(report_approve.ReportApprove)
+	approveItem, e := approveOb.GetItemById(approveId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批失败, Err: " + e.Error()
+		return
+	}
+
+	// 审批信息
+	detail := new(report_approve.ReportApproveDetail)
+	detail.Approve = new(report_approve.ReportApproveDetailItem)
+	detail.Approve.ReportApproveId = approveItem.ReportApproveId
+	detail.Approve.State = approveItem.State
+	detail.Approve.FlowId = approveItem.FlowId
+	detail.Approve.FlowVersion = approveItem.FlowVersion
+	detail.Approve.StartNodeId = approveItem.StartNodeId
+	detail.Approve.CurrNodeId = approveItem.CurrNodeId
+	detail.Approve.ApplyUserId = approveItem.ApplyUserId
+	detail.Approve.ApplyUserName = approveItem.ApplyUserName
+	detail.Approve.ApproveTime = utils.TimeTransferString(utils.FormatDateTime, approveItem.ApproveTime)
+	detail.Approve.CreateTime = utils.TimeTransferString(utils.FormatDateTime, approveItem.CreateTime)
+	detail.Approve.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, approveItem.ModifyTime)
+
+	// 审批流
+	//flowOb := new(report_approve.ReportApproveFlow)
+	//flowItem, e := flowOb.GetItemById(approveItem.FlowId)
+	//if e != nil {
+	//	if e.Error() == utils.ErrNoRow() {
+	//		br.Msg = "审批流已被删除, 请刷新页面"
+	//		return
+	//	}
+	//	br.Msg = "获取失败"
+	//	br.ErrMsg = "获取审批流失败, Err: " + e.Error()
+	//	return
+	//}
+	//detail.ApproveFlow = report_approve.FormatReportApproveFlow2Item(flowItem)
+
+	// 审批节点
+	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, approveItem.FlowId, approveItem.FlowVersion)
+	nodeItems, e := nodeOb.GetItemsByCondition(nodeCond, nodePars, []string{}, "")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批节点失败, Err: " + e.Error()
+		return
+	}
+
+	// 审批记录
+	recordOb := new(report_approve.ReportApproveRecord)
+	recordCond := fmt.Sprintf(` AND %s = ?`, report_approve.ReportApproveRecordCols.ReportApproveId)
+	recordPars := make([]interface{}, 0)
+	recordPars = append(recordPars, approveItem.ReportApproveId)
+	recordItems, e := recordOb.GetItemsByCondition(recordCond, recordPars, []string{}, fmt.Sprintf("%s DESC", report_approve.ReportApproveRecordCols.ApproveTime))
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批记录失败, Err: " + e.Error()
+		return
+	}
+	recordMap := make(map[string]*report_approve.ReportApproveRecord)
+	for _, v := range recordItems {
+		k := fmt.Sprintf("%d-%d", v.NodeId, v.ApproveUserId)
+		recordMap[k] = v
+	}
+
+	// 审批流节点详情
+	detail.ApproveFlowNodes = make([]*report_approve.ReportApproveDetailNodes, 0)
+	for _, v := range nodeItems {
+		t := new(report_approve.ReportApproveDetailNodes)
+		t.ReportApproveNodeId = v.ReportApproveNodeId
+		t.ReportApproveFlowId = v.ReportApproveFlowId
+		t.PrevNodeId = v.PrevNodeId
+		t.NextNodeId = v.NextNodeId
+		t.NodeType = v.NodeType
+		t.ApproveType = v.ApproveType
+		t.Users = make([]*report_approve.ReportApproveDetailNodeUser, 0)
+		us := make([]*report_approve.ReportApproveNodeUserReq, 0)
+		if v.Users != "" {
+			e = json.Unmarshal([]byte(v.Users), &us)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "节点用户解析失败, Err: " + e.Error()
+				return
+			}
+		}
+		for _, vu := range us {
+			u := new(report_approve.ReportApproveDetailNodeUser)
+			u.UserType = vu.UserType
+			u.UserId = vu.UserId
+			u.UserName = vu.UserName
+			u.Sort = vu.Sort
+			// 审批记录
+			k := fmt.Sprintf("%d-%d", v.ReportApproveNodeId, vu.UserId)
+			r := recordMap[k]
+			if r != nil {
+				u.ApproveRecord = new(report_approve.ReportApproveDetailNodeUserRecord)
+				u.ApproveRecord.State = r.State
+				u.ApproveRecord.ApproveUserId = r.ApproveUserId
+				u.ApproveRecord.ApproveUserName = r.ApproveUserName
+				u.ApproveRecord.ApproveRemark = r.ApproveRemark
+				u.ApproveRecord.ApproveTime = utils.TimeTransferString(utils.FormatDateTime, r.ApproveTime)
+			}
+			t.Users = append(t.Users, u)
+		}
+		detail.ApproveFlowNodes = append(detail.ApproveFlowNodes, t)
+	}
+
+	// 报告信息
+	detail.Report = new(report_approve.ReportApproveDetailReport)
+	detail.Report.ReportType = approveItem.ReportType
+	detail.Report.ReportId = approveItem.ReportId
+	if approveItem.ReportType == report_approve.FlowReportTypeChinese {
+		rp, e := models.GetReportById(approveItem.ReportId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "报告已被删除, 请刷新页面"
+				return
+			}
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取中文研报失败, Err: " + e.Error()
+			return
+		}
+		detail.Report.ReportTitle = rp.Title
+		detail.Report.ClassifyFirstId = rp.ClassifyIdFirst
+		detail.Report.ClassifySecondId = rp.ClassifyIdSecond
+		detail.Report.Content = html.UnescapeString(rp.Content)
+	}
+	if approveItem.ReportType == report_approve.FlowReportTypeEnglish {
+		rp, e := models.GetEnglishReportById(approveItem.ReportId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "报告已被删除, 请刷新页面"
+				return
+			}
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取英文研报失败, Err: " + e.Error()
+			return
+		}
+		detail.Report.ReportTitle = rp.Title
+		detail.Report.ClassifyFirstId = rp.ClassifyIdFirst
+		detail.Report.ClassifySecondId = rp.ClassifyIdSecond
+		detail.Report.Content = html.UnescapeString(rp.Content)
+	}
+	if approveItem.ReportType == report_approve.FlowReportTypeSmart {
+		smartOb := new(smart_report.SmartReport)
+		rp, e := smartOb.GetItemById(approveItem.ReportId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "报告已被删除, 请刷新页面"
+				return
+			}
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取智能研报失败, Err: " + e.Error()
+			return
+		}
+		detail.Report.ReportTitle = rp.Title
+		detail.Report.ClassifyFirstId = rp.ClassifyIdFirst
+		detail.Report.ClassifySecondId = rp.ClassifyIdSecond
+		detail.Report.Content = html.UnescapeString(rp.Content)
+	}
+
+	br.Data = detail
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Approve
+// @Title 通过审批
+// @Description 通过审批
+// @Param	request	body report_approve.ReportApproveFlowAddReq true "type json string"
+// @Success 200 {object} report_approve.ReportApproveDetailItem
+// @router /approve [post]
+func (this *ReportApproveFlowController) Approve() {
+	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.ReportApproveFlowAddReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Refuse
+// @Title 驳回审批
+// @Description 驳回审批
+// @Param	request	body report_approve.ReportApproveFlowAddReq true "type json string"
+// @Success 200 {object} report_approve.ReportApproveDetailItem
+// @router /refuse [post]
+func (this *ReportApproveFlowController) Refuse() {
+	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.ReportApproveFlowAddReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Cancel
+// @Title 撤销审批
+// @Description 撤销审批
+// @Param	request	body report_approve.ReportApproveFlowAddReq true "type json string"
+// @Success 200 {object} report_approve.ReportApproveDetailItem
+// @router /cancel [post]
+func (this *ReportApproveFlowController) Cancel() {
+	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.ReportApproveFlowAddReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 12 - 10
controllers/report_approve/report_approve_flow.go

@@ -14,7 +14,7 @@ import (
 	"time"
 )
 
-// ReportApproveFlowController 智能研
+// ReportApproveFlowController 报告审批流
 type ReportApproveFlowController struct {
 	controllers.BaseAuthController
 }
@@ -30,7 +30,7 @@ type ReportApproveFlowController struct {
 // @Param   Keyword				query	string	false	"搜索关键词"
 // @Param   SortRule			query	int		false	"排序方式: 1-正序; 2-倒序(默认)"
 // @Success 200 {object} report_approve.ReportApproveFlowListResp
-// @router /list [get]
+// @router /flow/list [get]
 func (this *ReportApproveFlowController) List() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
@@ -126,14 +126,16 @@ func (this *ReportApproveFlowController) List() {
 		br.ErrMsg = "获取英文分类失败, Err: " + e.Error()
 		return
 	}
+	enRootIdMap := make(map[int]int) // 英文分类的一级分类ID
 	for _, v := range enClassify {
 		enClassifyIdName[v.Id] = v.ClassifyName
+		enRootIdMap[v.Id] = v.RootId
 	}
 
 	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])
+			t.ReportClassify = fmt.Sprintf("%s/%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], enClassifyIdName[enRootIdMap[v.ClassifySecondId]], 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])
 		}
@@ -152,8 +154,8 @@ func (this *ReportApproveFlowController) List() {
 // @Title 新增审批流
 // @Description 新增审批流
 // @Param	request	body report_approve.ReportApproveFlowAddReq true "type json string"
-// @Success 200 {object} report_approve.ReportApproveDetailItem
-// @router /add [post]
+// @Success 200 {object} report_approve.ReportApproveFlowDetailItem
+// @router /flow/add [post]
 func (this *ReportApproveFlowController) Add() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
@@ -278,8 +280,8 @@ func (this *ReportApproveFlowController) Add() {
 // @Title 编辑审批流
 // @Description 编辑审批流
 // @Param	request	body report_approve.ReportApproveFlowEditReq true "type json string"
-// @Success 200 {object} report_approve.ReportApproveDetailItem
-// @router /edit [post]
+// @Success 200 {object} report_approve.ReportApproveFlowDetailItem
+// @router /flow/edit [post]
 func (this *ReportApproveFlowController) Edit() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
@@ -432,8 +434,8 @@ func (this *ReportApproveFlowController) Edit() {
 // @Title 审批流详情
 // @Description 审批流详情
 // @Param   ReportApproveFlowId  query  int  true  "审批流ID"
-// @Success 200 {object} report_approve.ReportApproveDetailItem
-// @router /detail [get]
+// @Success 200 {object} report_approve.ReportApproveFlowDetailItem
+// @router /flow/detail [get]
 func (this *ReportApproveFlowController) Detail() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
@@ -498,7 +500,7 @@ func (this *ReportApproveFlowController) Detail() {
 // @Description 删除审批流
 // @Param	request	body report_approve.ReportApproveFlowRemoveReq true "type json string"
 // @Success 200 string "操作成功"
-// @router /remove [post]
+// @router /flow/remove [post]
 func (this *ReportApproveFlowController) Remove() {
 	br := new(models.BaseResponse).Init()
 	defer func() {

+ 7 - 0
models/business_conf.go

@@ -172,3 +172,10 @@ func UpdateBusinessConfMulti(items []BusinessConfUpdate) (err error) {
 	}
 	return
 }
+
+func GetBusinessConfByKey(key string) (item *BusinessConf, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM business_conf WHERE conf_key = ? LIMIT 1`)
+	err = o.Raw(sql, key).QueryRow(&item)
+	return
+}

+ 1 - 0
models/classify.go

@@ -39,6 +39,7 @@ type Classify struct {
 	RelateTel         int       `description:"是否在电话会中可选: 0-否; 1-是"`
 	RelateVideo       int       `description:"是否在路演视频中可选: 0-否; 1-是"`
 	IsMassSend        int       `description:"1:群发,0:非群发"`
+	RootId            int       `description:"英文分类-一级分类ID"`
 }
 
 type ClassifyAddReq struct {

+ 5 - 2
models/db.go

@@ -464,7 +464,10 @@ func initSmartReport() {
 // initReportApprove 报告审批相关表
 func initReportApprove() {
 	orm.RegisterModel(
-		new(report_approve.ReportApproveFlow), // 审批流表
-		new(report_approve.ReportApproveNode), // 审批节点表
+		new(report_approve.ReportApprove),        // 审批表
+		new(report_approve.ReportApproveFlow),    // 审批流表
+		new(report_approve.ReportApproveNode),    // 审批节点表
+		new(report_approve.ReportApproveRecord),  // 审批记录表
+		new(report_approve.ReportApproveMessage), // 审批消息表
 	)
 }

+ 28 - 0
models/report.go

@@ -18,6 +18,16 @@ const (
 	ReportStatePass        = 6 // 已通过
 )
 
+// 报告操作
+const (
+	ReportOperateAdd           = 1 // 新增报告
+	ReportOperateEdit          = 2 // 编辑报告
+	ReportOperatePublish       = 3 // 发布报告
+	ReportOperateCancelPublish = 4 // 取消发布报告
+	ReportOperateSubmitApprove = 5 // 提交审批
+	ReportOperateCancelApprove = 6 // 撤回审批
+)
+
 type Report struct {
 	Id                 int       `orm:"column(id)" description:"报告Id"`
 	AddType            int       `description:"新增方式:1:新增报告,2:继承报告"`
@@ -51,6 +61,7 @@ type Report struct {
 	AdminId            int       `description:"创建者账号"`
 	AdminRealName      string    `description:"创建者姓名"`
 	ApproveTime        time.Time `description:"审批时间"`
+	ApproveId          int       `description:"审批ID"`
 }
 
 type ReportList struct {
@@ -1062,3 +1073,20 @@ func SetPrePublishReportById(reportId int, prePublishTime string, preMsgSend int
 	_, err = o.Raw(sql, prePublishTime, preMsgSend, reportId).Exec()
 	return
 }
+
+// ReportSubmitApproveReq 提交审批请求体
+type ReportSubmitApproveReq struct {
+	ReportId int `description:"报告ID"`
+}
+
+// ReportCancelApproveReq 撤回审批请求体
+type ReportCancelApproveReq struct {
+	ReportId int `description:"报告ID"`
+}
+
+func (m *Report) GetItemById(id int) (item *Report, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report WHERE id = ? LIMIT 1`
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}

+ 35 - 0
models/report_approve/constant.go

@@ -0,0 +1,35 @@
+package report_approve
+
+// 报告类型
+const (
+	FlowReportTypeChinese = 1 // 中文研报
+	FlowReportTypeEnglish = 2 // 英文研报
+	FlowReportTypeSmart   = 3 // 智能研报
+)
+
+var FlowReportTypeMap = map[int]string{
+	FlowReportTypeChinese: "中文研报",
+	FlowReportTypeEnglish: "英文研报",
+	FlowReportTypeSmart:   "智能研报",
+}
+
+// 节点审批方式
+const (
+	NodeApproveTypeRoll = 1 // 依次审批
+	NodeApproveTypeAll  = 2 // 会签
+	NodeApproveTypeAny  = 3 // 或签
+)
+
+// 节点审批人类型
+const (
+	NodeUserTypeNormal = "user" // 用户
+	NodeUserTypeRole   = "role" // 角色
+)
+
+// 报告审批状态
+const (
+	ReportApproveStateApproving = 1 // 待审批
+	ReportApproveStatePass      = 2 // 已审批
+	ReportApproveStateRefuse    = 3 // 已驳回
+	ReportApproveStateCancel    = 4 // 已撤销
+)

+ 466 - 0
models/report_approve/report_approve.go

@@ -0,0 +1,466 @@
+package report_approve
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"strings"
+	"time"
+)
+
+// ReportApprove 报告审批表
+type ReportApprove struct {
+	ReportApproveId  int       `orm:"column(report_approve_id);pk" description:"审批ID"`
+	ReportType       int       `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
+	ReportId         int       `description:"报告ID"`
+	ReportTitle      string    `description:"报告标题"`
+	ClassifyFirstId  int       `description:"一级分类ID"`
+	ClassifySecondId int       `description:"二级分类ID"`
+	State            int       `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	FlowId           int       `description:"审批流ID"`
+	FlowVersion      int       `description:"审批流版本"`
+	StartNodeId      int       `description:"开始节点ID"`
+	CurrNodeId       int       `description:"当前节点ID"`
+	ApplyUserId      int       `description:"申请人ID"`
+	ApplyUserName    string    `description:"申请人姓名"`
+	ApproveRemark    string    `description:"审批备注"`
+	ApproveTime      time.Time `description:"审批时间"`
+	CreateTime       time.Time `description:"创建时间"`
+	ModifyTime       time.Time `description:"修改时间"`
+}
+
+var ReportApproveCols = struct {
+	ReportApproveId  string
+	ReportType       string
+	ReportId         string
+	ReportTitle      string `description:"报告标题"`
+	ClassifyFirstId  string `description:"一级分类ID"`
+	ClassifySecondId string `description:"二级分类ID"`
+	State            string
+	FlowId           string
+	FlowVersion      string
+	StartNodeId      string
+	CurrNodeId       string
+	ApplyUserId      string `description:"申请人ID"`
+	ApplyUserName    string `description:"申请人姓名"`
+	ApproveRemark    string `description:"审批备注"`
+	ApproveTime      string `description:"审批时间"`
+	CreateTime       string
+	ModifyTime       string
+}{
+	ReportApproveId:  "report_approve_id",
+	ReportType:       "report_type",
+	ReportId:         "report_id",
+	ReportTitle:      "report_title",
+	ClassifyFirstId:  "classify_first_id",
+	ClassifySecondId: "classify_second_id",
+	State:            "state",
+	FlowId:           "flow_id",
+	FlowVersion:      "flow_version",
+	StartNodeId:      "start_node_id",
+	CurrNodeId:       "curr_node_id",
+	ApplyUserId:      "apply_user_id",
+	ApplyUserName:    "apply_user_name",
+	ApproveRemark:    "approve_remark",
+	ApproveTime:      "approve_time",
+	CreateTime:       "create_time",
+	ModifyTime:       "modify_time",
+}
+
+func (m *ReportApprove) TableName() string {
+	return "report_approve"
+}
+
+func (m *ReportApprove) PrimaryId() string {
+	return ReportApproveCols.ReportApproveId
+}
+
+func (m *ReportApprove) Create() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.ReportApproveId = int(id)
+	return
+}
+
+func (m *ReportApprove) CreateMulti(items []*ReportApprove) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *ReportApprove) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *ReportApprove) Del() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.ReportApproveId).Exec()
+	return
+}
+
+func (m *ReportApprove) MultiDel(menuIds []int) (err error) {
+	if len(menuIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.PrimaryId(), utils.GetOrmInReplace(len(menuIds)))
+	_, err = o.Raw(sql, menuIds).Exec()
+	return
+}
+
+func (m *ReportApprove) GetItemById(id int) (item *ReportApprove, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *ReportApprove) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *ReportApprove, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *ReportApprove) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *ReportApprove) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*ReportApprove, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *ReportApprove) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*ReportApprove, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// ReportApproveItem 报告审批信息
+type ReportApproveItem struct {
+	ReportApproveId  int    `description:"审批ID"`
+	ReportType       int    `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
+	ReportId         int    `description:"报告ID"`
+	ReportTitle      string `description:"报告标题"`
+	ReportClassify   string `description:"报告分类"`
+	ClassifyFirstId  int    `description:"一级分类ID"`
+	ClassifySecondId int    `description:"二级分类ID"`
+	State            int    `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	FlowId           int    `description:"审批流ID"`
+	FlowVersion      int    `description:"审批流版本"`
+	StartNodeId      int    `description:"开始节点ID"`
+	CurrNodeId       int    `description:"当前节点ID"`
+	ApplyUserId      int    `description:"申请人ID"`
+	ApplyUserName    string `description:"申请人姓名"`
+	ApproveRemark    string `description:"审批备注"`
+	ApproveTime      string `description:"审批时间"`
+	HandleTime       string `description:"处理时间"`
+	CreateTime       string `description:"创建时间"`
+	ModifyTime       string `description:"修改时间"`
+}
+
+// FormatReportApproveOrm2Item 格式化报告审批
+func FormatReportApproveOrm2Item(origin *ReportApproveItemOrm) (item *ReportApproveItem) {
+	item = new(ReportApproveItem)
+	if origin == nil {
+		return
+	}
+	item.ReportApproveId = origin.ReportApproveId
+	item.ReportType = origin.ReportType
+	item.ReportId = origin.ReportId
+	item.ReportTitle = origin.ReportTitle
+	item.ClassifyFirstId = origin.ClassifyFirstId
+	item.ClassifySecondId = origin.ClassifySecondId
+	item.State = origin.State
+	item.FlowId = origin.FlowId
+	item.FlowVersion = origin.FlowVersion
+	item.StartNodeId = origin.StartNodeId
+	item.CurrNodeId = origin.CurrNodeId
+	item.ApplyUserId = origin.ApplyUserId
+	item.ApplyUserName = origin.ApplyUserName
+	item.ApproveRemark = origin.ApproveRemark
+	item.ApproveTime = utils.TimeTransferString(utils.FormatDateTime, origin.ApproveTime)
+	item.HandleTime = utils.TimeTransferString(utils.FormatDateTime, origin.HandleTime)
+	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
+	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, origin.ModifyTime)
+	return
+}
+
+// ReportApproveListReq 审批列表请求体
+type ReportApproveListReq struct {
+	PageSize         int    `form:"PageSize"`
+	CurrentIndex     int    `form:"CurrentIndex"`
+	ListType         int    `form:"ListType" description:"列表类型:1-待处理;2-已处理;3-我发起的"`
+	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:"关键词:报告标题"`
+	ApproveState     int    `form:"ApproveState" description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	TimeType         int    `form:"TimeType" description:"时间类型:1-提交时间;2-处理时间;3-审批时间"`
+	StartTime        string `form:"StartTime" description:"开始时间"`
+	EndTime          string `form:"EndTime" description:"结束时间"`
+	SortField        int    `form:"SortField" description:"排序字段:1-提交时间;2-处理时间;3-审批时间"`
+	SortRule         int    `form:"SortRule" description:"排序方式: 1-正序; 2-倒序(默认)"`
+}
+
+// ReportApproveListResp 审批列表响应体
+type ReportApproveListResp struct {
+	List   []*ReportApproveItem
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+type ReportApproveItemOrm struct {
+	ReportApproveId  int       `description:"审批ID"`
+	ReportType       int       `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
+	ReportId         int       `description:"报告ID"`
+	ReportTitle      string    `description:"报告标题"`
+	ClassifyFirstId  int       `description:"一级分类ID"`
+	ClassifySecondId int       `description:"二级分类ID"`
+	State            int       `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	FlowId           int       `description:"审批流ID"`
+	FlowVersion      int       `description:"审批流版本"`
+	StartNodeId      int       `description:"开始节点ID"`
+	CurrNodeId       int       `description:"当前节点ID"`
+	ApplyUserId      int       `description:"申请人ID"`
+	ApplyUserName    string    `description:"申请人姓名"`
+	ApproveRemark    string    `description:"审批备注"`
+	ApproveTime      time.Time `description:"审批时间"`
+	HandleTime       time.Time `description:"处理时间"`
+	CreateTime       time.Time `description:"创建时间"`
+	ModifyTime       time.Time `description:"修改时间"`
+}
+
+// GetApprovingReportApproveCount 获取待处理的审批分页列表总数
+func GetApprovingReportApproveCount(cond string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	base := fmt.Sprintf(`SELECT a.report_approve_id
+		FROM report_approve AS a
+		JOIN report_approve_record AS b ON a.report_approve_id = b.report_approve_id
+		WHERE 1 = 1 %s
+		GROUP BY a.report_approve_id`, cond)
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM (%s) t`, base)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+// GetApprovingReportApprovePageList 获取待处理的审批列表-分页
+func GetApprovingReportApprovePageList(cond string, pars []interface{}, orderRule string, startSize, pageSize int) (items []*ReportApproveItemOrm, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	order := `ORDER BY a.create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT
+			a.*
+		FROM
+			report_approve AS a
+		JOIN report_approve_record AS b ON a.report_approve_id = b.report_approve_id
+		WHERE
+			1 = 1 %s
+		GROUP BY a.report_approve_id %s
+		LIMIT ?,?`, cond, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// GetApprovedReportApproveCount 获取已处理的审批分页列表总数
+func GetApprovedReportApproveCount(cond string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	base := fmt.Sprintf(`SELECT b.report_approve_record_id
+		FROM report_approve AS a
+		JOIN report_approve_record AS b ON a.report_approve_id = b.report_approve_id
+		WHERE 1 = 1 %s`, cond)
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM (%s) t`, base)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+// GetApprovedReportApprovePageList 获取已处理的审批列表-分页
+func GetApprovedReportApprovePageList(cond string, pars []interface{}, orderRule string, startSize, pageSize int) (items []*ReportApproveItemOrm, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	order := `ORDER BY a.create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT
+			a.*, b.approve_time AS handle_time
+		FROM
+			report_approve AS a
+		JOIN report_approve_record AS b ON a.report_approve_id = b.report_approve_id
+		WHERE
+			1 = 1 %s %s
+		LIMIT ?,?`, cond, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// GetApplyReportApproveCount 获取我发起的审批分页列表总数
+func GetApplyReportApproveCount(cond string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	base := fmt.Sprintf(`SELECT a.* FROM report_approve AS a WHERE 1 = 1 %s`, cond)
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM (%s) t`, base)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+// GetApplyReportApprovePageList 获取我发起的审批列表-分页
+func GetApplyReportApprovePageList(cond string, pars []interface{}, orderRule string, startSize, pageSize int) (items []*ReportApproveItemOrm, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	order := `ORDER BY a.create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT a.* FROM report_approve AS a WHERE 1 = 1 %s %s LIMIT ?,?`, cond, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// ReportApproveDetail 审批详情信息
+type ReportApproveDetail struct {
+	Report           *ReportApproveDetailReport  `description:"报告信息"`
+	Approve          *ReportApproveDetailItem    `description:"审批信息"`
+	ApproveFlowNodes []*ReportApproveDetailNodes `description:"审批节点信息"`
+	//ApproveFlow      *ReportApproveFlowItem      `description:"审批流信息"`
+}
+
+// ReportApproveDetailItem 审批详情-审批信息
+type ReportApproveDetailItem struct {
+	ReportApproveId int    `description:"审批ID"`
+	State           int    `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	FlowId          int    `description:"审批流ID"`
+	FlowVersion     int    `description:"审批流版本"`
+	StartNodeId     int    `description:"开始节点ID"`
+	CurrNodeId      int    `description:"当前节点ID"`
+	ApplyUserId     int    `description:"申请人ID"`
+	ApplyUserName   string `description:"申请人姓名"`
+	ApproveTime     string `description:"审批时间"`
+	CreateTime      string `description:"创建时间"`
+	ModifyTime      string `description:"修改时间"`
+}
+
+// ReportApproveDetailReport 审批详情-报告信息
+type ReportApproveDetailReport struct {
+	ReportType       int    `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
+	ReportId         int    `description:"报告ID"`
+	ReportTitle      string `description:"报告标题"`
+	ClassifyFirstId  int    `description:"一级分类ID"`
+	ClassifySecondId int    `description:"二级分类ID"`
+	Content          string `description:"报告内容"`
+}
+
+// CreateApproveAndRecord 新增审批和记录
+func (m *ReportApprove) CreateApproveAndRecord(approveItem *ReportApprove, recordItems []*ReportApproveRecord) (err error) {
+	if approveItem == nil {
+		err = fmt.Errorf("approve is nil")
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	tx, e := o.Begin()
+	if e != nil {
+		err = fmt.Errorf("orm begin err: %s", e.Error())
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+			return
+		}
+		_ = tx.Commit()
+	}()
+
+	lastId, e := tx.Insert(approveItem)
+	if e != nil {
+		err = fmt.Errorf("insert approve err: %s", e.Error())
+		return
+	}
+	approveItem.ReportApproveId = int(lastId)
+
+	if len(recordItems) > 0 {
+		for _, v := range recordItems {
+			v.ReportApproveId = approveItem.ReportApproveId
+		}
+		_, e = tx.InsertMulti(len(recordItems), recordItems)
+		if e != nil {
+			err = fmt.Errorf("insert records err: %s", e.Error())
+			return
+		}
+	}
+	return
+}
+
+// CancelApproveAndRecord 撤销审批和记录
+func (m *ReportApprove) CancelApproveAndRecord(approveItem *ReportApprove, recordItems []*ReportApproveRecord) (err error) {
+	if approveItem == nil {
+		err = fmt.Errorf("approve is nil")
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	tx, e := o.Begin()
+	if e != nil {
+		err = fmt.Errorf("orm begin err: %s", e.Error())
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+			return
+		}
+		_ = tx.Commit()
+	}()
+
+	lastId, e := tx.Insert(approveItem)
+	if e != nil {
+		err = fmt.Errorf("insert approve err: %s", e.Error())
+		return
+	}
+	approveItem.ReportApproveId = int(lastId)
+
+	if len(recordItems) > 0 {
+		for _, v := range recordItems {
+			v.ReportApproveId = approveItem.ReportApproveId
+		}
+		_, e = tx.InsertMulti(len(recordItems), recordItems)
+		if e != nil {
+			err = fmt.Errorf("insert records err: %s", e.Error())
+			return
+		}
+	}
+	return
+}

+ 4 - 16
models/report_approve/report_approve_flow.go

@@ -9,18 +9,6 @@ import (
 	"time"
 )
 
-const (
-	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"`
@@ -350,18 +338,18 @@ func (m *ReportApproveFlow) UpdateFlowAndNodes(flowItem *ReportApproveFlow, node
 	return
 }
 
-// ReportApproveDetailItem 报告审批流详情信息
-type ReportApproveDetailItem struct {
+// ReportApproveFlowDetailItem 报告审批流详情信息
+type ReportApproveFlowDetailItem struct {
 	ReportApproveFlowItem `description:"审批流信息"`
 	Nodes                 []*ReportApproveNodeItem `description:"节点信息"`
 }
 
 // FormatFlowAndNodesItem2Detail 格式化审批流详情
-func FormatFlowAndNodesItem2Detail(flowItem *ReportApproveFlow, nodeItems []*ReportApproveNode) (detail *ReportApproveDetailItem, err error) {
+func FormatFlowAndNodesItem2Detail(flowItem *ReportApproveFlow, nodeItems []*ReportApproveNode) (detail *ReportApproveFlowDetailItem, err error) {
 	if flowItem == nil {
 		return
 	}
-	detail = new(ReportApproveDetailItem)
+	detail = new(ReportApproveFlowDetailItem)
 	detail.ReportApproveFlowId = flowItem.ReportApproveFlowId
 	detail.FlowName = flowItem.FlowName
 	detail.ReportType = flowItem.ReportType

+ 185 - 0
models/report_approve/report_approve_message.go

@@ -0,0 +1,185 @@
+package report_approve
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// ReportApproveMessage 报告审批消息表
+type ReportApproveMessage struct {
+	Id              int       `orm:"column(id);pk"`
+	SendUserId      int       `description:"发送人ID"`
+	ReceiveUserId   int       `description:"接收者ID"`
+	Content         string    `description:"消息内容"`
+	Remark          string    `description:"备注信息"`
+	ReportApproveId int       `description:"审批ID"`
+	ApproveState    int       `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	IsRead          int       `description:"是否已读:0-未读;1-已读"`
+	CreateTime      time.Time `description:"创建时间"`
+	ModifyTime      time.Time `description:"修改时间"`
+}
+
+var ReportApproveMessageCols = struct {
+	Id              string
+	SendUserId      string
+	ReceiveUserId   string
+	Content         string
+	Remark          string
+	ReportApproveId string
+	ApproveState    string
+	IsRead          string
+	CreateTime      string
+	ModifyTime      string
+}{
+	Id:              "id",
+	SendUserId:      "send_user_id",
+	ReceiveUserId:   "receive_user_id",
+	Content:         "content",
+	Remark:          "remark",
+	ReportApproveId: "report_approve_id",
+	ApproveState:    "approve_state",
+	IsRead:          "is_read",
+	CreateTime:      "create_time",
+	ModifyTime:      "modify_time",
+}
+
+func (m *ReportApproveMessage) TableName() string {
+	return "report_approve_message"
+}
+
+func (m *ReportApproveMessage) PrimaryId() string {
+	return ReportApproveMessageCols.Id
+}
+
+func (m *ReportApproveMessage) Create() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.Id = int(id)
+	return
+}
+
+func (m *ReportApproveMessage) CreateMulti(items []*ReportApproveMessage) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *ReportApproveMessage) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *ReportApproveMessage) Del() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.Id).Exec()
+	return
+}
+
+func (m *ReportApproveMessage) MultiDel(menuIds []int) (err error) {
+	if len(menuIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.PrimaryId(), utils.GetOrmInReplace(len(menuIds)))
+	_, err = o.Raw(sql, menuIds).Exec()
+	return
+}
+
+func (m *ReportApproveMessage) GetItemById(id int) (item *ReportApproveMessage, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *ReportApproveMessage) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *ReportApproveMessage, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *ReportApproveMessage) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *ReportApproveMessage) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*ReportApproveMessage, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *ReportApproveMessage) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*ReportApproveMessage, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// ReportApproveMessageItem 报告审批消息信息
+type ReportApproveMessageItem struct {
+	Id              int
+	SendUserId      int    `description:"发送人ID"`
+	ReceiveUserId   int    `description:"接收者ID"`
+	Content         string `description:"消息内容"`
+	Remark          string `description:"备注信息"`
+	ReportApproveId int    `description:"审批ID"`
+	ApproveState    int    `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	IsRead          int    `description:"是否已读:0-未读;1-已读"`
+	CreateTime      string `description:"创建时间"`
+	ModifyTime      string `description:"修改时间"`
+}
+
+// FormatReportApproveMessage2Item 格式化报告审批消息
+func FormatReportApproveMessage2Item(origin *ReportApproveMessage) (item *ReportApproveMessageItem) {
+	item = new(ReportApproveMessageItem)
+	if origin == nil {
+		return
+	}
+	item.Id = origin.Id
+	item.SendUserId = origin.SendUserId
+	item.ReceiveUserId = origin.ReceiveUserId
+	item.Content = origin.Content
+	item.Remark = origin.Remark
+	item.ReportApproveId = origin.ReportApproveId
+	item.ApproveState = origin.ApproveState
+	item.IsRead = origin.IsRead
+	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
+	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, origin.ModifyTime)
+	return
+}

+ 17 - 11
models/report_approve/report_approve_node.go

@@ -9,17 +9,6 @@ import (
 	"time"
 )
 
-const (
-	NodeApproveTypeRoll = 1
-	NodeApproveTypeAll  = 2
-	NodeApproveTypeAny  = 3
-)
-
-const (
-	NodeUserTypeNormal = "user"
-	NodeUserTypeRole   = "role"
-)
-
 // ReportApproveNode 报告审批节点表
 type ReportApproveNode struct {
 	ReportApproveNodeId int       `orm:"column(report_approve_node_id);pk" description:"报告审批节点ID"`
@@ -185,6 +174,23 @@ type ReportApproveNodeItem struct {
 	Users               []*ReportApproveNodeUserReq `description:"审批人信息"`
 }
 
+// ReportApproveDetailNodes 审批详情-节点信息
+type ReportApproveDetailNodes struct {
+	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               []*ReportApproveDetailNodeUser `description:"审批人信息"`
+}
+
+// ReportApproveDetailNodeUser 审批详情-节点用户信息
+type ReportApproveDetailNodeUser struct {
+	ReportApproveNodeUserReq
+	ApproveRecord *ReportApproveDetailNodeUserRecord `description:"用户审批记录"`
+}
+
 // FormatReportApproveNode2Item 格式化报告审批节点信息
 func FormatReportApproveNode2Item(origin *ReportApproveNode) (item *ReportApproveNodeItem, err error) {
 	if origin == nil {

+ 219 - 0
models/report_approve/report_approve_record.go

@@ -1 +1,220 @@
 package report_approve
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// ReportApproveRecord 报告审批记录表
+type ReportApproveRecord struct {
+	ReportApproveRecordId int       `orm:"column(report_approve_record_id);pk" description:"审批记录ID"`
+	ReportApproveId       int       `description:"审批ID"`
+	State                 int       `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	NodeId                int       `description:"节点ID"`
+	NodeType              int       `description:"节点类型:0-审批;1-抄送"`
+	PrevNodeId            int       `description:"上级节点ID"`
+	NextNodeId            int       `description:"下级节点ID"`
+	ApproveType           int       `description:"审批类型:1-依次审批;2-会签;3-或签"`
+	ApproveUserId         int       `description:"审批人ID"`
+	ApproveUserName       string    `description:"审批人姓名"`
+	ApproveUserSort       int       `description:"依次审批:用户的审批顺序"`
+	ApproveRemark         string    `description:"审批备注(驳回备注等)"`
+	ApproveTime           time.Time `description:"审批时间"`
+	CreateTime            time.Time `description:"创建时间"`
+	ModifyTime            time.Time `description:"修改时间"`
+}
+
+var ReportApproveRecordCols = struct {
+	ReportApproveRecordId string
+	ReportApproveId       string
+	State                 string
+	NodeId                string
+	NodeType              string
+	PrevNodeId            string
+	NextNodeId            string
+	ApproveType           string
+	ApproveRemark         string
+	ApproveUserId         string
+	ApproveUserName       string
+	ApproveUserSort       string
+	ApproveTime           string
+	CreateTime            string
+	ModifyTime            string
+}{
+	ReportApproveRecordId: "report_approve_record_id",
+	ReportApproveId:       "report_approve_id",
+	State:                 "state",
+	NodeId:                "node_id",
+	NodeType:              "node_type",
+	PrevNodeId:            "prev_node_id",
+	NextNodeId:            "next_node_id",
+	ApproveType:           "approve_type",
+	ApproveUserId:         "approve_user_id",
+	ApproveUserName:       "approve_user_name",
+	ApproveUserSort:       "approve_user_sort",
+	ApproveRemark:         "approve_remark",
+	ApproveTime:           "approve_time",
+	CreateTime:            "create_time",
+	ModifyTime:            "modify_time",
+}
+
+func (m *ReportApproveRecord) TableName() string {
+	return "report_approve_record"
+}
+
+func (m *ReportApproveRecord) PrimaryId() string {
+	return ReportApproveRecordCols.ReportApproveRecordId
+}
+
+func (m *ReportApproveRecord) Create() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.ReportApproveRecordId = int(id)
+	return
+}
+
+func (m *ReportApproveRecord) CreateMulti(items []*ReportApproveRecord) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *ReportApproveRecord) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *ReportApproveRecord) Del() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.ReportApproveRecordId).Exec()
+	return
+}
+
+func (m *ReportApproveRecord) MultiDel(menuIds []int) (err error) {
+	if len(menuIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.PrimaryId(), utils.GetOrmInReplace(len(menuIds)))
+	_, err = o.Raw(sql, menuIds).Exec()
+	return
+}
+
+func (m *ReportApproveRecord) GetItemById(id int) (item *ReportApproveRecord, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *ReportApproveRecord) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *ReportApproveRecord, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *ReportApproveRecord) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *ReportApproveRecord) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*ReportApproveRecord, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *ReportApproveRecord) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*ReportApproveRecord, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// ReportApproveRecordItem 报告审批记录信息
+type ReportApproveRecordItem struct {
+	ReportApproveRecordId int    `description:"审批记录ID"`
+	ReportApproveId       int    `description:"审批ID"`
+	State                 int    `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	NodeId                int    `description:"节点ID"`
+	NodeType              int    `description:"节点类型:0-审批;1-抄送"`
+	PrevNodeId            int    `description:"上级节点ID"`
+	NextNodeId            int    `description:"下级节点ID"`
+	ApproveType           int    `description:"审批类型:1-依次审批;2-会签;3-或签"`
+	ApproveUserId         int    `description:"审批人ID"`
+	ApproveUserName       string `description:"审批人姓名"`
+	ApproveUserSort       int    `description:"依次审批:用户的审批顺序"`
+	ApproveRemark         string `description:"审批备注(驳回备注等)"`
+	ApproveTime           string `description:"审批时间"`
+	CreateTime            string `description:"创建时间"`
+	ModifyTime            string `description:"修改时间"`
+}
+
+// FormatReportApproveRecord2Item 格式化报告审批记录
+func FormatReportApproveRecord2Item(origin *ReportApproveRecord) (item *ReportApproveRecordItem) {
+	item = new(ReportApproveRecordItem)
+	if origin == nil {
+		return
+	}
+	item.ReportApproveRecordId = origin.ReportApproveRecordId
+	item.ReportApproveId = origin.ReportApproveId
+	item.State = origin.State
+	item.NodeId = origin.NodeId
+	item.NodeType = origin.NodeType
+	item.PrevNodeId = origin.PrevNodeId
+	item.NextNodeId = origin.NextNodeId
+	item.ApproveType = origin.ApproveType
+	item.ApproveUserId = origin.ApproveUserId
+	item.ApproveUserName = origin.ApproveUserName
+	item.ApproveUserSort = origin.ApproveUserSort
+	item.ApproveRemark = origin.ApproveRemark
+	item.ApproveTime = utils.TimeTransferString(utils.FormatDateTime, origin.ApproveTime)
+	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
+	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, origin.ModifyTime)
+	return
+}
+
+// ReportApproveDetailNodeUserRecord 审批详情-节点用户审批记录
+type ReportApproveDetailNodeUserRecord struct {
+	ReportApproveRecordId int    `description:"审批记录ID"`
+	State                 int    `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	ApproveUserId         int    `description:"审批人ID"`
+	ApproveUserName       string `description:"审批人姓名"`
+	ApproveRemark         string `description:"审批备注"`
+	ApproveTime           string `description:"审批时间"`
+}

+ 68 - 5
routers/commentsRouter.go

@@ -4363,10 +4363,46 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"],
+        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: "Approve",
+            Router: `/approve`,
+            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: "Cancel",
+            Router: `/cancel`,
+            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: "Add",
-            Router: `/add`,
+            Router: `/flow/add`,
             AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -4375,7 +4411,7 @@ func init() {
     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`,
+            Router: `/flow/detail`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -4384,7 +4420,7 @@ func init() {
     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`,
+            Router: `/flow/edit`,
             AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -4393,7 +4429,7 @@ func init() {
     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`,
+            Router: `/flow/list`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -4402,7 +4438,16 @@ func init() {
     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`,
+            Router: `/flow/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: "Refuse",
+            Router: `/refuse`,
             AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -6010,6 +6055,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "CancelApprove",
+            Router: `/approve/cancel`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "SubmitApprove",
+            Router: `/approve/submit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
         beego.ControllerComments{
             Method: "Author",

+ 1 - 0
routers/router.go

@@ -308,6 +308,7 @@ func init() {
 		),
 		web.NSNamespace("/report_approve",
 			web.NSInclude(
+				&report_approve.ReportApproveController{},
 				&report_approve.ReportApproveFlowController{},
 			),
 		),

+ 271 - 0
services/report_approve.go

@@ -4,7 +4,10 @@ import (
 	"eta/eta_api/models"
 	"eta/eta_api/models/report_approve"
 	"eta/eta_api/models/smart_report"
+	"eta/eta_api/utils"
 	"fmt"
+	"sort"
+	"time"
 )
 
 // GetReportClassifyTreeRecursive 递归获取报告分类树
@@ -61,3 +64,271 @@ func CheckReportApproveFlowChange(reportType, classifyFirstId, classifySecondId
 	}
 	return
 }
+
+// CheckReportCurrState 校验报告当前应有的状态
+func CheckReportCurrState(reportType, firstId, secondId, operate int) (state int, err error) {
+	// 获取审批配置
+	confMap, e := models.GetBusinessConf()
+	if e != nil {
+		err = fmt.Errorf("GetBusinessConf err: %s", e.Error())
+		return
+	}
+	openMap := map[string]bool{"false": false, "true": true}
+	openApprove := openMap[confMap[models.BusinessConfIsReportApprove]]
+
+	// 查询对应分类是否有审批流
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId)
+	flowPars := make([]interface{}, 0)
+	flowPars = append(flowPars, reportType, firstId, secondId)
+	flowItem, e := flowOb.GetItemByCondition(flowCond, flowPars, "")
+	if e != nil && e.Error() != utils.ErrNoRow() {
+		err = fmt.Errorf("ApproveFlow GetItemByCondition err: %s", e.Error())
+		return
+	}
+
+	// 开启审批/有审批流
+	if openApprove && (flowItem != nil || confMap[models.BusinessConfReportApproveType] == models.BusinessConfReportApproveTypeOther) {
+		// 操作为无审批的操作时, 会转为有审批的初始状态-待提交
+		stateMap := map[int]int{
+			models.ReportOperateAdd:           models.ReportStateWaitSubmit,  // 新增
+			models.ReportOperateEdit:          models.ReportStateWaitSubmit,  // 编辑
+			models.ReportOperatePublish:       models.ReportStateWaitSubmit,  // 发布
+			models.ReportOperateSubmitApprove: models.ReportStateWaitApprove, // 提审
+			models.ReportOperateCancelApprove: models.ReportStateWaitSubmit,  // 撤回
+		}
+		state = stateMap[operate]
+		return
+	}
+
+	// 关闭审批/分类无审批
+	// 操作为有审批的操作时, 会转为无审批的初始状态-未发布
+	stateMap := map[int]int{
+		models.ReportOperateAdd:           models.ReportStateUnpublished, // 新增
+		models.ReportOperateEdit:          models.ReportStateUnpublished, // 编辑
+		models.ReportOperatePublish:       models.ReportStatePublished,   // 发布
+		models.ReportOperateSubmitApprove: models.ReportStateUnpublished, // 提审
+		models.ReportOperateCancelApprove: models.ReportStateUnpublished, // 撤回
+	}
+	state = stateMap[operate]
+	return
+}
+
+//type SubmitReportApprovePars struct {
+//	ReportType   int
+//	ReportId     int
+//	ReportTitle  string
+//	FirstId      int
+//	SecondId     int
+//	SysAdminId   int
+//	SysAdminName string
+//}
+
+// SubmitReportApprove 提交审批
+func SubmitReportApprove(reportType, reportId int, reportTitle string, firstId, secondId int, sysAdminId int, sysAdminName string) (approveId int, err error) {
+	// 如果是走的第三方审批, 那么仅修改状态
+	confMap, e := models.GetBusinessConf()
+	if e != nil {
+		err = fmt.Errorf("GetBusinessConf err: %s", e.Error())
+		return
+	}
+	openMap := map[string]bool{"false": false, "true": true}
+	openApprove := openMap[confMap[models.BusinessConfIsReportApprove]]
+	if openApprove && confMap[models.BusinessConfReportApproveType] == models.BusinessConfReportApproveTypeOther {
+		return
+	}
+
+	// 查询审批流
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId)
+	flowPars := make([]interface{}, 0)
+	flowPars = append(flowPars, reportType, firstId, secondId)
+	flowItem, e := flowOb.GetItemByCondition(flowCond, flowPars, "")
+	if e != nil {
+		err = fmt.Errorf("ApproveFlow GetItemByCondition err: %s", e.Error())
+		return
+	}
+
+	// 查询审批节点
+	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)
+	nodeItems, e := nodeOb.GetItemsByCondition(nodeCond, nodePars, []string{}, "")
+	if e != nil {
+		err = fmt.Errorf("ApproveNodes GetItemsByCondition err: %s", e.Error())
+		return
+	}
+	if len(nodeItems) == 0 {
+		err = fmt.Errorf("无审批节点")
+		return
+	}
+
+	// 取出首个节点
+	firstNodeItem := new(report_approve.ReportApproveNode)
+	for _, v := range nodeItems {
+		if v.PrevNodeId == 0 {
+			firstNodeItem = v
+			continue
+		}
+	}
+	if firstNodeItem == nil {
+		err = fmt.Errorf("首个审批节点有误")
+		return
+	}
+	firstNode, e := report_approve.FormatReportApproveNode2Item(firstNodeItem)
+	if e != nil {
+		err = fmt.Errorf("首个审批节点信息有误, Err: %s", e.Error())
+		return
+	}
+	if len(firstNode.Users) == 0 {
+		err = fmt.Errorf("首个审批节点审批人信息有误")
+		return
+	}
+
+	// 审批信息
+	now := time.Now().Local()
+	newApprove := new(report_approve.ReportApprove)
+	newApprove.ReportType = reportType
+	newApprove.ReportId = reportId
+	newApprove.ReportTitle = reportTitle
+	newApprove.ClassifyFirstId = firstId
+	newApprove.ClassifySecondId = secondId
+	newApprove.State = report_approve.ReportApproveStateApproving
+	newApprove.FlowId = flowItem.ReportApproveFlowId
+	newApprove.FlowVersion = flowItem.CurrVersion
+	newApprove.StartNodeId = firstNodeItem.ReportApproveNodeId
+	newApprove.CurrNodeId = firstNodeItem.ReportApproveNodeId
+	newApprove.ApplyUserId = sysAdminId
+	newApprove.ApplyUserName = sysAdminName
+	newApprove.CreateTime = now
+	newApprove.ModifyTime = now
+
+	// 根据节点审批方式生成审批记录
+	newRecords := make([]*report_approve.ReportApproveRecord, 0)
+	sort.Slice(firstNode.Users, func(k, j int) bool {
+		return firstNode.Users[k].Sort < firstNode.Users[j].Sort
+	})
+	for _, u := range firstNode.Users {
+		r := new(report_approve.ReportApproveRecord)
+		r.State = report_approve.ReportApproveStateApproving
+		r.NodeId = firstNode.ReportApproveNodeId
+		r.PrevNodeId = firstNode.PrevNodeId
+		r.NextNodeId = firstNode.NextNodeId
+		r.ApproveType = firstNode.ApproveType
+		r.ApproveUserId = u.UserId
+		r.ApproveUserName = u.UserName
+		r.ApproveUserSort = u.Sort
+		r.CreateTime = now
+		r.ModifyTime = now
+		newRecords = append(newRecords, r)
+		// 依次审批仅生成一条记录
+		if firstNode.ApproveType == report_approve.NodeApproveTypeRoll {
+			break
+		}
+	}
+
+	// 新增审批和审批记录
+	if e = newApprove.CreateApproveAndRecord(newApprove, newRecords); e != nil {
+		err = fmt.Errorf("CreateApproveAndRecord err: %s", e.Error())
+		return
+	}
+	approveId = newApprove.ReportApproveId
+
+	// 推送审批消息
+	go func() {
+		messageOb := new(report_approve.ReportApproveMessage)
+		messages := make([]*report_approve.ReportApproveMessage, 0)
+		for _, v := range newRecords {
+			m := new(report_approve.ReportApproveMessage)
+			m.SendUserId = sysAdminId
+			m.ReceiveUserId = v.ApproveUserId
+			m.Content = "您有新的待办任务"
+			m.Remark = fmt.Sprintf("%s提交的【研报审批】需要您审批,请及时处理", sysAdminName)
+			m.ReportApproveId = newApprove.ReportApproveId
+			m.ApproveState = report_approve.ReportApproveStateApproving
+			m.CreateTime = now
+			m.ModifyTime = now
+			messages = append(messages, m)
+		}
+		e = messageOb.CreateMulti(messages)
+		if e != nil {
+			utils.FileLog.Info(fmt.Sprintf("SubmitReportApprove messages err: %s", e.Error()))
+			return
+		}
+	}()
+	return
+}
+
+// CancelReportApprove 撤回审批
+func CancelReportApprove(approveId, sysAdminId int, sysAdminName string) (err error) {
+	// 如果是走的第三方审批, 那么仅修改状态
+	confMap, e := models.GetBusinessConf()
+	if e != nil {
+		err = fmt.Errorf("GetBusinessConf err: %s", e.Error())
+		return
+	}
+	openMap := map[string]bool{"false": false, "true": true}
+	openApprove := openMap[confMap[models.BusinessConfIsReportApprove]]
+	if openApprove && confMap[models.BusinessConfReportApproveType] == models.BusinessConfReportApproveTypeOther {
+		return
+	}
+
+	// 修改审批信息状态
+	approveOb := new(report_approve.ReportApprove)
+	approveItem, e := approveOb.GetItemById(approveId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			return
+		}
+		err = fmt.Errorf("approve GetItemById err: %s", e.Error())
+		return
+	}
+	if approveItem.State == report_approve.ReportApproveStateCancel {
+		return
+	}
+	approveItem.State = report_approve.ReportApproveStateCancel
+	cols := []string{"State", "ModifyTime"}
+	if e = approveItem.Update(cols); e != nil {
+		err = fmt.Errorf("approve Update err: %s", e.Error())
+		return
+	}
+
+	// 推送撤回消息
+	go func() {
+		recordOb := new(report_approve.ReportApproveRecord)
+		recordCond := fmt.Sprintf(` AND %s = ?`, report_approve.ReportApproveRecordCols.ReportApproveId)
+		recordPars := make([]interface{}, 0)
+		recordPars = append(recordPars, approveId)
+		recordItems, e := recordOb.GetItemsByCondition(recordCond, recordPars, []string{}, "")
+		if e != nil {
+			utils.FileLog.Info(fmt.Sprintf("approve record GetItemsByCondition err: %s", e.Error()))
+			return
+		}
+
+		messageOb := new(report_approve.ReportApproveMessage)
+		messages := make([]*report_approve.ReportApproveMessage, 0)
+		for _, v := range recordItems {
+			m := new(report_approve.ReportApproveMessage)
+			m.SendUserId = sysAdminId
+			m.ReceiveUserId = v.ApproveUserId
+			m.Content = fmt.Sprintf("%s提交的【研报审批】已撤回", sysAdminName)
+			m.ReportApproveId = approveId
+			m.ApproveState = report_approve.ReportApproveStateCancel
+			m.CreateTime = time.Now().Local()
+			m.ModifyTime = time.Now().Local()
+			messages = append(messages, m)
+		}
+		e = messageOb.CreateMulti(messages)
+		if e != nil {
+			utils.FileLog.Info(fmt.Sprintf("CancelReportApprove messages err: %s", e.Error()))
+			return
+		}
+	}()
+	return
+}
+
+// ApproveReport 报告审批
+func ApproveReport() (err error) {
+	return
+}