|
|
@@ -0,0 +1,631 @@
|
|
|
+# TabBar 重构实施计划
|
|
|
+
|
|
|
+> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
|
|
|
+
|
|
|
+**目标:** 将小程序底部 TabBar 从 5 个五维标签(行/心/身/智/富)重构为 4 个功能标签(首页/健康/成长/我的)+ 中间五维启动器按钮,点击弹出半屏浮层显示 5 个维度入口。
|
|
|
+
|
|
|
+**架构:**
|
|
|
+- 4 个主包 TabBar 页:首页(index-home 复用)、健康(新建)、成长(growth/index 从分包移入)、我的(profile 从分包移入)
|
|
|
+- 5 个五维页(mind/body/wisdom/wealth)从主包移入分包,通过中间按钮 navigateTo 访问
|
|
|
+- 自定义 TabBar(custom-tab-bar/index.vue)重构为 4 Tab + 中间按钮 + 半屏浮层
|
|
|
+- 统一跳转工具 `utils/nav.js` 封装 switchTab/navigateTo 判断逻辑
|
|
|
+
|
|
|
+**技术栈:** uni-app Vue 2(微信小程序)、自定义 TabBar
|
|
|
+
|
|
|
+**关键数据:**
|
|
|
+- 主包体积变化:188KB → ~75KB+健康页(实际更小,无超限风险)
|
|
|
+- 需改 switchTab 引用:4 处(index-home、wisdom、self-quiz ×2)
|
|
|
+- teacher 独立 TabBar 保留不变
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 任务 1:创建 `utils/nav.js` 统一跳转工具
|
|
|
+
|
|
|
+**文件:**
|
|
|
+- 创建:`cfc-frontend/utils/nav.js`
|
|
|
+
|
|
|
+**职责:** 封装跨维度跳转逻辑,自动判断目标页是 TabBar 页(switchTab)还是分包页(navigateTo),避免后续所有页面重复判断。
|
|
|
+
|
|
|
+- [ ] **步骤 1:编写 nav.js**
|
|
|
+
|
|
|
+```javascript
|
|
|
+/**
|
|
|
+ * 统一导航工具
|
|
|
+ * TabBar 页面列表(4个新Tab)
|
|
|
+ */
|
|
|
+var TAB_BAR_PAGES = [
|
|
|
+ '/pages/index-home/index',
|
|
|
+ '/pages/health/index',
|
|
|
+ '/pages/growth/index',
|
|
|
+ '/pages/profile/profile'
|
|
|
+]
|
|
|
+
|
|
|
+/**
|
|
|
+ * 跳转到维度页面(五维页已移出 TabBar,统一用 navigateTo)
|
|
|
+ * 行 = index-home(仍是 TabBar 页,用 switchTab)
|
|
|
+ * 心/身/智/富 = 分包页,用 navigateTo
|
|
|
+ */
|
|
|
+function goDimension(dimCode) {
|
|
|
+ var dimMap = {
|
|
|
+ action: '/pages/index-home/index',
|
|
|
+ mind: '/pages/mind/index',
|
|
|
+ body: '/pages/body/index',
|
|
|
+ wisdom: '/pages/wisdom/index',
|
|
|
+ wealth: '/pages/wealth/index'
|
|
|
+ }
|
|
|
+ var url = dimMap[dimCode]
|
|
|
+ if (!url) return
|
|
|
+ if (TAB_BAR_PAGES.indexOf(url) !== -1) {
|
|
|
+ uni.switchTab({ url: url })
|
|
|
+ } else {
|
|
|
+ uni.navigateTo({ url: url })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 通用页面跳转
|
|
|
+ * 自动判断目标是否为 TabBar 页
|
|
|
+ */
|
|
|
+function goPage(url) {
|
|
|
+ if (!url) return
|
|
|
+ if (TAB_BAR_PAGES.indexOf(url) !== -1) {
|
|
|
+ uni.switchTab({ url: url })
|
|
|
+ } else {
|
|
|
+ uni.navigateTo({ url: url })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+module.exports = {
|
|
|
+ TAB_BAR_PAGES: TAB_BAR_PAGES,
|
|
|
+ goDimension: goDimension,
|
|
|
+ goPage: goPage
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 2:Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/utils/nav.js
|
|
|
+git commit -m "feat: add unified navigation utility for tabbar restructure"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 任务 2:改造 `pages.json`
|
|
|
+
|
|
|
+**文件:**
|
|
|
+- 修改:`cfc-frontend/pages.json`
|
|
|
+
|
|
|
+**职责:** 将 TabBar 从 5 页改为 4 页(首页/健康/成长/我的);将 mind/body/wisdom/wealth 从主包 `pages` 数组移入分包;将 growth/index 和 profile/profile 从分包移入主包。
|
|
|
+
|
|
|
+- [ ] **步骤 1:修改 pages.json 的 main pages 数组**
|
|
|
+
|
|
|
+将主包 `pages` 数组从 5 页改为 4 页:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "pages": [
|
|
|
+ { "path": "pages/index-home/index", "style": { "navigationBarTitleText": "首页" } },
|
|
|
+ { "path": "pages/health/index", "style": { "navigationBarTitleText": "健康" } },
|
|
|
+ { "path": "pages/growth/index", "style": { "navigationBarTitleText": "成长" } },
|
|
|
+ { "path": "pages/profile/profile", "style": { "navigationBarTitleText": "我的" } }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 2:修改 tabBar.list**
|
|
|
+
|
|
|
+```json
|
|
|
+"tabBar": {
|
|
|
+ "color": "#7A7E83",
|
|
|
+ "selectedColor": "#F97316",
|
|
|
+ "borderStyle": "black",
|
|
|
+ "backgroundColor": "#FFFFFF",
|
|
|
+ "list": [
|
|
|
+ { "pagePath": "pages/index-home/index", "text": "首页", "iconPath": "static/tab-home.png", "selectedIconPath": "static/tab-home-active.png" },
|
|
|
+ { "pagePath": "pages/health/index", "text": "健康", "iconPath": "static/tab-health.png", "selectedIconPath": "static/tab-health-active.png" },
|
|
|
+ { "pagePath": "pages/growth/index", "text": "成长", "iconPath": "static/tab-growth.png", "selectedIconPath": "static/tab-growth-active.png" },
|
|
|
+ { "pagePath": "pages/profile/profile", "text": "我的", "iconPath": "static/tab-profile.png", "selectedIconPath": "static/tab-profile-active.png" }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+> 注意:需要准备 4 组新的 TabBar 图标(首页、健康、成长、我的),放在 `static/` 目录下。可复用现有 teacher 模式的图标或重新设计。
|
|
|
+
|
|
|
+- [ ] **步骤 3:将五维页移入分包**
|
|
|
+
|
|
|
+将 mind/body/wisdom/wealth 的 index 页面从主包移到对应的 detail 分包中:
|
|
|
+
|
|
|
+```json
|
|
|
+// 在 pages/body-detail 分包中添加 body/index
|
|
|
+{ "root": "pages/body-detail", "pages": [
|
|
|
+ { "path": "index", "style": { "navigationBarTitleText": "身" } },
|
|
|
+ // ... 已有页面 health-report, health-dimensions, checkin 等
|
|
|
+] }
|
|
|
+
|
|
|
+// 在 pages/mind-detail 分包中添加 mind/index
|
|
|
+{ "root": "pages/mind-detail", "pages": [
|
|
|
+ { "path": "index", "style": { "navigationBarTitleText": "心" } },
|
|
|
+ // ... 已有页面 articles, training, emotion-report 等
|
|
|
+] }
|
|
|
+
|
|
|
+// 在 pages/wisdom-detail 分包中添加 wisdom/index
|
|
|
+{ "root": "pages/wisdom-detail", "pages": [
|
|
|
+ { "path": "index", "style": { "navigationBarTitleText": "智" } },
|
|
|
+ // ... 已有页面 cognitive-report, member-wisdom-detail 等
|
|
|
+] }
|
|
|
+
|
|
|
+// 新增 pages/wealth 分包,含 wealth/index + 现有 wealth-sub 内容
|
|
|
+// 或将 wealth/index 放入 pages/wealth 分包
|
|
|
+{ "root": "pages/wealth", "pages": [
|
|
|
+ { "path": "index", "style": { "navigationBarTitleText": "富" } }
|
|
|
+] }
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 4:从原分包移除 growth/index 和 profile/profile**
|
|
|
+
|
|
|
+从 `pages/growth` 分包的 `pages` 数组中移除 `{ "path": "index", ... }`。
|
|
|
+从 `pages/profile` 分包的 `pages` 数组中移除 `{ "path": "profile", ... }`。
|
|
|
+
|
|
|
+- [ ] **步骤 5:Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/pages.json
|
|
|
+git commit -m "refactor: restructure tabbar from 5-dim to 4-tab + center button"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 任务 3:替换所有 switchTab→五维页 的调用
|
|
|
+
|
|
|
+**文件:**
|
|
|
+- 修改:`cfc-frontend/pages/index-home/index.vue:852-858`
|
|
|
+- 修改:`cfc-frontend/pages/wisdom/index.vue:371-388`
|
|
|
+- 修改:`cfc-frontend/pages/wisdom/self-quiz.vue:453`
|
|
|
+- 修改:`cfc-frontend/pages/wisdom-detail/self-quiz.vue:453`
|
|
|
+
|
|
|
+**职责:** 将所有对五维页的 `switchTab` 调用改为 `nav.goPage()` 或 `nav.goDimension()`,确保五维页移出 TabBar 后跳转正常。
|
|
|
+
|
|
|
+- [ ] **步骤 1:修改 index-home/index.vue 的 onFuncClick**
|
|
|
+
|
|
|
+```javascript
|
|
|
+// 引入 nav.js
|
|
|
+var nav = require('../../utils/nav.js')
|
|
|
+
|
|
|
+// 修改 onFuncClick
|
|
|
+onFuncClick: function(item) {
|
|
|
+ var nativeTabs = ['/pages/index-home/index', '/pages/body/index', '/pages/mind/index', '/pages/wisdom/index', '/pages/wealth/index']
|
|
|
+ if (nativeTabs.indexOf(item.page) !== -1) {
|
|
|
+ nav.goPage(item.page) // 改用 nav.goPage 自动判断
|
|
|
+ } else {
|
|
|
+ uni.navigateTo({ url: item.page })
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 2:修改 wisdom/index.vue 的 onFuncClick**
|
|
|
+
|
|
|
+```javascript
|
|
|
+var nav = require('../../utils/nav.js')
|
|
|
+
|
|
|
+// 修改 onFuncClick
|
|
|
+onFuncClick: function(item) {
|
|
|
+ if (item.needLogin && !this.isLoggedIn) {
|
|
|
+ uni.showModal({
|
|
|
+ title: '提示',
|
|
|
+ content: '请先登录后使用此功能',
|
|
|
+ success: function(res) { if (res.confirm) uni.navigateTo({ url: '/pages/login/login' }) }
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (item.page) {
|
|
|
+ var nativeTabs = ['/pages/index-home/index', '/pages/body/index', '/pages/mind/index', '/pages/wisdom/index', '/pages/wealth/index']
|
|
|
+ if (nativeTabs.indexOf(item.page) !== -1) {
|
|
|
+ nav.goPage(item.page)
|
|
|
+ } else {
|
|
|
+ uni.navigateTo({ url: item.page })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 3:修改 wisdom/self-quiz.vue:453**
|
|
|
+
|
|
|
+```javascript
|
|
|
+// 原代码
|
|
|
+uni.switchTab({ url: '/pages/wisdom/index' })
|
|
|
+// 改为
|
|
|
+uni.navigateTo({ url: '/pages/wisdom/index' })
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 4:修改 wisdom-detail/self-quiz.vue:453**
|
|
|
+
|
|
|
+```javascript
|
|
|
+// 原代码
|
|
|
+uni.switchTab({ url: '/pages/wisdom/index' })
|
|
|
+// 改为
|
|
|
+uni.navigateTo({ url: '/pages/wisdom/index' })
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 5:全局 grep 兜底检查**
|
|
|
+
|
|
|
+运行:`grep -rn "switchTab.*/pages/\(mind\|body\|wisdom\|wealth\)" --include="*.vue" .`
|
|
|
+预期:无输出(无遗漏)
|
|
|
+
|
|
|
+- [ ] **步骤 6:Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/pages/index-home/index.vue cfc-frontend/pages/wisdom/index.vue cfc-frontend/pages/wisdom/self-quiz.vue cfc-frontend/pages/wisdom-detail/self-quiz.vue
|
|
|
+git commit -m "fix: replace switchTab with navigateTo for dimension pages moved out of tabbar"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 任务 4:重构 `custom-tab-bar/index.vue`
|
|
|
+
|
|
|
+**文件:**
|
|
|
+- 修改:`cfc-frontend/custom-tab-bar/index.vue`
|
|
|
+
|
|
|
+**职责:** 将自定义 TabBar 重构为 4 个功能 Tab + 中间五维启动器按钮。点击中间按钮弹出半屏浮层,显示行/心/身/智/富 5 个维度入口。
|
|
|
+
|
|
|
+- [ ] **步骤 1:重构 custom-tab-bar 模板**
|
|
|
+
|
|
|
+```html
|
|
|
+<template>
|
|
|
+ <view class="tab-bar-wrap" v-if="isLoggedIn">
|
|
|
+ <!-- 普通用户 TabBar -->
|
|
|
+ <view v-if="currentRole !== 'teacher'" class="tab-bar">
|
|
|
+ <!-- 4 Tab -->
|
|
|
+ <view v-for="(item, index) in mainTabs" :key="index"
|
|
|
+ class="tab-item"
|
|
|
+ :class="{ active: currentIndex === index }"
|
|
|
+ @click="switchTab(item, index)">
|
|
|
+ <image class="tab-icon" :src="currentIndex === index ? item.selectedIcon : item.icon" mode="aspectFit" />
|
|
|
+ <text class="tab-text">{{ item.text }}</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 中间五维启动器按钮 -->
|
|
|
+ <view class="tab-center-btn" @click="toggleDimOverlay">
|
|
|
+ <view class="center-btn-inner">
|
|
|
+ <text class="center-btn-icon">⭐</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 规划师 TabBar(保持不变) -->
|
|
|
+ <view v-else class="tab-bar">
|
|
|
+ <view v-for="(item, index) in teacherTabs" :key="index"
|
|
|
+ class="tab-item"
|
|
|
+ :class="{ active: currentIndex === index }"
|
|
|
+ @click="switchTab(item, index)">
|
|
|
+ <image class="tab-icon" :src="currentIndex === index ? item.selectedIcon : item.icon" mode="aspectFit" />
|
|
|
+ <text class="tab-text">{{ item.text }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 五维半屏浮层 -->
|
|
|
+ <view class="dim-overlay-mask" v-if="showDimOverlay" @click="toggleDimOverlay">
|
|
|
+ <view class="dim-overlay" @click.stop>
|
|
|
+ <view class="dim-overlay-header">
|
|
|
+ <text class="dim-overlay-title">五维能量</text>
|
|
|
+ <text class="dim-overlay-close" @click="toggleDimOverlay">✕</text>
|
|
|
+ </view>
|
|
|
+ <view class="dim-grid">
|
|
|
+ <view class="dim-item" v-for="dim in dimensions" :key="dim.code" @click="goDimPage(dim)">
|
|
|
+ <view class="dim-icon-wrap" :style="{ background: dim.bgColor }">
|
|
|
+ <text class="dim-icon">{{ dim.icon }}</text>
|
|
|
+ </view>
|
|
|
+ <text class="dim-name">{{ dim.name }}</text>
|
|
|
+ <text class="dim-title">{{ dim.title }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 2:重构 script 逻辑**
|
|
|
+
|
|
|
+```javascript
|
|
|
+var nav = require('../utils/nav.js')
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ currentIndex: 0,
|
|
|
+ showDimOverlay: false,
|
|
|
+ mainTabs: [
|
|
|
+ { text: '首页', pagePath: '/pages/index-home/index', icon: '/static/tab-home.png', selectedIcon: '/static/tab-home-active.png' },
|
|
|
+ { text: '健康', pagePath: '/pages/health/index', icon: '/static/tab-health.png', selectedIcon: '/static/tab-health-active.png' },
|
|
|
+ { text: '成长', pagePath: '/pages/growth/index', icon: '/static/tab-growth.png', selectedIcon: '/static/tab-growth-active.png' },
|
|
|
+ { text: '我的', pagePath: '/pages/profile/profile', icon: '/static/tab-profile.png', selectedIcon: '/static/tab-profile-active.png' }
|
|
|
+ ],
|
|
|
+ teacherTabs: [
|
|
|
+ { text: '首页', pagePath: '/pages/teacher/index', icon: '/static/tab-action.png', selectedIcon: '/static/tab-action-active.png' },
|
|
|
+ { text: '家庭', pagePath: '/pages/teacher/families', icon: '/static/tab-family.png', selectedIcon: '/static/tab-family-active.png' },
|
|
|
+ { text: '团队', pagePath: '/pages/teacher/team', icon: '/static/tab-team.png', selectedIcon: '/static/tab-team-active.png' },
|
|
|
+ { text: '成长档案', pagePath: '/pages/growth/index', icon: '/static/tab-growth.png', selectedIcon: '/static/tab-growth-active.png' },
|
|
|
+ { text: '我的', pagePath: '/pages/teacher/teacher-profile', icon: '/static/tab-profile.png', selectedIcon: '/static/tab-profile-active.png' }
|
|
|
+ ],
|
|
|
+ dimensions: [
|
|
|
+ { code: 'action', name: '行', title: '知行合一', icon: '🌿', color: '#10B981', bgColor: 'rgba(16,185,129,0.15)' },
|
|
|
+ { code: 'mind', name: '心', title: '大爱传承', icon: '🔥', color: '#FF6B9D', bgColor: 'rgba(255,107,157,0.15)' },
|
|
|
+ { code: 'body', name: '身', title: '主动健康', icon: '🌏', color: '#FF8C42', bgColor: 'rgba(255,140,66,0.15)' },
|
|
|
+ { code: 'wisdom', name: '智', title: '赋能未来', icon: '⚡', color: '#6366F1', bgColor: 'rgba(99,102,241,0.15)' },
|
|
|
+ { code: 'wealth', name: '富', title: '利他创富', icon: '💧', color: '#F59E0B', bgColor: 'rgba(245,158,11,0.15)' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ isLoggedIn() { return !!uni.getStorageSync('token') },
|
|
|
+ currentRole() { return uni.getStorageSync('currentRole') || 'parent' }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ toggleDimOverlay() { this.showDimOverlay = !this.showDimOverlay },
|
|
|
+ goDimPage(dim) {
|
|
|
+ this.showDimOverlay = false
|
|
|
+ nav.goDimension(dim.code)
|
|
|
+ },
|
|
|
+ switchTab(item, index) {
|
|
|
+ this.currentIndex = index
|
|
|
+ var nativeTabPages = ['/pages/index-home/index', '/pages/health/index', '/pages/growth/index', '/pages/profile/profile']
|
|
|
+ if (nativeTabPages.indexOf(item.pagePath) !== -1) {
|
|
|
+ uni.switchTab({ url: item.pagePath })
|
|
|
+ } else {
|
|
|
+ uni.redirectTo({ url: item.pagePath })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 3:添加半屏浮层样式**
|
|
|
+
|
|
|
+```css
|
|
|
+/* 五维半屏浮层 */
|
|
|
+.dim-overlay-mask {
|
|
|
+ position: fixed;
|
|
|
+ top: 0; left: 0; right: 0; bottom: 0;
|
|
|
+ background: rgba(0,0,0,0.5);
|
|
|
+ z-index: 1000;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-end;
|
|
|
+}
|
|
|
+.dim-overlay {
|
|
|
+ width: 100%;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 32rpx 32rpx 0 0;
|
|
|
+ padding: 40rpx 30rpx 60rpx;
|
|
|
+ animation: slideUp 0.3s ease;
|
|
|
+}
|
|
|
+@keyframes slideUp {
|
|
|
+ from { transform: translateY(100%); }
|
|
|
+ to { transform: translateY(0); }
|
|
|
+}
|
|
|
+.dim-overlay-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 32rpx;
|
|
|
+}
|
|
|
+.dim-overlay-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+.dim-overlay-close {
|
|
|
+ font-size: 36rpx;
|
|
|
+ color: #999;
|
|
|
+ padding: 8rpx;
|
|
|
+}
|
|
|
+.dim-grid {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 20rpx;
|
|
|
+}
|
|
|
+.dim-item {
|
|
|
+ width: calc(33.33% - 14rpx);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ padding: 24rpx 0;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ background: #f8f9fa;
|
|
|
+}
|
|
|
+.dim-icon-wrap {
|
|
|
+ width: 80rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+}
|
|
|
+.dim-icon { font-size: 36rpx; }
|
|
|
+.dim-name { font-size: 28rpx; font-weight: bold; color: #333; }
|
|
|
+.dim-title { font-size: 20rpx; color: #999; margin-top: 4rpx; }
|
|
|
+
|
|
|
+/* 中间按钮 */
|
|
|
+.tab-center-btn {
|
|
|
+ flex: 0 0 auto;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100rpx;
|
|
|
+ position: relative;
|
|
|
+ top: -20rpx;
|
|
|
+}
|
|
|
+.center-btn-inner {
|
|
|
+ width: 88rpx;
|
|
|
+ height: 88rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: linear-gradient(135deg, #F97316, #FB923C);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ box-shadow: 0 4rpx 16rpx rgba(249,115,22,0.4);
|
|
|
+}
|
|
|
+.center-btn-icon { font-size: 40rpx; }
|
|
|
+```
|
|
|
+
|
|
|
+- [ ] **步骤 4:Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/custom-tab-bar/index.vue
|
|
|
+git commit -m "feat: redesign custom tabbar with 4 tabs + center 5-dim launcher"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 任务 5:创建「健康」Tab 页
|
|
|
+
|
|
|
+**文件:**
|
|
|
+- 创建:`cfc-frontend/pages/health/index.vue`
|
|
|
+
|
|
|
+**职责:** 主动健康干预闭环的聚合入口,展示健康概览、测评入口、报告、打卡、饮食/运动/作息等模块。
|
|
|
+
|
|
|
+- [ ] **步骤 1:创建 health/index.vue**
|
|
|
+
|
|
|
+```html
|
|
|
+<template>
|
|
|
+ <view class="container">
|
|
|
+ <tab-transition v-if="showTabTransition" dimCode="body" ref="tabTransition" @close="showTabTransition = false" />
|
|
|
+
|
|
|
+ <!-- 未登录态 -->
|
|
|
+ <template v-if="!isLoggedIn">
|
|
|
+ <PageBanner theme="body"
|
|
|
+ tagline="科学管理全家健康"
|
|
|
+ quote="身体健康是幸福的基础" />
|
|
|
+ <LoginGuideCard
|
|
|
+ title="登录后查看全家健康数据"
|
|
|
+ :items="['查看健康报告', '记录每日健康打卡', '查看专属健康商品']" />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 登录态 -->
|
|
|
+ <template v-else>
|
|
|
+ <PageBanner theme="body"
|
|
|
+ tagline="主动健康 · 闭环管理"
|
|
|
+ quote="测评→报告→方案→执行→追踪" />
|
|
|
+
|
|
|
+ <FamilyMemberStrip
|
|
|
+ :members="familyMembersVisible"
|
|
|
+ :selectedMemberId="selectedMemberId"
|
|
|
+ @select="onFamilyMemberSelect" />
|
|
|
+
|
|
|
+ <!-- 健康概览卡片 -->
|
|
|
+ <view class="section">
|
|
|
+ <view class="health-score-card">
|
|
|
+ <text class="health-score-label">健康综合评分</text>
|
|
|
+ <text class="health-score-value">{{ healthScore || '--' }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 闭环入口网格 -->
|
|
|
+ <view class="func-grid">
|
|
|
+ <view class="func-item" @click="goAssessment">
|
|
|
+ <text class="func-icon">📋</text>
|
|
|
+ <text class="func-label">测评</text>
|
|
|
+ </view>
|
|
|
+ <view class="func-item" @click="goReports">
|
|
|
+ <text class="func-icon">📊</text>
|
|
|
+ <text class="func-label">报告</text>
|
|
|
+ </view>
|
|
|
+ <view class="func-item" @click="goCheckin">
|
|
|
+ <text class="func-icon">✅</text>
|
|
|
+ <text class="func-label">打卡</text>
|
|
|
+ </view>
|
|
|
+ <view class="func-item" @click="goDiet">
|
|
|
+ <text class="func-icon">🍽️</text>
|
|
|
+ <text class="func-label">饮食</text>
|
|
|
+ </view>
|
|
|
+ <view class="func-item" @click="goExercise">
|
|
|
+ <text class="func-icon">🏃</text>
|
|
|
+ <text class="func-label">运动</text>
|
|
|
+ </view>
|
|
|
+ <view class="func-item" @click="goSleep">
|
|
|
+ <text class="func-icon">😴</text>
|
|
|
+ <text class="func-label">作息</text>
|
|
|
+ </view>
|
|
|
+ <view class="func-item" @click="goMeditation">
|
|
|
+ <text class="func-icon">🧘</text>
|
|
|
+ <text class="func-label">冥想</text>
|
|
|
+ </view>
|
|
|
+ <view class="func-item" @click="goBodyDetail">
|
|
|
+ <text class="func-icon">🌏</text>
|
|
|
+ <text class="func-label">身体能量</text>
|
|
|
+ </view>
|
|
|
+ <view class="func-item" @click="goMindDetail">
|
|
|
+ <text class="func-icon">🔥</text>
|
|
|
+ <text class="func-label">心智能量</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <AIFloatingAvatar />
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+```
|
|
|
+
|
|
|
+> 注:完整页面需包含 `data`、`onLoad/onShow`、方法实现(跳转到各分包页)、数据加载等。方法实现参考现有 body/mind 页面的导航逻辑。
|
|
|
+
|
|
|
+- [ ] **步骤 2:Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/pages/health/index.vue
|
|
|
+git commit -m "feat: add health tab page as health intervention closed-loop hub"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 任务 6:验证 teacher 角色 TabBar 流程
|
|
|
+
|
|
|
+**文件:**
|
|
|
+- 检查:`cfc-frontend/custom-tab-bar/index.vue`
|
|
|
+- 检查:`cfc-frontend/pages/profile/profile.vue`
|
|
|
+
|
|
|
+**职责:** 确保 teacher 角色的独立 TabBar 不受影响,profile 页面的 teacher 重定向逻辑保持正常。
|
|
|
+
|
|
|
+- [ ] **步骤 1:检查 teacher 流程**
|
|
|
+
|
|
|
+确认 teacher 的 TabBar 在 custom-tab-bar 中通过 `v-if="currentRole === 'teacher'"` 分支渲染,中间按钮不显示。
|
|
|
+
|
|
|
+- [ ] **步骤 2:检查 profile 重定向**
|
|
|
+
|
|
|
+profile.vue 中 `onShow` 检测 `currentRole === 'teacher'` 时 redirectTo teacher-profile 的逻辑不变。teacher 点击"我的"Tab 时,切到 profile 但立即重定向,不影响体验。
|
|
|
+
|
|
|
+- [ ] **步骤 3:Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add cfc-frontend/custom-tab-bar/index.vue
|
|
|
+git commit -m "fix: preserve teacher tabbar and role redirect logic"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 任务 7:构建验证
|
|
|
+
|
|
|
+**职责:** 确保项目构建通过,无路由错误。
|
|
|
+
|
|
|
+- [ ] **步骤 1:npm run build**
|
|
|
+
|
|
|
+```bash
|
|
|
+cd cfc-frontend && npm run build:mp-weixin
|
|
|
+```
|
|
|
+
|
|
|
+预期:构建成功,无报错。
|
|
|
+
|
|
|
+- [ ] **步骤 2:全局路由引用检查**
|
|
|
+
|
|
|
+```bash
|
|
|
+grep -rn "switchTab.*\/pages\/\(mind\|body\|wisdom\|wealth\)\/index" --include="*.vue" .
|
|
|
+```
|
|
|
+
|
|
|
+预期:无输出(所有 switchTab 已改为 navigateTo)。
|
|
|
+
|
|
|
+- [ ] **步骤 3:Commit**
|
|
|
+
|
|
|
+```bash
|
|
|
+git add .
|
|
|
+git commit -m "chore: verify build and route integrity"
|
|
|
+```
|