优化报销功能
This commit is contained in:
1 parent
395c7f717e
commit
4306cbd74b
19 files changed
+2059
-534
No files matched your search
+176
-43
@@ -41,19 +41,19 @@ import (
|
||||
|
||||
// oaApprovalSubmitPayload 提交审批入参
|
||||
type oaApprovalSubmitPayload struct {
|
||||
BizType string `json:"biz_type"` // 单据类型(必填)
|
||||
FlowCode string `json:"flow_code"` // 指定流程(可选;留空取该 biz_type 默认流)
|
||||
FlowID uint64 `json:"flow_id"` // 指定流程ID(可选)
|
||||
BizTitle string `json:"biz_title"` // 单据标题(必填)
|
||||
BizID uint64 `json:"biz_id"` // 关联业务单据ID(可选)
|
||||
FormData map[string]interface{} `json:"form_data"` // 表单数据
|
||||
BizType string `json:"biz_type"` // 单据类型(必填)
|
||||
FlowCode string `json:"flow_code"` // 指定流程(可选;留空取该 biz_type 默认流)
|
||||
FlowID uint64 `json:"flow_id"` // 指定流程ID(可选)
|
||||
BizTitle string `json:"biz_title"` // 单据标题(必填)
|
||||
BizID uint64 `json:"biz_id"` // 关联业务单据ID(可选)
|
||||
FormData map[string]interface{} `json:"form_data"` // 表单数据
|
||||
}
|
||||
|
||||
// oaApprovalApprovePayload 审批入参
|
||||
type oaApprovalApprovePayload struct {
|
||||
TaskID uint64 `json:"task_id"` // 待审批任务ID(必填)
|
||||
Pass bool `json:"pass"` // true 通过 false 驳回
|
||||
Comment string `json:"comment"` // 审批意见
|
||||
TaskID uint64 `json:"task_id"` // 待审批任务ID(必填)
|
||||
Pass bool `json:"pass"` // true 通过 false 驳回
|
||||
Comment string `json:"comment"` // 审批意见
|
||||
}
|
||||
|
||||
// ============================ 工具 ============================
|
||||
@@ -267,8 +267,9 @@ func oaApprovalTaskTag(status int8) string {
|
||||
}
|
||||
}
|
||||
|
||||
// oaApprovalTaskView 任务视图(移动端时间线用)
|
||||
func oaApprovalTaskView(t models.ApprovalTask, isCurrent bool) map[string]interface{} {
|
||||
// oaApprovalTaskView 任务视图(移动端流程时间线用)
|
||||
// nodeType 来自流程定义(开始/审批/通知/结束),取不到时按审批节点处理。
|
||||
func oaApprovalTaskView(t models.ApprovalTask, isCurrent bool, nodeType int8) map[string]interface{} {
|
||||
finishTime := ""
|
||||
if t.FinishTime != nil {
|
||||
finishTime = t.FinishTime.Format("2006-01-02 15:04:05")
|
||||
@@ -277,23 +278,158 @@ func oaApprovalTaskView(t models.ApprovalTask, isCurrent bool) map[string]interf
|
||||
if t.Deadline != nil {
|
||||
deadline = t.Deadline.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"id": t.ID,
|
||||
"node_key": t.NodeKey,
|
||||
"node_name": t.NodeName,
|
||||
"approver_id": t.ApproverID,
|
||||
"approver_name": t.ApproverName,
|
||||
"multi_mode": t.MultiMode,
|
||||
"status": t.Status,
|
||||
"status_label": oaApprovalTaskText(t.Status),
|
||||
"status_tag": oaApprovalTaskTag(t.Status),
|
||||
"action": t.Action,
|
||||
"comment": t.Comment,
|
||||
"is_current": isCurrent,
|
||||
"deadline": deadline,
|
||||
"finish_time": finishTime,
|
||||
"create_time": t.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
if nodeType == 0 {
|
||||
nodeType = models.ApprovalNodeApproval
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"id": t.ID,
|
||||
"node_key": t.NodeKey,
|
||||
"node_name": t.NodeName,
|
||||
"node_type": nodeType,
|
||||
"approver_id": t.ApproverID,
|
||||
"approver_name": t.ApproverName,
|
||||
"approver_sub": oaApprovalUserOrgName(t.Tid, t.ApproverID),
|
||||
"multi_mode": t.MultiMode,
|
||||
"status": t.Status,
|
||||
"status_label": oaApprovalTaskText(t.Status),
|
||||
"status_tag": oaApprovalTaskTag(t.Status),
|
||||
"action": t.Action,
|
||||
"comment": t.Comment,
|
||||
"is_current": isCurrent,
|
||||
"deadline": deadline,
|
||||
"finish_time": finishTime,
|
||||
"create_time": t.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
|
||||
// oaApprovalUserOrgName 审批人所属部门名,用作流程节点副标题(如「财务部」),取不到返回空串。
|
||||
func oaApprovalUserOrgName(tid, uid uint64) string {
|
||||
if tid == 0 || uid == 0 {
|
||||
return ""
|
||||
}
|
||||
var tu models.SystemTenantUser
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("tid", tid).Filter("uid", uid).
|
||||
Filter("delete_time__isnull", true).One(&tu); err != nil {
|
||||
return ""
|
||||
}
|
||||
if tu.OrgID == 0 {
|
||||
return ""
|
||||
}
|
||||
var org models.BackendOrganization
|
||||
if err := models.Orm.QueryTable(new(models.BackendOrganization)).
|
||||
Filter("id", tu.OrgID).One(&org); err != nil {
|
||||
return ""
|
||||
}
|
||||
return org.OrgName
|
||||
}
|
||||
|
||||
// 时间线虚拟节点的 node_key:用于标识流程的开始 / 结束,前端据此区分渲染。
|
||||
const (
|
||||
oaApprovalStartKey = "__start__"
|
||||
oaApprovalEndKey = "__end__"
|
||||
)
|
||||
|
||||
// oaApprovalFlowTimeline 组装移动端「审批流程」时间线:
|
||||
// 首尾固定为提交申请(开始)与流程结束(结束),中间是流程产生的节点任务,
|
||||
// 让发起人一眼看出流程当前走到哪、是否已经走完。
|
||||
func oaApprovalFlowTimeline(inst models.ApprovalInstance, tasks []models.ApprovalTask) []map[string]interface{} {
|
||||
nodeTypes := oaApprovalNodeTypes(inst)
|
||||
timeline := make([]map[string]interface{}, 0, len(tasks)+2)
|
||||
timeline = append(timeline, oaApprovalStartNode(inst))
|
||||
for _, t := range tasks {
|
||||
timeline = append(timeline, oaApprovalTaskView(t, t.NodeKey == inst.CurrentNode, nodeTypes[t.NodeKey]))
|
||||
}
|
||||
timeline = append(timeline, oaApprovalEndNode(inst))
|
||||
return timeline
|
||||
}
|
||||
|
||||
// oaApprovalNodeTypes 读流程定义,取各节点类型(开始/审批/通知/结束)。
|
||||
// 流程被删除或改版时返回空表,调用方按审批节点兜底。
|
||||
func oaApprovalNodeTypes(inst models.ApprovalInstance) map[string]int8 {
|
||||
out := make(map[string]int8)
|
||||
flow, err := approvalEngine.LoadFlow(inst.Scope, inst.Tid, inst.BizType, inst.FlowID)
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
for i := range flow.Nodes {
|
||||
out[flow.Nodes[i].NodeKey] = flow.Nodes[i].NodeType
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// oaApprovalStartNode 虚拟开始节点:即发起人提交动作。
|
||||
func oaApprovalStartNode(inst models.ApprovalInstance) map[string]interface{} {
|
||||
timeStr := ""
|
||||
if inst.SubmitTime != nil {
|
||||
timeStr = inst.SubmitTime.Format("2006-01-02 15:04:05")
|
||||
} else if !inst.CreateTime.IsZero() {
|
||||
timeStr = inst.CreateTime.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"id": 0,
|
||||
"node_key": oaApprovalStartKey,
|
||||
"node_name": "提交申请",
|
||||
"node_type": models.ApprovalNodeStart,
|
||||
"approver_id": inst.SubmitUserID,
|
||||
"approver_name": inst.SubmitUserName,
|
||||
"approver_sub": oaApprovalUserOrgName(inst.Tid, inst.SubmitUserID),
|
||||
"multi_mode": 1,
|
||||
"status": models.ApprovalTaskApproved,
|
||||
"status_label": "已提交",
|
||||
"status_tag": "success",
|
||||
"action": 0,
|
||||
"comment": "",
|
||||
"is_current": false,
|
||||
"deadline": "",
|
||||
"finish_time": timeStr,
|
||||
"create_time": timeStr,
|
||||
}
|
||||
}
|
||||
|
||||
// oaApprovalEndNode 虚拟结束节点:实例运行中为「待完成」,结束后展示最终结果与完成时间。
|
||||
func oaApprovalEndNode(inst models.ApprovalInstance) map[string]interface{} {
|
||||
finishTime := ""
|
||||
if inst.FinishTime != nil {
|
||||
finishTime = inst.FinishTime.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
end := map[string]interface{}{
|
||||
"id": 0,
|
||||
"node_key": oaApprovalEndKey,
|
||||
"node_name": "流程结束",
|
||||
"node_type": models.ApprovalNodeEnd,
|
||||
"approver_id": 0,
|
||||
"approver_name": "",
|
||||
"multi_mode": 1,
|
||||
"status": models.ApprovalTaskPending,
|
||||
"status_label": "待完成",
|
||||
"status_tag": "info",
|
||||
"action": 0,
|
||||
"comment": "",
|
||||
"is_current": false,
|
||||
"deadline": "",
|
||||
"finish_time": finishTime,
|
||||
"create_time": finishTime,
|
||||
}
|
||||
switch inst.Status {
|
||||
case models.ApprovalInstanceApproved:
|
||||
end["status"] = models.ApprovalTaskApproved
|
||||
end["status_label"] = "已通过"
|
||||
end["status_tag"] = "success"
|
||||
case models.ApprovalInstanceRejected:
|
||||
end["status"] = models.ApprovalTaskRejected
|
||||
end["status_label"] = "已驳回"
|
||||
end["status_tag"] = "error"
|
||||
case models.ApprovalInstanceWithdrawn:
|
||||
end["status"] = models.ApprovalTaskSkipped
|
||||
end["status_label"] = "已撤回"
|
||||
end["status_tag"] = "info"
|
||||
case models.ApprovalInstanceCanceled:
|
||||
end["status"] = models.ApprovalTaskSkipped
|
||||
end["status_label"] = "已取消"
|
||||
end["status_tag"] = "info"
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
// ============================ 路由方法 ============================
|
||||
@@ -468,7 +604,7 @@ func (c *AppOaController) ApprovalTodo() {
|
||||
if inst.Status != models.ApprovalInstanceRunning {
|
||||
continue
|
||||
}
|
||||
view := oaApprovalTaskView(t, true)
|
||||
view := oaApprovalTaskView(t, true, oaApprovalNodeTypes(inst)[t.NodeKey])
|
||||
view["instance"] = oaApprovalInstanceView(inst)
|
||||
list = append(list, view)
|
||||
}
|
||||
@@ -529,16 +665,13 @@ func (c *AppOaController) ApprovalDetail() {
|
||||
}
|
||||
|
||||
tasks := oaApprovalTasksByInstance(inst.ID)
|
||||
timeline := make([]map[string]interface{}, 0, len(tasks))
|
||||
for _, t := range tasks {
|
||||
timeline = append(timeline, oaApprovalTaskView(t, t.NodeKey == inst.CurrentNode))
|
||||
}
|
||||
timeline := oaApprovalFlowTimeline(inst, tasks)
|
||||
|
||||
c.oaOk(map[string]interface{}{
|
||||
"item": oaApprovalInstanceView(inst),
|
||||
"timeline": timeline,
|
||||
"can_approve": isApprover,
|
||||
"can_withdraw": isSubmitter && inst.Status == models.ApprovalInstanceRunning,
|
||||
"item": oaApprovalInstanceView(inst),
|
||||
"timeline": timeline,
|
||||
"can_approve": isApprover,
|
||||
"can_withdraw": isSubmitter && inst.Status == models.ApprovalInstanceRunning,
|
||||
"current_task_id": currentTaskID,
|
||||
})
|
||||
}
|
||||
@@ -602,8 +735,8 @@ func (c *AppOaController) ApprovalSubmit() {
|
||||
Filter("id", instID).One(&inst)
|
||||
|
||||
c.oaOk(map[string]interface{}{
|
||||
"id": instID,
|
||||
"item": oaApprovalInstanceView(inst),
|
||||
"id": instID,
|
||||
"item": oaApprovalInstanceView(inst),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -662,11 +795,11 @@ func (c *AppOaController) ApprovalApprove() {
|
||||
Filter("id", res.InstanceID).One(&inst)
|
||||
|
||||
c.oaOk(map[string]interface{}{
|
||||
"finished": res.Finished,
|
||||
"instance_stat": res.InstanceStat,
|
||||
"current_node": res.CurrentNode,
|
||||
"message": res.Message,
|
||||
"item": oaApprovalInstanceView(inst),
|
||||
"finished": res.Finished,
|
||||
"instance_stat": res.InstanceStat,
|
||||
"current_node": res.CurrentNode,
|
||||
"message": res.Message,
|
||||
"item": oaApprovalInstanceView(inst),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user