[AI Generated]: feat(*): 完善数据页切换成员、首页接口对接及我的页缓存信息展示
This commit is contained in:
@@ -1,69 +0,0 @@
|
|||||||
/** 时间范围 */
|
|
||||||
export type TimeRange = '7d' | '30d' | '3m'
|
|
||||||
|
|
||||||
/** 单条测量记录 */
|
|
||||||
export interface RecordItem {
|
|
||||||
id: string
|
|
||||||
/** 格式 YYYY.MM.DD HH:mm */
|
|
||||||
time: string
|
|
||||||
weight: number
|
|
||||||
bmi: number
|
|
||||||
/** 体脂率(%) */
|
|
||||||
bodyFat: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 统计指标 */
|
|
||||||
export interface StatsData {
|
|
||||||
maxWeight: number
|
|
||||||
minWeight: number
|
|
||||||
avgWeight: number
|
|
||||||
/** 体重变化(kg,正=增重,负=减轻) */
|
|
||||||
weightDiff: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 全量 mock 记录(最近 3 个月数据,按时间倒序) */
|
|
||||||
const ALL_RECORDS: RecordItem[] = [
|
|
||||||
{ id: 'r-001', time: '2026.05.12 08:12', weight: 68.2, bmi: 22.0, bodyFat: 18.5 },
|
|
||||||
{ id: 'r-002', time: '2026.05.11 21:30', weight: 68.5, bmi: 22.1, bodyFat: 18.7 },
|
|
||||||
{ id: 'r-003', time: '2026.05.10 08:05', weight: 68.8, bmi: 22.3, bodyFat: 18.9 },
|
|
||||||
{ id: 'r-004', time: '2026.05.09 07:58', weight: 69.0, bmi: 22.4, bodyFat: 19.0 },
|
|
||||||
{ id: 'r-005', time: '2026.05.08 22:10', weight: 69.3, bmi: 22.5, bodyFat: 19.2 },
|
|
||||||
{ id: 'r-006', time: '2026.05.07 08:20', weight: 69.5, bmi: 22.6, bodyFat: 19.3 },
|
|
||||||
{ id: 'r-007', time: '2026.05.06 08:00', weight: 70.0, bmi: 22.7, bodyFat: 19.5 },
|
|
||||||
{ id: 'r-008', time: '2026.04.30 08:10', weight: 70.3, bmi: 22.8, bodyFat: 19.7 },
|
|
||||||
{ id: 'r-009', time: '2026.04.20 07:45', weight: 71.0, bmi: 23.0, bodyFat: 20.0 },
|
|
||||||
{ id: 'r-010', time: '2026.04.10 08:30', weight: 71.8, bmi: 23.2, bodyFat: 20.3 },
|
|
||||||
{ id: 'r-011', time: '2026.03.28 08:15', weight: 72.5, bmi: 23.5, bodyFat: 20.7 },
|
|
||||||
{ id: 'r-012', time: '2026.03.15 09:00', weight: 73.2, bmi: 23.7, bodyFat: 21.0 },
|
|
||||||
{ id: 'r-013', time: '2026.03.01 08:05', weight: 73.8, bmi: 23.9, bodyFat: 21.3 },
|
|
||||||
]
|
|
||||||
|
|
||||||
/** 各时间范围截取数量 */
|
|
||||||
const RANGE_COUNTS: Record<TimeRange, number> = {
|
|
||||||
'7d': 7,
|
|
||||||
'30d': 10,
|
|
||||||
'3m': 13,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 按时间范围获取 mock 记录列表
|
|
||||||
*/
|
|
||||||
export function getMockRecords(range: TimeRange): RecordItem[] {
|
|
||||||
return ALL_RECORDS.slice(0, RANGE_COUNTS[range])
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据记录列表计算统计指标
|
|
||||||
*/
|
|
||||||
export function calcStats(records: RecordItem[]): StatsData {
|
|
||||||
if (!records.length) {
|
|
||||||
return { maxWeight: 0, minWeight: 0, avgWeight: 0, weightDiff: 0 }
|
|
||||||
}
|
|
||||||
const weights = records.map(r => r.weight)
|
|
||||||
const maxWeight = Math.max(...weights)
|
|
||||||
const minWeight = Math.min(...weights)
|
|
||||||
const avgWeight = parseFloat((weights.reduce((a, b) => a + b, 0) / weights.length).toFixed(1))
|
|
||||||
// 最新 - 最旧
|
|
||||||
const weightDiff = parseFloat((weights[0] - weights[weights.length - 1]).toFixed(1))
|
|
||||||
return { maxWeight, minWeight, avgWeight, weightDiff }
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/** 最近一次测量记录 */
|
|
||||||
export interface WeightRecord {
|
|
||||||
/** 体重整数部分 */
|
|
||||||
weight: number
|
|
||||||
/** 体重小数部分,含小数点,如 ".20" */
|
|
||||||
weightDecimal: string
|
|
||||||
/** 测量时间显示,如 "今日 07:30" */
|
|
||||||
date: string
|
|
||||||
/** 与上次相比差值(负=减轻,正=增重) */
|
|
||||||
diff: number
|
|
||||||
/** 身高(cm) */
|
|
||||||
height: number
|
|
||||||
/** BMI 值 */
|
|
||||||
bmi: number
|
|
||||||
/** BMI 评级标签 */
|
|
||||||
bmiLabel: string
|
|
||||||
/** 标准体重(kg) */
|
|
||||||
stdWeight: number
|
|
||||||
/** 体脂率(%) */
|
|
||||||
bodyFat: number
|
|
||||||
/** 体脂肪(kg) */
|
|
||||||
bodyFatMass: number
|
|
||||||
/** 基础代谢(kcal) */
|
|
||||||
bmr: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Mock 最近一次测量记录 */
|
|
||||||
export const mockLatestRecord: WeightRecord = {
|
|
||||||
weight: 68,
|
|
||||||
weightDecimal: '.20',
|
|
||||||
date: '今日 07:30',
|
|
||||||
diff: -0.3,
|
|
||||||
height: 176,
|
|
||||||
bmi: 22.4,
|
|
||||||
bmiLabel: '标准',
|
|
||||||
stdWeight: 67.2,
|
|
||||||
bodyFat: 22.3,
|
|
||||||
bodyFatMass: 15.2,
|
|
||||||
bmr: 1652,
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/** 成员项(与 equipmentMember / data 页面共享结构) */
|
|
||||||
export interface MemberItem {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
gender: '男' | '女'
|
|
||||||
age: number
|
|
||||||
/** 身高(cm) */
|
|
||||||
height: number
|
|
||||||
/** 头像色块 */
|
|
||||||
avatar: string
|
|
||||||
isSelf: boolean
|
|
||||||
/** 他人添加的成员(只读,不显示编辑/删除) */
|
|
||||||
isFromOther: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 头像色块池 */
|
|
||||||
const AVATAR_COLORS = ['#1385FA', '#2AC79F', '#FF8FAB', '#FFB347', '#A78BFA', '#F87171']
|
|
||||||
|
|
||||||
/** Mock 成员列表 */
|
|
||||||
export const mockMembers: MemberItem[] = [
|
|
||||||
{
|
|
||||||
id: 'm-001',
|
|
||||||
name: '陈小飞',
|
|
||||||
gender: '男',
|
|
||||||
age: 28,
|
|
||||||
height: 175,
|
|
||||||
avatar: AVATAR_COLORS[0],
|
|
||||||
isSelf: true,
|
|
||||||
isFromOther: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'm-002',
|
|
||||||
name: '李镇南',
|
|
||||||
gender: '男',
|
|
||||||
age: 32,
|
|
||||||
height: 178,
|
|
||||||
avatar: AVATAR_COLORS[1],
|
|
||||||
isSelf: false,
|
|
||||||
isFromOther: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'm-003',
|
|
||||||
name: '张颖',
|
|
||||||
gender: '女',
|
|
||||||
age: 26,
|
|
||||||
height: 165,
|
|
||||||
avatar: AVATAR_COLORS[2],
|
|
||||||
isSelf: false,
|
|
||||||
isFromOther: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'm-004',
|
|
||||||
name: '王建国',
|
|
||||||
gender: '男',
|
|
||||||
age: 60,
|
|
||||||
height: 170,
|
|
||||||
avatar: AVATAR_COLORS[3],
|
|
||||||
isSelf: false,
|
|
||||||
isFromOther: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成下一个可用的头像色块
|
|
||||||
* @param existingCount 已有成员数量
|
|
||||||
*/
|
|
||||||
export function nextAvatarColor(existingCount: number): string {
|
|
||||||
return AVATAR_COLORS[existingCount % AVATAR_COLORS.length]
|
|
||||||
}
|
|
||||||
@@ -54,7 +54,7 @@ const EMPTY_STATS: MeasureStatistics = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 从生日字符串(YYYY-MM-DD)计算周岁 */
|
/** 从生日字符串(YYYY-MM-DD)计算周岁 */
|
||||||
function calcAge(birthday: string): number {
|
const calcAge = (birthday: string): number => {
|
||||||
if (!birthday) return 0
|
if (!birthday) return 0
|
||||||
const [year, month, day] = birthday.split('-').map(Number)
|
const [year, month, day] = birthday.split('-').map(Number)
|
||||||
if (!year || !month || !day) return 0
|
if (!year || !month || !day) return 0
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ interface DeviceCard {
|
|||||||
* 从生日字符串(YYYY-MM-DD)计算周岁
|
* 从生日字符串(YYYY-MM-DD)计算周岁
|
||||||
* @param birthday 生日字符串
|
* @param birthday 生日字符串
|
||||||
*/
|
*/
|
||||||
function calcAge(birthday: string): number {
|
const calcAge = (birthday: string): number => {
|
||||||
if (!birthday) return 0
|
if (!birthday) return 0
|
||||||
const parts = birthday.split('-').map(Number)
|
const parts = birthday.split('-').map(Number)
|
||||||
const [year, month, day] = parts
|
const [year, month, day] = parts
|
||||||
@@ -81,26 +81,16 @@ function calcAge(birthday: string): number {
|
|||||||
return Math.max(0, age)
|
return Math.max(0, age)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const toDeviceMember = (m: MemberDisplay): DeviceMember => ({
|
||||||
* MemberDisplay → DeviceMember 转换,供 lefu 同步层使用
|
id: m.id,
|
||||||
* @param m 展示用成员
|
name: m.realname,
|
||||||
*/
|
gender: m.sex === 1 ? 1 : 0,
|
||||||
function toDeviceMember(m: MemberDisplay): DeviceMember {
|
age: m.age,
|
||||||
return {
|
height: m.height,
|
||||||
id: m.id,
|
isSelf: m.relationType === 1,
|
||||||
name: m.realname,
|
})
|
||||||
gender: m.sex === 1 ? 1 : 0,
|
|
||||||
age: m.age,
|
|
||||||
height: m.height,
|
|
||||||
isSelf: m.relationType === 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
const syncToDevice = (members: MemberDisplay[]): void => {
|
||||||
* 将成员列表全量同步到设备
|
|
||||||
* @param members 展示用成员列表
|
|
||||||
*/
|
|
||||||
function syncToDevice(members: MemberDisplay[]): void {
|
|
||||||
const deviceMembers = members.map(toDeviceMember)
|
const deviceMembers = members.map(toDeviceMember)
|
||||||
wx.showLoading({ title: '正在同步成员...', mask: true })
|
wx.showLoading({ title: '正在同步成员...', mask: true })
|
||||||
lefuService.syncMembersToDevice(deviceMembers)
|
lefuService.syncMembersToDevice(deviceMembers)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { get } from '../../utils/request/index'
|
import { get } from '../../utils/request/index'
|
||||||
|
import { lefuService } from '../../lefu/index'
|
||||||
|
|
||||||
/** 设备信息 */
|
/** 设备信息 */
|
||||||
interface DeviceInfo {
|
interface DeviceInfo {
|
||||||
@@ -49,7 +50,7 @@ interface StorageUserInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 将体重数字拆成整数 + 小数字符串 */
|
/** 将体重数字拆成整数 + 小数字符串 */
|
||||||
function splitWeight(weight: number): { int: number; decimal: string } {
|
const splitWeight = (weight: number): { int: number; decimal: string } => {
|
||||||
const str = weight.toFixed(2)
|
const str = weight.toFixed(2)
|
||||||
const [intPart, decPart] = str.split('.')
|
const [intPart, decPart] = str.split('.')
|
||||||
return { int: Number(intPart), decimal: `.${decPart}` }
|
return { int: Number(intPart), decimal: `.${decPart}` }
|
||||||
@@ -66,9 +67,28 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
this.setData({
|
||||||
|
'device.connected': lefuService.isConnected,
|
||||||
|
'device.name': lefuService.deviceInfo?.name ?? '智能体重秤',
|
||||||
|
})
|
||||||
|
lefuService.onDeviceInfo((info) => {
|
||||||
|
this.setData({ 'device.name': info.name ?? '智能体重秤' })
|
||||||
|
})
|
||||||
|
lefuService.onDeviceConnect(() => {
|
||||||
|
this.setData({ 'device.connected': true })
|
||||||
|
})
|
||||||
|
lefuService.onDisconnected(() => {
|
||||||
|
this.setData({ 'device.connected': false })
|
||||||
|
})
|
||||||
this.loadData()
|
this.loadData()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onUnload() {
|
||||||
|
lefuService.onDeviceConnect(() => {})
|
||||||
|
lefuService.onDisconnected(() => {})
|
||||||
|
lefuService.onDeviceInfo(() => {})
|
||||||
|
},
|
||||||
|
|
||||||
onShareAppMessage(): WechatMiniprogram.Page.ICustomShareContent {
|
onShareAppMessage(): WechatMiniprogram.Page.ICustomShareContent {
|
||||||
return {
|
return {
|
||||||
title: '智能蓝牙秤',
|
title: '智能蓝牙秤',
|
||||||
@@ -118,8 +138,8 @@ Page({
|
|||||||
wx.switchTab({ url: '/pages/data/data' })
|
wx.switchTab({ url: '/pages/data/data' })
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 切换设备 */
|
/** 跳转设备列表页 */
|
||||||
onTapSwitchDevice() {
|
onTapSwitchDevice() {
|
||||||
wx.showToast({ title: '切换设备', icon: 'none' })
|
wx.switchTab({ url: '/pages/equipment/equipment' })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<view class="device">
|
<view class="device">
|
||||||
<view class="device-icon"></view>
|
<view class="device-icon"></view>
|
||||||
<view class="device-info">
|
<view class="device-info">
|
||||||
<view class="device-name">智能体脂秤 Pro</view>
|
<view class="device-name">{{ device.name }}</view>
|
||||||
<view class="device-status">
|
<view class="device-status">
|
||||||
<view class="status-dot {{ device.connected ? 'dot-on' : 'dot-off' }}"></view>
|
<view class="status-dot {{ device.connected ? 'dot-on' : 'dot-off' }}"></view>
|
||||||
<view class="status-text">{{ device.connected ? '蓝牙已连接' : '未连接' }}</view>
|
<view class="status-text">{{ device.connected ? '蓝牙已连接' : '未连接' }}</view>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const EMPTY_RECORD: WeightRecord = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 将体重数字拆成整数 + 小数字符串 */
|
/** 将体重数字拆成整数 + 小数字符串 */
|
||||||
function splitWeight(weight: number): { int: number; decimal: string } {
|
const splitWeight = (weight: number): { int: number; decimal: string } => {
|
||||||
const str = weight.toFixed(2)
|
const str = weight.toFixed(2)
|
||||||
const [intPart, decPart] = str.split('.')
|
const [intPart, decPart] = str.split('.')
|
||||||
return { int: Number(intPart), decimal: `.${decPart}` }
|
return { int: Number(intPart), decimal: `.${decPart}` }
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ interface PageUserInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 从生日字符串(YYYY-MM-DD)计算周岁 */
|
/** 从生日字符串(YYYY-MM-DD)计算周岁 */
|
||||||
function calcAge(birthday: string): number {
|
const calcAge = (birthday: string): number => {
|
||||||
if (!birthday) return 0
|
if (!birthday) return 0
|
||||||
const [year, month, day] = birthday.split('-').map(Number)
|
const [year, month, day] = birthday.split('-').map(Number)
|
||||||
if (!year || !month || !day) return 0
|
if (!year || !month || !day) return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user