fix(plan): 4 条阻塞 + 2 条 advisory 修复(re-review 反馈)
阻塞修复: 1. Task 7: chartData/chartOpts 加入 return,H5 模板可访问 2. Task 13: 补 onUnmounted import 3. Task 13: 删除 4 个重复的 onShow 草稿块,保留唯一规范版本 4. Task 2: 新增 USE_MOCK_API 翻 true 的步骤(api.js 默认 false) advisory 修复: - Task 10: margin: 24r 0 → 24rpx 0 - Task 13: 删 enablePullDownRefresh(与 scroll-view refresher 冲突) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
72c91c1787
commit
8f84b2ad58
@ -326,7 +326,21 @@ export const dashboardApi = {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Step 3: 手动验证 mock 触发**
|
- [ ] **Step 3: 打开 `USE_MOCK_API` 开关(关键前置步骤)**
|
||||||
|
|
||||||
|
> **重要**:项目 `frontend/utils/api.js` 第 9 行 `USE_MOCK_API` 默认是 `false`,会直接请求真实后端。后端尚未实现,必须先翻成 `true` 才能用 mock 验证。
|
||||||
|
|
||||||
|
修改 `frontend/utils/api.js`:
|
||||||
|
```javascript
|
||||||
|
// 第 9 行:
|
||||||
|
// 原始: const USE_MOCK_API = false
|
||||||
|
// 改为:
|
||||||
|
const USE_MOCK_API = true
|
||||||
|
```
|
||||||
|
|
||||||
|
> **切回真实接口**:后端 `/api/v1/dashboard/*` 7 个接口联调通过后,把这里改回 `false` 即可。
|
||||||
|
|
||||||
|
- [ ] **Step 4: 手动验证 mock 触发**
|
||||||
|
|
||||||
在 H5 dev console 跑:
|
在 H5 dev console 跑:
|
||||||
```js
|
```js
|
||||||
@ -335,11 +349,11 @@ const today = await dashboardApi.getTodayOverview(1)
|
|||||||
console.log(today) // 预期: { crystal_balance: 2713, today_income: 213, week_rank: 12 }
|
console.log(today) // 预期: { crystal_balance: 2713, today_income: 213, week_rank: 12 }
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Step 4: Commit**
|
- [ ] **Step 5: Commit**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git add frontend/utils/mock/dashboard.js frontend/utils/api.js
|
git add frontend/utils/mock/dashboard.js frontend/utils/api.js
|
||||||
git commit -m "feat(dashboard): 追加 mock 数据工厂 + dashboardApi 命名空间"
|
git commit -m "feat(dashboard): 追加 mock 数据工厂 + dashboardApi 命名空间 + 打开 USE_MOCK_API"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -1164,9 +1178,7 @@ git commit -m "feat(dashboard): CrystalOverview 双卡(水晶余额+今日收
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// #ifdef H5
|
import { computed } from 'vue'
|
||||||
import { ref, computed } from 'vue'
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'IncomeCurve',
|
name: 'IncomeCurve',
|
||||||
@ -1181,8 +1193,11 @@ export default {
|
|||||||
// 高亮当日(peak)
|
// 高亮当日(peak)
|
||||||
const peak = computed(() => props.points.find((p) => p.is_peak) || null)
|
const peak = computed(() => props.points.find((p) => p.is_peak) || null)
|
||||||
|
|
||||||
|
// 平台条件:仅 H5 编译图表所需变量
|
||||||
|
let chartData = null
|
||||||
|
let chartOpts = null
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
const chartData = computed(() => {
|
chartData = computed(() => {
|
||||||
const categories = props.points.map((p) => p.date.slice(5)) // MM.DD
|
const categories = props.points.map((p) => p.date.slice(5)) // MM.DD
|
||||||
const barData = props.points.map((p) => p.income)
|
const barData = props.points.map((p) => p.income)
|
||||||
const lineData = props.points.map((p) => p.income)
|
const lineData = props.points.map((p) => p.income)
|
||||||
@ -1195,7 +1210,7 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const chartOpts = {
|
chartOpts = {
|
||||||
color: ['#FFCC14', '#1BAFEE'],
|
color: ['#FFCC14', '#1BAFEE'],
|
||||||
padding: [16, 16, 8, 16],
|
padding: [16, 16, 8, 16],
|
||||||
dataLabel: false,
|
dataLabel: false,
|
||||||
@ -1214,7 +1229,7 @@ export default {
|
|||||||
console.log('[IncomeCurve] chart tap', e)
|
console.log('[IncomeCurve] chart tap', e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { peak, handleChartTap }
|
return { peak, handleChartTap, chartData, chartOpts }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -2045,7 +2060,7 @@ export default {
|
|||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
border-radius: 22rpx;
|
border-radius: 22rpx;
|
||||||
padding: 24rpx;
|
padding: 24rpx;
|
||||||
margin: 24r 0;
|
margin: 24rpx 0;
|
||||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.15);
|
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2631,26 +2646,16 @@ git commit -m "feat(dashboard): UpcomingUpgrades + RecentUpgrades 双列布局"
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
## Task 13: onShow 刷新 + Tab 缓存 + 下拉刷新
|
## Task 13: onShow 刷新 + Tab 缓存 + 下拉刷新
|
||||||
|
|
||||||
**Files:**
|
**Files:**
|
||||||
- Modify: `frontend/pages/dashboard/dashboard.vue`
|
- Modify: `frontend/pages/dashboard/dashboard.vue`(整文件重写为完整版)
|
||||||
- Modify: `frontend/pages.json`(启用下拉刷新)
|
- Modify: `frontend/pages.json`(**不**启用 `enablePullDownRefresh`;下拉刷新由 scroll-view 的 `:refresher-enabled` 接管,避免双触发冲突)
|
||||||
|
|
||||||
- [ ] **Step 1: 在 `uni.scss` 中追加 page-bg CSS 类**
|
- [ ] **Step 1: 整文件替换 `frontend/pages/dashboard/dashboard.vue`**
|
||||||
|
|
||||||
在 `uni.scss` 末尾 dashboard token 段后追加:
|
**直接用以下完整内容覆盖整个文件**(删除 Task 4 写入的占位版本、Task 6/8/9/10/12 追加挂载的中间版本):
|
||||||
```scss
|
|
||||||
/* dashboard 页面背景(CSS 类,组件用 class 引用,避免 inline 重复) */
|
|
||||||
.dashboard-page-bg {
|
|
||||||
background: linear-gradient(153deg, #FF9597 0%, #80DFFF 33%, #B8B8B8 74%, #D9D9D9 100%);
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: 重写 `frontend/pages/dashboard/dashboard.vue`(含 onShow + scroll-view + class 引用)**
|
|
||||||
|
|
||||||
完整文件内容:
|
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<template>
|
<template>
|
||||||
@ -2714,7 +2719,7 @@ git commit -m "feat(dashboard): UpcomingUpgrades + RecentUpgrades 双列布局"
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref } from 'vue'
|
import { ref, onUnmounted } from 'vue'
|
||||||
import DashboardHeader from './components/DashboardHeader.vue'
|
import DashboardHeader from './components/DashboardHeader.vue'
|
||||||
import CrystalOverview from './components/CrystalOverview.vue'
|
import CrystalOverview from './components/CrystalOverview.vue'
|
||||||
import IncomeCurve from './components/IncomeCurve.vue'
|
import IncomeCurve from './components/IncomeCurve.vue'
|
||||||
@ -2748,83 +2753,33 @@ export default {
|
|||||||
uni.stopPullDownRefresh()
|
uni.stopPullDownRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
// onShow:用户从其他页面返回时强制刷新一次(spec §4.1)
|
|
||||||
onShow lifecycle hook(uni-app 页面级,需在 export default 上声明,setup 内通过 getCurrentInstance 获取):
|
|
||||||
```js
|
|
||||||
// 在 export default 中追加:
|
|
||||||
onShow() {
|
|
||||||
this.$options._setupRef?.refresh?.(null, true)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
// 实际写法(替换上面注释块):在 setup 末尾 return 前暴露 refresh 引用
|
|
||||||
const setupRef = { refresh }
|
|
||||||
onShow lifecycle:见下方 onShow 实现
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
**关于 onShow 的关键说明**:uni-app 的 `onShow` 是 Options API 生命周期钩子,**必须在 `export default` 顶层声明**(不在 `setup` 内)。完整 onShow 实现:
|
|
||||||
|
|
||||||
在 `<script>` 块内的 `export default` 顶层(与 `components`、`setup` 同级)追加:
|
|
||||||
```javascript
|
|
||||||
export default {
|
|
||||||
components: { ... },
|
|
||||||
setup() { ... return { refresh, ... } },
|
|
||||||
onShow() {
|
|
||||||
// 页面 onShow 时强制刷新(绕 30 分钟缓存,spec §4.1)
|
|
||||||
this.refresh(null, true)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
注意:`onShow` 内的 `this.refresh` 来自 `setup()` 的 `return` 暴露,vue 会自动合并 setup return 到实例。
|
|
||||||
|
|
||||||
> **重要**:上面模板中 `onShow` 注释块仅作说明,**实际写入文件时按下方"onShow 完整写法"**(替换 `setup` 末段):
|
|
||||||
|
|
||||||
`setup()` 末段(return 之前)追加:
|
|
||||||
```javascript
|
|
||||||
// 将 refresh 暴露给 onShow 生命周期
|
|
||||||
const _refresh = refresh
|
|
||||||
// 在 return 中暴露
|
|
||||||
return {
|
|
||||||
activeTab, loading, error, data, isReady, lastFetched,
|
|
||||||
handleTabChange, handlePullDownRefresh,
|
|
||||||
refresh: _refresh, // 给 onShow 用
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
> 最终 onShow 写法(重写整个 export default):
|
|
||||||
```javascript
|
|
||||||
export default {
|
|
||||||
components: { DashboardHeader, CrystalOverview, IncomeCurve, ExhibitionCenter, LikeIncomeBoard, CollectionMatrix },
|
|
||||||
setup() {
|
|
||||||
const activeTab = ref('crystal')
|
|
||||||
const starId = ref(uni.getStorageSync('star_id') || null)
|
|
||||||
const { loading, error, data, refresh, isReady, lastFetched, dispose } = useDashboardData({ starId: starId.value })
|
|
||||||
function handleTabChange(tab) {
|
|
||||||
activeTab.value = tab
|
|
||||||
if (tab === 'crystal') refresh()
|
|
||||||
}
|
|
||||||
async function handlePullDownRefresh() {
|
|
||||||
await refresh(null, true)
|
|
||||||
uni.stopPullDownRefresh()
|
|
||||||
}
|
|
||||||
onUnmounted(() => dispose())
|
onUnmounted(() => dispose())
|
||||||
return { activeTab, loading, error, data, isReady, lastFetched, handleTabChange, handlePullDownRefresh, refresh }
|
|
||||||
|
return {
|
||||||
|
activeTab,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
data,
|
||||||
|
isReady,
|
||||||
|
lastFetched,
|
||||||
|
handleTabChange,
|
||||||
|
handlePullDownRefresh,
|
||||||
|
refresh,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
// uni-app 页面级生命周期(必须在 export default 顶层,不能放 setup 内)
|
||||||
onShow() {
|
onShow() {
|
||||||
// 从其他页面返回时强制刷新(spec §4.1)
|
// 从其他页面返回时强制刷新(绕 30 分钟缓存,spec §4.1)
|
||||||
if (this.refresh) this.refresh(null, true)
|
if (this.refresh) this.refresh(null, true)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
```
|
</script>
|
||||||
|
|
||||||
- [ ] **Step 3: 在 `<style>` 末尾追加 scroll-view 样式**
|
<style lang="scss" scoped>
|
||||||
|
.dashboard-page-bg {
|
||||||
在 dashboard.vue 的 `<style lang="scss" scoped>` 块末尾追加:
|
background: linear-gradient(153deg, #FF9597 0%, #80DFFF 33%, #B8B8B8 74%, #D9D9D9 100%);
|
||||||
```scss
|
min-height: 100vh;
|
||||||
|
}
|
||||||
.dashboard-scroll {
|
.dashboard-scroll {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
@ -2846,27 +2801,14 @@ export default {
|
|||||||
.placeholder-icon { font-size: 96rpx; margin-bottom: 24rpx; }
|
.placeholder-icon { font-size: 96rpx; margin-bottom: 24rpx; }
|
||||||
.placeholder-title { color: #ffffff; font-size: 36rpx; font-weight: 700; margin-bottom: 16rpx; }
|
.placeholder-title { color: #ffffff; font-size: 36rpx; font-weight: 700; margin-bottom: 16rpx; }
|
||||||
.placeholder-sub { color: rgba(255, 255, 255, 0.7); font-size: 26rpx; }
|
.placeholder-sub { color: rgba(255, 255, 255, 0.7); font-size: 26rpx; }
|
||||||
|
</style>
|
||||||
```
|
```
|
||||||
|
|
||||||
> **删掉** `dashboard.vue` 现有的 `.dashboard-container`、`.dashboard-content`、`.placeholder-*`、`.season-placeholder` 旧样式(被 `<style>` 末尾的覆盖即可,但为避免重复,请删旧版块)。
|
- [ ] **Step 2: 确认 `pages.json` 中 dashboard 条目未启用 `enablePullDownRefresh`**
|
||||||
|
|
||||||
- [ ] **Step 4: 在 `pages.json` 中启用下拉刷新**
|
Task 1 写入的 dashboard 条目已正确(不包含 `enablePullDownRefresh`)。**不要**手动加这个字段——下拉刷新由 scroll-view 的 `:refresher-enabled="true"` 接管,两者重复会冲突。
|
||||||
|
|
||||||
把 dashboard 条目改为:
|
- [ ] **Step 3: 手动验证**
|
||||||
```json
|
|
||||||
,{
|
|
||||||
"path": "pages/dashboard/dashboard",
|
|
||||||
"style": {
|
|
||||||
"navigationStyle": "custom",
|
|
||||||
"app-plus": {
|
|
||||||
"bounce": "none"
|
|
||||||
},
|
|
||||||
"enablePullDownRefresh": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 5: 手动验证**
|
|
||||||
|
|
||||||
刷新 H5 dev URL:
|
刷新 H5 dev URL:
|
||||||
- 拖动下拉 → 触发强制刷新(loading.overall 短暂为 true)
|
- 拖动下拉 → 触发强制刷新(loading.overall 短暂为 true)
|
||||||
@ -2875,7 +2817,7 @@ export default {
|
|||||||
- 关闭网络(DevTools Network → Offline)→ 各 section 显示错误态
|
- 关闭网络(DevTools Network → Offline)→ 各 section 显示错误态
|
||||||
- 恢复网络 → 点击错误卡片 → 该 section 重试成功
|
- 恢复网络 → 点击错误卡片 → 该 section 重试成功
|
||||||
|
|
||||||
- [ ] **Step 6: 验证 Figma 视觉一致性**
|
- [ ] **Step 4: 验证 Figma 视觉一致性**
|
||||||
|
|
||||||
用 `superpowers:verification-before-completion` 流程对照 `docs/figma-analysis-data-dashboard.md` 第三节设计 token 逐项核对:
|
用 `superpowers:verification-before-completion` 流程对照 `docs/figma-analysis-data-dashboard.md` 第三节设计 token 逐项核对:
|
||||||
- [ ] 颜色 token 与 §3.1 一致
|
- [ ] 颜色 token 与 §3.1 一致
|
||||||
@ -2883,15 +2825,13 @@ export default {
|
|||||||
- [ ] 圆角与 §3.3 一致
|
- [ ] 圆角与 §3.3 一致
|
||||||
- [ ] 5 个等级色与 §2.7.2 一致
|
- [ ] 5 个等级色与 §2.7.2 一致
|
||||||
|
|
||||||
- [ ] **Step 7: Commit**
|
- [ ] **Step 5: Commit**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git add frontend/pages/dashboard/dashboard.vue frontend/uni.scss frontend/pages.json
|
git add frontend/pages/dashboard/dashboard.vue
|
||||||
git commit -m "feat(dashboard): onShow 强制刷新 + Tab 缓存 + 下拉刷新 + SCSS class 引用"
|
git commit -m "feat(dashboard): onShow 强制刷新 + Tab 缓存 + 下拉刷新(scroll-view refresher)"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Task 14: 全链路手动验证
|
## Task 14: 全链路手动验证
|
||||||
|
|
||||||
**Files:** 无(验证任务)
|
**Files:** 无(验证任务)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user