totustec-unipp/pages/deviceManage/index.vue
2025-07-20 21:46:42 +08:00

1107 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="contai_warp">
<view class="top_area_warp">
<view class="top_status_area" :style="{ height: statusBarHeight + 'px' }"></view>
<view class="top_nav_warp">
<view>设备管理</view>
<view class="back_button_warp" @click="goBack()">
<image class="back_button_icon" src="https://online.totustec.com/upload/minePage/mine_area_right.png"></image>
</view>
</view>
</view>
<view class="content_area_warp">
<view class="content_warp">
<!-- 视频图片 -->
<view class="select_device_warp">
<view class="modal_warp">
<view class="select_device_item" :class="{ device_active: getType == 'video' }"
@click="getVideoImg('video')">
获取视频
</view>
<view class="select_device_item" :class="{ device_active: getType == 'img' }" @click="getVideoImg('img')">
获取图片
</view>
</view>
</view>
<!-- 视频图片区域含加载动画 -->
<view class="media_container">
<!-- 加载动画转圈效果 -->
<view class="loading_spinner" v-if="isMediaLoading">
<view class="spinner"></view>
</view>
<!-- 媒体内容 -->
<video class="img_video_warp" :src="socketData.videoUrl" v-if="socketData.videoUrl"
@loadedmetadata="isMediaLoading = false" @error="isMediaLoading = false"></video>
<image class="img_video_warp" v-else :src="socketData.imageUrl" @load="isMediaLoading = false"
@error="isMediaLoading = false"></image>
</view>
<!-- 设备状态选择 -->
<view class="select_device_warp">
<view class="modal_warp">
<view class="select_device_item device_model" :class="{ device_active: deviceType == 1 }"
@click="deviceType = 1">设备状态
</view>
<view class="select_device_item device_model" :class="{ device_active: deviceType == 2 }"
@click="deviceType = 2">设备日志
</view>
<view class="select_device_item device_model" :class="{ device_active: deviceType == 3 }"
@click="deviceType = 3">设备控制
</view>
</view>
</view>
<!-- 设备状态 -->
<view class="device_status_warp" v-if="deviceType == 1">
<view class="device_status_item" v-for="(field, idx) in statusFields" :key="idx">
<view class="statusItem_modal_warp">
<view class="item_content_warp">
<view class="item_content_left">{{ field.label }}</view>
<view class="item_content_middel">
<!-- 状态处理 完成-->
<template v-if="field.isStatus">
<view class="label_warp" v-if="deviceDetail.status == 0">
<view class="label_icon"></view>
<view class="label_text">空闲</view>
</view>
<view class="label_warp" v-if="deviceDetail.status == 1">
<view class="label_icon" style="background: #00d195"></view>
<view class="label_text" style="color: #00d195">打印中</view>
</view>
<view class="label_warp" v-if="deviceDetail.status == 2">
<view class="label_icon" style="background: #00abff"></view>
<view class="label_text" style="color: #00abff">准备中</view>
</view>
<view class="label_warp" v-if="deviceDetail.status == 3">
<view class="label_icon" style="background: #fdcb3b"></view>
<view class="label_text" style="color: #fdcb3b">铲件中</view>
</view>
<view class="label_warp" v-if="deviceDetail.status == -1">
<view class="label_icon" style="background: #999999"></view>
<view class="label_text" style="color: #999999">断开</view>
</view>
</template>
<!-- 子状态处理 -->
<template v-else-if="field.isErrorStatus">
<view class="label_warp2">
<view class="label_icon" :style="{ background: getStatusColor(printInfo.status) }"></view>
<view class="label_text label_text2" :style="{ color: getStatusColor(printInfo.status) }">
{{ getStatusText2(printInfo.status) }}
</view>
</view>
</template>
<!-- 错误码处理 -->
<template v-else-if="field.isErrorCode">
{{ deviceDetail.errorStatus === -1 ? '断开' : getStatusText(deviceDetail.errorStatus) }}
</template>
<!-- 当前时间特殊处理 -->
<template v-else-if="field.isCurrentTime">
{{ getCurrentTime() }}
</template>
<template v-else>
{{ deviceDetail[field.key] }}
</template>
</view>
</view>
<view class="itemContent_line_warp">
<view class="item_content_model">
<view class="item_content_line"></view>
</view>
</view>
</view>
</view>
<!-- 打印详情 -->
<view class="device_status_item" v-for="(field, idx) in statusTwoFields" :key="idx">
<view class="statusItem_modal_warp">
<view class="item_content_warp">
<view class="item_content_left">{{ field.label }}</view>
<view class="item_content_middel">
{{ printInfo[field.key] }}
</view>
</view>
<view class="itemContent_line_warp">
<view class="item_content_model">
<view class="item_content_line"></view>
</view>
</view>
</view>
</view>
</view>
<view class="device_status_warp" v-if="deviceType == 2">
<view class="empty_state_warp">
<image class="empty_state_icon"
src="https://online.totustec.com/upload/deviceManage/empty_log_icon.png"></image>
<view class="empty_state_title">暂无日志数据</view>
<!-- <view class="empty_state_desc">设备运行日志将在这里显示</view> -->
</view>
</view>
<!-- 设备控制 -->
<view class="device_control_warp" v-if="deviceType == 3">
<view class="deviceN_input_warp">
<view class="device_name_txt"> 打印文件名称:</view>
<view class="deviceN_input_area">
<input class="deviceN_input" type="text" v-model="deviceName" @input="onDeviceNameInput"/>
<view class="clear_deviceN_warp">
<image class="clear_deviceN_icon" @click="deviceName = ''" v-if="deviceName"
src="https://online.totustec.com/upload/deviceManage/clear_deviceN_icon.png">
</image>
</view>
</view>
</view>
<view class="deviceN_input_tip">文件位置桌面File文件夹内</view>
<view class="device_operation_warp">
<!--只有主状态等于0时候开始打印才能点击其他都不能点击-->
<view class="device_operation_btn"
@click="operationData('PRINT')"
:style="{backgroundColor:deviceDetail.status === 0? '#ffffff':'#cccccc'}
">
<image class="operation_btn_icon"
src="https://online.totustec.com/upload/deviceManage/print_status1.png"></image>
<view class="operation_btn_txt"
:style="{
color:deviceDetail.status === 0 ?'#333333':'#ece8e8' ,}"
>开始打印</view>
</view>
<!--继续打印-->
<view class="device_operation_btn"
@click="operationData('CONTINUE')"
:style="{backgroundColor:deviceDetail.status === 0 || printInfo.status !== 6? '#cccccc': '#ffffff'}"
>
<image class="operation_btn_icon" src="https://online.totustec.com/upload/deviceManage/print_status1.png">
</image>
<view class="operation_btn_txt"
:style="{color:deviceDetail.status === 0 || printInfo.status !== 6? '#ece8e8': '#333333'}"
>继续打印</view>
</view>
</view>
<!--暂停打印 退出打印-->
<view class="device_operation_warp">
<view class="device_operation_btn" @click="operationData('PAUSE')" :style="{
backgroundColor:printInfo.status !== 6 && deviceDetail.status !==0
? '#ffffff'
: '#cccccc',
}">
<image class="operation_btn_icon" src="https://online.totustec.com/upload/deviceManage/print_status1.png">
</image>
<view class="operation_btn_txt" :style="{
color:
printInfo.status !== 6 && deviceDetail.status !==0
? '#333333':'#ece8e8',
}"
>暂停打印</view>
</view>
<view class="device_operation_btn" @click="operationData('EXIT')" :style="{
backgroundColor:
deviceDetail.status != 0 && deviceDetail.status != -1 ? '#ffffff' : '#cccccc',
}">
<image class="operation_btn_icon" src="https://online.totustec.com/upload/deviceManage/print_status1.png">
</image>
<view class="operation_btn_txt"
:style="{
color: deviceDetail.status != 0 && deviceDetail.status != -1 ?'#333333': '#ece8e8',
}"
>退出打印</view>
</view>
</view>
<!-- 报警继续 报警退出-->
<view class="device_operation_warp">
<view class="device_operation_btn" @click="sendWsCommand('ALARM_CONTINUE')">
<image class="operation_btn_icon" src="https://online.totustec.com/upload/deviceManage/print_status2.png">
</image>
<view class="operation_btn_txt">报警继续</view>
</view>
<view class="device_operation_btn" @click="sendWsCommand('ALARM_EXIT')">
<image class="operation_btn_icon" src="https://online.totustec.com/upload/deviceManage/print_status2.png">
</image>
<view class="operation_btn_txt">报警退出</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
BASE_STOKECT_URL, BASE_IMG_URL, BASE_API_URL
} from "@/config.js";
export default {
data() {
return {
isMediaLoading: false,
deviceName: "",
title: "Hello",
statusBarHeight: 0,
getType: "video",
deviceType: 3,
deviceCode: "", // 存储接收到的设备编码
deviceDetail: {}, // 存储设备详情数据
printInfo: {},//存储设备二级详情数据
// 子状态
childStatusMap: {
0: {
text: "空闲",
color: "#00d195"
},
1: {
text: "归零中",
color: "#00d195"
},
2: {
text: "下降中",
color: "#00d195"
},
3: {
text: "曝光中",
color: "#00d195"
},
4: {
text: "抬升中",
color: "#00d195"
},
5: {
text: "正在执行暂停动作中",
color: "#00d195"
},
6: {
text: "已暂停",
color: "#00d195"
},
7: {
text: "正在执行停止动作中",
color: "#00d195"
},
8: {
text: "已停止",
color: "#00d195"
},
9: {
text: "打印完成",
color: "#00d195"
},
10: {
text: "文件检测中",
color: "#00d195"
},
11: {
text: "加液中",
color: "#00d195"
},
12: {
text: "铲件中",
color: "#00d195"
},
},
statusMap: {
0: {
text: "正常",
color: "#00d195"
}, // 绿色
1: {
text: "文件校验失败",
color: "#ff0000"
}, // 红色
2: {
text: "设备或加密错误",
color: "#ff0000"
},
3: {
text: "打印准备过程出错",
color: "#ff0000"
}, // 橙色
4: {
text: "打印出错",
color: "#ff0000"
},
5: {
text: "加液失败",
color: "#ff9800"
},
6: {
text: "铲件失败",
color: "#ff9800"
},
7: {
text: "图片异物",
color: "#ff0000"
},
},
statusFields: [
{
label: '设备名称',
key: 'brand'
},
{
label: '状态',
key: 'status',
isStatus: true
},
{
label: '子状态',
key: 'errorStatus',
isErrorStatus: true
},
{
label: '错误码',
key: 'errorStatus',
isErrorCode: true,
},
{
label: '当前时间',
key: 'currentTime',
isCurrentTime: true
}
],
statusTwoFields: [
{
label: '当前打印层数',
key: 'currentLayer'
},
{
label: '打印任务总层数',
key: 'totalLayer'
},
{
label: '已打印时间(s)',
key: 'currentTicks'
},
{
label: '总打印时间(s)',
key: 'totalTicks'
},
{
label: '打印文件名称',
key: 'filename'
},
{
label: '当前任务数量',
key: 'task'
},
{
label: '总共任务数量',
key: 'total'
},
],
// WebSocket 相关状态
socketTask: null, // uni-app 的 WebSocket 任务实例
isSocketConnected: false, // 连接状态
reconnectTimer: null, // 重连定时器
reconnectInterval: 5000, // 重连间隔5秒
socketData: {},
};
},
onLoad(options) {
const systemInfo = wx.getSystemInfoSync();
const {
statusBarHeight, // 状态栏高度单位px
} = systemInfo;
this.statusBarHeight = statusBarHeight;
this.deviceCode = options.deviceCode || "";
console.log("接收到的设备编码:", this.deviceCode);
// 立即根据设备编码获取详情数据
if (this.deviceCode) {
this.getDeviceDetail();
}
this.connectWebSocket(); // 初始化 WebSocket 连接
},
onUnload() {
this.closeWebSocket(); // 页面卸载时关闭连接
},
methods: {
// ---------------------- WebSocket 核心方法 ----------------------
connectWebSocket() {
const wsUrl = BASE_STOKECT_URL;
// 初始化 WebSocket 连接(使用 uni-app 接口)
this.socketTask = uni.connectSocket({
url: wsUrl,
success: () => {
console.log("WebSocket 连接成功");
this.isSocketConnected = true;
this.listenSocketMessage(); // 监听消息
},
fail: (err) => {
console.error("连接失败:", err);
this.tryReconnect(); // 尝试重连
},
});
},
listenSocketMessage() {
// 监听 WebSocket 消息
uni.onSocketMessage((event) => {
console.log("event", event);
const message = JSON.parse(event.data);
this.getDeviceDetail();
this.updateDeviceStatus(message); // 更新设备状态
});
},
closeWebSocket() {
// 关闭连接并清理资源
if (this.socketTask) {
uni.closeSocket();
this.socketTask = null;
this.isSocketConnected = false;
}
clearTimeout(this.reconnectTimer);
},
tryReconnect() {
// 自动重连机制
clearTimeout(this.reconnectTimer);
this.reconnectTimer = setTimeout(() => {
console.log("尝试重连 WebSocket...");
this.connectWebSocket();
}, this.reconnectInterval);
},
updateDeviceStatus(message) {
console.log("实时消息", message);
// CLOSE、STATUS 你那就刷新接口就行
if (message.msgType == "CLOSE" || message.msgType == "STATUS") {
this.getDeviceDetail();
}
// ERROR 抛出异常信息
if (message.msgType == "ERROR") {
uni.showToast({
title: message.msg,
icon: "none"
});
}
// INFO 返回视频/图片地址
if (message.msgType == "INFO") {
this.isMediaLoading = true;
this.socketData = message.data;
if (this.socketData.imageUrl) {
this.socketData.imageUrl =
BASE_IMG_URL + message.data.imageUrl;
}
}
// WRITEIMG 接收图片数据中
if (message.msgType == "WRITEIMG") {
if (message.data.chunkIndex == message.data.totalChunks) {
// 微信图片小区域转圈圈加载
} else {
// 关闭加载
}
}
},
/**
* 发送 WebSocket 指令
* @param {string} command - 指令值(如 PAUSE、CONTINUE 等)
*/
sendWsCommand(command) {
if (!this.isSocketConnected) {
console.warn("WebSocket 未连接,无法发送指令");
return;
}
// 确保 deviceCode 存在(从 URL 参数获取)
if (!this.deviceCode) {
console.error("设备编号未获取,无法发送指令");
return;
}
const message = {
Topic: `sdcp/request/${this.deviceCode}`, // 替换 MainboardID 为 deviceCode
command: command,
};
if (command == "PRINT") {
message.filename = this.deviceName;
}
// 发送消息(使用 uni-app 的 sendSocketMessage
uni
.sendSocketMessage({
data: JSON.stringify(message),
})
.then(() => {
console.log("指令发送成功:", message);
})
.catch((err) => {
console.error("指令发送失败:", err);
});
},
operationData(type) {
if (type == "PRINT") {
// 检查设备状态
if (this.deviceDetail.status == 0 && this.deviceDetail.status != -1) {
// 检查设备名称是否为空
if (!this.deviceName || this.deviceName.trim() === '') {
uni.showToast({
title: '请输入设备名称',
icon: 'none',
duration: 2000
});
return;
}
// 显示确认提示框
uni.showModal({
title: '确认打印',
content: '请确认门关闭并且设备处于可打印状态!',
confirmText: '确认执行',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
// 用户确认后执行打印
this.sendWsCommand(type);
}
}
});
}
}
if (type === "CONTINUE") {
// 检查设备状态
if (this.deviceDetail.status === 0 || this.printInfo.status !== 6) {
return;
}
// 显示确认提示框
uni.showModal({
title: '确认打印',
content: '确定要继续执行打印吗?',
confirmText: '确认执行',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
// 用户确认后执行打印
this.sendWsCommand(type);
}
}
});
}
if (type == 'PAUSE') {
console.log(this.deviceDetail.status ===0)
if (this.printInfo.status === 6 || this.deviceDetail.status ===0){
// uni.showToast({
// title: "当前设备已暂定,禁止操作",
// icon: "none",
// duration: 1500
// });
return;
}
uni.showModal({
title: '提示',
content: '确定要暂停打印吗?',
confirmText: '确定',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
this.sendWsCommand(type);
}
}
});
}
if (type == 'EXIT') {
if (this.deviceDetail.status != 0 && this.deviceDetail.status != -1) {
uni.showModal({
title: '提示',
content: '确定要退出打印吗?',
confirmText: '确定',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
this.sendWsCommand(type);
}
}
});
}
}
},
getVideoImg(type) {
this.isMediaLoading = true;
if (type == "img") {
this.getType = "img";
this.sendWsCommand("IMAGE");
} else {
this.getType = "video";
this.sendWsCommand("OPEN_VIDEO");
}
},
// 获取状态文字
getStatusText(status) {
if (status == -1) {
return "断开";
}
return this.statusMap[status]?.text || "";
},
getStatusText2(status) {
//如果状态为-1就算断开
if (status === -1) {
return "断开";
}
return this.childStatusMap[status]?.text || "";
},
// 获取状态颜色
getStatusColor(status) {
if (status == -1) {
return "#999999";
}
return this.childStatusMap[status]?.color; // 默认灰色
},
getCurrentTime() {
const date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0"); // 月份补零
const day = String(date.getDate()).padStart(2, "0"); // 日期补零
const hours = String(date.getHours()).padStart(2, "0"); // 小时补零
const minutes = String(date.getMinutes()).padStart(2, "0"); // 分钟补零
const seconds = String(date.getSeconds()).padStart(2, "0"); // 新增:秒补零
// 格式YYYY.MM.DD HH:MM:SS
return `${year}.${month}.${day} ${hours}:${minutes}:${seconds}`;
},
goBack() {
uni.navigateBack();
},
async getDeviceDetail() {
try {
const res = await uni.request({
url: BASE_API_URL + '/api/front/device/get',
method: "GET",
data: {
deviceCode: this.deviceCode,
},
header: {
"Content-Type": "application/x-www-form-urlencoded", // 关键配置
Authorization: uni.getStorageSync("userInfo")?.token || "",
},
});
if (res.statusCode === 200) {
this.deviceDetail = res.data;
this.printInfo = res.data.printInfo;
console.log("设备详情:", this.deviceDetail);
//判断状态是否为断开
// 判断状态是否为断开
if (res.data.status == -1) {
uni.showToast({
title: '设备处于断开状态,暂不支持查看',
icon: 'none',
duration: 2000, // 提示显示时长
complete: () => {
// 提示显示完成后跳转
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
});
}, 1500); // 稍微延迟一点确保用户看到提示
}
});
return;
}
}
} catch (error) {
console.error("获取设备详情失败:", error);
uni.showToast({
title: "获取设备信息失败",
icon: "none"
});
}
},
onDeviceNameInput(e) {
this.deviceName = e.detail.value;
// console.log('输入内容:', e.detail.value);
},
},
};
</script>
<!-- 临时样式 -->
<style scoped>
/* 媒体容器(相对定位,用于加载动画绝对定位) */
.media_container {
position: relative;
width: 100%;
margin: 22rpx 0 32rpx 0;
}
/* 加载动画容器 */
.loading_spinner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
/* 与媒体区域背景一致 */
border-radius: 20rpx;
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
/* 确保在媒体上层显示 */
}
/* 转圈动画元素 */
.spinner {
width: 60rpx;
height: 60rpx;
border: 6rpx solid rgba(255, 255, 255, 0.3);
border-top-color: #ffffff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
/* 旋转动画定义 */
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 缺省状态样式 */
.empty_state_warp {
width: 100%;
height: 400rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 60rpx 0;
}
.empty_state_icon {
width: 120rpx;
height: 120rpx;
margin-bottom: 30rpx;
opacity: 0.6;
}
.empty_state_title {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #999999;
margin-bottom: 16rpx;
}
.empty_state_desc {
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 26rpx;
color: #cccccc;
text-align: center;
}
.operation_btn_icon {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
.operation_btn_txt {
font-weight: 600;
font-size: 28rpx;
color: #333333;
}
.device_operation_btn {
width: 320rpx;
height: 68rpx;
background: #ffffff;
border-radius: 20rpx;
display: flex;
justify-content: center;
align-items: center;
border: 2rpx solid #cccccc;
color: #cccccc;
}
.device_operation_warp {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 24rpx;
}
.deviceN_input_tip {
margin: 24rpx 0 70rpx 0;
font-weight: 400;
font-size: 26rpx;
color: #666666;
width: 100%;
display: flex;
justify-content: center;
}
.device_control_warp {
width: 710rpx;
margin-top: 32rpx;
display: flex;
flex-direction: column;
}
.deviceN_input_warp {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.device_name_txt {
font-weight: 600;
font-size: 32rpx;
color: #333333;
}
.deviceN_input_area {
position: relative;
}
.clear_deviceN_warp {
position: absolute;
right: 16rpx;
top: 0;
height: 100%;
display: flex;
align-items: center;
z-index: 99;
pointer-events: auto;
width: 40rpx;
}
.clear_deviceN_icon {
width: 26rpx;
height: 26rpx;
}
.deviceN_input {
width: 419rpx;
height: 74rpx;
background: #ffffff;
border-radius: 10rpx;
padding-left: 30rpx;
font-weight: 400;
font-size: 28rpx;
color: #666666;
}
.label_text {
margin-left: 8rpx;
}
.label_text2 {
color: #ff0000;
}
.label_warp {
display: flex;
align-items: center;
}
.label_warp2 {
display: flex;
align-items: center;
}
.label_icon {
width: 18rpx;
height: 18rpx;
background: #cccccc;
border-radius: 100%;
}
.item_content_model {
padding: 0 20rpx;
}
.item_content_line {
width: 100%;
height: 1rpx;
background-color: #ededed;
}
.itemContent_line_warp {
width: 100%;
position: absolute;
bottom: 0;
left: 0;
}
.item_content_middel {
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 26rpx;
color: #666666;
display: flex;
align-items: center;
}
.item_content_left {
font-family: PingFang SC, PingFang SC;
font-weight: 600;
font-size: 28rpx;
color: #333333;
margin-left: 5rpx;
width: 222rpx;
}
.item_content_warp {
display: flex;
align-items: center;
}
.statusItem_modal_warp {
padding: 0 22rpx;
height: 100%;
display: flex;
justify-content: center;
flex-direction: column;
position: relative;
}
.device_status_item {
width: 100%;
height: 81rpx;
}
.device_status_warp {
width: 710rpx;
background: #ffffff;
margin-top: 23rpx;
display: flex;
flex-direction: column;
}
.modal_warp {
padding: 0 16rpx;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.device_active {
background-color: #ffffff !important;
}
.select_device_item {
width: 329rpx;
height: 56rpx;
background: #e2edff;
border-radius: 60rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 600;
font-size: 28rpx;
color: #333333;
display: flex;
justify-content: center;
align-items: center;
}
.select_device_warp {
width: 710rpx;
height: 68rpx;
background: #e2edff;
border-radius: 60rpx;
}
.content_warp {
padding: 16rpx 20rpx 0 20rpx;
display: flex;
flex-direction: column;
}
.content_area_warp {
width: 100%;
}
</style>
<style scoped>
.device_model {
width: 33%;
}
.img_video_warp {
width: 100%;
height: 321;
background: rgba(0, 0, 0, 0.3);
border-radius: 20rpx;
margin: 22rpx 0 32rpx 0;
}
.back_button_icon {
transform: rotate(180deg);
width: 28rpx;
height: 28rpx;
}
.back_button_warp {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding-left: 20rpx;
}
.contai_warp {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
font-family: PingFang SC, PingFang SC !important;
min-height: 100vh;
background-color: #f1f6fc;
overflow-x: hidden !important;
}
.top_area_warp {
width: 100%;
display: flex;
flex-direction: column;
position: relative;
}
.top_status_area {
width: 100%;
}
.top_nav_warp {
width: 100%;
height: 88rpx;
display: flex;
justify-content: center;
align-items: center;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #000000;
position: relative;
z-index: 5;
position: relative;
}
</style>