소스 검색

照明系统对接

learshaw 1 일 전
부모
커밋
d4559b7ee9
3개의 변경된 파일1702개의 추가작업 그리고 1130개의 파일을 삭제
  1. 1347 1111
      ems-ui-cloud/src/views/adapter/zm/index.vue
  2. 175 7
      ems-ui-cloud/src/views/basecfg/device/index.vue
  3. 180 12
      ems-ui-cloud/src/views/devmgr/device/index.vue

+ 1347 - 1111
ems-ui-cloud/src/views/adapter/zm/index.vue

@@ -1,1256 +1,1492 @@
 <template>
   <div class="app-container">
-    <el-row :gutter="20">
-      <el-col :span="4" :xs="24">
-        <div class="head-container">
-          <el-input v-model="areaName" placeholder="请输入区域名称" clearable size="small" prefix-icon="el-icon-search"
-                    style="margin-bottom: 20px"
-          />
-        </div>
-        <div class="head-container" style="height: 100vh; overflow: hidden; position: relative;">
-          <el-tree :data="treeAreaOptions" :props="defaultProps" :expand-on-click-node="false"
-                   :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current
-                   @node-click="handleNodeClick" style="height: calc(100vh - 50px); overflow-y: auto;"
-          />
-        </div>
-      </el-col>
-      <el-col :span="20" :xs="24">
-        <div class="contents">
-          <div class="other-content">
-            <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
-                     label-width="68px"
-            >
-              <el-form-item label="设备分类" prop="deviceSubCategory">
-                <el-select v-model="queryParams.deviceSubCategory">
-                  <el-option v-for="item in subCategoryOptions" placeholder="设备分类" :label="item.name"
-                             :value="item.code"
-                             :key="item.code"
-                  />
-                </el-select>
-              </el-form-item>
-              <el-form-item label="归属设施" prop="refFacs">
-                <el-select v-model="queryParams.refFacs">
-                  <el-option v-for="item in facsOptions" :label="item.facsName" :value="item.facsCode"
-                             :key="item.facsCode"
-                  />
-                </el-select>
-              </el-form-item>
-              <el-form-item label="子系统" prop="subsystemCode">
-                <el-select v-model="queryParams.subsystemCode">
-                  <el-option v-for="item in subsystemOptions" :label="item.systemName" :value="item.systemCode"
-                             :key="item.systemCode"
-                  />
-                </el-select>
-              </el-form-item>
-              <el-form-item>
-                <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-                <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-              </el-form-item>
-            </el-form>
-
-            <el-row :gutter="10" class="mb8">
-              <el-col :span="1.5">
-                <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
-                           v-hasPermi="['ems:device:add']"
-                >新增
-                </el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
-                           v-hasPermi="['ems:device:edit']"
-                >修改
-                </el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
-                           @click="handleDelete"
-                           v-hasPermi="['ems:device:remove']"
-                >删除
-                </el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
-                           v-hasPermi="['ems:device:export']"
-                >导出
-                </el-button>
-              </el-col>
-              <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-            </el-row>
+    <!-- 系统基础信息卡片 -->
+    <el-card class="system-info-card">
+      <div slot="header" class="card-header">
+        <span class="title">
+          <i class="el-icon-sunny"></i>
+          {{ systemInfo.systemName || '智慧照明系统' }}
+        </span>
+        <el-tag :type="systemStatus === '1' ? 'success' : 'danger'" effect="dark">
+          {{ systemStatus === '1' ? '正常' : '异常' }}
+        </el-tag>
+      </div>
+
+      <el-row :gutter="20">
+        <el-col :span="6">
+          <div class="info-group">
+            <div class="group-title">系统信息</div>
+            <div class="info-item">
+              <label>系统代码:</label>
+              <span class="code">{{ systemInfo.systemCode }}</span>
+            </div>
+            <div class="info-item">
+              <label>系统名称:</label>
+              <span>{{ systemInfo.systemName }}</span>
+            </div>
+            <div class="info-item">
+              <label>系统简称:</label>
+              <span>{{ systemInfo.shortName || '-' }}</span>
+            </div>
+            <div class="info-item">
+              <label>模型代码:</label>
+              <span class="code">{{ systemInfo.modelCode }}</span>
+            </div>
           </div>
-
-          <div class="table-content">
-            <!--分页-->
-            <div class="button-group-container">
-              <el-button-group>
-                <el-button :type="primary1" icon="el-icon-s-fold" @click="switchData(1)"/>
-                <el-button :type="primary2" icon="el-icon-menu" @click="switchData(2)"/>
-              </el-button-group>
+        </el-col>
+        <el-col :span="6">
+          <div class="info-group">
+            <div class="group-title">厂商信息</div>
+            <div class="info-item">
+              <label>对接厂商:</label>
+              <span>{{ systemInfo.manFacturer || '-' }}</span>
             </div>
-
-            <el-table v-loading="loading" :data="deviceList" @selection-change="handleSelectionChange"
-                      v-if="istable === 1">
-              <el-table-column type="selection" width="55" align="center"/>
-              <el-table-column label="设备名称" align="left" prop="deviceName"/>
-              <el-table-column label="安装位置" align="left" prop="areaPath" width="220px"/>
-              <el-table-column label="归属设施" align="center" prop="refFacsName"/>
-              <el-table-column label="设备分类" align="center" prop="deviceCategoryName"/>
-              <el-table-column label="子系统" align="center" prop="subsystemName"/>
-              <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-                <template slot-scope="scope">
-                  <el-button size="mini" type="text" icon="el-icon-info" @click="handleDevProcess(scope.row)"
-                             v-hasPermi="['basecfg:device:edit']" v-if="shouldShowDevProcessButton(scope.row)"
-                  >
-                    器件
-                  </el-button>
-                  <el-button size="mini" type="text" icon="el-icon-info" @click="handleDetail(scope.row)"
-                             v-hasPermi="['basecfg:device:edit']"
-                  >
-                    详情
-                  </el-button>
-                  <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
-                             v-hasPermi="['basecfg:device:edit']"
-                  >
-                    修改
-                  </el-button>
-                  <el-button size="mini" type="text" icon="el-icon-delete" class="deleteBtn"
-                             @click="handleDelete(scope.row)" v-hasPermi="['basecfg:device:remove']"
-                  >
-                    删除
+            <div class="info-item">
+              <label>联系人:</label>
+              <span>{{ systemInfo.contactPerson || '-' }}</span>
+            </div>
+            <div class="info-item">
+              <label>联系电话:</label>
+              <span>{{ systemInfo.contactNumber || '-' }}</span>
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="6">
+          <div class="info-group">
+            <div class="group-title">维护信息</div>
+            <div class="info-item">
+              <label>维护人:</label>
+              <span>{{ systemInfo.maintainerPerson || '-' }}</span>
+            </div>
+            <div class="info-item">
+              <label>维护电话:</label>
+              <span>{{ systemInfo.maintainerNumber || '-' }}</span>
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="6">
+          <div class="info-group">
+            <div class="group-title">系统统计</div>
+            <div class="info-item">
+              <label>项目数量:</label>
+              <span class="stat-number">{{ projectList.length }}</span>
+            </div>
+            <div class="info-item">
+              <label>分组数量:</label>
+              <span class="stat-number">{{ subsetList.length }}</span>
+            </div>
+            <div class="info-item">
+              <label>设备总数:</label>
+              <span class="stat-number">{{ deviceStats.total }}</span>
+            </div>
+          </div>
+        </el-col>
+      </el-row>
+    </el-card>
+
+    <!-- 系统详情标签页 -->
+    <el-card class="detail-card">
+      <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+        <!-- 系统总览标签页 -->
+        <el-tab-pane label="系统总览" name="overview">
+          <div class="tab-content">
+            <!-- 快速操作面板 -->
+            <div class="quick-actions">
+              <h4 class="section-title">
+                <i class="el-icon-s-operation"></i>
+                快速操作
+              </h4>
+              <el-row :gutter="20">
+                <el-col :span="6" v-for="action in quickActions" :key="action.key">
+                  <el-button
+                    class="action-btn"
+                    :icon="action.icon"
+                    @click="handleQuickAction(action)"
+                    :loading="action.loading">
+                    {{ action.name }}
                   </el-button>
+                </el-col>
+              </el-row>
+            </div>
 
-                </template>
-              </el-table-column>
-            </el-table>
-
-            <div v-else-if="istable === 2">
-              <el-row :gutter="20" class="device-list">
-                <el-col v-for="device in deviceList" :key="device.id" :span="6">
-                  <div :class="`device-card ${backStyle(device.areaPath)}`">
-                    <div class="device-header">
-                      <i class="el-icon-s-operation" style="margin-right: 8px;"></i>
-                      {{ device.deviceName }}
+            <!-- 实时监控面板 -->
+            <div class="monitor-panel">
+              <h4 class="section-title">
+                <i class="el-icon-monitor"></i>
+                实时监控
+              </h4>
+              <el-row :gutter="20">
+                <el-col :span="6">
+                  <div class="monitor-card">
+                    <div class="monitor-icon online">
+                      <i class="el-icon-circle-check"></i>
+                    </div>
+                    <div class="monitor-info">
+                      <div class="monitor-value">{{ deviceStats.online }}</div>
+                      <div class="monitor-label">在线设备</div>
                     </div>
-                    <div class="device-body">
-                      <p>设备代码:<span class="device-code">{{ device.deviceCode }}</span></p>
-                      <p>安装位置:<span class="deviceOthers">{{ device.areaPath }}</span></p>
-                      <p>归属设施:<span class="deviceOthers">{{ device.refFacsName }}</span></p>
-                      <p>设备分类:<span class="deviceOthers">{{ device.deviceCategoryName }}</span></p>
-                      <p>子系统:<span class="deviceOthers">{{ device.subsystemName }}</span></p>
+                  </div>
+                </el-col>
+                <el-col :span="6">
+                  <div class="monitor-card">
+                    <div class="monitor-icon offline">
+                      <i class="el-icon-circle-close"></i>
+                    </div>
+                    <div class="monitor-info">
+                      <div class="monitor-value">{{ deviceStats.offline }}</div>
+                      <div class="monitor-label">离线设备</div>
+                    </div>
+                  </div>
+                </el-col>
+                <el-col :span="6">
+                  <div class="monitor-card">
+                    <div class="monitor-icon lamps">
+                      <i class="el-icon-light"></i>
                     </div>
-                    <div class="device-footer">
-                      <el-button size="mini" plain icon=" el-icon-document" @click="handleDetail(device)">详情
-                      </el-button>
-                      <el-button size="mini" plain icon="el-icon-edit" @click="handleUpdate(device)">修改</el-button>
-                      <el-button size="mini" plain icon="el-icon-delete" type="danger" @click="handleDelete(device)">
-                        删除
-                      </el-button>
+                    <div class="monitor-info">
+                      <div class="monitor-value">{{ lampStats.on }}</div>
+                      <div class="monitor-label">开启灯组</div>
+                    </div>
+                  </div>
+                </el-col>
+                <el-col :span="6">
+                  <div class="monitor-card">
+                    <div class="monitor-icon power">
+                      <i class="el-icon-s-data"></i>
+                    </div>
+                    <div class="monitor-info">
+                      <div class="monitor-value">{{ totalPower.toFixed(2) }}W</div>
+                      <div class="monitor-label">总功率</div>
                     </div>
                   </div>
                 </el-col>
               </el-row>
             </div>
+          </div>
+        </el-tab-pane>
+
+        <!-- 系统属性标签页 -->
+        <el-tab-pane label="系统属性" name="attributes">
+          <div class="tab-content">
+            <!-- 协议属性 -->
+            <div class="attr-section" v-if="protocolAttrs.length > 0">
+              <h4 class="section-title">
+                <i class="el-icon-connection"></i>
+                协议信息
+              </h4>
+              <el-table :data="protocolAttrs" border stripe>
+                <el-table-column prop="attrName" label="属性名称" width="200"></el-table-column>
+                <el-table-column label="属性值">
+                  <template slot-scope="scope">
+                    <span v-if="scope.row.attrKey === 'url'" class="url-text">
+                      {{ scope.row.attrValue }}
+                    </span>
+                    <span v-else-if="scope.row.attrKey === 'password'">
+                      ••••••••
+                    </span>
+                    <span v-else>{{ scope.row.attrValue || '-' }}</span>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </div>
 
+            <!-- 状态属性 -->
+            <div class="attr-section" v-if="stateAttrs.length > 0">
+              <h4 class="section-title">
+                <i class="el-icon-info"></i>
+                状态信息
+              </h4>
+              <el-table :data="stateAttrs" border stripe>
+                <el-table-column prop="attrName" label="属性名称" width="200"></el-table-column>
+                <el-table-column label="属性值">
+                  <template slot-scope="scope">
+                    <el-tag v-if="scope.row.attrKey === 'interfaceStatus'"
+                            :type="scope.row.attrValue === '1' ? 'success' : 'danger'">
+                      {{ scope.row.attrValueName }}
+                    </el-tag>
+                    <span v-else>{{ scope.row.attrValueName || scope.row.attrValue || '-' }}</span>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="updateTime" label="更新时间" width="180"></el-table-column>
+              </el-table>
+            </div>
 
