佳友厚苑 MVP 第一阶段开发文档
1. 项目目标与范围
1.1 项目目标
第一阶段目标是快速搭建“扫码溯源展示能力”,跑通最小业务闭环:
- 用户扫码 → 打开溯源页面
- 页面展示商品、农场、批次、检测报告、合格证
- 支撑运营实际使用(打印标签 + 贴标 + 直播/发货使用)
1.2 本阶段解决的问题
- 如何让用户“看到可信信息”
- 如何快速上线溯源能力
- 如何支撑运营落地流程
1.3 本阶段不做内容
- 不做商城交易系统
- 不做登录注册
- 不接农小禹系统
- 不做农事记录
- 不接设备/摄像头数据
- 不做复杂审核流
- 不做统计分析
2. 业务流程
2.1 标准流程
- 运营创建批次
- 填写商品信息、农场信息、批次信息
- 收集农户提供的:
- 在爱智农后台上传资料
- 生成批次二维码
- 生成标签打印文件
- 打印标签并贴标
- 用户扫码进入溯源页查看信息
2.2 关键约束
- 批次创建时必须填写商品与农场信息
- 批次未发布不可扫码
- 所有展示内容均来源于批次
3. 角色与职责
3.1 运营人员
- 创建批次
- 收集合格证与检测报告
- 上传资料
- 生成二维码
- 打印标签
- 校验扫码效果
3.2 系统(爱智农)
- 提供批次管理能力
- 提供文件上传能力
- 提供二维码生成能力
- 提供标签打印能力
3.3 用户
4. 核心数据模型
4.1 核心对象:批次(Batch)
第一阶段所有数据围绕“批次”组织
4.2 批次结构
批次包含以下信息:
商品信息
农场信息
批次信息
- 批次号
- 生产/采收日期
- 包装日期
- 状态(草稿/已发布/已下线)
文件信息
4.3 设计原则
- 批次创建时必须填写商品与农场信息
- 批次为唯一展示数据源
- 前端不单独维护数据
5. 前端页面说明(溯源页)
5.1 页面目标
让用户快速理解:
- 买的是什么(商品基础信息清晰可见)
- 来自哪里(农场来源明确)
- 属于哪一批(批次信息明确)
- 是否经过检测(检测报告可查看)
- 是否具备合格证(合格证可查看)
- 页面整体有一定品牌感与可信感
5.2 页面结构
1. 页面头部
- 品牌名称:佳友厚苑
- 页面标题:商品溯源信息
- 商品/农场背景图
- 品牌文案(如:可追溯 · 更安心)
- 商品主视觉图优先,若无则使用农场图
2. 商品信息区
3. 农场信息区
4. 批次信息区
5. 检测报告区
- 检测状态(合格/待补充)
- 检测日期(可选)
- 报告编号(可选)
- 报告文件预览(PDF/图片)
- 查看原件按钮
6. 合格证区
- 合格证状态
- 开具日期
- 合格证文件预览
- 查看原件按钮
- 合格证编号(可选)
7. 溯源说明区
- 数据来源说明(前端固定文案)
- 溯源说明文案(前端固定文案)
示例文案:
数据来源说明:
本页面信息由佳友厚苑溯源系统提供,相关检测报告及合格证由平台统一收集并上传,确保信息真实可查。
溯源说明文案:
本商品支持溯源查询,您可通过本页面查看该批次的商品来源、生产信息、检测报告及合格证等内容,让消费更安心。
说明:
- 第一阶段溯源说明区内容建议由前端写死为固定文案,不依赖后台配置
- 若检测报告或合格证缺失,通过对应模块内“待补充”提示即可,不单独设置“数据完整性说明”区域
8. 底部引导
5.3 页面状态设计
正常状态
空数据状态
- 显示:
- “检测报告待补充”
- “合格证待补充”
- “农场信息待补充”
异常状态
- 批次不存在 → 提示“无效二维码”
- 批次未发布 → 提示“暂未开放查询”
- 批次已下线 → 提示“该批次已下线”
5.4 第一阶段溯源页展示建议(推荐采用卡片式布局)
推荐展示顺序
- 页面头部(品牌 + 标题 + 主视觉)
- 商品信息区
- 农场信息区
- 批次信息区
- 检测报告区
- 合格证区
- 溯源说明区
- 底部引导区
推荐展示原则
- 先展示用户最关心的信息:商品、农场、批次
- 再展示证明可信的信息:检测报告、合格证
- 再展示平台与品牌说明,增强页面完整度
- 第一阶段即使数据不全,也建议将展示结构预留完整,未填字段以空状态或待补充提示处理
- 第一阶段展示字段以“实用、易维护、可快速上线”为原则,暂不引入冗余修饰型字段
- 第一阶段仅保留必要展示字段,避免增加运营录入负担与前后端复杂度
6. 爱智农后台功能说明
6.1 批次管理
功能
- 创建批次
- 编辑批次
- 查看批次
- 上传检测报告(操作按钮)
- 上传合格证(操作按钮)
- 生成二维码
- 打印标签
- 发布/下线
关键规则
- 创建时必须填写商品与农场信息
- 草稿状态不可生成二维码
6.2 检测报告管理
- 通过批次管理操作按钮上传
- 支持 PDF 或多张图片上传
- 支持查看/预览与覆盖上传
6.3 合格证管理
- 通过批次管理操作按钮上传
- 支持 PDF 或多张图片上传
- 支持查看/预览与覆盖上传
6.4 二维码生成
6.5 标签打印管理
功能
标签内容
- 二维码(核心,保证清晰可扫码)
- 商品名称(用户可快速识别商品)
- 批次号(用于溯源对应)
- 简要提示文案(如:扫码查看溯源信息)
- 品牌名称(佳友厚苑,可选)
- 打印日期(可选)
标签展示设计建议
- 不建议仅打印二维码,必须搭配文字说明,否则用户无法理解用途
- 推荐结构:二维码在中间或左侧,文字信息在下方或右侧
- 建议至少包含一句引导语:如“扫码查看商品溯源信息”
- 商品名称建议简化显示,避免过长导致排版拥挤
- 批次号可使用较小字体展示
- 整体布局保持简洁,确保二维码识别优先
6.6 发布管理
批次状态:
7. 字段定义(简要)
批次
- batchNo
- productName
- productSpec
- productImage
- productDesc
- farmName
- farmRegion
- farmImage
- farmIntro
- produceDate
- packageDate
- status
检测报告
- reportStatus(上传状态:uploaded/pending)
- reportFiles(文件列表,支持PDF或多图)
- reportDate(必填)
- reportNo(必填)
合格证
- certStatus(上传状态:uploaded/pending)
- certFiles(文件列表,支持PDF或多图)
- certIssueDate(必填)
- certNo(必填)
8. 二维码与标签打印方案
8.1 二维码内容
- 二维码本质为一个带 batchId 的溯源访问链接
- 推荐格式:
/trace/{batchId}(可扩展 source、campaign 参数)
- 若区分入口来源,可扩展参数:
- source:来源渠道(如 packaging / douyin / wechat / service)
- campaign:活动标识(可选)
第一阶段二维码承载的信息原则
- 二维码本身只承载访问入口,不直接写入完整业务数据
- 实际展示内容通过 batchId 在后台查询获取
- 所有前端展示内容均通过批次数据统一返回
二维码关联的前端展示内容
扫码后进入溯源页,页面展示内容包括:
- 商品信息
- 农场信息
- 批次信息
- 检测报告
- 合格证
- 溯源说明
二维码生成规则
- 每个批次生成唯一二维码
- 未发布批次不可生成正式可用二维码
- 批次下线后,扫码应提示“该批次已下线”或“暂不可查询”
8.2 打印方案
- 打印机:热敏标签打印机
- 标签尺寸:40×30mm(推荐)
- 文件格式:PDF
- 打印方式:人工触发
- 标签打印内容建议与溯源页保持一致性(至少包含商品名与批次号)
- 标签需包含用户可读信息(如商品名称 + 溯源提示语),避免仅二维码导致用户无法理解用途
- 二维码尺寸需保证可扫码识别
- 生成的PDF需固定尺寸,避免打印缩放导致二维码失效
- 首期采用“后台生成PDF + 人工触发打印”的轻方案
9. 接口清单(第一阶段)
本章节仅作为接口总览,详细接口定义及返回结构详见第 14 章。
前端核心接口:
- 获取溯源详情接口(/api/trace/{batchId})
后台接口分类:
- 批次管理
- 检测报告管理
- 合格证管理
- 二维码生成
- 标签打印
10. 验收标准
- 能创建批次
- 能上传检测报告
- 能上传合格证
- 能生成二维码
- 扫码可打开溯源页
- 页面显示真实数据
- 页面展示结构完整(商品 / 农场 / 批次 / 检测报告 / 合格证)
- 报告与合格证支持预览或查看原件
- 页面空状态与异常状态展示正常
- 标签可打印
- 打印二维码可扫码
11. 开发排期建议
第1-2天
第3-5天
第6-7天
第8-10天
12. 总体原则
- 批次为核心数据模型
- 前端只展示,不维护数据
- 优先保证“能用”
- 不追求复杂功能
- 先跑通,再优化
13. 数据库设计(第一阶段)
13.1 批次表(batch)
字段:
- id(主键)
- batch_no(批次号,唯一)
- product_name(商品名称)
- product_spec(商品规格)
- product_image(商品图片URL)
- product_desc(商品简介,可选)
- farm_name(农场名称)
- farm_region(农场所在地)
- farm_image(农场图片URL)
- farm_intro(农场简介,可选)
- produce_date(生产/采收日期)
- package_date(包装日期)
- status(状态:draft/published/offline)
- created_at
- updated_at
约束:
- batch_no 唯一
- status 仅允许:draft/published/offline
13.2 检测报告表(report)
字段:
- id(主键)
- batch_id(关联批次)
- report_status(状态:uploaded/pending)
- report_files(JSON数组,文件URL列表)
- report_no(报告编号,必填)
- report_date(检测日期,必填)
- created_at
约束:
- batch_id 唯一(第一阶段每批次仅一条报告)
13.3 合格证表(certificate)
字段:
- id(主键)
- batch_id(关联批次)
- cert_status(状态:uploaded/pending)
- cert_files(JSON数组,文件URL列表)
- cert_no(合格证编号,必填)
- cert_issue_date(开具日期,必填)
- created_at
约束:
- batch_id 唯一(第一阶段每批次仅一张合格证)
14. 接口设计(第一阶段)
14.1 前端溯源接口(核心)
GET /api/trace/{batchId}
返回示例:
{
"batch": {
"batchNo": "B20250101",
"productName": "有机鸡蛋",
"productSpec": "30枚",
"productImage": "https://example.com/product.jpg",
"productDesc": "新鲜鸡蛋,适合家庭日常食用。",
"farmName": "阳光农场",
"farmRegion": "陕西西安",
"farmImage": "https://example.com/farm.jpg",
"farmIntro": "阳光农场位于西安周边,采用规范化种养管理。",
"produceDate": "2025-01-01",
"packageDate": "2025-01-02",
"status": "published"
},
"report": {
"reportStatus": "uploaded",
"reportFiles": ["https://example.com/report1.jpg"],
"reportDate": "2025-01-02",
"reportNo": "R20250102001"
},
"certificate": {
"certStatus": "uploaded",
"certFiles": ["https://example.com/cert1.jpg"],
"certIssueDate": "2025-01-02",
"certNo": "C20250102001"
}
}
说明:
- 前端所有展示数据统一通过该接口返回
- productDesc、farmIntro 为可选字段
- reportStatus、certStatus 表示“文件上传状态”,不是检测结果
- 前端需将 uploaded/pending 映射为“已上传/待补充”进行展示
14.2 后台接口
批次:
- POST /api/batch(创建)
- GET /api/batch/list(列表)
- GET /api/batch/{id}(详情)
- PUT /api/batch/{id}(编辑)
- POST /api/batch/{id}/publish(发布)
- POST /api/batch/{id}/offline(下线)
检测报告:
- POST /api/report/upload
- GET /api/report/{batchId}
合格证:
- POST /api/certificate/upload
- GET /api/certificate/{batchId}
二维码:
- GET /api/qrcode/{batchId}
打印:
15. 业务规则说明
15.1 批次规则
- 批次必须绑定商品与农场信息
- 批次创建后默认状态为 draft
- draft 状态不可生成二维码
- 只有 published 状态可扫码访问
- offline 状态扫码提示不可用
15.2 文件规则
- 每个批次多检测报告(支持多文件)
- 每个批次多个合格证(支持多文件)
- 支持 PDF 或多张图片上传
- 报告编号、检测日期为必填
- 合格证编号、开具日期为必填
- 支持覆盖上传(新文件覆盖旧文件)
15.3 二维码规则
- 每个批次生成唯一二维码
- 二维码内容为带 batchId 的溯源访问链接
- 可扩展 source / campaign 参数用于渠道区分
15.4 打印规则
- 标签必须包含二维码 + 商品名称 + 批次号
- 打印文件为固定尺寸 PDF
- 不允许缩放打印
15.5 页面展示规则
- 页面数据统一来源于批次接口
- 数据缺失需展示“待补充”
- 商品简介、农场简介为可选字段
- 报告/合格证状态由后端返回,前端根据状态展示
- reportStatus、certStatus 仅表示文件是否上传,不表示检测是否合格
16. HTTP 请求工具模块
16.1 模块概述
项目已集成企业级 HTTP 请求工具模块,提供统一的网络请求能力,支持 Web 和 uni-app 多端运行。
核心特性
- 基于 axios 封装,支持 uni-app 适配
- 统一的请求/响应拦截器
- 自动 Token 管理
- 统一错误处理
- 文件上传/下载支持
- 请求重试机制
- 防重复请求
- 多环境配置
16.2 目录结构
utils/
├── request.js # 核心请求模块(基于 axios)
├── uniRequest.js # uni-app 原生请求适配器(备选)
├── upload.js # 文件上传模块
├── download.js # 文件下载模块
├── retry.js # 请求重试模块
├── storage.js # 本地存储模块
├── ui.js # UI 交互模块
├── platform.js # 平台检测模块
├── env.js # 环境配置模块
├── index.js # 统一导出
├── README.md # 使用文档
└── ARCHITECTURE.md # 架构设计文档
api/
├── user.js # 用户相关 API
├── order.js # 订单相关 API
├── product.js # 产品相关 API
└── index.js # API 统一导出
16.3 快速使用
基础请求
import { getUserInfo, getOrderList } from '@/api'
export default {
async onLoad() {
// 获取用户信息
const userInfo = await getUserInfo()
// 获取订单列表
const orders = await getOrderList({ page: 1, size: 10 })
}
}
文件上传
import { chooseAndUploadImage } from '@/utils/upload'
const handleUpload = async () => {
const result = await chooseAndUploadImage({
count: 1,
onProgress: (progress) => {
console.log('上传进度:', progress + '%')
}
})
console.log('上传成功', result)
}
文件下载
import { downloadFile } from '@/utils/download'
const handleDownload = async () => {
await downloadFile('/file/download', '文件名.pdf')
}
16.4 配置说明
环境配置
修改 utils/env.js 配置不同环境的 API 地址:
const envConfig = {
development: {
baseURL: 'http://localhost:3000/api',
timeout: 10000
},
production: {
baseURL: 'https://api.example.com/api',
timeout: 20000
}
}
Token 配置
Token 会自动注入到请求头,格式为:
config.headers['Authorization'] = `Bearer ${token}`
如需修改格式,编辑 utils/request.js 中的请求拦截器。
白名单配置
不需要 Token 的接口添加到白名单:
const WHITE_LIST = [
'/auth/login',
'/auth/register',
'/auth/captcha'
]
16.5 API 层设计
按业务模块组织
// api/user.js
export const login = (data) => post('/auth/login', data)
export const getUserInfo = () => get('/user/info')
// api/order.js
export const getOrderList = (params) => get('/order/list', params)
export const createOrder = (data) => post('/order/create', data)
统一导出
// api/index.js
export * from './user'
export * from './order'
export * from './product'
16.6 错误处理
全局错误处理
已在 utils/request.js 中实现:
- HTTP 状态码错误(401、403、500 等)
- 业务错误码处理
- Token 过期自动跳转登录
- 网络错误处理
局部错误处理
try {
const data = await getUserInfo()
} catch (error) {
console.error('获取用户信息失败', error)
}
隐藏错误提示
const data = await getUserInfo({}, {
hideError: true // 不显示错误提示
})
16.7 高级功能
请求重试
import { createRetryRequest } from '@/utils/retry'
const getDataWithRetry = createRetryRequest(
() => get('/api/data'),
3 // 最大重试 3 次
)
并发请求
const [userInfo, orders, products] = await Promise.all([
getUserInfo(),
getOrderList({ page: 1 }),
getProductList({ page: 1 })
])
请求取消
import axios from 'axios'
const source = axios.CancelToken.source()
get('/api/data', {}, {
cancelToken: source.token
})
// 取消请求
source.cancel('请求被用户取消')
16.8 配置项说明
所有请求方法都支持以下配置:
{
showLoading: true, // 是否显示 loading
loadingText: '加载中...', // loading 文字
hideError: false, // 是否隐藏错误提示
preventDuplicate: false, // 是否防止重复请求
noCache: false, // 是否添加时间戳防缓存
timeout: 10000, // 超时时间
headers: {} // 自定义请求头
}
16.9 详细文档
更多详细信息请参考:
utils/README.md - 完整使用文档
utils/ARCHITECTURE.md - 架构设计文档
utils/examples/INSTALL.md - 安装配置指南
utils/examples/ - 示例代码
16.10 注意事项
- 首次使用前需配置
utils/env.js 中的 baseURL
- 根据后端返回格式调整
utils/request.js 中的业务状态码
- 根据后端 Token 格式调整请求拦截器中的 Token 注入方式
- 小程序环境需在管理后台配置服务器域名白名单
- 所有 API 接口建议统一在
api/ 目录下管理,不要在组件中直接调用 request