数据可视化大屏
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

537 line
15KB

  1. import { Component, OnInit, ViewChild, inject } from '@angular/core';
  2. import { STColumn, STComponent } from '@delon/abc/st';
  3. import { SFSchema } from '@delon/form';
  4. import { CommonModule } from '@angular/common';
  5. import { ModalHelper, _HttpClient } from '@delon/theme';
  6. import { SHARED_IMPORTS } from '@shared';
  7. import { DataVCardComponent } from '../card/card.component';
  8. import * as echarts from 'echarts';
  9. import { AgGridAngular } from 'ag-grid-angular';
  10. import { DataVTitleComponent } from '../title/title.component';
  11. import { ColDef } from 'ag-grid-community'; // Column Definition Type Interface
  12. import { NzProgressModule } from 'ng-zorro-antd/progress';
  13. import { NzBadgeModule } from 'ng-zorro-antd/badge';
  14. import { Subscription, finalize } from 'rxjs';
  15. import { IMqttMessage, MqttService } from 'ngx-mqtt';
  16. import { ChartComponentComponent } from './chart-component/chart-component.component';
  17. import { NzListModule } from 'ng-zorro-antd/list';
  18. @Component({
  19. selector: 'app-data-v-s1',
  20. standalone: true,
  21. templateUrl: './s1.component.html',
  22. styleUrls: ['./s1.component.less'],
  23. imports: [CommonModule, NzBadgeModule, NzProgressModule, AgGridAngular, DataVCardComponent, DataVTitleComponent, NzListModule, ...SHARED_IMPORTS, ChartComponentComponent]
  24. })
  25. export class DataVS1Component implements OnInit {
  26. private readonly http = inject(_HttpClient);
  27. private readonly modal = inject(ModalHelper);
  28. chartConfig = {
  29. //每行数
  30. rowNumber: 1,
  31. //check 表格
  32. optionsCheckList: [
  33. { label: '全水', options: {}, checked: true },
  34. { label: '热值', options: {}, checked: true },
  35. { label: '全硫', options: {}, checked: false },
  36. { label: '内水', options: {}, checked: false },
  37. { label: '灰分', options: {}, checked: false },
  38. { label: '挥发分', options: {}, checked: false },
  39. ],
  40. //底部
  41. optionBottomList: [{}]
  42. };
  43. handleCheckedItems(checkedItems: { label: string, checked: boolean }[]) {
  44. console.log('当前选中的项目:', checkedItems);
  45. }
  46. chart_options = {}
  47. chart_options0 = {}
  48. chart_options1 = {}
  49. chart_options2 = {}
  50. chart_options3 = {}
  51. chart_options4 = {}
  52. rowData: object[] = [];
  53. colDefs1: ColDef[] = [
  54. { headerName: '时间', field: 'rwmc', flex: 1 },
  55. { headerName: '系统/设备', field: 'rwms', flex: 1 },
  56. { headerName: '操作描述', field: 'kssj', flex: 1 },
  57. { headerName: '操作人员', field: 'jhwcsj', flex: 1 }
  58. ];
  59. colDefs2: ColDef[] = [
  60. { headerName: '序号', field: 'rwmc', flex: 1 },
  61. { headerName: '时间', field: 'kssj', flex: 2 },
  62. { headerName: '任务描述', field: 'rwms', flex: 1 },
  63. { headerName: '等级', field: 'dqzt', flex: 1.5 }
  64. ];
  65. private subscription: Subscription;
  66. constructor(private _mqttService: MqttService) {
  67. this.subscription = this._mqttService.observe('s1').subscribe((message: IMqttMessage) => {
  68. const messagePayload = JSON.parse(message.payload.toString());
  69. console.log('Received message as object: ', messagePayload.msg);
  70. this.chart_options0 = messagePayload.msg;
  71. });
  72. }
  73. ngOnInit(): void {
  74. /** 获取服务器配置 */
  75. this.getServerConfig();
  76. for (var i = 1; i < 30; i++) {
  77. this.rowData.push({
  78. rwmc: '任务' + i, rwms: '任务描述' + i, kssj: '2024-1-' + i + ' 13:38:' + i * 11, jhwcsj: '2024-1-' + i + ' 13:38:' + i * 10, sfcq: '否',
  79. dqzt: "正常", dqjd: "节点" + i, sjwcsj: '2024-1-' + i + ' 13:38:' + i * 27, bjmc: "报警5", bjms: "报警描述5", bjsj: '2024-1-' + i + ' 13:38:' + i * 12,
  80. gzyy: "-", clff: "-", tzsj: '2024-1-' + i + ' 13:38:' + i * 19, zycd: "一般", tzmc: '系统提示', tznr: '账户登录', fj: "-", cz: "操作"
  81. });
  82. }
  83. var errorData = [];
  84. var categoryData = [];
  85. var barData = [];
  86. var dataCount = 100;
  87. for (var i = 0; i < dataCount; i++) {
  88. var val = Math.random() * 1000;
  89. categoryData.push('category' + i);
  90. errorData.push([
  91. i,
  92. echarts.number.round(Math.max(0, val - Math.random() * 100)),
  93. echarts.number.round(val + Math.random() * 80)
  94. ]);
  95. barData.push(echarts.number.round(val, 2));
  96. }
  97. this.chart_options = {
  98. backgroundColor: 'transparent',
  99. series: [
  100. {
  101. type: 'gauge',
  102. startAngle: 180,
  103. endAngle: 0,
  104. center: ['50%', '75%'],
  105. radius: '90%',
  106. min: 0,
  107. max: 1,
  108. splitNumber: 8,
  109. axisLine: {
  110. lineStyle: {
  111. width: 6,
  112. color: [
  113. [0.25, '#74FAFB'],
  114. [0.5, '#74FAFB'],
  115. [0.75, '#74FAFB'],
  116. [1, '#74FAFB']
  117. ]
  118. }
  119. },
  120. pointer: {
  121. icon: 'path://M12.8,0.7l12,40.1H0.7L12.8,0.7z',
  122. length: '12%',
  123. width: 20,
  124. offsetCenter: [0, '-60%'],
  125. itemStyle: {
  126. color: 'auto'
  127. }
  128. },
  129. axisTick: {
  130. length: 12,
  131. lineStyle: {
  132. color: 'auto',
  133. width: 2
  134. }
  135. },
  136. splitLine: {
  137. length: 20,
  138. lineStyle: {
  139. color: 'auto',
  140. width: 5
  141. }
  142. },
  143. axisLabel: {
  144. color: '#464646',
  145. fontSize: 20,
  146. distance: -60,
  147. rotate: 'tangential',
  148. formatter: function (value: any) {
  149. if (value === 0.875) {
  150. return '';
  151. } else if (value === 0.625) {
  152. return '';
  153. } else if (value === 0.375) {
  154. return '';
  155. } else if (value === 0.125) {
  156. return '';
  157. }
  158. return '';
  159. }
  160. },
  161. title: {
  162. offsetCenter: [0, '-10%'],
  163. fontSize: 20
  164. },
  165. detail: {
  166. fontSize: 30,
  167. offsetCenter: [0, '-5%'],
  168. valueAnimation: true,
  169. formatter: function (value: any) {
  170. return Math.round(value * 100) + '';
  171. },
  172. color: 'inherit'
  173. },
  174. data: [
  175. {
  176. value: 0.9,
  177. name: ''
  178. }
  179. ]
  180. }
  181. ]
  182. };
  183. this.chart_options0 = {
  184. backgroundColor: 'transparent',
  185. series: [
  186. {
  187. type: 'gauge',
  188. startAngle: 180,
  189. endAngle: 0,
  190. center: ['50%', '75%'],
  191. radius: '90%',
  192. min: 0,
  193. max: 1,
  194. splitNumber: 8,
  195. axisLine: {
  196. lineStyle: {
  197. width: 6,
  198. color: [
  199. [0.25, '#74FAFB'],
  200. [0.5, '#74FAFB'],
  201. [0.75, '#74FAFB'],
  202. [1, '#74FAFB']
  203. ]
  204. }
  205. },
  206. pointer: {
  207. icon: 'path://M12.8,0.7l12,40.1H0.7L12.8,0.7z',
  208. length: '12%',
  209. width: 20,
  210. offsetCenter: [0, '-60%'],
  211. itemStyle: {
  212. color: 'auto'
  213. }
  214. },
  215. axisTick: {
  216. length: 12,
  217. lineStyle: {
  218. color: 'auto',
  219. width: 2
  220. }
  221. },
  222. splitLine: {
  223. length: 20,
  224. lineStyle: {
  225. color: 'auto',
  226. width: 5
  227. }
  228. },
  229. axisLabel: {
  230. color: '#464646',
  231. fontSize: 20,
  232. distance: -60,
  233. rotate: 'tangential',
  234. formatter: function (value: any) {
  235. if (value === 0.875) {
  236. return '';
  237. } else if (value === 0.625) {
  238. return '';
  239. } else if (value === 0.375) {
  240. return '';
  241. } else if (value === 0.125) {
  242. return '';
  243. }
  244. return '';
  245. }
  246. },
  247. title: {
  248. offsetCenter: [0, '0%'],
  249. fontSize: 20
  250. },
  251. detail: {
  252. fontSize: 30,
  253. offsetCenter: [0, '-5%'],
  254. valueAnimation: true,
  255. formatter: function (value: any) {
  256. return Math.round(value * 100) + '';
  257. },
  258. color: 'inherit'
  259. },
  260. data: [
  261. {
  262. value: 0.97,
  263. name: ''
  264. }
  265. ]
  266. }
  267. ]
  268. };
  269. this.chart_options1 = {
  270. title: {
  271. textStyle: {
  272. color: "#ffffff"
  273. },
  274. text: '全水',
  275. subtext: '(kg/kg)',
  276. },
  277. legend: {
  278. data: ['测量值', '上限值', '下限值',]
  279. },
  280. calculable: true,
  281. xAxis: [
  282. {
  283. axisLine: {
  284. lineStyle: {
  285. color: [
  286. [0.25, '#74FAFB'],
  287. [0.5, '#74FAFB'],
  288. [0.75, '#74FAFB'],
  289. [1, '#74FAFB']
  290. ]
  291. }
  292. },
  293. position: 'bottom',
  294. type: 'category',
  295. data: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
  296. }
  297. ],
  298. yAxis: [
  299. {
  300. type: 'value'
  301. }
  302. ],
  303. series: [
  304. {
  305. name: '测量值',
  306. type: 'line',
  307. data: [100, 155, 139, 199, 220, 160, 120, 182.2, 150, 155, 160, 180],
  308. markPoint: {
  309. data: [
  310. { name: '最大值', value: 220, xAxis: 4, yAxis: 220 },
  311. { name: '最小值', value: 100, xAxis: 0, yAxis: 100 }
  312. ]
  313. },
  314. markLine: {
  315. data: [{ type: 'average', name: '平均值' }]
  316. }
  317. },
  318. {
  319. type: 'custom',
  320. name: 'error',
  321. itemStyle: {
  322. borderWidth: 1.5
  323. },
  324. renderItem: function (_params: any, api: any) {
  325. var xValue = api.value(0);
  326. var highPoint = api.coord([xValue, api.value(1)]);
  327. var lowPoint = api.coord([xValue, api.value(2)]);
  328. var halfWidth = api.size([1, 0])[0] * 0.1;
  329. var style = api.style({
  330. stroke: api.visual('color'),
  331. fill: undefined
  332. });
  333. return {
  334. type: 'group',
  335. children: [
  336. {
  337. type: 'line',
  338. transition: ['shape'],
  339. shape: {
  340. x1: highPoint[0] - halfWidth,
  341. y1: highPoint[1],
  342. x2: highPoint[0] + halfWidth,
  343. y2: highPoint[1]
  344. },
  345. style: style
  346. },
  347. {
  348. type: 'line',
  349. transition: ['shape'],
  350. shape: {
  351. x1: highPoint[0],
  352. y1: highPoint[1],
  353. x2: lowPoint[0],
  354. y2: lowPoint[1]
  355. },
  356. style: style
  357. },
  358. {
  359. type: 'line',
  360. transition: ['shape'],
  361. shape: {
  362. x1: lowPoint[0] - halfWidth,
  363. y1: lowPoint[1],
  364. x2: lowPoint[0] + halfWidth,
  365. y2: lowPoint[1]
  366. },
  367. style: style
  368. }
  369. ]
  370. };
  371. },
  372. encode: {
  373. x: 0,
  374. y: [1, 2]
  375. },
  376. data: errorData,
  377. z: 100
  378. }
  379. ]
  380. };
  381. this.chart_options2 = {
  382. title: {
  383. text: '热值',
  384. subtext: '(kg/kg)'
  385. },
  386. legend: {
  387. data: ['超差样数量', '不合格样数量']
  388. },
  389. xAxis: [
  390. {
  391. type: 'category',
  392. // prettier-ignore
  393. data: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
  394. }
  395. ],
  396. yAxis: [
  397. {
  398. type: 'value'
  399. }
  400. ],
  401. series: [
  402. {
  403. name: '超差样数量',
  404. type: 'line',
  405. data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3],
  406. markPoint: {
  407. data: [
  408. { type: 'max', name: 'Max' },
  409. { type: 'min', name: 'Min' }
  410. ]
  411. }
  412. },
  413. {
  414. name: '不合格样数量',
  415. type: 'bar',
  416. data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3],
  417. markPoint: {
  418. data: [
  419. { name: 'Max', value: 182.2, xAxis: 7, yAxis: 183 },
  420. { name: 'Min', value: 2.3, xAxis: 11, yAxis: 3 }
  421. ]
  422. },
  423. markLine: {
  424. data: [{ type: 'average', name: 'Avg' }]
  425. }
  426. }
  427. ],
  428. grid: {
  429. left: '3%',
  430. right: '3%',
  431. bottom: '3%',
  432. containLabel: true
  433. },
  434. toolbox: {
  435. show: false,
  436. feature: {
  437. dataView: { show: true, readOnly: false },
  438. magicType: { show: true, type: ['line', 'bar'] },
  439. restore: { show: true },
  440. saveAsImage: { show: true }
  441. }
  442. },
  443. calculable: true,
  444. };
  445. this.chart_options3 = {
  446. title: {
  447. text: '煤样超差率',
  448. },
  449. grid: {
  450. top: '10%',
  451. left: '3%',
  452. right: '4%',
  453. bottom: '3%',
  454. containLabel: true
  455. },
  456. xAxis: {
  457. type: 'category',
  458. data: ['超差样量', '总样量']
  459. },
  460. yAxis: {
  461. type: 'value'
  462. },
  463. series: [{
  464. data: [3, 16],
  465. label: {
  466. show: true,
  467. position: 'top',
  468. formatter: function (data: { value: string; }) {
  469. return data.value
  470. }
  471. },
  472. type: 'bar'
  473. }]
  474. };
  475. this.chart_options4 = {
  476. title: {
  477. text: '煤样合格率',
  478. left: 'center',
  479. },
  480. grid: {
  481. top: '10%',
  482. left: '3%',
  483. right: '4%',
  484. bottom: '3%',
  485. containLabel: true
  486. },
  487. xAxis: {
  488. type: 'category',
  489. data: ['超差样量', '总样量']
  490. },
  491. yAxis: {
  492. type: 'value'
  493. },
  494. series: [{
  495. data: [15, 16],
  496. type: 'bar',
  497. label: {
  498. show: true,
  499. position: 'top',
  500. formatter: function (data: { value: string; }) {
  501. return data.value
  502. }
  503. },
  504. }]
  505. };
  506. this.chartConfig.optionsCheckList[0].options = this.chart_options1;
  507. this.chartConfig.optionsCheckList[1].options = this.chart_options2;
  508. this.chartConfig.optionsCheckList[2].options = this.chart_options3;
  509. this.chartConfig.optionsCheckList[3].options = this.chart_options4;
  510. this.chartConfig.optionBottomList[0] = this.chart_options3;
  511. this.chartConfig.optionBottomList[1] = this.chart_options4;
  512. }
  513. public unsafePublish(topic: string, message: string): void {
  514. this._mqttService.unsafePublish(topic, message, { qos: 1, retain: true });
  515. }
  516. ngOnDestroy(): void {
  517. this.subscription.unsubscribe();
  518. }
  519. /**
  520. * 服务器获取配置
  521. */
  522. getServerConfig() {
  523. this.http
  524. .get('s1/',)
  525. .subscribe(res => {
  526. this.chartConfig = res['data'];
  527. });
  528. }
  529. }