areaCard.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /* 自定义tabs */
  2. <template>
  3. <div class="body" :style="style">
  4. <img class="logo" src="../../assets/img/logo.png" alt="">
  5. <div class="title">{{ title }}</div>
  6. <div style="margin-top: 50px; height:85%;" @contextmenu="contextmenu">
  7. <el-scrollbar>
  8. <div class="scoll">
  9. <div class="matrix" v-if="startList.length>0">
  10. <div class="problemTitle">启动</div>
  11. <MatrixBlock @on-click="handleDetial" @choose-click="handleClick" :dataList="startList">
  12. </MatrixBlock>
  13. </div>
  14. <div class="matrix" v-if="stopList.length>0">
  15. <div class="problemTitle">停机</div>
  16. <MatrixBlock @on-click="handleDetial" @choose-click="handleClick" :dataList="stopList">
  17. </MatrixBlock>
  18. </div>
  19. </div>
  20. </el-scrollbar>
  21. </div>
  22. <div v-if="current==1" class="send" @click="handleSend">发送</div>
  23. <div class="success" v-if="showFlag&&current===0">指令发送成功</div>
  24. </div>
  25. <WindturbineDetailPages v-model="dialogVisible" :showSvg="showSvg" @close="handleClose" :svgWeb="svgWeb"
  26. :stationName="stationName" :windturbine="currentWindturbine"></WindturbineDetailPages>
  27. </template>
  28. <script>
  29. import BackgroundData from 'utils/BackgroundData'
  30. import WindturbineDetailPages from "../WindturbineDetailPages.vue";
  31. import MatrixBlock from "../matrixBlock.vue";
  32. import MessageBridge from 'utils/MessageBridge'
  33. export default {
  34. name: 'gy-card',
  35. components: {
  36. MatrixBlock,
  37. WindturbineDetailPages
  38. },
  39. created: function () {
  40. console.log(this.current)
  41. this.initData();
  42. this.suggestion();
  43. },
  44. emits: ["parentRun"],
  45. props: {
  46. title: {
  47. type: String,
  48. default: '',
  49. required: true,
  50. },
  51. height: {
  52. type: Number,
  53. default: 200,
  54. },
  55. },
  56. data() {
  57. return {
  58. current: 1,
  59. windturbinelist: {},
  60. titleList: [],
  61. startList: [],
  62. stopList: [],
  63. chooseList: [],
  64. sendList: [],
  65. currentWindturbine: {},
  66. dialogVisible: false,
  67. showSvg: false,
  68. showFlag: false,
  69. svgWeb: '',
  70. stationName: '',
  71. // 定时器
  72. timer: "",
  73. controlErorCodes: [
  74. "控制成功",
  75. "控制命令发送失败",
  76. "无效的控制地址",
  77. "被控设备异常",
  78. "无效的控制功能",
  79. "网络连接错误,检查场站通信",
  80. "控制结果读取超时",
  81. "未知错误",
  82. "控制命令错误",
  83. "收到无法识别数据",
  84. "未读取到数据包",
  85. "未知错误",
  86. "风机操作过频繁",
  87. "风机被挂牌",
  88. "风机操作与风机状态不符",
  89. "需要登录",
  90. ],
  91. boosterStation: {
  92. 'MHS_SYZ': {
  93. name: '麻黄山升压站'
  94. },
  95. 'NSS_SYZ': {
  96. name: '牛首山升压站'
  97. },
  98. 'QS_SYZ': {
  99. name: '青山升压站'
  100. },
  101. 'QS3_SYZ': {
  102. name: '青山三期升压站'
  103. },
  104. 'SBQ_SYZ': {
  105. name: '石板泉升压站'
  106. },
  107. 'XS_SYZ': {
  108. name: '香山升压站'
  109. },
  110. 'DWK_SYZ': {
  111. name: '大武口升压站'
  112. },
  113. 'PL_SYZ': {
  114. name: '平罗升压站'
  115. },
  116. 'PL2_SYZ': {
  117. name: '平罗二期升压站'
  118. },
  119. 'XH_SYZ': {
  120. name: '宣和升压站'
  121. },
  122. 'MCH_SYZ': {
  123. name: '马场湖升压站'
  124. },
  125. 'HZJ_SYZ': {
  126. name: '海子井升压站'
  127. },
  128. }
  129. }
  130. },
  131. computed: {
  132. style() {
  133. return `width: 100%; height: ${this.height}vh;`
  134. },
  135. },
  136. methods: {
  137. control(current){
  138. this.current = current?current:1
  139. },
  140. initData: function () {
  141. var mb = MessageBridge.getInstance();
  142. var vs = [{ key: "/topic/suggestion", action: this.suggestion }];
  143. var vss = [{ key: "/topic/voice-control", action: this.windturbineMessage }];
  144. mb.register(vs);
  145. mb.register(vss);
  146. },
  147. suggestion(msg, headers) {
  148. this.titleList = msg?JSON.parse(msg):this.$store.state.suggestion
  149. if(msg){
  150. // api.sendRecommend(this.titleList).then(res =>{
  151. // if(res){
  152. // }
  153. // })
  154. }
  155. if (this.current === 0) {
  156. let dateList = []
  157. this.titleList.forEach(item => {
  158. item.operateStyle === 'Start' ? this.windturbinelist[item.windturbineId].controlType = 1 : this.windturbinelist[item.windturbineId].controlType = 2
  159. dateList.push(this.windturbinelist[item.windturbineId])
  160. })
  161. let mss = {}
  162. mss.type = 'send'
  163. this.timer = setTimeout(() => {
  164. this.menuClicked(mss, dateList, 'automatic')
  165. this.showFlag = false
  166. clearInterval(this.timer);
  167. }, 3000);
  168. }
  169. },
  170. windturbineMessage(msg) {
  171. let arr = []
  172. if (msg === 'CLOSE') {
  173. arr.push(msg)
  174. } else {
  175. arr = msg.split('-')
  176. }
  177. this.dialogVisible = false
  178. this.showSvg = false
  179. this.svgWeb = ''
  180. console.log(arr);
  181. if (arr[0] === 'OPEN_FJ') {
  182. this.currentWindturbine = this.windturbinelist[arr[1]]
  183. this.dialogVisible = true;
  184. } else if (arr[0] === 'CLOSE') {
  185. this.dialogVisible = false
  186. } else if (arr[0] === 'OPEN_SYZ') {
  187. this.showSvg = true
  188. this.dialogVisible = true
  189. this.svgWeb = arr[1];
  190. this.stationName = this.boosterStation[arr[1]].name
  191. } else if (arr[0] === 'CONTROL_START' || arr[0] === 'CONTROL_STOP' || arr[0] === 'CONTROL_MAINTAIN') {
  192. let mss = {}
  193. let windturbine = this.windturbinelist[arr[1]]
  194. switch (arr[0]) {
  195. case 'CONTROL_START':
  196. mss.controlType = '1'
  197. break
  198. case 'CONTROL_STOP':
  199. mss.controlType = '2'
  200. break
  201. case 'CONTROL_MAINTAIN':
  202. mss.controlType = '6'
  203. break
  204. }
  205. mss.type = 'send'
  206. this.menuClicked(mss, windturbine)
  207. }
  208. // else if (arr[0] === 'CONTROL_LOCK_OVERHAUL' || arr[0] === 'CONTROL_LOCK_MAINTAIN' || arr[0] === 'CONTROL_LOCK_LNVOLVED_OVERHAUL' ||
  209. // arr[0] === 'CONTROL_LOCK_LNVOLVED_MAINTAIN' || arr[0] === 'CONTROL_LOCK_LNVOLVED_PG' || arr[0] === 'CONTROL_LOCK_LNVOLVED_WEATHER' || arr[0] === 'CONTROL_UNLOCK') {
  210. // let windturbine = this.windturbinelist[arr[1]]
  211. // switch (arr[0]) {
  212. // case 'CONTROL_LOCK_OVERHAUL':
  213. // this.menuClicked({ type: "lock", value: "CheckLock" }, windturbine);
  214. // break;
  215. // case 'CONTROL_LOCK_MAINTAIN':
  216. // this.menuClicked({ type: "lock", value: "FaultLock" }, windturbine);
  217. // break;
  218. // case 'CONTROL_LOCK_LNVOLVED_OVERHAUL':
  219. // this.menuClicked({ type: "lock", value: "StationCheckLock" }, windturbine);
  220. // break;
  221. // case 'CONTROL_LOCK_LNVOLVED_MAINTAIN':
  222. // this.menuClicked({ type: "lock", value: "StationFaulLock" }, windturbine);
  223. // break;
  224. // case 'CONTROL_LOCK_LNVOLVED_PG':
  225. // this.menuClicked({ type: "lock", value: "StationPowerLineLock" }, windturbine);
  226. // break;
  227. // case 'CONTROL_LOCK_LNVOLVED_WEATHER':
  228. // this.menuClicked({ type: "lock", value: "StationWeatherLock" }, windturbine);
  229. // break;
  230. // case 'CONTROL_UNLOCK':
  231. // this.menuClicked({ type: "lock", value: "UnLock" }, windturbine);
  232. // break;
  233. // }
  234. // }
  235. },
  236. handleClick(values) {
  237. if (values.active) {
  238. let showIndex = null
  239. this.chooseList.forEach((item, index) => {
  240. if (item.windturbineId === values.windturbineId) {
  241. showIndex = index
  242. }
  243. })
  244. this.chooseList.splice(showIndex, 1);
  245. } else {
  246. this.chooseList.push(values)
  247. }
  248. this.startList.forEach(item => { if (item.windturbineId === values.windturbineId) { item.active = !item.active } })
  249. this.stopList.forEach(item => { if (item.windturbineId === values.windturbineId) { item.active = !item.active } })
  250. },
  251. handleDetial(itm) {
  252. this.dialogVisible = true;
  253. this.currentWindturbine = itm;
  254. },
  255. handleClose() {
  256. this.dialogVisible = false
  257. this.showSvg = false
  258. },
  259. handleSend() {
  260. if (this.chooseList.length > 0) {
  261. this.menuClicked({ type: "send" });
  262. }
  263. },
  264. /* 右键菜单 */
  265. contextmenu() {
  266. const { remote } = require("electron");
  267. var that = this;
  268. const menuTemplate = [
  269. {
  270. label: "发送",
  271. click() {
  272. that.menuClicked({ type: "send" });
  273. },
  274. },
  275. {
  276. label: "挂牌",
  277. submenu: [
  278. {
  279. label: "检修",
  280. click() {
  281. that.menuClicked({ type: "lock", value: "CheckLock" });
  282. },
  283. },
  284. {
  285. label: "故障维修",
  286. click() {
  287. that.menuClicked({ type: "lock", value: "FaultLock" });
  288. },
  289. },
  290. {
  291. label: "场内受累检修",
  292. click() {
  293. that.menuClicked({ type: "lock", value: "StationCheckLock" });
  294. },
  295. },
  296. {
  297. label: "场内受累故障",
  298. click() {
  299. that.menuClicked({ type: "lock", value: "StationFaulLock" });
  300. },
  301. },
  302. {
  303. label: "场外受累电网",
  304. click() {
  305. that.menuClicked({
  306. type: "lock",
  307. value: "StationPowerLineLock",
  308. });
  309. },
  310. },
  311. {
  312. label: "场外受累天气",
  313. click() {
  314. that.menuClicked({ type: "lock", value: "StationWeatherLock" });
  315. },
  316. },
  317. ],
  318. },
  319. // {
  320. // label: "标注",
  321. // click() {
  322. // that.menuClicked({ type: "marking" });
  323. // },
  324. // },
  325. ];
  326. const menu = remote.Menu.buildFromTemplate(menuTemplate);
  327. menu.popup(remote.getCurrentWindow());
  328. },
  329. menuClicked(msg, windturbine, automatic) {
  330. var bd = BackgroundData.getInstance();
  331. if (!bd.LoginUser) {
  332. this.$notify({
  333. title: "请登录",
  334. message: "控制风机需要先登录!",
  335. type: "warning",
  336. position: "bottom-right",
  337. offset: 60,
  338. duration: 3000,
  339. });
  340. return;
  341. }
  342. if (msg.type == "lock") {
  343. // 挂牌
  344. this.chooseList.forEach(item => {
  345. item.lockType = msg.value;
  346. })
  347. bd.windturbineControl(
  348. this.chooseList,
  349. true,
  350. '',
  351. this.controlSuccess,
  352. this.controlError
  353. );
  354. } else if (msg.type == "send") {
  355. // 发送
  356. let sendList = []
  357. if (automatic) {
  358. sendList = windturbine
  359. }
  360. else if (windturbine) {
  361. windturbine.controlType = msg.controlType
  362. sendList.push(windturbine)
  363. } else {
  364. this.chooseList.forEach(item => {
  365. if (item.operateStyle === "Start") {
  366. item.controlType = 1
  367. } else if (item.operateStyle === "Stop") {
  368. item.controlType = 2
  369. }
  370. })
  371. sendList = this.chooseList
  372. }
  373. this.showFlag = true
  374. if (sendList.length > 0) {
  375. bd.checkout(sendList);
  376. if (automatic) {
  377. bd.windturbineControl(
  378. sendList,
  379. false,
  380. 'automatic',
  381. this.controlSuccess,
  382. this.controlError
  383. );
  384. } else {
  385. bd.windturbineControl(
  386. sendList,
  387. false,
  388. '',
  389. this.controlSuccess,
  390. this.controlError
  391. );
  392. }
  393. }
  394. } else if (msg.type == "marking") {
  395. // 标注
  396. var vvs = this.getSelectedItems();
  397. bd.marking(vvs);
  398. }
  399. this.clearSelected();
  400. },
  401. clearSelected() {
  402. this.startList.forEach(item => {
  403. item.active = false
  404. })
  405. this.stopList.forEach(item => {
  406. item.active = false
  407. })
  408. this.chooseList = []
  409. },
  410. /* 控制成功 */
  411. controlSuccess(msg) {
  412. var bd = BackgroundData.getInstance();
  413. console.log(msg);
  414. if (msg.data || msg.data !== {}) {
  415. var mss = ''; // 信息
  416. var iserror = false;// 是否有控制错误的风机
  417. for (var v in msg.data) {
  418. var val = msg.data[v];
  419. if (val.errorCode > 0) {
  420. iserror = true;
  421. mss += `${val.windturbineId} ${this.controlErorCodes[val.errorCode]}\n`;
  422. }
  423. }
  424. var tp = iserror ? "warning" : "success";
  425. var dt = iserror ? 0 : 4500;
  426. if (!iserror) {
  427. mss = "控制成功";
  428. }
  429. this.$notify({
  430. title: "控制",
  431. message: mss,
  432. type: tp,
  433. position: "bottom-right",
  434. offset: 60,
  435. duration: 3000,
  436. });
  437. } else {
  438. this.$notify({
  439. title: "控制出现错误",
  440. message: '控制失败,请重试',
  441. type: "warning",
  442. position: "bottom-right",
  443. offset: 60,
  444. duration: 3000,
  445. });
  446. }
  447. },
  448. /* 控制失败 */
  449. controlError(err) {
  450. this.$notify({
  451. title: "控制出现错误",
  452. message: err.message,
  453. type: "warning",
  454. position: "bottom-right",
  455. offset: 60,
  456. duration: 3000,
  457. });
  458. },
  459. },
  460. watch: {
  461. "$store.getters.windturbinelist": {
  462. deep: true,
  463. handler: function (json) {
  464. this.windturbinelist = json
  465. let arr = Object.keys(json).sort()
  466. this.stopList = []
  467. this.startList = []
  468. for (var id of arr) {
  469. var val = json[id];
  470. this.chooseList.forEach(item => {
  471. if (item.windturbineId === val.windturbineId) {
  472. val.active = true
  473. }
  474. })
  475. this.titleList.forEach(item => {
  476. if (item.windturbineId === val.windturbineId) {
  477. val.operateStyle = item.operateStyle
  478. if (item.operateStyle === "Start" && val.status === 2) {
  479. this.startList.push(val)
  480. } else if (item.operateStyle === "Stop" && val.status === 4) {
  481. this.stopList.push(val)
  482. }
  483. }
  484. })
  485. }
  486. let checkoutList = BackgroundData.getInstance().checkouts;
  487. checkoutList.forEach(item => {
  488. let showIndex = null
  489. let starFlag = false
  490. let stopFlag = false
  491. this.startList.forEach((param, index) => {
  492. if (item.windturbineId === param.windturbineId) {
  493. showIndex = index
  494. starFlag = true
  495. }
  496. })
  497. this.stopList.forEach((param, index) => {
  498. if (item.windturbineId === param.windturbineId) {
  499. showIndex = index
  500. stopFlag = true
  501. }
  502. })
  503. starFlag ? this.startList.splice(showIndex, 1) : '';
  504. stopFlag ? this.stopList.splice(showIndex, 1) : '';
  505. })
  506. },
  507. },
  508. "$store.getters.current": {
  509. handler: function (json) {
  510. this.current = json
  511. if (json === 0) {
  512. let dateList = []
  513. this.titleList.forEach(item => {
  514. item.operateStyle === 'Start' ? this.windturbinelist[item.windturbineId].controlType = 1 : this.windturbinelist[item.windturbineId].controlType = 2
  515. dateList.push(this.windturbinelist[item.windturbineId])
  516. })
  517. let mss = {}
  518. mss.type = 'send'
  519. this.timer = setTimeout(() => {
  520. this.menuClicked(mss, dateList, 'automatic')
  521. this.showFlag = false
  522. clearInterval(this.timer);
  523. }, 3000);
  524. }
  525. }
  526. }
  527. },
  528. }
  529. </script>
  530. <style scoped="scoped">
  531. .body {
  532. border: 1px solid #373737;
  533. width: 100%;
  534. margin-left: 15px;
  535. margin-top: 20px;
  536. }
  537. .body .scoll {
  538. height: 91%;
  539. }
  540. .title {
  541. color: #ffffff;
  542. font-size: 14px;
  543. margin-left: 32px;
  544. /* margin-top: 12px; */
  545. margin-bottom: 10px;
  546. /* width: 570px; */
  547. width: 29vw;
  548. height: 50px;
  549. display: flex;
  550. align-items: center;
  551. position: absolute;
  552. background-color: #000000;
  553. }
  554. .title::before {
  555. z-index: 1;
  556. content: '';
  557. position: absolute;
  558. left: -18px !important;
  559. /* top: 30px !important; */
  560. width: 5px;
  561. height: 5px;
  562. background-color: #54B75A;
  563. border-radius: 50%;
  564. }
  565. .logo {
  566. position: absolute;
  567. top: 12px;
  568. left: 12px;
  569. }
  570. .matrix {
  571. margin-left: 20px;
  572. margin-right: 10px;
  573. padding-bottom: 20px;
  574. border-bottom: 1px solid rgba(31, 31, 31, 1);
  575. }
  576. .problemTitle {
  577. font-size: 12px;
  578. color: #BFBFBF;
  579. margin-top: 20px;
  580. margin-bottom: 20px;
  581. margin-left: 12px;
  582. }
  583. .send {
  584. width: 86px;
  585. height: 26px;
  586. display: flex;
  587. align-items: center;
  588. justify-content: center;
  589. background-color: rgba(84, 183, 90, 1);
  590. color: #ffffff;
  591. font-size: 14px;
  592. position: absolute;
  593. bottom: 20px;
  594. right: 10px;
  595. }
  596. .success {
  597. display: flex;
  598. align-items: center;
  599. justify-content: center;
  600. width: 250px;
  601. height: 48px;
  602. position: absolute;
  603. bottom: 20px;
  604. right: 20%;
  605. border: 1px solid rgba(55, 55, 55, 1);
  606. border-radius: 10px;
  607. color: #ffffff;
  608. font-size: 14px;
  609. }
  610. </style>