index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  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.windturbineId"
  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. <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-space>
  137. </el-card>
  138. <div class="table-wrapper">
  139. <el-table
  140. :data="state.tableData"
  141. height="calc(100% - 35px - 10px)"
  142. style="width: 100%"
  143. border
  144. stripe
  145. >
  146. <template v-if="state.isshowwindturbineName">
  147. <el-table-column
  148. v-for="item in state.tableHeader"
  149. :label="item.title"
  150. :prop="item.code"
  151. :key="item.code"
  152. :width="item.width || ''"
  153. show-overflow-tooltip
  154. header-align="center"
  155. >
  156. <template #default="scope">
  157. <p :style="item.style && item.style(item)">
  158. <span v-if="item.code == 'rank'">
  159. {{ tableFilter(scope.row.rank) }}
  160. </span>
  161. <span v-else-if="item.code == 'ts'">
  162. {{ formatTime(scope.row.ts) }}
  163. </span>
  164. <span v-else>
  165. {{ scope.row[item.code] }}
  166. </span>
  167. </p>
  168. </template>
  169. </el-table-column>
  170. </template>
  171. <template v-else>
  172. <el-table-column
  173. v-for="item in state.tableHeader1"
  174. :label="item.title"
  175. :prop="item.code"
  176. :key="item.code"
  177. :width="item.width || ''"
  178. show-overflow-tooltip
  179. header-align="center"
  180. >
  181. <template #default="scope">
  182. <p :style="item.style && item.style(item)">
  183. <span v-if="item.code == 'rank'">
  184. {{ tableFilter(scope.row.rank) }}
  185. </span>
  186. <span v-else-if="item.code == 'ts'">
  187. {{ formatTime(scope.row.ts) }}
  188. </span>
  189. <span v-else>
  190. {{ scope.row[item.code] }}
  191. </span>
  192. </p>
  193. </template>
  194. </el-table-column>
  195. </template>
  196. </el-table>
  197. <div class="pagination-wrapper">
  198. <el-pagination
  199. background
  200. layout="total, prev, pager, next"
  201. hide-on-single-page
  202. :current-page="query.page"
  203. :page-size="query.limit"
  204. :total="query.pageTotal"
  205. @current-change="handlePageChange"
  206. ></el-pagination>
  207. </div>
  208. </div>
  209. </template>
  210. <script setup>
  211. import { watch, reactive, nextTick, computed, onMounted, ref } from "vue";
  212. import { useRouter, useRoute } from "vue-router";
  213. import dayjs from "dayjs";
  214. import {
  215. alarm_history,
  216. new_alarm_history,
  217. fetchWindturbineList,
  218. fetchModel,
  219. fetchRelatePartAndAlarmType,
  220. getWpList,
  221. } from "/@/api/api.js";
  222. import { ElMessage } from "element-plus";
  223. import { initWebSocket } from "/@/websocket/indextest";
  224. import { outExportExcel } from "/@/utils/exportExcel"; //引入文件
  225. import { useStore } from "vuex";
  226. const store = useStore();
  227. const isStation = computed(() => store.getters.isStation);
  228. const route = useRoute();
  229. onMounted(() => {
  230. state.dateTime = [
  231. dayjs().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
  232. dayjs().format("YYYY-MM-DD HH:mm:ss"),
  233. ];
  234. state.deviceId = route.params.deviceId || "";
  235. state.alarmId = route.params.alarmId || "";
  236. getStationList();
  237. getequipmentmodel_list();
  238. getfetchRelatePart();
  239. });
  240. // 机型
  241. const getequipmentmodel_list = async () => {
  242. const { data } = await fetchModel();
  243. state.modelListAll = data;
  244. };
  245. //所属部件
  246. const getfetchRelatePart = async () => {
  247. const { data } = await fetchRelatePartAndAlarmType();
  248. state.fetchListAll = data;
  249. };
  250. const getColumnStyle = (columnItem) => {
  251. let style = "color:";
  252. if (columnItem.endts) {
  253. style += "var(--el-color-success)";
  254. } else {
  255. style += "var(--el-color-danger)";
  256. }
  257. return style;
  258. };
  259. const state = reactive({
  260. typeList: [
  261. {
  262. label: "升压站",
  263. value: "booststation",
  264. },
  265. // {
  266. // label: "自定义",
  267. // value: "custom",
  268. // },
  269. {
  270. label: "风机",
  271. value: "windturbine",
  272. },
  273. {
  274. label: "光伏",
  275. value: "inverter",
  276. },
  277. ],
  278. c: "windturbine",
  279. stationId: "",
  280. alarmId: "",
  281. typeVal: "windturbine",
  282. windturbineList: [],
  283. windturbineId: "",
  284. modelListAll: {},
  285. fetchListAll: {},
  286. modelId: "", //型号
  287. components: "", //部件
  288. description: "", //描述
  289. dateTime: [],
  290. startDate: null,
  291. endDate: null,
  292. tableData: [],
  293. isshowwindturbineName: true,
  294. tableHeader: [
  295. { title: "时间", code: "ts", width: "150" },
  296. { title: "场站", code: "stationname", width: "150" },
  297. { title: "机组", code: "devicename", width: "150" },
  298. { title: "报警信息", code: "description", width: "180" },
  299. { title: "故障原因", code: "faultCause" },
  300. // { title: "故障编码", code: "nemCode", width: "100" },
  301. // { title: "故障解决方法", code: "resolvent" },
  302. { title: "级别", code: "rank", width: "80" },
  303. {
  304. title: "状态",
  305. code: "isCloseName",
  306. width: "80",
  307. style: getColumnStyle,
  308. width: 100,
  309. },
  310. { title: "类型", code: "deviceTypeName", width: "80" },
  311. ],
  312. tableHeader1: [
  313. { title: "时间", code: "ts", width: "150" },
  314. { title: "升压站", code: "stationname", width: "150" },
  315. { title: "报警信息", code: "description" },
  316. { title: "级别", code: "rank", width: "80" },
  317. {
  318. title: "状态",
  319. code: "isCloseName",
  320. style: getColumnStyle,
  321. width: 100,
  322. width: "80",
  323. },
  324. { title: "类型", code: "deviceTypeName", width: "80" },
  325. ],
  326. });
  327. // 场站列表/升压站列表
  328. const stationList = ref([]);
  329. const getStationList = async () => {
  330. const { data } = await getWpList(state.typeVal);
  331. stationList.value = data;
  332. };
  333. watch(
  334. () => stationList,
  335. (val, old) => {
  336. val?.value?.length &&
  337. nextTick(async () => {
  338. state.stationId = val.value[0]?.id;
  339. await getWindturbineList();
  340. await getAlarmHistoryt();
  341. });
  342. },
  343. {
  344. deep: true,
  345. immediate: true,
  346. }
  347. );
  348. watch(
  349. () => route,
  350. (val, old) => {
  351. state.deviceId = route.params.deviceId || "";
  352. state.alarmId = route.params.alarmId || "";
  353. nextTick(async () => {
  354. if (route.params.deviceId && route.params.alarmId) {
  355. await getAlarmHistoryt();
  356. }
  357. });
  358. },
  359. {
  360. deep: true,
  361. immediate: true,
  362. }
  363. );
  364. //型号列表
  365. const modelList = computed(() => {
  366. if (state.typeVal == "windturbine") {
  367. if (state.stationId == "") {
  368. return [];
  369. } else {
  370. state.modelId = state.modelListAll[state.stationId]?.[0]?.id || "";
  371. return state.modelListAll[state.stationId];
  372. }
  373. } else {
  374. return [];
  375. }
  376. });
  377. //部件列表
  378. const componentList = computed(() => {
  379. if (state.typeVal == "windturbine") {
  380. if (state.stationId == "") {
  381. return [];
  382. } else {
  383. if (state.stationId.includes("FDC")) {
  384. return state.fetchListAll?.fjbj;
  385. } else {
  386. return state.fetchListAll?.gfbj;
  387. }
  388. }
  389. } else {
  390. return [];
  391. }
  392. });
  393. //get 风机
  394. const getWindturbineList = async () => {
  395. state.windturbineList = [];
  396. state.windturbineId = "";
  397. const { data } = await fetchWindturbineList(state.stationId);
  398. state.windturbineList = data;
  399. };
  400. const query = reactive({
  401. page: 1,
  402. limit: 17,
  403. pageTotal: null,
  404. });
  405. // 获取历史记录表
  406. const getAlarmHistoryt = async () => {
  407. if (route.params.deviceId && route.params.alarmId) {
  408. state.stationId = "";
  409. }
  410. let params = {
  411. pageNum: query.page,
  412. pageSize: query.limit,
  413. alarmId: state.alarmId,
  414. alarmType: "custom",
  415. deviceType: state.typeVal,
  416. stationid: state.stationId,
  417. deviceid:
  418. state.deviceId ||
  419. (state.typeVal == "booststation" ? "" : state.windturbineId),
  420. modelId: state.typeVal == "booststation" ? "" : state.modelId,
  421. components: state.components,
  422. description: state.description,
  423. begin: state.dateTime[0],
  424. end: state.dateTime[1],
  425. };
  426. const { data } = await alarm_history(params);
  427. query.pageTotal = data?.total;
  428. data?.ls?.forEach((ele) => {
  429. ele.isCloseName = ele.endts ? "已解除" : "未解除";
  430. ele.deviceTypeName = tableFilter(ele.deviceType);
  431. });
  432. state.tableData = data?.ls;
  433. };
  434. //报警类型变化
  435. const typechange = () => {
  436. state.isshowwindturbineName = state.typeVal == "booststation" ? false : true;
  437. };
  438. // 批量导出
  439. const export2Excel = async () => {
  440. let params = {
  441. pageNum: query.page,
  442. pageSize: query.pageTotal,
  443. alarmType: state.typeVal,
  444. stationid: state.stationId,
  445. deviceid: state.typeVal == "booststation" ? "" : state.windturbineId,
  446. modelId: state.modelId,
  447. components: state.components,
  448. description: state.description,
  449. begin: state.dateTime[0],
  450. end: state.dateTime[1],
  451. };
  452. if (state.dateTime[1] - state.dateTime[0] > 6 * 24 * 60 * 60 * 1000) {
  453. this.$message({
  454. message: "导出时间范围不能大于7天",
  455. type: "warning",
  456. });
  457. } else {
  458. let tableHeader = [];
  459. let tableKey = [];
  460. const { data } = await alarm_history(params);
  461. if (state.isshowwindturbineName) {
  462. tableHeader = state.tableHeader.map((item) => item.title);
  463. tableKey = state.tableHeader.map((item) => item.code);
  464. } else {
  465. tableHeader = state.tableHeader1.map((item) => item.title);
  466. tableKey = state.tableHeader1.map((item) => item.code);
  467. }
  468. const stationName = stationList.value.find((ele) => {
  469. return ele.id === state.stationId;
  470. }).name;
  471. const fileName = `${stationName} ${state.dateTime[0]} ~ ${state.dateTime[1]} 数据表`;
  472. outExportExcel(
  473. tableHeader,
  474. tableKey,
  475. data.ls.map((item) => {
  476. return {
  477. ...item,
  478. ts: formatTime(item.ts),
  479. rank: tableFilter(item.rank),
  480. deviceType: tableFilter(item.deviceType),
  481. };
  482. }),
  483. fileName
  484. );
  485. ElMessage.success(`导出成功!`);
  486. }
  487. };
  488. // 分页导航
  489. const handlePageChange = (val) => {
  490. query.page = val;
  491. getAlarmHistoryt();
  492. };
  493. // 时间格式化
  494. const formatTime = (val) => {
  495. return dayjs(val).format("YYYY-MM-DD HH:mm:ss");
  496. };
  497. // 格式化
  498. const obj = {
  499. 1: "低级",
  500. 2: "低中级",
  501. 3: "中级",
  502. 4: "中高级",
  503. 5: "高级",
  504. booststation: "升压站",
  505. custom: "自定义",
  506. windturbine: "风机",
  507. inverter: "光伏",
  508. };
  509. const messageTypeObj = {
  510. 1: "触发",
  511. 3: "解除",
  512. };
  513. const tableFilter = (val) => {
  514. return obj[val];
  515. };
  516. const messageTypeFilter = (val) => {
  517. return messageTypeObj[val];
  518. };
  519. </script>
  520. <style scoped lang="scss">
  521. .table-wrapper {
  522. height: calc(100% - 70px - 50px);
  523. background-color: #fff;
  524. margin-top: 10px;
  525. padding: 20px;
  526. .pagination-wrapper :deep {
  527. text-align: right;
  528. margin-top: 10px;
  529. .el-icon {
  530. width: unset;
  531. }
  532. }
  533. }
  534. </style>