8.8 KiB
H5 材料浏览端 设计文档
- 日期:2026-04-24
- 作者:caoqianming
- 状态:草案
1 · 背景与目标
在现有 mat3 项目(PC 端材料管理 + Django 后端)基础上,新增面向手机浏览器的 H5 材料查看端。 核心诉求:只读浏览——登录后按 "大类 → 种类 → 子类 → 材料 → 详情" 的层级快速找到材料并查看详细信息。 不包含新增 / 编辑 / 导入 / 审批等写操作。
2 · 项目结构与技术栈
2.1 组织方式
新建独立项目 frontend-h5/,与现有 frontend/ 平级;独立 Vite、独立依赖、独立打包。
frontend-h5/
├── index.html
├── vite.config.js # base: '/m/',dev proxy → 后端
├── package.json
├── tailwind.config.js
├── postcss.config.js
└── src/
├── main.js
├── App.vue
├── router/ # vue-router 4,history 模式
├── store/ # pinia
├── api/ # 参照 frontend/src/api 复制同名文件,保持一致
├── composables/ # useAuth / useInfiniteScroll / useToast ...
├── styles/ # tailwind.css、全局变量
├── components/ # MaterialCard / CategoryCard / StarLevel / Chip / NavBar / Toast ...
└── views/
├── Login.vue
├── Home.vue
├── CategoryDetail.vue
└── MaterialDetail.vue
2.2 技术栈
- Vue 3 + vue-router 4 + Pinia
- Axios(同 PC 端一致的拦截器:附 token、统一错误处理、401 跳登录)
- Tailwind CSS(自定义设计令牌),不使用 Vant/NutUI
- 少量自研组件(Toast、NavBar、Tab、InfiniteList、StarLevel、Chip、Skeleton)
2.3 部署
- 构建产物部署到 Nginx 子路径
/m/(与 PC 端同域名) vite.config.js设base: '/m/'- 开发期
vitedevServer 走本地端口(如 5174),通过server.proxy把/api转发到后端
2.4 登录态
localStorage存 token,key 为h5_token(与 PC 端token隔离,避免互相污染)- Pinia
authStore暴露token/user/login()/logout() - Axios request 拦截器:存在
h5_token则附Authorization - Axios response 拦截器:401 清 token 并跳
/login?redirect=<current>
3 · 路由与页面流
| 路径 | 页面 | 说明 |
|---|---|---|
/login |
Login | 账号密码登录 |
/ |
Home | 大类卡片 + 选中后展开种类区 |
/category/:major/:category |
CategoryDetail | 子类 Tab + 材料列表 |
/material/:id |
MaterialDetail | 材料详情(三块) |
路由守卫:非 /login 页进入前校验 token;无 token → 跳 /login?redirect=<原路径>;登录成功后回跳。
过渡:页面切换用右推左 slide + fade CSS 过渡。
状态保留:
- Pinia
uiStore记录 Home 选中的大类、CategoryDetail 选中的子类 Tab、列表滚动位置 - 从详情返回时恢复选中态和滚动位置
- 使用
<keep-alive>缓存 Home 与 CategoryDetail
4 · 数据接口
4.1 复用现有接口
| 用途 | 接口 |
|---|---|
| 登录 | POST /auth/login/ |
| 当前用户 | GET /auth/user/ |
| 材料列表 | GET /material/?major_category=&material_category=&material_subcategory=&search=&page=&page_size= |
| 材料详情 | GET /material/{id}/ |
| 选项字典 | GET /material/choices/ |
4.2 新增接口
由于 MaterialCategory 与 Material.major_category 没有 FK 关系,"大类下的种类""种类下的子类" 需要从 Material 表按大类 distinct 计算。两个新接口都作为 MaterialViewSet 的 @action 提供。
接口 1:GET /material/categories-by-major/?major_category=architecture
- 从
Material表取major_category=X的记录,按material_category分组 count - 响应:
[ { "value": "地砖", "count": 12 }, { "value": "涂料", "count": 8 } ]
接口 2:GET /material/subcategories-by-category/?major_category=&material_category=
- 同上,按
material_subcategory分组 count,过滤空值 - 响应:
[ { "value": "釉面砖", "count": 5 }, { "value": "通体砖", "count": 3 } ]
"全部"分类不从后端返回,由前端在 Tab 第一项注入,点击时不传 material_subcategory 参数。
4.3 列表卡片使用字段
name(材料名称)cost_compare(成本对比,百分数,负数表示更便宜)advantage_display(竞争优势,取前 2 个 chip 显示)importance_level(重要等级 chip)score_level(综合评分,1-3 星)factory_short_name(供应商简称)
4.4 分页与加载
page_size = 20- 列表支持下拉刷新 + 上拉无限加载(基于 IntersectionObserver 的
useInfiniteScroll)
5 · 视觉与交互设计
5.1 设计语言
克制的卡片式 · 暖中性色 + 墨绿品牌色
- 背景:白
#FFFFFF+ 极浅灰分层#FAFAFA/#F5F4F2 - 主色:
#2F4F3F(墨绿),用于按钮、重点数值、选中态 - 辅助色:红
#D2584A(核心)、蓝#5A7FB8(优先)、灰#8A8A8A(一般) - 卡片圆角
16-20px;阴影0 1px 2px rgba(0,0,0,.04);不用重描边 - 字体:系统栈 (
-apple-system, "PingFang SC", ...);数值字段启用font-feature-settings: "tnum"等宽 - 点按反馈:
active:scale-[0.98]+ 背景变深
以上颜色 / 圆角 / 间距在 tailwind.config.js 定义为 theme tokens,后续组件直接用工具类。
5.2 关键页面
Login
- 上 60% 留白 + 品牌标识
- 下 40% 表单:用户名、密码、提交按钮
- 失败信息由 Toast 从顶部下滑显示,2s 自动消失
Home
- 顶部栏:欢迎语 + 用户名 + 退出图标
- 主体:2×2 大类卡片网格(建筑/景观/设备/装修),每卡显示大类名 + 材料总数
- 选中大类后在下方 slide-down + fade 出现种类卡片区(2 列网格,卡带材料数角标)
- 未选中时下方显示引导文案
- 选中的大类 ID 写入
uiStore,从详情返回恢复展开状态
CategoryDetail
- 顶部 NavBar:返回按钮 + 种类名标题
- 吸顶的子类 Tab 栏(横向滚动,"全部" 为第一项,选中下划线 + 文字加重)
- 材料卡列表:通栏,左信息区(名称 / 供应商 / 优势 chip)+ 右数值区(成本 / 评分 / 重要等级)
- 下拉刷新、上拉无限加载
- 空态:图标 + "暂无材料"
MaterialDetail
-
顶部 NavBar
-
可选顶部 banner:
brochure宣传图(16:9,懒加载,点击可全屏预览) -
三个 section,每个 section 是一张圆角卡:
- 材料信息:基础 / 应用 / 优势 / 成本 / 评分,
grid-cols-[auto_1fr]标签值布局;竞争优势、应用场景、重要等级、替代类型用 chip;4 项等级用星级可视化。长文本(优势说明、成本说明、应用说明)独立成段。 - 品牌与供应商:品牌、供应商简称/全称、合作模式、省-市、对接人、对接人联系方式。电话字段带
tel:链接可一键拨打。 - 案例信息:落地项目、案例(保留换行)、经办人、备注。
- 材料信息:基础 / 应用 / 优势 / 成本 / 评分,
5.3 通用交互
- Loading:顶部 NProgress 细线进度条;列表用骨架屏
- 错误:非 401 错误 Toast 提示;页面级错误态带"重试"按钮
- 401:清 token + 跳登录
6 · 后端改动清单
apps/material/views.py
MaterialViewSet新增两个@action(detail=False, methods=['get']):categories_by_majorsubcategories_by_category
- 两者权限与现有列表一致(登录用户可访问)
- 考虑给
material_category/material_subcategory字段的"查询计数"加缓存(低优,后续再说)
无 model migration。
7 · 验收标准
- 手机浏览器(iOS Safari / 微信内置 / Android Chrome)访问
/m/,可完成 登录 → 大类 → 种类 → 子类 → 材料详情 的完整浏览 - 详情页三块布局、字段映射与本文档 §5.2 一致
- 从详情返回上级页面,滚动位置与选中 Tab 保持
- 401 时自动跳登录且登录后回跳原路径
- 包体积:首屏 gzip 后 < 150 KB(不含首图)
- 单手可达性:关键按钮在屏幕下半区
- PC 端
/功能不受影响
8 · 非目标
- 新增、编辑、导入、导出、审批
- 离线缓存 / PWA
- 多语言
- 手机号验证码登录(后续视需要再开 Spec)
9 · 风险与开放项
- 微信内置浏览器差异:目前未要求适配微信分享/JSSDK,仅确保页面能正常打开
- H5 与 PC 登录态隔离:使用不同 localStorage key,后端 token 为同一份 JWT,无服务端改动成本
- 种类 distinct 性能:当前数据量小可直接 SQL
GROUP BY;后续若过万条可再加索引或 Redis 缓存 - 视觉最终稿:本文档只定方向,具体 mockup 由后续
frontend-design技能产出