Files
laoyang c30ca99d22 v24 第 17 批:城市聚合 / 高德地址 / 表单精简(用户 10 条)
用户 10 条原话要点与落地:
- ①「统计出来的不是目的地,也不是车站,而是城市…城市要聚合,有多段行程,
  都有青岛作为出发地或者目的地,那么就只记一次」
  → trip_nodes 补 from_city/to_city(Schema v22),Trip::cities() 改成
    「出发地 ∪ 到达地」去重、按最早时间 + 出发地优先排。
    详情页信息区显示的就是这个聚合结果(第 4 条:「图片右侧显示的是聚合的城市,
    而不是终点地址」)。
- ②「类型不够丰富,你看看 triplog 里面都有哪些,都拿过来」
  → NodeType::TRIPLOG_TYPES(休息/突发/购物/拜访亲友),在 all() 里读时自愈补齐。
- ③「出行方式,只有选择自驾,才让选车辆;车辆下拉框不需要出现什么财务里登记的车,
  只把车辆列出来就行了」→ DRIVE_MODES 收窄成 ['drive'];
  Vehicle::pickable() 只回车辆库;车辆页删掉「财务里已登记的车」那块。
- ③「飞机、铁路,只记录车次、航班号就可以…座位什么的不记录了」
  → seat_info / gate 从表单与列表**彻底移除**(列保留,老数据不丢;
    saveNode 的 UPDATE 也不再写这两列,否则会抹掉迁来的数据)。
- ③「出发地和到达地,都用高德地图的接口,记录详细地址」+「参与人弹框选择」
  +「给参与人标注角色这个功能去掉」
  → 新增 templates/trips/_loc_field.php(高德联想 + 详细地址 + 坐标 + 城市 +
    导航链接,没配 key 也能手输);参与人改用全局弹框选人组件;
    角色输入框删除,saveNodeMembers 改成差集增删(否则老 role_tag 被静默抹掉)。
- ④「triplog 中的行程花销数据,没有同步过来,需要迁移过来」
  → 新增 _tooling/_fb_b17_backfill.php:迁地址(20 条)、花销(4 笔 ¥8584)、
    车辆(3 台)。线上已执行并核对(笔数与金额一分不差)。
- ④「行程中,时间明明具体到了时分秒,怎么不显示?」
  → Trip::nodeSpan():行程时间精确到时分(同一天只写一次日期、跨天写月日、
    两头都没时分就不写 00:00)。

其他:
- App\Geo 扩展 cityFromPoint / cityFromText / navUrl / jsConfig。
  中文地址提城市修掉四种错法(白名单→黑名单、取最后→取第一个、直辖市最先认、
  离线表只能兜底),并加了「五大连池 ≠ 大连」的位置守卫。
- config.example.php 加 amap 段(key / security_js / nav_src)。

验证:
- e2e 920/0(+29 条本批断言)· 升级 149/0(+15 条 v22 断言)·
  城市解析 32/32(新套件,样例全是 TripLog 线上真实地址)·
  桌面几何 428/0 · 移动端 688/0 · 交互 92/0 · 窄屏溢出 24/0。
- 反向验证 5/5:城市退回读 place / 只算到达地 / 时间退回只到日期 /
  打车也要车 / 类型不补 —— 五种坏法全部被断言抓住。
- 部署:服务器自检 19/19;线上 schema v22;补迁后花销 4 笔 ¥8584 与源库对齐。
2026-10-05 16:45:10 +08:00

