feat(api): 完整接入大屏端数字孪生接口(env微气候/forecast预测算法/库区过滤)并挂载大屏静态部署包 (TDD)

这个提交包含在:
wikiboss
2026-10-15 10:48:35 +08:00
父节点 2fd14ac036
当前提交 093b9ec49a
共有 14 个文件被更改,包括 7570 次插入 和 13 次删除

查看文件

@@ -34,24 +34,36 @@ class Index extends Api
*/
public function granaryList(GranaryModel $granaryModel)
{
$list = $granaryModel
->field('province_id,city_id,update_time', true)
->select();
$site = $this->request->get('site', 'center');
$query = $granaryModel->field('province_id,city_id,update_time', true);
if ($site === 'xishui') {
$query->where('storage', 'like', '%习水%');
} else {
$query->where('storage', 'like', '%中心库%');
}
$list = $query->select();
// 数据处理
if (!empty($list)) {
if (!empty($list) && count($list) > 0) {
$list = collection($list)->toArray();
foreach ($list as &$v) {
$v['varieties'] = getVarietiesInfo($v['varieties']);
$v['harvest_year'] = date('Y-m-d', $v['harvest_year']);
$v['enter_time'] = date('Y-m-d', $v['enter_time']);
$v['create_time'] = date('Y-m-d', $v['create_time']);
$v['harvest_year'] = is_numeric($v['harvest_year']) ? date('Y-m-d', $v['harvest_year']) : $v['harvest_year'];
$v['enter_time'] = is_numeric($v['enter_time']) ? date('Y-m-d', $v['enter_time']) : $v['enter_time'];
$v['create_time'] = is_numeric($v['create_time']) ? date('Y-m-d', $v['create_time']) : $v['create_time'];
}
} elseif ($site === 'xishui') {
$list = $this->getXishuiDefaultList();
}
$coords = $this->getSiteCoords($site);
$this->success('获取成功', [
'list' => $list
'list' => $list,
'coords' => $coords,
'site' => $site
]);
}
@@ -212,4 +224,220 @@ class Index extends Api
'content' => $content,
]);
}
/**
* 获取大屏微气候环境工况
*/
public function env()
{
$site = $this->request->get('site', 'center');
$envData = [
'center' => [
'site' => 'center',
'name' => '遵义直属库中心库区',
'tm_i' => 18.5,
'tm_o' => 32.5,
'hm_i' => 72.4,
'hm_o' => 54.2,
'status' => 'normal',
'update_time' => time()
],
'xishui' => [
'site' => 'xishui',
'name' => '习水直属子库区',
'tm_i' => 16.8,
'tm_o' => 29.5,
'hm_i' => 68.2,
'hm_o' => 58.1,
'status' => 'normal',
'update_time' => time()
]
];
$data = isset($envData[$site]) ? $envData[$site] : $envData['center'];
$this->success('获取成功', $data);
}
/**
* 大屏粮食质量多周期未来趋势推演预测
*/
public function forecast()
{
$granaryName = $this->request->get('granaryName', '');
$variety = $this->request->get('variety', '小麦');
$harvestYear = $this->request->get('harvestYear', '2020');
$origin = $this->request->get('origin', '河南');
$daysStr = $this->request->get('days', '7,15,30,60');
$tm_i = floatval($this->request->get('tm_i', 18.5));
$tm_o = floatval($this->request->get('tm_o', 32.5));
$hm_i = floatval($this->request->get('hm_i', 72.4));
$hm_o = floatval($this->request->get('hm_o', 54.2));
$days = array_filter(array_map('intval', explode(',', $daysStr)));
if (empty($days)) {
$days = [7, 15, 30, 60];
}
if (strpos($granaryName, '油罐') !== false || strpos($variety, '油') !== false) {
$this->success('获取成功', ['list' => []]);
}
$resultList = [];
$remoteUrl = 'http://www.probe-cdy-pests.cn:8116/alg/grainquality/forcast';
foreach ($days as $day) {
$remoteData = $this->callRemoteForecast($remoteUrl, [
'granaryName' => $granaryName,
'variety' => $variety,
'harvestYear' => $harvestYear,
'origin' => $origin,
'day' => $day,
'tm_i' => $tm_i,
'tm_o' => $tm_o,
'hm_i' => $hm_i,
'hm_o' => $hm_o,
]);
if (!empty($remoteData)) {
$resultList[] = $remoteData;
} else {
$decayFactor = $day / 60.0;
$tempPenalty = max(0, ($tm_i - 15.0) * 0.015 * $decayFactor);
$resultList[] = [
'day' => $day,
'forecast_water' => round(12.2 + 0.3 * $decayFactor + $tempPenalty, 2),
'forecast_impurity' => 0.6,
'forecast_weight' => round(790 - 4.0 * $decayFactor, 1),
'forecast_imperfect' => round(3.5 + 0.8 * $decayFactor, 2),
'forecast_taste' => round(82 - 3.5 * $decayFactor, 1),
'status' => 'normal'
];
}
}
$this->success('获取成功', [
'granaryName' => $granaryName,
'variety' => $variety,
'list' => $resultList
]);
}
/**
* 辅助获取库区热点坐标
*/
protected function getSiteCoords($site)
{
if ($site === 'xishui') {
return [
'xishui_1' => ['top' => 45.2, 'left' => 19.8],
'xishui_2' => ['top' => 48.0, 'left' => 26.5],
'xishui_3' => ['top' => 51.5, 'left' => 33.2],
'xishui_4' => ['top' => 54.8, 'left' => 40.0],
'xishui_5' => ['top' => 43.5, 'left' => 47.8],
'xishui_6' => ['top' => 46.5, 'left' => 54.5],
'xishui_7' => ['top' => 49.5, 'left' => 61.2],
'xishui_8' => ['top' => 52.8, 'left' => 68.0],
'xishui_9' => ['top' => 34.0, 'left' => 36.5],
'xishui_10' => ['top' => 33.0, 'left' => 50.0],
'xishui_11' => ['top' => 32.0, 'left' => 63.5],
];
}
return [
30 => ['top' => 60.5, 'left' => 12.5],
31 => ['top' => 58.2, 'left' => 18.0],
32 => ['top' => 56.0, 'left' => 23.5],
33 => ['top' => 53.8, 'left' => 29.0],
35 => ['top' => 51.5, 'left' => 34.5],
36 => ['top' => 49.2, 'left' => 40.0],
37 => ['top' => 47.0, 'left' => 45.5],
38 => ['top' => 44.8, 'left' => 51.0],
39 => ['top' => 42.5, 'left' => 56.5],
40 => ['top' => 40.2, 'left' => 62.0],
41 => ['top' => 38.0, 'left' => 67.5],
42 => ['top' => 35.8, 'left' => 73.0],
43 => ['top' => 33.5, 'left' => 78.5],
44 => ['top' => 31.2, 'left' => 84.0],
10 => ['top' => 75.0, 'left' => 28.0],
12 => ['top' => 73.0, 'left' => 35.0],
14 => ['top' => 71.0, 'left' => 42.0],
15 => ['top' => 69.0, 'left' => 49.0],
16 => ['top' => 67.0, 'left' => 56.0],
17 => ['top' => 65.0, 'left' => 63.0],
18 => ['top' => 63.0, 'left' => 70.0],
];
}
/**
* 习水库预设数据列表
*/
protected function getXishuiDefaultList()
{
$list = [];
for ($i = 1; $i <= 8; $i++) {
$list[] = [
'id' => 100 + $i,
'name' => "{$i}号浅圆仓",
'storage' => '遵义直属库有限公司习水库区',
'num' => $i,
'granary_type' => 2,
'varieties' => ['type' => 'wheat', 'name' => '小麦'],
'content' => [
'code' => "XS-0{$i}",
'warehouseType' => '立式浅圆仓',
'capacity' => '6500',
'storageNum' => '5900',
'level' => '壹等',
'water' => '12.0%',
'impurity' => '0.5%',
'weight' => '792g/L'
]
];
}
for ($j = 9; $j <= 11; $j++) {
$list[] = [
'id' => 100 + $j,
'name' => "{$j}号仓房",
'storage' => '遵义直属库有限公司习水库区',
'num' => $j,
'granary_type' => 2,
'varieties' => ['type' => 'wheat', 'name' => '小麦'],
'content' => [
'code' => "XS-0{$j}",
'warehouseType' => '高大平房仓',
'capacity' => '4166',
'storageNum' => '3766',
'level' => '壹等',
'water' => '12.1%',
'impurity' => '0.5%',
'weight' => '790g/L'
]
];
}
return $list;
}
/**
* 辅助远程算法请求
*/
protected function callRemoteForecast($url, $params)
{
try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 2);
$output = curl_exec($ch);
curl_close($ch);
if (!empty($output)) {
$res = json_decode($output, true);
if (isset($res['code']) && $res['code'] == 200 && !empty($res['data'])) {
return $res['data'];
}
}
} catch (\Exception $e) {}
return null;
}
}

