| | |
| | | ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] |
| | | ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] |
| | | ElButton: typeof import('element-plus/es')['ElButton'] |
| | | ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'] |
| | | ElCalendar: typeof import('element-plus/es')['ElCalendar'] |
| | | ElCard: typeof import('element-plus/es')['ElCard'] |
| | | ElCascader: typeof import('element-plus/es')['ElCascader'] |
| | | ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] |
| | | ElCheckboxButton: typeof import('element-plus/es')['ElCheckboxButton'] |
| | | ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] |
| | | ElCol: typeof import('element-plus/es')['ElCol'] |
| | | ElCollapse: typeof import('element-plus/es')['ElCollapse'] |
| | |
| | | ElDialog: typeof import('element-plus/es')['ElDialog'] |
| | | ElDivider: typeof import('element-plus/es')['ElDivider'] |
| | | ElDrawer: typeof import('element-plus/es')['ElDrawer'] |
| | | ElDropdown: typeof import('element-plus/es')['ElDropdown'] |
| | | ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] |
| | | ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] |
| | | ElEmpty: typeof import('element-plus/es')['ElEmpty'] |
| | | ElForm: typeof import('element-plus/es')['ElForm'] |
| | | ElFormItem: typeof import('element-plus/es')['ElFormItem'] |
| | |
| | | ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] |
| | | ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] |
| | | ElOption: typeof import('element-plus/es')['ElOption'] |
| | | ElPageHeader: typeof import('element-plus/es')['ElPageHeader'] |
| | | ElPagination: typeof import('element-plus/es')['ElPagination'] |
| | | ElPopover: typeof import('element-plus/es')['ElPopover'] |
| | | ElRadio: typeof import('element-plus/es')['ElRadio'] |
| | |
| | | ElTooltip: typeof import('element-plus/es')['ElTooltip'] |
| | | ElTree: typeof import('element-plus/es')['ElTree'] |
| | | ElUpload: typeof import('element-plus/es')['ElUpload'] |
| | | FormCol: typeof import('./src/components/layout/FormCol.vue')['default'] |
| | | FYDownloadTableButton: typeof import('./src/components/button/FYDownloadTableButton.vue')['default'] |
| | | FYForm: typeof import('./src/components/form/FYForm.vue')['default'] |
| | | FYImageSelectDialog: typeof import('./src/components/FYImageSelectDialog.vue')['default'] |
| | |
| | | FYReconfrimButton: typeof import('./src/components/button/FYReconfrimButton.vue')['default'] |
| | | FYSearchBar: typeof import('./src/components/search-option/FYSearchBar.vue')['default'] |
| | | FYTable: typeof import('./src/components/table/FYTable.vue')['default'] |
| | | IEpDataLine: typeof import('~icons/ep/data-line')['default'] |
| | | IEpDownload: typeof import('~icons/ep/download')['default'] |
| | | IEpGrid: typeof import('~icons/ep/grid')['default'] |
| | | IEpInfoFilled: typeof import('~icons/ep/info-filled')['default'] |
| | | IEpWarning: typeof import('~icons/ep/warning')['default'] |
| | | ItemDevice: typeof import('./src/components/list-item/ItemDevice.vue')['default'] |
| | | ItemMonitorObj: typeof import('./src/components/list-item/ItemMonitorObj.vue')['default'] |
| | | ItemScene: typeof import('./src/components/list-item/ItemScene.vue')['default'] |
| | |
| | | const ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] |
| | | const ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] |
| | | const ElButton: typeof import('element-plus/es')['ElButton'] |
| | | const ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'] |
| | | const ElCalendar: typeof import('element-plus/es')['ElCalendar'] |
| | | const ElCard: typeof import('element-plus/es')['ElCard'] |
| | | const ElCascader: typeof import('element-plus/es')['ElCascader'] |
| | | const ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] |
| | | const ElCheckboxButton: typeof import('element-plus/es')['ElCheckboxButton'] |
| | | const ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] |
| | | const ElCol: typeof import('element-plus/es')['ElCol'] |
| | | const ElCollapse: typeof import('element-plus/es')['ElCollapse'] |
| | |
| | | const ElDialog: typeof import('element-plus/es')['ElDialog'] |
| | | const ElDivider: typeof import('element-plus/es')['ElDivider'] |
| | | const ElDrawer: typeof import('element-plus/es')['ElDrawer'] |
| | | const ElDropdown: typeof import('element-plus/es')['ElDropdown'] |
| | | const ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] |
| | | const ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] |
| | | const ElEmpty: typeof import('element-plus/es')['ElEmpty'] |
| | | const ElForm: typeof import('element-plus/es')['ElForm'] |
| | | const ElFormItem: typeof import('element-plus/es')['ElFormItem'] |
| | |
| | | const ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] |
| | | const ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] |
| | | const ElOption: typeof import('element-plus/es')['ElOption'] |
| | | const ElPageHeader: typeof import('element-plus/es')['ElPageHeader'] |
| | | const ElPagination: typeof import('element-plus/es')['ElPagination'] |
| | | const ElPopover: typeof import('element-plus/es')['ElPopover'] |
| | | const ElRadio: typeof import('element-plus/es')['ElRadio'] |
| | |
| | | const ElTooltip: typeof import('element-plus/es')['ElTooltip'] |
| | | const ElTree: typeof import('element-plus/es')['ElTree'] |
| | | const ElUpload: typeof import('element-plus/es')['ElUpload'] |
| | | const FormCol: typeof import('./src/components/layout/FormCol.vue')['default'] |
| | | const FYDownloadTableButton: typeof import('./src/components/button/FYDownloadTableButton.vue')['default'] |
| | | const FYForm: typeof import('./src/components/form/FYForm.vue')['default'] |
| | | const FYImageSelectDialog: typeof import('./src/components/FYImageSelectDialog.vue')['default'] |
| | |
| | | const FYReconfrimButton: typeof import('./src/components/button/FYReconfrimButton.vue')['default'] |
| | | const FYSearchBar: typeof import('./src/components/search-option/FYSearchBar.vue')['default'] |
| | | const FYTable: typeof import('./src/components/table/FYTable.vue')['default'] |
| | | const IEpDataLine: typeof import('~icons/ep/data-line')['default'] |
| | | const IEpDownload: typeof import('~icons/ep/download')['default'] |
| | | const IEpGrid: typeof import('~icons/ep/grid')['default'] |
| | | const IEpInfoFilled: typeof import('~icons/ep/info-filled')['default'] |
| | | const IEpWarning: typeof import('~icons/ep/warning')['default'] |
| | | const ItemDevice: typeof import('./src/components/list-item/ItemDevice.vue')['default'] |
| | | const ItemMonitorObj: typeof import('./src/components/list-item/ItemMonitorObj.vue')['default'] |
| | | const ItemScene: typeof import('./src/components/list-item/ItemScene.vue')['default'] |
| | |
| | | </head> |
| | | <body> |
| | | <div id="app"></div> |
| | | <script type="text/javascript"> |
| | | window._AMapSecurityConfig = { |
| | | serviceHost: 'https://fyami.com.cn:449/_AMapService', |
| | | } |
| | | </script> |
| | | <script type="module" src="/src/main.js"></script> |
| | | </body> |
| | | </html> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-col :xs="cols.xs" :sm="cols.sm" :md="cols.md" :lg="cols.lg" :xl="cols.xl"> |
| | | <slot></slot> |
| | | </el-col> |
| | | </template> |
| | | |
| | | <script> |
| | | import { formResponsiveCols } from '@/style/layout' |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | cols: formResponsiveCols(), |
| | | } |
| | | }, |
| | | } |
| | | </script> |
| | | <style scoped></style> |
| | |
| | | { |
| | | path: '/index/monitor/data-dashboard', |
| | | icon: 'solar:window-frame-line-duotone', |
| | | name: 'æ°æ®çæ¿', |
| | | name: '污ææå¿', |
| | | }, |
| | | { |
| | | path: '/index/monitor/data-exception', |
| | | icon: 'solar:siren-line-duotone', |
| | | name: 'å¼å¸¸åæ', |
| | | name: 'çæµé¢è¦', |
| | | }, |
| | | { |
| | | path: '/index/monitor/data-analysis-all', |
| | | icon: 'solar:presentation-graph-line-duotone', |
| | | name: 'è¦ç´ åæ', |
| | | children: [ |
| | | { |
| | | path: '/index/monitor/data-analysis-all', |
| | | icon: 'solar:structure-line-duotone', |
| | | name: 'å
¨è¦ç´ åæ', |
| | | }, |
| | | { |
| | | icon: 'solar:round-graph-line-duotone', |
| | | name: 'åè¦ç´ åæ', |
| | | children: [ |
| | | { |
| | | path: '/index/monitor/data-analysis-concentration', |
| | | icon: 'solar:graph-new-line-duotone', |
| | | name: 'æ²¹çæµåº¦', |
| | | }, |
| | | { |
| | | path: '/index/monitor/data-analysis-online-rate', |
| | | icon: 'solar:graph-new-line-duotone', |
| | | name: 'å¨çº¿ç', |
| | | }, |
| | | { |
| | | path: '/index/monitor/data-analysis-open-rate', |
| | | icon: 'solar:graph-new-line-duotone', |
| | | name: 'å¼å¯ç', |
| | | }, |
| | | { |
| | | path: '/index/monitor/data-analysis-over-standard-rate', |
| | | icon: 'solar:graph-new-line-duotone', |
| | | name: 'è¶
æ ç', |
| | | }, |
| | | ], |
| | | }, |
| | | ], |
| | | name: 'æ°æ®åæ', |
| | | }, |
| | | // { |
| | | // icon: 'solar:presentation-graph-line-duotone', |
| | | // name: 'æ°æ®åæ', |
| | | // children: [ |
| | | // { |
| | | // path: '/index/monitor/data-analysis-all', |
| | | // icon: 'solar:structure-line-duotone', |
| | | // name: 'å
¨è¦ç´ åæ', |
| | | // }, |
| | | // { |
| | | // icon: 'solar:round-graph-line-duotone', |
| | | // name: 'åè¦ç´ åæ', |
| | | // children: [ |
| | | // { |
| | | // path: '/index/monitor/data-analysis-concentration', |
| | | // icon: 'solar:graph-new-line-duotone', |
| | | // name: 'æ²¹çæµåº¦', |
| | | // }, |
| | | // { |
| | | // path: '/index/monitor/data-analysis-online-rate', |
| | | // icon: 'solar:graph-new-line-duotone', |
| | | // name: 'å¨çº¿ç', |
| | | // }, |
| | | // { |
| | | // path: '/index/monitor/data-analysis-open-rate', |
| | | // icon: 'solar:graph-new-line-duotone', |
| | | // name: 'å¼å¯ç', |
| | | // }, |
| | | // { |
| | | // path: '/index/monitor/data-analysis-over-standard-rate', |
| | | // icon: 'solar:graph-new-line-duotone', |
| | | // name: 'è¶
æ ç', |
| | | // }, |
| | | // ], |
| | | // }, |
| | | // ], |
| | | // }, |
| | | { |
| | | path: '/index/monitor/data-history', |
| | | icon: 'solar:graph-new-line-duotone', |
| | | name: 'å岿°æ®', |
| | | }, |
| | | ], |
| | | }, |
| | |
| | | { |
| | | name: 'scene-info', |
| | | path: 'scene-info', |
| | | component: () => import('@/views/inspection/scene/SceneInfo.vue'), |
| | | component: () => import('@/views/inspection/scenenew/UserInfo.vue'), |
| | | }, |
| | | { |
| | | //è´¦æ·ç¼è¾ |
| | | name: 'scene-info-edit', |
| | | path: 'scene-info-edit/:userId', |
| | | component: () => import('@/views/inspection/scenenew/UserEdit.vue'), |
| | | }, |
| | | { |
| | | name: 'pro-check', |
| | |
| | | <!-- å¼å¸¸æ
åµç æçº¿å¾ç»ä»¶ |
| | | åç»ä»¶æåºæ¬çæ ·å¼ |
| | | åç»ä»¶æåºæ¬çæ ·å¼ |
| | | 使ç¨åä¸ä¸ªå¾å½¢å®ä¾ï¼æ¥åç¶ç»ä»¶ä¼ å
¥çæçº¿å¾option |
| | | **ç¶ç»ä»¶ |
| | | <ExceptionTypeLineChart |
| | |
| | | ></ExceptionTypeLineChart> |
| | | --> |
| | | <template> |
| | | <div id="main" class="line-chart"></div> |
| | | <div id="main" class="line-chart"></div> |
| | | </template> |
| | | |
| | | <script> |
| | | import * as echarts from 'echarts'; |
| | | import * as echarts from 'echarts' |
| | | |
| | | export default { |
| | | props: { |
| | | option:{ |
| | | type:Object, |
| | | default(){ |
| | | option: { |
| | | type: Object, |
| | | default() { |
| | | return {} |
| | | } |
| | | }, |
| | | }, |
| | | isOpenDialog:{ |
| | | type:Boolean |
| | | isOpenDialog: { |
| | | type: Boolean, |
| | | }, |
| | | |
| | | }, |
| | | data() { |
| | | return { |
| | | chart: null |
| | | }; |
| | | chart: null, |
| | | } |
| | | }, |
| | | mounted() { |
| | | // è·å页é¢å®½åº¦çä¸å |
| | | |
| | | this.initChart(); |
| | | // è·å页é¢å®½åº¦çä¸å |
| | | |
| | | this.initChart() |
| | | this.chart.clear |
| | | this.chart.setOption(this.option,true) |
| | | window.addEventListener('resize', this.resizeChart); |
| | | this.chart.setOption(this.option, true) |
| | | window.addEventListener('resize', this.resizeChart) |
| | | }, |
| | | watch: { |
| | | option(){ |
| | | option() { |
| | | // this.chart.dispose; |
| | | // this.initChart(); |
| | | // this.chart.clear |
| | | // ä¸ä¸ä¹åçoptionè¿è¡åå¹¶ |
| | | this.chart.setOption(this.option,true) |
| | | this.chart.setOption(this.option, true) |
| | | }, |
| | | isOpenDialog(){ |
| | | window.addEventListener('resize', this.resizeChart); |
| | | isOpenDialog() { |
| | | window.addEventListener('resize', this.resizeChart) |
| | | }, |
| | | }, |
| | | beforeUnmount() { |
| | | if (this.chart) { |
| | | this.chart.dispose; |
| | | this.chart.dispose |
| | | } |
| | | }, |
| | | methods: { |
| | | initChart() { |
| | | // å建echartså®ä¾ |
| | | this.chart = echarts.init(document.getElementById('main')); |
| | | this.chart = echarts.init(document.getElementById('main')) |
| | | // å®ä¹å¾è¡¨çé
ç½®é¡¹åæ°æ® |
| | | const option = { |
| | | grid: { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | containLabel: true, |
| | | }, |
| | | tooltip: {}, |
| | | toolbox: { |
| | |
| | | // yAxisIndex: 'none' |
| | | // }, |
| | | // ä¿å为å¾ç |
| | | saveAsImage: {} |
| | | } |
| | | saveAsImage: {}, |
| | | }, |
| | | }, |
| | | xAxis: { |
| | | type: 'time', |
| | |
| | | { |
| | | name: 'æ²¹çæµåº¦', |
| | | type: 'line', |
| | | data: [] |
| | | } |
| | | ] |
| | | }; |
| | | data: [], |
| | | }, |
| | | ], |
| | | } |
| | | // 使ç¨åæå®çé
ç½®é¡¹åæ°æ®æ¾ç¤ºå¾è¡¨ |
| | | this.chart.setOption(option, true); |
| | | this.chart.setOption(option, true) |
| | | }, |
| | | |
| | | // è·é¡µé¢ååºå¼åå |
| | | resizeChart() { |
| | | this.$nextTick(() => { |
| | | if (this.chart) { |
| | | this.chart.resize(); |
| | | this.chart.resize() |
| | | } |
| | | }); |
| | | }) |
| | | // this.chart.resize(); |
| | | } |
| | | } |
| | | }; |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | |
| | | <style> |
| | | .line-chart { |
| | | width:920px; |
| | | width: 100%; |
| | | height: 300px; |
| | | margin-bottom: 20px; |
| | | /* margin-left: 10px; */ |
| | |
| | | <!-- æ¥ææ¶é´éæ©å¨ç»ä»¶ |
| | | <!-- æ¥ææ¶é´éæ©å¨ç»ä»¶ |
| | | ä¼å°åå§é»è®¤æ¶é´ï¼ä¸å¨åï¼åæ¹åçæ¶é´éè¿äºä»¶âsubmitTimeâä¼ éç»ç¶ç»ä»¶ |
| | | |
| | | |
| | | åå§æ¸²ææ¶å°±å°æ¶é´ä¼ éç»ç¶ç»ä»¶ï¼ |
| | | ** |
| | | ** |
| | | å¨ç¶ç»ä»¶ä¸è®¾ç½® |
| | | <TimeSelect @submit-time="giveTime"></TimeSelect> |
| | | giveTime(val) { |
| | |
| | | import dayjs from 'dayjs' |
| | | export default { |
| | | emits: ['submitTime'], |
| | | props: { |
| | | // æ§å¶æ¯å¦å¯ç¨æ°çææï¼å¿«æ·æé® + 详æ
æé®ï¼ |
| | | useNewStyle: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | }, |
| | | |
| | | data() { |
| | | return { |
| | | //ä¿åå¼å§åç»ææ¶é´ |
| | | // é便设置åå§å¼ ï¼mountedæ¶å设æ£ç¡®çï¼ç®çæ¯æ¹åæ¶é´äºè§¦åchange |
| | | time: ['2023-06-01 12:00:00', '2023-06-20 16:00:00'] |
| | | }; |
| | | time: ['2023-06-01 12:00:00', '2023-06-20 16:00:00'], |
| | | // æ§å¶æ¶é´éæ©å¨çæ¾ç¤º/éèï¼ä»
卿°æ ·å¼ä¸ä½¿ç¨ï¼ |
| | | showTimePicker: false, |
| | | // æ¶é´èå´é项 |
| | | timeRanges: [ |
| | | { value: 'today', label: '仿¥' }, |
| | | { value: 'yesterday', label: 'æ¨æ¥' }, |
| | | { value: 'thisWeek', label: 'æ¬å¨' }, |
| | | { value: 'lastWeek', label: 'ä¸å¨' }, |
| | | { value: 'thisMonth', label: 'æ¬æ' }, |
| | | { value: 'lastMonth', label: '䏿' }, |
| | | ], |
| | | // éä¸çæ¶é´èå´ |
| | | selectedRange: '', |
| | | } |
| | | }, |
| | | |
| | | // å°åå§é»è®¤å¼å§åç»ææ¶é´ä¼ éç»ç¶ç»ä»¶ |
| | | mounted() { |
| | | this,this.initOneWeekAgoTime() |
| | | this.$emit('submitTime', this.time); |
| | | if (this.useNewStyle) { |
| | | // æ°æ ·å¼ä¸é»è®¤éä¸ä»æ¥ |
| | | this.selectedRange = 'today' |
| | | this.selectTimeRange('today') |
| | | } else { |
| | | // åææ ·å¼ä¸ä½¿ç¨ä¸å¨åçé»è®¤æ¶é´ |
| | | this.initOneWeekAgoTime() |
| | | this.$emit('submitTime', this.time) |
| | | } |
| | | }, |
| | | |
| | | methods:{ |
| | | initOneWeekAgoTime(){ |
| | | methods: { |
| | | initOneWeekAgoTime() { |
| | | // ç»æ¶é´éæ©å¨è®¾ç½®é»è®¤æ¶é´ä¸ºä¸å¨å |
| | | this.time[0] = dayjs().subtract(4, 'week').format('YYYY-MM-DD HH:mm:ss'); |
| | | this.time[1] = dayjs().format('YYYY-MM-DD HH:mm:ss'); |
| | | } |
| | | } |
| | | }; |
| | | this.time[0] = dayjs().subtract(4, 'week').format('YYYY-MM-DD HH:mm:ss') |
| | | this.time[1] = dayjs().format('YYYY-MM-DD HH:mm:ss') |
| | | }, |
| | | |
| | | // å¿«æ·æ¶æ®µéæ© |
| | | selectTimeRange(range) { |
| | | let now = dayjs() |
| | | let start, end |
| | | |
| | | switch (range) { |
| | | case 'today': |
| | | start = now.startOf('day').format('YYYY-MM-DD HH:mm:ss') |
| | | end = now.endOf('day').format('YYYY-MM-DD HH:mm:ss') |
| | | break |
| | | case 'yesterday': |
| | | start = now.subtract(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss') |
| | | end = now.subtract(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss') |
| | | break |
| | | case 'thisWeek': |
| | | start = now.startOf('week').format('YYYY-MM-DD HH:mm:ss') |
| | | end = now.endOf('week').format('YYYY-MM-DD HH:mm:ss') |
| | | break |
| | | case 'lastWeek': |
| | | start = now.subtract(1, 'week').startOf('week').format('YYYY-MM-DD HH:mm:ss') |
| | | end = now.subtract(1, 'week').endOf('week').format('YYYY-MM-DD HH:mm:ss') |
| | | break |
| | | case 'thisMonth': |
| | | start = now.startOf('month').format('YYYY-MM-DD HH:mm:ss') |
| | | end = now.endOf('month').format('YYYY-MM-DD HH:mm:ss') |
| | | break |
| | | case 'lastMonth': |
| | | start = now.subtract(1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss') |
| | | end = now.subtract(1, 'month').endOf('month').format('YYYY-MM-DD HH:mm:ss') |
| | | break |
| | | } |
| | | |
| | | this.time = [start, end] |
| | | this.$emit('submitTime', this.time) |
| | | }, |
| | | |
| | | // å¤çæ¶é´èå´éæ©åå |
| | | handleRangeChange(val) { |
| | | if (val) { |
| | | this.selectTimeRange(val) |
| | | } |
| | | }, |
| | | |
| | | // 忢æ¶é´éæ©å¨çæ¾ç¤º/éè |
| | | toggleTimePicker() { |
| | | this.showTimePicker = !this.showTimePicker |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <!-- æ¥ææ¶é´éæ©å¨ --> |
| | | <div class="block"> |
| | | <span class="demonstration">èµ·æ¢æ¶é´ï¼</span> |
| | | <!-- æ¶é´éæ©ç»ä»¶ --> |
| | | <div v-if="useNewStyle" class="time-select-container"> |
| | | <el-row align="middle" class="m-b-8"> |
| | | <span class="demonstration">æ¶é´ï¼</span> |
| | | <!-- å¿«æ·æ¶æ®µéæ©æé® --> |
| | | <div class="quick-time-buttons"> |
| | | <el-radio-group v-model="selectedRange" @change="handleRangeChange"> |
| | | <el-radio-button v-for="range in timeRanges" :key="range.value" :label="range.value"> |
| | | {{ range.label }} |
| | | </el-radio-button> |
| | | </el-radio-group> |
| | | <el-button size="small" type="primary" @click="toggleTimePicker">æ¶é´è¯¦æ
</el-button> |
| | | </div> |
| | | </el-row> |
| | | |
| | | <!-- æ¶é´éæ©å¨ï¼é»è®¤éèï¼ --> |
| | | <div v-show="showTimePicker" class="time-picker-container"> |
| | | <el-date-picker |
| | | v-model="time" |
| | | type="daterange" |
| | | range-separator="~" |
| | | start-placeholder="å¼å§æ¶é´" |
| | | end-placeholder="ç»ææ¶é´" |
| | | @change="$emit('submitTime', time)" |
| | | class="pick-date" |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- åææ ·å¼ --> |
| | | <div v-else class="block"> |
| | | <span class="demonstration">æ¶é´ï¼</span> |
| | | <el-date-picker |
| | | v-model="time" |
| | | type="datetimerange" |
| | | type="daterange" |
| | | range-separator="~" |
| | | start-placeholder="Start date" |
| | | end-placeholder="End date" |
| | | @change="$emit('submitTime', time)" |
| | | class="pick-date" |
| | | |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <style> |
| | | .time-select-container { |
| | | /* width: 100%; */ |
| | | } |
| | | |
| | | .time-label { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .quick-time-buttons { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | align-items: center; |
| | | } |
| | | |
| | | .time-picker-container { |
| | | display: flex; |
| | | align-items: center; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .demonstration { |
| | | margin-left: 30px; |
| | | margin-top: 5px; |
| | | margin-right: 10px; |
| | | font-weight: bold; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .pick-date { |
| | | width: 100%; |
| | | } |
| | | |
| | | .block { |
| | | display: flex; |
| | | justify-content: center; |
| | | /* width: 50%; */ |
| | | white-space: nowrap; |
| | | } |
| | | .pick-date { |
| | | width: 100%; |
| | | |
| | | } |
| | | .block .demonstration { |
| | | margin-left: 30px; |
| | | margin-top: 5px; |
| | | } |
| | | </style> |
| | |
| | | body { |
| | | margin: 0; |
| | | } |
| | | |
| | | /************************************** font size **************************************/ |
| | | $fontsize: ( |
| | | s: var(--el-font-size-small), |
| | | b: var(--el-font-size-base), |
| | | m: var(--el-font-size-medium), |
| | | l: var(--el-font-size-large), |
| | | ); |
| | | |
| | | @each $dName, $dValue in $fontsize { |
| | | .f-#{$dName} { |
| | | font-size: #{$dValue}; |
| | | } |
| | | } |
| | | |
| | | /************************************** color **************************************/ |
| | | $colors: ( |
| | | p: var(--el-color-primary), |
| | | s: var(--el-color-success), |
| | | w: var(--el-color-warning), |
| | | d: var(--el-color-danger), |
| | | e: var(--el-color-error), |
| | | i: var(--el-color-info), |
| | | ); |
| | | |
| | | @each $dName, $dValue in $colors { |
| | | .color-#{$dName} { |
| | | color: #{$dValue}; |
| | | } |
| | | .b-color-#{$dName} { |
| | | background-color: #{$dValue}; |
| | | } |
| | | } |
| | | |
| | | /************************************** å
å¤è¾¹è· **************************************/ |
| | | $direction: ( |
| | | l: 'left', |
| | | t: 'top', |
| | | r: 'right', |
| | | b: 'bottom', |
| | | ); |
| | | $size: (4, 8, 10, 16); |
| | | @each $dName, $dValue in $direction { |
| | | @each $i in $size { |
| | | .p-#{$dName}-#{$i} { |
| | | padding-#{$dValue}: #{$i}px; |
| | | } |
| | | .m-#{$dName}-#{$i} { |
| | | margin-#{$dValue}: #{$i}px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | @each $i in $size { |
| | | .p-#{$i} { |
| | | padding: #{$i}px; |
| | | } |
| | | .p-v-#{$i} { |
| | | padding: #{$i}px 0; |
| | | } |
| | | .p-h-#{$i} { |
| | | padding: 0 #{$i}px; |
| | | } |
| | | .m-v-#{$i} { |
| | | margin: #{$i}px 0; |
| | | } |
| | | .m-h-#{$i} { |
| | | margin: 0 #{$i}px; |
| | | } |
| | | } |
| | | |
| | | /************************************** å®½é« **************************************/ |
| | | $csize: ( |
| | | small: var(--el-component-size-small), |
| | | default: var(--el-component-size-default), |
| | | large: var(--el-component-size-large), |
| | | ); |
| | | $ws: (20px, 40px, 60px, 100px, 150px, 250px, 300px); |
| | | @each $name, $value in $csize { |
| | | .w-#{$name} { |
| | | width: #{$value}; |
| | | } |
| | | .h-#{$name} { |
| | | height: #{$value}; |
| | | } |
| | | } |
| | | @each $i in $ws { |
| | | .w-#{$i} { |
| | | width: #{$i}; |
| | | } |
| | | .h-#{$i} { |
| | | height: #{$i}; |
| | | } |
| | | } |
| | | |
| | | // |
| | | .cursor-p { |
| | | cursor: pointer; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // 表åçååºå¼æ
æ ¼å¸å± |
| | | function formResponsiveCols() { |
| | | return { |
| | | xs: { |
| | | span: 24, |
| | | offset: 0, |
| | | push: 0, |
| | | pull: 0 |
| | | }, |
| | | sm: { |
| | | span: 24, |
| | | offset: 0, |
| | | push: 0, |
| | | pull: 0 |
| | | }, |
| | | md: { |
| | | span: 20, |
| | | offset: 2, |
| | | push: 0, |
| | | pull: 0 |
| | | }, |
| | | lg: { |
| | | span: 18, |
| | | offset: 3, |
| | | push: 0, |
| | | pull: 0 |
| | | }, |
| | | xl: { |
| | | span: 14, |
| | | offset: 5, |
| | | push: 0, |
| | | pull: 0 |
| | | } |
| | | }; |
| | | } |
| | | |
| | | const cardResponsiveCols = { |
| | | xs: { |
| | | span: 24, |
| | | offset: 0, |
| | | push: 0, |
| | | pull: 0 |
| | | }, |
| | | sm: { |
| | | span: 24, |
| | | offset: 0, |
| | | push: 0, |
| | | pull: 0 |
| | | }, |
| | | md: { |
| | | span: 24, |
| | | offset: 0, |
| | | push: 0, |
| | | pull: 0 |
| | | }, |
| | | lg: { |
| | | span: 12, |
| | | offset: 0, |
| | | push: 0, |
| | | pull: 0 |
| | | }, |
| | | xl: { |
| | | span: 8, |
| | | offset: 0, |
| | | push: 0, |
| | | pull: 0 |
| | | } |
| | | }; |
| | | |
| | | export { formResponsiveCols, cardResponsiveCols }; |
| | |
| | | import { map, AMap, onMapMounted } from './index'; |
| | | import { map, AMap, onMapMounted } from './index' |
| | | |
| | | // è¡æ¿åºåç¼å |
| | | var districtPolygonMap = new Map(); |
| | | var districtPolygonMap = new Map() |
| | | // å½åæ¾ç¤ºçåºå¿ |
| | | var activeDistrict = undefined; |
| | | var activeDistrict = undefined |
| | | export default { |
| | | // ç»å¶åºå¿è¾¹ç |
| | | drawDistrict(districtName, isNew) { |
| | | if(!districtName) return; |
| | | if (!districtName) return |
| | | onMapMounted(() => { |
| | | if (!isNew && districtPolygonMap.has(districtName)) { |
| | | const districtPolygon = districtPolygonMap.get(districtName); |
| | | map.add(districtPolygon); |
| | | map.setFitView(districtPolygon); |
| | | activeDistrict = districtPolygon; |
| | | const { polygon, mask } = districtPolygonMap.get(districtName) |
| | | map.add(polygon) |
| | | map.setFitView(polygon) |
| | | map.setMask(mask) |
| | | activeDistrict = polygon |
| | | } else { |
| | | var district = new AMap.DistrictSearch({ |
| | | extensions: 'all', //è¿åè¡æ¿åºè¾¹çåæ çå
·ä½ä¿¡æ¯ |
| | | level: 'district' //设置æ¥è¯¢è¡æ¿åºçº§å«ä¸ºåº |
| | | }); |
| | | level: 'district', //设置æ¥è¯¢è¡æ¿åºçº§å«ä¸ºåº |
| | | }) |
| | | district.search(districtName, function (status, result) { |
| | | var bounds = result.districtList[0].boundaries; //è·åè¾¹çä¿¡æ¯ |
| | | if (bounds) { |
| | | if (status === 'complete') { |
| | | var bounds = result.districtList[0].boundaries //è·åè¾¹çä¿¡æ¯ |
| | | var mask = [] |
| | | var polygon = [] |
| | | for (var i = 0; i < bounds.length; i++) { |
| | | mask.push([bounds[i]]) |
| | | |
| | | //çæè¡æ¿åºå polygon |
| | | const districtPolygon = new AMap.Polygon({ |
| | | map: map, //æ¾ç¤ºè¯¥è¦çç©çå°å¾å¯¹è±¡ |
| | | strokeWeight: 1, //è½®å»çº¿å®½åº¦ |
| | | strokeWeight: 2, //è½®å»çº¿å®½åº¦ |
| | | path: bounds[i], //å¤è¾¹å½¢è½®å»çº¿çèç¹åæ æ°ç» |
| | | fillOpacity: 0.4, //å¤è¾¹å½¢å¡«å
éæåº¦ |
| | | fillOpacity: 0, //å¤è¾¹å½¢å¡«å
éæåº¦ |
| | | fillColor: '#0077ff', |
| | | strokeColor: '#CC66CC' //线æ¡é¢è² |
| | | }); |
| | | strokeColor: '#99ffff', //线æ¡é¢è² |
| | | }) |
| | | |
| | | districtPolygonMap.set(districtName, districtPolygon); |
| | | activeDistrict = districtPolygon; |
| | | map.setFitView(districtPolygon, true); |
| | | polygon.push(districtPolygon) |
| | | } |
| | | activeDistrict = polygon |
| | | districtPolygonMap.set(districtName, { polygon, mask }) |
| | | map.setFitView(polygon, true) |
| | | map.setMask(mask) |
| | | } |
| | | }); |
| | | }) |
| | | } |
| | | }); |
| | | }) |
| | | }, |
| | | removeDistrict() { |
| | | onMapMounted(() => { |
| | | if (activeDistrict) { |
| | | map.remove(activeDistrict); |
| | | activeDistrict = undefined; |
| | | map.remove(activeDistrict) |
| | | activeDistrict = undefined |
| | | } |
| | | }) |
| | | } |
| | | }; |
| | | }, |
| | | districtLayer(districtName) { |
| | | onMapMounted(() => { |
| | | //2ãå建çå¸ç®æè¡æ¿åºå¾å± |
| | | var distProvince = new AMap.DistrictLayer.Province({ |
| | | zIndex: 10, //设置å¾å±å±çº§ |
| | | zooms: [2, 15], //设置å¾å±æ¾ç¤ºèå´ |
| | | adcode: districtName, //è®¾ç½®è¡æ¿åº adcode |
| | | depth: 2, //è®¾ç½®æ°æ®æ¾ç¤ºå±çº§ï¼0ï¼æ¾ç¤ºå½å®¶é¢ï¼1ï¼æ¾ç¤ºç级ï¼å½å½å®¶ä¸ºä¸å½æ¶è®¾ç½®depth为2çå¯ä»¥æ¾ç¤ºå¸ä¸çº§ |
| | | }) |
| | | // 3ãè®¾ç½®è¡æ¿åºå¾å±æ ·å¼ |
| | | distProvince.setStyles({ |
| | | 'stroke-width': 2, //æè¾¹çº¿å®½ |
| | | fill: function (data) { |
| | | //设置åºåå¡«å
é¢è²ï¼å¯æ ¹æ®åè°ä¿¡æ¯è¿ååºåä¿¡æ¯è®¾ç½®ä¸åå¡«å
è² |
| | | //åè°è¿ååºåä¿¡æ¯æ°æ®ï¼å段å
æ¬ SOC(å½å®¶ä»£ç )ãNAME_ENG(è±æåç§°)ãNAME_CHN(䏿åç§°)ç |
| | | //å½å®¶ä»£ç å称说æåè https://a.amap.com/jsapi_demos/static/demo-center/js/soc-list.json |
| | | return '#ffffffe7' |
| | | }, |
| | | }) |
| | | //4ãå°ç®æè¡æ¿åºå¾å±æ·»å å°å°å¾ |
| | | map.add(distProvince) |
| | | }) |
| | | }, |
| | | } |
| | |
| | | import AMapLoader from '@amap/amap-jsapi-loader'; |
| | | import AMapLoader from '@amap/amap-jsapi-loader' |
| | | |
| | | var mapInitDone = false; |
| | | var onMapMountedEvents = []; |
| | | var mapInitDone = false |
| | | var onMapMountedEvents = [] |
| | | |
| | | var AMap; |
| | | var AMap |
| | | // å°å¾å¯¹è±¡ |
| | | var map; |
| | | var map |
| | | // 嫿å¾å± |
| | | var satellite; |
| | | var satellite |
| | | // é¼ æ ç»å¾ |
| | | var mouseTool; |
| | | var mouseTool |
| | | // 3Då¾å± |
| | | var object3Dlayer; |
| | | var object3Dlayer |
| | | // å°å¾æå¨ç¶æ |
| | | var isDragging = false; |
| | | var isDragging = false |
| | | |
| | | // å°å¾å è½½å®æè§¦å |
| | | function onMapMounted(...events) { |
| | | if (mapInitDone) { |
| | | events.forEach((e) => { |
| | | e(); |
| | | }); |
| | | e() |
| | | }) |
| | | } else { |
| | | onMapMountedEvents = onMapMountedEvents.concat(events); |
| | | onMapMountedEvents = onMapMountedEvents.concat(events) |
| | | } |
| | | } |
| | | |
| | |
| | | 'AMap.ControlBar', |
| | | 'AMap.ToolBar', |
| | | 'AMap.Scale', |
| | | 'AMap.DistrictSearch' |
| | | 'AMap.DistrictSearch', |
| | | // 'AMap.DragRoute', |
| | | // 'AMap.MouseTool', |
| | | // 'AMap.PolygonEditor' |
| | | ] |
| | | ], |
| | | }) |
| | | .then((_AMap) => { |
| | | AMap = _AMap; |
| | | _initMap(id); |
| | | mapInitDone = true; |
| | | AMap = _AMap |
| | | _initMap(id) |
| | | mapInitDone = true |
| | | onMapMountedEvents.forEach((e) => { |
| | | e(); |
| | | }); |
| | | onMapMountedEvents = []; |
| | | console.log('-------------------map init done'); |
| | | e() |
| | | }) |
| | | onMapMountedEvents = [] |
| | | console.log('-------------------map init done') |
| | | }) |
| | | .catch((e) => { |
| | | console.log(e); |
| | | }); |
| | | console.log(e) |
| | | }) |
| | | } |
| | | |
| | | function destroyMap() { |
| | | map?.destroy(); |
| | | map = null; |
| | | mapInitDone = false; |
| | | map?.destroy() |
| | | map = null |
| | | mapInitDone = false |
| | | } |
| | | |
| | | function _initMap(elementId) { |
| | | map = new AMap.Map(elementId, { |
| | | // mapStyle: 'amap://styles/e1e78509de64ddcd2efb4cb34c6fae2a', |
| | | features: ['bg', 'road'], |
| | | pitch: 45, // å°å¾ä¿¯ä»°è§åº¦ï¼ææèå´ 0 度- 83 度 |
| | | viewMode: '2D', // å°å¾æ¨¡å¼ |
| | | pitch: 30, // å°å¾ä¿¯ä»°è§åº¦ï¼ææèå´ 0 度- 83 度 |
| | | viewMode: '3D', // å°å¾æ¨¡å¼ |
| | | resizeEnable: true, |
| | | center: [121.6039283, 31.25295567], |
| | | zooms: [2, 26], |
| | | zoom: 14 |
| | | }); |
| | | zoom: 14, |
| | | }) |
| | | // map = new AMap.Map(elementId); |
| | | |
| | | // æ·»å 嫿å°å¾ |
| | | satellite = new AMap.TileLayer.Satellite(); |
| | | satellite.hide(); |
| | | map.add([satellite]); |
| | | satellite = new AMap.TileLayer.Satellite() |
| | | const roadNet = new AMap.TileLayer.RoadNet() |
| | | // satellite.hide() |
| | | map.add([satellite, roadNet]) |
| | | |
| | | // _initMouseTool(); |
| | | // _init3DLayer(); |
| | |
| | | |
| | | // é¼ æ ç»å¾åå§å |
| | | function _initMouseTool() { |
| | | mouseTool = new AMap.MouseTool(map); |
| | | mouseTool = new AMap.MouseTool(map) |
| | | } |
| | | |
| | | // 3Då¾å±åå§å |
| | | function _init3DLayer() { |
| | | object3Dlayer = new AMap.Object3DLayer(); |
| | | map.add(object3Dlayer); |
| | | object3Dlayer = new AMap.Object3DLayer() |
| | | map.add(object3Dlayer) |
| | | } |
| | | |
| | | // 设置å°å¾ææ½çå¬äºä»¶ |
| | | function _initDragEvent() { |
| | | let dragEndEvent; |
| | | let dragEndEvent |
| | | map.on('dragstart', () => { |
| | | clearTimeout(dragEndEvent); |
| | | isDragging = true; |
| | | }); |
| | | clearTimeout(dragEndEvent) |
| | | isDragging = true |
| | | }) |
| | | map.on('dragend', function () { |
| | | dragEndEvent = setTimeout(() => { |
| | | isDragging = false; |
| | | }, 8000); |
| | | }); |
| | | isDragging = false |
| | | }, 8000) |
| | | }) |
| | | } |
| | | |
| | | export { |
| | | createMap, |
| | | destroyMap, |
| | | onMapMounted, |
| | | map, |
| | | AMap, |
| | | mouseTool, |
| | | object3Dlayer, |
| | | isDragging |
| | | }; |
| | | export { createMap, destroyMap, onMapMounted, map, AMap, mouseTool, object3Dlayer, isDragging } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-page-header @back="onBack"> |
| | | <template #content> |
| | | <span> è´¦æ·ä¿¡æ¯ç¼è¾ </span> |
| | | </template> |
| | | </el-page-header> |
| | | <el-divider /> |
| | | <el-tabs v-model="activeName" class="p-h-8" @tab-click="handleClick"> |
| | | <el-tab-pane label="åºæ¬ä¿¡æ¯" name="first"> |
| | | <FormCol> |
| | | <div class="sub-title">è´¦æ·ä¿¡æ¯</div> |
| | | <CompUserInfo :model="formUser" /> |
| | | </FormCol> |
| | | <el-divider /> |
| | | <FormCol> |
| | | <div class="sub-title">åºéºä¿¡æ¯</div> |
| | | <CompSceneInfo :form-info="formSceneInfo" /> |
| | | </FormCol> |
| | | <el-divider /> |
| | | <FormCol> |
| | | <div class="sub-title">ä¼ä¸ä¿¡æ¯</div> |
| | | <CompCompanyInfo :form-info="formCompanyInfo" /> |
| | | </FormCol> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="设å¤ç®¡ç" name="second"> |
| | | <FormCol> |
| | | <el-row class="sub-title" justify="space-between"> |
| | | <div>çæµè®¾å¤ä¿¡æ¯</div> |
| | | <el-button type="success" @click="addDevice">æ°å¢è®¾å¤</el-button> |
| | | </el-row> |
| | | <!-- æ°å¢è®¾å¤è¡¨å --> |
| | | <CompDeviceInfo |
| | | v-if="showAddDevice" |
| | | :form-info="newDeviceForm" |
| | | :create="true" |
| | | @onSubmit="handleDeviceSubmit" |
| | | @onCancel="handleDeviceCancel" |
| | | /> |
| | | <!-- 设å¤å表 --> |
| | | <div v-if="formDeviceList.length === 0 && !showAddDevice" class="empty-device"> |
| | | <el-empty description="ææ è®¾å¤ä¿¡æ¯" /> |
| | | </div> |
| | | <CompDeviceInfo |
| | | v-else-if="formDeviceList.length > 0" |
| | | v-for="(item, index) in formDeviceList" |
| | | :key="index" |
| | | :form-info="item" |
| | | /> |
| | | </FormCol> |
| | | </el-tab-pane> |
| | | |
| | | <el-tab-pane label="å±åºææ±¡" name="third"> |
| | | <FormCol> |
| | | <div class="sub-title">å±åºææ±¡æ¸
å</div> |
| | | <CompHazardousWasteFile :form-info="formHazardousWasteFile" /> |
| | | </FormCol> |
| | | <FormCol> |
| | | <div class="sub-title">å±åºææ±¡è®°å½</div> |
| | | <CompHazardousWasteRecord :form-info="formHazardousWasteRecord" /> |
| | | </FormCol> |
| | | </el-tab-pane> |
| | | |
| | | <el-tab-pane label="è¡æ¿å¤ç½" name="fourth"> |
| | | <FormCol> |
| | | <div class="sub-title">è¡æ¿å¤ç½è¡¨</div> |
| | | <!-- <CompPunishment :form-info="formProblem" /> --> |
| | | </FormCol> |
| | | </el-tab-pane> |
| | | |
| | | <el-tab-pane label="信访æè¯" name="fifth"> |
| | | <FormCol> |
| | | <div class="sub-title">信访æè¯</div> |
| | | <!-- <CompLaint :form-info="formLaint" /> --> |
| | | </FormCol> |
| | | </el-tab-pane> |
| | | |
| | | <el-tab-pane label="å·¡æ¥é®é¢è¡¨" name="sixth"> |
| | | <FormCol> |
| | | <div class="sub-title">å·¡æ¥é®é¢è¡¨</div> |
| | | <!-- <CompProblem :form-info="formProblem" /> --> |
| | | </FormCol> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | |
| | | <!-- <ComBaseInformation v-model="drawer"></ComBaseInformation> --> |
| | | </template> |
| | | |
| | | <script> |
| | | import userApi from '@/api/fytz/userApi' |
| | | import CompUserInfo from './components/CompUserInfo.vue' |
| | | import CompSceneInfo from './components/CompSceneInfo.vue' |
| | | import CompCompanyInfo from './components/CompCompanyInfo.vue' |
| | | import CompDeviceInfo from './components/CompDeviceInfo.vue' |
| | | import CompHazardousWasteFile from './components/CompHazardousWasteFile.vue' |
| | | import CompHazardousWasteRecord from './components/CompHazardousWasteRecord.vue' |
| | | |
| | | export default { |
| | | components: { |
| | | // ComBaseInformation, |
| | | // CompLaint, |
| | | CompUserInfo, |
| | | CompSceneInfo, |
| | | CompCompanyInfo, |
| | | CompDeviceInfo, |
| | | CompHazardousWasteFile, |
| | | CompHazardousWasteRecord, |
| | | // CompPanyInfo, |
| | | // CompFumePurifyDevice, |
| | | // CompHazardousWasteFile, |
| | | // CompHazardousWasteRecord, |
| | | // CompProblem, |
| | | // CompPunishment, |
| | | // CompRestaurantBaseInfo, |
| | | // CompVehicleBaseInfo, |
| | | // CompUserInfos, |
| | | }, |
| | | data() { |
| | | return { |
| | | drawer: false, |
| | | formUser: {}, |
| | | formSceneInfo: {}, |
| | | formCompanyInfo: {}, |
| | | // formSubScene: {}, |
| | | formLaint: {}, |
| | | formDeviceList: [], |
| | | formPanyInfo: {}, |
| | | formFumePurifyDevice: {}, |
| | | formHazardousWasteFile: {}, |
| | | formHazardousWasteRecord: {}, |
| | | formProblem: {}, |
| | | formPunishment: {}, |
| | | formRestaurantBaseInfo: {}, |
| | | activeName: 'first', |
| | | scroll: '', |
| | | showAddDevice: false, |
| | | newDeviceForm: {}, |
| | | } |
| | | }, |
| | | beforeRouteEnter(to, from, next) { |
| | | userApi.fetchUserBaseInfo(to.params.userId).then((res) => { |
| | | next((vm) => { |
| | | if (res.userInfo) { |
| | | vm.formUser = res.userInfo |
| | | } else { |
| | | vm.formUser = { |
| | | guid: to.params.userId, |
| | | } |
| | | } |
| | | }) |
| | | }) |
| | | }, |
| | | methods: { |
| | | handleClick(tab) { |
| | | console.log('tab', tab) |
| | | }, |
| | | // åéé¡µé¢ |
| | | onBack() { |
| | | this.$router.back() |
| | | }, |
| | | // æ°å¢è®¾å¤ |
| | | addDevice() { |
| | | this.showAddDevice = true |
| | | this.newDeviceForm = {} |
| | | }, |
| | | // è®¾å¤æäº¤ |
| | | handleDeviceSubmit(formData) { |
| | | // è¿éå¯ä»¥æ·»å å®é
çAPIè°ç¨ |
| | | this.formDeviceList.push(formData.value) |
| | | this.showAddDevice = false |
| | | this.newDeviceForm = {} |
| | | }, |
| | | // 设å¤åæ¶ |
| | | handleDeviceCancel() { |
| | | this.showAddDevice = false |
| | | this.newDeviceForm = {} |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | <style scoped> |
| | | .sub-title { |
| | | font-size: var(--el--font--size--large); |
| | | margin-bottom: 30px; |
| | | margin-top: 30px; |
| | | margin-left: 20px; |
| | | } |
| | | .empty-device { |
| | | padding: 40px 0; |
| | | text-align: center; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <FYTable @search="onSearch" :row-class-name="tableRowClassName"> |
| | | <template #options> |
| | | <FYOptionLocation |
| | | :allOption="true" |
| | | :level="5" |
| | | v-model:value="formSearch._locations" |
| | | ></FYOptionLocation> |
| | | <FYOptionText |
| | | label="åºæ¯åç§°" |
| | | placeholder="è¾å
¥åç§°å
³é®å" |
| | | v-model:value="formSearch.searchText" |
| | | ></FYOptionText> |
| | | <FYOptionScene |
| | | :allOption="true" |
| | | :type="1" |
| | | :initValue="false" |
| | | v-model:value="formSearch.scensetype" |
| | | ></FYOptionScene> |
| | | <FYOptionOnlineStatus |
| | | :allOption="true" |
| | | v-model:value="formSearch.online" |
| | | ></FYOptionOnlineStatus> |
| | | </template> |
| | | |
| | | <template #table-column> |
| | | <el-table-column |
| | | fixed="left" |
| | | prop="userInfo.realname" |
| | | label="åç§°" |
| | | :show-overflow-tooltip="true" |
| | | width="400" |
| | | > |
| | | </el-table-column> |
| | | <el-table-column prop="userInfo.acountname" label="è´¦å·" width="110" /> |
| | | <el-table-column prop="sceneTypeName" label="ç±»å" width="100" /> |
| | | <el-table-column prop="biProvinceName" label="ç" width="80" /> |
| | | <el-table-column prop="biCityName" label="å¸" width="80" /> |
| | | <!-- <el-table-column prop="districtname" label="åºå¿" width="90" /> --> |
| | | <el-table-column prop="userInfo.extension1" label="åºå¿" width="80" /> |
| | | <el-table-column prop="biTownName" label="è¡é" width="110" /> |
| | | <el-table-column prop="biArea" label="éä¸åº" width="110" /> |
| | | <el-table-column prop="biManagementCompany" label="ç©ä¸" min-width="110" /> |
| | | <el-table-column prop="userInfo.isenable" label="ç¶æ" width="90"> |
| | | <template #default="{ row }"> |
| | | {{ row.userInfo.isenable ? 'ä¸çº¿ä¸' : 'å·²ä¸çº¿' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="userInfo.usertype" label="ç¨æ·ç±»å" width="90" /> |
| | | <el-table-column fixed="right" align="right" label="æä½" width="190"> |
| | | <template #header> |
| | | <el-button icon="DocumentAdd" size="default" type="success" @click="drawer = true" |
| | | >æ°å¢ç¨æ·</el-button |
| | | > |
| | | </template> |
| | | <template #default="{ row }"> |
| | | <el-space> |
| | | <el-button |
| | | :loading="row.loading2" |
| | | :type="row.userInfo.isenable != '0' ? 'danger' : 'primary'" |
| | | size="small" |
| | | @click="itemActive(row)" |
| | | >{{ row.userInfo.isenable != '0' ? 'ä¸çº¿' : 'ä¸çº¿' }}</el-button |
| | | > |
| | | <el-button-group> |
| | | <el-button type="primary" :loading="row.loading1" size="small" @click="editRow(row)" |
| | | >æ¥ç</el-button |
| | | > |
| | | <el-dropdown @command="handleCommand" trigger="click"> |
| | | <el-button |
| | | type="primary" |
| | | :loading="row.downloadLoading" |
| | | size="small" |
| | | :icon="row.downloadLoading ? '' : 'ArrowDown'" |
| | | ></el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item icon="Download" :command="{ c: 1, p: row }" |
| | | >ä¸è½½ç¯ä¿¡ç </el-dropdown-item |
| | | > |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | </el-button-group> |
| | | <!-- <el-dropdown |
| | | split-button |
| | | :loading="row.loading1" |
| | | size="small" |
| | | type="primary" |
| | | @click="editRow(row)" |
| | | @command="handleCommand" |
| | | trigger="click" |
| | | > |
| | | æ¥ç |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item icon="Download" :command="{ c: 1, p: row }" |
| | | >ä¸è½½ç¯ä¿¡ç </el-dropdown-item |
| | | > |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> --> |
| | | </el-space> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </FYTable> |
| | | <CompUserInfoAddDrawer v-model="drawer"></CompUserInfoAddDrawer> |
| | | </template> |
| | | |
| | | <script> |
| | | import userApi from '@/api/fytz/userApi' |
| | | import creditApi from '@/api/fytz/creditApi' |
| | | import { useLoadingStore } from '@/stores/loadingStore' |
| | | import { mapStores } from 'pinia' |
| | | import { useMessageBoxTip } from '@/composables/messageBox' |
| | | import CompUserInfoAddDrawer from './components/CompUserInfoAddDrawer.vue' |
| | | |
| | | export default { |
| | | components: { |
| | | CompUserInfoAddDrawer, |
| | | }, |
| | | data() { |
| | | return { |
| | | // æ¥è¯¢æ¡ä»¶ |
| | | formSearch: { |
| | | _locations: {}, |
| | | searchText: '', |
| | | scensetype: { |
| | | label: 'é¤é¥®', |
| | | value: '1', |
| | | }, |
| | | online: {}, |
| | | }, |
| | | // æ°å¢ç¨æ·å¼¹åºæ¡ |
| | | drawer: false, |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapStores(useLoadingStore), |
| | | }, |
| | | methods: { |
| | | onSearch(page, func) { |
| | | const f = this.formSearch |
| | | const area = {} |
| | | // è¡æ¿åºå |
| | | area.provinceCode = f._locations.pCode |
| | | area.provinceName = f._locations.pName |
| | | if (area.provinceCode == null) { |
| | | area.provinceCode = null |
| | | area.provinceName = null |
| | | } |
| | | area.cityCode = f._locations.cCode |
| | | area.cityName = f._locations.cName |
| | | area.districtCode = f._locations.dCode |
| | | area.districtName = f._locations.dName |
| | | area.townCode = f._locations.tCode |
| | | area.townName = f._locations.tName |
| | | // åºæ¯ç±»å |
| | | area.sceneTypes = [] |
| | | f.scensetype.value == null ? (area.sceneTypes = []) : (area.sceneTypes = [f.scensetype.value]) |
| | | // ä¸ä¸çº¿ç¶æ |
| | | area.online = f.online.value |
| | | // å
³é®å |
| | | area.searchText = f.searchText |
| | | |
| | | userApi.fetchUser(page.currentPage, page.pageSize, area).then((res) => { |
| | | if (res) { |
| | | func({ |
| | | data: res.data, |
| | | total: res.head.totalCount, |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | editRow(row) { |
| | | row.loading1 = true |
| | | this.loadingStore.pushLoading(() => (row.loading1 = false)) |
| | | this.$router.push(`scene-info-edit/${row.userInfo.guid}`) |
| | | }, |
| | | itemActive(row) { |
| | | const param = { |
| | | guid: row.userInfo.guid, |
| | | isenable: !row.userInfo.isenable, |
| | | } |
| | | const msg = row.userInfo.isenable ? 'ä¸çº¿' : 'ä¸çº¿' |
| | | useMessageBoxTip({ |
| | | confirmMsg: `确认${msg}è¯¥åºæ¯ï¼`, |
| | | confirmTitle: msg, |
| | | onConfirm: async () => { |
| | | row.loading2 = true |
| | | return userApi |
| | | .updateUserInfo(param) |
| | | .then((res) => { |
| | | if (res.success) { |
| | | row.userInfo.isenable = param.isenable |
| | | } |
| | | }) |
| | | .finally(() => { |
| | | row.loading2 = false |
| | | }) |
| | | }, |
| | | }) |
| | | }, |
| | | tableRowClassName({ row }) { |
| | | return row.userInfo.isenable ? 'online-row' : 'offline-row' |
| | | }, |
| | | handleCommand(e) { |
| | | const userId = e.p.userInfo.guid |
| | | switch (e.c) { |
| | | // ä¸è½½ç¯ä¿¡ç |
| | | case 1: |
| | | e.p.downloadLoading = true |
| | | creditApi.downloadCode(userId).finally(() => { |
| | | e.p.downloadLoading = false |
| | | }) |
| | | break |
| | | |
| | | default: |
| | | break |
| | | } |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | <style></style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-form |
| | | :inline="false" |
| | | :model="formObj" |
| | | ref="formRef" |
| | | :rules="rules" |
| | | label-position="right" |
| | | label-width="150px" |
| | | > |
| | | <el-form-item label="åä½åç§°" prop="companyName"> |
| | | <el-input clearable v-model="formObj.companyName" placeholder="åä½åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="主è¦ä»äºä¸å¡" prop="businessScope"> |
| | | <el-input |
| | | clearable |
| | | v-model="formObj.businessScope" |
| | | placeholder="主è¦ä»äºä¸å¡" |
| | | type="textarea" |
| | | rows="2" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="æå±éå¢" prop="group"> |
| | | <el-input clearable v-model="formObj.group" placeholder="æå±éå¢" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç份åç§°" prop="province"> |
| | | <el-input clearable v-model="formObj.province" placeholder="ç份åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="å°å¸åç§°" prop="city"> |
| | | <el-input clearable v-model="formObj.city" placeholder="å°å¸åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="åºå¿åç§°" prop="district"> |
| | | <el-input clearable v-model="formObj.district" placeholder="åºå¿åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="è¡éåç§°" prop="town"> |
| | | <el-input clearable v-model="formObj.town" placeholder="è¡éåç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="æå¨å·¥ä¸åº" prop="industrialZone"> |
| | | <el-input clearable v-model="formObj.industrialZone" placeholder="æå¨å·¥ä¸åº" /> |
| | | </el-form-item> |
| | | <el-form-item label="åä½å°å" prop="address"> |
| | | <el-input |
| | | clearable |
| | | v-model="formObj.address" |
| | | placeholder="åä½å°å" |
| | | type="textarea" |
| | | rows="2" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ç»ç»æºæä»£ç " prop="orgCode"> |
| | | <el-input clearable v-model="formObj.orgCode" placeholder="ç»ç»æºæä»£ç " /> |
| | | </el-form-item> |
| | | <el-form-item label="æ³äºº" prop="legalPerson"> |
| | | <el-input clearable v-model="formObj.legalPerson" placeholder="æ³äºº" /> |
| | | </el-form-item> |
| | | <el-form-item label="è¡ä¸ç±»å«" prop="industryCategory"> |
| | | <el-input clearable v-model="formObj.industryCategory" placeholder="è¡ä¸ç±»å«" /> |
| | | </el-form-item> |
| | | <el-form-item label="è¡ä¸ä»£ç " prop="industryCode"> |
| | | <el-input clearable v-model="formObj.industryCode" placeholder="è¡ä¸ä»£ç " /> |
| | | </el-form-item> |
| | | <el-form-item label="ç»è®°æ³¨åç±»å" prop="registrationType"> |
| | | <el-input clearable v-model="formObj.registrationType" placeholder="ç»è®°æ³¨åç±»å" /> |
| | | </el-form-item> |
| | | <el-form-item label="注åèµæ¬ï¼ä¸å
ï¼" prop="registeredCapital"> |
| | | <el-input |
| | | clearable |
| | | type="number" |
| | | v-model="formObj.registeredCapital" |
| | | placeholder="注åèµæ¬ï¼ä¸å
ï¼" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="建åå¹´æ" prop="establishmentDate"> |
| | | <el-input clearable v-model="formObj.establishmentDate" placeholder="建åå¹´æ" /> |
| | | </el-form-item> |
| | | <el-form-item label="ææ°æ¹æ©å»ºå¹´æ" prop="latestExpansionDate"> |
| | | <el-input clearable v-model="formObj.latestExpansionDate" placeholder="ææ°æ¹æ©å»ºå¹´æ" /> |
| | | </el-form-item> |
| | | <el-form-item label="è工人æ°" prop="employeeCount"> |
| | | <el-input clearable type="number" v-model="formObj.employeeCount" placeholder="è工人æ°" /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¼ä¸è§æ¨¡" prop="companyScale"> |
| | | <el-input clearable v-model="formObj.companyScale" placeholder="ä¼ä¸è§æ¨¡" /> |
| | | </el-form-item> |
| | | <el-form-item label="忬¡ç¯è¯å®¡æ¹å¹´æ" prop="ç¯è¯ApprovalDate"> |
| | | <el-input clearable v-model="formObj.ç¯è¯ApprovalDate" placeholder="忬¡ç¯è¯å®¡æ¹å¹´æ" /> |
| | | </el-form-item> |
| | | <el-form-item label="ææ±¡è®¸å¯è¯ç¼å·" prop="pollutantLicenseNumber"> |
| | | <el-input clearable v-model="formObj.pollutantLicenseNumber" placeholder="ææ±¡è®¸å¯è¯ç¼å·" /> |
| | | </el-form-item> |
| | | <el-form-item label="ææ±¡æäº¤ææä»¶" prop="emissionRightFile"> |
| | | <el-input clearable v-model="formObj.emissionRightFile" placeholder="ææ±¡æäº¤ææä»¶" /> |
| | | </el-form-item> |
| | | <el-form-item label="鮿¿ç¼ç " prop="postalCode"> |
| | | <el-input clearable v-model="formObj.postalCode" placeholder="鮿¿ç¼ç " /> |
| | | </el-form-item> |
| | | <el-form-item label="è系人å§å" prop="contactName"> |
| | | <el-input clearable v-model="formObj.contactName" placeholder="è系人å§å" /> |
| | | </el-form-item> |
| | | <el-form-item label="èç³»çµè¯" prop="telephone"> |
| | | <el-input clearable type="tel" v-model="formObj.telephone" placeholder="èç³»çµè¯"> |
| | | <template #prepend> |
| | | <el-icon><Iphone /></el-icon> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="è系微信å·" prop="wechat"> |
| | | <el-input clearable v-model="formObj.wechat" placeholder="è系微信å·" /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¼ ç" prop="fax"> |
| | | <el-input clearable v-model="formObj.fax" placeholder="ä¼ ç" /> |
| | | </el-form-item> |
| | | <el-form-item label="çµåé®ç®±" prop="email"> |
| | | <el-input clearable type="email" v-model="formObj.email" placeholder="çµåé®ç®±" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <el-button :disabled="!edit" type="primary" @click="onSubmit" :loading="updateLoading" |
| | | >æäº¤</el-button |
| | | > |
| | | <el-button :disabled="!edit" @click="onReset">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { defineProps, defineEmits, reactive, ref, watch } from 'vue' |
| | | import { Iphone } from '@element-plus/icons-vue' |
| | | import { useFormConfirm } from '@/composables/formConfirm' |
| | | |
| | | const props = defineProps({ |
| | | //ä¼ä¸ä¿¡æ¯ |
| | | formInfo: Object, |
| | | //æ¯å建æè
æ´æ° |
| | | create: Boolean, |
| | | }) |
| | | const emit = defineEmits(['onSubmit', 'onCancel']) |
| | | |
| | | const { formObj, formRef, edit, onSubmit, onReset } = useFormConfirm({ |
| | | submit: { |
| | | do: submit, |
| | | }, |
| | | cancel: { |
| | | do: cancel, |
| | | }, |
| | | }) |
| | | const updateLoading = ref(false) |
| | | const rules = reactive({ |
| | | companyName: [ |
| | | { |
| | | required: true, |
| | | message: 'åä½åç§°ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | address: [ |
| | | { |
| | | required: true, |
| | | message: 'åä½å°åä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | contactName: [ |
| | | { |
| | | required: true, |
| | | message: 'è系人å§åä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | telephone: [ |
| | | { |
| | | required: true, |
| | | message: 'èç³»çµè¯ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | }) |
| | | |
| | | // ä¼ä¸ä¿¡æ¯æ ¼å¼å |
| | | function parseCompanyInfo(s) { |
| | | return s |
| | | } |
| | | |
| | | function updateCompany() { |
| | | updateLoading.value = true |
| | | // è¿éå¯ä»¥æ·»å å®é
çAPIè°ç¨ |
| | | setTimeout(() => { |
| | | updateLoading.value = false |
| | | }, 1000) |
| | | } |
| | | |
| | | watch( |
| | | () => props.formInfo, |
| | | (nValue) => { |
| | | formObj.value = parseCompanyInfo(nValue) |
| | | }, |
| | | ) |
| | | |
| | | function submit() { |
| | | emit('onSubmit', formObj) |
| | | return updateCompany() |
| | | } |
| | | function cancel() { |
| | | emit('onCancel') |
| | | } |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-form |
| | | :inline="false" |
| | | :model="formObj" |
| | | ref="formRef" |
| | | :rules="rules" |
| | | label-position="right" |
| | | label-width="150px" |
| | | > |
| | | <el-form-item label="设å¤åç§°" prop="deviceName"> |
| | | <el-input clearable v-model="formObj.deviceName" placeholder="设å¤åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="设å¤åå·" prop="deviceModel"> |
| | | <el-input clearable v-model="formObj.deviceModel" placeholder="设å¤åå·" /> |
| | | </el-form-item> |
| | | <el-form-item label="设å¤ç¼å·" prop="deviceCode"> |
| | | <el-input clearable v-model="formObj.deviceCode" placeholder="设å¤ç¼å·" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç产åå®¶" prop="manufacturer"> |
| | | <el-input clearable v-model="formObj.manufacturer" placeholder="ç产åå®¶" /> |
| | | </el-form-item> |
| | | <el-form-item label="å®è£
æ¥æ" prop="installationDate"> |
| | | <el-input clearable v-model="formObj.installationDate" placeholder="å®è£
æ¥æ" /> |
| | | </el-form-item> |
| | | <el-form-item label="设å¤ç¶æ" prop="status"> |
| | | <el-select v-model="formObj.status" placeholder="设å¤ç¶æ"> |
| | | <el-option label="æ£å¸¸" value="normal" /> |
| | | <el-option label="å¼å¸¸" value="abnormal" /> |
| | | <el-option label="ç»´æ¤ä¸" value="maintenance" /> |
| | | <el-option label="åç¨" value="disabled" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="设å¤ä½ç½®" prop="location"> |
| | | <el-input clearable v-model="formObj.location" placeholder="设å¤ä½ç½®" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç»´æ¤å¨æ" prop="maintenanceCycle"> |
| | | <el-input clearable v-model="formObj.maintenanceCycle" placeholder="ç»´æ¤å¨æ" /> |
| | | </el-form-item> |
| | | <el-form-item label="䏿¬¡ç»´æ¤æ¥æ" prop="lastMaintenanceDate"> |
| | | <el-input clearable v-model="formObj.lastMaintenanceDate" placeholder="䏿¬¡ç»´æ¤æ¥æ" /> |
| | | </el-form-item> |
| | | <el-form-item label="è´è´£äºº" prop="responsiblePerson"> |
| | | <el-input clearable v-model="formObj.responsiblePerson" placeholder="è´è´£äºº" /> |
| | | </el-form-item> |
| | | <el-form-item label="èç³»çµè¯" prop="contactPhone"> |
| | | <el-input clearable type="tel" v-model="formObj.contactPhone" placeholder="èç³»çµè¯"> |
| | | <template #prepend> |
| | | <el-icon><Iphone /></el-icon> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="è®¾å¤æè¿°" prop="description"> |
| | | <el-input |
| | | clearable |
| | | v-model="formObj.description" |
| | | placeholder="è®¾å¤æè¿°" |
| | | type="textarea" |
| | | rows="2" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <el-button :disabled="!edit" type="primary" @click="onSubmit" :loading="updateLoading" |
| | | >æäº¤</el-button |
| | | > |
| | | <el-button :disabled="!edit" @click="onReset">éç½®</el-button> |
| | | <el-button v-if="create" @click="cancel">åæ¶</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { defineProps, defineEmits, reactive, ref, watch } from 'vue' |
| | | import { Iphone } from '@element-plus/icons-vue' |
| | | import { useFormConfirm } from '@/composables/formConfirm' |
| | | |
| | | const props = defineProps({ |
| | | //设å¤ä¿¡æ¯ |
| | | formInfo: Object, |
| | | //æ¯å建æè
æ´æ° |
| | | create: Boolean, |
| | | }) |
| | | const emit = defineEmits(['onSubmit', 'onCancel']) |
| | | |
| | | const { formObj, formRef, edit, onSubmit, onReset } = useFormConfirm({ |
| | | submit: { |
| | | do: submit, |
| | | }, |
| | | cancel: { |
| | | do: cancel, |
| | | }, |
| | | }) |
| | | const updateLoading = ref(false) |
| | | const rules = reactive({ |
| | | deviceName: [ |
| | | { |
| | | required: true, |
| | | message: '设å¤åç§°ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | deviceModel: [ |
| | | { |
| | | required: true, |
| | | message: '设å¤åå·ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | deviceCode: [ |
| | | { |
| | | required: true, |
| | | message: '设å¤ç¼å·ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | manufacturer: [ |
| | | { |
| | | required: true, |
| | | message: 'ç产åå®¶ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | status: [ |
| | | { |
| | | required: true, |
| | | message: '设å¤ç¶æä¸è½ä¸ºç©º', |
| | | trigger: 'change', |
| | | }, |
| | | ], |
| | | }) |
| | | |
| | | // 设å¤ä¿¡æ¯æ ¼å¼å |
| | | function parseDeviceInfo(s) { |
| | | return s |
| | | } |
| | | |
| | | function updateDevice() { |
| | | updateLoading.value = true |
| | | // è¿éå¯ä»¥æ·»å å®é
çAPIè°ç¨ |
| | | setTimeout(() => { |
| | | updateLoading.value = false |
| | | }, 1000) |
| | | } |
| | | |
| | | watch( |
| | | () => props.formInfo, |
| | | (nValue) => { |
| | | formObj.value = parseDeviceInfo(nValue) |
| | | }, |
| | | ) |
| | | |
| | | function submit() { |
| | | emit('onSubmit', formObj) |
| | | return updateDevice() |
| | | } |
| | | function cancel() { |
| | | emit('onCancel') |
| | | } |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template>s</template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template>s</template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-form |
| | | :inline="false" |
| | | :model="formObj" |
| | | ref="formRef" |
| | | :rules="rules" |
| | | label-position="right" |
| | | label-width="150px" |
| | | > |
| | | <el-form-item label="åºéºåç§°" prop="shopName"> |
| | | <el-input clearable v-model="formObj.shopName" placeholder="åºéºåç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="æå±å
¬å¸" prop="company"> |
| | | <el-input clearable v-model="formObj.company" placeholder="æå±å
¬å¸" /> |
| | | </el-form-item> |
| | | <el-form-item label="éä¸åº" prop="centralArea"> |
| | | <el-input clearable v-model="formObj.centralArea" placeholder="éä¸åº" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç©ä¸å
¬å¸" prop="propertyCompany"> |
| | | <el-input clearable v-model="formObj.propertyCompany" placeholder="ç©ä¸å
¬å¸" /> |
| | | </el-form-item> |
| | | <el-form-item label="è系人" prop="contactName"> |
| | | <el-input clearable v-model="formObj.contactName" placeholder="è系人" /> |
| | | </el-form-item> |
| | | <el-form-item label="èç³»çµè¯" prop="telephone"> |
| | | <el-input clearable type="tel" v-model="formObj.telephone" placeholder="èç³»çµè¯"> |
| | | <template #prepend> |
| | | <el-icon><Iphone /></el-icon> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å°å" prop="address"> |
| | | <el-input clearable v-model="formObj.address" placeholder="å°å" type="textarea" rows="2" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <el-button :disabled="!edit" type="primary" @click="onSubmit" :loading="updateLoading" |
| | | >æäº¤</el-button |
| | | > |
| | | <el-button :disabled="!edit" @click="onReset">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { defineProps, defineEmits, reactive, ref, watch } from 'vue' |
| | | import { Iphone } from '@element-plus/icons-vue' |
| | | import { useFormConfirm } from '@/composables/formConfirm' |
| | | |
| | | const props = defineProps({ |
| | | //åºæ¬ä¿¡æ¯ |
| | | formInfo: Object, |
| | | //æ¯å建æè
æ´æ° |
| | | create: Boolean, |
| | | }) |
| | | const emit = defineEmits(['onSubmit', 'onCancel']) |
| | | |
| | | const { formObj, formRef, edit, onSubmit, onReset } = useFormConfirm({ |
| | | submit: { |
| | | do: submit, |
| | | }, |
| | | cancel: { |
| | | do: cancel, |
| | | }, |
| | | }) |
| | | const updateLoading = ref(false) |
| | | const rules = reactive({ |
| | | shopName: [ |
| | | { |
| | | required: true, |
| | | message: 'åºéºåç§°ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | company: [ |
| | | { |
| | | required: true, |
| | | message: 'æå±å
¬å¸ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | contactName: [ |
| | | { |
| | | required: true, |
| | | message: 'è系人ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | telephone: [ |
| | | { |
| | | required: true, |
| | | message: 'èç³»çµè¯ä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | address: [ |
| | | { |
| | | required: true, |
| | | message: 'å°åä¸è½ä¸ºç©º', |
| | | trigger: 'blur', |
| | | }, |
| | | ], |
| | | }) |
| | | |
| | | // åºæ¯åºæ¬ä¿¡æ¯æ ¼å¼å |
| | | function parseSceneBaseInfo(s) { |
| | | return s |
| | | } |
| | | |
| | | function updateScene() { |
| | | updateLoading.value = true |
| | | // è¿éå¯ä»¥æ·»å å®é
çAPIè°ç¨ |
| | | setTimeout(() => { |
| | | updateLoading.value = false |
| | | }, 1000) |
| | | } |
| | | |
| | | watch( |
| | | () => props.formInfo, |
| | | (nValue) => { |
| | | formObj.value = parseSceneBaseInfo(nValue) |
| | | }, |
| | | ) |
| | | |
| | | function submit() { |
| | | emit('onSubmit', formObj) |
| | | return updateScene() |
| | | } |
| | | function cancel() { |
| | | emit('onCancel') |
| | | } |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <FYForm |
| | | :form-info="formInfo" |
| | | :rules="rules" |
| | | :doClear="active" |
| | | :useCancel="create" |
| | | :useReset="!create" |
| | | @update:isEdit="(v) => $emit('updateEdit', v)" |
| | | @submit="submit" |
| | | @cancel="$emit('onCancel')" |
| | | > |
| | | <template #form-item="{ formObj }"> |
| | | <!-- <el-form-item label="头åurl" prop="HeadIconUrl"> |
| | | <el-input |
| | | clearable |
| | | v-model="formObj.HeadIconUrl" |
| | | placeholder="头åurl" |
| | | /> |
| | | </el-form-item> --> |
| | | <el-form-item label="è´¦æ·å" prop="acountname"> |
| | | <el-input clearable v-model="formObj.acountname" placeholder="è´¦æ·å" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¨æ·æµç§°" prop="realname"> |
| | | <el-input clearable v-model="formObj.realname" placeholder="ç¨æ·æµç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="å¯ç " prop="password"> |
| | | <el-col :span="18"> |
| | | <el-input |
| | | :disabled="true" |
| | | clearable |
| | | type="password" |
| | | v-model="formObj.password" |
| | | placeholder="é»è®¤å¯ç 123456" |
| | | /> |
| | | </el-col> |
| | | <el-col :span="6" v-if="!create"> |
| | | <el-row justify="end"> |
| | | <el-button type="danger" @click="onResetPw" :loading="pwLoading">éç½®å¯ç </el-button> |
| | | </el-row> |
| | | </el-col> |
| | | </el-form-item> |
| | | <FYOptionUserType |
| | | prop="_usertype" |
| | | :allOption="false" |
| | | :initValue="false" |
| | | v-model:value="formObj._usertype" |
| | | ></FYOptionUserType> |
| | | <!-- <el-form-item label="æå±ä¼ä¸" prop="departmentname"> |
| | | <el-input |
| | | clearable |
| | | v-model="formObj.departmentname" |
| | | placeholder="æå±ä¼ä¸" |
| | | disabled |
| | | /> |
| | | </el-form-item> --> |
| | | <el-form-item label="æ¯å¦å¯ç¨" prop="isenable"> |
| | | <el-switch v-model="formObj.isenable" /> |
| | | <span style="margin-left: 16px">{{ formObj.isenable ? 'å¯ç¨' : 'ä¸å¯ç¨' }}</span> |
| | | </el-form-item> |
| | | <el-form-item label="å·¥å·" prop="workno"> |
| | | <el-input clearable v-model="formObj.workno" placeholder="å·¥å·" /> |
| | | </el-form-item> |
| | | <el-form-item label="ææº" prop="telephone"> |
| | | <el-input clearable type="tel" v-model="formObj.telephone" placeholder="ææº" /> |
| | | </el-form-item> |
| | | <FYOptionLocation |
| | | v-if="create" |
| | | prop="_locations" |
| | | :allOption="false" |
| | | :level="5" |
| | | :checkStrictly="true" |
| | | :initValue="false" |
| | | v-model:value="formObj._locations" |
| | | ></FYOptionLocation> |
| | | <FYOptionScene |
| | | prop="_scenetype" |
| | | :allOption="false" |
| | | :type="1" |
| | | :initValue="false" |
| | | v-model:value="formObj._scenetype" |
| | | ></FYOptionScene> |
| | | </template> |
| | | </FYForm> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { defineProps, defineEmits, reactive, ref, watch, computed } from 'vue'; |
| | | import { getSceneName } from '@/enum/scene'; |
| | | import userApi from '@/api/fytz/userApi'; |
| | | import { useMessageBoxTip } from '@/composables/messageBox'; |
| | | |
| | | const props = defineProps({ |
| | | //åºæ¬ä¿¡æ¯ |
| | | model: { |
| | | type: Object |
| | | // default: () => { |
| | | // return { isenable: true }; |
| | | // } |
| | | }, |
| | | create: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | active: { |
| | | type: Boolean, |
| | | default: false |
| | | } |
| | | }); |
| | | |
| | | const formInfo = ref({ isenable: true }); |
| | | |
| | | watch( |
| | | () => props.model, |
| | | (nValue) => { |
| | | formInfo.value = parseUserInfo(nValue); |
| | | } |
| | | ); |
| | | |
| | | const emit = defineEmits(['onSubmit', 'onCancel', 'updateEdit']); |
| | | |
| | | const rules = reactive({ |
| | | acountname: [ |
| | | { |
| | | required: true, |
| | | message: 'è´¦æ·åä¸è½ä¸ºç©º', |
| | | trigger: 'blur' |
| | | } |
| | | ], |
| | | realname: [ |
| | | { |
| | | required: true, |
| | | message: 'ç¨æ·æµç§°ä¸è½ä¸ºç©º', |
| | | trigger: 'blur' |
| | | } |
| | | ] |
| | | // password: [ |
| | | // { |
| | | // required: props.create, |
| | | // message: 'å¯ç ä¸è½ä¸ºç©º', |
| | | // trigger: 'blur', |
| | | // }, |
| | | // ], |
| | | }); |
| | | |
| | | // ç¨æ·åºæ¬ä¿¡æ¯æ ¼å¼å |
| | | function parseUserInfo(s) { |
| | | if (s.usertype && s.usertypeid) { |
| | | s._usertype = { |
| | | label: s.usertype, |
| | | value: s.usertypeid + '' |
| | | }; |
| | | } |
| | | |
| | | if (s.extension2) { |
| | | s._scenetype = getSceneName(s.extension2, 1); |
| | | } |
| | | |
| | | s._locations = {}; |
| | | |
| | | return s; |
| | | } |
| | | |
| | | function parseUserInfoReverse(v) { |
| | | // è¡æ¿åºåä¿¡æ¯å¡«å
|
| | | const a = v._locations; |
| | | v.extension1 = a.dName; |
| | | // ç¨æ·ç±»åä¿¡æ¯å¡«å
|
| | | const b = v._usertype; |
| | | v.usertypeid = b.value; |
| | | v.usertype = b.label; |
| | | |
| | | // åºæ¯ç±»åä¿¡æ¯å¡«å
|
| | | const c = v._scenetype; |
| | | v.extension2 = c.value; |
| | | |
| | | return v; |
| | | } |
| | | |
| | | function createUser(v, success, fail) { |
| | | const l = v._locations; |
| | | const params = { |
| | | userInfo: v, |
| | | baseInfo: { |
| | | biProvinceCode: l.pCode, |
| | | biProvinceName: l.pName, |
| | | biCityCode: l.cCode, |
| | | biCityName: l.cName, |
| | | biDistrictCode: l.dCode, |
| | | biDistrictName: l.dName, |
| | | biTownCode: l.tCode, |
| | | biTownName: l.tName, |
| | | biAreaCode: l.aCode, |
| | | biArea: l.aName |
| | | // biManagementCompanyId: |
| | | // biManagementCompany: |
| | | // biContact |
| | | // biTelephone |
| | | // biAddress |
| | | } |
| | | }; |
| | | return userApi |
| | | .createUser(params) |
| | | .then(() => { |
| | | emit('onSubmit', params); |
| | | success(); |
| | | }) |
| | | .catch((err) => { |
| | | fail(err); |
| | | }); |
| | | } |
| | | |
| | | function updateUser(v, success, fail) { |
| | | return userApi |
| | | .updateUserInfo(v) |
| | | .then(() => { |
| | | emit('onSubmit', v); |
| | | if (success) success(); |
| | | }) |
| | | .catch((err) => { |
| | | if (fail) fail(err); |
| | | }); |
| | | } |
| | | |
| | | function submit(v, success, fail) { |
| | | parseUserInfoReverse(v.value); |
| | | |
| | | return props.create ? createUser(v.value, success, fail) : updateUser(v.value, success, fail); |
| | | // parseUserInfoReverse(props.formInfo); |
| | | |
| | | // return props.create |
| | | // ? createUser(props.formInfo, success, fail) |
| | | // : updateUser(props.formInfo, success, fail); |
| | | } |
| | | |
| | | // éç½®å¯ç |
| | | const pwLoading = ref(false); |
| | | |
| | | function onResetPw() { |
| | | useMessageBoxTip({ |
| | | confirmMsg: 'æ¯å¦éç½®è¯¥åºæ¯å¯ç ï¼', |
| | | confirmTitle: 'éç½®å¯ç ', |
| | | onConfirm: async () => { |
| | | pwLoading.value = true; |
| | | return userApi.resetPassword(formInfo.value.guid).finally(() => { |
| | | pwLoading.value = false; |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-drawer |
| | | title="æ°å¢ç¨æ·" |
| | | direction="rtl" |
| | | :model-value="modelValue" |
| | | @open="updateDrawer(true)" |
| | | @close="updateDrawer(false)" |
| | | :before-close="onDrawerClose" |
| | | > |
| | | <CompUserInfo |
| | | :create="true" |
| | | :active="modelValue" |
| | | @updateEdit="(v) => (drawerEdit = v)" |
| | | @on-submit="updateDrawer(false)" |
| | | @on-cancel="updateDrawer(false)" |
| | | ></CompUserInfo> |
| | | </el-drawer> |
| | | </template> |
| | | |
| | | <script> |
| | | import CompUserInfo from './CompUserInfo.vue'; |
| | | import { useMessageBox } from '@/composables/messageBox'; |
| | | |
| | | export default { |
| | | components: { CompUserInfo }, |
| | | props: ['modelValue'], |
| | | emits: ['update:modelValue'], |
| | | data() { |
| | | return { |
| | | drawerEdit: false |
| | | }; |
| | | }, |
| | | methods: { |
| | | updateDrawer(status) { |
| | | this.$emit('update:modelValue', status); |
| | | }, |
| | | onDrawerClose(done) { |
| | | if (this.drawerEdit) { |
| | | // å¼¹åºç¡®è®¤æ¡ |
| | | useMessageBox({ |
| | | confirmMsg: 'æ¯å¦æ¾å¼å·²ç¼è¾çå
容ï¼', |
| | | confirmTitle: 'å
³éå¼¹åºæ¡', |
| | | onConfirm: () => { |
| | | done(); |
| | | } |
| | | }); |
| | | } else { |
| | | // ç´æ¥å
³é |
| | | done(); |
| | | } |
| | | }, |
| | | } |
| | | }; |
| | | </script> |
| | |
| | | <template> |
| | | <el-container class="data-dashboard"> |
| | | <el-main> |
| | | <div class="grid-container"> |
| | | <div class="left-section"> |
| | | <!-- 设å¤å¨çº¿æ
åµåºå --> |
| | | <DeviceStatus |
| | | :online-count="onlineCount" |
| | | :offline-count="offlineCount" |
| | | :normal-count="normalCount" |
| | | :fault-count="faultCount" |
| | | /> |
| | | <!-- ååºæ°æ®æååºå --> |
| | | <DistrictRanking |
| | | style="flex: 1" |
| | | :selected-month="selectedMonth" |
| | | :ranking-type="rankingType" |
| | | :ranking-data="rankingData" |
| | | :sorted-ranking-data="sortedRankingData" |
| | | @month-change="handleMonthChange" |
| | | @type-change="handleTypeChange" |
| | | /> |
| | | <div class="data-dashboard"> |
| | | <!-- 顶鍿æ å¡çåº --> |
| | | <div class="top-cards"> |
| | | <div class="cards-container"> |
| | | <!-- æ¶é´å¨æé项å¡ç --> |
| | | <div class="time-period-card"> |
| | | <div class="card-title">æ¶é´å¨æ</div> |
| | | <div class="time-tab-container"> |
| | | <div |
| | | v-for="tab in timeTabs" |
| | | :key="tab.value" |
| | | class="time-tab" |
| | | :class="{ active: activeTime === tab.value }" |
| | | @click="handleTimeChange(tab)" |
| | | > |
| | | {{ tab.label }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="right-section"> |
| | | <!-- 设å¤å®æ¶æ°æ®åºå --> |
| | | <RealTimeData style="flex: 1" :devices="devices" /> |
| | | |
| | | <!-- è¶
æ æ° --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">{{ getPeriodLabel() }}è¶
æ æ°</div> |
| | | <div class="card-icon warning-icon"> |
| | | <svg |
| | | width="20" |
| | | height="20" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path d="M12 9V13" stroke="currentColor" stroke-width="2" stroke-linecap="round" /> |
| | | <path |
| | | d="M12 17.5V17" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | /> |
| | | <path |
| | | d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.overStandardCount }}</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ up: metrics.overStandardTrend > 0, down: metrics.overStandardTrend < 0 }" |
| | | > |
| | | {{ metrics.overStandardTrend > 0 ? 'â' : 'â' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.overStandardTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- å¨çº¿ç --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">å¨çº¿ç</div> |
| | | <div class="card-icon online-icon"> |
| | | <svg |
| | | width="20" |
| | | height="20" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path |
| | | d="M9 12L11 14L15 10" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | <path |
| | | d="M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.onlineRate }}%</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ up: metrics.onlineRateTrend > 0, down: metrics.onlineRateTrend < 0 }" |
| | | > |
| | | {{ metrics.onlineRateTrend > 0 ? 'â' : 'â' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.onlineRateTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- ååå¨è¿è¡æç --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">ååå¨è¿è¡æç</div> |
| | | <div class="card-icon efficiency-icon"> |
| | | <svg |
| | | width="20" |
| | | height="20" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path |
| | | d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2Z" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | <path |
| | | d="M12 6V12L16 14" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.purifierEfficiency }}%</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ |
| | | up: metrics.purifierEfficiencyTrend > 0, |
| | | down: metrics.purifierEfficiencyTrend < 0, |
| | | }" |
| | | > |
| | | {{ metrics.purifierEfficiencyTrend > 0 ? 'â' : 'â' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.purifierEfficiencyTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- ä»»å¡å®æç --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">ä»»å¡å®æç</div> |
| | | <div class="card-icon task-icon"> |
| | | <svg |
| | | width="20" |
| | | height="20" |
| | | viewBox="0 0 24 24" |
| | | fill="none" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | > |
| | | <path |
| | | d="M22 11.08V12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C15.7376 2 19.0503 4.16113 20.7748 7.33007" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | <path |
| | | d="M22 4L12 14.01L9 11.01" |
| | | stroke="currentColor" |
| | | stroke-width="2" |
| | | stroke-linecap="round" |
| | | stroke-linejoin="round" |
| | | /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.taskCompletionRate }}%</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ |
| | | up: metrics.taskCompletionRateTrend > 0, |
| | | down: metrics.taskCompletionRateTrend < 0, |
| | | }" |
| | | > |
| | | {{ metrics.taskCompletionRateTrend > 0 ? 'â' : 'â' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.taskCompletionRateTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- å¨çº¿è®¾å¤ååºéºæ¸
ååºå --> |
| | | <ShopList |
| | | :shops="shops" |
| | | :shop-types="shopTypes" |
| | | :districts="districts" |
| | | :filter="filter" |
| | | @filter-change="handleFilterChange" |
| | | /> |
| | | </el-main> |
| | | </el-container> |
| | | <!-- 主è¦å
å®¹åº --> |
| | | <div class="main-content"> |
| | | <!-- ä¸é¨GISå°å¾åº --> |
| | | <div class="map-section"> |
| | | <div id="map" class="map-container"> |
| | | <BaseMap></BaseMap> |
| | | </div> |
| | | |
| | | <!-- å°å¾ç¹ä½å¼¹çª --> |
| | | <el-dialog v-model="dialogVisible" title="ä¼ä¸å®æ¶æ°æ®" width="400px"> |
| | | <div class="dialog-content"> |
| | | <el-descriptions :column="1" border> |
| | | <el-descriptions-item label="ä¼ä¸åç§°">{{ |
| | | selectedPoint.enterpriseName |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="设å¤ç¼å·">{{ |
| | | selectedPoint.deviceId |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ²¹çæµåº¦" |
| | | >{{ selectedPoint.oilSmokeConcentration }} mg/m³</el-descriptions-item |
| | | > |
| | | <el-descriptions-item label="é¢ç²ç©" |
| | | >{{ selectedPoint.particulateMatter }} mg/m³</el-descriptions-item |
| | | > |
| | | <el-descriptions-item label="éç²ç·æ»ç" |
| | | >{{ selectedPoint.nonMethaneHydrocarbon }} mg/m³</el-descriptions-item |
| | | > |
| | | <el-descriptions-item label="çæµæ¶é´">{{ |
| | | selectedPoint.monitoringTime |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="è¶
æ æ
åµ"> |
| | | <el-tag :type="selectedPoint.isOverStandard ? 'danger' : 'success'"> |
| | | {{ selectedPoint.isOverStandard ? 'è¶
æ ' : 'æ£å¸¸' }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">å
³é</el-button> |
| | | <el-button type="primary" @click="viewDetails">æ¥ç详æ
</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | |
| | | <!-- å³ä¾§å®æ¶çæµæ»è§åº --> |
| | | <div class="overview-section"> |
| | | <div class="section-header"> |
| | | <h3>宿¶çæµæ»è§</h3> |
| | | <span class="view-more">æ¥çæ´å¤</span> |
| | | </div> |
| | | |
| | | <div class="overview-items-container"> |
| | | <div class="overview-item"> |
| | | <div class="overview-label">é¤é¥®åºéºæ»æ°</div> |
| | | <div class="overview-value">{{ overview.totalShops }}</div> |
| | | </div> |
| | | |
| | | <div class="overview-item"> |
| | | <div class="overview-label">å¨çº¿è®¾å¤æ°</div> |
| | | <div class="overview-value">{{ overview.onlineDevices }}</div> |
| | | </div> |
| | | |
| | | <div class="overview-item"> |
| | | <div class="overview-label">ç¦»çº¿è®¾å¤æ°</div> |
| | | <div class="overview-value">{{ overview.offlineDevices }}</div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 设å¤ç¶æé¥¼å¾ --> |
| | | <div class="device-status-chart"> |
| | | <canvas id="deviceStatusChart"></canvas> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import DeviceStatus from '@/components/monitor/DeviceStatus.vue' |
| | | import RealTimeData from '@/components/monitor/RealTimeData.vue' |
| | | import DistrictRanking from '@/components/monitor/DistrictRanking.vue' |
| | | import ShopList from '@/components/monitor/ShopList.vue' |
| | | import * as echarts from 'echarts' |
| | | import { onMapMounted, map, AMap } from '@/utils/map/index' |
| | | import districtSearch from '@/utils/map/districtsearch.js' |
| | | |
| | | export default { |
| | | name: 'DataDashboard', |
| | | components: { |
| | | DeviceStatus, |
| | | RealTimeData, |
| | | DistrictRanking, |
| | | ShopList, |
| | | }, |
| | | data() { |
| | | return { |
| | | // 设å¤å¨çº¿æ
嵿°æ® |
| | | onlineCount: 0, |
| | | offlineCount: 0, |
| | | normalCount: 0, |
| | | faultCount: 0, |
| | | |
| | | // 设å¤å®æ¶æ°æ® |
| | | devices: [], |
| | | |
| | | // ååºæ°æ®æå |
| | | selectedMonth: '2023-12', |
| | | rankingType: 'hourly', |
| | | rankingData: [], |
| | | sortedRankingData: [], |
| | | |
| | | // ç鿡件 |
| | | filter: { |
| | | district: '', |
| | | shopType: '', |
| | | status: '', |
| | | }, |
| | | shopTypes: ['ä¸é¤', '西é¤', 'å¿«é¤', 'ç«é
', 'ç§ç¤'], |
| | | districts: ['ä¸ååº', '西ååº', 'æé³åº', 'æµ·æ·åº', '丰å°åº'], |
| | | |
| | | // åºéºæ°æ® |
| | | shops: [ |
| | | { |
| | | id: 1, |
| | | name: 'å¼ ä¸é¤å
', |
| | | deviceCount: 2, |
| | | status: 'å¨çº¿', |
| | | district: 'ä¸ååº', |
| | | type: 'ä¸é¤', |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: 'æåé¥åº', |
| | | deviceCount: 1, |
| | | status: '离线', |
| | | district: '西ååº', |
| | | type: '西é¤', |
| | | }, |
| | | { |
| | | id: 3, |
| | | name: 'çäºå°å', |
| | | deviceCount: 3, |
| | | status: 'å¨çº¿', |
| | | district: 'æé³åº', |
| | | type: 'å¿«é¤', |
| | | }, |
| | | { |
| | | id: 4, |
| | | name: 'èµµå
ç«é
', |
| | | deviceCount: 2, |
| | | status: 'å¨çº¿', |
| | | district: 'æµ·æ·åº', |
| | | type: 'ç«é
', |
| | | }, |
| | | { |
| | | id: 5, |
| | | name: 'é±ä¸ç§ç¤', |
| | | deviceCount: 1, |
| | | status: '离线', |
| | | district: '丰å°åº', |
| | | type: 'ç§ç¤', |
| | | }, |
| | | activeTime: 'day', |
| | | timeTabs: [ |
| | | { label: 'æ¥', value: 'day' }, |
| | | { label: 'å¨', value: 'week' }, |
| | | { label: 'æ', value: 'month' }, |
| | | ], |
| | | dialogVisible: false, |
| | | selectedPoint: { |
| | | enterpriseName: '', |
| | | deviceId: '', |
| | | oilSmokeConcentration: 0, |
| | | particulateMatter: 0, |
| | | nonMethaneHydrocarbon: 0, |
| | | monitoringTime: '', |
| | | isOverStandard: false, |
| | | }, |
| | | metrics: { |
| | | overStandardCount: 12, |
| | | overStandardTrend: 5, |
| | | onlineRate: 92, |
| | | onlineRateTrend: 2, |
| | | purifierEfficiency: 85, |
| | | purifierEfficiencyTrend: -3, |
| | | taskCompletionRate: 78, |
| | | taskCompletionRateTrend: 10, |
| | | }, |
| | | overview: { |
| | | totalShops: 245, |
| | | onlineDevices: 220, |
| | | offlineDevices: 25, |
| | | }, |
| | | map: null, |
| | | refreshTimer: null, |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.initData() |
| | | this.startRealTimeUpdate() |
| | | this.initMap() |
| | | this.initDeviceStatusChart() |
| | | this.startAutoRefresh() |
| | | }, |
| | | beforeUnmount() { |
| | | if (this.refreshTimer) { |
| | | clearInterval(this.refreshTimer) |
| | | } |
| | | }, |
| | | methods: { |
| | | initData() { |
| | | // åå§å设å¤å¨çº¿æ
嵿°æ® |
| | | this.updateDeviceStatus() |
| | | |
| | | // åå§å宿¶æ°æ® |
| | | this.updateRealTimeData() |
| | | |
| | | // åå§åååºæ°æ®æå |
| | | this.updateRankingData() |
| | | handleTimeChange(tab) { |
| | | this.activeTime = tab.value |
| | | // 模æåæ¢æ¶é´å¨æåçæ°æ®æ´æ° |
| | | this.updateMetrics() |
| | | }, |
| | | |
| | | updateDeviceStatus() { |
| | | // æ¨¡ææ°æ® - å®é
åºä»APIè·å |
| | | this.onlineCount = Math.floor(Math.random() * 50) + 50 |
| | | this.offlineCount = Math.floor(Math.random() * 20) |
| | | this.normalCount = this.onlineCount |
| | | this.faultCount = this.offlineCount |
| | | getPeriodLabel() { |
| | | switch (this.activeTime) { |
| | | case 'day': |
| | | return '仿¥' |
| | | case 'week': |
| | | return 'æ¬å¨' |
| | | case 'month': |
| | | return 'æ¬æ' |
| | | default: |
| | | return '仿¥' |
| | | } |
| | | }, |
| | | |
| | | updateRealTimeData() { |
| | | // æ¨¡ææ°æ® - å®é
åºä»APIè·å |
| | | this.devices = [ |
| | | { |
| | | deviceId: 'DEV-001', |
| | | supplier: 'ä¾åºåA', |
| | | status: 'æ£å¸¸', |
| | | monitorTime: new Date().toLocaleString(), |
| | | smokeDensity: (Math.random() * 2).toFixed(2), |
| | | fanCurrent: (Math.random() * 5 + 1).toFixed(2), |
| | | purifierCurrent: (Math.random() * 3 + 0.5).toFixed(2), |
| | | hourlyData: this.generateHourlyData(), |
| | | }, |
| | | { |
| | | deviceId: 'DEV-002', |
| | | supplier: 'ä¾åºåB', |
| | | status: 'æ£å¸¸', |
| | | monitorTime: new Date().toLocaleString(), |
| | | smokeDensity: (Math.random() * 2).toFixed(2), |
| | | fanCurrent: (Math.random() * 5 + 1).toFixed(2), |
| | | purifierCurrent: (Math.random() * 3 + 0.5).toFixed(2), |
| | | hourlyData: this.generateHourlyData(), |
| | | }, |
| | | { |
| | | deviceId: 'DEV-003', |
| | | supplier: 'ä¾åºåC', |
| | | status: 'å¼å¸¸', |
| | | monitorTime: new Date().toLocaleString(), |
| | | smokeDensity: (Math.random() * 15 + 5).toFixed(2), |
| | | fanCurrent: (Math.random() * 3 + 4).toFixed(2), |
| | | purifierCurrent: (Math.random() * 2 + 2).toFixed(2), |
| | | hourlyData: this.generateHourlyData(), |
| | | }, |
| | | { |
| | | deviceId: 'DEV-004', |
| | | supplier: 'ä¾åºåD', |
| | | status: 'å¼å¸¸', |
| | | monitorTime: new Date().toLocaleString(), |
| | | smokeDensity: (Math.random() * 15 + 5).toFixed(2), |
| | | fanCurrent: (Math.random() * 3 + 4).toFixed(2), |
| | | purifierCurrent: (Math.random() * 2 + 2).toFixed(2), |
| | | hourlyData: this.generateHourlyData(), |
| | | }, |
| | | ] |
| | | getCompareLabel() { |
| | | switch (this.activeTime) { |
| | | case 'day': |
| | | return 'è¾æ¨æ¥' |
| | | case 'week': |
| | | return 'è¾ä¸å¨' |
| | | case 'month': |
| | | return 'è¾ä¸æ' |
| | | default: |
| | | return 'è¾æ¨æ¥' |
| | | } |
| | | }, |
| | | updateMetrics() { |
| | | // è¿éåºè¯¥æ ¹æ®éæ©çæ¶é´å¨æä»æ¥å£è·åæ°æ® |
| | | // æ¨¡ææ°æ®æ´æ° |
| | | setTimeout(() => { |
| | | this.metrics = { |
| | | overStandardCount: Math.floor(Math.random() * 30), |
| | | overStandardTrend: Math.floor(Math.random() * 20) - 10, |
| | | onlineRate: Math.floor(Math.random() * 20) + 80, |
| | | onlineRateTrend: Math.floor(Math.random() * 10) - 5, |
| | | purifierEfficiency: Math.floor(Math.random() * 30) + 70, |
| | | purifierEfficiencyTrend: Math.floor(Math.random() * 10) - 5, |
| | | taskCompletionRate: Math.floor(Math.random() * 40) + 60, |
| | | taskCompletionRateTrend: Math.floor(Math.random() * 15) - 7, |
| | | } |
| | | }, 300) |
| | | }, |
| | | initMap() { |
| | | // setTimeout(() => { |
| | | districtSearch.removeDistrict() |
| | | districtSearch.drawDistrict('䏿µ·å¸') |
| | | // districtSearch.districtLayer('310106') |
| | | // }, 2000) |
| | | }, |
| | | initDeviceStatusChart() { |
| | | const chartDom = document.getElementById('deviceStatusChart') |
| | | if (chartDom) { |
| | | const chart = echarts.init(chartDom) |
| | | const option = { |
| | | tooltip: { |
| | | trigger: 'item', |
| | | formatter: '{b}: {c} ({d}%)', |
| | | backgroundColor: 'rgba(255, 255, 255, 0.95)', |
| | | borderColor: '#e8e8e8', |
| | | borderWidth: 1, |
| | | textStyle: { |
| | | color: '#333', |
| | | }, |
| | | }, |
| | | legend: { |
| | | bottom: '0%', |
| | | left: 'center', |
| | | textStyle: { |
| | | color: '#86909c', |
| | | fontSize: 12, |
| | | }, |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '设å¤ç¶æ', |
| | | type: 'pie', |
| | | radius: ['50%', '75%'], |
| | | center: ['50%', '45%'], |
| | | avoidLabelOverlap: false, |
| | | itemStyle: { |
| | | borderRadius: 8, |
| | | borderColor: '#ffffff', |
| | | borderWidth: 2, |
| | | shadowBlur: 5, |
| | | shadowOffsetX: 0, |
| | | shadowColor: 'rgba(0, 0, 0, 0.1)', |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'center', |
| | | formatter: '{d}%', |
| | | fontSize: 18, |
| | | fontWeight: 'bold', |
| | | color: '#262626', |
| | | }, |
| | | labelLine: { |
| | | show: false, |
| | | }, |
| | | data: [ |
| | | { |
| | | value: this.overview.onlineDevices, |
| | | name: 'å¨çº¿', |
| | | itemStyle: { |
| | | color: '#1890ff', |
| | | }, |
| | | }, |
| | | { |
| | | value: this.overview.offlineDevices, |
| | | name: '离线', |
| | | itemStyle: { |
| | | color: '#f5222d', |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ], |
| | | } |
| | | chart.setOption(option) |
| | | |
| | | generateHourlyData() { |
| | | // çææ¨¡æçè¿ä¸å°æ¶æ°æ® |
| | | const hourlyData = [] |
| | | for (let i = 59; i >= 0; i--) { |
| | | const time = new Date() |
| | | time.setMinutes(time.getMinutes() - i) |
| | | hourlyData.push({ |
| | | time: time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }), |
| | | smokeDensity: (Math.random() * 2).toFixed(2), |
| | | fanCurrent: (Math.random() * 5 + 1).toFixed(2), |
| | | purifierCurrent: (Math.random() * 3 + 0.5).toFixed(2), |
| | | // ååºå¼è°æ´ |
| | | window.addEventListener('resize', () => { |
| | | chart.resize() |
| | | }) |
| | | } |
| | | return hourlyData |
| | | }, |
| | | |
| | | updateRankingData() { |
| | | // æ¨¡ææ°æ® - å®é
åºä»APIè·å |
| | | this.rankingData = [ |
| | | { name: 'çæ¦åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 }, |
| | | { name: '秦淮åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -1 }, |
| | | { name: '建éºåº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 }, |
| | | { name: '鼿¥¼åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 }, |
| | | { name: '浦å£åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -2 }, |
| | | { name: 'æ éåº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 2 }, |
| | | { name: 'é¨è±å°åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 }, |
| | | { name: 'æ±å®åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 }, |
| | | { name: 'å
ååº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -1 }, |
| | | { name: '溧水åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 }, |
| | | { name: '髿·³åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 }, |
| | | ] |
| | | |
| | | // æåº |
| | | this.sortedRankingData = [...this.rankingData].sort( |
| | | (a, b) => parseFloat(b.value) - parseFloat(a.value), |
| | | ) |
| | | }, |
| | | |
| | | startRealTimeUpdate() { |
| | | // æ¯30ç§æ´æ°ä¸æ¬¡æ°æ® |
| | | this.realTimeInterval = setInterval(() => { |
| | | this.updateDeviceStatus() |
| | | this.updateRealTimeData() |
| | | startAutoRefresh() { |
| | | // æ¯30ç§èªå¨å·æ°æ°æ® |
| | | this.refreshTimer = setInterval(() => { |
| | | this.updateMetrics() |
| | | // è¿éåºè¯¥åæ¶æ´æ°å°å¾ç¹ä½æ°æ® |
| | | }, 30000) |
| | | }, |
| | | |
| | | handleMonthChange(val) { |
| | | this.selectedMonth = val |
| | | this.updateRankingData() |
| | | }, |
| | | |
| | | handleTypeChange(val) { |
| | | this.rankingType = val |
| | | this.updateRankingData() |
| | | }, |
| | | |
| | | handleFilterChange(val) { |
| | | this.filter = { ...val } |
| | | viewDetails() { |
| | | // 跳转å°ä¼ä¸çæ§è¯¦æ
页 |
| | | this.$router.push('/monitor/enterprise-detail') |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | /* å
¨å±æ ·å¼ */ |
| | | .data-dashboard { |
| | | min-height: 100vh; |
| | | width: 100%; |
| | | height: calc(100vh - 60px); |
| | | background-color: #f5f7fa; |
| | | color: #333; |
| | | box-sizing: border-box; |
| | | font-family: |
| | | -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; |
| | | position: relative; |
| | | } |
| | | |
| | | .el-header { |
| | | /* 顶鍿æ å¡çåº */ |
| | | .top-cards { |
| | | position: absolute; |
| | | top: 24px; |
| | | left: 24px; |
| | | z-index: 10; |
| | | margin-bottom: 24px; |
| | | } |
| | | |
| | | .cards-container { |
| | | display: grid; |
| | | grid-template-columns: 280px; |
| | | grid-template-rows: auto repeat(4, auto); |
| | | gap: 16px; |
| | | background-color: rgba(255, 255, 255, 0.9); |
| | | padding: 16px; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | /* æ¶é´å¨æå¡ç */ |
| | | .time-period-card { |
| | | background-color: #ffffff; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .el-header h1 { |
| | | font-size: 24px; |
| | | .time-period-card .card-title { |
| | | font-size: 14px; |
| | | color: #86909c; |
| | | font-weight: 500; |
| | | margin-bottom: 16px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .time-tab-container { |
| | | display: flex; |
| | | flex-direction: row; |
| | | gap: 8px; |
| | | width: 100%; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .time-tab { |
| | | padding: 2px 4px; |
| | | border-radius: 4px; |
| | | cursor: pointer; |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | transition: all 0.3s ease; |
| | | color: #4e5969; |
| | | text-align: center; |
| | | border: 1px solid #e8e8e8; |
| | | background-color: #fafafa; |
| | | } |
| | | |
| | | .time-tab.active { |
| | | background-color: #1890ff; |
| | | color: #ffffff; |
| | | border-color: #1890ff; |
| | | box-shadow: 0 2px 8px rgba(24, 144, 255, 0.2); |
| | | } |
| | | |
| | | .time-tab:hover:not(.active) { |
| | | color: #1890ff; |
| | | border-color: #e6f7ff; |
| | | background-color: #e6f7ff; |
| | | } |
| | | |
| | | /* ææ å¡ç */ |
| | | .metric-card { |
| | | background-color: #ffffff; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .metric-card:hover { |
| | | transform: translateY(-2px); |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .card-title { |
| | | font-size: 14px; |
| | | color: #86909c; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .card-icon { |
| | | color: #1890ff; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .warning-icon { |
| | | color: #fa8c16; |
| | | } |
| | | |
| | | .online-icon { |
| | | color: #52c41a; |
| | | } |
| | | |
| | | .efficiency-icon { |
| | | color: #722ed1; |
| | | } |
| | | |
| | | .task-icon { |
| | | color: #1890ff; |
| | | } |
| | | |
| | | .card-value { |
| | | font-size: 32px; |
| | | font-weight: bold; |
| | | margin: 12px 0; |
| | | color: #262626; |
| | | line-height: 1.2; |
| | | } |
| | | |
| | | .card-trend { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | font-size: 12px; |
| | | padding-top: 12px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .trend-arrow { |
| | | font-size: 14px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .trend-arrow.up { |
| | | color: #52c41a; |
| | | } |
| | | |
| | | .trend-arrow.down { |
| | | color: #f5222d; |
| | | } |
| | | |
| | | .trend-text { |
| | | color: #262626; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .trend-label { |
| | | color: #86909c; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | /* 主è¦å
å®¹åº */ |
| | | .main-content { |
| | | width: 100%; |
| | | height: 100%; |
| | | position: relative; |
| | | } |
| | | |
| | | /* ä¸é¨GISå°å¾åº */ |
| | | .map-section { |
| | | width: 100%; |
| | | height: 100%; |
| | | position: relative; |
| | | overflow: hidden; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .section-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 16px; |
| | | color: #262626; |
| | | } |
| | | |
| | | .section-header h3 { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #262626; |
| | | margin: 0; |
| | | } |
| | | |
| | | .view-more { |
| | | font-size: 12px; |
| | | color: #1890ff; |
| | | cursor: pointer; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .view-more:hover { |
| | | text-decoration: underline; |
| | | } |
| | | |
| | | .map-container { |
| | | flex: 1; |
| | | position: relative; |
| | | overflow: hidden; |
| | | background-color: #fafafa; |
| | | } |
| | | |
| | | .map-placeholder { |
| | | width: 100%; |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | color: #86909c; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | /* å³ä¾§å®æ¶çæµæ»è§åº */ |
| | | .overview-section { |
| | | position: absolute; |
| | | top: 200px; |
| | | right: 24px; |
| | | width: 320px; |
| | | background-color: rgba(255, 255, 255, 0.9); |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | padding: 20px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | z-index: 10; |
| | | max-height: calc(100vh - 220px); |
| | | } |
| | | |
| | | .overview-items-container { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 24px; |
| | | padding-bottom: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .overview-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | flex: 1; |
| | | text-align: center; |
| | | } |
| | | |
| | | .overview-label { |
| | | font-size: 12px; |
| | | color: #86909c; |
| | | font-weight: 500; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .overview-value { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #262626; |
| | | } |
| | | |
| | | .device-status-chart { |
| | | flex: 1; |
| | | margin-top: 16px; |
| | | min-height: 200px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | /* å¼¹çªæ ·å¼ */ |
| | | .dialog-content { |
| | | color: #333; |
| | | } |
| | | |
| | | .el-main { |
| | | padding: 20px; |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | |
| | | .grid-container { |
| | | display: flex; |
| | | /* display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | grid-template-rows: min-content; */ |
| | | gap: 20px; |
| | | /* éªçææ */ |
| | | @keyframes blink { |
| | | 0%, |
| | | 100% { |
| | | opacity: 1; |
| | | } |
| | | 50% { |
| | | opacity: 0.5; |
| | | } |
| | | } |
| | | |
| | | .left-section { |
| | | flex: 2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | } |
| | | |
| | | .right-section { |
| | | width: 670px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | .blink { |
| | | animation: blink 1s infinite; |
| | | } |
| | | |
| | | /* ååºå¼è®¾è®¡ */ |
| | | @media (max-width: 768px) { |
| | | .grid-container { |
| | | grid-template-columns: 1fr; |
| | | @media (max-width: 1200px) { |
| | | .top-cards { |
| | | position: relative; |
| | | margin-bottom: 24px; |
| | | } |
| | | |
| | | .left-section, |
| | | .right-section { |
| | | margin-bottom: 10px; |
| | | .cards-container { |
| | | grid-template-columns: repeat(2, 1fr); |
| | | grid-template-rows: auto auto; |
| | | background-color: #ffffff; |
| | | } |
| | | |
| | | .main-content { |
| | | height: calc(100vh - 300px); |
| | | } |
| | | |
| | | .overview-section { |
| | | position: relative; |
| | | top: 0; |
| | | right: 0; |
| | | width: 100%; |
| | | max-height: none; |
| | | height: 300px; |
| | | margin-top: 16px; |
| | | background-color: #ffffff; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .data-dashboard { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .top-cards { |
| | | left: 16px; |
| | | } |
| | | |
| | | .cards-container { |
| | | grid-template-columns: 1fr; |
| | | grid-template-rows: auto repeat(4, auto); |
| | | } |
| | | |
| | | .time-period-card { |
| | | order: -1; |
| | | } |
| | | |
| | | .time-tab-container { |
| | | flex-direction: row; |
| | | } |
| | | |
| | | .time-tab { |
| | | flex: 1; |
| | | padding: 8px 0; |
| | | } |
| | | |
| | | .overview-section { |
| | | right: 16px; |
| | | } |
| | | |
| | | .overview-items-container { |
| | | flex-direction: column; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .overview-item { |
| | | flex-direction: row; |
| | | justify-content: space-between; |
| | | width: 100%; |
| | | text-align: left; |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-container class="data-dashboard"> |
| | | <el-main> |
| | | <div class="grid-container"> |
| | | <div class="left-section"> |
| | | <!-- 设å¤å¨çº¿æ
åµåºå --> |
| | | <DeviceStatus |
| | | :online-count="onlineCount" |
| | | :offline-count="offlineCount" |
| | | :normal-count="normalCount" |
| | | :fault-count="faultCount" |
| | | /> |
| | | <!-- ååºæ°æ®æååºå --> |
| | | <DistrictRanking |
| | | style="flex: 1" |
| | | :selected-month="selectedMonth" |
| | | :ranking-type="rankingType" |
| | | :ranking-data="rankingData" |
| | | :sorted-ranking-data="sortedRankingData" |
| | | @month-change="handleMonthChange" |
| | | @type-change="handleTypeChange" |
| | | /> |
| | | </div> |
| | | <div class="right-section"> |
| | | <!-- 设å¤å®æ¶æ°æ®åºå --> |
| | | <RealTimeData style="flex: 1" :devices="devices" /> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- å¨çº¿è®¾å¤ååºéºæ¸
ååºå --> |
| | | <ShopList |
| | | :shops="shops" |
| | | :shop-types="shopTypes" |
| | | :districts="districts" |
| | | :filter="filter" |
| | | @filter-change="handleFilterChange" |
| | | /> |
| | | </el-main> |
| | | </el-container> |
| | | </template> |
| | | |
| | | <script> |
| | | import DeviceStatus from '@/components/monitor/DeviceStatus.vue' |
| | | import RealTimeData from '@/components/monitor/RealTimeData.vue' |
| | | import DistrictRanking from '@/components/monitor/DistrictRanking.vue' |
| | | import ShopList from '@/components/monitor/ShopList.vue' |
| | | |
| | | export default { |
| | | name: 'DataDashboard', |
| | | components: { |
| | | DeviceStatus, |
| | | RealTimeData, |
| | | DistrictRanking, |
| | | ShopList, |
| | | }, |
| | | data() { |
| | | return { |
| | | // 设å¤å¨çº¿æ
嵿°æ® |
| | | onlineCount: 0, |
| | | offlineCount: 0, |
| | | normalCount: 0, |
| | | faultCount: 0, |
| | | |
| | | // 设å¤å®æ¶æ°æ® |
| | | devices: [], |
| | | |
| | | // ååºæ°æ®æå |
| | | selectedMonth: '2023-12', |
| | | rankingType: 'hourly', |
| | | rankingData: [], |
| | | sortedRankingData: [], |
| | | |
| | | // ç鿡件 |
| | | filter: { |
| | | district: '', |
| | | shopType: '', |
| | | status: '', |
| | | }, |
| | | shopTypes: ['ä¸é¤', '西é¤', 'å¿«é¤', 'ç«é
', 'ç§ç¤'], |
| | | districts: ['ä¸ååº', '西ååº', 'æé³åº', 'æµ·æ·åº', '丰å°åº'], |
| | | |
| | | // åºéºæ°æ® |
| | | shops: [ |
| | | { |
| | | id: 1, |
| | | name: 'å¼ ä¸é¤å
', |
| | | deviceCount: 2, |
| | | status: 'å¨çº¿', |
| | | district: 'ä¸ååº', |
| | | type: 'ä¸é¤', |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: 'æåé¥åº', |
| | | deviceCount: 1, |
| | | status: '离线', |
| | | district: '西ååº', |
| | | type: '西é¤', |
| | | }, |
| | | { |
| | | id: 3, |
| | | name: 'çäºå°å', |
| | | deviceCount: 3, |
| | | status: 'å¨çº¿', |
| | | district: 'æé³åº', |
| | | type: 'å¿«é¤', |
| | | }, |
| | | { |
| | | id: 4, |
| | | name: 'èµµå
ç«é
', |
| | | deviceCount: 2, |
| | | status: 'å¨çº¿', |
| | | district: 'æµ·æ·åº', |
| | | type: 'ç«é
', |
| | | }, |
| | | { |
| | | id: 5, |
| | | name: 'é±ä¸ç§ç¤', |
| | | deviceCount: 1, |
| | | status: '离线', |
| | | district: '丰å°åº', |
| | | type: 'ç§ç¤', |
| | | }, |
| | | ], |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.initData() |
| | | this.startRealTimeUpdate() |
| | | }, |
| | | methods: { |
| | | initData() { |
| | | // åå§å设å¤å¨çº¿æ
嵿°æ® |
| | | this.updateDeviceStatus() |
| | | |
| | | // åå§å宿¶æ°æ® |
| | | this.updateRealTimeData() |
| | | |
| | | // åå§åååºæ°æ®æå |
| | | this.updateRankingData() |
| | | }, |
| | | |
| | | updateDeviceStatus() { |
| | | // æ¨¡ææ°æ® - å®é
åºä»APIè·å |
| | | this.onlineCount = Math.floor(Math.random() * 50) + 50 |
| | | this.offlineCount = Math.floor(Math.random() * 20) |
| | | this.normalCount = this.onlineCount |
| | | this.faultCount = this.offlineCount |
| | | }, |
| | | |
| | | updateRealTimeData() { |
| | | // æ¨¡ææ°æ® - å®é
åºä»APIè·å |
| | | this.devices = [ |
| | | { |
| | | deviceId: 'DEV-001', |
| | | supplier: 'ä¾åºåA', |
| | | status: 'æ£å¸¸', |
| | | monitorTime: new Date().toLocaleString(), |
| | | smokeDensity: (Math.random() * 2).toFixed(2), |
| | | fanCurrent: (Math.random() * 5 + 1).toFixed(2), |
| | | purifierCurrent: (Math.random() * 3 + 0.5).toFixed(2), |
| | | hourlyData: this.generateHourlyData(), |
| | | }, |
| | | { |
| | | deviceId: 'DEV-002', |
| | | supplier: 'ä¾åºåB', |
| | | status: 'æ£å¸¸', |
| | | monitorTime: new Date().toLocaleString(), |
| | | smokeDensity: (Math.random() * 2).toFixed(2), |
| | | fanCurrent: (Math.random() * 5 + 1).toFixed(2), |
| | | purifierCurrent: (Math.random() * 3 + 0.5).toFixed(2), |
| | | hourlyData: this.generateHourlyData(), |
| | | }, |
| | | { |
| | | deviceId: 'DEV-003', |
| | | supplier: 'ä¾åºåC', |
| | | status: 'å¼å¸¸', |
| | | monitorTime: new Date().toLocaleString(), |
| | | smokeDensity: (Math.random() * 15 + 5).toFixed(2), |
| | | fanCurrent: (Math.random() * 3 + 4).toFixed(2), |
| | | purifierCurrent: (Math.random() * 2 + 2).toFixed(2), |
| | | hourlyData: this.generateHourlyData(), |
| | | }, |
| | | { |
| | | deviceId: 'DEV-004', |
| | | supplier: 'ä¾åºåD', |
| | | status: 'å¼å¸¸', |
| | | monitorTime: new Date().toLocaleString(), |
| | | smokeDensity: (Math.random() * 15 + 5).toFixed(2), |
| | | fanCurrent: (Math.random() * 3 + 4).toFixed(2), |
| | | purifierCurrent: (Math.random() * 2 + 2).toFixed(2), |
| | | hourlyData: this.generateHourlyData(), |
| | | }, |
| | | ] |
| | | }, |
| | | |
| | | generateHourlyData() { |
| | | // çææ¨¡æçè¿ä¸å°æ¶æ°æ® |
| | | const hourlyData = [] |
| | | for (let i = 59; i >= 0; i--) { |
| | | const time = new Date() |
| | | time.setMinutes(time.getMinutes() - i) |
| | | hourlyData.push({ |
| | | time: time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }), |
| | | smokeDensity: (Math.random() * 2).toFixed(2), |
| | | fanCurrent: (Math.random() * 5 + 1).toFixed(2), |
| | | purifierCurrent: (Math.random() * 3 + 0.5).toFixed(2), |
| | | }) |
| | | } |
| | | return hourlyData |
| | | }, |
| | | |
| | | updateRankingData() { |
| | | // æ¨¡ææ°æ® - å®é
åºä»APIè·å |
| | | this.rankingData = [ |
| | | { name: 'çæ¦åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 }, |
| | | { name: '秦淮åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -1 }, |
| | | { name: '建éºåº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 }, |
| | | { name: '鼿¥¼åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 }, |
| | | { name: '浦å£åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -2 }, |
| | | { name: 'æ éåº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 2 }, |
| | | { name: 'é¨è±å°åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 }, |
| | | { name: 'æ±å®åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 }, |
| | | { name: 'å
ååº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -1 }, |
| | | { name: '溧水åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 }, |
| | | { name: '髿·³åº', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 }, |
| | | ] |
| | | |
| | | // æåº |
| | | this.sortedRankingData = [...this.rankingData].sort( |
| | | (a, b) => parseFloat(b.value) - parseFloat(a.value), |
| | | ) |
| | | }, |
| | | |
| | | startRealTimeUpdate() { |
| | | // æ¯30ç§æ´æ°ä¸æ¬¡æ°æ® |
| | | this.realTimeInterval = setInterval(() => { |
| | | this.updateDeviceStatus() |
| | | this.updateRealTimeData() |
| | | }, 30000) |
| | | }, |
| | | |
| | | handleMonthChange(val) { |
| | | this.selectedMonth = val |
| | | this.updateRankingData() |
| | | }, |
| | | |
| | | handleTypeChange(val) { |
| | | this.rankingType = val |
| | | this.updateRankingData() |
| | | }, |
| | | |
| | | handleFilterChange(val) { |
| | | this.filter = { ...val } |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .data-dashboard { |
| | | min-height: 100vh; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | .el-header { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | .el-header h1 { |
| | | font-size: 24px; |
| | | margin: 0; |
| | | color: #333; |
| | | } |
| | | |
| | | .el-main { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .grid-container { |
| | | display: flex; |
| | | /* display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | grid-template-rows: min-content; */ |
| | | gap: 20px; |
| | | } |
| | | |
| | | .left-section { |
| | | flex: 2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | } |
| | | |
| | | .right-section { |
| | | width: 670px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | /* ååºå¼è®¾è®¡ */ |
| | | @media (max-width: 768px) { |
| | | .grid-container { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | |
| | | .left-section, |
| | | .right-section { |
| | | margin-bottom: 10px; |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="data-dashboard"> |
| | | <!-- 顶鍿æ å¡çåº --> |
| | | <div class="top-cards"> |
| | | <div class="cards-container"> |
| | | <!-- æ¶é´å¨æé项å¡ç --> |
| | | <div class="time-period-card"> |
| | | <div class="card-title">æ¶é´å¨æ</div> |
| | | <div class="time-tab-container"> |
| | | <div |
| | | v-for="tab in timeTabs" |
| | | :key="tab.value" |
| | | class="time-tab" |
| | | :class="{ active: activeTime === tab.value }" |
| | | @click="handleTimeChange(tab)" |
| | | > |
| | | {{ tab.label }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- è¶
æ æ° --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">{{ getPeriodLabel() }}è¶
æ æ°</div> |
| | | <div class="card-icon warning-icon">â </div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.overStandardCount }}</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ up: metrics.overStandardTrend > 0, down: metrics.overStandardTrend < 0 }" |
| | | > |
| | | {{ metrics.overStandardTrend > 0 ? 'â' : 'â' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.overStandardTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- å¨çº¿ç --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">{{ getPeriodLabel() }}å¨çº¿ç</div> |
| | | <div class="card-icon online-icon">ð¢</div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.onlineRate }}%</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ up: metrics.onlineRateTrend > 0, down: metrics.onlineRateTrend < 0 }" |
| | | > |
| | | {{ metrics.onlineRateTrend > 0 ? 'â' : 'â' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.onlineRateTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- ååå¨è¿è¡æç --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">{{ getPeriodLabel() }}ååå¨è¿è¡æç</div> |
| | | <div class="card-icon efficiency-icon">â</div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.purifierEfficiency }}%</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ |
| | | up: metrics.purifierEfficiencyTrend > 0, |
| | | down: metrics.purifierEfficiencyTrend < 0, |
| | | }" |
| | | > |
| | | {{ metrics.purifierEfficiencyTrend > 0 ? 'â' : 'â' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.purifierEfficiencyTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- ä»»å¡å®æç --> |
| | | <div class="metric-card"> |
| | | <div class="card-header"> |
| | | <div class="card-title">{{ getPeriodLabel() }}ä»»å¡å®æç</div> |
| | | <div class="card-icon task-icon">â
</div> |
| | | </div> |
| | | <div class="card-value">{{ metrics.taskCompletionRate }}%</div> |
| | | <div class="card-trend"> |
| | | <span |
| | | class="trend-arrow" |
| | | :class="{ |
| | | up: metrics.taskCompletionRateTrend > 0, |
| | | down: metrics.taskCompletionRateTrend < 0, |
| | | }" |
| | | > |
| | | {{ metrics.taskCompletionRateTrend > 0 ? 'â' : 'â' }} |
| | | </span> |
| | | <span class="trend-text">{{ Math.abs(metrics.taskCompletionRateTrend) }}%</span> |
| | | <span class="trend-label">{{ getCompareLabel() }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- ä¸é¨GISå°å¾åº --> |
| | | <div class="map-section"> |
| | | <div id="map" class="map-container"></div> |
| | | |
| | | <!-- å°å¾ç¹ä½å¼¹çª --> |
| | | <el-dialog v-model="dialogVisible" title="ä¼ä¸å®æ¶æ°æ®" width="400px"> |
| | | <div class="dialog-content"> |
| | | <el-descriptions :column="1" border> |
| | | <el-descriptions-item label="ä¼ä¸åç§°">{{ |
| | | selectedPoint.enterpriseName |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="设å¤ç¼å·">{{ |
| | | selectedPoint.deviceId |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ²¹çæµåº¦" |
| | | >{{ selectedPoint.oilSmokeConcentration }} mg/m³</el-descriptions-item |
| | | > |
| | | <el-descriptions-item label="é¢ç²ç©" |
| | | >{{ selectedPoint.particulateMatter }} mg/m³</el-descriptions-item |
| | | > |
| | | <el-descriptions-item label="éç²ç·æ»ç" |
| | | >{{ selectedPoint.nonMethaneHydrocarbon }} mg/m³</el-descriptions-item |
| | | > |
| | | <el-descriptions-item label="çæµæ¶é´">{{ |
| | | selectedPoint.monitoringTime |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="è¶
æ æ
åµ"> |
| | | <el-tag :type="selectedPoint.isOverStandard ? 'danger' : 'success'"> |
| | | {{ selectedPoint.isOverStandard ? 'è¶
æ ' : 'æ£å¸¸' }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">å
³é</el-button> |
| | | <el-button type="primary" @click="viewDetails">æ¥ç详æ
</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | |
| | | <!-- å³ä¾§å®æ¶çæµæ»è§åº --> |
| | | <div class="overview-section"> |
| | | <div class="overview-card"> |
| | | <div class="overview-title">宿¶çæµæ»è§</div> |
| | | |
| | | <div class="overview-items-container"> |
| | | <div class="overview-item"> |
| | | <div class="overview-label">é¤é¥®åºéºæ»æ°</div> |
| | | <div class="overview-value">{{ overview.totalShops }}</div> |
| | | </div> |
| | | |
| | | <div class="overview-item"> |
| | | <div class="overview-label">å¨çº¿è®¾å¤æ°</div> |
| | | <div class="overview-value">{{ overview.onlineDevices }}</div> |
| | | </div> |
| | | |
| | | <div class="overview-item"> |
| | | <div class="overview-label">ç¦»çº¿è®¾å¤æ°</div> |
| | | <div class="overview-value">{{ overview.offlineDevices }}</div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 设å¤ç¶æé¥¼å¾ --> |
| | | <div class="device-status-chart"> |
| | | <canvas id="deviceStatusChart"></canvas> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import * as echarts from 'echarts' |
| | | |
| | | export default { |
| | | name: 'DataDashboard', |
| | | data() { |
| | | return { |
| | | activeTime: 'day', |
| | | timeTabs: [ |
| | | { label: 'æ¥', value: 'day' }, |
| | | { label: 'å¨', value: 'week' }, |
| | | { label: 'æ', value: 'month' }, |
| | | ], |
| | | dialogVisible: false, |
| | | selectedPoint: { |
| | | enterpriseName: '', |
| | | deviceId: '', |
| | | oilSmokeConcentration: 0, |
| | | particulateMatter: 0, |
| | | nonMethaneHydrocarbon: 0, |
| | | monitoringTime: '', |
| | | isOverStandard: false, |
| | | }, |
| | | metrics: { |
| | | overStandardCount: 12, |
| | | overStandardTrend: 5, |
| | | onlineRate: 92, |
| | | onlineRateTrend: 2, |
| | | purifierEfficiency: 85, |
| | | purifierEfficiencyTrend: -3, |
| | | taskCompletionRate: 78, |
| | | taskCompletionRateTrend: 10, |
| | | }, |
| | | overview: { |
| | | totalShops: 245, |
| | | onlineDevices: 220, |
| | | offlineDevices: 25, |
| | | }, |
| | | map: null, |
| | | refreshTimer: null, |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.initMap() |
| | | this.initDeviceStatusChart() |
| | | this.startAutoRefresh() |
| | | }, |
| | | beforeUnmount() { |
| | | if (this.refreshTimer) { |
| | | clearInterval(this.refreshTimer) |
| | | } |
| | | }, |
| | | methods: { |
| | | handleTimeChange(tab) { |
| | | this.activeTime = tab.value |
| | | // 模æåæ¢æ¶é´å¨æåçæ°æ®æ´æ° |
| | | this.updateMetrics() |
| | | }, |
| | | getPeriodLabel() { |
| | | switch (this.activeTime) { |
| | | case 'day': |
| | | return '仿¥' |
| | | case 'week': |
| | | return 'æ¬å¨' |
| | | case 'month': |
| | | return 'æ¬æ' |
| | | default: |
| | | return '仿¥' |
| | | } |
| | | }, |
| | | getCompareLabel() { |
| | | switch (this.activeTime) { |
| | | case 'day': |
| | | return 'è¾æ¨æ¥' |
| | | case 'week': |
| | | return 'è¾ä¸å¨' |
| | | case 'month': |
| | | return 'è¾ä¸æ' |
| | | default: |
| | | return 'è¾æ¨æ¥' |
| | | } |
| | | }, |
| | | updateMetrics() { |
| | | // è¿éåºè¯¥æ ¹æ®éæ©çæ¶é´å¨æä»æ¥å£è·åæ°æ® |
| | | // æ¨¡ææ°æ®æ´æ° |
| | | setTimeout(() => { |
| | | this.metrics = { |
| | | overStandardCount: Math.floor(Math.random() * 30), |
| | | overStandardTrend: Math.floor(Math.random() * 20) - 10, |
| | | onlineRate: Math.floor(Math.random() * 20) + 80, |
| | | onlineRateTrend: Math.floor(Math.random() * 10) - 5, |
| | | purifierEfficiency: Math.floor(Math.random() * 30) + 70, |
| | | purifierEfficiencyTrend: Math.floor(Math.random() * 10) - 5, |
| | | taskCompletionRate: Math.floor(Math.random() * 40) + 60, |
| | | taskCompletionRateTrend: Math.floor(Math.random() * 15) - 7, |
| | | } |
| | | }, 300) |
| | | }, |
| | | initMap() { |
| | | // è¿éåºè¯¥åå§åçå®çGISå°å¾ |
| | | // 模æå°å¾åå§å |
| | | const mapElement = document.getElementById('map') |
| | | if (mapElement) { |
| | | mapElement.innerHTML = '<div class="map-placeholder">GISå°å¾å è½½ä¸...</div>' |
| | | // å®é
项ç®ä¸è¿éåºè¯¥ä½¿ç¨çå®çå°å¾APIï¼å¦é«å¾·å°å¾ãç¾åº¦å°å¾ç |
| | | } |
| | | }, |
| | | initDeviceStatusChart() { |
| | | const chartDom = document.getElementById('deviceStatusChart') |
| | | if (chartDom) { |
| | | const chart = echarts.init(chartDom) |
| | | const option = { |
| | | tooltip: { |
| | | trigger: 'item', |
| | | formatter: '{b}: {c} ({d}%)', |
| | | backgroundColor: 'rgba(255, 255, 255, 0.95)', |
| | | borderColor: '#ebeef5', |
| | | borderWidth: 1, |
| | | textStyle: { |
| | | color: '#303133', |
| | | }, |
| | | }, |
| | | legend: { |
| | | bottom: '0%', |
| | | left: 'center', |
| | | textStyle: { |
| | | color: '#606266', |
| | | fontSize: 12, |
| | | }, |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '设å¤ç¶æ', |
| | | type: 'pie', |
| | | radius: ['40%', '65%'], |
| | | center: ['50%', '45%'], |
| | | avoidLabelOverlap: false, |
| | | itemStyle: { |
| | | borderRadius: 8, |
| | | borderColor: '#ffffff', |
| | | borderWidth: 2, |
| | | shadowBlur: 10, |
| | | shadowOffsetX: 0, |
| | | shadowColor: 'rgba(0, 0, 0, 0.1)', |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'outside', |
| | | formatter: '{b}: {d}%', |
| | | fontSize: 12, |
| | | color: '#606266', |
| | | }, |
| | | labelLine: { |
| | | show: true, |
| | | length: 10, |
| | | length2: 20, |
| | | lineStyle: { |
| | | color: '#606266', |
| | | width: 1, |
| | | }, |
| | | }, |
| | | data: [ |
| | | { |
| | | value: this.overview.onlineDevices, |
| | | name: 'å¨çº¿', |
| | | itemStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: '#67c23a' }, |
| | | { offset: 1, color: '#409eff' }, |
| | | ]), |
| | | }, |
| | | }, |
| | | { |
| | | value: this.overview.offlineDevices, |
| | | name: '离线', |
| | | itemStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: '#f56c6c' }, |
| | | { offset: 1, color: '#e6a23c' }, |
| | | ]), |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ], |
| | | } |
| | | chart.setOption(option) |
| | | |
| | | // ååºå¼è°æ´ |
| | | window.addEventListener('resize', () => { |
| | | chart.resize() |
| | | }) |
| | | } |
| | | }, |
| | | startAutoRefresh() { |
| | | // æ¯30ç§èªå¨å·æ°æ°æ® |
| | | this.refreshTimer = setInterval(() => { |
| | | this.updateMetrics() |
| | | // è¿éåºè¯¥åæ¶æ´æ°å°å¾ç¹ä½æ°æ® |
| | | }, 30000) |
| | | }, |
| | | viewDetails() { |
| | | // 跳转å°ä¼ä¸çæ§è¯¦æ
页 |
| | | this.$router.push('/monitor/enterprise-detail') |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .data-dashboard { |
| | | width: 100%; |
| | | height: 100vh; |
| | | background-color: #f5f7fa; |
| | | color: #303133; |
| | | padding: 20px; |
| | | box-sizing: border-box; |
| | | display: grid; |
| | | grid-template-rows: auto 1fr; |
| | | grid-template-columns: 1fr 300px; |
| | | grid-template-areas: |
| | | 'top overview' |
| | | 'map overview'; |
| | | gap: 20px; |
| | | } |
| | | |
| | | .top-cards { |
| | | grid-area: top; |
| | | } |
| | | |
| | | .time-period-card { |
| | | background-color: #ffffff; |
| | | border: 1px solid #ebeef5; |
| | | border-radius: 12px; |
| | | padding: 24px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08); |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .time-period-card .card-title { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | font-weight: 500; |
| | | margin-bottom: 16px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .time-tab-container { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | width: 100%; |
| | | } |
| | | |
| | | .time-tab { |
| | | padding: 2px 4px; |
| | | border-radius: 8px; |
| | | cursor: pointer; |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | transition: all 0.3s ease; |
| | | color: #606266; |
| | | text-align: center; |
| | | border: 1px solid #ebeef5; |
| | | background-color: #f9f9f9; |
| | | } |
| | | |
| | | .time-tab.active { |
| | | background-color: #409eff; |
| | | color: #ffffff; |
| | | border-color: #409eff; |
| | | box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3); |
| | | } |
| | | |
| | | .time-tab:hover:not(.active) { |
| | | color: #409eff; |
| | | border-color: #c6e2ff; |
| | | background-color: #ecf5ff; |
| | | } |
| | | |
| | | .time-tab.active { |
| | | background-color: #409eff; |
| | | color: #ffffff; |
| | | box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3); |
| | | } |
| | | |
| | | .time-tab:hover:not(.active) { |
| | | color: #409eff; |
| | | background-color: rgba(64, 158, 255, 0.1); |
| | | } |
| | | |
| | | .cards-container { |
| | | display: grid; |
| | | grid-template-columns: 120px repeat(4, 1fr); |
| | | gap: 20px; |
| | | } |
| | | |
| | | .metric-card { |
| | | background-color: #ffffff; |
| | | border: 1px solid #ebeef5; |
| | | border-radius: 12px; |
| | | padding: 24px; |
| | | transition: all 0.3s ease; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08); |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .metric-card::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 4px; |
| | | height: 100%; |
| | | background-color: #409eff; |
| | | } |
| | | |
| | | .metric-card:nth-child(1)::before { |
| | | background-color: #f56c6c; |
| | | } |
| | | |
| | | .metric-card:nth-child(2)::before { |
| | | background-color: #67c23a; |
| | | } |
| | | |
| | | .metric-card:nth-child(3)::before { |
| | | background-color: #e6a23c; |
| | | } |
| | | |
| | | .metric-card:nth-child(4)::before { |
| | | background-color: #909399; |
| | | } |
| | | |
| | | .metric-card:hover { |
| | | transform: translateY(-5px); |
| | | box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12); |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .card-title { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .card-icon { |
| | | font-size: 20px; |
| | | } |
| | | |
| | | .card-value { |
| | | font-size: 36px; |
| | | font-weight: bold; |
| | | margin: 16px 0; |
| | | color: #303133; |
| | | line-height: 1.2; |
| | | } |
| | | |
| | | .card-trend { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | font-size: 13px; |
| | | padding-top: 12px; |
| | | border-top: 1px solid #f0f2f5; |
| | | } |
| | | |
| | | .trend-arrow { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .trend-arrow.up { |
| | | color: #67c23a; |
| | | } |
| | | |
| | | .trend-arrow.down { |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .trend-text { |
| | | color: #606266; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .trend-label { |
| | | color: #909399; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .map-section { |
| | | grid-area: map; |
| | | background-color: #ffffff; |
| | | border: 1px solid #ebeef5; |
| | | border-radius: 8px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .map-container { |
| | | width: 100%; |
| | | height: 100%; |
| | | position: relative; |
| | | } |
| | | |
| | | .map-placeholder { |
| | | width: 100%; |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | color: #909399; |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .overview-section { |
| | | grid-area: overview; |
| | | } |
| | | |
| | | .overview-card { |
| | | background-color: #ffffff; |
| | | border: 1px solid #ebeef5; |
| | | border-radius: 8px; |
| | | padding: 20px 0px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .overview-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | margin-bottom: 20px; |
| | | text-align: center; |
| | | color: #303133; |
| | | } |
| | | |
| | | .overview-items-container { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | width: 100%; |
| | | } |
| | | |
| | | .overview-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | flex: 1; |
| | | text-align: center; |
| | | padding: 12px 0; |
| | | } |
| | | |
| | | .overview-item:last-child { |
| | | border-right: none; |
| | | } |
| | | |
| | | .overview-label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | font-weight: 500; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .overview-value { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | |
| | | .device-status-chart { |
| | | flex: 1; |
| | | margin-top: 20px; |
| | | min-height: 200px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | /* background-color: #c6e2ff; */ |
| | | } |
| | | |
| | | .dialog-content { |
| | | color: #333; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | |
| | | /* éªçææ */ |
| | | @keyframes blink { |
| | | 0%, |
| | | 100% { |
| | | opacity: 1; |
| | | } |
| | | 50% { |
| | | opacity: 0.5; |
| | | } |
| | | } |
| | | |
| | | .blink { |
| | | animation: blink 1s infinite; |
| | | } |
| | | |
| | | /* ååºå¼è®¾è®¡ */ |
| | | @media (max-width: 1200px) { |
| | | .data-dashboard { |
| | | grid-template-columns: 1fr; |
| | | grid-template-areas: |
| | | 'top' |
| | | 'map' |
| | | 'overview'; |
| | | height: auto; |
| | | } |
| | | |
| | | .cards-container { |
| | | grid-template-columns: 160px repeat(2, 1fr); |
| | | } |
| | | |
| | | .overview-section { |
| | | height: 300px; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .cards-container { |
| | | grid-template-columns: 1fr; |
| | | grid-template-rows: auto repeat(4, auto); |
| | | } |
| | | |
| | | .time-period-card { |
| | | order: -1; |
| | | } |
| | | |
| | | .time-tab-container { |
| | | flex-direction: row; |
| | | } |
| | | |
| | | .time-tab { |
| | | flex: 1; |
| | | padding: 8px 0; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <el-row ref="h1"> |
| | | <el-col> |
| | | <!-- èå读æ é¢ --> |
| | | <div ref="h1" class="header-container"> |
| | | <span class="describe-info">åºéºåéæ©ï¼</span> |
| | | <!-- åºéºå 级è --> |
| | | <ShopNameAndID @submit-id="(n) => (deviceId[1] = n)"></ShopNameAndID> |
| | | |
| | | <!-- å¼å¸¸ç±»åéæ© --> |
| | | <ExceptionType @submitExceptionType="(val) => (exceptionValue = val)"> </ExceptionType> |
| | | |
| | | <TimeSelect @submit-time="giveTime"></TimeSelect> |
| | | <div class="data-exception-container"> |
| | | <!-- æç´¢åºå --> |
| | | <div ref="h1" class="search-container"> |
| | | <!-- <div class="search-header"> |
| | | <h3>æ¥è¯¢è¡¨æ ¼</h3> |
| | | </div> --> |
| | | <el-row> |
| | | <div class="search-form"> |
| | | <div class="form-row"> |
| | | <div class="form-item"> |
| | | <span class="form-label">åºéºè®¾å¤ï¼</span> |
| | | <ShopNameAndID @submit-id="(n) => (deviceId[1] = n)"></ShopNameAndID> |
| | | </div> |
| | | <div class="form-item"> |
| | | <ExceptionType @submitExceptionType="(val) => (exceptionValue = val)"> |
| | | </ExceptionType> |
| | | </div> |
| | | </div> |
| | | <div class="form-row"> |
| | | <div class="form-item full-width"> |
| | | <TimeSelect @submit-time="giveTime" :useNewStyle="true"></TimeSelect> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="form-actions"> |
| | | <el-button type="primary" :loading="button.queryButton" @click="showTable" |
| | | >æ¥è¯¢</el-button |
| | | > |
| | | <el-tooltip |
| | | class="box-item" |
| | | effect="dark" |
| | | content="ç¹å»å¯å¯¼åºExcelæä»¶" |
| | | placement="top-start" |
| | | > |
| | | <el-icon class="iconExcel clickable" title="导åºExcelæä»¶" @click="exportDom"> |
| | | <i-ep-Download /> |
| | | </el-icon> |
| | | </el-tooltip> |
| | | </div> |
| | | </el-row> |
| | | <div class="summary-info"> |
| | | <span>{{ beginTime }} ââ {{ endTime }} æ²¹ççæµå¼å¸¸ä¿¡æ¯æ±æ»</span> |
| | | </div> |
| | | <div ref="h2" style="display: flex; margin-top: 2px; justify-content: right"> |
| | | <el-button |
| | | type="primary" |
| | | plain |
| | | style="margin-left: 20px" |
| | | :loading="button.queryButton" |
| | | @click="showTable" |
| | | >æ¥è¯¢</el-button |
| | | > |
| | | </div> |
| | | |
| | | <el-tooltip |
| | | class="box-item" |
| | | effect="dark" |
| | | content="ç¹å»å¯å¯¼åºExcelæä»¶" |
| | | placement="top-start" |
| | | > |
| | | <!-- åæå½æ°jsæä»¶ --> |
| | | <el-icon class="iconExcel clickable" title="导åºExcelæä»¶" @click="exportDom"> |
| | | <i-ep-Download /> |
| | | <!-- 导åºä¸ºExcel --> |
| | | </el-icon> |
| | | </el-tooltip> |
| | | </div> |
| | | <div style="display: flex; justify-content: right; margin-right: 40px"> |
| | | <span class="collapse-header-text"> |
| | | éå®åº {{ beginTime }} ââ {{ endTime }} æ²¹ççæµå¼å¸¸ä¿¡æ¯æ±æ»</span |
| | | > |
| | | </div> |
| | | <br /> |
| | | |
| | | <el-collapse ref="h3" v-model="activeNames"> |
| | | <!-- å¼å¸¸åæ --> |
| | | <div class="analysis-container"> |
| | | <el-collapse v-model="activeNames"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <el-tooltip class="box-item" effect="dark" content="ç¹å»å¯æå " placement="right-start"> |
| | | <div class="collapse-title"> |
| | | <h4 class="collapse-header">å¼å¸¸åæ</h4> |
| | | <el-icon class="header-icon"> |
| | | <i-ep-info-filled /> |
| | | </el-icon> |
| | | </el-tooltip> |
| | | |
| | | <el-tooltip class="box-item" effect="dark" content="ç¹å»å¯æå " placement="right-start"> |
| | | </el-tooltip> |
| | | </div> |
| | | </template> |
| | | <el-card class="box-card"> |
| | | <el-row :gutter="25"> |
| | | <el-card class="analysis-card"> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="8"> |
| | | <div style="display: flex"> |
| | | <img |
| | | src="@/assets/exceed.jpg" |
| | | style="width: 25px; height: 25px; margin-top: 5px" |
| | | /> |
| | | <span |
| | | style="font-size: 16px; font-weight: bold; margin-top: 4px; margin-left: 4px" |
| | | >æ²¹çæµåº¦è¶
æ </span |
| | | > |
| | | </div> |
| | | |
| | | <div class="box-card-label"> |
| | | <el-scrollbar> |
| | | <span class="box-card-label">å¼å¸¸åºéºå æ¯ï¼</span> |
| | | <span style="font-size: 20px">{{ exception0.length }} /{{ shopsTotal }} </span> |
| | | <span style="font-size: 17px"> |
| | | ({{ ((exception0.length / shopsTotal) * 100).toFixed(1) }}%)</span |
| | | > |
| | | {{ shopsTotal }} |
| | | <span class="right-text"> |
| | | <div class="analysis-item"> |
| | | <div class="item-header"> |
| | | <img src="@/assets/exceed.jpg" class="item-icon" /> |
| | | <span class="item-title">æ²¹çæµåº¦è¶
æ </span> |
| | | </div> |
| | | <div class="item-content"> |
| | | <div class="item-stats"> |
| | | <span class="stats-label">å¼å¸¸åºéºå æ¯ï¼</span> |
| | | <span class="stats-value">{{ exception0.length }} /{{ shopsTotal }}</span> |
| | | <span class="stats-percent" |
| | | >({{ ((exception0.length / shopsTotal) * 100).toFixed(1) }}%)</span |
| | | > |
| | | </div> |
| | | <div class="item-percent"> |
| | | å¼å¸¸æ°å æ¯ï¼{{ ((exception0Num / exceptionAllNum) * 100).toFixed(1) }}% |
| | | </span> |
| | | </el-scrollbar> |
| | | </div> |
| | | |
| | | <hr /> |
| | | <div class="box-card-butcontainer"> |
| | | <el-card class="sub-box-card"> |
| | | <el-scrollbar max-height="70px"> |
| | | </div> |
| | | </div> |
| | | <hr class="item-divider" /> |
| | | <div class="item-shops"> |
| | | <el-scrollbar max-height="80px"> |
| | | <ExceptionText |
| | | v-for="(item, index) in exception0" |
| | | :key="item" |
| | |
| | | <span v-if="index < exception0.length - 1" class="text-blank">,</span> |
| | | </ExceptionText> |
| | | </el-scrollbar> |
| | | </el-card> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | |
| | | <el-col :span="8"> |
| | | <div style="display: flex"> |
| | | <img |
| | | src="@/assets/exception.jpg" |
| | | style="width: 25px; height: 25px; margin-top: 5px" |
| | | /> |
| | | <span |
| | | style="font-size: 16px; font-weight: bold; margin-top: 5px; margin-left: 4px" |
| | | >ä¾çµå¼å¸¸</span |
| | | > |
| | | </div> |
| | | <div class="box-card-label"> |
| | | <el-scrollbar> |
| | | <span class="box-card-label">å¼å¸¸åºéºå æ¯ï¼</span> |
| | | <span style="font-size: 20px">{{ exception1.length }} /{{ shopsTotal }}</span> |
| | | <span style="font-size: 17px"> |
| | | ({{ ((exception1.length / shopsTotal) * 100).toFixed(1) }}%)</span |
| | | > |
| | | <span class="right-text"> |
| | | <div class="analysis-item"> |
| | | <div class="item-header"> |
| | | <img src="@/assets/exception.jpg" class="item-icon" /> |
| | | <span class="item-title">ä¾çµå¼å¸¸</span> |
| | | </div> |
| | | <div class="item-content"> |
| | | <div class="item-stats"> |
| | | <span class="stats-label">å¼å¸¸åºéºå æ¯ï¼</span> |
| | | <span class="stats-value">{{ exception1.length }} /{{ shopsTotal }}</span> |
| | | <span class="stats-percent" |
| | | >({{ ((exception1.length / shopsTotal) * 100).toFixed(1) }}%)</span |
| | | > |
| | | </div> |
| | | <div class="item-percent"> |
| | | å¼å¸¸æ°å æ¯ï¼{{ ((exception1Num / exceptionAllNum) * 100).toFixed(1) }}% |
| | | </span> |
| | | </el-scrollbar> |
| | | </div> |
| | | |
| | | <hr /> |
| | | |
| | | <div> |
| | | <el-card class="sub-box-card"> |
| | | <el-scrollbar max-height="70px"> |
| | | </div> |
| | | </div> |
| | | <hr class="item-divider" /> |
| | | <div class="item-shops"> |
| | | <el-scrollbar max-height="80px"> |
| | | <ExceptionText |
| | | v-for="(item, index) in exception1" |
| | | :key="item" |
| | |
| | | <span v-if="index < exception1.length - 1" class="text-blank">,</span> |
| | | </ExceptionText> |
| | | </el-scrollbar> |
| | | </el-card> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | |
| | | <el-col :span="8"> |
| | | <div style="display: flex"> |
| | | <img |
| | | src="@/assets/offline.jpg" |
| | | style="width: 25px; height: 25px; margin-top: 5px" |
| | | /> |
| | | <span |
| | | style="font-size: 16px; font-weight: bold; margin-top: 5px; margin-left: 4px" |
| | | >è®¾å¤æç½ç»å¼å¸¸</span |
| | | > |
| | | </div> |
| | | <div class="box-card-label"> |
| | | <el-scrollbar> |
| | | <span class="box-card-label">å¼å¸¸åºéºå æ¯ï¼</span> |
| | | <span style="font-size: 20px">{{ exception2.length }} /{{ shopsTotal }}</span> |
| | | <span style="font-size: 17px"> |
| | | ({{ ((exception2.length / shopsTotal) * 100).toFixed(1) }}%)</span |
| | | > |
| | | <span class="right-text"> å¼å¸¸æ°å æ¯ï¼{{ connectException }}% </span> |
| | | </el-scrollbar> |
| | | </div> |
| | | <hr /> |
| | | <div> |
| | | <el-card class="sub-box-card"> |
| | | <el-scrollbar max-height="70px"> |
| | | <div class="analysis-item"> |
| | | <div class="item-header"> |
| | | <img src="@/assets/offline.jpg" class="item-icon" /> |
| | | <span class="item-title">è®¾å¤æç½ç»å¼å¸¸</span> |
| | | </div> |
| | | <div class="item-content"> |
| | | <div class="item-stats"> |
| | | <span class="stats-label">å¼å¸¸åºéºå æ¯ï¼</span> |
| | | <span class="stats-value">{{ exception2.length }} /{{ shopsTotal }}</span> |
| | | <span class="stats-percent" |
| | | >({{ ((exception2.length / shopsTotal) * 100).toFixed(1) }}%)</span |
| | | > |
| | | </div> |
| | | <div class="item-percent">å¼å¸¸æ°å æ¯ï¼{{ connectException }}%</div> |
| | | </div> |
| | | <hr class="item-divider" /> |
| | | <div class="item-shops"> |
| | | <el-scrollbar max-height="80px"> |
| | | <ExceptionText |
| | | v-for="(item, index) in exception2" |
| | | :key="item" |
| | |
| | | <span v-if="index < exception2.length - 1" class="text-blank">,</span> |
| | | </ExceptionText> |
| | | </el-scrollbar> |
| | | </el-card> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </el-card> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | |
| | | <h4 class="table-text">å¼å¸¸æ°æ®</h4> |
| | | </el-col> |
| | | </el-row> |
| | | <el-card class="table-page" v-show="!isNoData"> |
| | | <el-table |
| | | ref="tableH" |
| | | size="small" |
| | | v-loading="loading" |
| | | :data="displayData" |
| | | style="width: 100%" |
| | | border |
| | | :height="tableHeight" |
| | | :cell-class-name="tableCellClassName" |
| | | > |
| | | <el-table-column prop="diName" label="åºéºåç§°" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.diName"> |
| | | <div class="cell ellipsis">{{ row.diName }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column prop="devId" label="设å¤ç¼å·" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.devId"> |
| | | <div class="cell ellipsis">{{ row.devId }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column prop="diSupplier" label="ä¾åºå" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.diSupplier"> |
| | | <div class="cell ellipsis">{{ row.diSupplier }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column prop="exception" label="å¼å¸¸åç±»" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.exception"> |
| | | <div class="cell ellipsis">{{ row.exception }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å¼å¸¸ç±»å" align="center"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.exceptionType == '0'">æ²¹çæ°æ®è¶
æ </span> |
| | | <span v-else-if="row.exceptionType == '1'">çä¼¼ä¾çµå¼å¸¸</span> |
| | | <span v-else-if="row.exceptionType == '2'">æçº¿</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="region" label="å°åº" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.region"> |
| | | <div class="cell ellipsis">{{ row.region }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column prop="beginTime" label="å¼å§æ¶é´" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.beginTime"> |
| | | <div class="cell ellipsis">{{ row.beginTime }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="endTime" label="ç»ææ¶é´" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.endTime"> |
| | | <div class="cell ellipsis">{{ row.endTime }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-button type="primary" class="table-button" @click="showDrawer(row)" |
| | | >æ¥ç详æ
</el-button |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <el-pagination |
| | | ref="h4" |
| | | background |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | :total="total" |
| | | :page-size="pageSize" |
| | | layout="total,prev, pager, next, jumper" |
| | | /> |
| | | </el-card> |
| | | <el-empty v-show="isNoData" :image-size="200" /> |
| | | <!-- å¯¹è¯æ¡ --> |
| | | <div> |
| | | <el-dialog v-model="centerDialogVisible" draggable align-center> |
| | | <template #header> |
| | | <div style="font-size: 17px"> |
| | | åºéºåï¼{{ rowShopName }} |
| | | <span style="margin-left: 40px">å¼å¸¸ç±»åï¼</span> |
| | | <span v-if="rowExceptionType == '0'">æ²¹çæ°æ®è¶
æ </span> |
| | | <span v-else-if="rowExceptionType == '1'">ä¾çµå¼å¸¸</span> |
| | | <span v-else-if="rowExceptionType == '2'">æçº¿</span> |
| | | <div style="margin-top: 10px"> |
| | | å¼å¸¸æ¶é´æ®µï¼{{ rowBeginTime }} ~ |
| | | {{ rowEndTime }} |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="dialog-button-position"> |
| | | <el-button |
| | | type="danger" |
| | | :loading="button.preButton" |
| | | :disabled="isPreCantouch || banTouch" |
| | | @click="getPreviousRowData" |
| | | >䏿¡å¼å¸¸</el-button |
| | | > |
| | | <el-button |
| | | type="danger" |
| | | :loading="button.afterButton" |
| | | :disabled="isNextCantouch || banTouch" |
| | | @click="getNextRowData" |
| | | >䏿¡å¼å¸¸</el-button |
| | | > |
| | | </div> |
| | | </template> |
| | | |
| | | <!-- è¶
æ æ°æ®æ¶ --> |
| | | <!-- æçº¿å¾ --> |
| | | |
| | | <!-- æçº¿ --> |
| | | <!-- <div |
| | | ref="ref" |
| | | v-show="isOfflineShow" |
| | | style=" |
| | | width: 100%; |
| | | height: 300px; |
| | | /* min-width: 100px; */ |
| | | margin-bottom: 20px; |
| | | margin-left: 10px; |
| | | min-width: 350px; |
| | | " |
| | | ></div> --> |
| | | |
| | | <ExceptionTypeLineChart |
| | | :option="option" |
| | | :is-open-dialog="centerDialogVisible" |
| | | v-loading="chartLoading" |
| | | ></ExceptionTypeLineChart> |
| | | |
| | | <!-- --> |
| | | <div style="margin-top: 40px; margin-bottom: 5px; border: 1px"> |
| | | <el-table :data="exceedingData" height="360" border style="margin-top: 25px"> |
| | | <el-table-column |
| | | type="index" |
| | | label="åºå·" |
| | | width="60px" |
| | | align="center" |
| | | fixed |
| | | :index="indexMethod" |
| | | ></el-table-column> |
| | | <el-table-column fixed prop="diName" label="åºéºåç§°" show-overflow-tooltip /> |
| | | <el-table-column |
| | | prop="mvStatCode" |
| | | label="设å¤ç¼å·" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column prop="diSupplier" label="ä¾åºå" align="center" show-overflow-tooltip /> |
| | | <el-table-column |
| | | prop="mvDataTime" |
| | | label="ééæ¶é´" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | |
| | | <el-table-column |
| | | prop="mvFumeConcentration2" |
| | | label="æ²¹çæµåº¦(mg/m³)" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | <!-- å¼å¸¸æ°æ®è¡¨æ ¼ --> |
| | | <div class="table-container"> |
| | | <h4 class="table-title">å¼å¸¸æ°æ®</h4> |
| | | <el-card v-show="!isNoData"> |
| | | <el-table |
| | | ref="tableH" |
| | | v-loading="loading" |
| | | :data="displayData" |
| | | style="width: 100%" |
| | | border |
| | | :height="tableHeight" |
| | | :cell-class-name="tableCellClassName" |
| | | > |
| | | <el-table-column prop="diName" label="åºéºåç§°" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.diName"> |
| | | <div class="cell ellipsis">{{ row.diName }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="devId" label="设å¤ç¼å·" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.devId"> |
| | | <div class="cell ellipsis">{{ row.devId }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="diSupplier" label="ä¾åºå" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.diSupplier"> |
| | | <div class="cell ellipsis">{{ row.diSupplier }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="exception" label="å¼å¸¸åç±»" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.exception"> |
| | | <div class="cell ellipsis">{{ row.exception }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å¼å¸¸ç±»å" align="center"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.exceptionType == '0'">æ²¹çæ°æ®è¶
æ </span> |
| | | <span v-else-if="row.exceptionType == '1'">çä¼¼ä¾çµå¼å¸¸</span> |
| | | <span v-else-if="row.exceptionType == '2'">æçº¿</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="region" label="å°åº" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.region"> |
| | | <div class="cell ellipsis">{{ row.region }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="beginTime" label="å¼å§æ¶é´" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.beginTime"> |
| | | <div class="cell ellipsis">{{ row.beginTime }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="endTime" label="ç»ææ¶é´" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.endTime"> |
| | | <div class="cell ellipsis">{{ row.endTime }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" align="center" width="120"> |
| | | <template #default="{ row }"> |
| | | <el-button type="primary" size="small" @click="showDrawer(row)">æ¥ç</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | <div class="pagination-container"> |
| | | <el-pagination |
| | | ref="h4" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | :total="total" |
| | | :page-size="pageSize" |
| | | layout="total, prev, pager, next, jumper" |
| | | /> |
| | | </div> |
| | | </el-card> |
| | | <el-empty v-show="isNoData" :image-size="200" /> |
| | | </div> |
| | | |
| | | <el-tag type="success" class="mx-1" effect="dark" round |
| | | ><span class="table-line-lable" v-show="rowExceptionType == '0'">å¼å¸¸è®°å½ï¼ </span> |
| | | <span v-show="rowExceptionType == '1' || rowExceptionType == '2'">ç¼ºå¤±æ°æ®ï¼</span> |
| | | <span class="table-line-num">{{ exceptionTotal }}æ¡</span> |
| | | <span v-show="rowExceptionType === '1' || rowExceptionType === '2'"> (é»è¾è®¡ç®)</span> |
| | | </el-tag> |
| | | </el-dialog> |
| | | <!-- å¯¹è¯æ¡ --> |
| | | <div> |
| | | <el-dialog v-model="centerDialogVisible" draggable align-center class="detail-dialog"> |
| | | <template #header> |
| | | <div class="dialog-header"> |
| | | <div class="dialog-title"> |
| | | <span>åºéºåï¼{{ rowShopName }}</span> |
| | | <span class="dialog-info" |
| | | >å¼å¸¸ç±»åï¼ |
| | | <span v-if="rowExceptionType == '0'">æ²¹çæ°æ®è¶
æ </span> |
| | | <span v-else-if="rowExceptionType == '1'">ä¾çµå¼å¸¸</span> |
| | | <span v-else-if="rowExceptionType == '2'">æçº¿</span> |
| | | </span> |
| | | <div class="dialog-time">å¼å¸¸æ¶é´æ®µï¼{{ rowBeginTime }} ~ {{ rowEndTime }}</div> |
| | | </div> |
| | | <div class="dialog-actions"> |
| | | <el-button |
| | | type="primary" |
| | | :loading="button.preButton" |
| | | :disabled="isPreCantouch || banTouch" |
| | | @click="getPreviousRowData" |
| | | >䏿¡å¼å¸¸</el-button |
| | | > |
| | | <el-button |
| | | type="primary" |
| | | :loading="button.afterButton" |
| | | :disabled="isNextCantouch || banTouch" |
| | | @click="getNextRowData" |
| | | >䏿¡å¼å¸¸</el-button |
| | | > |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <ExceptionTypeLineChart |
| | | :option="option" |
| | | :is-open-dialog="centerDialogVisible" |
| | | v-loading="chartLoading" |
| | | ></ExceptionTypeLineChart> |
| | | |
| | | <div class="dialog-table-container"> |
| | | <el-table :data="exceedingData" height="360" border style="margin-top: 20px"> |
| | | <el-table-column |
| | | type="index" |
| | | label="åºå·" |
| | | width="60px" |
| | | align="center" |
| | | fixed |
| | | :index="indexMethod" |
| | | ></el-table-column> |
| | | <el-table-column fixed prop="diName" label="åºéºåç§°" show-overflow-tooltip /> |
| | | <el-table-column |
| | | prop="mvStatCode" |
| | | label="设å¤ç¼å·" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | prop="diSupplier" |
| | | label="ä¾åºå" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | prop="mvDataTime" |
| | | label="ééæ¶é´" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | prop="mvFumeConcentration2" |
| | | label="æ²¹çæµåº¦(mg/m³)" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div class="dialog-footer"> |
| | | <el-tag type="success" effect="dark" round |
| | | ><span v-show="rowExceptionType == '0'">å¼å¸¸è®°å½ï¼</span> |
| | | <span v-show="rowExceptionType == '1' || rowExceptionType == '2'">ç¼ºå¤±æ°æ®ï¼</span> |
| | | <span class="table-line-num">{{ exceptionTotal }}æ¡</span> |
| | | <span v-show="rowExceptionType === '1' || rowExceptionType === '2'"> (é»è¾è®¡ç®)</span> |
| | | </el-tag> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { defineAsyncComponent } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import ExceptionType from '@/sfc/ExceptionType.vue' |
| | | import TimeSelect from '@/sfc/TimeSelect.vue' |
| | | import ExceptionText from '@/sfc/ExceptionText.vue' |
| | |
| | | |
| | | //åè½ï¼ å¨æè®¡ç®è¡¨æ ¼é«åº¦ |
| | | calcTableHeight() { |
| | | const h1 = this.$refs.h1.$el.offsetHeight |
| | | const h1 = this.$refs.h1.offsetHeight |
| | | const h2 = this.$refs.h4.$el.offsetHeight |
| | | this.tableHeight = `calc(100vh - ${h1}px - ${h2}px - 45px - var(--el-main-padding) * 2 - var(--el-card-padding))` |
| | | }, |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .header-container { |
| | | display: flex; |
| | | margin-left: 20px; |
| | | /* flex-wrap: wrap; |
| | | align-items: center; */ |
| | | /* å
¨å±å®¹å¨ */ |
| | | .data-exception-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | /* æç´¢åºå */ |
| | | .search-container { |
| | | background-color: white; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | margin-bottom: 20px; |
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .search-header { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .search-header h3 { |
| | | margin: 0; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .search-form { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 16px; |
| | | flex: 1; |
| | | } |
| | | |
| | | .form-row { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | gap: 16px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .form-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | flex: 1; |
| | | min-width: 200px; |
| | | } |
| | | |
| | | .form-item.full-width { |
| | | flex: 100%; |
| | | } |
| | | |
| | | .form-label { |
| | | font-weight: bolder; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .form-actions { |
| | | margin-left: auto; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .summary-info { |
| | | text-align: right; |
| | | font-size: 14px; |
| | | color: #999; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | /* å¼å¸¸åæ */ |
| | | .analysis-container { |
| | | background-color: white; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | margin-bottom: 20px; |
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .collapse-title { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .collapse-header { |
| | | margin: 0; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .header-icon { |
| | | color: #1890ff; |
| | | } |
| | | |
| | | .analysis-card { |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .analysis-item { |
| | | height: 180px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .item-header { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .item-icon { |
| | | width: 24px; |
| | | height: 24px; |
| | | } |
| | | |
| | | .item-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .item-content { |
| | | flex: 1; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .item-stats { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .stats-label { |
| | | font-size: 13px; |
| | | color: #666; |
| | | } |
| | | |
| | | .stats-value { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .stats-percent { |
| | | font-size: 13px; |
| | | color: #999; |
| | | } |
| | | |
| | | .item-percent { |
| | | font-size: 13px; |
| | | color: #666; |
| | | margin-top: 4px; |
| | | } |
| | | |
| | | .item-divider { |
| | | margin: 10px 0; |
| | | border: 0.5px solid #f0f0f0; |
| | | } |
| | | |
| | | .item-shops { |
| | | flex: 1; |
| | | } |
| | | |
| | | /* è¡¨æ ¼åºå */ |
| | | .table-container { |
| | | background-color: white; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .table-title { |
| | | margin: 0 0 16px 0; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .pagination-container { |
| | | margin-top: 16px; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | /* å¯¹è¯æ¡ */ |
| | | .detail-dialog { |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .dialog-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: flex-start; |
| | | width: 100%; |
| | | } |
| | | |
| | | .dialog-title { |
| | | font-size: 16px; |
| | | color: #333; |
| | | } |
| | | |
| | | .dialog-info { |
| | | margin-left: 24px; |
| | | color: #666; |
| | | } |
| | | |
| | | .dialog-time { |
| | | margin-top: 8px; |
| | | font-size: 14px; |
| | | color: #666; |
| | | } |
| | | |
| | | .dialog-actions { |
| | | display: flex; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .dialog-table-container { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | margin-top: 20px; |
| | | text-align: right; |
| | | } |
| | | |
| | | /* éç¨æ ·å¼ */ |
| | | .ellipsis { |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | |
| | | } |
| | | |
| | | .iconExcel { |
| | | font-size: 25px; |
| | | margin-left: 20px; |
| | | bottom: -6px; |
| | | font-size: 20px; |
| | | cursor: pointer; |
| | | color: #1890ff; |
| | | } |
| | | |
| | | /* å¯é¼ æ ç®å¤´å为å¯ç¹å»ç¶æ */ |
| | | .clickable { |
| | | cursor: pointer; |
| | | } |
| | | .card-header { |
| | | margin: 0; |
| | | } |
| | | |
| | | body { |
| | | margin: 0; |
| | | } |
| | | .exception-divider-rowline { |
| | | margin: 10px 0px; |
| | | } |
| | | /* å¼å¸¸åææ°æ®ä¸æé® */ |
| | | .exception-container { |
| | | display: flex; |
| | | } |
| | | .example-showcase .el-loading-mask { |
| | | z-index: 9; |
| | | } |
| | | |
| | | .scrollbar-demo-item { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 20px; |
| | | margin: 10px; |
| | | text-align: center; |
| | | border-radius: 4px; |
| | | background: var(--el-color-primary-light-9); |
| | | color: var(--el-color-primary); |
| | | } |
| | | .collapse-header { |
| | | margin-left: 5px; |
| | | font-size: 18px; |
| | | } |
| | | .collapse-header-text { |
| | | margin-top: 5px; |
| | | font-size: 14px; |
| | | color: gray; |
| | | } |
| | | |
| | | .box-card-label { |
| | | font-size: 14px; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .right-text { |
| | | /* float :right; */ |
| | | /* text-align: right; */ |
| | | margin-left: 80px; |
| | | } |
| | | :deep().el-card { |
| | | border-radius: 9px; |
| | | } |
| | | |
| | | /* âæ¥ç详æ
â çå¼¹åºæ¡é«åº¦è°æ´ */ |
| | | :deep().el-dialog { |
| | | height: 98%; |
| | | /* ä¸åºç°æ»å¨æ¡ */ |
| | | overflow-y: hidden; |
| | | border-radius: 9px; |
| | | } |
| | | .table-page { |
| | | margin-left: 20px; |
| | | } |
| | | |
| | | .table-text { |
| | | font-size: 18px; |
| | | margin: 5px 0px 10px 20px; |
| | | } |
| | | .text-blank { |
| | | margin-right: 10px; |
| | | color: #000000; |
| | | } |
| | | /* åºéºåéæ©ææ¬ */ |
| | | .describe-info { |
| | | margin-top: 5px; |
| | | font-weight: bold; |
| | | white-space: nowrap; |
| | | } |
| | | /* æ¶é´éæ©ææ¬ */ |
| | | .describe-time-text { |
| | | margin-left: 30px; |
| | | margin-top: 5px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | /* å¼å¸¸è¡¨æ ¼ä¸æ ç¾ä¸çæ°ç» */ |
| | | .table-line-num { |
| | | font-weight: bold; |
| | | color: black; |
| | | } |
| | | .button_info.el-button_inner { |
| | | text-align: left; |
| | | |
| | | /* è¡¨æ ¼è¡æ ·å¼ */ |
| | | :deep().el-table__row .exceeding-row { |
| | | background-color: #fff1f0; |
| | | color: #cf1322; |
| | | } |
| | | |
| | | :deep().el-table__row .abnormal-power-supply { |
| | | background-color: #fffbe6; |
| | | color: #d48806; |
| | | } |
| | | |
| | | :deep().el-table__row .disconnect { |
| | | background-color: #e6f7ff; |
| | | color: #1890ff; |
| | | } |
| | | |
| | | /* è¡¨æ ¼æ ·å¼ */ |
| | | :deep().el-table { |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | :deep().el-table th { |
| | | background-color: #fafafa; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | /* æé®æ ·å¼ */ |
| | | :deep().el-button--primary { |
| | | background-color: #1890ff; |
| | | border-color: #1890ff; |
| | | } |
| | | |
| | | :deep().el-button--primary:hover { |
| | | background-color: #40a9ff; |
| | | border-color: #40a9ff; |
| | | } |
| | | |
| | | /* å¡çæ ·å¼ */ |
| | | :deep().el-card { |
| | | border-radius: 8px; |
| | | border: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | /* ååºå¼è°æ´ */ |
| | | @media (max-width: 1200px) { |
| | | .search-form { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | } |
| | | |
| | | .form-actions { |
| | | margin-left: 0; |
| | | margin-top: 12px; |
| | | } |
| | | } |
| | | |
| | | /* åææ ·å¼å
¼å®¹ */ |
| | | .header-container { |
| | | display: flex; |
| | | margin-left: 0; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .describe-info { |
| | | margin-top: 0; |
| | | font-weight: 500; |
| | | white-space: nowrap; |
| | | color: #666; |
| | | } |
| | | |
| | | .table-page { |
| | | margin-left: 0; |
| | | } |
| | | |
| | | .table-text { |
| | | font-size: 16px; |
| | | margin: 0 0 16px 0; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .el-collapse { |
| | | margin-left: 20px; |
| | | margin-left: 0; |
| | | } |
| | | :deep().el-collapse .el-collapse-item__content { |
| | | padding-bottom: 0px; |
| | | } |
| | | |
| | | .box-card { |
| | | height: 190px; |
| | | height: auto; |
| | | min-height: 190px; |
| | | } |
| | | |
| | | .sub-box-card { |
| | | height: 100px; |
| | | height: auto; |
| | | min-height: 100px; |
| | | border: 0px; |
| | | } |
| | | |
| | | .mx-1 { |
| | | margin-bottom: 0px; |
| | | } |
| | | .dialog-button-position { |
| | | display: flex; |
| | | justify-content: right; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | :deep().el-table__row .exceeding-row { |
| | | background-color: #f53f3f; |
| | | } |
| | | :deep().el-table__row .abnormal-power-supply { |
| | | background-color: #fdf4bf; |
| | | } |
| | | :deep().el-table__row .disconnect { |
| | | background-color: #f7ba1e; |
| | | } |
| | | |
| | | .el-table { |
| | | color: #000000; |
| | | } |
| | | |
| | | /* è¡¨æ ¼ä¸çæé®å®½åº¦éºæ»¡ */ |
| | | .table-button { |
| | | width: 100%; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-row ref="h1"> |
| | | <el-col> |
| | | <!-- èå读æ é¢ --> |
| | | <div ref="h1" class="header-container"> |
| | | <span class="describe-info">åºéºåéæ©ï¼</span> |
| | | <!-- åºéºå 级è --> |
| | | <ShopNameAndID @submit-id="(n) => (deviceId[1] = n)"></ShopNameAndID> |
| | | |
| | | <!-- å¼å¸¸ç±»åéæ© --> |
| | | <ExceptionType @submitExceptionType="(val) => (exceptionValue = val)"> </ExceptionType> |
| | | |
| | | <TimeSelect @submit-time="giveTime"></TimeSelect> |
| | | </div> |
| | | <div ref="h2" style="display: flex; margin-top: 2px; justify-content: right"> |
| | | <el-button |
| | | type="primary" |
| | | plain |
| | | style="margin-left: 20px" |
| | | :loading="button.queryButton" |
| | | @click="showTable" |
| | | >æ¥è¯¢</el-button |
| | | > |
| | | |
| | | <el-tooltip |
| | | class="box-item" |
| | | effect="dark" |
| | | content="ç¹å»å¯å¯¼åºExcelæä»¶" |
| | | placement="top-start" |
| | | > |
| | | <!-- åæå½æ°jsæä»¶ --> |
| | | <el-icon class="iconExcel clickable" title="导åºExcelæä»¶" @click="exportDom"> |
| | | <i-ep-Download /> |
| | | <!-- 导åºä¸ºExcel --> |
| | | </el-icon> |
| | | </el-tooltip> |
| | | </div> |
| | | <div style="display: flex; justify-content: right; margin-right: 40px"> |
| | | <span class="collapse-header-text"> |
| | | éå®åº {{ beginTime }} ââ {{ endTime }} æ²¹ççæµå¼å¸¸ä¿¡æ¯æ±æ»</span |
| | | > |
| | | </div> |
| | | <br /> |
| | | |
| | | <el-collapse ref="h3" v-model="activeNames"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <el-tooltip class="box-item" effect="dark" content="ç¹å»å¯æå " placement="right-start"> |
| | | <h4 class="collapse-header">å¼å¸¸åæ</h4> |
| | | <el-icon class="header-icon"> |
| | | <i-ep-info-filled /> |
| | | </el-icon> |
| | | </el-tooltip> |
| | | |
| | | <el-tooltip class="box-item" effect="dark" content="ç¹å»å¯æå " placement="right-start"> |
| | | </el-tooltip> |
| | | </template> |
| | | <el-card class="box-card"> |
| | | <el-row :gutter="25"> |
| | | <el-col :span="8"> |
| | | <div style="display: flex"> |
| | | <img |
| | | src="@/assets/exceed.jpg" |
| | | style="width: 25px; height: 25px; margin-top: 5px" |
| | | /> |
| | | <span |
| | | style="font-size: 16px; font-weight: bold; margin-top: 4px; margin-left: 4px" |
| | | >æ²¹çæµåº¦è¶
æ </span |
| | | > |
| | | </div> |
| | | |
| | | <div class="box-card-label"> |
| | | <el-scrollbar> |
| | | <span class="box-card-label">å¼å¸¸åºéºå æ¯ï¼</span> |
| | | <span style="font-size: 20px">{{ exception0.length }} /{{ shopsTotal }} </span> |
| | | <span style="font-size: 17px"> |
| | | ({{ ((exception0.length / shopsTotal) * 100).toFixed(1) }}%)</span |
| | | > |
| | | {{ shopsTotal }} |
| | | <span class="right-text"> |
| | | å¼å¸¸æ°å æ¯ï¼{{ ((exception0Num / exceptionAllNum) * 100).toFixed(1) }}% |
| | | </span> |
| | | </el-scrollbar> |
| | | </div> |
| | | |
| | | <hr /> |
| | | <div class="box-card-butcontainer"> |
| | | <el-card class="sub-box-card"> |
| | | <el-scrollbar max-height="70px"> |
| | | <ExceptionText |
| | | v-for="(item, index) in exception0" |
| | | :key="item" |
| | | :devId="item.devId" |
| | | exception-value="0" |
| | | :begin-time="beginTime" |
| | | :end-time="endTime" |
| | | @submit-exception-data="getAbnormalDataByClick" |
| | | > |
| | | {{ item.diName }} |
| | | <span v-if="index < exception0.length - 1" class="text-blank">,</span> |
| | | </ExceptionText> |
| | | </el-scrollbar> |
| | | </el-card> |
| | | </div> |
| | | </el-col> |
| | | |
| | | <el-col :span="8"> |
| | | <div style="display: flex"> |
| | | <img |
| | | src="@/assets/exception.jpg" |
| | | style="width: 25px; height: 25px; margin-top: 5px" |
| | | /> |
| | | <span |
| | | style="font-size: 16px; font-weight: bold; margin-top: 5px; margin-left: 4px" |
| | | >ä¾çµå¼å¸¸</span |
| | | > |
| | | </div> |
| | | <div class="box-card-label"> |
| | | <el-scrollbar> |
| | | <span class="box-card-label">å¼å¸¸åºéºå æ¯ï¼</span> |
| | | <span style="font-size: 20px">{{ exception1.length }} /{{ shopsTotal }}</span> |
| | | <span style="font-size: 17px"> |
| | | ({{ ((exception1.length / shopsTotal) * 100).toFixed(1) }}%)</span |
| | | > |
| | | <span class="right-text"> |
| | | å¼å¸¸æ°å æ¯ï¼{{ ((exception1Num / exceptionAllNum) * 100).toFixed(1) }}% |
| | | </span> |
| | | </el-scrollbar> |
| | | </div> |
| | | |
| | | <hr /> |
| | | |
| | | <div> |
| | | <el-card class="sub-box-card"> |
| | | <el-scrollbar max-height="70px"> |
| | | <ExceptionText |
| | | v-for="(item, index) in exception1" |
| | | :key="item" |
| | | :devId="item.devId" |
| | | exception-value="1" |
| | | :begin-time="beginTime" |
| | | :end-time="endTime" |
| | | @submit-exception-data="getAbnormalDataByClick" |
| | | > |
| | | {{ item.diName }} |
| | | <span v-if="index < exception1.length - 1" class="text-blank">,</span> |
| | | </ExceptionText> |
| | | </el-scrollbar> |
| | | </el-card> |
| | | </div> |
| | | </el-col> |
| | | |
| | | <el-col :span="8"> |
| | | <div style="display: flex"> |
| | | <img |
| | | src="@/assets/offline.jpg" |
| | | style="width: 25px; height: 25px; margin-top: 5px" |
| | | /> |
| | | <span |
| | | style="font-size: 16px; font-weight: bold; margin-top: 5px; margin-left: 4px" |
| | | >è®¾å¤æç½ç»å¼å¸¸</span |
| | | > |
| | | </div> |
| | | <div class="box-card-label"> |
| | | <el-scrollbar> |
| | | <span class="box-card-label">å¼å¸¸åºéºå æ¯ï¼</span> |
| | | <span style="font-size: 20px">{{ exception2.length }} /{{ shopsTotal }}</span> |
| | | <span style="font-size: 17px"> |
| | | ({{ ((exception2.length / shopsTotal) * 100).toFixed(1) }}%)</span |
| | | > |
| | | <span class="right-text"> å¼å¸¸æ°å æ¯ï¼{{ connectException }}% </span> |
| | | </el-scrollbar> |
| | | </div> |
| | | <hr /> |
| | | <div> |
| | | <el-card class="sub-box-card"> |
| | | <el-scrollbar max-height="70px"> |
| | | <ExceptionText |
| | | v-for="(item, index) in exception2" |
| | | :key="item" |
| | | :devId="item.devId" |
| | | exception-value="2" |
| | | :begin-time="beginTime" |
| | | :end-time="endTime" |
| | | @submit-exception-data="getAbnormalDataByClick" |
| | | > |
| | | {{ item.diName }} |
| | | <span v-if="index < exception2.length - 1" class="text-blank">,</span> |
| | | </ExceptionText> |
| | | </el-scrollbar> |
| | | </el-card> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </el-card> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | |
| | | <h4 class="table-text">å¼å¸¸æ°æ®</h4> |
| | | </el-col> |
| | | </el-row> |
| | | <el-card class="table-page" v-show="!isNoData"> |
| | | <el-table |
| | | ref="tableH" |
| | | size="small" |
| | | v-loading="loading" |
| | | :data="displayData" |
| | | style="width: 100%" |
| | | border |
| | | :height="tableHeight" |
| | | :cell-class-name="tableCellClassName" |
| | | > |
| | | <el-table-column prop="diName" label="åºéºåç§°" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.diName"> |
| | | <div class="cell ellipsis">{{ row.diName }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column prop="devId" label="设å¤ç¼å·" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.devId"> |
| | | <div class="cell ellipsis">{{ row.devId }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column prop="diSupplier" label="ä¾åºå" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.diSupplier"> |
| | | <div class="cell ellipsis">{{ row.diSupplier }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column prop="exception" label="å¼å¸¸åç±»" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.exception"> |
| | | <div class="cell ellipsis">{{ row.exception }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å¼å¸¸ç±»å" align="center"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.exceptionType == '0'">æ²¹çæ°æ®è¶
æ </span> |
| | | <span v-else-if="row.exceptionType == '1'">çä¼¼ä¾çµå¼å¸¸</span> |
| | | <span v-else-if="row.exceptionType == '2'">æçº¿</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="region" label="å°åº" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.region"> |
| | | <div class="cell ellipsis">{{ row.region }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column prop="beginTime" label="å¼å§æ¶é´" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.beginTime"> |
| | | <div class="cell ellipsis">{{ row.beginTime }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="endTime" label="ç»ææ¶é´" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.endTime"> |
| | | <div class="cell ellipsis">{{ row.endTime }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-button type="primary" class="table-button" @click="showDrawer(row)" |
| | | >æ¥ç详æ
</el-button |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <el-pagination |
| | | ref="h4" |
| | | background |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | :total="total" |
| | | :page-size="pageSize" |
| | | layout="total,prev, pager, next, jumper" |
| | | /> |
| | | </el-card> |
| | | <el-empty v-show="isNoData" :image-size="200" /> |
| | | <!-- å¯¹è¯æ¡ --> |
| | | <div> |
| | | <el-dialog v-model="centerDialogVisible" draggable align-center> |
| | | <template #header> |
| | | <div style="font-size: 17px"> |
| | | åºéºåï¼{{ rowShopName }} |
| | | <span style="margin-left: 40px">å¼å¸¸ç±»åï¼</span> |
| | | <span v-if="rowExceptionType == '0'">æ²¹çæ°æ®è¶
æ </span> |
| | | <span v-else-if="rowExceptionType == '1'">ä¾çµå¼å¸¸</span> |
| | | <span v-else-if="rowExceptionType == '2'">æçº¿</span> |
| | | <div style="margin-top: 10px"> |
| | | å¼å¸¸æ¶é´æ®µï¼{{ rowBeginTime }} ~ |
| | | {{ rowEndTime }} |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="dialog-button-position"> |
| | | <el-button |
| | | type="danger" |
| | | :loading="button.preButton" |
| | | :disabled="isPreCantouch || banTouch" |
| | | @click="getPreviousRowData" |
| | | >䏿¡å¼å¸¸</el-button |
| | | > |
| | | <el-button |
| | | type="danger" |
| | | :loading="button.afterButton" |
| | | :disabled="isNextCantouch || banTouch" |
| | | @click="getNextRowData" |
| | | >䏿¡å¼å¸¸</el-button |
| | | > |
| | | </div> |
| | | </template> |
| | | |
| | | <!-- è¶
æ æ°æ®æ¶ --> |
| | | <!-- æçº¿å¾ --> |
| | | |
| | | <!-- æçº¿ --> |
| | | <!-- <div |
| | | ref="ref" |
| | | v-show="isOfflineShow" |
| | | style=" |
| | | width: 100%; |
| | | height: 300px; |
| | | /* min-width: 100px; */ |
| | | margin-bottom: 20px; |
| | | margin-left: 10px; |
| | | min-width: 350px; |
| | | " |
| | | ></div> --> |
| | | |
| | | <ExceptionTypeLineChart |
| | | :option="option" |
| | | :is-open-dialog="centerDialogVisible" |
| | | v-loading="chartLoading" |
| | | ></ExceptionTypeLineChart> |
| | | |
| | | <!-- --> |
| | | <div style="margin-top: 40px; margin-bottom: 5px; border: 1px"> |
| | | <el-table :data="exceedingData" height="360" border style="margin-top: 25px"> |
| | | <el-table-column |
| | | type="index" |
| | | label="åºå·" |
| | | width="60px" |
| | | align="center" |
| | | fixed |
| | | :index="indexMethod" |
| | | ></el-table-column> |
| | | <el-table-column fixed prop="diName" label="åºéºåç§°" show-overflow-tooltip /> |
| | | <el-table-column |
| | | prop="mvStatCode" |
| | | label="设å¤ç¼å·" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column prop="diSupplier" label="ä¾åºå" align="center" show-overflow-tooltip /> |
| | | <el-table-column |
| | | prop="mvDataTime" |
| | | label="ééæ¶é´" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | |
| | | <el-table-column |
| | | prop="mvFumeConcentration2" |
| | | label="æ²¹çæµåº¦(mg/m³)" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | /> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <el-tag type="success" class="mx-1" effect="dark" round |
| | | ><span class="table-line-lable" v-show="rowExceptionType == '0'">å¼å¸¸è®°å½ï¼ </span> |
| | | <span v-show="rowExceptionType == '1' || rowExceptionType == '2'">ç¼ºå¤±æ°æ®ï¼</span> |
| | | <span class="table-line-num">{{ exceptionTotal }}æ¡</span> |
| | | <span v-show="rowExceptionType === '1' || rowExceptionType === '2'"> (é»è¾è®¡ç®)</span> |
| | | </el-tag> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { defineAsyncComponent } from 'vue' |
| | | import ExceptionType from '@/sfc/ExceptionType.vue' |
| | | import TimeSelect from '@/sfc/TimeSelect.vue' |
| | | import ExceptionText from '@/sfc/ExceptionText.vue' |
| | | |
| | | import * as XLSX from 'xlsx/xlsx.mjs' |
| | | import dayjs from 'dayjs' |
| | | import axiosInstanceInstance from '@/utils/request.js' |
| | | |
| | | const ShopNameAndID = defineAsyncComponent(() => import('@/sfc/ShopNameAndID.vue')) |
| | | |
| | | // å¼å¸¸å¾å½¢å¼æ¥ç»ä»¶ |
| | | const ExceptionTypeLineChart = defineAsyncComponent( |
| | | () => import('@/sfc/ExceptionTypeLineChart.vue'), |
| | | ) |
| | | export default { |
| | | name: 'TablePage', |
| | | components: { |
| | | ExceptionType, |
| | | TimeSelect, |
| | | ShopNameAndID, |
| | | ExceptionText, |
| | | ExceptionTypeLineChart, |
| | | }, |
| | | data() { |
| | | return { |
| | | exception0Num: 0, |
| | | exception1Num: 0, |
| | | exception2Num: 0, |
| | | // æçº¿å¾å è½½ä¸ |
| | | chartLoading: false, |
| | | button: { |
| | | // æ¥è¯¢æé® |
| | | queryButton: false, |
| | | // ä¸ä¸æ¡æé® |
| | | preButton: false, |
| | | // ä¸ä¸æ¡æé® |
| | | afterButton: false, |
| | | // |
| | | banTouch: 0, |
| | | }, |
| | | // å¼å¸¸æçº¿å¾çé
ç½® |
| | | option: {}, |
| | | // æçº¿å¾å±ç¤º |
| | | isChartShow: false, |
| | | // tableå
ç´ |
| | | tableRef: null, |
| | | // å¼å¸¸è¡¨æ ¼æ°æ® |
| | | tableHeight: 300, |
| | | // ç©ºæ°æ®ç¶æ |
| | | isNoData: false, |
| | | // å¼¹åºæ¡ä¸è¡¨æ ¼æ¡æ° |
| | | exceptionTotal: 0, |
| | | // æ æ°æ®æ¶çæ¶é´æ°ç»ï¼å
ç´ ç¸å·®10åé |
| | | // abnormalTimeTenMinute: [], |
| | | // åºéºæ»æ° |
| | | shopsTotal: 0, |
| | | |
| | | // âä¸ä¸æ¡âæé®æ¯å¦å¯ä»¥è¢«ç¹å»ç¶æ |
| | | isPreCantouch: false, |
| | | // âä¸ä¸æ¡âæé®æ¯å¦å¯ä»¥è¢«ç¹å»ç¶æ |
| | | isNextCantouch: false, |
| | | |
| | | // å¯¹è¯æ¡æ¯å¦å±ç¤º |
| | | centerDialogVisible: false, |
| | | |
| | | // æ½å±å¤´é¨ä¿¡æ¯ |
| | | // æçº¿å¾å¯¹åºçå½åè¡¨æ ¼è¡æ°æ® |
| | | // åºéºå |
| | | rowShopName: '', |
| | | // å¼å¸¸ç±»å |
| | | rowExceptionType: '', |
| | | // å¼å¸¸å¼å§æ¶é´ |
| | | rowBeginTime: '', |
| | | // å¼å¸¸ç»ææ¶é´ |
| | | rowEndTime: '', |
| | | // å¼å¸¸ç设å¤ç¼å· |
| | | rowMvStatCode: '', |
| | | // ä¾åºå |
| | | rowDiSupplier: '', |
| | | // è¡¨æ ¼çä¸è¡æ°æ® |
| | | rowTable: [], |
| | | //æ¼æ¥çæææ°æ® |
| | | allExceptionTimeData: [], |
| | | // æ æ°æ®æ¶å¢å çå30åéæ°æ® |
| | | beforeData: [], |
| | | // æ æ°æ®æ¶å¢å çå40åéæ°æ® |
| | | afterData: [], |
| | | |
| | | // -1表示æªéæ©è¡¨æ ¼çè¡ |
| | | selectedRowIndex: -1, |
| | | |
| | | // é»è®¤éæ©çæå 颿¿ç¼å· |
| | | activeNames: ['1'], |
| | | // å¼å¸¸æ¶çè¡¨æ ¼ |
| | | abnormalTb: [], |
| | | // å¼å¸¸çèµ·æ¢æ¶é´ |
| | | abnormalBt: '', |
| | | abnormalEt: '', |
| | | // æ¯å¦å±ç¤ºæ¶é´è½´ å¦ |
| | | isAbnormal: false, |
| | | // ä¿åçå¼å¸¸ç±»å0对åºçåºéºåç§°å设å¤ç¼å· |
| | | exception0: [], |
| | | // ä¿åçå¼å¸¸ç±»å1对åºçåºéºåç§°å设å¤ç¼å· |
| | | exception1: [], |
| | | // ä¿åçå¼å¸¸ç±»å2对åºçåºéºåç§°å设å¤ç¼å· |
| | | exception2: [], |
| | | // å è½½å¨ç» |
| | | loading: false, |
| | | // æ½å±å è½½å¨ç» |
| | | loadingDrawer: true, |
| | | // å页å±ç¤ºæ°æ® |
| | | |
| | | // å¼å¸¸è¡¨çæ°æ® |
| | | displayData: [], |
| | | // åæ¾å端è¿åçjsonæ°æ® |
| | | jsonData: [], |
| | | // å页çèµ·å§ç´¢å¼ |
| | | startIndex: 0, |
| | | // å½å页 |
| | | currentPage: 1, |
| | | // æ¯é¡µæ¡æ° |
| | | pageSize: 10, |
| | | total: 0, |
| | | // éæ©åºéºå |
| | | deviceId: [], |
| | | deviceInfo: [], |
| | | // æ¶é´éæ©å¨å¼å§æ¶é´ |
| | | beginTime: '', |
| | | // æ¶é´éæ©å¨ç»ææ¶é´ |
| | | endTime: '', |
| | | // å¼å¸¸è¡¨æ°æ® |
| | | abnormalData: [], |
| | | // å¼¹åºçå¯¹è¯æ¡ä¸çå¼å¸¸è¡¨æ ¼æ°æ® |
| | | exceedingData: [], |
| | | drawerVisible: false, |
| | | // è¡¨æ ¼çä¸è¡æ°æ® |
| | | drawerData: {}, |
| | | // æ½å±æ¹åï¼ä»å³åå·¦æå¼ |
| | | drawerDirection: 'rtl', |
| | | optionsTime: [ |
| | | // æ¶é´é¢ç²åº¦ |
| | | { |
| | | value: '10', |
| | | label: '10åéæ°æ®', |
| | | disabled: true, |
| | | }, |
| | | ], |
| | | // åºéºå 级èéæ©å¨ |
| | | optionsShop: [], |
| | | // å¼å¸¸ç±»åéæ©å¨ |
| | | exceptionValue: [], |
| | | } |
| | | }, |
| | | // çå¬ å¤ææé®æ¯å¦å¯ç¹å» |
| | | watch: { |
| | | selectedRowIndex(newVaue) { |
| | | // å¤äºè¡¨æ ¼çæå䏿¡æ°æ® 设置âä¸ä¸æ¡âæé®ä¸å¯ç¹ |
| | | if (newVaue === this.displayData.length - 1) { |
| | | this.isPreCantouch = true |
| | | //ç¨æ·å
ç¹äºç¬¬ä¸æ¡ï¼pre为true,ç¶åç¹å»æå䏿¡,next为trueãæ¤æ¶ä¸¤ä¸ªæé®é½è¢«å°é |
| | | if (this.isNextCantouch == true) { |
| | | this.isNextCantouch = false |
| | | } |
| | | } |
| | | // å¤äºè¡¨æ ¼ç¬¬ä¸æ¡æ°æ® 设置âä¸ä¸æ¡âæé®ä¸å¯ç¹ |
| | | else if (newVaue === 0) { |
| | | this.isNextCantouch = true |
| | | //ç¨æ·å
ç¹äºè¡¨æ ¼æå䏿¡,next为true,ç¶åç¹å»ç¬¬ä¸æ¡ï¼pre为trueãæ¤æ¶ä¸¤ä¸ªæé®é½è¢«å°é |
| | | if (this.isPreCantouch == true) { |
| | | this.isPreCantouch = false |
| | | } |
| | | } |
| | | // å¤äºè¡¨æ ¼çä¸é´è¡ å°æé®è®¾ç½®ä¸ºå¯ç¹å»ç¶æ |
| | | else { |
| | | this.isPreCantouch = false |
| | | this.isNextCantouch = false |
| | | } |
| | | }, |
| | | |
| | | // å½éæ©çæ¶é´åçååæ¶ï¼å¼å¸¸åæé¨åçå¼å¸¸åºéºæ°é忥åå |
| | | beginTime() { |
| | | this.getShopNames() |
| | | }, |
| | | endTime() { |
| | | this.getShopNames() |
| | | }, |
| | | centerDialogVisible() { |
| | | window.addEventListener('resize', this.updateChart) |
| | | }, |
| | | }, |
| | | computed: { |
| | | exceptionAllNum() { |
| | | let sum = this.exception0Num + this.exception1Num + this.exception2Num |
| | | return sum == 0 ? 1 : sum |
| | | }, |
| | | connectException() { |
| | | let sum = this.exception0Num + this.exception1Num + this.exception2Num |
| | | if (sum == 0) { |
| | | return 0 |
| | | } else { |
| | | return (100 - (this.exception0Num / sum) * 100 - (this.exception1Num / sum) * 100).toFixed( |
| | | 1, |
| | | ) |
| | | } |
| | | }, |
| | | }, |
| | | mounted() { |
| | | // 仿¥å£è·ååºéºåç§° ç»çº§èä¸ææ¡ |
| | | this.getDeviceInfo() |
| | | // å±ç¤ºæè¿7å¤©æ°æ® |
| | | this.getRecentSevenDays() |
| | | // æ ¹æ®å¼å¸¸ç±»åè¿ååºéºåç§°å设å¤ç¼å· 渲æå¼å¸¸åæé¨å对åºçåºéºå |
| | | this.getShopNames() |
| | | this.calcTableHeight() |
| | | window.addEventListener('resize', this.updateChart) |
| | | }, |
| | | methods: { |
| | | // åè½ï¼å¯¹è¯æ¡è¡¨æ ¼åºå·éå¢ |
| | | // æ¶é´ï¼2023-8-17 |
| | | indexMethod(index) { |
| | | return index + 1 |
| | | }, |
| | | |
| | | // åè½ï¼æ¹åè¡¨æ ¼æä¸ªåå
æ ¼çé¢è² |
| | | tableCellClassName({ row, column, rowIndex, columnIndex }) { |
| | | if (columnIndex == 4) { |
| | | if (row.exceptionType == '0') { |
| | | return 'exceeding-row' |
| | | } else if (row.exceptionType == '1') { |
| | | return 'abnormal-power-supply' |
| | | } else if (row.exceptionType == '2') { |
| | | return 'disconnect' |
| | | } |
| | | } |
| | | }, |
| | | |
| | | //åè½ï¼ å¨æè®¡ç®è¡¨æ ¼é«åº¦ |
| | | calcTableHeight() { |
| | | const h1 = this.$refs.h1.$el.offsetHeight |
| | | const h2 = this.$refs.h4.$el.offsetHeight |
| | | this.tableHeight = `calc(100vh - ${h1}px - ${h2}px - 45px - var(--el-main-padding) * 2 - var(--el-card-padding))` |
| | | }, |
| | | |
| | | //åè½ï¼ æ¶é´æ¯å¦è¶
è¿10åé |
| | | isTimeDifferenceGreaterThan10Minutes(dateString1, dateString2) { |
| | | const date1 = new Date(dateString1) |
| | | const date2 = new Date(dateString2) |
| | | |
| | | // 计ç®ä¸¤ä¸ªæ¥æçæ¶é´å·®ï¼æ¯«ç§ï¼ |
| | | const timeDifferenceMs = Math.abs(date1 - date2) |
| | | |
| | | // 转æ¢ä¸ºåé |
| | | const timeDifferenceMinutes = Math.floor(timeDifferenceMs / (1000 * 60)) |
| | | |
| | | // 夿æ¶é´å·®æ¯å¦å¤§äº10åé |
| | | return timeDifferenceMinutes > 10 |
| | | }, |
| | | |
| | | // 以10åé为é´éè¿åæ¶é´å符串æ°ç» |
| | | generateTimePoints(timePoints, yAxisData) { |
| | | let updatedTimePoints = [] |
| | | let yAxisDataAdressed = [] |
| | | for (let i = 0; i < timePoints.length; i++) { |
| | | updatedTimePoints.push(timePoints[i]) |
| | | yAxisDataAdressed.push(yAxisData[i]) |
| | | if (i < timePoints.length - 1) { |
| | | let current = timePoints[i] |
| | | let next = timePoints[i + 1] |
| | | while (this.isTimeDifferenceGreaterThan10Minutes(current, next)) { |
| | | current = dayjs(current).add(10, 'minute').format('YYYY-MM-DD HH:mm:ss') |
| | | updatedTimePoints.push(current) |
| | | yAxisDataAdressed.push(null) |
| | | } |
| | | } |
| | | } |
| | | let obj = {} |
| | | obj['time'] = updatedTimePoints |
| | | obj['data'] = yAxisDataAdressed |
| | | return obj |
| | | }, |
| | | |
| | | isExceedOneMonth(dateStr1, dateStr2) { |
| | | // è¶
è¿ä¸ä¸ªæï¼è¿åTrueï¼å¦åè¿åFalse |
| | | // å°æ¥æåç¬¦ä¸²è½¬ä¸ºæ¥æå¯¹è±¡ |
| | | const date1 = new Date(dateStr1) |
| | | const date2 = new Date(dateStr2) |
| | | |
| | | // è·åä¸¤ä¸ªæ¥æçå¹´ãæãæ¥ |
| | | const year1 = date1.getFullYear() |
| | | const month1 = date1.getMonth() |
| | | const day1 = date1.getDate() |
| | | |
| | | const year2 = date2.getFullYear() |
| | | const month2 = date2.getMonth() |
| | | const day2 = date2.getDate() |
| | | |
| | | // å¤æä¸¤ä¸ªæ¥ææ¯å¦ç¸å·®ä¸ä¸ªæ |
| | | if (year1 === year2) { |
| | | // 年份ç¸çï¼æ¯è¾æä»½å·®å¼ |
| | | if (Math.abs(month1 - month2) === 1) { |
| | | // æä»½å·®å¼ä¸º1ï¼è¿éè¦å¤æå
·ä½æ¥æ |
| | | if ((month1 < month2 && day1 < day2) || (month1 > month2 && day1 > day2)) { |
| | | return true |
| | | } |
| | | } |
| | | } else if (Math.abs(year1 - year2) === 1) { |
| | | // 年份差å¼ä¸º1ï¼æ¯è¾æä»½åæ¥æ |
| | | if ( |
| | | (year1 < year2 && month1 === 11 && month2 === 0 && day1 < day2) || |
| | | (year1 > year2 && month1 === 0 && month2 === 11 && day1 > day2) |
| | | ) { |
| | | return true |
| | | } |
| | | } |
| | | |
| | | // é»è®¤è¿åfalseï¼è¡¨ç¤ºä¸¤ä¸ªæ¥æå符串ä¸ç¸å·®ä¸ä¸ªæ |
| | | return false |
| | | }, |
| | | |
| | | // åæå¼å¡çæ¶ç¬¬ä¸ä¸ªå¾å½¢ä¸ä¼èªå¨ä¼¸ç¼© å½ç¹å»ä¸/ä¸ä¸æ¡æ¶ä¼èªå¨ä¼¸ç¼© |
| | | // å¾å½¢ååºå¼åå |
| | | // updateChart() { |
| | | // this.$nextTick(() => { |
| | | // if (this.chart1) { |
| | | // this.chart1.resize(); |
| | | // } |
| | | // if (this.chart2) { |
| | | // this.chart2.resize(); |
| | | // } |
| | | // }); |
| | | // }, |
| | | |
| | | // 仿¶é´éæ©å¨ç»ä»¶æ¿å°å¼å§åç»ææ¶é´ |
| | | giveTime(val) { |
| | | //å°ä¸å½æ åæ¶é´è½¬ä¸ºæå®æ ¼å¼(该ç»ä»¶è¿åçæ åæ¶é´çæ ¼å¼ï¼æä»¥å¿
é¡»çå è¿ä¸ªå½æ°) |
| | | this.beginTime = dayjs(val[0]).format('YYYY-MM-DD HH:mm:ss') |
| | | this.endTime = dayjs(val[1]).format('YYYY-MM-DD HH:mm:ss') |
| | | }, |
| | | |
| | | // åæ°ï¼å¼å¸¸çå¼å§åç»ææ¶é´ãè¿åæ¶é´æ°ç»ï¼ä»å¼å§æ¶é´çå10åéå°ç»ææ¶é´ä¸ºæ¢ã |
| | | // æ¯å¦12:00:00-13:00:00 æä»¥è¿åçæ°ç»å
ç´ æ¯ 12:10:00 ,12:20:00,12:30:00....13:00:00 |
| | | descTenTime(begin, end) { |
| | | let time = [] |
| | | if (begin == end) { |
| | | time.push(begin) |
| | | return time |
| | | } |
| | | // ä¿çç»æ 00 10 20 30 |
| | | let temp = dayjs(begin).add(10, 'minute').format('YYYY-MM-DD HH:mm:ss') |
| | | while (temp != end) { |
| | | time.push(temp) |
| | | temp = dayjs(temp).add(10, 'minute').format('YYYY-MM-DD HH:mm:ss') |
| | | } |
| | | // å ä¸å¼å¸¸çç»ææ¶é´ |
| | | time.push(temp) |
| | | return time |
| | | }, |
| | | |
| | | // ä¿åå½åéæ©çè¡ææä¿¡æ¯ |
| | | setinfo(index) { |
| | | this.rowShopName = this.displayData[index].diName |
| | | this.rowExceptionType = this.displayData[index].exceptionType |
| | | this.rowBeginTime = this.displayData[index].beginTime |
| | | this.rowEndTime = this.displayData[index].endTime |
| | | this.rowMvStatCode = this.displayData[index].devId |
| | | this.rowDiSupplier = this.displayData[index].diSupplier |
| | | }, |
| | | |
| | | //åè½ï¼ ä¾çµå¼å¸¸åæçº¿æ¶çè¡¨æ ¼æ°æ® |
| | | setExceptionData() { |
| | | // æ æ°æ®æ¶çæ¶é´æ°ç» æ¶é´ç¸å·®10åé |
| | | const abnormalTimeTenMinute = this.descTenTime(this.rowBeginTime, this.rowEndTime) |
| | | // å»é¤ä¾çµå¼å¸¸åæçº¿åºé´ç第ä¸ä¸ªæå
ç´ çå¼ |
| | | this.exceedingData = [] |
| | | |
| | | for (let i = 0; i < abnormalTimeTenMinute.length; i++) { |
| | | this.exceedingData.push({ |
| | | mvStatCode: this.rowMvStatCode, |
| | | diName: this.rowShopName, |
| | | diSupplier: this.rowDiSupplier, |
| | | mvDataTime: abnormalTimeTenMinute[i], |
| | | mvFumeConcentration2: '', |
| | | }) |
| | | } |
| | | |
| | | // ä¿åæ æ°æ®æ¶è¡¨æ ¼æ¡æ° |
| | | this.exceptionTotal = abnormalTimeTenMinute.length |
| | | }, |
| | | // ç¹å»è¡¨æ ¼çè¡æ¶ |
| | | selectTableRow(row) { |
| | | // è·åå½åè¡çç´¢å¼ |
| | | this.selectedRowIndex = this.displayData.indexOf(row) |
| | | // è¿å
¥æ½å±é¡µé¢æ´æ°å¤´é¨æ°æ® |
| | | this.setinfo(this.selectedRowIndex) |
| | | }, |
| | | |
| | | // è·åè·åè¡¨æ ¼ä¸ä¸è¡æ°æ® |
| | | getNextRowData() { |
| | | // 䏿¯è¡¨æ ¼ç第ä¸è¡ |
| | | if (this.selectedRowIndex !== 0) { |
| | | // ç¹å»è¿ç¨ä¸ éä½ä¸ä¸æ¡æé® å¨è®¾ç½®å®å¾å½¢é
置项åè§£é |
| | | this.banTouch = 1 |
| | | |
| | | //å¾å°ä¸ä¸è¡æ°æ®ç´¢å¼ |
| | | this.selectedRowIndex = this.selectedRowIndex - 1 |
| | | //è¯·æ±æ°æ® æ¹åexceedingData |
| | | this.setinfo(this.selectedRowIndex) |
| | | let params = {} |
| | | if (this.drawerData.devId) { |
| | | params['devId'] = this.displayData[this.selectedRowIndex].devId |
| | | } |
| | | if (this.drawerData.beginTime) { |
| | | params['beginTime'] = this.displayData[this.selectedRowIndex].beginTime |
| | | } |
| | | if (this.drawerData.endTime) { |
| | | params['endTime'] = this.displayData[this.selectedRowIndex].endTime |
| | | } |
| | | this.button.afterButton = true |
| | | axiosInstanceInstance.get('/fume/exceed', { params: params }).then((response) => { |
| | | // ä¿åè¿åçè¶
æ æ°æ® |
| | | this.exceedingData = response.data.data |
| | | this.drawChartTest() |
| | | this.exceptionTotal = this.exceedingData.length |
| | | this.button.afterButton = false |
| | | }) |
| | | } |
| | | }, |
| | | |
| | | // è·åè·åè¡¨æ ¼ä¸ä¸è¡æ°æ® |
| | | getPreviousRowData() { |
| | | // 䏿¯è¡¨æ ¼ç第ä¸è¡ |
| | | if (this.selectedRowIndex < this.displayData.length - 1) { |
| | | // ç¹å»è¿ç¨ä¸ éä½ä¸ä¸æ¡æé® å¨è®¾ç½®å®å¾å½¢é
置项åè§£é |
| | | this.banTouch = 1 |
| | | |
| | | //å¾å°ä¸ä¸è¡æ°æ®ç´¢å¼ |
| | | this.selectedRowIndex = this.selectedRowIndex + 1 |
| | | |
| | | //è¯·æ±æ°æ® æ¹åexceedingData |
| | | this.setinfo(this.selectedRowIndex) |
| | | let params = {} |
| | | if (this.drawerData.devId) { |
| | | params['devId'] = this.displayData[this.selectedRowIndex].devId |
| | | } |
| | | if (this.drawerData.beginTime) { |
| | | params['beginTime'] = this.displayData[this.selectedRowIndex].beginTime |
| | | } |
| | | if (this.drawerData.endTime) { |
| | | params['endTime'] = this.displayData[this.selectedRowIndex].endTime |
| | | } |
| | | this.button.preButton = true |
| | | axiosInstanceInstance.get('/fume/exceed', { params: params }).then((response) => { |
| | | // ä¿åè¿åçè¶
æ æ°æ® |
| | | this.exceedingData = response.data.data |
| | | this.drawChartTest() |
| | | this.exceptionTotal = this.exceedingData.length |
| | | this.button.preButton = false |
| | | }) |
| | | } |
| | | }, |
| | | |
| | | // âæ¥ç详æ
â å¼¹åºæ¡é¨å |
| | | showDrawer(row) { |
| | | // 计ç®å½åè¡çç´¢å¼ |
| | | this.selectTableRow(row) |
| | | |
| | | this.rowTable = row |
| | | |
| | | // è¡¨æ ¼çè¡æ°æ®ä»¥å¯¹è±¡å½¢å¼ç»drawerData |
| | | this.drawerData = row |
| | | |
| | | this.centerDialogVisible = true |
| | | |
| | | // æ ¹æ®è¡æ°æ®è¯·æ±è¯¦ç»è¶
æ æ°æ®æ¸²ææçº¿å¾ |
| | | let params = {} |
| | | if (this.drawerData.devId) { |
| | | params['devId'] = this.drawerData.devId |
| | | } |
| | | if (this.drawerData.beginTime) { |
| | | params['beginTime'] = this.drawerData.beginTime |
| | | } |
| | | if (this.drawerData.endTime) { |
| | | params['endTime'] = this.drawerData.endTime |
| | | } |
| | | |
| | | axiosInstanceInstance.get('/fume/exceed', { params: params }).then((response) => { |
| | | // ä¿åè¿åçè¶
æ æ°æ® |
| | | this.exceedingData = response.data.data |
| | | this.drawChartTest() |
| | | this.exceptionTotal = this.exceedingData.length |
| | | }) |
| | | }, |
| | | |
| | | // ç¨æ·æ ¹æ®è¾å
¥çæ¡ä»¶æ¥è¯¢ |
| | | showTable() { |
| | | if (this.isExceedOneMonth(this.beginTime, this.endTime)) { |
| | | alert('æ¶é´è·¨åº¦ä¸è½è¶
è¿ä¸ä¸ªæ') |
| | | return |
| | | } |
| | | let params = {} |
| | | |
| | | if (this.deviceId[1]) { |
| | | params['devId'] = this.deviceId[1] |
| | | } |
| | | if (this.exceptionValue.length != 0) { |
| | | params['exceptionValue'] = this.exceptionValue.join() |
| | | } |
| | | |
| | | if (this.beginTime) { |
| | | params['beginTime'] = this.beginTime |
| | | } |
| | | if (this.endTime) { |
| | | params['endTime'] = this.endTime |
| | | } |
| | | this.loading = true |
| | | this.button.queryButton = true |
| | | |
| | | axiosInstanceInstance.get('/fume/abnormalthree', { params: params }).then((response) => { |
| | | this.abnormalData = response.data.data |
| | | this.total = this.abnormalData.length |
| | | this.loading = false |
| | | this.button.queryButton = false |
| | | if (response.data.data.length == 0) { |
| | | ElMessage('è¯¥æ¶æ®µæ æ°æ®') |
| | | this.isNoData = true |
| | | return |
| | | } |
| | | // ç§»é¤ç©ºæ°æ®ç¶æ |
| | | this.isNoData = false |
| | | this.handleCurrentChange(1) |
| | | }) |
| | | }, |
| | | handleSizeChange(val) { |
| | | this.pageSize = val |
| | | // æ¹åæ¯é¡µæ¾ç¤ºæ°ç®æ¶è·³å°ç¬¬ä¸é¡µ |
| | | this.handleCurrentChange(1) |
| | | }, |
| | | handleCurrentChange(val) { |
| | | const startIndex = (val - 1) * this.pageSize |
| | | const endIndex = startIndex + this.pageSize |
| | | |
| | | this.displayData = this.abnormalData.slice(startIndex, endIndex) |
| | | }, |
| | | |
| | | //ç¸å·®å¤å°ä¸ªååé 计ç®ä¸å¹¶ä¸å
æ¬å¼å§æ¶é´ï¼ä½å
æ¬ç»ææ¶é´ã |
| | | diffTenMinutesNum(beginNormal, endNormal) { |
| | | // å°å¼å§æ¶é´åç»ææ¶é´è½¬æ¢ä¸ºdayjs对象 |
| | | const start = dayjs(beginNormal) |
| | | const end = dayjs(endNormal) |
| | | |
| | | // 计ç®ç»ææ¶é´åå»å¼å§æ¶é´ä¸é´ç¸å·®å¤å°ä¸ªååé |
| | | const diffInMinutes = end.diff(start, 'minute') |
| | | const diffInTenMinutes = Math.floor(diffInMinutes / 10) |
| | | return diffInTenMinutes |
| | | }, |
| | | |
| | | // åæ°ï¼å¼å¸¸çå¼å§æ¶é´ï¼å¼å¸¸çç»ææ¶é´ã |
| | | // åè½ï¼è¿åå¼å§æ¶é´çå30åéçæ¶é´ç¹ï¼ç»ææ¶é´å40åéçæ¶é´ç¹ |
| | | before30AndAfter40(begin, end) { |
| | | let time = [] |
| | | const before30MinBegin = dayjs(begin).subtract(30, 'minute').format('YYYY-MM-DD HH:mm:ss') |
| | | // å䏿®µçå¼å§æ¶é´ |
| | | const after10MinBegin = dayjs(end).add(10, 'minute').format('YYYY-MM-DD HH:mm:ss') |
| | | // å¾å40åé |
| | | const after40MinEnd = dayjs(end).add(40, 'minute').format('YYYY-MM-DD HH:mm:ss') |
| | | time.push(before30MinBegin) |
| | | time.push(after10MinBegin) |
| | | time.push(after40MinEnd) |
| | | return time |
| | | }, |
| | | |
| | | // åæ°ï¼è®¾å¤ç¼å·ï¼ å¼å§æ¶é´ï¼ ç»ææ¶é´ |
| | | // åè½ï¼è¿åæè®¾å¤å¨è¯¥æ¶æ®µå岿°æ®çget请æ±åæ°ã |
| | | requestGetParms(devnum, begin, end) { |
| | | return { |
| | | devId: devnum, |
| | | beginTime: begin, |
| | | endTime: end, |
| | | } |
| | | }, |
| | | // åæ°ï¼å¯¹è±¡æ°ç»(该对象ä¸ç屿§ä¸è½æ¯å¼ç¨ç±»åï¼å¦åæ·è´çå¼è¿æ¯ä¼ç¸äºå½±å) |
| | | // åè½ï¼æ·è´è¯¥å¯¹è±¡æ°ç»ã |
| | | shallowCopyList(itemIsObjOfList) { |
| | | let tempList = [] |
| | | itemIsObjOfList.forEach((item) => { |
| | | tempList.push({ ...item }) |
| | | }) |
| | | return tempList |
| | | }, |
| | | |
| | | // åæ°ï¼æ·»å é¦å°¾æ¶é´æ°æ®çå¼å¸¸æ°æ®æ°ç»(å
ç´ ä¸ºå¯¹è±¡) |
| | | // åè½ï¼å¯¹ä¸é´å¼å¸¸åºé´æ¶é´åå¼è¿è¡è¡¥å
ï¼è¿åå¤çåçç»æ |
| | | // è¯¦ç»æè¿°ï¼éåæ°ç»ï¼å½åç°æ°ç»å
ç´ ä¸ºç©ºæ¶ï¼è®¾ç½®è¯¥å
ç´ çæ¶é´ä¸ºä¸ä¸ä¸ªå
ç´ æ¶é´çå10åéï¼å¹¶ææµåº¦å¼è®¾ç½®ä¸ºnull(ä¸ä¸ªå
ç´ çæ¶é´ä¸å®ä¸ä¸ºç©ºï¼æ éåå»å¤æä¸ä¸ªå
ç´ ä¸ºç©ºçæ
åµ)ã |
| | | addTenMinutes(exceptionDataArr) { |
| | | // xè½´ æ¥ææ¶é´ |
| | | let dateList = [] |
| | | // yè½´ è¶
æ æ²¹çæµåº¦ |
| | | let fumeExceeding = [] |
| | | let obj = {} |
| | | for (let i = 0; i < exceptionDataArr.length; i++) { |
| | | if (exceptionDataArr[i] == null) { |
| | | //xè½´æ¥æãå
ç´ ä¸ºnullæ¶ï¼ 设置该å
ç´ çæ¶é´ä¸ºåä¸å
ç´ çæ¶é´å10åé |
| | | dateList.push( |
| | | dayjs(dateList[dateList.length - 1]) |
| | | .add(10, 'minute') |
| | | .format('YYYY-MM-DD HH:mm:ss'), |
| | | ) |
| | | // è¶
æ æ²¹çæµåº¦ |
| | | fumeExceeding.push(null) |
| | | } else { |
| | | //xè½´æ¥æ |
| | | dateList.push(exceptionDataArr[i].mvDataTime) |
| | | // è¶
æ æ²¹çæµåº¦ |
| | | fumeExceeding.push(exceptionDataArr[i].mvFumeConcentration2) |
| | | } |
| | | } |
| | | obj['dateList'] = dateList |
| | | obj['fumeExceeding'] = fumeExceeding |
| | | return obj |
| | | }, |
| | | |
| | | // åæ°ï¼å ä¸åååºé´çå¼å¸¸æ°æ®ï¼æ¶é´å符串 |
| | | // åè½ï¼å¤ædata䏿¯å¦æè¯¥æ¥ææ¶é´ï¼åå¨è¿å该æ¶é´å¯¹åºçæµåº¦å¼ï¼å¦åè¿å-1 |
| | | findTimeInExceptionData(data, time) { |
| | | for (let i = 0; i < data.length; i++) { |
| | | if (data[i] == null) { |
| | | continue |
| | | } |
| | | if (data[i]['mvDataTime'] == time) { |
| | | return data[i]['mvFumeConcentration2'] |
| | | } |
| | | } |
| | | return -1 |
| | | }, |
| | | // åæ°:ååºé´çå¼å§æ¶é´ï¼ ååºé´çç»ææ¶é´, å ä¸åååºé´çæ»æ¶é´æ®µçå¼å¸¸æ°æ®ç对象æ°ç» |
| | | // åè½ï¼æ ¹æ®å¼å§åç»ææ¶é´,è¿å以10åé为é´éçæ¶é´å对åºçå¼ |
| | | keepContinuousByEachTenMinutes(intervalStarTime, intervalEndTime, headAndTailExceptionData) { |
| | | let xAxis = [] |
| | | let yAxis = [] |
| | | let obj = {} |
| | | let current = intervalStarTime |
| | | let tail = dayjs(intervalEndTime).add(10, 'minute').format('YYYY-MM-DD HH:mm:ss') |
| | | while (current != tail) { |
| | | let value = this.findTimeInExceptionData(headAndTailExceptionData, current) |
| | | if (value != -1) { |
| | | xAxis.push(current) |
| | | yAxis.push(value) |
| | | } else { |
| | | xAxis.push(current) |
| | | yAxis.push(null) |
| | | } |
| | | current = dayjs(current).add(10, 'minute').format('YYYY-MM-DD HH:mm:ss') |
| | | } |
| | | obj['xAxis'] = xAxis |
| | | obj['yAxis'] = yAxis |
| | | return obj |
| | | }, |
| | | |
| | | // åæ°ï¼è¶
æ æ°æ®åé¢åºé´çæ°æ® |
| | | // åè½ï¼è¿åé¤å»æåä¸ä¸ªå
ç´ çæ°ç» |
| | | removeLastItemOfBeforeData(beforeDataOfExceeding) { |
| | | let tempList = [] |
| | | if (beforeDataOfExceeding.length == 1) { |
| | | return tempList |
| | | } else { |
| | | for (let i = 0; i < beforeDataOfExceeding.length - 1; i++) { |
| | | tempList.push({ ...beforeDataOfExceeding[i] }) |
| | | } |
| | | return tempList |
| | | } |
| | | }, |
| | | |
| | | // 设置option |
| | | // åæ°ï¼xè½´æ¶é´ï¼ yè½´æ²¹çæµåº¦ï¼ å¼å¸¸ç±»å«(0代表è¶
æ ï¼1代表ä¾çµå¼å¸¸åæçº¿), å¼å¸¸å¼å§æ¶é´ï¼å¼å¸¸ç»ææ¶é´ï¼å¼å¸¸å¼å§æ¶é´å¨æ´ä¸ªåºé´çç´¢å¼ä¸æ ï¼å¼å¸¸ç»ææ¶é´å¨æ´ä¸ªåºé´çç´¢å¼ä¸æ |
| | | setOption( |
| | | xData, |
| | | yData, |
| | | exceptionCategory, |
| | | exceptionBeginTime, |
| | | exceptionEndTime, |
| | | beginIndex, |
| | | endIndex, |
| | | ) { |
| | | this.option = {} |
| | | // è¶
æ |
| | | if (exceptionCategory == 0) { |
| | | this.option = { |
| | | tooltip: {}, |
| | | toolbox: { |
| | | // å·¥å
·æ |
| | | feature: { |
| | | // dataZoom: { |
| | | // yAxisIndex: 'none' |
| | | // }, |
| | | // ä¿å为å¾ç |
| | | saveAsImage: {}, |
| | | }, |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: xData, |
| | | name: 'æ¶é´', |
| | | axisLabel: { |
| | | formatter: function (value) { |
| | | return value.slice(11, -3) |
| | | }, |
| | | }, |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | name: 'mg/m³', |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'æ²¹çæµåº¦', |
| | | type: 'line', |
| | | data: yData.map((item) => { |
| | | if (item >= 1) { |
| | | return { |
| | | value: item, |
| | | itemStyle: { |
| | | color: 'red', |
| | | }, |
| | | } |
| | | } |
| | | return item |
| | | }), |
| | | // 忢æå®æ¶é´åºé´çèæ¯é¢è² |
| | | markArea: { |
| | | itemStyle: { |
| | | color: 'rgba(255, 173, 177, 0.4)', |
| | | }, |
| | | data: [ |
| | | [ |
| | | { |
| | | name: 'è¶
æ æ¶é´æ®µ', |
| | | xAxis: exceptionBeginTime, |
| | | }, |
| | | { |
| | | xAxis: exceptionEndTime, |
| | | }, |
| | | ], |
| | | ], |
| | | }, |
| | | markLine: { |
| | | symbol: 'none', |
| | | itemStyle: { |
| | | // åºçº¿å
Œ
±æ ·å¼ |
| | | normal: { |
| | | lineStyle: { |
| | | type: 'dashed', |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'end', |
| | | formatter: '{b}', |
| | | }, |
| | | }, |
| | | }, |
| | | data: [ |
| | | { |
| | | name: 'è¶
æ ', |
| | | type: 'average', |
| | | yAxis: 1, |
| | | lineStyle: { |
| | | // color: '#ff0000' |
| | | color: 'red', |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | }, |
| | | ], |
| | | // æå®æ¶é´åºé´ç线段åé¢è² |
| | | visualMap: { |
| | | show: false, |
| | | dimension: 0, |
| | | pieces: [ |
| | | { |
| | | lte: beginIndex, |
| | | color: 'green', |
| | | }, |
| | | { |
| | | gt: beginIndex, |
| | | lte: endIndex, |
| | | color: 'red', |
| | | }, |
| | | { |
| | | gt: endIndex, |
| | | lte: xData.length - 1, |
| | | color: 'green', |
| | | }, |
| | | ], |
| | | }, |
| | | } |
| | | } |
| | | // ä¾çµå¼å¸¸åæçº¿ |
| | | else if (exceptionCategory == 1) { |
| | | this.option = { |
| | | tooltip: {}, |
| | | toolbox: { |
| | | // å·¥å
·æ |
| | | feature: { |
| | | // dataZoom: { |
| | | // // åºåç¼©æ¾ |
| | | // yAxisIndex: 'none' |
| | | // }, |
| | | // ä¿å为å¾ç |
| | | saveAsImage: {}, |
| | | }, |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: xData, |
| | | name: 'æ¶é´', |
| | | axisLabel: { |
| | | formatter: function (value) { |
| | | return value.slice(11, -3) |
| | | }, |
| | | }, |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | name: 'mg/m³', |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'æ²¹çæ°æ®', |
| | | type: 'line', |
| | | data: yData, |
| | | markLine: { |
| | | silent: true, |
| | | data: [ |
| | | // æ æ³¨æ æ°æ®æ¶é´æ®µçææï¼å°è¿ä¸ªæ¶é´æ®µçæ°è½´é¨ååä¸ºçº¢è² |
| | | { |
| | | name: 'æ æ°æ®', |
| | | xAxis: exceptionBeginTime, |
| | | }, |
| | | { |
| | | xAxis: exceptionEndTime, |
| | | }, |
| | | ], |
| | | lineStyle: { |
| | | color: 'red', |
| | | }, |
| | | }, |
| | | }, |
| | | ], |
| | | } |
| | | } |
| | | this.banTouch = 0 |
| | | }, |
| | | |
| | | // åè½ï¼ç¹å» âæ¥ç详æ
âï¼ âä¸ä¸æ¡âæé®æ¶ä¼ å
é»è¾è®¡ç®ãæåå±ç¤ºå¾å½¢ |
| | | drawChartTest() { |
| | | this.beforeData = [] |
| | | this.afterData = [] |
| | | this.allExceptionTimeData = [] |
| | | //å¼å¸¸çå¼å§æ¶é´ ç»ææ¶é´ |
| | | let exceptionBeginTime = this.rowBeginTime |
| | | let exceptionEndTime = this.rowEndTime |
| | | |
| | | // beforeAndAfterTime[0]:å30åéçæ¶é´ç¹ |
| | | // beforeAndAfterTime[1]:å10åéçæ¶é´ç¹ |
| | | // beforeAndAfterTime[2]:å40åéçæ¶é´ç¹ |
| | | let beforeAndAfterTime = this.before30AndAfter40(exceptionBeginTime, exceptionEndTime) |
| | | |
| | | // æé å¼å¸¸æ¶é´åçåºé´æ°æ®è¯·æ±åæ° |
| | | let paramsBefore = this.requestGetParms( |
| | | this.displayData[this.selectedRowIndex].devId, |
| | | beforeAndAfterTime[0], |
| | | this.displayData[this.selectedRowIndex].beginTime, |
| | | ) |
| | | |
| | | // æé å¼å¸¸æ¶é´åçåºé´æ°æ®è¯·æ±åæ° |
| | | let paramsAfter = this.requestGetParms( |
| | | this.displayData[this.selectedRowIndex].devId, |
| | | beforeAndAfterTime[1], |
| | | beforeAndAfterTime[2], |
| | | ) |
| | | |
| | | // æçº¿å¾å è½½ä¸ææ |
| | | this.chartLoading = true |
| | | // 请æ±ååæ®µ |
| | | axiosInstanceInstance.get('/fume/history', { params: paramsBefore }).then((result1) => { |
| | | this.beforeData = result1.data.data |
| | | // 请æ±ååæ®µ |
| | | axiosInstanceInstance.get('/fume/history', { params: paramsAfter }).then((result2) => { |
| | | this.afterData = result2.data.data |
| | | //ä¿åå¼å¸¸åºé´çå¼ |
| | | let tempArr = [] |
| | | // ä¿åå¼å¸¸åºé´ååçå¼ |
| | | let before = [] |
| | | let after = [] |
| | | |
| | | // 夿æ¯å¦æ¯ä¾çµå¼å¸¸ææçº¿ |
| | | if (this.rowExceptionType === '1' || this.rowExceptionType === '2') { |
| | | // éæè¡¨æ ¼ 缺失å¼å¸¸æ°æ®èªå¨å¡«å
|
| | | this.setExceptionData() |
| | | |
| | | //ç¸å·®å 个10åé |
| | | const TenMinuteNum = this.diffTenMinutesNum(exceptionBeginTime, exceptionEndTime) |
| | | //ç¨nullå¡«å
ä¸å¼å¸¸æ æ°æ®çæ¶é´ |
| | | for (let i = 0; i < TenMinuteNum; i++) { |
| | | tempArr.push(null) |
| | | } |
| | | before = this.shallowCopyList(this.beforeData) |
| | | |
| | | after = this.shallowCopyList(this.afterData) |
| | | // after = this.afterData |
| | | } |
| | | // è¶
æ |
| | | else { |
| | | let beforeTemp = this.removeLastItemOfBeforeData(this.beforeData) |
| | | // åååºé´åªæ¾ç¤ºè·ç¦»è¶
æ åºé´æ¶é´æè¿çæµåº¦å°äº1çæ¶é´ç¹ |
| | | for (let i = beforeTemp.length - 1; i >= 0; i--) { |
| | | if (beforeTemp[i].mvFumeConcentration2 >= 1) { |
| | | break |
| | | } |
| | | if (beforeTemp[i].mvFumeConcentration2 < 1) { |
| | | before.unshift(this.beforeData[i]) |
| | | } |
| | | } |
| | | |
| | | for (let i = 0; i < this.afterData.length; i++) { |
| | | if (this.afterData[i].mvFumeConcentration2 >= 1) { |
| | | break |
| | | } |
| | | if (this.afterData[i].mvFumeConcentration2 < 1) { |
| | | after.unshift(this.afterData[i]) |
| | | } |
| | | } |
| | | tempArr = this.shallowCopyList(this.exceedingData) |
| | | } |
| | | |
| | | // å°åååºé´æ°æ® ä¸ å¼å¸¸åºé´æ°æ® åå¹¶ |
| | | this.allExceptionTimeData = [...before, ...tempArr, ...after] |
| | | // xè½´æ¥ææ¶é´ |
| | | let dateList |
| | | // yè½´ è¶
æ æ²¹çæµåº¦ |
| | | let fumeExceeding |
| | | let timeAndValue |
| | | |
| | | // 仿·»å äºé¦ä½åºé´çå¼å§åç»ææ¶é´è¿è¡éå ä¿è¯æ¶é´ä»¥10åé为é´é |
| | | timeAndValue = this.keepContinuousByEachTenMinutes( |
| | | beforeAndAfterTime[0], |
| | | beforeAndAfterTime[2], |
| | | this.allExceptionTimeData, |
| | | ) |
| | | |
| | | dateList = timeAndValue['xAxis'] |
| | | fumeExceeding = timeAndValue['yAxis'] |
| | | |
| | | // æåå¼å¸¸èµ·å§æ¶é´ç¹å¨æ´ä¸ªåºé´å
çæ°æ®ç´¢å¼ |
| | | let startIndex = dateList.findIndex((item) => item === exceptionBeginTime) |
| | | let endIndex = dateList.findIndex((item) => item === exceptionEndTime) |
| | | |
| | | // ä¾çµå¼å¸¸åæçº¿æ
åµ è¶
æ æ
åµ |
| | | if (this.rowExceptionType === '1' || this.rowExceptionType === '2') { |
| | | this.setOption( |
| | | dateList, |
| | | fumeExceeding, |
| | | 1, |
| | | exceptionBeginTime, |
| | | exceptionEndTime, |
| | | startIndex, |
| | | endIndex, |
| | | ) |
| | | } else { |
| | | // è¶
æ æ
åµ |
| | | this.setOption( |
| | | dateList, |
| | | fumeExceeding, |
| | | 0, |
| | | exceptionBeginTime, |
| | | exceptionEndTime, |
| | | startIndex, |
| | | endIndex, |
| | | ) |
| | | } |
| | | this.chartLoading = false |
| | | }) |
| | | }) |
| | | }, |
| | | |
| | | getDeviceInfo() { |
| | | // 级èä¸ææ¡æ°æ® 仿¥å£ä¸å¨æè·å |
| | | axiosInstanceInstance.get('/fume/device').then((result) => { |
| | | this.deviceInfo = result.data.data |
| | | // è·åå°æ»çåºéºæ°é |
| | | this.shopsTotal = result.data.data.length |
| | | this.deviceInfo.forEach((item) => { |
| | | this.optionsShop[this.optionsShop.length] = { |
| | | value: item.diName, |
| | | label: item.diName, |
| | | children: [ |
| | | { |
| | | value: item.diCode, |
| | | label: item.diCode, |
| | | }, |
| | | ], |
| | | } |
| | | }) |
| | | }) |
| | | }, |
| | | exportDom() { |
| | | // 导åºä¸ºExcelæä»¶ |
| | | const fields = ['devId', 'exceptionType', 'region', 'beginTime', 'endTime'] |
| | | const itemsFormatted = this.abnormalData.map((item) => { |
| | | const newItem = {} |
| | | fields.forEach((field) => { |
| | | newItem[field] = item[field] |
| | | }) |
| | | return newItem |
| | | }) |
| | | // å建xlsx对象 |
| | | const xls = XLSX.utils.json_to_sheet(itemsFormatted) |
| | | // ç¼è¾è¡¨å¤´è¡ ä¿®æ¹è¡¨å¤´ |
| | | xls['A1'].v = '设å¤ç¼å·' |
| | | xls['B1'].v = 'å¼å¸¸ç±»å' |
| | | xls['C1'].v = 'å°åº' |
| | | xls['D1'].v = 'å¼å§æ¶é´' |
| | | xls['E1'].v = 'ç»ææ¶é´' |
| | | // å建workbookï¼å¹¶æsheetæ·»å è¿å» |
| | | const wb = XLSX.utils.book_new() |
| | | XLSX.utils.book_append_sheet(wb, xls, 'Sheet1') |
| | | // å°workbook转为äºè¿å¶xlsxæä»¶å¹¶ä¸è½½ |
| | | XLSX.writeFile(wb, 'åææ°æ®.xlsx') |
| | | }, |
| | | |
| | | getAbnormalDataByClick(val) { |
| | | this.abnormalData = val |
| | | this.total = this.abnormalData.length |
| | | // é»è®¤æ¾ç¤ºç¬¬ä¸é¡µ |
| | | this.handleCurrentChange(1) |
| | | }, |
| | | |
| | | // æ ¹æ®å¼å¸¸ç±»åè¿ååºéºåç§°å设å¤ç¼å· |
| | | // æ¯å¦æ²¹çè¶
æ 对åºçææåºéºåç§°å设å¤ç¼å·ï¼å·²å»é¤éå¤çåºéºåï¼ |
| | | getShopNames() { |
| | | axiosInstanceInstance |
| | | .get('/fume/shopname', { |
| | | params: { |
| | | exceptionType: '0', |
| | | beginTime: this.beginTime, |
| | | endTime: this.endTime, |
| | | }, |
| | | }) |
| | | .then((result) => { |
| | | this.exception0 = result.data.data |
| | | }) |
| | | axiosInstanceInstance |
| | | .get('/fume/shopname', { |
| | | params: { |
| | | exceptionType: '1', |
| | | beginTime: this.beginTime, |
| | | endTime: this.endTime, |
| | | }, |
| | | }) |
| | | .then((result) => { |
| | | this.exception1 = result.data.data |
| | | }) |
| | | axiosInstanceInstance |
| | | .get('/fume/shopname', { |
| | | params: { |
| | | exceptionType: '2', |
| | | beginTime: this.beginTime, |
| | | endTime: this.endTime, |
| | | }, |
| | | }) |
| | | .then((result) => { |
| | | this.exception2 = result.data.data |
| | | }) |
| | | |
| | | /* å¼å¸¸æ°é */ |
| | | axiosInstanceInstance |
| | | .get('/fume/exceptionnum', { |
| | | params: { |
| | | exceptionType: '0', |
| | | beginTime: this.beginTime, |
| | | endTime: this.endTime, |
| | | }, |
| | | }) |
| | | .then((result) => { |
| | | this.exception0Num = result.data.data |
| | | }) |
| | | axiosInstanceInstance |
| | | .get('/fume/exceptionnum', { |
| | | params: { |
| | | exceptionType: '1', |
| | | beginTime: this.beginTime, |
| | | endTime: this.endTime, |
| | | }, |
| | | }) |
| | | .then((result) => { |
| | | this.exception1Num = result.data.data |
| | | }) |
| | | axiosInstanceInstance |
| | | .get('/fume/exceptionnum', { |
| | | params: { |
| | | exceptionType: '2', |
| | | beginTime: this.beginTime, |
| | | endTime: this.endTime, |
| | | }, |
| | | }) |
| | | .then((result) => { |
| | | this.exception2Num = result.data.data |
| | | }) |
| | | }, |
| | | |
| | | // 页é¢å è½½æ¶é»è®¤å±ç¤º7天å¼å¸¸è¡¨æ°æ® |
| | | getRecentSevenDays() { |
| | | // ç»çº§èéæ©å¨è®¾ç½®é»è®¤ç鿩项 |
| | | this.devId = ['ä»å°å§å¨æé½', 'qinshi_31010320210010'] |
| | | let params = {} |
| | | params['beginTime'] = this.beginTime |
| | | params['endTime'] = this.endTime |
| | | axiosInstanceInstance.get('/fume/abnormalthree', { params: params }).then((response) => { |
| | | if (response.data.data.length == 0) { |
| | | ElMessage('è¯¥æ¶æ®µæ æ°æ®') |
| | | return |
| | | } |
| | | // ä¿åè¿åç |
| | | this.abnormalData = response.data.data |
| | | // å页 |
| | | this.total = this.abnormalData.length |
| | | // é»è®¤æ¾ç¤ºç¬¬ä¸é¡µ |
| | | this.handleCurrentChange(1) |
| | | this.loading = false |
| | | }) |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .header-container { |
| | | display: flex; |
| | | margin-left: 20px; |
| | | /* flex-wrap: wrap; |
| | | align-items: center; */ |
| | | } |
| | | .ellipsis { |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .iconExcel { |
| | | font-size: 25px; |
| | | margin-left: 20px; |
| | | bottom: -6px; |
| | | } |
| | | |
| | | /* å¯é¼ æ ç®å¤´å为å¯ç¹å»ç¶æ */ |
| | | .clickable { |
| | | cursor: pointer; |
| | | } |
| | | .card-header { |
| | | margin: 0; |
| | | } |
| | | |
| | | body { |
| | | margin: 0; |
| | | } |
| | | .exception-divider-rowline { |
| | | margin: 10px 0px; |
| | | } |
| | | /* å¼å¸¸åææ°æ®ä¸æé® */ |
| | | .exception-container { |
| | | display: flex; |
| | | } |
| | | .example-showcase .el-loading-mask { |
| | | z-index: 9; |
| | | } |
| | | |
| | | .scrollbar-demo-item { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 20px; |
| | | margin: 10px; |
| | | text-align: center; |
| | | border-radius: 4px; |
| | | background: var(--el-color-primary-light-9); |
| | | color: var(--el-color-primary); |
| | | } |
| | | .collapse-header { |
| | | margin-left: 5px; |
| | | font-size: 18px; |
| | | } |
| | | .collapse-header-text { |
| | | margin-top: 5px; |
| | | font-size: 14px; |
| | | color: gray; |
| | | } |
| | | |
| | | .box-card-label { |
| | | font-size: 14px; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .right-text { |
| | | /* float :right; */ |
| | | /* text-align: right; */ |
| | | margin-left: 80px; |
| | | } |
| | | :deep().el-card { |
| | | border-radius: 9px; |
| | | } |
| | | |
| | | /* âæ¥ç详æ
â çå¼¹åºæ¡é«åº¦è°æ´ */ |
| | | :deep().el-dialog { |
| | | height: 98%; |
| | | /* ä¸åºç°æ»å¨æ¡ */ |
| | | overflow-y: hidden; |
| | | border-radius: 9px; |
| | | } |
| | | .table-page { |
| | | margin-left: 20px; |
| | | } |
| | | |
| | | .table-text { |
| | | font-size: 18px; |
| | | margin: 5px 0px 10px 20px; |
| | | } |
| | | .text-blank { |
| | | margin-right: 10px; |
| | | color: #000000; |
| | | } |
| | | /* åºéºåéæ©ææ¬ */ |
| | | .describe-info { |
| | | margin-top: 5px; |
| | | font-weight: bold; |
| | | white-space: nowrap; |
| | | } |
| | | /* æ¶é´éæ©ææ¬ */ |
| | | .describe-time-text { |
| | | margin-left: 30px; |
| | | margin-top: 5px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | /* å¼å¸¸è¡¨æ ¼ä¸æ ç¾ä¸çæ°ç» */ |
| | | .table-line-num { |
| | | font-weight: bold; |
| | | color: black; |
| | | } |
| | | .button_info.el-button_inner { |
| | | text-align: left; |
| | | } |
| | | .el-collapse { |
| | | margin-left: 20px; |
| | | } |
| | | :deep().el-collapse .el-collapse-item__content { |
| | | padding-bottom: 0px; |
| | | } |
| | | .box-card { |
| | | height: 190px; |
| | | } |
| | | |
| | | .sub-box-card { |
| | | height: 100px; |
| | | border: 0px; |
| | | } |
| | | |
| | | .mx-1 { |
| | | margin-bottom: 0px; |
| | | } |
| | | .dialog-button-position { |
| | | display: flex; |
| | | justify-content: right; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | :deep().el-table__row .exceeding-row { |
| | | background-color: #f53f3f; |
| | | } |
| | | :deep().el-table__row .abnormal-power-supply { |
| | | background-color: #fdf4bf; |
| | | } |
| | | :deep().el-table__row .disconnect { |
| | | background-color: #f7ba1e; |
| | | } |
| | | |
| | | .el-table { |
| | | color: #000000; |
| | | } |
| | | |
| | | /* è¡¨æ ¼ä¸çæé®å®½åº¦éºæ»¡ */ |
| | | .table-button { |
| | | width: 100%; |
| | | } |
| | | </style> |
| | |
| | | <!-- å岿°æ® --> |
| | | <script> |
| | | import { defineAsyncComponent } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import * as XLSX from 'xlsx/xlsx.mjs' |
| | | import dayjs from 'dayjs' |
| | | import axiosInstanceInstance from '@/utils/request.js' |
| | |
| | | <template> |
| | | <!-- solid #000000 --> |
| | | <div style="margin: 20px; padding: 10px; border: 1px; height: 620px"> |
| | | <h1 style="margin-bottom: 20px; display: flex; white-space: nowrap">æ²¹çå岿°æ®</h1> |
| | | <div style="display: flex"> |
| | | <span class="palce-text"><span class="palce-text-area">åºåï¼</span>éå®åº </span> |
| | | <!-- <span class="palce-text"><span class="palce-text-area">åºåï¼</span>éå®åº </span> --> |
| | | |
| | | <!-- åºéºå 级è --> |
| | | <!-- <el-cascader v-model="devId" :options="optionsShop" :props="{ expandTrigger: 'hover' }" placeholder="è¯·éæ©åºéºå" |
| | |
| | | :data="displayData" |
| | | style="width: 100%; margin-top: 25px" |
| | | height="500px" |
| | | table-layout="auto" |
| | | table-layout="fixed" |
| | | :show-overflow-tooltip="true" |
| | | > |
| | | <el-table-column fixed prop="mvStatCode" label="设å¤ç¼å·"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.mvStatCode"> |
| | | <div class="cell ellipsis">{{ row.mvStatCode }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="diName" label="åºéºåç§°"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.diName"> |
| | | <div class="cell ellipsis">{{ row.diName }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column prop="mvDataTime" label="ééæ¶é´"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.mvDataTime"> |
| | | <div class="cell ellipsis">{{ row.mvDataTime }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="mvFanElectricity" label="飿ºçµæµ(A)"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.mvFanElectricity"> |
| | | <div class="cell ellipsis">{{ row.mvFanElectricity }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="mvPurifierElectricity" label="ååå¨çµæµ(A)"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.mvPurifierElectricity"> |
| | | <div class="cell ellipsis">{{ row.mvPurifierElectricity }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="mvFumeConcentration2" label="æ²¹çæµåº¦(mg/m³)"> |
| | | <template #default="{ row }"> |
| | | <el-tooltip effect="dark" :content="row.mvFumeConcentration2"> |
| | | <div class="cell ellipsis">{{ row.mvFumeConcentration2 }}</div> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed prop="mvStatCode" label="设å¤ç¼å·"> </el-table-column> |
| | | <el-table-column prop="diName" label="åºéºåç§°"> </el-table-column> |
| | | <el-table-column prop="mvDataTime" label="ééæ¶é´"> </el-table-column> |
| | | <el-table-column prop="mvFanElectricity" label="飿ºçµæµ(A)"> </el-table-column> |
| | | <el-table-column prop="mvPurifierElectricity" label="ååå¨çµæµ(A)"> </el-table-column> |
| | | <el-table-column prop="mvFumeConcentration2" label="æ²¹çæµåº¦(mg/m³)"> </el-table-column> |
| | | </el-table> |
| | | <el-pagination |
| | | background |