嗯来吧 · 首页模块规则说明

版本 v11.0 | 范围:底部任务单跑马灯、瀑布流固定槽位(今日最新 ↔ 新潮热门) | 读者:前端 / 后端 / 测试

阅读方式:每个模块分 ① 定义 ② 正常规则 ③ 异常规则 ④ 字段接口 ⑤ 埋点 ⑥ 验收用例;规则编号与《产品规则手册》一致(跑马灯 R-T01~R-T27,场景位 R-G03~R-G06)。

模块一 · 底部任务单跑马灯

1.1 定义与位置

首页底部 Tab 栏上方的通条轮播(高 44px):📢 + 订单标题 + 【金额¥】+ 去接单 + ×。目的:把「可接的求助单」直接推到施助者面前。

1.2 正常规则 · 取数

场景处理
数据来源仅求助订单(不含技能 / 组队 / 活动 / 闲置)
入池条件状态为「招募中 / 待接单」、未被接单、未过期、审核通过
城市范围按「采用城市」:手动选城 > 精确定位 > 城市级定位 > 省级(全省模式)> 默认上海
距离范围同城 + 20km 内可接;省级(全省)模式不做半径过滤
条数最多 5 条(marquee.maxItems 本期固定 5 条,见 1.2.2);不足按实际条数;0 条则隐藏
更多入口跑马灯右侧「查看全部 ›」→ 求助大厅列表页(承接想看更多的需求)
取数分层近 24 小时发布优先 → 不足用近 3 天补齐 → 仍不足按实际条数(不用过期单凑数)

1.2.1 入池条件(订单怎么进来)

维度条件(全部满足才进池)
类型仅求助订单(技能 / 组队 / 活动 / 闲置不进池)
状态招募中 / 待接单;未接单、未取消、未下架
时间未过期(订单有效期 > 当前时间)
地域属于「采用城市」:手动选城 > 定位城市 > 省级=全省 > 默认上海
距离同城且 ≤ 20km(可配);省级模式不做半径过滤
审核审核通过,无违规标记
发布者信用分 > 50(信用差限流不进池);未被封禁
资金赏金已托管成功(冻结失败的不展示)
内容标题 / 图片合规;命中敏感词不进池
控屏同一发布者最多占 2 条;同一条订单 1 小时内最多曝光 3 轮

1.2.2 为什么默认 5 条(条数取值依据)

取值后果结论
1–2 条像单条广告;大量可接订单得不到曝光;发布者投诉❌
3–4 条轮转更快,但覆盖率偏低(高峰池子常 20+ 条)⚠️ 池子小时按实际
5 条一轮 25–30 秒(5 × 5–6 秒);用户可接受再次看到首条✅ 默认
6–8 条一轮 35–45 秒;第 6 条后曝光≈0,拖慢轮转❌ 边际收益为负
100 条轮播机制下用户永远看不到末尾条目,纯占位❌ 无意义

取值依据:① 轮次时长 = 条数 × 平均停留,需控制在 20–30 秒;② 轮播位注意力集中在前 2 条,第 6 条起曝光接近 0;③ 校园同城 20km 未接单池通常十几到几十条,取前 5 即最优。

补充设计:跑马灯右侧提供「查看全部 ›」进入求助大厅列表页,满足想看更多的需求 —— 跑马灯做精选曝光,列表页做全量浏览。

可配置:marquee.maxItems 默认 5、范围 3–8;上线后依据一轮点击率与第 N 条点击率决定是否下调为 4。

1.3 正常规则 · 排序与轮播

项规则
有定位(精确 / 城市级)距离升序 → 发布时间倒序 → 金额倒序
无定位 / 省级模式金额倒序 → 发布时间倒序
主推条排序第 1 条为「主推条」,停留 +2 秒
停留时长基础(按字数)+ 加成,封顶 12 秒:≤10 字 4s / 11–15 字 5s / 16–20 字 6s / 21–25 字 7s / ≥26 字 8s;加成:本轮第 1 条 +2s、含打赏 +1s、综合金额 ≥500 元 +1s、已曝光 2 轮 −1s
滚动方式按排序顺序循环播放;每轮顺序固定(不随机)
重排时机每 15 分钟或下拉刷新重算一次
新单下一轮生效;若金额高于当前首条可插入队首
疲劳控制同一条订单 1 小时内最多曝光 3 轮,超出顺延下一条

