# 修复区域图表"其他"重复问题

## Context

区域资产分布概览的"按城市"柱状图出现两个"其他"。原因：28 辆运营车辆的 `city` 和 `province` 均为 `null`（GPS 未上报），`resolveCity` 返回"其他"，排进 Top 8。然后 Top 8 之外的城市又合并出另一个"其他"。

## 方案

不改 `resolveCity`（城市为空归"其他"是合理的）。修改 `/region-chart` 端点的 Top N 合并逻辑：**先把名为"其他"的条目从排序列表中移除，取 Top N 后，将剩余部分（包括原始的"其他"）一起合并为最终的"其他"**。

**文件**: `src/server/routes/vehicles.ts` — `/region-chart` 端点

### 修改合并逻辑

```typescript
app.get('/region-chart', async (c) => {
  const vehicles = await getVehicles();
  const operating = vehicles.filter((v) => v.status === 'Operating');
  const groupBy = c.req.query('groupBy') || 'region';
  const top = Number(c.req.query('top')) || 8;

  const counts = new Map<string, number>();
  for (const v of operating) {
    const key = groupBy === 'city' ? resolveCity(v.city, v.province) : mapMacroRegion(v.province, v.city);
    counts.set(key, (counts.get(key) || 0) + 1);
  }

  // 分离"其他"，对非"其他"排序取 Top N，剩余全部合入"其他"
  const otherCount = counts.get('其他') || 0;
  counts.delete('其他');

  const sorted = Array.from(counts.entries())
    .map(([name, value]) => ({ name, value }))
    .sort((a, b) => b.value - a.value);

  const result = sorted.slice(0, top);
  const restTotal = sorted.slice(top).reduce((s, item) => s + item.value, 0) + otherCount;
  if (restTotal > 0) result.push({ name: '其他', value: restTotal });
  return c.json(result);
});
```

## 验证

1. `npx tsc --noEmit` 通过
2. `curl http://localhost:3000/api/vehicles/region-chart?groupBy=city&top=8` — 只有一个"其他"
3. 页面柱状图每个名称唯一
