diff --git a/App.vue b/App.vue index 4c9d31f..c8dacb7 100644 --- a/App.vue +++ b/App.vue @@ -15,12 +15,9 @@ \ No newline at end of file + .uni-picker-view-content{ + position: inherit; + } + .uni-picker-view-wrapper{ + background: rgba(42, 42, 42, 1); + } + diff --git a/api/6170/callPolice.js b/api/6170/callPolice.js new file mode 100644 index 0000000..88a5e01 --- /dev/null +++ b/api/6170/callPolice.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' +//报警 +export function deviceSendAlarmMessage(data) { + return request({ + url: '/app/bjq/device/sendAlarmMessage', + method: 'post', + data: data + }) +} \ No newline at end of file diff --git a/api/6170/deviceControl.js b/api/6170/deviceControl.js index 44b4601..e257231 100644 --- a/api/6170/deviceControl.js +++ b/api/6170/deviceControl.js @@ -2,7 +2,7 @@ import request from '@/utils/request' export function deviceDetail(id) { return request({ - url: `/app/device/${id}`, + url: `/app/bjq/device/${id}`, method: 'get', }) } @@ -16,7 +16,7 @@ export function deviceShareId(id) { // 人员信息登记 export function registerPersonInfo(data) { return request({ - url: `/app/device/registerPersonInfo`, + url: `/app/bjq/device/registerPersonInfo`, method: 'post', data: data }) @@ -24,8 +24,41 @@ export function registerPersonInfo(data) { // 发送信息 export function deviceSendMessage(data) { return request({ - url: `/app/device/sendMessage`, + url: `/app/bjq/device/sendMessage`, method: 'post', data: data }) } +// 灯光模式设置 +export function lightModeSettings(data) { + return request({ + url: `/app/bjq/device/lightModeSettings`, + method: 'post', + data: data + }) +} +// 激光模式设置 +export function laserModeSettings(data) { + return request({ + url: `/app/bjq/device/laserModeSettings`, + method: 'post', + data: data + }) +} +// 灯光亮度设置 + +export function lightBrightnessSettings(data) { + return request({ + url: `/app/bjq/device/lightBrightnessSettings`, + method: 'post', + data: data + }) +} +// 地图逆解析 +export function mapReverseGeocoding(data) { + return request({ + url: `/app/bjq/device/mapReverseGeocoding`, + method: 'post', + data: data + }) +} \ No newline at end of file diff --git a/components/CustomPopup/CustomPopup.vue b/components/CustomPopup/CustomPopup.vue index e2ca6db..2cafe95 100644 --- a/components/CustomPopup/CustomPopup.vue +++ b/components/CustomPopup/CustomPopup.vue @@ -1,182 +1,292 @@ \ No newline at end of file diff --git a/components/TimePicker/TimePicker.vue b/components/TimePicker/TimePicker.vue new file mode 100644 index 0000000..190def0 --- /dev/null +++ b/components/TimePicker/TimePicker.vue @@ -0,0 +1,88 @@ + + + + + \ No newline at end of file diff --git a/components/custom-navbar/custom-navbar.vue b/components/custom-navbar/custom-navbar.vue index 35b5593..102fe99 100644 --- a/components/custom-navbar/custom-navbar.vue +++ b/components/custom-navbar/custom-navbar.vue @@ -22,9 +22,17 @@ {{ rightText }} + + - + @@ -60,6 +68,11 @@ rightIconSize: { // 图标大小 type: Number, default: 24 + }, + rightIcons: { + type: Array, + default: () => [] + // 格式: [{src: '/path/icon1.png'}, {src: '/path/icon2.png'}] } }, data() { @@ -76,6 +89,10 @@ }, handleRightClick() { this.$emit('right-click'); // 触发右侧点击事件 + }, + // 新增图标点击方法 + handleIconClick(index) { + this.$emit('icon-click', index) } } } diff --git a/manifest.json b/manifest.json index d4a5a53..5a09c99 100644 --- a/manifest.json +++ b/manifest.json @@ -62,7 +62,10 @@ "appid" : "uni.app.UNIA21EF43", "privacyDescription" : { "NSBluetoothPeripheralUsageDescription" : "需要蓝牙访问权限,用于设备通信", - "NSBluetoothAlwaysUsageDescription" : "需要蓝牙访问权限,用于设备通信" + "NSBluetoothAlwaysUsageDescription" : "需要蓝牙访问权限,用于设备通信", + "NSLocationWhenInUseUsageDescription" : "App需要您的同意,才能在使用期间访问位置", + "NSLocationAlwaysUsageDescription" : "App需要您的同意,才能始终访问位置", + "NSLocationAlwaysAndWhenInUseUsageDescription" : "App需要您的同意,才能始终访问位置" }, "dSYMs" : false }, @@ -81,7 +84,8 @@ "name" : "amapHG8nIFW5", "appkey_ios" : "065c43f02c7b627a74ad7dd23b16bb4f", "appkey_android" : "d7d852dbda2b95f6f796fb9a711a9fee" - } + }, + "customStyle": true }, "oauth" : {}, "push" : {} diff --git a/pages/210/addDevice/index.vue b/pages/210/addDevice/index.vue new file mode 100644 index 0000000..67077f0 --- /dev/null +++ b/pages/210/addDevice/index.vue @@ -0,0 +1,332 @@ + + + + + \ No newline at end of file diff --git a/pages/210/deviceControl/index.vue b/pages/210/deviceControl/index.vue new file mode 100644 index 0000000..4c9088f --- /dev/null +++ b/pages/210/deviceControl/index.vue @@ -0,0 +1,1384 @@ + + + + + \ No newline at end of file diff --git a/pages/210/historyRecords/index.vue b/pages/210/historyRecords/index.vue new file mode 100644 index 0000000..d9802c3 --- /dev/null +++ b/pages/210/historyRecords/index.vue @@ -0,0 +1,120 @@ + + + + + \ No newline at end of file diff --git a/pages/210/onlineDevice/index.vue b/pages/210/onlineDevice/index.vue new file mode 100644 index 0000000..6de0039 --- /dev/null +++ b/pages/210/onlineDevice/index.vue @@ -0,0 +1,254 @@ + + + + + \ No newline at end of file diff --git a/pages/6170/allShare/index.vue b/pages/6170/allShare/index.vue index 4cdfb9d..cadcdb2 100644 --- a/pages/6170/allShare/index.vue +++ b/pages/6170/allShare/index.vue @@ -17,7 +17,7 @@ {{ tabs[activeTab].name === '我的分享' ? `分享给“${group.sharedTo}”的设备` - : `来自“${group.sharedTo}”分享的设备` + : `来自“${group.othersharedTo}”分享的设备` }} {{editingGroup === groupIndex ? '完成' : '编辑'}} @@ -40,8 +40,11 @@ ID:{{item.deviceImei}} - 在线 - 电量:{{item.battery || '80'}}% + + 在线 + + 离线 + 电量:{{item.battery || '0'}}% @@ -49,11 +52,6 @@ - - @@ -67,7 +65,7 @@ - + {{ tabs[activeTab].name === '我的分享' ? '确定停止分享该设备' : '确定移除他人分享给你的这台设备' }} @@ -117,10 +115,12 @@ const groups = {}; this.deviceList.forEach(device => { // 这里假设device.sharedTo是分享目标的手机号 - const key = device.sharedTo || '未分享'; + const key = this.activeTab === 0 ? device.phonenumber : device.otherPhonenumber; + const displayName = this.activeTab === 0 ? device.phonenumber : device.otherPhonenumber; if (!groups[key]) { groups[key] = { - sharedTo: key, + sharedTo: displayName, // 显示用名称 + othersharedTo: displayName, // 显示用名称 devices: [] }; } @@ -213,7 +213,8 @@ const newDevices = res.rows.map(device => ({ ...device, showConfirm: false, - sharedTo: device.phonenumber || '未分享' + sharedTo: device.phonenumber, + othersharedTo: device.otherPhonenumber })); // 分页处理 if (this.page === 1) { diff --git a/pages/6170/callPolice/index.vue b/pages/6170/callPolice/index.vue new file mode 100644 index 0000000..1b34bd6 --- /dev/null +++ b/pages/6170/callPolice/index.vue @@ -0,0 +1,413 @@ + + + + + \ No newline at end of file diff --git a/pages/6170/deviceControl/index.vue b/pages/6170/deviceControl/index.vue index 8c96320..664f710 100644 --- a/pages/6170/deviceControl/index.vue +++ b/pages/6170/deviceControl/index.vue @@ -6,7 +6,7 @@ @@ -16,16 +16,22 @@ - + - 90% + + {{deviceInfo.batteryPercentage}}% + 电量 + + + - + - 1小时 + {{deviceInfo.batteryRemainingTime || '0'}}分钟 续航时间 @@ -42,28 +48,46 @@ 设备状态 - 运行中 + {{deviceInfo.onlineStatus===0?'离线':'在线'}} - 定位信息 - - 114.72 30.28 - 深圳市龙华区富源晟 + 定位信息 + + + {{ deviceInfo && deviceInfo.longitude ? Number(deviceInfo.longitude).toFixed(4) : '' }} + {{ deviceInfo && deviceInfo.latitude ? Number(deviceInfo.latitude).toFixed(4) : '' }} + + + + {{deviceInfo.address}} + + + 设备强制报警中 + + + + 灯光亮度 {{ sliderValue }}% + - - + + + + @@ -71,7 +95,7 @@ - + 灯光模式 {{ currentMainMode }} @@ -80,15 +104,16 @@ - + 激光模式 + {{currentlaserMode}} - + 开机画面 上传 @@ -111,19 +136,23 @@ 单位: - + 姓名: - + 职位: - + ID: - + @@ -135,7 +164,8 @@ - + @@ -143,15 +173,15 @@ 产品信息 - + 产品参数 - + 操作说明 - + 操作视频 @@ -185,16 +215,12 @@ 上传开机画面 - - - @@ -208,9 +234,9 @@ - 确认开启激光模式? + {{ isLaserOn ? '确认关闭激光模式?' : '确认开启激光模式?' }} - + 注意事项 1.禁止直视光源或反射面! 2.避免直射人或易燃物! @@ -225,8 +251,40 @@ - + + + + + + + + + + + @@ -237,27 +295,36 @@ deviceDetail, registerPersonInfo, deviceSendMessage, - deviceShareId + deviceShareId, + lightModeSettings, //灯光模式设置 + laserModeSettings, //激光模式设置 + lightBrightnessSettings, //灯光亮度设置 } from '@/api/6170/deviceControl.js' - import { - getDeviceId - } from '../../../store/BLETools'; import { baseURL, getToken, clientid } from '@/utils/request' + import { + deviceSendAlarmMessage + } from '@/api/6170/callPolice.js' export default { data() { return { + lastBrightnessTime: 0, + isCardSliding: false, + cardRect: null, + touchStartX: 0, + touchStartY: 0, pageLoading: true, mainMode: 'string', secondaryMode: 'string', navBarHeight: 70 + uni.getSystemInfoSync().statusBarHeight, navTitle: "", - sliderValue: 30, + sliderValue: 25, lightModeA: false, currentMainMode: '强光', + currentlaserMode: "关闭", lightModeB: false, lightModeC: false, //激光提示框 items: [], @@ -273,13 +340,6 @@ code: '', }, deviceInfo: {}, - modeInstructions: { - '关灯': [1, 0, 0, 0, 0], - '强光': [1, 1, 0, 0, 0], - '弱光': [1, 2, 0, 0, 0], - '爆闪': [1, 3, 0, 0, 0], - '泛光': [1, 4, 0, 0, 0] - }, activePermissions: [], // 存储当前设备的权限数组 isSharedDevice: false, // 标记是否来自分享 isRightIconVisible: false, @@ -289,7 +349,26 @@ showUploadPopup: false, selectedImage: null, // 添加这个变量来存储选择的图片 file: '', - selectedItemIndex: 0 + selectedItemIndex: 0, + popupType: 'person', //弹框类型 + isLaserOn: false, + // 进度条 + Progress: { + show: false, //是否显示 + height: '40rpx', + showMask: true, //是否显示mask + maskBgColor: 'rgba(0, 0, 0, 0.5)', // 半透明黑色遮罩 + contentBgColor: 'rgba(18, 18, 18, 0.8)', // 主背景带透明度 + showText: true, //是否显示当前进度的文字 + txtColor: '#ffffffde', //文字的颜色 + curr: 20, //当前进度 + total: 100, //总进度 + proBgColor: '#2a2a2a', //进度条底色, + proBorder: '', //进度条border + currBgColor: '#bbe600', //当前进度底色 + currBorder: '', //当前进度border + borderRadius: '10rpx' + } } }, computed: { @@ -298,21 +377,145 @@ } }, methods: { + filterChinese(e) { + const value = e.detail.value; + // 允许中文和常见中文标点 + this.messageToSend = value.replace(/[^\u4e00-\u9fa5,。?!、;:“”‘’()【】《》…—]/g, ''); + // 修复某些平台输入法兼容性问题 + this.$nextTick(() => { + e.target.value = this.messageToSend; + }); + }, // 点击弹框外的区域关闭 closePopup() { this.lightModeA = false; this.lightModeB = false; this.lightModeC = false; }, + closeProgress() { + this.Progress.show = false; // 直接关闭进度条 + }, // *******定位****** - gpsPosition() { + gpsPosition(item) { + // 添加调试日志 uni.navigateTo({ - url: '/pages/common/map/index' + url: '/pages/common/map/index', + events: { + ack: function(data) {} + }, + success: (res) => { + res.eventChannel.emit('Map', { + data: item + }); + } }) }, + // 强制报警() + handlePolice() { + this.popupType = 'cancel'; + this.popupMessage = '确认要解除所选设备的报警状态'; + this.showPopupFlag = true; + }, // ***********进度条*********** + cardTouchStart(e) { + if (!this.cardRect) return; + this.touchStartX = e.touches[0].clientX; + this.touchStartY = e.touches[0].clientY; + }, + + cardTouchMove(e) { + if (!this.cardRect || e.touches.length === 0) return; + const deltaX = e.touches[0].clientX - this.touchStartX; + const deltaY = e.touches[0].clientY - this.touchStartY; + + // 只有当水平滑动距离大于垂直距离时,才判断为有效滑动 + if (Math.abs(deltaX) > Math.abs(deltaY)) { + this.isCardSliding = true; + this.updateSliderFromTouch(e); + } + }, + cardTouchEnd(e) { + if (this.isCardSliding) { + // 触摸结束时,调用滑动结束的处理函数来发送最终值 + this.onSliderChangeEnd({ + detail: { + value: this.sliderValue + } + }); + this.isCardSliding = false; + } + this.touchStartX = 0; + this.touchStartY = 0; + }, + + updateSliderFromTouch(e) { + const touchX = e.touches[0].clientX; + const cardLeft = this.cardRect.left; + const cardWidth = this.cardRect.width; + let relativeX = touchX - cardLeft; + // 边界处理 + if (relativeX < 0) relativeX = 0; + if (relativeX > cardWidth) relativeX = cardWidth; + const newValue = Math.round((relativeX / cardWidth) * 100); + // 调用已有的节流函数来更新值和发送命令 + this.onSliderChanging({ + detail: { + value: newValue + } + }); + }, onSliderChanging(e) { - this.sliderValue = e.detail.value; + if (!this.cardRect) return; + let value = e.detail.value; + if (value < 10) { + value = 10; + } + this.sliderValue = value; // 实时更新UI + + const now = Date.now(); + // 使用节流防止指令发送过于频繁 + if (now - this.lastBrightnessTime > 200) { // 200毫秒节流 + this.lastBrightnessTime = now; + + // 增加轻微的震动反馈,提升手感 + uni.vibrateShort({ + type: 'light' + }); + + let data = { + deviceId: this.deviceID, + instructValue: this.sliderValue + '.00', + deviceImei:this.itemInfo.deviceImei + } + lightBrightnessSettings(data).then((res) => { + if (res.code !== 200) { + // 可以在这里处理错误,但滑动中不建议用toast + } + }) + } + }, + onSliderChangeEnd(e) { + let value = e.detail.value; + if (value < 10) { + value = 10; + } + this.sliderValue = value; + + let data = { + deviceId: this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId, + instructValue: this.sliderValue + '.00', + deviceImei:this.itemInfo.deviceImei + } + lightBrightnessSettings(data).then((res) => { + if (res.code == 200) { + // 可以在此处理成功反馈 + } else { + uni.showToast({ + icon: 'none', + title: res.msg || '亮度调节失败' + }) + } + }) }, selectMode(type) { this.modeType = type; @@ -321,30 +524,37 @@ this.items = [{ text: '强光', selected: this.currentMainMode === '强光', // 修正匹配条件 - image: '/static/images/sett.png', + image: '/static/images/6170/sett.png', + instructValue: '1' }, { text: '弱光', selected: this.currentMainMode === '弱光', - image: '/static/images/sett.png' + image: '/static/images/6170/rg.png', + instructValue: '2' }, { text: '爆闪', selected: this.currentMainMode === '爆闪', - image: '/static/images/bs.png' + image: '/static/images/6170/bs.png', + instructValue: '3' }, { text: '泛光', selected: this.currentMainMode === '泛光', - image: '/static/images/settt.png' + image: '/static/images/6170/settt.png', + instructValue: '4' + }, + { + text: '关闭', + selected: this.currentMainMode === '关闭', + image: '/static/images/6170/close.png', + instructValue: '0' }, ]; } }, - // 激光模式 - lasermode() { - this.lightModeC = true - }, + // 人员信息登录 toggleForm() { this.isFormExpanded = !this.isFormExpanded; }, @@ -366,28 +576,64 @@ }, // 灯光模式的确认 handleSumbit() { - if (this.selectedItemIndex === null) return; - const selectedItem = this.items[this.selectedItemIndex]; - const instruction = this.modeInstructions[selectedItem.text]; - console.log(selectedItem, 'selectedItemselectedItem'); - // 修正这里的赋值错误,应该保存索引而不是文本 - this.selectedItemIndex = this.selectedItemIndex; - console.log(this.selectedItemIndex,'this.selectedItemIndexthis.selectedItemIndex'); - // if (instruction) { - // const topic = `B/${this.itemInfo.deviceImei}`; - // const message = JSON.stringify(instruction); - // // 确保mqttClient已连接 - // if (this.mqttClient && this.mqttClient.client && this.mqttClient.client.isConnected()) { - // this.mqttClient.publish(topic, message); - // console.log('已发送指令:', instruction); - // } else { - // uni.showToast({ - // title: 'MQTT未连接', - // icon: 'none' - // }); - // } - // } - this.lightModeA = false; + if (this.selectedItemIndex === null) return; + const selectedItem = this.items[this.selectedItemIndex]; + console.log(selectedItem, 'selectedItemselectedItem'); + // 修正这里的赋值错误,应该保存索引而不是文本 + this.selectedItemIndex = this.selectedItemIndex; + let data = { + deviceId: this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId, + instructValue: selectedItem.instructValue, + deviceImei:this.itemInfo.deviceImei + } + lightModeSettings(data).then((res) => { + if (res.code == 200) { + uni.showToast({ + icon: 'none', + title: res.msg + }) + this.lightModeA = false; + } else { + uni.showToast({ + icon: 'none', + title: res.msg + }) + } + }) + }, + // 激光模式 + lasermode() { + this.lightModeC = true + }, + // 激光确认框提交 + handleBtn() { + const instructValue = this.isLaserOn ? 0 : 1; + let data = { + deviceId: this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId, + instructValue: instructValue, + deviceImei:this.itemInfo.deviceImei + } + laserModeSettings(data).then((res) => { + if (res.code == 200) { + uni.showToast({ + icon: 'none', + title: res.msg + }) + this.isLaserOn = !this.isLaserOn; + this.currentlaserMode = this.isLaserOn ? "开启" : "关闭"; // 更新显示文本 + this.lightModeC = false + } else { + uni.showToast({ + icon: 'none', + title: res.msg + }) + } + }) + + }, + //激光取消 + handleDisagree() { + this.lightModeC = false }, // 上传开机画面 uploadStartup() { @@ -414,7 +660,7 @@ } this.selectedImage = res.tempFilePaths[0]; console.log('选择的图片:', res); - this.file = res.tempFiles[0].file + //this.file = res.tempFiles[0].file }, fail: (err) => { console.error('选择图片失败:', err); @@ -434,12 +680,21 @@ }); return; } + // 显示进度条 + this.Progress = { + ...this.Progress, + show: true, + curr: 0, + showText: true + }; + uni.uploadFile({ - url: baseURL + '/app/device/uploadLogo', + url: baseURL + '/app/bjq/device/uploadLogo', filePath: this.selectedImage, - name: this.file, + name: 'file', formData: { - deviceId: this.deviceID, + deviceId: this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId, + deviceImei:this.itemInfo.deviceImei }, header: { 'Authorization': 'Bearer ' + getToken(), @@ -450,10 +705,6 @@ try { const responseData = JSON.parse(res.data); if (responseData.code === 200) { - uni.showToast({ - title: responseData.msg, - icon: 'success' - }); this.selectedImage = ''; this.file = null; this.lightModeB = false @@ -468,12 +719,12 @@ title: '上传失败', icon: 'none' }); + this.Progress.show = false; // 上传失败隐藏进度条 } finally { uni.hideLoading(); } } }) - }, // 分享 shareUp() { @@ -492,48 +743,29 @@ // 操作说明 operatingInst() { + let id = this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId uni.navigateTo({ - url: `/pages/common/operatingInstruct/index?id=${this.deviceID}` + url: `/pages/common/operatingInstruct/index?id=${id}` }) }, // 产品参数 productparams() { + let id = this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId uni.navigateTo({ - url: `/pages/common/productDes/index?id=${this.deviceID}` + url: `/pages/common/productDes/index?id=${id}` }) }, // 操作视频 operatingVideo() { + let id = this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId uni.navigateTo({ - url: `/pages/common/operationVideo/index?id=${this.deviceID}` + url: `/pages/common/operationVideo/index?id=${id}` }) }, - // 激光确认框 - handleBtn() { - this.lightModeC = false - }, - //取消 - handleDisagree() { - this.lightModeC = false - }, + // 发送人员信息 sendPersonnelInfo() { - // if (!this.mqttClient || !this.mqttClient.client.isConnected()) { - // uni.showToast({ - // title: 'MQTT未连接', - // icon: 'none' - // }); - // return; - // } - // const topic = `device/command/${this.deviceID}/personnel`; - // const message = JSON.stringify(this.personnelInfo); - // this.mqttClient.publish(topic, message); - // uni.showToast({ - // title: '人员信息已发送', - // icon: 'success' - // }); - if (!this.personnelInfo.unitName) { uni.showToast({ title: '单位名称不能为空', @@ -571,11 +803,12 @@ name: this.personnelInfo.name, position: this.personnelInfo.position, unitName: this.personnelInfo.unitName, - deviceId: this.deviceID + deviceId: this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId, } registerPersonInfo(data).then((res) => { if (res.code == 200) { uni.hideLoading() + this.popupType = 'person'; this.showPopupFlag = true this.popupMessage = '人员信息发送成功' } else { @@ -590,6 +823,32 @@ this.showPopupFlag = false console.log('用户点击了确定') }, + // 解除报警 + onPopupConfirmPolice() { + let data = { + deviceIds: this.apiType === 'listA' ? [this.deviceID] : [this.itemInfo.deviceId], + instructValue: 0, // '解除报警' + } + deviceSendAlarmMessage(data).then((res) => { + if (res.code == 200) { + uni.showToast({ + title: res.msg, + icon: 'none' + }); + this.showPopupFlag = false + setTimeout(() => { + this.fetchDeviceDetail(this.deviceID); + uni.$emit('deviceStatusUpdate', {}); + }, 500) + + } else { + uni.showToast({ + title: res.msg, + icon: 'none' + }); + } + }); + }, // 发送文本消息 sendTextMessage() { if (!this.messageToSend) { @@ -605,11 +864,14 @@ }) let data = { sendMsg: this.messageToSend, - deviceIds: [this.deviceID] + //deviceIds: [this.deviceID], + deviceIds: this.apiType === 'listA' ? [this.deviceID] : [this.itemInfo.deviceId], + } deviceSendMessage(data).then((res) => { if (res.code == 200) { uni.hideLoading() + this.popupType = 'person'; this.showPopupFlag = true this.popupMessage = '发送信息成功' } else { @@ -619,18 +881,19 @@ }); } }) - // const topic = `device/command/${this.deviceID}/message`; - // this.mqttClient.publish(topic, this.messageToSend); - // uni.showToast({ - // title: '消息已发送', - // icon: 'success' - // }); }, // 统一处理返回方法 handleDeviceData(res, isFromShared = false) { if (res.code == 200) { // 最后关闭加载状态 this.pageLoading = false + this.$nextTick(() => { + uni.createSelectorQuery().in(this).select('.control-card').boundingClientRect(data => { + if (data) { + this.cardRect = data; + } + }).exec(); + }) this.deviceInfo = res.data this.personnelInfo = { unitName: res.data.personnelInfo?.unitName || '', @@ -683,7 +946,14 @@ icon: 'none' }) } + }, + handleMqttLost() { + this.Progress = { + ...this.Progress, + show: false, // 隐藏进度条 + }; } + }, onLoad(options) { const eventChannel = this.getOpenerEventChannel(); @@ -705,23 +975,65 @@ // 订阅来自设备的状态更新 const statusTopic = `A/${this.itemInfo.deviceImei}`; this.mqttClient.subscribe(statusTopic, (payload) => { - console.log(`收到来自 ${statusTopic} 的消息:`, payload); - // uni.showModal({ - // title: '收到设备消息', - // content: payload, - // showCancel: false - // }); + try { + console.log(`收到来自 ${statusTopic} 的消息:`, payload); + //收到电量上报。延迟20s请求接口数据 + const parsedMessage = typeof payload === 'string' ? JSON.parse(payload) : + payload; + const deviceState = parsedMessage.state; // 直接取 state 数组 + // ✅ 发送全局事件通知主页面更新 + uni.$emit('deviceStatusUpdate', { + message: parsedMessage, // 消息内容 + timestamp: new Date().getTime() // 时间戳 + }); + if (deviceState[0] === 12) { + setTimeout(() => { + this.fetchDeviceDetail(data.data.id); + }, 20000); + // 这里判断电量低于20%,弹框提示 + if (this.deviceInfo.batteryPercentage < 20) { + this.popupType = 'bettery' + this.popupMessage = '请及时充电'; + this.showPopupFlag = true; + } + } + // 处理上传照片进度消息 + if (deviceState[0] === 3) { + const progress = deviceState[1]; + // 更新进度条 + this.Progress = { + ...this.Progress, + curr: progress * 2, + show: progress < 50 // 进度达到100时自动隐藏 + }; + // 当进度为100时显示成功弹框 + if (progress === 50) { + this.popupType = 'logo'; + this.popupMessage = '上传成功'; + this.showPopupFlag = true; + this.lightModeB = false; // 关闭上传弹窗 + this.selectedImage = ''; // 清空已选图片 + } + } + } catch (error) { + console.error('解析MQTT消息失败:', error, '原始消息:', payload); + } }); - }); + }) + // 设置连接丢失回调 + uni.$on('mqttConnectionLost', this.handleMqttLost); if (this.apiType === 'listA') { this.fetchDeviceDetail(data.data.id) } else { - this.fetchSharedDeviceDetail(data.data.deviceId) + // 查分享权限详情 + this.fetchSharedDeviceDetail(data.data.id) } }); // 如果需要向调用页面返回数据,可以触发 'ack' 事件 - eventChannel.emit('ack', {}) + eventChannel.emit('ack', { + + }) }, onUnload() { @@ -729,6 +1041,10 @@ if (this.mqttClient) { this.mqttClient.disconnect(); } + uni.$off('mqttConnectionLost', this.handleMqttLost); + if (this.mqttClient) { + this.mqttClient.disconnect(); + } }, } @@ -796,7 +1112,6 @@ width: 204rpx; height: 144rpx; margin-top: 30rpx; - object-fit: contain; } .dlIMG { @@ -804,6 +1119,12 @@ height: 52rpx; } + .chargeStateIMG { + width: 27rpx; + height: 37rpx; + margin-left: 10rpx; + } + .cpIMG { width: 66rpx; height: 66rpx; @@ -859,7 +1180,7 @@ .info-card { background-color: rgb(26, 26, 26); border-radius: 16rpx; - padding: 10rpx 30rpx 5rpx 30rpx; + padding: 10rpx 20rpx 5rpx 20rpx; margin-bottom: 20rpx; } @@ -873,6 +1194,7 @@ .info-label { font-size: 28rpx; color: rgba(255, 255, 255, 0.87); + white-space: nowrap; } .info-value { @@ -885,6 +1207,13 @@ text-align: end; } + .locationGPS { + width: 88%; + text-align: end; + float: right; + line-height: 50rpx; + } + .control-card { background-color: rgb(26, 26, 26); border-radius: 16rpx; @@ -952,6 +1281,18 @@ } + .callpolice { + display: flex; + justify-content: space-between; + border-radius: 16rpx; + background: rgba(224, 52, 52, 1); + padding: 15rpx; + margin-bottom: 15rpx; + color: #fff; + line-height: 35rpx; + font-size: 26rpx; + } + .example-body { position: absolute; left: 50%; @@ -1014,6 +1355,7 @@ .form-label { font-size: 32rpx; color: rgba(255, 255, 255, 0.87); + white-space: nowrap; } .form-input { @@ -1021,6 +1363,15 @@ border: 1rpx solid transparent; font-size: 32rpx; color: rgba(255, 255, 255, 0.87); + width: 100%; + } + + .form-input1 { + height: 80rpx; + border: 1rpx solid transparent; + font-size: 32rpx; + color: rgba(255, 255, 255, 0.87); + width: 98%; } .product-section { @@ -1100,7 +1451,7 @@ /* 弹窗主体 */ .agreement-popup { width: 100%; - height: 40%; + height: 50%; background-color: rgb(42, 42, 42); border-radius: 60rpx 60rpx 0rpx 0rpx; padding: 40rpx; diff --git a/pages/6170/shareDevices/index.vue b/pages/6170/shareDevices/index.vue index 8766f08..fcc8ac6 100644 --- a/pages/6170/shareDevices/index.vue +++ b/pages/6170/shareDevices/index.vue @@ -48,7 +48,7 @@ - + 设备分享成功 diff --git a/pages/6170/shareManagement/index.vue b/pages/6170/shareManagement/index.vue index 91e7a96..5466a96 100644 --- a/pages/6170/shareManagement/index.vue +++ b/pages/6170/shareManagement/index.vue @@ -4,7 +4,7 @@ - + 用户名:{{item.deviceName}} @@ -22,7 +22,7 @@ - + 确定移除该用户! @@ -86,7 +86,7 @@ }, getData(val) { let data = { - deviceid: val + deviceId: val } deviceShareList(data).then((res) => { if (res.code == 200) { diff --git a/pages/common/addvideo/index.vue b/pages/common/addvideo/index.vue index 3b34679..abddf44 100644 --- a/pages/common/addvideo/index.vue +++ b/pages/common/addvideo/index.vue @@ -25,7 +25,7 @@ - + 保存成功! diff --git a/pages/common/allType/index.vue b/pages/common/allType/index.vue index 29571b7..b2555f8 100644 --- a/pages/common/allType/index.vue +++ b/pages/common/allType/index.vue @@ -4,7 +4,7 @@ - + {{ item.typeName }} diff --git a/pages/common/index/index.vue b/pages/common/index/index.vue index ac6cf8a..a898dee 100644 --- a/pages/common/index/index.vue +++ b/pages/common/index/index.vue @@ -2,22 +2,25 @@ + rightIcon="/static/images/common/add.png" @right-click="scan"> - - - - {{tab.typeName}} + + + + + {{tab.typeName}} + + + + - - - - - - + + + 报警 位置 发送信息 @@ -27,7 +30,8 @@ + @click="handleSwipeClick($event, item, index)" class="device-card" + :style="{ border: item.communicationMode==0 && item.onlineStatus==0 ? '1px solid rgba(224, 52, 52, 1)' : 'none' }"> @@ -39,17 +43,24 @@ ID:{{item.deviceImei}} ID:{{item.deviceMac}} - 在线 - 电量:90% + + 在线 + + 离线 + 电量:{{item.battery || '0'}}% - + 报警中 + 已连接 未连接 - + @@ -67,10 +78,10 @@ - + - + 确定删除所选设备! @@ -83,7 +94,7 @@ - + @@ -101,9 +112,9 @@ - + - + @@ -112,9 +123,9 @@ - + - + @@ -163,23 +174,23 @@ RenameModel: false, menuItems: [{ text: '扫一扫添加', - icon: '/static/images/scane.png', + icon: '/static/images/common/scane.png', action: 'scan' }, { text: '蓝牙添加', - icon: '/static/images/bluetooth.png', + icon: '/static/images/common/bluetooth.png', action: 'bluetooth' } ], shareItems: [{ text: '所有类型', - icon: '/static/images/type.png', + icon: '/static/images/common/type.png', action: 'type' }, { text: '所有分享', - icon: '/static/images/share.png', + icon: '/static/images/common/share.png', action: 'share' } ], @@ -289,17 +300,38 @@ onScrollToLower() { this.getData(); }, - // 添加扫一三图标 + // 添加扫一扫图标 scan() { this.showTooltip = !this.showTooltip; }, + closePopupTooltip() { + this.showTooltip = !this.showTooltip + this.showshare = !this.showshare + }, // 添加设备,扫一扫,蓝牙 handleMenuClick(item) { this.showTooltip = false; // 关闭弹窗 switch (item.action) { case 'scan': - uni.navigateTo({ - url: '/pages/common/scan/scan' + // uni.navigateTo({ + // url: '/pages/common/scan/scan' + // }); + // 扫一扫 + uni.scanCode({ + success: (res) => { + console.log('条码内容:' + res.result); + // 跳转并传递扫描结果 + uni.navigateTo({ + url: `/pages/common/qrcode/qrcode?deviceId=${encodeURIComponent(res.result)}` + }); + }, + fail: (err) => { + console.log('扫码失败', err); + uni.showToast({ + title: '扫码失败', + icon: 'none' + }); + } }); break; case 'bluetooth': @@ -311,7 +343,6 @@ }, // 右滑点击事件处理 handleSwipeClick(e, item, index) { - const { content } = e @@ -346,6 +377,7 @@ }); setTimeout(() => { this.onIntall(); + this.getTab() }, 500); this.deleteShow = false // 关闭所有滑动项 @@ -394,10 +426,27 @@ } }) }, + // 报警 + callpolice() { + const currentTab = this.tabs[this.activeTab]; + const deviceType = currentTab.id || ''; + console.log(`跳转到发送信息页面\n当前设备类型: ${deviceType}\n设备类型名称: ${currentTab.typeName}`); + uni.navigateTo({ + url: '/pages/6170/callPolice/index', + events: { + ack: function(data) {} + }, + success: (res) => { + res.eventChannel.emit('devicePolice', { + data: deviceType + }); + } + }) + }, // 发生短信 handleSend() { const currentTab = this.tabs[this.activeTab]; - const deviceType = currentTab.id || 'all'; + const deviceType = currentTab.id || ''; console.log(`跳转到发送信息页面\n当前设备类型: ${deviceType}\n设备类型名称: ${currentTab.typeName}`); uni.navigateTo({ url: '/pages/common/send/index', @@ -414,13 +463,21 @@ // 位置 location() { uni.navigateTo({ - url: '/pages/common/map/index' + url: '/pages/common/map/index', + events: { + ack: function(data) {} + }, + success: (res) => { + // 页面跳转成功后的回调函数 + res.eventChannel.emit('Map', { + data: this.deviceList, + }); + } }) }, handleFile(item) { - //console.log('item' + JSON.stringify(item)); - // communicationMode 0是4G 1是蓝牙 - if (item.communicationMode == 0) { + // communicationMode 0是4G 1是蓝牙,考虑多个4g设备 + if (item.typeName == 'BJQ6170') { uni.navigateTo({ url: "/pages/6170/deviceControl/index", events: { @@ -434,14 +491,29 @@ }); } }) + } else if (item.typeName == 'HBY210') { + const currentTab = this.tabs[this.activeTab]; + const deviceType = currentTab.id || ''; + uni.navigateTo({ + url: "/pages/210/deviceControl/index", + events: { + ack: function(data) {} + }, + success: (res) => { + // 页面跳转成功后的回调函数 + res.eventChannel.emit('deviceControl', { + data: item, + deviceType: deviceType, + apiType: 'listA' // 自定义标识 + }); + } + }) } if (item.typeName == '6155') { uni.navigateTo({ url: "/pages/6155/deviceDetail", events: { - ack: function(data) { - - } + ack: function(data) {} }, success: (res) => { res.eventChannel.emit('detailData', { @@ -450,14 +522,36 @@ } }) } - - }, onIntall() { this.page = 1; this.finished = false; this.getData(this.deviceType); // 重新加载第一页数据 }, + updateDeviceStatus(data) { + this.deviceList = this.deviceList + .map(item => { + if (!item) return null; // 如果 item 是 undefined/null,返回 null + if (item.communicationMode == 0) { + let messageData; + try { + messageData = data.message; + } catch (e) { + return item; // 解析失败则返回原 item + } + const [deviceId, onlineStatus, battery] = messageData.state || []; + console.log('我收到消息了没', item.battery); + return { + ...item, + battery: battery ?? item.battery, + onlineStatus: onlineStatus ?? item.onlineStatus, + lastUpdate: data.timestamp, + }; + } + return item; + }) + .filter(Boolean); + }, }, onLoad() { this.getTab() @@ -467,11 +561,19 @@ this.getTab() // 刷新数据 this.onIntall() }); + // 监听设备状态更新事件 + uni.$on('deviceStatusUpdate', (data) => { + console.log('列表收到消息了么'); + this.onIntall() + }); }, beforeDestroy() { // 组件销毁前移除监听器 uni.$off('refreshDeviceList'); }, + onUnload() { + uni.$off('deviceStatusUpdate'); + } } @@ -498,11 +600,10 @@ .tab-container { display: flex; - /* justify-content: space-around; */ cursor: pointer; margin-bottom: 40rpx; - /* min-width: 100%; */ - /* 最小宽度 */ + padding-right: 80rpx; + /* 预留更多按钮空间 */ } .tab-item { @@ -530,26 +631,26 @@ font-size: 28rpx; } - .uniui-more { + .tab-bar-wrap { + display: flex; + /* 横向排列 */ + align-items: baseline; + /* 垂直居中 */ position: relative; - width: 100%; + /* 可选(若需要绝对定位 fallback) */ + } + + .tab-more { + margin-left: 10rpx; + /* 与Tab的间距 */ + display: flex; + align-items: center; + background: linear-gradient(-88.60deg, rgba(18, 18, 18, 1), rgba(18, 18, 18, 0) 100%); } .more { width: 40rpx; height: 8rpx; - /* position: absolute; */ - /* right: 0rpx; - z-index: 100; */ - float: right; - top: -95rpx - } - - .gprs { - width: 28rpx; - height: 35rpx; - position: absolute; - left: 50rpx } .Sendmessage { @@ -599,6 +700,20 @@ } + .device-callpolice { + width: 122rpx; + height: 52rpx; + font-size: 24rpx; + border-radius: 0px 8px 0px 8px; + background-color: rgba(224, 52, 52, 1); + position: absolute; + top: 0rpx; + right: -4rpx; + text-align: center; + line-height: 52rpx; + color: #fff; + } + .device-status { width: 122rpx; height: 52rpx; @@ -672,6 +787,21 @@ left: -20rpx } + .offlines { + position: relative; + } + + .offlines::before { + content: ''; + position: absolute; + width: 15rpx; + height: 15rpx; + background: rgba(255, 255, 255, 0.4); + border-radius: 50%; + top: 20rpx; + left: -20rpx + } + .line { width: 2rpx; height: 24rpx; diff --git a/pages/common/login/index.vue b/pages/common/login/index.vue index fef908c..3dd79b6 100644 --- a/pages/common/login/index.vue +++ b/pages/common/login/index.vue @@ -1,6 +1,6 @@ - \ No newline at end of file + .loading-content { + color: #fff; + font-size: 16px; + padding: 12px 24px; + background: rgba(0, 0, 0, 0.7); + border-radius: 8px; + } + + .empty-tip { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: rgba(0, 0, 0, 0.7); + color: #fff; + padding: 10px 20px; + border-radius: 4px; + z-index: 99; + } + + \ No newline at end of file diff --git a/pages/common/operatingInstruct/index.vue b/pages/common/operatingInstruct/index.vue index 6d35941..4f2fa14 100644 --- a/pages/common/operatingInstruct/index.vue +++ b/pages/common/operatingInstruct/index.vue @@ -17,7 +17,7 @@ - + @@ -38,7 +38,7 @@ - + 确定删除所选设备! diff --git a/pages/common/operationVideo/index.vue b/pages/common/operationVideo/index.vue index 0c8453f..68ea82f 100644 --- a/pages/common/operationVideo/index.vue +++ b/pages/common/operationVideo/index.vue @@ -10,20 +10,20 @@ @click="handleSwipeClick($event, index,item)" class="content"> - + {{item.videoName}} {{item.videoUrl}} - + - + diff --git a/pages/common/productDes/index.vue b/pages/common/productDes/index.vue index e1befda..f450cfc 100644 --- a/pages/common/productDes/index.vue +++ b/pages/common/productDes/index.vue @@ -17,7 +17,7 @@ - + @@ -38,7 +38,7 @@ - + 确定删除所选设备! diff --git a/pages/common/qrcode/qrcode.vue b/pages/common/qrcode/qrcode.vue index 088b5e9..14f5249 100644 --- a/pages/common/qrcode/qrcode.vue +++ b/pages/common/qrcode/qrcode.vue @@ -2,16 +2,20 @@ - + ID: {{ deviceId }} - - + + + + 设备名:{{deviceId}} ID:{{deviceId}} diff --git a/pages/common/send/index.vue b/pages/common/send/index.vue index 3e85cb9..34806e3 100644 --- a/pages/common/send/index.vue +++ b/pages/common/send/index.vue @@ -16,32 +16,29 @@ 设备:{{item.deviceName}} - ID:{{item.deviceImei}} - - ID:{{item.deviceMac}} - - 离线 - 电量:90% + ID:{{item.deviceImei}} + 在线 + + 离线 + 电量:{{item.battery || '0'}}% - - 已连接 - 未连接 - 编辑信息