| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754 |
- <template>
- <view class="page">
- <view class="nav-bar" :style="{ paddingTop: statusBarHeight}">
- <view class="nav-back" @tap="goBack">
- <!-- <text class="back-text">‹ 返回</text> -->
- <image class="back-text" src="@/static/images/pages_watch/icons/back_arrow_icon24.png"></image>
- </view>
- <view class="nav-title">FitCloud智能手表</view>
- <image class="next-text" src="@/static/images/pages_watch/icons/more_icon24.png"></image>
- </view>
- <view class="content">
- <view class="section-header">我的设备</view>
- <view class="empty-container" v-if="!loading&&xhsDeviceList&&xhsDeviceList.length==0">
- <image class="empty-img" src="/static/images/empty.png" mode="aspectFit"></image>
- <view class="es-fs-28 es-c-99 es-mt-20">暂无设备</view>
- <button class="btn btn-primary es-mt-40" @click="goScan" style="width: 280rpx;">添加设备</button>
- </view>
- <view v-show="loading">
- <u-loading-icon text="加载中" textSize="16" :vertical="true"></u-loading-icon>
- </view>
- <view class="status-card" :class="{ connected: item.newXhsDeviceId == connectedDeviceMac }"
- v-for="(item,index) in xhsDeviceList" :key="index">
- <image class="deviceimg" src="/static/images/pages_watch/icons/smartwatch_img.png" mode="aspectFit">
- </image>
- <view class="x-f flex">
- <view class="flex">
- <view class="device-name">{{item.newXhsDeviceId}}</view>
- <view class="status-row">
- <!-- <text class="status-label ">连接状态</text> -->
- <text class="status-value"
- :class="item.newXhsDeviceId === connectedDeviceMac ? (connectionState || '').toLowerCase() : (item.connectedDeviceMac || '').toLowerCase()">
- {{ connectionText(item) }}
- </text>
- </view>
- </view>
- <button class="device-connect" :disabled="disconnecting" :loading="disconnecting" @tap="unbindDevice(item)">解绑</button>
- <button class="device-connect" @tap="connectDevice(item)">连接</button>
- </view>
- </view>
- <!-- connectionState === 'CONNECTED' -->
- <view class="panel" v-if="connectedDeviceMac" style="margin-top: 24rpx;">
- <view class="panel-title x-bc">
- <text>实时健康数据</text>
- <text style="color: #07c160;" v-show="dataSync=='success'">同步成功</text>
- <button class="device-item-btn" v-show="dataSync!='success'" :disabled="dataSync=== 'loading'"
- :loading="dataSync=== 'loading'" @click="xhsDataAdd(connectedDeviceMac,1)">
- {{ dataSync=== 'loading' ? '同步中' : dataSync === 'error'? '重新同步': '同步成功'}}
- </button>
- </view>
- <view class="health-monitoring">
- <view class="health-monitoring-item">
- <view class="health-monitoring-title">
- <view>
- <view class="health-monitoring-maintitle">心率</view>
- <view>心脏健康管理</view>
- </view>
- <image src="/static/images/pages_watch/icons/heart_rate_icon.png" mode="aspectFill"></image>
- </view>
- <view class="health-monitoring-res resnum">{{ healthData.heartRate}}</view>
- </view>
- <view class="health-monitoring-item">
- <view class="health-monitoring-title">
- <view>
- <view class="health-monitoring-maintitle">血氧</view>
- <view>血氧风险管控</view>
- </view>
- <image src="/static/images/pages_watch/icons/blood_oxygen_icon.png" mode="aspectFill">
- </image>
- </view>
- <view class="health-monitoring-res resnum">{{ healthData.oxygen}}</view>
- </view>
- <view class="health-monitoring-item">
- <view class="health-monitoring-title">
- <view>
- <view class="health-monitoring-maintitle">血压</view>
- <view>血压健康监测</view>
- </view>
- <image src="/static/images/pages_watch/icons/blood_pressure_icon.png" mode="aspectFill"></image>
- </view>
- <view class="health-monitoring-res resnum">
- {{ healthData.systolicPressure }}/{{ healthData.diastolicPressure }}</view>
- </view>
- </view>
- <template v-if="connectionState == 'CONNECTED'">
- <view class="btn-row">
- <button class="btn btn-primary" @click="startRealTimeData" :disabled="isMeasuring">开始测量</button>
- <button class="btn btn-danger" @click="stopRealTimeData" :disabled="!isMeasuring">停止测量</button>
- </view>
- <view class="btn-row">
- <button class="btn btn-default" @click="disconnect">断开连接</button>
- <!-- <button class="btn btn-danger-outline" @click="unbindDevice">解绑设备</button> -->
- </view>
- </template>
- </view>
- <!-- connectionState === 'CONNECTED' v-if="connectedDeviceMac"-->
- <view class="panel es-mt-20" v-if="connectedDeviceMac">
- <view class="panel-title x-bc">
- <text>其他数据</text>
- <text style="color: #07c160;" v-show="dataOtherSync=='success'&&!isSyncing">同步成功</text>
- <button class="device-item-btn" v-show="dataOtherSync!='success'" :disabled="dataOtherSync=== 'loading'"
- :loading="dataOtherSync=== 'loading'" @click="syncData()">
- {{ dataOtherSync=== 'loading' ? '同步中' : dataOtherSync === 'error'||dataOtherSync === 'errorSync'? '重新同步': '同步成功'}}
- </button>
- </view>
- <view class="history-section" v-if="sleepDataList && sleepDataList.length > 0">
- <view class="section-title">睡眠记录 (最新{{ sleepDataList.length }}条)</view>
- <scroll-view scroll-y class="history-list">
- <view class="history-item" v-for="(item, index) in sleepDataList" :key="index">
- <view class="history-header">
- <text class="date">{{ formatTime(item.timestamp) }}</text>
- <text class="count">{{ item.items ? item.items.length : 0 }}段</text>
- </view>
- <view class="history-detail" v-if="item.items && item.items.length > 0">
- <view class="detail-row" v-for="(detail, dIndex) in item.items" :key="dIndex">
- <text class="time">{{ formatTimeOnly(detail.startTime) }} - {{ formatTimeOnly(detail.endTime) }}</text>
- <text class="status" :class="'status-' + detail.status">
- {{ getSleepStatus(detail.status) }}
- </text>
- </view>
- </view>
- </view>
- </scroll-view>
- </view>
- <view class="empty-tip" v-else>暂无睡眠数据</view>
- <!-- 运动数据展示 -->
- <view class="history-section" v-if="sportDataList && sportDataList.length > 0">
- <view class="section-title">锻炼记录 (最新{{ sportDataList.length }}条)</view>
- <scroll-view scroll-y class="history-list">
- <view class="history-item" v-for="(item, index) in sportDataList" :key="index">
- <view class="history-header">
- <text class="date">{{ formatTime(item.timestamp) }}</text>
- <text class="count">类型: {{ item.sportType }}</text>
- </view>
- <view class="history-detail">
- <view class="detail-row">
- <text class="time">时长: {{ item.duration }}秒</text>
- <text class="status">消耗: {{ item.calories }}千卡</text>
- </view>
- <view class="detail-row">
- <text class="time">步数: {{ item.steps }}步</text>
- <text class="status">距离: {{ item.distance }}公里</text>
- </view>
- </view>
- </view>
- </scroll-view>
- </view>
- <view class="empty-tip" v-else>暂无锻炼记录</view>
- <!-- 计步数据展示 -->
- <view class="history-section" v-if="stepDataList && stepDataList.length > 0">
- <view class="section-title">计步记录 (最新{{ stepDataList.length }}条)</view>
- <scroll-view scroll-y class="history-list">
- <view class="history-item" v-for="(item, index) in stepDataList" :key="index">
- <view class="history-header">
- <text class="date">{{ formatTime(item.timestamp) }}</text>
- </view>
- <view class="history-detail">
- <view class="detail-row">
- <text class="time">步数: {{ item.steps }}步</text>
- <text class="status">消耗: {{ item.calories }}千卡</text>
- </view>
- <view class="detail-row">
- <text class="time">距离: {{ item.distance }}公里</text>
- </view>
- </view>
- </view>
- </scroll-view>
- </view>
- <view class="empty-tip" v-else>暂无计步记录</view>
- </view>
- <!-- v-if="!connectionState || connectionState == 'DISCONNECTED'" -->
- <template v-if="false">
- <!-- <view class="section-header">设备扫描</view> -->
- <button class="es-w-200 es-h-88" v-show="!isFamily"
- @click="editXHSDevice('EF:00:11:11:8F:05')">绑定</button>
- <button class="es-w-200 es-h-88" v-show="isFamily"
- @click="editMyfamily('EF:00:11:11:8F:05')">家人绑定</button>
- <button class="es-w-200 es-h-88" @click="xhsDataAddTest('EF:00:11:11:8F:05')">记录</button>
- <!-- <view class="btn-row">
- <button class="btn btn-primary" @click="startScan" :loading="isScanning">扫描设备</button>
- <button class="btn btn-default" @click="stopScan" :disabled="!isScanning">停止扫描</button>
- </view> -->
- <view class="panel" v-if="deviceList&&deviceList.length>0">
- <view class="list-title">发现的设备({{ deviceList.length }})</view>
- <view class="device-list">
- <scroll-view scroll-y="true" class="scroll-y">
- <view class="device-item" v-for="(item, index) in deviceList" :key="index">
- <view class="device-info">
- <text class="device-name">{{ item.name || '未知设备' }}</text>
- <view>
- <text class="device-mac">{{ item.mac }}</text>
- </view>
- </view>
-
- <!-- 带连接状态的按钮 -->
- <view
- @click="connectDevice(item)"
- class="device-connectbox"
- :style="{opacity: item.mac === connectedDeviceMac && connectionState === 'CONNECTING' ? 0.6 : 1}"
- >
- <!-- 状态判断 -->
- <text
- class="device-connect"
- :class="{
- connected: item.mac === connectedDeviceMac && connectionState === 'CONNECTED',
- connecting: item.mac === connectedDeviceMac && connectionState === 'CONNECTING'
- }"
- >
- {{
- item.mac === connectedDeviceMac
- ? (connectionState === 'CONNECTED' ? '已连接' : connectionState === 'CONNECTING' ? '连接中...' : '连接')
- : '连接'
- }}
- </text>
- </view>
- </view>
- </scroll-view>
- <view class="empty-tip" v-if="deviceList.length === 0">暂无设备</view>
- </view>
- </view>
- </template>
- </view>
- </view>
- </template>
- <script>
- import {
- getWatchUserInfo,
- editMyfamily
- } from "@/api/pages_watch/user.js";
- import {
- editXHSDevice,
- xhsDataAddList,
- removeXHSDevice,
- getLastData
- } from "@/api/pages_watch/device.js"
- // 引入原生插件
- const fitCloudWatch = uni.requireNativePlugin('fitCloudWatch');
- export default {
- data() {
- return {
- disconnecting: false,
- isScanning: false,
- deviceList: [],
- connectionState: 'DISCONNECTED', // CONNECTED, DISCONNECTED, CONNECTING
- connectedDeviceMac: '',
- isMeasuring: false,
- isAutoConnecting: false, // 避免收到原生旧状态干扰的标识
- healthData: {
- heartRate: 0,
- oxygen: 0,
- diastolicPressure: 0,
- systolicPressure: 0,
- respiratoryRate: 0
- },
- isSyncing: false,
- sleepDataList: [],
- sportDataList: [],
- stepDataList: [],
- statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px',
- xhsDeviceList: [],
- loading: true,
- fitCloudWatchUser: {},
- deviceType: 2, //0腕表1小护士2新表
- isFamily: false,
- selectUser: 0,
- boundDevice: null,
- dataSync: 'success',
- dataSyncFunInfo: "",
- dataOtherSync: 'success',
- dataOtherSyncFunInfo: "",
- otherDevice: []
- }
- },
- computed: {
- connectionText() {
- const map = {
- 'CONNECTED': '已连接',
- 'DISCONNECTED': '未连接',
- 'CONNECTING': '连接中...'
- };
- return (item) => {
- return item.newXhsDeviceId == this.connectedDeviceMac ? map[item.connectionState] : map[this.connectionState];
- }
- }
- },
- watch: {
- connectionState(newVal) {
- this.updateXhsDeviceStatus();
- },
- connectedDeviceMac: {
- handler(newVal) {
- // if (newVal) {
- // getLastData(newVal)
- // }
- this.updateXhsDeviceStatus();
- },
- immediate: true
- },
- },
- onLoad(option) {
- this.selectUser = Number(option.selectUser || 0)
- this.isFamily = option.selectUser != '0';
- this.getUser()
- const sys = uni.getSystemInfoSync();
- },
- onShow() {
- // 页面显示时注册事件和检查状态,保证从后台切回或从其他页面返回时都能自动重连
- this.registerGlobalEvents();
- if(this.xhsDeviceList&&this.xhsDeviceList.length>0) {
- this.checkCurrentConnectionState();
- }
- // this.checkCurrentConnectionState();
- },
- onHide() {
- // 页面隐藏时清理事件,避免多实例问题
- this.removeGlobalEvents();
- },
- onUnload() {
- // 页面卸载时停止扫描和测量,防止内存泄漏
- if (this.isScanning) {
- this.stopScan();
- }
- if (this.isMeasuring) {
- this.stopRealTimeData();
- }
- this.removeGlobalEvents();
- },
- methods: {
- goScan() {
- uni.navigateTo({
- url: '/pages_bluetooth/scanFitWatch?selectUser='+this.selectUser
- })
- },
- // 检查当前连接状态
- checkCurrentConnectionState() {
- if (!fitCloudWatch) return;
-
- try {
- fitCloudWatch.getConnectionState({}, (res) => {
- console.log(type,'当前连接状态:', res);
- if (res.state === 'CONNECTED' && res.mac) {
- // 原生层已经连接,直接恢复 UI 状态
- // 校验:缓存设备是否在当前列表中
- const isDeviceValid = res.mac && this.xhsDeviceList.some(
- item => item.newXhsDeviceId == res.mac
- );
- if(isDeviceValid) {
- this.connectionState = 'CONNECTED';
- this.connectedDeviceMac = res.mac;
- // uni.showToast({ title: '已恢复连接状态', icon: 'none' });
- } else {
- // // 校验:缓存设备是否在当前列表中
- // this.disconnect()
- this.checkAutoConnect();
- }
- } else {
- // 原生层未连接,尝试自动连接已绑定的设备
- this.checkAutoConnect();
- }
- });
- } catch (e) {
- console.error('调用 getConnectionState 失败:', e);
- // 降级处理,直接尝试自动连接
- this.checkAutoConnect();
- }
- },
- updateXhsDeviceStatus() {
- this.xhsDeviceList.forEach((item, index) => {
- if (item.newXhsDeviceId === this.connectedDeviceMac) {
- this.$set(this.xhsDeviceList[index], 'connectionState', this.connectionState);
- } else {
- this.$set(this.xhsDeviceList[index], 'connectionState', '');
- }
- });
- },
- goBack() {
- uni.navigateBack({
- delta: 1
- });
- },
- // 注册插件的全局事件监听
- registerGlobalEvents() {
- // 先移除旧的监听,防止重复注册
- this.removeGlobalEvents();
-
- // 监听扫描到的设备
- plus.globalEvent.addEventListener('onFitCloudDeviceFound', this.onDeviceFound);
- // 监听连接状态变化
- plus.globalEvent.addEventListener('onFitCloudConnectionStateChanged', this.onConnectionStateChanged);
- // 监听连接错误
- plus.globalEvent.addEventListener('onFitCloudConnectionError', this.onConnectionError);
- // 监听实时健康数据
- plus.globalEvent.addEventListener('onFitCloudRealTimeData', this.onRealTimeData);
- // 监听实时测量错误
- plus.globalEvent.addEventListener('onFitCloudRealTimeDataError', this.onRealTimeDataError);
- // 监听睡眠数据同步
- plus.globalEvent.addEventListener('onFitCloudSleepData', this.onSleepData);
- // 监听运动数据同步
- plus.globalEvent.addEventListener('onFitCloudSportData', this.onSportData);
- // 监听计步数据同步
- plus.globalEvent.addEventListener('onFitCloudStepData', this.onStepData);
- },
- removeGlobalEvents() {
- plus.globalEvent.removeEventListener('onFitCloudDeviceFound', this.onDeviceFound);
- plus.globalEvent.removeEventListener('onFitCloudConnectionStateChanged', this.onConnectionStateChanged);
- plus.globalEvent.removeEventListener('onFitCloudConnectionError', this.onConnectionError);
- plus.globalEvent.removeEventListener('onFitCloudRealTimeData', this.onRealTimeData);
- plus.globalEvent.removeEventListener('onFitCloudRealTimeDataError', this.onRealTimeDataError);
- plus.globalEvent.removeEventListener('onFitCloudSleepData', this.onSleepData);
- plus.globalEvent.removeEventListener('onFitCloudSportData', this.onSportData);
- plus.globalEvent.removeEventListener('onFitCloudStepData', this.onStepData);
- },
- onDeviceFound(device) {
- console.log('扫描到设备:', JSON.stringify(device));
- // 原生层已经做好了 MAC 和 FLink 的强过滤,前端直接展示即可
- const index = this.deviceList.findIndex(item => item.mac === device.mac);
- if (index === -1) {
- this.deviceList.push(device);
- } else {
- // 更新信号强度
- this.$set(this.deviceList, index, device);
- }
- },
- onConnectionStateChanged(res) {
- console.log('状态改变:', res.state);
-
- if (res.state === 'DISCONNECTED') {
- if (this.isAutoConnecting) {
- // 自动连接中收到的断开状态很可能是原生的旧状态,忽略它
- console.log('忽略自动连接中的断开状态事件');
- return;
- }
- this.connectionState = res.state;
- uni.showToast({ title: '已断开连接', icon: 'none' });
- this.isMeasuring = false;
- } else if (res.state === 'CONNECTED') {
- this.connectionState = res.state;
- this.isAutoConnecting = false; // 连接成功,立即重置
- uni.showToast({ title: '连接成功', icon: 'success' });
- // 如果 res 里面带了 mac,更新一下
- if (res.mac) {
- this.connectedDeviceMac = res.mac;
- }
- // 连接成功后,缓存 MAC 地址以便下次自动连接
- if (this.connectedDeviceMac) {
- uni.setStorageSync('fitCloudWatch_mac', this.connectedDeviceMac);
- if (this.isFamily) {
- this.editMyfamily(this.connectedDeviceMac)
- } else {
- this.editXHSDevice(this.connectedDeviceMac)
- }
- }
- } else {
- this.connectionState = res.state;
- }
- },
- onConnectionError(res) {
- console.log('连接错误:', res);
- // 如果是 SDK 内部在重试,可以不弹窗打扰用户
- if (res.isRetry) {
- console.log('正在重试连接...');
- return;
- }
- // 只有当前不在已连接状态,或者不是重试时才提示
- if (this.connectionState !== 'CONNECTED') {
- uni.showToast({
- title: '连接异常: ' + (res.error || '未知错误'),
- icon: 'none',
- duration: 3000
- });
- this.connectionState = 'DISCONNECTED';
- this.isAutoConnecting = false;
- }
- },
- onRealTimeData(data) {
- this.healthData = {
- ...this.healthData,
- ...data
- };
- },
-
- onRealTimeDataError(error) {
- uni.showToast({ title: '测量异常: ' + error.error, icon: 'none' });
- this.isMeasuring = false;
- },
-
- onSleepData(res) {
- console.log('接收睡眠数据:', res);
- if (res.sleepData && res.sleepData.length > 0) {
- this.sleepDataList = res.sleepData;
- this.xhsOtherDataAdd(this.connectedDeviceMac)
- }
- },
-
- onSportData(res) {
- console.log('接收到运动(锻炼)数据:', res);
- if (res.sportData && res.sportData.length > 0) {
- this.sportDataList = res.sportData;
- this.xhsOtherDataAdd(this.connectedDeviceMac)
- }
- },
-
- onStepData(res) {
- console.log('接收到计步数据:', res);
- if (res.stepData && res.stepData.length > 0) {
- this.stepDataList = res.stepData;
- this.xhsOtherDataAdd(this.connectedDeviceMac)
- }
- },
- // 自动连接
- checkAutoConnect() {
- if (!fitCloudWatch) return;
- const savedMac = uni.getStorageSync('fitCloudWatch_mac');
- if (savedMac) {
- this.connectionState = 'CONNECTING';
- this.connectedDeviceMac = savedMac;
- // 标记正在自动连接中,避免被原生的初始状态事件(DISCONNECTED)干扰
- this.isAutoConnecting = true;
- uni.showLoading({ title: '自动连接中...' });
- const userId = this.fitCloudWatchUser.userId + '_' + savedMac
- fitCloudWatch.connect({
- mac: savedMac,
- userId: userId, // 测试用户ID
- isBind: true, // 测试绑定模式
- sex: this.fitCloudWatchUser.sex || true, // 男
- age: this.fitCloudWatchUser.age || 25,
- height: this.fitCloudWatchUser.height || 175,
- weight: this.fitCloudWatchUser.weight || 70
- }, (res) => {
- uni.hideLoading();
- if (res.code !== 0) {
- this.connectionState = 'DISCONNECTED';
- this.isAutoConnecting = false;
- uni.showToast({ title: '自动连接指令发送失败', icon: 'none' });
- } else {
- // 连接指令发送成功,重置标记,让状态监听正常接管
- setTimeout(() => {
- this.isAutoConnecting = false;
- }, 1500); // 延迟 1.5 秒重置,跳过旧状态的干扰
- }
- });
- }
- },
- // 1. 开始扫描
- async startScan() {
- if (!fitCloudWatch) {
- uni.showToast({ title: '原生插件未加载,请在自定义基座或原生App中运行', icon: 'none' });
- return;
- }
-
- // Android 平台必须动态申请定位和蓝牙权限
- if (plus.os.name === 'Android') {
- const permissions = [
- 'android.permission.ACCESS_FINE_LOCATION',
- 'android.permission.ACCESS_COARSE_LOCATION'
- ];
-
- // 适配 Android 12+ 蓝牙权限
- if (parseInt(plus.os.version) >= 12) {
- permissions.push('android.permission.BLUETOOTH_SCAN');
- permissions.push('android.permission.BLUETOOTH_CONNECT');
- }
-
- for (let i = 0; i < permissions.length; i++) {
- const result = await new Promise(resolve => {
- plus.android.requestPermissions([permissions[i]], (res) => {
- resolve(res.granted.length > 0);
- }, (e) => {
- resolve(false);
- });
- });
- if (!result) {
- uni.showToast({ title: '需要定位和蓝牙权限才能扫描设备', icon: 'none' });
- return;
- }
- }
-
- // 检查蓝牙是否开启
- const main = plus.android.runtimeMainActivity();
- const BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");
- const BAdapter = BluetoothAdapter.getDefaultAdapter();
- if(!BAdapter.isEnabled()){
- uni.showModal({
- title: '提示',
- content: '请先打开蓝牙',
- showCancel: false
- });
- return;
- }
- }
-
- this.deviceList = [];
- this.isScanning = true;
-
- // 将保存的 MAC 传给原生,让原生直接过滤
- const savedMac = uni.getStorageSync('fitCloudWatch_mac');
- fitCloudWatch.startScan({ mac: savedMac || '' }, (res) => {
- if (res.code !== 0) {
- this.isScanning = false;
- uni.showToast({ title: '启动扫描失败: ' + res.message, icon: 'none' });
- }
- });
- },
-
- // 2. 停止扫描
- stopScan() {
- if (!fitCloudWatch) return;
- fitCloudWatch.stopScan({}, (res) => {
- this.isScanning = false;
- });
- },
- // 3. 连接设备
- connectDevice(device) {
- // 连接状态检测
- if (this.connectionState === 'CONNECTED') {
- if (this.connectedDeviceMac === device.mac) {
- uni.showToast({ title: '该设备已连接,无需重复连接', icon: 'none' });
- return;
- } else {
- uni.showToast({ title: '请先断开当前设备后再连接新设备', icon: 'none' });
- return;
- }
- }
- if (this.isScanning) {
- this.stopScan();
- }
- this.connectionState = 'CONNECTING';
- this.connectedDeviceMac = device.mac;
-
- // 判断 xhsDeviceList 中是否已存在当前设备
- const existIndex = this.xhsDeviceList.findIndex(item => item.newXhsDeviceId === device.mac);
- if (existIndex !== -1) {
- // 已存在 → 更新连接状态
- this.$set(this.xhsDeviceList[existIndex], 'connectionState', 'CONNECTING');
- } else {
- // // 不存在 → 添加新设备
- // this.xhsDeviceList.push({
- // newXhsDeviceId: device.mac,
- // connectionState: ''
- // });
- }
- uni.showLoading({
- title: '连接中...'
- });
- const userId = this.fitCloudWatchUser.userId + '_' + device.mac
- fitCloudWatch.connect({
- mac: device.mac,
- userId: userId, // 测试用户ID
- isBind: true, // 测试绑定模式
- sex: this.fitCloudWatchUser.sex || true, // 男
- age: this.fitCloudWatchUser.age || 25,
- height: this.fitCloudWatchUser.height || 175,
- weight: this.fitCloudWatchUser.weight || 70
- }, (res) => {
- uni.hideLoading();
- if (res.code !== 0) {
- this.connectionState = 'DISCONNECTED';
- uni.showToast({
- title: '连接指令发送失败,请检查蓝牙和定位是否打开',
- icon: 'none'
- });
- } else {
- // setTimeout(()=>{
- // const fitWatchDevice = uni.getStorageSync('fitCloudWatch_mac');
- // if(fitWatchDevice == this.connectedDeviceMac) {
- // this.connectionState = 'CONNECTED';
- // }
- // },1000)
- }
- });
- },
- // 4. 断开连接
- disconnect() {
- fitCloudWatch.disconnect({}, (res) => {
- console.log('断开指令发送', res);
- });
- },
- editXHSDevice(selectedDeviceId) {
- if (!selectedDeviceId || this.xhsDeviceList.some(item => item.newXhsDeviceId == selectedDeviceId)) return;
- const newXhsDeviceId = this.xhsDeviceList.map(item => item.newXhsDeviceId);
- newXhsDeviceId.push(selectedDeviceId);
- console.log("newXhsDeviceId==", newXhsDeviceId)
- const param = {
- newXhsDeviceId: newXhsDeviceId.join(','), // 设备唯一MAC
- deviceType: this.deviceType
- }
- uni.showLoading({ title: '绑定中'});
- editXHSDevice(param).then(res => {
- uni.hideLoading();
- if (res.code == 200) {
- this.xhsDeviceList.push({
- newXhsDeviceId: selectedDeviceId,
- connectionState: this.connectionState
- })
- this.boundDevice = selectedDeviceId
- this.deviceList = this.deviceList.filter(it=>it.mac!=selectedDeviceId)
- uni.showToast({ title: '绑定成功'});
- if (this.isScanning) {
- this.stopScan();
- }
- uni.setStorageSync('fitCloudWatch_mac', this.boundDevice);
- } else {
- uni.showToast({
- title: res.msg,
- icon: 'none'
- })
- }
- })
- },
- editMyfamily(selectedDeviceId) {
- if (!selectedDeviceId || this.xhsDeviceList.some(item => item.newXhsDeviceId == selectedDeviceId)) return;
- let newXhsDeviceId = this.xhsDeviceList.map(item => item.newXhsDeviceId);
- newXhsDeviceId.push(selectedDeviceId);
- this.otherDevice[this.selectUser - 1].newXhsDeviceId = newXhsDeviceId.join(',')
- uni.showLoading({ title: '绑定中'});
- editMyfamily({
- otherDevice: JSON.stringify(this.otherDevice)
- }).then(async res => {
- uni.hideLoading();
- if (res.code == 200) {
- this.xhsDeviceList.push({
- newXhsDeviceId: selectedDeviceId,
- connectionState: this.connectionState
- })
- this.boundDevice = selectedDeviceId
- this.deviceList = this.deviceList.filter(it=>it.mac!=selectedDeviceId)
- uni.showToast({ title: '绑定成功'});
- if (this.isScanning) {
- this.stopScan();
- }
- uni.setStorageSync('fitCloudWatch_mac', this.boundDevice);
- } else {
- uni.showToast({
- title: res.msg,
- icon: 'none'
- })
- // if (this.connected) {
- // await this.disconnect();
- // }
- // uni.removeStorageSync('fitCloudWatch_mac');
- }
- })
- },
- getUser() {
- this.loading = true
- getWatchUserInfo({
- isFamily: false
- }).then(res => {
- if (res.code == 200) {
- this.fitCloudWatchUser = res.user
- uni.setStorageSync("userWatchInfo", JSON.stringify(res.user))
- if (this.isFamily) {
- // 安全解析家庭成员设备
- this.otherDevice = this.fitCloudWatchUser.otherDevice ? JSON.parse(this.fitCloudWatchUser.otherDevice) : [];
- console.log("otherDevice===",this.otherDevice)
- // 格式化设备ID为对象数组
- const formattedDevices = this.otherDevice.map(item => ({
- ...item,
- newXhsDeviceId: item.newXhsDeviceId ?
- item.newXhsDeviceId.split(',').map(id => ({
- newXhsDeviceId: id,
- connectionState: ''
- })) : []
- }));
- // 安全取当前选中成员的设备(防越界)
- const index = this.selectUser - 1;
- this.loading = false
- this.xhsDeviceList = formattedDevices[index]?.newXhsDeviceId || [];
- console.log("newXhsDeviceId===",this.xhsDeviceList)
- } else {
- // 个人设备格式化
- const deviceIds = this.fitCloudWatchUser.newXhsDeviceId ? this.fitCloudWatchUser.newXhsDeviceId.split(',') : [];
- this.loading = false
- this.xhsDeviceList = deviceIds.map(id => ({
- newXhsDeviceId: id,
- connectionState: ''
- }));
- }
- this.checkConnectedDeviceMac()
- } else {
- this.loading = false
- uni.showToast({
- title:res.msg,
- icon: 'none'
- })
- }
- }).catch(()=>{
- this.loading = false
- uni.showToast({
- title: "请求接口失败",
- icon: 'none'
- })
- })
- },
- checkConnectedDeviceMac() {
- // 2. 设备绑定 & 自动连接逻辑(统一处理,无重复代码)
- if (!this.xhsDeviceList || this.xhsDeviceList.length === 0) {
- // 无设备:清空绑定缓存
- uni.removeStorageSync('fitCloudWatch_mac');
- this.boundDevice = null;
- } else {
- // 有设备:安全获取绑定设备
- let boundDevice = uni.getStorageSync('fitCloudWatch_mac');
-
- try {
-
- // 校验:缓存设备是否在当前列表中
- const isDeviceValid = boundDevice && this.xhsDeviceList.some(
- item => item.newXhsDeviceId == boundDevice
- );
-
- // 确定最终绑定设备
- this.boundDevice = isDeviceValid ? boundDevice : this.xhsDeviceList[0]
- .newXhsDeviceId;
-
- // 持久化保存
- uni.setStorageSync('fitCloudWatch_mac', this.boundDevice);
-
- // 赋值选中设备信息
- // this.selectedDeviceId = this.boundDevice.deviceId;
- // this.selectedDeviceName = this.boundDevice.name;
- // this.deviceId = this.selectedDeviceId;
-
- // 自动连接 & 获取数据
- this.connectedDeviceMac = this.boundDevice
- this.checkCurrentConnectionState()
-
- } catch (e) {
- this.connectedDeviceMac = this.boundDevice
- // 异常兜底:绑定第一个设备
- this.boundDevice = this.xhsDeviceList[0].newXhsDeviceId;
- uni.setStorageSync('fitCloudWatch_mac', this.boundDevice);
- // 赋值选中设备信息
- // this.selectedDeviceId = this.boundDevice.deviceId;
- // this.selectedDeviceName = this.boundDevice.name;
- // this.deviceId = this.selectedDeviceId;
- // 自动连接 & 获取数据
- this.checkCurrentConnectionState()
- console.error('设备绑定异常:', e);
- }
- }
- },
- // 解绑设备
- unbindDevice(item) {
- uni.showModal({
- title: '解绑确认',
- content: '确定要解绑当前手表吗?',
- success: (res) => {
- if (res.confirm) {
- // 处理缓存设备,解绑的当前连接设备需要从列表连接一个新设备
- let boundDevice = uni.getStorageSync('fitCloudWatch_mac');
- if (boundDevice && boundDevice === deviceId) {
- uni.removeStorageSync('fitCloudWatch_mac');
- }
- // 统一删除设备方法
- const removeDevice = () => {
- this.isFamily
- ? this.removeXHSDevicefamily(item.newXhsDeviceId)
- : this.removeXHSDevice(item.newXhsDeviceId);
- };
-
- // 判断是否是当前连接设备
- if (item.newXhsDeviceId === this.connectedDeviceMac) {
- try {
- fitCloudWatch.unbind({}, (unbindRes) => {
- // 无论解绑成功/失败,都执行删除
- if (unbindRes.code === 0) {
- this.disconnect();
- }
- removeDevice();
- });
- } catch (error) {
- // 出错了也强制删除设备
- removeDevice();
- console.error('解绑异常:', error);
- }
- } else {
- removeDevice();
- }
- }
- }
- });
- },
- // 5. 开始测量实时数据
- startRealTimeData() {
- this.isMeasuring = true;
- // 重置数据展示
- this.healthData = {
- heartRate: 0,
- oxygen: 0,
- diastolicPressure: 0,
- systolicPressure: 0,
- respiratoryRate: 0
- };
- fitCloudWatch.startRealTimeData({
- heartRate: true,
- oxygen: true,
- bloodPressure: true,
- respiratoryRate: true
- }, (res) => {
- if (res.code !== 0) {
- this.isMeasuring = false;
- uni.showToast({
- title: '开启测量失败',
- icon: 'none'
- });
- }
- });
- },
- // 6. 停止测量实时数据
- stopRealTimeData() {
- this.xhsDataAdd(this.connectedDeviceMac)
- fitCloudWatch.stopRealTimeData({}, (res) => {
- this.isMeasuring = false;
- });
- },
- xhsDataAdd(deviceId, type) {
- // 无设备ID直接返回
- if (!deviceId) return;
- // 条件一致时不重新构造数据
- if (type === 1 && this.dataSyncFunInfo?.[0]?.deviceId === deviceId) {
- // 不处理,直接走接口
- } else {
- // 解构防止 healthData 不存在报错
- const { systolicPressure, diastolicPressure, heartRate, oxygen } = this.healthData || {};
- // 构造参数(0:血压 1:血糖 2:心率 3尿酸 4血氧 5步数 6运动)
- this.dataSyncFunInfo = [{
- recordType: 0, // 血压
- recordValue: JSON.stringify({
- sdb: systolicPressure,
- dbp: diastolicPressure
- }),
- deviceId: deviceId,
- deviceType: this.deviceType
- }, {
- recordType: 2, // 心率
- recordValue: heartRate,
- deviceId: deviceId,
- deviceType: this.deviceType
- }, {
- recordType: 4, // 血氧
- recordValue: oxygen,
- deviceId: deviceId,
- deviceType: this.deviceType
- }];
- }
- this.dataSync = 'loading'
- xhsDataAddList(this.dataSyncFunInfo).then(res => {
- if (res.code == 200) {
- this.dataSync = 'success'
- this.dataSyncFunInfo = []
- } else {
- this.dataSync = 'error'
- uni.showToast({
- title: '数据同步失败' + JSON.stringify(res.msg),
- icon: 'none'
- })
- }
- }).catch(() => {
- this.dataSync = 'error'
- uni.showToast({
- title: '数据同步失败',
- icon: 'none'
- })
- })
- },
- // 同步睡眠、步数,运动
- xhsOtherDataAdd(deviceId, type) {
- // 无设备ID直接返回
- if (!deviceId) return;
-
- // 条件一致时不重新构造数据
- if (type === 1 && this.dataOtherSyncFunInfo?.[0]?.deviceId === deviceId) {
- // 不处理,直接走接口
- } else {
- // 构造参数(0:血压 1:血糖 2:心率 3尿酸 4血氧 5步数 6运动 7睡眠)
- this.dataOtherSyncFunInfo = [{
- recordType: 5, // 步数
- recordValue: JSON.stringify(this.stepDataList),
- deviceId: deviceId,
- deviceType: this.deviceType
- }, {
- recordType: 6, // 运动
- recordValue: JSON.stringify(this.sportDataList),
- deviceId: deviceId,
- deviceType: this.deviceType
- }, {
- recordType: 7, // 睡眠
- recordValue: JSON.stringify(this.sleepDataList),
- deviceId: deviceId,
- deviceType: this.deviceType
- }];
- }
- this.dataOtherSync = 'loading'
- xhsDataAddList(this.dataOtherSyncFunInfo).then(res => {
- if (res.code == 200) {
- this.dataOtherSync = 'success'
- this.dataOtherSyncFunInfo = []
- } else {
- this.dataOtherSync = 'error'
- uni.showToast({
- title: '数据同步失败' + JSON.stringify(res.msg),
- icon: 'none'
- })
- }
- }).catch(() => {
- this.dataOtherSync = 'error'
- uni.showToast({
- title: '数据同步失败',
- icon: 'none'
- })
- })
- },
- // 7. 同步历史数据 (包含睡眠、运动、计步等)
- syncData() {
- if(this.dataOtherSync == 'error'){
- this.xhsOtherDataAdd(this.connectedDeviceMac, 1)
- return
- }
- console.log("同步历史数据this.isSyncing",this.isSyncing)
- if (this.isSyncing) return;
-
- this.isSyncing = true;
- // 清理旧数据
- this.sleepDataList = [];
- this.sportDataList = [];
- this.stepDataList = [];
- uni.showLoading({ title: '同步中...' });
- this.dataOtherSync = 'loading'
- try {
- fitCloudWatch.syncData({}, (res) => {
- this.isSyncing = false;
- uni.hideLoading();
- if (res.code === 0) {
- uni.showToast({ title: '同步指令已发送', icon: 'success' });
- } else {
- this.dataOtherSync = 'errorSync'
- uni.showToast({ title: '同步失败: ' + (res.message || '未知错误'), icon: 'none' });
- }
- });
- } catch (err) {
- console.error("同步失败:", err);
- this.isSyncing = false;
- this.dataOtherSync = 'errorSync';
- uni.hideLoading();
- uni.showToast({ title: "同步异常,请重试", icon: "none" });
- }
- },
- formatTime(timestamp) {
- if (!timestamp) return '--';
- const date = new Date(timestamp);
- const y = date.getFullYear();
- const m = (date.getMonth() + 1).toString().padStart(2, '0');
- const d = date.getDate().toString().padStart(2, '0');
- return `${y}-${m}-${d}`;
- },
- // 辅助方法:状态转换
- getSleepStatus(status) {
- const statusMap = {
- 1: '深睡',
- 2: '浅睡',
- 3: '清醒'
- };
- return statusMap[status] || '未知';
- },
- formatTimeOnly(timestamp) {
- if (!timestamp) return '';
- const date = new Date(timestamp);
- const h = String(date.getHours()).padStart(2, '0');
- const m = String(date.getMinutes()).padStart(2, '0');
- return `${h}:${m}`;
- },
- xhsDataAddTest(deviceId) {
- this.healthData = {
- heartRate: 80,
- oxygen: 99,
- diastolicPressure: 114,
- systolicPressure: 80,
- respiratoryRate: 0
- }
- const recordValue = {
- sdb: this.healthData.systolicPressure,
- dbp: this.healthData.diastolicPressure,
- }
- let param = [{
- recordType: 0, // 0:血压 1:血糖 2:心率 3尿酸 4血氧
- recordValue: JSON.stringify(recordValue),
- deviceId: deviceId,
- deviceType: this.deviceType
- }, {
- recordType: 2, // 0:血压 1:血糖 2:心率 3尿酸 4血氧
- recordValue: this.healthData.heartRate,
- deviceId: deviceId,
- deviceType: this.deviceType
- }, {
- recordType: 4, // 0:血压 1:血糖 2:心率 3尿酸 4血氧
- recordValue: this.healthData.oxygen,
- deviceId: deviceId,
- deviceType: this.deviceType
- }]
- this.dataSync = 'loading'
- this.dataSyncFunInfo = param
- uni.showLoading({
- title: '数据同步中'
- })
- xhsDataAddList(this.dataSyncFunInfo).then(res => {
- uni.hideLoading()
- if (res.code == 200) {
- this.dataSync = 'success'
- this.dataSyncFunInfo = []
- } else {
- this.dataSync = 'error'
- uni.showToast({
- title: '数据同步失败' + JSON.stringify(res.msg),
- icon: 'none'
- })
- }
- }).catch(() => {
- uni.hideLoading()
- this.dataSync = 'error'
- uni.showToast({
- title: '数据同步失败',
- icon: 'none'
- })
- })
- },
- // 小护士解除绑定设备(自己)
- removeXHSDevice(newXhsDeviceId) {
- uni.showLoading({
- title: '解绑中'
- })
- removeXHSDevice({
- newXhsDeviceId: newXhsDeviceId,
- deviceType: this.deviceType
- }).then(async res => {
- uni.hideLoading()
- if (res.code == 200) {
- // this.disconnect();
- this.connectionState = ''
- this.connectedDeviceMac = ''
- this.xhsDeviceList = this.xhsDeviceList.filter(item => item.newXhsDeviceId !=
- newXhsDeviceId)
- uni.showToast({
- title: '解绑成功',
- icon: 'success'
- });
- } else {
- uni.showToast({
- title: res.msg,
- icon: 'none'
- })
- }
- }).catch(err => {
- uni.hideLoading()
- uni.showToast({
- title: '设备解绑失败',
- icon: 'none'
- })
- })
- },
- removeXHSDevicefamily(deviceId) {
- let newXhsDeviceId = this.xhsDeviceList.map(item => item.newXhsDeviceId);
- newXhsDeviceId = newXhsDeviceId.filter(item => item != deviceId);
- this.otherDevice[this.selectUser - 1].newXhsDeviceId = newXhsDeviceId.join(',')
- console.log("==this.otherDevice=", this.otherDevice)
- uni.showLoading({
- title: '解绑中'
- })
- editMyfamily({
- otherDevice: JSON.stringify(this.otherDevice)
- }).then(async res => {
- uni.hideLoading()
- if (res.code == 200) {
- this.xhsDeviceList = this.xhsDeviceList.filter(item => item.newXhsDeviceId != deviceId)
- this.connectionState = ''
- this.connectedDeviceMac = ''
- uni.showToast({
- title: '解绑成功',
- icon: 'success'
- });
- } else {
- uni.showToast({
- title: res.msg,
- icon: 'none'
- })
- // if (this.connected) {
- // await this.disconnect();
- // }
- uni.removeStorageSync('fitCloudWatch_mac');
- }
- }).catch(async err => {
- uni.hideLoading()
- uni.showToast({
- title: '设备解绑失败',
- icon: 'none'
- })
- });
- },
- // 获取接口数据
- getLastData(selectedDeviceId) {
- const param = {
- deviceId: selectedDeviceId,
- deviceType: this.deviceType
- }
- getLastData(param).then(res => {
- if (res.code == 200) {
- // // 0:血压 1:血糖 2:心率 3尿酸 4血氧
- // // 状态标记
- // this.dataSync = 'success';
- // 安全获取数据列表
- const {
- data = []
- } = res;
- // 一次性提取所有需要的数据(只遍历一次数组,性能更好)
- const bloodPressure = data.find(item => item.recordType === 0);
- const pulse = data.find(item => item.recordType === 2);
- const oxygen = data.find(item => item.recordType === 4);
- const glucose = data.find(item => item.recordType === 1);
- const uricAcid = data.find(item => item.recordType === 3);
- // 血压数据解析(安全处理)
- let bpData = {};
- try {
- bpData = bloodPressure?.recordValue ? JSON.parse(bloodPressure.recordValue) : {};
- } catch (e) {
- bpData = {};
- }
- // 统一赋值(带默认值,防止 undefined 报错)
- this.cardGlucose = {
- value: glucose?.recordValue || '',
- unit: 'mmol/L',
- time: glucose?.createTime || ''
- };
- this.healthData = {
- heartRate: pulse?.recordValue,
- oxygen: oxygen?.recordValue,
- diastolicPressure: bpData.dbp,
- systolicPressure: bpData.sdb,
- respiratoryRate: null
- }
- } else {
- uni.showToast({
- title: res.msg,
- icon: 'none'
- })
- }
- })
- },
- }
- }
- </script>
- <style lang="scss" scoped>
- .page {
- min-height: 100vh;
- background: #ffffff;
- }
- .empty-container {
- display: flex;
- flex-direction: column;
- align-items: center;
- .empty-img {
- width: 200rpx;
- height: 200rpx;
- }
- .es-c-99 {
- color: #999999;
- font-size: 28rpx;
- margin-top: 20rpx;
- }
- }
- .deviceimg {
- width: 120rpx;
- height: 120rpx;
- margin-right: 24rpx;
- }
- .nav-bar {
- position: sticky;
- top: 0;
- z-index: 10;
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin: 0 24rpx;
- background: #fff;
- }
- .back-text {
- width: 64rpx;
- height: 64rpx;
- }
- .next-text {
- width: 48rpx;
- height: 48rpx;
- }
- .nav-back,
- .nav-placeholder {
- width: 84rpx;
- height: 64rpx;
- display: flex;
- align-items: center;
- }
- .nav-back {
- justify-content: flex-start;
- }
- .nav-placeholder {
- justify-content: flex-end;
- }
- .back-text {
- font-size: 30rpx;
- color: #ff5c03;
- }
- .nav-title {
- font-size: 34rpx;
- font-weight: 600;
- color: #333;
- }
- .content {
- padding: 32rpx 24rpx 48rpx;
- }
- .section-header {
- font-size: 32rpx;
- font-weight: 700;
- color: #333;
- margin-bottom: 24rpx;
- padding-left: 8rpx;
- }
- .status-card {
- background: #fff;
- border-radius: 24rpx;
- padding: 32rpx;
- border: 2rpx solid #f0f0f0;
- margin-bottom: 24rpx;
- display: flex;
- align-items: center;
- }
- .status-info {
- flex: 1;
- }
- .device-name {
- font-size: 30rpx;
- font-weight: 600;
- color: #222;
- margin-bottom: 16rpx;
- }
- .status-card.connected {
- background: #fffaf7;
- border-color: rgba(255, 92, 3, 0.15);
- box-shadow: 0 4rpx 12rpx rgba(255, 92, 3, 0.05);
- }
- .status-row {
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .status-row:not(:last-child) {
- margin-bottom: 12rpx;
- }
- .status-label {
- font-size: 26rpx;
- color: #999;
- }
- .status-value {
- font-size: 28rpx;
- font-weight: 600;
- color: #333;
- }
- .status-value.connected {
- color: #07c160;
- }
- .status-value.disconnected {
- color: #999;
- }
- .status-value.connecting {
- color: #ff9501;
- }
- .status-value.mac {
- font-family: monospace;
- font-weight: normal;
- color: #666;
- font-size: 24rpx;
- }
- .success {
- color: #07c160;
- }
- .error {
- color: #e64340;
- }
- .panel {
- background: #fff;
- border-radius: 24rpx;
- padding: 24rpx;
- margin-bottom: 24rpx;
- border: 2rpx solid #f5f5f5;
- }
- .panel-head {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 20rpx;
- }
- .panel-title {
- font-size: 30rpx;
- font-weight: 600;
- color: #333;
- margin-bottom: 20rpx;
- }
- .panel-head .panel-title {
- margin-bottom: 0;
- }
- .health-monitoring {
- display: flex;
- align-items: center;
- justify-content: flex-start;
- flex-wrap: wrap;
- margin-right: -16rpx;
- &-item {
- width: calc(50% - 16rpx);
- min-height: 264rpx;
- margin: 0 16rpx 16rpx 0;
- overflow: hidden;
- background: #F5f7fa;
- border-radius: 16rpx 16rpx 16rpx 16rpx;
- padding: 24rpx 34rpx 24rpx 24rpx;
- box-sizing: border-box;
- }
- &-maintitle {
- margin-bottom: 4rpx;
- font-weight: 500;
- font-size: 30rpx;
- color: #333333;
- }
- &-title {
- display: flex;
- align-items: center;
- justify-content: space-between;
- font-weight: 400;
- font-size: 24rpx;
- color: #999999;
- image {
- width: 72rpx;
- height: 72rpx;
- flex-shrink: 0;
- }
- }
- .resnum {
- font-family: DIN, DIN;
- font-weight: 500;
- font-size: 64rpx;
- }
- &-res {
- height: 78rpx;
- margin: 20rpx 0 6rpx;
- font-family: PingFang SC, PingFang SC;
- font-weight: 600;
- font-size: 48rpx;
- color: #333333;
- }
- &-time {
- font-weight: 400;
- font-size: 22rpx;
- color: #999999;
- }
- }
- .unit {
- font-size: 22rpx;
- color: #999;
- font-weight: 500;
- }
- .btn-row {
- display: flex;
- gap: 16rpx;
- margin-bottom: 16rpx;
- }
- .btn-row:last-child {
- margin-bottom: 0;
- }
- .btn {
- flex: 1;
- height: 84rpx;
- line-height: 84rpx;
- border-radius: 42rpx;
- font-size: 28rpx;
- border: none;
- }
- .btn-primary {
- background: linear-gradient(90deg, #f8551f 0%, #ff9501 100%);
- color: #fff;
- }
- .btn-default {
- background: #f5f7fa;
- color: #67686f;
- }
- .btn-danger {
- background: #e64340;
- color: #fff;
- }
- .btn-danger-outline {
- background: #fff;
- color: #e64340;
- border: 2rpx solid #e64340;
- }
- .btn-mini-primary {
- width: 160rpx;
- height: 64rpx;
- line-height: 64rpx;
- padding: 0 20rpx;
- border-radius: 32rpx;
- font-size: 24rpx;
- background: #ff7700;
- color: #fff;
- }
- .device-list {
- margin-top: 8rpx;
- background: #f5f7fa;
- border-radius: 16rpx;
- padding: 16rpx;
- }
- .list-title {
- font-size: 24rpx;
- color: #666;
- margin-bottom: 16rpx;
- }
- .scroll-y {
- max-height: 520rpx;
- }
- .device-item {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 18rpx 8rpx;
- border-bottom: 1rpx solid #ebedf0;
- }
- .device-item:last-child {
- border-bottom: none;
- }
- .device-info {
- display: flex;
- flex-direction: column;
- }
- .device-mac {
- margin-top: 6rpx;
- font-size: 22rpx;
- color: #999;
- }
- .device-rssi {
- font-size: 24rpx;
- color: #ff7700;
- }
- .device-connectbox {
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- .device-connect {
- font-family: PingFang SC, PingFang SC;
- font-weight: 500;
- font-size: 26rpx;
- color: #fff;
- padding: 16rpx 32rpx;
- background: #FF7700;
- border-radius: 26rpx 26rpx 26rpx 26rpx;
- // 已连接
- &.connected {
- background: #07c160;
- }
- // 连接中
- &.connecting {
- background: #ff9501;
- }
- }
- .empty-tip {
- text-align: center;
- font-size: 24rpx;
- color: #999;
- padding: 28rpx 0 18rpx;
- }
- .sleep-list {
- margin-top: 8rpx;
- }
- .sleep-item {
- background: #f5f7fa;
- border-radius: 14rpx;
- padding: 18rpx 16rpx;
- margin-bottom: 12rpx;
- }
- .sleep-date {
- display: block;
- font-size: 24rpx;
- color: #333;
- }
- .sleep-detail {
- display: block;
- margin-top: 8rpx;
- font-size: 22rpx;
- color: #999;
- }
- .device-item-btn {
- background: #07c160;
- color: #fff;
- padding: 16rpx 24rpx;
- border-radius: 44rpx;
- font-size: 28rpx;
- margin: 0;
- min-width: 160rpx;
- }
- .history-section {
- margin-top: 30rpx;
- background: #fff;
- border-radius: 12rpx;
- padding: 16rpx;
- box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
- .section-title {
- font-size: 28rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 16rpx;
- border-left: 6rpx solid #007aff;
- padding-left: 12rpx;
- }
-
- .history-list {
- max-height: 360rpx;
- }
-
- .history-item {
- background: #f9f9f9;
- border-radius: 8rpx;
- padding: 16rpx;
- margin-bottom: 16rpx;
- }
-
- .history-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 12rpx;
- border-bottom: 2rpx dashed #eee;
- padding-bottom: 8rpx;
- }
-
- .history-header .date {
- font-size: 26rpx;
- color: #333;
- font-weight: bold;
- }
-
- .history-header .count {
- font-size: 24rpx;
- color: #007aff;
- background: rgba(0, 122, 255, 0.1);
- padding: 4rpx 12rpx;
- border-radius: 20rpx;
- }
-
- .history-detail {
- display: flex;
- flex-direction: column;
- gap: 8rpx;
- }
-
- .detail-row {
- display: flex;
- justify-content: space-between;
- font-size: 24rpx;
- color: #666;
- }
-
- .status-1 { color: #5B8FF9; } /* 深睡 */
- .status-2 { color: #5AD8A6; } /* 浅睡 */
- .status-3 { color: #F6BD16; } /* 清醒 */
- }
- </style>
|