From ef6ed76478355dec26bed41eec4133503b833526 Mon Sep 17 00:00:00 2001 From: Pine Date: Mon, 17 Aug 2026 18:37:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20OPC=20=E6=99=BA=E8=83=BD=E5=9B=AD?= =?UTF-8?q?=E5=8C=BA=E6=95=B0=E6=8D=AE=E5=A4=A7=E5=B1=8F=E4=B8=BB=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DataScreen.jsx:园区数字运营中心(深色科技风) - 五大 KPI(TOKEN/工具/项目/就业/营收)+ 三栏数据面板 + 实时动态 - 入驻企业信息表真实数据 + 每 2.2s 模拟跳动 - datascreen.css:完整大屏样式(Appica 图标配色/概览卡/导航按钮) --- src/pages/DataScreen.jsx | 748 +++++++++++++++++ src/styles/datascreen.css | 1626 +++++++++++++++++++++++++++++++++++++ 2 files changed, 2374 insertions(+) create mode 100644 src/pages/DataScreen.jsx create mode 100644 src/styles/datascreen.css diff --git a/src/pages/DataScreen.jsx b/src/pages/DataScreen.jsx new file mode 100644 index 0000000..34b6d75 --- /dev/null +++ b/src/pages/DataScreen.jsx @@ -0,0 +1,748 @@ +import { useState, useEffect, useRef } from 'react'; +import { useNavigate } from 'react-router-dom'; +import '../styles/datascreen.css'; +import Icon from '../components/Icons'; +import PageHeader from '../components/PageHeader'; + +/* ========================================================= + 昆明市大学生创业园 · OPC 智能园区数字运营中心 + —— 数据大屏(深色科技风 · 实时模拟数据) + --------------------------------------------------------- + 基础数据来源: + · 《昆明市创业园宣传册》:在园项目 150+ / 累计孵化 200+ / + 带动就业 2000+ / 累计营收 2 亿+ / 企业估值 5 亿+ / + 高企 32 家 / 重点研发项目 18 项 / 大赛奖项 47 项 + · 《昆明市大学生创业园入驻企业信息表》:39 家本期入驻企业 + (区域、行业、名称) + 大屏实时数据为演示模拟(每 2.2s 跳动一次) + ========================================================= */ + +/* ---------- 真实基础数据(入驻企业信息表) ---------- */ +// [企业名, 区域, 行业] +const PROJECTS = [ + ['云南派音人工智能科技', '加速区', 'AI 科技'], + ['米勒克尔蓝宝石珠宝', '加速区', '新材料'], + ['中泰研学合作', '加速区', '教育培训'], + ['云南宸中低空经济', '加速区', '低空经济'], + ['昆明智海银高文化科技', '加速区', 'AI 科技'], + ['AI 机器人大模型训练', '加速区', 'AI 科技'], + ['云南廷秀文旅康养', '加速区', '文旅康养'], + ['瀚颖 AI+ 教育咨询', '加速区', '教育培训'], + ['云南大学 AI+ 创业平台', '加速区', 'AI 科技'], + ['仰光客厅', '国际区', '文旅康养'], + ['云南上古绝学文化', '国际区', '文化创意'], + ['千楣之路', '国际区', '跨境电商'], + ['中越生物医疗', '国际区', '生物医药'], + ['中越文旅交流', '国际区', '文旅康养'], + ['绿态环保科技', '国际区', '绿色环保'], + ['联翼航空低空经济', '国际区', '低空经济'], + ['酷享野农 AI 农业', '国际区', '现代农业'], + ['滇缅国际设计', '国际区', '企业服务'], + ['昆明舒诺生物科技', '国际区', '生物医药'], + ['达岸教育管理', '国际区', '教育培训'], + ['昆明滇油石化', '成长区', '绿色环保'], + ['花仙子园艺肥料', '成长区', '现代农业'], + ['Facebook 越商茶器', '成长区', '跨境电商'], + ['研X 同行者网络', '成长区', 'AI 科技'], + ['鬼才明 AI 创意工作室', '成长区', 'AI 科技'], + ['朵哈·玫瑰特色产业链', '成长区', '文化创意'], + ['昆明云韵体育', '成长区', '文化创意'], + ['昆明舒护安养老服务', '成长区', '生物医药'], + ['南菌优培食用菌', '成长区', '生物医药'], + ['五华区丽裳文化', '成长区', '文化创意'], + ['云南星瑞航空', '成长区', '低空经济'], + ['云南直播私域平台', '成长区', '跨境电商'], + ['昆明屿澈电商', 'OPC 空间', '跨境电商'], + ['中外青少年研学', 'OPC 空间', '教育培训'], + ['星杭商务信息咨询', 'OPC 空间', '企业服务'], + ['蓝智科技', 'OPC 空间', '现代农业'], + ['云品出滇·纸享万家', 'OPC 空间', '跨境电商'], + ['云迹轻旅', 'OPC 空间', '文旅康养'], + ['启元人工智能科技', 'OPC 空间', 'AI 科技'], +]; + +/* 区域分布(39 家本期企业) */ +const ZONE_DIST = [ + { name: '孵化加速区', value: 9, color: '#4c8dff' }, + { name: '国际创客区', value: 7, color: '#22d3ee' }, + { name: '成长苗圃区', value: 8, color: '#34d399' }, + { name: 'OPC 创业空间', value: 6, color: '#fbbf24' }, + { name: '待分配', value: 9, color: '#7c8db0' }, +]; + +/* 就业行业分布(累计 2186 人) */ +const INDUSTRY = [ + { name: 'AI 与数字经济', value: 520, color: '#4cc2ff' }, + { name: '电商与贸易', value: 310, color: '#7c9bff' }, + { name: '生物医药与大健康', value: 240, color: '#34d399' }, + { name: '文创与农业', value: 260, color: '#f472b6' }, + { name: '文旅与康养', value: 190, color: '#fbbf24' }, + { name: '教育培训', value: 180, color: '#a78bfa' }, + { name: '低空经济', value: 160, color: '#22d3ee' }, + { name: '绿色新材料与企业服务', value: 326, color: '#9aa7c4' }, +]; + +/* 模型占比 */ +const MODELS = [ + { name: 'DeepSeek-V3', value: 38, color: '#4c8dff' }, + { name: '通义千问', value: 21, color: '#22d3ee' }, + { name: '智谱 GLM-4', value: 16, color: '#34d399' }, + { name: '豆包', value: 12, color: '#fbbf24' }, + { name: '讯飞星火', value: 8, color: '#a78bfa' }, + { name: '其他', value: 5, color: '#64748b' }, +]; + +/* 工具调用占比 */ +const TOOL_RANK = [ + { name: '文档生成', value: 34 }, + { name: '数据查询', value: 27 }, + { name: '图像创作', value: 16 }, + { name: '代码执行', value: 13 }, + { name: '语音合成', value: 10 }, +]; + +const TOOL_NAMES = TOOL_RANK.map((t) => t.name); +const MODEL_NAMES = MODELS.map((m) => m.name); +const COMPANY_NAMES = PROJECTS.map((p) => p[0]); + +/* ---------- 工具函数 ---------- */ +const pick = (arr) => arr[Math.floor(Math.random() * arr.length)]; +const fmtInt = (n) => Math.round(n).toLocaleString('zh-CN'); +const fmtWan = (n) => (n >= 10000 ? (n / 10000).toFixed(2) + '亿' : n >= 100 ? n.toFixed(1) + '万' : n.toFixed(1)); +const nowTime = () => new Date().toLocaleTimeString('zh-CN', { hour12: false }); + +function makeSeries(base, growth, noise, n = 30) { + const arr = []; + let v = base; + for (let i = 0; i < n; i++) { + v = v * (1 + growth) + (Math.random() - 0.5) * noise; + arr.push(Math.max(1, Math.round(v * 100) / 100)); + } + return arr; +} + +/* 实时动态事件模板 */ +function genEvent() { + const r = Math.random; + const pool = [ + { icon: 'bolt', text: `AI 推理任务完成 · 消耗 ${Math.round(800 + r() * 9000).toLocaleString()} tokens(${pick(MODEL_NAMES)})` }, + { icon: 'wrench', text: `工具「${pick(TOOL_NAMES)}」被调用 ${Math.round(10 + r() * 90)} 次` }, + { icon: 'building', text: `「${pick(COMPANY_NAMES)}」提交入驻申请 · 进入评审流程` }, + { icon: 'users', text: `「${pick(COMPANY_NAMES)}」新增招聘岗位 ${Math.round(1 + r() * 5)} 个` }, + { icon: 'coin', text: `园区企业完成一笔 ¥${(0.5 + r() * 9).toFixed(1)}万 交易` }, + { icon: 'broadcast', text: `创业沙龙「AI 一人公司实战课」报名开启` }, + { icon: 'robot', text: `「${pick(MODEL_NAMES)}」模型完成一次微调任务` }, + { icon: 'flask', text: `在孵项目完成实验验证 · 进入加速评审` }, + ]; + const e = pick(pool); + return { id: Date.now() + Math.random(), icon: e.icon, text: e.text, time: nowTime() }; +} + +function initFeed() { + return [ + { id: 1, icon: 'bolt', text: '云南派音AI 完成音频向量嵌入任务 · 消耗 12,480 tokens(DeepSeek-V3)', time: '09:02:14' }, + { id: 2, icon: 'building', text: '「启元人工智能科技」通过评审 · 正式入驻 OPC 创业空间', time: '09:05:41' }, + { id: 3, icon: 'wrench', text: '工具「文档生成」被调用 36 次', time: '09:11:03' }, + { id: 4, icon: 'coin', text: '园区企业完成一笔 ¥3.6万 交易', time: '09:17:26' }, + { id: 5, icon: 'users', text: '「昆明舒护安养老服务」新增招聘岗位 2 个', time: '09:23:58' }, + ]; +} + +/* ---------- 模拟数据引擎(每 2.2s 跳动) ---------- */ +function initSnapshot() { + return { + t: 0, + token: { today: 128.64, total: 12840, rate: 84.6, series: makeSeries(82, 0.012, 9) }, + tools: { today: 3568, total: 365204, success: 98.7 }, + projects: { inPark: 158, cum: 208, todayNew: 2 }, + jobs: { total: 2186, todayNew: 3 }, + revenue: { today: 38.6, total: 20800, growth: 8.2, series: makeSeries(30, 0.006, 4) }, + park: { devices: 98.6, energy: 386, people: 127, desk: 76, meeting: 3, nodes: 12 }, + feed: initFeed(), + }; +} + +function nextSnapshot(s) { + const r = Math.random; + const tDeltaWan = +(0.26 + r() * 0.34).toFixed(2); // 万 tokens + + const token = { + today: +(s.token.today + tDeltaWan).toFixed(2), + total: +(s.token.total + tDeltaWan).toFixed(2), + rate: +(76 + r() * 20).toFixed(1), + }; + const toolDelta = Math.round(13 + r() * 22); + const tools = { + today: s.tools.today + toolDelta, + total: s.tools.total + toolDelta, + success: +(98.1 + r() * 1.2).toFixed(1), + }; + const revDelta = +(0.6 + r() * 1.7).toFixed(1); + const revenue = { + ...s.revenue, + today: +(s.revenue.today + revDelta).toFixed(1), + total: +(s.revenue.total + revDelta).toFixed(1), + growth: +(7.2 + r() * 2.2).toFixed(1), + }; + const park = { + devices: +(97.6 + r() * 1.6).toFixed(1), + energy: Math.round(320 + r() * 130), + people: Math.round(80 + r() * 95), + desk: Math.round(62 + r() * 24), + meeting: Math.round(2 + r() * 4), + nodes: 12, + }; + + const projects = { ...s.projects }; + if (r() < 0.055) projects.todayNew += 1; + if (r() < 0.035) { projects.inPark += 1; projects.cum += 1; } + const jobs = { ...s.jobs }; + if (r() < 0.08) jobs.todayNew += 1; + if (r() < 0.05) jobs.total += 1; + + // 30 日曲线:今日点持续爬升,每 12 个 tick 滚动一天 + let tSeries = s.token.series.slice(); + tSeries[tSeries.length - 1] = +(tSeries[tSeries.length - 1] + tDeltaWan).toFixed(2); + if (s.t % 12 === 11) tSeries = [...tSeries.slice(1), +(72 + r() * 30).toFixed(2)]; + token.series = tSeries; + + let rSeries = s.revenue.series.slice(); + rSeries[rSeries.length - 1] = +(rSeries[rSeries.length - 1] + revDelta).toFixed(1); + if (s.t % 12 === 11) rSeries = [...rSeries.slice(1), +(26 + r() * 9).toFixed(1)]; + revenue.series = rSeries; + + const feed = s.t % 3 === 2 ? [genEvent(), ...s.feed].slice(0, 7) : s.feed; + + return { ...s, t: s.t + 1, token, tools, revenue, park, projects, jobs, feed }; +} + +function useParkSim() { + const [snap, setSnap] = useState(initSnapshot); + useEffect(() => { + const iv = setInterval(() => setSnap((p) => nextSnapshot(p)), 2200); + return () => clearInterval(iv); + }, []); + return snap; +} + +/* ---------- 通用 Hooks ---------- */ + +/* 数字平滑滚动(rAF 缓动;进度钳制 [0,1],避免边缘环境时间戳异常导致发散) */ +function useAnimatedNumber(target, duration = 900) { + const [cur, setCur] = useState(target); + const curRef = useRef(target); + const raf = useRef(); + useEffect(() => { + const from = curRef.current; + if (from === target) return; + const t0 = performance.now(); + cancelAnimationFrame(raf.current); + const tick = (now) => { + const p = Math.min(1, Math.max(0, (now - t0) / duration)); + const e = 1 - Math.pow(1 - p, 3); + const v = from + (target - from) * e; + curRef.current = v; + setCur(v); + if (p < 1) raf.current = requestAnimationFrame(tick); + }; + raf.current = requestAnimationFrame(tick); + return () => cancelAnimationFrame(raf.current); + }, [target, duration]); + return cur; +} + +/* ---------- 通用小组件 ---------- */ +function CardHead({ title, right, icon }) { + return ( +
+
+ {icon && } + {title} +
+ {right &&
{right}
} +
+ ); +} + +function Pill({ children, tone = 'blue' }) { + return {children}; +} + +/* 面积图 + 折线(viewBox 高度动态匹配容器,满宽绘制、无留白错位) */ +function AreaChart({ series, color, height = 100, unit = '', lastLabel }) { + const W = 300, PL = 8, PR = 8, PT = 16, PB = 18; + const ref = useRef(null); + const [vh, setVh] = useState(height); // viewBox 高度(按容器宽高比计算) + useEffect(() => { + const el = ref.current; + if (!el) return; + const update = () => { + const w = el.clientWidth, h = el.clientHeight; + if (w > 0 && h > 0) setVh(Math.max(40, Math.round((W * h) / w))); + }; + update(); + const ro = new ResizeObserver(update); + ro.observe(el); + return () => ro.disconnect(); + }, []); + const H = vh; + const min = Math.min(...series), max = Math.max(...series); + const lo = min * 0.9, hi = max * 1.08, span = hi - lo || 1; + const px = (i) => PL + (i / (series.length - 1)) * (W - PL - PR); + const py = (v) => H - PB - ((v - lo) / span) * (H - PT - PB); + const line = series.map((v, i) => `${px(i).toFixed(1)},${py(v).toFixed(1)}`).join(' '); + const area = `${line} ${px(series.length - 1).toFixed(1)},${(H - PB).toFixed(1)} ${px(0).toFixed(1)},${(H - PB).toFixed(1)}`; + const gid = useRef('g' + Math.random().toString(36).slice(2, 8)).current; + return ( + + {[0.25, 0.5, 0.75].map((t) => ( + + ))} + + + + + + + + + + 30 天前 + 今日 + {lastLabel && ( + {lastLabel} + )} + + ); +} + +/* 环形图 */ +function Donut({ items, size = 148, thickness = 18, centerTop, centerBottom }) { + const total = items.reduce((a, b) => a + b.value, 0); + const R = (size - thickness) / 2; + const C = 2 * Math.PI * R; + const cx = size / 2; + let acc = 0; + return ( + + + {items.map((it, i) => { + const frac = it.value / total; + const dash = Math.max(0.5, frac * C - 1.5); + const off = -acc * C; + acc += frac; + return ( + + ); + })} + {centerTop} + {centerBottom} + + ); +} + +/* 横向排行条 */ +function HBar({ items, color = '#4cc2ff', unit = '%' }) { + const max = Math.max(...items.map((i) => i.value)); + return ( +
+ {items.map((it, i) => ( +
+ {it.name} +
+
+
+ {it.value}{unit} +
+ ))} +
+ ); +} + +/* ========================================================= + 面板组件 + ========================================================= */ + +/* ---------- KPI 核心指标带(5 大必须指标) ---------- */ +function KpiCard({ icon, label, value, unit, sub, tone }) { + const v = useAnimatedNumber(value); + return ( +
+
+
+
{label}
+
+ {tone === 'revenue' || tone === 'token' + ? {fmtWan(v)} + : {fmtInt(v)}} + {unit && {unit}} +
+
{sub}
+
+ +
+ ); +} + +/* ========================================================= + 园区今日概览(标题右侧内联运行状态 + 五个指标一行) + ┌──────────────────────────────────────────────┐ + │ 园区今日概览 · [6 项运行状态内联] · 实时刷新 │ + ├──────┬──────┬──────┬──────┬──────┤ + │ TOKEN│ 营收 │ 入园 │ 工具 │ 就业 │ ← 五个卡片一行 + └──────┴──────┴──────┴──────┴──────┘ + (园区实时动态 → 整体页面右下方) + ========================================================= */ +function TodayOverview({ d }) { + /* 园区运行状态 —— 内联在标题右侧,不作为独立卡片 */ + const status = [ + { icon: 'gauge', label: '设备在线率', value: `${d.park.devices}%`, color: '#17b26a' }, + { icon: 'flame', label: '能耗', value: `${d.park.energy} kWh`, color: '#2f6bff' }, + { icon: 'users', label: '人流量', value: `${d.park.people} 人`, color: '#f79009' }, + { icon: 'briefcase', label: '工位', value: `${d.park.desk}%`, color: '#8b5cf6' }, + { icon: 'radio', label: '会议室', value: `${d.park.meeting}/6`, color: '#f04438' }, + { icon: 'cpu', label: '云桌面', value: `${Math.round(d.park.people * 0.42)} 个`, color: '#0ea5e9' }, + ]; + return ( +
+
+
+ + 园区今日概览 +
+
+ {status.map((s) => ( + + + {s.label} + {s.value} + + ))} +
+
+ 实时刷新 · 2s +
+
+ {/* 五个指标卡片:必须一行展示 */} +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ ); +} + +/* ---------- 园区概览(页面最底部 · 综合指标条) ---------- */ +function ParkOverviewStrip({ d }) { + const chips = [ + { icon: 'building', label: '在园项目', value: `${d.projects.inPark} 家` }, + { icon: 'users', label: '带动就业', value: `${fmtInt(d.jobs.total)} 人` }, + { icon: 'coin', label: '累计', value: `${fmtWan(d.revenue.total)} 元` }, + { icon: 'factory', label: '高新技术企业', value: '32 家' }, + { icon: 'flask', label: '省级以上重点研发', value: '18 项' }, + { icon: 'trophy', label: '创业大赛奖项', value: '47 项' }, + { icon: 'diamond', label: '孵化企业估值', value: '5.2 亿元' }, + { icon: 'map-pin', label: '园区面积', value: '1.2 万㎡' }, + { icon: 'graduation', label: '创业导师', value: '58 位' }, + { icon: 'chart-line', label: '累计孵化企业', value: `${d.projects.cum} 家` }, + ]; + return ( +
+
园区概览
+
+ {chips.map((c, i) => ( +
+ + {c.label} + {c.value} +
+ ))} +
+
+ ); +} + +/* ---------- TOKEN 消耗 ---------- */ +function TokenPanel({ d }) { + return ( +
+ {/* 概括数据内联在标题右侧 */} + + 今日{fmtWan(d.token.today)} tokens + 累计{fmtWan(d.token.total)} tokens + 速率{d.token.rate} t/s +
+ } + /> + {/* 四列布局:环形图(最左) · 模型(左) · 折线图(中) · 数值(右) */} +
+
+ +
+
+ {MODELS.map((m) => ( +
+ + {m.name} +
+ ))} +
+
+ +
+
+ {MODELS.map((m) => ( +
+ + {m.value}% +
+ ))} +
+
+
+ ); +} + +/* ---------- 工具调用 ---------- */ +function ToolsPanel({ d }) { + return ( +
+ {/* 概括数据内联在标题右侧 */} + + 今日调用{fmtInt(d.tools.today)} 次 + 累计调用{(d.tools.total / 10000).toFixed(1)}万 次 + 成功{d.tools.success}% + {/* 服务节点12 / 12 在线 */} +
+ } + /> +
热门工具调用占比
+ +
+ · 文本创作 34% + · 智能分析 27% + · 多模态生成 16% +
+ + ); +} + +/* ---------- 入园项目 ---------- */ +function ProjectsPanel({ d }) { + return ( +
+ {/* 概括数据内联在标题右侧 */} + + 在园{d.projects.inPark} 家 + 累计孵化{d.projects.cum} 家 + 本月新增{d.projects.todayNew} 家 + {/* 高企 / 研发32 / 18 */} +
+ } + /> +
+ +
+ {ZONE_DIST.map((z) => ( +
+ + {z.name} + {z.value} 家 +
+ ))} +
+
+
入驻企业名录 (39 家)
+
+
+ {[...COMPANY_NAMES, ...COMPANY_NAMES].map((c, i) => ( +
+ + {c} +
+ ))} +
+
+ + ); +} + +/* ---------- 带动就业 ---------- */ +function JobsPanel({ d }) { + return ( +
+ {/* 概括数据内联在标题右侧 */} + + 就业{fmtInt(d.jobs.total)} 人 + 毕业生1,680 人 + 实习506 人 + 新增{d.jobs.todayNew} 人 +
+ } + /> +
行业就业分布
+
+ {INDUSTRY.slice(0, 6).map((it, i) => { + const max = Math.max(...INDUSTRY.map((x) => x.value)); + return ( +
+
+
+
+ {it.value} + {it.name} +
+ ); + })} +
+
+ ); +} + +/* ---------- 营收总数 ---------- */ +function RevenuePanel({ d }) { + return ( +
+ {/* 概括数据内联在标题右侧 */} + + 累计{fmtWan(d.revenue.total)} 元 + 今日+{d.revenue.today} 万 + 估值5.2 亿元 + 环比+{d.revenue.growth}% +
+ } + /> +
+ +
+
+ 大赛奖项 47 + 重点研发 18 + 高新技术企业 32 +
+ + ); +} + +/* ---------- 实时动态(纯列表,外层自行包裹卡片) ---------- */ +function LiveFeed({ feed, limit = 7 }) { + return ( +
+ {feed.slice(0, limit).map((e) => ( +
+ + {e.text} + {e.time} +
+ ))} +
+ ); +} + +/* ========================================================= + 页面 + ========================================================= */ +export default function DataScreen() { + const d = useParkSim(); + const navigate = useNavigate(); + + // 左右方向键:→ 进入数字孪生页,← 返回(管理页为左端) + useEffect(() => { + const onKey = (e) => { + if (e.key === 'ArrowRight') navigate('/twin'); + else if (e.key === 'ArrowLeft') navigate('/admin'); + }; + window.addEventListener('keydown', onKey); + return () => window.removeEventListener('keydown', onKey); + }, [navigate]); + + return ( +
+ {/* 顶栏(共享组件,与数字孪生页风格一致) */} + + + {/* 园区今日概览(五个指标一行 + 标题右侧运行状态) */} + + + {/* 主体:下方内容三列显示 */} +
+ {/* 第 1 列:TOKEN 消耗 · 工具调用 */} +
+ + +
+ + {/* 第 2 列:入园项目 · 带动就业 */} +
+ + +
+ + {/* 第 3 列:营收总数 */} +
+ +
+
+ + {/* 园区实时动态(底部整行 · 园区概览条上方 · 内容三列) */} +
+
+ ● LIVE} /> + +
+
+ + {/* 园区概览(保持在最底部) */} + +
+ ); +} diff --git a/src/styles/datascreen.css b/src/styles/datascreen.css new file mode 100644 index 0000000..513fb52 --- /dev/null +++ b/src/styles/datascreen.css @@ -0,0 +1,1626 @@ +/* ========================================================= + 昆明市大学生创业园 · OPC 智能园区数据大屏 + 浅色科技风 · 通透玻璃质感 · 弱化卡片感(对齐参考图) + ========================================================= */ +.bd-page { + --bd-blue: #2f6bff; + --bd-blue-deep: #1d4fd8; + --bd-cyan: #4cc2ff; + --bd-green: #17b26a; + --bd-red: #f04438; + --bd-orange: #f79009; + --bd-ink: #1d2c44; + --bd-sub: #7d8fa9; + --bd-line: #e3ecf7; + + height: 100vh; + overflow: hidden; + position: relative; + display: flex; + flex-direction: column; + color: var(--bd-ink); + 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; + user-select: none; + -webkit-user-select: none; +} + +/* 网格底纹(更细腻) */ +.bd-page::before { + content: ''; + position: fixed; + inset: 0; + z-index: 0; + pointer-events: none; + opacity: 0.5; + background-image: + repeating-linear-gradient(to right, rgba(47, 107, 255, 0.045) 0 1px, transparent 1px 52px), + repeating-linear-gradient(to bottom, rgba(47, 107, 255, 0.045) 0 1px, transparent 1px 52px); +} + +/* ============ 顶栏 ============ */ +.bd-header { + position: relative; + z-index: 1500; + height: 62px; + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 clamp(18px, 2.4vw, 34px); + background: rgba(255, 255, 255, 0.55); + backdrop-filter: blur(18px) saturate(150%); + -webkit-backdrop-filter: blur(18px) saturate(150%); + border-bottom: 1px solid rgba(47, 107, 255, 0.08); +} +.bd-header-left { + display: flex; + align-items: center; + gap: 13px; + min-width: 0; +} +.bd-logo { + width: 38px; + height: 38px; + flex-shrink: 0; + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + color: #fff; + background: linear-gradient(140deg, var(--bd-blue) 0%, var(--bd-cyan) 100%); + box-shadow: 0 6px 18px rgba(47, 107, 255, 0.32); +} +.bd-header-titles { + min-width: 0; +} +.bd-header-title { + font-size: 21px; + font-weight: 700; + letter-spacing: 0.03em; + color: var(--bd-ink); + white-space: nowrap; +} +.bd-header-title-accent { + color: var(--bd-blue); + font-weight: 700; +} +.bd-header-sub { + margin-top: 2px; + font-size: 11px; + color: var(--bd-sub); + letter-spacing: 0.04em; + white-space: nowrap; +} +.bd-header-right { + display: flex; + align-items: center; + gap: 14px; + flex-shrink: 0; +} +.bd-live { + display: inline-flex; + align-items: center; + gap: 7px; + padding: 6px 13px; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.08em; + color: var(--bd-green); + background: rgba(23, 178, 106, 0.08); + border: 1px solid rgba(23, 178, 106, 0.22); + border-radius: 20px; +} +.bd-live-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--bd-green); + box-shadow: 0 0 8px rgba(23, 178, 106, 0.7); + animation: bdPulse 1.6s ease-in-out infinite; +} +@keyframes bdPulse { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.35; transform: scale(0.8); } +} +.bd-clock { + text-align: right; + padding-right: 6px; +} +.bd-clock-time { + font-family: "JetBrains Mono", "Oswald", monospace; + font-size: 19px; + font-weight: 600; + color: var(--bd-ink); + letter-spacing: 0.05em; + line-height: 1.1; +} +.bd-clock-date { + font-size: 10.5px; + color: var(--bd-sub); + margin-top: 1px; +} + +/* ============ KPI 核心指标带 ============ */ +.bd-kpis { + position: relative; + z-index: 2; + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: clamp(8px, 0.9vw, 14px); + padding: clamp(10px, 1vw, 14px) clamp(12px, 1.5vw, 22px) 0; + flex-shrink: 0; +} +.bd-kpi { + position: relative; + overflow: hidden; + display: flex; + align-items: center; + gap: 10px; + padding: 7px 12px; + border-radius: 14px; + background: rgba(255, 255, 255, 0.62); + border: 1px solid rgba(120, 160, 220, 0.16); + box-shadow: 0 5px 20px rgba(56, 100, 170, 0.08), 0 1px 0 rgba(255, 255, 255, 0.9) inset; + backdrop-filter: blur(14px) saturate(140%); + -webkit-backdrop-filter: blur(14px) saturate(140%); + transition: box-shadow 0.25s, transform 0.25s; +} +.bd-kpi:hover { + box-shadow: 0 9px 28px rgba(56, 100, 170, 0.13), 0 1px 0 rgba(255, 255, 255, 0.95) inset; + transform: translateY(-2px); +} +.bd-kpi-ico { + width: 36px; + height: 36px; + flex-shrink: 0; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + background: rgba(47, 107, 255, 0.09); + border: 1px solid rgba(47, 107, 255, 0.14); +} +.bd-kpi.token .bd-kpi-ico { background: rgba(76, 194, 255, 0.12); border-color: rgba(76, 194, 255, 0.24); } +.bd-kpi.tool .bd-kpi-ico { background: rgba(47, 107, 255, 0.09); border-color: rgba(47, 107, 255, 0.16); } +.bd-kpi.project .bd-kpi-ico { background: rgba(23, 178, 106, 0.10); border-color: rgba(23, 178, 106, 0.2); } +.bd-kpi.job .bd-kpi-ico { background: rgba(247, 144, 9, 0.10); border-color: rgba(247, 144, 9, 0.2); } +.bd-kpi.revenue .bd-kpi-ico { background: rgba(240, 68, 56, 0.09); border-color: rgba(240, 68, 56, 0.18); } +.bd-kpi-body { + min-width: 0; + flex: 1; +} +.bd-kpi-label { + font-size: 11.5px; + color: var(--bd-sub); + letter-spacing: 0.06em; + font-weight: 600; +} +.bd-kpi-value { + font-family: "JetBrains Mono", "Oswald", monospace; + font-size: 22px; + font-weight: 700; + color: var(--bd-ink); + line-height: 1.2; + margin-top: 1px; + white-space: nowrap; +} +.bd-kpi-value em { + font-style: normal; + font-size: 11px; + font-weight: 600; + color: var(--bd-sub); + margin-left: 4px; +} +.bd-kpi-sub { + font-size: 10.5px; + color: var(--bd-sub); + margin-top: 2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.bd-kpi-sub b { + color: var(--bd-blue); + font-weight: 700; +} + +/* ============ 主体(下方内容三列) ============ */ +.bd-main { + position: relative; + z-index: 2; + flex: 1; + min-height: 0; + display: grid; + gap: clamp(8px, 0.9vw, 14px); + padding: clamp(10px, 1vw, 14px) clamp(12px, 1.5vw, 22px); +} +.bd-main-3col { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} +.bd-col { + display: flex; + flex-direction: column; + gap: clamp(8px, 0.9vw, 14px); + min-height: 0; + min-width: 0; +} +/* 第 1 列:TOKEN(略高)· 工具调用 */ +.bd-col-left .bd-token-panel { flex: 1.15; } +.bd-col-left .bd-tools-panel { flex: 0.85; } +/* 第 2 列:入园项目(略高)· 带动就业 */ +.bd-col-mid .bd-projects-panel { flex: 1.15; } +.bd-col-mid .bd-jobs-panel { flex: 0.85; } +/* 第 3 列:营收总数 */ +.bd-col-right .bd-revenue-panel { flex: 1; } + +/* ============ 园区实时动态(底部整行 · 内容三列) ============ */ +.bd-feed-row { + position: relative; + z-index: 2; + flex-shrink: 0; + padding: 0 clamp(12px, 1.5vw, 22px); +} +.bd-feed-row .bd-feed-card { + height: 128px; +} +.bd-feed-row .bd-feed { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 4px 10px; + min-height: 0; + overflow: hidden; + align-content: center; +} +.bd-feed-row .bd-feed-item { + padding: 4px 10px; + font-size: 11px; + line-height: 1.2; +} +.bd-feed-row .bd-feed-ico { + width: 18px; + height: 18px; + font-size: 10px; +} +.bd-feed-row .bd-feed-text { + font-size: 11px; +} +.bd-feed-row .bd-feed-time { + font-size: 9.5px; +} + +/* ============ 卡片(通透玻璃,弱化卡片感) ============ */ +.bd-card { + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + min-height: 0; + overflow: hidden; + border-radius: 16px; + padding: clamp(10px, 0.9vw, 14px); + background: rgba(255, 255, 255, 0.58); + border: 1px solid rgba(120, 160, 220, 0.14); + box-shadow: + 0 6px 24px rgba(56, 100, 170, 0.07), + 0 1px 0 rgba(255, 255, 255, 0.85) inset; + backdrop-filter: blur(14px) saturate(140%); + -webkit-backdrop-filter: blur(14px) saturate(140%); + transition: box-shadow 0.25s ease; +} +.bd-card:hover { + box-shadow: + 0 10px 34px rgba(56, 100, 170, 0.11), + 0 1px 0 rgba(255, 255, 255, 0.9) inset; +} +.bd-card-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: clamp(4px, 0.5vw, 8px); + flex-shrink: 0; +} +.bd-title { + display: flex; + align-items: center; + gap: 7px; + font-size: clamp(12.5px, 0.85vw, 14px); + font-weight: 700; + color: var(--bd-ink); + letter-spacing: 0.01em; + white-space: nowrap; +} +.bd-title::before { + content: ''; + width: 4px; + height: 14px; + border-radius: 2px; + background: linear-gradient(180deg, var(--bd-blue), var(--bd-cyan)); +} +.bd-title-ico { + font-size: 14px; +} +.bd-head-right { + display: flex; + align-items: center; + gap: 6px; + white-space: nowrap; +} + +/* 标签(轻量徽标) */ +.bd-pill-tag { + display: inline-flex; + align-items: center; + gap: 5px; + padding: 3px 10px; + font-size: 10.5px; + font-weight: 700; + border-radius: 20px; + letter-spacing: 0.02em; + white-space: nowrap; +} +.bd-pill-tag.blue { color: var(--bd-blue); background: rgba(47, 107, 255, 0.08); border: 1px solid rgba(47, 107, 255, 0.16); } +.bd-pill-tag.cyan { color: #0e9ecb; background: rgba(76, 194, 255, 0.1); border: 1px solid rgba(76, 194, 255, 0.24); } +.bd-pill-tag.green { color: var(--bd-green); background: rgba(23, 178, 106, 0.08); border: 1px solid rgba(23, 178, 106, 0.18); } +.bd-pill-tag.orange { color: #d97706; background: rgba(247, 144, 9, 0.09); border: 1px solid rgba(247, 144, 9, 0.2); } +.bd-pill-tag.red { color: var(--bd-red); background: rgba(240, 68, 56, 0.07); border: 1px solid rgba(240, 68, 56, 0.18); } +.bd-pill-tag.red .bd-live-dot { + display: inline-block; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--bd-red); + box-shadow: 0 0 7px rgba(240, 68, 56, 0.7); + animation: bdPulse 1.2s ease-in-out infinite; +} + +/* 面板统计行 */ +.bd-panel-stats { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 7px; + margin-bottom: clamp(5px, 0.5vw, 8px); + flex-shrink: 0; +} +.bd-panel-stat { + padding: 6px 9px; + border-radius: 10px; + background: rgba(244, 248, 253, 0.8); + border: 1px solid rgba(47, 107, 255, 0.07); + min-width: 0; +} +.bd-panel-stat-label { + display: block; + font-size: 10px; + color: var(--bd-sub); + margin-bottom: 2px; + white-space: nowrap; +} +.bd-panel-stat b { + font-family: "JetBrains Mono", "Oswald", monospace; + font-size: 15px; + font-weight: 700; + color: var(--bd-ink); + white-space: nowrap; +} +.bd-panel-stat b em { + font-style: normal; + font-size: 9.5px; + font-weight: 500; + color: var(--bd-sub); + margin-left: 3px; +} + +/* 图表 SVG */ +.bd-chart-svg { + flex: 1; + min-height: 0; + width: 100%; + height: 100%; + display: block; +} +.bd-chart-block { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + margin-bottom: 2px; +} +.bd-chart-block .bd-chart-svg { + flex: 1; + min-height: 0; +} + +/* donut + 图例 */ +.bd-split { + display: flex; + align-items: center; + gap: 10px; + flex-shrink: 0; +} +/* TOKEN 四列布局:环形图(最左) · 模型(左) · 折线图(中) · 数值(右) */ +.bd-split-tri { + flex: 1; + min-height: 0; + align-items: center; + gap: clamp(8px, 0.9vw, 14px); +} +.bd-split-tri .bd-donut-block { + align-self: center; +} +.bd-model-list { + flex: 0 0 128px; + display: flex; + flex-direction: column; + justify-content: center; + gap: 5px; + min-width: 0; +} +.bd-value-list { + flex: 0 0 56px; + display: flex; + flex-direction: column; + justify-content: center; + gap: 5px; + min-width: 0; +} +.bd-value-list .bd-legend-row { justify-content: flex-end; } +.bd-value-num { + font-family: "JetBrains Mono", "Oswald", monospace; + font-size: 13px; + font-weight: 700; + color: var(--bd-ink); +} +.bd-chart-mid { + flex: 1; + min-width: 0; + margin-bottom: 0; +} +.bd-donut-block { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; +} +/* donut 在窄容器内可缩放(max-width 兜底) */ +.bd-donut { + max-width: 100%; +} +.bd-donut-total { + font-family: "JetBrains Mono", "Oswald", monospace; + font-size: 19px; + font-weight: 700; + fill: var(--bd-ink); +} +.bd-donut-label { + font-size: 9px; + fill: var(--bd-sub); +} +.bd-legend { + flex: 1; + display: flex; + flex-direction: column; + gap: 4.5px; + min-width: 0; +} +.bd-legend-row { + display: flex; + align-items: center; + gap: 6px; + font-size: 10.5px; + color: var(--bd-sub); + min-width: 0; +} +.bd-legend-dot { + width: 8px; + height: 8px; + border-radius: 3px; + flex-shrink: 0; + box-shadow: 0 0 4px rgba(47, 107, 255, 0.25); +} +.bd-legend-name { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.bd-legend-val { + font-family: "JetBrains Mono", monospace; + font-weight: 700; + color: var(--bd-ink); +} + +/* 横向排行条 */ +.bd-hbars { + display: flex; + flex-direction: column; + gap: 6px; + flex: 1; + min-height: 0; + justify-content: center; +} +.bd-hbar { + display: grid; + grid-template-columns: 60px minmax(0, 1fr) 34px; + align-items: center; + gap: 7px; +} +.bd-hbar-name { + font-size: 11px; + color: var(--bd-sub); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.bd-hbar-track { + height: 8px; + border-radius: 5px; + background: rgba(47, 107, 255, 0.07); + overflow: hidden; +} +.bd-hbar-fill { + height: 100%; + border-radius: 5px; + transition: width 1s ease; +} +.bd-hbar-val { + font-family: "JetBrains Mono", monospace; + font-size: 11px; + font-weight: 700; + color: var(--bd-ink); + text-align: right; + white-space: nowrap; +} +.bd-hbar-title { + font-size: 10.5px; + color: var(--bd-sub); + margin: 1px 0 5px; + letter-spacing: 0.04em; + flex-shrink: 0; +} +.bd-tools-foot { + display: flex; + gap: 10px; + font-size: 9.5px; + color: var(--bd-sub); + margin-top: 5px; + flex-shrink: 0; + white-space: nowrap; +} + +/* 迷你状态 */ +.bd-minis { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 9px 14px; + flex: 1; + align-content: center; +} +.bd-mini { + padding: 8px 10px; + border-radius: 11px; + background: rgba(244, 248, 253, 0.75); + border: 1px solid rgba(47, 107, 255, 0.06); +} +.bd-mini-top { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 6px; + margin-bottom: 5px; +} +.bd-mini-label { + font-size: 11px; + color: var(--bd-sub); + white-space: nowrap; +} +.bd-mini-top b { + font-family: "JetBrains Mono", monospace; + font-size: 14px; + font-weight: 700; + color: var(--bd-ink); + white-space: nowrap; +} +.bd-mini-track { + height: 5px; + border-radius: 4px; + background: rgba(47, 107, 255, 0.08); + overflow: hidden; +} +.bd-mini-fill { + height: 100%; + border-radius: 4px; + transition: width 1.2s ease; +} + +/* 3D 园区 */ +.bd-plan-card { + background: linear-gradient(180deg, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0.18)); + border-color: rgba(120, 160, 220, 0.1); + box-shadow: none; + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); +} +.bd-plan-card:hover { box-shadow: none; } +.bd-plan-ov { + position: absolute; + top: 10px; + left: 12px; + right: 12px; + z-index: 5; + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + pointer-events: none; +} +.bd-plan-ov-title { + font-size: 12.5px; + font-weight: 700; + color: var(--bd-ink); + letter-spacing: 0.08em; + display: flex; + align-items: center; + gap: 8px; +} +.bd-plan-ov-title::before { + content: ''; + width: 16px; + height: 2px; + border-radius: 2px; + background: linear-gradient(90deg, var(--bd-blue), var(--bd-cyan)); +} +.bd-plan-ov-tags { + display: flex; + gap: 7px; +} +.bd-plan-ov-tags span { + font-size: 10.5px; + font-weight: 600; + color: #4a5b76; + background: rgba(255, 255, 255, 0.82); + border: 1px solid rgba(47, 107, 255, 0.12); + padding: 3px 9px; + border-radius: 14px; + white-space: nowrap; + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); + box-shadow: 0 2px 8px rgba(29, 44, 68, 0.08); +} +.bd-plan-ov-tags b { + color: var(--bd-blue); + font-family: "JetBrains Mono", monospace; + font-size: 11.5px; +} +.bd3d-wrap { + flex: 1; + min-height: 0; + width: 100%; + position: relative; +} +.bd3d-wrap canvas { + touch-action: none; +} +.bd3d-loading { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + font-size: 13px; + color: var(--bd-sub); + letter-spacing: 0.08em; +} +.bd3d-loading i { + width: 16px; + height: 16px; + border-radius: 50%; + border: 2px solid rgba(47, 107, 255, 0.2); + border-top-color: var(--bd-blue); + animation: bdSpin 0.9s linear infinite; +} +@keyframes bdSpin { to { transform: rotate(360deg); } } + +/* 3D 房间悬浮标签(原浅色风格) */ +.bd3d-tag { + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; + transform: translateY(-4px); +} +.bd3d-bubble { + padding: 3px 11px; + border-radius: 20px; + color: #fff; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.02em; + white-space: nowrap; + box-shadow: 0 4px 14px rgba(29, 44, 68, 0.22); +} +.bd3d-bubble.cold { + background: linear-gradient(135deg, #3d7bff, #6fb1ff); + box-shadow: 0 4px 16px rgba(47, 107, 255, 0.4); +} +.bd3d-bubble.ok { + background: linear-gradient(135deg, #17b26a, #4cd69a); + box-shadow: 0 4px 16px rgba(23, 178, 106, 0.38); +} +.bd3d-bubble.hot { + background: linear-gradient(135deg, #f04438, #ff7d6b); + box-shadow: 0 4px 16px rgba(240, 68, 56, 0.38); +} +.bd3d-roomname { + font-size: 12px; + font-weight: 600; + color: #4a5b76; + background: rgba(255, 255, 255, 0.82); + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); + border: 1px solid rgba(47, 107, 255, 0.12); + padding: 2px 10px; + border-radius: 8px; + white-space: nowrap; + box-shadow: 0 2px 8px rgba(29, 44, 68, 0.1); + display: inline-flex; + align-items: center; + gap: 6px; +} +.bd3d-no { + font-family: "Oswald", "JetBrains Mono", sans-serif; + font-size: 11px; + font-weight: 700; + color: #fff; + background: linear-gradient(140deg, #2f6bff, #4cc2ff); + border-radius: 5px; + padding: 1px 6px; + letter-spacing: 0.03em; + box-shadow: 0 2px 6px rgba(47, 107, 255, 0.35); +} +.bd3d-tag.hallway .bd3d-no { background: linear-gradient(140deg, #4a8cff, #7fb5ff); } +.bd3d-tag.desk .bd3d-no { background: linear-gradient(140deg, #f0903c, #f5b862); } +.bd3d-tag.lounge .bd3d-no { background: linear-gradient(140deg, #2f9a6b, #6fd3a0); } +.bd3d-tag.meeting .bd3d-no { background: linear-gradient(140deg, #e8891d, #f5a53c); } +.bd3d-tag.stair .bd3d-no { background: linear-gradient(140deg, #dd7a14, #f5a53c); } + +/* 实时动态 */ +.bd-feed-card { + padding-bottom: 8px; +} +.bd-feed { + display: flex; + flex-direction: column; + gap: 4px; + min-height: 0; +} +.bd-feed-item { + display: flex; + align-items: center; + gap: 8px; + padding: 5px 10px; + border-radius: 9px; + background: rgba(244, 248, 253, 0.85); + border: 1px solid rgba(47, 107, 255, 0.07); + font-size: 11.5px; + animation: bdSlideIn 0.5s ease both; +} +@keyframes bdSlideIn { + from { opacity: 0; transform: translateY(-9px); } + to { opacity: 1; transform: translateY(0); } +} +.bd-feed-ico { + width: 22px; + height: 22px; + flex-shrink: 0; + border-radius: 7px; + display: flex; + align-items: center; + justify-content: center; + font-size: 11px; + background: rgba(47, 107, 255, 0.09); + border: 1px solid rgba(47, 107, 255, 0.14); +} +.bd-feed-text { + flex: 1; + min-width: 0; + color: #4a5b76; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.bd-feed-time { + font-family: "JetBrains Mono", monospace; + font-size: 10px; + color: #9fb0c6; + flex-shrink: 0; +} + +/* 入园项目:区域分布 */ +.bd-zone-wrap { + display: flex; + align-items: center; + gap: 10px; + flex-shrink: 0; + margin-bottom: 6px; +} +.bd-zone-legend { + flex: 1; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + column-gap: 10px; + row-gap: 3px; + min-width: 0; +} +.bd-zone-row { + display: flex; + align-items: center; + gap: 6px; + font-size: 10.5px; + color: var(--bd-sub); +} +.bd-zone-name { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.bd-zone-val { + font-family: "JetBrains Mono", monospace; + font-weight: 700; + color: var(--bd-ink); + font-size: 10px; +} + +/* 企业名录滚动 */ +.bd-ticker-title { + font-size: 10.5px; + color: var(--bd-sub); + margin-bottom: 4px; + letter-spacing: 0.04em; + flex-shrink: 0; +} +.bd-ticker-title span { + color: #9fb0c6; +} +.bd-ticker { + flex: 1; + min-height: 0; + overflow: hidden; + position: relative; + mask-image: linear-gradient(180deg, transparent, #000 6%, #000 94%, transparent); + -webkit-mask-image: linear-gradient(180deg, transparent, #000 6%, #000 94%, transparent); +} +.bd-ticker-inner { + animation: bdTickerY 46s linear infinite; +} +.bd-ticker:hover .bd-ticker-inner { + animation-play-state: paused; +} +@keyframes bdTickerY { + from { transform: translateY(0); } + to { transform: translateY(-50%); } +} +.bd-ticker-item { + display: flex; + align-items: center; + gap: 8px; + padding: 3.5px 9px; + font-size: 11px; + color: #4a5b76; + border-radius: 8px; + white-space: nowrap; +} +.bd-ticker-item:nth-child(odd) { + background: rgba(244, 248, 253, 0.75); +} +.bd-ticker-dot { + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--bd-cyan); + box-shadow: 0 0 5px rgba(76, 194, 255, 0.7); + flex-shrink: 0; +} + +/* 带动就业:竖向柱 */ +.bd-jobs-bars { + flex: 1; + min-height: 0; + display: flex; + gap: 5px; + align-items: stretch; + padding-top: 5px; +} +.bd-vbar { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + min-width: 0; + gap: 2.5px; +} +.bd-vbar-track { + flex: 1; + width: 100%; + min-height: 0; + display: flex; + align-items: flex-end; + justify-content: center; + background: rgba(47, 107, 255, 0.05); + border-radius: 5px; + overflow: hidden; +} +.bd-vbar-fill { + width: 100%; + border-radius: 5px; + min-height: 2px; + transition: height 1.2s ease; +} +.bd-vbar-val { + font-family: "JetBrains Mono", monospace; + font-size: 9.5px; + font-weight: 700; + color: var(--bd-ink); +} +.bd-vbar-name { + font-size: 8.5px; + color: var(--bd-sub); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; +} + +/* 营收 */ +.bd-revenue-tags { + display: flex; + gap: 6px; + flex-shrink: 0; + flex-wrap: wrap; +} +.bd-revenue-tags span { + font-size: 10px; + color: #64748d; + background: rgba(255, 255, 255, 0.75); + border: 1px solid rgba(23, 178, 106, 0.16); + padding: 3px 8px; + border-radius: 8px; + white-space: nowrap; +} +.bd-revenue-tags b { + color: var(--bd-green); + font-family: "JetBrains Mono", monospace; +} + +/* ============ 底部综合指标条 ============ */ +.bd-strip { + position: relative; + z-index: 2; + flex-shrink: 0; + display: flex; + align-items: center; + gap: 16px; + padding: 8px clamp(12px, 1.5vw, 22px); + background: rgba(255, 255, 255, 0.5); + backdrop-filter: blur(14px) saturate(140%); + -webkit-backdrop-filter: blur(14px) saturate(140%); + border-top: 1px solid rgba(47, 107, 255, 0.08); +} +.bd-strip-title { + font-size: 12px; + font-weight: 700; + color: var(--bd-ink); + letter-spacing: 0.08em; + white-space: nowrap; + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; +} +.bd-strip-title::before { + content: ''; + width: 14px; + height: 2px; + border-radius: 2px; + background: linear-gradient(90deg, var(--bd-blue), var(--bd-cyan)); +} +.bd-strip-chips { + flex: 1; + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 4px clamp(6px, 1vw, 14px); + min-width: 0; +} +.bd-chip { + display: flex; + align-items: center; + gap: 6px; + font-size: 11px; + color: var(--bd-sub); + white-space: nowrap; + flex-shrink: 0; +} +.bd-chip-ico { + font-size: 13px; +} +.bd-chip-label { + color: #9fb0c6; +} +.bd-chip b { + color: var(--bd-blue); + font-family: "JetBrains Mono", monospace; + font-weight: 700; +} + +/* ============ 自适应(所有内容一屏展示 · 禁止滚动条) ============ */ +/* 中低高度屏幕:压缩固定尺寸 */ +@media (max-height: 920px) { + .bd-overview-head { margin-bottom: 6px; } + .bd-kpi-value { font-size: 21px; } + .bd-kpi-ico { width: 34px; height: 34px; font-size: 15px; } + .bd-kpi { padding: 8px 11px; gap: 9px; } + .bd-donut { width: 96px; height: 96px; } + .bd-zone-wrap .bd-donut { width: 84px; height: 84px; } + .bd-cell-feed .bd-feed-item { padding: 1px 6px; } + .bd-panel-stat { padding: 5px 8px; } + .bd-vbar-name { font-size: 8px; } + .bd-feed-row .bd-feed-card { height: 120px; } +} +/* 小高度屏幕:继续压缩 */ +@media (max-height: 900px) { + .bd-header { height: 54px; } + .bd-header-title { font-size: 17px; } + .bd-header-sub { display: none; } + .bd-clock-time { font-size: 16px; } + .bd-title { font-size: 12.5px; } + .bd-kpi-value { font-size: 19px; } + .bd-kpi { padding: 6px 10px; } + .bd-kpi-ico { width: 30px; height: 30px; font-size: 14px; } + .bd-kpi-label { font-size: 10.5px; } + .bd-kpi-sub { font-size: 10px; } + .bd-donut { width: 76px; height: 76px; } + .bd-zone-wrap .bd-donut { width: 56px; height: 56px; } + .bd-panel-stat b { font-size: 13.5px; } + .bd-panel-stat { padding: 3px 7px; } + .bd-ticker-title { display: none; } + .bd-tools-foot { display: none; } + .bd-hbar-title { display: none; } + .bd-zone-wrap { margin-bottom: 0; } + .bd-revenue-tags span { padding: 2px 6px; font-size: 9px; } + .bd-overview, .bd-strip, .bd-feed-row { flex-shrink: 0; } +} +/* 极矮屏幕:极限压缩,保证一屏完整、无滚动 */ +@media (max-height: 800px) { + .bd-header { height: 50px; } + .bd-header-title { font-size: 16px; } + .bd-clock-time { font-size: 14px; } + .bd-overview { padding-top: 8px; } + .bd-overview-head { margin-bottom: 5px; } + .bd-ov-status { gap: 4px; } + .bd-ost-chip { padding: 2px 7px; font-size: 9.5px; } + .bd-kpi { padding: 5px 9px; gap: 8px; } + .bd-kpi-ico { width: 26px; height: 26px; font-size: 13px; } + .bd-kpi-value { font-size: 17px; } + .bd-kpi-label { font-size: 10px; } + .bd-kpi-sub { font-size: 9.5px; } + .bd-donut { width: 60px; height: 60px; } + .bd-zone-wrap .bd-donut { width: 48px; height: 48px; } + .bd-card { padding: 8px 10px; } + .bd-card-head { margin-bottom: 4px; } + .bd-panel-stat { padding: 2px 6px; } + .bd-panel-stat b { font-size: 12.5px; } + .bd-panel-stat-label { font-size: 9px; } + .bd-hbar { gap: 5px; } + .bd-hbar-track { height: 6px; } + .bd-hbars { gap: 4px; } + .bd-hbar-name { font-size: 10px; } + .bd-vbar-val { font-size: 8.5px; } + .bd-vbar-name { font-size: 7.5px; } + .bd-jobs-bars { gap: 3px; } + .bd-revenue-tags { gap: 4px; } + .bd-revenue-tags span { padding: 2px 5px; font-size: 8.5px; } + .bd-feed-row .bd-feed-card { height: 108px; } + .bd-feed-row .bd-feed-item { padding: 2px 7px; font-size: 10px; } + .bd-strip { padding: 5px clamp(12px, 1.5vw, 22px); } + .bd-strip-title { font-size: 11px; } + .bd-chip { font-size: 10px; } + .bd-model-list { flex-basis: 88px; } + .bd-value-list { flex-basis: 44px; } + .bd-split-tri .bd-donut { width: 64px; height: 64px; } +} +/* 窄屏:收缩 TOKEN 卡内部列宽 + 概览条压缩 */ +@media (max-width: 1500px) { + .bd-model-list { flex-basis: 92px; } + .bd-value-list { flex-basis: 46px; } + .bd-split-tri .bd-donut { width: 72px; height: 72px; } + .bd-strip-title { display: none; } + .bd-strip-chips { gap: 3px 8px; } + .bd-chip { font-size: 10px; } + .bd-chip-ico { font-size: 12px; } +} + +/* ============ Appica SVG 图标 ============ */ +.appica-ico { + display: inline-block; + vertical-align: -0.18em; + flex-shrink: 0; +} +.bd-title-ico .appica-ico, +.bd-title-ico svg { color: var(--bd-blue); } +.bd-kpi-ico .appica-ico, +.bd-kpi-ico svg { color: currentColor; } +.bd-kpi.token .bd-kpi-ico { color: #4cc2ff; } +.bd-kpi.tool .bd-kpi-ico { color: #5b8cff; } +.bd-kpi.project .bd-kpi-ico { color: #2fd08b; } +.bd-kpi.job .bd-kpi-ico { color: #f5a53c; } +.bd-kpi.revenue .bd-kpi-ico { color: #ff7a6b; } +.bd-feed-ico .appica-ico, +.bd-feed-ico svg { color: #7fa8ff; } +.bd-chip-ico .appica-ico, +.bd-chip-ico svg { color: var(--bd-blue); } +.bd-revenue-tags svg, +.bd-revenue-tags .appica-ico { color: #f79009; vertical-align: -0.15em; margin-right: 2px; } + +/* ============ Appica Autocomplete 企业搜索 ============ */ +.bd-search { + position: relative; + width: 240px; +} +.bd-search .AppicaAutocomplete-root, +.bd-search [data-appica-autocomplete] { + width: 100%; +} +/* 输入框 */ +.bd-search .AppicaAutocomplete-input, +.bd-search input[role="combobox"] { + width: 100%; + height: 34px; + padding: 0 30px 0 34px; + font-size: 12.5px; + color: var(--bd-ink); + background: rgba(255, 255, 255, 0.7); + border: 1px solid rgba(47, 107, 255, 0.16); + border-radius: 9px; + outline: none; + transition: border-color 0.2s, box-shadow 0.2s; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); +} +.bd-search input[role="combobox"]::placeholder { + color: #8fa1ba; +} +.bd-search input[role="combobox"]:focus { + border-color: rgba(47, 107, 255, 0.5); + box-shadow: 0 0 0 3px rgba(47, 107, 255, 0.12); +} +/* 弹出层 */ +.bd-search-pos { + z-index: 2000 !important; +} +.bd-search-pop { + z-index: 2000; + min-width: 280px; + overflow: hidden; + background: rgba(20, 30, 50, 0.96); + border: 1px solid rgba(120, 160, 220, 0.25); + border-radius: 12px; + box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); +} +.bd-search-pop [role="listbox"] { + max-height: 320px; + overflow-y: auto; + padding: 6px; +} +.bd-search-pop [role="option"] { + display: flex; + align-items: center; + padding: 8px 10px; + border-radius: 8px; + cursor: pointer; + color: #dbe6f5; + font-size: 12.5px; + transition: background 0.15s; +} +.bd-search-pop [role="option"]:hover, +.bd-search-pop [role="option"][data-highlighted] { + background: rgba(76, 140, 255, 0.18); +} +.bd-search-pop [role="option"][data-selected] { + background: rgba(76, 140, 255, 0.25); +} +.bd-search-pop [role="presentation"]:empty { + padding: 14px; + text-align: center; + color: #7d8fa9; + font-size: 12px; +} +/* 列表项 */ +.bd-search-item { + display: flex; + align-items: center; + gap: 10px; + width: 100%; +} +.bd-search-zone { + display: inline-flex; + flex-shrink: 0; +} +.bd-search-info { + display: flex; + flex-direction: column; + gap: 1px; + min-width: 0; + flex: 1; +} +.bd-search-info b { + font-size: 12.5px; + font-weight: 600; + color: #eaf1fb; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.bd-search-info em { + font-style: normal; + font-size: 11px; + color: #7d93b5; +} +.bd-search-room { + flex-shrink: 0; + font-family: "JetBrains Mono", monospace; + font-size: 11px; + font-weight: 600; + color: #4cc2ff; + background: rgba(76, 194, 255, 0.12); + border: 1px solid rgba(76, 194, 255, 0.25); + border-radius: 6px; + padding: 2px 7px; +} +/* 选中结果 */ +.bd-search-result { + position: absolute; + top: 40px; + right: 0; + width: 280px; + z-index: 900; + padding: 12px 14px; + background: rgba(20, 30, 50, 0.97); + border: 1px solid rgba(120, 160, 220, 0.25); + border-radius: 12px; + box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); +} +.bd-search-result-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 8px; +} +.bd-search-result-name { + font-size: 14px; + font-weight: 700; + color: #fff; +} +.bd-search-result-zone { + font-size: 12px; + font-weight: 600; +} +.bd-search-result-meta { + display: flex; + gap: 14px; + font-size: 11.5px; + color: #8fa1ba; +} +.bd-search-result-meta b { + color: #eaf1fb; + font-weight: 600; + margin-left: 3px; +} +.bd-search-result-meta b.ok { + color: #34d399; +} + +/* 深色页面下 autocomplete 内联控件颜色 */ +.bd-page [data-appica-clear], +.bd-page [data-appica-chevron] { + color: #8fa1ba; +} + +/* ============ 数字孪生独立页(/twin) ============ */ +.bd-twin-page { + height: 100vh; + display: flex; + 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; +} +.bd-twin-main { + flex: 1; + min-height: 0; + display: grid; + grid-template-columns: minmax(0, 1fr) 320px; + gap: 14px; + padding: 14px; +} +.bd-twin-stage { + position: relative; + min-width: 0; + border-radius: 16px; + overflow: hidden; + background: linear-gradient(180deg, rgba(255,255,255,0.4), rgba(255,255,255,0.15)); + border: 1px solid rgba(120, 160, 220, 0.14); +} +.bd-twin-stage .bd3d-wrap { + position: absolute; + inset: 0; +} +.bd-twin-legend { + position: absolute; + bottom: 14px; + left: 14px; + z-index: 10; + display: flex; + gap: 14px; + padding: 8px 14px; + background: rgba(255,255,255,0.85); + border: 1px solid rgba(120,160,220,0.2); + border-radius: 10px; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); +} +.bd-twin-legend span { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 11.5px; + color: #4a5b76; + font-weight: 500; +} +.bd-twin-legend i { + width: 9px; + height: 9px; + border-radius: 50%; +} +/* 右侧面板 */ +.bd-twin-side { + display: flex; + flex-direction: column; + gap: 12px; + min-height: 0; + min-width: 0; + overflow: hidden; +} +.bd-twin-zones { + display: flex; + gap: 8px; + flex-shrink: 0; +} +.bd-twin-zone { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; + padding: 10px 6px; + font-size: 13px; + font-weight: 700; + color: #64748d; + background: rgba(255,255,255,0.7); + border: 1px solid rgba(120,160,220,0.2); + border-radius: 10px; + cursor: pointer; + transition: all 0.2s; +} +.bd-twin-zone em { + font-style: normal; + font-size: 10.5px; + font-weight: 500; + color: #8fa1ba; +} +.bd-twin-zone.active { + background: rgba(255,255,255,0.95); + box-shadow: 0 4px 14px rgba(47,107,255,0.12); +} +.bd-twin-list { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; + flex: 1; + min-height: 0; + overflow-y: auto; + padding: 2px; + align-content: start; +} +.bd-twin-item { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 5px; + padding: 9px 10px; + background: rgba(255,255,255,0.72); + border: 1px solid rgba(120,160,220,0.16); + border-radius: 10px; + cursor: pointer; + text-align: left; + transition: all 0.2s; +} +.bd-twin-item:hover { + background: rgba(255,255,255,0.95); + transform: translateY(-1px); +} +.bd-twin-item.active { + background: rgba(76,140,255,0.10); + border-color: rgba(76,140,255,0.4); + box-shadow: 0 4px 14px rgba(76,140,255,0.15); +} +.bd-twin-room { + font-family: "JetBrains Mono", monospace; + font-size: 11px; + font-weight: 700; + border: 1px solid; + border-radius: 5px; + padding: 1px 6px; +} +.bd-twin-name { + font-size: 11.5px; + font-weight: 600; + color: #33415c; + line-height: 1.35; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.bd-twin-detail { + flex-shrink: 0; + padding: 12px 14px; + background: rgba(255,255,255,0.85); + border: 1px solid rgba(120,160,220,0.2); + border-radius: 12px; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); +} +.bd-twin-detail-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 8px; +} +.bd-twin-detail-head b { + font-size: 14px; + color: #1d2c44; +} +.bd-twin-detail-head span { + font-size: 12px; + font-weight: 600; +} +.bd-twin-detail-meta { + display: flex; + gap: 16px; + font-size: 12px; + color: #64748d; +} +.bd-twin-detail-meta b { color: #1d2c44; margin-left: 3px; } +.bd-twin-detail-meta b.ok { color: #17b26a; } +.bd-twin-feed { + flex-shrink: 0; + max-height: 190px; +} +.bd-twin-feed .bd-feed { + overflow-y: auto; +} + +/* 导航提示按钮 */ +.bd-nav-hint { + display: inline-flex; + align-items: center; + gap: 5px; + padding: 7px 13px; + font-size: 12.5px; + font-weight: 600; + color: #4a5b76; + background: rgba(255,255,255,0.75); + border: 1px solid rgba(47,107,255,0.16); + border-radius: 9px; + cursor: pointer; + transition: all 0.2s; + white-space: nowrap; +} +.bd-nav-hint:hover { + color: var(--bd-blue); + border-color: rgba(47,107,255,0.4); + background: rgba(255,255,255,0.95); +} +.bd-nav-hint .appica-ico { color: var(--bd-blue); } + +/* ============ 园区今日概览 ============ */ +.bd-overview { + position: relative; + z-index: 2; + flex-shrink: 0; + padding: clamp(10px, 1vw, 14px) clamp(12px, 1.5vw, 22px) 0; +} +.bd-overview-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: clamp(7px, 0.7vw, 10px); +} +/* 运行状态内联条(标题右侧) */ +.bd-ov-status { + flex: 1; + min-width: 0; + display: flex; + align-items: center; + justify-content: flex-end; + flex-wrap: wrap; + gap: 5px; +} +/* 卡片标题右侧的概括数据内联 */ +.bd-head-stats { + display: flex; + align-items: center; + justify-content: flex-end; + flex-wrap: wrap; + gap: 5px; +} +.bd-ost-chip { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 3px 9px; + font-size: 10px; + border-radius: 12px; + white-space: nowrap; + background: rgba(255, 255, 255, 0.75); + border: 1px solid rgba(47, 107, 255, 0.14); +} +.bd-ost-chip .appica-ico { color: var(--bd-blue); } +.bd-ost-chip i { + font-style: normal; + color: var(--bd-sub); +} +.bd-ost-chip b { + font-family: "JetBrains Mono", "Oswald", monospace; + font-weight: 700; + color: var(--bd-blue); +} +.bd-overview-grid { + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + grid-template-rows: auto; + gap: clamp(6px, 0.6vw, 10px); +} +.bd-cell { + min-width: 0; + min-height: 0; + display: flex; +} +.bd-cell .bd-kpi { flex: 1; } +/* 五个指标卡片:一行展示 */ +.bd-cell-token { grid-column: 1; } +.bd-cell-revenue { grid-column: 2; } +.bd-cell-projects { grid-column: 3; } +.bd-cell-tools { grid-column: 4; } +.bd-cell-jobs { grid-column: 5; } + +/* 底部园区概览(见 .bd-strip 区块) */