- 卡片右上角按钮改用「来自哪个模块」的主题色:HomeCards 登记表新增 mod 字段 与 module(),首页从登记表取色(原来是模板里硬编码 in_array(['agenda','tasks']) 白名单,新加带按钮的卡片会默默变灰) - 首页日程把日历本放到色块右侧:.ag-ev 改弹性行,「时间+标题」包进 .ag-ev-main(flex:1 1 auto; min-width:0),日历本作右侧兄弟。 原来 display:block 会把日历本顶到第二行,色块一矮就完全看不见 - 旅程地图显示题图:服务端把 media_url(cover_key) 塞进地图数据, 地图卡片左侧 40x40 题图(object-fit:cover),没有题图不留灰框 - 系统设置第一块改叫「系统标语」;删掉「首页上那一行小字」提示、 「不是全家的统一口号」说明、「上次结构升级有步骤失败了」整框; 运行环境删「排错时看这一块」与「亲属连线」那一行(功能与数据未动) - 公共标签:说明文字全删;列表与编辑合并成一行(色块+名字+N人+箭头+编辑); person_groups 加 color 列(Schema addColumn,老库可升);点「编辑」弹框 改名字与颜色、点「完成」提交;下面那个独立编辑列表撤掉。删除挪进弹框 - 个人设置删掉「手动签发接口令牌」整块;settings/api_token 路由保留但挡下提交 (只删界面会留下知道地址就能用的后门);令牌只由登录后自动签发, 设备管理卡保留。apiTokens/apiPlain/apiLabel/apiBase 四个变量一并撤掉
80 lines
4.9 KiB
PHP
80 lines
4.9 KiB
PHP
<?php
|
||
/**
|
||
* 旅程**地图视图**的主体(v54 用户 2026-10-16 第 3 条)。
|
||
*
|
||
* 用户原话:「你去读一下 TripLog 的代码,在旅程这个模块,**可以在地图上显示旅程数据**。
|
||
* 1. 先读一下它之前那个代码是怎么实现的,**在我们的旅程模块也实现一下**。」
|
||
*
|
||
* ── TripLog 那套是怎么做的(读了它的 `templates/activities/index.php`)──
|
||
* · 用**高德 JS API**(`AMap.Map` + `AMap.Marker`);
|
||
* · 每个活动一枚标记;标记的 `content` 是自绘的"小卡片"(封面图 + 标题 + 地点),
|
||
* 同城/邻近的卡片会**环形扇开**+画引线,避免叠在一起;
|
||
* · `map.setFitView()` 自动框住所有点,但**上限 11 级**(不然只有一趟时会被
|
||
* 一路放大到街道级,那是导航视角不是"足迹"视角)。
|
||
*
|
||
* ── 本仓怎么落地(同一套思路,但数据源更规整)──
|
||
* · 坐标来源:`Trip::attachSpots()` —— 旅程下所有节点的 from/to 坐标**取重心**;
|
||
* 没有坐标就退到城市(内置离线城市表,**不发网络请求**,见那里的说明)。
|
||
* · 每趟旅程一枚标记,点它进 `trips/show`。
|
||
* · 🔴 v63(用户 2026-10-19 第 3 条):「旅程地图模式,应该显示旅程的题图。」
|
||
* ⇒ 卡片左侧加一枚**题图小方图**(`trip_details.cover_key`,与列表页同一个来源、
|
||
* 同一套 `media_url()` 出口)。没有题图就只显示文字,不留灰框。
|
||
* ⚠️ URL 在**服务端**算好塞进 JSON:`media_url()` 依赖站点路径与代理前缀
|
||
* (见那个函数的说明),端上拼不出来。
|
||
* · 视野上限同样 11 级、贴合全部标记。
|
||
*
|
||
* ⚠️ **合规**:地图用高德(腾讯/高德/百度/天地图是合规白名单内),
|
||
* 绝不用 Google/OSM 等境外瓦片。key 走本仓既有配置(`App\Geo::jsConfig()`),
|
||
* 由 `layout.php` 的 `fb-amap` 按需加载 —— 本页不自己拼 SDK 地址。
|
||
* ⚠️ 容器必须有**固定高度**(这里是 `.trip-map` 的 CSS 高度):
|
||
* 高德地图在"高度为 0 的容器"里渲染出来是空白,这是最常见的坑。
|
||
* ⚠️ 没有坐标的旅程**不画**(数据里说了 `trip_spot=false`);
|
||
* 若**一个点都没有**,不渲染地图容器,直接给一句说明(免得用户对着白框发呆)。
|
||
*
|
||
* 变量:$rows(Trip::all + attachDerived + attachSpots 之后)、$total
|
||
*/
|
||
$mapPoints = [];
|
||
foreach ((array)($rows ?? []) as $row) {
|
||
if (empty($row['trip_spot'])) {
|
||
continue;
|
||
}
|
||
$mapPoints[] = [
|
||
'id' => (int)$row['id'],
|
||
'title' => (string)$row['title'],
|
||
'lng' => (float)$row['trip_lng'],
|
||
'lat' => (float)$row['trip_lat'],
|
||
'when' => \App\Trip::activitySpan($row['starts_at'] ?? null, $row['ends_at'] ?? null),
|
||
'city' => (string)($row['city'] ?? ''),
|
||
'url' => url('trips/show', ['id' => (int)$row['id']]),
|
||
// 🔴 v63 第 3 条:题图。⚠️ 用 `media_url()` 而不是直接拼 storage 路径 ——
|
||
// 图片统一走 media.php 代理(桶不必开公共读),且**必须带版本号**,
|
||
// 否则换了题图缓存里还是老图。
|
||
'cover' => !empty($row['cover_key']) ? media_url((string)$row['cover_key']) : '',
|
||
];
|
||
}
|
||
?>
|
||
<?php if (!$mapPoints): ?>
|
||
<?php /* 一个坐标都没有 —— 如实说清楚"为什么没有",而不是给个空地图。
|
||
常见原因:行程里没填出发/到达地,或填了但(当时没配高德)没解析出坐标。 */ ?>
|
||
<div class="card card-pad empty" id="tripMapEmpty">
|
||
<b>还没有能在地图上显示的旅程</b>
|
||
地图要靠行程里的**出发地 / 到达地**(有坐标或能认出城市)。
|
||
去某趟旅程里加一段行程、把出发到达填上,它就会出现在这里。
|
||
</div>
|
||
<?php else: ?>
|
||
<?php /* 🔴 高度写在内联 style 上不够稳(有的主题会覆盖),
|
||
所以主要靠 `.trip-map` 的 CSS;这里只在**无 JS** 时兜一个提示。 */ ?>
|
||
<div class="trip-map-wrap">
|
||
<div class="trip-map" id="tripMapCanvas"
|
||
data-points="<?= e(json_encode($mapPoints, JSON_UNESCAPED_UNICODE | JSON_HEX_APOS | JSON_HEX_QUOT)) ?>">
|
||
<noscript><p class="trip-map-fallback">地图需要 JavaScript;用左侧的「列表」看旅程。</p></noscript>
|
||
</div>
|
||
<?php if (count($mapPoints) < (int)($total ?? 0)): ?>
|
||
<?php /* 有旅程不在图上 —— 说清楚,免得用户以为"少了几趟"。 */ ?>
|
||
<p class="small muted trip-map-hint">
|
||
有 <?= (int)($total ?? 0) - count($mapPoints) ?> 趟旅程没有可用位置(行程里没填出发/到达,或认不出城市),
|
||
没有画在地图上 —— 它们在「列表」里照常显示。
|
||
</p>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endif; ?>
|