index.vue 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741
  1. <template>
  2. <div class="app-container">
  3. <el-row :gutter="20">
  4. <el-col :span="4" :xs="24">
  5. <div class="head-container">
  6. <el-input v-model="areaName" placeholder="请输入区域名称" clearable size="small" prefix-icon="el-icon-search"
  7. style="margin-bottom: 20px"
  8. />
  9. </div>
  10. <div class="head-container" style="height: 100vh; overflow: hidden; position: relative;">
  11. <el-tree :data="treeAreaOptions" :props="defaultProps" :expand-on-click-node="false"
  12. :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current
  13. @node-click="handleNodeClick" style="height: calc(100vh - 50px); overflow-y: auto;"
  14. />
  15. </div>
  16. </el-col>
  17. <el-col :span="20" :xs="24">
  18. <el-tabs v-model="queryParams.deviceCategory" @tab-click="deviceCategoryChange">
  19. <el-tab-pane label="产能设备" name="E"></el-tab-pane>
  20. <el-tab-pane label="储能设备" name="C"></el-tab-pane>
  21. <el-tab-pane label="输配设备" name="W"></el-tab-pane>
  22. <el-tab-pane label="用能设备" name="Z"></el-tab-pane>
  23. </el-tabs>
  24. <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
  25. label-width="68px"
  26. >
  27. <el-form-item label="设备分类" prop="deviceSubCategory">
  28. <el-select v-model="queryParams.deviceSubCategory">
  29. <el-option v-for="item in subCategoryOptions" placeholder="设备分类" :label="item.name" :value="item.code"
  30. :key="item.code"
  31. />
  32. </el-select>
  33. </el-form-item>
  34. <el-form-item label="归属设施" prop="refFacs">
  35. <el-select v-model="queryParams.refFacs">
  36. <el-option v-for="item in facsOptions" :label="item.facsName" :value="item.facsCode"
  37. :key="item.facsCode"
  38. />
  39. </el-select>
  40. </el-form-item>
  41. <el-form-item label="归属系统" prop="subsystemCode">
  42. <el-select v-model="queryParams.subsystemCode">
  43. <el-option v-for="item in subsystemOptions" :label="item.systemName" :value="item.systemCode"
  44. :key="item.systemCode"
  45. />
  46. </el-select>
  47. </el-form-item>
  48. <el-form-item label="功能类型" prop="psCode" v-if="queryParams.deviceCategory === 'W'">
  49. <el-select v-model="queryParams.psCode">
  50. <el-option v-for="item in devOptions" :label="item.psName" :value="item.psCode" :key="item.psCode"/>
  51. </el-select>
  52. </el-form-item>
  53. <el-form-item>
  54. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  55. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  56. </el-form-item>
  57. </el-form>
  58. <el-row :gutter="10" class="mb8">
  59. <el-col :span="1.5">
  60. <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  61. v-hasPermi="['ems:device:add']"
  62. >新增
  63. </el-button>
  64. </el-col>
  65. <el-col :span="1.5">
  66. <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
  67. v-hasPermi="['ems:device:edit']"
  68. >修改
  69. </el-button>
  70. </el-col>
  71. <el-col :span="1.5">
  72. <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
  73. v-hasPermi="['ems:device:remove']"
  74. >删除
  75. </el-button>
  76. </el-col>
  77. <el-col :span="1.5">
  78. <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  79. v-hasPermi="['ems:device:export']"
  80. >导出
  81. </el-button>
  82. </el-col>
  83. <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  84. </el-row>
  85. <el-table v-loading="loading" :data="deviceList" @selection-change="handleSelectionChange">
  86. <el-table-column type="selection" width="55" align="center"/>
  87. <el-table-column label="设备名称" align="left" prop="deviceName"/>
  88. <el-table-column label="安装位置" align="left" prop="areaPath" width="220px"/>
  89. <el-table-column label="归属设施" align="center" prop="refFacsName"/>
  90. <el-table-column label="设备分类" align="center" prop="deviceCategoryName"/>
  91. <el-table-column label="归属系统" align="center" prop="subsystemName"/>
  92. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  93. <template slot-scope="scope">
  94. <el-button size="mini" type="text" icon="el-icon-s-tools" @click="handleDetail(scope.row)"
  95. v-hasPermi="['basecfg:device:edit']"
  96. >管理
  97. </el-button>
  98. </template>
  99. </el-table-column>
  100. </el-table>
  101. <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
  102. :limit.sync="queryParams.pageSize"
  103. @pagination="getList"
  104. />
  105. <!-- 调用日志详情弹窗 -->
  106. <el-dialog :visible.sync="callLogDetailDialog" title="调用日志详情" width="50%">
  107. <div v-if="callLogDetailData">
  108. <p><strong>对象编号:</strong>{{ callLogDetailData.objCode }}</p>
  109. <p><strong>对象名称:</strong>{{ callLogDetailData.objName }}</p>
  110. <p><strong>设备模型:</strong>{{ callLogDetailData.modelName + " (" + callLogDetailData.modelCode + ")"}}</p>
  111. <p><strong>对象能力:</strong>{{ callLogDetailData.abilityName + " (" + callLogDetailData.abilityKey + ")"}}</p>
  112. <p><strong>调用时间:</strong>{{ callLogDetailData.callTime }}</p>
  113. <p><strong>响应时间:</strong>{{ callLogDetailData.resTime }}</p>
  114. <p><strong>调用结果:</strong>{{ formatCallStatus(callLogDetailData.callStatus) }}</p>
  115. <p><strong>调用载体:</strong></p>
  116. <pre style="white-space: pre-wrap; background-color: #f5f5f5; padding: 10px; border-radius: 4px;"
  117. >{{ callLogDetailData.callPayload }}</pre>
  118. <p><strong>响应载体:</strong></p>
  119. <pre style="white-space: pre-wrap; background-color: #f5f5f5; padding: 10px; border-radius: 4px;"
  120. >{{ callLogDetailData.resPayload }}</pre>
  121. </div>
  122. </el-dialog>
  123. <!-- 设备日志详情弹窗 -->
  124. <el-dialog :visible.sync="reportDetailDialog" title="设备日志详情" width="50%">
  125. <div v-if="reportDetailData">
  126. <p><strong>对象编号:</strong>{{ reportDetailData.objCode }}</p>
  127. <p><strong>对象名称:</strong>{{ reportDetailData.objName }}</p>
  128. <p><strong>设备模型:</strong>{{ reportDetailData.modelName }}({{ reportDetailData.modelCode }})</p>
  129. <p><strong>消息类型:</strong>{{ reportDetailData.msgDesc }}</p>
  130. <p><strong>上报时间:</strong>{{ reportDetailData.reportTime }}</p>
  131. <p><strong>上报载体:</strong></p>
  132. <pre style="white-space: pre-wrap; background-color: #f5f5f5; padding: 10px; border-radius: 4px;"
  133. >{{ reportDetailData.reportPayload }}</pre>
  134. </div>
  135. </el-dialog>
  136. <!-- 事件日志详情弹窗 -->
  137. <el-dialog :visible.sync="eventLogDetailDialog" title="事件日志详情" width="50%">
  138. <div v-if="eventLogDetailData">
  139. <p><strong>对象编号:</strong>{{ eventLogDetailData.objCode }}</p>
  140. <p><strong>对象名称:</strong>{{ eventLogDetailData.objName }}</p>
  141. <p><strong>事件名称:</strong>{{ eventLogDetailData.eventName }}({{eventLogDetailData.eventKey}})</p>
  142. <p><strong>事件时间:</strong>{{ eventLogDetailData.eventTime }}</p>
  143. <p><strong>事件描述:</strong>{{ eventLogDetailData.eventDetail }}</p>
  144. </div>
  145. </el-dialog>
  146. <!-- 添加或修改能源设备对话框 -->
  147. <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  148. <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  149. <div>
  150. <el-form-item label="归属区域" prop="areaCode">
  151. <el-select v-model="form.areaCode" placeholder="请选择归属区域" @change="handleAreaChange">
  152. <el-option v-for="item in areaOptions" :key="item.id" :label="item.label" :value="item.id"
  153. ></el-option>
  154. </el-select>
  155. </el-form-item>
  156. <el-form-item label="归属子区" prop="locationRef">
  157. <el-select v-model="form.locationRef" placeholder="请选择归属子区">
  158. <el-option v-for="item in subAreaOptions" :key="item.id" :label="item.label" :value="item.id"
  159. ></el-option>
  160. </el-select>
  161. </el-form-item>
  162. <el-form-item label="归属设施" prop="refFacs">
  163. <el-select v-model="form.refFacs" placeholder="请选择归属设施" >
  164. <el-option v-for="item in facsOptions" :key="item.facsCode" :label="item.facsName"
  165. :value="item.facsCode"
  166. ></el-option>
  167. </el-select>
  168. </el-form-item>
  169. <el-form-item label="安装位置" prop="location">
  170. <el-input v-model="form.location" placeholder="请输入安装位置"></el-input>
  171. </el-form-item>
  172. <el-form-item label="设备代码" prop="deviceCode">
  173. <el-input v-model="form.deviceCode" placeholder="请输入设备代码"/>
  174. </el-form-item>
  175. <el-form-item label="设备名称" prop="deviceName">
  176. <el-input v-model="form.deviceName" placeholder="请输入设备名称"/>
  177. </el-form-item>
  178. <el-form-item label="设备型号" prop="deviceSpec">
  179. <el-input v-model="form.deviceSpec" placeholder="请输入设备型号"/>
  180. </el-form-item>
  181. <el-form-item label="供应商" prop="deviceBrand">
  182. <el-input v-model="form.deviceBrand" placeholder="请输入设备供应商"/>
  183. </el-form-item>
  184. <el-form-item label="功能类型" prop="psCode" v-if="queryParams.deviceCategory === 'W'">
  185. <el-select v-model="form.psCode" clearable>
  186. <el-option v-for="item in devOptions" :label="item.psName" :value="item.psCode"
  187. :key="item.psCode"
  188. />
  189. </el-select>
  190. </el-form-item>
  191. <el-form-item label="设备模型" prop="deviceModel">
  192. <el-select v-model="form.deviceModel" style="width:100%" @change="handleModelChange" clearable>
  193. <el-option
  194. v-for="item in modelList"
  195. :label="item.modelName"
  196. :value="item.modelCode"
  197. :key="item.modelCode"
  198. />
  199. </el-select>
  200. </el-form-item>
  201. <el-form-item label="归属系统" prop="subsystemCode">
  202. <el-select v-model="form.subsystemCode" clearable>
  203. <el-option v-for="item in subsystemOptions" :label="item.systemName" :value="item.systemCode"
  204. :key="item.systemCode"
  205. />
  206. </el-select>
  207. </el-form-item>
  208. </div>
  209. <!-- 属性名称、属性值 -->
  210. <div v-if="attrList.length > 0" class="attr-list-container">设备参数:
  211. <ul>
  212. <li v-for="attr in attrList" :key="attr.attrKey" class="attr-item">
  213. <span class="attr-name">{{ attr.attrName }} ({{ attr.attrUnit }}): </span>
  214. <el-input
  215. v-model="attrValuesMap[attr.attrKey]"
  216. placeholder="点击编辑"
  217. size="small"
  218. @blur="updateAttrValue(attr.attrKey, attrValuesMap[attr.attrKey])"
  219. class="attr-input"
  220. />
  221. </li>
  222. </ul>
  223. </div>
  224. <div v-if="attrList.length > 0" class="attr-list-container">设备自定义参数:
  225. <el-form-item label="" prop="attrList">
  226. <el-table class="attr-table" v-loading="loading" :data="form.customAttrs" max-height="280px"
  227. key="'customAttrs'"
  228. >
  229. <el-table-column label="标识" align="center" prop="attrKey">
  230. <template slot-scope="scope">
  231. <el-input size="mini" v-model="scope.row.attrKey" placeholder="请输入标识"/>
  232. </template>
  233. </el-table-column>
  234. <el-table-column label="属性名" align="center" prop="attrName">
  235. <template slot-scope="scope">
  236. <el-input size="mini" v-model="scope.row.attrName" placeholder="请输入属性名"/>
  237. </template>
  238. </el-table-column>
  239. <el-table-column label="属性值" align="center" prop="attrValue">
  240. <template slot-scope="scope">
  241. <el-input size="mini" v-model="scope.row.attrValue" placeholder="请输入属性值"/>
  242. </template>
  243. </el-table-column>
  244. <el-table-column align="center" label="操作">
  245. <template slot="header">
  246. <div class="operateBtns" @click="addCustomAttr">
  247. <span>添加</span><i class="el-icon-circle-plus-outline"></i>
  248. </div>
  249. </template>
  250. <template slot-scope="scope">
  251. <i class="el-icon-delete" @click="deleteCustomAttr(scope.$index)"></i>
  252. </template>
  253. </el-table-column>
  254. </el-table>
  255. </el-form-item>
  256. </div>
  257. </el-form>
  258. <div slot="footer" class="dialog-footer">
  259. <el-button type="primary" @click="submitForm">确 定</el-button>
  260. <el-button @click="cancel">取 消</el-button>
  261. </div>
  262. </el-dialog>
  263. <!--设备器件-->
  264. <el-drawer :title=ComponentRow.deviceName size="80%" :visible.sync="showDevProcessDrawer" direction="rtl">
  265. <div class="drawer-content" style="padding-left:50px">
  266. <el-row :gutter="10" class="mb8">
  267. <el-col :span="1.5">
  268. <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleComponentAdd"
  269. v-hasPermi="['ems:component:add']"
  270. >新增
  271. </el-button>
  272. </el-col>
  273. </el-row>
  274. <el-table v-loading="loading" :data="ComponentList">
  275. <el-table-column type="selection" width="55" align="center"/>
  276. <el-table-column label="部件编码" align="center" prop="compoCode"/>
  277. <el-table-column label="部件标签" align="center" prop="compoTag">
  278. <template slot-scope="scope">
  279. {{ objComTypeMapping[scope.row.compoTag] }}
  280. </template>
  281. </el-table-column>
  282. <el-table-column label="工艺标识代码" align="center" prop="psCode"/>
  283. <el-table-column label="外系统部件编码" align="center" prop="extCompoCode"/>
  284. <el-table-column label="部件模型" align="center" prop="compoModel"/>
  285. <el-table-column label="部件品牌" align="center" prop="compoBrand"/>
  286. <el-table-column label="部件型号" align="center" prop="compoSpec"/>
  287. <el-table-column label="祖籍列表" align="center" prop="ancestors"/>
  288. <el-table-column label="上级部件" align="center" prop="parentEqpt"/>
  289. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  290. <template slot-scope="scope">
  291. <el-button size="mini" type="text" icon="el-icon-edit" @click="handleComponentUpdate(scope.row)"
  292. v-hasPermi="['ems:component:edit']"
  293. >
  294. 修改
  295. </el-button>
  296. <el-button size="mini" type="text" icon="el-icon-delete" class="deleteBtn"
  297. @click="handleComponentDelete(scope.row)" v-hasPermi="['ems:component:remove']"
  298. >
  299. 删除
  300. </el-button>
  301. </template>
  302. </el-table-column>
  303. </el-table>
  304. <!-- <pagination v-show="componentTotal>0" :total="componentTotal" :page.sync="queryComponentParams.pageNum"-->
  305. <!-- :limit.sync="queryComponentParams.pageSize"-->
  306. <!-- @pagination="getComponentList"-->
  307. <!-- />-->
  308. <!-- 添加或修改设备器件对话框 -->
  309. <el-dialog :title="title" :visible.sync="componentOpen" width="600px" append-to-body>
  310. <el-form ref="componentForm" :model="componentForm" :rules="componentRules" label-width="150px">
  311. <el-form-item label="部件编码" prop="compoCode">
  312. <el-input v-model="componentForm.compoCode" placeholder="请输入部件编码"/>
  313. </el-form-item>
  314. <el-form-item label="部件标签" prop="compoTag">
  315. <el-select v-model="componentForm.compoTag" placeholder="请输入部件标签">
  316. <el-option v-for="item in objComTypeOptions"
  317. :label="item.name"
  318. :value="item.code"
  319. :key="item.code"
  320. />
  321. </el-select>
  322. </el-form-item>
  323. <el-form-item label="工艺标签代码" prop="psCode">
  324. <el-select v-model="componentForm.psCode" placeholder="请输入工艺标签代码">
  325. <el-option v-for="item in devOptions" :label="item.psCode" :value="item.psCode" :key="item.psCode"/>
  326. </el-select>
  327. </el-form-item>
  328. <el-form-item label="外系统部件编码" prop="extCompoCode">
  329. <el-input v-model="componentForm.extCompoCode" placeholder="请输入外系统部件编码"/>
  330. </el-form-item>
  331. <el-form-item label="部件模型" prop="compoModel">
  332. <el-select v-model="componentForm.compoModel" placeholder="请输入部件模型">
  333. <el-option v-for="item in this.modelList" :label="item.modelCode" :value="item.modelCode"
  334. :key="item.modelCode"
  335. />
  336. </el-select>
  337. </el-form-item>
  338. <el-form-item label="部件品牌" prop="compoBrand">
  339. <el-input v-model="componentForm.compoBrand" placeholder="请输入部件品牌"/>
  340. </el-form-item>
  341. <el-form-item label="部件型号" prop="compoSpec">
  342. <el-input v-model="componentForm.compoSpec" placeholder="请输入部件型号"/>
  343. </el-form-item>
  344. <el-form-item label="祖籍列表" prop="ancestors">
  345. <el-input v-model="componentForm.ancestors" placeholder="请输入祖籍列表"/>
  346. </el-form-item>
  347. <el-form-item label="上级列表" prop="parentCompo">
  348. <el-input v-model="componentForm.parentCompo" placeholder="请输入上级列表"/>
  349. </el-form-item>
  350. </el-form>
  351. <div slot="footer" class="dialog-footer">
  352. <el-button type="primary" @click="submitComponentForm">确 定</el-button>
  353. <el-button @click="ComponentCancel">取 消</el-button>
  354. </div>
  355. </el-dialog>
  356. </div>
  357. </el-drawer>
  358. <!-- 详情弹框 -->
  359. <el-dialog :visible.sync="showDrawer" title="设备详情" width="65%" custom-class="detail-dialog">
  360. <!-- 表格属性详情弹框 -->
  361. <el-dialog :visible.sync="showTableDetail" title="表格数据详情" width="70%" append-to-body :modal-append-to-body="true">
  362. <el-table :data="tableDetailData" style="width: 100%">
  363. <el-table-column type="index" label="序号" width="50"></el-table-column>
  364. <el-table-column prop="name" label="名称"></el-table-column>
  365. <el-table-column prop="key" label="键"></el-table-column>
  366. <el-table-column prop="value" label="值"></el-table-column>
  367. <el-table-column prop="updateTime" label="更新时间"></el-table-column>
  368. </el-table>
  369. <div slot="footer" class="dialog-footer">
  370. <el-button @click="showTableDetail = false">关闭</el-button>
  371. </div>
  372. </el-dialog>
  373. <div v-if="curRow">
  374. <!-- 分页导航 -->
  375. <el-tabs v-model="activeTab">
  376. <el-tab-pane label="设备基本信息" name="basic"></el-tab-pane>
  377. <el-tab-pane label="设备参数" name="attr"></el-tab-pane>
  378. <el-tab-pane label="设备能力" name="ability"></el-tab-pane>
  379. <el-tab-pane label="事件日志" name="eventLog"></el-tab-pane>
  380. <el-tab-pane label="调用日志" name="callLog"></el-tab-pane>
  381. <el-tab-pane label="上报日志" name="reportLog"></el-tab-pane>
  382. </el-tabs>
  383. <!-- 设备基本信息 -->
  384. <div v-if="activeTab === 'basic'">
  385. <el-card class="box-card">
  386. <div slot="header" class="clearfix">
  387. <span class="section-title">设备基本信息</span>
  388. </div>
  389. <div>
  390. <p><span class="bold">设备名称:</span>{{ curRow.deviceName }}</p>
  391. <p><span class="bold">设备代码:</span>{{ curRow.deviceCode }}</p>
  392. <p><span class="bold">设备分类:</span>{{ curRow.deviceCategoryName + getPsName(curRow.psName) }}</p>
  393. <p><span class="bold">设备型号:</span>{{ curRow.deviceSpec }}</p>
  394. <p><span class="bold">供应商:</span>{{ curRow.deviceBrand }}</p>
  395. <p><span class="bold">归属设施:</span>{{ curRow.refFacsName }}</p>
  396. <p><span class="bold">归属区域:</span>{{ buildRefAreaName(curRow) }}</p>
  397. <p><span class="bold">安装位置:</span>{{ curRow.location === null ? '无' : curRow.location }}</p>
  398. <p><span class="bold">归属系统:</span>{{ curRow.subsystemName === null ? '无' : curRow.subsystemName }}</p>
  399. <p>
  400. <span class="bold">设备状态:</span>
  401. <span :class="getDeviceStatusClass(curRow.deviceStatus)">
  402. {{ getDeviceStatus(curRow.deviceStatus) }}
  403. </span>
  404. </p>
  405. </div>
  406. <div class="footer">
  407. <div class="footer">
  408. <el-button type="primary" plain icon="el-icon-edit" size="mini" @click="handleUpdate(curRow)"
  409. v-hasPermi="['ems:device:edit']">修改</el-button>
  410. <el-button type="danger" plain icon="el-icon-delete" size="mini" @click="handleDelete(curRow)"
  411. v-hasPermi="['ems:device:remove']">删除</el-button>
  412. <el-button type="warning" plain icon="el-icon-s-tools" size="mini" @click="handleDevProcess(curRow)"
  413. v-hasPermi="['ems:device:edit']" v-if="shouldShowDevProcessButton(curRow)">器件</el-button>
  414. </div>
  415. </div>
  416. </el-card>
  417. </div>
  418. <!-- 属性信息 -->
  419. <div v-if="activeTab === 'attr'">
  420. <el-card class="box-card">
  421. <div v-for="(tableData, tableName) in attrTables" :key="tableName">
  422. <p class="section-title" @click="toggleCollapse(tableName)" style="cursor: pointer;">
  423. <i :class="collapsed[tableName] ? 'el-icon-arrow-right' : 'el-icon-arrow-down'" style="margin-right: 8px;"></i>
  424. {{ tableData.title }} ({{ tableData.data.length }})
  425. </p>
  426. <el-table v-if="!collapsed[tableName]" :data="tableData.data" style="width: 100%" :show-header="true" :empty-text="'暂无数据'">
  427. <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
  428. <el-table-column label="属性名称" prop="attrName"></el-table-column>
  429. <el-table-column label="属性标识" prop="attrKey"></el-table-column>
  430. <!-- 动态显示属性值 -->
  431. <el-table-column label="属性值" align="center">
  432. <template slot-scope="scope">
  433. <span v-if="scope.row.attrValueType === 'Table'">
  434. <el-button type="text" size="small" @click="handleTableAttrDetail(scope.row)">详情</el-button>
  435. </span>
  436. <span v-else-if="tableData.title === '状态属性'">
  437. {{ scope.row.attrValueName || getAttrValueText(scope.row.attrValue) }}
  438. <span v-if="scope.row.attrUnit">{{ scope.row.attrUnit }}</span>
  439. </span>
  440. <span v-else>
  441. {{ scope.row.attrValue }}
  442. </span>
  443. </template>
  444. </el-table-column>
  445. </el-table>
  446. </div>
  447. </el-card>
  448. </div>
  449. <!-- 设备能力-->
  450. <div v-if="
  451. activeTab === 'ability'">
  452. <el-card class="box-card">
  453. <div slot="header" class="clearfix">
  454. <span class="section-title">设备能力</span>
  455. </div>
  456. <el-table :data="abilityData" style="width: 100%" :show-header="true" :empty-text="'暂无数据'">
  457. <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
  458. <el-table-column label="能力名称" prop="abilityName"></el-table-column>
  459. <el-table-column label="能力键" prop="abilityKey"></el-table-column>
  460. <el-table-column label="能力描述" prop="abilityDesc"></el-table-column>
  461. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  462. <template slot-scope="scope">
  463. <el-button size="mini" type="text" icon="el-icon-edit" @click="handleAbilityEdit(scope.row)">
  464. 执行
  465. </el-button>
  466. </template>
  467. </el-table-column>
  468. </el-table>
  469. </el-card>
  470. </div>
  471. <el-dialog title="设备能力执行" :visible.sync="abilityDialogVisible" width="60%" append-to-body>
  472. <el-form ref="abilityForm" :model="abilityForm" label-width="120px">
  473. <el-form-item label="能力名称">
  474. <el-input v-model="abilityForm.abilityName" placeholder="请输入能力名称" disabled></el-input>
  475. </el-form-item>
  476. <el-form-item label="能力键">
  477. <el-input v-model="abilityForm.abilityKey" placeholder="请输入能力键" disabled></el-input>
  478. </el-form-item>
  479. <el-form-item label="能力描述">
  480. <el-input type="textarea" v-model="abilityForm.abilityDesc" placeholder="请输入能力描述" disabled
  481. ></el-input>
  482. </el-form-item>
  483. <el-form-item label="能力参数">
  484. <el-input type="textarea" v-model="abilityForm.abilityParam" placeholder="请输入能力参数"></el-input>
  485. </el-form-item>
  486. </el-form>
  487. <div slot="footer" class="dialog-footer">
  488. <el-button type="primary" @click="saveAbilityEdit">执行</el-button>
  489. <el-button @click="cancelAbilityEdit">取消</el-button>
  490. </div>
  491. </el-dialog>
  492. <!-- 设备事件日志= -->
  493. <!-- <div v-if="activeTab === 'eventLog'">-->
  494. <!-- <el-card class="box-card">-->
  495. <!-- <div slot="header" class="clearfix">-->
  496. <!-- <span class="section-title">设备事件</span>-->
  497. <!-- </div>-->
  498. <!-- <el-table :data="eventData" style="width: 100%" :show-header="true" :empty-text="'暂无数据'">-->
  499. <!-- <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>-->
  500. <!-- <el-table-column label="事件名称" prop="eventKey"></el-table-column>-->
  501. <!-- <el-table-column label="事件类型" prop="eventType" :formatter="formatEventType"></el-table-column>-->
  502. <!-- <el-table-column label="事件代码" prop="eventCode"></el-table-column>-->
  503. <!-- <el-table-column label="外部事件代码" prop="extEventCode"></el-table-column>-->
  504. <!-- </el-table>-->
  505. <!-- </el-card>-->
  506. <!-- </div>-->
  507. <!-- 设备事件日志 -->
  508. <div v-if="activeTab === 'eventLog'">
  509. <el-form inline>
  510. <el-form-item label="记录时间">
  511. <el-date-picker
  512. v-model="logDaterangeTime"
  513. style="width: 240px"
  514. value-format="yyyy-MM-dd HH:mm"
  515. type="datetimerange"
  516. range-separator="-"
  517. start-placeholder="开始日期"
  518. end-placeholder="结束日期"
  519. ></el-date-picker>
  520. </el-form-item>
  521. <el-form-item label="事件名称">
  522. <el-select v-model="eventLogQueryParams.eventName" clearable>
  523. <el-option
  524. v-for="item in eventData"
  525. :key="item.eventKey"
  526. :label="item.eventName"
  527. :value="item.eventKey"
  528. ></el-option>
  529. </el-select>
  530. </el-form-item>
  531. <el-form-item>
  532. <el-button type="primary" @click="handleEventLogQuery">查询</el-button>
  533. <el-button @click="resetEventLogQuery">重置</el-button>
  534. </el-form-item>
  535. </el-form>
  536. <el-table :data="eventLogData" style="width: 100%" :show-header="true" :empty-text="'暂无数据'">
  537. <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
  538. <el-table-column label="对象编号" prop="objCode"></el-table-column>
  539. <el-table-column label="对象名称" prop="objName"></el-table-column>
  540. <el-table-column label="事件名称" prop="eventName"></el-table-column>
  541. <el-table-column label="事件时间" prop="eventTime"></el-table-column>
  542. <el-table-column label="操作" align="center" width="100">
  543. <template slot-scope="scope">
  544. <el-button type="text" size="mini" icon="el-icon-info" @click="handleEventLogDetail(scope.row)">详情</el-button>
  545. </template>
  546. </el-table-column>
  547. </el-table>
  548. <pagination
  549. v-show="eventLogQueryTotal > 0"
  550. :total="eventLogQueryTotal"
  551. :page.sync="eventLogQueryParams.pageNum"
  552. :limit.sync="eventLogQueryParams.pageSize"
  553. @pagination="handleEventLogQuery"
  554. />
  555. </div>
  556. <!-- 调用日志 -->
  557. <div v-if="activeTab === 'callLog'">
  558. <!-- 调用日志表格 -->
  559. <el-form inline>
  560. <el-form-item label="记录时间">
  561. <el-date-picker
  562. v-model="callDaterangeTime"
  563. style="width: 355px"
  564. value-format="yyyy-MM-dd HH:mm"
  565. type="datetimerange"
  566. range-separator="-"
  567. start-placeholder="开始日期"
  568. end-placeholder="结束日期"
  569. ></el-date-picker>
  570. </el-form-item>
  571. <el-form-item label="能力标识">
  572. <el-select v-model="callLogQueryParams.abilityKey" style="width: 200px;" clearable>
  573. <el-option
  574. v-for="item in abilityData"
  575. :key="item.abilityKey"
  576. :label="item.abilityName"
  577. :value="item.abilityKey"
  578. ></el-option>
  579. </el-select>
  580. </el-form-item>
  581. <el-form-item label="调用状态" >
  582. <el-select v-model="callLogQueryParams.callStatus" style="width: 100px;" clearable>
  583. <el-option
  584. v-for="(value, key) in callStatusOptions"
  585. :key="key"
  586. :label="value"
  587. :value="key"
  588. ></el-option>
  589. </el-select>
  590. </el-form-item>
  591. <el-form-item>
  592. <el-button type="primary" @click="handleCallLogQuery">查询</el-button>
  593. <el-button @click="resetCallLogQuery">重置</el-button>
  594. </el-form-item>
  595. </el-form>
  596. <el-table :data="callLogData" style="width: 100%" :show-header="true" :empty-text="'暂无数据'">
  597. <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
  598. <el-table-column label="对象编号" prop="objCode"></el-table-column>
  599. <el-table-column label="对象名称" prop="objName"></el-table-column>
  600. <el-table-column label="对象能力" prop="abilityName"></el-table-column>
  601. <el-table-column label="调用时间" prop="callTime"></el-table-column>
  602. <el-table-column label="调用结果" align="center" width="100">
  603. <template slot-scope="scope">
  604. <span>{{ formatCallStatus(scope.row.callStatus) }}</span>
  605. </template>
  606. </el-table-column>
  607. <el-table-column label="操作" align="center" width="100">
  608. <template slot-scope="scope">
  609. <el-button type="text" size="mini" icon="el-icon-info" @click="handleCallLogDetail(scope.row)">详情
  610. </el-button>
  611. </template>
  612. </el-table-column>
  613. </el-table>
  614. <pagination
  615. v-show="callLogQueryTotal > 0"
  616. :total="callLogQueryTotal"
  617. :page.sync="callLogQueryParams.pageNum"
  618. :limit.sync="callLogQueryParams.pageSize"
  619. @pagination="handleCallLogQuery"
  620. />
  621. </div>
  622. <!-- 设备日志 -->
  623. <div v-if="activeTab === 'reportLog'">
  624. <el-form inline>
  625. <el-form-item label="记录时间">
  626. <el-date-picker
  627. v-model="logDaterangeTime"
  628. style="width: 240px"
  629. value-format="yyyy-MM-dd HH:mm"
  630. type="datetimerange"
  631. range-separator="-"
  632. start-placeholder="开始日期"
  633. end-placeholder="结束日期"
  634. ></el-date-picker>
  635. </el-form-item>
  636. <el-form-item>
  637. <el-button type="primary" @click="handleLogQuery">查询</el-button>
  638. <el-button @click="resetLogQuery">重置</el-button>
  639. </el-form-item>
  640. </el-form>
  641. <el-table :data="reportLogData" style="width: 100%" :show-header="true" :empty-text="'暂无数据'">
  642. <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
  643. <el-table-column label="对象编号" prop="objCode"></el-table-column>
  644. <el-table-column label="对象名称" prop="objName"></el-table-column>
  645. <el-table-column label="消息类型" prop="msgDesc"></el-table-column>
  646. <el-table-column label="上报时间" prop="reportTime" width="180"></el-table-column>
  647. <el-table-column label="操作" align="center" width="100">
  648. <template slot-scope="scope">
  649. <el-button type="text" size="mini" icon="el-icon-info" @click="handleReportLogDetail(scope.row)">详情
  650. </el-button>
  651. </template>
  652. </el-table-column>
  653. </el-table>
  654. <pagination
  655. v-show="logQueryTotal > 0"
  656. :total="logQueryTotal"
  657. :page.sync="logQueryParams.pageNum"
  658. :limit.sync="logQueryParams.pageSize"
  659. @pagination="handleLogQuery"
  660. />
  661. </div>
  662. </div>
  663. </el-dialog>
  664. </el-col>
  665. </el-row>
  666. </div>
  667. </template>
  668. <script>
  669. import { listDevRecursionByArea, getDevice, delDevice, addDevice, updateDevice } from '@/api/device/device'
  670. import { areaTreeSelect } from '@/api/basecfg/area'
  671. import { getFacsCategorygetByCode, listAllFacs,listFacs } from '@/api/basecfg/emsfacs'
  672. import { listSubsystemAll } from '@/api/adapter/subsystem'
  673. import { getModelByCode, listAllModel } from '@/api/basecfg/objModel'
  674. import { getObjAttr } from '@/api/basecfg/objAttribute'
  675. import { addAttrValueBatch } from '@/api/basecfg/objAttributeValue'
  676. import { getDevProcess } from '@/api/commonApi'
  677. import { addComponent, delComponent, getComponent, listByDevice, updateComponent } from '@/api/basecfg/component'
  678. import Treeselect from '@riophae/vue-treeselect'
  679. import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  680. import { listcallAbility } from '@/api/basecfg/objAbility'
  681. import { getCallLog, getReportLog, listCallLog, listReportLog,listEventLog,getEventLog } from '@/api/basecfg/objLog'
  682. export default {
  683. name: 'Device',
  684. components: { Treeselect },
  685. data() {
  686. return {
  687. // 表格属性详情弹窗状态
  688. showTableDetail: false,
  689. // 表格详情数据
  690. tableDetailData: [],
  691. // 归属区域下拉选项
  692. areaOptions: [],
  693. // 归属子区下拉选项
  694. subAreaOptions: [],
  695. abilityDialogVisible: false,
  696. abilityForm: {
  697. abilityName: '',
  698. abilityKey: '',
  699. abilityParam: '',
  700. abilityDesc: ''
  701. },
  702. currentAbilityIndex: -1,
  703. activeTab: 'basic',
  704. ComponentRow: [],
  705. componentForm: {},
  706. subcategoryCode: '',
  707. // 属性模板数组
  708. attrList: [],
  709. attrValues: [],
  710. ComponentList: [],
  711. abilityDevice: [],
  712. attrValuesMap: {},
  713. modelList: [],
  714. showDrawer: false,
  715. showDevProcessDrawer: false,
  716. componentOpen: false,
  717. // 遮罩层
  718. loading: true,
  719. // 选中数组
  720. ids: [],
  721. // 非单个禁用
  722. single: true,
  723. // 非多个禁用
  724. multiple: true,
  725. // 显示搜索条件
  726. showSearch: true,
  727. // 总条数
  728. total: 0,
  729. // 能源设备表格数据
  730. deviceList: [],
  731. // 弹出层标题
  732. title: '',
  733. // 是否显示弹出层
  734. open: false,
  735. // 区域名称
  736. areaName: undefined,
  737. // 区域树选项
  738. treeAreaOptions: undefined,
  739. totalAreaOptions: undefined,
  740. // 设施选项
  741. facsOptions: undefined,
  742. // 设备分类
  743. subCategoryOptions: undefined,
  744. subsystemOptions: undefined,
  745. devOptions: undefined,
  746. defaultProps: {
  747. children: 'children',
  748. label: 'label'
  749. },
  750. callDaterangeTime: [],
  751. logDaterangeTime: [],
  752. reportLogData: [],
  753. logQueryParams: {
  754. startTime: '',
  755. endTime: '',
  756. pageNum: 1,
  757. pageSize: 10
  758. },
  759. logQueryTotal: 0,
  760. callLogData: [],
  761. callLogQueryParams: {
  762. abilityKey: '',
  763. callStatus: '',
  764. startTime: '',
  765. endTime: '',
  766. pageNum: 1,
  767. pageSize: 10
  768. },
  769. callLogQueryTotal: 0,
  770. callStatusOptions: {
  771. 0: '成功',
  772. 1: '进行中',
  773. 2: '失败'
  774. },
  775. callLogDetailDialog: false,
  776. callLogDetailData: {},
  777. reportDetailDialog: false,
  778. reportDetailData: {},
  779. callLog: false,
  780. reportLog: false,
  781. eventLogData: [],
  782. eventLogQueryParams: {
  783. eventName:'',
  784. eventKey:'',
  785. startTime: '',
  786. endTime: '',
  787. pageNum: 1,
  788. pageSize: 10
  789. },
  790. eventLogQueryTotal: 0,
  791. eventLogDetailDialog: false,
  792. eventLogDetailData: {},
  793. // 查询参数
  794. queryParams: {
  795. psCode: null,
  796. pageNum: 1,
  797. pageSize: 10,
  798. deviceCode: null,
  799. deviceSubCategory: '',
  800. deviceCategory: 'E',
  801. locationRef: null,
  802. locationRefName: null,
  803. refFacs: null,
  804. customAttrs: null,
  805. areaCode: null,
  806. location: null
  807. },
  808. queryComponentParams: {
  809. pageNum: 1,
  810. pageSize: 10
  811. },
  812. componentTotal:0,
  813. objComTypeMapping: {
  814. 1: '总开',
  815. 2: '照明',
  816. 3: '风机'
  817. },
  818. objComTypeOptions: [
  819. { code: 1, name: '总开' },
  820. { code: 2, name: '照明' },
  821. { code: 3, name: '风机' }
  822. ],
  823. curRow: {},
  824. abilityData: [],
  825. eventData: [],
  826. BaseData: [],
  827. ProtocolData: [],
  828. StateData: [],
  829. MeasureData: [],
  830. // 折叠状态,默认全部折叠
  831. collapsed: {
  832. Base: true,
  833. Protocol: true,
  834. State: true,
  835. Measure: true
  836. },
  837. attrTables: {
  838. Base: { title: '基础属性', data: [] },
  839. Protocol: { title: '协议属性', data: [] },
  840. State: { title: '状态属性', data: [] },
  841. Measure: { title: '计量属性', data: [] }
  842. },
  843. // 控制表格显示的方法
  844. toggleCollapse(tableName) {
  845. this.collapsed[tableName] = !this.collapsed[tableName];
  846. },
  847. // 表单参数
  848. form: {
  849. customAttrs: []
  850. },
  851. // 表单校验
  852. rules: {
  853. refFacs: [
  854. { required: true, message: '归属设施', trigger: 'blur' }
  855. ],
  856. areaCode:[
  857. { required: true, message: '归属区域', trigger: 'blur' }
  858. ],
  859. locationRef:[
  860. { required: true, message: '归属子区', trigger: 'blur' }
  861. ],
  862. refArea: [
  863. { required: true, message: '安装位置', trigger: 'blur' }
  864. ],
  865. deviceCode: [
  866. { required: true, message: '设备代码不能为空', trigger: 'blur' }
  867. ],
  868. deviceName: [
  869. { required: true, message: '设备名称不能为空', trigger: 'blur' }
  870. ]
  871. },
  872. componentRules: {
  873. deviceCode: [
  874. { required: true, message: '设备code不能为空', trigger: 'blur' }
  875. ],
  876. compoCode: [
  877. { required: true, message: '部件编码不能为空', trigger: 'blur' }
  878. ],
  879. psCode: [
  880. { required: true, message: '工艺标签代码不能为空', trigger: 'blur' }
  881. ]
  882. }
  883. }
  884. },
  885. watch: {
  886. // 根据名称筛选区域树
  887. areaName(val) {
  888. this.$refs.tree.filter(val)
  889. },
  890. // 监听 activeTab 的变化
  891. activeTab(newVal) {
  892. if (newVal === 'callLog') {
  893. // 当切换到“调用日志”时,调用查询接口
  894. this.handleCallLogQuery()
  895. }else if(newVal ==='reportLog'){
  896. this.handleLogQuery()
  897. } else if (newVal === 'eventLog') {
  898. this.handleEventLogQuery()
  899. }
  900. }
  901. },
  902. created() {
  903. this.getList()
  904. this.getAreaTree('0', 2)
  905. this.getFacsOptions()
  906. this.getSubsystem()
  907. this.getSubCategorygetByCode()
  908. this.getDevModel()
  909. this.getAllDevProcess(this.subcategoryCode)
  910. const now = new Date()
  911. const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0)
  912. const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59)
  913. this.logQueryParams.startTime = this.formatDate(startOfDay)
  914. this.logQueryParams.endTime = this.formatDate(endOfDay)
  915. this.callLogQueryParams.startTime = this.formatDate(startOfDay)
  916. this.callLogQueryParams.endTime = this.formatDate(endOfDay)
  917. // 设置默认日期范围
  918. this.callDaterangeTime = [this.formatDate(startOfDay), this.formatDate(endOfDay)]
  919. this.logDaterangeTime = [this.formatDate(startOfDay), this.formatDate(endOfDay)]
  920. this.loadAreaOptions() // 加载归属区域数据
  921. },
  922. methods: {
  923. // 处理表格属性详情点击事件
  924. handleTableAttrDetail(row) {
  925. try {
  926. // 解析JSON格式的属性值
  927. const tableData = JSON.parse(row.attrValue);
  928. // 格式化表格数据,确保包含所需字段
  929. this.tableDetailData = tableData.map((item, index) => ({
  930. ...item,
  931. name: item.name || `项目${index + 1}`,
  932. key: item.key || '',
  933. value: item.value || '',
  934. updateTime: item.updateTime || ''
  935. }));
  936. // 显示弹窗
  937. this.showTableDetail = true;
  938. } catch (error) {
  939. this.$message.error('解析表格数据失败,请检查数据格式');
  940. console.error('解析表格数据失败:', error);
  941. }
  942. },
  943. // 根据区域代码获取区域名称
  944. buildRefAreaName(curRow) {
  945. const area = this.areaOptions.find(a => a.id === curRow.areaCode);
  946. const areaName = area ? area.label : '未知区域';
  947. if (curRow.locationRef !== curRow.areaCode) {
  948. return areaName + ' - ' + curRow.locationRefName;
  949. }
  950. return areaName;
  951. },
  952. /**下拉归属区域*/
  953. loadAreaOptions() {
  954. areaTreeSelect('0', 1).then(response => {
  955. this.areaOptions = response.data || []
  956. })
  957. },
  958. /**下拉归属子区*/
  959. loadSubAreaOptions(rootCode) {
  960. areaTreeSelect(rootCode, 2).then(response => {
  961. this.subAreaOptions = response.data || []
  962. })
  963. },
  964. /** 归属区域变更时查询归属子区和归属设施 */
  965. handleAreaChange(value) {
  966. //清空
  967. this.form.locationRef = null;
  968. this.form.refFacs = null;
  969. this.subAreaOptions = [];
  970. this.facsOptions = [];
  971. // 归属子区
  972. this.loadSubAreaOptions(value);
  973. // 归属设施
  974. this.getFacsOptions(value);
  975. },
  976. /** 查询归属设施 */
  977. getFacsOptions(refArea) {
  978. const getFacsParams = {
  979. refArea: refArea,
  980. facsCategory: this.queryParams.deviceCategory,
  981. subCategory: this.queryParams.deviceSubCategory
  982. };
  983. listAllFacs(getFacsParams).then(response => {
  984. this.facsOptions = response.data || [];
  985. console.log("归属设施",this.facsOptions);
  986. });
  987. },
  988. formatDate(date) {
  989. if (!date) return ''
  990. const year = date.getFullYear()
  991. const month = (date.getMonth() + 1).toString().padStart(2, '0')
  992. const day = date.getDate().toString().padStart(2, '0')
  993. const hours = date.getHours().toString().padStart(2, '0')
  994. const minutes = date.getMinutes().toString().padStart(2, '0')
  995. const seconds = date.getSeconds().toString().padStart(2, '0')
  996. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
  997. },
  998. formatCallStatus(status) {
  999. const statusMap = {
  1000. 0: '成功',
  1001. 1: '进行中',
  1002. 2: '失败'
  1003. }
  1004. return statusMap[status] || '未知状态'
  1005. },
  1006. /** 查询设备事件日志 */
  1007. handleEventLogQuery() {
  1008. if (this.curRow) {
  1009. const startTime = this.logDaterangeTime[0]
  1010. const endTime = this.logDaterangeTime[1]
  1011. const eventKey = this.eventLogQueryParams.eventName;
  1012. this.getEventLog(this.curRow.deviceCode, eventKey,startTime, endTime)
  1013. }
  1014. },
  1015. /** 事件日志表格 */
  1016. getEventLog(deviceCode,eventKey,startTime, endTime) {
  1017. const query = {
  1018. objCode: deviceCode,
  1019. startRecTime: startTime,
  1020. endRecTime: endTime,
  1021. eventKey: eventKey,
  1022. pageNum: this.eventLogQueryParams.pageNum,
  1023. pageSize: this.eventLogQueryParams.pageSize
  1024. }
  1025. listEventLog(query).then(response => {
  1026. this.eventLogData = response.rows || []
  1027. console.log("事件日志",this.eventLogData)
  1028. this.eventLogQueryTotal = response.total
  1029. })
  1030. },
  1031. /** 事件日志详情 */
  1032. handleEventLogDetail(row) {
  1033. getEventLog(row.id).then(response => {
  1034. this.eventLogDetailData = response.data || {}
  1035. console.log("事件日志详情",this.eventLogDetailData)
  1036. this.eventLogDetailDialog = true
  1037. })
  1038. },
  1039. /** 重置事件日志查询 */
  1040. resetEventLogQuery() {
  1041. this.logDaterangeTime = []
  1042. this.eventLogQueryParams.eventName=''
  1043. this.eventLogQueryParams.pageNum = 1
  1044. this.eventLogQueryParams.pageSize = 10
  1045. this.handleEventLogQuery()
  1046. },
  1047. /**重置调用日志*/
  1048. resetCallLogQuery() {
  1049. this.callDaterangeTime = []
  1050. this.callLogQueryParams.abilityKey = ''
  1051. this.callLogQueryParams.callStatus = ''
  1052. this.callLogQueryParams.pageNum = 1
  1053. this.callLogQueryParams.pageSize = 10
  1054. this.handleCallLogQuery()
  1055. },
  1056. /**查询调用日志*/
  1057. handleCallLogQuery() {
  1058. if (this.curRow) {
  1059. const startTime = this.callDaterangeTime[0]
  1060. const endTime = this.callDaterangeTime[1]
  1061. const abilityKey = this.callLogQueryParams.abilityKey
  1062. const callStatus = this.callLogQueryParams.callStatus
  1063. this.getCallLog(this.curRow.deviceCode, startTime, endTime, abilityKey, callStatus)
  1064. }
  1065. },
  1066. /**调用日志表格*/
  1067. getCallLog(deviceCode, startTime, endTime, abilityKey, callStatus) {
  1068. const query = {
  1069. objCode: deviceCode,
  1070. objType: '2',
  1071. startRecTime: startTime,
  1072. endRecTime: endTime,
  1073. abilityKey: abilityKey,
  1074. callStatus: callStatus,
  1075. pageNum: this.callLogQueryParams.pageNum,
  1076. pageSize: this.callLogQueryParams.pageSize
  1077. }
  1078. listCallLog(query).then(response => {
  1079. this.callLogData = response.rows || []
  1080. this.callLogQueryTotal = response.total
  1081. })
  1082. },
  1083. /**调用日志详情*/
  1084. handleCallLogDetail(row) {
  1085. getCallLog(row.id).then(response => {
  1086. this.callLogDetailData = response.data || {}
  1087. this.callLogDetailDialog = true
  1088. })
  1089. },
  1090. /**重置设备日志*/
  1091. resetLogQuery() {
  1092. this.logDaterangeTime = []
  1093. this.logQueryParams.pageNum = 1
  1094. this.logQueryParams.pageSize = 10
  1095. this.handleLogQuery() // 重新查询
  1096. },
  1097. /** 查询设备日志*/
  1098. handleLogQuery() {
  1099. if (this.curRow) {
  1100. const startTime = this.logDaterangeTime[0]
  1101. const endTime = this.logDaterangeTime[1]
  1102. this.getReportLog(this.curRow.deviceCode, startTime, endTime)
  1103. }
  1104. },
  1105. /**设备日志表格*/
  1106. getReportLog(deviceCode, startTime, endTime) {
  1107. const query = {
  1108. objCode: deviceCode,
  1109. objType: '2',
  1110. startRecTime: startTime,
  1111. endRecTime: endTime,
  1112. pageNum: this.logQueryParams.pageNum,
  1113. pageSize: this.logQueryParams.pageSize
  1114. }
  1115. listReportLog(query).then(response => {
  1116. this.reportLogData = response.rows || []
  1117. this.logQueryTotal = response.total
  1118. })
  1119. },
  1120. /**设备日志详情*/
  1121. handleReportLogDetail(row) {
  1122. getReportLog(row.id).then(response => {
  1123. this.reportDetailData = response.data || {}
  1124. this.reportDetailDialog = true
  1125. })
  1126. },
  1127. formatEventType(row, column, cellValue) {
  1128. return cellValue === 1 ? '消息上报' : '异常告警'
  1129. },
  1130. getAttrValueText(attrValue) {
  1131. const valueMap = {
  1132. 0: '关闭',
  1133. 1: '开启',
  1134. 2: '通电'
  1135. }
  1136. return valueMap[attrValue] || attrValue
  1137. },
  1138. /** 查询能源设备列表 */
  1139. getList() {
  1140. this.loading = true
  1141. listDevRecursionByArea(this.queryParams).then(response => {
  1142. this.deviceList = response.rows
  1143. this.total = response.total
  1144. this.loading = false
  1145. })
  1146. },
  1147. /**新增、修改、删除*/
  1148. handleComponentAdd() {
  1149. this.componentReset()
  1150. this.componentOpen = true
  1151. this.title = '添加设备器件属性'
  1152. this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
  1153. },
  1154. handleComponentUpdate(row) {
  1155. this.componentReset()
  1156. const id = row.id || this.ids
  1157. getComponent(id).then(response => {
  1158. this.componentForm = response.data
  1159. this.componentOpen = true
  1160. this.title = '修改设备器件属性'
  1161. this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
  1162. })
  1163. },
  1164. handleComponentDelete(row) {
  1165. const ids = row.id || this.ids
  1166. this.$modal.confirm('是否确认删除能源对象属性编号为"' + ids + '"的数据项?').then(function() {
  1167. return delComponent(ids)
  1168. }).then(() => {
  1169. this.getComponentList(row.deviceCode)
  1170. this.$modal.msgSuccess('删除成功')
  1171. }).catch(() => {
  1172. })
  1173. },
  1174. submitComponentForm() {
  1175. this.$refs['componentForm'].validate(valid => {
  1176. if (valid) {
  1177. if (this.componentForm.id != null) {
  1178. updateComponent(this.componentForm).then(response => {
  1179. this.$modal.msgSuccess('修改成功')
  1180. this.componentOpen = false
  1181. this.getComponentList(this.componentForm.deviceCode)
  1182. })
  1183. } else {
  1184. addComponent(this.componentForm).then(response => {
  1185. this.$modal.msgSuccess('新增成功')
  1186. this.componentOpen = false
  1187. this.getComponentList(this.componentForm.deviceCode)
  1188. })
  1189. }
  1190. }
  1191. })
  1192. },
  1193. ComponentCancel() {
  1194. this.componentOpen = false
  1195. this.componentReset()
  1196. },
  1197. /**查询器件列表*/
  1198. getComponentList(deviceCode) {
  1199. listByDevice(deviceCode).then(response => {
  1200. this.ComponentList = response.data
  1201. })
  1202. },
  1203. /** 查询区域树结构 */
  1204. getAreaTree(areaCode, layer) {
  1205. areaTreeSelect(areaCode, layer).then(response => {
  1206. this.treeAreaOptions = [{
  1207. id: null,
  1208. label: '全部',
  1209. children: response.data
  1210. }]
  1211. })
  1212. },
  1213. // 筛选节点
  1214. filterNode(value, data) {
  1215. if (!value) return true
  1216. return data.label.indexOf(value) !== -1
  1217. },
  1218. // 节点单击事件
  1219. handleNodeClick(data) {
  1220. this.queryParams.locationRef = data.id
  1221. this.handleQuery()
  1222. },
  1223. // 取消按钮
  1224. cancel() {
  1225. this.open = false
  1226. this.reset()
  1227. },
  1228. /** 执行弹框 */
  1229. handleAbilityEdit(row) {
  1230. // 复制当前行记录的值到弹框表单中
  1231. this.abilityForm = JSON.parse(JSON.stringify(row))
  1232. this.currentAbilityIndex = this.abilityData.indexOf(row)
  1233. this.abilityDialogVisible = true
  1234. },
  1235. /**设备能力-执行按钮*/
  1236. saveAbilityEdit() {
  1237. if (this.currentAbilityIndex !== -1) {
  1238. const updatedAbility = { ...this.abilityForm }
  1239. const abilityParams = {
  1240. objCode: this.curRow.deviceCode,
  1241. objType: 2,
  1242. modeCode: updatedAbility.modelCode,
  1243. abilityKey: updatedAbility.abilityKey,
  1244. abilityParam: updatedAbility.abilityParam
  1245. }
  1246. listcallAbility(abilityParams)
  1247. .then((response) => {
  1248. if (response.code === 200) {
  1249. this.$message.success('保存成功')
  1250. this.abilityData.splice(this.currentAbilityIndex, 1, updatedAbility)
  1251. }
  1252. })
  1253. this.abilityDialogVisible = false
  1254. }
  1255. },
  1256. /** 取消执行按钮 */
  1257. cancelAbilityEdit() {
  1258. this.abilityDialogVisible = false
  1259. this.abilityForm = {
  1260. abilityName: '',
  1261. abilityKey: '',
  1262. abilityParam: '',
  1263. abilityDesc: ''
  1264. }
  1265. this.currentAbilityIndex = -1
  1266. },
  1267. // 表单重置
  1268. reset() {
  1269. this.form = {
  1270. id: null,
  1271. areaCode: null,
  1272. location: null,
  1273. locationRef: null,
  1274. deviceCode: null,
  1275. deviceName: null,
  1276. deviceType: null,
  1277. deviceSpec: null,
  1278. deviceBrand: null,
  1279. deviceStatus: null,
  1280. deviceModel: null,
  1281. refArea: null,
  1282. refFacs: null,
  1283. subsystemCode: null,
  1284. psCode: null,
  1285. createTime: null,
  1286. updateTime: null,
  1287. customAttrs: []
  1288. }
  1289. this.attrList = []
  1290. this.attrValuesMap = {}
  1291. this.resetForm('form')
  1292. },
  1293. componentReset() {
  1294. this.componentForm = {
  1295. id: null,
  1296. deviceCode: this.ComponentRow.deviceCode || '',
  1297. compoCode: null,
  1298. compoTag: null,
  1299. psCode: null,
  1300. extCompoCode: null,
  1301. compoModel: null,
  1302. compoBrand: null,
  1303. compoSpec: null,
  1304. ancestors: null,
  1305. parentCompo: null
  1306. }
  1307. this.resetForm('componentForm')
  1308. },
  1309. /** 搜索按钮操作 */
  1310. handleQuery() {
  1311. this.queryParams.pageNum = 1
  1312. this.getList()
  1313. },
  1314. /** 重置按钮操作 */
  1315. resetQuery() {
  1316. this.queryParams.locationRef = null
  1317. this.resetForm('queryForm')
  1318. this.handleQuery()
  1319. },
  1320. // 多选框选中数据
  1321. handleSelectionChange(selection) {
  1322. this.ids = selection.map(item => item.id)
  1323. this.single = selection.length !== 1
  1324. this.multiple = !selection.length
  1325. },
  1326. /** 新增按钮操作 */
  1327. handleAdd() {
  1328. this.reset()
  1329. this.open = true
  1330. this.title = '添加能源设备'
  1331. this.attrList = []
  1332. this.form.customAttrs = []
  1333. this.attrValuesMap = {}
  1334. // 加载归属子区
  1335. this.loadSubAreaOptions(this.form.areaCode)
  1336. },
  1337. /**设备器件按钮*/
  1338. handleDevProcess(row) {
  1339. this.showDevProcessDrawer = true
  1340. this.ComponentRow = row
  1341. listByDevice(this.ComponentRow.deviceCode).then(response => {
  1342. this.ComponentList = response.data
  1343. })
  1344. },
  1345. shouldShowDevProcessButton(row) {
  1346. const categoryIsW = this.queryParams.deviceCategory === 'W'
  1347. const validPsCodes = ['AA', 'AH', 'AJ', 'AM', 'AP', 'AL', 'APE', 'ALE', 'AF', 'ACC']
  1348. const psCodeIsValid = validPsCodes.includes(row.psCode)
  1349. // 只有当设备分类为输能设备且设备工艺代码有效时,才返回true
  1350. return categoryIsW && psCodeIsValid
  1351. },
  1352. /**设备管理按钮*/
  1353. handleDetail(row) {
  1354. this.showDrawer = true
  1355. this.curRow = row
  1356. console.log('设备详情', this.curRow)
  1357. this.subKey = this.$options.data().subKey
  1358. getModelByCode(this.curRow.deviceModel).then(response => {
  1359. this.eventData = response.data?.eventList || []
  1360. this.abilityData = response.data?.abilityList || []
  1361. })
  1362. getObjAttr(2, this.curRow.deviceCode).then(response => {
  1363. this.attrTables.Base.data = response.data?.Base || []
  1364. this.attrTables.Protocol.data = response.data?.Protocol || []
  1365. this.attrTables.State.data = response.data?.State || []
  1366. this.attrTables.Measure.data = response.data?.Measure || []
  1367. })
  1368. this.activeTab = 'basic'
  1369. },
  1370. getDeviceStatus(status) {
  1371. return status === 1 ? '在线' : '离线'
  1372. },
  1373. getDeviceStatusClass(status) {
  1374. return status === 1 ? 'status-online' : 'status-offline'
  1375. },
  1376. /** 修改按钮操作 */
  1377. handleUpdate(row) {
  1378. this.reset()
  1379. const id = row.id || this.ids
  1380. getDevice(id).then(response => {
  1381. this.form = response.data
  1382. // 加载归属子区
  1383. this.loadSubAreaOptions(this.form.areaCode)
  1384. console.log('this.form', this.form)
  1385. this.open = true
  1386. this.title = '修改能源设备'
  1387. this.attrList = []
  1388. this.form.customAttrs = []
  1389. this.attrValuesMap = {}
  1390. this.getObjAttr(2, this.form.deviceCode)
  1391. })
  1392. },
  1393. /** 提交按钮 */
  1394. submitForm() {
  1395. if (!this.attrList) {
  1396. this.attrList = []
  1397. }
  1398. if (!this.form.customAttrs) {
  1399. this.form.customAttrs = []
  1400. }
  1401. let dataToSubmit = []
  1402. this.attrList.forEach(attr => {
  1403. const attrName = attr.attrName
  1404. const attrKey = attr.attrKey
  1405. const attrValue = this.attrValuesMap[attrKey]
  1406. const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
  1407. if (existingIndex === -1) {
  1408. dataToSubmit.push({
  1409. modelCode: this.form.deviceModel,
  1410. objCode: this.form.deviceCode,
  1411. objType: 2,
  1412. attrKey: attrKey,
  1413. attrValue: attrValue,
  1414. attrName: attrName
  1415. })
  1416. }
  1417. })
  1418. // 添加自定义属性数据
  1419. this.form.customAttrs.forEach(customAttr => {
  1420. const attrName = customAttr.attrName
  1421. const attrKey = customAttr.attrKey
  1422. const attrValue = customAttr.attrValue
  1423. const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
  1424. if (existingIndex === -1) {
  1425. dataToSubmit.push({
  1426. modelCode: '',
  1427. objCode: this.form.deviceCode,
  1428. objType: 2,
  1429. attrKey: attrKey,
  1430. attrValue: attrValue,
  1431. attrName: attrName
  1432. })
  1433. }
  1434. })
  1435. this.$refs['form'].validate(valid => {
  1436. if (valid) {
  1437. if (this.form.id != null) {
  1438. updateDevice(this.form).then(response => {
  1439. this.$modal.msgSuccess('修改成功')
  1440. this.open = false
  1441. this.showDrawer = false
  1442. this.getList()
  1443. if (this.showDrawer && this.curRow && this.curRow.id === this.form.id) {
  1444. this.handleDetail(this.form)
  1445. }
  1446. })
  1447. if (dataToSubmit.length > 0) {
  1448. addAttrValueBatch(dataToSubmit)
  1449. .then(response => {
  1450. if (response.code === 200) {
  1451. this.$message.success('属性添加成功')
  1452. }
  1453. })
  1454. }
  1455. } else {
  1456. addDevice(this.form).then(response => {
  1457. this.$modal.msgSuccess('新增成功')
  1458. this.open = false
  1459. this.getList() // 刷新设备列表
  1460. })
  1461. if (dataToSubmit.length > 0) {
  1462. addAttrValueBatch(dataToSubmit)
  1463. .then(response => {
  1464. if (response.code === 200) {
  1465. this.$message.success('属性添加成功')
  1466. }
  1467. })
  1468. }
  1469. }
  1470. }
  1471. })
  1472. },
  1473. /** 删除按钮操作 */
  1474. handleDelete(row) {
  1475. const ids = row.id || this.ids
  1476. this.$modal.confirm('是否确认删除能源设备编号为"' + ids + '"的数据项?').then(function() {
  1477. return delDevice(ids)
  1478. }).then(() => {
  1479. this.getList()
  1480. this.$modal.msgSuccess('删除成功')
  1481. }).catch(() => {
  1482. })
  1483. },
  1484. /** 导出按钮操作 */
  1485. handleExport() {
  1486. this.download('ems/basecfg/device/export', {
  1487. ...this.queryParams
  1488. }, `device_${new Date().getTime()}.xlsx`)
  1489. },
  1490. getSubCategorygetByCode() {
  1491. getFacsCategorygetByCode(this.queryParams.deviceCategory).then(response => {
  1492. this.subCategoryOptions = response.data.subtypeList || []
  1493. })
  1494. },
  1495. getSubsystem() {
  1496. listSubsystemAll().then(response => {
  1497. this.subsystemOptions = response.data
  1498. })
  1499. },
  1500. getAllDevProcess(subcategoryCode) {
  1501. getDevProcess(subcategoryCode).then(response => {
  1502. this.devOptions = response.data
  1503. })
  1504. },
  1505. deviceCategoryChange() {
  1506. this.queryParams.deviceSubCategory = ''
  1507. if (this.queryParams.deviceCategory === 'E' || this.queryParams.deviceCategory === 'W'
  1508. || this.queryParams.deviceCategory === 'T' || this.queryParams.deviceCategory === 'C') {
  1509. this.getAreaTree('0', 2)
  1510. } else if (this.queryParams.deviceCategory === 'Z') {
  1511. this.getAreaTree('0', 2)
  1512. }
  1513. this.getSubCategorygetByCode()
  1514. this.getFacsOptions()
  1515. this.handleQuery()
  1516. },
  1517. /**自定义属性表格*/
  1518. addCustomAttr() {
  1519. // 添加一个新的自定义属性
  1520. if (!Array.isArray(this.form.customAttrs)) {
  1521. this.form.customAttrs = []
  1522. }
  1523. this.form.customAttrs.push({
  1524. attrKey: '',
  1525. attrName: '',
  1526. attrValue: ''
  1527. })
  1528. // 强制更新视图
  1529. this.$forceUpdate()
  1530. },
  1531. deleteCustomAttr(index) {
  1532. // 删除指定索引的自定义属性
  1533. if (this.form.customAttrs.length > 0) {
  1534. this.form.customAttrs.splice(index, 1)
  1535. }
  1536. },
  1537. /**设备模型*/
  1538. updateAttrValue(attrKey, newValue) {
  1539. this.attrValuesMap[attrKey] = newValue
  1540. },
  1541. getPsName(psName) {
  1542. return psName === null ? '' : ' - '+psName;
  1543. },
  1544. getDevModel() {
  1545. listAllModel(2).then(response => {
  1546. this.modelList = response.data
  1547. })
  1548. },
  1549. handleModelChange(modelCode) {
  1550. if (modelCode) {
  1551. this.getModelByCode(modelCode)
  1552. this.getObjAttr(2, this.form.deviceCode)
  1553. }
  1554. },
  1555. getModelByCode(modelCode) {
  1556. getModelByCode(modelCode).then(response => {
  1557. const filteredAttrList = response.data.attrList.filter(attr => attr.attrType === 0)
  1558. this.attrList = filteredAttrList
  1559. })
  1560. },
  1561. /** getObjAttr存在问题 */
  1562. getObjAttr(objType, deviceCode) {
  1563. getObjAttr(objType, deviceCode).then(response => {
  1564. // const attrs = response.data.attrs;
  1565. const attrs = response.data.attrs.filter(attr => attr.attrType === 0)
  1566. const attrValues = response.data.attrValues || [] // 确保是一个数组
  1567. // 创建一个映射对象,用于存储 attrKey 与对应的 attrValue
  1568. const attrValuesMap = {}
  1569. // 遍历 attrs 数组
  1570. attrs.forEach(attr => {
  1571. // 查找 attrValues 数组中是否有匹配的 attrKey
  1572. const attrValueObj = attrValues.find(value => value.attrKey === attr.attrKey)
  1573. if (attrValueObj) {
  1574. attrValuesMap[attr.attrKey] = attrValueObj.attrValue
  1575. } else {
  1576. attrValuesMap[attr.attrKey] = ''
  1577. }
  1578. })
  1579. // 更新 attrValuesMap 到组件的数据中
  1580. this.attrValuesMap = attrValuesMap
  1581. })
  1582. }
  1583. }
  1584. }
  1585. </script>
  1586. <style lang="scss" scoped>
  1587. .divider {
  1588. border-bottom: 2px solid #ebeef5;
  1589. margin: 10px 0;
  1590. }
  1591. .section-title {
  1592. font-size: 18px;
  1593. font-weight: bold;
  1594. margin-top: 20px;
  1595. margin-bottom: 10px;
  1596. }
  1597. .drawer-content {
  1598. padding: 0 20px;
  1599. }
  1600. .section-title {
  1601. font-size: 18px;
  1602. font-weight: bold;
  1603. }
  1604. .attr-list-container {
  1605. border: 1px solid #ccc;
  1606. padding: 10px;
  1607. margin: 10px 0;
  1608. font-weight: bold;
  1609. }
  1610. .attr-list-container ul {
  1611. padding: 0;
  1612. list-style: none;
  1613. }
  1614. .attr-item {
  1615. display: flex;
  1616. align-items: center;
  1617. margin-bottom: 10px;
  1618. }
  1619. .attr-input {
  1620. min-width: 100px;
  1621. flex: 1;
  1622. }
  1623. .status-online {
  1624. color: #00FF00; /* 在线状态颜色 */
  1625. background-color: #DDFFDD;
  1626. padding: 2px 6px;
  1627. border-radius: 4px;
  1628. }
  1629. .status-offline {
  1630. color: #FF0000; /* 离线状态颜色 */
  1631. background-color: #FFDDDD;
  1632. padding: 2px 6px;
  1633. border-radius: 4px;
  1634. }
  1635. .detail-dialog .el-dialog {
  1636. width: 80%;
  1637. }
  1638. .section-title {
  1639. font-size: 16px;
  1640. font-weight: bold;
  1641. margin: 10px 0;
  1642. padding: 5px 0;
  1643. border-bottom: 1px solid #ebeef5;
  1644. }
  1645. .dialog-header {
  1646. display: flex;
  1647. justify-content: space-between;
  1648. align-items: center;
  1649. width: 100%;
  1650. }
  1651. .button-group {
  1652. display: flex;
  1653. gap: 10px;
  1654. }
  1655. /* 禁用状态的输入框样式 */
  1656. .el-input.is-disabled .el-input__inner,
  1657. .el-textarea.is-disabled .el-textarea__inner {
  1658. background-color: #f5f7fa;
  1659. border-color: #e4e7ed;
  1660. color: #c0c4cc;
  1661. }
  1662. .footer {
  1663. display: flex;
  1664. justify-content: flex-end;
  1665. margin-top: 10px;
  1666. }
  1667. .status-online {
  1668. color: #00FF00; /* 在线状态颜色 */
  1669. background-color: #DDFFDD;
  1670. padding: 2px 6px;
  1671. border-radius: 4px;
  1672. }
  1673. .status-offline {
  1674. color: #FF0000; /* 离线状态颜色 */
  1675. background-color: #FFDDDD;
  1676. padding: 2px 6px;
  1677. border-radius: 4px;
  1678. }
  1679. </style>