105 lines
5.2 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 车辆管理(v24 第 16 批 用户第 8 条;第 17 批 第 3 条改)。
*
* 用户原话(第 16 批 第 8 条):
* 「增加一个设置按钮,用来设置车辆管理、出行方式、节点类型。
* 注意,我们在财务中,已经把车辆添加进去了…但是可以添加其他的车辆,
* 比如租的车,借别人的车。」
*
* 用户原话(**第 17 批 第 3 条 —— 本次,推翻上一批的做法**):
* 「车辆下拉框,**不需要出现什么财务里登记的车**,只把车辆列出来就行了。」
*
* ⚠️ 所以这一页现在**只有一块**:「出行用的车」(自家 / 租的 / 借的)。
* 原来那块「财务里已登记的车」整块删掉了 —— 财务里的 kind=car 是**资产账目**
* ("这台车值多少钱"),它没有车牌车型,混进选车列表只会让人发懵。
* `Vehicle::fromLedger()` 方法保留在模型层(将来按车统计油费/保养还要用它
* 跟 `vehicles.ledger_id` 对上),但**不再被任何界面调用**。
*
* @param array $mine Vehicle::all() 的结果
*/
$canWrite = \App\Auth::canWrite();
$mine = $mine ?? [];
$back = url('trips');
?>
<div class="page-head">
<h1>车辆管理</h1>
<span class="sub">出行时能挑的车:自家的、租的、借别人的</span>
<div class="actions">
<a class="btn btn-ghost" href="<?= e($back) ?>">返回旅程</a>
<?php $trSetCurrent = 'vehicles'; require __DIR__ . '/_settings_menu.php'; ?>
</div>
</div>
<div class="card card-pad">
<h2 class="cinema-h2">
出行用的车
<span class="hint">自家车录一台方便选;租的车、借的车也录在这里</span>
</h2>
<?php if ($mine): ?>
<ul class="veh-list">
<?php foreach ($mine as $v): ?>
<li class="veh-row">
<span class="veh-ico"><?= ($v['vtype'] ?? 'own') === 'rental' ? '🔑' : (($v['vtype'] ?? 'own') === 'borrowed' ? '🤝' : '🚗') ?></span>
<?php if ($canWrite): ?>
<form class="inline-form veh-form" method="post" action="<?= e(url('trips/vehicles_save')) ?>">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$v['id'] ?>">
<input class="input" name="plate" value="<?= e((string)$v['plate']) ?>"
placeholder="车牌" aria-label="车牌">
<input class="input" name="name" value="<?= e((string)$v['name']) ?>"
placeholder="车型名" required aria-label="车型名">
<select class="select" name="vtype" aria-label="来源">
<?php foreach (\App\Vehicle::TYPES as $vk => $vv): ?>
<option value="<?= e($vk) ?>"<?= (string)$v['vtype'] === $vk ? ' selected' : '' ?>>
<?= e($vv) ?>
</option>
<?php endforeach; ?>
</select>
<input class="input" name="vendor" value="<?= e((string)($v['vendor'] ?? '')) ?>"
placeholder="租车公司 / 车主" aria-label="租车公司或车主">
<label class="veh-def">
<input type="checkbox" name="is_default" value="1"<?= (int)$v['is_default'] === 1 ? ' checked' : '' ?>>
<span>默认</span>
</label>
<button class="btn btn-sm" type="submit">保存</button>
</form>
<form class="inline-form" method="post" action="<?= e(url('trips/vehicles_del')) ?>">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$v['id'] ?>">
<button class="btn btn-ghost btn-sm" type="submit"
onclick="return confirm('删掉这辆车?')">删</button>
</form>
<?php else: ?>
<span class="veh-name"><?= e(\App\Vehicle::label($v)) ?></span>
<span class="veh-tag"><?= e(\App\Vehicle::TYPES[(string)$v['vtype']] ?? '') ?></span>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p class="empty-hint">还没有。自家车录一台,出行时能直接挑。</p>
<?php endif; ?>
<?php if ($canWrite): ?>
<h3 class="set-sub">加一辆车</h3>
<form class="inline-form veh-form veh-add" method="post" action="<?= e(url('trips/vehicles_save')) ?>">
<?= csrf_field() ?>
<input class="input" name="plate" placeholder="车牌(借的车可不填)" aria-label="车牌">
<input class="input" name="name" placeholder="车型名,如「大众朗逸」" required aria-label="车型名">
<select class="select" name="vtype" aria-label="来源">
<?php foreach (\App\Vehicle::TYPES as $vk => $vv): ?>
<option value="<?= e($vk) ?>"><?= e($vv) ?></option>
<?php endforeach; ?>
</select>
<input class="input" name="vendor" placeholder="租车公司 / 车主" aria-label="租车公司或车主">
<input class="input" name="order_no" placeholder="租车订单号" aria-label="租车订单号">
<label class="veh-def">
<input type="checkbox" name="is_default" value="1">
<span>设为默认</span>
</label>
<button class="btn btn-sm" type="submit">加进车辆库</button>
</form>
<?php endif; ?>
</div>