优化设备配置流程,重构用户增删改查及信息下发逻辑

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
17792275749
2026-03-11 11:04:29 +08:00
co-authored by Claude Opus 4.6
parent 05b388020b
commit f89f0f9531
10 changed files with 204 additions and 155 deletions
@@ -1,6 +1,25 @@
const app = getApp();
import $ from "../../utils/request";
/**
* 根据生日计算年龄
* @param {string} birthday 生日字符串,如 "1990-05-20"
* @returns {number|null} 年龄,无法计算时返回 null
*/
function calcAge(birthday) {
if (!birthday) return null;
let birthDate = new Date(birthday.replace(/-/g, '/'));
if (isNaN(birthDate.getTime())) return null;
let today = new Date();
let age = today.getFullYear() - birthDate.getFullYear();
let monthDiff = today.getMonth() - birthDate.getMonth();
// 未过生日则减一岁
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
age--;
}
return age;
}
Component({
data: {
BLUE_STATE: {},
@@ -49,6 +68,10 @@ Component({
},
addUser() {
if (this.data.userList.length >= 10) {
wx.showToast({ title: "超过最大用户数", icon: "none" });
return;
}
this.selectComponent("#configureDevice2AddUser").showModal();
},
@@ -61,7 +84,14 @@ Component({
let sn = app.globalData.ppScale.device.mac.replace(/:/g, '');
$.ajax("weighingScale/v2/select/user", { sn }, "GET", true, "正在获取用户列表...").then(res => {
if (res.result && res.result.length) {
this.setData({ userList: res.result });
let list = res.result.map(user => {
// 没有 age 时通过 birthday 计算
if (!user.age && user.birthday) {
user.age = calcAge(user.birthday);
}
return user;
});
this.setData({ userList: list });
} else {
this.setData({ userList: [] });
}
@@ -81,12 +111,14 @@ Component({
content: "确定要删除该用户吗?",
success: (res) => {
if (res.confirm) {
$.ajax("weighingScale/v2/del/user", { id }, "DELETE", true, "正在删除...").then(() => {
$.ajax("weighingScale/v2/del/user", { id }, "DELETE", true, "正在删除...", "application/x-www-form-urlencoded").then(() => {
wx.showToast({
title: "删除成功",
icon: "success"
})
this.fetchUserList();
setTimeout(() => {
this.fetchUserList();
}, 1500)
}).catch(() => {
wx.showToast({
title: "删除失败,请重试",
@@ -120,9 +152,11 @@ Component({
wx.showLoading({ title: "正在下发用户信息...", mask: true });
app.globalData.ppScale.activeProtocol.dataFetchUserID((deviceUserIds) => {
console.log("设备端已有用户ID列表", deviceUserIds);
let existIds = Array.isArray(deviceUserIds) ? deviceUserIds : [];
let needSyncList = userList.filter(user => !existIds.includes(user.userId));
let rawList = Array.isArray(deviceUserIds) ? deviceUserIds : [];
// 兼容对象数组和纯ID数组,统一转为字符串比对
let existIds = rawList.map(item => String(item.userID || item));
let needSyncList = userList.filter(user => !existIds.includes(String(user.id)));
console.log(needSyncList);
if (!needSyncList.length) {
wx.hideLoading();
wx.showToast({
@@ -150,17 +184,17 @@ Component({
}
let user = needSyncList[index];
app.globalData.ppScale.activeProtocol.dataSyncUserInfo({
userID: user.userId,
userName: user.realname,
memberID: "",
age: user.age,
gender: user.sex,
height: user.height,
isAthleteMode: 0,
currentWeight: String(user.weight),
deviceHeaderIndex: index,
targetWeight: "",
idealWeight: "",
userID: user.id, // 用户唯一标识 ID。
userName: user.realname, // 用户昵称/姓名。
memberID: "", // 成员 ID(用于区分主账号下的子成员,例如一家人共用一台体脂秤)。
age: user.age, // 年龄。
gender: user.sex, // 性别(通常 0 代表女性,1 代表男性,或者根据具体协议定义)。
height: user.height, // 身高(单位通常为 cm)。
isAthleteMode: 0, // 运动员模式开关(0 表示普通人,1 表示运动员。该模式会影响体脂率等算法的计算)。
deviceHeaderIndex: index, // 设备头像索引(用于在秤端或 App 列表显示的头像图标编号)。
currentWeight: String(user.weight), // 当前体重。
targetWeight: "", // 目标体重。
idealWeight: "", // 理想体重(通常由系统根据身高、年龄自动计算得出)。
recentData: [],
}, (res) => {
if (res == 0) {
@@ -33,49 +33,59 @@
</view>
<view class="section">
<view class="from">
<scroll-view class="~scrollView" scroll-y>
<view class="scrollViewContent">
<block wx:for="{{userList}}" wx:key="userId">
<view class="userList">
<view class="userAvatar">
<block wx:if="{{item.avatar}}">
<image src="{{item.avatar}}" />
</block>
<block wx:else>
<block wx:if="{{item.sex === 1}}">
<image src="/images/configureDevice/userAvatarMan.png" />
<block wx:if="{{userList && userList.length}}">
<scroll-view class="~scrollView" scroll-y>
<view class="scrollViewContent">
<block wx:for="{{userList}}" wx:key="id">
<view class="userList">
<view class="userAvatar">
<block wx:if="{{item.avatar}}">
<image src="{{item.avatar}}" />
</block>
<block wx:else>
<image src="/images/configureDevice/userAvatarWoman.png" />
<block wx:if="{{item.sex === 1}}">
<image src="/images/configureDevice/userAvatarMan.png" />
</block>
<block wx:else>
<image src="/images/configureDevice/userAvatarWoman.png" />
</block>
</block>
</block>
</view>
<view class="userInfo">
<view class="userInfo_1">
<view>{{item.realname}}</view>
<view class="{{item.sex === 1 ? 'man' : 'woman'}}">
<view>
<block wx:if="{{item.sex === 1}}">
<image src="/images/configureDevice/man.png" />
</block>
<block wx:else>
<image src="/images/configureDevice/woman.png" mode=""/>
</block>
</view>
<view>{{item.age}}</view>
</view>
<view class="userInfo">
<view class="userInfo_1">
<view>{{item.realname}}</view>
<view class="{{item.sex === 1 ? 'man' : 'woman'}}">
<view>
<block wx:if="{{item.sex === 1}}">
<image src="/images/configureDevice/man.png" />
</block>
<block wx:else>
<image src="/images/configureDevice/woman.png" mode=""/>
</block>
</view>
<view>{{item.age}}</view>
</view>
</view>
<view class="userInfo_2">
<view>身高:{{item.height}}cm</view>
<view></view>
<view>体重:{{item.weight}}kg</view>
</view>
</view>
<view class="userInfo_2">
<view>身高:{{item.height}}cm</view>
<view></view>
<view>体重:{{item.weight}}kg</view>
</view>
<view class="delUser" bind:tap="delUserClick" data-id="{{item.id}}">-</view>
</view>
<view class="delUser" bind:tap="delUserClick" data-id="{{item.id}}">-</view>
</view>
</block>
</block>
</view>
</scroll-view>
</block>
<block wx:else>
<view class="nullData">
<view>
<image src="/images/configureDevice/null.png" />
</view>
<view>暂无用户数据</view>
</view>
</scroll-view>
</block>
</view>
<view class="btn">
<view bind:tap="addUser">添加用户</view>
@@ -213,6 +213,25 @@ input {
background-color: #F24439;
}
.nullData {
width: 100%;
padding: 200rpx 0 250rpx;
}
.nullData>view:first-of-type {
width: 230rpx;
height: 160rpx;
margin: 0 auto 15rpx;
}
.nullData>view:last-of-type {
color: #B6B6B6;
height: 30rpx;
font-size: 30rpx;
line-height: 30rpx;
text-align: center;
}
.btn {
width: 100%;
padding: 0 55rpx;