commit 04d373b84e69e0bda0fe271e59f4e45a6706553c Author: 17792275749 <812100002@qq.com> Date: Tue Mar 25 20:52:15 2025 +0800 第一版 diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..115cc02 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,31 @@ +/* + * Eslint config file + * Documentation: https://eslint.org/docs/user-guide/configuring/ + * Install the Eslint extension before using this feature. + */ +module.exports = { + env: { + es6: true, + browser: true, + node: true, + }, + ecmaFeatures: { + modules: true, + }, + parserOptions: { + ecmaVersion: 2018, + sourceType: 'module', + }, + globals: { + wx: true, + App: true, + Page: true, + getCurrentPages: true, + getApp: true, + Component: true, + requirePlugin: true, + requireMiniProgram: true, + }, + // extends: 'eslint:recommended', + rules: {}, +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..960990f --- /dev/null +++ b/README.md @@ -0,0 +1,1138 @@ +# 乐福蓝牙秤 +## 设备接入指南 +### 介绍 +本文档提供了小程序设备接入的指导,以确保秤设备能够成功连接到程序并正常工作。 +### 流程图 +#### 通过设备列表获取设备信息 + +![https://api.apifox.cn/api/v1/projects/2900435/resources/394147/image-preview](https://api.apifox.cn/api/v1/projects/2900435/resources/394147/image-preview) +#### 操作测量流程 + +![https://api.apifox.cn/api/v1/projects/2900435/resources/394148/image-preview](https://api.apifox.cn/api/v1/projects/2900435/resources/394148/image-preview) +#### 数据解析 + +![https://api.apifox.cn/api/v1/projects/2900435/resources/394149/image-preview](https://api.apifox.cn/api/v1/projects/2900435/resources/394149/image-preview) +### 准备工作 +在开始设备接入之前,请确保您已经完成以下准备工作 +确认设备已经按照制造商的说明正确组装和连接。 +确保设备所需的供电已经连接,并处于正常工作状态。 +准备好所需的网络连接信息,如Wi-Fi名称和密码。 +申请蓝牙插件和使用身体数据解析接口申请与使用步骤如下: +#### 申请与使用步骤 +1. 申请蓝牙插件:请访问蓝牙秤插件申请地址 [https://mp.weixin.qq.com/wxopen/plugindevdoc?appid=wx0ffb48417ce6345c](https://mp.weixin.qq.com/wxopen/plugindevdoc?appid=wx0ffb48417ce6345c),在该页面进行申请。 + +2. 申请身体数据解析AppId 和 AppSecret:请访问身体数据解析申请地址 [https://uniquehealth.lefuenergy.com/unique-open-web/index.html](https://uniquehealth.lefuenergy.com/unique-open-web/index.html),在该页面进行申请。 + +3. 申请蓝牙插件和开放官网注册账号:请访问开放官网注册页面,填写相关信息进行账号注册。 + +4. 生成 AppId 和 AppSecret:在注册成功后,登录开放官网,点击Appkey管理,生成你的 AppId 和 AppSecret。 + +5. 下载示例代码:请访问示例代码地址 [https://gitee.com/shenzhen-lfscale/bluetoothkit-webwidgetdemo.git](https://gitee.com/shenzhen-lfscale/bluetoothkit-webwidgetdemo.git),下载示例代码到本地。 + +6. 开发插件功能:根据你的需求,使用示例代码进行开发,将你的 AppId 和 AppSecret 配置到代码中。 + +以上是申请和使用蓝牙插件以及申请身体数据解析的流程。 +#### 导入插件 +将所申请的插件导入到你的应用程序中,确保插件可以正常使用。 + +### 获取设备列表 +#### 注册设备蓝牙列表获取回调 +在你的应用程序中注册回调函数,用于获取设备的蓝牙列表。当回调触发时,你可以获取到可用设备的列表。 +#### 调用开启start方法 +调用相应的方法来开启设备的蓝牙功能,以便进行蓝牙设备的连接和通信。 +#### 设备蓝牙列表获取 +通过设备蓝牙列表回调,获取到可用设备的蓝牙列表。这些设备通常是附近的蓝牙设备。 +#### 选择蓝牙列表中需要连接的设备 +根据你的需求,在蓝牙列表中选择需要连接的设备,记录选择的蓝牙对象。 + +### 选择连接蓝牙设备测量流程 +#### 进入设备详情页 +打开设备的详情页,显示设备的详细信息和配置选项。 +#### 注册监听相关回调 +- 注册蓝牙连接设备回调 +在你的应用程序中注册回调函数,用于处理设备的蓝牙连接事件。当设备成功连接时,回调函数将被触发。 +- 注册蓝牙监听秤端数据回调 +注册回调函数,用于监听来自秤端的数据。当踩秤有新的数据传输时,回调函数将被触发。 +- 注册蓝牙设备自动断连回调 +注册回调函数,用于处理设备自动断开连接的事件。当设备断开连接时,回调函数将被触。 +- 注册蓝牙锁定数据回调 +注册回调函数,用于处理来自秤端的锁定数据。当秤端锁定数据可用时,回调函数将被触发。 +- 注册蓝牙连接状态回调 +注册回调函数,用于处理蓝牙连接状态的变化。当蓝牙连接状态发生改变时,回调函数将被触发。 +- 注册蓝牙修改设备回调 +注册回调函数,用于处理对设备进行修改的事件。当设备配置发生改变时,回调函数将被触发。 +- 注册域名修改回调 +在域名修改的接口中,添加回调函数的参数。当域名修改成功后,调用回调函数,并传递修改成功的状态。 +- 注册WiFi配网SN回调 +在WiFi配网SN的接口中,添加回调函数的参数。当WiFi配网SN修改成功后,调用回调函数,并传递修改成功的SN数据。 +#### 踩秤 +用户踩上秤盘,使秤处于活跃状态。 +#### 调用开启方法 +调用相应的方法,开启设备的测量功能。 +#### 停止扫描 +停止扫描附近的蓝牙设备,以节省电力和资源。 +#### 连接蓝牙设备 +根据用户选择的设备,进行蓝牙设备的连接。连接设备回调开始处理开启过程数据监听。 +#### 蓝牙连接设备秤端相关配置操作 +- 设备单位修改方法 +秤端单位修改成功触发设备配置回调方法返回修改成功或失败状态 +- 设备域名修改方法 +秤端域名修改成功触发回调方法成功状态 +- 设备wifi配网ssid与passwd方法 +秤端wifi配网成功触发回调方法返回修改成功snData值 +#### 上秤测量 +在设备连接成功后,进行秤端的测量操作。 +#### 秤端数据回调方法返回秤端数据显示 +当秤端传输数据时,回调函数将被触发,将秤端数据显示给用户。 +#### 秤端锁定数据回调方法返回秤端锁定数据显示 +当秤端锁定数据可用时,回调函数将被触发,将锁定的数据显示给用户。 +#### 完成测量 +用户完成测量操作,准备进行数据解析和显示。 + +### 解析数据 +#### 根据申请的AppID与Key获取请求token +#### 拿锁定数据测量值请求数据解析接口 +将锁定的数据发送给数据解析接口,请求解析数据的结果。 +#### 得到身体数据解析值 +接收数据解析接口返回的解析结果,得到身体数据的解析值。 +#### 显示测量 +将解析得到的身体数据显示给用户,完成整个测量过程。 + + +## 方法说明 +### plugin.Blue + +plugin.Blue 是一系列控制蓝牙设备的命令和函数的封装,可以用于在项目中连接和通信蓝牙秤设备。以下是该插件所支持的命令和函数: + +**重要!插件1.0.5以上版本如无法扫描出设备 需要调用setDeviceSetting设置相应的蓝牙秤配置** +**setDeviceSetting**设置蓝牙设备搜索的设备数组列表 新名字的秤需向开发者注册设备项: +```setDeviceSetting(devicesList: array): void``` + +**start**开始蓝牙扫描,参数devicesName为设备名称的数组,autoFlag是否自动连接秤端 默认为是: +```start(devicesName: array, autoFlag: Boolean): void``` + +**stop**停止蓝牙扫描,关闭所有事件监听与关闭蓝牙秤连接,通常用于业务结束后需要调用: +```stop(): void``` + +**disconnect**关闭蓝牙秤连接: +```disconnect(fn: function): object``` + + +**createBLEConnection**接受一个蓝牙秤设备对象 连接后触发`deviceConnect`回调 +```createBLEConnection(device: object): object``` + + +**stopBluetoothDevicesDiscovery**停止扫描设备回调 +```stopBluetoothDevicesDiscovery(fn: function): object``` + +**visibleLog** 是否打印插件内部日志 +```visibleLog(flag: boolean):void``` + +### plugin.ScaleAction + +plugin.ScaleAction APP操作是蓝牙秤端的通用方法,切换蓝牙秤的单位和开启监听蓝牙秤数据 + + +**configWifi** 蓝牙配网 - 该功能用于蓝牙WiFi秤,在给秤配置网络时使用 +``` +// 首先确保已经绑定了蓝牙WiFi秤 2、用户输入Wifi账号和密码 3、发起连接设备 4、plugin.bus.subscribe("snData")方法返回sn码,此时秤上的WiFi图标会先闪烁(连接路由器中),再常量(连接路由器成功并获取到sn)将sn传给Server验证秤是否已经完成注册 7、Server返回成功,则配网成功,否则配网失败 +configWifi(ssid: string, password:string): void +``` + +**configDomain** 修改秤端服务器域名 修改后调用configWifi开始蓝牙配网 +``` +// 首先确保已经绑定了蓝牙WiFi秤 +发起蓝牙配网是先更新秤端服务器域名 防止域名调试篡改 +configDomain(domain: string): void +``` + + +**startDataProgress**蓝牙秤端发送数据 需要在设备连接成功后即`deviceConnect`回调中使用 +``` +startDataProgress(): void +// 示例 +plugin.bus.subscribe("deviceConnect", (res) => { + // 必须调用 不然无法获得秤端数据 + plugin.ScaleAction.startDataProgress() +}); + +``` + +**fetchDeviceHistoryData** +``` +fetchDeviceHistoryData(): void +// 示例 +plugin.bus.subscribe("syncDeviceHistorySuccess", (res) => { + //同步历史数据成功回调 +}); + +``` + +**deleteDeviceHistoryData** +``` +deleteDeviceHistoryData(): void +// 示例 +plugin.bus.subscribe("deleteDeviceHistoryDataSuccess", (res) => { + //删除历史数据成功回调 +}); +``` + +**syncDeviceSetting** +体重秤syncDeviceSetting 传入对象键值对 + +| Property | Value | Value | +| ---------------- | ------- | ------- | +| gender | 0 | 性别对应 Plugin.PPBluetoothDefine.PPDeviceGenderType| +| unit | 0 | 单位对应 Plugin.PPBluetoothDefine.PPDeviceUnit | +| isAthleteMode | false | 孕妇 | +| isPregnantMode | false | 运动员模式 | +| age | 23 | 年龄 | +| height | 123 | 身高 | + +**食物秤**syncDeviceSetting 传入对象键值对 + +| Property | Value | Value | +| ---------------- | ------- | ------- | +| unit | 0 | 单位对应 Plugin.PPBluetoothDefine.PPDeviceUnit | +| isBuzzerGateMode | false | 开启蜂鸣 | +| isToZeroMode | false | 食物称置零 | + +``` +syncDeviceSetting(): object +// 体重秤示例 +plugin.ScaleAction.syncDeviceSetting({ + gender:0, + unit:0, + isAthleteMode:false, + isPregnantMode:false, + age:23, + height:123, +}) + +// 食物秤示例 食物称只能修改单一项 +plugin.ScaleAction.syncDeviceSetting({ + isBuzzerGateMode: true, +}) +plugin.ScaleAction.syncDeviceSetting({ + unit: 0, +}) +plugin.ScaleAction.syncDeviceSetting({ + isToZeroMode: true, +}) + +``` + + +**historyData** 获取历史带历史过程数据 +其中res为对象键值为 + +| Property | Value | 描述 | +| -------------- | ------- | ------- | +| isPlus | true | 是否是正数 | +| isOverload | false | 是否超载 | +| weight | 0 | 重量放大了100倍 | +| resistance | 0 | 阻抗 | +| isEnd | false | 本次测量是否结束 | +| isHeartRating | false | 心律是否测量中 | +| heartRate | 0 | 心律 | +| unit | 0 | 设备单位 对应Plugin.PPBluetoothDefine.PPDeviceUnit | +``` + plugin.bus.subscribe("historyData", (res) => { + console.log("historyData", res); + }); +``` + + +**devicesModel** 获取设备模型设备模型可以根据Plugin.PPBluetoothDefine了解秤相关信息 + +``` + plugin.bus.subscribe("devicesModel", (res) => { + console.log("devicesModel", res); + }); +``` + + +**devicesInfo** 获取设备内置信息 + +``` + plugin.bus.subscribe("devicesInfo", (res) => { + console.log("devicesInfo", res); + }); +``` + + +**syncDeviceTimeSuccess** 时间同步 时间同步成功回调 + +``` + plugin.bus.subscribe("syncDeviceTimeSuccess", (res) => { + console.log("syncDeviceTimeSuccess", res); + }); +``` + + +**syncDeviceHistorySuccess** 同步历史数据回调 + +``` + plugin.bus.subscribe("syncDeviceHistorySuccess", (res) => { + console.log("syncDeviceHistorySuccess", res); + }); +``` + + +**deleteDeviceHistoryDataSuccess** 历史数据删除成功回调 + +``` + plugin.bus.subscribe("deleteDeviceHistoryDataSuccess", (res) => { + console.log("deleteDeviceHistoryDataSuccess", res); + }); +``` + + +**deviceWillDisconnect** 设备将要断连回调 + +``` + plugin.bus.subscribe("deviceWillDisconnect", (res) => { + console.log("deviceWillDisconnect", res); + }); +``` +### plugin.bus + plugin.bus通信蓝牙设备,用于监听蓝牙以及秤端的数据与状态,以下是该插件所支持的命令: + +**connectState** 蓝牙与蓝牙秤状态监听 + +``` + plugin.bus.subscribe("connectState", (res) => { + console.log("connectState", res); + }); +``` + +**unitChange** 蓝牙秤单位切换状态监听 + +``` + plugin.bus.subscribe("unitChange", (res) => { + console.log("unitChange", res); + }); +``` + +**devicesList** 获取过滤后的附近设备列表 + +``` + plugin.bus.subscribe("devicesList", (res) => { + console.log("devicesList", res); + }); +``` + +**getDeviceInfo** 获取附件所有附近设备信息 自动连接autoFlag不为false时有数据 + +``` + plugin.bus.subscribe("getDeviceInfo", (res) => { + console.log("getDeviceInfo", res); + }); +``` + +**deviceConnect** 蓝牙秤设备成功连接后连接中状态监听 + +``` + plugin.bus.subscribe("deviceConnect", (res) => { + plugin.ScaleAction.startDataProgress() + }); +``` + +**progressData** 蓝牙秤端过程数据,监听不稳定体重的实时状态 +其中res为对象键值为 + +| Property | Value | 描述 | +| -------------- | ------- | ------- | +| isPlus | true | 是否是正数 | +| isOverload | false | 是否超载 | +| weight | 0 | 重量放大了100倍 | +| resistance | 0 | 阻抗 | +| isEnd | false | 本次测量是否结束 | +| isHeartRating | false | 心律是否测量中 | +| heartRate | 0 | 心律 | +| unit | 0 | 设备单位 对应Plugin.PPBluetoothDefine.PPDeviceUnit | + +**食物秤**中res为对象键值为 + +| Property | Value | 描述 | +| -------------- | ------- | ------- | +| isPlus | true | 是否是正数 | +| isOverload | false | 是否超载 | +| weight | 0 | 重量放大了100倍 | +| isEnd | false | 本次测量是否结束 | +| unit | 0 | 设备单位 对应Plugin.PPBluetoothDefine.PPDeviceUnit | + +``` + plugin.bus.subscribe("progressData", (res) => { + console.log("progressData", res); + }); + +``` + + +**lockData** 蓝牙秤端完成测量锁定数据,锁定的体重和阻抗 + +``` + plugin.bus.subscribe("lockData", (res) => { + console.log("lockData", res); + }); +``` + + +**heartRate** 蓝牙秤端锁定心率值,必须根据已有秤功能调用 + +``` + plugin.bus.subscribe("heartRate", (res) => { + console.log("heartRate", res); + }); +``` + +**snData** 配网成功后返回sn码 sn码用于请求验证秤是否已经完成注册 + +``` + plugin.bus.subscribe("snData", (res) => { + console.log("snData", res); + }); +``` + +**domainChange** 修改域名成功后返回提示 + +``` + plugin.bus.subscribe("domainChange", (res) => { + console.log("domainChange", res); + }); +``` + + +### plugin.getDeviceSettingList + +**插件1.0.5以上版本新增api** + +***plugin.getDeviceSettingList*** 获取设置设备列表 +``` +//获取设备设置列表用于用户添加扫描设备 +plugin.getDeviceSettingList({ + url: baseUrl, + data: { + appKey: appInfo.appKey + }, + header: { + "token": bodyToken, + "Accept-Language": wx.getStorageSync("lang") || 'zh' + } +}).then((res)=>{ + if (res.data.code == 200) { + plugin.Blue.setDeviceSetting(res.data.data) + console.log("plugin==", plugin.PPBluetoothDefine) + } +}) +``` + +***plugin.getAcLfBodyData*** 交流秤数据解析 +``` +// 设备device 根据plugin.Blue.getDeviceModel 获取设备类型deviceConnectType 根据相应的类型请求解析 +var param = { + weightKg: 60, + impedance: 5076001, + sex: 1, 0(女) 1(男) + age: 22, + height: 170, + heartRate: 80, + token: '必传', + } + plugin.getAcLfBodyData({url:url,data:param,header:{ "token":res.data.data.token,"Accept-Language":"zh"}}).then(res => { + console.log('解析结果',res) +}) +``` + + +### plugin.getDcLfBodyData +***plugin.getDcLfBodyData*** 直流秤数据解析 +``` +// 设备device 根据plugin.Blue.getDeviceModel 获取设备类型deviceConnectType 根据相应的类型请求解析 +var param = { + "age":23, + "heartRate":0, + "height":123, + "impedance":0, + "peopleType":0, + "sex":0, + "weightKg":66.6, + } + plugin.getDcLfBodyData({url:url,data:param,header:{ "token":res.data.data.token,"Accept-Language":"zh"}}).then(res => { + console.log('解析结果',res) +}) +``` + + +### plugin.refreshToken +***plugin.refreshToken*** 刷新token +``` + +// 使用refreshToken与解析数据方法结合示例 +function refreshFn() { + this.refreshToken(() => { + callDcLfBodyData(param); + }, true); +} + +async function refreshToken(fn, flag) { + let bodyToken = localStorage.getItem('bodyToken'); + let bodyTokenTime = localStorage.getItem('bodyTokenTime'); + if (!bodyToken || bodyTokenTime * 1000 < +new Date() || flag) { + let res = await plugin.refreshToken({ + url: 'https://uniquehealth.lefuenergy.com', + data: { + "appSecret": "插件开发者申请", + "appKey": "插件开发者申请" + } + }); + console.log("res", res); + if (res.data.code == 200) { + localStorage.setItem('bodyToken', res.data.data.token); + localStorage.setItem('bodyTokenTime', res.data.data.expireTime); + fn(); + } + } else { + fn(); + } +} + +function handleResponse(res) { + console.log("res-=-=-|||", res.data.data); + if (res.data.code == 200) { + + // 获取解析数据操作 + + } else if (res.data.code == 401) { + this.refreshToken(() => { + callDcLfBodyData(param); + }, true); + } +} + +function handleResponseList(res) { + console.log("res-=-=-|||", res.data.data); + if (res.data.code == 200) { + // 获取解析数据操作 + } else if (res.data.code == 401) { + this.refreshToken(() => { + getDeviceSettingList(param); + }, true); + } +} + +function getDeviceSettingList(param){ + let bodyToken = localStorage.getItem('bodyToken'); + plugin.getDeviceSettingList({ + url: 'https://uniquehealth.lefuenergy.com', + data: param, + header: { + "token": bodyToken, + "Accept-Language": localStorage.getItem("lang") || 'zh' + } + }).then(handleResponseList); +} + + +function callDcLfBodyData(param) { + let bodyToken = localStorage.getItem('bodyToken'); + plugin.getDcLfBodyData({ + url: 'https://uniquehealth.lefuenergy.com', + data: param, + header: { + "token": bodyToken, + "Accept-Language": localStorage.getItem("lang") || 'zh' + } + }).then(handleResponse); +} + + + +``` + +## Torre协议测量 + +### Torre测量流程 + +连接设备后 必须先调用更新MTU接口 再调用开始测量接口后数据返回 +``` + +let getActiveProtocol = null +plugin.bus.subscribe("deviceConnect", (res) => { + console.log('成功连接设备') + // 获取协议调用方法 + getActiveProtocol = plugin.ScaleAction.getActiveProtocol() + // 更新MTU + getActiveProtocol.codeUpdateMTU((res) => { + console.log("codeUpdateMTU", res) + }) +}); +//开始测量 +activeProtocol.codeStartMeasure((res) => { + console.log("res", res) +}) +//监听到数据变化 +plugin.bus.subscribe("progressData", (res) => {console.log(res)}) +//获得测量结果 +plugin.bus.subscribe("lockData", (res) => {console.log(res)}) + +``` + +### 配网流程 + +配网需要先调用获取wifi列表接口 返回数据后再进行配网 + +``` +let getActiveProtocol = plugin.ScaleAction.getActiveProtocol() +activeProtocol.dataFindSurroundDevice((res) => { + console.log("wifiList", res) + activeProtocol.dataConfigNetWork({ + domain: "http://domain", + ssid: 'IT32', + password: 'whs123456' + }, (res) => { + console.log("dataConfigNetWork", res) + }) +}) + +``` + + +开始测量 +下发此指令后设备才会上报称重情况 +参数:无 +handler: 0设置成功 1设置失败 +``` +codeStartMeasure((status) => {}) +``` + +保活指令 +推荐首次连接成功后每10秒调用一次,可以保证设备不会主动断开连接 +``` +sendKeepAliveCode() +``` + +停止测量 +停止设备的测量操作 +参数:无 +handler: 0设置成功 1设置失败 +``` +codeStopMeasure((status) => {}) +``` + +获取设备单位 +获取设备当前的单位信息 +参数:无 +``` +codeFetchUnit((status) => {}) +``` + +修改设备单位 +修改设备的单位信息 +参数:无 +unit: 单位 +0x00:单位kg +0x01:单位lb +0x02:单位斤 +0x03:单位st +0x04:单位st:lb +handler: +0x00:设置成功 +0x01:设置失败 +``` +codeChangeUnit(unit,(status) => {}) +``` + +同步设备时间 +同步设备的时间 +参数:无 +``` +codeSyncTime((status) => {}) +``` + +获取设备屏幕亮度 +获取设备当前的屏幕亮度 +``` +codeFetchScreenLuminance((status)=>{}) +``` + +设置设备屏幕亮度 +设置设备的屏幕亮度 +``` +codeSetScreenLuminance(50,(status)=>{}) +``` + +清除设备数据 +清除设备中的不同类型的数据 +参数- +cmd: +0x00:清除所有设备数据(用户信息、历史数据、配网数据、设置信息) +0x01:清除用户信息 +0x02:清除历史数据 +0x03:清除配网状态 +0x04:清除设置信息 +handler: +0x00:成功 +0x01:失败 +``` +codeClearDeviceData("00",(status)=>{}) +``` + +获取心率开关状态 +获取设备当前的心率测量开关状态 +参数:无 +``` +codeFetchHeartRateSwitch((status)=>{}) +``` + +打开心率测量 +打开设备的心率测量功能 +参数:无 +``` +codeOpenHeartRateSwitch((status)=>{}) +``` + +关闭心率测量 +关闭设备的心率测量功能 +参数:无 +``` +codeCloseHeartRateSwitch((status)=>{}) +``` + +获取阻抗开关状态 +获取设备当前的阻抗测量开关状态 +参数:无 +``` +codeFetchImpedanceSwitch((status)=>{}) +``` + +打开阻抗测量 +打开设备的阻抗测量功能 +参数:无 +``` +codeOpenImpedanceSwitch((status)=>{}) +``` + +关闭阻抗测量 +关闭设备的阻抗测量功能 +参数:无 +``` +codeCloseImpedanceSwitch((status)=>{}) +``` + +获取设备配网状态 +获取设备当前的配网状态 +参数:无 +``` +codeFetchWifiConfig((status)=>{}) +``` + +退出配网模式 +退出设备的配网模式 +参数:无 +``` +dataExitWifiConfig((status)=>{}) +``` + +获取设备当前配置热点的ssid +获取设备当前配置的热点SSID名称 +参数:无 +handler: ssid名称 +``` +dataFetchConfigNetworkSSID((status)=>{}) +``` + +设置设备绑定状态 +设置设备的绑定状态 +参数:无 +handler: +0:设置成功 +1:设置失败 +``` +codeSetBindingState((status)=>{}) +``` + +设置设备未绑定状态 +设置设备的未绑定状态 +参数:无 +handler: +0:设置成功 +1:设置失败 +``` +codeSetUnbindingState((status)=>{}) +``` + +获取设备绑定状态 +获取设备当前的绑定状态 +参数:无 +``` +codeFetchBindingState((status)=>{}) +``` + +开启抱婴模式 +开启设备的抱婴模式 +参数: +step: 第几次上称(0/1) +weight: 上次上称时的重量(step为0时传0) +handler: +0:设置成功 +1:设置失败 + +``` +codeEnableBabyModel(0,0,fn) +``` +退出抱婴模式 +退出设备的抱婴模式 +参数:无 +handler: +0:设置成功 +1:设置失败 + +``` +codeExitBabyModel((status)=>{}) +``` + + +更新MTU +更新设备的MTU(最大传输单元) +参数:无 +handler: +0:设置成功 +1:设置失败 + +``` +codeUpdateMTU((status)=>{}) + +``` + +发现周围的可连接热点 +搜索周围的可连接WiFi热点 +参数:无 +handler: 返回结果,包含热点名称和强度的数组对象 + +``` +dataFindSurroundDevice((list)=>{}) + +``` + +获取WIFI MAC地址 +获取设备的WiFi MAC地址 +参数:无 +handler: WiFi MAC地址,示例:MAC 地址:01:02:03:04:05:06(当MAC地址为00:00:00:00:00:00时表示获取不到) + +``` +codeFetchWifiMac((mac)=>{}) + +``` + +通过WIFI进行OTA升级 +使用WiFi进行设备的OTA(空中固件升级) +参数:无 +handler: 进度和失败状态 + +``` +codeOtaUpdate((status)=>{}) + +``` + +获取设备端用户列表 +获取设备端的用户ID列表 +参数:无 +handler: 返回设备端所有用户的userId + +``` +dataFetchUserID((list)=>{}) + +``` + +删除用户 +删除设备端的用户信息 +参数:无 +userModel: 单个用户信息,包含userId和memberId +handler: +0:设置成功 +1:设置失败 + +``` +dataDeleteUser({userID: "15820440620", memberID: "1885639"},(status)=>{}) +``` + + +获取某个用户下所有成员的历史记录 +获取某个用户下所有成员的历史记录 +参数:无 +userModel: 用户对象,userId为必传项 +handler: 历史数据结果 + +``` +dataFetchHistoryData({userID: "15820440620"},(status)=>{}) +dataHistoricalDataStatusReport((res) => {console.log("历史数据", res)}) +``` + + +选中测量用户 +用于测量过程中指定测量用户,指定后不需要在设备端进行选择 +参数-userModel: 单个用户信息,包含userId和memberId +handler: +0:设置成功 +1:设置失败 + +``` +dataSelectUser({userID: "15820440620", memberID: "1885639", }, (status) => {}) +``` +同步单个用户给设备 +将单个用户信息同步给设备,如果设备中已存在该用户,则会更新用户信息;如果不存在,则会插入。 +参数-infos: 单个用户信息,包含各个属性的值(参考代码注释) +handler: +0:设置成功 +1:设置失败 +``` +dataSyncUserInfo({ + userID: "15820440621", + memberID: "1885629", + age: "25", + gender: 0, + height: "158", + isAthleteMode: 0, + currentWeight: "55", + deviceHeaderIndex: 0, + targetWeight: "54", + idealWeight: "52.8", + recentData: [{ + weightKg: 59.00, + timeStamp: 1677046795028 + }, + { + weightKg: 58.79, + timeStamp: 1692264965631 + }, + { + weightKg: 52.20, + timeStamp: 1693894960948 + }, + { + weightKg: 46.50, + timeStamp: 1694051103700 + }, + { + weightKg: 61.95, + timeStamp: 1694159727308 + }, + { + weightKg: 61.59, + timeStamp: 1694232070904 + }, + { + weightKg: 62.35, + timeStamp: 1694425016834 + }, + ], + userName: "名字", + },(status)=>{}) +``` +配置热点 +配置设备连接的WiFi热点信息 +参数-model: 包含用于连接热点的信息(domain, ssid, password) +handler: 配网过程中的状态和错误码 + +``` +dataConfigNetWork({domain:"domain", ssid:"ssid", password:"password"},(status)=>{}) +``` + +## 常量与枚举值 +### plugin.PPBluetoothDefine +以下是对给定的枚举类型介绍: + +### PPDeviceConnectType (设备连接类型) + +- `PPDeviceConnectTypeUnknow` (未知) +- `PPDeviceConnectTypeBleAdv` (蓝牙广播秤) +- `PPDeviceConnectTypeBleConnect` (蓝牙连接秤) + +### PPDeviceType (设备类型) + +- `PPDeviceTypeUnknow` (未知) +- `PPDeviceTypeCF` (体脂秤) +- `PPDeviceTypeCE` (体重秤) +- `PPDeviceTypeCB` (婴儿秤) +- `PPDeviceTypeCA` (厨房秤) + +### PPDeviceProtocolType (设备蓝牙协议版本) + +- `PPDeviceProtocolTypeUnknow` (未知) +- `PPDeviceProtocolTypeV2` (2.x版本) +- `PPDeviceProtocolTypeV3` (3.x版本) +- `PPDeviceProtocolTypeTorre` (torre版本) + +### PPDeviceCalcuteType (测脂计算方式) + +- `PPDeviceCalcuteTypeUnknow` (未知) +- `PPDeviceCalcuteTypeInScale` (秤端计算) +- `PPDeviceCalcuteTypeDirect` (直流算法) +- `PPDeviceCalcuteTypeAlternate` (交流算法) +- `PPDeviceCalcuteTypeAlternate8` (8电极交流算法) +- `PPDeviceCalcuteTypeAlternateNormal` (默认计算库直接用合泰返回的体脂率) +- `PPDeviceCalcuteTypeNeedNot` (无需计算) + +### PPDevicePowerType (设备供电方式) + +- `PPDevicePowerTypeUnknow` (未知) +- `PPDevicePowerTypeBattery` (电池) +- `PPDevicePowerTypeSolar` (太阳能) +- `PPDevicePowerTypeCharge` (充电) + +### PPDeviceFuncType (设备功能类型) + +- `PPDeviceFuncTypeWeight` (称重) +- `PPDeviceFuncTypeFat` (测脂) +- `PPDeviceFuncTypeHeartRate` (心律) +- `PPDeviceFuncTypeHistory` (历史) +- `PPDeviceFuncTypeSafe` (孕妇) +- `PPDeviceFuncTypeBMDJ` (闭目单脚) +- `PPDeviceFuncTypeBaby` (抱婴模式) +- `PPDeviceFuncTypeWifi` (wifi配网) + +### PPDeviceAccuracyType (设备精度) + +- `PPDeviceAccuracyTypeUnknow` (未知) +- `PPDeviceAccuracyTypePoint01` (0.1KG精度) +- `PPDeviceAccuracyTypePoint005` (0.05KG精度) +- `PPDeviceAccuracyTypePoint001` (0.01KG精度) +- `PPDeviceAccuracyTypePointG` (1G精度) +- `PPDeviceAccuracyTypePoint01G` (0.1G精度) + +### PPDeviceUnitType (设备具有的单位) + +- `PPDeviceUnitTypeKG(KG)` +- `PPDeviceUnitTypeLB(LB)` +- `PPDeviceUnitTypeSTLB(STLB)` +- `PPDeviceUnitTypeJin(Jin)` +- `PPDeviceUnitTypeG(G)` +- `PPDeviceUnitTypeLBOZ(LBOZ)` +- `PPDeviceUnitTypeOZ(FLOZ)` +- `PPDeviceUnitTypeMLWater(MLWater)` +- `PPDeviceUnitTypeMLMilk(MLMilk)` +- `PPDeviceUnitTypeFLOZWater(FLOZWater)` +- `PPDeviceUnitTypeFLOZMilk(FLOZMilk)` +- `PPDeviceUnitTypeST(ST)` + +### PPDeviceUnit (用户使用的单位) + +- `PPUnitKG(KG)` +- `PPUnitLB(LB)` +- `PPUnitST(ST)` +- `PPUnitJin(Jin)` +- `PPUnitSTLB(STLB)` +- `PPUnitG(G)` +- `PPUnitLBOZ(LBOZ)` +- `PPUnitOZ(OZ)` +- `PPUnitMLWater(MLWater)` +- `PPUnitMLMilk(MLMilk)` +- `PPUnitFLOZWater(FLOZWater)` +- `PPUnitFLOZMilk(FLOZMilk)` + +### PPDeviceGenderType (性别) + +- `PPDeviceGenderTypeFemale` (女性) +- `PPDeviceGenderTypeMale` (男性) + +### PPWIFIConfigState (配网错误状态) + +- `PPWIFIConfigStateUnknow` +- `PPWIFIConfigStateStart` +- `PPWIFIConfigStateStartSuccess` +- `PPWIFIConfigStateStartFailed` +- `PPWIFIConfigStateDomainSendStart` +- `PPWIFIConfigStateDomainSendSuccess` +- `PPWIFIConfigStateDomainSendFailed` +- `PPWIFIConfigStateDomainSendCode` +- `PPWIFIConfigStateDomainSendCodeSuccess` +- `PPWIFIConfigStateDomainSendCodeFailed` +- `PPWIFIConfigStateSSIDSendStart` +- `PPWIFIConfigStateSSIDSendSuccess` +- `PPWIFIConfigStateSSIDSendFailed` +- `PPWIFIConfigStateSSIDSendCode` +- `PPWIFIConfigStateSSIDSendCodeSuccess` +- `PPWIFIConfigStateSSIDSendCodeFailed` +- `PPWIFIConfigStatePasswordSendStart` +- `PPWIFIConfigStatePasswordSendSuccess` +- `PPWIFIConfigStatePasswordSendFailed` +- `PPWIFIConfigStatePasswordSendCode` +- `PPWIFIConfigStatePasswordSendCodeSuccess` +- `PPWIFIConfigStatePasswordSendCodeFailed` +- `PPWIFIConfigStateRegist` +- `PPWIFIConfigStateRegistSuccess` +- `PPWIFIConfigStateRegistFailedTimeOut` +- `PPWIFIConfigStateRegistFailedConnect` +- `PPWIFIConfigStateRegistFailedHTTP` +- `PPWIFIConfigStateRegistFailedHTTPS` +- `PPWIFIConfigStateRegistFailedRegist` +- `PPWIFIConfigStateRegistFailedCommand` + +### plugin.BLUE_STATE +connectState 状态 +BLUE_STATE对应值为 + +| 常量名 | 描述 | +| --- | --- | +| UNAVAILABLE | 蓝牙不可用 | +| READY | 蓝牙准备就绪 | +| SCANING | 正在搜索... | +| CONNECTSUCCESS | 连接成功 | +| CONNECTFAILED | 连接失败, 请重试! | +| WIFISUCCESS | 配网成功 | + +## 使用插件示例 + +https://gitee.com/shenzhen-lfscale/bluetoothkit-webwidgetdemo.git + +app.json 的 plugins 字段加入组件插件路径: +``` + "plugins": { + "ppScale-plugin": { + "version": "版本号", + "provider": "插件appid" + } + }, +``` + +index.json 的 usingComponents 字段加入组件插件路径: +``` + "ppScale": "plugin://ppScale-plugin/ppScale" +``` + +index.wxml 页面中使用: +``` + +``` + +## 常见问题 +### 开启扫描但不到设备 +需要确认系统蓝牙与应用权限蓝牙是否开启 +如果开启依旧无法扫描到蓝牙 需要开启位置信息 部分移动设备需要开启移动信息才能扫描到设备 +是否为真机调试 开发者工具部分版本真机调试蓝牙无法使用 需要换成预览模式调试开发 +### wifi配网后如何判断成功 +wifi配网需要确认路由器wi-Fi频段是否为2.4GHz +调用wifi配网api 如果wifi配网成功则snData会返回回调方法 如果30秒内snData监听没有回调则为配网失败 +### ios有数据返回 安卓无数据返回 +确认页面是否在上一层页调用了插件stop方法 安卓端stop方法执行满导致新注册测量页面回调被清空 需要延迟几百毫秒再注册回调方法 +### 如何获取ios真实mac地址 +注册秤模型回调 连接成功秤后 返回秤模型回调拥有设备真实mac地址 +### 传入设备对象获取到秤端模型 +秤端模型需要设备对象的advertisData 对象复制后advertisData里的二进制数据丢失导致无法计算出设备模型 +复制设备对象时需要记录advertisData的二进制值 advertisData有真实值才能获得真实的秤模型 +### ios无法配网成功 +**ios配网成功必须满足的选项 如iPhone11如下** +- 蓝牙秤确保配网时已经连接且里热点手机不远 +- iPhone11开启的热点可被其他手机扫描到 +- iPhone11为关闭wifi状态 +- 域名与wifi名密码正确 + + + + + + + + diff --git a/app.js b/app.js new file mode 100644 index 0000000..a1deaf8 --- /dev/null +++ b/app.js @@ -0,0 +1,46 @@ +App({ + onLaunch() { + this.initPpScale(); + }, + + globalData: { + // wx.request 请求的服务地址 + wxRequestUrl: "http://device.shuziweidao.com:8889/", + + // 秤的所有信息 + ppScale: { + plugin: null, + activeProtocol: null, + domain: "http://device.shuziweidao.com:8889", // http://192.168.10.173:8889 + wifi: { + ssid: "", + password: "" + }, + options: { + key: "lefudc91611833e18d94", + secret: "eQ50JYimMp0X7uhNLj6D3lTEk4TUUvEG7dvaqKM9t1U=" + }, + device: { + setting: [], // 即将要搜索周边秤的配置 + list: [], // 根据配置搜索到秤的列表 + mac: null, // 选中的设备mac地址/SN码 + name: "", // 设备名称 + connection: null, // 默认选中连接的设备 + } + } + }, + + initPpScale() { + this.globalData.ppScale.plugin = requirePlugin('ppScale-plugin'); + const plugin = this.globalData.ppScale.plugin; + + plugin.bus.subscribe("connectState", (res) => { + console.log("app.js ===> connectState", res); + }); + + plugin.bus.subscribe("devicesModel", (res) => { + console.log('app.js devicesModel', res); + this.globalData.ppScale.device.mac = res.deviceMac; + }); + }, +}) \ No newline at end of file diff --git a/app.json b/app.json new file mode 100644 index 0000000..4e066b2 --- /dev/null +++ b/app.json @@ -0,0 +1,52 @@ +{ + "pages": [ + "pages/home/home", + "pages/searchDevice/searchDevice", + "pages/connectedDevice/connectedDevice", + "pages/connectionSuccessful/connectionSuccessful", + "pages/getWifiList/getWifiList", + "pages/setWifiPassword/setWifiPassword", + "pages/setNetwork/setNetwork", + "pages/setNetworkSuccessful/setNetworkSuccessful", + "pages/my/my", + "pages/userInfo/userInfo", + "pages/deviceInfo/deviceInfo", + "pages/familyMembers/familyMembers", + "pages/index/index" + ], + "window": { + "navigationBarTitleText": "", + "navigationBarTextStyle": "black", + "navigationBarBackgroundColor": "#ffffff" + }, + "tabBar": { + "color": "#808080", + "selectedColor": "#1385FA", + "borderStyle": "white", + "list": [{ + "pagePath": "pages/home/home", + "iconPath": "/images/tabBar/home.png", + "selectedIconPath": "/images/tabBar/home_.png", + "text": "首页" + }, { + "pagePath": "pages/my/my", + "iconPath": "/images/tabBar/my.png", + "selectedIconPath": "/images/tabBar/my_.png", + "text": "我的" + }] + }, + "style": "v2", + "plugins": { + "ppScale-plugin": { + "version": "1.2.14", + "provider": "wx0ffb48417ce6345c" + } + }, + "permission": { + "scope.userLocation": { + "desc": "获取 WiFi 列表需要使用您的位置信息" + } + }, + "sitemapLocation": "sitemap.json", + "lazyCodeLoading": "requiredComponents" +} \ No newline at end of file diff --git a/app.wxss b/app.wxss new file mode 100644 index 0000000..5d4946a --- /dev/null +++ b/app.wxss @@ -0,0 +1,43 @@ +page { + width: 100%; + height: 100%; + box-sizing: border-box; + background-color: #F5F7FB; +} + +image { + width: 100%; + height: 100%; +} + +button { + all: unset; + display: inline-block; +} + +button::after { + display: none; +} + +.scrollView { + width: 100%; + height: 100%; +} + +.arrowAfter { + position: relative; +} + +.arrowAfter::after { + position: absolute; + right: 6rpx; + top: 0; + bottom: 0; + margin: auto; + content: ""; + width: 12rpx; + height: 12rpx; + border-left: 5rpx solid #b6b6b6; + border-top: 5rpx solid #b6b6b6; + transform: rotate(135deg); +} \ No newline at end of file diff --git a/components/navigation-bar/navigation-bar.js b/components/navigation-bar/navigation-bar.js new file mode 100644 index 0000000..66daae3 --- /dev/null +++ b/components/navigation-bar/navigation-bar.js @@ -0,0 +1,107 @@ +Component({ + options: { + multipleSlots: true // 在组件定义时的选项中启用多slot支持 + }, + /** + * 组件的属性列表 + */ + properties: { + extClass: { + type: String, + value: '' + }, + title: { + type: String, + value: '' + }, + background: { + type: String, + value: '' + }, + color: { + type: String, + value: '' + }, + back: { + type: Boolean, + value: true + }, + loading: { + type: Boolean, + value: false + }, + homeButton: { + type: Boolean, + value: false, + }, + animated: { + // 显示隐藏的时候opacity动画效果 + type: Boolean, + value: true + }, + show: { + // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在 + type: Boolean, + value: true, + observer: '_showChange' + }, + // back为true的时候,返回的页面深度 + delta: { + type: Number, + value: 1 + }, + }, + /** + * 组件的初始数据 + */ + data: { + displayStyle: '' + }, + lifetimes: { + attached() { + const rect = wx.getMenuButtonBoundingClientRect() + wx.getSystemInfo({ + success: (res) => { + const isAndroid = res.platform === 'android' + const isDevtools = res.platform === 'devtools' + this.setData({ + ios: !isAndroid, + innerPaddingRight: `padding-right: ${res.windowWidth - rect.left}px`, + leftWidth: `width: ${res.windowWidth - rect.left }px`, + safeAreaTop: isDevtools || isAndroid ? `height: calc(var(--height) + ${res.safeArea.top}px); padding-top: ${res.safeArea.top}px` : `` + }) + } + }) + }, + }, + /** + * 组件的方法列表 + */ + methods: { + _showChange(show) { + const animated = this.data.animated + let displayStyle = '' + if (animated) { + displayStyle = `opacity: ${ + show ? '1' : '0' + };transition:opacity 0.5s;` + } else { + displayStyle = `display: ${show ? '' : 'none'}` + } + this.setData({ + displayStyle + }) + }, + back() { + const data = this.data + if (data.delta) { + wx.navigateBack({ + delta: data.delta + }) + } + this.triggerEvent('back', { + delta: data.delta + }, {}) + } + }, +}) \ No newline at end of file diff --git a/components/navigation-bar/navigation-bar.json b/components/navigation-bar/navigation-bar.json new file mode 100644 index 0000000..2f56a9b --- /dev/null +++ b/components/navigation-bar/navigation-bar.json @@ -0,0 +1,5 @@ +{ + "component": true, + "styleIsolation": "apply-shared", + "usingComponents": {} +} \ No newline at end of file diff --git a/components/navigation-bar/navigation-bar.wxml b/components/navigation-bar/navigation-bar.wxml new file mode 100644 index 0000000..57a74ce --- /dev/null +++ b/components/navigation-bar/navigation-bar.wxml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{title}} + + + + + + + + + + + + \ No newline at end of file diff --git a/components/navigation-bar/navigation-bar.wxss b/components/navigation-bar/navigation-bar.wxss new file mode 100644 index 0000000..56e9c43 --- /dev/null +++ b/components/navigation-bar/navigation-bar.wxss @@ -0,0 +1,98 @@ +.weui-navigation-bar { + --weui-FG-0: rgba(0, 0, 0, .9); + --height: 44px; + --left: 16px; +} + +.weui-navigation-bar .android { + --height: 48px; +} + +.weui-navigation-bar { + overflow: hidden; + color: var(--weui-FG-0); + flex: none; +} + +.weui-navigation-bar__inner { + position: relative; + top: 0; + left: 0; + height: calc(var(--height) + env(safe-area-inset-top)); + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding-top: env(safe-area-inset-top); + width: 100%; + box-sizing: border-box; +} + +.weui-navigation-bar__left { + position: relative; + padding-left: var(--left); + display: flex; + flex-direction: row; + align-items: flex-start; + height: 100%; + box-sizing: border-box; +} + +.weui-navigation-bar__btn_goback_wrapper { + padding: 11px 18px 11px 16px; + margin: -11px -18px -11px -16px; +} + +.weui-navigation-bar__btn_goback_wrapper.weui-active { + opacity: 0.5; +} + +.weui-navigation-bar__btn_goback { + font-size: 12px; + width: 12px; + height: 24px; + -webkit-mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%; + mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%; + -webkit-mask-size: cover; + mask-size: cover; + background-color: var(--weui-FG-0); +} + +.weui-navigation-bar__center { + font-size: 17px; + text-align: center; + position: relative; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + font-weight: bold; + flex: 1; + height: 100%; +} + +.weui-navigation-bar__loading { + margin-right: 4px; + align-items: center; +} + +.weui-loading { + font-size: 16px; + width: 16px; + height: 16px; + display: block; + background: transparent url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='80px' height='80px' viewBox='0 0 80 80' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3Eloading%3C/title%3E%3Cdefs%3E%3ClinearGradient x1='94.0869141%25' y1='0%25' x2='94.0869141%25' y2='90.559082%25' id='linearGradient-1'%3E%3Cstop stop-color='%23606060' stop-opacity='0' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3ClinearGradient x1='100%25' y1='8.67370605%25' x2='100%25' y2='90.6286621%25' id='linearGradient-2'%3E%3Cstop stop-color='%23606060' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3C/defs%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' opacity='0.9'%3E%3Cg%3E%3Cpath d='M40,0 C62.09139,0 80,17.90861 80,40 C80,62.09139 62.09139,80 40,80 L40,73 C58.2253967,73 73,58.2253967 73,40 C73,21.7746033 58.2253967,7 40,7 L40,0 Z' fill='url(%23linearGradient-1)'%3E%3C/path%3E%3Cpath d='M40,0 L40,7 C21.7746033,7 7,21.7746033 7,40 C7,58.2253967 21.7746033,73 40,73 L40,80 C17.90861,80 0,62.09139 0,40 C0,17.90861 17.90861,0 40,0 Z' fill='url(%23linearGradient-2)'%3E%3C/path%3E%3Ccircle id='Oval' fill='%23606060' cx='40.5' cy='3.5' r='3.5'%3E%3C/circle%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A") no-repeat; + background-size: 100%; + margin-left: 0; + animation: loading linear infinite 1s; +} + +@keyframes loading { + from { + transform: rotate(0); + } + + to { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/images/connectedDevice/device.png b/images/connectedDevice/device.png new file mode 100644 index 0000000..843faf3 Binary files /dev/null and b/images/connectedDevice/device.png differ diff --git a/images/connectionSuccessful/icon.png b/images/connectionSuccessful/icon.png new file mode 100644 index 0000000..6c7a21e Binary files /dev/null and b/images/connectionSuccessful/icon.png differ diff --git a/images/deviceInfo/device.png b/images/deviceInfo/device.png new file mode 100644 index 0000000..6e62bc0 Binary files /dev/null and b/images/deviceInfo/device.png differ diff --git a/images/familyMembers/add.png b/images/familyMembers/add.png new file mode 100644 index 0000000..a6cf6b5 Binary files /dev/null and b/images/familyMembers/add.png differ diff --git a/images/getWifiList/icon.png b/images/getWifiList/icon.png new file mode 100644 index 0000000..a0882a8 Binary files /dev/null and b/images/getWifiList/icon.png differ diff --git a/images/home/bg.jpg b/images/home/bg.jpg new file mode 100644 index 0000000..f23f89d Binary files /dev/null and b/images/home/bg.jpg differ diff --git a/images/home/user.png b/images/home/user.png new file mode 100644 index 0000000..8d7c532 Binary files /dev/null and b/images/home/user.png differ diff --git a/images/my/1.png b/images/my/1.png new file mode 100644 index 0000000..74e4e7b Binary files /dev/null and b/images/my/1.png differ diff --git a/images/my/2.png b/images/my/2.png new file mode 100644 index 0000000..04262ff Binary files /dev/null and b/images/my/2.png differ diff --git a/images/my/3.png b/images/my/3.png new file mode 100644 index 0000000..ed9edac Binary files /dev/null and b/images/my/3.png differ diff --git a/images/my/user.png b/images/my/user.png new file mode 100644 index 0000000..8d7c532 Binary files /dev/null and b/images/my/user.png differ diff --git a/images/searchDevice/icon.png b/images/searchDevice/icon.png new file mode 100644 index 0000000..8304216 Binary files /dev/null and b/images/searchDevice/icon.png differ diff --git a/images/setNetwork/icon.png b/images/setNetwork/icon.png new file mode 100644 index 0000000..9974df8 Binary files /dev/null and b/images/setNetwork/icon.png differ diff --git a/images/setNetworkSuccessful/icon.png b/images/setNetworkSuccessful/icon.png new file mode 100644 index 0000000..6c7a21e Binary files /dev/null and b/images/setNetworkSuccessful/icon.png differ diff --git a/images/setNetworkSuccessful/success.png b/images/setNetworkSuccessful/success.png new file mode 100644 index 0000000..8d979ed Binary files /dev/null and b/images/setNetworkSuccessful/success.png differ diff --git a/images/setNetworkSuccessful/wifi.png b/images/setNetworkSuccessful/wifi.png new file mode 100644 index 0000000..a0882a8 Binary files /dev/null and b/images/setNetworkSuccessful/wifi.png differ diff --git a/images/setWifiPassword/close.png b/images/setWifiPassword/close.png new file mode 100644 index 0000000..6e32387 Binary files /dev/null and b/images/setWifiPassword/close.png differ diff --git a/images/setWifiPassword/icon.png b/images/setWifiPassword/icon.png new file mode 100644 index 0000000..2999896 Binary files /dev/null and b/images/setWifiPassword/icon.png differ diff --git a/images/setWifiPassword/open.png b/images/setWifiPassword/open.png new file mode 100644 index 0000000..2b2c650 Binary files /dev/null and b/images/setWifiPassword/open.png differ diff --git a/images/tabBar/home.png b/images/tabBar/home.png new file mode 100644 index 0000000..186b569 Binary files /dev/null and b/images/tabBar/home.png differ diff --git a/images/tabBar/home_.png b/images/tabBar/home_.png new file mode 100644 index 0000000..3fe72ed Binary files /dev/null and b/images/tabBar/home_.png differ diff --git a/images/tabBar/my.png b/images/tabBar/my.png new file mode 100644 index 0000000..52b5312 Binary files /dev/null and b/images/tabBar/my.png differ diff --git a/images/tabBar/my_.png b/images/tabBar/my_.png new file mode 100644 index 0000000..4383c26 Binary files /dev/null and b/images/tabBar/my_.png differ diff --git a/pages/connectedDevice/connectedDevice.js b/pages/connectedDevice/connectedDevice.js new file mode 100644 index 0000000..8587778 --- /dev/null +++ b/pages/connectedDevice/connectedDevice.js @@ -0,0 +1,107 @@ +const app = getApp(); +import $ from "../../utils/request"; + +Page({ + data: { + name: "", + deviceSelect: null + }, + + onLoad(options) { + let name = app.globalData.ppScale.device.name; + let deviceSelect = app.globalData.ppScale.device.connection; + this.setData({ + name: name ? name : deviceSelect.name, + deviceSelect: deviceSelect + }) + + app.globalData.ppScale.plugin.bus.subscribe("deviceConnect", (res) => { + console.log('connectedDevice ===》deviceConnect', res); + + app.globalData.ppScale.plugin.ScaleAction.startDataProgress(); + app.globalData.ppScale.activeProtocol = app.globalData.ppScale.plugin.ScaleAction.getActiveProtocol(); + + app.globalData.ppScale.activeProtocol.codeUpdateMTU((res) => { + console.log("connectedDevice ===》codeUpdateMTU", res); + + app.globalData.ppScale.activeProtocol.codeFetchBindingState((res) => { + console.log("connectedDevice ===》codeFetchBindingState", res); + + wx.hideLoading(); + if (res === 1) { + wx.showModal({ + title: '提示', + content: '当前设备已被绑定,你确定要覆盖绑定吗?', + success: (res) => { + if (res.confirm) { + app.globalData.ppScale.activeProtocol.codeClearDeviceData("00", (res) => { + console.log("deviceInfo === codeClearDeviceData", res); + + let scaleDeviceId = app.globalData.ppScale.device.mac.replace(/:/g, ''); + let params = { + equipmentCode: scaleDeviceId, + }; + $.ajax("weighingScale/del/device", params, "POST", true, "正在初始化设备...").then(res => { + wx.showToast({ + icon: "none", + title: res.message, + }) + let pages = getCurrentPages(); + let prevPage = pages[pages.length - 2]; + prevPage.setData({ + getDeviceSetting: true + }) + setTimeout(() => { + wx.navigateBack({ + delta: 1 + }) + }, 1500); + }); + }) + } else if (res.cancel) { + app.globalData.ppScale.plugin.Blue.disconnect(); + } + } + }) + } else { + app.globalData.ppScale.device.name = this.data.name; + wx.navigateTo({ + url: "/pages/connectionSuccessful/connectionSuccessful" + }) + } + }) + }); + }); + }, + + nameInput(e) { + this.setData({ + name: e.detail.value + }) + }, + + // 配对 + openConnectionSuccessful() { + let deviceSelect = this.data.deviceSelect; + if (deviceSelect) { + let name = this.data.name; + if (name) { + wx.showLoading({ + title: "蓝牙配对中...", + mask: true + }); + app.globalData.ppScale.plugin.Blue.createBLEConnection(deviceSelect); + } else { + wx.showToast({ + icon: "none", + title: "设备名称不能为空" + }) + } + } else { + wx.showToast({ + icon: "none", + title: "配对设备不能为空" + }) + } + }, +}) \ No newline at end of file diff --git a/pages/connectedDevice/connectedDevice.json b/pages/connectedDevice/connectedDevice.json new file mode 100644 index 0000000..7c0a326 --- /dev/null +++ b/pages/connectedDevice/connectedDevice.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "设备命名", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/connectedDevice/connectedDevice.wxml b/pages/connectedDevice/connectedDevice.wxml new file mode 100644 index 0000000..580c8b3 --- /dev/null +++ b/pages/connectedDevice/connectedDevice.wxml @@ -0,0 +1,14 @@ +型号:{{deviceSelect.name}} + + + + + + + 设备名称 + + + + + +配对 \ No newline at end of file diff --git a/pages/connectedDevice/connectedDevice.wxss b/pages/connectedDevice/connectedDevice.wxss new file mode 100644 index 0000000..5a64677 --- /dev/null +++ b/pages/connectedDevice/connectedDevice.wxss @@ -0,0 +1,68 @@ +page { + padding: 50rpx 60rpx 0; + background-color: #ffffff; +} + +.equipmentModel { + color: #252535; + width: 100%; + height: 48rpx; + font-size: 48rpx; + font-weight: bold; + line-height: 48rpx; + margin-bottom: 60rpx; +} + +.equipmentIcon { + width: 320rpx; + height: 320rpx; + margin: 0 auto 40rpx; +} + +.equipmentName { + width: 100%; + height: 126rpx; + display: flex; + flex-wrap: nowrap; + padding-right: 35rpx; + box-sizing: border-box; + margin-bottom: 550rpx; + justify-content: space-between; + border-bottom: 1rpx solid #EAECF1; +} + +.equipmentName>view:first-of-type { + color: #252535; + height: 126rpx; + line-height: 126rpx; + font-size: 36rpx; + font-weight: bold; +} + +.equipmentName>view:last-of-type { + flex: 1; + width: 0; + height: 126rpx; +} + +.equipmentName>view:last-of-type input { + color: #808080; + width: 100%; + height: 126rpx; + text-align: right; + font-size: 36rpx; + line-height: 126rpx; +} + +.btn { + color: #FFFFFF; + width: 580rpx; + height: 88rpx; + line-height: 88rpx; + margin: 0 auto; + font-size: 32rpx; + font-weight: bold; + border-radius: 44rpx; + text-align: center; + background-color: #1385FA; +} \ No newline at end of file diff --git a/pages/connectionSuccessful/connectionSuccessful.js b/pages/connectionSuccessful/connectionSuccessful.js new file mode 100644 index 0000000..bd48f97 --- /dev/null +++ b/pages/connectionSuccessful/connectionSuccessful.js @@ -0,0 +1,10 @@ +const app = getApp(); + +Page({ + // 获取wifi列表 + openGetWifiList() { + wx.navigateTo({ + url: "/pages/getWifiList/getWifiList" + }) + } +}) \ No newline at end of file diff --git a/pages/connectionSuccessful/connectionSuccessful.json b/pages/connectionSuccessful/connectionSuccessful.json new file mode 100644 index 0000000..84c4caf --- /dev/null +++ b/pages/connectionSuccessful/connectionSuccessful.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "绑定成功", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/connectionSuccessful/connectionSuccessful.wxml b/pages/connectionSuccessful/connectionSuccessful.wxml new file mode 100644 index 0000000..b3cbcf3 --- /dev/null +++ b/pages/connectionSuccessful/connectionSuccessful.wxml @@ -0,0 +1,10 @@ + + + + + 绑定成功 + + +随时随地同步测量数据 + +配置网络 \ No newline at end of file diff --git a/pages/connectionSuccessful/connectionSuccessful.wxss b/pages/connectionSuccessful/connectionSuccessful.wxss new file mode 100644 index 0000000..a4e895d --- /dev/null +++ b/pages/connectionSuccessful/connectionSuccessful.wxss @@ -0,0 +1,49 @@ +page { + width: 100%; + padding: 200rpx 85rpx 0; + box-sizing: border-box; + background-color: #ffffff; +} + +.icon { + width: 100%; + margin-bottom: 540rpx; +} + +.icon>view:first-of-type { + width: 360rpx; + height: 295rpx; + margin: 0 auto 50rpx; +} + +.icon>view:last-of-type { + color: #252535; + width: 100%; + height: 40rpx; + font-size: 40rpx; + font-weight: bold; + line-height: 40rpx; + text-align: center; +} + +.describe { + color: #B6B6B6; + width: 100%; + height: 26rpx; + font-size: 28rpx; + line-height: 28rpx; + text-align: center; + margin-bottom: 46rpx; +} + +.btn { + color: #FFFFFF; + width: 100%; + height: 88rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 88rpx; + text-align: center; + border-radius: 44rpx; + background-color: #1385FA; +} \ No newline at end of file diff --git a/pages/deviceInfo/deviceInfo.js b/pages/deviceInfo/deviceInfo.js new file mode 100644 index 0000000..9cfda1f --- /dev/null +++ b/pages/deviceInfo/deviceInfo.js @@ -0,0 +1,151 @@ +const app = getApp(); +import $ from "../../utils/request"; + +Page({ + data: { + deviceConnect: false, + + deviceInfo: null + }, + + onLoad(options) { + this.getDevice(); + this.initBluetooth(); + + app.globalData.ppScale.plugin.bus.subscribe("deviceConnect", (res) => { + console.log('deviceInfo ===》deviceConnect', res); + + app.globalData.ppScale.plugin.ScaleAction.startDataProgress(); + app.globalData.ppScale.activeProtocol = app.globalData.ppScale.plugin.ScaleAction.getActiveProtocol(); + + app.globalData.ppScale.activeProtocol.codeUpdateMTU((res) => { + console.log("deviceInfo ===》codeUpdateMTU", res); + + $.ajax("weighingScale/list/device", {}, "GET", false).then((res) => { + if(res.result && res.result.length) { + let deviceConnect = res.result.some(item => item.macAddress === app.globalData.ppScale.device.mac); + if(deviceConnect) { + this.setData({ + deviceConnect: true + }) + } else { + app.globalData.ppScale.plugin.Blue.disconnect(); + } + } + }) + }); + }); + }, + + // 初始化蓝牙 + initBluetooth() { + wx.openBluetoothAdapter({ + success: () => { + this.getDeviceSettingList(); + }, + fail: (err) => { + if (err.errCode === 10001) { + wx.showModal({ + title: "提示", + content: "请打开手机蓝牙", + }); + } + }, + }); + }, + + async refreshToken(fn, flag) { + let bodyToken = wx.getStorageSync('bodyToken'); + let bodyTokenTime = wx.getStorageSync('bodyTokenTime'); + if (!bodyToken || bodyTokenTime * 1000 < +new Date() || flag) { + let res = await app.globalData.ppScale.plugin.refreshToken({ + url: "https://uniquehealth.lefuenergy.com", + data: { + "appKey": app.globalData.ppScale.options.key, + "appSecret": app.globalData.ppScale.options.secret + } + }); + if (res.data.code == 200) { + wx.setStorageSync('bodyToken', res.data.data.token); + wx.setStorageSync('bodyTokenTime', res.data.data.expireTime); + fn(); + } + } else { + fn(); + } + }, + getDeviceSettingList() { + let bodyToken = wx.getStorageSync("bodyToken"); + app.globalData.ppScale.plugin.getDeviceSettingList({ + url: "https://uniquehealth.lefuenergy.com", + data: { + appKey: app.globalData.ppScale.options.key + }, + header: { + "token": bodyToken, + "Accept-Language": wx.getStorageSync("lang") || 'zh' + } + }).then((res) => { + if (res.data.code == 200) { + app.globalData.ppScale.plugin.Blue.setDeviceSetting(res.data.data); + app.globalData.ppScale.device.setting = res.data.data; + let deviceNames = res.data.data.map(item => item.deviceName); + app.globalData.ppScale.plugin.Blue.start(deviceNames, false); + app.globalData.ppScale.plugin.bus.subscribe("devicesList", (res_) => { + app.globalData.ppScale.plugin.Blue.stopBluetoothDevicesDiscovery(); + app.globalData.ppScale.plugin.Blue.createBLEConnection(res_[0]); + }); + } else if (res.data.code == 401 || res.data.code == 4008) { + // 401 token过期 / 4008 token为空 + // 重新请求token解析数据 + this.refreshToken(() => { + this.getDeviceSettingList(); + }, true); + } + }); + }, + + // 获取已经绑定的设备列表 + getDevice() { + let params = {}; + $.ajax("weighingScale/list/device", params, "GET", false).then((res) => { + this.setData({ + deviceInfo: res.result[0] + }) + }) + }, + + delDevice() { + if(this.data.deviceConnect) { + app.globalData.ppScale.activeProtocol.codeClearDeviceData("00", (res) => { + console.log("deviceInfo === codeClearDeviceData", res); + + let scaleDeviceId = app.globalData.ppScale.device.mac.replace(/:/g, ''); + let params = { + equipmentCode: scaleDeviceId, + }; + $.ajax("weighingScale/del/device", params, "POST", true, "正在解绑设备...").then(res_ => { + wx.showToast({ + icon: "none", + title: res_.message, + }) + setTimeout(() => { + wx.navigateBack({ + delta: 1 + }) + }, 1500); + }); + }) + } else { + wx.showToast({ + icon: "none", + title: "删除失败,请靠近设备并点亮后再试" + }) + this.initBluetooth(); + } + }, + + onUnload() { + app.globalData.ppScale.plugin.Blue.stop(); + } +}) \ No newline at end of file diff --git a/pages/deviceInfo/deviceInfo.json b/pages/deviceInfo/deviceInfo.json new file mode 100644 index 0000000..a1e80a4 --- /dev/null +++ b/pages/deviceInfo/deviceInfo.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "设备详情", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/deviceInfo/deviceInfo.wxml b/pages/deviceInfo/deviceInfo.wxml new file mode 100644 index 0000000..97c33a5 --- /dev/null +++ b/pages/deviceInfo/deviceInfo.wxml @@ -0,0 +1,34 @@ + + + + + + {{deviceInfo.equipmentName}} + 型号:{{deviceInfo.type}} + + + + + + 设备名称 + {{deviceInfo.equipmentName}} + + + 设备SN + {{deviceInfo.equipmentCode}} + + + 配置Wi-Fi + {{deviceInfo.wifiName}} + + + 成员 + {{deviceInfo.subUserNum}}人 + + + MAC地址 + {{deviceInfo.macAddress}} + + + +删除设备 \ No newline at end of file diff --git a/pages/deviceInfo/deviceInfo.wxss b/pages/deviceInfo/deviceInfo.wxss new file mode 100644 index 0000000..88487ae --- /dev/null +++ b/pages/deviceInfo/deviceInfo.wxss @@ -0,0 +1,94 @@ +page { + padding: 30rpx 30rpx 0; +} + +.device { + width: 100%; + display: flex; + flex-wrap: nowrap; + align-items: center; + padding: 30rpx; + box-sizing: border-box; + border-radius: 24rpx; + margin-bottom: 24rpx; + background-color: #FFFFFF; +} + +.device>view:first-of-type { + width: 180rpx; + height: 180rpx; + margin-right: 20rpx; +} + +.device>view:last-of-type { + flex: 1; + width: 0; +} + +.device>view:last-of-type>view:first-of-type { + color: #252535; + width: 100%; + height: 40rpx; + font-weight: bold; + font-size: 40rpx; + line-height: 40rpx; + margin-bottom: 22rpx; +} + +.device>view:last-of-type>view:last-of-type { + color: #808080; + width: 100%; + height: 26rpx; + font-size: 26rpx; + line-height: 26rpx; +} + +.info { + width: 100%; + border-radius: 24rpx; + margin-bottom: 88rpx; + background-color: #FFFFFF; +} + +.info>view { + width: 100%; + height: 120rpx; + padding: 0 30rpx; + box-sizing: border-box; + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + border-bottom: 1rpx solid #EAECF1; +} + +.info>view:last-of-type { + border-bottom: 0; +} + +.info>view>view { + height: 120rpx; + font-size: 30rpx; + line-height: 120rpx; +} + +.info>view>view:first-of-type { + color: #252535; + font-weight: bold; +} + +.info>view>view:last-of-type { + color: #808080; +} + +.btn { + color: #FFFFFF; + width: 580rpx; + height: 88rpx; + margin: 0 auto; + font-size: 32rpx; + font-weight: bold; + line-height: 88rpx; + text-align: center; + border-radius: 44rpx; + background-color: #1385FA; +} \ No newline at end of file diff --git a/pages/familyMembers/familyMembers.js b/pages/familyMembers/familyMembers.js new file mode 100644 index 0000000..8630a22 --- /dev/null +++ b/pages/familyMembers/familyMembers.js @@ -0,0 +1,45 @@ +import $ from "../../utils/request"; + +Page({ + data: { + userInfo: null, + + subUserList: [], + }, + + onShow() { + this.setData({ + userInfo: wx.getStorageSync("userInfo") || null + }) + this.getSubUser(); + }, + + // 获取家庭成员列表 + getSubUser() { + let params = {}; + $.ajax("weighingScale/list/subUser", params, "GET", true, "正在获取...").then(res => { + this.setData({ + subUserList: res.result + }) + }) + }, + + openUserInfo() { + wx.navigateTo({ + url: "/pages/userInfo/userInfo?initBluetooth=1&customerType=0" + }) + }, + + editMyInfo() { + wx.navigateTo({ + url: "/pages/userInfo/userInfo?initBluetooth=1&customerType=1" + }) + }, + + editUserInfo(e) { + let id = e.currentTarget.dataset.id; + wx.navigateTo({ + url: "/pages/userInfo/userInfo?id="+ id +"&initBluetooth=1&customerType=0" + }) + } +}) \ No newline at end of file diff --git a/pages/familyMembers/familyMembers.json b/pages/familyMembers/familyMembers.json new file mode 100644 index 0000000..2a8298a --- /dev/null +++ b/pages/familyMembers/familyMembers.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "家庭成员", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/familyMembers/familyMembers.wxml b/pages/familyMembers/familyMembers.wxml new file mode 100644 index 0000000..944b486 --- /dev/null +++ b/pages/familyMembers/familyMembers.wxml @@ -0,0 +1,31 @@ + + + + + {{userInfo ? userInfo.realname : '-'}} + 修改我的档案 + + + + 家庭成员 + + + + + + + + {{item.realname}} + 修改档案 + + + + + + + + + + + 添加新成员 + \ No newline at end of file diff --git a/pages/familyMembers/familyMembers.wxss b/pages/familyMembers/familyMembers.wxss new file mode 100644 index 0000000..41d2062 --- /dev/null +++ b/pages/familyMembers/familyMembers.wxss @@ -0,0 +1,128 @@ +page { + padding: 30rpx 30rpx 0; +} + +.myInfo { + width: 100%; + height: 150rpx; + padding: 0 30rpx 0 38rpx; + box-sizing: border-box; + display: flex; + flex-wrap: nowrap; + align-items: center; + border-radius: 16rpx; + margin-bottom: 40rpx; + background-color: #FFFFFF; +} + +.myInfo>view:nth-of-type(1) { + width: 84rpx; + height: 84rpx; + border-radius: 50%; + margin-right: 24rpx; +} + +.myInfo>view:nth-of-type(2) { + color: #252535; + flex: 1; + height: 32rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 32rpx; +} + +.myInfo>view:nth-of-type(3) { + color: #B6B6B6; + height: 28rpx; + font-size: 28rpx; + line-height: 28rpx; + padding-right: 30rpx; +} + +.familyMembers { + width: 100%; + margin-bottom: 24rpx; +} + +.familyMembers>view:first-of-type { + color: #252535; + width: 100%; + height: 32rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 32rpx; + margin-bottom: 30rpx; +} + +.familyMembers>view:last-of-type { + width: 100%; + border-radius: 16rpx; +} + +.familyMembers>view:last-of-type>view { + width: 100%; + height: 150rpx; + padding: 0 30rpx 0 38rpx; + box-sizing: border-box; + display: flex; + flex-wrap: nowrap; + align-items: center; + background-color: #FFFFFF; + border-bottom: 1rpx solid #EAECF1; +} + +.familyMembers>view:last-of-type>view:last-of-type { + border-bottom: 0; +} + +.familyMembers>view:last-of-type>view>view:nth-of-type(1) { + width: 84rpx; + height: 84rpx; + border-radius: 50%; + margin-right: 24rpx; +} + +.familyMembers>view:last-of-type>view>view:nth-of-type(2) { + color: #252535; + flex: 1; + height: 32rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 32rpx; +} + +.familyMembers>view:last-of-type>view>view:nth-of-type(3) { + color: #B6B6B6; + height: 28rpx; + font-size: 28rpx; + line-height: 28rpx; + padding-right: 30rpx; +} + +.btn { + width: 100%; + height: 150rpx; + padding: 0 38rpx; + box-sizing: border-box; + display: flex; + flex-wrap: nowrap; + align-items: center; + border-radius: 16rpx; + background-color: #FFFFFF; +} + +.btn>view:first-of-type { + width: 84rpx; + height: 84rpx; + border-radius: 50%; + margin-right: 24rpx; +} + +.btn>view:last-of-type { + color: #252535; + flex: 1; + height: 32rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 32rpx; +} \ No newline at end of file diff --git a/pages/getWifiList/getWifiList.js b/pages/getWifiList/getWifiList.js new file mode 100644 index 0000000..9ddd513 --- /dev/null +++ b/pages/getWifiList/getWifiList.js @@ -0,0 +1,32 @@ +const app = getApp(); + +Page({ + data: { + wifiList: [] + }, + + onLoad() { + this.initWifi(); + }, + + initWifi() { + wx.showLoading({ + title: "正在获取Wi-Fi列表...", + mask: true + }); + app.globalData.ppScale.activeProtocol.dataFindSurroundDevice((res) => { + wx.hideLoading(); + console.log("wifiList", res); + this.setData({ + wifiList: res + }) + }) + }, + + openSetWifiPassword(e) { + let item = JSON.stringify(e.currentTarget.dataset.item); + wx.navigateTo({ + url: "/pages/setWifiPassword/setWifiPassword?item=" + item + }) + } +}) \ No newline at end of file diff --git a/pages/getWifiList/getWifiList.json b/pages/getWifiList/getWifiList.json new file mode 100644 index 0000000..47fb2f9 --- /dev/null +++ b/pages/getWifiList/getWifiList.json @@ -0,0 +1,4 @@ +{ + "usingComponents": {}, + "disableScroll": true +} \ No newline at end of file diff --git a/pages/getWifiList/getWifiList.wxml b/pages/getWifiList/getWifiList.wxml new file mode 100644 index 0000000..98814b6 --- /dev/null +++ b/pages/getWifiList/getWifiList.wxml @@ -0,0 +1,19 @@ + + 可用Wi-Fi + 网络列表(设备暂不支持5GWi-Fi网络) + + + + + + + + + + + {{item.ssid}} + + + + + \ No newline at end of file diff --git a/pages/getWifiList/getWifiList.wxss b/pages/getWifiList/getWifiList.wxss new file mode 100644 index 0000000..66493d5 --- /dev/null +++ b/pages/getWifiList/getWifiList.wxss @@ -0,0 +1,64 @@ +page { + display: flex; + flex-direction: column; + background-color: #ffffff; +} + +.title { + width: 100%; + padding: 50rpx 55rpx 24rpx; + box-sizing: border-box; +} + +.title>view:first-of-type { + color: #252535; + width: 100%; + height: 48rpx; + font-size: 48rpx; + font-weight: bold; + line-height: 48rpx; + margin-bottom: 60rpx; +} + +.title>view:last-of-type { + color: #B6B6B6; + width: 100%; + height: 30rpx; + font-size: 30rpx; + line-height: 30rpx; +} + +.wifi { + flex: 1; + overflow: hidden; +} + +.content { + width: 100%; + padding: 0 55rpx; + box-sizing: border-box; +} + +.content>view { + width: 100%; + height: 80rpx; + margin: 30rpx 0; + display: flex; + flex-wrap: nowrap; +} + +.content>view>view:nth-of-type(1) { + width: 80rpx; + height: 80rpx; + margin-right: 24rpx; +} + +.content>view>view:nth-of-type(2) { + color: #252535; + flex: 1; + width: 0; + height: 80rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 80rpx; +} \ No newline at end of file diff --git a/pages/home/home.js b/pages/home/home.js new file mode 100644 index 0000000..522b94f --- /dev/null +++ b/pages/home/home.js @@ -0,0 +1,92 @@ +import $ from "../../utils/request"; + +Page({ + data: { + token: null, + userInfo: null, + + deviceList: [] + }, + + onShow() { + let token = wx.getStorageSync("token") || null; + let userInfo = wx.getStorageSync("userInfo") || null; + this.setData({ + token: token, + userInfo: userInfo + }) + if(token && userInfo) { + this.getDevice(); + } + }, + + // 点击登录或注册 + openLoginOrReg() { + wx.login({ + success: (res) => { + if (res.code) { + this.checkOpenIdLogin(res.code); + } else { + wx.showToast({ + icon: "none", + title: "登录失败,请稍后再试!", + }) + } + } + }) + }, + + // 微信一键登录 + checkOpenIdLogin(code) { + let params = { + code: code + }; + $.ajax("weighingScale/checkOpenIdLogin", params, "POST", true, "登录中...").then((res) => { + wx.setStorageSync("userInfo", res.result.user); + wx.setStorageSync("token", res.result.token); + if(res.result.token && res.result.user) { + this.setData({ + token: res.result.token, + userInfo: res.result.user + }) + this.getDevice(); + } else { + wx.showToast({ + icon: "none", + title: "请先补全个人信息" + }) + setTimeout(() => { + wx.navigateTo({ + url: "/pages/userInfo/userInfo?initBluetooth=0&customerType=1" + }) + }, 1500) + } + }) + }, + + // 获取已经绑定的设备列表 + getDevice() { + let params = {}; + $.ajax("weighingScale/list/device", params, "GET", true, "获取设备列表").then((res) => { + this.setData({ + deviceList: res.result + }) + }) + }, + + // 添加设备 + openSearchDevice() { + let token = this.data.token; + let userInfo = this.data.userInfo; + if (token && userInfo) { + wx.navigateTo({ + url: "/pages/searchDevice/searchDevice" + }) + } else { + wx.showToast({ + icon: "none", + title: "请先登录" + }) + } + } +}) \ No newline at end of file diff --git a/pages/home/home.json b/pages/home/home.json new file mode 100644 index 0000000..7930213 --- /dev/null +++ b/pages/home/home.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationStyle": "custom", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/home/home.wxml b/pages/home/home.wxml new file mode 100644 index 0000000..0acabd7 --- /dev/null +++ b/pages/home/home.wxml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + {{userInfo.realname}} + + + 登录/注册 + + + 智能体脂秤 + 注重更好的健康生活品质 + + + + 请添加设备 + 添加设备后,解锁更多体验 + + 添加设备 + + + 登录/注册 + + + \ No newline at end of file diff --git a/pages/home/home.wxss b/pages/home/home.wxss new file mode 100644 index 0000000..209f8f8 --- /dev/null +++ b/pages/home/home.wxss @@ -0,0 +1,118 @@ +.bg { + position: absolute; + z-index: 1; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; +} + +.home { + position: relative; + z-index: 2; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 215rpx 60rpx 120rpx; + box-sizing: border-box; +} + +.title { + width: 100%; +} + +.title>view:nth-of-type(1) { + width: 100%; + height: 80rpx; + display: flex; + flex-wrap: nowrap; + margin-bottom: 56rpx; +} + +.title>view:nth-of-type(1)>view:first-of-type { + width: 80rpx; + height: 80rpx; + overflow: hidden; + border-radius: 50%; + margin-right: 20rpx; +} + +.title>view:nth-of-type(1)>view:last-of-type { + color: #FFFFFF; + height: 80rpx; + line-height: 80rpx; + font-size: 28rpx; + font-weight: bold; + padding-right: 26rpx; +} + +.title>view:nth-of-type(1)>view:last-of-type::after { + border-left: 5rpx solid #ffffff; + border-top: 5rpx solid #ffffff; +} + +.title>view:nth-of-type(2) { + color: #FFFFFF; + height: 58rpx; + font-size: 58rpx; + font-weight: bold; + line-height: 58rpx; + margin-bottom: 34rpx; +} + +.title>view:nth-of-type(3) { + color: #FFFFFF; + height: 32rpx; + font-size: 32rpx; + line-height: 32rpx; + margin-bottom: 48rpx; +} + +.title>view:nth-of-type(4) { + width: 120rpx; + height: 6rpx; + border-radius: 3rpx; + background-color: #FFFFFF; +} + +.device { + width: 580rpx; + margin: 0 auto; +} + +.device>view:nth-of-type(1) { + color: #FFFFFF; + width: 100%; + height: 36rpx; + font-size: 36rpx; + font-weight: bold; + text-align: center; + line-height: 36rpx; + margin-bottom: 30rpx; +} + +.device>view:nth-of-type(2) { + color: #FFFFFF; + width: 100%; + height: 30rpx; + font-size: 30rpx; + text-align: center; + line-height: 30rpx; + margin-bottom: 80rpx; +} + +.device>view:nth-of-type(3) { + color: #FFFFFF; + width: 100%; + height: 106rpx; + font-size: 32rpx; + font-weight: bold; + text-align: center; + line-height: 106rpx; + border-radius: 16rpx; + border: 1rpx solid #FFFFFF; +} diff --git a/pages/index/index.js b/pages/index/index.js new file mode 100644 index 0000000..2066c4f --- /dev/null +++ b/pages/index/index.js @@ -0,0 +1,2 @@ +// index.js +Page({}) diff --git a/pages/index/index.json b/pages/index/index.json new file mode 100644 index 0000000..aa3f1b0 --- /dev/null +++ b/pages/index/index.json @@ -0,0 +1,5 @@ +{ + "usingComponents": { + "navigation-bar": "/components/navigation-bar/navigation-bar" + } +} \ No newline at end of file diff --git a/pages/index/index.wxml b/pages/index/index.wxml new file mode 100644 index 0000000..57cc6da --- /dev/null +++ b/pages/index/index.wxml @@ -0,0 +1,7 @@ + + + + + Weixin + + diff --git a/pages/index/index.wxss b/pages/index/index.wxss new file mode 100644 index 0000000..8c2b75a --- /dev/null +++ b/pages/index/index.wxss @@ -0,0 +1,10 @@ +/**index.wxss**/ +page { + height: 100vh; + display: flex; + flex-direction: column; +} +.scrollarea { + flex: 1; + overflow-y: hidden; +} diff --git a/pages/my/my.js b/pages/my/my.js new file mode 100644 index 0000000..4b3cb79 --- /dev/null +++ b/pages/my/my.js @@ -0,0 +1,112 @@ +import $ from "../../utils/request"; + +Page({ + data: { + userInfo: null, + + deviceInfo: null + }, + + onShow() { + let token = wx.getStorageSync("token") || null; + let userInfo = wx.getStorageSync("userInfo") || null; + this.setData({ + userInfo: userInfo + }) + if(token && userInfo) { + this.getDevice(); + } + }, + + // 打开用户信息 + openUserInfo() { + if(this.data.userInfo) { + wx.navigateTo({ + url: "/pages/userInfo/userInfo?initBluetooth=1&customerType=1" + }) + } else { + wx.showToast({ + icon: "none", + title: "请先登录" + }) + } + }, + + // 打开设备详情 + openDeviceInfo() { + if(this.data.userInfo) { + let deviceInfo = this.data.deviceInfo; + if(deviceInfo) { + wx.navigateTo({ + url: "/pages/deviceInfo/deviceInfo" + }) + } else { + wx.showModal({ + title: "提示", + content: "当前暂未绑定设备,需要绑定吗?", + confirmText: "去绑定", + success: (res) => { + if (res.confirm) { + wx.navigateTo({ + url: "/pages/searchDevice/searchDevice" + }) + } + } + }) + } + } else { + wx.showToast({ + icon: "none", + title: "请先登录" + }) + } + }, + + // 打开成员管理 + openFamilyMembers() { + if(this.data.userInfo) { + wx.navigateTo({ + url: "/pages/familyMembers/familyMembers" + }) + } else { + wx.showToast({ + icon: "none", + title: "请先登录" + }) + } + }, + + // 获取已经绑定的设备列表 + getDevice() { + let params = {}; + $.ajax("weighingScale/list/device", params, "GET", false).then((res) => { + this.setData({ + deviceInfo: res.result && res.result.length ? res.result[0] : null + }) + }) + }, + + // 退出登录 + exitLogin() { + wx.showModal({ + title: "提示", + content: "你确定要退出登录吗?", + success: (res) => { + if (res.confirm) { + $.ajax("weighingScale/logout", {}, "POST", true, "正在退出登录...").then(res => { + wx.showToast({ + icon: "none", + title: res.message + }) + setTimeout(() => { + wx.clearStorageSync(); + wx.switchTab({ + url: "/pages/home/home" + }) + }, 1500) + }) + } + } + }) + } +}) \ No newline at end of file diff --git a/pages/my/my.json b/pages/my/my.json new file mode 100644 index 0000000..7930213 --- /dev/null +++ b/pages/my/my.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationStyle": "custom", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/my/my.wxml b/pages/my/my.wxml new file mode 100644 index 0000000..608e284 --- /dev/null +++ b/pages/my/my.wxml @@ -0,0 +1,59 @@ + + + + + + {{userInfo && userInfo.realname ? userInfo.realname : '未登录'}} + + + + 身高(cm) + {{userInfo && userInfo.height ? userInfo.height : '--'}} + + + + 体重(kg) + {{userInfo && userInfo.weight ? userInfo.weight : '--'}} + + + + BMI + {{userInfo && userInfo.bmi ? userInfo.bmi : '--'}} + + + + + + + 我的服务 + + + + + 设备绑定 + {{deviceInfo ? '已绑定('+ deviceInfo.equipmentName +')' : '未绑定'}} + + + + + + 成员管理 + + + + + + + + + 隐私协议 + + + + + + + + 退出登录 + + diff --git a/pages/my/my.wxss b/pages/my/my.wxss new file mode 100644 index 0000000..d2133f7 --- /dev/null +++ b/pages/my/my.wxss @@ -0,0 +1,165 @@ +.userInfo { + width: 100%; + height: 488rpx; + margin-bottom: 24rpx; + box-sizing: border-box; + padding: 185rpx 40rpx 0; + background: linear-gradient(#F3F9FD 0%, #FFFFFF 100%); +} + +.user { + width: 100%; + height: 136rpx; + display: flex; + flex-wrap: nowrap; + margin-bottom: 46rpx; +} + +.user>view:first-of-type { + width: 126rpx; + height: 126rpx; + margin-right: 24rpx; + border-radius: 50%; + border: 5rpx solid #FFFFFF; +} + +.user>view:last-of-type { + color: #252536; + flex: 1; + height: 136rpx; + font-size: 40rpx; + font-weight: bold; + line-height: 136rpx; +} + +.info { + width: 100%; + display: flex; + flex-wrap: nowrap; + align-items: center; +} + +.info>view:nth-of-type(1), +.info>view:nth-of-type(3), +.info>view:nth-of-type(5) { + flex: 1; +} + +.info>view:nth-of-type(2n) { + width: 2rpx; + height: 52rpx; + background-color: #EAECF1; +} + +.info>view>view:first-of-type { + color: #394356; + width: 100%; + height: 28rpx; + font-size: 28rpx; + line-height: 28rpx; + text-align: center; + margin-bottom: 18rpx; +} + +.info>view>view:last-of-type { + color: #394356; + width: 100%; + height: 36rpx; + font-size: 36rpx; + font-weight: bold; + line-height: 36rpx; + text-align: center; +} + +.content { + width: 100%; + padding: 0 30rpx; + box-sizing: border-box; + margin-bottom: 360rpx; +} + +.content .arrowAfter::after { + right: 36rpx; +} + +.service { + width: 100%; + margin-bottom: 24rpx; + border-radius: 16rpx; + background-color: #FFFFFF; +} + +.title { + color: #394356; + width: 100%; + height: 96rpx; + line-height: 96rpx; + padding: 0 30rpx; + font-size: 30rpx; + font-weight: bold; + box-sizing: border-box; + border-bottom: 1rpx solid #EAECF1; +} + +.list { + width: 100%; + height: 96rpx; + padding: 0 30rpx; + display: flex; + flex-wrap: nowrap; + align-items: center; + box-sizing: border-box; + border-bottom: 1rpx solid #EAECF1; +} + +.list:last-of-type { + border-bottom: none; +} + +.list>view:nth-of-type(1) { + width: 56rpx; + height: 56rpx; + margin-right: 30rpx; +} + +.list>view:nth-of-type(2) { + flex: 1; + color: #394356; + height: 96rpx; + line-height: 96rpx; + font-size: 32rpx; + font-weight: bold; +} + +.list>view:nth-of-type(3) { + color: #77849E; + height: 96rpx; + font-size: 28rpx; + line-height: 96rpx; + padding-right: 34rpx; +} + +.agreement { + width: 100%; + border-radius: 16rpx; + background-color: #FFFFFF; +} + +.btn { + width: 100%; + padding: 0 85rpx; + box-sizing: border-box; +} + +.btn>view { + color: #1385FA; + width: 580rpx; + height: 88rpx; + line-height: 88rpx; + font-size: 32rpx; + border-radius: 44rpx; + text-align: center; + background-color: #F5F7FB; + border: 1rpx solid #1385FA; + +} \ No newline at end of file diff --git a/pages/searchDevice/searchDevice.js b/pages/searchDevice/searchDevice.js new file mode 100644 index 0000000..297099c --- /dev/null +++ b/pages/searchDevice/searchDevice.js @@ -0,0 +1,112 @@ +const app = getApp(); + +Page({ + data: { + getDeviceSetting: false, + + initText: "", + devicesList: [] + }, + + onLoad(options) { + this.initBluetooth(); + }, + + onShow() { + if (this.data.getDeviceSetting) { + this.getDeviceSettingList(); + } + }, + + // 初始化蓝牙 + initBluetooth() { + this.setData({ + initText: "正在初始化蓝牙..." + }) + wx.openBluetoothAdapter({ + success: () => { + this.setData({ + initText: "蓝牙初始化成功" + }) + this.getDeviceSettingList(); + }, + fail: (err) => { + this.setData({ + initText: "蓝牙初始化失败" + }) + if (err.errCode === 10001) { + wx.showModal({ + title: "提示", + content: "请打开手机蓝牙", + }); + } + }, + }); + }, + + async refreshToken(fn, flag) { + let bodyToken = wx.getStorageSync('bodyToken'); + let bodyTokenTime = wx.getStorageSync('bodyTokenTime'); + if (!bodyToken || bodyTokenTime * 1000 < +new Date() || flag) { + let res = await app.globalData.ppScale.plugin.refreshToken({ + url: "https://uniquehealth.lefuenergy.com", + data: { + "appKey": app.globalData.ppScale.options.key, + "appSecret": app.globalData.ppScale.options.secret + } + }); + if (res.data.code == 200) { + wx.setStorageSync('bodyToken', res.data.data.token); + wx.setStorageSync('bodyTokenTime', res.data.data.expireTime); + fn(); + } + } else { + fn(); + } + }, + getDeviceSettingList() { + this.setData({ + initText: "获取设备配置中..." + }) + let bodyToken = wx.getStorageSync("bodyToken"); + app.globalData.ppScale.plugin.getDeviceSettingList({ + url: "https://uniquehealth.lefuenergy.com", + data: { + appKey: app.globalData.ppScale.options.key + }, + header: { + "token": bodyToken, + "Accept-Language": wx.getStorageSync("lang") || 'zh' + } + }).then((res) => { + if (res.data.code == 200) { + this.setData({ + initText: "设备搜索中..." + }); + app.globalData.ppScale.plugin.Blue.setDeviceSetting(res.data.data); + app.globalData.ppScale.device.setting = res.data.data; + let deviceNames = res.data.data.map(item => item.deviceName); + app.globalData.ppScale.plugin.Blue.start(deviceNames, false); + app.globalData.ppScale.plugin.bus.subscribe("devicesList", (res_) => { + console.log("searchDevice ===> devicesList", res_); + this.setData({ + getDeviceSetting: false, + initText: "设备搜索完成" + }); + app.globalData.ppScale.plugin.Blue.stopBluetoothDevicesDiscovery(); + app.globalData.ppScale.device.list = res_; + app.globalData.ppScale.device.connection = res_[0]; + wx.navigateTo({ + url: "/pages/connectedDevice/connectedDevice" + }) + }); + } else if (res.data.code == 401 || res.data.code == 4008) { + // 401 token过期 / 4008 token为空 + // 重新请求token解析数据 + this.refreshToken(() => { + this.getDeviceSettingList(); + }, true); + } + }); + } +}) \ No newline at end of file diff --git a/pages/searchDevice/searchDevice.json b/pages/searchDevice/searchDevice.json new file mode 100644 index 0000000..58616d8 --- /dev/null +++ b/pages/searchDevice/searchDevice.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "搜索设备", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/searchDevice/searchDevice.wxml b/pages/searchDevice/searchDevice.wxml new file mode 100644 index 0000000..0a6d437 --- /dev/null +++ b/pages/searchDevice/searchDevice.wxml @@ -0,0 +1,12 @@ + + + + + + + + + + {{initText}} + 请轻轻踩秤,保证屏幕亮起 + \ No newline at end of file diff --git a/pages/searchDevice/searchDevice.wxss b/pages/searchDevice/searchDevice.wxss new file mode 100644 index 0000000..f2149ff --- /dev/null +++ b/pages/searchDevice/searchDevice.wxss @@ -0,0 +1,78 @@ +page { + width: 100%; + height: 100%; + padding-top: 120rpx; + box-sizing: border-box; + background-color: #FFFFFF; +} + +.icon { + width: 556rpx; + height: 556rpx; + position: relative; + margin: 0 auto 120rpx; +} + +.icon>view:nth-of-type(1) { + position: absolute; + z-index: 3; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + width: 200rpx; + height: 200rpx; + border-radius: 50%; +} + +.icon>view:nth-of-type(2), +.icon>view:nth-of-type(3) { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + width: 200rpx; + height: 200rpx; + border-radius: 50%; + animation: expand 2s infinite; +} + +@keyframes expand { + 0% { + width: 200rpx; + height: 200rpx; + background-color: #3194FB; + } + 100% { + width: 556rpx; + height: 556rpx; + background-color: rgba(0, 0, 0, 0); + } +} + +.description { + width: 100%; +} + +.description>view:nth-of-type(1) { + color: #252535; + width: 100%; + height: 36rpx; + font-size: 36rpx; + font-weight: bold; + line-height: 36rpx; + text-align: center; + margin-bottom: 30rpx; +} + +.description>view:nth-of-type(2) { + color: #808080; + width: 100%; + height: 30rpx; + font-size: 30rpx; + line-height: 30rpx; + text-align: center; +} \ No newline at end of file diff --git a/pages/setNetwork/setNetwork.js b/pages/setNetwork/setNetwork.js new file mode 100644 index 0000000..8c79b80 --- /dev/null +++ b/pages/setNetwork/setNetwork.js @@ -0,0 +1,42 @@ +const app = getApp(); +import $ from "../../utils/request"; + +Page({ + onLoad(options) { + let ssid = options.ssid; + let password = options.password; + app.globalData.ppScale.activeProtocol.dataConfigNetWork({ + domain: app.globalData.ppScale.domain, + ssid: options.ssid, + password: options.password + }, (res) => { + app.globalData.ppScale.wifi.ssid = ssid; + app.globalData.ppScale.wifi.password = password; + + let scaleDeviceId = app.globalData.ppScale.device.mac.replace(/:/g, ''); + let params = { + equipmentName: app.globalData.ppScale.device.name, + scaleDeviceId: scaleDeviceId, + }; + $.ajax("weighingScale/binding/device", params, "POST").then(res => { + app.globalData.ppScale.activeProtocol.codeSetBindingState((res) => { + console.log("setNetwork.js codeSetBindingState", res); + + wx.navigateTo({ + url: "/pages/setNetworkSuccessful/setNetworkSuccessful" + }) + }) + }).catch(err => { + wx.showToast({ + icon: "none", + title: err.message + }) + setTimeout(() => { + wx.switchTab({ + url: "/pages/home/home" + }) + }, 1500) + }) + }) + } +}) \ No newline at end of file diff --git a/pages/setNetwork/setNetwork.json b/pages/setNetwork/setNetwork.json new file mode 100644 index 0000000..754b6a9 --- /dev/null +++ b/pages/setNetwork/setNetwork.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "正在配网", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/setNetwork/setNetwork.wxml b/pages/setNetwork/setNetwork.wxml new file mode 100644 index 0000000..d5908ce --- /dev/null +++ b/pages/setNetwork/setNetwork.wxml @@ -0,0 +1,13 @@ + + + + + 已链接,配网中... + 请持续站在秤上,耐心等待 + + + + 手机尽量靠近设备(2米以内) + Wi-Fi指示灯闪烁,处于配网状态 + Wi-Fi指示灯长亮为已连接状态 + \ No newline at end of file diff --git a/pages/setNetwork/setNetwork.wxss b/pages/setNetwork/setNetwork.wxss new file mode 100644 index 0000000..d15b18d --- /dev/null +++ b/pages/setNetwork/setNetwork.wxss @@ -0,0 +1,54 @@ +page { + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 90rpx 60rpx 120rpx; + background-color: #ffffff; +} + +.icon { + width: 100%; +} + +.icon>view:nth-of-type(1) { + width: 565rpx; + height: 500rpx; + margin: 0 auto; +} + +.icon>view:nth-of-type(2) { + color: #1385FA; + width: 100%; + height: 36rpx; + font-size: 36rpx; + font-weight: bold; + line-height: 36rpx; + text-align: center; + margin-bottom: 28rpx; +} + +.icon>view:nth-of-type(3) { + color: #808080; + width: 100%; + height: 30rpx; + font-size: 30rpx; + text-align: center; + line-height: 30rpx; +} + +.describe { + width: 100%; +} + +.describe>view { + color: #808080; + width: 100%; + font-size: 26rpx; + font-weight: bold; + line-height: 26rpx; + margin-bottom: 26rpx; +} + +.describe>view:last-of-type { + margin-bottom: 0; +} \ No newline at end of file diff --git a/pages/setNetworkSuccessful/setNetworkSuccessful.js b/pages/setNetworkSuccessful/setNetworkSuccessful.js new file mode 100644 index 0000000..bf4d50b --- /dev/null +++ b/pages/setNetworkSuccessful/setNetworkSuccessful.js @@ -0,0 +1,115 @@ +const app = getApp(); + +Page({ + data: { + userInfo: null, + subUser: { + i: 0, + data: [] + }, + + ssid: "" + }, + + onLoad(options) { + this.setData({ + userInfo: wx.getStorageSync("userInfo"), + ssid: app.globalData.ppScale.wifi.ssid + }); + }, + + completeClick() { + let userInfo = this.data.userInfo; + // 设置主用户时userID为小程序的用户ID,memberID为空 + app.globalData.ppScale.activeProtocol.dataSyncUserInfo({ + userID: userInfo.id, + userName: userInfo.realname, + memberID: "", + age: this.getAge(userInfo.birthday), // + gender: userInfo.sex, // + height: userInfo.height, // + isAthleteMode: 0, + currentWeight: userInfo.weight, // + deviceHeaderIndex: 0, + targetWeight: "", + idealWeight: "", + recentData: [], + }, (res) => { + console.log("dataSyncUserInfo", res); + + if(this.data.subUser.data && this.data.subUser.data.length) { + wx.showLoading({ + title: "正在同步用户信息,请稍等...", + mask: true + }); + setSubUser(); + } else { + app.globalData.ppScale.plugin.Blue.stop(); + wx.switchTab({ + url: "/pages/home/home" + }) + } + }) + }, + + setSubUser() { + let userInfo = this.data.userInfo; + let i = this.data.subUser.i; + let subUser = this.data.subUser.data; + app.globalData.ppScale.activeProtocol.dataSyncUserInfo({ + userID: userInfo.id, + userName: subUser[i].realname, + memberID: subUser[i].id, + age: this.getAge(subUser[i].birthday), // + gender: subUser[i].sex, // + height: subUser[i].height, // + isAthleteMode: 0, + currentWeight: subUser[i].weight, // + deviceHeaderIndex: 0, + targetWeight: "", + idealWeight: "", + recentData: [], + }, (res) => { + console.log("dataSyncSubUserInfo", res); + if(i < subUser.length) { + this.setData({ + ['subUser.i']: i + 1 + }) + setSubUser(); + } else { + app.globalData.ppScale.plugin.Blue.stop(); + wx.hideLoading(); + wx.switchTab({ + url: "/pages/home/home" + }) + } + }) + }, + + // 获取家庭成员列表 + getSubUser() { + let params = {}; + $.ajax("weighingScale/list/subUser", params, "GET", true, "正在获取成员列表...").then(res => { + this.setData({ + ['subUser.data']: res.result + }) + }) + }, + + // 根据生日获取年龄 + getAge(birthDateString) { + const birthDate = new Date(birthDateString); + const today = new Date(); + + let age = today.getFullYear() - birthDate.getFullYear(); + const monthDiff = today.getMonth() - birthDate.getMonth(); + const dayDiff = today.getDate() - birthDate.getDate(); + + // 如果当前月份小于出生月份,或者同月但当前日期小于出生日期,年龄需要减 1 + if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) { + age--; + } + + return age; + } +}) \ No newline at end of file diff --git a/pages/setNetworkSuccessful/setNetworkSuccessful.json b/pages/setNetworkSuccessful/setNetworkSuccessful.json new file mode 100644 index 0000000..84c4caf --- /dev/null +++ b/pages/setNetworkSuccessful/setNetworkSuccessful.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "绑定成功", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/setNetworkSuccessful/setNetworkSuccessful.wxml b/pages/setNetworkSuccessful/setNetworkSuccessful.wxml new file mode 100644 index 0000000..25db03c --- /dev/null +++ b/pages/setNetworkSuccessful/setNetworkSuccessful.wxml @@ -0,0 +1,21 @@ + + + + + 配网成功 + + + + 当前设备配置Wi-Fi + + + + + {{ssid}} + + + + + + +完成 \ No newline at end of file diff --git a/pages/setNetworkSuccessful/setNetworkSuccessful.wxss b/pages/setNetworkSuccessful/setNetworkSuccessful.wxss new file mode 100644 index 0000000..ec46075 --- /dev/null +++ b/pages/setNetworkSuccessful/setNetworkSuccessful.wxss @@ -0,0 +1,93 @@ +page { + width: 100%; + padding: 200rpx 85rpx 0; + box-sizing: border-box; + background-color: #ffffff; +} + +.icon { + width: 100%; + margin-bottom: 120rpx; +} + +.icon>view:first-of-type { + width: 360rpx; + height: 295rpx; + margin: 0 auto 50rpx; +} + +.icon>view:last-of-type { + color: #252535; + width: 100%; + height: 40rpx; + font-size: 40rpx; + font-weight: bold; + line-height: 40rpx; + text-align: center; +} + +.info { + width: 100%; + margin-bottom: 380rpx; +} + +.info>view:first-of-type { + color: #B6B6B6; + width: 100%; + height: 30rpx; + font-size: 30rpx; + line-height: 30rpx; + margin-bottom: 40rpx; +} + +.info>view:last-of-type { + width: 100%; + height: 80rpx; + margin: 30rpx 0; + display: flex; + flex-wrap: nowrap; + align-items: center; +} + +.info>view:last-of-type>view:nth-of-type(1) { + width: 80rpx; + height: 80rpx; + margin-right: 24rpx; +} + +.info>view:last-of-type>view:nth-of-type(2) { + color: #252535; + flex: 1; + width: 0; + height: 80rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 80rpx; +} + +.info>view:last-of-type>view:nth-of-type(3) { + width: 32rpx; + height: 32rpx; +} + +.describe { + color: #B6B6B6; + width: 100%; + height: 26rpx; + font-size: 28rpx; + line-height: 28rpx; + text-align: center; + margin-bottom: 46rpx; +} + +.btn { + color: #FFFFFF; + width: 100%; + height: 88rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 88rpx; + text-align: center; + border-radius: 44rpx; + background-color: #1385FA; +} \ No newline at end of file diff --git a/pages/setWifiPassword/setWifiPassword.js b/pages/setWifiPassword/setWifiPassword.js new file mode 100644 index 0000000..895e02d --- /dev/null +++ b/pages/setWifiPassword/setWifiPassword.js @@ -0,0 +1,27 @@ +const app = getApp(); + +Page({ + data: { + wifiInfo: null, + password: "mimahaojige8" + }, + + onLoad(options) { + this.setData({ + wifiInfo: JSON.parse(options.item) + }) + }, + + passwordInput(e) { + this.setData({ + password: e.detail.value + }) + }, + + // 打开配网 + openSetNetwork() { + wx.navigateTo({ + url: "/pages/setNetwork/setNetwork?ssid=" + this.data.wifiInfo.ssid + "&password=" + this.data.password + }) + } +}) \ No newline at end of file diff --git a/pages/setWifiPassword/setWifiPassword.json b/pages/setWifiPassword/setWifiPassword.json new file mode 100644 index 0000000..4200326 --- /dev/null +++ b/pages/setWifiPassword/setWifiPassword.json @@ -0,0 +1,5 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "输入Wi-Fi密码", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/setWifiPassword/setWifiPassword.wxml b/pages/setWifiPassword/setWifiPassword.wxml new file mode 100644 index 0000000..4ca529d --- /dev/null +++ b/pages/setWifiPassword/setWifiPassword.wxml @@ -0,0 +1,24 @@ + + + + + + {{wifiInfo.ssid}} + + + 密码 + + + + + + + + + +连接 \ No newline at end of file diff --git a/pages/setWifiPassword/setWifiPassword.wxss b/pages/setWifiPassword/setWifiPassword.wxss new file mode 100644 index 0000000..ebd4598 --- /dev/null +++ b/pages/setWifiPassword/setWifiPassword.wxss @@ -0,0 +1,81 @@ +page { + padding: 55rpx 55rpx 0; + background-color: #ffffff; +} + +.form { + width: 100%; + margin-bottom: 64rpx; +} + +.form>view { + width: 100%; + height: 96rpx; + display: flex; + flex-wrap: nowrap; + align-items: center; + padding: 0 24rpx; + box-sizing: border-box; + border-radius: 16rpx; + background-color: #F6F6F6; +} + +.form>view:first-of-type { + margin-bottom: 32rpx; +} + +.form>view>view:nth-of-type(1) { + color: #252535; + width: 100rpx; + height: 96rpx; + line-height: 96rpx; + font-size: 32rpx; + font-weight: bold; +} + +.form>view:first-of-type>view:nth-of-type(1) { + padding: 24rpx 45rpx 24rpx 7rpx; + box-sizing: border-box; + display: flex; + align-items: center; +} + +.form>view>view:nth-of-type(2) { + color: #252535; + flex: 1; + width: 0; + height: 96rpx; + font-size: 32rpx; + line-height: 96rpx; +} + +.form>view>view:nth-of-type(2) input { + color: #252535; + width: 100%; + height: 96rpx; + font-size: 32rpx; + line-height: 96rpx; +} + +.placeholderClass { + color: #B6B6B6; + font-size: 32rpx; +} + +.form>view>view:nth-of-type(3) { + width: 56rpx; + height: 56rpx; +} + +.btn { + color: #FFFFFF; + width: 580rpx; + height: 88rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 88rpx; + margin: 0 auto; + text-align: center; + border-radius: 44rpx; + background-color: #1385FA; +} \ No newline at end of file diff --git a/pages/userInfo/userInfo.js b/pages/userInfo/userInfo.js new file mode 100644 index 0000000..4bd57e1 --- /dev/null +++ b/pages/userInfo/userInfo.js @@ -0,0 +1,475 @@ +const app = getApp(); +import $ from "../../utils/request"; + +Page({ + data: { + deviceConnect: false, + + initBluetooth: "0", + customerType: "1", + + id: "", + realname: "", + sex: { + index: null, + data: [{ + id: 1, + name: '男' + }, { + id: 2, + name: '女' + }] + }, + birthday: { + label: "1980年01月01日", + value: "1980-01-01" + }, + phone: "", + height: { + index: 50, + data: Array.from({ length: 200 - 120 + 1 }, (_, i) => i + 120) + }, + weight: { + index: 20, + data: Array.from({ length: 100 - 50 + 1 }, (_, i) => i + 50) + }, + }, + + onLoad(options) { + // initBluetooth 是否初始化蓝牙和设备 1 是 / 0 否 + // customerType 用户类型 1 自己 / 0 他人 + // id 用户ID 当customerType为0时,家庭成员的用户ID / 为1时始终为空字符串 + this.setData({ + id: options.id ? options.id : null, + initBluetooth: options.initBluetooth, + customerType: options.customerType, + }) + if(options.customerType === "0") { + wx.setNavigationBarTitle({ + title: options.id ? '编辑成员档案' : '新增成员档案' + }) + if(options.id) { + this.subUserInfo() + } + } else { + let userInfo = wx.getStorageSync("userInfo") || null; + if (userInfo && options.initBluetooth === "1") { + let [year, month, day] = userInfo.birthday.split("-"); + this.setData({ + realname: userInfo.realname, + ["sex.index"]: this.data.sex.data.findIndex(item => {return item.name === userInfo.sex_dictText}), + birthday: { + label: year + "年" + month + "月" + day + "日", + value: userInfo.birthday + }, + phone: userInfo.phone, + ["height.index"]: this.data.height.data.findIndex(item => {return item === userInfo.height}), + ["weight.index"]: this.data.weight.data.findIndex(item => {return item === userInfo.weight}), + }) + } + } + if(options.initBluetooth === "1") { + this.initBluetooth(); + + app.globalData.ppScale.plugin.bus.subscribe("deviceConnect", (res) => { + console.log('deviceInfo ===》deviceConnect', res); + + + app.globalData.ppScale.plugin.ScaleAction.startDataProgress(); + app.globalData.ppScale.activeProtocol = app.globalData.ppScale.plugin.ScaleAction.getActiveProtocol(); + + app.globalData.ppScale.activeProtocol.codeUpdateMTU((res) => { + console.log("deviceInfo ===》codeUpdateMTU", res); + + $.ajax("weighingScale/list/device", {}, "GET", false).then((res) => { + if(res.result && res.result.length) { + let deviceConnect = res.result.some(item => item.macAddress === app.globalData.ppScale.device.mac); + if(deviceConnect) { + this.setData({ + deviceConnect: true + }) + } else { + app.globalData.ppScale.plugin.Blue.disconnect(); + } + } + }) + }); + }); + } + }, + + // 初始化蓝牙 + initBluetooth() { + wx.openBluetoothAdapter({ + success: () => { + this.getDeviceSettingList(); + }, + fail: (err) => { + if (err.errCode === 10001) { + wx.showModal({ + title: "提示", + content: "请打开手机蓝牙", + }); + } + }, + }); + }, + + async refreshToken(fn, flag) { + let bodyToken = wx.getStorageSync('bodyToken'); + let bodyTokenTime = wx.getStorageSync('bodyTokenTime'); + if (!bodyToken || bodyTokenTime * 1000 < +new Date() || flag) { + let res = await app.globalData.ppScale.plugin.refreshToken({ + url: "https://uniquehealth.lefuenergy.com", + data: { + "appKey": app.globalData.ppScale.options.key, + "appSecret": app.globalData.ppScale.options.secret + } + }); + if (res.data.code == 200) { + wx.setStorageSync('bodyToken', res.data.data.token); + wx.setStorageSync('bodyTokenTime', res.data.data.expireTime); + fn(); + } + } else { + fn(); + } + }, + getDeviceSettingList() { + let bodyToken = wx.getStorageSync("bodyToken"); + app.globalData.ppScale.plugin.getDeviceSettingList({ + url: "https://uniquehealth.lefuenergy.com", + data: { + appKey: app.globalData.ppScale.options.key + }, + header: { + "token": bodyToken, + "Accept-Language": wx.getStorageSync("lang") || 'zh' + } + }).then((res) => { + if (res.data.code == 200) { + app.globalData.ppScale.plugin.Blue.setDeviceSetting(res.data.data); + app.globalData.ppScale.device.setting = res.data.data; + let deviceNames = res.data.data.map(item => item.deviceName); + app.globalData.ppScale.plugin.Blue.start(deviceNames, false); + app.globalData.ppScale.plugin.bus.subscribe("devicesList", (res_) => { + app.globalData.ppScale.plugin.Blue.stopBluetoothDevicesDiscovery(); + app.globalData.ppScale.plugin.Blue.createBLEConnection(res_[0]); + }); + } else if (res.data.code == 401 || res.data.code == 4008) { + // 401 token过期 / 4008 token为空 + // 重新请求token解析数据 + this.refreshToken(() => { + this.getDeviceSettingList(); + }, true); + } + }); + }, + + // 姓名输入 + realnameInput(e) { + let realname = e.detail.value.replace(/\s+/g, ''); + this.setData({ + realname: realname + }) + }, + + // 性别选择 + sexChange(e) { + let sex = e.detail.value; + console.log(sex); + this.setData({ + ['sex.index']: e.detail.value + }) + if(this.data.height.index === null) { + this.setData({ + ['height.index']: sex == 0 ? 50 : 40 + }) + } + if(this.data.weight.index === null) { + this.setData({ + ['weight.index']: sex == 0 ? 20 : 10 + }) + } + }, + + // 生日选择 + birthdayChange(e) { + let v = e.detail.value; + let [year, month, day] = v.split("-"); + this.setData({ + birthday: { + label: year + "年" + month + "月" + day + "日", + value: v + } + }) + }, + + // 获取手机号 + getPhoneNumber(e) { + let params = { + code: e.detail.code, + thirdId: wx.getStorageSync("userInfo").thirdId + }; + $.ajax("weighingScale/getPhone", params, "POST").then(res => { + wx.setStorageSync("userInfo", res.result.user); + wx.setStorageSync("token", res.result.token); + this.setData({ + phone: res.result.user.phone + }) + }) + }, + + // 身高选择 + heightChange(e) { + this.setData({ + ['height.index']: e.detail.value + }) + }, + + // 体重选择 + weightChange(e) { + this.setData({ + ['weight.index']: e.detail.value + }) + }, + + // 提交判断 + submit() { + let realname = this.data.realname; + let sex = this.data.sex; + let birthday = this.data.birthday; + let phone = this.data.phone; + let height = this.data.height; + let weight = this.data.weight; + if(this.data.initBluetooth === "1" && !this.data.deviceConnect) { + wx.showToast({ + icon: "none", + title: "请靠近设备并点亮后再试" + }) + this.initBluetooth(); + return false; + } + if(!realname) { + wx.showToast({ + icon: "none", + title: "姓名不能为空" + }) + return false; + } + if(sex.index === null) { + wx.showToast({ + icon: "none", + title: "性别不能为空" + }) + return false; + } + if(!birthday.value) { + wx.showToast({ + icon: "none", + title: "生日不能为空" + }) + return false; + } + if(this.data.customerType === "1" && !phone) { + wx.showToast({ + icon: "none", + title: "手机号不能为空" + }) + return false; + } + if(height.index === null) { + wx.showToast({ + icon: "none", + title: "身高不能为空" + }) + return false; + } + if(weight.index === null) { + wx.showToast({ + icon: "none", + title: "体重不能为空" + }) + return false; + } + if(this.data.customerType === "1") { + this.submitMe({ + realname: realname, + sex: sex.data[sex.index].id, + birthday: birthday.value, + phone: phone, + height: height.data[height.index], + weight: weight.data[weight.index] + }); + } else { + this.submitUser({ + id: this.data.id, + realname: realname, + sex: sex.data[sex.index].id, + birthday: birthday.value, + height: height.data[height.index], + weight: weight.data[weight.index] + }); + } + }, + + // 提交自己的信息 + submitMe(params) { + $.ajax("weighingScale/edit/user", params, "POST", true, "保存中...").then(res => { + $.ajax("weighingScale/select/user", {}, "GET", true, "更新用户信息中...").then(res_ => { + wx.setStorageSync("userInfo", res_.result); + wx.showToast({ + icon: "none", + title: res.message + }) + if(this.data.initBluetooth === "1") { + app.globalData.ppScale.activeProtocol.dataSyncUserInfo({ + userID: res_.result.id, + userName: res_.result.realname, + memberID: "", + age: this.getAge(res_.result.birthday), // + gender: res_.result.sex, // + height: res_.result.height, // + isAthleteMode: 0, + currentWeight: res_.result.weight, // + deviceHeaderIndex: 0, + targetWeight: "", + idealWeight: "", + recentData: [], + }, (res) => { + console.log("dataSyncUserInfo", res) + app.globalData.ppScale.plugin.Blue.stop(); + setTimeout(() => { + wx.navigateBack({ + delta: 1 + }) + }, 1500) + }) + } else { + setTimeout(() => { + wx.navigateBack({ + delta: 1 + }) + }, 1500) + } + }) + }) + }, + + // 提交家庭成员的信息 + submitUser(params) { + $.ajax("weighingScale/edit/subUser", params, "POST", true, "保存中...").then(res => { + wx.showToast({ + icon: "none", + title: res.message + }) + app.globalData.ppScale.activeProtocol.dataSyncUserInfo({ + userID: wx.getStorageSync("userInfo").id, + userName: params.realname, + memberID: res.result, + age: this.getAge(params.birthday), // + gender: params.sex, // + height: params.height, // + isAthleteMode: 0, + currentWeight: params.weight, // + deviceHeaderIndex: 0, + targetWeight: "", + idealWeight: "", + recentData: [], + }, (res) => { + console.log("dataSyncUserInfo", res) + app.globalData.ppScale.plugin.Blue.stop(); + setTimeout(() => { + wx.navigateBack({ + delta: 1 + }) + }, 1500) + }) + }) + }, + + // 删除家庭成员 + delUser() { + if(this.data.deviceConnect) { + wx.showModal({ + title: "提示", + content: "你要定要删除此成员吗?", + success: (res) => { + if (res.confirm) { + let params = { + id: this.data.id + }; + console.log(params); + $.ajax("weighingScale/del/subUser", params, "POST", true, "删除中...").then(res => { + wx.showToast({ + icon: "none", + title: res.message + }) + app.globalData.ppScale.activeProtocol.dataDeleteUser({ + userID: wx.getStorageSync("userInfo").id, + memberID: this.data.id, + }, (res) => { + console.log("dataDeleteUser", res); + app.globalData.ppScale.plugin.Blue.stop(); + setTimeout(() => { + wx.navigateBack({ + delta: 1 + }) + }, 1500); + }) + }) + } + } + }) + } else { + wx.showToast({ + icon: "none", + title: "删除失败,请靠近设备并点亮后再试" + }) + this.initBluetooth(); + } + }, + + // 获取家庭成员信息详情 + subUserInfo() { + let params = { + userId: this.data.id + }; + $.ajax("weighingScale/select/subUser", params, "GET", false).then(res => { + let [year, month, day] = res.result.birthday.split("-"); + this.setData({ + realname: res.result.realname, + ["sex.index"]: this.data.sex.data.findIndex(item => {return item.name === res.result.sex_dictText}), + birthday: { + label: year + "年" + month + "月" + day + "日", + value: res.result.birthday + }, + ["height.index"]: this.data.height.data.findIndex(item => {return item === res.result.height}), + ["weight.index"]: this.data.weight.data.findIndex(item => {return item === res.result.weight}), + }) + }) + }, + + // 根据生日获取年龄 + getAge(birthDateString) { + const birthDate = new Date(birthDateString); + const today = new Date(); + + let age = today.getFullYear() - birthDate.getFullYear(); + const monthDiff = today.getMonth() - birthDate.getMonth(); + const dayDiff = today.getDate() - birthDate.getDate(); + + // 如果当前月份小于出生月份,或者同月但当前日期小于出生日期,年龄需要减 1 + if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) { + age--; + } + + return age; + }, + + onUnload() { + if(this.data.initBluetooth === "1") { + app.globalData.ppScale.plugin.Blue.stop(); + } + } +}) \ No newline at end of file diff --git a/pages/userInfo/userInfo.json b/pages/userInfo/userInfo.json new file mode 100644 index 0000000..6becaf9 --- /dev/null +++ b/pages/userInfo/userInfo.json @@ -0,0 +1,6 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "用户档案", + "navigationBarBackgroundColor": "#F5F7FB", + "disableScroll": true +} \ No newline at end of file diff --git a/pages/userInfo/userInfo.wxml b/pages/userInfo/userInfo.wxml new file mode 100644 index 0000000..bf1eb72 --- /dev/null +++ b/pages/userInfo/userInfo.wxml @@ -0,0 +1,66 @@ +请填写和完善您家人的健康信息,将用于计算身体数据及运动卡路里消耗等,以便准确的分析数据。我们会严格保护您的家庭信息安全。 + + + + 姓名 + + + + + + 性别 + + + {{sex.index === null ? '请选择性别' : sex.data[sex.index].name}} + + + + + 生日 + + + {{birthday.value ? birthday.label : '请选择生日'}} + + + + + + 手机号 + + + {{phone}} + + + + + + + + + 身高 + + + {{height.index === null ? '请选择身高' : height.data[height.index] + ' cm'}} + + + + + 体重 + + + {{weight.index === null ? '请选择体重' : weight.data[weight.index] + ' kg'}} + + + + + +确定 + + + 删除该档案 + \ No newline at end of file diff --git a/pages/userInfo/userInfo.wxss b/pages/userInfo/userInfo.wxss new file mode 100644 index 0000000..c8823f2 --- /dev/null +++ b/pages/userInfo/userInfo.wxss @@ -0,0 +1,96 @@ +page { + padding: 30rpx 30rpx 0; +} + +.tips { + color: #77849E; + width: 100%; + font-size: 26rpx; + line-height: 40rpx; + margin-bottom: 40rpx; + padding: 0 30rpx; + box-sizing: border-box; +} + +.form { + width: 100%; + padding: 0 30rpx; + border-radius: 16rpx; + box-sizing: border-box; + background-color: #FFFFFF; + margin-bottom: 80rpx; +} + +.form>view { + width: 100%; + height: 120rpx; + padding: 0 10rpx; + display: flex; + flex-wrap: nowrap; + box-sizing: border-box; + border-bottom: 1rpx solid #EAECF1; +} + +.form>view>view:first-of-type { + color: #252535; + height: 120rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 120rpx; +} + +.form>view>view:last-of-type { + flex: 1; + width: 0; + color: #B6B6B6; + font-size: 28rpx; + height: 120rpx; + line-height: 120rpx; + text-align: right; +} + +.form>view>view:last-of-type.arrowAfter { + padding-right: 30rpx; +} + +.form>view>view:last-of-type input { + color: #252535; + width: 100%; + height: 120rpx; + line-height: 120rpx; + text-align: right; +} + +.placeholderClass { + color: #B6B6B6; + font-size: 28rpx; +} + +.form>view { + border-bottom: 0; +} + +.btn { + color: #FFFFFF; + width: 580rpx; + height: 88rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 88rpx; + text-align: center; + border-radius: 44rpx; + margin: 0 auto 50rpx; + background-color: #1385FA; +} + +.delBtn { + color: #1385FA; + width: 580rpx; + height: 88rpx; + font-size: 32rpx; + font-weight: bold; + line-height: 88rpx; + text-align: center; + border-radius: 44rpx; + margin: 0 auto; +} \ No newline at end of file diff --git a/project.config.json b/project.config.json new file mode 100644 index 0000000..0868a6f --- /dev/null +++ b/project.config.json @@ -0,0 +1,29 @@ +{ + "appid": "wx6c71f3ebcdcddffd", + "compileType": "miniprogram", + "libVersion": "3.7.11", + "packOptions": { + "ignore": [], + "include": [] + }, + "setting": { + "coverView": true, + "es6": true, + "postcss": true, + "minified": true, + "enhance": true, + "showShadowRootInWxmlPanel": true, + "packNpmRelationList": [], + "babelSetting": { + "ignore": [], + "disablePlugins": [], + "outputPath": "" + } + }, + "condition": {}, + "editorSetting": { + "tabIndent": "tab", + "tabSize": 4 + }, + "simulatorPluginLibVersion": {} +} \ No newline at end of file diff --git a/project.private.config.json b/project.private.config.json new file mode 100644 index 0000000..cc1267e --- /dev/null +++ b/project.private.config.json @@ -0,0 +1,10 @@ +{ + "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", + "projectname": "weightScaleMini", + "setting": { + "compileHotReLoad": true, + "urlCheck": false, + "bigPackageSizeSupport": true + }, + "libVersion": "3.7.10" +} \ No newline at end of file diff --git a/sitemap.json b/sitemap.json new file mode 100644 index 0000000..cd24f35 --- /dev/null +++ b/sitemap.json @@ -0,0 +1,7 @@ +{ + "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", + "rules": [{ + "action": "allow", + "page": "*" + }] +} \ No newline at end of file diff --git a/utils/request.js b/utils/request.js new file mode 100644 index 0000000..cfbc780 --- /dev/null +++ b/utils/request.js @@ -0,0 +1,94 @@ +const app = getApp(); +let loadingCount = 0; + +const showLoading = (title) => { + if (loadingCount === 0) { + wx.showLoading({ + title: title, + mask: true + }); + } + loadingCount++; +}; + +const hideLoading = () => { + if (loadingCount > 0) { + loadingCount--; + } + if (loadingCount === 0) { + wx.hideLoading(); + } +} + +const ajax = (url, params, methos, loading = true, title = "加载中...") => { + let requestUrl = app.globalData.wxRequestUrl + url; + if (loading) { + showLoading(title); + } + + return new Promise((resolve, reject) => { + let header = { + "content-type": "application/json" + }; + + let token = wx.getStorageSync("token"); + if (Boolean(token)) { + header['X-Access-Token'] = token; + } + wx.request({ + url: requestUrl, + data: params, + method: methos, + header: header, + success: (res) => { + if (loading) { + hideLoading(); + } + console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 开始 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓"); + switch (res.data.code) { + case 200: + resolve(res.data); + console.log("接口【 " + url + " 】请求成功!状态码为:200(正常)"); + break; + case 400: + reject(res.data); + console.error("接口【 " + url + " 】请求错误!状态码为:400(报错)"); + break; + case 401: + wx.clearStorageSync(); + reject(res.data); + console.error("接口【 " + url + " 】请求错误!状态码为:401(未登录)"); + break; + case 500: + reject(res.data); + console.error("接口【 " + url + " 】请求错误!状态码为:500(服务器错误)"); + break; + default: + reject(res.data); + console.error("接口【 " + url + " 】请求错误!状态码为:未知"); + } + console.log("Header参数为 ↓↓↓"); + console.log(header); + console.log("请求参数为 ↓↓↓"); + console.log(params); + console.log("返回参数为 ↓↓↓") + console.log(res.data); + console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 结束 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"); + }, + fail: (error) => { + if (loading) { + hideLoading(); + } + wx.showToast({ + title: "请求失败,请重试!", + icon: "none" + }) + reject(error); + } + }) + }) +} + +export default { + ajax +} \ No newline at end of file