index.vue 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  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-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. <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
  118. :limit.sync="queryParams.pageSize"
  119. @pagination="getList"
  120. />
  121. <!-- 添加或修改能源设备对话框 -->
  122. <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  123. <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  124. <el-form-item label="归属设施" prop="refFacs">
  125. <el-select v-model="form.refFacs">
  126. <el-option v-for="item in facsOptions" :label="item.facsName" :value="item.facsCode"
  127. :key="item.facsCode"
  128. />
  129. </el-select>
  130. </el-form-item>
  131. <el-form-item label="设备代码" prop="deviceCode">
  132. <el-input v-model="form.deviceCode" placeholder="请输入设备代码"/>
  133. </el-form-item>
  134. <el-form-item label="设备名称" prop="deviceName">
  135. <el-input v-model="form.deviceName" placeholder="请输入设备名称"/>
  136. </el-form-item>
  137. <el-form-item label="设备工艺" prop="psCode" v-if="queryParams.deviceCategory === 'W'">
  138. <el-select v-model="form.psCode">
  139. <el-option v-for="item in devOptions" :label="item.psName" :value="item.psCode"
  140. :key="item.psCode"
  141. />
  142. </el-select>
  143. </el-form-item>
  144. <el-form-item label="设备类型" prop="deviceType">
  145. <el-select v-model="form.deviceCategory">
  146. <el-option v-for="item in subCategoryOptions" :label="item.name" :value="item.code"
  147. :key="item.code"
  148. />
  149. </el-select>
  150. </el-form-item>
  151. <el-form-item label="设备模型" prop="deviceModel">
  152. <el-select v-model="form.deviceModel" style="width:100%" @change="handleModelChange">
  153. <el-option
  154. v-for="item in modelList"
  155. :label="item.modelName"
  156. :value="item.modelCode"
  157. :key="item.modelCode"
  158. />
  159. </el-select>
  160. </el-form-item>
  161. <!-- 这里可以展示属性名称和属性值 -->
  162. <div v-if="attrList.length > 0" class="attr-list-container">
  163. <h3>模型属性:</h3>
  164. <ul>
  165. <li v-for="attr in attrList" :key="attr.attrKey" class="attr-item">
  166. <span class="attr-name">{{ attr.attrName }} ({{ attr.attrUnit }}):</span>
  167. <!-- 使用 el-input 组件允许用户编辑属性值 -->
  168. <el-input
  169. v-model="attrValuesMap[attr.attrKey]"
  170. placeholder="点击编辑"
  171. size="small"
  172. @blur="updateAttrValue(attr.attrKey, attrValuesMap[attr.attrKey])"
  173. >
  174. </el-input>
  175. </li>
  176. </ul>
  177. </div>
  178. <h3 class="attr-list-container" v-if="attrList.length > 0">自定义属性
  179. <el-form-item label="" prop="attrList">
  180. <el-table class="attr-table" v-loading="loading" :data="form.customAttrs" max-height="280px"
  181. key="'customAttrs'"
  182. >
  183. <el-table-column label="标识" align="center" prop="attrKey">
  184. <template slot-scope="scope">
  185. <el-input size="mini" v-model="scope.row.attrKey" placeholder="请输入标识"/>
  186. </template>
  187. </el-table-column>
  188. <el-table-column label="属性名" align="center" prop="attrName">
  189. <template slot-scope="scope">
  190. <el-input size="mini" v-model="scope.row.attrName" placeholder="请输入属性名"/>
  191. </template>
  192. </el-table-column>
  193. <el-table-column label="属性值" align="center" prop="attrValue">
  194. <template slot-scope="scope">
  195. <el-input size="mini" v-model="scope.row.attrValue" placeholder="请输入属性值"/>
  196. </template>
  197. </el-table-column>
  198. <el-table-column align="center" label="操作">
  199. <template slot="header">
  200. <div class="operateBtns" @click="addCustomAttr">
  201. <span>添加</span><i class="el-icon-circle-plus-outline"></i>
  202. </div>
  203. </template>
  204. <template slot-scope="scope">
  205. <i class="el-icon-delete" @click="deleteCustomAttr(scope.$index)"></i>
  206. </template>
  207. </el-table-column>
  208. </el-table>
  209. </el-form-item>
  210. </h3>
  211. <el-form-item label="子系统" prop="subsystemCode">
  212. <el-select v-model="form.subsystemCode">
  213. <el-option v-for="item in subsystemOptions" :label="item.systemName" :value="item.systemCode"
  214. :key="item.systemCode"
  215. />
  216. </el-select>
  217. </el-form-item>
  218. </el-form>
  219. <div slot="footer" class="dialog-footer">
  220. <el-button type="primary" @click="submitForm">确 定</el-button>
  221. <el-button @click="cancel">取 消</el-button>
  222. </div>
  223. </el-dialog>
  224. <!--设备器件-->
  225. <el-drawer :title=ComponentRow.deviceName size="80%" :visible.sync="showDevProcessDrawer" direction="rtl">
  226. <div class="drawer-content" style="padding-left:50px">
  227. <el-row :gutter="10" class="mb8">
  228. <el-col :span="1.5">
  229. <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleComponentAdd"
  230. v-hasPermi="['ems:component:add']"
  231. >新增
  232. </el-button>
  233. </el-col>
  234. </el-row>
  235. <el-table v-loading="loading" :data="ComponentList">
  236. <el-table-column type="selection" width="55" align="center"/>
  237. <!-- <el-table-column label="设备代码" align="center" prop="deviceCode" />-->
  238. <el-table-column label="部件编码" align="center" prop="compoCode"/>
  239. <el-table-column label="部件标签" align="center" prop="compoTag">
  240. <template slot-scope="scope">
  241. {{ objComTypeMapping[scope.row.compoTag] }}
  242. </template>
  243. </el-table-column>
  244. <el-table-column label="工艺标识代码" align="center" prop="psCode"/>
  245. <el-table-column label="外系统部件编码" align="center" prop="extCompoCode"/>
  246. <el-table-column label="部件模型" align="center" prop="compoModel"/>
  247. <el-table-column label="部件品牌" align="center" prop="compoBrand"/>
  248. <el-table-column label="部件型号" align="center" prop="compoSpec"/>
  249. <el-table-column label="祖籍列表" align="center" prop="ancestors"/>
  250. <el-table-column label="上级部件" align="center" prop="parentEqpt"/>
  251. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  252. <template slot-scope="scope">
  253. <el-button size="mini" type="text" icon="el-icon-edit" @click="handleComponentUpdate(scope.row)"
  254. v-hasPermi="['ems:component:edit']"
  255. >
  256. 修改
  257. </el-button>
  258. <el-button size="mini" type="text" icon="el-icon-delete" class="deleteBtn"
  259. @click="handleComponentDelete(scope.row)" v-hasPermi="['ems:component:remove']"
  260. >
  261. 删除
  262. </el-button>
  263. </template>
  264. </el-table-column>
  265. </el-table>
  266. <pagination v-show="total>0" :total="total" :page.sync="queryComponentParams.pageNum"
  267. :limit.sync="queryComponentParams.pageSize"
  268. @pagination="getComponentList"
  269. />
  270. <!-- 添加或修改设备器件对话框 -->
  271. <el-dialog :title="title" :visible.sync="componentOpen" width="500px" append-to-body>
  272. <el-form ref="componentForm" :model="componentForm" :rules="componentRules" label-width="150px">
  273. <!-- <el-form-item label="设备code" prop="deviceCode">-->
  274. <!-- <el-input v-model="componentForm.deviceCode" placeholder="请输入设备code" />-->
  275. <!-- </el-form-item>-->
  276. <el-form-item label="部件编码" prop="compoCode">
  277. <el-input v-model="componentForm.compoCode" placeholder="请输入部件编码"/>
  278. </el-form-item>
  279. <el-form-item label="部件标签" prop="compoTag">
  280. <el-select v-model="componentForm.compoTag" placeholder="请输入部件标签">
  281. <el-option v-for="item in objComTypeOptions"
  282. :label="item.name"
  283. :value="item.code"
  284. :key="item.code"
  285. />
  286. </el-select>
  287. </el-form-item>
  288. <el-form-item label="工艺标签代码" prop="psCode">
  289. <el-select v-model="componentForm.psCode" placeholder="请输入工艺标签代码">
  290. <el-option v-for="item in devOptions" :label="item.psCode" :value="item.psCode" :key="item.psCode"/>
  291. </el-select>
  292. </el-form-item>
  293. <el-form-item label="外系统部件编码" prop="extCompoCode">
  294. <el-input v-model="componentForm.extCompoCode" placeholder="请输入外系统部件编码"/>
  295. </el-form-item>
  296. <el-form-item label="部件模型" prop="compoModel">
  297. <el-select v-model="componentForm.compoModel" placeholder="请输入部件模型">
  298. <el-option v-for="item in this.modelList" :label="item.modelCode" :value="item.modelCode"
  299. :key="item.modelCode"
  300. />
  301. </el-select>
  302. </el-form-item>
  303. <el-form-item label="部件品牌" prop="compoBrand">
  304. <el-input v-model="componentForm.compoBrand" placeholder="请输入部件品牌"/>
  305. </el-form-item>
  306. <el-form-item label="部件型号" prop="compoSpec">
  307. <el-input v-model="componentForm.compoSpec" placeholder="请输入部件型号"/>
  308. </el-form-item>
  309. <el-form-item label="祖籍列表" prop="ancestors">
  310. <el-input v-model="componentForm.ancestors" placeholder="请输入祖籍列表"/>
  311. </el-form-item>
  312. <el-form-item label="上级列表" prop="parentCompo">
  313. <el-input v-model="componentForm.parentCompo" placeholder="请输入上级列表"/>
  314. </el-form-item>
  315. </el-form>
  316. <div slot="footer" class="dialog-footer">
  317. <el-button type="primary" @click="submitComponentForm">确 定</el-button>
  318. <el-button @click="ComponentCancel">取 消</el-button>
  319. </div>
  320. </el-dialog>
  321. </div>
  322. </el-drawer>
  323. <!-- 详情弹框 -->
  324. <el-dialog :visible.sync="showDrawer" title="设备详情">
  325. <div v-if="curRow">
  326. <!-- 设备基本信息 -->
  327. <el-card class="box-card">
  328. <div slot="header" class="clearfix">
  329. <span class="section-title">设备基本信息</span>
  330. </div>
  331. <div>
  332. <p>设备代码:{{ curRow.deviceCode }}</p>
  333. <p>设备名称:{{ curRow.deviceName }}</p>
  334. <p>设备类型:{{ curRow.deviceCategoryName }}</p>
  335. <p>子系统:{{ curRow.subsystemName }}</p>
  336. <p>归属区域:{{ curRow.areaPath }}</p>
  337. <p>归属设施:{{ curRow.refFacsName }}</p>
  338. </div>
  339. </el-card>
  340. <!-- 属性信息 -->
  341. <el-card class="box-card" v-if="attrData.length > 0">
  342. <div slot="header" class="clearfix">
  343. <span class="section-title">属性定义</span>
  344. </div>
  345. <div v-for="(item, index) in attrData" :key="index">
  346. <p>属性名称:{{ item.attrName }}</p>
  347. <p>属性值:{{ item.attrValue }}</p>
  348. <p>属性单位:{{ item.attrUnit }}</p>
  349. <!-- 在每个条目之后添加横线,除了最后一个条目 -->
  350. <div v-if="index < attrData.length - 1" class="divider"></div>
  351. </div>
  352. </el-card>
  353. <!-- 能力信息 -->
  354. <el-card class="box-card" v-if="abilityData.length > 0">
  355. <div slot="header" class="clearfix">
  356. <span class="section-title">能力定义</span>
  357. </div>
  358. <div v-for="(item, index) in abilityData" :key="index">
  359. <p>能力名称:{{ item.abilityName }}</p>
  360. <p>能力键:{{ item.abilityKey }}</p>
  361. <p>能力参数:{{ item.abilityParam }}</p>
  362. <p>能力描述:{{ item.abilityDesc }}</p>
  363. <!-- 在每个条目之后添加横线,除了最后一个条目 -->
  364. <div v-if="index < abilityData.length - 1" class="divider"></div>
  365. </div>
  366. </el-card>
  367. <!-- 事件信息 -->
  368. <el-card class="box-card" v-if="eventData.length > 0">
  369. <div slot="header" class="clearfix">
  370. <span class="section-title">事件定义</span>
  371. </div>
  372. <div v-for="(item, index) in eventData" :key="index">
  373. <p>事件名称:{{ item.eventKey }}</p>
  374. <p>事件类型:{{ item.eventType === 1 ? '消息上报' : '异常告警' }}</p>
  375. <p>事件代码:{{ item.eventCode }}</p>
  376. <p>外部事件代码:{{ item.extEventCode }}</p>
  377. <!-- 在每个条目之后添加横线,除了最后一个条目 -->
  378. <div v-if="index < eventData.length - 1" class="divider"></div>
  379. </div>
  380. </el-card>
  381. </div>
  382. </el-dialog>
  383. </el-col>
  384. </el-row>
  385. </div>
  386. </template>
  387. <script>
  388. import { listDevRecursionByArea, getDevice, delDevice, addDevice, updateDevice } from '@/api/device/device'
  389. import { areaTreeSelect } from '@/api/basecfg/area'
  390. import { getFacsCategorygetByCode, listAllFacs } from '@/api/basecfg/emsfacs'
  391. import { listSubsystemAll } from '@/api/adapter/subsystem'
  392. import { getModelByCode, listAllModel } from '@/api/basecfg/objModel'
  393. import { getObjAttr } from '@/api/basecfg/objAttribute'
  394. import { addAttrValueBatch } from '@/api/basecfg/objAttributeValue'
  395. import { getDevProcess } from '@/api/commonApi'
  396. import { addComponent, delComponent, getComponent, listByDevice, updateComponent } from '@/api/basecfg/component'
  397. import Treeselect from '@riophae/vue-treeselect'
  398. import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  399. export default {
  400. name: 'Device',
  401. components: { Treeselect },
  402. data() {
  403. return {
  404. ComponentRow: [],
  405. componentForm: {},
  406. subcategoryCode: '',
  407. attrList: [], // 属性模板数组
  408. attrValues: [],
  409. ComponentList: [],
  410. attrValuesMap: {},
  411. modelList: [],
  412. showDrawer: false,
  413. showDevProcessDrawer: false,
  414. componentOpen: false,
  415. // 遮罩层
  416. loading: true,
  417. // 选中数组
  418. ids: [],
  419. // 非单个禁用
  420. single: true,
  421. // 非多个禁用
  422. multiple: true,
  423. // 显示搜索条件
  424. showSearch: true,
  425. // 总条数
  426. total: 0,
  427. // 能源设备表格数据
  428. deviceList: [],
  429. // 弹出层标题
  430. title: '',
  431. // 是否显示弹出层
  432. open: false,
  433. // 区域名称
  434. areaName: undefined,
  435. // 区域树选项
  436. treeAreaOptions: undefined,
  437. totalAreaOptions: undefined,
  438. // 设施选项
  439. facsOptions: undefined,
  440. // 设备分类
  441. subCategoryOptions: undefined,
  442. subsystemOptions: undefined,
  443. devOptions: undefined,
  444. defaultProps: {
  445. children: 'children',
  446. label: 'label'
  447. },
  448. // 查询参数
  449. queryParams: {
  450. psCode: null,
  451. pageNum: 1,
  452. pageSize: 10,
  453. deviceCode: null,
  454. deviceSubCategory: '',
  455. deviceCategory: 'E',
  456. locationRef: null,
  457. refFacs: null,
  458. customAttrs: null
  459. },
  460. queryComponentParams: {
  461. pageNum: 1,
  462. pageSize: 10
  463. },
  464. objComTypeMapping: {
  465. 1: '总开',
  466. 2: '照明',
  467. 3: '风机'
  468. },
  469. objComTypeOptions: [
  470. { code: 1, name: '总开' },
  471. { code: 2, name: '照明' },
  472. { code: 3, name: '风机' }
  473. ],
  474. curRow: {},
  475. attrData: [],
  476. abilityData: [],
  477. eventData: [],
  478. // 表单参数
  479. form: {
  480. customAttrs: [] // 自定义属性数组
  481. },
  482. // 表单校验
  483. rules: {
  484. refFacs: [
  485. { required: true, message: '归属设施', trigger: 'blur' }
  486. ],
  487. refArea: [
  488. { required: true, message: '安装位置', trigger: 'blur' }
  489. ],
  490. deviceCode: [
  491. { required: true, message: '设备代码不能为空', trigger: 'blur' }
  492. ],
  493. deviceName: [
  494. { required: true, message: '设备名称不能为空', trigger: 'blur' }
  495. ]
  496. },
  497. componentRules: {
  498. deviceCode: [
  499. { required: true, message: '设备code不能为空', trigger: 'blur' }
  500. ],
  501. compoCode: [
  502. { required: true, message: '部件编码不能为空', trigger: 'blur' }
  503. ],
  504. psCode: [
  505. { required: true, message: '工艺标签代码不能为空', trigger: 'blur' }
  506. ]
  507. }
  508. }
  509. },
  510. watch: {
  511. // 根据名称筛选区域树
  512. areaName(val) {
  513. this.$refs.tree.filter(val)
  514. }
  515. },
  516. created() {
  517. this.getList()
  518. this.getAreaTree(false,'0')
  519. this.getFacsOptions()
  520. this.getSubsystem()
  521. this.getSubCategorygetByCode()
  522. this.getFacsModel()
  523. this.getAllDevProcess(this.subcategoryCode)
  524. },
  525. methods: {
  526. /** 查询能源设备列表 */
  527. getList() {
  528. this.loading = true
  529. listDevRecursionByArea(this.queryParams).then(response => {
  530. this.deviceList = response.rows
  531. this.total = response.total
  532. this.loading = false
  533. })
  534. },
  535. /**新增、修改、删除*/
  536. handleComponentAdd() {
  537. this.componentReset()
  538. this.componentOpen = true
  539. this.title = '添加设备器件属性'
  540. this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
  541. },
  542. handleComponentUpdate(row) {
  543. this.componentReset()
  544. const id = row.id || this.ids
  545. getComponent(id).then(response => {
  546. this.componentForm = response.data
  547. this.componentOpen = true
  548. this.title = '修改设备器件属性'
  549. this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
  550. })
  551. },
  552. handleComponentDelete(row) {
  553. const ids = row.id || this.ids
  554. this.$modal.confirm('是否确认删除能源对象属性编号为"' + ids + '"的数据项?').then(function() {
  555. return delComponent(ids)
  556. }).then(() => {
  557. this.getComponentList(row.deviceCode)
  558. this.$modal.msgSuccess('删除成功')
  559. }).catch(() => {
  560. })
  561. },
  562. submitComponentForm() {
  563. this.$refs['componentForm'].validate(valid => {
  564. if (valid) {
  565. if (this.componentForm.id != null) {
  566. updateComponent(this.componentForm).then(response => {
  567. this.$modal.msgSuccess('修改成功')
  568. this.componentOpen = false
  569. this.getComponentList(this.componentForm.deviceCode)
  570. })
  571. } else {
  572. addComponent(this.componentForm).then(response => {
  573. this.$modal.msgSuccess('新增成功')
  574. this.componentOpen = false
  575. this.getComponentList(this.componentForm.deviceCode)
  576. })
  577. }
  578. }
  579. })
  580. },
  581. ComponentCancel() {
  582. this.componentOpen = false
  583. this.componentReset()
  584. },
  585. /**查询部件列表*/
  586. getComponentList(deviceCode) {
  587. listByDevice(deviceCode).then(response => {
  588. this.ComponentList = response.data
  589. })
  590. },
  591. /** 查询区域树结构 */
  592. getAreaTree(recursion, areaCode) {
  593. areaTreeSelect(recursion, areaCode).then(response => {
  594. this.treeAreaOptions = [{
  595. id: null,
  596. label: '全部',
  597. children: response.data
  598. }]
  599. })
  600. },
  601. // 筛选节点
  602. filterNode(value, data) {
  603. if (!value) return true
  604. return data.label.indexOf(value) !== -1
  605. },
  606. // 节点单击事件
  607. handleNodeClick(data) {
  608. this.queryParams.locationRef = data.id
  609. this.handleQuery()
  610. },
  611. // 取消按钮
  612. cancel() {
  613. this.open = false
  614. this.reset()
  615. },
  616. // 表单重置
  617. reset() {
  618. this.form = {
  619. id: null,
  620. deviceCode: null,
  621. deviceName: null,
  622. deviceType: null,
  623. deviceStatus: null,
  624. deviceModel: null,
  625. refArea: null,
  626. refFacs: null,
  627. subsystemCode: null,
  628. psCode: null,
  629. createTime: null,
  630. updateTime: null
  631. }
  632. this.resetForm('form')
  633. },
  634. componentReset() {
  635. this.componentForm = {
  636. id: null,
  637. deviceCode: this.ComponentRow.deviceCode || '', // 使用ComponentRow的deviceCode,或者空字符串
  638. compoCode: null,
  639. compoTag: null,
  640. psCode: null,
  641. extCompoCode: null,
  642. compoModel: null,
  643. compoBrand: null,
  644. compoSpec: null,
  645. ancestors: null,
  646. parentCompo: null
  647. }
  648. this.resetForm('componentForm')
  649. },
  650. /** 搜索按钮操作 */
  651. handleQuery() {
  652. this.queryParams.pageNum = 1
  653. this.getList()
  654. },
  655. /** 重置按钮操作 */
  656. resetQuery() {
  657. this.queryParams.locationRef = null
  658. this.resetForm('queryForm')
  659. this.handleQuery()
  660. },
  661. // 多选框选中数据
  662. handleSelectionChange(selection) {
  663. this.ids = selection.map(item => item.id)
  664. this.single = selection.length !== 1
  665. this.multiple = !selection.length
  666. },
  667. /** 新增按钮操作 */
  668. handleAdd() {
  669. this.reset()
  670. this.open = true
  671. this.title = '添加能源设备'
  672. },
  673. /**设备器件按钮*/
  674. handleDevProcess(row) {
  675. this.showDevProcessDrawer = true
  676. this.ComponentRow = row
  677. listByDevice(this.ComponentRow.deviceCode).then(response => {
  678. this.ComponentList = response.data
  679. })
  680. },
  681. shouldShowDevProcessButton(row) {
  682. const categoryIsW = this.queryParams.deviceCategory === 'W'
  683. const validPsCodes = ['AA', 'AH', 'AJ', 'AM', 'AP', 'AL', 'APE', 'ALE', 'AF', 'ACC']
  684. const psCodeIsValid = validPsCodes.includes(row.psCode)
  685. // 只有当设备分类为输能设备且设备工艺代码有效时,才返回true
  686. return categoryIsW && psCodeIsValid
  687. },
  688. /**设备详情按钮*/
  689. handleDetail(row) {
  690. this.showDrawer = true
  691. this.curRow = row
  692. this.subKey = this.$options.data().subKey
  693. getModelByCode(this.curRow.facsModel).then(response => {
  694. const code = response.data
  695. this.eventData = response.data.eventList
  696. this.abilityData = response.data.abilityList
  697. })
  698. getObjAttr(2, this.curRow.deviceCode).then(response => {
  699. const attrs = response.data.attrs
  700. const attrValues = response.data.attrValues
  701. // 合并 attrs 和 attrValues 数组
  702. const mergedData = attrValues.map(attrValue => {
  703. const attr = attrs.find(a => a.attrKey === attrValue.attrKey)
  704. return {
  705. ...attrValue,
  706. attrName: attr ? attr.attrName : attrValue.attrName,
  707. attrUnit: attr ? attr.attrUnit : ''
  708. }
  709. })
  710. this.attrData = mergedData
  711. })
  712. },
  713. /** 修改按钮操作 */
  714. handleUpdate(row) {
  715. this.reset()
  716. const id = row.id || this.ids
  717. getDevice(id).then(response => {
  718. this.form = response.data
  719. this.open = true
  720. this.title = '修改能源设备'
  721. })
  722. const recursion = true
  723. const areaCode = '0'
  724. areaTreeSelect(recursion, areaCode).then(response => {
  725. this.totalAreaOptions = response.data
  726. })
  727. },
  728. /** 提交按钮 */
  729. submitForm() {
  730. // 重置 attrList 和 form.customAttrs
  731. if (!this.attrList) {
  732. this.attrList = []
  733. }
  734. if (!this.form.customAttrs) {
  735. this.form.customAttrs = []
  736. }
  737. // 准备要发送的数据
  738. let dataToSubmit = []
  739. // 添加模型属性数据
  740. this.attrList.forEach(attr => {
  741. const attrName = attr.attrName
  742. const attrKey = attr.attrKey
  743. const attrValue = this.attrValuesMap[attrKey]
  744. const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
  745. if (existingIndex === -1) {
  746. // 如果attrKey不存在于dataToSubmit中,则添加
  747. dataToSubmit.push({
  748. modelCode: this.form.deviceModel, // 模型代码
  749. objCode: this.form.deviceCode, // 设备代码
  750. objType: 2, // 对象类型
  751. attrKey: attrKey,
  752. attrValue: attrValue,
  753. attrName: attrName
  754. })
  755. }
  756. })
  757. // 添加自定义属性数据
  758. this.form.customAttrs.forEach(customAttr => {
  759. const attrName = customAttr.attrName
  760. const attrKey = customAttr.attrKey
  761. const attrValue = customAttr.attrValue
  762. const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
  763. if (existingIndex === -1) {
  764. // 如果attrKey不存在于dataToSubmit中,则添加
  765. dataToSubmit.push({
  766. modelCode: '', // 模型代码
  767. objCode: this.form.deviceCode, // 设备代码
  768. objType: 2, // 对象类型
  769. attrKey: attrKey,
  770. attrValue: attrValue,
  771. attrName: attrName
  772. })
  773. }
  774. })
  775. this.$refs['form'].validate(valid => {
  776. if (valid) {
  777. if (this.form.id != null) {
  778. updateDevice(this.form).then(response => {
  779. this.$modal.msgSuccess('修改成功')
  780. this.open = false
  781. this.getList()
  782. }).catch(error => {
  783. console.error('修改失败:', error)
  784. this.$message.error('修改失败')
  785. })
  786. if (dataToSubmit.length > 0) {
  787. addAttrValueBatch(dataToSubmit)
  788. .then(response => {
  789. if (response.code === 200) {
  790. this.$message.success('属性添加成功')
  791. } else {
  792. this.$message.error('属性添加失败')
  793. }
  794. }).catch(error => {
  795. console.error('属性添加失败:', error)
  796. this.$message.error('属性添加失败')
  797. })
  798. }
  799. } else {
  800. addDevice(this.form).then(response => {
  801. this.$modal.msgSuccess('新增成功')
  802. this.open = false
  803. this.getList()
  804. }).catch(error => {
  805. console.error('新增失败:', error)
  806. this.$message.error('新增失败')
  807. })
  808. if (dataToSubmit.length > 0) {
  809. addAttrValueBatch(dataToSubmit)
  810. .then(response => {
  811. if (response.code === 200) {
  812. this.$message.success('属性添加成功')
  813. } else {
  814. this.$message.error('属性添加失败')
  815. }
  816. }).catch(error => {
  817. console.error('属性添加失败:', error)
  818. this.$message.error('属性添加失败')
  819. })
  820. } else {
  821. // this.$message.info('没有属性需要添加');
  822. }
  823. }
  824. }
  825. })
  826. },
  827. /** 删除按钮操作 */
  828. handleDelete(row) {
  829. const ids = row.id || this.ids
  830. this.$modal.confirm('是否确认删除能源设备编号为"' + ids + '"的数据项?').then(function() {
  831. return delDevice(ids)
  832. }).then(() => {
  833. this.getList()
  834. this.$modal.msgSuccess('删除成功')
  835. }).catch(() => {
  836. })
  837. },
  838. /** 导出按钮操作 */
  839. handleExport() {
  840. this.download('ems/basecfg/device/export', {
  841. ...this.queryParams
  842. }, `device_${new Date().getTime()}.xlsx`)
  843. },
  844. getFacsOptions() {
  845. const getFacsParams = {
  846. facsCategory: this.queryParams.deviceCategory,
  847. subCategory: this.queryParams.deviceSubCategory
  848. }
  849. listAllFacs(getFacsParams).then(response => {
  850. this.facsOptions = response.data
  851. })
  852. },
  853. getSubCategorygetByCode() {
  854. getFacsCategorygetByCode(this.queryParams.deviceCategory).then(response => {
  855. this.subCategoryOptions = response.data.subtypeList || []
  856. })
  857. },
  858. getSubsystem() {
  859. listSubsystemAll().then(response => {
  860. this.subsystemOptions = response.data
  861. })
  862. },
  863. getAllDevProcess(subcategoryCode) {
  864. getDevProcess(subcategoryCode).then(response => {
  865. this.devOptions = response.data
  866. })
  867. },
  868. deviceCategoryChange() {
  869. this.queryParams.deviceSubCategory = ''
  870. //this.queryParams.psCode = null; // 重置设备工艺选择
  871. if (this.queryParams.deviceCategory === 'E' || this.queryParams.deviceCategory === 'W'
  872. || this.queryParams.deviceCategory === 'T' || this.queryParams.deviceCategory === 'C') {
  873. this.getAreaTree(false,'0')
  874. } else if (this.queryParams.deviceCategory === 'Z') {
  875. this.getAreaTree(true,'0')
  876. }
  877. this.getSubCategorygetByCode()
  878. this.getFacsOptions()
  879. this.handleQuery()
  880. },
  881. /**自定义属性表格*/
  882. addCustomAttr() {
  883. // 添加一个新的自定义属性
  884. if (!Array.isArray(this.form.customAttrs)) {
  885. this.form.customAttrs = []
  886. }
  887. this.form.customAttrs.push({
  888. attrKey: '',
  889. attrName: '',
  890. attrValue: ''
  891. })
  892. // 强制更新视图
  893. this.$forceUpdate()
  894. },
  895. deleteCustomAttr(index) {
  896. // 删除指定索引的自定义属性
  897. if (this.form.customAttrs.length > 0) {
  898. this.form.customAttrs.splice(index, 1)
  899. }
  900. },
  901. /**设备模型*/
  902. updateAttrValue(attrKey, newValue) {
  903. this.attrValuesMap[attrKey] = newValue
  904. },
  905. getFacsModel() {
  906. listAllModel(2).then(response => {
  907. this.modelList = response.data
  908. })
  909. },
  910. handleModelChange(modelCode) {
  911. if (modelCode) {
  912. this.getModelByCode(modelCode)
  913. this.getObjAttr(2, this.form.deviceCode)
  914. }
  915. },
  916. getModelByCode(modelCode) {
  917. getModelByCode(modelCode).then(response => {
  918. // this.attrList = response.data.attrList;
  919. const filteredAttrList = response.data.attrList.filter(attr => attr.attrType === 0)
  920. this.attrList = filteredAttrList
  921. })
  922. },
  923. getObjAttr(objType, deviceCode) {
  924. getObjAttr(objType, deviceCode).then(response => {
  925. // const attrs = response.data.attrs;
  926. const attrs = response.data.attrs.filter(attr => attr.attrType === 0)
  927. const attrValues = response.data.attrValues || [] // 确保是一个数组
  928. // 创建一个映射对象,用于存储 attrKey 与对应的 attrValue
  929. const attrValuesMap = {}
  930. // 遍历 attrs 数组
  931. attrs.forEach(attr => {
  932. // 查找 attrValues 数组中是否有匹配的 attrKey
  933. const attrValueObj = attrValues.find(value => value.attrKey === attr.attrKey)
  934. // 如果找到匹配的 attrValue,更新 attrValuesMap
  935. if (attrValueObj) {
  936. attrValuesMap[attr.attrKey] = attrValueObj.attrValue
  937. } else {
  938. // 如果没有找到匹配的 attrValue,则设置为 '暂无数据'
  939. attrValuesMap[attr.attrKey] = ''
  940. }
  941. })
  942. // 更新 attrValuesMap 到组件的数据中
  943. this.attrValuesMap = attrValuesMap
  944. })
  945. }
  946. }
  947. }
  948. </script>
  949. <style lang="scss" scoped>
  950. .divider {
  951. border-bottom: 2px solid #ebeef5;
  952. margin: 10px 0;
  953. }
  954. .section-title {
  955. font-size: 18px;
  956. font-weight: bold;
  957. margin-top: 20px;
  958. margin-bottom: 10px;
  959. }
  960. .drawer-content {
  961. padding: 0 20px;
  962. }
  963. .section-title {
  964. font-size: 18px;
  965. font-weight: bold;
  966. }
  967. .attr-list-container {
  968. border: 1px solid #ccc;
  969. padding: 10px;
  970. margin: 10px 0;
  971. font-weight: bold;
  972. }
  973. .attr-list-container h3 {
  974. font-weight: bold;
  975. }
  976. .attr-item {
  977. list-style-type: none;
  978. margin-bottom: 5px;
  979. }
  980. .attr-name {
  981. font-weight: bold;
  982. }
  983. </style>