diff --git a/miniprogram/app.json b/miniprogram/app.json index 35f9c5a..9ca157d 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -1,18 +1,19 @@ { "pages": [ - "pages/userManagement/userManagement", + "pages/home/home", "pages/login/login", "pages/supplementPersonal/supplementPersonal", "pages/connectedDevice/connectedDevice", "pages/connectedWifi/connectedWifi", - "pages/home/home", "pages/equipment/equipment", + "pages/userManagement/userManagement", "pages/addUser/addUser", "pages/data/data", "pages/my/my", "pages/personalInformation/personalInformation", "pages/helpCenter/helpCenter", - "pages/questionDetails/questionDetails" + "pages/questionDetails/questionDetails", + "pages/detailedReport/detailedReport" ], "usingComponents": { "empty-data": "/components/emptyData/emptyData" diff --git a/miniprogram/components/navBar/navBar.json b/miniprogram/components/navBar/navBar.json new file mode 100644 index 0000000..e32c3ff --- /dev/null +++ b/miniprogram/components/navBar/navBar.json @@ -0,0 +1,5 @@ +{ + "component": true, + "usingComponents": {}, + "multipleSlots": true +} \ No newline at end of file diff --git a/miniprogram/components/navBar/navBar.less b/miniprogram/components/navBar/navBar.less new file mode 100644 index 0000000..f4b809b --- /dev/null +++ b/miniprogram/components/navBar/navBar.less @@ -0,0 +1,60 @@ +.nav-spacer { + width: 100%; +} + +.nav-wrap { + width: 100%; +} + +.nav-content { + width: 100%; + display: flex; + align-items: center; + position: relative; + box-sizing: border-box; +} + +.nav-left { + height: 100%; + flex-shrink: 0; + z-index: 1; + display: flex; + align-items: center; +} + +.back-btn { + width: 60rpx; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +.back-arrow { + width: 18rpx; + height: 18rpx; + border-left: 4rpx solid #252535; + border-bottom: 4rpx solid #252535; + transform: rotate(45deg); +} + +.nav-center { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 0; + pointer-events: none; +} + +.nav-title { + color: #252535; + font-size: 16px; + font-weight: bold; + line-height: 1; + pointer-events: auto; +} diff --git a/miniprogram/components/navBar/navBar.ts b/miniprogram/components/navBar/navBar.ts new file mode 100644 index 0000000..853cee5 --- /dev/null +++ b/miniprogram/components/navBar/navBar.ts @@ -0,0 +1,61 @@ +import { getNavBarLayout } from '../../utils/navBar/index'; + +Component({ + options: { + multipleSlots: true, + }, + + properties: { + title: { type: String, value: '' }, + back: { type: String, value: 'auto' }, + fixed: { type: Boolean, value: false }, + zIndex: { type: Number, value: 100 }, + bgColor: { type: String, value: 'transparent' }, + color: { type: String, value: '#252535' }, + arrowColor: { type: String, value: '#252535' }, + }, + + data: { + statusBarHeight: 0, + navBarHeight: 44, + totalNavHeight: 0, + navPaddingRight: 0, + _showBack: false, + _spacerHeight: 'auto', + _navStyle: '', + }, + + lifetimes: { + attached() { + const layout = getApp().globalData.navBarLayout || getNavBarLayout(); + this._applyLayout(layout); + }, + }, + + observers: { + 'fixed, back, zIndex'(_fixed: boolean, _back: string, _zIndex: number) { + const layout = getApp().globalData.navBarLayout || getNavBarLayout(); + this._applyLayout(layout); + }, + }, + + methods: { + _applyLayout(layout: ReturnType) { + const { fixed, back, zIndex } = this.properties; + const _showBack = back === 'show' || (back === 'auto' && getCurrentPages().length > 1); + + this.setData({ + ...layout, + _showBack, + _spacerHeight: fixed ? layout.totalNavHeight + 'px' : 'auto', + _navStyle: fixed + ? `position: fixed; top: 0; left: 0; right: 0; z-index: ${zIndex};` + : '', + }); + }, + + onBack() { + wx.navigateBack({ delta: 1 }); + }, + }, +}); diff --git a/miniprogram/components/navBar/navBar.wxml b/miniprogram/components/navBar/navBar.wxml new file mode 100644 index 0000000..a1a2d1d --- /dev/null +++ b/miniprogram/components/navBar/navBar.wxml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + {{title}} + + + + \ No newline at end of file diff --git a/miniprogram/pages/detailedReport/detailedReport.json b/miniprogram/pages/detailedReport/detailedReport.json new file mode 100644 index 0000000..79e97ab --- /dev/null +++ b/miniprogram/pages/detailedReport/detailedReport.json @@ -0,0 +1,6 @@ +{ + "usingComponents": { + "navBar": "/components/navBar/navBar" + }, + "navigationStyle": "custom" +} diff --git a/miniprogram/pages/detailedReport/detailedReport.less b/miniprogram/pages/detailedReport/detailedReport.less new file mode 100644 index 0000000..a00e4bc --- /dev/null +++ b/miniprogram/pages/detailedReport/detailedReport.less @@ -0,0 +1,276 @@ +.detailedReport { + width: 100%; + height: 100%; + //padding: 24rpx 32rpx; + //box-sizing: border-box; + //background-color: #F5F7FB; + + .scrollViewContent { + width: 100%; + padding: 24rpx 32rpx; + box-sizing: border-box; + + /* 顶部头部 */ + .header { + width: 100%; + height: 360rpx; + border-radius: 24rpx; + background: linear-gradient(135deg, #C0E0FD 0%, #E2E9F9 100%); + display: flex; + flex-direction: column; + justify-content: center; + padding: 0 40rpx; + box-sizing: border-box; + margin-bottom: 24rpx; + + .header-slogan { + margin-bottom: 24rpx; + + .slogan-title { + color: #1A3F68; + height: 32rpx; + font-size: 32rpx; + line-height: 32rpx; + } + + .slogan-sub { + color: #446D99; + height: 26rpx; + font-size: 26rpx; + line-height: 26rpx; + margin-top: 12rpx; + } + } + + .header-date { + color: #FFFFFF; + height: 26rpx; + font-size: 26rpx; + line-height: 26rpx; + } + + .header-weight { + display: flex; + align-items: flex-end; + margin-top: 24rpx; + + .weight-num { + color: #FFFFFF; + height: 120rpx; + font-size: 120rpx; + line-height: 120rpx; + } + + .weight-unit { + color: #FFFFFF; + height: 28rpx; + font-size: 28rpx; + line-height: 28rpx; + margin: 0 0 24rpx 12rpx; + } + } + + .header-info { + display: flex; + align-items: center; + margin-top: 16rpx; + + .header-bmi { + color: #FFFFFF; + height: 22rpx; + font-size: 22rpx; + line-height: 22rpx; + margin-right: 24rpx; + } + + .header-change { + color: #FFFFFF; + height: 22rpx; + font-size: 22rpx; + line-height: 22rpx; + } + } + } + + /* 卡片 */ + .card { + width: 100%; + padding: 32rpx; + border-radius: 24rpx; + background-color: #FFFFFF; + box-sizing: border-box; + margin-bottom: 24rpx; + + .card-title { + display: flex; + align-items: center; + margin-bottom: 24rpx; + + .title-bar { + width: 6rpx; + height: 20rpx; + border-radius: 4rpx; + background-color: #1385FA; + margin-right: 16rpx; + } + + .title-text { + color: #252535; + height: 32rpx; + font-size: 32rpx; + line-height: 32rpx; + } + } + + /* 基础指标 2x2 */ + .basic-grid { + display: flex; + flex-wrap: wrap; + + .basic-item { + width: 50%; + box-sizing: border-box; + padding: 24rpx 0; + + .basic-label { + color: #808080; + height: 26rpx; + font-size: 26rpx; + line-height: 26rpx; + margin-bottom: 16rpx; + } + + .basic-value-row { + display: flex; + align-items: flex-end; + + .basic-value { + color: #252535; + height: 48rpx; + font-size: 48rpx; + line-height: 48rpx; + } + + .basic-unit { + color: #252535; + height: 26rpx; + font-size: 26rpx; + line-height: 26rpx; + margin: 0 0 6rpx 8rpx; + } + + .basic-tag { + height: 30rpx; + padding: 0 10rpx; + font-size: 18rpx; + line-height: 30rpx; + border-radius: 8rpx; + color: #FFFFFF; + background-color: #2AC79F; + margin: 0 0 6rpx 12rpx; + } + } + } + } + + /* BMI 刻度 */ + .bmi-scale { + margin-top: 24rpx; + + .scale-track { + display: flex; + height: 20rpx; + border-radius: 6rpx; + overflow: hidden; + + .scale-block { + flex: 1; + } + + .scale-block--low { + background-color: #1385FA; + } + + .scale-block--normal { + background-color: #2AC79F; + } + + .scale-block--over { + background-color: #FFA151; + } + + .scale-block--obese { + background-color: #F24439; + } + } + + .scale-row { + display: flex; + margin-top: 16rpx; + + > view { + flex: 1; + text-align: center; + color: #77849E; + height: 24rpx; + font-size: 24rpx; + line-height: 24rpx; + } + } + + .scale-row--range { + margin-top: 12rpx; + + > view { + color: #B6B6B6; + height: 20rpx; + font-size: 20rpx; + line-height: 20rpx; + } + } + } + + /* 指标行 */ + .metric-row { + width: 100%; + display: flex; + align-items: center; + padding: 20rpx 0; + + .metric-label { + flex: 1; + color: #77849E; + height: 28rpx; + font-size: 28rpx; + line-height: 28rpx; + } + + .metric-value { + color: #252535; + height: 28rpx; + font-size: 28rpx; + line-height: 28rpx; + margin-right: 24rpx; + } + + .metric-status { + height: 24rpx; + font-size: 24rpx; + line-height: 24rpx; + } + + .metric-status--normal { + color: #2AC79F; + } + + .metric-status--low { + color: #1385FA; + } + + .metric-status--high { + color: #F24439; + } + } + } + } +} diff --git a/miniprogram/pages/detailedReport/detailedReport.ts b/miniprogram/pages/detailedReport/detailedReport.ts new file mode 100644 index 0000000..0588860 --- /dev/null +++ b/miniprogram/pages/detailedReport/detailedReport.ts @@ -0,0 +1,105 @@ +// pages/detailedReport/detailedReport.ts +Page({ + data: { + // 导航栏背景色,根据滚动位置动态变化 + navBgColor: 'rgba(255,255,255,0)', + + header: { + date: '2026-07-23 16:32', + weight: '68.80', + unit: 'kg', + bmi: 'BMI正常', + change: '较上次-0.3kg' + }, + basic: [ + { label: '身高', value: '172', unit: 'cm', tag: '' }, + { label: 'BMI', value: '22.4', unit: '', tag: '标准' }, + { label: '身体得分', value: '73', unit: '分', tag: '一般' }, + { label: '体脂率', value: '22.1', unit: '%', tag: '' } + ], + sections: [ + { + title: '身体成分', + items: [ + { label: '水分率', value: '50%', status: '不足', statusClass: 'low' }, + { label: '水分量', value: '30.6kg', status: '标准', statusClass: 'normal' }, + { label: '蛋白质率', value: '10%', status: '超量', statusClass: 'high' }, + { label: '蛋白质量', value: '8.2kg', status: '标准', statusClass: 'normal' }, + { label: '脂肪量', value: '14.3kg', status: '标准', statusClass: 'normal' }, + { label: '肌肉量', value: '38.8kg', status: '标准', statusClass: 'normal' }, + { label: '肌肉率', value: '69.2%', status: '标准', statusClass: 'normal' }, + { label: '骨骼肌量', value: '22.5kg', status: '标准', statusClass: 'normal' }, + { label: '骨骼肌率', value: '40%', status: '标准', statusClass: 'normal' }, + { label: '骨量', value: '2.3kg', status: '标准', statusClass: 'normal' } + ] + }, + { + title: '脂肪分析', + items: [ + { label: '内脏脂肪', value: '6', status: '不足', statusClass: 'low' }, + { label: '皮下脂肪率', value: '22.5%', status: '标准', statusClass: 'normal' }, + { label: '皮下脂肪量', value: '12.6kg', status: '标准', statusClass: 'normal' } + ] + }, + { + title: '体态管理', + items: [ + { label: '理想体重', value: '62.1kg', status: '标准', statusClass: 'normal' }, + { label: '去脂体重', value: '41.7kg', status: '标准', statusClass: 'normal' }, + { label: '身体年龄', value: '20岁', status: '标准', statusClass: 'normal' }, + { label: '身体类型', value: '缺乏运动型', status: '标准', statusClass: 'normal' }, + { label: '推测腰臀比', value: '0.8%', status: '标准', statusClass: 'normal' } + ] + }, + { + title: '体重管控', + items: [ + { label: '控制体重', value: '3.9kg', status: '标准', statusClass: 'normal' }, + { label: '脂肪控制量', value: '-0.5kg', status: '标准', statusClass: 'normal' }, + { label: '肌肉控制量', value: '4.4kg', status: '标准', statusClass: 'normal' } + ] + }, + { + title: '细胞液分析', + items: [ + { label: '细胞内水量', value: '11.4kg', status: '标准', statusClass: 'normal' }, + { label: '细胞外水量', value: '19.1kg', status: '标准', statusClass: 'normal' }, + { label: '无机盐量', value: '2.9kg', status: '不足', statusClass: 'low' }, + { label: '身体细胞量', value: '27.4kg', status: '标准', statusClass: 'normal' }, + { label: '骨骼肌质量指数', value: '7.2kg/m²', status: '标准', statusClass: 'normal' } + ] + } + ], + limbSections: [ + { + title: '躯干/四肢脂肪', + items: [ + { label: '左臂', value: '2.3kg丨80.9%' }, + { label: '右臂', value: '2.3kg丨80.9%' }, + { label: '左腿', value: '6.3kg丨100%' }, + { label: '右腿', value: '6.3kg丨100%' }, + { label: '躯干', value: '18.4kg丨97.8%' } + ] + }, + { + title: '躯干/四肢肌肉', + items: [ + { label: '左臂', value: '2.3kg丨80.9%' }, + { label: '右臂', value: '2.3kg丨80.9%' }, + { label: '左腿', value: '6.3kg丨100%' }, + { label: '右腿', value: '6.3kg丨100%' }, + { label: '躯干', value: '18.4kg丨97.8%' } + ] + } + ] + }, + + // 滚动时导航栏背景渐显 + onScroll(e: WechatMiniprogram.ScrollViewScroll) { + const scrollTop = e.detail.scrollTop; + const opacity = Math.min(Math.max(scrollTop / 300, 0), 1); + this.setData({ + navBgColor: `rgba(255,255,255,${opacity})`, + }); + }, +}) diff --git a/miniprogram/pages/detailedReport/detailedReport.wxml b/miniprogram/pages/detailedReport/detailedReport.wxml new file mode 100644 index 0000000..b097eef --- /dev/null +++ b/miniprogram/pages/detailedReport/detailedReport.wxml @@ -0,0 +1,98 @@ + + + + + + + + + + 设备智联 · 掌握健康 + 留存测量记录,见证身形变化 + + {{ header.date }} + + {{ header.weight }} + {{ header.unit }} + + + {{ header.bmi }} + {{ header.change }} + + + + + + + + 基础指标 + + + + + {{ item.label }} + + {{ item.value }} + {{ item.unit }} + {{ item.tag }} + + + + + + + + + + + + + 消瘦 + 正常 + 超重 + 肥胖 + + + BMI<18.5 + 18.5≤BMI<24 + 24≤BMI<28 + BMI≥28 + + + + + + + + + + {{ section.title }} + + + + {{ item.label }} + {{ item.value }} + {{ item.status }} + + + + + + + + + + + {{ section.title }} + + + + {{ item.label }} + {{ item.value }} + + + + + + + diff --git a/miniprogram/pages/home/home.less b/miniprogram/pages/home/home.less index dafffe8..c31e154 100644 --- a/miniprogram/pages/home/home.less +++ b/miniprogram/pages/home/home.less @@ -123,7 +123,11 @@ height: 32rpx; font-size: 26rpx; line-height: 32rpx; - padding-right: 50rpx; + padding-right: 20rpx; + + &::after { + right: 0; + } } } diff --git a/miniprogram/pages/home/home.ts b/miniprogram/pages/home/home.ts index e7c888e..9dee101 100644 --- a/miniprogram/pages/home/home.ts +++ b/miniprogram/pages/home/home.ts @@ -33,4 +33,9 @@ Page({ onTapSwitchDevice() { wx.switchTab({ url: '/pages/equipment/equipment' }) }, + + /** 跳转详细报告页 */ + onTapDetailedReport() { + wx.navigateTo({ url: '/pages/detailedReport/detailedReport' }) + }, }) diff --git a/miniprogram/pages/home/home.wxml b/miniprogram/pages/home/home.wxml index 8b5c53b..da06a59 100644 --- a/miniprogram/pages/home/home.wxml +++ b/miniprogram/pages/home/home.wxml @@ -21,7 +21,7 @@ 最近测量 - 详细报告 + 详细报告 diff --git a/miniprogram/pages/my/my.json b/miniprogram/pages/my/my.json index d2a12c7..a55c21c 100644 --- a/miniprogram/pages/my/my.json +++ b/miniprogram/pages/my/my.json @@ -1,4 +1,6 @@ { - "usingComponents": {}, - "navigationStyle": "custom" + "usingComponents": { + "navBar": "/components/navBar/navBar" + }, + "navigationStyle": "custom" } \ No newline at end of file diff --git a/miniprogram/pages/my/my.ts b/miniprogram/pages/my/my.ts index 3535b49..d1b37db 100644 --- a/miniprogram/pages/my/my.ts +++ b/miniprogram/pages/my/my.ts @@ -5,7 +5,8 @@ Page({ * 页面的初始数据 */ data: { - + // 导航栏背景色,根据滚动位置动态变化 + navBgColor: 'rgba(255,255,255,0)', }, /** @@ -15,6 +16,15 @@ Page({ }, + // 滚动时导航栏背景渐显 + onScroll(e: WechatMiniprogram.ScrollViewScroll) { + const scrollTop = e.detail.scrollTop; + const opacity = Math.min(Math.max(scrollTop / 300, 0), 1); + this.setData({ + navBgColor: `rgba(255,255,255,${opacity})`, + }); + }, + onTapPersonalInfo() { wx.navigateTo({ url: '/pages/personalInformation/personalInformation' }) }, diff --git a/miniprogram/pages/my/my.wxml b/miniprogram/pages/my/my.wxml index 91e9954..a6467c2 100644 --- a/miniprogram/pages/my/my.wxml +++ b/miniprogram/pages/my/my.wxml @@ -1,3 +1,5 @@ + + diff --git a/miniprogram/utils/navBar/index.ts b/miniprogram/utils/navBar/index.ts new file mode 100644 index 0000000..150c2f4 --- /dev/null +++ b/miniprogram/utils/navBar/index.ts @@ -0,0 +1,53 @@ +/** + * 获取自定义导航栏布局参数,应用启动时调用一次存入 globalData, + * 各页面直接从 getApp().globalData.navBarLayout 取值即可。 + * + * 布局示意: + * ┌──────────────────────────────────┐ + * │ 状态栏 (statusBar) │ ← statusBarHeight + * ├──────────────────────────────────┤ ← navContentTop + * │ ┌─┐ ┌─────────┐ ┌──────┐ │ + * │ │←│ │ 标题 │ │ 胶囊 │ │ ← navBarHeight + * │ └─┘ └─────────┘ └──────┘ │ + * └──────────────────────────────────┘ + * |← capsuleLeft →| |← capRight →| + * |← windowWidth →| + * + * 返回键放置示例(非 tabBar 页面): + * 判断显示:getCurrentPages().length > 1 + * WXML: + * ← 返回 + */ +export const getNavBarLayout = () => { + const sys = wx.getWindowInfo(); + const capsule = wx.getMenuButtonBoundingClientRect(); + const statusBarHeight = sys.statusBarHeight || 0; + const navBarHeight = capsule.height + (capsule.top - statusBarHeight) * 2; + return { + /** 状态栏高度 */ + statusBarHeight, + /** 导航栏内容区高度(不含状态栏) */ + navBarHeight, + /** 状态栏 + 导航栏总高度,页面顶部占位直接设这个即可 */ + totalNavHeight: statusBarHeight + navBarHeight, + /** 导航栏内容区起始 Y 坐标(状态栏底部),放置返回键、标题等元素以此为 top */ + navContentTop: statusBarHeight, + /** 屏幕宽度 */ + windowWidth: sys.windowWidth, + /** 胶囊按钮宽度 */ + capsuleWidth: capsule.width, + /** 胶囊按钮高度 */ + capsuleHeight: capsule.height, + /** 胶囊按钮距屏幕顶部距离,垂直对齐自定义元素时以此为基准 */ + capsuleTop: capsule.top, + /** 胶囊按钮距屏幕左侧距离 */ + capsuleLeft: capsule.left, + /** 胶囊按钮距屏幕右侧距离 */ + capsuleRight: sys.windowWidth - capsule.right, + /** 导航栏右侧安全内边距,避免内容被胶囊遮挡 */ + navPaddingRight: sys.windowWidth - capsule.left, + }; +};