面向泰国年轻人的本地生活服务 + 分享社交 App。4 个主界面:附近(动态流 + 朋友圈 + Google 定位周边)/ 好友(聊天为主 + 通讯录入口)/ 服务(后台可配的模块中心,H5 内嵌)/ 我的。 另附四张二级页:聊天、服务详情页(租车 / 按摩 / 餐厅,第三方多家列表,评分从高到低)、商家详情页(套餐 / 时段 / 地图 / 全部评价)、通讯录(好友独立页,分组 + A–Z 索引)。 所有列表数据来自 mock.js,经 api.js 的异步桩返回, 页面只负责组合 styles.css 里的组件 —— 后端接入时只需替换 api 层实现。 界面支持 中文 / English / ไทย 三语切换(顶栏语言胶囊)。可直接在这些机框里操作:点底部 + 发布、点服务模块看 H5 内嵌抽屉、切顶栏语言、点动态里的“想去”。
暖纸底 + 墨黑文字,主色钴蓝、辅色芒果橙。大圆角卡片、克制的层叠阴影、4px 间距栅格。字体优先泰国本地字体(Sukhumvit Set / Thonburi / Leelawadee UI),图标统一 Lucide 线性图标,全程无 emoji。
租车买车 / 附近餐厅 / 周边按摩 / 生鲜配送已上线,卡片带 H5 角标;修车、票务为「即将上线」占位。客户端只读取 模块列表接口,新增或下线模块无需发版 —— 点任意模块卡即可看到 WebView 容器演示(含地址栏与「无需更新 App」说明)。
顶栏语言胶囊支持 中 / EN / ไทย 三语实时切换(含导航、分区标题、按钮、设置项,以及距离、时间、状态的动态文案),选择写入 localStorage。定位展示走 Google 定位口径:行政区 + 半径 1/3/5/10 公里筛选,动态只显示模糊距离。
一个模板 · 三种数据:service.html?type=car|massage|food。租车 / 按摩 / 餐厅都是第三方服务,页面结构一致:Hero 大图 → 关键数据(平均评分 / 商家数 / 起价 / 最近距离,均由商家数据实时算出)→ 优惠券横滑 → 吸顶排序 → 筛选 → 商家列表 → 评分分布 + 用户评价 → 常见问题 → 底部固定操作栏。
商家默认按评分从高到低排列(同分看评价数),前两名挂「优选」角标并显示 #1 #2 名次;可切「距离最近 / 价格最低」,可叠加「营业中 / 可预约 / 4.5 分以上 / 2 公里内」筛选,筛选后无结果会显示空状态。详情页隐藏底部 tabbar,改为「收藏 · 客服 · 起价 · 立即预约」操作栏。点商家卡进入商家详情页。
merchant.html?id=m-car-7。图廊(1 大 2 小 + 共 N 张)→ 商家头卡(评分 / 星级 / 评价数 / 营业状态 / 标签 / 距离 · 营业时间)→ 四个动作(导航 / 电话 / 分享 / 收藏)→ 套餐 → 到店时段 → 位置与交通(小地图 + 地址 + 导航)→ 用户评价(评分分布 + 星级筛选)→ 商家信息(营业时间 / 电话 / 地址 / 支付 / 停车)→ 常见问题。
套餐可选中(默认选中 HOT 那档),选中后底部操作栏价格实时换算;时段按「今天 / 明天 / 后天」切换,已约满的时段置灰不可点;未选时段点「立即预约」会提示先选时间。21 家商家共用 3 套品类模板,套餐价格由商家自己的基础价推导,所以每家店的价格都自洽。
一排一选 → 一发 → 大家来评论 / 参与 / 前往。首页有四个并排的服务入口:按摩 / 租车 / 生鲜 / 到店账单,点一个即弹出分享面板(已选中该项 + 分享范围:附近动态 / 好友 / 群聊),再点一次「立即分享」就发到附近动态并自动滚到你的新帖。
四类服务共用同一张卡片:缩略图 + 服务类型角标 + 名称 + 商家·距离 → 评论 / 参与 · N / 前往 三个动作。发布面板里的「分享到店账单」也直接进入这条链路,所以晒账单、按摩、租车、生鲜是同一套交互,只是数据不同。
首页把动态流提到筛选栏正下方,第一屏就是动态;半径筛选和地图下沉成「探索周边」区块。
半径默认 「全部」= 不限制距离,且由近到远排序 —— 你会先看到自己街区的内容,远处的分享照样能看到(去不了不代表不能看)。只有主动选 1/3/5/10 公里才做距离过滤。动态标题同时说明范围和排序(「不限距离 · 距离最近」/「10 公里 · 附近动态 · 最新发布」)。某个半径真的没内容时,空状态给一个「看全部」按钮一键还原。
动态标题右侧的排序按钮打开排序面板:距离最近 / 最新发布 / 最多人想去,换排序会重新分页,缓存按「分类 + 半径 + 排序」隔离。
顶栏把搜索和加好友都做成按钮(搜索框默认收起,点放大镜才展开,收起时自动清掉筛选),标题右侧不再是输入框。「当前在线」放在最上面,接着才是聊天列表。
聊天区改成紧凑单行标题:标题 + 橙色未读数胶囊同行显示,去掉了之前占两行的主副标题。
顺序为:快捷入口(通讯录 / 群聊 / 新朋友 / 饭搭子) → 当前在线 → 聊天 → 好友申请 → 附近的人 → 社交概览。好友列表不再挤在这里,而是通过「通讯录」这个快捷按钮进入独立页面。
快捷功能格从 4 个(钱包 / 优惠券 / 收藏的店 / 足迹,且文案写死在 HTML 里)改成 6 个数据驱动的格子,由 DB.meQuick 下发,后台加一格不用改客户端:我的点赞 214 · 我的收藏 86 · 我的订单 12 · 我的优惠券 6 · 收藏的店 32 · 我的足迹 48。
点赞和收藏排在最前两位 —— 这是之前翻遍「我的」都找不到入口的两项。每格显示图标 + 右上角计数 + 标签,标签走三语字典(k.likes / k.saves),窄屏超长自动省略号。钱包不再占格(上方已有独立的余额卡)。
到店坐下第一件事就是扫码点餐,所以入口有两个:首页顶栏最右侧(通知铃铛右边,是顶栏里唯一着色的控件)和「我的」页顶栏左上角(标题左边)。两处共用同一个面板、同一套三语文案(t.scan / sc.*)。
点开不是一张选择菜单,而是一整屏的相机:顶部「关闭 / 扫一扫 / 手电筒」→ 上方取景框(深色镜面 + 四角框 + 主色扫描线上下往复)→ 取景框下方的提示语 → 取景框下面并排三个动作:扫码点餐 · 扫码付款 · 相册里的码。用的还是 data-sheet="scan" 这套弹层机制,只是换成了全屏形态(.sheet__panel--full)。
扫码不限自家的码:任何系统的二维码都能识别,取景框下面直接写清楚「所有二维码都能扫 · 链接会用浏览器打开」。扫到东西后,扫描线停下、识别结果卡片从底部推上来 —— 外部链接不在 App 内打开,而是给「用浏览器打开」和「继续扫描」两个动作,把链接交回浏览器处理。
位置是怎么腾出来的:去掉顶栏右上角的个人头像。那个头像是进「我的」的快捷方式,而底部 tab 已经有「ของฉัน」,属于重复入口。去掉后顶栏不增宽、定位文字也不用被压缩。
contacts.html。好友多起来之后需要一个正经的页面:统计条(好友 / 在线 / 新申请 / 群聊)→ 常一起吃饭横向栏(按一起吃过次数排序,本 App 特有的分组)→ 筛选(全部 / 在线 / 星标好友)→ 好友列表 → A–Z 索引条。
列表只有列表一种形态(不做卡片/网格),右上角不加切换按钮;分组按「星标好友 → A / B / C / F / J / K / M / N / P / S / T」排列,组头吸顶在导航下方,右侧 A–Z 索引条点字母直接跳组。12 位好友全部来自一张扁平表,所有分组都是前端推导的(真实接口只返回行,分组交给客户端)。
输入条左边的 + 打开「发送内容」面板,三组各四个:发送(图片 / 视频 / 位置 / 语音)· 从我这里发(我的订单 / 我的足迹 / 我的收藏 / 评价过的店)· 分享(好友名片 / 附近的店 / 我的点赞 / 我的预约)。每一格都真的往对话里插一条消息 —— 不是弹一句 toast 了事,所以能看到自己发出去的长什么样。
消息有 8 种形态:文字、图片、视频(封面 + 播放键 + 时长)、语音(麦克风 + 声波 + 秒数)、位置,以及统一走 .msgcard 的富卡片(订单 / 足迹 / 收藏 / 评价 / 好友名片 / 店铺)。
长按气泡(或右键)打开消息操作:复制 · 转发 · 收藏 · 多选 · 撤回 · 删除;撤回只出现在自己发的消息上 —— 别人的话收不回来,撤回后气泡原地变成一行系统提示。多选把输入条换成操作条(已选 N 条 / 转发 / 撤回 / 删除),点气泡即勾选;转发打开可多选的聊天列表,一次发给多个会话就是群发。
顶栏 ⋯ 是「聊天设置」(查找记录 / 免打扰 / 置顶 / 选择消息 / 清空记录 / 拉黑)—— 长按能用,但不能指望每个人都猜得到,所以这里也留了一个入口。顶栏头像和名字改由 DB.threadPeer 渲染,不会再出现「拿我自己的头像去代表聊天对象」。
首页动态池 24 条、8 种内容形态。首屏加载 6 条,底部“加载更多动态”按页追加(不跳屏),并显示 6 / 24 进度;顶部黑色胶囊提示“12 条新动态”,一点即刷新。切筛选或半径会重新分页;加载中显示骨架屏,无结果显示空状态。
「全部服务」已经存在的这张卡片列表,本质是一张服务注册表。每张卡只由 type 决定怎么打开:自研原生(站内路由,走 SOI 的设计与接口)· 外部链接嵌入(独立项目以 H5 进 WebView 容器)· 混合(外壳原生、内容嵌 H5)。
名字 / 图标 / 链接 / 简介 / 服务接口 / 鉴权方式 / 角标 / 排序 / 上下架全部由后台下发,客户端零改动。后台点一下就能加一个服务、改个图标或下架,不用发版 —— 这是这套架构存在的唯一理由。
现在待接入的四个既有项目、各自的入口与改造点(含 免登令牌怎么写、每个项目 token key 都不一样)都写在 开发文档.md 里,含字段表、接口约定与分阶段落地顺序。
底部 + 打开的不再是一排只弹 toast 的入口,而是一条真正的发布流程:发什么 → 发到哪(附近动态 / 朋友圈)→ 谁可以看 → 发布。两个空间的可见性名单完全不同:广场里是「公开到附近 / 附近的好友 / 匿名 / 仅自己」,关系链里是「全部好友 / 不给谁看 / 只给谁看 / 仅自己」。
落到数据上只有一张 Post 表,靠 space + audience 分流,服务端 visibleTo() 一个函数收口 —— 客户端不参与可见性判断。发到朋友圈的动态不会出现在附近流里,「我的发布」每格带可见性角标(🔒 仅自己 / 👥 仅好友 / 👁 匿名)。
顺带修掉原来那个假的选择:分享服务时选「好友 / 群聊」以前照样发到公开动态,现在真的进聊天(发一张服务卡片)。完整规则见 发布与可见性设计.md。
商家会越来越多,所以任何一个行业都不能各做一套。周边服务定了标准:分类(我要哪一类)+ 内容(不知道要什么,看看别人)+ 列表(决定了,比价下单)+ 空状态(这里什么都没有,但别让用户走)。七段顺序固定,新行业只填数据、不改页面。
分类 = 一组标签的命名,一家店可以同时属于多个分类,加分类不用动商家数据。分类 rail 和排序栏一起吸顶 —— 滚到第三屏也够得着。「大家在看」是内容条(探店视频 + 优质点评),另外每 4 家店再插一张内容卡,列表往后翻也不会只剩重复的卡片。
偏远地区或筛选无结果时,走空状态:说清原因 + 一个能立刻点出去的按钮(重置筛选 / 看看全城)+ 下面永远有内容可看。内容条这一段在空状态下自动让位,不会出现两次。完整规则与数据契约见 频道页标准.md。