172 lines
6.0 KiB
Go
172 lines
6.0 KiB
Go
package controllers
|
||
|
||
import (
|
||
"fmt"
|
||
"time"
|
||
|
||
"server/models"
|
||
"server/services/approval"
|
||
|
||
"github.com/beego/beego/v2/client/orm"
|
||
)
|
||
|
||
// =============================================================
|
||
// 域名申请 × 审批流引擎 的接入层(严格模式,无单级兼容)
|
||
//
|
||
// 口径:
|
||
// - 域名申请提交必须命中已配置的默认流程,走引擎多级流转;
|
||
// - 未配置流程 / 节点无有效审批人 → 提交失败并回滚刚创建的域名行,绝不留下无法审批的脏数据;
|
||
// - 审核只能通过引擎:必须存在在途实例且命中当前审批人的待办,否则拒绝操作。
|
||
// =============================================================
|
||
|
||
// submitDomainApprovalChecked 将域名提交进平台侧审批流。
|
||
// 成功返回空串;失败则软删回滚刚创建的域名行,并返回给前端的错误文案。
|
||
func submitDomainApprovalChecked(domainRowID, bizTid, submitUID uint64, submitName, fullDomain string) string {
|
||
_, err := approval.Submit(approval.SubmitInput{
|
||
Scope: models.ApprovalScopePlatform,
|
||
BizTid: bizTid,
|
||
BizType: models.ApprovalBizDomain,
|
||
BizID: domainRowID,
|
||
BizTitle: fullDomain,
|
||
SubmitUID: submitUID,
|
||
SubmitName: submitName,
|
||
})
|
||
if err == nil {
|
||
return ""
|
||
}
|
||
// 提交失败:回滚刚创建的域名行(软删除),避免出现无法审批的待审僵尸数据
|
||
_, _ = models.Orm.QueryTable(new(models.SystemTenantDomain)).
|
||
Filter("id", domainRowID).Update(map[string]interface{}{"delete_time": time.Now()})
|
||
if _, ok := err.(*approval.ErrNoFlow); ok {
|
||
return "平台尚未配置域名审批流程,无法提交申请"
|
||
}
|
||
if _, ok := err.(*approval.ErrNoApprover); ok {
|
||
return "域名审批流程未配置有效审批人,无法提交申请"
|
||
}
|
||
return "提交审批失败:" + err.Error()
|
||
}
|
||
|
||
// findRunningDomainInstance 取某域名当前在途的平台侧审批实例
|
||
func findRunningDomainInstance(domainID uint64) (*models.ApprovalInstance, bool) {
|
||
var inst models.ApprovalInstance
|
||
err := models.Orm.QueryTable(new(models.ApprovalInstance)).
|
||
Filter("scope", models.ApprovalScopePlatform).
|
||
Filter("biz_type", models.ApprovalBizDomain).
|
||
Filter("biz_id", domainID).
|
||
Filter("status", models.ApprovalInstanceRunning).
|
||
Filter("is_deleted", 0).
|
||
OrderBy("-id").One(&inst)
|
||
if err == orm.ErrNoRows {
|
||
return nil, false
|
||
}
|
||
if err != nil {
|
||
return nil, false
|
||
}
|
||
return &inst, true
|
||
}
|
||
|
||
// myPendingDomainTask 取指定审批人在该实例上的当前待办任务
|
||
func myPendingDomainTask(instID, approverID uint64) (*models.ApprovalTask, bool) {
|
||
var task models.ApprovalTask
|
||
err := models.Orm.QueryTable(new(models.ApprovalTask)).
|
||
Filter("instance_id", instID).
|
||
Filter("approver_id", approverID).
|
||
Filter("status", models.ApprovalTaskPending).
|
||
Filter("is_deleted", 0).
|
||
OrderBy("sort", "id").One(&task)
|
||
if err != nil {
|
||
return nil, false
|
||
}
|
||
return &task, true
|
||
}
|
||
|
||
// applyDomainApprovalResult 依据引擎结果回写域名状态(仅实例终结时改动)
|
||
func applyDomainApprovalResult(domainID uint64, res *approval.ApproveResult) {
|
||
if res == nil || !res.Finished {
|
||
return
|
||
}
|
||
newStatus := 2 // 默认拒绝/驳回
|
||
if res.InstanceStat == models.ApprovalInstanceApproved {
|
||
newStatus = 1 // 通过生效
|
||
}
|
||
now := time.Now()
|
||
_, _ = models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("id", domainID).
|
||
Update(orm.Params{"status": newStatus, "update_time": now})
|
||
}
|
||
|
||
// domainApprovalProgress 组装域名审批进度(节点 + 任务),供平台端展示
|
||
func domainApprovalProgress(domainID uint64) map[string]interface{} {
|
||
inst, ok := findRunningDomainInstance(domainID)
|
||
if !ok {
|
||
// 无在途实例:可能未走引擎(单级审核)或已结束
|
||
return map[string]interface{}{"engine": false}
|
||
}
|
||
flow, err := approval.LoadFlow(models.ApprovalScopePlatform, 0, models.ApprovalBizDomain, inst.FlowID)
|
||
nodes := []map[string]interface{}{}
|
||
if err == nil && flow != nil {
|
||
for _, nd := range flow.Nodes {
|
||
nodes = append(nodes, map[string]interface{}{
|
||
"node_key": nd.NodeKey,
|
||
"node_name": nd.NodeName,
|
||
"node_type": nd.NodeType,
|
||
"sort": nd.Sort,
|
||
})
|
||
}
|
||
}
|
||
var tasks []models.ApprovalTask
|
||
_, _ = models.Orm.QueryTable(new(models.ApprovalTask)).
|
||
Filter("instance_id", inst.ID).Filter("is_deleted", 0).
|
||
OrderBy("sort", "id").All(&tasks)
|
||
taskList := make([]map[string]interface{}, 0, len(tasks))
|
||
for _, t := range tasks {
|
||
taskList = append(taskList, map[string]interface{}{
|
||
"id": t.ID,
|
||
"node_key": t.NodeKey,
|
||
"node_name": t.NodeName,
|
||
"approver_id": t.ApproverID,
|
||
"approver_name": t.ApproverName,
|
||
"status": t.Status,
|
||
"action": t.Action,
|
||
"comment": t.Comment,
|
||
})
|
||
}
|
||
return map[string]interface{}{
|
||
"engine": true,
|
||
"instance_id": inst.ID,
|
||
"current_node": inst.CurrentNode,
|
||
"status": inst.Status,
|
||
"nodes": nodes,
|
||
"tasks": taskList,
|
||
}
|
||
}
|
||
|
||
// engineDomainAudit 平台端审批入口(严格引擎驱动):
|
||
// 必须存在在途实例且命中当前审批人的待办;否则拒绝,不做任何单级回退。
|
||
func engineDomainAudit(domainID, adminID uint64, pass bool, comment string, bizTid uint64) (msg string, code int) {
|
||
inst, ok := findRunningDomainInstance(domainID)
|
||
if !ok {
|
||
return "该域名申请未进入审批流程(未配置流程或已处理)", 400
|
||
}
|
||
task, ok := myPendingDomainTask(inst.ID, adminID)
|
||
if !ok {
|
||
return "该单据在审批流程中,当前不在您的待办节点", 403
|
||
}
|
||
res, err := approval.Approve(task.ID, approval.ApproveInput{
|
||
ApproverID: adminID,
|
||
Pass: pass,
|
||
Comment: comment,
|
||
BizTid: bizTid,
|
||
})
|
||
if err != nil {
|
||
return err.Error(), 400
|
||
}
|
||
applyDomainApprovalResult(domainID, res)
|
||
if res.Finished {
|
||
if res.InstanceStat == models.ApprovalInstanceApproved {
|
||
return "审批通过,域名已生效", 200
|
||
}
|
||
return "已驳回", 200
|
||
}
|
||
return fmt.Sprintf("已%s,流程继续(%s)", map[bool]string{true: "通过", false: "驳回"}[pass], res.Message), 200
|
||
}
|