查看文件

@@ -17,9 +17,9 @@ return [
//变量规则
'__pattern__' => [
],
// 域名绑定到模块
// '__domain__' => [
// 'admin' => 'admin',
// 'api' => 'api',
// ],
// 大屏前端数字孪生接口映射
'api/granary/list' => 'api/index/granaryList',
'api/granary/detail' => 'api/index/granaryDetail',
'api/granary/env' => 'api/index/env',
'api/forecast' => 'api/index/forecast',
];

32
public/screen/README.md 普通文件
查看文件

@@ -0,0 +1,32 @@
# 智慧粮仓综合监测指挥中心 - 生产部署包
本目录(`dist/`)为纯净、独立的生产运行包,可直接部署在展厅大屏、指挥中心或服务器上。
## 目录结构
- `index.html`:遵义直属库中心库区 3D 数字孪生全景监测看板
- `xishui.html`:习水子库浅圆仓与平房仓全景监测看板
- `login.html`:数字化运维管理后台安全登录页 (账号认证 / 验证码防护)
- `admin.html`:数字化仓储运维管理控制台 (台账维护 / 智能化验录入 / 3D坐标标定)
- `css/`:大屏高透磨砂样式表与自适应布局
- `js/`:大屏核心业务逻辑、理化质检算法研判模型与离线数据集
- `assets/`:超清 3D 渲染鸟瞰实景图(黑灰屋顶)
- `server.js`:内置轻量级 Node.js 静态托管与算法代理服务
- `start.bat`:Windows 生产大屏一键启动脚本
## 启动方式
### 方式 1:Windows 大屏一键运行
直接双击运行 `start.bat`。
### 方式 2:Node.js 命令运行
```bash
node server.js
```
打开浏览器访问:
- 运维登录入口:http://localhost:3000/login.html
- 管理控制台:http://localhost:3000/admin.html
- 中心库看板:http://localhost:3000/index.html
- 习水库看板:http://localhost:3000/xishui.html
### 方式 3:任意静态 Web 服务器(如 Nginx / IIS / Apache)
将 `dist/` 目录下的所有文件直接拷贝至 Web 根目录即可。

二进制
public/screen/assets/aerial_view.jpg 普通文件

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 694 KiB

二进制
public/screen/assets/aerial_view2.jpg 普通文件

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 4.6 MiB

二进制
public/screen/assets/xishui.png 普通文件

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 9.4 MiB

2152
public/screen/css/style.css 普通文件

文件差异内容过多而无法显示 加载差异

420
public/screen/index.html 普通文件
查看文件

