right.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <template>
  2. <div>
  3. <CusModule title="告警信息">
  4. <BaseChart height="200px" width="100%" :option="pieOptions"/>
  5. <div class="custom-table">
  6. <el-table :data="tableData" class="customer-table" style="width: 100%" height="650">
  7. <el-table-column type="index" label="序号" width="60" align="center"/>
  8. <el-table-column prop="type" label="报警类型" align="center">
  9. <template #default="{ row }">
  10. <dict-tag :options="dict.type.alarm_type" :value="row.alarmType"/>
  11. </template>
  12. </el-table-column>
  13. <el-table-column prop="alarmMsg" label="报警内容" align="center"/>
  14. <el-table-column prop="alarmTime" label="告警事件" align="center"/>
  15. </el-table>
  16. <el-pagination :current-page="page.pageIndex" :page-size="page.pageSize" :small="'small'" :background="true"
  17. layout="total, prev, pager, next, jumper" :total="page.total" @size-change="handleSizeChange"
  18. @current-change="handleCurrentChange"/>
  19. </div>
  20. </CusModule>
  21. </div>
  22. </template>
  23. <script>
  24. import CusModule from '../components/CusModule.vue';
  25. import BaseChart from '@/components/BaseChart/index.vue'
  26. import {mapState} from 'vuex';
  27. import {fetchCntDateAlarmType, listAlarmInfo} from "@/api/alarm/alarm-info";
  28. import {ALARM_STATE} from "@/enums/alarm";
  29. import {ApiCode} from "@/api/apiEmums";
  30. const colorDic = {
  31. 3: {
  32. itemStyle: {
  33. color: '#FF4949'
  34. },
  35. },
  36. 2: {
  37. itemStyle: {
  38. color: '#FFBD1F'
  39. },
  40. },
  41. 1: {
  42. itemStyle: {
  43. color: '#1990FF'
  44. },
  45. },
  46. 4: {
  47. itemStyle: {
  48. color: '#2fe30f'
  49. },
  50. },
  51. 5: {
  52. itemStyle: {
  53. color: '#737386'
  54. },
  55. },
  56. 6: {
  57. itemStyle: {
  58. color: 'rgba(232,244,255,0.58)'
  59. },
  60. }
  61. }
  62. export default {
  63. name: 'DeviceRight',
  64. dicts: ['alarm_type'],
  65. data() {
  66. return {
  67. pieData: [],
  68. tableData: [],
  69. page: {
  70. pageIndex: 1,
  71. pageSize: 10,
  72. total: 0
  73. }
  74. }
  75. },
  76. components: {
  77. CusModule,
  78. BaseChart,
  79. },
  80. computed: {
  81. ...mapState('userState', ['areaType']),
  82. pieOptions() {
  83. return this.getPie3D(this.pieData, 0)// 可做为调整内环大小 0为实心圆饼图,大于0 小于1 为圆环
  84. }
  85. },
  86. watch: {
  87. areaType() {
  88. this.getPieData()
  89. }
  90. },
  91. mounted() {
  92. this.getPieData()
  93. this.timer && clearInterval(this.timer)
  94. this.timer = setInterval(() => {
  95. this.getPieData()
  96. }, 60000 * 3)
  97. },
  98. beforeDestroy() {
  99. this.timer && clearInterval(this.timer)
  100. },
  101. methods: {
  102. handleSizeChange(size) {
  103. this.page.pageIndex = 1
  104. this.page.pageSize = size
  105. this.getRealTimeAlarm()
  106. },
  107. handleCurrentChange(index) {
  108. this.page.pageIndex = index
  109. this.getRealTimeAlarm()
  110. },
  111. getPieData() {
  112. this.getDateAlarmType()
  113. this.getRealTimeAlarm()
  114. },
  115. getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
  116. const midRatio = (startRatio + endRatio) / 2;
  117. const startRadian = startRatio * Math.PI * 2;
  118. const endRadian = endRatio * Math.PI * 2;
  119. const midRadian = midRatio * Math.PI * 2;
  120. // 如果只有一个扇形,则不实现选中效果。
  121. if (startRatio === 0 && endRatio === 1) {
  122. isSelected = false;
  123. }
  124. k = typeof k !== 'undefined' ? k : 1 / 3;
  125. const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
  126. const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
  127. // 鼠标滑过时外环放大大小
  128. const hoverRate = isHovered ? 1.05 : 1;
  129. // 返回曲面参数方程
  130. return {
  131. u: {
  132. min: -Math.PI,
  133. max: Math.PI * 3,
  134. step: Math.PI / 32,
  135. },
  136. v: {
  137. min: 0,
  138. max: Math.PI * 2,
  139. step: Math.PI / 20,
  140. },
  141. x(u, v) {
  142. if (u < startRadian) {
  143. return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
  144. }
  145. if (u > endRadian) {
  146. return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
  147. }
  148. return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
  149. },
  150. y(u, v) {
  151. if (u < startRadian) {
  152. return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
  153. }
  154. if (u > endRadian) {
  155. return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
  156. }
  157. return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
  158. },
  159. z(u, v) {
  160. if (u < -Math.PI * 0.5) {
  161. return Math.sin(u);
  162. }
  163. if (u > Math.PI * 2.5) {
  164. return Math.sin(u) * h * 0.1;
  165. }
  166. // 当前图形的高度是Z根据h(每个value的值决定的)
  167. return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
  168. },
  169. };
  170. },
  171. getPie3D(pieData, internalDiameterRatio) {
  172. const series = [];
  173. let sumValue = 0;
  174. let startValue = 0;
  175. let endValue = 0;
  176. const legendData = [];
  177. const k =
  178. typeof internalDiameterRatio !== 'undefined'
  179. ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
  180. : 1 / 3;
  181. for (let i = 0; i < pieData.length; i += 1) {
  182. sumValue += pieData[i].value;
  183. const seriesItem = {
  184. name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
  185. type: 'surface',
  186. parametric: true,
  187. wireframe: {
  188. show: false,
  189. },
  190. pieData: pieData[i],
  191. pieStatus: {
  192. selected: false,
  193. hovered: false,
  194. k,
  195. },
  196. };
  197. if (typeof pieData[i].itemStyle !== 'undefined') {
  198. const {itemStyle} = pieData[i];
  199. // eslint-disable-next-line no-unused-expressions
  200. typeof pieData[i].itemStyle.color !== 'undefined' ? (itemStyle.color = pieData[i].itemStyle.color) : null;
  201. // eslint-disable-next-line no-unused-expressions
  202. typeof pieData[i].itemStyle.opacity !== 'undefined'
  203. ? (itemStyle.opacity = pieData[i].itemStyle.opacity)
  204. : null;
  205. seriesItem.itemStyle = itemStyle;
  206. }
  207. series.push(seriesItem);
  208. }
  209. for (let i = 0; i < series.length; i += 1) {
  210. endValue = startValue + series[i].pieData.value;
  211. series[i].pieData.startRatio = startValue / sumValue;
  212. series[i].pieData.endRatio = endValue / sumValue;
  213. series[i].parametricEquation = this.getParametricEquation(
  214. series[i].pieData.startRatio,
  215. series[i].pieData.endRatio,
  216. false,
  217. false,
  218. k,
  219. 10//在此处传入饼图初始高度h
  220. );
  221. startValue = endValue;
  222. legendData.push(series[i].name);
  223. }
  224. // 准备待返回的配置项,把准备好的series 传入。
  225. const option = {
  226. legend: {
  227. orient: "vertical",
  228. right: '8%',
  229. top: '22%',
  230. textStyle: {
  231. color: "#fff",
  232. fontSize: 14,
  233. },
  234. icon: 'circle',
  235. formatter: (name) => {
  236. if (this.pieData.length) {
  237. const item = this.pieData.filter((item) => item.name === name)[0];
  238. let str = `${name}(${item.value}) ${item.proportion}%`
  239. return str
  240. }
  241. },
  242. },
  243. tooltip: {
  244. formatter: (params) => {
  245. let str = `${params.marker}${params.seriesName}:${this.pieData[params.seriesIndex].value}` + '个,占比:' + `${this.pieData[params.seriesIndex].proportion}` + '%'
  246. return str;
  247. },
  248. },
  249. xAxis3D: {
  250. min: -1,
  251. max: 1,
  252. },
  253. yAxis3D: {
  254. min: -1,
  255. max: 1,
  256. },
  257. zAxis3D: {
  258. min: -1,
  259. max: 1,
  260. },
  261. grid3D: {
  262. show: false,
  263. boxHeight: 25,//修改立体饼图的高度
  264. top: '-10%',
  265. left: '-20%',
  266. viewControl: {
  267. // 3d效果可以放大、旋转等,
  268. alpha: 35,//饼图翻转的程度
  269. beta: 30,
  270. rotateSensitivity: 1,
  271. zoomSensitivity: 0,
  272. panSensitivity: 0,
  273. autoRotate: true,//是否自动旋转
  274. distance: 300,//距离越小看到的饼图越大
  275. },
  276. },
  277. series,
  278. };
  279. return option;
  280. },
  281. async getDateAlarmType() {
  282. const {data} = await fetchCntDateAlarmType(
  283. {
  284. areaCode: this.areaType,
  285. }
  286. )
  287. if (!data) {
  288. return
  289. }
  290. const pieData = data.map(item => {
  291. return {
  292. name: this.dict.label.alarm_type[item.alarmType],
  293. alarmType: item.alarmType,
  294. value: item.cnt,
  295. proportion: item.proportion,
  296. }
  297. })
  298. let totalValue = pieData.reduce((acc, cur) => acc + cur.value, 0);
  299. this.pieData = pieData.map(item => {
  300. item.proportion = (item.value / totalValue * 100).toFixed(2)
  301. let color = colorDic[item.alarmType] || colorDic['6']
  302. return {
  303. ...item,
  304. ...color
  305. }
  306. })
  307. },
  308. async getRealTimeAlarm() {
  309. let result = [];
  310. const {
  311. code,
  312. rows,
  313. total,
  314. } = await listAlarmInfo({
  315. pageNum: this.page.pageIndex,
  316. pageSize: this.page.pageSize,
  317. areaCode: this.areaType,
  318. alarmStateList: [
  319. ALARM_STATE.new.value, ALARM_STATE.disposing.value,
  320. ]
  321. });
  322. if (ApiCode.SUCCESS === code && rows && rows.length > 0) {
  323. result = rows;
  324. }
  325. this.tableData = result;
  326. this.page.total = total
  327. },
  328. }
  329. }
  330. </script>
  331. <style lang='scss' scoped>
  332. @import url("../index.scss");
  333. .custom-table {
  334. position: relative;
  335. /* 去掉table所有边框 */
  336. ::v-deep.el-table--border th.el-table__cell,
  337. ::v-deep.el-table td.el-table__cell {
  338. border-bottom: 1px solid #204D74;
  339. }
  340. ::v-deep .el-table th.is-leaf {
  341. /* 去除上边框 */
  342. border: none;
  343. }
  344. ::v-deep.el-table--border .el-table__cell {
  345. border-right: none !important;
  346. }
  347. ::v-deep.el-table--group,
  348. .el-table--border {
  349. border: none !important;
  350. }
  351. ::v-deep.el-table::before,
  352. .el-table--group::after,
  353. .el-table--border::after {
  354. background-color: unset !important;
  355. }
  356. // 去掉el-table的所有背景颜色以及所有hover的颜色
  357. ::v-deep.el-table,
  358. ::v-deep.el-table .el-table__header-wrapper th,
  359. ::v-deep.el-table--border {
  360. background-color: transparent;
  361. color: #07e3f9;
  362. }
  363. ::v-deep.el-table tr,
  364. ::v-deep.el-table__body tr:hover > td {
  365. background-color: transparent !important;
  366. }
  367. ::v-deep .el-table__header-wrapper thead th {
  368. background: #1B4B6D !important;
  369. color: #07e3f9;
  370. }
  371. ::v-deep .el-table__body-wrapper td {
  372. color: #B3E3E8;
  373. background: #0A2431;
  374. }
  375. }
  376. .el-pagination {
  377. margin-top: 10px;
  378. }
  379. ::v-deep .el-pagination__total,
  380. ::v-deep .el-pagination__jump {
  381. color: #fff;
  382. }
  383. </style>