diff --git a/api/device.js b/api/device.js new file mode 100644 index 0000000..3d053c3 --- /dev/null +++ b/api/device.js @@ -0,0 +1,97 @@ +import request from '@/api/http/client' + +// 后端就绪后置为 false 即可恢复真实请求。 +const USE_MOCK = true + +// 模拟设备列表数据(后端 /device/list 就绪后删除)。 +const MOCK_DEVICES = [ + { id: 1, name: '客厅体征监测仪', model: 'ED713', online: true }, + { id: 2, name: '卧室体征监测仪', model: 'ED713', online: false }, + { id: 3, name: '书房跌倒检测雷达', model: 'ED719', online: true }, + { id: 4, name: '走廊跌倒检测雷达', model: 'ED719', online: false } +] + +/** + * 获取指定场所下的设备列表。 + * 约定:data 为数组,每项至少含 { id, name, model, online },model 取值 ED713 | ED719。 + * @param {*} sceneId 场景 id,全部/未选择时可传 null + */ +export function getDeviceList(sceneId) { + if (USE_MOCK) { + // 模拟网络延迟,让 loading 态可见。 + return new Promise((resolve) => setTimeout(() => resolve(MOCK_DEVICES), 500)) + } + return request.get('/device/list', { sceneId }) +} + +// 模拟 ED713 实时体征数据(后端 /device/vitals 就绪后删除)。 +// 字段与 web 端 runTimeInfo.properties 对齐;枚举值见 detail 页映射表。 +const MOCK_VITALS = { + heartRate: 72, + respiratoryRate: 16, + bodyMovement: 3, + moveState: 3, + onbedStatus: 1, + bodyStatus: 2, + bodyPosition: 8 +} + +// 心率读数模拟状态:跨调用保留最近 50 个读数(与 web 端 pageSize:50 一致), +// 每次轮询推进 2~3 个新读数、挤出最旧的——等价于 web 端每 3 秒按 createTime 倒序重拉最新 50 条。 +const heartState = { + series: [], + value: 72 +} + +// 心率读数小幅随机游走(60~90 BPM)。 +function driftHeartRate() { + heartState.value += Math.round((Math.random() - 0.5) * 4) + heartState.value = Math.min(90, Math.max(60, heartState.value)) + return heartState.value +} + +// 初始预填 50 个读数,首屏即有完整曲线。 +for (let i = 0; i < 50; i++) { + heartState.series.push(driftHeartRate()) +} + +// 推进若干新读数并保留最近 50 个。 +function pushHeartReadings() { + const n = 2 + Math.round(Math.random()) + for (let i = 0; i < n; i++) { + heartState.series.push(driftHeartRate()) + } + if (heartState.series.length > 50) { + heartState.series = heartState.series.slice(-50) + } +} + +/** + * 获取 ED713 设备实时体征属性。 + * 约定:data 含 { heartRate, respiratoryRate, bodyMovement, moveState, onbedStatus, bodyStatus, bodyPosition }。 + * @param {*} deviceId 设备 id + */ +export function getVitalSigns(deviceId) { + if (USE_MOCK) { + const heartRate = driftHeartRate() + return new Promise((resolve) => + setTimeout(() => resolve({ ...MOCK_VITALS, heartRate, deviceId }), 300) + ) + } + return request.get('/device/vitals', { deviceId }) +} + +/** + * 获取心率历史序列(与 web 端一致:最近 50 条心率读数、按时间升序喂给面积图)。 + * 约定:data 为 number 数组;每次调用推进若干新读数,曲线随轮询向左滚动。 + * @param {*} deviceId 设备 id + */ +export function getHeartRateHistory(deviceId) { + if (USE_MOCK) { + pushHeartReadings() + return new Promise((resolve) => + setTimeout(() => resolve([...heartState.series]), 300) + ) + } + return request.get('/device/heart-history', { deviceId }) +} diff --git a/components/vital-wave.vue b/components/vital-wave.vue new file mode 100644 index 0000000..94f65ee --- /dev/null +++ b/components/vital-wave.vue @@ -0,0 +1,179 @@ + + + + + + diff --git a/constants/routes.js b/constants/routes.js index 3506cd0..685362a 100644 --- a/constants/routes.js +++ b/constants/routes.js @@ -8,6 +8,7 @@ export const ROUTES = Object.freeze({ MINE: '/pages/mine/index', DEVICE_ADD: '/pages/device/add', DEVICE_CONFIG: '/pages/device/config', + DEVICE_DETAIL: '/pages/device/detail', SCENE_SELECT: '/pages/scene/select' }) diff --git a/pages.json b/pages.json index dade0f7..d5759f9 100644 --- a/pages.json +++ b/pages.json @@ -36,6 +36,12 @@ "navigationStyle": "custom" } }, + { + "path": "pages/device/detail", + "style": { + "navigationStyle": "custom" + } + }, { "path": "pages/scene/select", "style": { diff --git a/pages/device/detail.vue b/pages/device/detail.vue new file mode 100644 index 0000000..016ba9a --- /dev/null +++ b/pages/device/detail.vue @@ -0,0 +1,343 @@ + + + + + + diff --git a/pages/index/index.vue b/pages/index/index.vue index 9a45e31..340de1a 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -29,8 +29,39 @@ - - + + + + + + + + + + + + + + + + + + + + + {{ device.name }} + + + + {{ device.online ? '在线' : '离线' }} + + + @@ -40,19 +71,31 @@