Dashboard.tsx
9.05 KB
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import { useNavigate } from 'react-router-dom'
import { message } from 'antd'
import { useAppDispatch } from '@/store'
import { openTab } from '@/store/tabs'
import { IconAi } from '@/components/icons'
interface KpiRow {
role?: string
item: string
desc: string
today: string
total: string
red?: boolean
sub?: string
roleSpan?: number
subSpan?: number
}
const kpiRows: KpiRow[] = [
{ role: '核价人员', item: '01/04【新增】新报价单', desc: '报价单明细', today: '-', total: '-', sub: '估价管理流程', roleSpan: 4, subSpan: 5 },
{ item: '02/04 审核后报价单->客户确认价格', desc: '报价单明细', today: '16', total: '16', red: true },
{ item: '03/04 客户不认可->二次确认', desc: '报价单明细', today: '-', total: '-' },
{ item: '04/04 报价单->销售订单', desc: '销售订单明细', today: '1', total: '1', red: true },
{ role: '销售人员', item: '04/04 报价单->销售订单(标签)', desc: '销售订单明细(标签)', today: '0', total: '0', red: true },
{ role: '印前', item: '1/2 新增设计申请单', desc: '设计申请明细', today: '-', total: '-', sub: '设计制作流程', roleSpan: 2, subSpan: 2 },
{ item: '2/2 设计申请->设计制作', desc: '根据设计申请单进行设计制作,当日16:00前审核的为今日任务,16:00后(含)顺延至次日', today: '11', total: '11', red: true },
{ role: '客服部', item: '1/1 研发申请->文件制作', desc: '根据研发申请单,制作电子文件,当日16:00前下达的为今日任务,16:00后(含)顺延至次日', today: '0', total: '12', red: true, sub: '新品研发流程', subSpan: 5 },
{ role: '客服部', item: '1/5 新增研发申请单', desc: '研发申请明细', today: '-', total: '-' },
{ role: '技术研发部', item: '2/5 研发申请>>研发工单', desc: '及时开立研发工单,当日16:00前审核的为今日任务,16:00后(含)顺延至次日', today: '4', total: '4', red: true, roleSpan: 2 },
{ item: '3/5 研发工单>>完工处理', desc: '计划人员在交货日期前确认工单完工', today: '7', total: '7', red: true },
{ role: '客服部', item: '4/5 研发工单->客户确认', desc: '工单完工后需在7天内和客户确认样品', today: '-', total: '2703' },
{ role: '技术研发部', item: '5/5 客户确认->工艺卡', desc: '根据客户已经确认的研发工单,生成产品工艺卡。当日16:00前确认的为今日任务,16:00后(含)顺延至次日', today: '0', total: '1632', red: true },
{ role: '车间主管', item: '1/3 工单(测试部门数)->车间反馈', desc: '车间主管在工单完工前对测试材料进行数据反馈', today: '10', total: '115', red: true, sub: '材料测试流程', subSpan: 3 },
{ item: '2/3 车间反馈->车间补充(多部门)', desc: '补充新材料测试信息,车间反馈次日16:00前的为当日任务,16:00后(含)顺延一日', today: '8', total: '8', red: true, roleSpan: 2 },
{ role: '技术研发部', item: '2/3 车间反馈->工程部反馈(单部门)', desc: '工程部对新材料的测试结果进行反馈,车间反馈次日16:00前的为当日任务,16:00后(含)顺延一日', today: '23', total: '23', red: true },
]
const kpiHeads = ['导航类型', '角色', 'KPI待处理事项(当前行双击进入)', 'KPI内容描述及处理结果(点击蓝色查看明细)', '今日未处理', '未清总数', '子流程']
const navTreeRoles = [
['所有部门', 37428, true], ['核价人员', 17], ['销售人员', 0], ['印前', 11], ['客服部', 30127],
['技术研发部', 47], ['车间主管', 316], ['工艺部', 6], ['物控部', 728], ['生产计划部', 225],
['版房', 120], ['生产车间', 596], ['工艺技术部', 0], ['品质管理部', 589], ['储运部', 3496],
['通用', 0], ['外发组', 867], ['材料仓管', 0], ['机修组', 42], ['应收', 30],
['出纳', 211], ['应付', 0], ['客服', 0],
] as const
const navTreeFlows = [
['估价管理流程', 17], ['设计制作流程', 11], ['新品研发流程', 11],
['材料测试流程', 51], ['订单下达流程', 30118],
] as const
export default function Dashboard() {
const navigate = useNavigate()
const dispatch = useAppDispatch()
const goUserList = () => {
dispatch(openTab({ key: 'userlist', title: '用户列表', path: '/users' }))
navigate('/users')
}
const total = kpiRows.length
return (
<section style={{ height: '100%', overflow: 'auto' }}>
<div className="main-wrap">
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minHeight: 0 }}>
<div className="panel kpi-head">
<span className="title">KPI监控</span>
<span className="stat">今日未处理:<b>37428</b></span>
<span className="sep">|</span>
<span className="stat blue">未清总数:<b>56433</b></span>
<button className="ai-btn" onClick={() => message.info('AI 助手 - 未实现')}>
<IconAi />
小ai同学,请帮我安排今日工作
</button>
</div>
<div className="three-col">
<div className="left-nav nav-tree">
<div className="group"><span className="arrow"></span><span className="ico">📁</span>按角色</div>
{navTreeRoles.map(([name, count, active]) => (
<div key={name as string} className={`item${active ? ' active' : ''}`}>
<span className="ico">📄</span>{name} ({count})
</div>
))}
<div className="group"><span className="arrow"></span><span className="ico">📁</span>按流程</div>
{navTreeFlows.map(([name, count]) => (
<div key={name as string} className="item">
<span className="ico">📄</span>{name} ({count})
</div>
))}
</div>
<div className="center">
<div className="panel" style={{ overflow: 'auto' }}>
<div
className="kpi-body"
style={{ gridTemplateRows: `38px repeat(${total}, minmax(38px, auto))` }}
>
{kpiHeads.map(h => (
<div key={h} className="h">{h}</div>
))}
<div className="center" style={{ gridColumn: '1', gridRow: `2 / span ${total}` }}>按角色</div>
{kpiRows.map((row, i) => {
const altClass = i % 2 === 1 ? 'row-alt' : ''
const curRow = i + 2
const cells: React.ReactNode[] = []
if (row.role) {
cells.push(
<div
key={`role-${i}`}
className={`center ${altClass}`}
style={{ gridColumn: '2', gridRow: `${curRow} / span ${row.roleSpan || 1}` }}
>
{row.role}
</div>,
)
}
cells.push(
<div key={`item-${i}`} className={`link ${altClass}`} style={{ gridColumn: '3', gridRow: `${curRow}` }}>{row.item}</div>,
<div key={`desc-${i}`} className={`link ${altClass}`} style={{ gridColumn: '4', gridRow: `${curRow}` }}>{row.desc}</div>,
<div key={`today-${i}`} className={`num ${row.red ? 'num-red' : ''} ${altClass}`} style={{ gridColumn: '5', gridRow: `${curRow}` }}>{row.today}</div>,
<div key={`total-${i}`} className={`num ${row.red ? 'num-red' : ''} ${altClass}`} style={{ gridColumn: '6', gridRow: `${curRow}` }}>{row.total}</div>,
)
if (row.sub && row.subSpan) {
cells.push(
<div key={`sub-${i}`} className="subproc" style={{ gridColumn: '7', gridRow: `${curRow} / span ${row.subSpan}` }}>
{row.sub}
</div>,
)
}
return cells
})}
</div>
</div>
</div>
</div>
</div>
<div className="panel common-ops" style={{ height: 'fit-content' }}>
<div className="h">常用操作</div>
<a onClick={goUserList}>用户列表</a>
<a onClick={() => message.info('系统功能模块设置 - 未实现')}>系统功能模块设置</a>
</div>
</div>
<footer className="foot">
<span style={{ verticalAlign: 'middle' }}>🛠</span>
©Copyright Antler Software <span className="pipe">|</span> 印刷智慧工厂 <span className="pipe">|</span> 印刷MES <span className="pipe">|</span> 印刷ERP <span className="pipe">|</span> 印刷电商平台 <span className="pipe">|</span> 文件智能处理 <span className="pipe">|</span> 印前自动化 <span className="pipe">|</span> 400-880-6237
<span className="police">
<svg viewBox="0 0 24 24" fill="#3a6cb6"><path d="M12 2l9 4v6c0 5-4 9-9 10-5-1-9-5-9-10V6z" /></svg>
沪ICP备14034791号-1
</span>
</footer>
</section>
)
}