-            <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
-                        :limit.sync="queryParams.pageSize"
-                        @pagination="getList"
-            />
-
-            <!-- 添加或修改能源设备对话框 -->
-            <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-              <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-                <el-form-item label="归属设施" prop="refFacs">
-                  <el-select v-model="form.refFacs">
-                    <el-option v-for="item in facsOptions" :label="item.facsName" :value="item.facsCode"
-                               :key="item.facsCode"
-                    />
-                  </el-select>
-                </el-form-item>
-
-                <el-form-item label="设备代码" prop="deviceCode">
-                  <el-input v-model="form.deviceCode" placeholder="请输入设备代码"/>
-                </el-form-item>
-                <el-form-item label="设备名称" prop="deviceName">
-                  <el-input v-model="form.deviceName" placeholder="请输入设备名称"/>
-                </el-form-item>
-
-
-                <el-form-item label="功能类型" prop="psCode" v-if="queryParams.deviceCategory === 'W'">
-                  <el-select v-model="form.psCode">
-                    <el-option v-for="item in devOptions" :label="item.psName" :value="item.psCode"
-                               :key="item.psCode"
-                    />
-                  </el-select>
-                </el-form-item>
-
-                <el-form-item label="设备类型" prop="deviceType">
-                  <el-select v-model="form.deviceCategory">
-                    <el-option v-for="item in subCategoryOptions" :label="item.name" :value="item.code"
-                               :key="item.code"
-                    />
-                  </el-select>
-                </el-form-item>
-                <el-form-item label="设备模型" prop="deviceModel">
-                  <el-select v-model="form.deviceModel" style="width:100%" @change="handleModelChange">
-                    <el-option
-                      v-for="item in modelList"
-                      :label="item.modelName"
-                      :value="item.modelCode"
-                      :key="item.modelCode"
-                    />
-                  </el-select>
-                </el-form-item>
-                <!-- 这里可以展示属性名称和属性值 -->
-                <div v-if="attrList.length > 0" class="attr-list-container">
-                  <h3>模型属性:</h3>
-                  <ul>
-                    <li v-for="attr in attrList" :key="attr.attrKey" class="attr-item">
-                      <span class="attr-name">{{ attr.attrName }} ({{ attr.attrUnit }}):</span>
-                      <!-- 使用 el-input 组件允许用户编辑属性值 -->
-                      <el-input
-                        v-model="attrValuesMap[attr.attrKey]"
-                        placeholder="点击编辑"
-                        size="small"
-                        @blur="updateAttrValue(attr.attrKey, attrValuesMap[attr.attrKey])"
-                      >
-                      </el-input>
-                    </li>
-                  </ul>
-                </div>
-                <h3 class="attr-list-container" v-if="attrList.length > 0">自定义属性
-                  <el-form-item label="" prop="attrList">
-                    <el-table class="attr-table" v-loading="loading" :data="form.customAttrs" max-height="280px"
-                              key="'customAttrs'"
-                    >
-                      <el-table-column label="标识" align="center" prop="attrKey">
-                        <template slot-scope="scope">
-                          <el-input size="mini" v-model="scope.row.attrKey" placeholder="请输入标识"/>
-                        </template>
-                      </el-table-column>
-                      <el-table-column label="属性名" align="center" prop="attrName">
-                        <template slot-scope="scope">
-                          <el-input size="mini" v-model="scope.row.attrName" placeholder="请输入属性名"/>
-                        </template>
-                      </el-table-column>
-                      <el-table-column label="属性值" align="center" prop="attrValue">
-                        <template slot-scope="scope">
-                          <el-input size="mini" v-model="scope.row.attrValue" placeholder="请输入属性值"/>
-                        </template>
-                      </el-table-column>
-                      <el-table-column align="center" label="操作">
-                        <template slot="header">
-                          <div class="operateBtns" @click="addCustomAttr">
-                            <span>添加</span><i class="el-icon-circle-plus-outline"></i>
-                          </div>
-                        </template>
-                        <template slot-scope="scope">
-                          <i class="el-icon-delete" @click="deleteCustomAttr(scope.$index)"></i>
-                        </template>
-                      </el-table-column>
-                    </el-table>
-                  </el-form-item>
-                </h3>
-                <el-form-item label="子系统" prop="subsystemCode">
-                  <el-select v-model="form.subsystemCode">
-                    <el-option v-for="item in subsystemOptions" :label="item.systemName" :value="item.systemCode"
-                               :key="item.systemCode"
-                    />
-                  </el-select>
-                </el-form-item>
-              </el-form>
-              <div slot="footer" class="dialog-footer">
-                <el-button type="primary" @click="submitForm">确 定</el-button>
-                <el-button @click="cancel">取 消</el-button>
-              </div>
-            </el-dialog>
-
-            <!--设备器件-->
-            <el-drawer :title=ComponentRow.deviceName size="80%" :visible.sync="showDevProcessDrawer" direction="rtl">
-              <div class="drawer-content" style="padding-left:50px">
-                <el-row :gutter="10" class="mb8">
-                  <el-col :span="1.5">
-                    <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleComponentAdd"
-                               v-hasPermi="['ems:component:add']"
-                    >新增
-                    </el-button>
-                  </el-col>
-                </el-row>
-                <el-table v-loading="loading" :data="ComponentList">
-                  <el-table-column type="selection" width="55" align="center"/>
-                  <el-table-column label="部件编码" align="center" prop="compoCode"/>
-                  <el-table-column label="部件标签" align="center" prop="compoTag">
+            <!-- 基础属性 -->
+            <div class="attr-section" v-if="baseAttrs.length > 0">
+              <h4 class="section-title">
+                <i class="el-icon-folder"></i>
+                基础信息
+              </h4>
+
+              <!-- 项目列表 -->
+              <div v-if="projectList.length > 0" class="project-section">
+                <h5>项目列表</h5>
+                <el-table :data="projectList" border stripe size="small">
+                  <el-table-column prop="projectName" label="项目名称"></el-table-column>
+                  <el-table-column prop="projectAddress" label="项目地址"></el-table-column>
+                  <el-table-column prop="projectDeviceNum" label="设备数量" width="100" align="center">
                     <template slot-scope="scope">
-                      {{ objComTypeMapping[scope.row.compoTag] }}
+                      <el-tag size="small">{{ scope.row.projectDeviceNum }}</el-tag>
                     </template>
                   </el-table-column>
-                  <el-table-column label="工艺标识代码" align="center" prop="psCode"/>
-                  <el-table-column label="外系统部件编码" align="center" prop="extCompoCode"/>
-                  <el-table-column label="部件模型" align="center" prop="compoModel"/>
-                  <el-table-column label="部件品牌" align="center" prop="compoBrand"/>
-                  <el-table-column label="部件型号" align="center" prop="compoSpec"/>
-                  <el-table-column label="祖籍列表" align="center" prop="ancestors"/>
-                  <el-table-column label="上级部件" align="center" prop="parentEqpt"/>
-
-                  <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+                  <el-table-column prop="projectSubsetNum" label="分组数量" width="100" align="center">
                     <template slot-scope="scope">
-                      <el-button size="mini" type="text" icon="el-icon-edit" @click="handleComponentUpdate(scope.row)"
-                                 v-hasPermi="['ems:component:edit']"
-                      >
-                        修改
-                      </el-button>
-                      <el-button size="mini" type="text" icon="el-icon-delete" class="deleteBtn"
-                                 @click="handleComponentDelete(scope.row)" v-hasPermi="['ems:component:remove']"
-                      >
-                        删除
-                      </el-button>
+                      <el-tag size="small" type="info">{{ scope.row.projectSubsetNum }}</el-tag>
                     </template>
                   </el-table-column>
                 </el-table>
-                <pagination v-show="total>0" :total="total" :page.sync="queryComponentParams.pageNum"
-                            :limit.sync="queryComponentParams.pageSize"
-                            @pagination="getComponentList"
-                />
-
-                <!-- 添加或修改设备器件对话框 -->
-                <el-dialog :title="title" :visible.sync="componentOpen" width="500px" append-to-body>
-                  <el-form ref="componentForm" :model="componentForm" :rules="componentRules" label-width="150px">
-                    <!--                <el-form-item label="设备code" prop="deviceCode">-->
-                    <!--                  <el-input v-model="componentForm.deviceCode" placeholder="请输入设备code" />-->
-                    <!--                </el-form-item>-->
-                    <el-form-item label="部件编码" prop="compoCode">
-                      <el-input v-model="componentForm.compoCode" placeholder="请输入部件编码"/>
-                    </el-form-item>
-                    <el-form-item label="部件标签" prop="compoTag">
-                      <el-select v-model="componentForm.compoTag" placeholder="请输入部件标签">
-                        <el-option v-for="item in objComTypeOptions"
-                                   :label="item.name"
-                                   :value="item.code"
-                                   :key="item.code"
-                        />
-
-                      </el-select>
-                    </el-form-item>
-                    <el-form-item label="工艺标签代码" prop="psCode">
-                      <el-select v-model="componentForm.psCode" placeholder="请输入工艺标签代码">
-                        <el-option v-for="item in devOptions" :label="item.psCode" :value="item.psCode"
-                                   :key="item.psCode"/>
-                      </el-select>
-                    </el-form-item>
-                    <el-form-item label="外系统部件编码" prop="extCompoCode">
-                      <el-input v-model="componentForm.extCompoCode" placeholder="请输入外系统部件编码"/>
-                    </el-form-item>
-                    <el-form-item label="部件模型" prop="compoModel">
-                      <el-select v-model="componentForm.compoModel" placeholder="请输入部件模型">
-                        <el-option v-for="item in this.modelList" :label="item.modelCode" :value="item.modelCode"
-                                   :key="item.modelCode"
-                        />
-                      </el-select>
-                    </el-form-item>
-                    <el-form-item label="部件品牌" prop="compoBrand">
-                      <el-input v-model="componentForm.compoBrand" placeholder="请输入部件品牌"/>
-                    </el-form-item>
-                    <el-form-item label="部件型号" prop="compoSpec">
-                      <el-input v-model="componentForm.compoSpec" placeholder="请输入部件型号"/>
-                    </el-form-item>
-                    <el-form-item label="祖籍列表" prop="ancestors">
-                      <el-input v-model="componentForm.ancestors" placeholder="请输入祖籍列表"/>
-                    </el-form-item>
-                    <el-form-item label="上级列表" prop="parentCompo">
-                      <el-input v-model="componentForm.parentCompo" placeholder="请输入上级列表"/>
-                    </el-form-item>
-
-                  </el-form>
-                  <div slot="footer" class="dialog-footer">
-                    <el-button type="primary" @click="submitComponentForm">确 定</el-button>
-                    <el-button @click="ComponentCancel">取 消</el-button>
-                  </div>
-                </el-dialog>
               </div>
-            </el-drawer>
-
-            <!-- 详情弹框 -->
-            <el-dialog :visible.sync="showDrawer" title="设备详情">
-              <div v-if="curRow">
-                <!-- 设备基本信息 -->
-                <el-card class="box-card">
-                  <div slot="header" class="clearfix">
-                    <span class="section-title">设备基本信息</span>
-                  </div>
-                  <div>
-                    <p>设备代码:{{ curRow.deviceCode }}</p>
-                    <p>设备名称:{{ curRow.deviceName }}</p>
-                    <p>设备类型:{{ curRow.deviceCategoryName }}</p>
-                    <p>子系统:{{ curRow.subsystemName }}</p>
-                    <p>归属区域:{{ curRow.areaPath }}</p>
-                    <p>归属设施:{{ curRow.refFacsName }}</p>
-                  </div>
-                </el-card>
-                <el-card class="box-card" style="margin-top: 10px">
-                  <div slot="header" class="clearfix">
-                    <span class="section-title">状态属性</span>
-                  </div>
-                  <div>
-                    <p v-for="attr in statusAttr" :key="attr.attr">{{ attr.attr }}:{{ attr.attrValue }} {{
-                        attr.attrUnit
-                      }}</p>
-                  </div>
-                </el-card>
-                <!-- 属性信息 -->
-                <el-card class="box-card" v-if="attrData.length > 0">
-                  <div slot="header" class="clearfix">
-                    <span class="section-title">属性定义</span>
-                  </div>
-                  <div v-for="(item, index) in attrData" :key="index">
-                    <p>属性名称:{{ item.attrName }}</p>
-                    <p>属性值:{{ item.attrValue }}</p>
-                    <p>属性单位:{{ item.attrUnit }}</p>
-                    <!-- 在每个条目之后添加横线,除了最后一个条目 -->
-                    <div v-if="index < attrData.length - 1" class="divider"></div>
+
+              <!-- 分组列表 -->
+              <div v-if="subsetList.length > 0" class="project-section">
+                <h5>分组列表</h5>
+                <el-table :data="subsetList" border stripe size="small">
+                  <el-table-column prop="subsetName" label="分组名称"></el-table-column>
+                  <el-table-column prop="subsetId" label="分组ID"></el-table-column>
+                  <el-table-column prop="subsetDeviceNum" label="设备数量" width="100" align="center">
+                    <template slot-scope="scope">
+                      <el-tag size="small" :type="scope.row.subsetDeviceNum > 0 ? 'success' : 'info'">
+                        {{ scope.row.subsetDeviceNum }}
+                      </el-tag>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+        </el-tab-pane>
+
+        <!-- 系统能力标签页 -->
+        <el-tab-pane label="系统能力" name="abilities">
+          <div class="tab-content">
+            <el-table :data="systemAbilities" border stripe v-loading="abilityLoading">
+              <el-table-column prop="abilityName" label="能力名称" width="200"></el-table-column>
+              <el-table-column prop="abilityKey" label="能力标识" width="200"></el-table-column>
+              <el-table-column prop="abilityDesc" label="能力描述"></el-table-column>
+              <el-table-column label="操作" width="150" align="center">
+                <template slot-scope="scope">
+                  <el-button
+                    type="primary"
+                    size="mini"
+                    icon="el-icon-caret-right"
+                    @click="executeAbility(scope.row)"
+                    :loading="scope.row.executing">
+                    执行
+                  </el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </el-tab-pane>
+
+        <!-- 关联设备标签页 -->
+        <el-tab-pane label="关联设备" name="devices">
+          <div class="tab-content">
+            <!-- 设备统计 -->
+            <div class="device-stats">
+              <el-row :gutter="20">
+                <el-col :span="6">
+                  <div class="stat-item">
+                    <div class="stat-value">{{ deviceStats.total }}</div>
+                    <div class="stat-label">设备总数</div>
                   </div>
