统计公式
++ 本月按时交付率 = 本月未超时完结流程数 ÷ 本月全部完结流程数 × 100% +
++ 当前口径:{summary.onTime} ÷ {summary.total} = {formatRate(summary.rate)} · 超时 {summary.overtime} · 待计算 {summary.pending} +
++ 美术按“品牌策划主管分配任务”至“品牌策划主管审核”计算;内容按规则计至“编导审核”或“内容主管审核”。 +
+共 {summary.total} 条
+流程完结并完成每小时同步后,将自动进入本月交付时效统计。
+| 流程 | +发起人 / 部门 | +计时节点 | +标准时效 | +实际用时 | +判定 | +
|---|---|---|---|---|---|
|
+ {item.title} +{item.businessId || item.id} +{item.projectType} + |
+
+ {item.initiatorName} +{item.initiatorDepartment} + |
+
+ {item.assessment.startNodeLabel} +{formatDate(item.assessment.startedAt, true)} +{item.assessment.endNodeLabel} +{formatDate(item.assessment.finishedAt, true)} + |
+ + {formatDuration(item.assessment.standardDuration, item.assessment.durationUnit)} + | ++ {formatDuration(item.assessment.actualDuration, item.assessment.durationUnit)} + | +
+ 缺少标准配置或关键节点时间 + )} + |
+
{hasFirstPassSource ? '当前首轮通过率' : hasRealProjectSource ? '当前未完结流程' : hasMonthlyLaunchSource ? '本月已完结 / 新品流程总数' : '总览示例值'}
- {isOnTimeDelivery && metric.exampleNumericValue !== undefined - ?{hasFirstPassSource ? formatRate(firstPassPage.summary.rate) : hasRealProjectSource ? projectInsights.total : hasMonthlyLaunchSource ? `${monthlyLaunches.summary.completed}/${monthlyLaunches.summary.total}` : metric.exampleValue}
} +{hasFirstPassSource ? '当前首轮通过率' : hasRealProjectSource ? '当前未完结流程' : hasMonthlyLaunchSource ? '本月已完结 / 新品流程总数' : hasOnTimeDeliverySource ? '本月按时交付率' : '总览示例值'}
+ {hasOnTimeDeliverySource && onTimeDelivery.summary.rate !== null + ?{hasFirstPassSource ? formatRate(firstPassPage.summary.rate) : hasRealProjectSource ? projectInsights.total : hasMonthlyLaunchSource ? `${monthlyLaunches.summary.completed}/${monthlyLaunches.summary.total}` : hasOnTimeDeliverySource ? '—' : metric.exampleValue}
}明细数据
-{hasFirstPassSource ? `V1通过 ${firstPassPage.summary.firstPassApproved} / 全部 ${firstPassPage.summary.totalUploads}` : hasRealProjectSource ? `${projectInsights.total} 条流程快照` : hasMonthlyLaunchSource ? `本月已完结 ${monthlyLaunches.summary.completed} / 当前进行中 ${monthlyLaunches.summary.ongoing}` : '等待业务数据源'}
+{hasFirstPassSource ? `V1通过 ${firstPassPage.summary.firstPassApproved} / 全部 ${firstPassPage.summary.totalUploads}` : hasRealProjectSource ? `${projectInsights.total} 条流程快照` : hasMonthlyLaunchSource ? `本月已完结 ${monthlyLaunches.summary.completed} / 当前进行中 ${monthlyLaunches.summary.ongoing}` : hasOnTimeDeliverySource ? `未超时 ${onTimeDelivery.summary.onTime} / 本月完结 ${onTimeDelivery.summary.total}` : '等待业务数据源'}
同步状态
@@ -286,6 +388,10 @@ export default function CoreMetricDetail({ metric, query, projectInsights, month ? monthlyLaunches.summary.lastSyncedAt ? `每小时增量同步 · ${formatDate(monthlyLaunches.summary.lastSyncedAt, true)}` : monthlyLaunches.summary.syncStatus === 'error' ? '首轮同步失败' : '等待首轮同步' + : hasOnTimeDeliverySource + ? onTimeDelivery.summary.lastSyncedAt + ? `每小时增量同步 · ${formatDate(onTimeDelivery.summary.lastSyncedAt, true)}` + : onTimeDelivery.summary.syncStatus === 'error' ? '首轮同步失败' : '等待首轮同步' : hasFirstPassSource ? '打开页面时读取' : '每日同步待接入'}+
{value}
)} @@ -215,6 +249,14 @@ export default function CoreMetricsDashboard() { {isMonthlyLaunch && monthlyLaunches.status === 'loading' && (正在读取本地流程快照
)} + {isOnTimeDelivery && onTimeDelivery.status === 'success' && ( ++ 未超时 {onTimeDelivery.data.onTime} / 本月完结 {onTimeDelivery.data.total} +
+ )} + {isOnTimeDelivery && onTimeDelivery.status === 'loading' && ( +正在计算本月交付时效
+ )}{metric.description}
@@ -222,13 +264,13 @@ export default function CoreMetricsDashboard() { - {isOngoingWorkflow || isMonthlyLaunch - ? (isOngoingWorkflow ? ongoingWorkflows.status : monthlyLaunches.status) === 'error' ? '刷新页面重试' : '每小时增量同步' + {isOngoingWorkflow || isMonthlyLaunch || isOnTimeDelivery + ? (isOngoingWorkflow ? ongoingWorkflows.status : isMonthlyLaunch ? monthlyLaunches.status : onTimeDelivery.status) === 'error' ? '刷新页面重试' : '每小时增量同步' : isFirstPass ? (firstPass.status === 'error' ? '刷新页面重试' : '打开页面时读取') : '每日同步'} - {isOngoingWorkflow || isMonthlyLaunch - ? (isOngoingWorkflow ? ongoingWorkflows.status : monthlyLaunches.status) === 'error' ? '数据未加载' : '钉钉流程快照' + {isOngoingWorkflow || isMonthlyLaunch || isOnTimeDelivery + ? (isOngoingWorkflow ? ongoingWorkflows.status : isMonthlyLaunch ? monthlyLaunches.status : onTimeDelivery.status) === 'error' ? '数据未加载' : '钉钉流程快照' : isFirstPass ? (firstPass.status === 'error' ? '数据未加载' : '口径已定义') : '公式待接入'} diff --git a/components/department-dashboard/core-metrics.ts b/components/department-dashboard/core-metrics.ts index 76c58efb..1e8ad39f 100644 --- a/components/department-dashboard/core-metrics.ts +++ b/components/department-dashboard/core-metrics.ts @@ -51,10 +51,10 @@ export const CORE_METRICS: CoreMetric[] = [ label: '按时交付', exampleValue: '94.6%', exampleNumericValue: 94.6, - description: '在约定节点内完成交付的项目占比。', + description: '本月未超时完结流程占本月全部完结流程的比例。', icon: Clock3, - detailDescription: '用于核对计划交付时间、实际交付时间与时间偏差。', - plannedFields: ['项目', '计划时间', '实际时间', '时间偏差', '结果'], + detailDescription: '查看本月完结流程的标准时效、实际用时与超时判定;美术和内容流程分别沿用对应外部看板的计算规则。', + plannedFields: ['流程', '发起人', '计时节点', '标准时效', '实际用时', '判定结果'], }, { key: 'first-pass-rate', diff --git a/lib/__tests__/ding-workflow-delivery.test.ts b/lib/__tests__/ding-workflow-delivery.test.ts new file mode 100644 index 00000000..84447b52 --- /dev/null +++ b/lib/__tests__/ding-workflow-delivery.test.ts @@ -0,0 +1,154 @@ +import { assessDingWorkflowDelivery } from '@/lib/ding-workflow-delivery' +import type { DingWorkflowDetailFormFields, OngoingDingWorkflowActiveTask } from '@/lib/ding-workflow-sync' + +const ART_PROCESS_CODE = 'PROC-3571C915-0506-4490-A91A-8AA7EA33F838' +const CONTENT_PROCESS_CODE = 'PROC-AE9FF3E1-A442-4E6A-85CF-0F2B86409673' + +function formFields(overrides: Partial