Bläddra i källkod

S8审批流,看板 bug

YY968XX 3 månader sedan
förälder
incheckning
373513b4a8

+ 2 - 0
Web/src/views/aidop/s8/api/s8ExceptionApi.ts

@@ -28,6 +28,8 @@ export interface S8ExceptionRow {
 	timeoutFlag: boolean;
 	createdAt: string;
 	closedAt?: string | null;
+	activeFlowInstanceId?: number | null;
+	activeFlowBizType?: string | null;
 }
 
 export interface S8DecisionRow {

+ 14 - 16
Web/src/views/aidop/s8/exceptions/S8TaskDetailPage.vue

@@ -28,13 +28,7 @@ const imageEvidences = computed(() => evidences.value.filter((item) => imagePatt
 const fileEvidences = computed(() => evidences.value.filter((item) => !imagePattern.test(item.fileUrl || item.fileName)));
 const currentStatus = computed(() => String(detail.value?.status || ''));
 const hasActiveFlow = computed(() => !!detail.value?.activeFlowInstanceId);
-const activeBizType = computed(() => {
-	if (!hasActiveFlow.value) return '';
-	const lastAction = [...timeline.value].reverse().find(
-		(t) => t.actionCode === 'ESCALATE_START' || t.actionCode === 'CLOSURE_START',
-	);
-	return lastAction?.actionCode === 'ESCALATE_START' ? 'EXCEPTION_ESCALATION' : 'EXCEPTION_CLOSURE';
-});
+const activeBizType = computed(() => detail.value?.activeFlowBizType ?? '');
 const canClaim = computed(() => currentStatus.value === 'NEW');
 const canTransfer = computed(() => !['', 'CLOSED'].includes(currentStatus.value));
 const canUpgrade = computed(() => !hasActiveFlow.value && ['ASSIGNED', 'IN_PROGRESS'].includes(currentStatus.value));
@@ -66,7 +60,8 @@ async function loadDetail() {
 }
 
 async function loadEmployees() {
-	employees.value = (await s8ExceptionApi.employees({ factoryRefId: 1 })) as typeof employees.value;
+	const factoryRefId = Number(detail.value?.factoryId ?? 1);
+	employees.value = (await s8ExceptionApi.employees({ factoryRefId })) as typeof employees.value;
 }
 
 function openAction(mode: string) {
@@ -83,7 +78,7 @@ function actionTitle() {
 			transfer: '转派',
 			upgrade: '升级',
 			reject: '驳回',
-			close: '关闭',
+			close: '提交关闭申请',
 			comment: '补充说明',
 		}[dialogMode.value] ?? '动作'
 	);
@@ -133,7 +128,8 @@ async function submitAction() {
 }
 
 onMounted(async () => {
-	await Promise.all([loadDetail(), loadEmployees()]);
+	await loadDetail();
+	await loadEmployees();
 });
 </script>
 
@@ -162,12 +158,14 @@ onMounted(async () => {
 				<el-col :span="8">
 					<el-card shadow="never">
 						<template #header>操作面板</template>
-						<ApprovalPanel
-							v-if="hasActiveFlow"
-							:biz-type="activeBizType"
-							:biz-id="detail.id"
-							@completed="onApprovalCompleted"
-						/>
+							<ApprovalPanel
+								v-if="hasActiveFlow"
+								:biz-type="activeBizType"
+								:biz-id="detail.id"
+								@refresh="onApprovalCompleted"
+								@flow-started="onApprovalCompleted"
+								@flow-completed="onApprovalCompleted"
+							/>
 						<template v-else>
 							<div class="action-grid">
 								<el-button type="primary" :disabled="!canClaim" @click="openAction('claim')">认领</el-button>

+ 3 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Dto/S8/AdoS8Dtos.cs

@@ -24,6 +24,7 @@ public class AdoS8ExceptionQueryDto
 public class AdoS8ExceptionListItemDto
 {
     public long Id { get; set; }
+    public long FactoryId { get; set; }
     public string ExceptionCode { get; set; } = string.Empty;
     public string Title { get; set; } = string.Empty;
     public string Status { get; set; } = string.Empty;
@@ -55,6 +56,8 @@ public class AdoS8ExceptionDetailDto : AdoS8ExceptionListItemDto
     public string? ReporterName { get; set; }
     public DateTime? AssignedAt { get; set; }
     public DateTime? UpdatedAt { get; set; }
+    public long? ActiveFlowInstanceId { get; set; }
+    public string? ActiveFlowBizType { get; set; }
 }
 
 public class AdoS8ManualReportCreateDto

+ 4 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Entity/S8/AdoS8Exception.cs

@@ -90,6 +90,10 @@ public class AdoS8Exception
     [SugarColumn(ColumnName = "active_flow_instance_id", IsNullable = true)]
     public long? ActiveFlowInstanceId { get; set; }
 
+    /// <summary>当前进行中的审批业务类型(EXCEPTION_ESCALATION / EXCEPTION_CLOSURE)</summary>
+    [SugarColumn(ColumnName = "active_flow_biz_type", Length = 32, IsNullable = true)]
+    public string? ActiveFlowBizType { get; set; }
+
     [SugarColumn(ColumnName = "is_deleted", ColumnDataType = "boolean")]
     public bool IsDeleted { get; set; }
 

+ 15 - 5
server/Plugins/Admin.NET.Plugin.AiDOP/Service/S8/ExceptionClosureBizHandler.cs

@@ -27,15 +27,17 @@ public class ExceptionClosureBizHandler : IFlowBizHandler, ITransient
     {
         var e = await _rep.GetByIdAsync(bizId) ?? throw new S8BizException("异常不存在");
         e.ActiveFlowInstanceId = instanceId;
+        e.ActiveFlowBizType = BizType;
         e.UpdatedAt = DateTime.Now;
         await _rep.UpdateAsync(e);
-        await InsertTimelineAsync(e.Id, "CLOSURE_START", "发起关闭确认", null, null, instanceId, null);
+        await InsertTimelineAsync(e.Id, "CLOSE_START", "发起关闭确认", null, null, instanceId, null);
     }
 
     public async Task OnFlowCompleted(long bizId, long instanceId, FlowInstanceStatusEnum finalStatus, long? lastApproverId)
     {
         var e = await _rep.GetByIdAsync(bizId) ?? throw new S8BizException("异常不存在");
         e.ActiveFlowInstanceId = null;
+        e.ActiveFlowBizType = null;
         e.UpdatedAt = DateTime.Now;
 
         if (finalStatus == FlowInstanceStatusEnum.Approved)
@@ -43,14 +45,21 @@ public class ExceptionClosureBizHandler : IFlowBizHandler, ITransient
             e.Status = "CLOSED";
             e.ClosedAt = DateTime.Now;
             await _rep.UpdateAsync(e);
-            await InsertTimelineAsync(e.Id, "CLOSURE_APPROVED", "关闭已确认", "RESOLVED", "CLOSED",
+            await InsertTimelineAsync(e.Id, "CLOSE_APPROVED", "关闭已确认", "RESOLVED", "CLOSED",
+                instanceId, lastApproverId);
+        }
+        else if (finalStatus == FlowInstanceStatusEnum.Cancelled)
+        {
+            // 撤回:状态维持 RESOLVED,不写终态
+            await _rep.UpdateAsync(e);
+            await InsertTimelineAsync(e.Id, "CLOSE_CANCELLED", "处理人撤回关闭申请", null, null,
                 instanceId, lastApproverId);
         }
         else
         {
             e.Status = "IN_PROGRESS";
             await _rep.UpdateAsync(e);
-            await InsertTimelineAsync(e.Id, "CLOSURE_REJECTED", "关闭被驳回", "RESOLVED", "IN_PROGRESS",
+            await InsertTimelineAsync(e.Id, "CLOSE_REJECTED", "关闭被驳回", "RESOLVED", "IN_PROGRESS",
                 instanceId, lastApproverId);
         }
     }
@@ -61,14 +70,14 @@ public class ExceptionClosureBizHandler : IFlowBizHandler, ITransient
         if (e == null) return new Dictionary<string, object>();
         return new Dictionary<string, object>
         {
-            ["sceneCode"] = e.SceneCode,
+            ["sceneCode"] = e.SceneCode ?? string.Empty,
+            ["factoryCode"] = e.FactoryId.ToString(),
         };
     }
 
     private async Task InsertTimelineAsync(long exceptionId, string code, string label,
         string? from, string? to, long? instanceId, long? approverId)
     {
-        // P4-17: 补齐审批人 ID 到 Timeline 留痕
         string? remark = null;
         if (instanceId.HasValue && approverId.HasValue)
             remark = $"审批实例ID: {instanceId},审批人: {approverId}";
@@ -84,6 +93,7 @@ public class ExceptionClosureBizHandler : IFlowBizHandler, ITransient
             ActionLabel = label,
             FromStatus = from,
             ToStatus = to,
+            OperatorId = approverId,
             ActionRemark = remark,
             CreatedAt = DateTime.Now
         });

+ 16 - 4
server/Plugins/Admin.NET.Plugin.AiDOP/Service/S8/ExceptionEscalationBizHandler.cs

@@ -28,6 +28,7 @@ public class ExceptionEscalationBizHandler : IFlowBizHandler, ITransient
         var e = await _rep.GetByIdAsync(bizId) ?? throw new S8BizException("异常不存在");
         e.Status = "ESCALATED";
         e.ActiveFlowInstanceId = instanceId;
+        e.ActiveFlowBizType = BizType;
         e.UpdatedAt = DateTime.Now;
         await _rep.UpdateAsync(e);
         await InsertTimelineAsync(e.Id, "ESCALATE_START", "发起升级", null, "ESCALATED", instanceId, null);
@@ -37,15 +38,25 @@ public class ExceptionEscalationBizHandler : IFlowBizHandler, ITransient
     {
         var e = await _rep.GetByIdAsync(bizId) ?? throw new S8BizException("异常不存在");
         e.ActiveFlowInstanceId = null;
+        e.ActiveFlowBizType = null;
         e.UpdatedAt = DateTime.Now;
 
         if (finalStatus == FlowInstanceStatusEnum.Approved)
         {
             e.Status = "ASSIGNED";
+            if (lastApproverId.HasValue)
+                e.AssigneeId = lastApproverId.Value;
             await _rep.UpdateAsync(e);
             await InsertTimelineAsync(e.Id, "ESCALATE_APPROVED", "升级已确认", "ESCALATED", "ASSIGNED",
                 instanceId, lastApproverId);
         }
+        else if (finalStatus == FlowInstanceStatusEnum.Cancelled)
+        {
+            e.Status = "IN_PROGRESS";
+            await _rep.UpdateAsync(e);
+            await InsertTimelineAsync(e.Id, "ESCALATE_CANCELLED", "发起人撤回升级申请", "ESCALATED", "IN_PROGRESS",
+                instanceId, lastApproverId);
+        }
         else
         {
             e.Status = "IN_PROGRESS";
@@ -61,16 +72,16 @@ public class ExceptionEscalationBizHandler : IFlowBizHandler, ITransient
         if (e == null) return new Dictionary<string, object>();
         return new Dictionary<string, object>
         {
-            ["severity"] = e.Severity,
-            ["sceneCode"] = e.SceneCode,
-            ["priorityLevel"] = e.PriorityLevel,
+            ["severity"] = e.Severity ?? string.Empty,
+            ["sceneCode"] = e.SceneCode ?? string.Empty,
+            ["priorityLevel"] = e.PriorityLevel ?? string.Empty,
+            ["factoryCode"] = e.FactoryId.ToString(),
         };
     }
 
     private async Task InsertTimelineAsync(long exceptionId, string code, string label,
         string? from, string? to, long? instanceId, long? approverId)
     {
-        // P4-17: 补齐审批人 ID 到 Timeline 留痕
         string? remark = null;
         if (instanceId.HasValue && approverId.HasValue)
             remark = $"审批实例ID: {instanceId},审批人: {approverId}";
@@ -86,6 +97,7 @@ public class ExceptionEscalationBizHandler : IFlowBizHandler, ITransient
             ActionLabel = label,
             FromStatus = from,
             ToStatus = to,
+            OperatorId = approverId,
             ActionRemark = remark,
             CreatedAt = DateTime.Now
         });

+ 6 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Service/S8/S8ExceptionService.cs

@@ -53,6 +53,7 @@ public class S8ExceptionService : ITransient
             .Select((e, sc) => new AdoS8ExceptionListItemDto
             {
                 Id = e.Id,
+                FactoryId = e.FactoryId,
                 ExceptionCode = e.ExceptionCode,
                 Title = e.Title,
                 Status = e.Status,
@@ -112,6 +113,7 @@ public class S8ExceptionService : ITransient
             .Select((e, sc) => new AdoS8ExceptionDetailDto
             {
                 Id = e.Id,
+                FactoryId = e.FactoryId,
                 ExceptionCode = e.ExceptionCode,
                 Title = e.Title,
                 Description = e.Description,
@@ -132,7 +134,9 @@ public class S8ExceptionService : ITransient
                 CreatedAt = e.CreatedAt,
                 ClosedAt = e.ClosedAt,
                 AssignedAt = e.AssignedAt,
-                UpdatedAt = e.UpdatedAt
+                UpdatedAt = e.UpdatedAt,
+                ActiveFlowInstanceId = e.ActiveFlowInstanceId,
+                ActiveFlowBizType = e.ActiveFlowBizType
             })
             .Take(1)
             .ToListAsync();
@@ -191,6 +195,7 @@ public class S8ExceptionService : ITransient
             }
             else
             {
+                row.ResponsibleDeptName = deptMap.GetValueOrDefault(row.ResponsibleDeptId);
                 row.AssigneeName = row.AssigneeId.HasValue ? empMap.GetValueOrDefault(row.AssigneeId.Value) : null;
             }
         }