index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. <template>
  2. <el-card>
  3. <el-space wrap>
  4. <div class="search-input">
  5. <span class="lable">类型:</span>
  6. <el-select
  7. v-model="state.typeVal"
  8. clearable
  9. size="mini"
  10. style="width: 100px"
  11. placeholder="全部"
  12. popper-class="select"
  13. @change="
  14. () => {
  15. getStationList();
  16. typechange();
  17. }
  18. "
  19. >
  20. <el-option
  21. v-for="item in state.typeList"
  22. :key="item.value"
  23. :value="item.value"
  24. :label="item.label"
  25. >
  26. </el-option>
  27. </el-select>
  28. </div>
  29. <div class="search-input" v-if="!isStation">
  30. <span class="lable">{{
  31. state.isshowwindturbineName ? "场站:" : "升压站:"
  32. }}</span>
  33. <el-select
  34. v-model="state.stationId"
  35. clearable
  36. size="mini"
  37. placeholder="全部"
  38. popper-class="select"
  39. @change="getWindturbineList"
  40. >
  41. <el-option
  42. v-for="item in stationList"
  43. :key="item.id"
  44. :value="item.id"
  45. :label="item.name"
  46. ></el-option>
  47. </el-select>
  48. </div>
  49. <div class="search-input" v-if="state.isshowwindturbineName">
  50. <span class="lable">机组:</span>
  51. <el-select
  52. v-model="state.deviceId"
  53. clearable
  54. size="mini"
  55. placeholder="全部"
  56. popper-class="select"
  57. >
  58. <el-option
  59. v-for="item in state.windturbineList"
  60. :key="item.id"
  61. :value="item.id"
  62. :label="item.name"
  63. >
  64. </el-option>
  65. </el-select>
  66. </div>
  67. <div class="search-input" v-if="state.isshowwindturbineName">
  68. <span class="lable">型号:</span>
  69. <el-select
  70. v-model="state.modelId"
  71. clearable
  72. size="mini"
  73. placeholder="全部"
  74. popper-class="select"
  75. >
  76. <el-option
  77. v-for="item in modelList"
  78. :key="item.id"
  79. :value="item.id"
  80. :label="item.name"
  81. >
  82. </el-option>
  83. </el-select>
  84. </div>
  85. <div class="search-input" v-if="state.isshowwindturbineName">
  86. <span class="lable">部件:</span>
  87. <el-select
  88. v-model="state.components"
  89. clearable
  90. size="mini"
  91. placeholder="全部"
  92. popper-class="select"
  93. >
  94. <el-option
  95. v-for="item in componentList"
  96. :key="item.id"
  97. :value="item.id"
  98. :label="item.name"
  99. >
  100. </el-option>
  101. </el-select>
  102. </div>
  103. <div class="search-input">
  104. <span class="lable">描述:</span>
  105. <el-input
  106. v-model="state.description"
  107. style="width: 100px"
  108. size="mini"
  109. ></el-input>
  110. </div>
  111. <div class="search-input">
  112. <span class="lable">日期:</span>
  113. <el-date-picker
  114. v-model="state.dateTime"
  115. size="mini"
  116. type="datetimerange"
  117. range-separator="-"
  118. format="YYYY-MM-DD HH:mm:ss"
  119. value-format="YYYY-MM-DD HH:mm:ss"
  120. start-placeholder="开始"
  121. end-placeholder="结束"
  122. >
  123. </el-date-picker>
  124. </div>
  125. <div>
  126. <el-button type="primary" size="mini" @click="getAlarmHistoryt"
  127. >查询</el-button
  128. >
  129. <el-button
  130. size="mini"
  131. type="primary"
  132. @click="export2Excel"
  133. :disabled="state.tableData?.length == 0 ? true : false"
  134. >
  135. 导出</el-button
  136. >
  137. <el-button
  138. type="primary"
  139. size="mini"
  140. :disabled="!state.tableData?.length"
  141. @click="confirmItem(state.tableData)"
  142. >确认本页</el-button
  143. >
  144. </div>
  145. </el-space>
  146. </el-card>
  147. <div class="table-wrapper">
  148. <el-table
  149. :data="state.tableData"
  150. height="calc(100% - 35px - 10px)"
  151. style="width: 100%"
  152. border
  153. stripe
  154. >
  155. <template v-if="state.isshowwindturbineName">
  156. <el-table-column
  157. v-for="item in state.tableHeader"
  158. :label="item.title"
  159. :prop="item.code"
  160. :key="item.code"
  161. :width="item.width || ''"
  162. show-overflow-tooltip
  163. header-align="center"
  164. >
  165. <template #default="scope">
  166. <p :style="item.style && item.style(scope.row)">
  167. <span v-if="item.code == 'rank'">
  168. {{ tableFilter(scope.row.rank) }}
  169. </span>
  170. <span v-else-if="item.code == 'ts'">
  171. {{ formatTime(scope.row.ts) }}
  172. </span>
  173. <span
  174. :style="`color:${
  175. scope.row.confirmed
  176. ? 'var(--el-color-primary)'
  177. : 'var(--el-color-danger)'
  178. }`"
  179. v-else-if="item.code == 'confirmed'"
  180. >
  181. {{ scope.row.confirmed ? "是" : "否" }}
  182. </span>
  183. <span v-else>
  184. {{ scope.row[item.code] }}
  185. </span>
  186. </p>
  187. </template>
  188. </el-table-column>
  189. <el-table-column
  190. label="操作"
  191. width="100"
  192. header-align="center"
  193. align="center"
  194. fixed="right"
  195. >
  196. <template #default="scope">
  197. <el-button type="text" @click="confirmItem([scope.row])"
  198. >确认本条</el-button
  199. >
  200. </template>
  201. </el-table-column>
  202. </template>
  203. <template v-else>
  204. <el-table-column
  205. v-for="item in state.tableHeader1"
  206. :label="item.title"
  207. :prop="item.code"
  208. :key="item.code"
  209. :width="item.width || ''"
  210. show-overflow-tooltip
  211. header-align="center"
  212. >
  213. <template #default="scope">
  214. <p :style="item.style && item.style(scope.row)">
  215. <span v-if="item.code == 'rank'">
  216. {{ tableFilter(scope.row.rank) }}
  217. </span>
  218. <span v-else-if="item.code == 'ts'">
  219. {{ formatTime(scope.row.ts) }}
  220. </span>
  221. <span
  222. :style="`color:${
  223. scope.row.confirmed
  224. ? 'var(--el-color-primary)'
  225. : 'var(--el-color-danger)'
  226. }`"
  227. v-else-if="item.code == 'confirmed'"
  228. >
  229. {{ scope.row.confirmed ? "是" : "否" }}
  230. </span>
  231. <span v-else>
  232. {{ scope.row[item.code] }}
  233. </span>
  234. </p>
  235. </template>
  236. </el-table-column>
  237. <el-table-column
  238. label="操作"
  239. width="100"
  240. header-align="center"
  241. align="center"
  242. fixed="right"
  243. >
  244. <template #default="scope">
  245. <el-button type="text" @click="confirmItem([scope.row])"
  246. >确认本条</el-button
  247. >
  248. </template>
  249. </el-table-column>
  250. </template>
  251. </el-table>
  252. <div class="pagination-wrapper">
  253. <el-pagination
  254. background
  255. layout="total, sizes, prev, pager, next"
  256. :current-page="query.page"
  257. :page-size="query.limit"
  258. :page-sizes="[15, 100, 500, 1000]"
  259. :total="query.pageTotal"
  260. @size-change="
  261. (value) => {
  262. query.limit = value;
  263. getAlarmHistoryt();
  264. }
  265. "
  266. @current-change="handlePageChange"
  267. ></el-pagination>
  268. </div>
  269. </div>
  270. </template>
  271. <script setup>
  272. import {
  273. watch,
  274. reactive,
  275. nextTick,
  276. computed,
  277. onMounted,
  278. ref,
  279. onActivated,
  280. onUpdated,
  281. } from "vue";
  282. import { useRouter, useRoute } from "vue-router";
  283. import dayjs from "dayjs";
  284. import {
  285. alarm_history,
  286. new_alarm_history,
  287. fetchWindturbineList,
  288. fetchModel,
  289. fetchRelatePartAndAlarmType,
  290. getWpList,
  291. confirmAlart,
  292. } from "/@/api/api.js";
  293. import { ElMessage } from "element-plus";
  294. import { initWebSocket } from "/@/websocket/indextest";
  295. import { outExportExcel } from "/@/utils/exportExcel"; //引入文件
  296. import { useStore } from "vuex";
  297. const store = useStore();
  298. const isStation = computed(() => store.getters.isStation);
  299. const route = useRoute();
  300. onMounted(() => {
  301. state.dateTime = [
  302. dayjs().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
  303. dayjs().format("YYYY-MM-DD HH:mm:ss"),
  304. ];
  305. state.deviceId = route.params.deviceId || "";
  306. state.alarmId = route.params.alarmId || "";
  307. getStationList();
  308. getequipmentmodel_list();
  309. getfetchRelatePart();
  310. });
  311. // 机型
  312. const getequipmentmodel_list = async () => {
  313. const { data } = await fetchModel();
  314. state.modelListAll = data;
  315. };
  316. //所属部件
  317. const getfetchRelatePart = async () => {
  318. const { data } = await fetchRelatePartAndAlarmType();
  319. state.fetchListAll = data;
  320. };
  321. const confirmItem = (alarmItem) => {
  322. ElMessageBox("您确定要执行此操作吗?", "提示", {
  323. confirmButtonText: "确定",
  324. cancelButtonText: "取消",
  325. type: "warning",
  326. })
  327. .then(() => {
  328. confirmAlart(alarmItem)
  329. .then((res) => {
  330. if (res.code === 200) {
  331. ElMessage.success("确认成功");
  332. store.commit("removeWarning", alarmItem);
  333. getAlarmHistoryt();
  334. }
  335. })
  336. .catch(() => {
  337. ElMessage.error("确认失败,请重试");
  338. });
  339. })
  340. .catch(() => {});
  341. };
  342. const getColumnStyle = (columnItem) => {
  343. let style = "color:";
  344. if (columnItem.endts) {
  345. style += "var(--el-color-success)";
  346. } else {
  347. style += "var(--el-color-danger)";
  348. }
  349. return style;
  350. };
  351. const state = reactive({
  352. typeList: [
  353. // {
  354. // label: "升压站",
  355. // value: "booststation",
  356. // },
  357. // {
  358. // label: "自定义",
  359. // value: "custom",
  360. // },
  361. {
  362. label: "风机",
  363. value: "windturbine",
  364. },
  365. {
  366. label: "光伏",
  367. value: "inverter",
  368. },
  369. ],
  370. c: "windturbine",
  371. stationId: "",
  372. alarmId: "",
  373. typeVal: "windturbine",
  374. windturbineList: [],
  375. deviceId: "",
  376. modelListAll: {},
  377. fetchListAll: {},
  378. modelId: "", //型号
  379. components: "", //部件
  380. description: "", //描述
  381. dateTime: [],
  382. startDate: null,
  383. endDate: null,
  384. tableData: [],
  385. isshowwindturbineName: true,
  386. tableHeader: [
  387. { title: "时间", code: "ts", width: "150" },
  388. { title: "场站", code: "stationname", width: "150" },
  389. { title: "机组", code: "devicename", width: "150" },
  390. { title: "报警信息", code: "description", width: "250" },
  391. { title: "故障原因", code: "faultCause" },
  392. // { title: "故障编码", code: "nemCode", width: "100" },
  393. // { title: "故障解决方法", code: "resolvent" },
  394. // { title: "级别", code: "rank", width: "80" },
  395. {
  396. title: "状态",
  397. code: "isCloseName",
  398. width: "80",
  399. style: getColumnStyle,
  400. width: 100,
  401. },
  402. { title: "是否确认", code: "confirmed", width: "100" },
  403. { title: "类型", code: "deviceTypeName", width: "80" },
  404. ],
  405. tableHeader1: [
  406. { title: "时间", code: "ts", width: "150" },
  407. { title: "升压站", code: "stationname", width: "150" },
  408. { title: "报警信息", code: "description", width: "250" },
  409. // { title: "级别", code: "rank", width: "80" },
  410. {
  411. title: "状态",
  412. code: "isCloseName",
  413. style: getColumnStyle,
  414. width: 100,
  415. width: "80",
  416. },
  417. { title: "是否确认", code: "confirmed", width: "100" },
  418. { title: "类型", code: "deviceTypeName", width: "80" },
  419. ],
  420. });
  421. // 场站列表/升压站列表
  422. const stationList = ref([]);
  423. const getStationList = async () => {
  424. const { data } = await getWpList(state.typeVal);
  425. stationList.value = data;
  426. if (state.deviceId) {
  427. let station = data.find((i) => {
  428. let st = i.id.split("_")[2];
  429. let dt = state.deviceId.split("_")[2];
  430. if (st == dt) {
  431. return i;
  432. }
  433. });
  434. state.stationId = station?.id;
  435. } else {
  436. state.stationId =
  437. state.typeVal == "windturbine" ? "SXJ_KGDL_DJY_FDC_STA" : data[0]?.id;
  438. }
  439. };
  440. watch(
  441. () => stationList,
  442. (val, old) => {
  443. val?.value?.length &&
  444. nextTick(async () => {
  445. await getWindturbineList();
  446. await getAlarmHistoryt();
  447. });
  448. },
  449. {
  450. deep: true,
  451. immediate: true,
  452. }
  453. );
  454. watch(
  455. () => route,
  456. (val, old) => {
  457. state.deviceId = route.params.deviceId || "";
  458. state.alarmId = route.params.alarmId || "";
  459. // nextTick(async () => {
  460. // if (route.params.deviceId && route.params.alarmId) {
  461. // await getAlarmHistoryt();
  462. // }
  463. // });
  464. },
  465. {
  466. deep: true,
  467. immediate: true,
  468. }
  469. );
  470. //型号列表
  471. const modelList = computed(() => {
  472. if (state.stationId == "") {
  473. return [];
  474. } else {
  475. state.modelId = route.params.deviceId
  476. ? ""
  477. : state.modelListAll[state.stationId]?.[0]?.id || "";
  478. return state.modelListAll[state.stationId];
  479. }
  480. });
  481. //部件列表
  482. const componentList = computed(() => {
  483. if (state.stationId == "") {
  484. return [];
  485. } else {
  486. if (state.stationId.includes("FDC")) {
  487. return state.fetchListAll?.fjbj;
  488. } else {
  489. return state.fetchListAll?.gfbj;
  490. }
  491. }
  492. });
  493. //get 风机
  494. const getWindturbineList = async () => {
  495. const { data } = await fetchWindturbineList(state.stationId);
  496. state.windturbineList = data;
  497. };
  498. const query = reactive({
  499. page: 1,
  500. limit: 15,
  501. pageTotal: null,
  502. });
  503. // 获取历史记录表
  504. const getAlarmHistoryt = async () => {
  505. // if (route.params.deviceId && route.params.alarmId) {
  506. // state.stationId = "";
  507. // }
  508. let params = {
  509. pageNum: query.page,
  510. pageSize: query.limit,
  511. alarmId: state.alarmId,
  512. alarmType: "custom",
  513. deviceType: state.typeVal,
  514. stationid: state.stationId,
  515. deviceid:
  516. state.deviceId || (state.typeVal == "booststation" ? "" : state.deviceId),
  517. modelId: state.typeVal == "booststation" ? "" : state.modelId,
  518. components: state.components,
  519. description: state.description,
  520. begin: state.dateTime[0],
  521. end: state.dateTime[1],
  522. };
  523. const { data } = await alarm_history(params);
  524. query.pageTotal = data?.total;
  525. data?.ls?.forEach((ele) => {
  526. ele.isCloseName = ele.endts ? "已解除" : "未解除";
  527. ele.deviceTypeName = tableFilter(ele.deviceType);
  528. });
  529. state.tableData = data?.ls;
  530. };
  531. //报警类型变化
  532. const typechange = () => {
  533. state.alarmId = "";
  534. state.deviceId = "";
  535. state.isshowwindturbineName = state.typeVal == "booststation" ? false : true;
  536. };
  537. // 批量导出
  538. const export2Excel = async () => {
  539. let params = {
  540. pageNum: query.page,
  541. pageSize: query.pageTotal,
  542. alarmType: state.typeVal,
  543. stationid: state.stationId,
  544. deviceid: state.typeVal == "booststation" ? "" : state.deviceId,
  545. modelId: state.modelId,
  546. components: state.components,
  547. description: state.description,
  548. begin: state.dateTime[0],
  549. end: state.dateTime[1],
  550. };
  551. if (state.dateTime[1] - state.dateTime[0] > 6 * 24 * 60 * 60 * 1000) {
  552. this.$message({
  553. message: "导出时间范围不能大于7天",
  554. type: "warning",
  555. });
  556. } else {
  557. let tableHeader = [];
  558. let tableKey = [];
  559. const { data } = await alarm_history(params);
  560. if (state.isshowwindturbineName) {
  561. tableHeader = state.tableHeader.map((item) => item.title);
  562. tableKey = state.tableHeader.map((item) => item.code);
  563. } else {
  564. tableHeader = state.tableHeader1.map((item) => item.title);
  565. tableKey = state.tableHeader1.map((item) => item.code);
  566. }
  567. const stationName = stationList.value.find((ele) => {
  568. return ele.id === state.stationId;
  569. }).name;
  570. const fileName = `${stationName} ${state.dateTime[0]} ~ ${state.dateTime[1]} 数据表`;
  571. outExportExcel(
  572. tableHeader,
  573. tableKey,
  574. data.ls.map((item) => {
  575. return {
  576. ...item,
  577. ts: formatTime(item.ts),
  578. rank: tableFilter(item.rank),
  579. deviceType: tableFilter(item.deviceType),
  580. };
  581. }),
  582. fileName
  583. );
  584. ElMessage.success(`导出成功!`);
  585. }
  586. };
  587. // 分页导航
  588. const handlePageChange = (val) => {
  589. query.page = val;
  590. getAlarmHistoryt();
  591. };
  592. // 时间格式化
  593. const formatTime = (val) => {
  594. return dayjs(val).format("YYYY-MM-DD HH:mm:ss");
  595. };
  596. // 格式化
  597. const obj = {
  598. 1: "低级",
  599. 2: "低中级",
  600. 3: "中级",
  601. 4: "中高级",
  602. 5: "高级",
  603. booststation: "升压站",
  604. custom: "自定义",
  605. windturbine: "风机",
  606. inverter: "光伏",
  607. };
  608. const messageTypeObj = {
  609. 1: "触发",
  610. 3: "解除",
  611. };
  612. const tableFilter = (val) => {
  613. return obj[val];
  614. };
  615. const messageTypeFilter = (val) => {
  616. return messageTypeObj[val];
  617. };
  618. </script>
  619. <style scoped lang="scss">
  620. .table-wrapper {
  621. height: calc(100% - 160px);
  622. background-color: #fff;
  623. margin-top: 10px;
  624. padding: 20px;
  625. .pagination-wrapper :deep {
  626. text-align: right;
  627. margin-top: 10px;
  628. .el-icon {
  629. width: unset;
  630. }
  631. }
  632. }
  633. </style>