index.vue 45 KB

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