feat: 优化共享页眉组件,增加页面状态识别及导航功能
This commit is contained in:
@@ -1,15 +1,25 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate, useLocation } from 'react-router-dom';
|
||||||
import Icon from './Icons';
|
import Icon from './Icons';
|
||||||
|
import { PAGE_ORDER, usePageIndex } from '../utils/pageNav';
|
||||||
|
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'
|
||||||
|
|
||||||
/* =========================================================
|
/* =========================================================
|
||||||
共享页眉 —— 两个大屏页面(数据大屏 / 数字孪生)统一风格
|
共享页眉 —— 所有大屏页面统一(由 ScreenLayout 注入)
|
||||||
仅通过 props 区分:导航目标、状态文案
|
状态文案按当前页面自动识别;左右键循环 + 可点击按钮切换
|
||||||
========================================================= */
|
========================================================= */
|
||||||
|
|
||||||
export default function PageHeader({ nav, status = '数据实时' }) {
|
const STATUS_BY_PATH = {
|
||||||
|
'/': '数据实时',
|
||||||
|
'/twin': '3D 实时',
|
||||||
|
'/screen': '媒体播放',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function PageHeader() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
const [now, setNow] = useState(new Date());
|
const [now, setNow] = useState(new Date());
|
||||||
|
const pageIdx = usePageIndex();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const iv = setInterval(() => setNow(new Date()), 1000);
|
const iv = setInterval(() => setNow(new Date()), 1000);
|
||||||
@@ -19,33 +29,43 @@ export default function PageHeader({ nav, status = '数据实时' }) {
|
|||||||
const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
|
const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
|
||||||
const week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()];
|
const week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()];
|
||||||
const timeStr = now.toLocaleTimeString('zh-CN', { hour12: false });
|
const timeStr = now.toLocaleTimeString('zh-CN', { hour12: false });
|
||||||
|
const status = STATUS_BY_PATH[location.pathname] || '在线';
|
||||||
|
|
||||||
|
// 循环中的相邻页面(左/右)
|
||||||
|
const n = PAGE_ORDER.length;
|
||||||
|
const left = pageIdx >= 0 ? PAGE_ORDER[(pageIdx - 1 + n) % n] : null;
|
||||||
|
const right = pageIdx >= 0 ? PAGE_ORDER[(pageIdx + 1) % n] : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="bd-header">
|
<header className="bd-header">
|
||||||
<div className="bd-header-left">
|
<div className="bd-header-left">
|
||||||
<span className="bd-logo">
|
{/* <span className="bd-logo">
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round">
|
<Image src="/logo.png" alt="Logo" />
|
||||||
<path d="M3 21V9l6-5 6 5v12" />
|
</span> */}
|
||||||
<path d="M9 21v-6h6v6" />
|
<Avatar size="lg">
|
||||||
<path d="M15 9.5V21" />
|
<AvatarImage src="/public/logo.png" alt="" />
|
||||||
</svg>
|
</Avatar>
|
||||||
</span>
|
|
||||||
<div className="bd-header-titles">
|
<div className="bd-header-titles">
|
||||||
<h1 className="bd-header-title">昆明市大学生创业园 <span className="bd-header-title-accent">· OPC 智能园区数字运营中心</span></h1>
|
<h1 className="bd-header-title">昆明市大学生创业园 <span className="bd-header-title-accent">· OPC 智能园区数字运营中心</span></h1>
|
||||||
<div className="bd-header-sub">云南省首家政府主办大学生创业孵化园区 · 空间+孵化+融资+政策+资源+AI赋能+综合服务 七位一体</div>
|
<div className="bd-header-sub">云南省首家政府主办大学生创业孵化园区 · <span className="bd-header-content—highlights">空间+孵化+融资+政策+资源+AI赋能+综合服务</span> 七位一体</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bd-header-right">
|
<div className="bd-header-right">
|
||||||
{nav && (
|
<div className="bd-nav-keys" title="左右方向键或点击切换页面">
|
||||||
<button
|
{left && (
|
||||||
className="bd-nav-hint"
|
<button className="bd-nav-key" onClick={() => navigate(left.path)}>
|
||||||
onClick={() => navigate(nav.to)}
|
<Icon name="chevron-left" size={13} />
|
||||||
title={nav.title}
|
{left.label}
|
||||||
>
|
</button>
|
||||||
<Icon name={nav.icon || 'chevron-right'} size={14} />
|
)}
|
||||||
{nav.label}
|
<span className="bd-nav-dot">·</span>
|
||||||
</button>
|
{right && (
|
||||||
)}
|
<button className="bd-nav-key" onClick={() => navigate(right.path)}>
|
||||||
|
{right.label}
|
||||||
|
<Icon name="chevron-right" size={13} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="bd-live">
|
<div className="bd-live">
|
||||||
<span className="bd-live-dot" />
|
<span className="bd-live-dot" />
|
||||||
{status}
|
{status}
|
||||||
|
|||||||
+64
-23
@@ -2,6 +2,29 @@
|
|||||||
昆明市大学生创业园 · OPC 智能园区数据大屏
|
昆明市大学生创业园 · OPC 智能园区数据大屏
|
||||||
浅色科技风 · 通透玻璃质感 · 弱化卡片感(对齐参考图)
|
浅色科技风 · 通透玻璃质感 · 弱化卡片感(对齐参考图)
|
||||||
========================================================= */
|
========================================================= */
|
||||||
|
|
||||||
|
/* 全局布局壳:页眉由 App 注入,所有页面统一使用 */
|
||||||
|
.bd-layout {
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background:
|
||||||
|
radial-gradient(ellipse 75% 60% at 88% -8%, rgba(76, 194, 255, 0.16) 0%, transparent 62%),
|
||||||
|
radial-gradient(ellipse 65% 55% at 5% 110%, rgba(47, 107, 255, 0.12) 0%, transparent 58%),
|
||||||
|
linear-gradient(158deg, #eef5fe 0%, #f7fbff 46%, #e9f1fc 100%);
|
||||||
|
}
|
||||||
|
.bd-layout-main {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 页面内容块:在 bd-layout-main 内撑满,不再自持页眉与 100vh */
|
||||||
.bd-page {
|
.bd-page {
|
||||||
--bd-blue: #2f6bff;
|
--bd-blue: #2f6bff;
|
||||||
--bd-blue-deep: #1d4fd8;
|
--bd-blue-deep: #1d4fd8;
|
||||||
@@ -13,17 +36,14 @@
|
|||||||
--bd-sub: #7d8fa9;
|
--bd-sub: #7d8fa9;
|
||||||
--bd-line: #e3ecf7;
|
--bd-line: #e3ecf7;
|
||||||
|
|
||||||
height: 100vh;
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
color: var(--bd-ink);
|
color: var(--bd-ink);
|
||||||
font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
|
font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
|
||||||
background:
|
|
||||||
radial-gradient(ellipse 75% 60% at 88% -8%, rgba(76, 194, 255, 0.16) 0%, transparent 62%),
|
|
||||||
radial-gradient(ellipse 65% 55% at 5% 110%, rgba(47, 107, 255, 0.12) 0%, transparent 58%),
|
|
||||||
linear-gradient(158deg, #eef5fe 0%, #f7fbff 46%, #e9f1fc 100%);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@@ -86,9 +106,15 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.bd-header-title-accent {
|
.bd-header-title-accent {
|
||||||
color: var(--bd-blue);
|
color: #fc8318;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bd-header-content—highlights {
|
||||||
|
color: #022697;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.bd-header-sub {
|
.bd-header-sub {
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
@@ -1538,13 +1564,10 @@
|
|||||||
|
|
||||||
/* ============ 数字孪生独立页(/twin) ============ */
|
/* ============ 数字孪生独立页(/twin) ============ */
|
||||||
.bd-twin-page {
|
.bd-twin-page {
|
||||||
height: 100vh;
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background:
|
|
||||||
radial-gradient(ellipse 70% 55% at 85% -5%, rgba(76, 194, 255, 0.14) 0%, transparent 60%),
|
|
||||||
radial-gradient(ellipse 60% 50% at 8% 108%, rgba(47, 107, 255, 0.10) 0%, transparent 55%),
|
|
||||||
linear-gradient(155deg, #eef5fe 0%, #f5f9ff 45%, #eaf2fc 100%);
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.bd-twin-main {
|
.bd-twin-main {
|
||||||
@@ -1724,28 +1747,46 @@
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 导航提示按钮 */
|
/* 页眉左右切换按钮(← 左页 · 右页 →,可点击) */
|
||||||
.bd-nav-hint {
|
.bd-nav-keys {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 5px;
|
gap: 6px;
|
||||||
padding: 7px 13px;
|
padding: 5px 10px;
|
||||||
font-size: 12.5px;
|
font-size: 11.5px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #4a5b76;
|
color: #4a5b76;
|
||||||
background: rgba(255,255,255,0.75);
|
background: rgba(255,255,255,0.7);
|
||||||
border: 1px solid rgba(47,107,255,0.16);
|
border: 1px solid rgba(47,107,255,0.14);
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
|
white-space: nowrap;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
.bd-nav-key {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: inherit;
|
||||||
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
.bd-nav-hint:hover {
|
.bd-nav-key:hover {
|
||||||
color: var(--bd-blue);
|
color: var(--bd-blue);
|
||||||
border-color: rgba(47,107,255,0.4);
|
background: rgba(47, 107, 255, 0.1);
|
||||||
background: rgba(255,255,255,0.95);
|
}
|
||||||
|
.bd-nav-key .appica-ico { color: var(--bd-blue); }
|
||||||
|
.bd-nav-dot {
|
||||||
|
color: rgba(125, 147, 181, 0.5);
|
||||||
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
.bd-nav-hint .appica-ico { color: var(--bd-blue); }
|
|
||||||
|
|
||||||
/* ============ 园区今日概览 ============ */
|
/* ============ 园区今日概览 ============ */
|
||||||
.bd-overview {
|
.bd-overview {
|
||||||
|
|||||||
Reference in New Issue
Block a user