index.vue 20 KB

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