SAYEQU · 决策看板

附近热门营地排序
与城市搜索优化

把 Web H5 与微信小程序的「附近热门营地」从“前端小样本重排”升级为后端统一排序:距离第一,点赞第二;搜索补强城市/省份命中能力。

距离优先有定位时后端按全量筛选结果计算距离排序
点赞其次距离相同/接近时用 like_count 做二级热度
双端统一Web 与小程序都走 /api/camp/list 新合同

当前算法现状

已探查 Web、Taro、后端三条链路
后端列表

/api/camp/list

关键词只搜 name/address/tags;默认排序是 rating DESC, like_count DESC。没有距离排序,没有 city 参数。

Web 首页

先取 50,再前端重排

首页先拿后端热门前 50,有定位才在客户端按 Haversine 排序,最后展示前 8。

小程序列表

搜索不按距离

列表页只传 type/keyword/pageSize=20,后端仍按评分/点赞返回;附近入口等价普通列表。

核心问题

为什么用户感觉“附近热门”不够准
现在

“热门样本里的附近”

后端先按评分/点赞取前 50
前端只对这 50 条算距离
截断首页只展示前 8
结果近但不热门的营地可能漏掉
建议

“全量筛选后的附近”

后端先做搜索/筛选
计算完整结果集算距离
排序距离 ASC,点赞 DESC
分页最后再返回前 N 条

推荐排序规则

严格满足“距离第一,点赞第二”
有定位
  1. 有效坐标营地优先,无坐标或 0,0 排最后
  2. 距离升序:离用户越近越靠前
  3. 点赞数降序:距离同级时,热度高者靠前
  4. 评分降序:作为质量兜底
  5. ID 或创建时间稳定排序,避免抖动
无定位

保持现有默认推荐

无定位或坐标无效时,不强行改体验,继续按当前后端默认排序:

ORDER BY rating DESC, like_count DESC

这样不会影响拒绝定位、IP 定位失败、首屏尚未拿到定位的用户。

统一 API 合同

不新增复杂引擎,增强现有 /camp/list
GET /api/camp/list
/api/camp/list?page=1&pageSize=20&lat=30.67&lng=104.06&sort=nearby
lat / lng用户当前位置,GCJ02 坐标系
sort=nearby启用距离优先排序;无效坐标回退默认
distance响应里覆盖为实时距离,与 /camp/nearby 一致

实施范围

最小闭环,双端一致
后端
luying-camp-web/app/api/camp/list/route.ts
新增 lat/lng/sort,nearby 路径全量筛选后排序;keyword 加 province。
工具
luying-camp-web/lib/server/campRanking.ts
封装坐标有效性、距离计算、距离+点赞排序。
Web
app/(mobile)/page.tsx、app/(mobile)/camp/list/page.tsx
传定位参数,删除首页本地距离排序,搜索文案加入城市。
小程序
src/pages/home/index.tsx、src/pages/camp-list/index.tsx
传定位参数,列表页也按后端附近排序,搜索文案加入城市。

需要拍板的边界

建议本次按左侧方案落地
排序模型

不用加权分

采用字典序:距离 ASC → 点赞 DESC。优点是可解释、符合“距离第一”。

城市搜索

先不加 city 字段

本次只扩展 province + address 搜索,避免牵涉发布、后台、迁移、回填。

nearby 接口

保留不改

/camp/nearby 继续服务附近地点选择;主列表统一增强 /camp/list。

验收方式

上线前看这几项是否成立
接口
无定位请求排序保持评分/点赞,不破坏默认推荐。
带 lat/lng/sort=nearby 后,结果按距离升序。
距离接近时,点赞高的排前。
keyword=四川 能命中 province;keyword=成都 通过 address 命中。
端侧
Web 首页与列表页授权定位后顺序一致。
小程序首页与列表页不再只在 20/50 条样本内排序。
拒绝定位时仍正常加载。
类型筛选、VIP 锁卡、距离标签不退化。