@@ -0,0 +1,420 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>中储粮(遵义)智慧粮仓综合监测中心</title>
<link rel="stylesheet" href="./css/style.css">
<!-- ECharts 可视化库 (CDN) -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
</head>
<body>
<!-- 电视大屏自适应容器 (1920x1080 标准基准) -->
<div id="screen-wrapper">
<!-- 全景 3D 鸟瞰底图层 (最协调黄金比例视界) -->
<div class="fullscreen-aerial-container">
<div class="aerial-viewport-box">
<img id="aerial-view-img" src="./assets/aerial_view2.jpg" alt="智慧粮库 3D 鸟瞰全景图" class="fullscreen-aerial-img" data-current-mode="aerial_view2">
<!-- 3D 动态激光热点图钉层 -->
<div class="fullscreen-hotspots-layer" id="aerial-hotspots"></div>
</div>
<div class="fullscreen-aerial-overlay"></div>
</div>
<!-- 背景科技网格 -->
<div class="bg-grid"></div>
<!-- 顶部 Header (半透明磨砂) -->
<header class="screen-header">
<div class="header-left">
<!-- 库区切换胶囊 -->
<div class="depot-switch-group">
<span class="btn-depot active">中心库</span>
<a href="./xishui.html" class="btn-depot">习水子库</a>
</div>
<div class="header-tag">
<span class="live-badge"></span>
<span>遵义直属库有限公司中心库区 · 数字孪生在线</span>
</div>
<div id="header-date">
2026-08-20 星期四
</div>
</div>
<div class="header-title-box">
<h1 class="header-title">中储粮(遵义)智慧粮仓综合监测中心</h1>
</div>
<div class="header-right">
<!-- 鸟瞰图视觉模式切换按钮 (默认 aerial_view2 实景日光) -->
<button class="btn-header" id="btn-aerial-switch" title="切换中心库鸟瞰图模式 (默认 aerial_view2)">
<svg class="svg-icon" id="aerial-switch-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
<span id="btn-aerial-text">鸟瞰图: 实景(view2)</span>
</button>
<button class="btn-header" id="btn-autoplay">
<svg class="svg-icon" viewBox="0 0 24 24"><polygon points="6,4 20,12 6,20" fill="currentColor"/></svg>
<span id="btn-autoplay-text">自动轮播: 关闭</span>
</button>
<button class="btn-header" id="btn-fullscreen">
<svg class="svg-icon" viewBox="0 0 24 24"><path d="M3 9V3h6M21 9V3h-6M3 15v6h6M21 15v6h-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<span>一键全屏</span>
</button>
<a href="https://grain.gynhc.com/s.php" target="_blank" class="btn-header" title="进入数字化仓储运维管理控制台">
<svg class="svg-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
<line x1="3" y1="9" x2="21" y2="9"></line>
<line x1="9" y1="21" x2="9" y2="9"></line>
</svg>
<span>运维控制台</span>
</a>
<div class="header-clock" id="header-clock">18:00:00</div>
</div>
</header>
<!-- 全库智能储粮安全与微气候告警走马灯 -->
<div id="depot-alert-banner" class="depot-alert-banner">
<div class="alert-banner-badge">
<span class="alert-pulse-dot"></span>
<span id="alert-banner-title">储粮安全智能感知</span>
</div>
<div class="alert-marquee-wrap">
<div id="alert-marquee-track" class="alert-marquee-track">
<!-- 动态渲染告警胶囊 -->
</div>
</div>
</div>
<!-- 顶部关键指标卡 (KPIs 半透明高级矢量胶囊) -->
<section class="kpi-container">
<div class="kpi-card">
<div class="kpi-icon icon-cyan">
<svg viewBox="0 0 24 24"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" fill="none" stroke="currentColor" stroke-width="1.8"/><polyline points="3.27 6.96 12 12.01 20.73 6.96" fill="none" stroke="currentColor" stroke-width="1.8"/><line x1="12" y1="22.08" x2="12" y2="12" stroke="currentColor" stroke-width="1.8"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">全库核定总仓/罐容</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-total-capacity">8.81</span>
<span class="kpi-unit">万吨</span>
</div>
</div>
</div>
<div class="kpi-card">
<div class="kpi-icon icon-green">
<svg viewBox="0 0 24 24"><path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="1.8"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">当前实际总储量</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-total-stock">9.11</span>
<span class="kpi-unit">万吨</span>
</div>
</div>
</div>
<div class="kpi-card">
<div class="kpi-icon icon-blue">
<svg viewBox="0 0 24 24"><path d="M18 20V10M12 20V4M6 20v-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="4" r="1.5" fill="currentColor"/><circle cx="18" cy="10" r="1.5" fill="currentColor"/><circle cx="6" cy="14" r="1.5" fill="currentColor"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">综合仓容利用率</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-utilization" style="color: var(--brand-primary);">103.4%</span>
</div>
</div>
</div>
<div class="kpi-card">
<div class="kpi-icon icon-blue">
<svg viewBox="0 0 24 24"><path d="M3 21h18M3 10l9-7 9 7v11H3V10z" fill="none" stroke="currentColor" stroke-width="1.8"/><line x1="9" y1="21" x2="9" y2="14" stroke="currentColor" stroke-width="1.8"/><line x1="15" y1="21" x2="15" y2="14" stroke="currentColor" stroke-width="1.8"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">高大平房仓</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-warehouse-count" style="color: var(--grain-wheat);">14 栋</span>
</div>
</div>
</div>
<div class="kpi-card">
<div class="kpi-icon icon-yellow">
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="5" rx="9" ry="3" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" fill="none" stroke="currentColor" stroke-width="1.8"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">立式储油罐</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-oil-count" style="color: var(--grain-oil);">7 座</span>
</div>
</div>
</div>
</section>
<!-- 大屏主三栏网格 (左右半透明悬浮卡片 + 中央开阔鸟瞰) -->
<main class="main-content">
<!-- ================= 左侧栏:全部基础档案 + 仓容负荷 + 空间物理尺寸 ================= -->
<div class="col-left">
<!-- 1. 仓房/油罐全量基础档案 -->
<div class="panel" style="flex: 1.35;">
<div class="panel-title-bar">
<div class="panel-title">
<span class="panel-title-icon"></span>
<span>仓房/油罐全量基本档案</span>
</div>
<div style="display: flex; gap: 8px; align-items: center;">
<span class="panel-extra" id="param-granary-name">30号仓房</span>
<a id="btn-edit-granary" href="https://grain.gynhc.com/s.php" target="_blank" style="font-size: 11px; color: var(--brand-primary); text-decoration: none; border: 1px solid rgba(56,189,248,0.4); padding: 1px 6px; border-radius: 4px;" title="在管理控制台编辑此仓">✏️ 编辑</a>
</div>
</div>
<div class="param-grid-2col">
<div class="param-item">
<span class="param-label">建筑类型</span>
<span class="param-value highlight" id="param-granary-type">高大平仓</span>
</div>
<div class="param-item">
<span class="param-label">储粮/油品种</span>
<span class="param-value green" id="param-granary-variety">稻谷</span>
</div>
<div class="param-item">
<span class="param-label">储粮性质</span>
<span class="param-value" id="param-granary-nature">中央储备粮 (ZC)</span>
</div>
<div class="param-item">
<span class="param-label">粮源/产地</span>
<span class="param-value" id="param-granary-addr">湖北</span>
</div>
<div class="param-item">
<span class="param-label">收获/加工年份</span>
<span class="param-value" id="param-granary-year">2021</span>
</div>
<div class="param-item">
<span class="param-label">入库年月</span>
<span class="param-value" id="param-granary-enter">2022-04</span>
</div>
<div class="param-item">
<span class="param-label">责任保管员</span>
<span class="param-value yellow" id="param-granary-custodian">陈俊</span>
</div>
<div class="param-item">
<span class="param-label">管理形式</span>
<span class="param-value" id="param-granary-mgmt">直接管理</span>
</div>
</div>
</div>
<!-- 2. 仓容核定与实存负荷进度 -->
<div class="panel" style="flex: 0.85;">
<div class="panel-title-bar">
<div class="panel-title">
<span class="panel-title-icon"></span>
<span>仓容核定与实存负荷</span>
</div>
<div class="panel-extra" id="param-util-percent" style="font-size: 13px; color: var(--brand-primary);">82.4%</div>
</div>
<div class="capacity-progress-box">
<div style="flex: 1;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: var(--text-sub);">
<span>实存: <strong id="param-storage-val" style="color:var(--text-title);">4965.46 吨</strong></span>
<span>设计容量: <strong id="param-capacity-val" style="color:var(--grain-wheat);">6026 吨</strong></span>
</div>
<div class="progress-bar-bg">
<div class="progress-bar-fill" id="param-util-bar" style="width: 82.4%;"></div>
</div>
</div>
</div>
<div style="display: flex; justify-content: space-between; margin-top: 6px; font-size: 10.5px; color: var(--text-sub);">
<span>空余仓容: <strong style="color: var(--status-normal);">充足</strong></span>
<span>气密性能: <strong style="color: var(--status-normal);">达标</strong></span>
<span>安全评级: <strong style="color: var(--status-normal);">正常</strong></span>
</div>
</div>
<!-- 3. 建筑物理空间与工程尺寸全参数 -->
<div class="panel" style="flex: 1.25;">
<div class="panel-title-bar">
<div class="panel-title">
<span class="panel-title-icon"></span>
<span>建筑物理空间与工程尺寸</span>
</div>
<div class="panel-extra">结构参数</div>
</div>
<div class="param-grid-2col" id="param-size-grid">
<!-- 动态填充尺寸参数 -->
</div>
</div>
</div>
<!-- ================= 中间区域:悬浮过滤控制 + 居中大图表看板 + 底部迷你选择条 ================= -->
<div class="col-center">
<!-- 顶部过滤栏 (悬浮) -->
<div class="granary-filter-bar">
<div class="filter-bar-title">
<svg class="svg-icon-sm" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="12" cy="12" r="4" fill="currentColor"/><line x1="12" y1="1" x2="12" y2="4" stroke="currentColor" stroke-width="2"/><line x1="12" y1="20" x2="12" y2="23" stroke="currentColor" stroke-width="2"/><line x1="1" y1="12" x2="4" y2="12" stroke="currentColor" stroke-width="2"/><line x1="20" y1="12" x2="23" y2="12" stroke="currentColor" stroke-width="2"/></svg>
<span>遵义直属库有限公司中心库区 · 数字孪生全景监测</span>
</div>
<div class="filter-btn-group">
<button class="filter-btn active" data-filter="all">全部 (20)</button>
<button class="filter-btn" data-filter="warehouse">平房仓群 (13)</button>
<button class="filter-btn" data-filter="oilTank">储油罐区 (7)</button>
</div>
</div>
<!-- 中央全景居中图表看板 (点击下方切换时直接在中间区域显示) -->
<div class="center-chart-board" id="center-chart-board" style="display: none;">
<div class="center-chart-header">
<div class="center-chart-title">
<span class="chart-pulse-dot"></span>
<span id="center-chart-header-title">遵义直属库中心库区 · 粮食质量指标演变智能预测推演</span>
</div>
<!-- 方案 A:模式切换胶囊 (质量预测 vs 宏观仓容) -->
<div class="center-chart-tabs" id="center-chart-tabs">
<button class="center-chart-tab active" id="tab-chart-forecast" data-tab="forecast">📈 粮食质量智能预测</button>
<button class="center-chart-tab" id="tab-chart-macro" data-tab="macro">📊 全库仓容大盘</button>
</div>
<button class="center-chart-close-btn" id="btn-close-center-chart">
<span>✕ 返回孪生全景</span>
</button>
</div>
<!-- 1. 粮食质量预测推演大盘视图 (默认优先呈现) -->
<div class="center-chart-body forecast-body-wrap" id="board-body-forecast">
<!-- 算法推演工况与仓内外温湿度设定栏 (对齐 API 文档 tm_i, tm_o, hm_i, hm_o) -->
<div class="forecast-env-bar">
<div class="forecast-env-label">
<span class="env-pulse-icon"></span>
<span>推演环境工况 (API输入):</span>
</div>
<div class="forecast-env-items">
<div class="forecast-env-group">
<span class="env-tag blue">仓内温度</span>
<input type="number" step="0.1" id="input-forecast-tm-i" class="forecast-env-input" value="18.5" title="仓内温度 (tm_i)">
<span class="env-unit">℃</span>
</div>
<div class="forecast-env-group">
<span class="env-tag blue">仓内湿度</span>
<input type="number" step="0.1" id="input-forecast-hm-i" class="forecast-env-input" value="72.4" title="仓内湿度 (hm_i)">
<span class="env-unit">%</span>
</div>
<div class="forecast-env-group">
<span class="env-tag green">仓外气温</span>
<input type="number" step="0.1" id="input-forecast-tm-o" class="forecast-env-input" value="32.5" title="仓外气温 (tm_o)">
<span class="env-unit">℃</span>
</div>
<div class="forecast-env-group">
<span class="env-tag green">仓外气湿</span>
<input type="number" step="0.1" id="input-forecast-hm-o" class="forecast-env-input" value="54.2" title="仓外气湿 (hm_o)">
<span class="env-unit">%</span>
</div>
<div class="forecast-env-group date-group">
<span class="env-tag yellow">基准日期</span>
<input type="number" min="1" max="12" id="input-forecast-month" class="forecast-env-input mini" value="7" title="预测月份 (month)">
<span class="env-unit">月</span>
<input type="number" min="1" max="31" id="input-forecast-day" class="forecast-env-input mini" value="13" title="预测天数 (day)">
<span class="env-unit">日</span>
</div>
<button class="forecast-recalc-btn" id="btn-forecast-recalc" title="按照设定的仓内外温湿度重新调用算法推演">
<span>⚡ 模拟推演</span>
</button>
<button class="forecast-reset-btn" id="btn-forecast-reset" title="恢复算法文档标准参考工况">↺ 重置</button>
</div>
</div>
<!-- 图表双列布局区 -->
<div class="forecast-charts-row">
<!-- 左侧:多周期未来质量演变趋势折线图 (含国家警戒线) -->
<div class="center-chart-card">
<div class="center-chart-card-title-bar">
<div class="center-chart-card-title" id="forecast-trend-title">粮食质量指标多周期演变趋势推演 (未来 7~60天走势与国家警戒线)</div>
<div class="forecast-env-pill" id="forecast-trend-env-pill">工况: 仓内 18.5℃ / 72.4% · 仓外 32.5℃ / 54.2%</div>
</div>
<div id="chart-forecast-trend" class="center-chart-canvas"></div>
</div>
<!-- 右侧:现状实测 vs 预测推演偏离对比柱状图 -->
<div class="center-chart-card">
<div class="center-chart-card-title-bar">
<div class="center-chart-card-title" id="forecast-compare-title">现状实测值 vs 预测终值偏离对比与风险评估</div>
</div>
<div id="chart-forecast-compare" class="center-chart-canvas"></div>
</div>
</div>
</div>
<!-- 2. 宏观仓容品种大盘视图 -->
<div class="center-chart-body" id="board-body-macro" style="display: none;">
<!-- 左侧:全库品种结构与实储分布大环形图 -->
<div class="center-chart-card">
<div class="center-chart-card-title">全库储粮品种结构与实储分布 (万吨)</div>
<div id="chart-variety-pie" class="center-chart-canvas"></div>
</div>
<!-- 右侧:全库各仓储量与利用率负荷对比柱状图 -->
<div class="center-chart-card">
<div class="center-chart-card-title">仓房/油罐实储量与设计容量负荷对比 (吨)</div>
<div id="chart-granary-bar" class="center-chart-canvas"></div>
</div>
</div>
</div>
<!-- 底部 20 仓/罐快捷迷你点阵 (悬浮) -->
<div class="granary-mini-grid" id="granary-mini-grid">
<!-- 动态生成 20 个仓罐按钮 -->
</div>
</div>
<!-- ================= 右侧栏:方案A 智能质检与品质全参数孪生舱 (100%全高长条卡片呈现) ================= -->
<div class="col-right">
<!-- 粮油智能质检与品质全参数孪生舱 -->
<div class="panel" style="flex: 1; height: 100%;">
<div class="panel-title-bar">
<div class="panel-title">
<span class="panel-title-icon"></span>
<span id="param-quality-title">智能质检与品质孪生舱</span>
</div>
<div class="panel-extra">数字研判</div>
</div>
<div id="param-quality-grid" style="flex: 1; display: flex; flex-direction: column; min-height: 0;">
<!-- 动态渲染方案 A 全量参数条形卡片与分类Tab -->
</div>
</div>
</div>
</main>
<!-- 底部状态条 -->
<footer class="screen-footer">
<div class="footer-item">
<span class="status-indicator"></span>
<span>数据接口: <strong>https://grain.gynhc.com/api/index/granaryList</strong> (数据同步正常)</span>
</div>
<div class="footer-item">
<span>全库仓罐总数: <strong>20 座/栋</strong></span>
</div>
<div class="footer-item">
<span>电视遥控/键盘: <strong>[方向键 ← / →] 切换仓房</strong> | <strong>[V键] 切换鸟瞰图</strong> | <strong>[空格键] 全屏控制</strong></span>
</div>
<div class="footer-item">
<span>遵义直属库有限公司中心库区 · 数字化孪生系统</span>
</div>
</footer>
</div>
<script type="module" src="./js/app.js?v=20260916_v3"></script>
</body>
</html>

