Files
prop-ai-hr/docs/superpowers/plans/2026-07-11-mobile-uni-employee-pages-visual-redesign.md
T
admin ee396d1e7a feat(mobile): 重做员工端首页、问答和训练页视觉
统一员工端 tabBar、共享卡片和三大核心页面的视觉基础,同时保持现有移动端业务流程不变。补充 H5 输入兼容、页面结构和训练回滚行为的回归测试。
2026-07-11 01:13:14 +08:00

451 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Mobile Uni Employee Pages Visual Redesign 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:** 将员工端 `today / sop / practice` 三页及其强相关的 `tabBar / 共享卡片样式` 调整为接近设计基准稿的统一视觉,同时保持现有业务交互和接口行为不变。
**Architecture:** 采用“视觉优先、业务最小改动”的改法:先建立员工端共享视觉 token 与基础样式,再按首页、问师傅页、训练页的顺序逐页重排结构和样式。页面内部函数、接口调用与路由保留,主要改模板层级、类名、样式组织和少量静态资源引用。
**Tech Stack:** uni-app Vue3、Vite、TypeScript、CSS、Node 原生测试、H5 构建校验
---
### Task 1: 建立员工端共享视觉基座
**Files:**
- Modify: `mobile-uni/src/styles/base.css`
- Modify: `mobile-uni/src/pages.json`
- Test: `mobile-uni/tests/mobile-user-pages.test.mjs`
- [x] **Step 1: 写一个失败测试,锁住 Vue3 manifest 与员工端视觉约束继续有效**
```js
test('tabBar 继续保留员工端四个固定入口', async () => {
const source = await pageSource('../src/pages.json');
assert.match(source, /pages\/user\/today\/index/);
assert.match(source, /pages\/user\/practice\/index/);
assert.match(source, /pages\/user\/sop\/index/);
assert.match(source, /pages\/user\/profile\/index/);
});
```
- [x] **Step 2: 运行测试,确认新增断言先失败或当前文件尚未覆盖该约束**
Run: `node --test tests/mobile-user-pages.test.mjs`
Expected: 新增测试如果还没加入会缺失;加入后在修改前至少能作为后续回归校验入口存在。
- [x] **Step 3: 在 `base.css` 中整理员工端共享 token,不扩大到全站侵入式重置**
```css
:root {
--employee-bg: #f4f6fb;
--employee-surface: #ffffff;
--employee-primary: #2f6bff;
--employee-primary-soft: #eaf1ff;
--employee-success: #34b368;
--employee-warning: #ff8a1f;
--employee-danger: #ff5b4d;
--employee-text: #182230;
--employee-muted: #6b7280;
--employee-card-radius: 24px;
--employee-card-shadow: 0 12px 32px rgba(47, 107, 255, 0.08);
}
.employee-card {
border-radius: var(--employee-card-radius);
background: var(--employee-surface);
box-shadow: var(--employee-card-shadow);
}
.employee-section-title {
color: var(--employee-text);
font-size: 20px;
font-weight: 900;
}
```
- [x] **Step 4: 调整 `pages.json` 的员工端 tabBar 视觉参数,保留四 tab 结构和路径**
```json
"tabBar": {
"color": "#7b8494",
"selectedColor": "#2f6bff",
"backgroundColor": "#ffffff",
"borderStyle": "white",
"height": "66px",
"fontSize": "12px",
"iconWidth": "25px",
"spacing": "3px",
"list": [
{ "pagePath": "pages/user/today/index", "text": "今日" },
{ "pagePath": "pages/user/practice/index", "text": "练" },
{ "pagePath": "pages/user/sop/index", "text": "问" },
{ "pagePath": "pages/user/profile/index", "text": "我" }
]
}
```
- [x] **Step 5: 更新回归测试,验证 tabBar 四入口与共享样式关键 token 存在**
```js
test('共享视觉基座包含员工端主色和卡片圆角 token', async () => {
const source = await pageSource('../src/styles/base.css');
assert.match(source, /--employee-primary:/);
assert.match(source, /--employee-card-radius:/);
});
```
- [x] **Step 6: 运行测试验证通过**
Run: `node --test tests/mobile-user-pages.test.mjs`
Expected: PASS,且已有输入兼容与 manifest 测试继续通过。
- [ ] **Step 7: 提交这一阶段改动**
```bash
git add mobile-uni/src/styles/base.css mobile-uni/src/pages.json mobile-uni/tests/mobile-user-pages.test.mjs
git commit -m "feat: add employee visual foundation"
```
### Task 2: 重做员工端首页视觉
**Files:**
- Modify: `mobile-uni/src/pages/user/today/index.vue`
- Modify: `mobile-uni/src/styles/base.css`
- Test: `mobile-uni/tests/mobile-user-pages.test.mjs`
- [x] **Step 1: 为首页结构写失败测试,锁住设计稿要求的核心区块**
```js
test('员工首页保留师傅区、语音条、今日安排、我的地图四段结构', async () => {
const source = await pageSource('../src/pages/user/today/index.vue');
assert.match(source, /mentor-hero/);
assert.match(source, /voice-panel/);
assert.match(source, /今日安排/);
assert.match(source, /我的地图/);
});
```
- [x] **Step 2: 运行测试确认结构断言可作为改版护栏**
Run: `node --test tests/mobile-user-pages.test.mjs`
Expected: 失败或在旧结构下不足以覆盖新样式目标,后续补全后通过。
- [x] **Step 3: 重排首页模板,保留原有交互函数但调整为设计稿节奏**
```vue
<view class="mentor-hero employee-hero">
<view class="hero-copy">
<text class="hero-role">{{ positionProfile.value }}</text>
<text class="hero-title">{{ positionProfile.heroTitle }}</text>
<text class="hero-sub">有问题,随时问老师傅</text>
</view>
<image class="mentor-image" src="/static/mentor.png" mode="aspectFit" />
<view class="mentor-bubble">
<text>{{ mentorBubbleText }}</text>
</view>
</view>
<view class="voice-panel employee-card">
<button class="voice-primary" @click="goSop">...</button>
<button class="voice-secondary" @click="goSop">...</button>
</view>
<view class="section-card employee-card" v-else-if="hasSchedule">...</view>
<view class="section-card employee-card" v-if="loggedIn">...</view>
```
- [x] **Step 4: 用 scoped 样式还原首页视觉,控制人物占屏不超过首屏约五分之一**
```css
.today-page {
background: radial-gradient(circle at top, #eef5ff 0%, #f7f9fc 38%, #f4f6fb 100%);
}
.mentor-hero {
min-height: 220px;
padding: 28px 24px 0;
}
.mentor-image {
right: 24px;
bottom: 0;
width: 108px;
height: 148px;
}
.voice-panel {
margin-top: -28px;
grid-template-columns: 1.4fr 1fr;
}
.map-tile {
border-radius: 22px;
min-height: 136px;
}
```
- [x] **Step 5: 更新测试,验证首页地图主标题继续显示真实 `tile.title`,避免回退成单字标题**
```js
test('员工首页地图主标题继续显示真实工具名称', async () => {
const source = await pageSource('../src/pages/user/today/index.vue');
assert.match(source, /<text class="map-title">\{\{ tile\.title \}\}<\/text>/);
});
```
- [x] **Step 6: 运行测试验证首页改版没有破坏护栏**
Run: `node --test tests/mobile-user-pages.test.mjs`
Expected: PASS。
- [ ] **Step 7: 提交首页改版**
```bash
git add mobile-uni/src/pages/user/today/index.vue mobile-uni/src/styles/base.css mobile-uni/tests/mobile-user-pages.test.mjs
git commit -m "feat: redesign employee home page"
```
### Task 3: 重做问师傅页视觉与总结卡展现
**Files:**
- Modify: `mobile-uni/src/pages/user/sop/index.vue`
- Modify: `mobile-uni/src/styles/base.css`
- Test: `mobile-uni/tests/mobile-user-pages.test.mjs`
- [x] **Step 1: 为问师傅页写失败测试,锁住搜索主导与总结卡入口仍然存在**
```js
test('问师傅页保留搜索框、答案区和总结卡入口', async () => {
const source = await pageSource('../src/pages/user/sop/index.vue');
assert.match(source, /query-panel/);
assert.match(source, /answer-panel/);
assert.match(source, /summary-panel/);
});
```
- [x] **Step 2: 运行测试确认护栏建立成功**
Run: `node --test tests/mobile-user-pages.test.mjs`
Expected: 断言可执行,作为后续视觉重排的结构保护。
- [x] **Step 3: 收紧问师傅页头部,改为“轻标题 + 强搜索框”的布局**
```vue
<view class="page sop-page">
<view class="sop-toolbar">
<text class="page-title">查SOP</text>
<text class="page-subtitle">直接搜 SOP、案例和常用话术</text>
</view>
<view class="panel query-panel employee-card">
<textarea v-model="query" class="textarea sop-query-textarea" ... />
<view class="chip-row">...</view>
<button class="primary-button query-submit" ...>问老师傅</button>
</view>
</view>
```
- [x] **Step 4: 调整答案卡、引用依据和总结卡为更接近设计稿的卡片层级与底部浮层感**
```css
.sop-page {
background: linear-gradient(180deg, #f7f9fc 0%, #f4f6fb 100%);
}
.query-panel {
border-radius: 22px;
padding: 18px;
}
.answer-panel {
border-left: 0;
border-radius: 22px;
}
.modal-card {
border-radius: 28px 28px 0 0;
max-width: 430px;
width: calc(100% - 16px);
}
```
- [x] **Step 5: 保持 H5 输入兼容测试存在,防止误把 `textarea` 再次改成 `border-box`**
```js
test('SOP 查询框不覆盖 textarea 的 box-sizing', async () => {
const source = await pageSource('../src/pages/user/sop/index.vue');
const queryPanelStyle = source.match(/\.query-panel \.textarea \{[\s\S]*?\n\}/)?.[0] || '';
assert.equal(queryPanelStyle.includes('box-sizing'), false);
});
```
- [x] **Step 6: 运行测试验证通过**
Run: `node --test tests/mobile-user-pages.test.mjs`
Expected: PASS。
- [ ] **Step 7: 提交问师傅页改版**
```bash
git add mobile-uni/src/pages/user/sop/index.vue mobile-uni/src/styles/base.css mobile-uni/tests/mobile-user-pages.test.mjs
git commit -m "feat: redesign employee sop page"
```
### Task 4: 重做训练页视觉但保留训练逻辑
**Files:**
- Modify: `mobile-uni/src/pages/user/practice/index.vue`
- Modify: `mobile-uni/src/styles/base.css`
- Test: `mobile-uni/tests/mobile-user-pages.test.mjs`
- [x] **Step 1: 为训练页写失败测试,锁住训练关键区块仍存在**
```js
test('训练页保留场景区、对话区、回复区和结果区', async () => {
const source = await pageSource('../src/pages/user/practice/index.vue');
assert.match(source, /scenario-card/);
assert.match(source, /dialogue-card/);
assert.match(source, /reply-card/);
assert.match(source, /result-card/);
});
```
- [x] **Step 2: 运行测试确认结构护栏存在**
Run: `node --test tests/mobile-user-pages.test.mjs`
Expected: 断言可运行,用于防止视觉重排时误删功能区块。
- [x] **Step 3: 调整训练页模板,让头部、场景卡、老师傅提示更接近设计稿的训练面板结构**
```vue
<view class="practice-head">
<text class="practice-eyebrow">数字师傅 · 场景训练</text>
<text class="page-title">{{ activeScenarioName }}</text>
<text class="page-subtitle">与业主、老师傅完成一轮真实工作对话</text>
</view>
<view v-if="loggedIn" class="panel scenario-card employee-card">...</view>
<view v-if="turns.length" class="panel dialogue-card employee-card">...</view>
<view v-if="status === 'active' || status === 'submitting'" class="panel reply-card employee-card">...</view>
```
- [x] **Step 4: 用样式强化三类角色区分与老师傅提示卡,但不引入每轮真实评分**
```css
.turn-row.customer {
background: linear-gradient(180deg, #fff8f1 0%, #ffffff 100%);
}
.turn-row.trainee {
background: linear-gradient(180deg, #f2fbf6 0%, #ffffff 100%);
}
.turn-row.coach {
background: linear-gradient(180deg, #eef5ff 0%, #ffffff 100%);
}
.reply-card .primary-button {
min-height: 52px;
border-radius: 18px;
}
.help-card,
.mentor-rewrite {
border-radius: 22px;
}
```
- [x] **Step 5: 保留并复用提交失败回滚测试,避免训练视觉改版时误伤已有状态修复**
```js
test('训练页提交失败会回滚本次乐观追加的对话', async () => {
const source = await pageSource('../src/pages/user/practice/index.vue');
assert.match(source, /const previousTurns = turns\.value\.slice\(\)/);
assert.match(source, /turns\.value = previousTurns/);
});
```
- [x] **Step 6: 运行测试验证通过**
Run: `node --test tests/mobile-user-pages.test.mjs`
Expected: PASS。
- [ ] **Step 7: 提交训练页改版**
```bash
git add mobile-uni/src/pages/user/practice/index.vue mobile-uni/src/styles/base.css mobile-uni/tests/mobile-user-pages.test.mjs
git commit -m "feat: redesign employee practice page"
```
### Task 5: 全量验证与收尾
**Files:**
- Verify: `mobile-uni/src/pages/user/today/index.vue`
- Verify: `mobile-uni/src/pages/user/sop/index.vue`
- Verify: `mobile-uni/src/pages/user/practice/index.vue`
- Verify: `mobile-uni/src/styles/base.css`
- Verify: `mobile-uni/src/pages.json`
- Test: `mobile-uni/tests/mobile-user-pages.test.mjs`
- [x] **Step 1: 运行员工端页面回归测试**
Run: `node --test tests/mobile-user-pages.test.mjs`
Expected: PASS。
- [x] **Step 2: 运行全量单测**
Run: `npm run test:unit`
Expected: 全部 PASS;允许保留既有 WebSocket 噪音,只要没有失败。
- [x] **Step 3: 运行类型检查**
Run: `npm run typecheck`
Expected: PASS。
- [x] **Step 4: 运行 H5 构建**
Run: `npm run build:h5`
Expected: `Build complete.`
- [ ] **Step 5: 本地打开首页进行人工快速核对**
Run: `open "http://localhost:5175/h5/#/pages/user/today/index"`
Expected: 能看到新的首页首屏结构、语音条、今日安排、我的地图和统一 tabBar。
- [ ] **Step 6: 提交最终整体验证结果**
```bash
git add mobile-uni/src/pages/user/today/index.vue mobile-uni/src/pages/user/sop/index.vue mobile-uni/src/pages/user/practice/index.vue mobile-uni/src/styles/base.css mobile-uni/src/pages.json mobile-uni/tests/mobile-user-pages.test.mjs
git commit -m "feat: unify employee mobile page visuals"
```
## 计划自检
### Spec 覆盖检查
- 三页范围:Task 2、Task 3、Task 4 覆盖 `today / sop / practice`。
- 共享样式与 tabBar:Task 1 覆盖。
- 老师傅仅复用现有素材、不扩展业务:Task 2 与 Task 4 的模板调整限制在现有资源与逻辑内。
- SOP 不伪造能力:Task 3 明确保留真实能力,不新增假 tab 行为。
- 训练页不做每轮真实评分:Task 4 明确只改视觉分层,不新增该模块。
- 验证要求:Task 5 覆盖页面测试、全量单测、类型检查、H5 构建。
### Placeholder 扫描
- 无 `TODO`、`TBD`、`适当处理` 等空泛描述。
- 每个任务都包含具体文件、命令和代码片段。
### 类型与命名一致性
- 继续沿用现有页面类名:`scenario-card`、`dialogue-card`、`reply-card`、`summary-panel`、`voice-panel` 等。
- 复用现有关键回归点:`tile.title`、`previousTurns`、`box-sizing`、`vueVersion`。