| | |
| | | <template> |
| | | <router-link :to="{ name: 'dashboard' }"> |
| | | <div class="flex logo-container flex-center"> |
| | | <!-- <img class="logo-img" :src="@/assets/img/logo.png" alt="logo" /> --> |
| | | <img v-if="localInfo.logoPath" class="logo-img" :src="localInfo.logoPath" alt="logo" /> |
| | | <img v-else class="logo-img" src="@/assets/img/menuLogo.png" alt="logo" /> |
| | | <img class="logo-img" :src="homeLogo" alt="logo" /> |
| | | <!-- <h1 class="logo-title" v-if="showTitle">{{ title }}</h1> --> |
| | | </div> |
| | | </router-link> |
| | | </template> |
| | | |
| | | <script> |
| | | import homeLogo from '@/assets/img/sdjt.jpg' |
| | | |
| | | export default { |
| | | name: 'Logo', |
| | | |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | localInfo: {}, |
| | | homeLogo, |
| | | } |
| | | }, |
| | | created() { |
| | | this.localInfo = JSON.parse(localStorage.getItem('localInfo')) |
| | | }, |
| | | } |
| | | </script> |
| | |
| | | } |
| | | } |
| | | </style> |
| | | |
| | |
| | | <template> |
| | | <div style="margin-right: 30px" class="data-reMechanism"> |
| | | <div style="margin-right: 30px" class="data-reMechanism" :class="{ 'trend-detail-open': trendDetailVisible }"> |
| | | <div style="display: flex; align-items: center"> |
| | | <div style="margin-right:12px;font-size:16px;font-weight:bold">趋势分析</div> |
| | | <a-radio-group v-model="trendAnalysisType" @change="trendAnalysisTypeChange"> |
| | |
| | | </a-radio-group> |
| | | </div> |
| | | <div> |
| | | <div style="display: flex; align-items: flex-end; flex-direction: column"> |
| | | <div class="trend-analysis-chart" :class="{ 'is-modal-open': trendDetailVisible }" style="display: flex; align-items: flex-end; flex-direction: column"> |
| | | <a-radio-group |
| | | style="margin: 20px 0" |
| | | size="small" |
| | |
| | | :chartData="trendAnalysisData" |
| | | style="width: 100%" |
| | | :showpercent="trendAnalysisChartShowPercent" |
| | | :enablePointClick="true" |
| | | @chart-click="handleTrendChartClick" |
| | | ></DataReLineChart> |
| | | </div> |
| | | <div id="trendAnalysisChartID"></div> |
| | |
| | | :typeOneTotal="customerOneTotal" |
| | | :typeTwoTotal="customerTwoTotal" |
| | | ></TopTenCustomers> |
| | | <a-modal |
| | | centered |
| | | width="70%" |
| | | :footer="null" |
| | | v-model="trendDetailVisible" |
| | | :title="trendDetailTitle" |
| | | :zIndex="5000" |
| | | :getContainer="getModalContainer" |
| | | wrapClassName="trend-detail-modal-wrap" |
| | | @cancel="closeTrendDetail" |
| | | > |
| | | <a-table |
| | | size="middle" |
| | | bordered |
| | | :columns="trendDetailColumns" |
| | | :dataSource="trendDetailData" |
| | | :loading="trendDetailLoading" |
| | | :scroll="{ y: 420 }" |
| | | :pagination="{ pageSize: 10, showSizeChanger: true, pageSizeOptions: ['10', '20', '50'] }" |
| | | :rowKey=" |
| | | (record, index) => { |
| | | return record.id || record.licenseNum || record.captureTime || record.startTime || index |
| | | } |
| | | " |
| | | > |
| | | </a-table> |
| | | </a-modal> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | trendAnalysisUnit: 'DAYS', //趋势分析选择时间 |
| | | trendAnalysisData: {}, //趋势分析数据 |
| | | trendAnalysisChart: null, //趋势分析图表 |
| | | trendDetailVisible: false, |
| | | trendDetailTitle: '趋势分析明细', |
| | | trendDetailLoading: false, |
| | | trendDetailData: [], |
| | | trendDetailColumns: [], |
| | | beforeStartTime: '', |
| | | beforeEndTime: '', |
| | | afterStartTime: '', |
| | |
| | | |
| | | methods: { |
| | | moment, |
| | | getModalContainer() { |
| | | return document.body |
| | | }, |
| | | getTrendDetailColumnsByType() { |
| | | let commonIndexColumn = { |
| | | title: '序号', |
| | | dataIndex: '', |
| | | key: 'rowIndex', |
| | | width: 80, |
| | | align: 'center', |
| | | customRender: function (t, r, index) { |
| | | return parseInt(index) + 1 |
| | | }, |
| | | } |
| | | if (this.trendAnalysisType == 0) { |
| | | return [ |
| | | commonIndexColumn, |
| | | { title: '抓拍时间', align: 'center', dataIndex: 'captureTime' }, |
| | | { title: '车流量', align: 'center', dataIndex: 'carCount' }, |
| | | { title: '车型编码', align: 'center', dataIndex: 'modelCode' }, |
| | | { title: '设备编码', align: 'center', dataIndex: 'cameraCode' }, |
| | | ] |
| | | } |
| | | if (this.trendAnalysisType == 4 || this.trendAnalysisType == 5) { |
| | | return [ |
| | | commonIndexColumn, |
| | | { title: '更新时间', align: 'center', dataIndex: 'updateTimeSelf' }, |
| | | { title: '车牌号', align: 'center', dataIndex: 'licenseNum' }, |
| | | { title: '客户类型', align: 'center', dataIndex: 'clientName' }, |
| | | { title: '累计加油次数', align: 'center', dataIndex: 'oilCount' }, |
| | | { title: '累计油品销量', align: 'center', dataIndex: 'oilSum' }, |
| | | ] |
| | | } |
| | | return [ |
| | | commonIndexColumn, |
| | | { title: '进站时间', align: 'center', dataIndex: 'startTime' }, |
| | | { title: '车牌号', align: 'center', dataIndex: 'licenseNum' }, |
| | | { title: '行为类型', align: 'center', dataIndex: 'behaviorText' }, |
| | | { title: '加油位', align: 'center', dataIndex: 'oilPosition' }, |
| | | { title: '油品销量', align: 'center', dataIndex: 'oilVolume' }, |
| | | { title: '通过率(分)', align: 'center', dataIndex: 'spandTime' }, |
| | | ] |
| | | }, |
| | | handleTrendChartClick(params) { |
| | | if (!params || !params.name) { |
| | | return |
| | | } |
| | | if (this.$refs.trendAnalysisLineRef && this.$refs.trendAnalysisLineRef.hideTooltip) { |
| | | this.$refs.trendAnalysisLineRef.hideTooltip() |
| | | } |
| | | this.trendDetailVisible = true |
| | | this.trendDetailTitle = '趋势分析明细 - ' + params.name |
| | | this.trendDetailColumns = this.getTrendDetailColumnsByType() |
| | | this.trendDetailLoading = true |
| | | postAction('/jyz/dataTable/statTrendDetail', { |
| | | orgCode: this.selectTreeObj.orgCode, |
| | | startTime: this.startTime, |
| | | endTime: this.endTime, |
| | | trendType: this.trendAnalysisType, |
| | | timeUnit: this.trendAnalysisUnit, |
| | | statTime: params.name, |
| | | seriesName: params.seriesName, |
| | | }) |
| | | .then((res) => { |
| | | this.trendDetailData = res.result || [] |
| | | }) |
| | | .finally(() => { |
| | | this.trendDetailLoading = false |
| | | }) |
| | | }, |
| | | closeTrendDetail() { |
| | | this.trendDetailVisible = false |
| | | this.trendDetailData = [] |
| | | }, |
| | | //获取车型/加油位折线图数据 |
| | | getVehicleTypeLineData() { |
| | | postAction('/jyz/dataTable/statisMidTable', { |
| | |
| | | background: #fff; |
| | | } |
| | | .data-reMechanism { |
| | | position: relative; |
| | | isolation: isolate; |
| | | > div { |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | > div:nth-child(2) { |
| | | z-index: 1; |
| | | } |
| | | &.trend-detail-open { |
| | | pointer-events: none; |
| | | } |
| | | .trend-analysis-chart { |
| | | position: relative; |
| | | z-index: 1; |
| | | overflow: hidden; |
| | | } |
| | | .trend-analysis-chart.is-modal-open { |
| | | pointer-events: none; |
| | | } |
| | | .table-operator { |
| | | position: relative; |
| | | z-index: 2; |
| | | margin: 24px 0 0 0; |
| | | } |
| | | .block-title { |
| | |
| | | font-size: 16px; |
| | | } |
| | | .fueling-overview-ct { |
| | | position: relative; |
| | | z-index: 2; |
| | | // margin: 0 12px; |
| | | .fueling-overview-block { |
| | | display: flex; |
| | |
| | | } |
| | | } |
| | | .oil-freq-compare-ct { |
| | | position: relative; |
| | | z-index: 2; |
| | | margin: 8px 12px 24px 12px; |
| | | .oil-freq-compare-operator { |
| | | display: flex; |
| | |
| | | } |
| | | } |
| | | </style> |
| | | <style lang="less"> |
| | | .trend-detail-modal-wrap { |
| | | z-index: 5000 !important; |
| | | } |
| | | .trend-detail-modal-wrap + .ant-modal-mask { |
| | | z-index: 4999 !important; |
| | | } |
| | | </style> |
| | |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | enablePointClick: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | chartEntity: null, |
| | | zrClickHandler: null, |
| | | zrMoveHandler: null, |
| | | zrMouseOutHandler: null, |
| | | lastHoverIndex: -1, |
| | | lastEmitName: '', |
| | | lastEmitAt: 0, |
| | | lastLegendToggleAt: 0, |
| | | } |
| | | }, |
| | | methods: { |
| | | getOffsetPoint(event) { |
| | | if (!event) { |
| | | return null |
| | | } |
| | | if (event.offsetX !== undefined && event.offsetY !== undefined) { |
| | | return [event.offsetX, event.offsetY] |
| | | } |
| | | if (event.event && event.event.offsetX !== undefined && event.event.offsetY !== undefined) { |
| | | return [event.event.offsetX, event.event.offsetY] |
| | | } |
| | | return null |
| | | }, |
| | | isPointInGrid(point) { |
| | | if (!this.chartEntity || !this.chartEntity.containPixel || !point) { |
| | | return false |
| | | } |
| | | return this.chartEntity.containPixel({ gridIndex: 0 }, point) |
| | | }, |
| | | getXData() { |
| | | return this.chartData && this.chartData.xData ? this.chartData.xData : [] |
| | | }, |
| | | resolveNearestIndexByOffsetX(offsetX) { |
| | | let xData = this.getXData() |
| | | if (!this.chartEntity || !this.chartEntity.convertToPixel || !xData.length) { |
| | | return -1 |
| | | } |
| | | let nearestIndex = -1 |
| | | let minDistance = Number.MAX_VALUE |
| | | for (let i = 0; i < xData.length; i++) { |
| | | let xPixel = this.chartEntity.convertToPixel({ xAxisIndex: 0 }, xData[i]) |
| | | if (Array.isArray(xPixel)) { |
| | | xPixel = xPixel[0] |
| | | } |
| | | if (xPixel === undefined || xPixel === null || Number.isNaN(Number(xPixel))) { |
| | | continue |
| | | } |
| | | let distance = Math.abs(Number(offsetX) - Number(xPixel)) |
| | | if (distance < minDistance) { |
| | | minDistance = distance |
| | | nearestIndex = i |
| | | } |
| | | } |
| | | if (nearestIndex === -1) { |
| | | return -1 |
| | | } |
| | | return nearestIndex |
| | | }, |
| | | resolveClickIndex(event, params) { |
| | | let xData = this.getXData() |
| | | if (!xData.length) { |
| | | return -1 |
| | | } |
| | | let point = this.getOffsetPoint(event) |
| | | if (!this.isPointInGrid(point)) { |
| | | return -1 |
| | | } |
| | | if (params && typeof params.dataIndex === 'number' && xData[params.dataIndex] !== undefined) { |
| | | return params.dataIndex |
| | | } |
| | | if (params && params.name) { |
| | | let nameIndex = xData.findIndex((item) => item === params.name) |
| | | if (nameIndex > -1) { |
| | | return nameIndex |
| | | } |
| | | } |
| | | if (this.chartEntity && this.chartEntity.convertFromPixel && event) { |
| | | let xAxisValue = this.chartEntity.convertFromPixel({ xAxisIndex: 0 }, [event.offsetX, event.offsetY]) |
| | | if (xAxisValue !== undefined && xAxisValue !== null && !Number.isNaN(Number(xAxisValue))) { |
| | | let xIndex = Math.round(Number(xAxisValue)) |
| | | if (xIndex >= 0 && xIndex < xData.length) { |
| | | return xIndex |
| | | } |
| | | } |
| | | } |
| | | if (event && event.offsetX !== undefined && event.offsetX !== null) { |
| | | return this.resolveNearestIndexByOffsetX(event.offsetX) |
| | | } |
| | | return -1 |
| | | }, |
| | | emitChartClickByIndex(index, seriesName) { |
| | | let xData = this.getXData() |
| | | if (index < 0 || index >= xData.length) { |
| | | return |
| | | } |
| | | let clickName = xData[index] |
| | | let now = Date.now() |
| | | if (this.lastEmitName === clickName && now - this.lastEmitAt < 120) { |
| | | return |
| | | } |
| | | this.lastEmitName = clickName |
| | | this.lastEmitAt = now |
| | | this.$emit('chart-click', { |
| | | name: clickName, |
| | | seriesName: seriesName || null, |
| | | }) |
| | | }, |
| | | hideTooltip() { |
| | | if (!this.chartEntity) { |
| | | return |
| | | } |
| | | this.chartEntity.dispatchAction({ |
| | | type: 'hideTip', |
| | | }) |
| | | }, |
| | | bindChartClick() { |
| | | if (!this.chartEntity) { |
| | | return |
| | | } |
| | | this.chartEntity.off('click') |
| | | if (this.chartEntity.getZr) { |
| | | let zr = this.chartEntity.getZr() |
| | | if (this.zrClickHandler) { |
| | | zr.off('click', this.zrClickHandler) |
| | | } |
| | | if (this.zrMoveHandler) { |
| | | zr.off('mousemove', this.zrMoveHandler) |
| | | } |
| | | if (this.zrMouseOutHandler) { |
| | | zr.off('globalout', this.zrMouseOutHandler) |
| | | } |
| | | } |
| | | if (!this.enablePointClick) { |
| | | let chartDom = document.getElementById(this.domId) |
| | | if (chartDom) { |
| | | chartDom.style.cursor = 'default' |
| | | } |
| | | return |
| | | } |
| | | let chartDom = document.getElementById(this.domId) |
| | | if (chartDom) { |
| | | chartDom.style.cursor = 'pointer' |
| | | } |
| | | this.chartEntity.on('legendselectchanged', () => { |
| | | this.lastLegendToggleAt = Date.now() |
| | | }) |
| | | this.chartEntity.on('click', (params) => { |
| | | if (params && params.componentType === 'legend') { |
| | | return |
| | | } |
| | | if (Date.now() - this.lastLegendToggleAt < 180) { |
| | | return |
| | | } |
| | | let index = this.resolveClickIndex(params && params.event ? params.event : null, params) |
| | | this.emitChartClickByIndex(index, params ? params.seriesName : null) |
| | | }) |
| | | this.zrMoveHandler = (event) => { |
| | | let xData = this.getXData() |
| | | if (!xData.length) { |
| | | return |
| | | } |
| | | let xIndex = this.resolveClickIndex(event, null) |
| | | if (xIndex < 0 || xIndex >= xData.length) { |
| | | return |
| | | } |
| | | if (this.lastHoverIndex === xIndex) { |
| | | return |
| | | } |
| | | this.lastHoverIndex = xIndex |
| | | this.chartEntity.dispatchAction({ |
| | | type: 'showTip', |
| | | seriesIndex: 0, |
| | | dataIndex: xIndex, |
| | | }) |
| | | } |
| | | this.zrMouseOutHandler = () => { |
| | | this.lastHoverIndex = -1 |
| | | this.hideTooltip() |
| | | } |
| | | this.zrClickHandler = (event) => { |
| | | if (Date.now() - this.lastLegendToggleAt < 180) { |
| | | return |
| | | } |
| | | let index = this.resolveClickIndex(event, null) |
| | | this.emitChartClickByIndex(index, null) |
| | | } |
| | | let zr = this.chartEntity.getZr() |
| | | zr.on('mousemove', this.zrMoveHandler) |
| | | zr.on('globalout', this.zrMouseOutHandler) |
| | | zr.on('click', this.zrClickHandler) |
| | | }, |
| | | setChart() { |
| | | if (!this.chartEntity) { |
| | | let chartDom = document.getElementById(this.domId) |
| | |
| | | var option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | confine: true, |
| | | extraCssText: 'pointer-events:none;', |
| | | axisPointer: { |
| | | // 坐标轴指示器,坐标轴触发有效 |
| | | type: 'line', // 默认为直线,可选为:'line' | 'shadow' |
| | |
| | | ], |
| | | } |
| | | option && this.chartEntity.setOption(option, true) |
| | | this.bindChartClick() |
| | | }, |
| | | setPieUpChart() { |
| | | if (!this.chartEntity) { |
| | |
| | | var option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | confine: true, |
| | | extraCssText: 'pointer-events:none;', |
| | | axisPointer: { |
| | | // 坐标轴指示器,坐标轴触发有效 |
| | | type: 'line', // 默认为直线,可选为:'line' | 'shadow' |
| | |
| | | series: [...data], |
| | | } |
| | | option && this.chartEntity.setOption(option, true) |
| | | this.bindChartClick() |
| | | }, |
| | | setOnlyLineChart() { |
| | | if (!this.chartEntity) { |
| | |
| | | var option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | confine: true, |
| | | extraCssText: 'pointer-events:none;', |
| | | axisPointer: { |
| | | // 坐标轴指示器,坐标轴触发有效 |
| | | type: 'line', // 默认为直线,可选为:'line' | 'shadow' |
| | |
| | | ], |
| | | } |
| | | option && this.chartEntity.setOption(option, true) |
| | | this.bindChartClick() |
| | | }, |
| | | }, |
| | | } |
| | |
| | | <style lang="less" scoped> |
| | | .line-chart { |
| | | height: 20vh; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | </style> |