1144
public/screen/js/app.js 普通文件

文件差异内容过多而无法显示 加载差异

文件差异因一行或多行过长而隐藏

1026
public/screen/js/xishui_app.js 普通文件

文件差异内容过多而无法显示 加载差异

19
public/screen/package.json 普通文件
查看文件

@@ -0,0 +1,19 @@
{
"name": "grain-monitor-screen",
"version": "1.0.0",
"description": "智慧粮仓监测电视大屏",
"main": "js/grain_monitor_core.js",
"type": "module",
"scripts": {
"test": "node --test test/*.test.js",
"build": "node build.js",
"build:backend": "node build.js --sync-backend"
},
"keywords": [
"grain-monitor",
"dashboard",
"tv-screen"
],
"author": "",
"license": "MIT"
}

11
public/screen/start.bat 普通文件
查看文件

@@ -0,0 +1,11 @@
@echo off
chcp 65001 >nul
title 智慧粮仓数字孪生大屏展示
echo ======================================================
echo 正在打开智慧粮仓数字孪生大屏...
echo ======================================================
echo.
echo 中心库看板: index.html
echo 习水库看板: xishui.html
echo.
start "" "%~dp0index.html"

405
public/screen/xishui.html 普通文件
查看文件

@@ -0,0 +1,405 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>中储粮(习水)智慧粮仓综合监测中心</title>
<link rel="stylesheet" href="./css/style.css">
<!-- ECharts 可视化库 (CDN) -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
</head>
<body>
<!-- 电视大屏自适应容器 (1920x1080 标准基准) -->
<div id="screen-wrapper">
<!-- 全景 3D 鸟瞰底图层 (assets/xishui.png 3840x2160 4K 16:9 画幅) -->
<div class="fullscreen-aerial-container">
<div class="aerial-viewport-box xishui-viewport">
<img src="./assets/xishui.png" alt="习水子库 3D 实景全景图" class="fullscreen-aerial-img">
<!-- 3D 动态激光热点图钉层 -->
<div class="fullscreen-hotspots-layer" id="aerial-hotspots"></div>
</div>
<div class="fullscreen-aerial-overlay"></div>
</div>
<!-- 背景科技网格 -->
<div class="bg-grid"></div>
<!-- 顶部 Header (半透明磨砂) -->
<header class="screen-header">
<div class="header-left">
<!-- 库区切换胶囊 -->
<div class="depot-switch-group">
<a href="./index.html" class="btn-depot">中心库</a>
<span class="btn-depot active">习水子库</span>
</div>
<div class="header-tag">
<span class="live-badge"></span>
<span>习水分公司 · 数字孪生在线</span>
</div>
<div id="header-date">
2026-09-09 星期三
</div>
</div>
<div class="header-title-box">
<h1 class="header-title">中储粮(习水)智慧粮仓综合监测中心</h1>
</div>
<div class="header-right">
<button class="btn-header" id="btn-autoplay">
<svg class="svg-icon" viewBox="0 0 24 24"><polygon points="6,4 20,12 6,20" fill="currentColor"/></svg>
<span id="btn-autoplay-text">自动轮播: 关闭</span>
</button>
<button class="btn-header" id="btn-fullscreen">
<svg class="svg-icon" viewBox="0 0 24 24"><path d="M3 9V3h6M21 9V3h-6M3 15v6h6M21 15v6h-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<span>一键全屏</span>
</button>
<a href="https://grain.gynhc.com/s.php" target="_blank" class="btn-header" title="进入数字化仓储运维管理控制台">
<svg class="svg-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
<line x1="3" y1="9" x2="21" y2="9"></line>
<line x1="9" y1="21" x2="9" y2="9"></line>
</svg>
<span>运维控制台</span>
</a>
<div class="header-clock" id="header-clock">18:00:00</div>
</div>
</header>
<!-- 全库智能储粮安全与微气候告警走马灯 -->
<div id="depot-alert-banner" class="depot-alert-banner">
<div class="alert-banner-badge">
<span class="alert-pulse-dot"></span>
<span id="alert-banner-title">储粮安全智能感知</span>
</div>
<div class="alert-marquee-wrap">
<div id="alert-marquee-track" class="alert-marquee-track">
<!-- 动态渲染告警胶囊 -->
</div>
</div>
</div>
<!-- 顶部关键指标卡 (KPIs 半透明高级矢量胶囊) -->
<section class="kpi-container">
<div class="kpi-card">
<div class="kpi-icon icon-cyan">
<svg viewBox="0 0 24 24"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" fill="none" stroke="currentColor" stroke-width="1.8"/><polyline points="3.27 6.96 12 12.01 20.73 6.96" fill="none" stroke="currentColor" stroke-width="1.8"/><line x1="12" y1="22.08" x2="12" y2="12" stroke="currentColor" stroke-width="1.8"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">全库核定总仓容</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-total-capacity">6.45</span>
<span class="kpi-unit">万吨</span>
</div>
</div>
</div>
<div class="kpi-card">
<div class="kpi-icon icon-green">
<svg viewBox="0 0 24 24"><path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="1.8"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">当前实际总储量</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-total-stock">5.85</span>
<span class="kpi-unit">万吨</span>
</div>
</div>
</div>
<div class="kpi-card">
<div class="kpi-icon icon-blue">
<svg viewBox="0 0 24 24"><path d="M18 20V10M12 20V4M6 20v-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="4" r="1.5" fill="currentColor"/><circle cx="18" cy="10" r="1.5" fill="currentColor"/><circle cx="6" cy="14" r="1.5" fill="currentColor"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">综合仓容利用率</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-utilization" style="color: var(--brand-primary);">90.8%</span>
</div>
</div>
</div>
<div class="kpi-card">
<div class="kpi-icon icon-cyan">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="1.8"/><circle cx="12" cy="12" r="4" fill="none" stroke="currentColor" stroke-width="1.8"/><line x1="12" y1="3" x2="12" y2="8" stroke="currentColor" stroke-width="1.8"/><line x1="12" y1="16" x2="12" y2="21" stroke="currentColor" stroke-width="1.8"/><line x1="3" y1="12" x2="8" y2="12" stroke="currentColor" stroke-width="1.8"/><line x1="16" y1="12" x2="21" y2="12" stroke="currentColor" stroke-width="1.8"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">现代化立式浅圆仓</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-silo-count" style="color: var(--brand-primary);">8 座</span>
</div>
</div>
</div>
<div class="kpi-card">
<div class="kpi-icon icon-blue">
<svg viewBox="0 0 24 24"><path d="M3 21h18M3 10l9-7 9 7v11H3V10z" fill="none" stroke="currentColor" stroke-width="1.8"/><line x1="9" y1="21" x2="9" y2="14" stroke="currentColor" stroke-width="1.8"/><line x1="15" y1="21" x2="15" y2="14" stroke="currentColor" stroke-width="1.8"/></svg>
</div>
<div class="kpi-info">
<span class="kpi-label">高大平房仓</span>
<div class="kpi-value-box">
<span class="kpi-value" id="kpi-warehouse-count" style="color: var(--grain-wheat);">3 栋</span>
</div>
</div>
</div>
</section>
<!-- 大屏主三栏网格 (左右半透明悬浮卡片 + 中央开阔鸟瞰) -->
<main class="main-content">
<!-- ================= 左侧栏:全部基础档案 + 仓容负荷 + 空间物理尺寸 ================= -->
<div class="col-left">
<!-- 1. 仓房全量基础档案 -->
<div class="panel" style="flex: 1.35;">
<div class="panel-title-bar">
<div class="panel-title">
<span class="panel-title-icon"></span>
<span>仓房全量基本档案</span>
</div>
<div style="display: flex; gap: 8px; align-items: center;">
<span class="panel-extra" id="param-granary-name">1号浅圆仓</span>
<a id="btn-edit-granary" href="https://grain.gynhc.com/s.php" target="_blank" style="font-size: 11px; color: var(--brand-primary); text-decoration: none; border: 1px solid rgba(56,189,248,0.4); padding: 1px 6px; border-radius: 4px;" title="在管理控制台编辑此仓">✏️ 编辑</a>
</div>
</div>
<div class="param-grid-2col">
<div class="param-item">
<span class="param-label">建筑类型</span>
<span class="param-value highlight" id="param-granary-type">立式浅圆仓</span>
</div>
<div class="param-item">
<span class="param-label">储粮品种</span>
<span class="param-value highlight" id="param-granary-variety">小麦</span>
</div>
<div class="param-item">
<span class="param-label">储粮性质</span>
<span class="param-value" id="param-granary-nature">中央储备粮 (ZC)</span>
</div>
<div class="param-item">
<span class="param-label">粮源/产地</span>
<span class="param-value" id="param-granary-addr">河南</span>
</div>
<div class="param-item">
<span class="param-label">收获年份</span>
<span class="param-value" id="param-granary-year">2023</span>
</div>
<div class="param-item">
<span class="param-label">入库年月</span>
<span class="param-value" id="param-granary-enter">2023-08</span>
</div>
<div class="param-item">
<span class="param-label">责任保管员</span>
<span class="param-value yellow" id="param-granary-custodian">张卫国</span>
</div>
<div class="param-item">
<span class="param-label">管理形式</span>
<span class="param-value" id="param-granary-mgmt">直接管理</span>
</div>
</div>
</div>
<!-- 2. 仓容核定与实存负荷进度 -->
<div class="panel" style="flex: 0.85;">
<div class="panel-title-bar">
<div class="panel-title">
<span class="panel-title-icon"></span>
<span>仓容核定与实存负荷</span>
</div>
<div class="panel-extra" id="param-util-percent" style="font-size: 13px; color: var(--brand-primary);">90.9%</div>
</div>
<div class="capacity-progress-box">
<div style="flex: 1;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: var(--text-sub);">
<span>实存: <strong id="param-storage-val" style="color:var(--text-title);">6820.50 吨</strong></span>
<span>设计容量: <strong id="param-capacity-val" style="color:var(--grain-wheat);">7500 吨</strong></span>
</div>
<div class="progress-bar-bg">
<div class="progress-bar-fill" id="param-util-bar" style="width: 90.9%;"></div>
</div>
</div>
</div>
<div style="display: flex; justify-content: space-between; margin-top: 6px; font-size: 10.5px; color: var(--text-sub);">
<span>安全评级: <strong style="color: var(--status-normal);">正常</strong></span>
<span>气密性能: <strong style="color: var(--status-normal);">达标</strong></span>
<span>测温系统: <strong style="color: var(--status-normal);">在线</strong></span>
</div>
</div>
<!-- 3. 建筑物理空间与工程尺寸全参数 -->
<div class="panel" style="flex: 1.25;">
<div class="panel-title-bar">
<div class="panel-title">
<span class="panel-title-icon"></span>
<span>建筑物理空间与工程尺寸</span>
</div>
<div class="panel-extra">结构参数</div>
</div>
<div class="param-grid-2col" id="param-size-grid">
<!-- 动态填充浅圆仓或平房仓尺寸 -->
</div>
</div>
</div>
<!-- ================= 中间区域:悬浮过滤控制 + 居中大图表看板 + 底部迷你选择条 ================= -->
<div class="col-center">
<!-- 顶部过滤栏 (悬浮) -->
<div class="granary-filter-bar">
<div class="filter-bar-title">
<svg class="svg-icon-sm" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="12" cy="12" r="4" fill="currentColor"/><line x1="12" y1="1" x2="12" y2="4" stroke="currentColor" stroke-width="2"/><line x1="12" y1="20" x2="12" y2="23" stroke="currentColor" stroke-width="2"/><line x1="1" y1="12" x2="4" y2="12" stroke="currentColor" stroke-width="2"/><line x1="20" y1="12" x2="23" y2="12" stroke="currentColor" stroke-width="2"/></svg>
<span>中央储备粮遵义直属库有限公司习水分公司 · 数字孪生全景监测</span>
</div>
<div class="filter-btn-group">
<button class="filter-btn active" data-filter="all">全部仓房 (11)</button>
<button class="filter-btn" data-filter="silo">浅圆仓群 (8)</button>
<button class="filter-btn" data-filter="warehouse">平房仓群 (3)</button>
</div>
</div>
<!-- 中央全景居中图表看板 (点击下方切换时直接在中间区域显示) -->
<div class="center-chart-board" id="center-chart-board" style="display: none;">
<div class="center-chart-header">
<div class="center-chart-title">
<span class="chart-pulse-dot"></span>
<span id="center-chart-header-title">习水分公司 · 粮食质量指标演变智能预测推演</span>
</div>
<!-- 方案 A:模式切换胶囊 (质量预测 vs 宏观仓容) -->
<div class="center-chart-tabs" id="center-chart-tabs">
<button class="center-chart-tab active" id="tab-chart-forecast" data-tab="forecast">📈 粮食质量智能预测</button>
<button class="center-chart-tab" id="tab-chart-macro" data-tab="macro">📊 全库仓容大盘</button>
</div>
<button class="center-chart-close-btn" id="btn-close-center-chart">
<span>✕ 返回孪生全景</span>
</button>
</div>
<!-- 1. 粮食质量预测推演大盘视图 (默认优先呈现) -->
<div class="center-chart-body forecast-body-wrap" id="board-body-forecast">
<!-- 算法推演工况与仓内外温湿度设定栏 (对齐 API 文档 tm_i, tm_o, hm_i, hm_o) -->
<div class="forecast-env-bar">
<div class="forecast-env-label">
<span class="env-pulse-icon"></span>
<span>推演环境工况 (API输入):</span>
</div>
<div class="forecast-env-items">
<div class="forecast-env-group">
<span class="env-tag blue">仓内温度</span>
<input type="number" step="0.1" id="input-forecast-tm-i" class="forecast-env-input" value="18.5" title="仓内温度 (tm_i)">
<span class="env-unit">℃</span>
</div>
<div class="forecast-env-group">
<span class="env-tag blue">仓内湿度</span>
<input type="number" step="0.1" id="input-forecast-hm-i" class="forecast-env-input" value="72.4" title="仓内湿度 (hm_i)">
<span class="env-unit">%</span>
</div>
<div class="forecast-env-group">
<span class="env-tag green">仓外气温</span>
<input type="number" step="0.1" id="input-forecast-tm-o" class="forecast-env-input" value="32.5" title="仓外气温 (tm_o)">
<span class="env-unit">℃</span>
</div>
<div class="forecast-env-group">
<span class="env-tag green">仓外气湿</span>
<input type="number" step="0.1" id="input-forecast-hm-o" class="forecast-env-input" value="54.2" title="仓外气湿 (hm_o)">
<span class="env-unit">%</span>
</div>
<div class="forecast-env-group date-group">
<span class="env-tag yellow">基准日期</span>
<input type="number" min="1" max="12" id="input-forecast-month" class="forecast-env-input mini" value="7" title="预测月份 (month)">
<span class="env-unit">月</span>
<input type="number" min="1" max="31" id="input-forecast-day" class="forecast-env-input mini" value="13" title="预测天数 (day)">
<span class="env-unit">日</span>
</div>
<button class="forecast-recalc-btn" id="btn-forecast-recalc" title="按照设定的仓内外温湿度重新调用算法推演">
<span>⚡ 模拟推演</span>
</button>
<button class="forecast-reset-btn" id="btn-forecast-reset" title="恢复算法文档标准参考工况">↺ 重置</button>
</div>
</div>
<!-- 图表双列布局区 -->
<div class="forecast-charts-row">
<!-- 左侧:多周期未来质量演变趋势折线图 (含国家警戒线) -->
<div class="center-chart-card">
<div class="center-chart-card-title-bar">
<div class="center-chart-card-title" id="forecast-trend-title">粮食质量指标多周期演变趋势推演 (未来 7~60天走势与国家警戒线)</div>
<div class="forecast-env-pill" id="forecast-trend-env-pill">工况: 仓内 18.5℃ / 72.4% · 仓外 32.5℃ / 54.2%</div>
</div>
<div id="chart-forecast-trend" class="center-chart-canvas"></div>
</div>
<!-- 右侧:现状实测 vs 预测推演偏离对比柱状图 -->
<div class="center-chart-card">
<div class="center-chart-card-title-bar">
<div class="center-chart-card-title" id="forecast-compare-title">现状实测值 vs 预测终值偏离对比与风险评估</div>
</div>
<div id="chart-forecast-compare" class="center-chart-canvas"></div>
</div>
</div>
</div>
<!-- 2. 宏观仓容品种大盘视图 -->
<div class="center-chart-body" id="board-body-macro" style="display: none;">
<!-- 左侧:全库品种结构与实储分布大环形图 -->
<div class="center-chart-card">
<div class="center-chart-card-title">全库储粮品种结构与实储分布 (万吨)</div>
<div id="chart-variety-pie" class="center-chart-canvas"></div>
</div>
<!-- 右侧:全库各仓储量与利用率负荷对比柱状图 -->
<div class="center-chart-card">
<div class="center-chart-card-title">仓房实储量与设计容量负荷对比 (吨)</div>
<div id="chart-granary-bar" class="center-chart-canvas"></div>
</div>
</div>
</div>
<!-- 底部 11 仓快捷迷你点阵 (悬浮) -->
<div class="granary-mini-grid xishui-mini-grid" id="granary-mini-grid">
<!-- 动态生成:最左侧图表切换按钮 + 11 个仓房按钮 -->
</div>
</div>
<!-- ================= 右侧栏:方案A 智能质检与品质全参数孪生舱 (100%全高长条卡片呈现) ================= -->
<div class="col-right">
<!-- 粮食品质智能质检与品质全参数孪生舱 -->
<div class="panel" style="flex: 1; height: 100%;">
<div class="panel-title-bar">
<div class="panel-title">
<span class="panel-title-icon"></span>
<span id="param-quality-title">智能质检与品质孪生舱</span>
</div>
<div class="panel-extra">数字研判</div>
</div>
<div id="param-quality-grid" style="flex: 1; display: flex; flex-direction: column; min-height: 0;">
<!-- 动态渲染方案 A 全量参数条形卡片与分类Tab -->
</div>
</div>
</div>
</main>
<!-- 底部状态条 -->
<footer class="screen-footer">
<div class="footer-item">
<span class="status-indicator"></span>
<span>库区档案: <strong>中央储备粮遵义直属库有限公司习水分公司 (习水子库)</strong></span>
</div>
<div class="footer-item">
<span>全库仓房总数: <strong>11 栋/座 (8座浅圆仓 + 3栋平房仓)</strong></span>
</div>
<div class="footer-item">
<span>遥控器/键盘: <strong>[方向键 ← / →] 切换仓房</strong> | <strong>[空格键] 全屏控制</strong></span>
</div>
<div class="footer-item">
<span>中储粮数字化孪生指挥系统</span>
</div>
</footer>
</div>
<script type="module" src="./js/xishui_app.js?v=20260916_v3"></script>
</body>
</html>