feat: 审批流程改为时间轴样式,增加审批人/抄送人标识

- 审批流程使用时间轴样式显示
- 增加"审批人"和"抄送人"标签
- 已审批节点显示审批人姓名和审批时间
- 未审批节点显示节点名称(人名)
- 当前审批节点高亮显示

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-02-26 00:19:37 +08:00
parent be5dea1d24
commit 76c6e93e36
2 changed files with 77 additions and 22 deletions
+34 -2
View File
@@ -64,6 +64,9 @@
.approverItem {
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
display: flex;
align-items: center;
gap: 8px;
}
.approverItem:last-child {
@@ -73,12 +76,15 @@
.approverName {
font-size: 15px;
color: #333;
margin-bottom: 4px;
}
.approverType {
font-size: 13px;
color: #999;
color: #fff;
background: #666;
padding: 2px 8px;
border-radius: 4px;
flex-shrink: 0;
}
.formData {
@@ -183,6 +189,20 @@
align-items: center;
justify-content: center;
flex-shrink: 0;
background: #e8e8e8;
color: #999;
font-weight: 600;
}
.timelineDot.done {
background: #52c41a;
color: #fff;
}
.timelineDot.current {
background: #1890ff;
color: #fff;
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.2);
}
.timelineDotIcon {
@@ -197,6 +217,18 @@
font-size: 15px;
color: #333;
margin-bottom: 4px;
display: flex;
align-items: center;
gap: 8px;
}
.timelineType {
font-size: 13px;
color: #fff;
background: #666;
padding: 2px 8px;
border-radius: 4px;
flex-shrink: 0;
}
.timelineName {
+43 -20
View File
@@ -331,11 +331,15 @@ export default function ApprovalDetail() {
{/* 当前审批节点 */}
{detail.status === 'pending' && currentApprovers.length > 0 && (
<Card title="当前审批" className={styles.section}>
{currentApprovers.map((item, index) => (
<div key={index} className={styles.approverItem}>
<div className={styles.approverName}>{getNodeApproversNames(item.nodeId, item.nodeType)}</div>
</div>
))}
{currentApprovers.map((item, index) => {
const typeLabel = item.nodeType === 'notify' ? '抄送人' : '审批人'
return (
<div key={index} className={styles.approverItem}>
<span className={styles.approverType}>{typeLabel}</span>
<span className={styles.approverName}>{getNodeApproversNames(item.nodeId, item.nodeType)}</span>
</div>
)
})}
</Card>
)}
@@ -364,31 +368,50 @@ export default function ApprovalDetail() {
{/* 审批流程 */}
{detail.flow?.nodes && detail.flow.nodes.length > 0 && (
<Card title="审批流程" className={styles.section}>
<div className={styles.flowNodes}>
<div className={styles.timeline}>
{detail.flow.nodes.map((node, index) => {
const isCurrent = detail.current_nodes?.includes(node.id)
const record = detail.records.find((r) => r.node_id === node.id)
const records = detail.records.filter(r => r.node_id === node.id && r.action !== 'submit')
const hasApproved = records.length > 0
let status: 'pending' | 'done' = 'pending'
if (record) {
status = 'done'
// 判断节点状态
let nodeStatus: 'pending' | 'done' = 'pending'
if (hasApproved) {
nodeStatus = 'done'
} else if (!isCurrent && index > 0) {
// 检查前面的节点是否完成
const prevNode = detail.flow.nodes[index - 1]
const prevRecord = detail.records.find((r) => r.node_id === prevNode.id)
if (prevRecord) status = 'done'
if (prevRecord) nodeStatus = 'done'
}
// 获取节点类型标签
const typeLabel = node.type === 'notify' ? '抄送人' : '审批人'
// 获取显示名称和审批时间
let displayName = node.name || '待定'
let approvalTime = ''
if (hasApproved && records[0]) {
displayName = records[0].approver?.name || displayName
approvalTime = formatTime(records[0].created_at)
}
return (
<div
key={node.id}
className={`${styles.flowNode} ${styles[status]} ${isCurrent ? styles.current : ''}`}
>
<div className={styles.flowNodeDot}>
{status === 'done' ? '✓' : index + 1}
<div key={node.id} className={styles.timelineItem}>
<div className={`${styles.timelineDot} ${nodeStatus === 'done' ? styles.done : ''} ${isCurrent ? styles.current : ''}`}>
{nodeStatus === 'done' ? '✓' : index + 1}
</div>
<div className={styles.flowNodeContent}>
<div className={styles.flowNodeName}>{getNodeDisplayName(node)}</div>
<div className={styles.timelineContent}>
<div className={styles.timelineTitle}>
<span className={styles.timelineType}>{typeLabel}</span>
<span className={styles.timelineName}>{displayName}</span>
</div>
{approvalTime && (
<div className={styles.timelineTime}>{approvalTime}</div>
)}
{hasApproved && records[0]?.comment && (
<div className={styles.timelineComment}>备注: {records[0].comment}</div>
)}
</div>
</div>
)