index.vue 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  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. <div class="contents">
  19. <div class="other-content">
  20. <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
  21. label-width="68px"
  22. >
  23. <el-form-item label="设备分类" prop="deviceSubCategory">
  24. <el-select v-model="queryParams.deviceSubCategory">
  25. <el-option v-for="item in subCategoryOptions" placeholder="设备分类" :label="item.name"
  26. :value="item.code"
  27. :key="item.code"
  28. />
  29. </el-select>
  30. </el-form-item>
  31. <el-form-item label="归属设施" prop="refFacs">
  32. <el-select v-model="queryParams.refFacs">
  33. <el-option v-for="item in facsOptions" :label="item.facsName" :value="item.facsCode"
  34. :key="item.facsCode"
  35. />
  36. </el-select>
  37. </el-form-item>
  38. <el-form-item label="子系统" prop="subsystemCode">
  39. <el-select v-model="queryParams.subsystemCode">
  40. <el-option v-for="item in subsystemOptions" :label="item.systemName" :value="item.systemCode"
  41. :key="item.systemCode"
  42. />
  43. </el-select>
  44. </el-form-item>
  45. <el-form-item>
  46. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  47. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  48. </el-form-item>
  49. </el-form>
  50. <el-row :gutter="10" class="mb8">
  51. <el-col :span="1.5">
  52. <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  53. v-hasPermi="['ems:device:add']"
  54. >新增
  55. </el-button>
  56. </el-col>
  57. <el-col :span="1.5">
  58. <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
  59. v-hasPermi="['ems:device:edit']"
  60. >修改
  61. </el-button>
  62. </el-col>
  63. <el-col :span="1.5">
  64. <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
  65. @click="handleDelete"
  66. v-hasPermi="['ems:device:remove']"
  67. >删除
  68. </el-button>
  69. </el-col>
  70. <el-col :span="1.5">
  71. <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  72. v-hasPermi="['ems:device:export']"
  73. >导出
  74. </el-button>
  75. </el-col>
  76. <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  77. </el-row>
  78. </div>
  79. <div class="table-content">
  80. <!--分页-->
  81. <div class="button-group-container">
  82. <el-button-group>
  83. <el-button :type="primary1" icon="el-icon-s-fold" @click="switchData(1)"/>
  84. <el-button :type="primary2" icon="el-icon-menu" @click="switchData(2)"/>
  85. </el-button-group>
  86. </div>
  87. <el-table v-loading="loading" :data="deviceList" @selection-change="handleSelectionChange"
  88. v-if="istable === 1">
  89. <el-table-column type="selection" width="55" align="center"/>
  90. <el-table-column label="设备名称" align="left" prop="deviceName"/>
  91. <el-table-column label="安装位置" align="left" prop="areaPath" width="220px"/>
  92. <el-table-column label="归属设施" align="center" prop="refFacsName"/>
  93. <el-table-column label="设备分类" align="center" prop="deviceCategoryName"/>
  94. <el-table-column label="子系统" align="center" prop="subsystemName"/>
  95. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  96. <template slot-scope="scope">
  97. <el-button size="mini" type="text" icon="el-icon-info" @click="handleDevProcess(scope.row)"
  98. v-hasPermi="['basecfg:device:edit']" v-if="shouldShowDevProcessButton(scope.row)"
  99. >
  100. 器件
  101. </el-button>
  102. <el-button size="mini" type="text" icon="el-icon-info" @click="handleDetail(scope.row)"
  103. v-hasPermi="['basecfg:device:edit']"
  104. >
  105. 详情
  106. </el-button>
  107. <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  108. v-hasPermi="['basecfg:device:edit']"
  109. >
  110. 修改
  111. </el-button>
  112. <el-button size="mini" type="text" icon="el-icon-delete" class="deleteBtn"
  113. @click="handleDelete(scope.row)" v-hasPermi="['basecfg:device:remove']"
  114. >
  115. 删除
  116. </el-button>
  117. </template>
  118. </el-table-column>
  119. </el-table>
  120. <div v-else-if="istable === 2">
  121. <el-row :gutter="20" class="device-list">
  122. <el-col v-for="device in deviceList" :key="device.id" :span="6">
  123. <div :class="`device-card ${backStyle(device.areaPath)}`">
  124. <div class="device-header">
  125. <i class="el-icon-s-operation" style="margin-right: 8px;"></i>
  126. {{ device.deviceName }}
  127. </div>
  128. <div class="device-body">
  129. <p>设备代码:<span class="device-code">{{ device.deviceCode }}</span></p>
  130. <p>安装位置:<span class="deviceOthers">{{ device.areaPath }}</span></p>
  131. <p>归属设施:<span class="deviceOthers">{{ device.refFacsName }}</span></p>
  132. <p>设备分类:<span class="deviceOthers">{{ device.deviceCategoryName }}</span></p>
  133. <p>子系统:<span class="deviceOthers">{{ device.subsystemName }}</span></p>
  134. </div>
  135. <div class="device-footer">
  136. <el-button size="mini" plain icon=" el-icon-document" @click="handleDetail(device)">详情
  137. </el-button>
  138. <el-button size="mini" plain icon="el-icon-edit" @click="handleUpdate(device)">修改</el-button>
  139. <el-button size="mini" plain icon="el-icon-delete" type="danger" @click="handleDelete(device)">
  140. 删除
  141. </el-button>
  142. </div>
  143. </div>
  144. </el-col>
  145. </el-row>
  146. </div>
  147. <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
  148. :limit.sync="queryParams.pageSize"
  149. @pagination="getList"
  150. />
  151. <!-- 添加或修改能源设备对话框 -->
  152. <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  153. <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  154. <el-form-item label="归属设施" prop="refFacs">
  155. <el-select v-model="form.refFacs">
  156. <el-option v-for="item in facsOptions" :label="item.facsName" :value="item.facsCode"
  157. :key="item.facsCode"
  158. />
  159. </el-select>
  160. </el-form-item>
  161. <el-form-item label="设备代码" prop="deviceCode">
  162. <el-input v-model="form.deviceCode" placeholder="请输入设备代码"/>
  163. </el-form-item>
  164. <el-form-item label="设备名称" prop="deviceName">
  165. <el-input v-model="form.deviceName" placeholder="请输入设备名称"/>
  166. </el-form-item>
  167. <el-form-item label="功能类型" prop="psCode" v-if="queryParams.deviceCategory === 'W'">
  168. <el-select v-model="form.psCode">
  169. <el-option v-for="item in devOptions" :label="item.psName" :value="item.psCode"
  170. :key="item.psCode"
  171. />
  172. </el-select>
  173. </el-form-item>
  174. <el-form-item label="设备类型" prop="deviceType">
  175. <el-select v-model="form.deviceCategory">
  176. <el-option v-for="item in subCategoryOptions" :label="item.name" :value="item.code"
  177. :key="item.code"
  178. />
  179. </el-select>
  180. </el-form-item>
  181. <el-form-item label="设备模型" prop="deviceModel">
  182. <el-select v-model="form.deviceModel" style="width:100%" @change="handleModelChange">
  183. <el-option
  184. v-for="item in modelList"
  185. :label="item.modelName"
  186. :value="item.modelCode"
  187. :key="item.modelCode"
  188. />
  189. </el-select>
  190. </el-form-item>
  191. <!-- 这里可以展示属性名称和属性值 -->
  192. <div v-if="attrList.length > 0" class="attr-list-container">
  193. <h3>模型属性:</h3>
  194. <ul>
  195. <li v-for="attr in attrList" :key="attr.attrKey" class="attr-item">
  196. <span class="attr-name">{{ attr.attrName }} ({{ attr.attrUnit }}):</span>
  197. <!-- 使用 el-input 组件允许用户编辑属性值 -->
  198. <el-input
  199. v-model="attrValuesMap[attr.attrKey]"
  200. placeholder="点击编辑"
  201. size="small"
  202. @blur="updateAttrValue(attr.attrKey, attrValuesMap[attr.attrKey])"
  203. >
  204. </el-input>
  205. </li>
  206. </ul>
  207. </div>
  208. <h3 class="attr-list-container" v-if="attrList.length > 0">自定义属性
  209. <el-form-item label="" prop="attrList">
  210. <el-table class="attr-table" v-loading="loading" :data="form.customAttrs" max-height="280px"
  211. key="'customAttrs'"
  212. >
  213. <el-table-column label="标识" align="center" prop="attrKey">
  214. <template slot-scope="scope">
  215. <el-input size="mini" v-model="scope.row.attrKey" placeholder="请输入标识"/>
  216. </template>
  217. </el-table-column>
  218. <el-table-column label="属性名" align="center" prop="attrName">
  219. <template slot-scope="scope">
  220. <el-input size="mini" v-model="scope.row.attrName" placeholder="请输入属性名"/>
  221. </template>
  222. </el-table-column>
  223. <el-table-column label="属性值" align="center" prop="attrValue">
  224. <template slot-scope="scope">
  225. <el-input size="mini" v-model="scope.row.attrValue" placeholder="请输入属性值"/>
  226. </template>
  227. </el-table-column>
  228. <el-table-column align="center" label="操作">
  229. <template slot="header">
  230. <div class="operateBtns" @click="addCustomAttr">
  231. <span>添加</span><i class="el-icon-circle-plus-outline"></i>
  232. </div>
  233. </template>
  234. <template slot-scope="scope">
  235. <i class="el-icon-delete" @click="deleteCustomAttr(scope.$index)"></i>
  236. </template>
  237. </el-table-column>
  238. </el-table>
  239. </el-form-item>
  240. </h3>
  241. <el-form-item label="子系统" prop="subsystemCode">
  242. <el-select v-model="form.subsystemCode">
  243. <el-option v-for="item in subsystemOptions" :label="item.systemName" :value="item.systemCode"
  244. :key="item.systemCode"
  245. />
  246. </el-select>
  247. </el-form-item>
  248. </el-form>
  249. <div slot="footer" class="dialog-footer">
  250. <el-button type="primary" @click="submitForm">确 定</el-button>
  251. <el-button @click="cancel">取 消</el-button>
  252. </div>
  253. </el-dialog>
  254. <!--设备器件-->
  255. <el-drawer :title=ComponentRow.deviceName size="80%" :visible.sync="showDevProcessDrawer" direction="rtl">
  256. <div class="drawer-content" style="padding-left:50px">
  257. <el-row :gutter="10" class="mb8">
  258. <el-col :span="1.5">
  259. <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleComponentAdd"
  260. v-hasPermi="['ems:component:add']"
  261. >新增
  262. </el-button>
  263. </el-col>
  264. </el-row>
  265. <el-table v-loading="loading" :data="ComponentList">
  266. <el-table-column type="selection" width="55" align="center"/>
  267. <el-table-column label="部件编码" align="center" prop="compoCode"/>
  268. <el-table-column label="部件标签" align="center" prop="compoTag">
  269. <template slot-scope="scope">
  270. {{ objComTypeMapping[scope.row.compoTag] }}
  271. </template>
  272. </el-table-column>
  273. <el-table-column label="工艺标识代码" align="center" prop="psCode"/>
  274. <el-table-column label="外系统部件编码" align="center" prop="extCompoCode"/>
  275. <el-table-column label="部件模型" align="center" prop="compoModel"/>
  276. <el-table-column label="部件品牌" align="center" prop="compoBrand"/>
  277. <el-table-column label="部件型号" align="center" prop="compoSpec"/>
  278. <el-table-column label="祖籍列表" align="center" prop="ancestors"/>
  279. <el-table-column label="上级部件" align="center" prop="parentEqpt"/>
  280. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  281. <template slot-scope="scope">
  282. <el-button size="mini" type="text" icon="el-icon-edit" @click="handleComponentUpdate(scope.row)"
  283. v-hasPermi="['ems:component:edit']"
  284. >
  285. 修改
  286. </el-button>
  287. <el-button size="mini" type="text" icon="el-icon-delete" class="deleteBtn"
  288. @click="handleComponentDelete(scope.row)" v-hasPermi="['ems:component:remove']"
  289. >
  290. 删除
  291. </el-button>
  292. </template>
  293. </el-table-column>
  294. </el-table>
  295. <pagination v-show="total>0" :total="total" :page.sync="queryComponentParams.pageNum"
  296. :limit.sync="queryComponentParams.pageSize"
  297. @pagination="getComponentList"
  298. />
  299. <!-- 添加或修改设备器件对话框 -->
  300. <el-dialog :title="title" :visible.sync="componentOpen" width="500px" append-to-body>
  301. <el-form ref="componentForm" :model="componentForm" :rules="componentRules" label-width="150px">
  302. <!-- <el-form-item label="设备code" prop="deviceCode">-->
  303. <!-- <el-input v-model="componentForm.deviceCode" placeholder="请输入设备code" />-->
  304. <!-- </el-form-item>-->
  305. <el-form-item label="部件编码" prop="compoCode">
  306. <el-input v-model="componentForm.compoCode" placeholder="请输入部件编码"/>
  307. </el-form-item>
  308. <el-form-item label="部件标签" prop="compoTag">
  309. <el-select v-model="componentForm.compoTag" placeholder="请输入部件标签">
  310. <el-option v-for="item in objComTypeOptions"
  311. :label="item.name"
  312. :value="item.code"
  313. :key="item.code"
  314. />
  315. </el-select>
  316. </el-form-item>
  317. <el-form-item label="工艺标签代码" prop="psCode">
  318. <el-select v-model="componentForm.psCode" placeholder="请输入工艺标签代码">
  319. <el-option v-for="item in devOptions" :label="item.psCode" :value="item.psCode"
  320. :key="item.psCode"/>
  321. </el-select>
  322. </el-form-item>
  323. <el-form-item label="外系统部件编码" prop="extCompoCode">
  324. <el-input v-model="componentForm.extCompoCode" placeholder="请输入外系统部件编码"/>
  325. </el-form-item>
  326. <el-form-item label="部件模型" prop="compoModel">
  327. <el-select v-model="componentForm.compoModel" placeholder="请输入部件模型">
  328. <el-option v-for="item in this.modelList" :label="item.modelCode" :value="item.modelCode"
  329. :key="item.modelCode"
  330. />
  331. </el-select>
  332. </el-form-item>
  333. <el-form-item label="部件品牌" prop="compoBrand">
  334. <el-input v-model="componentForm.compoBrand" placeholder="请输入部件品牌"/>
  335. </el-form-item>
  336. <el-form-item label="部件型号" prop="compoSpec">
  337. <el-input v-model="componentForm.compoSpec" placeholder="请输入部件型号"/>
  338. </el-form-item>
  339. <el-form-item label="祖籍列表" prop="ancestors">
  340. <el-input v-model="componentForm.ancestors" placeholder="请输入祖籍列表"/>
  341. </el-form-item>
  342. <el-form-item label="上级列表" prop="parentCompo">
  343. <el-input v-model="componentForm.parentCompo" placeholder="请输入上级列表"/>
  344. </el-form-item>
  345. </el-form>
  346. <div slot="footer" class="dialog-footer">
  347. <el-button type="primary" @click="submitComponentForm">确 定</el-button>
  348. <el-button @click="ComponentCancel">取 消</el-button>
  349. </div>
  350. </el-dialog>
  351. </div>
  352. </el-drawer>
  353. <!-- 详情弹框 -->
  354. <el-dialog :visible.sync="showDrawer" title="设备详情">
  355. <div v-if="curRow">
  356. <!-- 设备基本信息 -->
  357. <el-card class="box-card">
  358. <div slot="header" class="clearfix">
  359. <span class="section-title">设备基本信息</span>
  360. </div>
  361. <div>
  362. <p>设备代码:{{ curRow.deviceCode }}</p>
  363. <p>设备名称:{{ curRow.deviceName }}</p>
  364. <p>设备类型:{{ curRow.deviceCategoryName }}</p>
  365. <p>子系统:{{ curRow.subsystemName }}</p>
  366. <p>归属区域:{{ curRow.areaPath }}</p>
  367. <p>归属设施:{{ curRow.refFacsName }}</p>
  368. </div>
  369. </el-card>
  370. <el-card class="box-card" style="margin-top: 10px">
  371. <div slot="header" class="clearfix">
  372. <span class="section-title">状态属性</span>
  373. </div>
  374. <div>
  375. <p v-for="attr in statusAttr" :key="attr.attr">{{ attr.attr }}:{{ attr.attrValue }} {{
  376. attr.attrUnit
  377. }}</p>
  378. </div>
  379. </el-card>
  380. <!-- 属性信息 -->
  381. <el-card class="box-card" v-if="attrData.length > 0">
  382. <div slot="header" class="clearfix">
  383. <span class="section-title">属性定义</span>
  384. </div>
  385. <div v-for="(item, index) in attrData" :key="index">
  386. <p>属性名称:{{ item.attrName }}</p>
  387. <p>属性值:{{ item.attrValue }}</p>
  388. <p>属性单位:{{ item.attrUnit }}</p>
  389. <!-- 在每个条目之后添加横线,除了最后一个条目 -->
  390. <div v-if="index < attrData.length - 1" class="divider"></div>
  391. </div>
  392. </el-card>
  393. <!-- 能力信息 -->
  394. <el-card class="box-card" v-if="abilityData.length > 0">
  395. <div slot="header" class="clearfix">
  396. <span class="section-title">能力定义</span>
  397. </div>
  398. <div v-for="(item, index) in abilityData" :key="index">
  399. <p>能力名称:{{ item.abilityName }}</p>
  400. <p>能力键:{{ item.abilityKey }}</p>
  401. <p>能力参数:{{ item.abilityParam }}</p>
  402. <p>能力描述:{{ item.abilityDesc }}</p>
  403. <!-- 在每个条目之后添加横线,除了最后一个条目 -->
  404. <div v-if="index < abilityData.length - 1" class="divider"></div>
  405. </div>
  406. </el-card>
  407. <!-- 事件信息 -->
  408. <el-card class="box-card" v-if="eventData.length > 0">
  409. <div slot="header" class="clearfix">
  410. <span class="section-title">事件定义</span>
  411. </div>
  412. <div v-for="(item, index) in eventData" :key="index">
  413. <p>事件名称:{{ item.eventKey }}</p>
  414. <p>事件类型:{{ item.eventType === 1 ? '消息上报' : '异常告警' }}</p>
  415. <p>事件代码:{{ item.eventCode }}</p>
  416. <p>外部事件代码:{{ item.extEventCode }}</p>
  417. <!-- 在每个条目之后添加横线,除了最后一个条目 -->
  418. <div v-if="index < eventData.length - 1" class="divider"></div>
  419. </div>
  420. </el-card>
  421. </div>
  422. </el-dialog>
  423. </div>
  424. </div>
  425. </el-col>
  426. </el-row>
  427. </div>
  428. </template>
  429. <script>
  430. import {addDevice, delDevice, getDevice, listDevRecursionByArea, updateDevice} from '@/api/device/device'
  431. import {areaTreeSelect} from '@/api/basecfg/area'
  432. import {getFacsCategorygetByCode, listAllFacs} from '@/api/basecfg/emsfacs'
  433. import {listSubsystemAll} from '@/api/adapter/subsystem'
  434. import {getModelByCode, listAllModel} from '@/api/basecfg/objModel'
  435. import {getObjAttr} from '@/api/basecfg/objAttribute'
  436. import {addAttrValueBatch} from '@/api/basecfg/objAttributeValue'
  437. import {addComponent, delComponent, getComponent, listByDevice, updateComponent} from '@/api/basecfg/component'
  438. import Treeselect from '@riophae/vue-treeselect'
  439. import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  440. export default {
  441. name: 'Device',
  442. components: {Treeselect},
  443. data() {
  444. return {
  445. primary1: 'primary',
  446. primary2: '',
  447. ComponentRow: [],
  448. componentForm: {},
  449. subcategoryCode: '',
  450. attrList: [], // 属性模板数组
  451. attrValues: [],
  452. ComponentList: [],
  453. attrValuesMap: {},
  454. modelList: [],
  455. showDrawer: false,
  456. showDevProcessDrawer: false,
  457. componentOpen: false,
  458. istable: 2,
  459. statusAttr: [{
  460. attr: '实施电量',
  461. attrUnit: 'kW·h',
  462. attrValue: '10.3'
  463. },
  464. {
  465. attr: '设备运行状态',
  466. attrUnit: '',
  467. attrValue: '工作中'
  468. },
  469. {
  470. attr: '设备电压',
  471. attrUnit: 'V',
  472. attrValue: '20'
  473. },
  474. {
  475. attr: '设备电流',
  476. attrUnit: 'A',
  477. attrValue: '5'
  478. },
  479. {
  480. attr: '设备功率',
  481. attrUnit: 'W',
  482. attrValue: '100'
  483. },
  484. ],
  485. // 遮罩层
  486. loading: true,
  487. // 选中数组
  488. ids: [],
  489. // 非单个禁用
  490. single: true,
  491. // 非多个禁用
  492. multiple: true,
  493. // 显示搜索条件
  494. showSearch: true,
  495. // 总条数
  496. total: 0,
  497. // 能源设备表格数据
  498. deviceList: [],
  499. // 弹出层标题
  500. title: '',
  501. // 是否显示弹出层
  502. open: false,
  503. // 区域名称
  504. areaName: undefined,
  505. // 区域树选项
  506. treeAreaOptions: undefined,
  507. totalAreaOptions: undefined,
  508. // 设施选项
  509. facsOptions: undefined,
  510. // 设备分类
  511. subCategoryOptions: undefined,
  512. subsystemOptions: undefined,
  513. devOptions: undefined,
  514. defaultProps: {
  515. children: 'children',
  516. label: 'label'
  517. },
  518. // 查询参数
  519. queryParams: {
  520. psCode: null,
  521. pageNum: 1,
  522. pageSize: 10,
  523. deviceCode: null,
  524. deviceSubCategory: '',
  525. deviceCategory: 'E',
  526. locationType: null,
  527. locationRef: null,
  528. refFacs: null,
  529. customAttrs: null
  530. },
  531. queryComponentParams: {
  532. pageNum: 1,
  533. pageSize: 10
  534. },
  535. objComTypeMapping: {
  536. 1: '总开',
  537. 2: '照明',
  538. 3: '风机'
  539. },
  540. objComTypeOptions: [
  541. {code: 1, name: '总开'},
  542. {code: 2, name: '照明'},
  543. {code: 3, name: '风机'}
  544. ],
  545. curRow: {},
  546. attrData: [],
  547. abilityData: [],
  548. eventData: [],
  549. // 表单参数
  550. form: {
  551. customAttrs: [] // 自定义属性数组
  552. },
  553. // 表单校验
  554. rules: {
  555. refFacs: [
  556. {required: true, message: '归属设施', trigger: 'blur'}
  557. ],
  558. refArea: [
  559. {required: true, message: '安装位置', trigger: 'blur'}
  560. ],
  561. deviceCode: [
  562. {required: true, message: '设备代码不能为空', trigger: 'blur'}
  563. ],
  564. deviceName: [
  565. {required: true, message: '设备名称不能为空', trigger: 'blur'}
  566. ]
  567. },
  568. componentRules: {
  569. deviceCode: [
  570. {required: true, message: '设备code不能为空', trigger: 'blur'}
  571. ],
  572. compoCode: [
  573. {required: true, message: '部件编码不能为空', trigger: 'blur'}
  574. ],
  575. psCode: [
  576. {required: true, message: '工艺标签代码不能为空', trigger: 'blur'}
  577. ]
  578. }
  579. }
  580. },
  581. watch: {
  582. // 根据名称筛选区域树
  583. areaName(val) {
  584. this.$refs.tree.filter(val)
  585. }
  586. },
  587. created() {
  588. this.queryParams.deviceCategory = 'E'; // 确保初始加载时就设置为 'E'
  589. this.getList()
  590. this.getAreaTree('0', 1)
  591. this.getFacsOptions()
  592. this.getSubsystem()
  593. this.getSubCategorygetByCode()
  594. this.getFacsModel()
  595. // this.getAllDevProcess(this.subcategoryCode)
  596. },
  597. methods: {
  598. /**分页切换*/
  599. switchData(v) {
  600. if (v === 1) {
  601. this.primary1 = "primary";
  602. this.primary2 = "";
  603. } else {
  604. this.primary1 = "";
  605. this.primary2 = "primary";
  606. }
  607. this.istable = v;
  608. },
  609. /** 查询能源设备列表 */
  610. getList() {
  611. this.loading = true
  612. listDevRecursionByArea(this.queryParams).then(response => {
  613. console.log('参数', JSON.stringify(this.queryParams))
  614. this.deviceList = response.rows
  615. this.total = response.total
  616. this.loading = false
  617. })
  618. },
  619. /**新增、修改、删除*/
  620. handleComponentAdd() {
  621. this.componentReset()
  622. this.componentOpen = true
  623. this.title = '添加设备器件属性'
  624. this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
  625. },
  626. handleComponentUpdate(row) {
  627. this.componentReset()
  628. const id = row.id || this.ids
  629. getComponent(id).then(response => {
  630. this.componentForm = response.data
  631. this.componentOpen = true
  632. this.title = '修改设备器件属性'
  633. this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
  634. })
  635. },
  636. handleComponentDelete(row) {
  637. const ids = row.id || this.ids
  638. this.$modal.confirm('是否确认删除能源对象属性编号为"' + ids + '"的数据项?').then(function () {
  639. return delComponent(ids)
  640. }).then(() => {
  641. console.log('删除row', row.deviceCode)
  642. this.getComponentList(row.deviceCode)
  643. this.$modal.msgSuccess('删除成功')
  644. }).catch(() => {
  645. })
  646. },
  647. submitComponentForm() {
  648. this.$refs['componentForm'].validate(valid => {
  649. if (valid) {
  650. if (this.componentForm.id != null) {
  651. updateComponent(this.componentForm).then(response => {
  652. this.$modal.msgSuccess('修改成功')
  653. this.componentOpen = false
  654. this.getComponentList(this.componentForm.deviceCode)
  655. })
  656. } else {
  657. addComponent(this.componentForm).then(response => {
  658. this.$modal.msgSuccess('新增成功')
  659. this.componentOpen = false
  660. this.getComponentList(this.componentForm.deviceCode)
  661. })
  662. }
  663. }
  664. })
  665. },
  666. ComponentCancel() {
  667. this.componentOpen = false
  668. this.componentReset()
  669. },
  670. /**查询部件列表*/
  671. getComponentList(deviceCode) {
  672. listByDevice(deviceCode).then(response => {
  673. this.ComponentList = response.data
  674. })
  675. },
  676. /** 查询区域树结构 */
  677. getAreaTree(areaCode, layer) {
  678. areaTreeSelect(areaCode, layer).then(response => {
  679. this.treeAreaOptions = [{
  680. id: '-1',
  681. label: '全部',
  682. children: response.data
  683. }]
  684. })
  685. },
  686. // 筛选节点
  687. filterNode(value, data) {
  688. if (!value) return true
  689. return data.label.indexOf(value) !== -1
  690. },
  691. // 节点单击事件
  692. handleNodeClick(data) {
  693. if (data.id === '-1') {
  694. this.queryParams.locationType = null;
  695. this.queryParams.locationRef = null;
  696. } else {
  697. this.queryParams.locationType = data.tier;
  698. this.queryParams.locationRef = data.id;
  699. }
  700. this.handleQuery();
  701. },
  702. // 取消按钮
  703. cancel() {
  704. this.open = false
  705. this.reset()
  706. },
  707. // 表单重置
  708. reset() {
  709. this.form = {
  710. id: null,
  711. deviceCode: null,
  712. deviceName: null,
  713. deviceType: null,
  714. deviceStatus: null,
  715. deviceModel: null,
  716. refArea: null,
  717. refFacs: null,
  718. subsystemCode: null,
  719. psCode: null,
  720. createTime: null,
  721. updateTime: null
  722. }
  723. this.resetForm('form')
  724. },
  725. componentReset() {
  726. this.componentForm = {
  727. id: null,
  728. deviceCode: this.ComponentRow.deviceCode || '', // 使用ComponentRow的deviceCode,或者空字符串
  729. compoCode: null,
  730. compoTag: null,
  731. psCode: null,
  732. extCompoCode: null,
  733. compoModel: null,
  734. compoBrand: null,
  735. compoSpec: null,
  736. ancestors: null,
  737. parentCompo: null
  738. }
  739. this.resetForm('componentForm')
  740. },
  741. /** 搜索按钮操作 */
  742. handleQuery() {
  743. this.queryParams.pageNum = 1
  744. console.log('搜索按钮this.queryParams', JSON.stringify(this.queryParams))
  745. this.getList()
  746. },
  747. /** 重置按钮操作 */
  748. resetQuery() {
  749. this.queryParams.locationType = null
  750. this.queryParams.locationRef = null
  751. this.resetForm('queryForm')
  752. this.handleQuery()
  753. },
  754. // 多选框选中数据
  755. handleSelectionChange(selection) {
  756. this.ids = selection.map(item => item.id)
  757. this.single = selection.length !== 1
  758. this.multiple = !selection.length
  759. },
  760. /** 新增按钮操作 */
  761. handleAdd() {
  762. this.reset()
  763. this.open = true
  764. this.title = '添加能源设备'
  765. },
  766. /**设备器件按钮*/
  767. handleDevProcess(row) {
  768. this.showDevProcessDrawer = true
  769. this.ComponentRow = row
  770. console.log('row', row)
  771. listByDevice(this.ComponentRow.deviceCode).then(response => {
  772. this.ComponentList = response.data
  773. })
  774. },
  775. shouldShowDevProcessButton(row) {
  776. const categoryIsW = this.queryParams.deviceCategory === 'W'
  777. const validPsCodes = ['AA', 'AH', 'AJ', 'AM', 'AP', 'AL', 'APE', 'ALE', 'AF', 'ACC']
  778. const psCodeIsValid = validPsCodes.includes(row.psCode)
  779. // 只有当设备分类为输能设备且设备工艺代码有效时,才返回true
  780. return categoryIsW && psCodeIsValid
  781. },
  782. backStyle(areaPath) {
  783. const firstLevel = areaPath.split('/')[0];
  784. switch (firstLevel) {
  785. case '北区':
  786. return 'north';
  787. case '南区':
  788. return 'south';
  789. case '主路':
  790. return 'main';
  791. default:
  792. return '';
  793. }
  794. },
  795. /**设备详情按钮*/
  796. handleDetail(row) {
  797. this.showDrawer = true
  798. this.curRow = row
  799. console.log('data', this.curRow)
  800. this.subKey = this.$options.data().subKey
  801. getModelByCode(this.curRow.facsModel).then(response => {
  802. const code = response.data
  803. console.log('code', code)
  804. this.eventData = response.data.eventList
  805. this.abilityData = response.data.abilityList
  806. })
  807. getObjAttr(2, this.curRow.deviceCode).then(response => {
  808. console.log('response值', response.data)
  809. const attrs = response.data.attrs
  810. const attrValues = response.data.attrValues
  811. // 合并 attrs 和 attrValues 数组
  812. const mergedData = attrValues.map(attrValue => {
  813. const attr = attrs.find(a => a.attrKey === attrValue.attrKey)
  814. return {
  815. ...attrValue,
  816. attrName: attr ? attr.attrName : attrValue.attrName,
  817. attrUnit: attr ? attr.attrUnit : ''
  818. }
  819. })
  820. this.attrData = mergedData
  821. })
  822. },
  823. /** 修改按钮操作 */
  824. handleUpdate(row) {
  825. this.reset()
  826. const id = row.id || this.ids
  827. getDevice(id).then(response => {
  828. this.form = response.data
  829. this.open = true
  830. this.title = '修改能源设备'
  831. })
  832. const layer = 1
  833. const areaCode = '0'
  834. areaTreeSelect(areaCode, layer).then(response => {
  835. this.totalAreaOptions = response.data
  836. })
  837. },
  838. /** 提交按钮 */
  839. submitForm() {
  840. // 重置 attrList 和 form.customAttrs
  841. if (!this.attrList) {
  842. this.attrList = []
  843. }
  844. if (!this.form.customAttrs) {
  845. this.form.customAttrs = []
  846. }
  847. // 准备要发送的数据
  848. let dataToSubmit = []
  849. // 添加模型属性数据
  850. this.attrList.forEach(attr => {
  851. const attrName = attr.attrName
  852. const attrKey = attr.attrKey
  853. const attrValue = this.attrValuesMap[attrKey]
  854. const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
  855. if (existingIndex === -1) {
  856. // 如果attrKey不存在于dataToSubmit中,则添加
  857. dataToSubmit.push({
  858. modelCode: this.form.deviceModel, // 模型代码
  859. objCode: this.form.deviceCode, // 设备代码
  860. objType: 2, // 对象类型
  861. attrKey: attrKey,
  862. attrValue: attrValue,
  863. attrName: attrName
  864. })
  865. }
  866. })
  867. // 添加自定义属性数据
  868. this.form.customAttrs.forEach(customAttr => {
  869. const attrName = customAttr.attrName
  870. const attrKey = customAttr.attrKey
  871. const attrValue = customAttr.attrValue
  872. const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
  873. if (existingIndex === -1) {
  874. // 如果attrKey不存在于dataToSubmit中,则添加
  875. dataToSubmit.push({
  876. modelCode: '', // 模型代码
  877. objCode: this.form.deviceCode, // 设备代码
  878. objType: 2, // 对象类型
  879. attrKey: attrKey,
  880. attrValue: attrValue,
  881. attrName: attrName
  882. })
  883. }
  884. })
  885. this.$refs['form'].validate(valid => {
  886. if (valid) {
  887. if (this.form.id != null) {
  888. updateDevice(this.form).then(response => {
  889. this.$modal.msgSuccess('修改成功')
  890. this.open = false
  891. this.getList()
  892. }).catch(error => {
  893. console.error('修改失败:', error)
  894. this.$message.error('修改失败')
  895. })
  896. if (dataToSubmit.length > 0) {
  897. addAttrValueBatch(dataToSubmit)
  898. .then(response => {
  899. if (response.code === 200) {
  900. this.$message.success('属性添加成功')
  901. } else {
  902. this.$message.error('属性添加失败')
  903. }
  904. }).catch(error => {
  905. console.error('属性添加失败:', error)
  906. this.$message.error('属性添加失败')
  907. })
  908. }
  909. } else {
  910. addDevice(this.form).then(response => {
  911. this.$modal.msgSuccess('新增成功')
  912. this.open = false
  913. this.getList()
  914. }).catch(error => {
  915. console.error('新增失败:', error)
  916. this.$message.error('新增失败')
  917. })
  918. if (dataToSubmit.length > 0) {
  919. addAttrValueBatch(dataToSubmit)
  920. .then(response => {
  921. if (response.code === 200) {
  922. this.$message.success('属性添加成功')
  923. } else {
  924. this.$message.error('属性添加失败')
  925. }
  926. }).catch(error => {
  927. console.error('属性添加失败:', error)
  928. this.$message.error('属性添加失败')
  929. })
  930. } else {
  931. // this.$message.info('没有属性需要添加');
  932. }
  933. }
  934. }
  935. })
  936. },
  937. /** 删除按钮操作 */
  938. handleDelete(row) {
  939. const ids = row.id || this.ids
  940. this.$modal.confirm('是否确认删除能源设备编号为"' + ids + '"的数据项?').then(function () {
  941. return delDevice(ids)
  942. }).then(() => {
  943. this.getList()
  944. this.$modal.msgSuccess('删除成功')
  945. }).catch(() => {
  946. })
  947. },
  948. /** 导出按钮操作 */
  949. handleExport() {
  950. this.download('ems/basecfg/device/export', {
  951. ...this.queryParams
  952. }, `device_${new Date().getTime()}.xlsx`)
  953. },
  954. getFacsOptions() {
  955. const getFacsParams = {
  956. facsCategory: this.queryParams.deviceCategory,
  957. subCategory: this.queryParams.deviceSubCategory
  958. }
  959. listAllFacs(getFacsParams).then(response => {
  960. this.facsOptions = response.data
  961. })
  962. },
  963. getSubCategorygetByCode() {
  964. getFacsCategorygetByCode(this.queryParams.deviceCategory).then(response => {
  965. this.subCategoryOptions = response.data.subtypeList || []
  966. })
  967. },
  968. getSubsystem() {
  969. listSubsystemAll().then(response => {
  970. this.subsystemOptions = response.data
  971. })
  972. },
  973. /**自定义属性表格*/
  974. addCustomAttr() {
  975. // 添加一个新的自定义属性
  976. if (!Array.isArray(this.form.customAttrs)) {
  977. this.form.customAttrs = []
  978. }
  979. this.form.customAttrs.push({
  980. attrKey: '',
  981. attrName: '',
  982. attrValue: ''
  983. })
  984. // 强制更新视图
  985. this.$forceUpdate()
  986. },
  987. deleteCustomAttr(index) {
  988. // 删除指定索引的自定义属性
  989. if (this.form.customAttrs.length > 0) {
  990. this.form.customAttrs.splice(index, 1)
  991. }
  992. },
  993. /**设备模型*/
  994. updateAttrValue(attrKey, newValue) {
  995. this.attrValuesMap[attrKey] = newValue
  996. },
  997. getFacsModel() {
  998. listAllModel(2).then(response => {
  999. this.modelList = response.data
  1000. console.log('this.modelList', this.modelList)
  1001. this.modelList.forEach(model => {
  1002. console.log(model.modelCode)
  1003. })
  1004. })
  1005. },
  1006. handleModelChange(modelCode) {
  1007. if (modelCode) {
  1008. this.getModelByCode(modelCode)
  1009. console.log('设备代码', this.form.deviceCode)
  1010. this.getObjAttr(2, this.form.deviceCode)
  1011. }
  1012. },
  1013. getModelByCode(modelCode) {
  1014. getModelByCode(modelCode).then(response => {
  1015. // this.attrList = response.data.attrList;
  1016. const filteredAttrList = response.data.attrList.filter(attr => attr.attrType === 0)
  1017. this.attrList = filteredAttrList
  1018. })
  1019. },
  1020. getObjAttr(objType, deviceCode) {
  1021. getObjAttr(objType, deviceCode).then(response => {
  1022. // const attrs = response.data.attrs;
  1023. const attrs = response.data.attrs.filter(attr => attr.attrType === 0)
  1024. console.log('attrs', attrs)
  1025. const attrValues = response.data.attrValues || [] // 确保是一个数组
  1026. console.log('attrValues', attrValues)
  1027. // 创建一个映射对象,用于存储 attrKey 与对应的 attrValue
  1028. const attrValuesMap = {}
  1029. // 遍历 attrs 数组
  1030. attrs.forEach(attr => {
  1031. // 查找 attrValues 数组中是否有匹配的 attrKey
  1032. const attrValueObj = attrValues.find(value => value.attrKey === attr.attrKey)
  1033. // 如果找到匹配的 attrValue,更新 attrValuesMap
  1034. if (attrValueObj) {
  1035. attrValuesMap[attr.attrKey] = attrValueObj.attrValue
  1036. } else {
  1037. // 如果没有找到匹配的 attrValue,则设置为 '暂无数据'
  1038. attrValuesMap[attr.attrKey] = ''
  1039. }
  1040. })
  1041. // 更新 attrValuesMap 到组件的数据中
  1042. this.attrValuesMap = attrValuesMap
  1043. // 打印更新后的 attrValuesMap,用于调试
  1044. console.log('Updated attrValuesMap', this.attrValuesMap)
  1045. })
  1046. }
  1047. }
  1048. }
  1049. </script>
  1050. <style lang="scss" scoped>
  1051. .divider {
  1052. border-bottom: 2px solid #ebeef5;
  1053. margin: 10px 0;
  1054. }
  1055. .section-title {
  1056. font-size: 18px;
  1057. font-weight: bold;
  1058. margin-top: 20px;
  1059. margin-bottom: 10px;
  1060. }
  1061. .drawer-content {
  1062. padding: 0 20px;
  1063. }
  1064. .section-title {
  1065. font-size: 18px;
  1066. font-weight: bold;
  1067. }
  1068. .attr-list-container {
  1069. border: 1px solid #ccc;
  1070. padding: 10px;
  1071. margin: 10px 0;
  1072. font-weight: bold;
  1073. }
  1074. .attr-list-container h3 {
  1075. font-weight: bold;
  1076. }
  1077. .attr-item {
  1078. list-style-type: none;
  1079. margin-bottom: 5px;
  1080. }
  1081. .attr-name {
  1082. font-weight: bold;
  1083. }
  1084. .contents {
  1085. border: 20px solid #f2f2f5;
  1086. background-color: #f2f2f5;
  1087. }
  1088. .other-content {
  1089. background-color: #ffffff; /* 白色背景 */
  1090. padding: 20px;
  1091. margin-bottom: 20px;
  1092. }
  1093. .table-content {
  1094. background-color: #ffffff; /* 白色背景 */
  1095. padding: 20px;
  1096. }
  1097. .pagination-container {
  1098. margin-bottom: 20px;
  1099. }
  1100. .button-group-container {
  1101. display: flex;
  1102. justify-content: flex-end;
  1103. min-width: 200px;
  1104. padding: 5px;
  1105. }
  1106. .device-list {
  1107. margin-top: 20px;
  1108. }
  1109. .device-card {
  1110. background-color: #fff;
  1111. border: 1px solid #bfcbd9;
  1112. border-radius: 4px;
  1113. overflow: hidden;
  1114. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  1115. transition: 0.3s;
  1116. padding: 10px;
  1117. font-size: 14px;
  1118. height: 200px;
  1119. margin-bottom: 20px;
  1120. display: flex;
  1121. flex-direction: column;
  1122. }
  1123. .device-header {
  1124. //background-color: #f2f2f5;
  1125. //padding: 10px;
  1126. color: #545353;
  1127. font-size: 20px;
  1128. font-weight: bold;
  1129. }
  1130. .device-code {
  1131. color: cornflowerblue;
  1132. }
  1133. .deviceOthers {
  1134. color: black;
  1135. }
  1136. .device-body {
  1137. padding: 10px;
  1138. color: #666666;
  1139. flex: 1; /* 使设备主体内容占据剩余空间 */
  1140. overflow-y: auto; /* 如果内容过多,允许滚动 */
  1141. }
  1142. .device-footer {
  1143. display: flex;
  1144. justify-content: space-between;
  1145. padding: 5px;
  1146. // background-color: #f9f9f9;
  1147. }
  1148. .device-footer .el-button {
  1149. padding: 5px 15px;
  1150. border: none; /* 移除默认边框 */
  1151. color: #5a5e66;
  1152. transition: background-color 0.3s; /* 平滑过渡背景色变化 */
  1153. }
  1154. /* 为按钮分配不同的颜色 */
  1155. .device-footer .el-button:first-child {
  1156. background-color: #d5f1d5; /* 淡绿色 */
  1157. border: 1px solid lightgreen;
  1158. color: #71e2aa;
  1159. }
  1160. .device-footer .el-button:nth-child(2) {
  1161. background-color: #ffe5b4; /* 淡橙色 */
  1162. border: 1px solid #ffba00;
  1163. color: #faad14;
  1164. }
  1165. .device-footer .el-button:last-child {
  1166. background-color: #ffd5d5; /* 淡红色 */
  1167. border: 1px solid lightpink;
  1168. color: #f5222d;
  1169. }
  1170. /* 鼠标悬停时加深颜色 */
  1171. .device-footer .el-button:hover {
  1172. filter: brightness(0.5); /* 颜色加深效果 */
  1173. }
  1174. /* 背景色样式 */
  1175. .north {
  1176. background: linear-gradient(to right, #e1f3d8, #fafafa);
  1177. }
  1178. .south {
  1179. background: linear-gradient(to right, #fff7e8, #fafafa);
  1180. }
  1181. .main {
  1182. background: linear-gradient(to right, #e0e0e0, #fafafa);
  1183. }
  1184. .el-table {
  1185. background-color: #ffffff; /* 白色背景 */
  1186. }
  1187. .el-card {
  1188. background-color: #ffffff; /* 白色背景 */
  1189. }
  1190. </style>