-                </el-card>
-                <!-- 能力信息 -->
-                <el-card class="box-card" v-if="abilityData.length > 0">
-                  <div slot="header" class="clearfix">
-                    <span class="section-title">能力定义</span>
+                </el-col>
+                <el-col :span="6">
+                  <div class="stat-item online">
+                    <div class="stat-value">{{ deviceStats.online }}</div>
+                    <div class="stat-label">在线设备</div>
                   </div>
-                  <div v-for="(item, index) in abilityData" :key="index">
-                    <p>能力名称:{{ item.abilityName }}</p>
-                    <p>能力键:{{ item.abilityKey }}</p>
-                    <p>能力参数:{{ item.abilityParam }}</p>
-                    <p>能力描述:{{ item.abilityDesc }}</p>
-                    <!-- 在每个条目之后添加横线,除了最后一个条目 -->
-                    <div v-if="index < abilityData.length - 1" class="divider"></div>
+                </el-col>
+                <el-col :span="6">
+                  <div class="stat-item offline">
+                    <div class="stat-value">{{ deviceStats.offline }}</div>
+                    <div class="stat-label">离线设备</div>
                   </div>
-                </el-card>
-                <!-- 事件信息 -->
-                <el-card class="box-card" v-if="eventData.length > 0">
-                  <div slot="header" class="clearfix">
-                    <span class="section-title">事件定义</span>
+                </el-col>
+                <el-col :span="6">
+                  <div class="stat-item lamps">
+                    <div class="stat-value">{{ deviceStats.lamps }}</div>
+                    <div class="stat-label">灯组总数</div>
                   </div>
-                  <div v-for="(item, index) in eventData" :key="index">
-                    <p>事件名称:{{ item.eventKey }}</p>
-                    <p>事件类型:{{ item.eventType === 1 ? '消息上报' : '异常告警' }}</p>
-                    <p>事件代码:{{ item.eventCode }}</p>
-                    <p>外部事件代码:{{ item.extEventCode }}</p>
-                    <!-- 在每个条目之后添加横线,除了最后一个条目 -->
-                    <div v-if="index < eventData.length - 1" class="divider"></div>
+                </el-col>
+              </el-row>
+            </div>
+
+            <!-- 设备列表 -->
+            <el-table
+              :data="deviceList"
+              border
+              stripe
+              v-loading="deviceLoading"
+              @row-click="handleDeviceClick"
+              ref="deviceTable">
+              <el-table-column type="expand">
+                <template slot-scope="props">
+                  <div class="device-detail">
+                    <el-tabs v-model="props.row.detailTab">
+                      <el-tab-pane label="设备属性" name="attrs">
+                        <el-descriptions :column="2" border size="small">
+                          <el-descriptions-item label="设备SN号">
+                            {{ getDeviceAttr(props.row.deviceCode, 'deviceUid') }}
+                          </el-descriptions-item>
+                          <el-descriptions-item label="设备型号ID">
+                            {{ getDeviceAttr(props.row.deviceCode, 'deviceModelId') }}
+                          </el-descriptions-item>
+                          <el-descriptions-item label="最小色温">
+                            {{ getDeviceAttr(props.row.deviceCode, 'minCct') }}K
+                          </el-descriptions-item>
+                          <el-descriptions-item label="最大色温">
+                            {{ getDeviceAttr(props.row.deviceCode, 'maxCct') }}K
+                          </el-descriptions-item>
+                          <el-descriptions-item label="信号强度">
+                            {{ getDeviceAttr(props.row.deviceCode, 'csq') }}
+                          </el-descriptions-item>
+                          <el-descriptions-item label="设备状态">
+                            <el-tag size="small" :type="getDeviceAttr(props.row.deviceCode, 'abnormal') === '0' ? 'success' : 'danger'">
+                              {{ getDeviceAttr(props.row.deviceCode, 'abnormal') === '0' ? '正常' : '异常' }}
+                            </el-tag>
+                          </el-descriptions-item>
+                        </el-descriptions>
+
+                        <!-- 设备图片 -->
+                        <div v-if="getDeviceAttr(props.row.deviceCode, 'imageUrl')" class="device-image" style="margin-top: 20px;">
+                          <h5>设备图片</h5>
+                          <el-image
+                            style="width: 200px; height: 150px"
+                            :src="getDeviceAttr(props.row.deviceCode, 'imageUrl')"
+                            :preview-src-list="[getDeviceAttr(props.row.deviceCode, 'imageUrl')]"
+                            fit="cover">
+                            <div slot="error" class="image-slot">
+                              <i class="el-icon-picture-outline"></i>
+                            </div>
+                          </el-image>
+                        </div>
+                      </el-tab-pane>
+
+                      <el-tab-pane label="灯组信息" name="lamps">
+                        <div v-if="getLampList(props.row.deviceCode).length > 0">
+                          <h5>灯组列表 ({{ getLampList(props.row.deviceCode).length }}个)</h5>
+                          <el-table :data="getLampList(props.row.deviceCode)" size="mini" max-height="300">
+                            <el-table-column prop="lampNo" label="灯具编号"></el-table-column>
+                            <el-table-column label="状态" width="80" align="center">
+                              <template slot-scope="scope">
+                                <el-tag size="mini" :type="scope.row.lampOnOff === 1 ? 'success' : 'info'">
+                                  {{ scope.row.lampOnOff === 1 ? '开' : '关' }}
+                                </el-tag>
+                              </template>
+                            </el-table-column>
+                            <el-table-column prop="lampBright" label="亮度(%)" width="100" align="center"></el-table-column>
+                            <el-table-column prop="cct" label="色温(K)" width="100" align="center"></el-table-column>
+                            <el-table-column prop="power" label="功率(W)" width="100" align="center"></el-table-column>
+                          </el-table>
+                        </div>
+                        <div v-else>
+                          <el-empty description="暂无灯组数据"></el-empty>
+                        </div>
+                      </el-tab-pane>
+                    </el-tabs>
                   </div>
