| 
					
				 | 
			
			
				@@ -0,0 +1,4483 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  <div class="timing-strategy-page"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <!-- 页面标题 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <div class="page-header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <h2 class="page-title"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-icon><Clock /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        定时策略管理 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </h2> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p class="page-description">管理设备的定时控制策略,支持按周期和时间自动执行设备操作</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <!-- 查询条件卡片 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <el-card class="search-card" shadow="hover"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <el-form :model="searchForm" inline class="search-form"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-form-item label="策略名称"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-input 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              v-model="searchForm.searchText" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              placeholder="请输入策略名称搜索" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              clearable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              prefix-icon="Search" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              @keyup.enter="handleSearch" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              class="search-input" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-button type="primary" @click="handleSearch" :icon="Search"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            搜索 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-button @click="handleReset" :icon="Refresh"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            重置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-button type="success" @click="handleAdd" :icon="Plus"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            新增策略 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </el-form> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </el-card> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <!-- 数据表格卡片 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <el-card class="table-card" shadow="hover"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <template #header> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div class="card-header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div class="header-left"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-icon><List /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <span>策略列表</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-tag type="info" class="count-tag">共 {{ pagination.total }} 条</el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <el-table 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          :data="tableData" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          stripe 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          class="strategy-table" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-table-column prop="timing_name" label="策略名称" min-width="150"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #default="{ row }"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="strategy-name"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-icon class="name-icon"><Timer /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              {{ row.timing_name }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-table-column> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-table-column prop="weeks" label="重复日期" min-width="200"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #default="{ row }"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="weeks-container"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-tag 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  v-for="week in getWeekTags(row.weeks)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :key="week.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :type="week.type" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  class="week-tag" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                {{ week.label }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-table-column> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-table-column prop="timing_start_time" label="执行时间" width="120"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #default="{ row }"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="time-display"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-icon><Clock /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              {{ row.timing_start_time }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-table-column> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 保持原来的设备指令列显示方式,但优化内容 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-table-column prop="timing_agreement" label="设备指令" min-width="180"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #default="{ row }"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="agreement-display"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-tag 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  v-for="(item, index) in getAgreementTags(row.timing_agreement)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :key="index" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :type="item.type" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  class="agreement-tag" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :class="item.configType" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <span class="tag-icon" v-if="item.icon"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <component :is="item.icon" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                {{ item.label }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <!-- 如果没有任何配置显示提示 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-tag v-if="getAgreementTags(row.timing_agreement).length === 0" type="info" size="small" class="no-config-tag"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-icon><InfoFilled /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                未配置路数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-table-column> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-table-column prop="timing_state" label="状态" width="100"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #default="{ row }"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-switch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v-model="row.timing_state" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                :active-value="1" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                :inactive-value="0" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                active-color="#13ce66" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                inactive-color="#ff4949" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                @change="handleStatusChange(row)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-table-column> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-table-column label="操作" width="180" fixed="right"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #default="{ row }"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="action-buttons"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  type="primary" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :icon="Edit" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  @click="handleEdit(row)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  link 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  class="action-btn control-btn" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                编辑 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  type="info" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :icon="View" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  @click="handleDetail(row)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  link 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                详情 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-table-column> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </el-table> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <!-- 分页 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <div class="pagination-container"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-pagination 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v-model:current-page="pagination.currentPage" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v-model:page-size="pagination.pageSize" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            :total="pagination.total" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            :page-sizes="[10, 20, 50, 100]" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            layout="total, sizes, prev, pager, next, jumper" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            background 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            @size-change="handleSizeChange" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            @current-change="handleCurrentChange" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </el-card> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <!-- 新增/编辑弹窗 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <el-dialog 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        v-model="dialogVisible" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :title="dialogTitle" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        width="900px" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :close-on-click-modal="false" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        class="strategy-dialog" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        @close="handleDialogClose" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <el-form 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          :model="formData" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          :rules="formRules" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ref="formRef" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          label-width="120px" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          class="strategy-form" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 基本信息 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div class="form-section"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <h3 class="section-title"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-icon><InfoFilled /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            基本信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-row :gutter="20"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-col :span="12"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-form-item label="策略名称" prop="timing_name"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-input 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v-model="formData.timing_name" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    placeholder="请输入策略名称" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    prefix-icon="Edit" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    maxlength="50" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    show-word-limit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-col :span="12"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-form-item label="执行时间" prop="timing_start_time"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-time-picker 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v-model="formData.timing_start_time" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    format="HH:mm" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    value-format="HH:mm" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    placeholder="选择时间" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    style="width: 100%" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <!-- 重复日期选择 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-form-item label="重复日期" prop="weeks"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="weeks-selection"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <!-- 快捷选择按钮 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="quick-select-buttons"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    @click="selectAllWeekdays" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :type="isAllWeekdaysSelected ? 'primary' : ''" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  工作日 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    @click="selectWeekend" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :type="isWeekendSelected ? 'primary' : ''" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  周末 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    @click="selectAllWeek" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :type="isAllWeekSelected ? 'primary' : ''" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  全选 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    @click="clearAllWeeks" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  清空 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <!-- 星期选择 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="week-selection-container"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="week-days-grid"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <div 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      v-for="day in weekDays" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :key="day.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :class="[ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        'week-day-item', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 'selected': formData.weeks.includes(day.value) }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 'weekend': day.isWeekend } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      ]" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      @click="toggleWeekDay(day.value)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <div class="day-content"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <div class="day-name">{{ day.name }}</div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <div class="day-en">{{ day.en }}</div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <div class="day-icon"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        <el-icon v-if="formData.weeks.includes(day.value)"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          <Check /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        </el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <!-- 特殊选项 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="special-options"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <div class="special-option-group"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <h4 class="option-group-title">特殊设置</h4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <div class="special-checkboxes"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <div 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :class="[ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            'special-checkbox', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            { 'checked': formData.weeks.includes(256) } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          ]" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          @click="toggleSpecialOption(256)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        <el-icon class="checkbox-icon"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          <Check v-if="formData.weeks.includes(256)" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        </el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        <span class="checkbox-label">节假日执行</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <div 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :class="[ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            'special-checkbox', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            { 'checked': formData.weeks.includes(512) } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          ]" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          @click="toggleSpecialOption(512)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        <el-icon class="checkbox-icon"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          <Check v-if="formData.weeks.includes(512)" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        </el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        <span class="checkbox-label">节假日不执行</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <!-- 选择结果预览 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="selection-preview" v-if="formData.weeks.length > 0"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="preview-title">已选择:</div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="preview-tags"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <el-tag 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      v-for="week in getSelectedWeekTags" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :key="week.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :type="week.type" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      closable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      @close="removeWeekDay(week.value)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      class="preview-tag" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    {{ week.label }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 设备选择 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div class="form-section"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <h3 class="section-title"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-icon><Monitor /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            设备选择 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-form-item label="选择方式"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-radio-group v-model="deviceSelectType" class="select-type-radio" @change="handleSelectTypeChange"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-radio label="region"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-icon><Location /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                按区域选择 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-radio> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-radio label="group"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-icon><Collection /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                按分组选择 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-radio> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-radio-group> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-row :gutter="20"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-col :span="8"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-form-item label="所属位置" prop="region_ids"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <!-- 区域选择 - 使用树形选择器 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-tree-select 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ref="regionTreeRef" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v-model="formData.region_ids" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :data="regionTreeData" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :props="regionTreeProps" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    placeholder="请选择所属位置" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    clearable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    filterable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    check-strictly 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :load="loadRegionNode" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    lazy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    style="width: 100%" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    @change="handleRegionSelectChange" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :default-expanded-keys="[]" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :show-checkbox="false" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    node-key="id" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :render-after-expand="false" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :cache-data="false" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :key="`region-tree-${treeKey}`" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-col :span="8"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-form-item label="设备分类" prop="category_id"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-select 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v-model="formData.category_id" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    placeholder="请选择设备分类" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    clearable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    style="width: 100%" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    @change="handleCategoryChange" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <el-option 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      v-for="item in categoryOptions" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :key="item.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :label="item.label" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :value="item.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-select> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-col :span="8"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-form-item label="设备型号" prop="device_type_id"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-select 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v-model="formData.device_type_id" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    placeholder="请选择设备型号" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    clearable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    style="width: 100%" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    @change="handleDeviceTypeChange" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <el-option 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      v-for="item in deviceTypeOptions" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :key="item.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :label="item.label" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :value="item.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-select> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-form-item label="设备名称" prop="device_ids"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="device-select-container"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-select 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  v-model="formData.device_ids" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  placeholder="请选择设备名称" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  multiple 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  clearable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  collapse-tags 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  collapse-tags-tooltip 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :max-collapse-tags="30" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  style="width: 100%" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  @change="handleDeviceChange" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <template #header> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <div class="device-select-header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <el-checkbox 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        v-model="isAllDevicesSelected" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        :indeterminate="isDeviceIndeterminate" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        @change="handleSelectAllDevices" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      全选设备 ({{ deviceOptions.length }}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    </el-checkbox> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-option 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v-for="item in deviceOptions" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :key="item.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :label="item.label" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :value="item.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-select> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="device-count-info" v-if="formData.device_ids.length > 0"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                已选择 {{ formData.device_ids.length }} 个设备 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 修改路数配置部分的模板 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div v-if="channelCount > 0" class="form-section"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <h3 class="section-title"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-icon><Connection /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            路数配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-tag type="info" size="small">{{ channelCount }}路设备</el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-tag type="warning" size="small" style="margin-left: 8px;">可选配置</el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <!-- 路数操作按钮 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <!-- 修改路数操作按钮部分 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div class="channel-operations"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="operation-buttons"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-button-group> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-button size="small" @click="selectAllChannels" :icon="Check"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  全部开启 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-button size="small" @click="unselectAllChannels" :icon="Close"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  全部关闭 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-button size="small" @click="reverseAllChannels" :icon="Refresh"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  反选 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-button-group> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-button size="small" @click="restoreChannelConfig" :icon="RefreshLeft" v-if="isEdit"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                恢复原配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-button size="small" @click="clearAllChannels" :icon="Delete" type="danger"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                清空配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="channel-status-info"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="status-line"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                开启: {{ getChannelStatusCount().on }} | 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                关闭: {{ getChannelStatusCount().off }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div class="channel-grid"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v-for="i in channelCount" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                :key="i" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                class="channel-item" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                :class="{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          'has-name': hasChannelName(i), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          'has-status': hasChannelStatus(i), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          'configured': hasChannelName(i) || hasChannelStatus(i) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="channel-header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="channel-info"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <span class="channel-number">{{ getChineseNumber(i) }}路</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-form-item 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :prop="`channel_names.Tag${i}`" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :rules="channelNameRules" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    class="channel-name-form-item" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <el-input 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      v-model="formData.channel_names[`Tag${i}`]" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      placeholder="可选:输入路数名称" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      class="channel-name-input" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      maxlength="20" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      clearable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      @input="handleChannelNameChange(i)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      @clear="handleChannelNameClear(i)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="channel-control"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="channel-buttons"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <el-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :type="formData.timing_agreement[`Tag${i}`] === 0 ? 'danger' : ''" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :plain="formData.timing_agreement[`Tag${i}`] !== 0" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      @click="toggleChannelStatus(i, 0)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      class="status-button" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <el-icon><SwitchButton /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    关闭 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <el-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :type="formData.timing_agreement[`Tag${i}`] === 1 ? 'success' : ''" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :plain="formData.timing_agreement[`Tag${i}`] !== 1" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      @click="toggleChannelStatus(i, 1)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      class="status-button" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <el-icon><SwitchButton /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    开启 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </el-form> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <template #footer> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div class="dialog-footer"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-button @click="dialogVisible = false" :icon="Close"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            取消 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-button type="primary" @click="handleSubmit" :icon="Check" :loading="submitLoading"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            {{ submitLoading ? '保存中...' : '确定' }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </el-dialog> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <!-- 详情弹窗 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <el-dialog 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        v-model="detailVisible" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title="策略详情" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        width="900px" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        class="detail-dialog" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <div class="detail-content" v-if="detailData"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div class="detail-section"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <h4>基本信息</h4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-descriptions :column="2" border> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-descriptions-item label="策略名称"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              {{ detailData.timing_name }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-descriptions-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-descriptions-item label="执行时间"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              {{ detailData.timing_start_time }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-descriptions-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-descriptions-item label="重复日期" :span="2"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-tag 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  v-for="week in getWeekTags(detailData.weeks)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :key="week.value" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  :type="week.type" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  size="small" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  class="week-tag" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                {{ week.label }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-descriptions-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-descriptions-item label="状态"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-tag :type="detailData.timing_state === 1 ? 'success' : 'danger'"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                {{ detailData.timing_state === 1 ? '启用' : '禁用' }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-descriptions-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-descriptions> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div class="detail-section"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <h4>设备指令</h4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div class="agreement-detail"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v-for="item in getAgreementTags(detailData.timing_agreement)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                :key="item.label" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                class="agreement-item" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <span class="channel-name">{{ item.label }}</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-tag :type="item.type" size="small">{{ item.status }}</el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </el-dialog> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<script setup name="zmTime"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Clock, Search, Refresh, Plus, List, Timer, Edit, View, Delete, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  InfoFilled, Monitor, Location, Collection, Connection, SwitchButton, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Close, Check, RefreshLeft 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} from '@element-plus/icons-vue' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { ref, reactive, onMounted, computed, watch, nextTick } from 'vue' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { ElMessage, ElMessageBox } from 'element-plus' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import axios from 'axios' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 响应式数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const searchForm = reactive({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  searchText: '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const pagination = reactive({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  currentPage: 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pageSize: 10, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  total: 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const tableData = ref([]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const dialogVisible = ref(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const detailVisible = ref(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const detailData = ref(null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const dialogTitle = ref('新增策略') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const isEdit = ref(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const deviceSelectType = ref('region') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const channelCount = ref(0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const submitLoading = ref(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const regionTreeRef = ref(null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const requestCache = new Map() // 请求缓存 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const requestQueue = new Map() // 请求队列,防止重复请求 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const treeKey = ref(0) // 用于强制刷新树组件 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let debounceTimer = null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 请求缓存工具函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getCacheKey = (url, params) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return `${url}?${new URLSearchParams(params).toString()}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getCachedRequest = (url, params) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const key = getCacheKey(url, params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return requestCache.get(key) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const setCachedRequest = (url, params, data) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const key = getCacheKey(url, params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  requestCache.set(key, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    data, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    timestamp: Date.now(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    expiry: 5 * 60 * 1000 // 5分钟过期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const isCacheValid = (cachedItem) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return cachedItem && (Date.now() - cachedItem.timestamp < cachedItem.expiry) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 区域树形数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const regionTreeData = ref([]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const regionTreeProps = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  value: 'id', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  label: 'name', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  children: 'children', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  isLeaf: (data) => data.children_count === 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 存储原始配置用于恢复 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const originalChannelConfig = ref({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  timing_agreement: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channel_names: {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const formData = reactive({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  timing_id: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  timing_name: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  weeks: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  timing_start_time: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  region_ids: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  group_id: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  category_id: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  device_type_id: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  device_ids: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  timing_agreement: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channel_names: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  region_type: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  selectedRegionNode: null  // 新增:保存完整的区域节点信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const categoryOptions = ref([]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const deviceTypeOptions = ref([]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const deviceOptions = ref([]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const formRef = ref() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 星期数据配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const weekDays = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { value: 2, name: '周一', en: 'MON', isWeekend: false }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { value: 4, name: '周二', en: 'TUE', isWeekend: false }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { value: 8, name: '周三', en: 'WED', isWeekend: false }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { value: 16, name: '周四', en: 'THU', isWeekend: false }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { value: 32, name: '周五', en: 'FRI', isWeekend: false }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { value: 64, name: '周六', en: 'SAT', isWeekend: true }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { value: 128, name: '周日', en: 'SUN', isWeekend: true } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 表单验证规则 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const formRules = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  timing_name: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { required: true, message: '请输入策略名称', trigger: 'blur' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { min: 2, max: 50, message: '策略名称长度在 2 到 50 个字符', trigger: 'blur' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  weeks: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      required: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      validator: (rule, value, callback) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!value || value.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callback(new Error('请选择重复日期')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callback() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      trigger: 'change' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  timing_start_time: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { required: true, message: '请选择执行时间', trigger: 'change' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  region_ids: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      validator: (rule, value, callback) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (deviceSelectType.value === 'region' && !value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callback(new Error('请选择所属位置')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callback() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      trigger: 'change' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  group_id: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      validator: (rule, value, callback) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (deviceSelectType.value === 'group' && !value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callback(new Error('请选择设备分组')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callback() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      trigger: 'change' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  category_id: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { required: true, message: '请选择设备分类', trigger: 'change' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  device_type_id: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { required: true, message: '请选择设备型号', trigger: 'change' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  device_ids: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      required: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      validator: (rule, value, callback) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!value || value.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callback(new Error('请选择至少一个设备')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callback() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      trigger: 'change' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 路数名称验证规则 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const channelNameRules = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { min: 1, max: 20, message: '路数名称长度在 1 到 20 个字符', trigger: 'blur' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 计算属性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const weekMap = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  2: { label: '周一', type: 'primary' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  4: { label: '周二', type: 'success' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  8: { label: '周三', type: 'info' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  16: { label: '周四', type: 'warning' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  32: { label: '周五', type: 'danger' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  64: { label: '周六', type: '' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  128: { label: '周日', type: '' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  256: { label: '节假日执行', type: 'success' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  512: { label: '节假日不执行', type: 'danger' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const hasChannelName = (channelNum) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return formData.channel_names[`Tag${channelNum}`] && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.channel_names[`Tag${channelNum}`].trim() !== '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const hasChannelStatus = (channelNum) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return formData.timing_agreement[`Tag${channelNum}`] !== undefined && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.timing_agreement[`Tag${channelNum}`] !== null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getNamedChannelCount = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let count = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (hasChannelName(i)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      count++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return count 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getChannelStatusType = (channelNum) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const status = formData.timing_agreement[`Tag${channelNum}`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (status === 1) return 'success' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (status === 0) return 'danger' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return 'info' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getChannelStatusText = (channelNum) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const status = formData.timing_agreement[`Tag${channelNum}`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (status === 1) return '开启' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (status === 0) return '关闭' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return '未设置' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const toggleChannelStatus = (channelNum, targetStatus) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const currentStatus = formData.timing_agreement[`Tag${channelNum}`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (currentStatus === targetStatus) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 如果当前状态与目标状态相同,则取消选择 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.timing_agreement[`Tag${channelNum}`] = undefined 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 否则设置为目标状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.timing_agreement[`Tag${channelNum}`] = targetStatus 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 只有在没有名称时才设置默认名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!formData.channel_names[`Tag${channelNum}`] || formData.channel_names[`Tag${channelNum}`].trim() === '') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.channel_names[`Tag${channelNum}`] = `${channelNum}路` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleChannelNameChange = (channelNum) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 当用户输入路数名称时,不自动设置状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 用户可以选择只设置名称而不设置开关状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleChannelNameClear = (channelNum) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 当用户清空路数名称时,只清空名称,不影响状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.channel_names[`Tag${channelNum}`] = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 修改批量操作方法,避免强制设置名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const selectAllChannels = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.timing_agreement[`Tag${i}`] = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 只有在没有名称时才设置默认名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!formData.channel_names[`Tag${i}`] || formData.channel_names[`Tag${i}`].trim() === '') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.channel_names[`Tag${i}`] = `${i}路` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const unselectAllChannels = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.timing_agreement[`Tag${i}`] = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 只有在没有名称时才设置默认名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!formData.channel_names[`Tag${i}`] || formData.channel_names[`Tag${i}`].trim() === '') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.channel_names[`Tag${i}`] = `${i}路` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const reverseAllChannels = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const currentStatus = formData.timing_agreement[`Tag${i}`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (currentStatus === 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.timing_agreement[`Tag${i}`] = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (currentStatus === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.timing_agreement[`Tag${i}`] = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 如果是未配置状态,设置为开启 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.timing_agreement[`Tag${i}`] = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 只有在没有名称时才设置默认名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!formData.channel_names[`Tag${i}`] || formData.channel_names[`Tag${i}`].trim() === '') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.channel_names[`Tag${i}`] = `${i}路` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 修改判断是否有配置的方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const hasChannelConfig = (channelNum) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return hasChannelName(channelNum) || hasChannelStatus(channelNum) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const clearChannelStatus = (channelNum) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.timing_agreement[`Tag${channelNum}`] = undefined 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const isChannelConfigured = (channelNum) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return formData.timing_agreement[`Tag${channelNum}`] !== undefined 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getChannelStatusCount = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let on = 0, off = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (formData.timing_agreement[`Tag${i}`] === 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      on++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (formData.timing_agreement[`Tag${i}`] === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      off++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return { on, off } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const clearAllChannels = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.timing_agreement[`Tag${i}`] = undefined 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.channel_names[`Tag${i}`] = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 快捷选择相关计算属性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const isAllWeekdaysSelected = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const weekdays = [2, 4, 8, 16, 32] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return weekdays.every(day => formData.weeks.includes(day)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const isWeekendSelected = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const weekend = [64, 128] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return weekend.every(day => formData.weeks.includes(day)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const isAllWeekSelected = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const allWeek = [2, 4, 8, 16, 32, 64, 128] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return allWeek.every(day => formData.weeks.includes(day)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getSelectedWeekTags = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return formData.weeks.map(week => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value: week, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    label: weekMap[week]?.label || week, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    type: weekMap[week]?.type || '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 设备选择相关计算属性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const isAllDevicesSelected = computed({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  get() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return deviceOptions.value.length > 0 && formData.device_ids.length === deviceOptions.value.length 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  set(value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.device_ids = deviceOptions.value.map(item => item.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.device_ids = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const isDeviceIndeterminate = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return formData.device_ids.length > 0 && formData.device_ids.length < deviceOptions.value.length 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 监听设备选择变化 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+watch(() => formData.device_ids, (newVal) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (newVal.length > 0 && channelCount.value > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 确保路数配置存在,但不强制设置值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (formData.timing_agreement[`Tag${i}`] === undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 保持未配置状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.timing_agreement[`Tag${i}`] = undefined 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (formData.channel_names[`Tag${i}`] === undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.channel_names[`Tag${i}`] = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}, { deep: true }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 工具方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getWeekTags = (weeks) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!weeks || !Array.isArray(weeks)) return [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return weeks.map(week => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value: week, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    label: weekMap[week]?.label || week, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    type: weekMap[week]?.type || '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getAgreementTags = (agreement, channelNames = null) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!agreement) return [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const parsed = typeof agreement === 'string' ? JSON.parse(agreement) : agreement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const result = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const processedTags = new Set() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 收集所有的Tag和name信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const tagStatus = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const nameInfo = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Object.keys(parsed).forEach(key => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (key.startsWith('Tag') || key.startsWith('tag')) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const tagKey = key.startsWith('Tag') ? key : `Tag${key.replace('tag', '')}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const num = tagKey.replace('Tag', '') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tagStatus[num] = parseInt(parsed[key]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else if (key.startsWith('name')) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const num = key.replace('name', '') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        nameInfo[num] = parsed[key] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 处理所有有配置的路数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const allNums = new Set([...Object.keys(tagStatus), ...Object.keys(nameInfo)]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    allNums.forEach(num => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (processedTags.has(num)) return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      processedTags.add(num) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const hasStatus = tagStatus.hasOwnProperty(num) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const hasName = nameInfo.hasOwnProperty(num) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (hasStatus || hasName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let channelName = nameInfo[num] || `${num}路` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let label = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let type = 'info' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let configType = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let icon = null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (hasStatus && hasName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 完整配置:显示名称和状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const status = tagStatus[num] === 1 ? '开启' : '关闭' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          label = `${channelName}: ${status}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type = tagStatus[num] === 1 ? 'success' : 'danger' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          configType = 'full-config' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          icon = tagStatus[num] === 1 ? 'Check' : 'Close' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if (hasStatus && !hasName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 仅状态配置:显示默认名称和状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const status = tagStatus[num] === 1 ? '开启' : '关闭' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          label = `${num}路: ${status}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type = tagStatus[num] === 1 ? 'success' : 'danger' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          configType = 'status-only' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          icon = tagStatus[num] === 1 ? 'Check' : 'Close' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if (hasName && !hasStatus) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 仅名称配置:只显示名称,标记为标识用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          label = `${channelName} ` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type = 'warning' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          configType = 'name-only' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          icon = 'PriceTag' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        result.push({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          label: label, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          status: hasStatus ? (tagStatus[num] === 1 ? '开启' : '关闭') : '标识', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type: type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          configType: configType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          channelName: channelName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          tagNum: num, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          hasStatus: hasStatus, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          hasName: hasName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          icon: icon 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 按路数排序 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    result.sort((a, b) => parseInt(a.tagNum) - parseInt(b.tagNum)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('解析设备指令失败:', e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getChineseNumber = (num) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const numbers = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return numbers[num] || num 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const restoreChannelConfig = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (isEdit.value && originalChannelConfig.value.timing_agreement) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.timing_agreement = { ...originalChannelConfig.value.timing_agreement } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.channel_names = { ...originalChannelConfig.value.channel_names } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.success('已恢复原配置') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 星期选择相关方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const toggleWeekDay = (value) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const index = formData.weeks.indexOf(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (index > -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.weeks.splice(index, 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.weeks.push(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const toggleSpecialOption = (value) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const index = formData.weeks.indexOf(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (index > -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.weeks.splice(index, 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 如果是节假日相关选项,需要互斥 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (value === 256) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const notRunIndex = formData.weeks.indexOf(512) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (notRunIndex > -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.weeks.splice(notRunIndex, 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (value === 512) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const runIndex = formData.weeks.indexOf(256) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (runIndex > -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.weeks.splice(runIndex, 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.weeks.push(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const removeWeekDay = (value) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const index = formData.weeks.indexOf(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (index > -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.weeks.splice(index, 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const selectAllWeekdays = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const weekdays = [2, 4, 8, 16, 32] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (isAllWeekdaysSelected.value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    weekdays.forEach(day => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const index = formData.weeks.indexOf(day) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (index > -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.weeks.splice(index, 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    weekdays.forEach(day => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!formData.weeks.includes(day)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.weeks.push(day) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const selectWeekend = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const weekend = [64, 128] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (isWeekendSelected.value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    weekend.forEach(day => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const index = formData.weeks.indexOf(day) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (index > -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.weeks.splice(index, 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    weekend.forEach(day => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!formData.weeks.includes(day)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.weeks.push(day) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const selectAllWeek = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const allWeek = [2, 4, 8, 16, 32, 64, 128] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (isAllWeekSelected.value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    allWeek.forEach(day => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const index = formData.weeks.indexOf(day) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (index > -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.weeks.splice(index, 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    allWeek.forEach(day => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!formData.weeks.includes(day)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.weeks.push(day) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const clearAllWeeks = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.weeks = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 设备选择相关方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleSelectAllDevices = (value) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.device_ids = deviceOptions.value.map(item => item.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.device_ids = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleSelectTypeChange = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 切换选择方式时清空相关数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.region_ids = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.group_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.category_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_type_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_ids = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  categoryOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceTypeOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channelCount.value = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.timing_agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.channel_names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleLocationOrGroupChange = async (value, node) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 清空相关数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.category_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_type_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_ids = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceTypeOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channelCount.value = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.timing_agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.channel_names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (value && node) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 从选中的节点获取完整的数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.region_ids = node.id || node.value  // 获取选中节点的id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.region_type = node.type             // 获取选中节点的type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('选中的区域数据:', { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      id: formData.region_ids, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      type: formData.region_type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      node: node 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await fetchDeviceCategories() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 如果没有选中值,清空相关字段 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.region_ids = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.region_type = null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理区域选择变化 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleRegionSelectChange = async (value) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 清除之前的防抖定时器 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (debounceTimer) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clearTimeout(debounceTimer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  debounceTimer = setTimeout(async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('区域选择变化:', value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 获取选中节点的完整数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const selectedNode = regionTreeRef.value?.getCurrentNode?.() || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          regionTreeRef.value?.getNode?.(value)?.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (selectedNode) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.region_ids = selectedNode.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.region_type = selectedNode.type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.selectedRegionNode = selectedNode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        console.log('区域选择变化:', { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          value: value, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          selectedNode: selectedNode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 清空相关数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        resetDeviceSelections() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 获取设备分类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await fetchDeviceCategories() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 清空选择 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.region_ids = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.region_type = null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.selectedRegionNode = null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      resetDeviceSelections() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 300) // 300ms 防抖 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 重置设备相关选择 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const resetDeviceSelections = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.category_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_type_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_ids = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceTypeOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channelCount.value = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.timing_agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.channel_names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 丰富节点信息,获取父级信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const enrichNodeWithParentInfo = async (node) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const enrichedNode = { ...node } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 如果是房间类型且没有parentName,尝试获取 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (node.type === 3 && !node.parentName && node.parentId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const parentNode = await getNodeById(node.parentId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (parentNode) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        enrichedNode.parentName = parentNode.name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 确保有建筑信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!enrichedNode.buildingName && enrichedNode.BuildingId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const buildingNode = await getNodeById(enrichedNode.BuildingId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (buildingNode) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        enrichedNode.buildingName = buildingNode.name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return enrichedNode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('丰富节点信息失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return node 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 根据ID获取节点信息(可能需要调用API) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getNodeById = async (nodeId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 首先在已加载的树数据中查找 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const foundNode = findNodeInTree(regionTreeData.value, nodeId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (foundNode) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return foundNode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 如果在树中找不到,可能需要调用API获取 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 这里可以根据实际情况调用相应的API 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取节点信息失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 强制刷新树形选择器 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const refreshTreeSelect = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (regionTreeRef.value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 清空树数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      regionTreeData.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await nextTick() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 重新加载根节点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await loadRootRegions() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await nextTick() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 重新设置选中值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (formData.region_ids) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        regionTreeRef.value.setCurrentKey(formData.region_ids) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('刷新树形选择器失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 区域树形加载方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const loadRegionNode = async (node, resolve) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let params = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let url = `${__LOCAL_API__}/illuminating/getBuildingRegionRoomTree` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (node.level === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (node.level === 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params = { building_id: node.data.id } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        building_id: node.data.BuildingId || getBuildingIdFromPath(node), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        region_parent_id: node.data.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 检查缓存 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const cacheKey = getCacheKey(url, params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const cachedData = getCachedRequest(url, params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (isCacheValid(cachedData)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log('使用缓存数据:', cacheKey) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      resolve(cachedData.data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 检查是否正在请求中 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (requestQueue.has(cacheKey)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log('等待现有请求:', cacheKey) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const existingRequest = requestQueue.get(cacheKey) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const result = await existingRequest 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      resolve(result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 创建新请求 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const requestPromise = axios.get(url, { params }).then(response => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const data = response.data.data || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const treeData = data.map(item => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ...item, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          id: item.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type: item.type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          BuildingId: item.BuildingId || params.building_id || item.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          children: item.children_count > 0 ? [] : undefined, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          RegionId: item.RegionId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          IsLastRegion: item.IsLastRegion, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          RegionType: item.RegionType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          parentName: item.parentName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          parentId: item.parentId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          label: item.name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          value: item.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 缓存结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        setCachedRequest(url, params, treeData) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return treeData 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        throw new Error(response.data.message || '获取区域数据失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }).finally(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 请求完成后从队列中移除 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      requestQueue.delete(cacheKey) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 将请求加入队列 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    requestQueue.set(cacheKey, requestPromise) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const result = await requestPromise 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    resolve(result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取区域数据失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('获取区域数据失败,请检查网络连接') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    resolve([]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 辅助函数:从节点路径中获取建筑ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getBuildingIdFromPath = (node) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let currentNode = node 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while (currentNode && currentNode.level > 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    currentNode = currentNode.parent 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return currentNode?.data?.BuildingId || currentNode?.data?.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 为编辑模式加载完整的区域路径 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const loadRegionPathForEdit = async (regionId, regionType, buildingId, parentId, regionName, fullPath) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('加载编辑区域路径:', { regionId, regionType, buildingId, parentId, regionName, fullPath }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 增加树组件的key,强制重新渲染 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    treeKey.value++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 等待组件重新渲染 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await nextTick() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 1. 首先加载根节点(建筑列表)- 只在没有数据时加载 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (regionTreeData.value.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await loadRootRegions() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await nextTick() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 2. 根据类型逐级展开节点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (regionType >= 2 && buildingId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await expandBuildingNode(buildingId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await nextTick() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (regionType === 3 && parentId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await expandRegionNode(parentId, buildingId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await nextTick() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 3. 设置选中值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.region_ids = regionId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 4. 手动设置树的当前节点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (regionTreeRef.value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        regionTreeRef.value.setCurrentKey(regionId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } catch (e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        console.warn('setCurrentKey失败:', e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('区域路径加载完成') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('加载编辑区域路径失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 加载根节点区域 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const loadRootRegions = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 如果已经有数据,直接返回,避免重复加载 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (regionTreeData.value.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/getBuildingRegionRoomTree`) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const data = response.data.data || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 去重处理 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const uniqueData = data.filter((item, index, self) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          index === self.findIndex(t => t.id === item.id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      regionTreeData.value = uniqueData.map(item => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...item, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        id: item.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type: item.type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        BuildingId: item.id, // 建筑的BuildingId就是自己的id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        children: item.children_count > 0 ? [] : undefined, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        RegionId: item.RegionId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        IsLastRegion: item.IsLastRegion, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        RegionType: item.RegionType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parentName: item.parentName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parentId: item.parentId || 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        label: item.name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        value: item.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('加载根节点失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 展开建筑节点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const expandBuildingNode = async (buildingId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/getBuildingRegionRoomTree`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params: { building_id: buildingId } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const data = response.data.data || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 找到对应的建筑节点并更新其children 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const updateBuildingChildren = (nodes) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let node of nodes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (node.id === buildingId && node.type === 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            node.children = data.map(item => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              ...item, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              id: item.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              type: item.type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              BuildingId: buildingId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              children: item.children_count > 0 ? [] : undefined, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              RegionId: item.RegionId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              IsLastRegion: item.IsLastRegion, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              RegionType: item.RegionType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              parentName: item.parentName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              parentId: item.parentId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              label: item.name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              value: item.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (node.children && node.children.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (updateBuildingChildren(node.children)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              return true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      updateBuildingChildren(regionTreeData.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('展开建筑节点失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 展开区域节点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const expandRegionNode = async (regionId, buildingId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/getBuildingRegionRoomTree`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        building_id: buildingId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        region_parent_id: regionId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const data = response.data.data || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 找到对应的区域节点并更新其children 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const updateRegionChildren = (nodes) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let node of nodes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (node.id === regionId && node.type === 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            node.children = data.map(item => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              ...item, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              id: item.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              type: item.type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              BuildingId: buildingId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              children: item.children_count > 0 ? [] : undefined, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              RegionId: item.RegionId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              IsLastRegion: item.IsLastRegion, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              RegionType: item.RegionType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              parentName: item.parentName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              parentId: item.parentId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              label: item.name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              value: item.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (node.children && node.children.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (updateRegionChildren(node.children)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              return true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      updateRegionChildren(regionTreeData.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('展开区域节点失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 事件处理方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleSearch = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pagination.currentPage = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fetchData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleReset = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  searchForm.searchText = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  handleSearch() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleAdd = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  dialogTitle.value = '新增策略' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  isEdit.value = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  resetForm() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  dialogVisible.value = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleEdit = async (row) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dialogTitle.value = '编辑策略' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    isEdit.value = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 先重置表单和清空树数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    resetForm() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 先调用详情接口获取完整数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/getTimingId`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params: { timing_id: row.timing_id } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const data = response.data.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 解析region_ids,格式为 "2-5-1=09A/09A" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let regionId = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let regionType = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let buildingId = null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let parentId = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let selectedRegionNode = null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let regionName = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let fullPath = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (data.region_ids) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const parts = data.region_ids.split('=') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fullPath = parts[1] || '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const idParts = parts[0].split('-') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (idParts.length >= 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          regionType = parseInt(idParts[0]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          regionId = parseInt(idParts[1]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (idParts.length > 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            buildingId = parseInt(idParts[2]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 从完整路径中解析当前节点名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const pathParts = fullPath.split('/') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (regionType === 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            regionName = pathParts[0] || '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            buildingId = regionId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } else if (regionType === 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            regionName = pathParts[pathParts.length - 1] || '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } else if (regionType === 3) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            regionName = pathParts[pathParts.length - 1] || '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          selectedRegionNode = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            id: regionId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            name: regionName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            type: regionType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            parentId: parentId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            RegionId: parentId || regionId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BuildingId: buildingId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            buildingName: pathParts[0] || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            parentName: pathParts.length > 2 ? pathParts[pathParts.length - 2] : '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fullPath: fullPath 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 设置选择方式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceSelectType.value = data.group_id ? 'group' : 'region' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 填充表单数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      Object.assign(formData, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        timing_id: data.timing_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        timing_name: data.timing_name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        weeks: data.weeks || [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        timing_start_time: data.timing_start_time, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        region_ids: regionId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        region_type: regionType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        selectedRegionNode: selectedRegionNode, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        group_id: data.group_id || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        category_id: data.category_id || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        device_type_id: data.device_type_id || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        device_ids: data.device_ids || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 处理路数配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await handleTimingAgreementData(data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 先打开对话框 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      dialogVisible.value = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 等待DOM更新后再加载数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await nextTick() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 然后异步加载区域树和其他数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await Promise.all([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        loadRegionPathForEdit(regionId, regionType, buildingId, parentId, regionName, fullPath), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        loadEditData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.error(response.data.message || '获取策略详情失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('加载编辑数据失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('加载数据失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理设备指令数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleTimingAgreementData = async (data) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (data.timing_agreement) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const agreement = typeof data.timing_agreement === 'string' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ? JSON.parse(data.timing_agreement) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          : data.timing_agreement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log('原始设备配置:', agreement) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 分离Tag配置和name配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const tagAgreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const channelNames = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let maxTagNum = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 先初始化所有路数为未配置状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tagAgreement[`Tag${i}`] = undefined 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        channelNames[`Tag${i}`] = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      Object.keys(agreement).forEach(key => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (key.startsWith('Tag')) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 直接使用Tag1格式存储 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          tagAgreement[key] = parseInt(agreement[key]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const tagNum = parseInt(key.replace('Tag', '')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          maxTagNum = Math.max(maxTagNum, tagNum) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if (key.startsWith('name')) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const tagNum = key.replace('name', '') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          channelNames[`Tag${tagNum}`] = agreement[key] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 如果没有从agreement中获取到name配置,尝试从设备数据中获取 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (Object.keys(channelNames).filter(key => channelNames[key]).length === 0 && data.devices && data.devices.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const firstDevice = data.devices[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (firstDevice.devices_json_object) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            const deviceData = JSON.parse(firstDevice.devices_json_object) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (let i = 1; i <= maxTagNum; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              if (deviceData[`name${i}`] && !channelNames[`Tag${i}`]) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                channelNames[`Tag${i}`] = deviceData[`name${i}`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } catch (e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            console.error('解析设备数据失败:', e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.timing_agreement = tagAgreement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.channel_names = channelNames 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      channelCount.value = Math.max(maxTagNum, channelCount.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 保存原始配置用于恢复 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      originalChannelConfig.value = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        timing_agreement: { ...tagAgreement }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        channel_names: { ...channelNames } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log('解析后的配置:', { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tagAgreement, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        channelNames, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        maxTagNum 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } catch (e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('解析设备指令失败:', e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 加载编辑数据的辅助方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const loadEditData = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 1. 先加载设备分类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await fetchDeviceCategories() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 2. 如果有分类ID,加载设备型号 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (formData.category_id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await fetchDeviceTypes() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 3. 如果有设备型号ID,加载设备列表和路数信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (formData.device_type_id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await Promise.all([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fetchDevices(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fetchChannelCount(formData.device_type_id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('加载编辑数据失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleDetail = (row) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  detailData.value = row 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  detailVisible.value = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleStatusChange = async (row) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await updateStrategyStatus(row.timing_id, row.timing_state) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.success(`策略已${row.timing_state === 1 ? '启用' : '禁用'}`) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 恢复原状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    row.timing_state = row.timing_state === 1 ? 0 : 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('状态更新失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleSizeChange = (size) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pagination.pageSize = size 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fetchData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleCurrentChange = (page) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pagination.currentPage = page 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fetchData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleDialogClose = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  resetForm() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleCategoryChange = (categoryId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_type_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_ids = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceTypeOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channelCount.value = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.timing_agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.channel_names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (categoryId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fetchDeviceTypes() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleDeviceTypeChange = (deviceTypeId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_ids = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channelCount.value = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.timing_agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.channel_names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (deviceTypeId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fetchDevices() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fetchChannelCount(deviceTypeId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleDeviceChange = (deviceIds) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 设备选择变化时的处理 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (deviceIds.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 如果没有选择设备,清空路数配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.timing_agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.channel_names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleSubmit = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await formRef.value.validate() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    submitLoading.value = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 构建region_ids格式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let regionIdsStr = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (deviceSelectType.value === 'region' && formData.selectedRegionNode) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      regionIdsStr = buildRegionIdsString(formData.selectedRegionNode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 构建完整的设备控制配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const fullAgreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const fullCommitAgreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 处理所有有配置的路数(包括只有名称的和只有状态的) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const tagKey = `Tag${i}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const hasName = hasChannelName(i) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const hasStatus = hasChannelStatus(i) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (hasName || hasStatus) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 如果有状态配置,添加状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (hasStatus) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const lowerKey = tagKey.toLowerCase() // Tag1 -> tag1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const value = formData.timing_agreement[tagKey] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          fullAgreement[lowerKey] = value.toString() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          fullCommitAgreement[lowerKey] = value.toString() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 如果有名称配置,添加名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (hasName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const nameKey = tagKey.replace('Tag', 'name') // Tag1 -> name1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const nameValue = formData.channel_names[tagKey] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          fullAgreement[nameKey] = nameValue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          fullCommitAgreement[nameKey] = nameValue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if (hasStatus) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 如果只有状态没有名称,使用默认名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          /*const nameKey = tagKey.replace('Tag', 'name') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const defaultName = `${i}路` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          fullAgreement[nameKey] = defaultName 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          fullCommitAgreement[nameKey] = defaultName*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('完整的设备配置:', fullAgreement) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 构建提交数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const submitData = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      timing_name: formData.timing_name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      weeks: formData.weeks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      timing_start_time: formData.timing_start_time, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      device_ids: formData.device_ids, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      timing_agreement: JSON.stringify(fullAgreement), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      commit_agreement: JSON.stringify(fullCommitAgreement), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      timing_state: 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      radio: 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 根据选择方式添加不同的参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (deviceSelectType.value === 'region') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      submitData.region_ids = regionIdsStr 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      submitData.group_id = formData.group_id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 如果是编辑模式,添加timing_id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (isEdit.value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      submitData.timing_id = formData.timing_id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('提交的数据:', submitData) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (isEdit.value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await updateStrategy(submitData) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.success('编辑成功') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await createStrategy(submitData) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.success('新增成功') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dialogVisible.value = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fetchData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (error.message) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.error(error.message) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('表单验证失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } finally { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    submitLoading.value = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 查找选中的区域节点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const findSelectedRegionNode = (regionId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 从区域树中查找选中的节点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return findNodeInTree(regionTreeData.value, regionId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 构建region_ids字符串 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const buildRegionIdsString = (regionNode) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('构建region_ids,节点数据:', regionNode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 根据节点数据构建ID字符串 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let idParts = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 添加type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (regionNode.type !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      idParts.push(regionNode.type) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 添加id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (regionNode.id !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      idParts.push(regionNode.id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 根据类型添加第三个参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (regionNode.type === 2 && regionNode.BuildingId !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 区域类型:type-id-buildingId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      idParts.push(regionNode.BuildingId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (regionNode.type === 3 && regionNode.RegionId !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 房间类型:type-id-regionId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      idParts.push(regionNode.RegionId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 构建完整的层级路径名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const fullPath = buildFullPathName(regionNode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 组装最终的region_ids字符串 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const idString = idParts.join('-') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const result = `${idString}=${fullPath}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('构建的region_ids:', result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('构建region_ids失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return `${regionNode.id}=${regionNode.name || ''}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 构建完整的层级路径名称(优化版) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const buildFullPathName = (regionNode) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const pathParts = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 根据节点类型构建路径 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (regionNode.type === 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 建筑类型:只显示建筑名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pathParts.push(regionNode.name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (regionNode.type === 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 区域类型:建筑名称/区域名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (regionNode.buildingName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pathParts.push(regionNode.buildingName) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 如果没有buildingName,尝试从树中获取 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const buildingName = getBuildingNameById(regionNode.BuildingId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (buildingName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          pathParts.push(buildingName) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pathParts.push(regionNode.name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (regionNode.type === 3) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 房间类型:建筑名称/父区域名称/房间名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (regionNode.buildingName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pathParts.push(regionNode.buildingName) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const buildingName = getBuildingNameById(regionNode.BuildingId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (buildingName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          pathParts.push(buildingName) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 添加父区域名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (regionNode.parentName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pathParts.push(regionNode.parentName) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 添加当前房间名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pathParts.push(regionNode.name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return pathParts.join('/') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('构建路径名称失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return regionNode.name || '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 根据建筑ID获取建筑名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getBuildingNameById = (buildingId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 从区域树数据中查找建筑名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const building = findBuildingInTree(regionTreeData.value, buildingId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return building ? building.name : null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取建筑名称失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 在树中查找建筑 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const findBuildingInTree = (treeData, buildingId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (const node of treeData) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (node.type === 1 && node.id === buildingId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return node 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (node.children && node.children.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const found = findBuildingInTree(node.children, buildingId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (found) return found 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 递归查找树节点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const findNodeInTree = (treeData, targetId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (const node of treeData) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (node.id === targetId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return node 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (node.children && node.children.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const found = findNodeInTree(node.children, targetId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (found) return found 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const resetForm = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 清除防抖定时器 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (debounceTimer) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clearTimeout(debounceTimer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    debounceTimer = null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Object.assign(formData, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    timing_id: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    timing_name: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    weeks: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    timing_start_time: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    region_ids: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    group_id: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    category_id: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    device_type_id: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    device_ids: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    timing_agreement: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    channel_names: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    region_type: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    selectedRegionNode: null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channelCount.value = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceSelectType.value = 'region' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  categoryOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceTypeOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 清空树形数据缓存 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  regionTreeData.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 增加树组件的key,强制重新渲染 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  treeKey.value++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  originalChannelConfig.value = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    timing_agreement: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    channel_names: {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 清除表单验证 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (formRef.value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formRef.value.clearValidate() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// API 调用方法 (获取定时策略列表) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const fetchData = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      currentPage: pagination.currentPage, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pageSize: pagination.pageSize, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      searchText: searchForm.searchText 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/getDeviceOrgid`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      tableData.value = response.data.data.Timing || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pagination.total = response.data.data.count || 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.error(response.data.message || '获取数据失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取列表数据失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('获取数据失败,请检查网络连接') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取设备分类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const fetchDeviceCategories = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 必须有id和type才能查询 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!formData.region_ids || !formData.region_type) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log('缺少必要参数:', { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        region_ids: formData.region_ids, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        region_type: formData.region_type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 构建请求参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      id: formData.region_ids, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      type: formData.region_type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('fetchDeviceCategories 请求参数:', params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/categoryPart`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const categories = response.data.data.BaseDevicesCategorys || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      categoryOptions.value = categories.map(item => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        label: item.category_name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        value: item.category_id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log('获取到的设备分类:', categoryOptions.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.error(response.data.message || '获取设备分类失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取设备分类失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('获取设备分类失败,请检查网络连接') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取设备型号 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const fetchDeviceTypes = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      category_id: formData.category_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      devices_enabled: -1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 根据选择方式添加不同的参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (deviceSelectType.value === 'region' && formData.region_ids) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params.id = formData.region_ids 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params.type = formData.region_type  // 使用从区域选择中获取的真实type值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (deviceSelectType.value === 'group' && formData.group_id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params.id = formData.group_id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params.type = 'group'  // 或者根据实际情况设置group的type值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('fetchDeviceTypes 请求参数:', params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/getTypeFind`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const deviceTypes = response.data.data.baseDeviceType || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceTypeOptions.value = deviceTypes.map(item => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        label: item.devices_type_name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        value: item.devices_type_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        code: item.devices_type_code, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 从dialect_agreements中获取路数信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        channelCount: getChannelCountFromDialects(item.dialect_agreements || []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.error(response.data.message || '获取设备型号失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceTypeOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取设备型号失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('获取设备型号失败,请检查网络连接') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    deviceTypeOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 从dialect_agreements中获取路数信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getChannelCountFromDialects = (dialects) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const tagDialects = dialects.filter(dialect => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      dialect.dialect_key && dialect.dialect_key.startsWith('Tag') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (tagDialects.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 获取最大的Tag数字 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const maxTag = Math.max(...tagDialects.map(dialect => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const match = dialect.dialect_key.match(/Tag(\d+)/) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return match ? parseInt(match[1]) : 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return maxTag 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 默认返回8路 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return 8 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取设备列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const fetchDevices = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      device_type_id: formData.device_type_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      devices_enabled: -1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 根据选择方式添加不同的参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (deviceSelectType.value === 'region' && formData.region_ids) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params.position_id = formData.region_ids 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params.position_type = formData.region_type  // 使用真实的type值,而不是固定的'region' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (deviceSelectType.value === 'group' && formData.group_id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params.position_id = formData.group_id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params.position_type = 'group'  // 或者根据实际情况设置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('fetchDevices 请求参数:', params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/deviceAllMini`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const devices = response.data.data.devices || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceOptions.value = devices.map(item => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        label: `${item.devices_name} (${item.full_region_name}/${item.room_name})`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        value: item.devices_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        deviceInfo: item 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.error(response.data.message || '获取设备列表失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取设备列表失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('获取设备列表失败,请检查网络连接') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    deviceOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取设备路数信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const fetchChannelCount = async (deviceTypeId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const deviceType = deviceTypeOptions.value.find(item => item.value === deviceTypeId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (deviceType && deviceType.channelCount) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      channelCount.value = deviceType.channelCount 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 初始化路数配置(设置为未配置状态) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!isEdit.value || Object.keys(formData.timing_agreement).length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let i = 1; i <= deviceType.channelCount; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          agreement[`Tag${i}`] = undefined // 设置为未配置状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          names[`Tag${i}`] = '' // 名称为空 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.timing_agreement = agreement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.channel_names = names 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 如果没有找到路数信息,使用默认值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      channelCount.value = 8 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!isEdit.value || Object.keys(formData.timing_agreement).length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let i = 1; i <= 8; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          agreement[`Tag${i}`] = undefined // 设置为未配置状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          names[`Tag${i}`] = '' // 名称为空 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.timing_agreement = agreement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        formData.channel_names = names 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取路数信息失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 使用默认路数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    channelCount.value = 8 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!isEdit.value || Object.keys(formData.timing_agreement).length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      for (let i = 1; i <= 8; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        agreement[`Tag${i}`] = undefined // 设置为未配置状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        names[`Tag${i}`] = '' // 名称为空 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.timing_agreement = agreement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.channel_names = names 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 创建定时策略 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const createStrategy = async (data) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.post(`${__LOCAL_API__}/illuminating/timingSave`, data, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      headers: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        'Content-Type': 'application/json' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return response.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      throw new Error(response.data.message || '创建策略失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('创建策略失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error(error.response?.data?.message || error.message || '创建策略失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 更新定时策略 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const updateStrategy = async (data) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.post(`${__LOCAL_API__}/illuminating/timingSave`, data, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      headers: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        'Content-Type': 'application/json' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return response.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      throw new Error(response.data.message || '更新策略失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('更新策略失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error(error.response?.data?.message || error.message || '更新策略失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 更新策略状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const updateStrategyStatus = async (timingId, status) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      timing_id: timingId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      timing_state: status 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/changeState`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return response.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      throw new Error(response.data.message || '状态更新失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('更新状态失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error(error.response?.data?.message || error.message || '状态更新失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 删除定时策略 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const deleteStrategy = async (timingId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.delete(`${__LOCAL_API__}/illuminating/deleteTimingStrategy/${timingId}`) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return response.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      throw new Error(response.data.message || '删除策略失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('删除策略失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error(error.response?.data?.message || error.message || '删除策略失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 批量操作方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleBatchDelete = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const selectedRows = tableData.value.filter(row => row.selected) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (selectedRows.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.warning('请选择要删除的策略') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await ElMessageBox.confirm( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        `确定要删除选中的 ${selectedRows.length} 个策略吗?`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        '批量删除', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          confirmButtonText: '确定', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          cancelButtonText: '取消', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type: 'warning', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const deletePromises = selectedRows.map(row => deleteStrategy(row.timing_id)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await Promise.all(deletePromises) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.success('批量删除成功') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fetchData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (error !== 'cancel') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.error('批量删除失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleBatchEnable = async (enable = true) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const selectedRows = tableData.value.filter(row => row.selected) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (selectedRows.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.warning('请选择要操作的策略') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const action = enable ? '启用' : '禁用' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await ElMessageBox.confirm( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        `确定要${action}选中的 ${selectedRows.length} 个策略吗?`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        `批量${action}`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          confirmButtonText: '确定', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          cancelButtonText: '取消', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type: 'warning', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const updatePromises = selectedRows.map(row => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        updateStrategyStatus(row.timing_id, enable ? 1 : 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await Promise.all(updatePromises) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.success(`批量${action}成功`) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fetchData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (error !== 'cancel') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.error(`批量${enable ? '启用' : '禁用'}失败`) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 导出功能 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleExport = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/exportTimingStrategies`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        searchText: searchForm.searchText 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      responseType: 'blob' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 创建下载链接 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const blob = new Blob([response.data], { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const url = window.URL.createObjectURL(blob) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const link = document.createElement('a') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    link.href = url 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    link.download = `定时策略_${new Date().toISOString().slice(0, 10)}.xlsx` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    document.body.appendChild(link) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    link.click() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    document.body.removeChild(link) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    window.URL.revokeObjectURL(url) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.success('导出成功') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('导出失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('导出失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 复制策略 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleCopyStrategy = async (row) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dialogTitle.value = '复制策略' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    isEdit.value = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 先调用详情接口获取完整数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.get(`${__LOCAL_API__}/illuminating/getTimingId`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      params: { timing_id: row.timing_id } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const data = response.data.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 解析region_ids 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let regionId = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (data.region_ids) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const parts = data.region_ids.split('=')[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const idParts = parts.split('-') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        regionId = idParts.length === 2 ? idParts[1] : idParts[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 设置选择方式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceSelectType.value = data.group_id ? 'group' : 'region' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 复制数据但不包含ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      Object.assign(formData, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        timing_id: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        timing_name: `${data.timing_name}_副本`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        weeks: [...(data.weeks || [])], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        timing_start_time: data.timing_start_time, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        region_ids: regionId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        group_id: data.group_id || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        category_id: data.category_id || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        device_type_id: data.device_type_id || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        device_ids: [...(data.device_ids || [])] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 复制路数配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (data.timing_agreement) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const agreement = typeof data.timing_agreement === 'string' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              ? JSON.parse(data.timing_agreement) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              : data.timing_agreement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 从设备数据中提取路数名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const channelNames = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (data.devices && data.devices.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            const firstDevice = data.devices[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (firstDevice.devices_json_object) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                const deviceData = JSON.parse(firstDevice.devices_json_object) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                for (let i = 1; i <= 12; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  if (deviceData[`name${i}`]) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    channelNames[`Tag${i}`] = deviceData[`name${i}`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              } catch (e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                console.error('解析设备数据失败:', e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          formData.timing_agreement = { ...agreement } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          formData.channel_names = { ...channelNames } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const tagCount = Object.keys(agreement).length 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          channelCount.value = tagCount 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } catch (e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          console.error('解析设备指令失败:', e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 按顺序加载相关选项数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await loadEditData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      dialogVisible.value = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.error(response.data.message || '获取策略详情失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('加载复制数据失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('复制策略失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 预览策略执行时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const previewExecutionTimes = (weeks, startTime) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!weeks || weeks.length === 0 || !startTime) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const now = new Date() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const times = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 获取未来7天的执行时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (let i = 0; i < 7; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const date = new Date(now) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    date.setDate(date.getDate() + i) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const dayOfWeek = Math.pow(2, date.getDay() === 0 ? 7 : date.getDay()) // 转换为位值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (weeks.includes(dayOfWeek)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const [hours, minutes] = startTime.split(':') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      date.setHours(parseInt(hours), parseInt(minutes), 0, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      times.push({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        date: date.toLocaleDateString(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        time: startTime, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dayName: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][date.getDay()] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return times 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 验证策略冲突 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const validateStrategyConflict = async (formData) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await axios.post(`${__LOCAL_API__}/illuminating/validateTimingConflict`, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      weeks: formData.weeks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      timing_start_time: formData.timing_start_time, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      device_ids: formData.device_ids, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      timing_id: formData.timing_id // 编辑时传入,用于排除自身 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.data.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const conflicts = response.data.data.conflicts || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (conflicts.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const conflictMessages = conflicts.map(conflict => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            `策略"${conflict.timing_name}"在${conflict.conflict_time}存在冲突` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ).join('\n') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await ElMessageBox.confirm( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            `检测到以下时间冲突:\n${conflictMessages}\n\n是否继续保存?`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            '策略冲突警告', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              confirmButtonText: '继续保存', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              cancelButtonText: '取消', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              type: 'warning', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (error === 'cancel') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('验证策略冲突失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 验证失败时允许继续,但给出提示 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.warning('无法验证策略冲突,请手动检查') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理周数据转换 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const convertWeeksToArray = (weekValue) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (Array.isArray(weekValue)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return weekValue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (typeof weekValue === 'number') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const weeks = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const weekValues = [2, 4, 8, 16, 32, 64, 128, 256, 512] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    weekValues.forEach(value => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (weekValue & value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        weeks.push(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return weeks 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理周数据转换为数字 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const convertWeeksToNumber = (weeksArray) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!Array.isArray(weeksArray)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return weeksArray.reduce((sum, week) => sum + week, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 格式化区域显示 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const formatRegionDisplay = (regionIds) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!regionIds) return '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 如果是 "1-1=南京芯片之城一期" 格式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (regionIds.includes('=')) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return regionIds.split('=')[1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return regionIds 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 解析设备JSON对象获取路数名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const parseDeviceChannelNames = (devices) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const channelNames = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!devices || devices.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return channelNames 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 从第一个设备获取路数名称配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const firstDevice = devices[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (firstDevice && firstDevice.devices_json_object) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const deviceData = JSON.parse(firstDevice.devices_json_object) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 提取name1-name12的配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      for (let i = 1; i <= 12; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const nameKey = `name${i}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (deviceData[nameKey] && deviceData[nameKey].trim() !== '' && deviceData[nameKey] !== '备用') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          channelNames[`Tag${i}`] = deviceData[nameKey] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('解析设备JSON失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return channelNames 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 生成默认路数名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const generateDefaultChannelNames = (count) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (let i = 1; i <= count; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    names[`Tag${i}`] = `${getChineseNumber(i)}路` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return names 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 验证表单数据完整性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const validateFormData = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 验证基本信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!formData.timing_name.trim()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error('请输入策略名称') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!formData.timing_start_time) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error('请选择执行时间') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!formData.weeks || formData.weeks.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error('请选择重复日期') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 验证设备选择 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (deviceSelectType.value === 'region' && !formData.region_ids) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error('请选择所属位置') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (deviceSelectType.value === 'group' && !formData.group_id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error('请选择设备分组') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!formData.category_id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error('请选择设备分类') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!formData.device_type_id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error('请选择设备型号') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!formData.device_ids || formData.device_ids.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    throw new Error('请选择至少一个设备') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 路数配置验证(可选) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (channelCount.value > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 验证已配置的路数名称长度 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (let i = 1; i <= channelCount.value; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const tagKey = `Tag${i}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (formData.timing_agreement[tagKey] !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const channelName = formData.channel_names[tagKey] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (channelName && channelName.length > 20) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          throw new Error(`第${i}路的名称长度不能超过20个字符`) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理表格数据显示 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const processTableData = (data) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return data.map(item => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ...item, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 处理周数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    weeks: convertWeeksToArray(item.timing_week || item.weeks), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 格式化区域显示 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    region_display: formatRegionDisplay(item.region_ids), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 处理设备指令显示 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    agreement_display: item.timing_agreement ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (typeof item.timing_agreement === 'string' ? item.timing_agreement : JSON.stringify(item.timing_agreement)) : '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 初始化页面数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const initPageData = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    await fetchData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('初始化页面数据失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('初始化页面失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 重置所有选择器 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const resetAllSelectors = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.category_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_type_id = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.device_ids = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  categoryOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceTypeOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  deviceOptions.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channelCount.value = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.timing_agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.channel_names = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理区域选择变化 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleRegionChange = (value) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.region_ids = value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  resetAllSelectors() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fetchDeviceCategories() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理分组选择变化 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleGroupChange = (value) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  formData.group_id = value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  resetAllSelectors() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (value) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fetchDeviceCategories() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取设备型号的路数配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getDeviceTypeChannelConfig = async (deviceTypeId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const deviceType = deviceTypeOptions.value.find(item => item.value === deviceTypeId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!deviceType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return { count: 8, names: generateDefaultChannelNames(8) } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const count = deviceType.channelCount || 8 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const names = generateDefaultChannelNames(count) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { count, names } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取设备型号路数配置失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { count: 8, names: generateDefaultChannelNames(8) } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 更新路数配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const updateChannelConfig = async (deviceTypeId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const { count, names } = await getDeviceTypeChannelConfig(deviceTypeId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    channelCount.value = count 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 如果是新增或者没有现有配置,初始化配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!isEdit.value || Object.keys(formData.timing_agreement).length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const agreement = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      for (let i = 1; i <= count; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        agreement[`Tag${i}`] = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.timing_agreement = agreement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.channel_names = { ...names } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 编辑模式下,确保路数名称存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      for (let i = 1; i <= count; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!formData.channel_names[`Tag${i}`]) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          formData.channel_names[`Tag${i}`] = names[`Tag${i}`] || `${i}路` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('更新路数配置失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理编辑数据的特殊逻辑 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleEditDataSpecial = (data) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 处理周数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (data.timing_week !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.weeks = convertWeeksToArray(data.timing_week) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else if (data.weeks) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.weeks = Array.isArray(data.weeks) ? data.weeks : convertWeeksToArray(data.weeks) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 处理区域ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (data.region_ids) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const parts = data.region_ids.split('=')[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const idParts = parts.split('-') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formData.region_ids = idParts.length === 2 ? idParts[1] : idParts[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 处理设备指令和路数名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (data.timing_agreement) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const agreement = typeof data.timing_agreement === 'string' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ? JSON.parse(data.timing_agreement) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          : data.timing_agreement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.timing_agreement = { ...agreement } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 从设备数据中提取路数名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const deviceChannelNames = parseDeviceChannelNames(data.devices) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 合并路数名称(优先使用设备中的名称) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const channelNames = { ...generateDefaultChannelNames(Object.keys(agreement).length) } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      Object.assign(channelNames, deviceChannelNames) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      formData.channel_names = channelNames 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 设置路数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      channelCount.value = Object.keys(agreement).length 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 保存原始配置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      originalChannelConfig.value = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        timing_agreement: { ...agreement }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        channel_names: { ...channelNames } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('处理设备指令失败:', error) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 生命周期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  initPageData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 导出组件需要的方法和数据(如果需要的话) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+defineExpose({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fetchData, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  resetForm, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  handleAdd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  handleEdit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 添加清理过期缓存的方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const clearExpiredCache = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const now = Date.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (const [key, value] of requestCache.entries()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (now - value.timestamp > value.expiry) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      requestCache.delete(key) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 在组件卸载时清理 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+onUnmounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (debounceTimer) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clearTimeout(debounceTimer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  requestCache.clear() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  requestQueue.clear() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 定期清理过期缓存 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+setInterval(clearExpiredCache, 1800000) // 每分钟清理一次 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<style scoped> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.timing-strategy-page { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f5f7fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  min-height: 90vh; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 页面标题 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.page-header { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.page-title { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0 0 8px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.page-description { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 卡片样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.search-card, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.table-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.card-header { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  justify-content: space-between; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.card-header .header-left { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.count-tag { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-left: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 搜索表单 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.search-form { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-form--inline .el-form-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: inline-flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-right: 32px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  vertical-align: baseline; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.search-input { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 280px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 表格样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-table { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 12px 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-name { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.name-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.weeks-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex-wrap: wrap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-tag { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 2px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.time-display { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #606266; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.agreement-display { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex-wrap: wrap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.agreement-tag { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 2px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.action-buttons { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 分页 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.pagination-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  justify-content: flex-end; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-top: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 弹窗样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-dialog :deep(.el-dialog__header) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 12px 12px 0 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-dialog :deep(.el-dialog__title) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-dialog :deep(.el-dialog__headerbtn .el-dialog__close) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-dialog :deep(.el-dialog__body) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 表单样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-form { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  max-height: 60vh; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  overflow-y: auto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding-right: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.form-section { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 32px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #fafbfc; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-left: 4px solid #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.section-title { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0 0 20px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 设备选择样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.device-select-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.device-select-header { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 8px 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-bottom: 1px solid #e4e7ed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f8f9fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.device-count-info { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-top: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  text-align: right; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 路数配置操作按钮 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-operations { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  justify-content: space-between; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid #b3d8ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.operation-buttons { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-status-info { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #606266; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 重复日期选择样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.weeks-selection { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid #e4e7ed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.quick-select-buttons { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding-bottom: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-bottom: 1px solid #f0f0f0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.quick-select-buttons .el-button { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 8px 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 13px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.quick-select-buttons .el-button:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: translateY(-1px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-selection-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-days-grid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: grid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grid-template-columns: repeat(7, 1fr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f8f9fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 2px solid #e9ecef; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 16px 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cursor: pointer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  user-select: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  overflow: hidden; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item::before { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  content: ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  position: absolute; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  top: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  left: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  right: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bottom: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  opacity: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: opacity 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  z-index: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: translateY(-2px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item:hover::before { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  opacity: 0.1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item.selected { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #667eea; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: translateY(-2px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item.weekend { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #fff5f5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #fed7d7; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item.weekend.selected { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #f093fb; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.day-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  z-index: 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.day-name { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  line-height: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.day-en { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 11px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  opacity: 0.7; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  line-height: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.day-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  position: absolute; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  top: -8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  right: -8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  height: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #67c23a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 50%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  justify-content: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  opacity: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: scale(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item.selected .day-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  opacity: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: scale(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 特殊选项 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.special-options { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f8f9fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid #e9ecef; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.special-option-group { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.option-group-title { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0 0 12px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding-bottom: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-bottom: 1px solid #e9ecef; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.special-checkboxes { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.special-checkbox { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 10px 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 2px solid #e9ecef; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cursor: pointer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  user-select: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.special-checkbox:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.special-checkbox.checked { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #ecf5ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.checkbox-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  height: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid #dcdfe6; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 3px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  justify-content: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.special-checkbox.checked .checkbox-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.checkbox-label { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 选择结果预览 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.selection-preview { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-top: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid #b3d8ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.preview-title { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.preview-tags { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex-wrap: wrap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.preview-tag { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.preview-tag:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: scale(1.05); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 设备选择样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.select-type-radio { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.select-type-radio .el-radio { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-right: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 12px 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid #e4e7ed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.select-type-radio .el-radio:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.select-type-radio .el-radio.is-checked { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #ecf5ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.select-type-radio .el-radio :deep(.el-radio__input) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.select-type-radio .el-radio :deep(.el-radio__label) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 路数配置样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-grid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: grid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid #e4e7ed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-item:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-header { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: flex-start; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-number { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  min-width: 40px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  line-height: 32px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 路数名称表单项样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-name-form-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-name-form-item :deep(.el-form-item__content) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-left: 0 !important; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-name-form-item :deep(.el-form-item__error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  position: static; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-top: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-name-input { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-control { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  justify-content: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-radio { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-radio .el-radio { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 8px 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid #e4e7ed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.radio-off.is-checked { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #f56c6c; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #fef0f0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #f56c6c; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.radio-on.is-checked { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #67c23a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #67c23a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-radio .el-radio :deep(.el-radio__input) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-radio .el-radio :deep(.el-radio__label) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 弹窗底部 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.dialog-footer { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  justify-content: flex-end; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #fafbfc; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 0 0 12px 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0 -24px -24px -24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 详情弹窗 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.detail-dialog :deep(.el-dialog__header) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 12px 12px 0 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.detail-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 8px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.detail-section { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.detail-section h4 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0 0 16px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding-bottom: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-bottom: 2px solid #e4e7ed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.agreement-detail { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: grid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.agreement-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  justify-content: space-between; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 12px 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f8f9fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-left: 3px solid #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-name { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 树形选择器样式优化 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select :deep(.el-tree-node__content) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 8px 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select :deep(.el-tree-node__content):hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select :deep(.el-tree-node.is-current > .el-tree-node__content) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #ecf5ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select :deep(.el-tree-node__expand-icon) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select :deep(.el-tree-node__loading-icon) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 响应式设计 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@media (max-width: 1200px) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .channel-grid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-days-grid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grid-template-columns: repeat(4, 1fr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@media (max-width: 768px) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .timing-strategy-page { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .page-title { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    font-size: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .search-input { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    width: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .search-form .el-form-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    margin-bottom: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-days-grid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grid-template-columns: repeat(2, 1fr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-day-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 12px 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .day-name { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    font-size: 13px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .day-en { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    font-size: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .quick-select-buttons { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    flex-wrap: wrap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .special-checkboxes { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .channel-grid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grid-template-columns: 1fr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .agreement-detail { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grid-template-columns: 1fr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .action-buttons { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .strategy-dialog { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    width: 95% !important; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    margin: 0 auto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .detail-dialog { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    width: 95% !important; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    margin: 0 auto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .weeks-selection { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .preview-tags { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .channel-operations { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    align-items: stretch; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .operation-buttons { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    justify-content: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .select-type-radio { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@media (max-width: 480px) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-days-grid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grid-template-columns: 1fr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-day-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .quick-select-buttons { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grid-template-columns: repeat(2, 1fr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    display: grid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .channel-radio { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .special-checkboxes { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .special-checkbox { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 8px 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 滚动条样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-form::-webkit-scrollbar { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-form::-webkit-scrollbar-track { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f1f1f1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 3px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-form::-webkit-scrollbar-thumb { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #c1c1c1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 3px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-form::-webkit-scrollbar-thumb:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #a8a8a8; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 动画效果 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-card:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: translateY(-2px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-button { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-table__row { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-table__row:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #f5f7fa !important; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 设备选择下拉框头部样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.device-select-header :deep(.el-checkbox) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.device-select-header :deep(.el-checkbox__label) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #606266; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 表单验证错误样式优化 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-form-item.is-error :deep(.el-input__wrapper) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 0 0 1px #f56c6c inset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-form-item.is-error :deep(.el-select .el-input__wrapper) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 0 0 1px #f56c6c inset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-form-item.is-error :deep(.el-tree-select .el-input__wrapper) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 0 0 1px #f56c6c inset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 提交按钮加载状态 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-button.is-loading { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pointer-events: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 路数配置状态指示 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-status-info { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gap: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.channel-status-info::before { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  content: ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  height: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 50%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #67c23a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: inline-block; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化选择器样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-select-dropdown__item.selected { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化时间选择器样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-time-picker { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-time-picker :deep(.el-input__wrapper) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-time-picker :deep(.el-input__wrapper):hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 0 0 1px #409eff inset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化多选标签样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-select :deep(.el-tag) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 2px 4px 2px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #b3d8ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-select :deep(.el-tag .el-tag__close) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-select :deep(.el-tag .el-tag__close):hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化开关样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-switch.is-checked :deep(.el-switch__core) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #13ce66; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-switch :deep(.el-switch__core) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #ff4949; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化描述列表样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-descriptions :deep(.el-descriptions__header) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-descriptions :deep(.el-descriptions__title) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-descriptions :deep(.el-descriptions__body) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #fafbfc; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-descriptions :deep(.el-descriptions-item__label) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #606266; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #f8f9fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-descriptions :deep(.el-descriptions-item__content) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 工具提示样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tooltip__popper { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  max-width: 300px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  word-break: break-all; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 过渡动画 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.special-checkbox, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.preview-tag { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 焦点状态 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item:focus, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.special-checkbox:focus { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  outline: 2px solid #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  outline-offset: 2px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 禁用状态 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.week-day-item.disabled { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  opacity: 0.5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cursor: not-allowed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pointer-events: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 减少动画模式支持 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@media (prefers-reduced-motion: reduce) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-day-item, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .special-checkbox, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .preview-tag, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .day-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transition: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 树形选择器下拉面板样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  max-height: 300px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown :deep(.el-tree) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown :deep(.el-tree-node) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown :deep(.el-tree-node__content) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 8px 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.2s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown :deep(.el-tree-node__content):hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown :deep(.el-tree-node.is-current > .el-tree-node__content) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #ecf5ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown :deep(.el-tree-node__label) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #606266; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown :deep(.el-tree-node.is-current .el-tree-node__label) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 加载状态样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown :deep(.el-tree-node__loading-icon) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  animation: rotating 2s linear infinite; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@keyframes rotating { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  0% { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transform: rotate(0deg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  100% { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transform: rotate(360deg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 空状态样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tree-select-dropdown :deep(.el-tree__empty-block) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  text-align: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化表格行高 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-table :deep(.el-table__row) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  height: 60px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-table :deep(.el-table__cell) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 12px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化表格头部样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-table :deep(.el-table__header-wrapper) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f8f9fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.strategy-table :deep(.el-table__header th) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f8f9fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #495057; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-bottom: 2px solid #e9ecef; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化分页样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-pagination { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-pagination :deep(.el-pagination__total) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #606266; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-pagination :deep(.btn-prev), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-pagination :deep(.btn-next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-pagination :deep(.btn-prev):hover, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-pagination :deep(.btn-next):hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: translateY(-1px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-pagination :deep(.el-pager li) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0 2px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-pagination :deep(.el-pager li:hover) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: translateY(-1px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-pagination :deep(.el-pager li.is-active) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: translateY(-1px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化消息提示样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-message { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-message.el-message--success { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #b3d8ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-message.el-message--error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #fef0f0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #fbc4c4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #f56c6c; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化确认框样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-message-box { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-message-box__header { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px 24px 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-bottom: 1px solid #e9ecef; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-message-box__title { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 18px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-message-box__content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-message-box__btns { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 16px 24px 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-top: 1px solid #e9ecef; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化加载动画 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-loading-mask { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: rgba(255, 255, 255, 0.9); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  backdrop-filter: blur(4px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-loading-spinner { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化表单项间距 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-form-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-form-item:last-child { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化输入框样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-input__wrapper { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-input__wrapper:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 0 0 1px #c0c4cc inset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-input__wrapper.is-focus { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 0 0 1px #409eff inset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化选择器样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-select .el-input__wrapper { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cursor: pointer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-select .el-input__wrapper:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 0 0 1px #c0c4cc inset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-select .el-input__wrapper.is-focus { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 0 0 1px #409eff inset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化按钮样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-button { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-button:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: translateY(-1px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-button--primary { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #409eff 0%, #3a8ee6 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-button--primary:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #66b1ff 0%, #409eff 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-button--success { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #67c23a 0%, #5daf34 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #67c23a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-button--success:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #85ce61 0%, #67c23a 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 4px 12px rgba(103, 194, 58, 0.4); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 优化标签样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tag { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tag:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: scale(1.05); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tag--primary { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #ecf5ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #b3d8ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tag--success { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #f0f9ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #b3e19d; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #67c23a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tag--info { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #f4f4f5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #d3d4d6; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tag--warning { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #fdf6ec; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #f5dab1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #e6a23c; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-tag--danger { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: #fef0f0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-color: #fbc4c4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #f56c6c; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 打印样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@media print { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .timing-strategy-page { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    background: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .search-card, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .pagination-container, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .action-buttons { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    display: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .table-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    box-shadow: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border: 1px solid #ddd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .strategy-table { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 高对比度模式支持 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@media (prefers-contrast: high) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-day-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border-width: 3px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-day-item.selected { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border-width: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .special-checkbox { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border-width: 2px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .el-button { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border-width: 2px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 深色模式支持 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@media (prefers-color-scheme: dark) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .timing-strategy-page { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    background: #1a1a1a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: #e5e5e5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .search-card, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .table-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    background: #2d2d2d; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border-color: #404040; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .form-section { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    background: #2a2a2a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border-left-color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-day-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    background: #3a3a3a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border-color: #505050; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: #e5e5e5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .week-day-item:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    background: #404040; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .channel-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    background: #3a3a3a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border-color: #505050; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.action-btn { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  min-width: 60px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  height: 32px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid transparent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.action-btn { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  width: 40%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  min-width: auto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.control-btn { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.control-btn:hover:not(:disabled) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: translateY(-1px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.control-btn:disabled { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #c0c4cc; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #ffffff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cursor: not-allowed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  transform: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  box-shadow: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</style> 
			 |