peng
2026-03-25 67d3b57765b0ba66ae25a9da84a16e44a4ef2937
调整
3个文件已修改
1个文件已添加
360 ■■■■■ 已修改文件
src/assets/img/sdjt.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Logo.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/components/DataReGasStation.vue 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/components/DataReLineChart.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/sdjt.jpg
src/components/tools/Logo.vue
@@ -1,15 +1,15 @@
<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',
@@ -27,11 +27,8 @@
  },
  data() {
    return {
      localInfo: {},
      homeLogo,
    }
  },
  created() {
    this.localInfo = JSON.parse(localStorage.getItem('localInfo'))
  },
}
</script>
@@ -76,4 +73,3 @@
  }
}
</style>
src/views/dataAnalysis/components/DataReGasStation.vue
@@ -1,5 +1,5 @@
<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">
@@ -12,7 +12,7 @@
      </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"
@@ -31,6 +31,8 @@
          :chartData="trendAnalysisData"
          style="width: 100%"
          :showpercent="trendAnalysisChartShowPercent"
          :enablePointClick="true"
          @chart-click="handleTrendChartClick"
        ></DataReLineChart>
      </div>
      <div id="trendAnalysisChartID"></div>
@@ -210,6 +212,33 @@
      :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>
@@ -264,6 +293,11 @@
      trendAnalysisUnit: 'DAYS', //趋势分析选择时间
      trendAnalysisData: {}, //趋势分析数据
      trendAnalysisChart: null, //趋势分析图表
      trendDetailVisible: false,
      trendDetailTitle: '趋势分析明细',
      trendDetailLoading: false,
      trendDetailData: [],
      trendDetailColumns: [],
      beforeStartTime: '',
      beforeEndTime: '',
      afterStartTime: '',
@@ -310,6 +344,80 @@
  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', {
@@ -554,7 +662,29 @@
  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 {
@@ -562,6 +692,8 @@
    font-size: 16px;
  }
  .fueling-overview-ct {
    position: relative;
    z-index: 2;
    // margin: 0 12px;
    .fueling-overview-block {
      display: flex;
@@ -578,6 +710,8 @@
    }
  }
  .oil-freq-compare-ct {
    position: relative;
    z-index: 2;
    margin: 8px 12px 24px 12px;
    .oil-freq-compare-operator {
      display: flex;
@@ -597,3 +731,11 @@
  }
}
</style>
<style lang="less">
.trend-detail-modal-wrap {
  z-index: 5000 !important;
}
.trend-detail-modal-wrap + .ant-modal-mask {
  z-index: 4999 !important;
}
</style>
src/views/dataAnalysis/components/DataReLineChart.vue
@@ -22,13 +22,204 @@
      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)
@@ -38,6 +229,8 @@
      var option = {
        tooltip: {
          trigger: 'axis',
          confine: true,
          extraCssText: 'pointer-events:none;',
          axisPointer: {
            // 坐标轴指示器,坐标轴触发有效
            type: 'line', // 默认为直线,可选为:'line' | 'shadow'
@@ -208,6 +401,7 @@
        ],
      }
      option && this.chartEntity.setOption(option, true)
      this.bindChartClick()
    },
    setPieUpChart() {
      if (!this.chartEntity) {
@@ -233,6 +427,8 @@
      var option = {
        tooltip: {
          trigger: 'axis',
          confine: true,
          extraCssText: 'pointer-events:none;',
          axisPointer: {
            // 坐标轴指示器,坐标轴触发有效
            type: 'line', // 默认为直线,可选为:'line' | 'shadow'
@@ -291,6 +487,7 @@
        series: [...data],
      }
      option && this.chartEntity.setOption(option, true)
      this.bindChartClick()
    },
    setOnlyLineChart() {
      if (!this.chartEntity) {
@@ -301,6 +498,8 @@
      var option = {
        tooltip: {
          trigger: 'axis',
          confine: true,
          extraCssText: 'pointer-events:none;',
          axisPointer: {
            // 坐标轴指示器,坐标轴触发有效
            type: 'line', // 默认为直线,可选为:'line' | 'shadow'
@@ -434,6 +633,7 @@
        ],
      }
      option && this.chartEntity.setOption(option, true)
      this.bindChartClick()
    },
  },
}
@@ -441,5 +641,7 @@
<style lang="less" scoped>
.line-chart {
  height: 20vh;
  position: relative;
  overflow: hidden;
}
</style>