weather-station/core/frontend/src/app.component.html

104 lines
6.1 KiB
HTML

<app-header #hdr [onlineDevices]="onlineDevices" [stations]="stations" (selectStation)="onSelectStation($event)"></app-header>
<div class="border-b" style="border-color: #ddd;margin-bottom: 1em;">
<div class="content-narrow mx-auto" style="max-width:1200px;">
<h1 class="text-xl md:text-3xl font-semibold" style="margin:0.8em 0; padding:12px 16px;">英卓气象站</h1>
</div>
</div>
<div class="content-narrow mx-auto px-4" style="max-width:1200px; margin-bottom:3em;">
<div *ngIf="isLoading" style="position:fixed;inset:0;z-index:2000;background:rgba(0,0,0,0.2);display:flex;align-items:center;justify-content:center;">
<div class="animate-spin" style="height:40px;width:40px;border:4px solid #e5e7eb;border-top-color:#2563eb;border-radius:9999px;"></div>
</div>
<div class="system-info bg-gray-100 p-3 mb-5 rounded text-sm border" style="border-color:#ddd;">
<strong>在线设备: </strong> {{onlineDevices}} 个 |
<strong>总设备: </strong>
<a href="#" class="text-blue-600 hover:text-blue-700 underline-offset-2" (click)="$event.preventDefault(); hdr.open()">{{ wh65lpCount }} 个</a>
</div>
<div class="bg-white border rounded p-3 mb-4" style="border-color:#ddd;">
<!-- 第一行:站点编号 / 地图类型 / 预报源 / 图例 -->
<div class="flex flex-wrap items-center gap-3 mb-3">
<label class="text-sm text-gray-600">站点编号</label>
<input class="px-2 py-1 border rounded w-32 font-mono text-sm" [(ngModel)]="decimalId" placeholder="十进制ID" />
<label class="text-sm text-gray-600">地图类型</label>
<select class="px-2 py-1 border rounded text-sm" [(ngModel)]="mapType" (change)="switchLayer(mapType)">
<option value="satellite">卫星图</option>
<option value="vector">矢量图</option>
<option value="terrain">地形图</option>
<option value="hybrid">混合地形图</option>
</select>
<label class="text-sm text-gray-600">预报源</label>
<select class="px-2 py-1 border rounded text-sm" [(ngModel)]="provider">
<option value="">不显示预报</option>
<option value="imdroid_mix">英卓 V4</option>
<option value="open-meteo">英卓 V3</option>
<option value="caiyun">英卓 V2</option>
<option value="imdroid">英卓 V1</option>
</select>
<label class="text-sm text-gray-600">图例</label>
<select class="px-2 py-1 border rounded text-sm" [(ngModel)]="legendMode">
<option value="combo_standard">综合</option>
<option value="verify_all">全部对比</option>
<option value="temp_compare">温度对比</option>
<option value="hum_compare">湿度对比</option>
<option value="rain_all">降水(+1/+2/+3h)</option>
<option value="pressure_compare">气压对比</option>
<option value="wind_compare">风速对比</option>
</select>
</div>
<!-- 第二行:数据粒度 / 开始 / 结束 / 查询按钮 -->
<div class="flex flex-wrap items-center gap-3 mb-3">
<label class="text-sm text-gray-600">数据粒度</label>
<select class="px-2 py-1 border rounded text-sm" [(ngModel)]="interval">
<option value="raw">原始(16s)</option>
<option value="10min">10分钟</option>
<option value="30min">30分钟</option>
<option value="1hour">1小时</option>
</select>
<label class="text-sm text-gray-600">开始</label>
<input type="datetime-local" class="px-2 py-1 border rounded text-sm" [(ngModel)]="start" />
<label class="text-sm text-gray-600">结束</label>
<input type="datetime-local" class="px-2 py-1 border rounded text-sm" [(ngModel)]="end" />
<button class="bg-blue-600 text-white px-3 py-1 rounded text-sm" (click)="query()">查看历史数据</button>
</div>
<!-- 第三行:叠加显示 / 时间选择 / 上一/下一时次 / 计数 -->
<div class="flex flex-wrap items-center gap-3">
<label class="text-sm text-gray-600">叠加显示</label>
<select class="px-2 py-1 border rounded text-sm" [(ngModel)]="tileProduct" (change)="onProductChange()">
<option value="none">不显示</option>
<option value="radar">水汽含量</option>
<option value="rain">1h 实际降雨</option>
</select>
<label class="text-sm text-gray-600">时间</label>
<select class="px-2 py-1 border rounded text-sm min-w-[220px]" [(ngModel)]="tileDt" (change)="renderTilesAt(tileDt)">
<option [ngValue]="''">请选择时间</option>
<option *ngFor="let t of tileTimes" [ngValue]="t">{{t}}</option>
</select>
<button class="px-2 py-1 text-sm border rounded bg-white" (click)="prevTile()">上一时次</button>
<span class="text-xs text-gray-800">共{{tileTimes.length}}条,第{{tileIndex>=0? (tileIndex+1):0}}条</span>
<button class="px-2 py-1 text-sm border rounded bg-white" (click)="nextTile()">下一时次</button>
</div>
</div>
<div id="mapContainer" class="rounded border mb-4" [ngClass]="{ 'collapsed': isMapCollapsed }" [style.borderColor]="'#ddd'" style="position:relative; overflow:hidden;" [style.height]="isMapCollapsed ? '38vh' : '60vh'">
<div id="map" style="width:100%; height:100%;"></div>
<button class="map-toggle-btn bg-blue-600 hover:bg-blue-700 text-white" style="position:absolute;top:10px;right:10px;z-index:1001;border-radius:4px;padding:5px 10px;font-size:12px;font-weight:bold;" (click)="toggleMap()">{{ isMapCollapsed ? '展开地图' : '折叠地图' }}</button>
<div id="tileValueTooltip" style="position:absolute;pointer-events:none;z-index:1003;display:none;background:rgba(0,0,0,0.65);color:#fff;font-size:12px;padding:4px 6px;border-radius:4px;"></div>
</div>
<div *ngIf="showPanels" id="chartSection" class="border rounded p-3 mb-4" style="border-color:#ddd;">
<div class="font-bold mb-5 mt-5 text-center">{{ selectedTitle }}</div>
<chart-panel [history]="history" [forecast]="forecast" [legendMode]="legendMode"></chart-panel>
</div>
<table-panel *ngIf="showPanels" [history]="history" [forecast]="forecast" [showPastForecast]="showPastForecast" [endDate]="end"></table-panel>
</div>