historywaring.vue 18 KB

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