File size: 6,290 Bytes
f4cac62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**
 * @license
 * SPDX-License-Identifier: Apache-2.0
 */

import React from 'react';
import { AccountabilityCase } from '../types';
import { Check, AlertCircle, Clock, CheckCircle2 } from 'lucide-react';

interface TimelineProps {
  currentCase: AccountabilityCase;
}

export const STEPS_DEFINITION = [
  { index: 1, name: '启动立案', desc: '成立问责调查组,录入案件基础信息' },
  { index: 2, name: '调查核实', desc: '开展谈话、送达事实见面材料、核查申辩、形成调查报告' },
  { index: 3, name: '合规审理', desc: '审理职责部门受理并出具合规审理意见书' },
  { index: 4, name: '会议审议', desc: '问责委员会委员召开会议并线上表决与签名' },
  { index: 5, name: '申诉窗口期', desc: '10个工作日内申诉确认或直接进入发文阶段' },
  { index: 6, name: '提起申诉', desc: '被问责人提交申诉材料(有异议时触发)' },
  { index: 7, name: '指派复查', desc: '指派审理组或协助调查组,出具复查意见' },
  { index: 8, name: '按程序复议', desc: '重新提请委员会,做出复议决议' },
  { index: 9, name: '发文归档', desc: '下发红头问责文件,抄送人力资源部归档' }
];

export default function CaseWorkflowTimeline({ currentCase }: TimelineProps) {
  const currentStep = currentCase.currentStep;
  
  // 判断哪些步骤被跳过或不需要
  // 如果案件没有申诉(在步骤5时选择无异议,或者已直接跳到步骤9),那么 6, 7, 8 被视为 skipped
  const isSkippedStep = (stepIdx: number): boolean => {
    if (!currentCase.hasAppeal && [6, 7, 8].includes(stepIdx)) {
      // 已经完成申诉期,或者在申诉期之前,且未触发申诉
      if (currentStep === 9 || currentStep === 5) {
        return true;
      }
    }
    return false;
  };

  const getStepStatus = (stepIdx: number): 'completed' | 'active' | 'pending' | 'skipped' => {
    if (isSkippedStep(stepIdx)) return 'skipped';
    if (currentStep > stepIdx) return 'completed';
    if (currentStep === stepIdx) return 'active';
    return 'pending';
  };

  // 期限计算说明
  const limitText = currentCase.category === 'asset' 
    ? '问题资产:启动后90天内需完成调查' 
    : '非问题资产:发起后30个工作日内需完成调查';

  return (
    <div className="bg-white border border-slate-200 rounded-lg p-4 shadow-2xs" id="workflow-timeline-card">
      <div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-2 mb-4 border-b border-slate-100 pb-3">
        <div>
          <h3 className="text-sm font-bold text-slate-900 flex items-center gap-1.5">
            <Clock className="w-4 h-4 text-slate-500" />
            银行问责生命周期追踪
          </h3>
          <p className="text-[11px] text-slate-500 mt-0.5">流程闭环可追溯,确保每个程序节点合规守信</p>
        </div>
        <div className="flex items-center gap-1.5 bg-slate-50 border border-slate-200 px-2.5 py-1 rounded text-[11px] font-medium text-slate-600">
          <AlertCircle className="w-3.5 h-3.5 text-amber-500" />
          <span>时限要求:{limitText}</span>
        </div>
      </div>

      {/* 9步流程横向/纵向进度条 */}
      <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-9 gap-2 relative">
        {STEPS_DEFINITION.map((step) => {
          const status = getStepStatus(step.index);
          
          return (
            <div 
              key={step.index} 
              className={`relative flex flex-col p-2 rounded border transition-all ${
                status === 'completed' 
                  ? 'bg-slate-50/80 border-slate-200 text-slate-700' 
                  : status === 'active'
                  ? 'bg-blue-50/50 border-blue-200 ring-2 ring-blue-500/5 text-blue-900'
                  : status === 'skipped'
                  ? 'bg-slate-100/50 border-slate-200/50 text-slate-400 opacity-60'
                  : 'bg-white border-slate-100 text-slate-400'
              }`}
            >
              {/* 编号 & 状态图标 */}
              <div className="flex justify-between items-center mb-1">
                <span className={`text-[9px] font-mono font-bold uppercase tracking-wider px-1 py-0.5 rounded ${
                  status === 'completed'
                    ? 'bg-slate-200 text-slate-700'
                    : status === 'active'
                    ? 'bg-blue-600 text-white'
                    : status === 'skipped'
                    ? 'bg-slate-200/60 text-slate-400'
                    : 'bg-slate-100 text-slate-400'
                }`}>
                  STEP 0{step.index}
                </span>
                
                {status === 'completed' && <Check className="w-3.5 h-3.5 text-emerald-600" />}
                {status === 'active' && (
                  <span className="flex h-1.5 w-1.5 relative">
                    <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75"></span>
                    <span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-blue-600"></span>
                  </span>
                )}
                {status === 'skipped' && <span className="text-[9px] text-slate-400">跳过</span>}
              </div>

              {/* 步骤名称 */}
              <h4 className={`text-[11px] font-bold ${
                status === 'active' ? 'text-blue-600' : 'text-slate-800'
              }`}>
                {step.name}
              </h4>
              
              {/* 简单说明 */}
              <p className="text-[10px] leading-relaxed text-slate-500 mt-1 line-clamp-2 md:line-clamp-none">
                {step.desc}
              </p>

              {/* 进度提示线 - 仅在非最后一步且大屏幕时显示 */}
              {step.index < 9 && (
                <div className="hidden lg:block absolute -right-1.5 top-1/2 -translate-y-1/2 z-10">
                  <span className={`text-sm font-bold ${
                    status === 'completed' ? 'text-slate-300' : 'text-slate-100'
                  }`}>→</span>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}