-                </el-card>
-              </div>
-            </el-dialog>
+                </template>
+              </el-table-column>
+              <el-table-column prop="deviceCode" label="设备代码" width="150"></el-table-column>
+              <el-table-column prop="deviceName" label="设备名称"></el-table-column>
+              <el-table-column prop="location" label="安装位置"></el-table-column>
+              <el-table-column prop="areaCode" label="区域" width="150">
+                <template slot-scope="scope">
+                  {{ scope.row.areaCode && scope.row.areaCode.includes('3001') ? '北区' : '南区' }}
+                </template>
+              </el-table-column>
+              <el-table-column label="设备状态" width="100" align="center">
+                <template slot-scope="scope">
+                  <el-tag :type="scope.row.deviceStatus === 1 ? 'success' : 'info'">
+                    {{ scope.row.deviceStatus === 1 ? '在线' : '离线' }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" width="100" align="center">
+                <template slot-scope="scope">
+                  <el-dropdown
+                    trigger="click"
+                    @command="handleDeviceCommand"
+                    @visible-change="(visible) => handleAbilityLoad(visible, scope.row)">
+                    <el-button type="text" size="mini">
+                      操作<i class="el-icon-arrow-down el-icon--right"></i>
+                    </el-button>
+                    <el-dropdown-menu slot="dropdown">
+                      <el-dropdown-item
+                        v-for="ability in deviceAbilities[scope.row.deviceCode] || []"
+                        :key="ability.abilityKey"
+                        :command="{device: scope.row, ability: ability}">
+                        {{ ability.abilityName }}
+                      </el-dropdown-item>
+                      <el-dropdown-item
+                        v-if="!deviceAbilities[scope.row.deviceCode] || deviceAbilities[scope.row.deviceCode].length === 0"
+                        disabled>
+                        无可用操作
+                      </el-dropdown-item>
+                    </el-dropdown-menu>
+                  </el-dropdown>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </el-tab-pane>
+
+        <!-- 调用日志标签页 -->
+        <el-tab-pane label="调用日志" name="callLogs">
+          <div class="tab-content">
+            <el-form :inline="true" :model="callLogQuery" class="log-filter">
+              <el-form-item label="时间范围">
+                <el-date-picker
+                  v-model="callLogQuery.dateRange"
+                  type="datetimerange"
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  value-format="yyyy-MM-dd HH:mm:ss">
+                </el-date-picker>
+              </el-form-item>
+              <el-form-item label="能力标识">
+                <el-input v-model="callLogQuery.abilityKey" placeholder="请输入能力标识" clearable></el-input>
+              </el-form-item>
+              <el-form-item label="调用状态">
+                <el-select v-model="callLogQuery.callStatus" placeholder="全部" clearable>
+                  <el-option label="成功" :value="0"></el-option>
+                  <el-option label="进行中" :value="1"></el-option>
+                  <el-option label="失败" :value="2"></el-option>
+                </el-select>
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" @click="queryCallLogs">查询</el-button>
+                <el-button @click="resetCallLogQuery">重置</el-button>
+              </el-form-item>
+            </el-form>
+
+            <el-table :data="callLogList" border stripe v-loading="logLoading">
+              <el-table-column prop="objCode" label="对象代码" min-width="150"></el-table-column>
+              <el-table-column prop="objName" label="对象名称" min-width="200"></el-table-column>
+              <el-table-column prop="abilityName" label="能力名称" min-width="150"></el-table-column>
+              <el-table-column prop="callTime" label="调用时间" width="180"></el-table-column>
+              <el-table-column label="调用状态" width="100" align="center">
+                <template slot-scope="scope">
+                  <el-tag size="small" :type="getCallStatusType(scope.row.callStatus)">
+                    {{ formatCallStatus(scope.row.callStatus) }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" width="80" align="center">
+                <template slot-scope="scope">
+                  <el-button type="text" size="mini" @click="handleCallLogDetail(scope.row)">详情</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+
+            <pagination
+              v-show="callLogTotal > 0"
+              :total="callLogTotal"
+              :page.sync="callLogQuery.pageNum"
+              :limit.sync="callLogQuery.pageSize"
+              @pagination="queryCallLogs"
+            />
           </div>
+        </el-tab-pane>
+
+        <!-- 事件日志标签页 -->
+        <el-tab-pane label="事件日志" name="eventLogs">
+          <div class="tab-content">
+            <el-form :inline="true" :model="eventLogQuery" class="log-filter">
+              <el-form-item label="时间范围">
+                <el-date-picker
+                  v-model="eventLogQuery.dateRange"
+                  type="datetimerange"
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  value-format="yyyy-MM-dd HH:mm:ss">
+                </el-date-picker>
+              </el-form-item>
+              <el-form-item label="事件标识">
+                <el-input v-model="eventLogQuery.eventKey" placeholder="请输入事件标识" clearable></el-input>
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" @click="queryEventLogs">查询</el-button>
+                <el-button @click="resetEventLogQuery">重置</el-button>
+              </el-form-item>
+            </el-form>
+
+            <el-table :data="eventLogList" border stripe v-loading="eventLogLoading">
+              <el-table-column prop="objCode" label="对象编号" min-width="150"></el-table-column>
+              <el-table-column prop="objName" label="对象名称" min-width="200"></el-table-column>
+              <el-table-column prop="eventName" label="事件名称" min-width="200"></el-table-column>
+              <el-table-column prop="eventTime" label="事件时间" width="180"></el-table-column>
+              <el-table-column label="操作" width="80" align="center">
+                <template slot-scope="scope">
+                  <el-button type="text" size="mini" @click="handleEventLogDetail(scope.row)">详情</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+
+            <pagination
+              v-show="eventLogTotal > 0"
+              :total="eventLogTotal"
+              :page.sync="eventLogQuery.pageNum"
+              :limit.sync="eventLogQuery.pageSize"
+              @pagination="queryEventLogs"
+            />
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </el-card>
+
+    <!-- 执行结果对话框 -->
+    <el-dialog
+      :title="executeDialog.title"
+      :visible.sync="executeDialog.visible"
+      width="600px">
+      <div class="execute-result">
+        <el-alert
+          :title="executeDialog.status"
+          :type="executeDialog.type"
+          :description="executeDialog.message"
+          show-icon>
+        </el-alert>
+        <div v-if="executeDialog.data" class="result-data">
+          <pre>{{ JSON.stringify(executeDialog.data, null, 2) }}</pre>
+        </div>
+      </div>
+      <span slot="footer">
+        <el-button @click="executeDialog.visible = false">关闭</el-button>
+      </span>
+    </el-dialog>
+
+    <!-- 调用日志详情弹窗 -->
+    <el-dialog :visible.sync="callLogDetailDialog" title="调用日志详情" width="60%">
+      <div v-if="callLogDetailData">
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="对象代码">{{ callLogDetailData.objCode }}</el-descriptions-item>
+          <el-descriptions-item label="模型代码">{{ callLogDetailData.modelCode }}</el-descriptions-item>
+          <el-descriptions-item label="能力标识">{{ callLogDetailData.abilityKey }}</el-descriptions-item>
+          <el-descriptions-item label="调用时间">{{ callLogDetailData.callTime }}</el-descriptions-item>
+          <el-descriptions-item label="响应时间">{{ callLogDetailData.resTime }}</el-descriptions-item>
+          <el-descriptions-item label="调用结果">
+            <el-tag :type="getCallStatusType(callLogDetailData.callStatus)">
+              {{ formatCallStatus(callLogDetailData.callStatus) }}
+            </el-tag>
+          </el-descriptions-item>
+        </el-descriptions>
+
+        <div style="margin-top: 20px;">
+          <h4>调用载体</h4>
+          <pre style="white-space: pre-wrap; background-color: #f5f5f5; padding: 10px; border-radius: 4px; max-height: 300px; overflow: auto;">{{ callLogDetailData.callPayload }}</pre>
+        </div>
+
+        <div style="margin-top: 20px;">
+          <h4>响应载体</h4>
+          <pre style="white-space: pre-wrap; background-color: #f5f5f5; padding: 10px; border-radius: 4px; max-height: 300px; overflow: auto;">{{ callLogDetailData.resPayload }}</pre>
         </div>
-      </el-col>
-    </el-row>
+      </div>
+    </el-dialog>
+
+    <!-- 事件日志详情弹窗 -->
+    <el-dialog :visible.sync="eventLogDetailDialog" title="事件日志详情" width="60%">
+      <div v-if="eventLogDetailData">
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="对象编号">{{ eventLogDetailData.objCode }}</el-descriptions-item>
+          <el-descriptions-item label="对象名称">{{ eventLogDetailData.objName }}</el-descriptions-item>
+          <el-descriptions-item label="事件名称">{{ eventLogDetailData.eventName }}</el-descriptions-item>
+          <el-descriptions-item label="事件标识">{{ eventLogDetailData.eventKey }}</el-descriptions-item>
+          <el-descriptions-item label="事件时间" :span="2">{{ eventLogDetailData.eventTime }}</el-descriptions-item>
+        </el-descriptions>
+
+        <div style="margin-top: 20px;">
+          <h4>事件描述</h4>
+          <div style="background-color: #f5f5f5; padding: 10px; border-radius: 4px;">
+            {{ eventLogDetailData.eventDetail || '无' }}
+          </div>
+        </div>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import {addDevice, delDevice, getDevice, listDevRecursionByArea, updateDevice} from '@/api/device/device'
-import {areaTreeSelect} from '@/api/basecfg/area'
-import {getFacsCategorygetByCode, listAllFacs} from '@/api/basecfg/emsfacs'
-import {listSubsystemAll} from '@/api/adapter/subsystem'
-import {getModelByCode, listAllModel} from '@/api/basecfg/objModel'
-import {getObjAttr} from '@/api/basecfg/objAttribute'
-import {addAttrValueBatch} from '@/api/basecfg/objAttributeValue'
-import {addComponent, delComponent, getComponent, listByDevice, updateComponent} from '@/api/basecfg/component'
-import Treeselect from '@riophae/vue-treeselect'
-import '@riophae/vue-treeselect/dist/vue-treeselect.css'
+import { getSubsystemByCode } from '@/api/adapter/subsystem'
+import { getModelByCode } from '@/api/basecfg/objModel'
+import { getObjAttr } from '@/api/basecfg/objAttribute'
+import { listcallAbility } from '@/api/basecfg/objAbility'
+import { getByCondition } from '@/api/device/device'
+import { listCallLog, listEventLog, getCallLog, getEventLog } from '@/api/basecfg/objLog'
 
 export default {
-  name: 'Device',
-  components: {Treeselect},
+  name: 'SmartLightingSystem',
   data() {
     return {
-      primary1: 'primary',
-      primary2: '',
-      ComponentRow: [],
-      componentForm: {},
-      subcategoryCode: '',
-      attrList: [], // 属性模板数组
-      attrValues: [],
-      ComponentList: [],
-      attrValuesMap: {},
-      modelList: [],
-      showDrawer: false,
-      showDevProcessDrawer: false,
-      componentOpen: false,
-      istable: 2,
-      // 遮罩层
-      loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 能源设备表格数据
+      // 系统代码
+      systemCode: 'SYS_ZHZM',
+      // 系统信息
+      systemInfo: {},
+      // 系统状态
+      systemStatus: '1',
+      // 当前标签页
+      activeTab: 'overview',
+      // 协议属性
+      protocolAttrs: [],
+      // 状态属性
+      stateAttrs: [],
+      // 基础属性
+      baseAttrs: [],
+      // 项目列表
+      projectList: [],
+      // 分组列表
+      subsetList: [],
+      // 系统能力
+      systemAbilities: [],
+      abilityLoading: false,
+      // 设备列表
       deviceList: [],
-      // 弹出层标题
-      title: '',
-      // 是否显示弹出层
-      open: false,
-      // 区域名称
-      areaName: undefined,
-      // 区域树选项
-      treeAreaOptions: undefined,
-      totalAreaOptions: undefined,
-      // 设施选项
-      facsOptions: undefined,
-      // 设备分类
-      subCategoryOptions: undefined,
-      subsystemOptions: undefined,
-      devOptions: undefined,
-      statusAttr: [{
-        attr: '开灯状态',
-        attrUnit: '',
-        attrValue: '开'
+      deviceLoading: false,
+      deviceAttrs: {},
+      // 设备能力缓存
+      deviceAbilities: {},
+      // 设备统计
+      deviceStats: {
+        total: 0,
+        online: 0,
+        offline: 0,
+        lamps: 0
       },
-        {
-          attr: '远程控制',
-          attrUnit: '',
-          attrValue: '否'
-        },
-        {
-          attr: '运行状态',
-          attrUnit: '',
-          attrValue: '在线'
-        }
-      ],
-      defaultProps: {
-        children: 'children',
-        label: 'label'
+      // 灯组统计
+      lampStats: {
+        on: 0,
+        off: 0
       },
-      // 查询参数
-      queryParams: {
-        psCode: null,
+      // 总功率
+      totalPower: 0,
+      // 快速操作
+      quickActions: [
+        { key: 'syncProject', name: '同步项目', icon: 'el-icon-refresh', loading: false },
+        { key: 'syncDevice', name: '同步设备', icon: 'el-icon-download', loading: false },
+        { key: 'allOn', name: '全部开灯', icon: 'el-icon-sunny', loading: false },
+        { key: 'allOff', name: '全部关灯', icon: 'el-icon-moon', loading: false }
+      ],
+      // 所有模型代码(系统 + 设备)
+      allModelCodes: [],
+      // 调用日志查询
+      callLogQuery: {
+        dateRange: [],
+        abilityKey: '',
+        callStatus: '',
         pageNum: 1,
-        pageSize: 10,
-        deviceCode: null,
-        deviceSubCategory: '',
-        deviceCategory: 'E',
-        locationType: null,
-        locationRef: null,
-        refFacs: null,
-        customAttrs: null
+        pageSize: 10
       },
-      queryComponentParams: {
+      callLogList: [],
+      callLogTotal: 0,
+      logLoading: false,
+      // 事件日志查询
+      eventLogQuery: {
+        dateRange: [],
+        eventKey: '',
         pageNum: 1,
         pageSize: 10
       },
-      objComTypeMapping: {
-        1: '总开',
-        2: '照明',
-        3: '风机'
-      },
-      objComTypeOptions: [
-        {code: 1, name: '总开'},
-        {code: 2, name: '照明'},
-        {code: 3, name: '风机'}
-
-      ],
-      curRow: {},
-      attrData: [],
-      abilityData: [],
-      eventData: [],
-
-      // 表单参数
-      form: {
-        customAttrs: [] // 自定义属性数组
-      },
-      // 表单校验
-      rules: {
-        refFacs: [
-          {required: true, message: '归属设施', trigger: 'blur'}
-        ],
-        refArea: [
-          {required: true, message: '安装位置', trigger: 'blur'}
-        ],
-        deviceCode: [
-          {required: true, message: '设备代码不能为空', trigger: 'blur'}
-        ],
-        deviceName: [
-          {required: true, message: '设备名称不能为空', trigger: 'blur'}
-        ]
-      },
-      componentRules: {
-        deviceCode: [
-          {required: true, message: '设备code不能为空', trigger: 'blur'}
-        ],
-        compoCode: [
-          {required: true, message: '部件编码不能为空', trigger: 'blur'}
-        ],
-        psCode: [
-          {required: true, message: '工艺标签代码不能为空', trigger: 'blur'}
-        ]
+      eventLogList: [],
+      eventLogTotal: 0,
+      eventLogLoading: false,
+      // 调用日志详情
+      callLogDetailDialog: false,
+      callLogDetailData: null,
+      // 事件日志详情
+      eventLogDetailDialog: false,
+      eventLogDetailData: null,
+      // 执行结果对话框
+      executeDialog: {
+        visible: false,
+        title: '',
+        status: '',
+        type: 'success',
+        message: '',
+        data: null
       }
     }
   },
-  watch: {
-    // 根据名称筛选区域树
-    areaName(val) {
-      this.$refs.tree.filter(val)
-    }
-  },
   created() {
-    this.queryParams.deviceCategory = 'ZHZM'; // 确保初始加载时就设置为 'ZHZM'
-    this.getList()
-    this.getAreaTree('0', 1)
-    this.getFacsOptions()
-    this.getSubsystem()
-    this.getSubCategorygetByCode()
-    this.getFacsModel()
-    // this.getAllDevProcess(this.subcategoryCode)
+    this.loadSystemInfo()
+    this.initDateRange()
   },
   methods: {
-    /**分页切换*/
-    switchData(v) {
-      if (v === 1) {
-        this.primary1 = "primary";
-        this.primary2 = "";
-      } else {
-        this.primary1 = "";
-        this.primary2 = "primary";
-      }
-      this.istable = v;
+    // 初始化时间范围(默认今天)
+    initDateRange() {
+      const now = new Date()
+      const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0)
+      const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59)
+
+      this.callLogQuery.dateRange = [
+        this.formatDate(startOfDay),
+        this.formatDate(endOfDay)
+      ]
+      this.eventLogQuery.dateRange = [
+        this.formatDate(startOfDay),
+        this.formatDate(endOfDay)
+      ]
     },
-    /** 查询能源设备列表 */
-    getList() {
-      this.loading = true
-      listDevRecursionByArea(this.queryParams).then(response => {
-        console.log('参数', JSON.stringify(this.queryParams))
-        this.deviceList = response.rows
-        this.total = response.total
-        this.loading = false
-      })
-    },
-    /**新增、修改、删除*/
-    handleComponentAdd() {
-      this.componentReset()
-      this.componentOpen = true
-      this.title = '添加设备器件属性'
-      this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
 
+    // 格式化日期
+    formatDate(date) {
+      if (!date) return ''
+      const year = date.getFullYear()
+      const month = (date.getMonth() + 1).toString().padStart(2, '0')
+      const day = date.getDate().toString().padStart(2, '0')
+      const hours = date.getHours().toString().padStart(2, '0')
+      const minutes = date.getMinutes().toString().padStart(2, '0')
+      const seconds = date.getSeconds().toString().padStart(2, '0')
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
     },
-    handleComponentUpdate(row) {
-      this.componentReset()
-      const id = row.id || this.ids
-      getComponent(id).then(response => {
-        this.componentForm = response.data
-        this.componentOpen = true
-        this.title = '修改设备器件属性'
-        this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
-      })
-    },
-    handleComponentDelete(row) {
-      const ids = row.id || this.ids
-      this.$modal.confirm('是否确认删除能源对象属性编号为"' + ids + '"的数据项?').then(function () {
-        return delComponent(ids)
-      }).then(() => {
-        console.log('删除row', row.deviceCode)
-        this.getComponentList(row.deviceCode)
-        this.$modal.msgSuccess('删除成功')
-      }).catch(() => {
-      })
+
+    // 加载系统信息
+    async loadSystemInfo() {
+      try {
+        // 1. 获取系统基础信息
+        const sysRes = await getSubsystemByCode(this.systemCode)
+        this.systemInfo = sysRes.data
+
+        // 2. 获取模型信息
+        if (this.systemInfo.modelCode) {
+          // 添加系统模型代码
+          this.allModelCodes.push(this.systemInfo.modelCode)
+
+          const modelRes = await getModelByCode(this.systemInfo.modelCode)
+          const modelData = modelRes.data
+
+          // 获取能力列表
+          this.systemAbilities = (modelData.abilityList || []).map(item => ({
+            ...item,
+            executing: false
+          }))
+        }
+
+        // 3. 获取系统属性值
+        const attrRes = await getObjAttr(3, this.systemCode)
+        const attrData = attrRes.data
+
+        this.protocolAttrs = attrData.Protocol || []
+        this.stateAttrs = attrData.State || []
+        this.baseAttrs = attrData.Base || []
+
+        // 解析项目列表和分组列表
+        this.parseBaseAttributes()
+
+        // 设置系统状态
+        const statusAttr = this.stateAttrs.find(attr => attr.attrKey === 'interfaceStatus')
+        if (statusAttr) {
+          this.systemStatus = statusAttr.attrValue
+        }
+
+        // 4. 加载关联设备
+        await this.loadDevices()
+      } catch (error) {
+        this.$message.error('加载系统信息失败:' + error.message)
+      }
     },
-    submitComponentForm() {
-      this.$refs['componentForm'].validate(valid => {
-        if (valid) {
-          if (this.componentForm.id != null) {
-            updateComponent(this.componentForm).then(response => {
-              this.$modal.msgSuccess('修改成功')
-              this.componentOpen = false
-              this.getComponentList(this.componentForm.deviceCode)
-            })
-          } else {
-            addComponent(this.componentForm).then(response => {
-              this.$modal.msgSuccess('新增成功')
-              this.componentOpen = false
-              this.getComponentList(this.componentForm.deviceCode)
-            })
+
+    // 解析基础属性中的项目和分组信息
+    parseBaseAttributes() {
+      this.baseAttrs.forEach(attr => {
+        if (attr.attrKey === 'projectList' && attr.attrValue) {
+          try {
+            this.projectList = JSON.parse(attr.attrValue)
+          } catch (e) {
+            console.error('解析项目列表失败', e)
+          }
+        }
+        if (attr.attrKey === 'projectSubsetList' && attr.attrValue) {
+          try {
+            this.subsetList = JSON.parse(attr.attrValue)
+          } catch (e) {
+            console.error('解析分组列表失败', e)
           }
         }
       })
     },
-    ComponentCancel() {
-      this.componentOpen = false
-      this.componentReset()
-    },
-    /**查询部件列表*/
-    getComponentList(deviceCode) {
-      listByDevice(deviceCode).then(response => {
-        this.ComponentList = response.data
-      })
-    },
-    /** 查询区域树结构 */
-    getAreaTree(areaCode, layer) {
-      areaTreeSelect(areaCode, layer).then(response => {
-        this.treeAreaOptions = [{
-          id: '-1',
-          label: '全部',
-          children: response.data
-        }]
-      })
-    },
-    // 筛选节点
-    filterNode(value, data) {
-      if (!value) return true
-      return data.label.indexOf(value) !== -1
-    },
-    // 节点单击事件
-    handleNodeClick(data) {
-      if (data.id === '-1') {
-        this.queryParams.locationType = null;
-        this.queryParams.locationRef = null;
-      } else {
-        this.queryParams.locationType = data.tier;
-        this.queryParams.locationRef = data.id;
+
+    // 加载设备列表
+    async loadDevices() {
+      this.deviceLoading = true
+      try {
+        const res = await getByCondition({
+          subsystemCode: this.systemCode
+        })
+
+        // 兼容不同的数据结构
+        const deviceData = res.data || res.rows || []
+
+        this.deviceList = deviceData.map(device => ({
+          ...device,
+          detailTab: 'attrs'
+        }))
+
+        // 收集所有设备的模型代码
+        const deviceModelCodes = new Set()
+        this.deviceList.forEach(device => {
+          if (device.deviceModel) {
+            deviceModelCodes.add(device.deviceModel)
+          }
+        })
+
+        // 将设备模型代码添加到总列表
+        deviceModelCodes.forEach(modelCode => {
+          if (!this.allModelCodes.includes(modelCode)) {
+            this.allModelCodes.push(modelCode)
+          }
+        })
+
+        // 统计设备信息
+        this.deviceStats.total = this.deviceList.length
+        this.deviceStats.online = this.deviceList.filter(d => d.deviceStatus === 1).length
+        this.deviceStats.offline = this.deviceList.filter(d => d.deviceStatus !== 1).length
+
+        // 加载每个设备的属性
+        for (const device of this.deviceList) {
+          await this.loadDeviceAttrs(device.deviceCode)
+        }
+
+        // 统计灯组数量
+        this.calculateLampStats()
+      } catch (error) {
+        this.$message.error('加载设备列表失败')
+      } finally {
+        this.deviceLoading = false
       }
-      this.handleQuery();
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false
-      this.reset()
     },
-    // 表单重置
-    reset() {
-      this.form = {
-        id: null,
-        deviceCode: null,
-        deviceName: null,
-        deviceType: null,
-        deviceStatus: null,
-        deviceModel: null,
-        refArea: null,
-        refFacs: null,
-        subsystemCode: null,
-        psCode: null,
-        createTime: null,
-        updateTime: null
 
+    // 加载设备属性
+    async loadDeviceAttrs(deviceCode) {
+      try {
+        const res = await getObjAttr(2, deviceCode)
+        this.deviceAttrs[deviceCode] = res.data || {}
+      } catch (error) {
+        // 忽略加载错误
       }
-      this.resetForm('form')
     },
-    componentReset() {
-      this.componentForm = {
-        id: null,
-        deviceCode: this.ComponentRow.deviceCode || '', // 使用ComponentRow的deviceCode,或者空字符串
-        compoCode: null,
-        compoTag: null,
-        psCode: null,
-        extCompoCode: null,
-        compoModel: null,
-        compoBrand: null,
-        compoSpec: null,
-        ancestors: null,
-        parentCompo: null
 
+    // 获取设备属性
+    getDeviceAttr(deviceCode, attrKey) {
+      const attrs = this.deviceAttrs[deviceCode]
+      if (!attrs) return '-'
+
+      // 搜索所有属性组
+      for (const group in attrs) {
+        if (attrs[group] && Array.isArray(attrs[group])) {
+          const attr = attrs[group].find(a => a.attrKey === attrKey)
+          if (attr) {
+            return attr.attrValue || '-'
+          }
+        }
       }
-      this.resetForm('componentForm')
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1
-      console.log('搜索按钮this.queryParams', JSON.stringify(this.queryParams))
-      this.getList()
+      return '-'
     },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.queryParams.locationType = null
-      this.queryParams.locationRef = null
-      this.resetForm('queryForm')
-      this.handleQuery()
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.id)
-      this.single = selection.length !== 1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset()
-      this.open = true
-      this.title = '添加能源设备'
-    },
-    /**设备器件按钮*/
-    handleDevProcess(row) {
-      this.showDevProcessDrawer = true
-      this.ComponentRow = row
-      console.log('row', row)
-      listByDevice(this.ComponentRow.deviceCode).then(response => {
-        this.ComponentList = response.data
-      })
 
-    },
-    shouldShowDevProcessButton(row) {
-      const categoryIsW = this.queryParams.deviceCategory === 'W'
-      const validPsCodes = ['AA', 'AH', 'AJ', 'AM', 'AP', 'AL', 'APE', 'ALE', 'AF', 'ACC']
-      const psCodeIsValid = validPsCodes.includes(row.psCode)
-      // 只有当设备分类为输能设备且设备工艺代码有效时,才返回true
-      return categoryIsW && psCodeIsValid
-    },
-    backStyle(areaPath) {
-      const firstLevel = areaPath.split('/')[0];
-      switch (firstLevel) {
-        case '北区':
-          return 'north';
-        case '南区':
-          return 'south';
-        case '主路':
-          return 'main';
-        default:
-          return '';
+    // 获取灯组列表
+    getLampList(deviceCode) {
+      const attrs = this.deviceAttrs[deviceCode]
+      if (!attrs || !attrs.RelDev) return []
+
+      const lampListAttr = attrs.RelDev.find(a => a.attrKey === 'lampList')
+      if (lampListAttr && lampListAttr.attrValue) {
+        try {
+          return JSON.parse(lampListAttr.attrValue)
+        } catch (e) {
+          return []
+        }
       }
+      return []
     },
-    /**设备详情按钮*/
-    handleDetail(row) {
-      this.showDrawer = true
-      this.curRow = row
-      console.log('data', this.curRow)
-      this.subKey = this.$options.data().subKey
-      getModelByCode(this.curRow.facsModel).then(response => {
-        const code = response.data
-        console.log('code', code)
-        this.eventData = response.data.eventList
-        this.abilityData = response.data.abilityList
 
-      })
-      getObjAttr(2, this.curRow.deviceCode).then(response => {
-        console.log('response值', response.data)
-        const attrs = response.data.attrs
-        const attrValues = response.data.attrValues
-
-        // 合并 attrs 和 attrValues 数组
-        const mergedData = attrValues.map(attrValue => {
-          const attr = attrs.find(a => a.attrKey === attrValue.attrKey)
-          return {
-            ...attrValue,
-            attrName: attr ? attr.attrName : attrValue.attrName,
-            attrUnit: attr ? attr.attrUnit : ''
+    // 统计灯组数量
+    calculateLampStats() {
+      let totalLamps = 0
+      let onLamps = 0
+      let offLamps = 0
+      let totalPower = 0
+
+      this.deviceList.forEach(device => {
+        const lamps = this.getLampList(device.deviceCode)
+        totalLamps += lamps.length
+        lamps.forEach(lamp => {
+          if (lamp.lampOnOff === 1) {
+            onLamps++
+            totalPower += parseFloat(lamp.power) || 0
+          } else {
+            offLamps++
           }
         })
-        this.attrData = mergedData
-      })
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset()
-      const id = row.id || this.ids
-      getDevice(id).then(response => {
-        this.form = response.data
-        this.open = true
-        this.title = '修改能源设备'
-      })
-      const layer = 1
-      const areaCode = '0'
-      areaTreeSelect(areaCode, layer).then(response => {
-        this.totalAreaOptions = response.data
       })
+
+      this.deviceStats.lamps = totalLamps
+      this.lampStats.on = onLamps
+      this.lampStats.off = offLamps
+      this.totalPower = totalPower
     },
-    /** 提交按钮 */
-    submitForm() {
-      // 重置 attrList 和 form.customAttrs
-      if (!this.attrList) {
-        this.attrList = []
+
+    // 处理快速操作
+    async handleQuickAction(action) {
+      action.loading = true
+      try {
+        switch (action.key) {
+          case 'syncProject':
+            await this.executeAbilityByKey('GetProjectList')
+            break
+          case 'syncDevice':
+            await this.executeAbilityByKey('GetDeviceList')
+            break
+          case 'allOn':
+            await this.controlAllDevices('on')
+            break
+          case 'allOff':
+            await this.controlAllDevices('off')
+            break
+        }
+        this.$message.success(`${action.name}成功`)
+      } catch (error) {
+        this.$message.error(`${action.name}失败`)
+      } finally {
+        action.loading = false
       }
-      if (!this.form.customAttrs) {
-        this.form.customAttrs = []
+    },
+
+    // 根据key执行能力
+    async executeAbilityByKey(abilityKey) {
+      const ability = this.systemAbilities.find(a => a.abilityKey === abilityKey)
+      if (ability) {
+        await this.executeAbility(ability)
       }
-      // 准备要发送的数据
-      let dataToSubmit = []
-      // 添加模型属性数据
-      this.attrList.forEach(attr => {
-        const attrName = attr.attrName
-        const attrKey = attr.attrKey
-        const attrValue = this.attrValuesMap[attrKey]
-        const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
-        if (existingIndex === -1) {
-          // 如果attrKey不存在于dataToSubmit中,则添加
-          dataToSubmit.push({
-            modelCode: this.form.deviceModel, // 模型代码
-            objCode: this.form.deviceCode, // 设备代码
-            objType: 2, // 对象类型
-            attrKey: attrKey,
-            attrValue: attrValue,
-            attrName: attrName
-
-          })
-        }
-      })
+    },
 
-      // 添加自定义属性数据
-      this.form.customAttrs.forEach(customAttr => {
-        const attrName = customAttr.attrName
-        const attrKey = customAttr.attrKey
-        const attrValue = customAttr.attrValue
-        const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
-        if (existingIndex === -1) {
-          // 如果attrKey不存在于dataToSubmit中,则添加
-          dataToSubmit.push({
-            modelCode: '', // 模型代码
-            objCode: this.form.deviceCode, // 设备代码
-            objType: 2, // 对象类型
-            attrKey: attrKey,
-            attrValue: attrValue,
-            attrName: attrName
-          })
-        }
-      })
+    // 控制所有设备
+    async controlAllDevices(action) {
+      try {
+        // 这里应该调用实际的批量控制接口
+        this.$message.info(`${action === 'on' ? '全部开灯' : '全部关灯'}命令已发送`)
+        // 刷新设备状态
+        await this.loadDevices()
+      } catch (error) {
+        throw error
+      }
+    },
 
-      this.$refs['form'].validate(valid => {
-        if (valid) {
-          if (this.form.id != null) {
-            updateDevice(this.form).then(response => {
-              this.$modal.msgSuccess('修改成功')
-              this.open = false
-              this.getList()
-            }).catch(error => {
-              console.error('修改失败:', error)
-              this.$message.error('修改失败')
-            })
-
-            if (dataToSubmit.length > 0) {
-              addAttrValueBatch(dataToSubmit)
-                .then(response => {
-                  if (response.code === 200) {
-                    this.$message.success('属性添加成功')
-                  } else {
-                    this.$message.error('属性添加失败')
-                  }
-                }).catch(error => {
-                console.error('属性添加失败:', error)
-                this.$message.error('属性添加失败')
-              })
-            }
-          } else {
-            addDevice(this.form).then(response => {
-              this.$modal.msgSuccess('新增成功')
-              this.open = false
-              this.getList()
-            }).catch(error => {
-              console.error('新增失败:', error)
-              this.$message.error('新增失败')
-            })
-
-            if (dataToSubmit.length > 0) {
-              addAttrValueBatch(dataToSubmit)
-                .then(response => {
-                  if (response.code === 200) {
-                    this.$message.success('属性添加成功')
-                  } else {
-                    this.$message.error('属性添加失败')
-                  }
-                }).catch(error => {
-                console.error('属性添加失败:', error)
-                this.$message.error('属性添加失败')
-              })
-            } else {
-              // this.$message.info('没有属性需要添加');
-            }
+    // 加载设备能力(当下拉菜单显示时)
+    async handleAbilityLoad(visible, device) {
+      if (visible && !this.deviceAbilities[device.deviceCode]) {
+        try {
+          // 确保设备有模型代码
+          if (!device.deviceModel) {
+            this.$set(this.deviceAbilities, device.deviceCode, [])
+            return
           }
+
+          const res = await getModelByCode(device.deviceModel)
+          // 获取能力列表
+          const abilities = res.data?.abilityList || []
+          this.$set(this.deviceAbilities, device.deviceCode, abilities)
+        } catch (error) {
+          this.$set(this.deviceAbilities, device.deviceCode, [])
         }
-      })
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const ids = row.id || this.ids
-      this.$modal.confirm('是否确认删除能源设备编号为"' + ids + '"的数据项?').then(function () {
-        return delDevice(ids)
-      }).then(() => {
-        this.getList()
-        this.$modal.msgSuccess('删除成功')
-      }).catch(() => {
-      })
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      this.download('ems/basecfg/device/export', {
-        ...this.queryParams
-      }, `device_${new Date().getTime()}.xlsx`)
+      }
     },
-    getFacsOptions() {
-      const getFacsParams = {
-        facsCategory: this.queryParams.deviceCategory,
-        subCategory: this.queryParams.deviceSubCategory
+
+    // 处理设备操作命令
+    async handleDeviceCommand(command) {
+      const { device, ability } = command
+      try {
+        await listcallAbility({
+          objCode: device.deviceCode,
+          objType: 2,
+          modelCode: device.deviceModel,
+          abilityKey: ability.abilityKey,
+          abilityParam: ability.abilityParam
+        })
+
+        this.$message.success(`${ability.abilityName}执行成功`)
+
+        // 重新加载设备属性
+        await this.loadDeviceAttrs(device.deviceCode)
+      } catch (error) {
+        this.$message.error(`${ability.abilityName}执行失败:${error.message}`)
       }
-      listAllFacs(getFacsParams).then(response => {
-        this.facsOptions = response.data
-      })
     },
-    getSubCategorygetByCode() {
-      getFacsCategorygetByCode(this.queryParams.deviceCategory).then(response => {
-        this.subCategoryOptions = response.data.subtypeList || []
-      })
+
+    // 执行系统能力
+    async executeAbility(ability) {
+      ability.executing = true
+      try {
+        const res = await listcallAbility({
+          objCode: this.systemCode,
+          objType: 3,
+          modelCode: this.systemInfo.modelCode,
+          abilityKey: ability.abilityKey,
+          abilityParam: ability.abilityParam
+        })
+
+        this.executeDialog = {
+          visible: true,
+          title: '执行结果 - ' + ability.abilityName,
+          status: '执行成功',
+          type: 'success',
+          message: '系统能力执行完成',
+          data: res.data
+        }
+
+        // 刷新相关数据
+        if (ability.abilityKey === 'GetProjectList' || ability.abilityKey === 'GetProjectSubsetList') {
+          await this.loadSystemInfo()
+        } else if (ability.abilityKey === 'GetDeviceList') {
+          await this.loadDevices()
+        }
+      } catch (error) {
+        this.executeDialog = {
+          visible: true,
+          title: '执行结果 - ' + ability.abilityName,
+          status: '执行失败',
+          type: 'error',
+          message: error.message,
+          data: null
+        }
+      } finally {
+        ability.executing = false
+      }
     },
-    getSubsystem() {
-      listSubsystemAll().then(response => {
-        this.subsystemOptions = response.data
-      })
+
+    // 处理设备行点击 - 展开/收起行详情
+    handleDeviceClick(row) {
+      this.$refs.deviceTable?.toggleRowExpansion(row)
     },
-    /**自定义属性表格*/
-    addCustomAttr() {
-      // 添加一个新的自定义属性
-      if (!Array.isArray(this.form.customAttrs)) {
-        this.form.customAttrs = []
-      }
-      this.form.customAttrs.push({
-        attrKey: '',
-        attrName: '',
-        attrValue: ''
-      })
-      // 强制更新视图
-      this.$forceUpdate()
 
+    // 标签页切换
+    handleTabClick(tab) {
+      if (tab.name === 'callLogs' && this.callLogList.length === 0) {
+        this.queryCallLogs()
+      } else if (tab.name === 'eventLogs' && this.eventLogList.length === 0) {
+        this.queryEventLogs()
+      }
     },
-    deleteCustomAttr(index) {
-      // 删除指定索引的自定义属性
-      if (this.form.customAttrs.length > 0) {
-        this.form.customAttrs.splice(index, 1)
+
+    // 查询调用日志
+    async queryCallLogs() {
+      this.logLoading = true
+      try {
+        const params = {
+          modelCodes: this.allModelCodes,
+          pageNum: this.callLogQuery.pageNum,
+          pageSize: this.callLogQuery.pageSize
+        }
+
+        // 添加时间范围
+        if (this.callLogQuery.dateRange && this.callLogQuery.dateRange.length === 2) {
+          params.startRecTime = this.callLogQuery.dateRange[0]
+          params.endRecTime = this.callLogQuery.dateRange[1]
+        }
+
+        // 添加能力标识
+        if (this.callLogQuery.abilityKey) {
+          params.abilityKey = this.callLogQuery.abilityKey
+        }
+
+        // 添加调用状态
+        if (this.callLogQuery.callStatus !== '') {
+          params.callStatus = this.callLogQuery.callStatus
+        }
+
+        const res = await listCallLog(params)
+        this.callLogList = res.rows || []
+        this.callLogTotal = res.total || 0
+      } catch (error) {
+        this.$message.error('查询调用日志失败')
+      } finally {
+        this.logLoading = false
       }
+    },
 
+    // 重置调用日志查询
+    resetCallLogQuery() {
+      this.initDateRange()
+      this.callLogQuery.abilityKey = ''
+      this.callLogQuery.callStatus = ''
+      this.callLogQuery.pageNum = 1
+      this.queryCallLogs()
     },
-    /**设备模型*/
-    updateAttrValue(attrKey, newValue) {
-      this.attrValuesMap[attrKey] = newValue
+
+    // 查询事件日志
+    async queryEventLogs() {
+      this.eventLogLoading = true
+      try {
+        const params = {
+          modelCodes: this.allModelCodes,
+          pageNum: this.eventLogQuery.pageNum,
+          pageSize: this.eventLogQuery.pageSize
+        }
+
+        // 添加时间范围
+        if (this.eventLogQuery.dateRange && this.eventLogQuery.dateRange.length === 2) {
+          params.startRecTime = this.eventLogQuery.dateRange[0]
+          params.endRecTime = this.eventLogQuery.dateRange[1]
+        }
+
+        // 添加事件标识
+        if (this.eventLogQuery.eventKey) {
+          params.eventKey = this.eventLogQuery.eventKey
+        }
+
+        const res = await listEventLog(params)
+        this.eventLogList = res.rows || []
+        this.eventLogTotal = res.total || 0
+      } catch (error) {
+        this.$message.error('查询事件日志失败')
+      } finally {
+        this.eventLogLoading = false
+      }
     },
 
-    getFacsModel() {
-      listAllModel(2).then(response => {
-        this.modelList = response.data
-        console.log('this.modelList', this.modelList)
-        this.modelList.forEach(model => {
-          console.log(model.modelCode)
-        })
-      })
+    // 重置事件日志查询
+    resetEventLogQuery() {
+      this.initDateRange()
+      this.eventLogQuery.eventKey = ''
+      this.eventLogQuery.pageNum = 1
+      this.queryEventLogs()
     },
-    handleModelChange(modelCode) {
-      if (modelCode) {
-        this.getModelByCode(modelCode)
-        console.log('设备代码', this.form.deviceCode)
-        this.getObjAttr(2, this.form.deviceCode)
+
+    // 格式化调用状态
+    formatCallStatus(status) {
+      const statusMap = {
+        0: '成功',
+        1: '进行中',
+        2: '失败'
       }
+      return statusMap[status] || '未知'
     },
-    getModelByCode(modelCode) {
-      getModelByCode(modelCode).then(response => {
-        // this.attrList = response.data.attrList;
-        const filteredAttrList = response.data.attrList.filter(attr => attr.attrType === 0)
-        this.attrList = filteredAttrList
 
-      })
+    // 获取调用状态类型
+    getCallStatusType(status) {
+      const typeMap = {
+        0: 'success',
+        1: 'warning',
+        2: 'danger'
+      }
+      return typeMap[status] || 'info'
     },
-    getObjAttr(objType, deviceCode) {
-      getObjAttr(objType, deviceCode).then(response => {
-        // const attrs = response.data.attrs;
-        const attrs = response.data.attrs.filter(attr => attr.attrType === 0)
-        console.log('attrs', attrs)
-        const attrValues = response.data.attrValues || [] // 确保是一个数组
-        console.log('attrValues', attrValues)
-
-        // 创建一个映射对象,用于存储 attrKey 与对应的 attrValue
-        const attrValuesMap = {}
-
-        // 遍历 attrs 数组
-        attrs.forEach(attr => {
-          // 查找 attrValues 数组中是否有匹配的 attrKey
-          const attrValueObj = attrValues.find(value => value.attrKey === attr.attrKey)
-          // 如果找到匹配的 attrValue,更新 attrValuesMap
-          if (attrValueObj) {
-            attrValuesMap[attr.attrKey] = attrValueObj.attrValue
-          } else {
-            // 如果没有找到匹配的 attrValue,则设置为 '暂无数据'
-            attrValuesMap[attr.attrKey] = ''
-          }
-        })
 
-        // 更新 attrValuesMap 到组件的数据中
-        this.attrValuesMap = attrValuesMap
-        // 打印更新后的 attrValuesMap,用于调试
-        console.log('Updated attrValuesMap', this.attrValuesMap)
+    // 查看调用日志详情
+    async handleCallLogDetail(row) {
+      try {
+        const res = await getCallLog(row.id)
+        this.callLogDetailData = res.data
+        this.callLogDetailDialog = true
+      } catch (error) {
+        this.$message.error('获取调用日志详情失败')
+      }
+    },
 
-      })
+    // 查看事件日志详情
+    async handleEventLogDetail(row) {
+      try {
+        const res = await getEventLog(row.id)
+        this.eventLogDetailData = res.data
+        this.eventLogDetailDialog = true
+      } catch (error) {
+        this.$message.error('获取事件日志详情失败')
+      }
     }
   }
 }
 </script>
-<style lang="scss" scoped>
 
-.divider {
-  border-bottom: 2px solid #ebeef5;
-  margin: 10px 0;
+<style lang="scss" scoped>
+.app-container {
+  padding: 20px;
+  background: #f5f7fa;
+  min-height: calc(100vh - 84px);
 }
 
-.section-title {
-  font-size: 18px;
-  font-weight: bold;
-  margin-top: 20px;
-  margin-bottom: 10px;
-}
+.system-info-card {
+  margin-bottom: 20px;
 
-.drawer-content {
-  padding: 0 20px;
-}
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
 
+    .title {
+      font-size: 18px;
+      font-weight: bold;
 
-.section-title {
-  font-size: 18px;
-  font-weight: bold;
-}
+      i {
+        margin-right: 8px;
+        color: #f39c12;
+      }
+    }
+  }
 
-.attr-list-container {
-  border: 1px solid #ccc;
-  padding: 10px;
-  margin: 10px 0;
-  font-weight: bold;
-}
+  .info-group {
+    .group-title {
+      font-size: 14px;
+      font-weight: bold;
+      color: #606266;
+      margin-bottom: 12px;
+      padding-bottom: 6px;
+      border-bottom: 1px solid #EBEEF5;
+    }
+  }
 
-.attr-list-container h3 {
-  font-weight: bold;
-}
+  .info-item {
+    margin-bottom: 12px;
+    font-size: 14px;
 
-.attr-item {
-  list-style-type: none;
-  margin-bottom: 5px;
-}
+    label {
+      color: #909399;
+      margin-right: 8px;
+      display: inline-block;
+      min-width: 80px;
+    }
 
-.attr-name {
-  font-weight: bold;
-}
+    .code {
+      font-family: monospace;
+      color: #f39c12;
+      background: #fff9e6;
+      padding: 2px 6px;
+      border-radius: 3px;
+    }
 
+    .stat-number {
+      color: #409EFF;
+      font-weight: bold;
+      font-size: 16px;
+    }
 
-.contents {
-  border: 20px solid #f2f2f5;
-  background-color: #f2f2f5;
+    .stat-number {
+      color: #409EFF;
+      font-weight: bold;
+      font-size: 16px;
+    }
+  }
 }
 
+.detail-card {
+  .tab-content {
+    min-height: 400px;
+  }
 
-.other-content {
-  background-color: #ffffff; /* 白色背景 */
-  padding: 20px;
-  margin-bottom: 20px;
-}
+  // 系统总览样式
+  .quick-actions {
+    margin-bottom: 30px;
 
-.table-content {
-  background-color: #ffffff; /* 白色背景 */
-  padding: 20px;
-}
+    .section-title {
+      margin: 0 0 15px 0;
+      color: #303133;
+      display: flex;
+      align-items: center;
 
-.pagination-container {
-  margin-bottom: 20px;
-}
+      i {
+        margin-right: 8px;
+        color: #409EFF;
+      }
+    }
 
-.button-group-container {
-  display: flex;
-  justify-content: flex-end;
-  min-width: 200px;
-  padding: 5px;
-}
+    .action-btn {
+      width: 100%;
+      height: 60px;
+      font-size: 14px;
+      border-radius: 8px;
+      transition: all 0.3s;
 
-.device-list {
-  margin-top: 20px;
-}
+      &:hover {
+        transform: translateY(-2px);
+        box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
+      }
+    }
+  }
 
-.device-card {
-  background-color: #fff;
-  border: 1px solid #bfcbd9;
-  border-radius: 4px;
-  overflow: hidden;
-  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-  transition: 0.3s;
-  padding: 10px;
-  font-size: 14px;
-  height: 200px;
-  margin-bottom: 20px;
-  display: flex;
-  flex-direction: column;
-}
+  .monitor-panel {
+    margin-bottom: 30px;
 
-.device-header {
-  //background-color: #f2f2f5;
-  //padding: 10px;
-  color: #545353;
-  font-size: 20px;
-  font-weight: bold;
-}
+    .section-title {
+      margin: 20px 0 15px 0;
+      color: #303133;
+      display: flex;
+      align-items: center;
 
-.device-code {
-  color: cornflowerblue;
-}
+      i {
+        margin-right: 8px;
+        color: #409EFF;
+      }
+    }
 
-.deviceOthers {
-  color: black;
-}
+    .monitor-card {
+      background: #fff;
+      border: 1px solid #EBEEF5;
+      border-radius: 8px;
+      padding: 20px;
+      display: flex;
+      align-items: center;
+      transition: all 0.3s;
+      cursor: pointer;
+
+      &:hover {
+        transform: translateY(-2px);
+        box-shadow: 0 4px 12px rgba(0,0,0,0.1);
+      }
 
-.device-body {
-  padding: 10px;
-  color: #666666;
-  flex: 1; /* 使设备主体内容占据剩余空间 */
-  overflow-y: auto; /* 如果内容过多,允许滚动 */
-}
+      .monitor-icon {
+        width: 50px;
+        height: 50px;
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 24px;
+        margin-right: 15px;
+
+        &.online {
+          background: #f0f9ff;
+          color: #67C23A;
+        }
 
-.device-footer {
-  display: flex;
-  justify-content: space-between;
-  padding: 5px;
-  // background-color: #f9f9f9;
-}
+        &.offline {
+          background: #fef0f0;
+          color: #F56C6C;
+        }
 
-.device-footer .el-button {
-  padding: 5px 15px;
-  border: none; /* 移除默认边框 */
-  color: #5a5e66;
-  transition: background-color 0.3s; /* 平滑过渡背景色变化 */
-}
+        &.lamps {
+          background: #fff9e6;
+          color: #f39c12;
+        }
 
-/* 为按钮分配不同的颜色 */
-.device-footer .el-button:first-child {
-  background-color: #d5f1d5; /* 淡绿色 */
-  border: 1px solid lightgreen;
-  color: #71e2aa;
+        &.power {
+          background: #f0f2f5;
+          color: #909399;
+        }
+      }
 
-}
+      .monitor-info {
+        .monitor-value {
+          font-size: 24px;
+          font-weight: bold;
+          color: #303133;
+        }
 
-.device-footer .el-button:nth-child(2) {
-  background-color: #ffe5b4; /* 淡橙色 */
-  border: 1px solid #ffba00;
-  color: #faad14;
-}
+        .monitor-label {
+          font-size: 14px;
+          color: #909399;
+          margin-top: 4px;
+        }
+      }
+    }
+  }
 
-.device-footer .el-button:last-child {
-  background-color: #ffd5d5; /* 淡红色 */
-  border: 1px solid lightpink;
-  color: #f5222d;
-}
+  .attr-section {
+    margin-bottom: 30px;
 
-/* 鼠标悬停时加深颜色 */
-.device-footer .el-button:hover {
-  filter: brightness(0.5); /* 颜色加深效果 */
-}
+    .section-title {
+      margin: 20px 0 15px 0;
+      color: #303133;
 
-/* 背景色样式 */
-.north {
-  background: linear-gradient(to right, #e1f3d8, #fafafa);
-}
+      i {
+        margin-right: 8px;
+        color: #409EFF;
+      }
+    }
 
-.south {
-  background: linear-gradient(to right, #fff7e8, #fafafa);
-}
+    .url-text {
+      color: #409EFF;
+      font-family: monospace;
+    }
+  }
 
-.main {
-  background: linear-gradient(to right, #e0e0e0, #fafafa);
-}
+  .project-section {
+    margin-bottom: 20px;
 
+    h5 {
+      margin: 15px 0 10px 0;
+      color: #606266;
+      font-size: 14px;
+    }
+  }
 
-.el-table {
-  background-color: #ffffff; /* 白色背景 */
+  .device-stats {
+    margin-bottom: 20px;
+
+    .stat-item {
+      text-align: center;
+      padding: 20px;
+      background: #fff;
+      border: 1px solid #EBEEF5;
+      border-radius: 4px;
+
+      .stat-value {
+        font-size: 28px;
+        font-weight: bold;
+        color: #303133;
+        margin-bottom: 8px;
+      }
+
+      .stat-label {
+        font-size: 14px;
+        color: #909399;
+      }
+
+      &.online .stat-value {
+        color: #67C23A;
+      }
+
+      &.offline .stat-value {
+        color: #F56C6C;
+      }
+
+      &.lamps .stat-value {
+        color: #f39c12;
+      }
+    }
+  }
+
+  .device-detail {
+    padding: 20px;
+    background: #f5f7fa;
+
+    h5 {
+      margin: 15px 0 10px 0;
+      color: #303133;
+    }
+  }
+
+  .log-filter {
+    margin-bottom: 20px;
+    padding: 15px;
+    background: #f5f7fa;
+    border-radius: 4px;
+  }
 }
 
-.el-card {
-  background-color: #ffffff; /* 白色背景 */
+.execute-result {
+  .result-data {
+    margin-top: 20px;
+
+    pre {
+      background: #f5f7fa;
+      padding: 15px;
+      border-radius: 4px;
+      overflow: auto;
+      max-height: 400px;
+      font-family: monospace;
+      font-size: 12px;
+    }
+  }
+}
+
+.image-slot {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background: #f5f7fa;
+  color: #909399;
+  font-size: 30px;
 }
 </style>

+ 175 - 7
ems-ui-cloud/src/views/basecfg/device/index.vue

@@ -361,7 +361,7 @@
             <!-- 设备参数 -->
             <div v-if="activeTab === 'attr'">
               <el-card class="box-card">
-                <div v-for="(tableData, tableName) in attrTables" :key="tableName">
+                <div v-for="(tableData, tableName) in getVisibleAttrTables()" :key="tableName">
                   <p class="section-title" @click="toggleCollapse(tableName)" style="cursor: pointer;">
                     <i :class="collapsed[tableName] ? 'el-icon-arrow-right' : 'el-icon-arrow-down'"></i>
                     {{ tableData.title }} ({{ tableData.data.length }})
@@ -372,14 +372,39 @@
                     <el-table-column label="属性标识" prop="attrKey"></el-table-column>
                     <el-table-column label="属性值" align="center">
                       <template slot-scope="scope">
-                        <span v-if="scope.row.attrValueType === 'Table'">
+                        <!-- 图片类型属性 -->
+                        <span v-if="scope.row.attrValueType === 'WebPic'">
+                          <el-image
+                            v-if="scope.row.attrValue && scope.row.attrValue !== '0'"
+                            :src="scope.row.attrValue"
+                            :preview-src-list="[scope.row.attrValue]"
+                            style="width: 60px; height: 60px; cursor: pointer;"
+                            fit="cover"
+                          >
+                            <div slot="error" class="image-slot">
+                              <i class="el-icon-picture-outline" style="font-size: 30px; color: #909399;"></i>
+                            </div>
+                          </el-image>
+                          <span v-else>暂无图片</span>
+                        </span>
+                        <!-- 子设备表格 -->
+                        <span v-else-if="scope.row.attrValueType === 'Table' && tableName === 'RelDev'">
+                          <el-button size="mini" type="text" @click="handleRelDevAttrDetail(scope.row)">查看子设备</el-button>
+                        </span>
+                        <!-- 普通表格 -->
+                        <span v-else-if="scope.row.attrValueType === 'Table'">
                           <el-button type="text" size="small" @click="handleTableAttrDetail(scope.row)">详情</el-button>
                         </span>
-                        <span v-else-if="tableData.title === '状态属性'">
-                          {{ scope.row.attrValueName || getAttrValueText(scope.row.attrValue) }}
+                        <!-- 枚举类型 - 优先显示attrValueName -->
+                        <span v-else-if="scope.row.attrValueType === 'Enum'">
+                          {{ scope.row.attrValueName || scope.row.attrValue }}
+                          <span v-if="scope.row.attrUnit">{{ scope.row.attrUnit }}</span>
+                        </span>
+                        <!-- Value和String类型 - 直接显示attrValue -->
+                        <span v-else>
+                          {{ scope.row.attrValue }}
                           <span v-if="scope.row.attrUnit">{{ scope.row.attrUnit }}</span>
                         </span>
-                        <span v-else>{{ scope.row.attrValue }}</span>
                       </template>
                     </el-table-column>
                   </el-table>
@@ -530,6 +555,32 @@
           </el-table>
         </el-dialog>
 
+        <!-- 子设备详情弹窗 -->
+        <el-dialog :visible.sync="relDevDetailDialog" :title="relDevDetailTitle" width="70%" append-to-body>
+          <el-table :data="relDevDetailData" style="width: 100%" :show-header="true" :empty-text="'暂无数据'">
+            <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
+            <el-table-column
+              v-for="column in relDevColumns"
+              :key="column.attrKey"
+              :label="column.attrName"
+              :prop="column.attrKey"
+              align="center"
+              min-width="100"
+            >
+              <template slot-scope="scope">
+                <!-- 如果有枚举值定义,使用枚举映射 -->
+                <span v-if="column.valueEnums && column.valueEnums.length > 0">
+                  {{ getEnumValue(scope.row[column.attrKey], column.valueEnums) }}
+                </span>
+                <!-- 否则直接显示原始值 -->
+                <span v-else>
+                  {{ scope.row[column.attrKey] !== undefined && scope.row[column.attrKey] !== null ? scope.row[column.attrKey] : '-' }}
+                </span>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-dialog>
+
         <!-- 能力执行弹窗 -->
         <el-dialog title="设备能力执行" :visible.sync="abilityDialogVisible" width="50%" append-to-body>
           <el-form ref="abilityForm" :model="abilityForm" label-width="100px">
@@ -710,19 +761,27 @@ export default {
       ProtocolData: [],
       StateData: [],
       MeasureData: [],
+      RelDevData: [],
       // 折叠状态,默认全部折叠
       collapsed: {
         Base: true,
         Protocol: true,
         State: true,
-        Measure: true
+        Measure: true,
+        RelDev: true
       },
       attrTables: {
         Base: { title: '基础属性', data: [] },
         Protocol: { title: '协议属性', data: [] },
         State: { title: '状态属性', data: [] },
-        Measure: { title: '计量属性', data: [] }
+        Measure: { title: '计量属性', data: [] },
+        RelDev: { title: '子设备', data: [] }
       },
+      // 子设备详情弹窗
+      relDevDetailDialog: false,
+      relDevDetailData: [],
+      relDevDetailTitle: '',
+      relDevColumns: [],
       // 控制表格显示的方法
       toggleCollapse(tableName) {
         this.collapsed[tableName] = !this.collapsed[tableName];
@@ -790,6 +849,85 @@ export default {
     this.loadAreaOptions()
   },
   methods: {
+    // 获取可见的属性表格(只返回有数据的分组)
+    getVisibleAttrTables() {
+      const visibleTables = {};
+      Object.keys(this.attrTables).forEach(key => {
+        if (this.attrTables[key].data && this.attrTables[key].data.length > 0) {
+          visibleTables[key] = this.attrTables[key];
+        }
+      });
+      return visibleTables;
+    },
+
+    // 处理子设备属性详情
+    handleRelDevAttrDetail(row) {
+      this.relDevDetailTitle = row.attrName;
+
+      // 解析表头定义
+      if (row.attrUnit) {
+        try {
+          // 直接解析 attrUnit
+          const headerDef = JSON.parse(row.attrUnit);
+
+          // 表头定义已经是正确的格式,直接使用
+          this.relDevColumns = headerDef;
+
+          console.log('解析后的表头定义:', this.relDevColumns);
+        } catch (e) {
+          console.error('解析表头定义失败:', e, 'attrUnit:', row.attrUnit);
+          // 使用默认列定义
+          this.relDevColumns = [
+            { attrKey: 'name', attrName: '名称' },
+            { attrKey: 'value', attrName: '值' }
+          ];
+        }
+      } else {
+        // 无表头定义,使用默认
+        this.relDevColumns = [
+          { attrKey: 'name', attrName: '名称' },
+          { attrKey: 'value', attrName: '值' }
+        ];
+      }
+
+      // 解析数据
+      try {
+        this.relDevDetailData = JSON.parse(row.attrValue);
+        // 确保数据是数组
+        if (!Array.isArray(this.relDevDetailData)) {
+          this.relDevDetailData = [this.relDevDetailData];
+        }
+        console.log('解析后的数据:', this.relDevDetailData);
+      } catch (e) {
+        this.relDevDetailData = [];
+        this.$message.error('解析子设备数据失败');
+      }
+
+      this.relDevDetailDialog = true;
+    },
+
+    // 获取枚举值的显示文本
+    getEnumValue(value, enumDef) {
+      if (value === undefined || value === null) return '-';
+      if (!enumDef) return value;
+
+      // 新格式:valueEnums是对象数组 [{"value":"0", "name":"关"},{"value":"1", "name":"开"}]
+      if (Array.isArray(enumDef)) {
+        const enumItem = enumDef.find(item => {
+          // 比较时需要考虑类型转换(value可能是字符串或数字)
+          return item.value == value;
+        });
+        return enumItem ? enumItem.name : value;
+      }
+
+      // 旧格式:如果 enumDef 是对象,直接从中取值
+      if (typeof enumDef === 'object' && !Array.isArray(enumDef)) {
+        return enumDef[value] || value;
+      }
+
+      return value;
+    },
+
     // 获取树节点图标
     getTreeIcon(data) {
       if (data.id === null) {
@@ -805,6 +943,27 @@ export default {
 
     // 处理表格属性详情点击事件
     handleTableAttrDetail(row) {
+      // 检查是否有自定义表头定义
+      if (row.attrUnit && row.attrValueType === 'Table') {
+        try {
+          // 解析表头定义
+          const headerDef = JSON.parse(row.attrUnit);
+          const tableData = JSON.parse(row.attrValue);
+
+          // 如果是数组格式的数据,使用自定义表头
+          if (Array.isArray(tableData) && Array.isArray(headerDef)) {
+            this.relDevColumns = headerDef;
+            this.relDevDetailData = tableData;
+            this.relDevDetailTitle = row.attrName;
+            this.relDevDetailDialog = true;
+            return;
+          }
+        } catch (e) {
+          console.log('使用默认表格格式');
+        }
+      }
+
+      // 默认处理方式
       try {
         const tableData = JSON.parse(row.attrValue);
         this.tableDetailData = tableData.map((item, index) => ({
@@ -1221,10 +1380,19 @@ export default {
         }))
       })
       getObjAttr(2, this.curRow.deviceCode).then(response => {
+        // 清空所有表格数据
+        this.attrTables.Base.data = []
+        this.attrTables.Protocol.data = []
+        this.attrTables.State.data = []
+        this.attrTables.Measure.data = []
+        this.attrTables.RelDev.data = []
+
+        // 填充数据
         this.attrTables.Base.data = response.data?.Base || []
         this.attrTables.Protocol.data = response.data?.Protocol || []
         this.attrTables.State.data = response.data?.State || []
         this.attrTables.Measure.data = response.data?.Measure || []
+        this.attrTables.RelDev.data = response.data?.RelDev || []
       })
       this.activeTab = 'basic'
     },

+ 180 - 12
ems-ui-cloud/src/views/devmgr/device/index.vue

@@ -184,7 +184,7 @@
             <!-- 设备参数 -->
             <div v-if="activeTab === 'attr'">
               <el-card class="box-card">
-                <div v-for="(tableData, tableName) in attrTables" :key="tableName">
+                <div v-for="(tableData, tableName) in getVisibleAttrTables()" :key="tableName">
                   <p class="section-title" @click="toggleCollapse(tableName)" style="cursor: pointer;">
                     <i :class="collapsed[tableName] ? 'el-icon-arrow-right' : 'el-icon-arrow-down'" style="margin-right: 8px;"></i>
                     {{ tableData.title }} ({{ tableData.data.length }})
@@ -195,15 +195,38 @@
                     <el-table-column label="属性标识" prop="attrKey"></el-table-column>
                     <el-table-column label="属性值" align="center">
                       <template slot-scope="scope">
-                        <span v-if="scope.row.attrValueType === 'Table'">
+                        <!-- WebPic图片类型 -->
+                        <span v-if="scope.row.attrValueType === 'WebPic'">
+                          <el-image
+                            v-if="scope.row.attrValue"
+                            :src="scope.row.attrValue"
+                            :preview-src-list="[scope.row.attrValue]"
+                            style="width: 60px; height: 60px; cursor: pointer;"
+                            fit="cover"
+                          >
+                            <div slot="error" class="image-slot">
+                              <i class="el-icon-picture-outline" style="font-size: 30px; color: #909399;"></i>
+                            </div>
+                          </el-image>
+                          <span v-else>暂无图片</span>
+                        </span>
+                        <!-- 子设备表格 -->
+                        <span v-else-if="scope.row.attrValueType === 'Table' && tableName === 'RelDev'">
+                          <el-button size="mini" type="text" @click="handleRelDevAttrDetail(scope.row)">查看子设备</el-button>
+                        </span>
+                        <!-- 普通表格 -->
+                        <span v-else-if="scope.row.attrValueType === 'Table'">
                           <el-button size="mini" type="text" @click="handleTableAttrDetail(scope.row)">详情</el-button>
                         </span>
-                        <span v-else-if="tableData.title === '状态属性'">
-                           {{ scope.row.attrValueName || getAttrValueText(scope.row.attrValue) }}
-                        <span v-if="scope.row.attrUnit">{{ scope.row.attrUnit }}</span>
+                        <!-- 枚举类型 - 优先显示attrValueName -->
+                        <span v-else-if="scope.row.attrValueType === 'Enum'">
+                          {{ scope.row.attrValueName || scope.row.attrValue }}
+                          <span v-if="scope.row.attrUnit">{{ scope.row.attrUnit }}</span>
                         </span>
+                        <!-- Value和String类型 - 直接显示attrValue -->
                         <span v-else>
                           {{ scope.row.attrValue }}
+                          <span v-if="scope.row.attrUnit">{{ scope.row.attrUnit }}</span>
                         </span>
                       </template>
                     </el-table-column>
@@ -362,6 +385,32 @@
             <el-table-column label="更新时间" prop="updateTime"></el-table-column>
           </el-table>
         </el-dialog>
+
+        <!-- 子设备详情弹窗 -->
+        <el-dialog :visible.sync="relDevDetailDialog" :title="relDevDetailTitle" width="70%">
+          <el-table :data="relDevDetailData" style="width: 100%" :show-header="true" :empty-text="'暂无数据'">
+            <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
+            <el-table-column
+              v-for="column in relDevColumns"
+              :key="column.attrKey"
+              :label="column.attrName"
+              :prop="column.attrKey"
+              align="center"
+              min-width="100"
+            >
+              <template slot-scope="scope">
+                <!-- 如果有枚举值定义,使用枚举映射 -->
+                <span v-if="column.valueEnums && column.valueEnums.length > 0">
+                  {{ getEnumValue(scope.row[column.attrKey], column.valueEnums) }}
+                </span>
+                <!-- 否则直接显示原始值 -->
+                <span v-else>
+                  {{ scope.row[column.attrKey] !== undefined && scope.row[column.attrKey] !== null ? scope.row[column.attrKey] : '-' }}
+                </span>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-dialog>
       </el-col>
     </el-row>
   </div>
@@ -429,22 +478,21 @@ export default {
       ProtocolData: [],
       StateData: [],
       MeasureData: [],
+      RelDevData: [],
       // 折叠状态,默认全部折叠
       collapsed: {
         Base: true,
         Protocol: true,
         State: true,
-        Measure: true
+        Measure: true,
+        RelDev: true
       },
       attrTables: {
         Base: { title: '基础属性', data: [] },
         Protocol: { title: '协议属性', data: [] },
         State: { title: '状态属性', data: [] },
-        Measure: { title: '计量属性', data: [] }
-      },
-      // 控制表格显示的方法
-      toggleCollapse(tableName) {
-        this.collapsed[tableName] = !this.collapsed[tableName];
+        Measure: { title: '计量属性', data: [] },
+        RelDev: { title: '子设备', data: [] }
       },
       // 查询参数
       queryParams: {
@@ -492,7 +540,12 @@ export default {
       // 表格属性详情弹窗
       tableAttrDetailDialog: false,
       tableAttrDetailData: [],
-      tableAttrDetailTitle: ''
+      tableAttrDetailTitle: '',
+      // 子设备详情弹窗
+      relDevDetailDialog: false,
+      relDevDetailData: [],
+      relDevDetailTitle: '',
+      relDevColumns: []
     }
   },
   watch: {
@@ -522,6 +575,90 @@ export default {
     this.logDaterangeTime = [this.formatDate(startOfDay), this.formatDate(endOfDay)]
   },
   methods: {
+    // 控制表格显示的方法
+    toggleCollapse(tableName) {
+      this.collapsed[tableName] = !this.collapsed[tableName];
+    },
+
+    // 获取可见的属性表格(只返回有数据的分组)
+    getVisibleAttrTables() {
+      const visibleTables = {};
+      Object.keys(this.attrTables).forEach(key => {
+        if (this.attrTables[key].data && this.attrTables[key].data.length > 0) {
+          visibleTables[key] = this.attrTables[key];
+        }
+      });
+      return visibleTables;
+    },
+
+    // 处理子设备属性详情
+    handleRelDevAttrDetail(row) {
+      this.relDevDetailTitle = row.attrName;
+
+      // 解析表头定义
+      if (row.attrUnit) {
+        try {
+          // 直接解析 attrUnit
+          const headerDef = JSON.parse(row.attrUnit);
+
+          // 表头定义已经是正确的格式,直接使用
+          this.relDevColumns = headerDef;
+
+          console.log('解析后的表头定义:', this.relDevColumns);
+        } catch (e) {
+          console.error('解析表头定义失败:', e, 'attrUnit:', row.attrUnit);
+          // 使用默认列定义
+          this.relDevColumns = [
+            { attrKey: 'name', attrName: '名称' },
+            { attrKey: 'value', attrName: '值' }
+          ];
+        }
+      } else {
+        // 无表头定义,使用默认
+        this.relDevColumns = [
+          { attrKey: 'name', attrName: '名称' },
+          { attrKey: 'value', attrName: '值' }
+        ];
+      }
+
+      // 解析数据
+      try {
+        this.relDevDetailData = JSON.parse(row.attrValue);
+        // 确保数据是数组
+        if (!Array.isArray(this.relDevDetailData)) {
+          this.relDevDetailData = [this.relDevDetailData];
+        }
+        console.log('解析后的数据:', this.relDevDetailData);
+      } catch (e) {
+        this.relDevDetailData = [];
+        this.$message.error('解析子设备数据失败');
+      }
+
+      this.relDevDetailDialog = true;
+    },
+
+    // 获取枚举值的显示文本
+    getEnumValue(value, enumDef) {
+      if (value === undefined || value === null) return '-';
+      if (!enumDef) return value;
+
+      // 新格式:valueEnums是对象数组 [{"value":"0", "name":"关"},{"value":"1", "name":"开"}]
+      if (Array.isArray(enumDef)) {
+        const enumItem = enumDef.find(item => {
+          // 比较时需要考虑类型转换(value可能是字符串或数字)
+          return item.value == value;
+        });
+        return enumItem ? enumItem.name : value;
+      }
+
+      // 旧格式:如果 enumDef 是对象,直接从中取值
+      if (typeof enumDef === 'object' && !Array.isArray(enumDef)) {
+        return enumDef[value] || value;
+      }
+
+      return value;
+    },
+
     // 获取树节点图标
     getTreeIcon(data) {
       if (data.id === null) {
@@ -799,16 +936,47 @@ export default {
         this.eventData = response.data?.eventList || []
       })
       getObjAttr(2, this.curRow.deviceCode).then(response => {
+        // 清空所有表格数据
+        this.attrTables.Base.data = []
+        this.attrTables.Protocol.data = []
+        this.attrTables.State.data = []
+        this.attrTables.Measure.data = []
+        this.attrTables.RelDev.data = []
+
+        // 填充数据
         this.attrTables.Base.data = response.data?.Base || []
         this.attrTables.Protocol.data = response.data?.Protocol || []
         this.attrTables.State.data = response.data?.State || []
         this.attrTables.Measure.data = response.data?.Measure || []
+        this.attrTables.RelDev.data = response.data?.RelDev || []
       })
       this.activeTab = 'basic'
     },
     // 处理表格类型属性详情
     handleTableAttrDetail(row) {
       this.tableAttrDetailTitle = row.attrName
+
+      // 检查是否有自定义表头定义
+      if (row.attrUnit && row.attrValueType === 'Table') {
+        try {
+          // 解析表头定义
+          const headerDef = JSON.parse(row.attrUnit);
+          const tableData = JSON.parse(row.attrValue);
+
+          // 如果是数组格式的数据,使用自定义表头
+          if (Array.isArray(tableData)) {
+            this.relDevColumns = headerDef;
+            this.relDevDetailData = tableData;
+            this.relDevDetailTitle = row.attrName;
+            this.relDevDetailDialog = true;
+            return;
+          }
+        } catch (e) {
+          console.log('使用默认表格格式');
+        }
+      }
+
+      // 默认处理方式
       try {
         this.tableAttrDetailData = JSON.parse(row.attrValue)
       } catch (e) {