Files
movecheck/src/pages/environment/index.vue

1065 lines
26 KiB
Vue
Raw Normal View History

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">
<!-- 温度卡片 -->
<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>
<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>
<!-- 湿度卡片 -->
<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>
<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>
<!-- 洁净度卡片 -->
<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>
<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">
<!-- 温度卡片 -->
<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>
<view class="detail-progress-bar">
<view class="detail-progress-fill temperature-progress" :style="{ width: temperatureProgress + '%' }"></view>
</view>
<view class="detail-range">
<text class="detail-range-text">{{ temperatureRange.min }}°C - {{ temperatureRange.max }}°C</text>
2025-09-29 23:53:09 +08:00
</view>
</view>
<!-- 湿度卡片 -->
<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>
<view class="detail-progress-bar">
<view class="detail-progress-fill humidity-progress" :style="{ width: humidityProgress + '%' }"></view>
</view>
<view class="detail-range">
<text class="detail-range-text">{{ humidityRange.min }}% - {{ humidityRange.max }}%</text>
2025-09-29 23:53:09 +08:00
</view>
</view>
<!-- 洁净度卡片 -->
<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>
<view class="detail-progress-bar">
<view class="detail-progress-fill cleanliness-progress" :style="{ width: cleanlinessProgress + '%' }"></view>
</view>
<view class="detail-range">
<text class="detail-range-text">暂无数据</text>
2025-09-29 23:53:09 +08:00
</view>
</view>
</view>
<!-- 空调目标参数设置 -->
<view class="air-conditioner-settings">
<view class="ac-header">
<text class="ac-title">空调目标参数设置</text>
2025-09-29 23:53:09 +08:00
</view>
<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">
<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>
</view> -->
2025-09-29 23:53:09 +08:00
</view>
<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">
<text class="range-label">温度控制</text>
<text class="range-value">{{ temperatureRange.min }}°C - {{ temperatureRange.max }}°C</text>
</view>
<view class="range-item">
<text class="range-label">湿度控制</text>
<text class="range-value">{{ humidityRange.min }}% - {{ humidityRange.max }}%</text>
</view>
</view>
2025-09-29 23:53:09 +08:00
</view>
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'
import { manualReconnect, sendMqttData } from '@/utils/sendMqtt.js'
import { thDataApi } 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: {
min: 0,
max: 100
},
humidityRange: {
min: 0,
max: 100
},
tempSettings: {
min: 25,
max: 35
},
humiditySettings: {
min: 0,
max: 100
},
connectionStatus: {
isConnected: false,
lastUpdate: null
},
targetTemperature: 30,
2025-09-29 23:53:09 +08:00
}
},
onLoad() {
console.log('环境参数页面加载')
this.initMqttListener()
// 获取最新空调温度
this.getLatestAirConditionerTemperature()
2025-09-29 23:53:09 +08:00
},
onUnload() {
// console.log('🔌 环境参数页面卸载,清理资源...')
2025-09-29 23:53:09 +08:00
// 页面卸载时移除监听器
if (this.dataUpdateHandler) {
mqttDataManager.removeListener('dataUpdate', this.dataUpdateHandler)
// console.log('✅ 数据更新监听器已移除')
2025-09-29 23:53:09 +08:00
}
if (this.statusUpdateHandler) {
mqttDataManager.removeListener('connectionStatus', this.statusUpdateHandler)
// console.log('✅ 状态更新监听器已移除')
2025-09-29 23:53:09 +08:00
}
// 清理调试定时器
if (this.debugInterval) {
clearInterval(this.debugInterval)
// console.log('✅ 调试定时器已清理')
2025-09-29 23:53:09 +08:00
}
// console.log('✅ 环境参数页面资源清理完成')
2025-09-29 23:53:09 +08:00
},
methods: {
// 获取最新空调温度
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() {
// console.log('🔧 环境参数页面开始初始化MQTT监听...')
2025-09-29 23:53:09 +08:00
// 监听数据更新
this.dataUpdateHandler = (data) => {
// console.log('📨 环境参数页面收到MQTT数据:', data)
2025-09-29 23:53:09 +08:00
this.updateEnvironmentData(data)
}
mqttDataManager.addListener('dataUpdate', this.dataUpdateHandler)
// 监听连接状态
this.statusUpdateHandler = (status) => {
// console.log('🔄 环境参数页面连接状态更新:', status)
2025-09-29 23:53:09 +08:00
const wasConnected = this.connectionStatus.isConnected
this.connectionStatus = status
// 只在状态发生变化时显示提示(避免重复提示)
if (wasConnected !== status.isConnected) {
// 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()
// console.log('📊 获取初始数据:', lastData)
2025-09-29 23:53:09 +08:00
if (lastData.timestamp) {
this.updateEnvironmentData(lastData)
}
// 获取初始连接状态
this.connectionStatus = mqttDataManager.getConnectionStatus()
// console.log('🔍 初始连接状态:', this.connectionStatus)
2025-09-29 23:53:09 +08:00
// 定期检查连接状态(用于调试)
this.debugInterval = setInterval(() => {
const currentStatus = mqttDataManager.getConnectionStatus()
// console.log('🔍 定期检查连接状态:', currentStatus)
2025-09-29 23:53:09 +08:00
}, 10000) // 每10秒检查一次
// console.log('✅ 环境参数页面MQTT监听初始化完成')
2025-09-29 23:53:09 +08:00
},
// 更新环境数据
updateEnvironmentData(data) {
// console.log('🌡️ 环境参数页面更新数据:', data)
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)
// 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)
// console.log('✅ 湿度已更新:', this.humidity)
2025-09-29 23:53:09 +08:00
}
this.lastUpdate = data.time || new Date().toLocaleString('zh-CN')
// 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)
}
},
// 降低目标温度
decreaseTemperature() {
if (this.targetTemperature > 16) {
this.targetTemperature--
console.log('目标温度降低至:', this.targetTemperature + '°C')
this.showTemperatureChangeToast()
} else {
uni.showToast({
title: '温度不能低于16°C',
icon: 'none'
})
}
},
// 提高目标温度
increaseTemperature() {
if (this.targetTemperature < 50) {
2025-09-29 23:53:09 +08:00
this.targetTemperature++
console.log('目标温度提高至:', this.targetTemperature + '°C')
this.showTemperatureChangeToast()
} else {
uni.showToast({
title: '温度不能高于50°C',
2025-09-29 23:53:09 +08:00
icon: 'none'
})
}
},
// 显示温度变化提示
showTemperatureChangeToast() {
// uni.showToast({
// title: `目标温度: ${this.targetTemperature}°C`,
// icon: 'success',
// duration: 1500
// })
// 发送空调参数到MQTT
this.sendAirConditionerParams()
},
// 发送空调参数
async sendAirConditionerParams() {
const airConditionerData = {
"TagValue": this.targetTemperature,
"TagName": "JS_COD",
"method": "setValue"
}
console.log('🌡️ 发送空调参数:', airConditionerData)
// 调用发送MQTT数据的方法
const success = sendMqttData(airConditionerData)
if (success) {
console.log('✅ 空调参数发送请求已提交')
// 发送成功后调用提交温湿度数据API
await this.submitTemperatureData()
} else {
console.log('❌ 空调参数发送失败')
}
},
// 提交温湿度数据
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;
padding: 25rpx 20rpx;
2025-09-29 23:53:09 +08:00
display: flex;
flex-direction: column;
align-items: center;
position: relative;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
2025-09-29 23:53:09 +08:00
min-height: 120rpx;
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 {
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;
}
.card-label {
font-size: 26rpx;
color: #666;
margin-bottom: 8rpx;
font-weight: 500;
}
2025-09-29 23:53:09 +08:00
.card-value {
font-size: 32rpx;
2025-09-29 23:53:09 +08:00
font-weight: bold;
color: #333;
}
.card-status {
position: absolute;
top: 15rpx;
right: 15rpx;
width: 14rpx;
height: 14rpx;
2025-09-29 23:53:09 +08:00
border-radius: 50%;
}
.card-status.active {
background-color: #4caf50;
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;
}
.parameter-details {
display: flex;
flex-direction: column;
gap: 20rpx;
margin-bottom: 20rpx;
2025-09-29 23:53:09 +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
}
.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
}
/* 温度详情卡片 */
.temperature-detail-card {
// border-left-color: #ff4444;
2025-09-29 23:53:09 +08:00
}
/* 湿度详情卡片 */
.humidity-detail-card {
// border-left-color: #4488ff;
2025-09-29 23:53:09 +08:00
}
/* 洁净度详情卡片 */
.cleanliness-detail-card {
// border-left-color: #ffaa00;
2025-09-29 23:53:09 +08:00
}
.detail-header {
2025-09-29 23:53:09 +08:00
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
}
.detail-label {
2025-09-29 23:53:09 +08:00
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.detail-value {
2025-09-29 23:53:09 +08:00
font-size: 28rpx;
color: #4488ff;
font-weight: bold;
}
.detail-progress-bar {
2025-09-29 23:53:09 +08:00
height: 16rpx;
background-color: #f0f0f0;
border-radius: 8rpx;
overflow: hidden;
margin-bottom: 10rpx;
2025-09-29 23:53:09 +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);
}
.detail-range {
2025-09-29 23:53:09 +08:00
display: flex;
justify-content: flex-end;
2025-09-29 23:53:09 +08:00
}
.detail-range-text {
2025-09-29 23:53:09 +08:00
font-size: 24rpx;
color: #666;
}
/* 空调目标参数设置样式 */
.air-conditioner-settings {
background: white;
border-radius: 16rpx;
padding: 30rpx;
2025-09-29 23:53:09 +08:00
margin-bottom: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.08);
border: 1rpx solid #f0f0f0;
2025-09-29 23:53:09 +08:00
}
.ac-header {
2025-09-29 23:53:09 +08:00
margin-bottom: 25rpx;
text-align: center;
2025-09-29 23:53:09 +08:00
}
.ac-title {
2025-09-29 23:53:09 +08:00
font-size: 32rpx;
font-weight: 600;
2025-09-29 23:53:09 +08:00
color: #333;
letter-spacing: 1rpx;
2025-09-29 23:53:09 +08:00
}
.ac-control {
2025-09-29 23:53:09 +08:00
display: flex;
flex-direction: column;
2025-09-29 23:53:09 +08:00
align-items: center;
gap: 20rpx;
2025-09-29 23:53:09 +08:00
}
.ac-label {
2025-09-29 23:53:09 +08:00
font-size: 28rpx;
color: #666;
font-weight: 500;
2025-09-29 23:53:09 +08:00
}
.ac-temp-control {
2025-09-29 23:53:09 +08:00
display: flex;
align-items: center;
gap: 30rpx;
background: #f8f9fa;
border-radius: 50rpx;
padding: 15rpx 25rpx;
border: 2rpx solid #e9ecef;
2025-09-29 23:53:09 +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;
font-size: 40rpx;
2025-09-29 23:53:09 +08:00
font-weight: bold;
border: none;
color: white;
transition: all 0.3s ease;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.1);
2025-09-29 23:53:09 +08:00
}
.ac-btn.decrease {
background: linear-gradient(135deg, #ff6b6b, #ee5a52);
2025-09-29 23:53:09 +08:00
}
.ac-btn.increase {
background: linear-gradient(135deg, #51cf66, #40c057);
2025-09-29 23:53:09 +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;
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;
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
}
.env-header {
2025-09-29 23:53:09 +08:00
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
2025-09-29 23:53:09 +08:00
}
.env-title {
2025-09-29 23:53:09 +08:00
font-size: 32rpx;
font-weight: 600;
2025-09-29 23:53:09 +08:00
color: #333;
letter-spacing: 1rpx;
2025-09-29 23:53:09 +08:00
}
.env-status {
2025-09-29 23:53:09 +08:00
display: flex;
align-items: center;
gap: 10rpx;
// background: #f0f8ff;
padding: 8rpx 16rpx;
border-radius: 20rpx;
// border: 1rpx solid #e6f3ff;
2025-09-29 23:53:09 +08:00
}
.status-dot {
width: 12rpx;
height: 12rpx;
2025-09-29 23:53:09 +08:00
border-radius: 50%;
background-color: #4a90e2;
2025-09-29 23:53:09 +08:00
}
.status-text {
font-size: 24rpx;
color: #4a90e2;
font-weight: 500;
2025-09-29 23:53:09 +08:00
}
.env-info {
margin-bottom: 25rpx;
2025-09-29 23:53:09 +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
}
.info-label {
font-size: 26rpx;
color: #666;
font-weight: 500;
2025-09-29 23:53:09 +08:00
}
.info-value {
font-size: 24rpx;
color: #4a90e2;
font-weight: 500;
2025-09-29 23:53:09 +08:00
}
.control-ranges {
display: flex;
flex-direction: column;
gap: 15rpx;
2025-09-29 23:53:09 +08:00
}
.range-item {
2025-09-29 23:53:09 +08:00
display: flex;
justify-content: space-between;
2025-09-29 23:53:09 +08:00
align-items: center;
padding: 15rpx 20rpx;
// background: #f8fbff;
border-radius: 12rpx;
// border-left: 4rpx solid #4a90e2;
2025-09-29 23:53:09 +08:00
}
.range-label {
font-size: 26rpx;
color: #666;
font-weight: 500;
2025-09-29 23:53:09 +08:00
}
.range-value {
font-size: 30rpx;
color: #4a90e2;
font-weight: 500;
2025-09-29 23:53:09 +08:00
}
.settings-button {
background-color: #3f51b5;
color: white;
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;
gap: 12rpx;
2025-09-29 23:53:09 +08:00
width: 100%;
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;
font-weight: 500;
2025-09-29 23:53:09 +08:00
}
/* 弹窗样式 */
.settings-modal {
background: white;
border-radius: 16rpx;
2025-09-29 23:53:09 +08:00
width: 600rpx;
max-width: 90vw;
overflow: hidden;
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;
// background-color: #f8fbff;
border-bottom: 1rpx solid #e6f3ff;
2025-09-29 23:53:09 +08:00
}
.modal-title {
font-size: 32rpx;
font-weight: 600;
2025-09-29 23:53:09 +08:00
color: #333;
letter-spacing: 1rpx;
2025-09-29 23:53:09 +08:00
}
.close-btn {
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 {
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;
margin-bottom: 15rpx;
font-weight: 500;
2025-09-29 23:53:09 +08:00
}
.range-inputs {
display: flex;
align-items: center;
gap: 20rpx;
2025-09-29 23:53:09 +08:00
}
.range-input {
flex: 1;
padding: 20rpx;
border: 2rpx solid #e6f3ff;
border-radius: 12rpx;
2025-09-29 23:53:09 +08:00
font-size: 28rpx;
text-align: center;
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;
color: #4a90e2;
font-weight: 600;
min-width: 40rpx;
text-align: center;
2025-09-29 23:53:09 +08:00
}
.unit {
font-size: 24rpx;
color: #4a90e2;
2025-09-29 23:53:09 +08:00
min-width: 60rpx;
font-weight: 500;
2025-09-29 23:53:09 +08:00
}
.modal-actions {
display: flex;
gap: 20rpx;
padding: 30rpx;
background-color: #f8fbff;
2025-09-29 23:53:09 +08:00
}
.cancel-btn {
flex: 1;
background-color: #f5f5f5;
color: #666;
2025-09-29 23:53:09 +08:00
padding: 20rpx;
border-radius: 12rpx;
2025-09-29 23:53:09 +08:00
font-size: 28rpx;
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;
border-radius: 12rpx;
2025-09-29 23:53:09 +08:00
font-size: 28rpx;
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>