feat: 新增产线看板功能并优化多端系统体验

1. 新增SSE看板广播机制,业务操作后主动推送刷新事件
2. 新增产线工序横道图与工位状态展示面板
3. 移除dashboard无用的three.js依赖
4. 重构WMS客户端布局与WMS前端资源哈希
5. 新增工位终端时钟图标与大屏自适应布局
6. 新增系统截图脚本与说明书生成工具
7. 修复多处代码细节与空值处理逻辑
This commit is contained in:
SunYF
2026-09-04 17:31:18 +08:00
parent b6799c9de4
commit 92f0439d89
64 changed files with 2263 additions and 633 deletions
+33 -41
View File
@@ -1,58 +1,32 @@
import { useEffect, useState } from 'react';
import { Layout, Nav, Tag, Spin } from '@douyinfe/semi-ui';
import { IconMonitorStroked, IconSaveStroked, IconGridView } from '@douyinfe/semi-icons';
import { useDashboardData } from '@bj_power_dashboard/hooks/useDashboardData';
import { ProductionBoard } from '@bj_power_dashboard/pages/ProductionBoard';
import { WarehouseBoard } from '@bj_power_dashboard/pages/WarehouseBoard';
import { LineModel } from '@bj_power_dashboard/pages/LineModel';
import { ErrorRetry } from '@bj_power_dashboard/components/ErrorRetry';
type PageKey = 'production' | 'warehouse' | 'model';
const navItems = [
{ itemKey: 'production', text: '生产总览', icon: <IconMonitorStroked /> },
{ itemKey: 'warehouse', text: '仓储动态', icon: <IconSaveStroked /> },
{ itemKey: 'model', text: '产线孪生', icon: <IconGridView /> },
];
const CYCLE_ORDER: PageKey[] = ['production', 'warehouse', 'model'];
const CYCLE_MS = 40_000;
import { useState } from 'react';
import { Layout, Tag, Spin } from '@douyinfe/semi-ui';
import { useDashboardData } from './hooks/useDashboardData';
import { ProductionBoard } from './pages/ProductionBoard';
import { WarehouseBoard } from './pages/WarehouseBoard';
import { LineModel } from './pages/LineModel';
import { ErrorRetry } from './components/ErrorRetry';
export function App() {
const [page, setPage] = useState<PageKey>('production');
const { data: dashboard, mode, error, retry } = useDashboardData();
const loading = !dashboard && !error;
const [now, setNow] = useState(() => new Date());
// 无人值守自动轮播:40s 切下一屏;手动点选后重新计
useEffect(() => {
const timer = setInterval(() => {
setPage((cur) => {
const idx = CYCLE_ORDER.indexOf(cur);
return CYCLE_ORDER[(idx + 1) % CYCLE_ORDER.length];
});
}, CYCLE_MS);
return () => clearInterval(timer);
}, [page]);
const selectPage = (k: string) => setPage(k as PageKey);
// 时
setTimeout(() => setNow(new Date()), 1000);
return (
<Layout className="app-shell">
<Layout.Header className="app-header">
<div className="app-title">线 · </div>
<div className="app-meta">
{mode === 'sse' && <Tag color="green"></Tag>}
{mode === 'polling' && <Tag color="blue"></Tag>}
{mode === 'demo' && <Tag color="amber"></Tag>}
{mode === 'init' && <Tag color="grey"></Tag>}
<span className="clock">{new Date().toLocaleTimeString('zh-CN')}</span>
<span className="clock">{now.toLocaleTimeString('zh-CN')}</span>
<span className="date">{now.toLocaleDateString('zh-CN', { weekday: 'long' })}</span>
</div>
</Layout.Header>
<Layout.Sider style={{ background: 'transparent' }}>
<Nav selectedKeys={[page]} onSelect={(k) => selectPage(String(k.itemKey))} items={navItems} />
</Layout.Sider>
<Layout.Content className="app-content">
{loading ? (
<div style={{ display: 'flex', justifyContent: 'center', padding: 80 }}>
@@ -60,9 +34,27 @@ export function App() {
</div>
) : (
<ErrorRetry error={error} mode={mode} loading={loading} onRetry={retry}>
{dashboard && page === 'production' && <ProductionBoard data={dashboard} />}
{dashboard && page === 'warehouse' && <WarehouseBoard data={dashboard} />}
{dashboard && page === 'model' && <LineModel data={dashboard} />}
{dashboard ? (
<div className="dashboard-grid">
<section className="dash-section production">
<div className="board-card">
<ProductionBoard data={dashboard} />
</div>
</section>
<section className="dash-section warehouse">
<div className="board-card">
<WarehouseBoard data={dashboard} />
</div>
</section>
<section className="dash-section model">
<LineModel data={dashboard} />
</section>
</div>
) : (
<div style={{ padding: 40, textAlign: 'center', color: '#94a3b8' }}>
线
</div>
)}
</ErrorRetry>
)}
</Layout.Content>