1.3 排序规则(两层,定稿)

顺序规则
① 距离档有定位时:≤1km / 1–3km / 3–5 / 5–10 / 10–20km,先近档后远档;无定位或省级模式跳过本层
② 金额分金额分 = min(综合金额, 500) ÷ 500,降序(综合金额 = 酬金(现金)+ 打赏豆数×0.1)
③ 兜底金额分相同 → orderId 升序(顺序稳定、可复现)
急单兜底距截止 ≤3 小时的订单,在同一距离档内提到最前,并显示「即将截止」标
无定位 / 省级跳过距离档,直接按 金额分 DESC 排

不使用时效分 / 新鲜分(原设想的 1−已过÷总时长 与 1−发布小时÷72)。四条例由:① 两者方向相反会互相抵消;② 权重过低救不了急单(同档内"剩 23 小时"仍排在"剩 0.5 小时"前面);③ 时效分依赖订单有效期字段;④ 新鲜度问题已由"每天一批 5 条"的批次制解决。

1.3.2 额外打赏规则

项规则
什么是打赏酬金=现金 / 余额(可提现);打赏=用吧豆支付的追加鼓励(接单者获得吧豆,不可提现,只能换权益 / 排名)
展示分开显示:【酬金 80¥】【打赏 50 豆】
排序影响综合金额 = 酬金 + 打赏豆数×0.1 → 金额分提高 → 同一距离档内更靠前;打赏只影响排序,不参与现金结算
约束① 打赏不影响入池条件;② 单条订单吧豆折算部分≤50 元;③ 本期无加急、无付费置顶;④ 打赏档位与吧豆折算率待商业化确认

1.4 正常规则 · 交互

项规则
点条目进入该求助订单详情页
点「去接单」进入详情页并聚焦报名区
点「×」消除二次确认「今天不再显示?」→ 当天不再出现,次日 0 点恢复
消除记录本地 + 服务端双写(换设备、清缓存仍生效)
出现时机进首页延迟 1.5 秒出现;页面下滑 >300px 隐藏,回到顶部再现
暂停长按条目 / 页面不可见 / 请求中 → 暂停;恢复后从剩余时长继续

1.4.1 被接单后的补位机制(实时 or T+1)

链路时效说明
主链路:实时推送≤ 30 秒订单被接单 → 服务端推送「移除 + 补位」,客户端即时替换该条
降级链路:轮询60 秒无推送通道(WebSocket 断开/后台)时,每 60 秒拉一次增量
主动刷新立即用户下拉刷新 / 切换城市 / 回到前台 → 立即全量拉取
兜底重排T+1 + 每 15 分钟每日 0 点全量重算;运行期每 15 分钟定时重排一次

补位细节:① 只前移不重排(保持顺序稳定,避免跳动);② 新单下一轮生效(金额高于首条可插队首);③ 补位后不足 5 条 → 按实际条数;④ 补位后为 0 条 → 隐藏跑马灯。

1.4.2 切换城市 / 省份时的刷新

步骤行为
1 触发用户在位置选择器选择新城市 / 全省 → 派发 locationChanged 事件
2 顶部立即更新顶部文案(城市名 / 「省份 · 全省」);选城 ≠ 定位城市时提示「恢复定位」
3 跑马灯立即清空并拉取新池(显示骨架 ≤300ms),不展示旧城市内容;新池为空则隐藏
4 场景位A(今日最新)、B(新潮热门)同时重算并按新城市替换
5 瀑布流按新城市刷新列表;保持滚动位置或回到顶部(建议回到顶部)
6 失败兜底拉取失败 → 保留旧内容 + 顶部提示「切换失败,点击重试」(不静默失败)
7 消除记录消除标记按 「城市 + 日期」 维度存储:换城市后重新展示(不共用)

特别说明(省级):用户只授权到省份(或 IP 定位)时,采用全省模式:城市字段显示「省份 · 全省」,订单池 = 全省可接求助单,距离显示「同省」,排序改用金额 → 计划完成时间,且不做 20km 半径过滤。

1.5 异常规则(研发必看)

