|
|
@@ -0,0 +1,834 @@
|
|
|
+<template>
|
|
|
+ <view class="device-config-container">
|
|
|
+ <!-- 顶部导航栏 -->
|
|
|
+ <view class="header-nav">
|
|
|
+ <view class="nav-left">
|
|
|
+ <text class="back-icon" @click="goBack">←</text>
|
|
|
+ </view>
|
|
|
+ <text class="nav-title">{{ isEditMode ? '编辑配置' : '添加配置' }}</text>
|
|
|
+ <view class="nav-right">
|
|
|
+ <text class="save-btn" @click="saveConfig">保存</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 配置表单 -->
|
|
|
+ <scroll-view class="config-form" scroll-y>
|
|
|
+ <!-- 基本参数 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">基本参数</text>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">配置名称</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ v-model="configForm.name"
|
|
|
+ placeholder="请输入配置名称"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">配置备注</text>
|
|
|
+ <textarea
|
|
|
+ class="textarea"
|
|
|
+ v-model="configForm.remark"
|
|
|
+ placeholder="请输入配置备注"
|
|
|
+ :rows="3"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 选项参数 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">选项参数</text>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">灯光工作模式</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ v-model="configForm.lightMode"
|
|
|
+ placeholder="0:全天暂停 1:全天营业 2:按时间段"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">维护模式</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ v-model="configForm.maintenanceMode"
|
|
|
+ placeholder="0:未设置 1:已设置"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">工作模式</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ v-model="configForm.workMode"
|
|
|
+ placeholder="0:全天暂停 1:全天营业 2:按时间段"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">屏幕类型</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ v-model="configForm.screenType"
|
|
|
+ placeholder="0:不支持视频 1:支持视频"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">屏幕左下方文本</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ v-model="configForm.userMessage1"
|
|
|
+ placeholder="请输入屏幕左下方文本"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">屏幕右下方文本</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ v-model="configForm.userMessage2"
|
|
|
+ placeholder="请输入屏幕右下方文本"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 时间参数 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">时间参数</text>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">自动启动</text>
|
|
|
+ <view class="switch-container">
|
|
|
+ <switch
|
|
|
+ :checked="configForm.motorFlowOn"
|
|
|
+ @change="configForm.motorFlowOn = $event.detail.value"
|
|
|
+ class="switch"
|
|
|
+ />
|
|
|
+ <text class="switch-desc">有流量时自动启动水泵</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">自动关闭</text>
|
|
|
+ <view class="switch-container">
|
|
|
+ <switch
|
|
|
+ :checked="configForm.motorFlowOff"
|
|
|
+ @change="configForm.motorFlowOff = $event.detail.value"
|
|
|
+ class="switch"
|
|
|
+ />
|
|
|
+ <text class="switch-desc">无流量时自动关闭水泵</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">启动延时(毫秒)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.motorOnDelay"
|
|
|
+ placeholder="推荐5000毫秒"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">关闭延时(毫秒)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.motorOffDelay"
|
|
|
+ placeholder="推荐1000毫秒"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">关闭灵敏度(毫秒)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.motorOnInterval"
|
|
|
+ placeholder="推荐10000毫秒"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">操作超时关机(秒)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.operationTimeout"
|
|
|
+ placeholder="推荐3600秒"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">空闲超时关机(秒)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.idleTimeout"
|
|
|
+ placeholder="推荐1200秒"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 价格参数 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">价格参数</text>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">清水单价(分/分钟)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.priceWater"
|
|
|
+ placeholder="请输入清水单价"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">泡沫单价(分/分钟)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.priceFoam"
|
|
|
+ placeholder="请输入泡沫单价"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">镀膜单价(分/分钟)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.priceCoat"
|
|
|
+ placeholder="请输入镀膜单价"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">吹气单价(分/分钟)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.priceBlow"
|
|
|
+ placeholder="请输入吹气单价"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">吸尘单价(分/分钟)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.priceCleaner"
|
|
|
+ placeholder="请输入吸尘单价"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">洗手单价(分/分钟)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.priceTap"
|
|
|
+ placeholder="请输入洗手单价"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">场地费单价(分/分钟)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.priceSpace"
|
|
|
+ placeholder="请输入场地费单价"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">扩展项目单价(分/分钟)</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.priceUserExt"
|
|
|
+ placeholder="请输入扩展项目单价"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">快速开机金额</text>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="number"
|
|
|
+ v-model="configForm.quickOpenMoney"
|
|
|
+ placeholder="设置为0可关闭此功能"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 时间周期设置 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">时间周期设置</text>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">照明时间段1</text>
|
|
|
+ <view class="time-picker-container">
|
|
|
+ <view class="time-range">
|
|
|
+ <picker mode="time" :value="lightStart1" @change="onTimeChange($event, 'lightStart1')" class="time-picker-item">
|
|
|
+ <view class="time-input">
|
|
|
+ <text v-if="lightStart1">{{ lightStart1 }}</text>
|
|
|
+ <text v-else class="placeholder">开始时间</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ <text class="time-separator">-</text>
|
|
|
+ <picker mode="time" :value="lightEnd1" @change="onTimeChange($event, 'lightEnd1')" class="time-picker-item">
|
|
|
+ <view class="time-input">
|
|
|
+ <text v-if="lightEnd1">{{ lightEnd1 }}</text>
|
|
|
+ <text v-else class="placeholder">结束时间</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">照明时间段2</text>
|
|
|
+ <view class="time-picker-container">
|
|
|
+ <view class="time-range">
|
|
|
+ <picker mode="time" :value="lightStart2" @change="onTimeChange($event, 'lightStart2')" class="time-picker-item">
|
|
|
+ <view class="time-input">
|
|
|
+ <text v-if="lightStart2">{{ lightStart2 }}</text>
|
|
|
+ <text v-else class="placeholder">开始时间</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ <text class="time-separator">-</text>
|
|
|
+ <picker mode="time" :value="lightEnd2" @change="onTimeChange($event, 'lightEnd2')" class="time-picker-item">
|
|
|
+ <view class="time-input">
|
|
|
+ <text v-if="lightEnd2">{{ lightEnd2 }}</text>
|
|
|
+ <text v-else class="placeholder">结束时间</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">营业时间段1</text>
|
|
|
+ <view class="time-picker-container">
|
|
|
+ <view class="time-range">
|
|
|
+ <picker mode="time" :value="workStart1" @change="onTimeChange($event, 'workStart1')" class="time-picker-item">
|
|
|
+ <view class="time-input">
|
|
|
+ <text v-if="workStart1">{{ workStart1 }}</text>
|
|
|
+ <text v-else class="placeholder">开始时间</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ <text class="time-separator">-</text>
|
|
|
+ <picker mode="time" :value="workEnd1" @change="onTimeChange($event, 'workEnd1')" class="time-picker-item">
|
|
|
+ <view class="time-input">
|
|
|
+ <text v-if="workEnd1">{{ workEnd1 }}</text>
|
|
|
+ <text v-else class="placeholder">结束时间</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">营业时间段2</text>
|
|
|
+ <view class="time-picker-container">
|
|
|
+ <view class="time-range">
|
|
|
+ <picker mode="time" :value="workStart2" @change="onTimeChange($event, 'workStart2')" class="time-picker-item">
|
|
|
+ <view class="time-input">
|
|
|
+ <text v-if="workStart2">{{ workStart2 }}</text>
|
|
|
+ <text v-else class="placeholder">开始时间</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ <text class="time-separator">-</text>
|
|
|
+ <picker mode="time" :value="workEnd2" @change="onTimeChange($event, 'workEnd2')" class="time-picker-item">
|
|
|
+ <view class="time-input">
|
|
|
+ <text v-if="workEnd2">{{ workEnd2 }}</text>
|
|
|
+ <text v-else class="placeholder">结束时间</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+
|
|
|
+ <!-- 底部操作栏 -->
|
|
|
+ <view class="bottom-action">
|
|
|
+ <button class="submit-btn" @click="saveConfig" :loading="loading">
|
|
|
+ {{ isEditMode ? '更新配置信息' : '立即添加配置' }}
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 加载状态 -->
|
|
|
+ <view class="loading-overlay" v-if="loading">
|
|
|
+ <text class="loading-spinner">🔄</text>
|
|
|
+ <text class="loading-text">保存中...</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted, computed } from 'vue'
|
|
|
+import { onLoad } from '@dcloudio/uni-app'
|
|
|
+import { showToast } from '../../utils/index.js'
|
|
|
+import { getDeviceConfigDetail, addDeviceConfig, modifyDeviceConfig } from '../../api/device.js'
|
|
|
+
|
|
|
+const configId = ref(null)
|
|
|
+const loading = ref(false)
|
|
|
+
|
|
|
+onLoad((options) => {
|
|
|
+ if (options.id) {
|
|
|
+ configId.value = options.id
|
|
|
+ loadConfigData()
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 时间变量
|
|
|
+const lightStart1 = ref('')
|
|
|
+const lightEnd1 = ref('')
|
|
|
+const lightStart2 = ref('')
|
|
|
+const lightEnd2 = ref('')
|
|
|
+const workStart1 = ref('')
|
|
|
+const workEnd1 = ref('')
|
|
|
+const workStart2 = ref('')
|
|
|
+const workEnd2 = ref('')
|
|
|
+
|
|
|
+const configForm = ref({
|
|
|
+ id: null,
|
|
|
+ name: '',
|
|
|
+ remark: '',
|
|
|
+ lightMode: 1,
|
|
|
+ maintenanceMode: 0,
|
|
|
+ workMode: 1,
|
|
|
+ screenType: 0,
|
|
|
+ userMessage1: '',
|
|
|
+ userMessage2: '',
|
|
|
+ motorFlowOn: false,
|
|
|
+ motorFlowOff: true,
|
|
|
+ motorOnDelay: 5000,
|
|
|
+ motorOffDelay: 1000,
|
|
|
+ motorOnInterval: 10000,
|
|
|
+ operationTimeout: 3600,
|
|
|
+ idleTimeout: 1200,
|
|
|
+ priceWater: 0,
|
|
|
+ priceFoam: 0,
|
|
|
+ priceCoat: 0,
|
|
|
+ priceBlow: 0,
|
|
|
+ priceCleaner: 0,
|
|
|
+ priceTap: 0,
|
|
|
+ priceSpace: 0,
|
|
|
+ priceUserExt: 0,
|
|
|
+ quickOpenMoney: 0,
|
|
|
+ lightTimePeriod1: '',
|
|
|
+ lightTimePeriod2: '',
|
|
|
+ workTimePeriod1: '',
|
|
|
+ workTimePeriod2: '',
|
|
|
+ soundVolume: 50,
|
|
|
+ videoSource: 0,
|
|
|
+ videoPlayDelay: 30,
|
|
|
+ workLightDelay: 30,
|
|
|
+ billDelay: 10,
|
|
|
+ tapOnDelay: 30,
|
|
|
+ noticeThresholdIdle: 60,
|
|
|
+ noticeThresholdOperation: 300
|
|
|
+})
|
|
|
+
|
|
|
+// 时间选择处理
|
|
|
+const onTimeChange = (e, type) => {
|
|
|
+ updateTimeValue(type, e.detail.value)
|
|
|
+}
|
|
|
+
|
|
|
+// 更新时间值
|
|
|
+const updateTimeValue = (type, time) => {
|
|
|
+ switch (type) {
|
|
|
+ case 'lightStart1':
|
|
|
+ lightStart1.value = time
|
|
|
+ break
|
|
|
+ case 'lightEnd1':
|
|
|
+ lightEnd1.value = time
|
|
|
+ break
|
|
|
+ case 'lightStart2':
|
|
|
+ lightStart2.value = time
|
|
|
+ break
|
|
|
+ case 'lightEnd2':
|
|
|
+ lightEnd2.value = time
|
|
|
+ break
|
|
|
+ case 'workStart1':
|
|
|
+ workStart1.value = time
|
|
|
+ break
|
|
|
+ case 'workEnd1':
|
|
|
+ workEnd1.value = time
|
|
|
+ break
|
|
|
+ case 'workStart2':
|
|
|
+ workStart2.value = time
|
|
|
+ break
|
|
|
+ case 'workEnd2':
|
|
|
+ workEnd2.value = time
|
|
|
+ break
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 同步时间到表单
|
|
|
+const syncTimeToForm = () => {
|
|
|
+ configForm.value.lightTimePeriod1 = lightStart1.value && lightEnd1.value
|
|
|
+ ? `${lightStart1.value} - ${lightEnd1.value}`
|
|
|
+ : ''
|
|
|
+ configForm.value.lightTimePeriod2 = lightStart2.value && lightEnd2.value
|
|
|
+ ? `${lightStart2.value} - ${lightEnd2.value}`
|
|
|
+ : ''
|
|
|
+ configForm.value.workTimePeriod1 = workStart1.value && workEnd1.value
|
|
|
+ ? `${workStart1.value} - ${workEnd1.value}`
|
|
|
+ : ''
|
|
|
+ configForm.value.workTimePeriod2 = workStart2.value && workEnd2.value
|
|
|
+ ? `${workStart2.value} - ${workEnd2.value}`
|
|
|
+ : ''
|
|
|
+}
|
|
|
+
|
|
|
+// 解析时间从表单
|
|
|
+const parseTimeFromForm = () => {
|
|
|
+ parseTimeRange(configForm.value.lightTimePeriod1, 'light')
|
|
|
+ parseTimeRange(configForm.value.lightTimePeriod2, 'light', 2)
|
|
|
+ parseTimeRange(configForm.value.workTimePeriod1, 'work')
|
|
|
+ parseTimeRange(configForm.value.workTimePeriod2, 'work', 2)
|
|
|
+}
|
|
|
+
|
|
|
+// 解析时间范围
|
|
|
+const parseTimeRange = (timeRange, type, index = 1) => {
|
|
|
+ if (!timeRange) return
|
|
|
+
|
|
|
+ const parts = timeRange.split(' - ')
|
|
|
+ if (parts.length === 2) {
|
|
|
+ if (type === 'light' && index === 1) {
|
|
|
+ lightStart1.value = parts[0]
|
|
|
+ lightEnd1.value = parts[1]
|
|
|
+ } else if (type === 'light' && index === 2) {
|
|
|
+ lightStart2.value = parts[0]
|
|
|
+ lightEnd2.value = parts[1]
|
|
|
+ } else if (type === 'work' && index === 1) {
|
|
|
+ workStart1.value = parts[0]
|
|
|
+ workEnd1.value = parts[1]
|
|
|
+ } else if (type === 'work' && index === 2) {
|
|
|
+ workStart2.value = parts[0]
|
|
|
+ workEnd2.value = parts[1]
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const isEditMode = computed(() => !!configId.value)
|
|
|
+
|
|
|
+// 加载配置数据
|
|
|
+const loadConfigData = async () => {
|
|
|
+ if (!configId.value) return
|
|
|
+
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ const res = await getDeviceConfigDetail(configId.value)
|
|
|
+ if (res && res.code === 200) {
|
|
|
+ // 覆盖表单数据
|
|
|
+ Object.assign(configForm.value, res.data)
|
|
|
+ // 解析时间数据
|
|
|
+ parseTimeFromForm()
|
|
|
+ } else {
|
|
|
+ showToast('加载配置失败')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载配置失败:', error)
|
|
|
+ showToast('加载配置失败')
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 保存配置
|
|
|
+const saveConfig = async () => {
|
|
|
+ // 验证表单
|
|
|
+ if (!configForm.value.name) {
|
|
|
+ showToast('请输入配置名称')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 同步时间到表单
|
|
|
+ syncTimeToForm()
|
|
|
+
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ const res = isEditMode.value
|
|
|
+ ? await modifyDeviceConfig(configForm.value)
|
|
|
+ : await addDeviceConfig(configForm.value)
|
|
|
+
|
|
|
+ if (res && res.code === 200) {
|
|
|
+ showToast('保存成功')
|
|
|
+ setTimeout(() => {
|
|
|
+ goBack()
|
|
|
+ }, 1500)
|
|
|
+ } else {
|
|
|
+ showToast(res.message || '保存失败')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('保存配置失败:', error)
|
|
|
+ showToast('保存失败')
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 返回上一页
|
|
|
+const goBack = () => {
|
|
|
+ uni.navigateBack()
|
|
|
+}
|
|
|
+
|
|
|
+// 页面加载时加载配置数据
|
|
|
+onMounted(() => {
|
|
|
+ // onLoad 已经处理了加载
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.device-config-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 100vh;
|
|
|
+ background-color: #F8F9FA;
|
|
|
+}
|
|
|
+
|
|
|
+/* 顶部导航栏 */
|
|
|
+.header-nav {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding-top: calc(24rpx + var(--status-bar-height));
|
|
|
+ padding-right: 30rpx;
|
|
|
+ padding-bottom: 24rpx;
|
|
|
+ padding-left: 30rpx;
|
|
|
+ background: linear-gradient(135deg, #667EEA 0%, #764BA2 100%);
|
|
|
+ box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.2);
|
|
|
+}
|
|
|
+
|
|
|
+.nav-left {
|
|
|
+ width: 180rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.back-icon {
|
|
|
+ font-size: 40rpx;
|
|
|
+ color: #FFFFFF;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-title {
|
|
|
+ font-size: 34rpx;
|
|
|
+ color: #FFFFFF;
|
|
|
+ font-weight: 600;
|
|
|
+ flex: 1;
|
|
|
+ text-align: center;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-right {
|
|
|
+ width: 180rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-end;
|
|
|
+}
|
|
|
+
|
|
|
+.save-btn {
|
|
|
+ font-size: 30rpx;
|
|
|
+ color: #FFFFFF;
|
|
|
+ font-weight: 600;
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+/* 配置表单 */
|
|
|
+.config-form {
|
|
|
+ flex: 1;
|
|
|
+ height: 0; /* 必须设置,否则 flex:1 在某些机型不生效 */
|
|
|
+ padding-bottom: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 底部操作栏 */
|
|
|
+.bottom-action {
|
|
|
+ padding: 20rpx 30rpx;
|
|
|
+ padding-bottom: calc(20rpx + var(--window-bottom));
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.05);
|
|
|
+}
|
|
|
+
|
|
|
+.submit-btn {
|
|
|
+ width: 100%;
|
|
|
+ height: 88rpx;
|
|
|
+ line-height: 88rpx;
|
|
|
+ background: linear-gradient(135deg, #667EEA 0%, #764BA2 100%);
|
|
|
+ color: #FFFFFF;
|
|
|
+ border-radius: 44rpx;
|
|
|
+ font-size: 30rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ border: none;
|
|
|
+ box-shadow: 0 8rpx 20rpx rgba(102, 126, 234, 0.3);
|
|
|
+}
|
|
|
+
|
|
|
+.submit-btn:active {
|
|
|
+ transform: scale(0.98);
|
|
|
+ opacity: 0.9;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表单部分 */
|
|
|
+.form-section {
|
|
|
+ margin: 20rpx;
|
|
|
+ background-color: #FFFFFF;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
|
|
+ padding: 24rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #1A1A1A;
|
|
|
+ font-weight: 600;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ display: block;
|
|
|
+ padding-bottom: 12rpx;
|
|
|
+ border-bottom: 1rpx solid #F0F0F0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表单项目 */
|
|
|
+.form-item {
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.form-item:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.label {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #666666;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ display: block;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.input {
|
|
|
+ width: 100%;
|
|
|
+ padding: 16rpx 20rpx;
|
|
|
+ border: 1rpx solid #E0E0E0;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #1A1A1A;
|
|
|
+ background-color: #F9F9F9;
|
|
|
+ box-sizing: border-box;
|
|
|
+ height: 72rpx;
|
|
|
+ line-height: 40rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.textarea {
|
|
|
+ width: 100%;
|
|
|
+ padding: 16rpx 20rpx;
|
|
|
+ border: 1rpx solid #E0E0E0;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #1A1A1A;
|
|
|
+ background-color: #F9F9F9;
|
|
|
+ box-sizing: border-box;
|
|
|
+ min-height: 120rpx;
|
|
|
+ line-height: 36rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ padding-top: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 开关容器 */
|
|
|
+.switch-container {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.switch {
|
|
|
+ transform: scale(0.8);
|
|
|
+ margin-right: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.switch-desc {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #999999;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* 加载状态 */
|
|
|
+.loading-overlay {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background-color: rgba(0, 0, 0, 0.4);
|
|
|
+ backdrop-filter: blur(2px);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ z-index: 999;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-spinner {
|
|
|
+ font-size: 64rpx;
|
|
|
+ animation: spin 1s linear infinite;
|
|
|
+ margin-bottom: 32rpx;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+/* 时间选择器样式 */
|
|
|
+.time-picker-container {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.time-range {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.time-picker-item {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.time-input {
|
|
|
+ width: 100%;
|
|
|
+ height: 72rpx;
|
|
|
+ padding: 0 20rpx;
|
|
|
+ border: 1rpx solid #E0E0E0;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #1A1A1A;
|
|
|
+ background-color: #F9F9F9;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.time-input:first-child {
|
|
|
+ border-top-right-radius: 0;
|
|
|
+ border-bottom-right-radius: 0;
|
|
|
+ border-right: none;
|
|
|
+}
|
|
|
+
|
|
|
+.time-input:last-child {
|
|
|
+ border-top-left-radius: 0;
|
|
|
+ border-bottom-left-radius: 0;
|
|
|
+ border-left: none;
|
|
|
+}
|
|
|
+
|
|
|
+.time-separator {
|
|
|
+ padding: 0 20rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #666666;
|
|
|
+ background-color: #F9F9F9;
|
|
|
+ border-top: 1rpx solid #E0E0E0;
|
|
|
+ border-bottom: 1rpx solid #E0E0E0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ height: 72rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.time-input .placeholder {
|
|
|
+ color: #999999;
|
|
|
+}
|
|
|
+
|
|
|
+.time-input:active {
|
|
|
+ background-color: #F0F0F0;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes spin {
|
|
|
+ from { transform: rotate(0deg); }
|
|
|
+ to { transform: rotate(360deg); }
|
|
|
+}
|
|
|
+</style>
|