DeviceHistoryEcharts.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. <template>
  2. <div class="charts-container">
  3. <a-form
  4. class="form-container"
  5. :model="historyParams"
  6. layout="inline"
  7. :label-col="{ style: { width: '100px' } }"
  8. :wrapper-col="{ span: 8 }"
  9. autocomplete="off"
  10. @submit.prevent="handleQuery"
  11. >
  12. <a-form-item v-if="isShowChildType" label="设备类型">
  13. <a-select v-model:value="deviceKind" style="width: 200px" @change="deviceKindChange">
  14. <a-select-option v-for="d in deviceKindOptions" :key="d.value" :value="d.value">{{ d.label }}</a-select-option>
  15. </a-select>
  16. </a-form-item>
  17. <a-form-item label="查询设备">
  18. <a-select v-model:value="historyParams.selectedDeviceId" style="width: 200px">
  19. <a-select-option v-for="d in deviceOptions" :key="d.deviceID" :value="d.deviceID">{{ d.strname }}</a-select-option>
  20. </a-select>
  21. </a-form-item>
  22. <a-form-item label="分析点位">
  23. <a-select v-model:value="historyParams.selectedValueCode" style="width: 200px" @change="handleChartColumn">
  24. <a-select-option v-for="item in chartsColumnList" :key="item.legend" :value="item.dataIndex">
  25. {{ item.legend }}
  26. </a-select-option>
  27. </a-select>
  28. </a-form-item>
  29. <a-form-item label="开始时间">
  30. <a-date-picker
  31. v-model:value="historyParams.startTime"
  32. style="width: 200px"
  33. show-time
  34. valueFormat="YYYY-MM-DD HH:mm:ss"
  35. placeholder="请选择开始时间"
  36. />
  37. </a-form-item>
  38. <a-form-item label="结束时间">
  39. <a-date-picker
  40. v-model:value="historyParams.endTime"
  41. style="width: 200px"
  42. show-time
  43. valueFormat="YYYY-MM-DD HH:mm:ss"
  44. placeholder="请选择结束时间"
  45. />
  46. </a-form-item>
  47. <a-form-item>
  48. <a-button type="primary" html-type="submit">查询</a-button>
  49. </a-form-item>
  50. </a-form>
  51. <Pagination
  52. v-if="isShowPagination"
  53. size="small"
  54. v-model:current="currentPage"
  55. v-model:page-size="pageSize"
  56. :total="total"
  57. :show-total="(total) => `共 ${total} 条`"
  58. style="position: absolute; z-index: 99; top: 2px; right: 30px"
  59. />
  60. <template v-if="chartData.length > 0 && historyParams.selectedValueCode">
  61. <BarAndLine
  62. class="device-history-echarts"
  63. :xAxisPropType="resultXAxisPropType"
  64. :dataSource="chartData"
  65. height="580px"
  66. :option="echartsOption"
  67. chartsType="history"
  68. :chartsColumns="currentChartsColumnList"
  69. />
  70. </template>
  71. <template v-else>
  72. <div class="no-data"> </div>
  73. </template>
  74. </div>
  75. </template>
  76. <script lang="ts">
  77. import { ref, defineComponent, watch, reactive, onMounted, watchEffect, inject } from 'vue';
  78. import BarAndLine from '/@/components/chart/BarAndLine.vue';
  79. import dayjs from 'dayjs';
  80. import { Select, Pagination, message } from 'ant-design-vue';
  81. import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
  82. import { getDictItemsByCode } from '/@/utils/dict';
  83. import { defHttp } from '/@/utils/http/axios';
  84. import { getDeviceHistoryData } from '@/views/vent/monitorManager/deviceMonitor/components/device/device.api';
  85. const deviceList = (params) => defHttp.post({ url: '/monitor/device', params });
  86. export default defineComponent({
  87. name: 'DeviceEcharts',
  88. components: { BarAndLine, Select, Pagination },
  89. props: {
  90. chartsColumns: {
  91. type: Array,
  92. default: () => [],
  93. },
  94. chartsColumnsHistory: {
  95. type: Array,
  96. default: () => [],
  97. },
  98. chartsColumnsType: {
  99. type: String,
  100. required: true,
  101. },
  102. dataSource: {
  103. type: Array,
  104. default: () => [],
  105. },
  106. deviceType: {
  107. type: String,
  108. required: true,
  109. },
  110. isShowChildType: {
  111. type: Boolean,
  112. default: false,
  113. },
  114. isShowPagination: {
  115. type: Boolean,
  116. default: false,
  117. },
  118. },
  119. setup(props) {
  120. const globalConfig = inject('globalConfig');
  121. const deviceKind = ref('');
  122. const chartsType = ref('history');
  123. const deviceId = ref('');
  124. const deviceOptions = ref([]);
  125. const historyParams = reactive({
  126. startTime: dayjs().startOf('date').format('YYYY-MM-DD HH:mm:ss').toString(),
  127. endTime: dayjs().format('YYYY-MM-DD HH:mm:ss').toString(),
  128. skip: '8',
  129. interval: '1h',
  130. selectedDeviceId: '',
  131. selectedValueCode: '',
  132. });
  133. const deviceKindOptions = ref([]);
  134. const chartsColumnList = ref([]);
  135. const currentChartsColumnList = ref([]);
  136. const resultXAxisPropType = ref('createtime');
  137. const chartData = ref<any[]>([]);
  138. const currentPage = ref<number>(1);
  139. const pageSize = ref<number>(20);
  140. const total = ref(0);
  141. const baseChartColumn = [
  142. {
  143. legend: '最大值',
  144. seriesName: '',
  145. ymax: 100,
  146. yname: '',
  147. linetype: 'line',
  148. yaxispos: 'left',
  149. color: '#DA3914',
  150. sort: 1,
  151. xRotate: 0,
  152. dataIndex: 'max',
  153. },
  154. {
  155. legend: '最小值', // average,max,median,min
  156. seriesName: '',
  157. ymax: 100,
  158. yname: '',
  159. linetype: 'line',
  160. yaxispos: 'left',
  161. color: '#00FFA8',
  162. sort: 1,
  163. xRotate: 0,
  164. dataIndex: 'min',
  165. },
  166. {
  167. legend: '平均值',
  168. seriesName: '',
  169. ymax: 100,
  170. yname: '',
  171. linetype: 'line',
  172. yaxispos: 'left',
  173. color: '#AE19FF',
  174. sort: 1,
  175. xRotate: 0,
  176. dataIndex: 'average',
  177. },
  178. {
  179. legend: '中位数',
  180. seriesName: '',
  181. ymax: 100,
  182. yname: '',
  183. linetype: 'line',
  184. yaxispos: 'left',
  185. color: '#749f83',
  186. sort: 1,
  187. xRotate: 0,
  188. dataIndex: 'median',
  189. },
  190. ];
  191. const echartsOption = {
  192. grid: {
  193. top: '80px',
  194. left: '20px',
  195. right: '20px',
  196. bottom: '5%',
  197. containLabel: true,
  198. },
  199. legend: {
  200. top: '0px',
  201. },
  202. toolbox: {
  203. feature: {},
  204. },
  205. xAxis: {
  206. axisLabel: {
  207. interval: 0,
  208. },
  209. },
  210. };
  211. const onChange = (pageNumber: number) => {
  212. console.log('Page: ', pageNumber);
  213. };
  214. const handleChartColumn = () => {
  215. const column = chartsColumnList.value.find((item) => item['dataIndex'] === historyParams.selectedValueCode);
  216. if (column) {
  217. const tempColumn = JSON.parse(JSON.stringify(column));
  218. tempColumn['legend'] = '实时值';
  219. tempColumn['sort'] = 1;
  220. tempColumn['linetype'] = 'line';
  221. tempColumn['yaxispos'] = 'left';
  222. tempColumn['yname'] = '';
  223. currentChartsColumnList.value = [tempColumn, ...baseChartColumn];
  224. }
  225. };
  226. const getDeviceList = async () => {
  227. const columnType = deviceKind.value ? deviceKind.value : props;
  228. const res = await deviceList({ devicetype: columnType, pagetype: 'normal' });
  229. // debugger;
  230. if (res['msgTxt'] && res['msgTxt'][0] && res['msgTxt'][0]['datalist']) {
  231. deviceOptions.value = res['msgTxt'][0]['datalist'];
  232. if (deviceOptions.value && deviceOptions.value.length > 0) historyParams.selectedDeviceId = deviceOptions.value[0]['deviceID'];
  233. }
  234. };
  235. const deviceKindChange = async (deviceTypeValue) => {
  236. const columnType = deviceTypeValue ? deviceTypeValue + '_chart' : props.deviceType + '_chart';
  237. chartsColumnList.value = getTableHeaderColumns(columnType) || [];
  238. if (chartsColumnList.value && chartsColumnList.value.length && chartsColumnList.value.length > 0) {
  239. historyParams.selectedValueCode = chartsColumnList.value[0].dataIndex;
  240. } else {
  241. historyParams.selectedValueCode = '';
  242. }
  243. handleChartColumn();
  244. await getDeviceList();
  245. };
  246. watch(
  247. () => props.deviceType,
  248. async (deviceTypeValue) => {
  249. const columnType = deviceKind.value ? deviceKind.value + '_chart' : deviceTypeValue + '_chart';
  250. deviceKindOptions.value = getDictItemsByCode(deviceTypeValue + 'kind');
  251. chartsColumnList.value = getTableHeaderColumns(columnType);
  252. if (chartsColumnList.value && chartsColumnList.value.length && chartsColumnList.value.length > 0) {
  253. historyParams.selectedValueCode = chartsColumnList.value[0].dataIndex;
  254. }
  255. deviceKind.value = deviceKindOptions.value[0].value;
  256. handleChartColumn();
  257. await getDeviceList();
  258. },
  259. { immediate: true }
  260. );
  261. async function handleQuery() {
  262. if (!historyParams.selectedDeviceId || !historyParams.selectedValueCode) {
  263. message.warning('请选择设备和分析点位');
  264. return;
  265. }
  266. try {
  267. chartData.value = [];
  268. const res = await getDeviceHistoryData({
  269. deviceId: historyParams.selectedDeviceId,
  270. valueCode: historyParams.selectedValueCode,
  271. startTime: historyParams.startTime,
  272. endTime: historyParams.endTime,
  273. });
  274. if (res && Array.isArray(res.list)) {
  275. // average,max,median,min
  276. chartData.value = res.list.map((item) => ({
  277. ...item,
  278. [historyParams.selectedValueCode]: Number(item.val),
  279. average: Number(res.average),
  280. max: Number(res.max),
  281. median: Number(res.median),
  282. min: Number(res.min),
  283. }));
  284. } else {
  285. chartData.value = [];
  286. }
  287. } catch (e) {
  288. chartData.value = [];
  289. }
  290. }
  291. onMounted(async () => {
  292. await getDeviceList();
  293. await handleQuery();
  294. });
  295. return {
  296. chartsType,
  297. deviceId,
  298. chartData,
  299. historyParams,
  300. deviceOptions,
  301. resultXAxisPropType,
  302. currentPage,
  303. pageSize,
  304. total,
  305. echartsOption,
  306. onChange,
  307. globalConfig,
  308. deviceKind,
  309. chartsColumnList,
  310. deviceKindOptions,
  311. currentChartsColumnList,
  312. handleQuery,
  313. handleChartColumn,
  314. deviceKindChange,
  315. };
  316. },
  317. });
  318. </script>
  319. <style lang="less">
  320. :deep(.vent-select-dropdown) {
  321. color: #000 !important;
  322. .vent-select-item {
  323. color: #000 !important;
  324. }
  325. }
  326. label {
  327. color: #fff !important;
  328. }
  329. </style>
  330. <style lang="less" scoped>
  331. @import '/@/design/theme.less';
  332. .charts-container {
  333. --image-no-camera_bg: url('/@/assets/images/vent/no-data.png');
  334. position: relative;
  335. height: 100%;
  336. .form-container {
  337. display: flex;
  338. // justify-content: center;
  339. margin-top: 50px !important;
  340. margin-bottom: 80px !important;
  341. }
  342. .charts-box {
  343. width: 100%;
  344. height: 100%;
  345. position: absolute;
  346. bottom: 0;
  347. top: 0px;
  348. }
  349. .@{ventSpace}-picker,
  350. .@{ventSpace}-select-selector {
  351. background: #00000017 !important;
  352. border: 1px solid @vent-form-item-border !important;
  353. input,
  354. .@{ventSpace}-select-selection-item,
  355. .@{ventSpace}-picker-suffix {
  356. color: #fff !important;
  357. }
  358. .@{ventSpace}-select-selection-placeholder {
  359. color: #b7b7b7 !important;
  360. }
  361. }
  362. .@{ventSpace}-select-arrow,
  363. .@{ventSpace}-picker-separator {
  364. color: #fff !important;
  365. }
  366. }
  367. .no-data {
  368. width: 100%;
  369. height: 475px;
  370. padding-top: 80px;
  371. background: var(--image-no-camera_bg) no-repeat;
  372. background-position: center;
  373. display: flex;
  374. justify-content: center;
  375. font-size: 50px;
  376. color: var(--vent-text-base);
  377. }
  378. :deep(.@{ventSpace}-select-dropdown) {
  379. color: #000 !important;
  380. .@{ventSpace}-select-item {
  381. color: #000 !important;
  382. }
  383. }
  384. </style>