场景处理
无数据整个跑马灯隐藏,不留白、不占位(瀑布流正常上移)
只有 1 条常显不轮播(避免"刚看到就切走")
2–4 条按实际条数循环;停留时长规则不变
订单被接单≤30 秒内移除并补位;补位后不重新排序(防列表跳动)
订单过期同样移除并补位;已展示的曝光数据照常上报
网络失败保留上次缓存内容继续轮播;仅首次无缓存时显示骨架屏,不显示错误页
定位权限被拒按上海 + 金额排序;距离显示「同城」,不显示公里数
仅省级精度按全省模式:金额排序、距离显示「同省」、不做半径过滤,并提示"选择城市可获得更准推荐"
选城 ≠ 定位城市按所选城市取数;顶部提示「当前按【X】展示 · 恢复定位」;距离以所选城市中心为基准并标注"按所选城市估算"
切换城市中保留旧内容,切换完成后一次性替换(不出现空白闪烁)
当天已消除不展示;次日 0 点恢复,以服务端时间为准(改客户端时间/跨时区无效)
违规 / 审核中订单不进池(状态过滤在服务端完成)
页面内有弹层打开暂停轮播计时,关闭后恢复
服务端时间与客户端不一致一切判定以服务端 serverTime 为准

1.6 字段与接口

GET /home/marquee?city={城市}&precision={exact|city|province|none}&lng=&lat=

字段说明
items[].orderId订单 ID(点击跳转用)
items[].title标题(前端按 1 行省略)
items[].amount金额(整数,单位元)
items[].district区县(用于距离展示)
items[].distance距离(km,1 位小数);无定位时返回 null
items[].publishedAt发布时间(服务端时间戳)
scrollSec / firstExtraSec服务端可下发停留时长与主推条加时,便于运营调节
hidden是否隐藏(无数据 = true)

1.7 埋点

曝光(条数 / 采用城市 / 定位模式)、轮播次数与每条停留时长、点击条目、点击「去接单」、点「×」消除、手动暂停。

1.8 验收用例

场景处理
正常 1有定位、池中有 5 条 → 按距离升序轮播,每条按字数停 4–8s,首条 +2s
正常 2无定位 → 按金额降序,距离列显示「同城」,不显示公里数
正常 3点「去接单」→ 详情页并聚焦报名区
正常 4点「×」→ 二次确认 → 当天不再出现;次日 0 点恢复
异常 1池中 0 条 → 跑马灯不显示,且页面无空白占位
异常 2仅 1 条 → 常显不轮播
异常 3某条被接单 → 30 秒内消失且后续条目前移,不重排
异常 4断网 → 保留缓存继续轮播;恢复网络后内容刷新且不闪空
异常 5拒绝定位权限 → 上海 + 金额排序 + 距离「同城」
异常 6仅省级精度 → 全省模式 + 金额排序 + 距离「同省」+ 不做半径过滤
异常 7选城与定位不同 → 按所选城市取数并显示"恢复定位"提示
异常 8修改客户端时间 → 消除记录与恢复时间不受影响

模块二 · 瀑布流固定槽位(今日最新 ↔ 新潮热门)

2.1 定义与位置

瀑布流内同一个固定槽位(不新增格子、卡片高度固定),在 A = 今日最新 与 B = 新潮热门 两个状态间轮换。卡片 = 封面图 + 标题(2 行)+ 价格/单位 + 发布者信用 + 距离;右上角 2 个圆点表示当前态,顶部细进度条表示剩余时间。

2.2 正常规则 · 取数

项规则
A 今日最新 · 时间窗当日 00:00–24:00 发布的内容
A 数量与入口显示 3 条(不足按实际),卡片底部「查看更多 ›」进入今日最新列表页
A 排序有定位 → 距离升序;无定位 → 发布时间升序;未授权定位 → 默认上海;两者都取前 3 条
A 排除审核中、已下架、已被接单(订单类)
B 新潮热门 · 时间窗近 7 天
B 数量与入口同样显示 3 条+「查看更多 ›」(两态结构对称,卡片高度一致)
B 热度分浏览 ×0.4 + 收藏 ×0.3 + 成交 ×0.3;新奇技能 ×1.3;同分按发布时间倒序
B 刷新每 10 分钟重算一次
去重A 与 B 不出现同一条;B 若与 A 重复则顺延取下一条

2.3 正常规则 · 轮换

