2025-09-29 23:53:09 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="environment-page">
|
|
|
|
|
|
<!-- 固定头部 -->
|
|
|
|
|
|
<view class="fixed-header">
|
|
|
|
|
|
<text class="header-title">移动式检修车间</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 内容区域 -->
|
|
|
|
|
|
<view class="tabbar-content">
|
|
|
|
|
|
<!-- 顶部参数卡片 -->
|
|
|
|
|
|
<view class="parameter-cards">
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<!-- 温度卡片 -->
|
|
|
|
|
|
<view class="card-item temperature-card">
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<view class="card-icon temperature-icon">🌡️</view>
|
|
|
|
|
|
<view class="card-content">
|
|
|
|
|
|
<text class="card-label">温度</text>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<text class="card-value">{{ temperature }}°C</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-status" :class="temperature > 0 ? 'active' : 'inactive'"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<!-- 湿度卡片 -->
|
|
|
|
|
|
<view class="card-item humidity-card">
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<view class="card-icon humidity-icon">💧</view>
|
|
|
|
|
|
<view class="card-content">
|
|
|
|
|
|
<text class="card-label">湿度</text>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<text class="card-value">{{ humidity }}%</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-status" :class="humidity > 0 ? 'active' : 'inactive'"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<!-- 洁净度卡片 -->
|
|
|
|
|
|
<view class="card-item cleanliness-card">
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<view class="card-icon cleanliness-icon">✨</view>
|
|
|
|
|
|
<view class="card-content">
|
|
|
|
|
|
<text class="card-label">洁净度</text>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<text class="card-value">{{ cleanliness > 0 ? cleanliness + '%' : '-%' }}</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-status" :class="cleanliness > 0 ? 'active' : 'inactive'"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 环境参数详情 -->
|
|
|
|
|
|
<view class="parameter-details">
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<!-- 温度卡片 -->
|
|
|
|
|
|
<view class="detail-card temperature-detail-card">
|
|
|
|
|
|
<view class="detail-header">
|
|
|
|
|
|
<text class="detail-label">温度</text>
|
|
|
|
|
|
<text class="detail-value">{{ temperature }}°C</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<view class="detail-progress-bar">
|
|
|
|
|
|
<view class="detail-progress-fill temperature-progress" :style="{ width: temperatureProgress + '%' }"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="detail-range">
|
2025-10-01 04:07:37 +08:00
|
|
|
|
<!-- <text class="detail-range-text">{{ temperatureRange.min }}°C - {{ temperatureRange.max }}°C</text> -->
|
|
|
|
|
|
<text class="detail-range-text">{{ 0 }}°C - {{ 100 }}°C</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<!-- 湿度卡片 -->
|
|
|
|
|
|
<view class="detail-card humidity-detail-card">
|
|
|
|
|
|
<view class="detail-header">
|
|
|
|
|
|
<text class="detail-label">湿度</text>
|
|
|
|
|
|
<text class="detail-value">{{ humidity }}%</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<view class="detail-progress-bar">
|
|
|
|
|
|
<view class="detail-progress-fill humidity-progress" :style="{ width: humidityProgress + '%' }"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="detail-range">
|
2025-10-01 04:07:37 +08:00
|
|
|
|
<!-- <text class="detail-range-text">{{ humidityRange.min }}% - {{ humidityRange.max }}%</text> -->
|
|
|
|
|
|
<text class="detail-range-text">{{ 0 }}% - {{ 100 }}%</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<!-- 洁净度卡片 -->
|
|
|
|
|
|
<view class="detail-card cleanliness-detail-card">
|
|
|
|
|
|
<view class="detail-header">
|
|
|
|
|
|
<text class="detail-label">洁净度</text>
|
|
|
|
|
|
<text class="detail-value">{{ cleanliness > 0 ? cleanliness + '%' : '-%' }}</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<view class="detail-progress-bar">
|
|
|
|
|
|
<view class="detail-progress-fill cleanliness-progress" :style="{ width: cleanlinessProgress + '%' }"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="detail-range">
|
2025-10-01 04:07:37 +08:00
|
|
|
|
<!-- <text class="detail-range-text">暂无数据</text> -->
|
|
|
|
|
|
<text class="detail-range-text">{{ 0 }}% - {{ 100 }}%</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 空调目标参数设置 -->
|
|
|
|
|
|
<view class="air-conditioner-settings">
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<view class="ac-header">
|
|
|
|
|
|
<text class="ac-title">空调目标参数设置</text>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<view class="ac-control">
|
|
|
|
|
|
<view class="ac-label">目标温度</view>
|
|
|
|
|
|
<view class="ac-temp-control">
|
|
|
|
|
|
<button class="ac-btn decrease" @click="decreaseTemperature">−</button>
|
|
|
|
|
|
<view class="ac-temp-display">
|
|
|
|
|
|
<text class="ac-temp-value">{{ targetTemperature }}</text>
|
|
|
|
|
|
<text class="ac-temp-unit">°C</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<button class="ac-btn increase" @click="increaseTemperature">+</button>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 环境控制区域 -->
|
|
|
|
|
|
<view class="environment-control">
|
2025-09-30 01:46:33 +08:00
|
|
|
|
<view class="env-header">
|
|
|
|
|
|
<text class="env-title">环境控制</text>
|
|
|
|
|
|
<!-- <view class="env-status">
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<view class="status-dot"></view>
|
|
|
|
|
|
<text class="status-text">异常</text>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
</view> -->
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
|
|
|
|
|
|
<view class="env-info">
|
|
|
|
|
|
<!-- <view class="info-item">
|
|
|
|
|
|
<text class="info-label">最后更新</text>
|
|
|
|
|
|
<text class="info-value">{{ lastUpdate }}</text>
|
|
|
|
|
|
</view> -->
|
|
|
|
|
|
|
|
|
|
|
|
<view class="control-ranges">
|
|
|
|
|
|
<view class="range-item">
|
2025-10-01 04:07:37 +08:00
|
|
|
|
<view class="range-header">
|
|
|
|
|
|
<text class="range-label">温度控制</text>
|
|
|
|
|
|
<view class="range-status" :class="getTemperatureStatus().class">
|
|
|
|
|
|
<text class="status-text">{{ getTemperatureStatus().text }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="range-content">
|
|
|
|
|
|
<text class="current-value">当前: {{ temperature }}°C</text>
|
|
|
|
|
|
<text class="range-value">范围: {{ temperatureRange.min }}°C - {{ temperatureRange.max }}°C</text>
|
|
|
|
|
|
</view>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view class="range-item">
|
2025-10-01 04:07:37 +08:00
|
|
|
|
<view class="range-header">
|
|
|
|
|
|
<text class="range-label">湿度控制</text>
|
|
|
|
|
|
<view class="range-status" :class="getHumidityStatus().class">
|
|
|
|
|
|
<text class="status-text">{{ getHumidityStatus().text }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="range-content">
|
|
|
|
|
|
<text class="current-value">当前: {{ humidity }}%</text>
|
|
|
|
|
|
<text class="range-value">范围: {{ humidityRange.min }}% - {{ humidityRange.max }}%</text>
|
|
|
|
|
|
</view>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
2025-09-30 01:46:33 +08:00
|
|
|
|
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<button class="settings-button" @click="openSettingsModal">
|
|
|
|
|
|
<text class="settings-icon">⚙️</text>
|
|
|
|
|
|
<text class="settings-text">参数设定</text>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 参数设定弹窗 -->
|
|
|
|
|
|
<uni-popup ref="settingsPopup" type="center" :mask-click="false">
|
|
|
|
|
|
<view class="settings-modal">
|
|
|
|
|
|
<view class="modal-header">
|
|
|
|
|
|
<text class="modal-title">参数设定</text>
|
|
|
|
|
|
<text class="close-btn" @click="closeSettingsModal">✕</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="modal-content">
|
|
|
|
|
|
<!-- 温度设定 -->
|
|
|
|
|
|
<view class="setting-item">
|
|
|
|
|
|
<text class="setting-label">温度控制范围</text>
|
|
|
|
|
|
<view class="range-inputs">
|
|
|
|
|
|
<input
|
|
|
|
|
|
class="range-input"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
v-model="tempSettings.min"
|
|
|
|
|
|
placeholder="最小值"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<text class="range-separator">-</text>
|
|
|
|
|
|
<input
|
|
|
|
|
|
class="range-input"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
v-model="tempSettings.max"
|
|
|
|
|
|
placeholder="最大值"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<text class="unit">°C</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 湿度设定 -->
|
|
|
|
|
|
<view class="setting-item">
|
|
|
|
|
|
<text class="setting-label">湿度控制范围</text>
|
|
|
|
|
|
<view class="range-inputs">
|
|
|
|
|
|
<input
|
|
|
|
|
|
class="range-input"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
v-model="humiditySettings.min"
|
|
|
|
|
|
placeholder="最小值"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<text class="range-separator">-</text>
|
|
|
|
|
|
<input
|
|
|
|
|
|
class="range-input"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
v-model="humiditySettings.max"
|
|
|
|
|
|
placeholder="最大值"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<text class="unit">%</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="modal-actions">
|
|
|
|
|
|
<button class="cancel-btn" @click="closeSettingsModal">取消</button>
|
|
|
|
|
|
<button class="confirm-btn" @click="saveSettings">确定</button>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</uni-popup>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import mqttDataManager from '@/utils/mqttDataManager.js'
|
2025-09-30 01:46:33 +08:00
|
|
|
|
import { manualReconnect, sendMqttData } from '@/utils/sendMqtt.js'
|
2025-10-01 04:07:37 +08:00
|
|
|
|
import { thDataApi, alertApi, eventApi } from '@/utils/api.js'
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
temperature: 0,
|
|
|
|
|
|
humidity: 0,
|
|
|
|
|
|
cleanliness: 0,
|
|
|
|
|
|
temperatureProgress: 0,
|
|
|
|
|
|
humidityProgress: 0,
|
|
|
|
|
|
cleanlinessProgress: 0,
|
|
|
|
|
|
lastUpdate: '暂无数据',
|
|
|
|
|
|
temperatureRange: {
|
2025-10-01 04:07:37 +08:00
|
|
|
|
min: 25,
|
|
|
|
|
|
max: 35
|
2025-09-29 23:53:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
humidityRange: {
|
2025-10-01 04:07:37 +08:00
|
|
|
|
min: 40,
|
|
|
|
|
|
max: 70
|
2025-09-29 23:53:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
tempSettings: {
|
|
|
|
|
|
min: 25,
|
|
|
|
|
|
max: 35
|
|
|
|
|
|
},
|
|
|
|
|
|
humiditySettings: {
|
2025-10-01 04:07:37 +08:00
|
|
|
|
min: 40,
|
|
|
|
|
|
max: 70
|
2025-09-29 23:53:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
connectionStatus: {
|
|
|
|
|
|
isConnected: false,
|
|
|
|
|
|
lastUpdate: null
|
|
|
|
|
|
},
|
2025-10-01 02:42:22 +08:00
|
|
|
|
targetTemperature: 30,
|
2025-10-01 04:07:37 +08:00
|
|
|
|
targetHumidity: 50, // 空调设定湿度
|
|
|
|
|
|
// 报警相关数据
|
|
|
|
|
|
acFaultStatus: 0, // 空调故障状态,1表示故障
|
|
|
|
|
|
alertHistory: [], // 报警历史记录
|
|
|
|
|
|
// 系统启动事件相关
|
|
|
|
|
|
hasCreatedStartupEvent: false, // 是否已创建启动事件
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
onLoad() {
|
|
|
|
|
|
console.log('环境参数页面加载')
|
2025-10-01 04:07:37 +08:00
|
|
|
|
|
|
|
|
|
|
// 从本地存储读取是否已创建启动事件的状态
|
|
|
|
|
|
const hasCreatedStartupEvent = uni.getStorageSync('hasCreatedStartupEvent')
|
|
|
|
|
|
if (hasCreatedStartupEvent) {
|
|
|
|
|
|
this.hasCreatedStartupEvent = true
|
|
|
|
|
|
console.log('📱 从本地存储读取到启动事件状态: 已创建')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 23:53:09 +08:00
|
|
|
|
this.initMqttListener()
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 获取最新空调温度
|
|
|
|
|
|
this.getLatestAirConditionerTemperature()
|
2025-10-01 04:07:37 +08:00
|
|
|
|
// 首次进入系统时创建启动事件
|
|
|
|
|
|
this.createStartupEventIfNeeded()
|
|
|
|
|
|
},
|
|
|
|
|
|
onShow() {
|
|
|
|
|
|
console.log('📱 环境参数页面显示,触发页面更新')
|
|
|
|
|
|
// 只有在非首次显示时才重新获取最新空调温度
|
|
|
|
|
|
if (this.hasCreatedStartupEvent) {
|
|
|
|
|
|
this.getLatestAirConditionerTemperature()
|
|
|
|
|
|
}
|
2025-09-29 23:53:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
onUnload() {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('🔌 环境参数页面卸载,清理资源...')
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 页面卸载时移除监听器
|
|
|
|
|
|
if (this.dataUpdateHandler) {
|
|
|
|
|
|
mqttDataManager.removeListener('dataUpdate', this.dataUpdateHandler)
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('✅ 数据更新监听器已移除')
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (this.statusUpdateHandler) {
|
|
|
|
|
|
mqttDataManager.removeListener('connectionStatus', this.statusUpdateHandler)
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('✅ 状态更新监听器已移除')
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清理调试定时器
|
|
|
|
|
|
if (this.debugInterval) {
|
|
|
|
|
|
clearInterval(this.debugInterval)
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('✅ 调试定时器已清理')
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('✅ 环境参数页面资源清理完成')
|
2025-09-29 23:53:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2025-10-01 04:07:37 +08:00
|
|
|
|
// 首次进入系统时创建启动事件
|
|
|
|
|
|
async createStartupEventIfNeeded() {
|
|
|
|
|
|
// 检查是否已经创建过启动事件
|
|
|
|
|
|
if (this.hasCreatedStartupEvent) {
|
|
|
|
|
|
console.log('✅ 启动事件已存在,跳过创建')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
console.log('🚀 首次进入系统,创建启动事件...')
|
|
|
|
|
|
|
|
|
|
|
|
const currentTime = this.formatDateTime(new Date())
|
|
|
|
|
|
const startupEvent = {
|
|
|
|
|
|
eventType: "设备重启",
|
|
|
|
|
|
eventTime: currentTime,
|
|
|
|
|
|
status: "已完成",
|
|
|
|
|
|
description: "设备正常重启维护",
|
|
|
|
|
|
deviceId: "AC_001"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('📤 提交启动事件:', startupEvent)
|
|
|
|
|
|
const response = await eventApi.create(startupEvent)
|
|
|
|
|
|
console.log('✅ 启动事件创建成功:', response)
|
|
|
|
|
|
|
|
|
|
|
|
// 标记已创建启动事件
|
|
|
|
|
|
this.hasCreatedStartupEvent = true
|
|
|
|
|
|
|
|
|
|
|
|
// 可以保存到本地存储,避免刷新页面后重复创建
|
|
|
|
|
|
uni.setStorageSync('hasCreatedStartupEvent', true)
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('❌ 启动事件创建失败:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取温度控制状态
|
|
|
|
|
|
getTemperatureStatus() {
|
|
|
|
|
|
if (this.temperature === 0) {
|
|
|
|
|
|
return { text: '无数据', class: 'no-data' }
|
|
|
|
|
|
} else if (this.temperature >= this.temperatureRange.min && this.temperature <= this.temperatureRange.max) {
|
|
|
|
|
|
return { text: '正常', class: 'normal' }
|
|
|
|
|
|
} else if (this.temperature < this.temperatureRange.min) {
|
|
|
|
|
|
return { text: '偏低', class: 'low' }
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return { text: '偏高', class: 'high' }
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取湿度控制状态
|
|
|
|
|
|
getHumidityStatus() {
|
|
|
|
|
|
if (this.humidity === 0) {
|
|
|
|
|
|
return { text: '无数据', class: 'no-data' }
|
|
|
|
|
|
} else if (this.humidity >= this.humidityRange.min && this.humidity <= this.humidityRange.max) {
|
|
|
|
|
|
return { text: '正常', class: 'normal' }
|
|
|
|
|
|
} else if (this.humidity < this.humidityRange.min) {
|
|
|
|
|
|
return { text: '偏低', class: 'low' }
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return { text: '偏高', class: 'high' }
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 获取最新空调温度
|
|
|
|
|
|
async getLatestAirConditionerTemperature() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
console.log('🌡️ 开始获取最新空调温度...')
|
|
|
|
|
|
const res = await thDataApi.getLatest();
|
|
|
|
|
|
if (res.status === 'success') {
|
|
|
|
|
|
this.targetTemperature = res.temperature;
|
|
|
|
|
|
// this.humidity = res.humidity;
|
|
|
|
|
|
// this.updateEnvironmentData({
|
|
|
|
|
|
// temperature: res.temperature,
|
|
|
|
|
|
// humidity: res.humidity,
|
|
|
|
|
|
// deviceType: 'WSD'
|
|
|
|
|
|
// })
|
|
|
|
|
|
}
|
|
|
|
|
|
// {
|
|
|
|
|
|
// "status": "success",
|
|
|
|
|
|
// "message": "获取成功",
|
|
|
|
|
|
// "temperature": 25.5,
|
|
|
|
|
|
// "humidity": 60.2,
|
|
|
|
|
|
// "deviceId": "TH_SENSOR_001",
|
|
|
|
|
|
// "createTime": "2025-09-30T15:55:13"
|
|
|
|
|
|
// }
|
|
|
|
|
|
console.log('✅ 最新空调温度数据:', res)
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('❌ 获取最新空调温度失败:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-09-29 23:53:09 +08:00
|
|
|
|
// 初始化MQTT监听
|
|
|
|
|
|
initMqttListener() {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('🔧 环境参数页面开始初始化MQTT监听...')
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 监听数据更新
|
|
|
|
|
|
this.dataUpdateHandler = (data) => {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('📨 环境参数页面收到MQTT数据:', data)
|
2025-09-29 23:53:09 +08:00
|
|
|
|
this.updateEnvironmentData(data)
|
|
|
|
|
|
}
|
|
|
|
|
|
mqttDataManager.addListener('dataUpdate', this.dataUpdateHandler)
|
|
|
|
|
|
|
|
|
|
|
|
// 监听连接状态
|
|
|
|
|
|
this.statusUpdateHandler = (status) => {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('🔄 环境参数页面连接状态更新:', status)
|
2025-09-29 23:53:09 +08:00
|
|
|
|
const wasConnected = this.connectionStatus.isConnected
|
|
|
|
|
|
this.connectionStatus = status
|
|
|
|
|
|
|
|
|
|
|
|
// 只在状态发生变化时显示提示(避免重复提示)
|
|
|
|
|
|
if (wasConnected !== status.isConnected) {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// if (status.isConnected) {
|
|
|
|
|
|
// console.log('✅ MQTT连接状态: 已连接')
|
|
|
|
|
|
// // 不显示Toast,因为sendMqtt.js中已经显示了
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// console.log('❌ MQTT连接状态: 未连接')
|
|
|
|
|
|
// // 不显示Toast,因为sendMqtt.js中已经显示了
|
|
|
|
|
|
// }
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
mqttDataManager.addListener('connectionStatus', this.statusUpdateHandler)
|
|
|
|
|
|
|
|
|
|
|
|
// 获取初始数据
|
|
|
|
|
|
const lastData = mqttDataManager.getLastData()
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('📊 获取初始数据:', lastData)
|
2025-09-29 23:53:09 +08:00
|
|
|
|
if (lastData.timestamp) {
|
|
|
|
|
|
this.updateEnvironmentData(lastData)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取初始连接状态
|
|
|
|
|
|
this.connectionStatus = mqttDataManager.getConnectionStatus()
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('🔍 初始连接状态:', this.connectionStatus)
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 定期检查连接状态(用于调试)
|
|
|
|
|
|
this.debugInterval = setInterval(() => {
|
|
|
|
|
|
const currentStatus = mqttDataManager.getConnectionStatus()
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('🔍 定期检查连接状态:', currentStatus)
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}, 10000) // 每10秒检查一次
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('✅ 环境参数页面MQTT监听初始化完成')
|
2025-09-29 23:53:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 更新环境数据
|
|
|
|
|
|
updateEnvironmentData(data) {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('🌡️ 环境参数页面更新数据:', data)
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
2025-10-01 04:07:37 +08:00
|
|
|
|
// 处理空调故障状态
|
|
|
|
|
|
if (data.deviceType === 'AC' && data.faultStatus !== undefined) {
|
|
|
|
|
|
this.acFaultStatus = data.faultStatus
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 23:53:09 +08:00
|
|
|
|
// 只处理WSD设备的数据
|
|
|
|
|
|
if (data.deviceType === 'WSD') {
|
|
|
|
|
|
if (data.temperature !== undefined) {
|
|
|
|
|
|
this.temperature = parseFloat(data.temperature.toFixed(1))
|
|
|
|
|
|
this.temperatureProgress = Math.min(Math.max(this.temperature, 0), 100)
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('✅ 温度已更新:', this.temperature)
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (data.humidity !== undefined) {
|
|
|
|
|
|
this.humidity = parseFloat(data.humidity.toFixed(1))
|
|
|
|
|
|
this.humidityProgress = Math.min(Math.max(this.humidity, 0), 100)
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('✅ 湿度已更新:', this.humidity)
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.lastUpdate = data.time || new Date().toLocaleString('zh-CN')
|
|
|
|
|
|
|
2025-10-01 04:07:37 +08:00
|
|
|
|
// 检查报警条件,传入MQTT原始数据
|
|
|
|
|
|
this.checkAlerts(data)
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// console.log('✅ 环境数据更新完成:', {
|
|
|
|
|
|
// temperature: this.temperature,
|
|
|
|
|
|
// humidity: this.humidity,
|
|
|
|
|
|
// lastUpdate: this.lastUpdate
|
|
|
|
|
|
// })
|
2025-09-29 23:53:09 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
console.log('⚠️ 非WSD设备数据,跳过更新:', data.deviceType)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-10-01 04:07:37 +08:00
|
|
|
|
// 格式化日期时间为指定格式
|
|
|
|
|
|
formatDateTime(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')
|
|
|
|
|
|
|
|
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 检查报警条件
|
|
|
|
|
|
checkAlerts(mqttData) {
|
|
|
|
|
|
const currentTime = this.formatDateTime(new Date())
|
|
|
|
|
|
|
|
|
|
|
|
// 只处理WSD设备的数据
|
|
|
|
|
|
if (mqttData.deviceType !== 'WSD') {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取MQTT原始数据
|
|
|
|
|
|
const mqttTemperature = mqttData.temperature
|
|
|
|
|
|
const mqttHumidity = mqttData.humidity
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 温度报警:使用环境控制设置的区间(使用MQTT原始数据)
|
|
|
|
|
|
if (mqttTemperature !== undefined && (mqttTemperature < this.temperatureRange.min || mqttTemperature > this.temperatureRange.max)) {
|
|
|
|
|
|
const alert = {
|
|
|
|
|
|
// content: `温度传感器异常,读数${mqttTemperature}°C超出控制范围${this.temperatureRange.min}°C-${this.temperatureRange.max}°C`,
|
|
|
|
|
|
content: `温度超出控制范围`,
|
|
|
|
|
|
category: "传感器故障",
|
|
|
|
|
|
alertTime: currentTime,
|
|
|
|
|
|
level: "高危",
|
|
|
|
|
|
action: "检查温度传感器连接",
|
|
|
|
|
|
actionTime: currentTime,
|
|
|
|
|
|
deviceId: "WSD_001"
|
|
|
|
|
|
}
|
|
|
|
|
|
this.logAlert(alert)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 湿度报警:使用环境控制设置的区间(使用MQTT原始数据)
|
|
|
|
|
|
if (mqttHumidity !== undefined && (mqttHumidity < this.humidityRange.min || mqttHumidity > this.humidityRange.max)) {
|
|
|
|
|
|
const alert = {
|
|
|
|
|
|
// content: `湿度传感器异常,读数${mqttHumidity}%超出控制范围${this.humidityRange.min}%-${this.humidityRange.max}%`,
|
|
|
|
|
|
content: `温度超出控制范围`,
|
|
|
|
|
|
category: "传感器故障",
|
|
|
|
|
|
alertTime: currentTime,
|
|
|
|
|
|
level: "高危",
|
|
|
|
|
|
action: "检查湿度传感器连接",
|
|
|
|
|
|
actionTime: currentTime,
|
|
|
|
|
|
deviceId: "WSD_001"
|
|
|
|
|
|
}
|
|
|
|
|
|
this.logAlert(alert)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 空调故障报警:acFaultStatus为1
|
|
|
|
|
|
if (this.acFaultStatus === 1) {
|
|
|
|
|
|
const alert = {
|
|
|
|
|
|
// content: "空调故障,需要手动设置温度",
|
|
|
|
|
|
content: "空调报警",
|
|
|
|
|
|
category: "设备故障",
|
|
|
|
|
|
alertTime: currentTime,
|
|
|
|
|
|
level: "高危",
|
|
|
|
|
|
action: "手动调节空调温度",
|
|
|
|
|
|
actionTime: currentTime,
|
|
|
|
|
|
deviceId: "AC_001"
|
|
|
|
|
|
}
|
|
|
|
|
|
this.logAlert(alert)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 温度偏差报警:|温湿度计温度 - 空调设定温度| / 空调设定温度 > 30%(使用MQTT原始数据)
|
|
|
|
|
|
if (mqttTemperature !== undefined && this.targetTemperature > 0) {
|
|
|
|
|
|
const temperatureDiff = Math.abs(mqttTemperature - this.targetTemperature)
|
|
|
|
|
|
const deviationPercent = (temperatureDiff / this.targetTemperature) * 100
|
|
|
|
|
|
|
|
|
|
|
|
if (deviationPercent > 30) {
|
|
|
|
|
|
const alert = {
|
|
|
|
|
|
// content: `温度偏差过大,实际${mqttTemperature}°C与设定${this.targetTemperature}°C偏差${deviationPercent.toFixed(1)}%`,
|
|
|
|
|
|
content: `温度偏差过大`,
|
|
|
|
|
|
category: "温度控制异常",
|
|
|
|
|
|
alertTime: currentTime,
|
|
|
|
|
|
level: "中危",
|
|
|
|
|
|
action: "调整空调设定温度",
|
|
|
|
|
|
actionTime: currentTime,
|
|
|
|
|
|
deviceId: "AC_001"
|
|
|
|
|
|
}
|
|
|
|
|
|
this.logAlert(alert)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 湿度偏差报警:|温湿度计湿度 - 空调设定湿度| / 空调设定湿度 > 30%(使用MQTT原始数据)
|
|
|
|
|
|
if (mqttHumidity !== undefined && this.targetHumidity > 0) {
|
|
|
|
|
|
const humidityDiff = Math.abs(mqttHumidity - this.targetHumidity)
|
|
|
|
|
|
const deviationPercent = (humidityDiff / this.targetHumidity) * 100
|
|
|
|
|
|
|
|
|
|
|
|
if (deviationPercent > 30) {
|
|
|
|
|
|
const alert = {
|
|
|
|
|
|
// content: `湿度偏差过大,实际${mqttHumidity}%与设定${this.targetHumidity}%偏差${deviationPercent.toFixed(1)}%`,
|
|
|
|
|
|
content: `湿度偏差过大`,
|
|
|
|
|
|
category: "湿度控制异常",
|
|
|
|
|
|
alertTime: currentTime,
|
|
|
|
|
|
level: "中危",
|
|
|
|
|
|
action: "调整空调设定湿度",
|
|
|
|
|
|
actionTime: currentTime,
|
|
|
|
|
|
deviceId: "AC_001"
|
|
|
|
|
|
}
|
|
|
|
|
|
this.logAlert(alert)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 记录报警到控制台并调用创建告警接口
|
|
|
|
|
|
async logAlert(alert) {
|
|
|
|
|
|
console.log('🚨 报警触发:', JSON.stringify(alert, null, 2))
|
|
|
|
|
|
this.alertHistory.push(alert)
|
|
|
|
|
|
|
|
|
|
|
|
// 调用创建告警接口
|
|
|
|
|
|
try {
|
|
|
|
|
|
console.log('📤 正在创建告警记录...')
|
|
|
|
|
|
const response = await alertApi.create(alert)
|
|
|
|
|
|
console.log('✅ 告警记录创建成功:', response)
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('❌ 告警记录创建失败:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 限制报警历史记录数量,避免内存溢出
|
|
|
|
|
|
if (this.alertHistory.length > 100) {
|
|
|
|
|
|
this.alertHistory = this.alertHistory.slice(-50)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-09-29 23:53:09 +08:00
|
|
|
|
// 降低目标温度
|
|
|
|
|
|
decreaseTemperature() {
|
|
|
|
|
|
if (this.targetTemperature > 16) {
|
|
|
|
|
|
this.targetTemperature--
|
|
|
|
|
|
console.log('目标温度降低至:', this.targetTemperature + '°C')
|
|
|
|
|
|
this.showTemperatureChangeToast()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '温度不能低于16°C',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 提高目标温度
|
|
|
|
|
|
increaseTemperature() {
|
2025-09-30 01:46:33 +08:00
|
|
|
|
if (this.targetTemperature < 50) {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
this.targetTemperature++
|
|
|
|
|
|
console.log('目标温度提高至:', this.targetTemperature + '°C')
|
|
|
|
|
|
this.showTemperatureChangeToast()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.showToast({
|
2025-09-30 01:46:33 +08:00
|
|
|
|
title: '温度不能高于50°C',
|
2025-09-29 23:53:09 +08:00
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
// 显示温度变化提示
|
|
|
|
|
|
showTemperatureChangeToast() {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// uni.showToast({
|
|
|
|
|
|
// title: `目标温度: ${this.targetTemperature}°C`,
|
|
|
|
|
|
// icon: 'success',
|
|
|
|
|
|
// duration: 1500
|
|
|
|
|
|
// })
|
2025-09-30 01:46:33 +08:00
|
|
|
|
|
2025-10-01 04:07:37 +08:00
|
|
|
|
// 发送空调参数到MQTT
|
|
|
|
|
|
this.sendAirConditionerParams()
|
|
|
|
|
|
|
|
|
|
|
|
// 温度变化后检查报警(使用当前页面数据模拟MQTT数据)
|
|
|
|
|
|
const mockMqttData = {
|
|
|
|
|
|
deviceType: 'WSD',
|
|
|
|
|
|
temperature: this.temperature,
|
|
|
|
|
|
humidity: this.humidity
|
|
|
|
|
|
}
|
|
|
|
|
|
this.checkAlerts(mockMqttData)
|
2025-09-30 01:46:33 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 发送空调参数
|
2025-10-01 02:42:22 +08:00
|
|
|
|
async sendAirConditionerParams() {
|
2025-09-30 01:46:33 +08:00
|
|
|
|
const airConditionerData = {
|
|
|
|
|
|
"TagValue": this.targetTemperature,
|
|
|
|
|
|
"TagName": "JS_COD",
|
|
|
|
|
|
"method": "setValue"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('🌡️ 发送空调参数:', airConditionerData)
|
|
|
|
|
|
|
|
|
|
|
|
// 调用发送MQTT数据的方法
|
|
|
|
|
|
const success = sendMqttData(airConditionerData)
|
|
|
|
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
|
|
console.log('✅ 空调参数发送请求已提交')
|
2025-10-01 02:42:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 发送成功后调用提交温湿度数据API
|
|
|
|
|
|
await this.submitTemperatureData()
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
console.log('❌ 空调参数发送失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-10-01 02:42:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 提交温湿度数据
|
|
|
|
|
|
async submitTemperatureData() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const temperatureData = {
|
|
|
|
|
|
temperature: this.targetTemperature,
|
|
|
|
|
|
deviceId: "TH_SENSOR_001",
|
|
|
|
|
|
humidity: 0,
|
|
|
|
|
|
}
|
|
|
|
|
|
await thDataApi.submit(temperatureData)
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('❌ 温湿度数据提交失败:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 手动重连MQTT
|
|
|
|
|
|
manualReconnect() {
|
|
|
|
|
|
console.log('🔄 用户手动触发MQTT重连')
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '正在重连...',
|
|
|
|
|
|
icon: 'loading',
|
|
|
|
|
|
duration: 2000
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 调用sendMqtt.js中的手动重连函数
|
|
|
|
|
|
manualReconnect()
|
|
|
|
|
|
},
|
|
|
|
|
|
openSettingsModal() {
|
|
|
|
|
|
// 打开弹窗前,将当前设置复制到临时变量
|
|
|
|
|
|
this.tempSettings = { ...this.temperatureRange }
|
|
|
|
|
|
this.humiditySettings = { ...this.humidityRange }
|
|
|
|
|
|
this.$refs.settingsPopup.open()
|
|
|
|
|
|
},
|
|
|
|
|
|
closeSettingsModal() {
|
|
|
|
|
|
this.$refs.settingsPopup.close()
|
|
|
|
|
|
},
|
|
|
|
|
|
saveSettings() {
|
|
|
|
|
|
// 保存设置
|
|
|
|
|
|
this.temperatureRange = { ...this.tempSettings }
|
|
|
|
|
|
this.humidityRange = { ...this.humiditySettings }
|
|
|
|
|
|
|
|
|
|
|
|
// 更新最后更新时间
|
|
|
|
|
|
this.lastUpdate = new Date().toLocaleString()
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭弹窗
|
|
|
|
|
|
this.closeSettingsModal()
|
|
|
|
|
|
|
|
|
|
|
|
// 显示保存成功提示
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '参数设置已保存',
|
|
|
|
|
|
icon: 'success'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
console.log('保存的温度范围:', this.temperatureRange)
|
|
|
|
|
|
console.log('保存的湿度范围:', this.humidityRange)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.environment-page {
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 顶部参数卡片样式 */
|
|
|
|
|
|
.parameter-cards {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 20rpx;
|
|
|
|
|
|
margin-bottom: 30rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-item {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
border-radius: 12rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
padding: 25rpx 20rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
position: relative;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
min-height: 120rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border: 2rpx solid transparent;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-item:hover {
|
|
|
|
|
|
transform: translateY(-2rpx);
|
|
|
|
|
|
box-shadow: 0 6rpx 16rpx rgba(0,0,0,0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 温度卡片 */
|
|
|
|
|
|
.temperature-card {
|
|
|
|
|
|
// border-left: 4rpx solid #ff4444;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.temperature-card .card-icon {
|
|
|
|
|
|
color: #ff4444;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 湿度卡片 */
|
|
|
|
|
|
.humidity-card {
|
|
|
|
|
|
// border-left: 4rpx solid #4488ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.humidity-card .card-icon {
|
|
|
|
|
|
color: #4488ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 洁净度卡片 */
|
|
|
|
|
|
.cleanliness-card {
|
|
|
|
|
|
// border-left: 4rpx solid #ffaa00;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.cleanliness-card .card-icon {
|
|
|
|
|
|
color: #ffaa00;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-icon {
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
margin-bottom: 12rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-content {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.card-label {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
margin-bottom: 8rpx;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 23:53:09 +08:00
|
|
|
|
.card-value {
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-size: 32rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-status {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 15rpx;
|
|
|
|
|
|
right: 15rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
width: 14rpx;
|
|
|
|
|
|
height: 14rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-status.active {
|
|
|
|
|
|
background-color: #4caf50;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
box-shadow: 0 0 8rpx rgba(76, 175, 80, 0.5);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-status.inactive {
|
|
|
|
|
|
background-color: #ccc;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.parameter-details {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 20rpx;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.detail-card {
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
padding: 25rpx;
|
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.08);
|
|
|
|
|
|
border-left: 4rpx solid transparent;
|
|
|
|
|
|
transition: all 0.3s ease;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.detail-card:hover {
|
|
|
|
|
|
transform: translateY(-1rpx);
|
|
|
|
|
|
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.12);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
/* 温度详情卡片 */
|
|
|
|
|
|
.temperature-detail-card {
|
|
|
|
|
|
// border-left-color: #ff4444;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
/* 湿度详情卡片 */
|
|
|
|
|
|
.humidity-detail-card {
|
|
|
|
|
|
// border-left-color: #4488ff;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
/* 洁净度详情卡片 */
|
|
|
|
|
|
.cleanliness-detail-card {
|
|
|
|
|
|
// border-left-color: #ffaa00;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.detail-header {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 15rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.detail-label {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.detail-value {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #4488ff;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.detail-progress-bar {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
height: 16rpx;
|
|
|
|
|
|
background-color: #f0f0f0;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
overflow: hidden;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
margin-bottom: 10rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.detail-progress-fill {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
height: 100%;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
transition: width 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.temperature-progress {
|
|
|
|
|
|
background: linear-gradient(90deg, #4488ff, #44ff88);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.humidity-progress {
|
|
|
|
|
|
background: linear-gradient(90deg, #4488ff, #44ff88);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.cleanliness-progress {
|
|
|
|
|
|
background: linear-gradient(90deg, #4488ff, #44ff88);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.detail-range {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
display: flex;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
justify-content: flex-end;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.detail-range-text {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 空调目标参数设置样式 */
|
|
|
|
|
|
.air-conditioner-settings {
|
|
|
|
|
|
background: white;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
padding: 30rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
margin-bottom: 20rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.08);
|
|
|
|
|
|
border: 1rpx solid #f0f0f0;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.ac-header {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
margin-bottom: 25rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
text-align: center;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.ac-title {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 32rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-weight: 600;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
color: #333;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
letter-spacing: 1rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.ac-control {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
display: flex;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
flex-direction: column;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
align-items: center;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
gap: 20rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.ac-label {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 28rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
color: #666;
|
|
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.ac-temp-control {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
gap: 30rpx;
|
|
|
|
|
|
background: #f8f9fa;
|
|
|
|
|
|
border-radius: 50rpx;
|
|
|
|
|
|
padding: 15rpx 25rpx;
|
|
|
|
|
|
border: 2rpx solid #e9ecef;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.ac-btn {
|
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
|
height: 80rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-size: 40rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
color: white;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.1);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.ac-btn.decrease {
|
|
|
|
|
|
background: linear-gradient(135deg, #ff6b6b, #ee5a52);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.ac-btn.increase {
|
|
|
|
|
|
background: linear-gradient(135deg, #51cf66, #40c057);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.ac-btn:active {
|
|
|
|
|
|
transform: scale(0.95);
|
|
|
|
|
|
box-shadow: 0 1rpx 4rpx rgba(0,0,0,0.2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ac-temp-display {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: baseline;
|
|
|
|
|
|
gap: 8rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
min-width: 120rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ac-temp-value {
|
|
|
|
|
|
font-size: 48rpx;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
line-height: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ac-temp-unit {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.environment-control {
|
|
|
|
|
|
background: white;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
padding: 30rpx;
|
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.08);
|
|
|
|
|
|
border: 1rpx solid #f0f0f0;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.env-header {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
margin-bottom: 25rpx;
|
|
|
|
|
|
padding-bottom: 20rpx;
|
|
|
|
|
|
border-bottom: 1rpx solid #f0f0f0;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.env-title {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 32rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-weight: 600;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
color: #333;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
letter-spacing: 1rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.env-status {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
// background: #f0f8ff;
|
|
|
|
|
|
padding: 8rpx 16rpx;
|
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
|
// border: 1rpx solid #e6f3ff;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-dot {
|
2025-09-30 01:46:33 +08:00
|
|
|
|
width: 12rpx;
|
|
|
|
|
|
height: 12rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
border-radius: 50%;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
background-color: #4a90e2;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-text {
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #4a90e2;
|
|
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.env-info {
|
|
|
|
|
|
margin-bottom: 25rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.info-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
padding: 15rpx 20rpx;
|
|
|
|
|
|
background: #f8fbff;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
border-left: 4rpx solid #4a90e2;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.info-label {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.info-value {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #4a90e2;
|
|
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.control-ranges {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 15rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.range-item {
|
2025-10-01 04:07:37 +08:00
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
background: #f8fbff;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
border-left: 4rpx solid #4a90e2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-header {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
display: flex;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
justify-content: space-between;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
align-items: center;
|
2025-10-01 04:07:37 +08:00
|
|
|
|
margin-bottom: 12rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-30 01:46:33 +08:00
|
|
|
|
.range-label {
|
2025-10-01 04:07:37 +08:00
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-status {
|
|
|
|
|
|
padding: 6rpx 12rpx;
|
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
|
font-size: 22rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 04:07:37 +08:00
|
|
|
|
.range-status.normal {
|
|
|
|
|
|
background-color: #e8f5e8;
|
|
|
|
|
|
color: #4caf50;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-status.low {
|
|
|
|
|
|
background-color: #fff3e0;
|
|
|
|
|
|
color: #ff9800;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-status.high {
|
|
|
|
|
|
background-color: #ffebee;
|
|
|
|
|
|
color: #f44336;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-status.no-data {
|
|
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.current-value {
|
|
|
|
|
|
font-size: 26rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
color: #4a90e2;
|
|
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 04:07:37 +08:00
|
|
|
|
.range-value {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 23:53:09 +08:00
|
|
|
|
.settings-button {
|
|
|
|
|
|
background-color: #3f51b5;
|
|
|
|
|
|
color: white;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
padding: 18rpx 30rpx;
|
|
|
|
|
|
border-radius: 12rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
gap: 12rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
width: 100%;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border: none;
|
|
|
|
|
|
box-shadow: 0 4rpx 12rpx rgba(74, 144, 226, 0.3);
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.settings-button:active {
|
|
|
|
|
|
transform: translateY(1rpx);
|
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(74, 144, 226, 0.4);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.settings-icon {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.settings-text {
|
|
|
|
|
|
font-size: 28rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 弹窗样式 */
|
|
|
|
|
|
.settings-modal {
|
|
|
|
|
|
background: white;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border-radius: 16rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
width: 600rpx;
|
|
|
|
|
|
max-width: 90vw;
|
|
|
|
|
|
overflow: hidden;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border: 1rpx solid #f0f0f0;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.modal-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 30rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
// background-color: #f8fbff;
|
|
|
|
|
|
border-bottom: 1rpx solid #e6f3ff;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.modal-title {
|
|
|
|
|
|
font-size: 32rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-weight: 600;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
color: #333;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
letter-spacing: 1rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.close-btn {
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
padding: 8rpx;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
|
height: 60rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.close-btn:active {
|
|
|
|
|
|
background-color: #e0e0e0;
|
|
|
|
|
|
transform: scale(0.95);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.modal-content {
|
|
|
|
|
|
padding: 30rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.setting-item {
|
2025-09-30 01:46:33 +08:00
|
|
|
|
margin-bottom: 30rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.setting-label {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
margin-bottom: 15rpx;
|
|
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-inputs {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
gap: 20rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-input {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
padding: 20rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border: 2rpx solid #e6f3ff;
|
|
|
|
|
|
border-radius: 12rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
text-align: center;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
background-color: #f8fbff;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-input:focus {
|
|
|
|
|
|
border-color: #4a90e2;
|
|
|
|
|
|
background-color: white;
|
|
|
|
|
|
box-shadow: 0 0 0 4rpx rgba(74, 144, 226, 0.1);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.range-separator {
|
|
|
|
|
|
font-size: 28rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
color: #4a90e2;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
min-width: 40rpx;
|
|
|
|
|
|
text-align: center;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.unit {
|
|
|
|
|
|
font-size: 24rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
color: #4a90e2;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
min-width: 60rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.modal-actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 20rpx;
|
|
|
|
|
|
padding: 30rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
background-color: #f8fbff;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.cancel-btn {
|
|
|
|
|
|
flex: 1;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
|
|
color: #666;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
padding: 20rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border-radius: 12rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 28rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border: 2rpx solid #e0e0e0;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.cancel-btn:active {
|
|
|
|
|
|
background-color: #e0e0e0;
|
|
|
|
|
|
transform: translateY(1rpx);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-btn {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
background-color: #3f51b5;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
padding: 20rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border-radius: 12rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
font-size: 28rpx;
|
2025-09-30 01:46:33 +08:00
|
|
|
|
border: none;
|
|
|
|
|
|
box-shadow: 0 4rpx 12rpx rgba(63, 81, 181, 0.3);
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-btn:active {
|
|
|
|
|
|
transform: translateY(1rpx);
|
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(63, 81, 181, 0.4);
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|