AGENTS.md
本文件为 Codex 在 lls_program 仓库中的协作说明。目标不是介绍 Taro 通用知识,而是帮助后续修改尽量贴合这个项目当前的真实实现。
项目概述
lls_program 是一个基于 Taro 4 + Vue 3 + NutUI 的微信小程序,当前核心业务包括:
- 家庭创建、加入、成员资料维护
- 活动页、广告页、海报打卡、扫码打卡
- 积分、奖励、优惠券相关页面
- 基于微信授权和
sessionid的登录态流转
最近一轮实现里,扫码打卡链路已经接入真实接口,并补上了注册来源归因、回跳续扫、地理围栏判断等逻辑。后续改动请优先遵守这些既有约定,不要在页面里重新长出一套平行逻辑。
技术栈
- 框架:Taro
4.1.7 - UI:Vue
3.3,统一使用<script setup> - UI 组件:NutUI Taro
4.3.13 - 样式:TailwindCSS
3.4+ Less - 状态管理:Pinia
3.0+taro-plugin-pinia - 请求库:
axios-miniprogram - 构建:Webpack 5
- 测试:Vitest
常用命令
项目当前 package.json 里是标准 npm scripts,使用 npm 或 pnpm 都可以,但文档和命令示例优先按仓库现状写 npm。
# 安装依赖
npm install
# 微信小程序开发
npm run dev:weapp
# 微信小程序打包
npm run build:weapp
# H5 / 支付宝 / 抖音
npm run dev:h5
npm run dev:alipay
npm run dev:tt
# 代码质量
npm run lint
npm run format
# 测试
npm run test
npm run test:run
npm run test:coverage
目录结构
src/
├── api/ # 只放接口调用
├── assets/ # 静态资源
├── components/ # 通用组件
├── pages/ # 页面
├── stores/ # Pinia 状态
├── utils/ # 纯工具逻辑、流程辅助、请求封装
├── app.config.js # 页面注册、权限声明
└── app.less # 全局样式
当前和扫码打卡强相关的目录:
src/api/map.jssrc/pages/ScanCheckinList/src/pages/ScanCheckinDetail/src/pages/Welcome/src/pages/AddProfile/src/pages/CreateFamily/src/pages/JoinFamily/src/utils/checkinLocation.jssrc/utils/scanCheckin.jssrc/utils/returnUrl.jssrc/utils/userProfile.jssrc/components/RichTextRenderer.vue
路径别名
项目已经配置好以下别名,新增代码优先使用别名,不要堆相对路径:
@/utils
@/components
@/assets
@/api
@/stores
@/composables
@/hooks
API 与请求约定
响应判断
所有接口统一按下面结构处理:
{
code: 1,
data: {},
msg: '...'
}
必须显式判断 res.code === 1,不要写成 if (res.code)。
sessionid 机制
项目通过 sessionid 做服务端认证:
-
src/utils/request.js每次请求前动态从 storage 读取sessionid - 请求头通过
config.headers.cookie = sessionid透传 - 401 由现有登录/静默授权流程接管
重要约定:
- 前端不要把
sessionid当成“能否继续业务流程”的唯一判断条件 - 是否能继续业务流程,应看接口结果和页面自己的业务条件
API 文件职责边界
src/api/*.js 只放接口定义和请求函数,不要把参数拼装、流程判断、字段归一化 helper 塞进去。
正确做法:
- API 请求函数放
src/api/ - payload 构建、字段解析、return_url 处理、地理围栏计算等 helper 放
src/utils/
当前已经落地的例子:
-
src/utils/userProfile.jsbuildUpdateUserProfilePayloadisUserProfileComplete
-
src/utils/scanCheckin.js- 负责从二维码内容里解析
activity_id/detail_id
- 负责从二维码内容里解析
-
src/utils/returnUrl.js- 负责
return_url解码和拼接
- 负责
-
src/utils/checkinLocation.js- 负责地理围栏判断
当前扫码打卡链路
这是现在最需要保持稳定的一条业务链路,后续改动请先看清楚,不要只盯某一个页面。
页面与接口
- 列表页:
src/pages/ScanCheckinList/index.vue- 使用
getScanStageListAPI
- 使用
- 详情页:
src/pages/ScanCheckinDetail/index.vue- 使用
getScanStageDetailAPI - 使用
submitScanCheckinAPI
- 使用
- 接口定义集中在
src/api/map.js
当前流程
- 用户从活动或二维码入口进入扫码打卡相关页面
- 扫码链接会带
activityId,详情页自身还可能带reg_source、reg_stage_id -
ScanCheckinDetail点击“扫码打卡”时,先按现有路线检查“是否已有家庭” - 没有家庭时,不直接扫码,先弹提示,再跳
Welcome -
Welcome再决定是否先补资料、再创建家庭或加入家庭 - 完成资料和家庭链路后,通过
return_url回到原扫码详情页 - 用户再次点击“扫码打卡”时:
- 重新静默获取当前位置
- 如果该关卡开启地理围栏,则先判断是否在范围内
- 调起微信扫码
- 从二维码结果里解析真实的
activity_id/detail_id - 调用打卡接口
- 打卡成功后跳转到
ScanCheckinList
关键业务约束
- 打卡提交参数来自二维码内容,不来自详情页当前路由参数
- 详情页路由参数主要用于展示、回跳和列表跳转
- 注册来源归因字段当前只保留:
reg_sourcereg_stage_id
-
reg_activity_id已经不再需要,不要再传 - “是否补全资料”的判断交给
Welcome链路,不要在ScanCheckinDetail再复制一套资料完整性分支
return_url 回跳约定
扫码打卡目前依赖多页串联回跳,任何一个页面处理不对,都会出现跳错页、路径双重编码、甚至 redirectTo 找不到页面。
当前约定:
- 统一使用
src/utils/returnUrl.js - 页面收到
options.return_url后,先走normalizeReturnUrl - 页面拼接下一个页面地址时,优先走
appendReturnUrlParam - 不要在页面里到处手写
decodeURIComponent(options.return_url || '')
当前受这个约束影响较大的页面:
src/pages/Welcome/index.vuesrc/pages/AddProfile/index.vuesrc/pages/CreateFamily/index.vuesrc/pages/JoinFamily/index.vue
注册资料与来源归因
buildUpdateUserProfilePayload 目前已经抽到 src/utils/userProfile.js,专门负责把页面表单转成接口 payload。
当前约定:
-
user.js里只保留接口调用 -
buildUpdateUserProfilePayload不回迁到 API 文件 - 注册来源字段在补资料接口里继续透传:
reg_sourcereg_stage_id
-
reg_stage_id需要按数值类型传给后端
地理围栏约定
扫码详情页如果 geo_enabled === true,必须做范围判断。
当前实现约定:
- 判断逻辑统一放
src/utils/checkinLocation.js - 页面层只负责调用,不要在页面里自己算经纬度距离
- 点击“扫码打卡”时重新调用
Taro.getLocation(),不依赖旧缓存 - 关卡详情接口字段:
geo_enabledcenter_lngcenter_latradius_meters
富文本与轮播图约定
扫码详情页当前已经不是单图和原生富文本直出:
- 顶部 banner 使用 NutUI
nut-swiper - 富文本显示统一走
src/components/RichTextRenderer.vue
后续如果再改扫码详情页:
- 不要再改回单张
<image> - 不要再临时拼一个简化版富文本组件替代现有
RichTextRenderer
页面开发约定
生命周期
页面优先使用 Taro 生命周期:
import { useLoad, useShow, useDidShow, useReady } from '@tarojs/taro'
尽量避免把页面主流程写到 Vue 的 onMounted / onUnmounted 里。
页面结构
每个页面目录通常包含:
index.vueindex.config.jsindex.less
新增页面后必须同步注册到 src/app.config.js。
小程序 API 约束
不要在页面或工具函数里使用浏览器 API,例如:
windowdocumentlocalStorage- 原生
fetch
统一使用 Taro API,例如:
Taro.navigateToTaro.redirectToTaro.switchTabTaro.getStorageTaro.scanCodeTaro.getLocation
样式约定
- NutUI 组件自动导入,不要手动 import
- 页面样式继续保持 Tailwind + Less 混合方式
- Less 样式默认
scoped - 深层覆盖 NutUI 时使用
:deep(...)
这个仓库已经有一个和扫码页相关的稳定样式经验:
-
ScanCheckinDetail底部按钮采用固定定位和安全区留白 - 如果只是调整按钮视觉位置,优先做 CSS 修改,不要顺手改业务逻辑
权限与配置
src/app.config.js 当前已经声明了位置权限:
requiredPrivateInfos: ['getLocation']permission['scope.userLocation']
所以如果你在扫码打卡里继续用定位能力,优先复用现有授权前提,不要再设计一套重复授权流程。
修改建议
适合抽到 utils 的逻辑
- 二维码参数解析
- 距离计算和范围判断
- return_url 编解码
- 用户资料 payload 构建
- 纯字段映射或判空逻辑
不适合放进 API 文件的逻辑
- 表单转 payload
- 页面跳转流程判断
- 二维码内容解析
- 路由参数兼容处理
- 页面专用字段映射
做改动前先检查
- 这是页面职责,还是工具职责
- 这是接口请求定义,还是接口参数拼装
- 这是详情页展示参数,还是打卡提交真实参数
- 这是当前页下一跳,还是完整链路里的回跳页面
交付标准
在这个仓库里完成修改时,优先做到:
- 与当前真实业务链路一致
- 不在页面里复制已有 helper
- 不在 API 文件里塞 helper
- 不破坏
return_url回跳 - 不破坏扫码打卡的地理围栏与注册来源归因
- 不把 Taro 小程序页面写成浏览器页面