项规则
轮换方式A → B → A → B 交替(顺序固定,不随机)
停留时长每个状态 8 秒(后台可配 5–15s)
首次进入默认显示 A(今日最新);重新进入首页都重置为 A
手动切换左右滑卡片 或 点击圆点 → 立即切换,并暂停自动轮询 3 个周期(24 秒)
暂停条件页面不可见、槽位滚出可视区、请求数据中、从详情页返回 2 秒内、长按卡片
恢复从剩余时长继续,不重新计时
预加载切换前 1 秒预取下一状态数据与首图;首屏 A、B 一次请求返回
动画横向滑动 300ms;低端机降级淡入 200ms;卡片高度固定,切换不引起瀑布流跳动

2.4 异常规则(研发必看)

场景处理
A 无数据只显示 B 且停止轮询(不显示空卡片)
A 只有 1–2 条按实际条数显示;「查看更多」入口保留
查看更多页为空显示空态「今天还没有新内容」+「去发布」按钮,不显示空白页
两态条数不一致按较少的一侧补齐占位或统一取 3 条,保证卡片高度一致(防瀑布流跳动)
B 无数据只显示 A 且停止轮询
A、B 都无隐藏整个槽位,瀑布流自动上移,不留白、不占位
A 与 B 返回同一条B 自动顺延取第 2 条,避免"切了等于没切"
B 数据不足 6 条B 常显 24 秒后回到 A,并把轮询间隔放宽到 15 秒
网络失败保留上次缓存内容继续轮换;仅首次失败显示骨架屏,不显示错误页
图片加载失败显示占位图;不影响标题、价格与点击
用户快速连续手动切换防抖 300ms,以最后一次点击为目标状态
切换城市 / 定位变化立即重算 A 与 B,整体替换内容并保持卡片高度
从后台回前台恢复计时(按剩余时长),并检查是否已超过刷新周期,超过则先刷新再继续
内容被下架 / 删除从当前轮换中移除并补位;若 A 或 B 因此为空,按"无数据"处理

2.5 字段与接口

GET /home/scene-slot?city={城市}&precision={exact|city|province|none}&lng=&lat= → 返回 { today:[…], hot:[…], durationSec:8 }

字段说明
today[].itemId / title / cover / price / unitA 态内容(当日发布),最多返回 3 条
todayTotal / hasMore当日总数与是否还有更多(决定「查看更多」是否可点)
today[].distance距离(km);无定位返回 null,前端显示「同城」
hot[].itemId / title / cover / priceB 态内容(近 7 天热度),最多返回 3 条
hotTotal / hasMore热门总数与是否还有更多
hot[].heatScore热度分(用于排查排序,前端不展示)
hot[].isNovel是否新奇技能(展示「新奇」角标)
durationSec / disableRotate停留时长、是否停止轮询(单侧为空时由服务端下发)

2.6 埋点

曝光(scene=A/B、itemId、停留时长、是否自动)、点击、手动切换、空态次数、切换城市后的内容刷新成功率。

2.7 验收用例

场景处理
正常 1A、B 各停 8 秒交替;进度条走完即切换,卡片高度不变
正常 2手动切换后 24 秒内不再自动切换;随后恢复交替
正常 3A 有定位按距离最近;无定位按当日最早发布
正常 4B 按热度分降序,新奇技能带角标且加权
正常 5今日最新显示 3 条,底部「查看更多」可点,进入列表页后可上滑分页加载
正常 6今日最新不足 3 条(1–2 条)时按实际显示且「查看更多」仍在
异常 1A 为空 → 只显示 B 且停止轮询
异常 2B 为空 → 只显示 A 且停止轮询
异常 3A、B 都空 → 槽位隐藏且无空白占位
异常 4A、B 返回同一条 → B 自动顺延,两次展示内容不同
异常 5B 仅 3 条 → 常显 24 秒后回 A,轮询间隔放宽到 15 秒
异常 6断网 → 显示缓存内容;恢复后刷新且不闪空
异常 7切换城市 → A、B 立即重算并整体替换,页面不跳动
异常 8切后台 5 分钟回前台 → 从剩余时长继续并先刷新数据
异常 9两态条数不同时卡片高度不变,瀑布流不跳动
异常 10查看更多页无内容 → 显示空态与「去发布」,不是空白页