类别显示名可自己维护,顺手把两套对不上的中文名合成一套

你要改的那个「海滩」原来根本不在数据里——它是 Go 里硬编码的 map,所以改不动。
更糟的是这样的 map 有**两张**,而且对不上:

  MKPOICategoryFoodMarket   菜市场(编辑页)  /  食品市场(补全页、GPX)
  MKPOICategoryCafe         咖啡馆              /  咖啡厅
  MKPOICategoryFitnessCenter 健身房             /  健身中心
  外加 ATM / Atm 大小写各写一份、一条永远匹配不上的 MKPOICategoryMarina2

现在合成一张内置表(42 条,冲突处取编辑页那套),并在它上面加了一层站点覆盖:

- 新表 category_labels(value, label),站点级、不挂 dataset——值本身才是稳定键
- 端点 POST /admin/edit/category/label;传空 label = 删掉覆盖行、恢复内置默认名
- 类别台账那行改成两个带标签的输入框:
      导出值 [MKPOICategoryBeach]   ← 会跟着导出写回手机
      显示名 [               ]      ← 只影响站内显示,placeholder 写着默认值
  是 MKPOICategory 枚举但内置表里没有的,会提示「填一个中文名」,这就是你要的补全入口

**显示名绝不写进 places.poi_category**——中文跟着写进去就把导出数据污染了,
专门加了 TestCategoryLabelNeverTouchesValue 钉这条。显示名会贯穿到所有中文名的地方:
编辑页/照片页/补全页的下拉、补全页「在用」标签、访客地点页、GPX 的 desc。

连带删掉两个绑在旧表上的模板函数 catName / poiname:模板里算不出显示名(要读站点覆盖),
改成在 Go 侧算好塞进数据(FillupRow.CatLabel、PlaceData.CategoryLabel)。
This commit is contained in:
tamakyi
2026-09-20 10:54:51 +08:00
parent cbb45b6d6b
commit 82e63412c0
12 changed files with 287 additions and 83 deletions
+9 -33
View File
@@ -537,6 +537,9 @@ type PlaceData struct {
Place stats.Place
Visits []stats.VisitRow
Points []MapPoint
// CategoryLabel 是类别的显示名(站点自定义的优先)。类别的中文名在模板里算不出来——
// 它要读站点覆盖,所以在这里先渲染好。
CategoryLabel string
// Verdict 是站长官方结论(1=推荐 / -1=踩雷 / 0=未标);Votes 是访客票数;
// MyVote 是当前访客自己对这一地点的投票。
Verdict int
@@ -908,10 +911,13 @@ type EditActivity struct {
// EditCategory 是类别台账的一行。类别没有表,值就是 places.poi_category,
// 所以「改名 / 清空」都是按值批量作用到地点上——改成另一个已有值就是合并。
// Label 是显示名(站点自定义的优先),Custom 表示它被改过,Missing 表示还没有中文名。
type EditCategory struct {
Value string
Label string
Places int
Value string
Label string
Places int
Custom bool
Missing bool
}
type EditPlace struct {
@@ -1279,33 +1285,6 @@ func colorOf(name string) string {
return "#5b6169"
}
var poiNames = map[string]string{
"MKPOICategoryStore": "商店", "MKPOICategoryRestaurant": "餐厅", "MKPOICategoryCafe": "咖啡厅",
"MKPOICategoryPublicTransport": "公共交通", "MKPOICategoryHotel": "酒店", "MKPOICategoryLandmark": "地标",
"MKPOICategoryFoodMarket": "食品市场", "MKPOICategoryMuseum": "博物馆", "MKPOICategoryZoo": "动物园",
"MKPOICategoryBeach": "海滩", "MKPOICategoryCampground": "露营地", "MKPOICategoryStadium": "体育场",
"MKPOICategoryPark": "公园", "MKPOICategoryNationalPark": "国家公园", "MKPOICategorySchool": "学校",
"MKPOICategoryPharmacy": "药店", "MKPOICategoryHospital": "医院", "MKPOICategorySpa": "水疗",
"MKPOICategoryAirport": "机场", "MKPOICategoryMarina": "码头", "MKPOICategoryPostOffice": "邮局",
"MKPOICategoryMarina2": "码头",
"MKPOICategoryBakery": "面包店", "MKPOICategoryLibrary": "图书馆",
"MKPOICategoryUniversity": "大学", "MKPOICategoryAquarium": "水族馆",
"MKPOICategoryFitnessCenter": "健身中心", "MKPOICategoryMovieTheater": "电影院",
"MKPOICategoryTheater": "剧院", "MKPOICategoryParking": "停车场",
"MKPOICategoryBank": "银行", "MKPOICategoryAtm": "取款机",
"MKPOICategoryPolice": "派出所", "MKPOICategoryCarRental": "租车",
"MKPOICategoryGasStation": "加油站", "MKPOICategoryAmusementPark": "游乐园",
"MKPOICategoryRestroom": "洗手间", "MKPOICategoryFireStation": "消防站",
}
func poiName(s string) string {
if v, ok := poiNames[s]; ok {
return v
}
return s
}
// iconOf 只保留 emoji 图标。rond 里的图标多为 SF Symbols 名称(如 house.fill),
// 在网页上无法渲染,直接返回空串让模板退回默认样式。
func iconOf(s string) string {
@@ -1347,8 +1326,6 @@ func templateFuncs() template.FuncMap {
"dt": func(t time.Time) string { return t.Local().Format("2006-01-02 15:04") },
// actKey 给活动冲突生成表单字段名,与处理函数共用同一套键
"actKey": rond.ActivityKey,
// catName 把 MKPOICategoryXxx 翻成中文,补全页的类别下拉要用
"catName": poiName,
// dtt 接受 *time.Time,nil 返回空串,便于可选时间字段直接渲染
"dtt": func(t *time.Time) string {
if t == nil {
@@ -1387,7 +1364,6 @@ func templateFuncs() template.FuncMap {
},
"safe": func(s string) template.HTML { return template.HTML(s) },
"colorof": colorOf,
"poiname": poiName,
"icon": iconOf,
"iconor": iconOr,
"condition": stats.ConditionName,