1774 lines
44 KiB
Vue
1774 lines
44 KiB
Vue
<template>
|
||
<view>
|
||
<!-- 添加全局加载遮罩 -->
|
||
<view v-if="pageLoading" class="page-loading-mask">
|
||
</view>
|
||
<!-- 使用自定义导航栏 -->
|
||
<view v-show="!pageLoading">
|
||
<custom-navbar :title="navTitle" :showBack="true" color="#FFFFFF"
|
||
:rightIcon="isRightIconVisible ? '/static/images/common/shape.png' : ''"
|
||
@right-click="shareUp"></custom-navbar>
|
||
<view class="device-detail-container" :style="{ paddingTop: navBarHeight + 'px' }">
|
||
<!-- 设备电量信息 -->
|
||
<view class="battery-section">
|
||
<view class="battery-sectionLeft">
|
||
<image :src="deviceInfo.devicePic" class="bipImg" mode="aspectFit"></image>
|
||
</view>
|
||
<view>
|
||
<view class="battery-v1">
|
||
<image src="/static/images/common/dl.png" class="dlIMG"></image>
|
||
<view>
|
||
<view class="battery-v2"
|
||
:style="{ color: deviceInfo.batteryPercentage < 20 ? '#FF0000' : '' }">
|
||
{{ deviceInfo.batteryPercentage }}%
|
||
</view>
|
||
<view class="battery-v3">电量</view>
|
||
</view>
|
||
<view v-if="deviceInfo.chargeState == 1">
|
||
<image src="/static/images/common/chargeState.png" class="chargeStateIMG"></image>
|
||
</view>
|
||
</view>
|
||
<view class="battery-v1">
|
||
<image src="/static/images/common/nz.png" class="dlIMG" mode="aspectFit"></image>
|
||
<view>
|
||
<view class="battery-v2">{{ deviceInfo.batteryRemainingTime || '0' }}分钟</view>
|
||
<view class="battery-v3">续航时间</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 设备基本信息 -->
|
||
<view class="info-card">
|
||
<view class="info-row">
|
||
<text class="info-label">IMEI号</text>
|
||
<text class="info-value status-running">{{ deviceInfo.deviceImei }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">设备状态</text>
|
||
<text class="info-value status-running">{{ deviceInfo.onlineStatus === 0 ? '离线' : '在线' }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label" style="display: flex; align-items: center;">定位信息</text>
|
||
<view class="info-value status-running" @click="gpsPosition(deviceInfo)">
|
||
<view class="info-value status-running">
|
||
{{ deviceInfo && deviceInfo.longitude ? Number(deviceInfo.longitude).toFixed(4) : '' }}
|
||
{{ deviceInfo && deviceInfo.latitude ? Number(deviceInfo.latitude).toFixed(4) : '' }}
|
||
</view>
|
||
<view class="info-value status-running locationGPS">
|
||
<uni-icons @click="toggleForm" type="location" size="17"
|
||
color="rgba(255, 255, 255, 0.8)" style="vertical-align: bottom;" />
|
||
{{ deviceInfo.address }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="callpolice" v-if="deviceInfo.onlineStatus == 1 && deviceInfo.alarmStatus == 1">
|
||
<view class="">设备强制报警中</view>
|
||
<view>
|
||
<uni-icons type="closeempty" size="15" color="rgba(255, 255, 255, 0.9)"
|
||
@click="handlePolice"></uni-icons>
|
||
</view>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">灯光亮度</text>
|
||
<text class="info-value status-running">{{ sliderValue }}%</text>
|
||
</view>
|
||
<!-- 灯光亮度控制 -->
|
||
<view class="control-card" @touchstart="cardTouchStart" @touchmove="cardTouchMove"
|
||
@touchend="cardTouchEnd">
|
||
<view @touchmove.prevent>
|
||
<slider :value="sliderValue" min="10" max="100" activeColor="rgb(187, 230, 0)"
|
||
backgroundColor="rgb(26, 26, 26)" :show-value="false" @changing="onSliderChanging"
|
||
@change="onSliderChangeEnd" block-color="#fff" block-size="20" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 灯光模式选择 -->
|
||
<view class="mode-section">
|
||
<view class="mode-buttons">
|
||
<view class="mode-v1" v-if="hasPermission('1')">
|
||
<view class="mode-v2" @click="selectMode('main')">
|
||
<image src="/static/images/6170/set.png" class="setIMG"></image>
|
||
<view>
|
||
<view class="battery-v2">灯光模式</view>
|
||
<view class="mode-v3">{{ currentMainMode }}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="mode-v1" v-if="hasPermission('2')">
|
||
<view class="mode-v2" @click="lasermode">
|
||
<image src="/static/images/6170/jg.png" class="setIMG" mode="aspectFit"></image>
|
||
<view>
|
||
<view class="battery-v2">激光模式</view>
|
||
<view class="mode-v3">{{ currentlaserMode }}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="mode-v1" v-if="hasPermission('3')">
|
||
<view class="mode-v2" @click="uploadStartup">
|
||
<image src="/static/images/common/path7.png" class="setIMG" mode="aspectFit"></image>
|
||
<view>
|
||
<view class="battery-v2">开机画面</view>
|
||
<view class="mode-v3">上传</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 人员信息登记 -->
|
||
<view class="form-section" v-if="hasPermission('4')">
|
||
<view class="mode-buttons">
|
||
<view class="section-title">人员信息登记</view>
|
||
<view class="right-icons">
|
||
<uni-icons @click="toggleForm" :type="isFormExpanded ? 'arrowup' : 'down'" size="20"
|
||
color="rgba(255, 255, 255, 0.87" class="toggle-icon" />
|
||
</view>
|
||
</view>
|
||
<view class="form-content" v-if="isFormExpanded">
|
||
<button class="send-btn1" @click.stop="sendPersonnelInfo">发送</button>
|
||
<view class="form-row">
|
||
<text class="form-label">单位:</text>
|
||
<input class="form-input" placeholder="请输入单位" v-model="personnelInfo.unitName"
|
||
:maxlength="15" />
|
||
</view>
|
||
<view class="form-row">
|
||
<text class="form-label">姓名:</text>
|
||
<input class="form-input" placeholder="请输入姓名" v-model="personnelInfo.name"
|
||
:maxlength="15" />
|
||
</view>
|
||
<view class="form-row">
|
||
<text class="form-label">职位:</text>
|
||
<input class="form-input" placeholder="请输入职位" v-model="personnelInfo.position"
|
||
:maxlength="15" />
|
||
</view>
|
||
<view class="form-row">
|
||
<text class="form-label">ID:</text>
|
||
<input class="form-input" placeholder="请输入ID号" v-model="personnelInfo.code"
|
||
:maxlength="15" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 人员信息登记 -->
|
||
<view class="form-section" v-if="hasPermission('5')">
|
||
<view class="mode-buttons">
|
||
<view class="section-title">发送信息</view>
|
||
<button class="send-btn" @click.stop="sendTextMessage">发送</button>
|
||
</view>
|
||
|
||
<view class="form-row">
|
||
<input class="form-input1" maxlength="20" placeholder="请输入文字" v-model="messageToSend" />
|
||
</view>
|
||
</view>
|
||
<!-- 产品信息 -->
|
||
<view v-if="hasPermission('6')">
|
||
<view class="section-title">产品信息</view>
|
||
<view class="mode-buttons">
|
||
<view class="mode_1" @click="productparams">
|
||
<image src="/static/images/common/cp.png" class="cpIMG" mode="aspectFit"></image>
|
||
<view class="">产品参数</view>
|
||
</view>
|
||
<view class="mode_1" @click="operatingInst">
|
||
<image src="/static/images/common/sm.png" class="cpIMG" mode="aspectFit"></image>
|
||
<view class="">操作说明</view>
|
||
</view>
|
||
<view class="mode_1" @click="operatingVideo">
|
||
<image src="/static/images/common/sp.png" class="cpIMG" mode="aspectFit"></image>
|
||
<view class="">操作视频</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 弹框 -->
|
||
<view class="agreement-mask" v-if="lightModeA" @click.stop="closePopup">
|
||
<!-- 灯光模式弹窗 -->
|
||
<view class="agreement-popup" @click.stop>
|
||
<!-- 标题 -->
|
||
<view class="popup-title"> {{ popupTitle }}</view>
|
||
<view class="popup-content">
|
||
<view v-for="(item, index) in items" :key="index">
|
||
<view class="item" :class="{ 'selected': item.selected }" @click="onItemClick(index)">
|
||
<image :src="item.image" class="setIMG"></image>
|
||
{{ item.text }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 按钮组 -->
|
||
<view class="popup-buttons">
|
||
<button class="agree" @click="handleSumbit">确定</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 上传开机画面弹框 -->
|
||
<view class="agreement-mask" v-if="lightModeB" @click.stop="closePopup">
|
||
<!-- 上传画面弹窗 -->
|
||
<view class="agreement-popupB" @click.stop>
|
||
<!-- 标题 -->
|
||
<view class="popup-title">上传开机画面</view>
|
||
<view class="popup-content">
|
||
<view class="example-body">
|
||
<view class="icoContent" @click="checkImgUpload">
|
||
<image v-if="selectedImage" :src="selectedImage" mode="aspectFit" class="img"
|
||
style="width: 100%; height: 100%;"></image>
|
||
<image v-else mode="aspectFit" class="img"
|
||
src="/static/images/6155/DeviceDetail/add.png"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 按钮组 -->
|
||
<view class="popup-buttons">
|
||
<button class="agree" @click="handleupload">确定</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!--===================== 激光提示框================== -->
|
||
<view class="agreement-mask" v-if="lightModeC" @click.stop="closePopup">
|
||
<!-- 上传画面弹窗 -->
|
||
<view class="agreement-popupC" @click.stop>
|
||
<!-- 标题 -->
|
||
<view class="popup-title">{{ isLaserOn ? '确认关闭激光模式?' : '确认开启激光模式?' }}</view>
|
||
<view class="popup-content">
|
||
<view class="popup-Title" v-if="!isLaserOn">
|
||
<view>注意事项</view>
|
||
<view>1.禁止直视光源或反射面!</view>
|
||
<view>2.避免直射人或易燃物!</view>
|
||
<view>3.需佩戴相应专业防护眼镜!</view>
|
||
</view>
|
||
</view>
|
||
<!-- 按钮组 -->
|
||
<view class="popup-buttons">
|
||
<button class="btn disagree" @click="handleDisagree">取消</button>
|
||
<button class="btn agreeBtn" @click.stop="handleBtn">确定</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 人员信息成功提示弹框 -->
|
||
<CustomPopup v-if="popupType === 'person'" :show="showPopupFlag" :message="popupMessage"
|
||
icon="/static/images/common/sendSucc.png" :confirm-text="popupConfirmText" :show-cancel="false"
|
||
@confirm="onPopupConfirm" />
|
||
<!-- 开机log上传成功的弹框提示 -->
|
||
<CustomPopup v-if="popupType === 'logo'" :show="showPopupFlag" :message="popupMessage"
|
||
icon="/static/images/common/upload.png" :confirm-text="popupConfirmText" :show-cancel="false"
|
||
@confirm="onPopupConfirm" />
|
||
<!--============= 电量低于提示弹框=========== -->
|
||
<CustomPopup v-if="popupType === 'bettery'" :show="showPopupFlag"
|
||
popupBorder="1rpx solid rgba(224, 52, 52, 0.3)" :message="popupMessage" title="设备电量低于20%"
|
||
titleColor="rgba(224, 52, 52, 1)" icon="/static/images/common/path.png" :confirm-text="popupConfirmText"
|
||
:show-cancel="true" @cancel="onPopupConfirm" @confirm="onPopupConfirm"
|
||
confirmBtnBg="rgba(224, 52, 52, 1)" confirmBtnColor="#fff" />
|
||
<!-- 解除报警 -->
|
||
<CustomPopup v-if="popupType === 'cancel'" :show="showPopupFlag"
|
||
popupBorder="1rpx solid rgba(224, 52, 52, 0.3)" :message="popupMessage"
|
||
icon="/static/images/6170/svg.png" :confirm-text="popupConfirmText" :show-cancel="false"
|
||
@confirm="onPopupConfirmPolice" confirmBtnBg="rgba(224, 52, 52, 1)" confirmBtnColor="#fff" />
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import MqttClient from '@/utils/mqtt.js';
|
||
import {
|
||
generateShortId
|
||
} from '@/utils/function.js';
|
||
import {
|
||
deviceDetail,
|
||
registerPersonInfo,
|
||
deviceSendMessage,
|
||
deviceShareId,
|
||
lightModeSettings, //灯光模式设置
|
||
laserModeSettings, //激光模式设置
|
||
lightBrightnessSettings, //灯光亮度设置
|
||
deviceRealTimeStatus //设备状态
|
||
} from '@/api/6170/deviceControl.js'
|
||
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,
|
||
navBarHeight: 70 + uni.getSystemInfoSync().statusBarHeight,
|
||
navTitle: "",
|
||
sliderValue: 25,
|
||
lightModeA: false,
|
||
currentMainMode: '强光',
|
||
currentlaserMode: "关闭",
|
||
lightModeB: false,
|
||
lightModeC: false, //激光提示框
|
||
items: [],
|
||
isFormExpanded: true, // 默认展开
|
||
deviceID: '',
|
||
itemInfo: {},
|
||
mqttClient: null,
|
||
messageToSend: '',
|
||
personnelInfo: {
|
||
unitName: '',
|
||
name: '',
|
||
position: '',
|
||
code: '',
|
||
},
|
||
deviceInfo: {},
|
||
activePermissions: [], // 存储当前设备的权限数组
|
||
isSharedDevice: false, // 标记是否来自分享
|
||
isRightIconVisible: false,
|
||
showPopupFlag: false, //是否显示弹框
|
||
popupMessage: '!',
|
||
popupConfirmText: '确认',
|
||
showUploadPopup: false,
|
||
selectedImage: null, // 添加这个变量来存储选择的图片
|
||
selectedItemIndex: 0,
|
||
popupType: 'person', //弹框类型
|
||
isLaserOn: false,
|
||
isSending: false,
|
||
isProcessing: false
|
||
}
|
||
},
|
||
computed: {
|
||
computedDeviceId() {
|
||
return this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId;
|
||
},
|
||
popupTitle() {
|
||
return this.modeType === 'main' ? '灯光模式' : '激光模式';
|
||
}
|
||
},
|
||
methods: {
|
||
/**
|
||
* 获取设备状态(带自动轮询)
|
||
* @param {number} val - 功能模式
|
||
* @param {string} batchId - 批次ID
|
||
* @param {number} [interval=800] - 轮询间隔(毫秒)
|
||
*/
|
||
async getdeviceSTatus(val, batchId, interval = 800) {
|
||
const checkStatus = async () => {
|
||
try {
|
||
const data = {
|
||
functionMode: val,
|
||
batchId: batchId,
|
||
typeName: this.itemInfo.typeName,
|
||
deviceImei: this.itemInfo.deviceImei
|
||
};
|
||
const res = await deviceRealTimeStatus(data);
|
||
if (res.code !== 200) {
|
||
throw new Error(res.msg || '请求失败');
|
||
}
|
||
switch (res.data.functionAccess) {
|
||
case 'OK':
|
||
return res; // 成功完成
|
||
case 'ACTIVE':
|
||
await new Promise(r => setTimeout(r, interval));
|
||
return checkStatus(); // 继续轮询
|
||
case 'FAILED':
|
||
throw new Error('设备操作失败');
|
||
case 'TIMEOUT':
|
||
throw new Error('设备响应超时');
|
||
default:
|
||
throw new Error('未知状态');
|
||
}
|
||
} catch (error) {
|
||
throw error;
|
||
}
|
||
};
|
||
return checkStatus();
|
||
},
|
||
// 点击弹框外的区域关闭
|
||
closePopup() {
|
||
this.lightModeA = false;
|
||
this.lightModeB = false;
|
||
this.lightModeC = false;
|
||
this.selectedImage = '';
|
||
this.file = null;
|
||
},
|
||
// *******定位******
|
||
gpsPosition(item) {
|
||
// 添加调试日志
|
||
uni.navigateTo({
|
||
url: '/pages/common/map/index',
|
||
events: {
|
||
ack: function(data) {}
|
||
},
|
||
success: (res) => {
|
||
res.eventChannel.emit('Map', {
|
||
data: item
|
||
});
|
||
}
|
||
})
|
||
},
|
||
|
||
// ***********进度条***********
|
||
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) {
|
||
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.computedDeviceId,
|
||
instructValue: this.sliderValue + '.00',
|
||
deviceImei: this.itemInfo.deviceImei,
|
||
}
|
||
lightBrightnessSettings(data).then((res) => {
|
||
if (res.code !== 200) {
|
||
// 可以在这里处理错误,但滑动中不建议用toast
|
||
}
|
||
})
|
||
}
|
||
},
|
||
onSliderChangeEnd(e) {
|
||
if (this.deviceInfo.onlineStatus !== 1) {
|
||
uni.showToast({
|
||
title: '设备已离线',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
let value = e.detail.value;
|
||
if (value < 10) {
|
||
value = 10;
|
||
}
|
||
this.sliderValue = value;
|
||
let data = {
|
||
deviceId: this.computedDeviceId,
|
||
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;
|
||
this.lightModeA = true;
|
||
if (type === 'main') {
|
||
this.items = [{
|
||
text: '强光',
|
||
selected: this.currentMainMode === '强光', // 修正匹配条件
|
||
image: '/static/images/6170/sett.png',
|
||
instructValue: '1'
|
||
},
|
||
{
|
||
text: '弱光',
|
||
selected: this.currentMainMode === '弱光',
|
||
image: '/static/images/6170/rg.png',
|
||
instructValue: '2'
|
||
},
|
||
{
|
||
text: '爆闪',
|
||
selected: this.currentMainMode === '爆闪',
|
||
image: '/static/images/6170/bs.png',
|
||
instructValue: '3'
|
||
},
|
||
{
|
||
text: '泛光',
|
||
selected: this.currentMainMode === '泛光',
|
||
image: '/static/images/6170/settt.png',
|
||
instructValue: '4'
|
||
},
|
||
{
|
||
text: '关闭',
|
||
selected: this.currentMainMode === '关闭',
|
||
image: '/static/images/6170/close.png',
|
||
instructValue: '0'
|
||
},
|
||
];
|
||
}
|
||
},
|
||
// 人员信息登录
|
||
toggleForm() {
|
||
this.isFormExpanded = !this.isFormExpanded;
|
||
},
|
||
onItemClick(index) {
|
||
const selectedItem = this.items[index];
|
||
if (selectedItem.text === '激光') {
|
||
this.lightModeC = true;
|
||
} else {
|
||
// 更新选中状态
|
||
this.items = this.items.map((item, i) => ({
|
||
...item,
|
||
selected: i === index
|
||
}));
|
||
this.currentMainMode = selectedItem.text;
|
||
this.selectedItemIndex = index;
|
||
// 强制更新视图(如果需要)
|
||
this.$forceUpdate();
|
||
}
|
||
},
|
||
// 灯光模式的确认
|
||
handleSumbit() {
|
||
if (this.deviceInfo.onlineStatus !== 1) {
|
||
uni.showToast({
|
||
title: '设备已离线',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
// 防重复提交
|
||
if (this.isProcessing) return;
|
||
let loadingShown = false;
|
||
uni.showLoading({
|
||
title: '处理中...',
|
||
mask: true
|
||
});
|
||
loadingShown = true;
|
||
this.isProcessing = true
|
||
if (this.selectedItemIndex === null) return;
|
||
const selectedItem = this.items[this.selectedItemIndex];
|
||
// 准备请求数据
|
||
let data = {
|
||
deviceId: this.computedDeviceId,
|
||
instructValue: selectedItem.instructValue,
|
||
deviceImei: this.itemInfo.deviceImei,
|
||
typeName: this.itemInfo.typeName,
|
||
};
|
||
lightModeSettings(data).then((res) => {
|
||
if (res.code == 200) {
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none'
|
||
})
|
||
uni.hideLoading();
|
||
this.lightModeA = false;
|
||
this.isProcessing = false
|
||
loadingShown = false
|
||
} else {
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none'
|
||
})
|
||
this.isProcessing = false
|
||
loadingShown = false
|
||
uni.hideLoading();
|
||
}
|
||
})
|
||
},
|
||
// 激光模式
|
||
lasermode() {
|
||
this.lightModeC = true
|
||
},
|
||
// 激光确认框提交
|
||
handleBtn() {
|
||
if (this.deviceInfo.onlineStatus !== 1) {
|
||
uni.showToast({
|
||
title: '设备已离线',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
// 防重复提交
|
||
if (this.isProcessing) return;
|
||
let loadingShown = false;
|
||
uni.showLoading({
|
||
title: '处理中...',
|
||
mask: true
|
||
});
|
||
loadingShown = true;
|
||
this.isProcessing = true
|
||
const instructValue = this.isLaserOn ? 0 : 1;
|
||
let data = {
|
||
deviceId: this.computedDeviceId,
|
||
instructValue: instructValue,
|
||
deviceImei: this.itemInfo.deviceImei,
|
||
typeName: this.itemInfo.typeName,
|
||
};
|
||
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;
|
||
this.isProcessing = false
|
||
loadingShown = false
|
||
} else {
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none'
|
||
});
|
||
this.isProcessing = false
|
||
loadingShown = false
|
||
}
|
||
})
|
||
},
|
||
//激光取消
|
||
handleDisagree() {
|
||
this.lightModeC = false
|
||
},
|
||
// 上传开机画面
|
||
uploadStartup() {
|
||
this.lightModeB = true
|
||
},
|
||
// 上传开机画面
|
||
checkImgUpload() {
|
||
uni.chooseImage({
|
||
count: 1,
|
||
sizeType: ['original', 'compressed'],
|
||
sourceType: ['album', 'camera'],
|
||
success: (res) => {
|
||
// 将选择的图片赋值给selectedImage
|
||
const file = res.tempFiles[0];
|
||
const fileSize = file.size || 0;
|
||
if (fileSize > 2 * 1024 * 1024) {
|
||
console.log(`文件过大: ${fileSize} 字节`); // 调试日志
|
||
uni.showToast({
|
||
title: '图片大小不能超过2MB',
|
||
icon: 'none',
|
||
duration: 3000
|
||
});
|
||
return;
|
||
}
|
||
this.selectedImage = res.tempFilePaths[0];
|
||
console.log('选择的图片:', res);
|
||
},
|
||
fail: (err) => {
|
||
uni.showToast({
|
||
title: '选择图片失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
});
|
||
},
|
||
// 上传开机画面确认按键
|
||
handleupload() {
|
||
let loadingShown = false;
|
||
if (!this.selectedImage) {
|
||
uni.showToast({
|
||
title: '请上传一张图片',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
if (this.deviceInfo.onlineStatus !== 1) {
|
||
uni.showToast({
|
||
title: '设备已离线',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
// 显示上传加载状态
|
||
uni.showLoading({
|
||
title: '图片上传中...',
|
||
mask: true
|
||
});
|
||
loadingShown = true;
|
||
uni.uploadFile({
|
||
url: baseURL + '/app/bjq/device/uploadLogo',
|
||
filePath: this.selectedImage,
|
||
name: 'file',
|
||
formData: {
|
||
deviceId: this.apiType === 'listA' ? this.deviceID : this.itemInfo.deviceId,
|
||
deviceImei: this.itemInfo.deviceImei,
|
||
typeName: this.itemInfo.typeName,
|
||
},
|
||
header: {
|
||
'Authorization': 'Bearer ' + getToken(),
|
||
'clientid': clientid(),
|
||
},
|
||
complete: async (res) => {
|
||
try {
|
||
uni.hideLoading(); // 首先关闭“
|
||
const responseData = JSON.parse(res.data);
|
||
if (responseData.code === 200) {
|
||
uni.showLoading({
|
||
title: '等待设备响应...',
|
||
mask: true
|
||
});
|
||
try {
|
||
// 获取设备状态
|
||
const statusRes = await this.getdeviceSTatus(1);
|
||
if (statusRes.data.functionAccess === 'OK') {
|
||
uni.hideLoading();
|
||
this.selectedImage = '';
|
||
this.file = null;
|
||
this.popupType = 'logo';
|
||
this.showPopupFlag = true;
|
||
this.popupMessage = '上传成功';
|
||
this.lightModeB = false;
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: error.message,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} else {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: responseData.msg,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} catch (e) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: e.message,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
}
|
||
});
|
||
},
|
||
// 分享
|
||
shareUp() {
|
||
uni.navigateTo({
|
||
url: '/pages/6170/share/index',
|
||
events: {
|
||
ack: function(data) {}
|
||
},
|
||
success: (res) => {
|
||
res.eventChannel.emit('share', {
|
||
data: this.itemInfo,
|
||
});
|
||
}
|
||
})
|
||
},
|
||
// 发送人员信息
|
||
async sendPersonnelInfo() {
|
||
if (this.isSending) return;
|
||
const requiredFields = [{
|
||
field: 'unitName',
|
||
message: '单位名称不能为空'
|
||
},
|
||
{
|
||
field: 'name',
|
||
message: '姓名不能为空'
|
||
},
|
||
{
|
||
field: 'position',
|
||
message: '职位不能为空'
|
||
},
|
||
{
|
||
field: 'code',
|
||
message: 'ID不能为空'
|
||
}
|
||
];
|
||
for (const {
|
||
field,
|
||
message
|
||
}
|
||
of requiredFields) {
|
||
if (!this.personnelInfo[field]) {
|
||
uni.showToast({
|
||
title: message,
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
}
|
||
if (this.deviceInfo.onlineStatus !== 1) {
|
||
uni.showToast({
|
||
title: '设备已离线',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
this.isSending = true;
|
||
let loadingShown = false;
|
||
try {
|
||
uni.showLoading({
|
||
title: '发送中...',
|
||
mask: true
|
||
});
|
||
loadingShown = true;
|
||
// 2. 准备请求数据
|
||
const data = {
|
||
code: this.personnelInfo.code,
|
||
name: this.personnelInfo.name,
|
||
position: this.personnelInfo.position,
|
||
unitName: this.personnelInfo.unitName,
|
||
deviceId: this.computedDeviceId,
|
||
deviceImei: this.itemInfo.deviceImei
|
||
};
|
||
const registerRes = await registerPersonInfo(data);
|
||
if (registerRes.code == 200) {
|
||
this.popupType = 'person';
|
||
this.showPopupFlag = true;
|
||
this.popupMessage = '人员信息发送成功';
|
||
} else {
|
||
uni.showToast({
|
||
title: registerRes.msg,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: error.msg,
|
||
icon: 'none'
|
||
});
|
||
} finally {
|
||
uni.hideLoading();
|
||
this.isSending = false;
|
||
}
|
||
},
|
||
// 所有弹框,确定关闭按钮
|
||
onPopupConfirm() {
|
||
this.showPopupFlag = false
|
||
},
|
||
// 强制报警()
|
||
handlePolice() {
|
||
this.popupType = 'cancel';
|
||
this.popupMessage = '确认要解除所选设备的报警状态';
|
||
this.showPopupFlag = true;
|
||
},
|
||
// 解除报警逻辑
|
||
async onPopupConfirmPolice() {
|
||
if (this.deviceInfo.onlineStatus !== 1) {
|
||
uni.showToast({
|
||
title: '设备已离线',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
try {
|
||
uni.showLoading({
|
||
title: '解除告警中...',
|
||
mask: true
|
||
});
|
||
// 2. 准备请求数据
|
||
const batchId = generateShortId();
|
||
const data = {
|
||
deviceIds: [this.computedDeviceId],
|
||
batchId: batchId,
|
||
typeName: this.itemInfo.typeName,
|
||
deviceImeiList: [this.itemInfo.deviceImei],
|
||
instructValue: 0, // '解除报警'
|
||
};
|
||
// 3.解除告警状态
|
||
const registerRes = await deviceSendAlarmMessage(data);
|
||
if (registerRes.code == 200) {
|
||
uni.showToast({
|
||
title: statusRes.msg,
|
||
icon: 'none'
|
||
});
|
||
// 刷新详情接口
|
||
this.fetchDeviceDetail(this.computedDeviceId, true);
|
||
uni.$emit('deviceStatusUpdate', {});
|
||
this.showPopupFlag = false
|
||
} else {
|
||
uni.showToast({
|
||
title: registerRes.message,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: error.message,
|
||
icon: 'none'
|
||
});
|
||
} finally {
|
||
uni.hideLoading();
|
||
}
|
||
},
|
||
// 发送文本消息
|
||
async sendTextMessage() {
|
||
if (this.deviceInfo.onlineStatus !== 1) {
|
||
uni.showToast({
|
||
title: '设备已离线',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
// 防重复提交
|
||
if (this.isSending) return;
|
||
if (!this.messageToSend) {
|
||
uni.showToast({
|
||
title: '请输入要发送的文字',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
this.isSending = true;
|
||
let loadingShown = false;
|
||
try {
|
||
uni.showLoading({
|
||
title: '正在发送...',
|
||
mask: true
|
||
});
|
||
loadingShown = true;
|
||
// 2. 准备请求数据
|
||
const batchId = generateShortId();
|
||
const data = {
|
||
sendMsg: this.messageToSend,
|
||
deviceIds: [this.computedDeviceId],
|
||
typeName: this.itemInfo.typeName,
|
||
batchId: batchId,
|
||
deviceImeiList: [this.itemInfo.deviceImei]
|
||
};
|
||
// 3.人员信息
|
||
const registerRes = await deviceSendMessage(data);
|
||
if (registerRes.code !== 200) {
|
||
uni.showToast({
|
||
title: registerRes.msg,
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
// 轮询获取状态(重要:这里必须await)
|
||
const statusRes = await this.getdeviceSTatus(2, batchId);
|
||
// 只有当状态为'OK'时才显示成功弹窗
|
||
if (statusRes.data.functionAccess === 'OK') {
|
||
this.popupType = 'person';
|
||
this.showPopupFlag = true;
|
||
this.popupMessage = '信息发送成功';
|
||
}
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: error.message,
|
||
icon: 'none'
|
||
});
|
||
} finally {
|
||
console.log('失败还是成功了');
|
||
uni.hideLoading();
|
||
this.isSending = false;
|
||
}
|
||
},
|
||
// 统一处理返回方法
|
||
handleDeviceData(res, isFromShared = false, isUpdate = false) {
|
||
if (res.code == 200) {
|
||
// 最后关闭加载状态
|
||
this.pageLoading = false
|
||
this.deviceInfo = res.data
|
||
|
||
if (!isUpdate) {
|
||
this.personnelInfo = {
|
||
unitName: res.data.personnelInfo.unitName || '',
|
||
name: res.data.personnelInfo.name || '',
|
||
code: res.data.personnelInfo.code || '',
|
||
position: res.data.personnelInfo.position || '',
|
||
};
|
||
this.messageToSend = res.data.sendMsg || '';
|
||
this.sliderValue = res.data.lightBrightness || '25'
|
||
let mainLightMode = parseInt(res.data.mainLightMode);
|
||
// 取主灯光模式初始值
|
||
this.currentMainMode = this.getMainLightModeLabel(mainLightMode)
|
||
console.log(this.currentMainMode, 'this.currentMainMode');
|
||
const laserMode = res.data.LaserLightMode;
|
||
this.isLaserOn = laserMode === 1;
|
||
this.currentlaserMode = this.isLaserOn ? "开启" : "关闭";
|
||
}
|
||
// 将权限字符串转换为数组 ["1", "2"]
|
||
if (isFromShared) {
|
||
this.isSharedDevice = true;
|
||
this.activePermissions = res.data.permission ? res.data.permission.split(',') : [];
|
||
} else {
|
||
this.isSharedDevice = false;
|
||
this.activePermissions = []; // 非分享设备清空权限
|
||
}
|
||
|
||
// 关闭加载中
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
// 检查权限的方法
|
||
hasPermission(permissionCode) {
|
||
// 如果还在加载中,直接返回false
|
||
if (this.pageLoading) return false
|
||
// 如果不是分享设备,默认有全部权限
|
||
if (!this.isSharedDevice) return true
|
||
return this.activePermissions.includes(permissionCode)
|
||
},
|
||
// 获取设备详情(普通详情)
|
||
async fetchDeviceDetail(id, isUpdate = false) {
|
||
try {
|
||
const res = await deviceDetail(id)
|
||
if(res.code==200){
|
||
this.handleDeviceData(res, false, isUpdate)
|
||
}else{
|
||
uni.showToast({
|
||
title: error.msg,
|
||
icon: 'none'
|
||
})
|
||
uni.hideLoading()
|
||
}
|
||
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
// uni.showToast({
|
||
// title: error.msg,
|
||
// icon: 'none'
|
||
// })
|
||
}
|
||
},
|
||
// 获取分享设备详情
|
||
async fetchSharedDeviceDetail(id) {
|
||
try {
|
||
const res = await deviceShareId(id)
|
||
if(res.code==200){
|
||
this.handleDeviceData(res, true)
|
||
}else{
|
||
uni.showToast({
|
||
title: error.msg,
|
||
icon: 'none'
|
||
})
|
||
}
|
||
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: error.msg,
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
// 操作说明
|
||
operatingInst() {
|
||
let id = this.computedDeviceId
|
||
uni.navigateTo({
|
||
url: `/pages/common/operatingInstruct/index?id=${id}`
|
||
})
|
||
},
|
||
// 产品参数
|
||
productparams() {
|
||
let id = this.computedDeviceId
|
||
uni.navigateTo({
|
||
url: `/pages/common/productDes/index?id=${id}`
|
||
})
|
||
},
|
||
// 操作视频
|
||
operatingVideo() {
|
||
let id = this.computedDeviceId
|
||
uni.navigateTo({
|
||
url: `/pages/common/operationVideo/index?id=${id}`
|
||
})
|
||
},
|
||
// 发送mqtt查询设备信息
|
||
queryDeviceStatus() {
|
||
if (this.mqttClient && this.mqttClient.isConnected()) {
|
||
const topic = `B/${this.itemInfo.deviceImei}`;
|
||
const message = '{"instruct":[12,0,0,0,0]}';
|
||
this.mqttClient.publish(topic, message, {
|
||
qos: 1
|
||
});
|
||
} else {
|
||
console.log('MQTT not connected, cannot query status.');
|
||
}
|
||
},
|
||
// 灯光模式共用封装共其他地方使用
|
||
getMainLightModeLabel(mode) {
|
||
const modeMap = {
|
||
0: '关闭',
|
||
1: '强光',
|
||
2: '弱光',
|
||
3: '爆闪',
|
||
4: '泛光'
|
||
}
|
||
return modeMap[mode] || (console.log('未知的灯光模式:', mode), '未知');
|
||
}
|
||
|
||
},
|
||
onLoad(options) {
|
||
const eventChannel = this.getOpenerEventChannel();
|
||
// 监听 'detailData' 事件,获取传过来的数据
|
||
uni.showLoading({
|
||
title: '加载中...'
|
||
})
|
||
eventChannel.on('detailData', (data) => {
|
||
console.log(data, 'data');
|
||
this.itemInfo = data.data;
|
||
this.deviceID = data.data.id;
|
||
this.navTitle = data.data.deviceName;
|
||
this.apiType = data.apiType
|
||
// 根据 apiType 设置右图标的显示状态
|
||
this.isRightIconVisible = this.apiType === 'listA';
|
||
// 初始化并连接MQTT
|
||
this.mqttClient = new MqttClient();
|
||
this.mqttClient.connect(() => {
|
||
// 订阅来自设备的状态更新
|
||
const statusTopic = `A/${this.itemInfo.deviceImei}`;
|
||
this.mqttClient.subscribe(statusTopic, (payload) => {
|
||
try {
|
||
console.log(`收到来自 ${statusTopic} 的消息:`, payload);
|
||
const parsedMessage = typeof payload === 'string' ? JSON.parse(
|
||
payload) :
|
||
payload;
|
||
const deviceState = parsedMessage.state; // 直接取 state 数组
|
||
// 切换主灯光模式,亮度值设备同步
|
||
if (!deviceState) return;
|
||
// 1设备切换灯光实时返回
|
||
switch (deviceState[0]) {
|
||
case 1:
|
||
this.currentMainMode = this.getMainLightModeLabel(deviceState[
|
||
1]);
|
||
this.sliderValue = deviceState[2];
|
||
this.deviceInfo.batteryRemainingTime = deviceState[3];
|
||
break;
|
||
// 12为设备实时上报
|
||
case 12:
|
||
this.currentMainMode = this.getMainLightModeLabel(deviceState[
|
||
1]);
|
||
this.isLaserOn = deviceState[2] === 1;
|
||
this.currentlaserMode = this.isLaserOn ? "开启" : "关闭";
|
||
if (this.deviceInfo) {
|
||
this.deviceInfo.batteryPercentage = deviceState[3];
|
||
this.deviceInfo.chargeState = deviceState[4];
|
||
this.deviceInfo.batteryRemainingTime = deviceState[5];
|
||
}
|
||
setTimeout(() => {
|
||
this.fetchDeviceDetail(data.data.id, true).then(
|
||
() => {
|
||
if (this.deviceInfo.batteryPercentage <
|
||
20) {
|
||
this.popupType = 'bettery';
|
||
this.popupMessage = '请及时充电';
|
||
this.showPopupFlag = true;
|
||
}
|
||
});
|
||
}, 10000);
|
||
// 上报电量,在列表里面同步
|
||
uni.$emit('deviceStatusUpdate', {
|
||
message: parsedMessage,
|
||
timestamp: new Date().getTime()
|
||
});
|
||
break;
|
||
default:
|
||
console.log('未知的 deviceState 类型:', deviceState[0]);
|
||
}
|
||
} catch (error) {
|
||
console.log('解析MQTT消息失败:', error, '原始消息:', payload);
|
||
}
|
||
});
|
||
// mqtt连接成功后,上报一次设备状态
|
||
this.queryDeviceStatus();
|
||
})
|
||
if (this.apiType === 'listA') {
|
||
this.fetchDeviceDetail(data.data.id)
|
||
} else {
|
||
// 查分享权限详情
|
||
this.fetchSharedDeviceDetail(data.data.id)
|
||
}
|
||
|
||
});
|
||
eventChannel.emit('ack', {
|
||
|
||
})
|
||
|
||
},
|
||
onUnload() {
|
||
// 页面卸载时断开MQTT连接
|
||
if (this.mqttClient) {
|
||
this.mqttClient.disconnect();
|
||
}
|
||
},
|
||
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page-loading-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: #121212;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 9999;
|
||
}
|
||
|
||
/* 优化权限控制区域的显示 */
|
||
.mode-section,
|
||
.form-section {
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.device-detail-container {
|
||
padding: 30rpx;
|
||
background: #121212;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.status-bar {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.time {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.battery {
|
||
font-size: 36rpx;
|
||
}
|
||
|
||
.battery-section {
|
||
background-color: rgb(26, 26, 26);
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 20rpx;
|
||
align-items: center;
|
||
}
|
||
|
||
.battery-info,
|
||
.duration {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.bipImg {
|
||
width: 204rpx;
|
||
height: 144rpx;
|
||
margin-top: 30rpx;
|
||
}
|
||
|
||
.dlIMG {
|
||
width: 52rpx;
|
||
height: 52rpx;
|
||
}
|
||
|
||
.chargeStateIMG {
|
||
width: 27rpx;
|
||
height: 37rpx;
|
||
margin-left: 10rpx;
|
||
}
|
||
|
||
.cpIMG {
|
||
width: 66rpx;
|
||
height: 66rpx;
|
||
}
|
||
|
||
.battery-sectionLeft {
|
||
width: 308rpx;
|
||
height: 220rpx;
|
||
background: rgba(42, 42, 42, 0.5);
|
||
border-radius: 16rpx;
|
||
text-align: center;
|
||
align-items: center;
|
||
line-height: 220rpx;
|
||
}
|
||
|
||
.percentage {
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
color: #007AFF;
|
||
}
|
||
|
||
.label {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
margin-top: 10rpx;
|
||
}
|
||
|
||
.battery-v1 {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
|
||
.battery-v2 {
|
||
color: rgba(255, 255, 255, 0.87);
|
||
margin-left: 18rpx;
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.battery-v3 {
|
||
color: rgba(255, 255, 255, 0.6);
|
||
margin-left: 25rpx;
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.mode-v3 {
|
||
color: rgba(255, 255, 255, 0.6);
|
||
font-size: 26rpx;
|
||
padding-top: 10rpx;
|
||
}
|
||
|
||
.info-card {
|
||
background-color: rgb(26, 26, 26);
|
||
border-radius: 16rpx;
|
||
padding: 10rpx 20rpx 5rpx 20rpx;
|
||
margin-bottom: 20rpx;
|
||
|
||
}
|
||
|
||
.info-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.info-label {
|
||
font-size: 28rpx;
|
||
color: rgba(255, 255, 255, 0.87);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.info-value {
|
||
font-size: 28rpx;
|
||
color: rgba(255, 255, 255, 0.87);
|
||
}
|
||
|
||
.status-running {
|
||
color: rgba(255, 255, 255, 0.6);
|
||
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;
|
||
margin-bottom: 20rpx;
|
||
position: relative;
|
||
}
|
||
|
||
.light {
|
||
position: absolute;
|
||
/* top:10rpx; */
|
||
color: rgba(74, 74, 74, 0.87);
|
||
top: 58rpx;
|
||
left: 108rpx
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
margin-bottom: 20rpx;
|
||
display: block;
|
||
color: rgba(255, 255, 255, 0.87);
|
||
}
|
||
|
||
.slider-container {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.slider {
|
||
flex: 1;
|
||
margin: 0 20rpx;
|
||
}
|
||
|
||
.mode-buttons {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.mode_1 {
|
||
width: 180rpx;
|
||
height: 180rpx;
|
||
border-radius: 16rpx;
|
||
background: rgb(26, 26, 26);
|
||
align-items: center;
|
||
text-align: center;
|
||
color: rgba(255, 255, 255, 0.6);
|
||
padding-top: 37rpx;
|
||
}
|
||
|
||
.mode-v1 {
|
||
background: #1A1A1A;
|
||
border-radius: 18rpx;
|
||
height: 150rpx;
|
||
margin-bottom: 20rpx;
|
||
width: 47%;
|
||
display: flex;
|
||
text-align: center;
|
||
}
|
||
|
||
.mode-v2 {
|
||
display: flex;
|
||
align-items: center;
|
||
text-align: center;
|
||
margin-left: 40rpx;
|
||
|
||
}
|
||
|
||
.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%;
|
||
top: 65%;
|
||
width: 100%;
|
||
transform: translate(-20%, -100%);
|
||
}
|
||
|
||
.icoContent {
|
||
width: 320rpx;
|
||
height: 160rpx;
|
||
border-radius: 8rpx;
|
||
background: rgba(58, 58, 58, 1);
|
||
text-align: center;
|
||
line-height: 200rpx;
|
||
}
|
||
|
||
.img {
|
||
width: 62rpx;
|
||
height: 62rpx;
|
||
}
|
||
|
||
.example_title {
|
||
color: rgba(255, 255, 255, 0.87);
|
||
}
|
||
|
||
.mode-btn {
|
||
width: 48%;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
background-color: #f5f5f5;
|
||
color: #333;
|
||
border-radius: 8rpx;
|
||
font-size: 28rpx;
|
||
border: none;
|
||
}
|
||
|
||
.mode-btn.active {
|
||
background-color: #007AFF;
|
||
color: #fff;
|
||
}
|
||
|
||
.form-section {
|
||
background-color: rgb(26, 26, 26);
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 30rpx;
|
||
|
||
}
|
||
|
||
.form-row {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
background: rgba(42, 42, 42, 1);
|
||
border-radius: 16rpx;
|
||
padding-left: 20rpx;
|
||
}
|
||
|
||
.form-label {
|
||
font-size: 32rpx;
|
||
color: rgba(255, 255, 255, 0.87);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.form-input {
|
||
height: 80rpx;
|
||
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 {
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 30rpx;
|
||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.product-tabs {
|
||
display: flex;
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.tab {
|
||
padding: 15rpx 30rpx;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
border-bottom: 4rpx solid transparent;
|
||
}
|
||
|
||
.tab.active {
|
||
color: #007AFF;
|
||
border-bottom-color: #007AFF;
|
||
}
|
||
|
||
.action-buttons {
|
||
padding: 30rpx 0;
|
||
}
|
||
|
||
.send-btn {
|
||
background-color: rgb(187, 230, 0);
|
||
color: rgba(35, 35, 35, 0.87);
|
||
height: 50rpx;
|
||
line-height: 50rpx;
|
||
border-radius: 16rpx;
|
||
font-size: 26rpx;
|
||
width: 112rpx;
|
||
white-space: nowrap;
|
||
text-align: center;
|
||
position: absolute;
|
||
right: 70rpx;
|
||
|
||
}
|
||
|
||
.send-btn1 {
|
||
background-color: rgb(187, 230, 0);
|
||
color: rgba(35, 35, 35, 0.87);
|
||
height: 50rpx;
|
||
line-height: 50rpx;
|
||
border-radius: 16rpx;
|
||
font-size: 26rpx;
|
||
width: 112rpx;
|
||
white-space: nowrap;
|
||
text-align: center;
|
||
position: absolute;
|
||
right: 0rpx;
|
||
top: -70rpx
|
||
}
|
||
|
||
|
||
/* 遮罩层 */
|
||
.agreement-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 9999;
|
||
}
|
||
|
||
/* 弹窗主体 */
|
||
.agreement-popup {
|
||
width: 100%;
|
||
height: 50%;
|
||
background-color: rgb(42, 42, 42);
|
||
border-radius: 60rpx 60rpx 0rpx 0rpx;
|
||
padding: 40rpx;
|
||
box-sizing: border-box;
|
||
position: absolute;
|
||
bottom: 0rpx;
|
||
}
|
||
|
||
.agreement-popupB {
|
||
width: 100%;
|
||
height: 32%;
|
||
background-color: rgb(42, 42, 42);
|
||
border-radius: 60rpx 60rpx 0rpx 0rpx;
|
||
padding: 40rpx;
|
||
box-sizing: border-box;
|
||
position: absolute;
|
||
bottom: 0rpx;
|
||
}
|
||
|
||
.agreement-popupC {
|
||
width: 80%;
|
||
background-color: rgb(42, 42, 42);
|
||
border-radius: 40rpx;
|
||
padding: 40rpx;
|
||
box-sizing: border-box;
|
||
border: 1px solid rgba(255, 200, 78, 1);
|
||
}
|
||
|
||
.popup-Title {
|
||
color: rgba(255, 200, 78, 1);
|
||
}
|
||
|
||
/* 标题 */
|
||
.popup-title {
|
||
font-size: 36rpx;
|
||
text-align: center;
|
||
margin-bottom: 30rpx;
|
||
color: rgba(255, 255, 255, 0.87);
|
||
}
|
||
|
||
/* 内容文本 */
|
||
.popup-content {
|
||
font-size: 30rpx;
|
||
line-height: 1.6;
|
||
color: rgba(255, 255, 255, 0.87);
|
||
margin-bottom: 50rpx;
|
||
}
|
||
|
||
.item {
|
||
padding: 10px;
|
||
margin: 5px 0;
|
||
display: flex;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
.setIMG {
|
||
width: 24px;
|
||
height: 24px;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.item.selected {
|
||
background-color: rgb(58, 58, 58);
|
||
color: rgba(255, 255, 255, 0.87);
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
/* 按钮容器 */
|
||
.popup-buttons {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
/*确定按钮 */
|
||
.agree {
|
||
background-color: rgb(187, 230, 0);
|
||
color: #232323;
|
||
border: none;
|
||
font-size: 24rpx;
|
||
height: 88rpx;
|
||
line-height: 88rpx;
|
||
font-size: 32rpx;
|
||
width: 100%;
|
||
position: absolute;
|
||
bottom: 0rpx;
|
||
left: 0rpx
|
||
}
|
||
|
||
/* 通用按钮样式 */
|
||
.btn {
|
||
flex: 1;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
border-radius: 40rpx;
|
||
font-size: 32rpx;
|
||
margin: 0 20rpx;
|
||
}
|
||
|
||
/* 不同意按钮 */
|
||
.disagree {
|
||
background-color: transparent;
|
||
color: rgba(255, 255, 255, 0.87);
|
||
border: 1px solid rgba(255, 200, 78, 0.7);
|
||
font-size: 24rpx;
|
||
color: rgba(255, 200, 78, 1);
|
||
}
|
||
|
||
/* 同意按钮 */
|
||
.agreeBtn {
|
||
background-color: rgba(255, 200, 78, 1);
|
||
color: #232323;
|
||
border: none;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.right-icons {
|
||
/* display: flex; */
|
||
align-items: center;
|
||
}
|
||
|
||
.toggle-icon {
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
margin-top: -40rpx;
|
||
}
|
||
|
||
.icon {
|
||
font-size: 14px;
|
||
color: #fff;
|
||
}
|
||
|
||
.form-content {
|
||
transition: all 0.3s ease;
|
||
margin-top: 60rpx;
|
||
position: relative;
|
||
}
|
||
</style> |