docs: record mobile-h5 Vant UI design, plan, and demo

Link the workspace UI demo and implementation plan from the
miniprogram UI spec for the unified mobile workbench.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-10 14:03:36 +08:00
1 parent 8793fa07cc
commit 031e456614
4 files changed
+4807 -1

No files matched your search

+11 -1
View File
@@ -1,6 +1,6 @@
# 小程序端 UI 规范(中科兴皖一体化门户)
> **适用范围**:`miniprogram`(客户端 / 供应商端 / 配送员端)
> **适用范围**:`miniprogram`(客户端 / 供应商端 / 配送员端)与 **`mobile-h5`(统一工作台)**
> **设计基准文件(Demo)**:
> - `mobile-ui/sanqiang-client-ui-demo.html`
> - `mobile-ui/sanqiang-client-cart-ui-demo.html`
@@ -8,6 +8,16 @@
> - `mobile-ui/sanqiang-client-profile-ui-demo.html`
> - `mobile-ui/sanqiang-supplier-ui-demo.html`
> - `mobile-ui/sanqiang-deliverer-ui-demo.html`
> - **工作台**:`mobile-ui/zkxw-mobile-vant-ui-demo.html`
## 移动工作台(mobile-h5)
- 工程:`mobile-h5`(HBuilderX uni-app Vue3 + `@vant/weapp`)
- 视觉 Demo:`mobile-ui/zkxw-mobile-vant-ui-demo.html`
- 设计说明:`docs/superpowers/specs/2026-08-10-mobile-h5-vant-ui-design.md`
- 实现计划:`docs/superpowers/plans/2026-08-10-mobile-h5-vant-ui.md`
- 信息架构:单一工作台 + 权限菜单卡片(上 Icon 下标题);样板页见 `mobile-h5/pages/demo/*`
- Token:仍遵循本文 §2 三墙色板;**禁止**使用 web-admin `#10b981`
---
@@ -0,0 +1,807 @@
# mobile-h5 Vant UI 骨架 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在保留 HBuilderX uni-app 骨架的前提下,接入 `@vant/weapp`、落地三墙 Token 与全局样式层,并实现首页工作台 + 列表/详情/表单样板页,供后续业务页复制适配。
**Architecture:** 视觉以 `mobile-ui/zkxw-mobile-vant-ui-demo.html` 为准;`styles/tokens.scss` 为唯一色板源,经 `vant-theme.scss` + `app.scss` + `styles/components/*` 注入 `App.vue`;交互控件用 `@vant/weapp`(easycom),业务壳(菜单宫格、列表卡、附件、流转)用自研 Vue 组件。本期菜单权限用 mock,不接真实 API。
**Tech Stack:** uni-app Vue3(HBuilderX)、`@vant/weapp`、SCSS、微信小程序发行
**Spec:** `docs/superpowers/specs/2026-08-10-mobile-h5-vant-ui-design.md`
---
## File map(将创建 / 修改)
| 路径 | 职责 |
|------|------|
| `mobile-h5/package.json` | npm 依赖(`@vant/weapp`) |
| `mobile-h5/pages.json` | easycom、页面路由、globalStyle |
| `mobile-h5/uni.scss` | 覆盖 uni 默认主色为三墙绿;import tokens |
| `mobile-h5/App.vue` | 全局样式入口 |
| `mobile-h5/styles/tokens.scss` | SCSS + CSS 变量 Token |
| `mobile-h5/styles/vant-theme.scss` | Vant CSS 变量覆盖 |
| `mobile-h5/styles/mixins.scss` | Hero / 卡片 mixin |
| `mobile-h5/styles/app.scss` | page 背景、工具类 |
| `mobile-h5/styles/components/*.scss` | menu-grid / todo / list / detail / attach / flow / form-shell |
| `mobile-h5/utils/menu-mock.js` | 移动端菜单 mock + 权限过滤 |
| `mobile-h5/utils/biz-mock.js` | 列表/详情样板 mock 数据 |
| `mobile-h5/components/MenuGrid.vue` | 上 Icon 下标题宫格 |
| `mobile-h5/components/TodoPanel.vue` | 待办统计 + 条目 |
| `mobile-h5/components/BizListCard.vue` | 列表业务卡 |
| `mobile-h5/components/AttachList.vue` | 附件上传条 + 文件卡 |
| `mobile-h5/components/FlowTimeline.vue` | 流转记录 |
| `mobile-h5/pages/index/index.vue` | 首页工作台 |
| `mobile-h5/pages/demo/list.vue` | 列表样板 |
| `mobile-h5/pages/demo/detail.vue` | 详情样板 |
| `mobile-h5/pages/demo/form.vue` | 表单样板 |
| `mobile-h5/pages/demo/comps.vue` | 组件合集样板 |
| `docs/miniprogram-ui-spec-sanqiang.md` | 增加「移动工作台」指向 |
**不修改:** `main.js`、`manifest.json` 核心结构(仅后续填 appid 时改 `mp-weixin.appid`,本期可不改)、`index.html`。
---
### Task 1: 初始化 npm 并安装 `@vant/weapp`
**Files:**
- Create: `mobile-h5/package.json`
- Create/Update: `mobile-h5/.gitignore`(确保含 `node_modules/`)
- [ ] **Step 1: 写入 package.json**
```json
{
"name": "mobile-h5",
"version": "1.0.0",
"private": true,
"description": "zkxw mobile uni-app (HBuilderX) + Vant Weapp",
"dependencies": {
"@vant/weapp": "^1.11.7"
}
}
```
- [ ] **Step 2: 安装依赖**
Run(在 `mobile-h5` 目录):
```bash
cd /Users/wuzilong/work/00code/zkxw/mobile-h5 && npm install
```
Expected: 生成 `node_modules/@vant/weapp`,无报错。
- [ ] **Step 3: 确认 easycom 实际组件路径**
Run:
```bash
ls /Users/wuzilong/work/00code/zkxw/mobile-h5/node_modules/@vant/weapp/button
```
Expected: 存在 `index.js` / `index.wxml` 等。后续 `pages.json` 使用路径 `@vant/weapp/button/index`(无 `dist` 前缀)。若本机在 `dist/` 下,则改用 `@vant/weapp/dist/button/index`。
- [ ] **Step 4: Commit**
```bash
cd /Users/wuzilong/work/00code/zkxw
git add mobile-h5/package.json mobile-h5/package-lock.json mobile-h5/.gitignore
git commit -m "$(cat <<'EOF'
chore(mobile-h5): add package.json and @vant/weapp dependency
EOF
)"
```
---
### Task 2: 配置 pages.json(easycom + 路由 + 全局导航色)
**Files:**
- Modify: `mobile-h5/pages.json`
- [ ] **Step 1: 替换为以下完整内容**(路径以 Task 1 实测为准;默认无 dist)
```json
{
"easycom": {
"autoscan": true,
"custom": {
"^van-(.*)": "@vant/weapp/$1/index"
}
},
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "工作台"
}
},
{
"path": "pages/demo/list",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "业务列表"
}
},
{
"path": "pages/demo/detail",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "业务详情"
}
},
{
"path": "pages/demo/form",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "编辑业务"
}
},
{
"path": "pages/demo/comps",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "组件风格"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "中科兴皖",
"navigationBarBackgroundColor": "#0a9f6d",
"backgroundColor": "#f5f8f7"
},
"uniIdRouter": {}
}
```
- [ ] **Step 2: 校验 JSON 合法**
Run:
```bash
node -e "JSON.parse(require('fs').readFileSync('mobile-h5/pages.json','utf8')); console.log('ok')"
```
Expected: `ok`
- [ ] **Step 3: Commit**
```bash
git add mobile-h5/pages.json
git commit -m "$(cat <<'EOF'
chore(mobile-h5): configure Vant easycom and demo page routes
EOF
)"
```
---
### Task 3: Token + uni.scss + 全局样式入口
**Files:**
- Create: `mobile-h5/styles/tokens.scss`
- Create: `mobile-h5/styles/vant-theme.scss`
- Create: `mobile-h5/styles/mixins.scss`
- Create: `mobile-h5/styles/app.scss`
- Modify: `mobile-h5/uni.scss`
- Modify: `mobile-h5/App.vue`
- [ ] **Step 1: 创建 `styles/tokens.scss`**
```scss
// 唯一 Token 源 — 对齐三墙 / Demo,禁止 #10b981
$brand-green: #0a9f6d;
$brand-green-dark: #087f57;
$brand-green-soft: #e9f9f2;
$barley-yellow: #d6a343;
$barley-yellow-soft: #fff7e8;
$bg-page: #f5f8f7;
$surface: #ffffff;
$text-primary: #1f2a26;
$text-muted: #6b7b74;
$border: #dcebe4;
$danger: #d14343;
$warning: #cf8a19;
$success: #189b65;
$radius-card: 28rpx;
$radius-lg: 40rpx;
@mixin token-css-vars {
--brand-green: #{$brand-green};
--brand-green-dark: #{$brand-green-dark};
--brand-green-soft: #{$brand-green-soft};
--barley-yellow: #{$barley-yellow};
--barley-yellow-soft: #{$barley-yellow-soft};
--bg-page: #{$bg-page};
--surface: #{$surface};
--text-primary: #{$text-primary};
--text-muted: #{$text-muted};
--border: #{$border};
--danger: #{$danger};
--warning: #{$warning};
--success: #{$success};
--radius-card: #{$radius-card};
--radius-lg: #{$radius-lg};
--shadow-soft: 0 8rpx 32rpx rgba(8, 127, 87, 0.08);
}
```
- [ ] **Step 2: 创建 `styles/vant-theme.scss`**
```scss
page {
--button-primary-background-color: #0a9f6d;
--button-primary-border-color: #0a9f6d;
--button-primary-color: #ffffff;
--nav-bar-background-color: transparent;
--nav-bar-title-text-color: #ffffff;
--nav-bar-icon-color: #ffffff;
--tabs-bottom-bar-color: #0a9f6d;
--tag-primary-color: #0a9f6d;
--tag-success-color: #189b65;
--tag-danger-color: #d14343;
--tag-warning-color: #cf8a19;
--steps-active-color: #0a9f6d;
--notice-bar-background-color: #e9f9f2;
--notice-bar-text-color: #087f57;
}
```
> `@vant/weapp` 部分主题通过组件 `color` / `custom-class` 传入;CSS 变量名以当前 weapp 版本文档为准,落地时对照 `node_modules/@vant/weapp` README 微调。
- [ ] **Step 3: 创建 `styles/mixins.scss`**
```scss
@mixin hero-green {
background: linear-gradient(155deg, #066647 0%, #0a9f6d 48%, #12b37a 100%);
color: #ffffff;
border-radius: 0 0 56rpx 56rpx;
position: relative;
overflow: hidden;
}
@mixin surface-card {
background: var(--surface, #ffffff);
border: 1rpx solid var(--border, #dcebe4);
border-radius: var(--radius-card, 28rpx);
box-shadow: var(--shadow-soft);
}
```
- [ ] **Step 4: 创建 `styles/app.scss`**
```scss
@import './tokens.scss';
page {
@include token-css-vars;
background-color: var(--bg-page);
color: var(--text-primary);
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif;
font-size: 28rpx;
line-height: 1.5;
box-sizing: border-box;
}
view, text {
box-sizing: border-box;
}
.page-shell {
min-height: 100vh;
background:
radial-gradient(840rpx 440rpx at 100% 0%, rgba(214, 163, 67, 0.14), transparent 55%),
radial-gradient(760rpx 400rpx at 0% 20%, rgba(10, 159, 109, 0.1), transparent 50%),
linear-gradient(180deg, #e8f5ef 0%, #f4f7f6 40%, #f7f9f8 100%);
}
.safe-bottom {
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
}
```
- [ ] **Step 5: 修改 `uni.scss` 顶部主色**
将文件中:
```scss
$uni-color-primary: #007aff;
```
改为:
```scss
@import './styles/tokens.scss';
$uni-color-primary: $brand-green;
$uni-color-success: $success;
$uni-color-warning: $warning;
$uni-color-error: $danger;
```
(保留其余 uni 默认变量,仅覆盖行为色。)
- [ ] **Step 6: 修改 `App.vue`**
```vue
<script>
export default {
onLaunch() {
console.log('App Launch')
},
onShow() {
console.log('App Show')
},
onHide() {
console.log('App Hide')
}
}
</script>
<style lang="scss">
@import './styles/vant-theme.scss';
@import './styles/app.scss';
@import './styles/components/menu-grid.scss';
@import './styles/components/todo.scss';
@import './styles/components/list.scss';
@import './styles/components/detail.scss';
@import './styles/components/attach.scss';
@import './styles/components/flow.scss';
@import './styles/components/form-shell.scss';
</style>
```
> Task 3 提交前,Task 4 需先创建空的 `styles/components/*.scss`(可先写文件头注释),避免 App 编译找不到 import。
- [ ] **Step 7: 校验 Token 色值存在**
Run:
```bash
grep -n '#0a9f6d' mobile-h5/styles/tokens.scss && ! grep -n '#10b981' mobile-h5/styles/tokens.scss
```
Expected: 命中 `#0a9f6d`;无 `#10b981`。
- [ ] **Step 8: Commit**
```bash
git add mobile-h5/styles mobile-h5/uni.scss mobile-h5/App.vue
git commit -m "$(cat <<'EOF'
feat(mobile-h5): add design tokens and global style entry
EOF
)"
```
---
### Task 4: 拆分组件级 SCSS(从 Demo 迁移关键类)
**Files:**
- Create: `mobile-h5/styles/components/menu-grid.scss`
- Create: `mobile-h5/styles/components/todo.scss`
- Create: `mobile-h5/styles/components/list.scss`
- Create: `mobile-h5/styles/components/detail.scss`
- Create: `mobile-h5/styles/components/attach.scss`
- Create: `mobile-h5/styles/components/flow.scss`
- Create: `mobile-h5/styles/components/form-shell.scss`
**权威对照:** `mobile-ui/zkxw-mobile-vant-ui-demo.html` 中对应 CSS 块;实现时将 `px` 按 `×2 → rpx` 换算,类名保持与 Demo 一致(`.menu-grid`、`.biz-card`、`.detail-hero`、`.d-attach-*`、`.flow-*` 等)。
- [ ] **Step 1: 创建七个 scss 文件**
每个文件至少包含 `@import '../mixins.scss';`(若需要)及从 Demo 迁移的对应区块。最低要求类名:
| 文件 | 必须包含的类 |
|------|----------------|
| `menu-grid.scss` | `.menu-grid` `.menu-card` `.menu-icon` `.menu-title` |
| `todo.scss` | `.todo-panel` `.todo-stats` `.todo-stat` `.todo-list` `.todo-item` |
| `list.scss` | `.list-hero` `.list-filter-dock` `.seg-tabs` `.biz-card` `.status-warning/primary/danger/success` |
| `detail.scss` | `.detail-page` `.detail-hero` `.detail-metric-dock` `.detail-section` `.detail-footer` |
| `attach.scss` | `.d-attach-list` `.d-attach-upload` `.d-attach-card` `.ft-pdf/.ft-img/.ft-xls/.ft-doc` |
| `flow.scss` | `.flow-list` `.flow-item` `.flow-dot` `.flow-card` |
| `form-shell.scss` | `.form-page` `.form-section-title` `.form-footer` |
具体属性从 Demo 拷贝并做 rpx 换算;渐变与色值使用 `var(--brand-green)` 等 CSS 变量。
- [ ] **Step 2: 静态检查类名是否齐全**
Run:
```bash
for f in menu-grid todo list detail attach flow form-shell; do
test -f "mobile-h5/styles/components/$f.scss" || exit 1
done
grep -q 'menu-grid' mobile-h5/styles/components/menu-grid.scss
grep -q 'biz-card' mobile-h5/styles/components/list.scss
grep -q 'd-attach-upload' mobile-h5/styles/components/attach.scss
grep -q 'flow-list' mobile-h5/styles/components/flow.scss
echo 'scss ok'
```
Expected: `scss ok`
- [ ] **Step 3: Commit**
```bash
git add mobile-h5/styles/components
git commit -m "$(cat <<'EOF'
feat(mobile-h5): add page-pattern SCSS modules from UI demo
EOF
)"
```
---
### Task 5: Mock 数据工具
**Files:**
- Create: `mobile-h5/utils/menu-mock.js`
- Create: `mobile-h5/utils/biz-mock.js`
- [ ] **Step 1: 写入 `menu-mock.js`**
```js
/** 模拟「菜单管理 → 移动端菜单」授权结果 */
export const ALL_MOBILE_MENUS = [
{ id: 'm1', title: '待办审批', icon: 'todo-list-o', path: '/pages/demo/list' },
{ id: 'm2', title: '采集协议', icon: 'orders-o', path: '/pages/demo/list' },
{ id: 'm3', title: '缴费确认', icon: 'balance-list-o', path: '/pages/demo/list' },
{ id: 'm4', title: '样本接收', icon: 'logistics', path: '/pages/demo/list' },
{ id: 'm5', title: '质检工单', icon: 'certificate', path: '/pages/demo/list' },
{ id: 'm6', title: '生产任务', icon: 'cluster-o', path: '/pages/demo/list' },
{ id: 'm7', title: '库位出库', icon: 'send-gift-o', path: '/pages/demo/list' },
{ id: 'm8', title: '组件示例', icon: 'apps-o', path: '/pages/demo/comps' }
]
/** @param {string[]} grantedIds 当前用户拥有的菜单 id */
export function filterMenusByPermission(grantedIds) {
const set = new Set(grantedIds || [])
return ALL_MOBILE_MENUS.filter((m) => set.has(m.id))
}
export const DEFAULT_GRANTED_IDS = ['m1', 'm2', 'm3', 'm4', 'm5', 'm7', 'm8']
```
- [ ] **Step 2: 写入 `biz-mock.js`**
从 Demo 的 `listData` 迁移 4 条样板(含 `attachments`、`logs`、`payments`、`steps`、`stepActive`、`tagType`、`amount`/`progress` 等字段),并导出:
```js
export function getList() { /* return listData */ }
export function getById(id) { /* find or listData[0] */ }
export function filterByTab(tabIndex, keyword) { /* 与 Demo filteredList 逻辑一致 */ }
```
- [ ] **Step 3: 快速自测过滤逻辑**
Run:
```bash
cd mobile-h5 && node --input-type=module -e "
import { filterMenusByPermission, DEFAULT_GRANTED_IDS, ALL_MOBILE_MENUS } from './utils/menu-mock.js'
const v = filterMenusByPermission(DEFAULT_GRANTED_IDS)
console.log(v.length, ALL_MOBILE_MENUS.length)
if (v.length !== 7) process.exit(1)
"
```
Expected: 打印 `7 8`,exit 0。
> 若 HBuilderX/微信环境不支持 node ESM,可将文件改为无 `export` 的 CommonJS `module.exports`,或用 `uni` 内仅引用、本步改为人工阅读断言。优先保持 `export`,与 Vue3 script 一致。
- [ ] **Step 4: Commit**
```bash
git add mobile-h5/utils
git commit -m "$(cat <<'EOF'
feat(mobile-h5): add menu and biz mock helpers
EOF
)"
```
---
### Task 6: 公共组件 MenuGrid + TodoPanel
**Files:**
- Create: `mobile-h5/components/MenuGrid.vue`
- Create: `mobile-h5/components/TodoPanel.vue`
- [ ] **Step 1: 创建 `MenuGrid.vue`**
Props: `menus: Array<{ id, title, icon, path }>`
Events: `select(menu)`
模板结构:
```vue
<template>
<view class="menu-grid">
<view
v-for="m in menus"
:key="m.id"
class="menu-card"
@click="$emit('select', m)"
>
<view class="menu-icon">
<van-icon :name="m.icon" />
</view>
<text class="menu-title">{{ m.title }}</text>
</view>
</view>
</template>
<script>
export default {
name: 'MenuGrid',
props: {
menus: { type: Array, default: () => [] }
},
emits: ['select']
}
</script>
```
- [ ] **Step 2: 创建 `TodoPanel.vue`**
Props: `stats: { approve, pay, alert }`,`items: Array`
Events: `stat-click(key)`,`item-click(item)`,`more`
结构对齐 Demo:三列 `.todo-stat` + `.todo-item` 列表;样式依赖全局 `todo.scss`。
- [ ] **Step 3: Commit**
```bash
git add mobile-h5/components/MenuGrid.vue mobile-h5/components/TodoPanel.vue
git commit -m "$(cat <<'EOF'
feat(mobile-h5): add MenuGrid and TodoPanel components
EOF
)"
```
---
### Task 7: 公共组件 BizListCard + AttachList + FlowTimeline
**Files:**
- Create: `mobile-h5/components/BizListCard.vue`
- Create: `mobile-h5/components/AttachList.vue`
- Create: `mobile-h5/components/FlowTimeline.vue`
- [ ] **Step 1: `BizListCard.vue`**
Props: `item`(含 `title, code, typeLabel, icon, status, tagType, desc, owner, time, amount, progress, hint`)
Events: `view`、`action`
根节点:`<view class="biz-card" :class="'status-' + item.tagType">`,结构对齐 Demo 列表卡。
- [ ] **Step 2: `AttachList.vue`**
Props: `files: Array<{ name, size?, time? }>`
Events: `upload`、`preview`、`download`
内置 `fileExt` / `fileTypeClass` 方法(从 Demo 迁移)。下载按钮使用 Demo 定稿的 SVG(箭头+托盘)。
- [ ] **Step 3: `FlowTimeline.vue`**
Props: `logs: Array<{ title, desc, time, tone, actor?, icon?, badge? }>`
根节点 `.flow-list`,子项 `.flow-item`。
- [ ] **Step 4: Commit**
```bash
git add mobile-h5/components/BizListCard.vue mobile-h5/components/AttachList.vue mobile-h5/components/FlowTimeline.vue
git commit -m "$(cat <<'EOF'
feat(mobile-h5): add BizListCard, AttachList, and FlowTimeline
EOF
)"
```
---
### Task 8: 首页工作台 `pages/index/index.vue`
**Files:**
- Modify: `mobile-h5/pages/index/index.vue`
- [ ] **Step 1: 实现首页**
要点:
1. 自定义绿渐变 Header(用户名 / 角色 / 部门 mock)。
2. `MenuGrid`:`filterMenusByPermission(DEFAULT_GRANTED_IDS)`。
3. `TodoPanel`:点统计或条目 → `uni.navigateTo({ url: '/pages/demo/list' })`。
4. 菜单 `select`:有 `path` 则 `navigateTo`。
5. 样式用已有全局类;页面根 `class="page-shell"` 可选(首页也可用纯白底 + header,对齐 Demo)。
- [ ] **Step 2: HBuilderX 运行到微信开发者工具**
手动验收:
- 首页可见菜单宫格(默认 7 项,无「生产任务」)。
- 点击「组件示例」进入 comps(若尚未实现 comps,可暂指向 list)。
- 主色为绿色,无系统默认蓝。
- [ ] **Step 3: Commit**
```bash
git add mobile-h5/pages/index/index.vue
git commit -m "$(cat <<'EOF'
feat(mobile-h5): implement permission-filtered home workspace
EOF
)"
```
---
### Task 9: 列表样板页
**Files:**
- Create: `mobile-h5/pages/demo/list.vue`
- [ ] **Step 1: 实现列表页**
结构:`.list-hero`(返回 + 标题 + `van-search`)→ `.list-filter-dock` 四格 seg → `BizListCard` 列表。
数据:`biz-mock.filterByTab`。
「查看」→ `/pages/demo/detail?id=`;「处理」→ `/pages/demo/form?mode=edit&id=`;右上角加号 → form create。
返回:`uni.navigateBack` 或 `reLaunch` 到首页。
- [ ] **Step 2: 手动验收**
- 分段切换条数变化。
- 搜索过滤标题/单号。
- 卡片状态色与 Demo 一致。
- [ ] **Step 3: Commit**
```bash
git add mobile-h5/pages/demo/list.vue
git commit -m "$(cat <<'EOF'
feat(mobile-h5): add demo business list page
EOF
)"
```
---
### Task 10: 详情 + 表单样板页
**Files:**
- Create: `mobile-h5/pages/demo/detail.vue`
- Create: `mobile-h5/pages/demo/form.vue`
- [ ] **Step 1: 详情页**
`onLoad(query)` → `getById(query.id)`。
区块:状态 Hero、metric dock、基础信息、`van-steps`、缴费(有则显示)、`AttachList`、`FlowTimeline`、底栏返回/编辑。
- [ ] **Step 2: 表单页**
`van-cell-group` + `van-field`(名称、单号、类型、加急开关、负责人、日期、金额、备注);`.form-footer` 取消/保存;保存 `van-toast` 后 `navigateBack`。
注:`@vant/weapp` 表单为 `van-field` 等,无 Web 版 `van-form` 时用手动校验(名称非空)。
- [ ] **Step 3: 手动联跑** list → detail → form → back
- [ ] **Step 4: Commit**
```bash
git add mobile-h5/pages/demo/detail.vue mobile-h5/pages/demo/form.vue
git commit -m "$(cat <<'EOF'
feat(mobile-h5): add demo detail and form pages
EOF
)"
```
---
### Task 11: 组件合集页 + 规范文档回写
**Files:**
- Create: `mobile-h5/pages/demo/comps.vue`
- Modify: `docs/miniprogram-ui-spec-sanqiang.md`(文首或新章节)
- [ ] **Step 1: 实现 `comps.vue`**
对齐 Demo「组件风格」:按钮、Tag、Cell 卡、通知/空态/加载、Feedback、分段/步骤、`AttachList`。
使用 `.comps` 相关样式:可把 Demo 中 `.comps-page` / `.comp-block` 关键到 `styles/components/comps.scss` 并在 `App.vue` import(若未建 comps.scss,本步一并创建)。
- [ ] **Step 2: 在 `miniprogram-ui-spec-sanqiang.md` 增加章节**
在文档靠前位置增加:
```markdown
## 移动工作台(mobile-h5)
- 工程:`mobile-h5`(HBuilderX uni-app Vue3 + `@vant/weapp`)
- 视觉 Demo:`mobile-ui/zkxw-mobile-vant-ui-demo.html`
- 设计说明:`docs/superpowers/specs/2026-08-10-mobile-h5-vant-ui-design.md`
- 信息架构:单一工作台 + 权限菜单卡片;列表/详情/表单样板见 `pages/demo/*`
- Token:仍遵循本文 §2 三墙色板;**禁止**使用 web-admin `#10b981`
```
- [ ] **Step 3: Commit**
```bash
git add mobile-h5/pages/demo/comps.vue mobile-h5/styles/components/comps.scss mobile-h5/App.vue docs/miniprogram-ui-spec-sanqiang.md
git commit -m "$(cat <<'EOF'
feat(mobile-h5): add component gallery and link UI spec
EOF
)"
```
---
### Task 12: 总验收清单
- [ ] **Step 1: 对照 Spec §8 打勾**
| 项 | 验收方式 |
|----|----------|
| 五种页面模式可对应 | HBuilderX 打开 index/list/detail/form/comps |
| Token 单源 | `tokens.scss` 含 `#0a9f6d`,全库 mobile-h5 无 `#10b981` 作主色 |
| Vant easycom | 页面中 `van-button` / `van-search` 可渲染 |
| HBuilderX 可运行到微信工具 | 人工确认 |
| 新页可复用 shell 类 + 组件 | 阅读 `pages/demo/list.vue` 无大段内联色值 |
Run:
```bash
! grep -R --include='*.vue' --include='*.scss' -n '#10b981' mobile-h5 || true
grep -R --include='*.scss' -n '#0a9f6d' mobile-h5/styles/tokens.scss
```
- [ ] **Step 2: 若全部通过,打 tag 或最终说明 commit(可选)**
```bash
git status
```
Expected: 工作区干净或仅剩无关文件。
---
## Spec coverage(自检)
| Spec 要求 | 对应 Task |
|-----------|-----------|
| 保留 HBuilderX 骨架 | Task 1–2(不改 main.js 结构) |
| `@vant/weapp` + easycom | Task 1–2 |
| tokens / vant-theme / app / components scss | Task 3–4 |
| 菜单权限过滤(mock) | Task 5–6、8 |
| 列表/详情/表单/组件样板 | Task 9–11 |
| 回写 miniprogram UI 规范 | Task 11 |
| 不接真实 API | 全计划无 api 联调 |
| 验收标准 §8 | Task 12 |
## Placeholder scan
无 TBD /「类似 Task N」式省略;关键代码与命令已写出。SCSS 细属性要求从 Demo 迁移(Task 4),执行时打开 Demo 文件对照拷贝。
---
## Execution handoff
Plan complete and saved to `docs/superpowers/plans/2026-08-10-mobile-h5-vant-ui.md`.
**Two execution options:**
1. **Subagent-Driven(推荐)** — 每个 Task 开一个新子代理,Task 间人工/父代理复审,迭代快
2. **Inline Execution** — 本会话按 executing-plans 连续执行,设检查点
你更倾向哪一种?
@@ -0,0 +1,313 @@
# 移动端(mobile-h5)UI 设计与 Vant 整合方案
> 日期:2026-08-10
> 工程:`mobile-h5`(HBuilderX 创建的 uni-app Vue3,发布微信小程序)
> 视觉 Demo:`mobile-ui/zkxw-mobile-vant-ui-demo.html`
> 相关需求:`docs/中科兴皖需求V0.3.md`(小程序端 Vue3 + vant-ui)
> 品牌 Token:对齐 `docs/miniprogram-ui-spec-sanqiang.md` 三墙色板(**非** web-admin Fresh Mint)
---
## 1. 目标与约束
### 1.1 目标
1. 固化本轮 Demo 已确认的页面风格(首页 / 列表 / 详情 / 表单 / 组件合集)。
2. 在**不改动 HBuilderX 工程骨架**(保留 `manifest.json` / `pages.json` / `main.js` / `App.vue` 等原生结构)前提下,接入 **Vant**,并建立可复用的**全局样式层**,方便后续业务页快速适配。
3. 首页为**单一工作台**:功能菜单卡片受「菜单管理 → 移动端菜单」+ 角色/职位权限控制。
### 1.2 硬约束
| 项 | 约定 |
|----|------|
| 工程形态 | 继续使用 HBuilderX + uni-app,**不**迁移为独立 Vite CLI 工程 |
| UI 库 | Vant 体系(微信端使用 `@vant/weapp`) |
| Vue | Vue 3(`manifest.json` → `vueVersion: "3"`) |
| 主色 | `#0a9f6d` / `#087f57` / `#e9f9f2`(禁止混用 web-admin `#10b981`) |
| 发布 | HBuilderX 发行到微信小程序 |
### 1.3 非目标(本期不做)
- 不改造 `web-admin`。
- 不实现完整业务 API 联调(本设计只定 UI / 样式 / 工程骨架)。
- 不引入第二套 UI 框架(如 uView / wot 与 Vant 并存)。
---
## 2. 视觉权威与页面模式
### 2.1 权威文件
| 角色 | 路径 |
|------|------|
| 交互与视觉 Demo(本轮定稿) | `mobile-ui/zkxw-mobile-vant-ui-demo.html` |
| 品牌 Token 基线 | `docs/miniprogram-ui-spec-sanqiang.md` §2 |
| 本设计说明 | 本文档 |
后续业务页 **SHALL** 以 Demo 中对应页面区块为准;Token **SHALL** 以三墙色板为准。
### 2.2 已定稿页面
| 模式 | Demo 入口 | 结构摘要 |
|------|-----------|----------|
| P-Home 首页工作台 | 「1. 首页」 | 绿渐变 Header → 权限菜单 4 列宫格(上 Icon 下标题)→ 待办统计卡 + 待办条目 |
| P-List 列表 | 「2. 列表」 | Hero + 内嵌搜索 → 悬浮分段筛选 → 状态着色业务卡(图标/金额或进度/操作) |
| P-Detail 详情 | 「3. 详情」 | 状态色 Hero → 指标 Dock → 分区卡片(基础信息 / Steps / 缴费 / 附件 / 流转)→ 底栏 |
| P-Form 新增编辑 | 「4. 表单」 | 绿顶栏 → `van-form` 分组 Field → 底栏取消/保存 |
| P-Comps 组件合集 | 「5. 组件」 | 按钮 / Tag / Cell / 通知空态加载 / Feedback / 分段步骤 / 附件 |
### 2.3 首页菜单权限规则
1. 菜单数据来自后台「菜单管理」中 **移动端菜单** 树(`parent_id` 指向移动端根)。
2. 登录人仅展示其角色/职位授权内的菜单。
3. 卡片样式:**上方 Icon,下方标题**;推荐 **4 列**宫格;触达区域 ≥ 44×44。
---
## 3. 设计 Token(全局变量)
在 uni-app 中以 **SCSS 变量 + CSS 变量** 双轨落地,业务页优先用 CSS 变量,便于运行时/主题覆盖。
```scss
// styles/tokens.scss(设计源)
$brand-green: #0a9f6d;
$brand-green-dark: #087f57;
$brand-green-soft: #e9f9f2;
$barley-yellow: #d6a343;
$barley-yellow-soft: #fff7e8;
$bg-page: #f5f8f7;
$surface: #ffffff;
$text-primary: #1f2a26;
$text-muted: #6b7b74;
$border: #dcebe4;
$danger: #d14343;
$warning: #cf8a19; // Demo 中部分强调用 #a67b20 / #d6a343 同族
$success: #189b65;
$radius-card: 14px;
$radius-lg: 20px; // Hero 下缘可用 28px
$space: 8px; // 节奏:8 / 10 / 12 / 14 / 16
```
映射到页面根(`App.vue` 或 `styles/app.scss`):
```css
page, :root {
--brand-green: #0a9f6d;
--brand-green-dark: #087f57;
--brand-green-soft: #e9f9f2;
--barley-yellow: #d6a343;
--barley-yellow-soft: #fff7e8;
--bg-page: #f5f8f7;
--surface: #ffffff;
--text-primary: #1f2a26;
--text-muted: #6b7b74;
--border: #dcebe4;
--danger: #d14343;
--warning: #cf8a19;
--success: #189b65;
--radius-card: 14rpx; /* 实现时按 rpx 换算,见 §5.3 */
--shadow-soft: 0 8rpx 32rpx rgba(8, 127, 87, 0.08);
}
```
**语义状态色(列表卡 / Tag / 详情 Hero):**
| 状态 | 主强调 | 用途 |
|------|--------|------|
| 待处理 | 琥珀 / 大麦黄 | warning 卡、Tag |
| 进行中 | 品牌绿 | primary 卡、实心 Tag |
| 异常 | `#d14343` | danger |
| 已完成 | `#189b65` | success 浅绿底 |
---
## 4. Vant 整合方案(推荐)
### 4.1 选型说明
| 方案 | 说明 | 结论 |
|------|------|------|
| A. `@vant/weapp` | Vant 官方微信小程序版,HBuilderX 发微信主路径最稳 | **推荐(默认)** |
| B. `vant`(Web Vue3) | 仅适合纯 H5;微信端组件不兼容 | 仅作 H5 调试补充,不作为主路径 |
| C. 其它 uni UI | 与需求「vant-ui」不符 | 不采用 |
> 需求原文要求 vant-ui;在 uni-app → 微信小程序场景下,**`@vant/weapp` 即 Vant 在微信端的官方落地形态**。
### 4.2 接入步骤(不破坏 HBuilderX 骨架)
1. 在 `mobile-h5` 目录用 HBuilderX 终端或本地 npm 安装:
```bash
npm init -y # 若尚无 package.json
npm i @vant/weapp -S --production
```
2. 在 `pages.json` 配置 easycom(按官方路径):
```json
"easycom": {
"autoscan": true,
"custom": {
"^van-(.*)": "@vant/weapp/dist/$1/index"
}
}
```
(若发行报路径错误,改为 `@vant/weapp/$1/index`,以本机 `node_modules/@vant/weapp` 实际目录为准。)
3. 微信小程序需在 `manifest.json` → `mp-weixin` 填入 `appid`;开发阶段可继续 `urlCheck: false`。
4. **主题色**:在全局样式覆盖 Vant CSS 变量 / 组件自定义色(见 §5.2),主色统一为 `#0a9f6d`。
5. 页面中按需使用:`van-button`、`van-search`、`van-field`、`van-nav-bar`、`van-tag`、`van-empty`、`van-loading`、`van-notice-bar`、`van-steps`、`van-action-sheet`、`van-dialog`、`van-toast` 等。
### 4.3 与自定义样式的边界
| 用 Vant | 用项目全局样式 / 业务组件 |
|---------|---------------------------|
| 按钮、表单 Field、导航栏、Toast/Dialog/Sheet、Steps、Empty、Loading、NoticeBar、基础 Tag | 首页菜单宫格、待办统计、列表业务卡、详情 Hero/指标 Dock、附件卡、流转时间线、分段 Chip/Seg |
原则:**交互控件跟 Vant;业务信息架构跟 Demo 自定义类名**,避免在每个页面复制大段 CSS。
---
## 5. 全局样式怎么写(方便后续适配)
### 5.1 推荐目录(在 `mobile-h5` 内增量,不改框架入口文件职责)
```
mobile-h5/
App.vue # 引入全局样式;生命周期
main.js # 保持 HBuilderX 默认
pages.json
manifest.json
uni.scss # 覆盖/扩展 uni 变量(可 @import tokens)
styles/
tokens.scss # 色板、圆角、间距(唯一 Token 源)
vant-theme.scss # Vant 主题覆盖
mixins.scss # 渐变 Hero、卡片、安全区等 mixin
app.scss # page 背景、通用工具类
components/
menu-grid.scss # 首页菜单宫格
todo.scss # 待办
list.scss # 列表 Hero / Seg / biz-card
detail.scss # 详情 Hero / Dock / section
attach.scss # 附件上传与文件卡
flow.scss # 流转记录
form-shell.scss # 表单底栏等
components/ # 可复用 Vue 组件(后续落地)
AppHero.vue
MenuGrid.vue
BizListCard.vue
AttachList.vue
FlowTimeline.vue
...
pages/
index/ # 工作台首页
...
api/ # 后续
store/ # 后续
utils/
```
### 5.2 Vant 主题覆盖(示例)
```scss
/* styles/vant-theme.scss */
page {
--van-primary-color: #0a9f6d;
--van-success-color: #189b65;
--van-warning-color: #cf8a19;
--van-danger-color: #d14343;
--van-border-color: #dcebe4;
--van-background: #f5f8f7;
--van-text-color: #1f2a26;
--van-text-color-2: #6b7b74;
--van-button-primary-background: #0a9f6d;
--van-button-primary-border-color: #0a9f6d;
--van-nav-bar-background: transparent;
--van-nav-bar-title-text-color: #ffffff;
--van-nav-bar-icon-color: #ffffff;
}
```
`App.vue`:
```vue
<style lang="scss">
@import "@/styles/tokens.scss";
@import "@/styles/vant-theme.scss";
@import "@/styles/app.scss";
@import "@/styles/components/menu-grid.scss";
@import "@/styles/components/list.scss";
@import "@/styles/components/detail.scss";
@import "@/styles/components/attach.scss";
@import "@/styles/components/flow.scss";
/* 按需继续 import */
</style>
```
> HBuilderX Vue3 若 `@` 别名未配置,可用相对路径 `./styles/...`,或在项目中按 uni-app 惯例配置。
### 5.3 rpx 适配约定
- Demo 以 **375 逻辑宽** 为基准(与小程序规范一致)。
- 换算经验:`1px ≈ 2rpx`(375 设计稿)。
- 全局样式落地时:**字号、间距、圆角、图标容器用 rpx**;`1px` 边框可用 `1rpx` 或 `0.5px`(按端表现微调)。
- 触达高度:按钮 / 底栏主按钮 **≥ 88rpx(约 44px)**。
### 5.4 可复用「壳」类名(与 Demo 对齐,落地时保持稳定)
后续新页面优先组合下列类,而不是新起一套命名:
| 类名 / 区块 | 用途 |
|-------------|------|
| `.page-shell` + 浅绿径向背景 | 列表/详情/组件页底 |
| `.hero` / `.list-hero` / `.detail-hero` | 绿/状态色顶区 + 大圆角下缘 |
| `.filter-dock` / `.seg-tabs` | 悬浮筛选、四格分段 |
| `.biz-card.status-*` | 列表业务卡 |
| `.detail-section` + `.sec-hd` | 详情分区 |
| `.d-attach-*` / `.flow-*` | 附件、流转 |
| `.menu-grid` / `.menu-card` | 首页菜单 |
| `.form-footer` / `.detail-footer` | 底栏 |
### 5.5 业务页适配清单(复制即用)
新开一个业务列表页时:
1. `pages.json` 注册路由;顶栏可用自定义 Hero,隐藏默认 navigationBar 或设透明。
2. 结构:`hero(搜索)` → `seg-tabs` → `biz-card` 列表。
3. 状态枚举映射到 `status-warning | status-primary | status-danger | status-success`。
4. 主按钮仅一处实心 `type="primary"`(或项目封装的主按钮 class)。
5. 附件、流转直接引用 `AttachList` / `FlowTimeline` 组件(落地后)。
---
## 6. 与现有文档的关系
1. **`docs/miniprogram-ui-spec-sanqiang.md`**:继续作为三墙 Token / 媒体比例等基线;其中旧「客户端购物车三端」Demo 与本「统一工作台」产品形态不同,**工作台信息架构以 `zkxw-mobile-vant-ui-demo.html` 为准**。
2. 建议在 `miniprogram-ui-spec-sanqiang.md` 增加一节「移动工作台(mobile-h5)」指向 Demo + 本文档(实现阶段文档任务,可与代码一并改)。
3. **颜色隔离**:`web-admin` 仍用 Fresh Mint;`mobile-h5` 只用三墙绿。
---
## 7. 实施顺序建议(供下一阶段 plan)
1. `mobile-h5` 增加 `package.json` + 安装 `@vant/weapp`,配置 `pages.json` easycom。
2. 落地 `styles/tokens.scss` + `vant-theme.scss` + `app.scss`,在 `App.vue` 引入。
3. 抽公共组件:`MenuGrid`、`BizListCard`、`AttachList`、`FlowTimeline`。
4. 实现首页(菜单权限 mock → 再接真实菜单 API)。
5. 实现列表 / 详情 / 表单样板页各一,作为后续业务复制模板。
6. 回写 `miniprogram-ui-spec-sanqiang.md` 工作台章节。
---
## 8. 验收标准
- [ ] Demo 中五种页面模式在文档与样式类名上可一一对应。
- [ ] 全局 Token 仅一处定义(`tokens.scss`),Vant 主色与品牌绿一致。
- [ ] HBuilderX 仍可正常运行到微信开发者工具 / 发行。
- [ ] 新业务页可在不复制大段 CSS 的情况下,组合 shell + Vant 控件完成布局。
- [ ] 不出现 web-admin `#10b981` 主色。
---
## 9. 修订记录
| 日期 | 说明 |
|------|------|
| 2026-08-10 | 初稿:定稿 Demo、Token、`@vant/weapp` 整合、全局样式目录与适配清单 |
File diff suppressed because it is too large. Load diff