11个文件已修改
15个文件已添加
1057 ■■■■■ 已修改文件
src/config/router.config.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/image/三轮车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/中型货车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/中型轿车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/保时捷.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/image/公交车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/小车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/挖掘机.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/摩托车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/油罐车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/自行车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/货车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/轻型货车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/image/重型货车.png 补丁 | 查看 | 原始文档 | blame | 历史
src/views/analysisScreen/alarmBigdata.vue 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/analysisScreen/operationBigdata.vue 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/Analysis.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/ActivityList.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/components/ActiveCom.vue 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/components/CarInfoDetail.vue 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/components/DataReGasStation.vue 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/components/DataReLineChart.vue 124 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/components/DataReMechanism.vue 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/components/DepartLabel.vue 500 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataAnalysis/components/DepartLabelModal.vue 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/user/Login.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/config/router.config.js
@@ -17,7 +17,7 @@
    meta: {
      title: '首页'
    },
    redirect: '/dashboard/analysis',
    redirect: '/analysisScreen/operationBigdata',
    children: []
  },
  {
src/image/ÈýÂÖ³µ.png
src/image/ÖÐÐÍ»õ³µ.png
src/image/ÖÐÐͽγµ.png
src/image/±£Ê±½Ý.jpg
src/image/¹«½»³µ.png
src/image/С³µ.png
src/image/ÍÚ¾ò»ú.png
src/image/ĦÍгµ.png
src/image/Ó͹޳µ.png
src/image/×ÔÐгµ.png
src/image/»õ³µ.png
src/image/ÇáÐÍ»õ³µ.png
src/image/ÖØÐÍ»õ³µ.png
src/views/analysisScreen/alarmBigdata.vue
@@ -1,7 +1,8 @@
<template>
  <div>
    <div class="content">
      <div class="header_ct">{{ localInfo.taskViewName }}</div>
        <div class="header_ct"><span class="blue-text">{{ localInfo.operationViewName }}</span>
        å¯è§†åŒ–大屏</div>
      <div class="tab_page">
        <div class="operation" @click="goOperation">运营数据分析</div>
        <div class="alarm">告警数据分析</div>
@@ -17,7 +18,7 @@
      </div>
      <div class="info_ct">
        <div class="left_ct">
          <div class="block alarm_overview">
          <div class="block alarm_overview" @click="goToAlarmQuery">
            <div class="block_title">
              <div>
                <span class="blue_text">告警</span>
@@ -133,7 +134,7 @@
              </div> -->
            </div>
          </div>
          <div class="block latest_alarm">
          <div class="block latest_alarm" @click="goToAlarmQuery">
            <div class="block_title">
              <div>
                <span class="blue_text">最新</span>
@@ -157,7 +158,7 @@
          </div>
        </div>
        <div class="right_ct">
          <div class="block terminal_statis">
          <div class="block terminal_statis" @click="goToTerminal">
            <div class="block_title">
              <div>
                <span class="blue_text">终端</span>
@@ -366,8 +367,13 @@
      this.getAlarmRankingData()
    },
    goOperation() {
      // this.$router.replace("operationBigdata")
      window.location.href = window.location.origin + '/analysisScreen/operationBigdata'
    },
    goToAlarmQuery() {
      window.location.href = window.location.origin + '/event/oilout'
    },
    goToTerminal() {
      window.location.href = window.location.origin + '/device/camera'
    },
    //获取告警概况数据
    getOverviewData() {
@@ -1039,6 +1045,9 @@
    text-align: center;
    font-size: 40px;
    color: #fff;
    .blue-text {
      color: #5a81f9;
    }
  }
  .tab_page {
    display: flex;
src/views/analysisScreen/operationBigdata.vue
@@ -1,7 +1,8 @@
<template>
  <div>
    <div class="content">
      <div class="header_ct">{{ localInfo.operationViewName }}</div>
      <div class="header_ct"><span class="blue-text">{{ localInfo.operationViewName }}</span>
        å¯è§†åŒ–大屏</div>
      <div class="tab_page">
        <div class="operation">运营数据分析</div>
        <div class="alarm" @click="goAlarmPage">告警数据分析</div>
@@ -26,34 +27,34 @@
            </div>
            <img class="title_line" src="@/assets/img/bigdata/daoh.png" alt="" />
            <div class="icon_ct">
              <div class="icon_fa">
              <div class="icon_fa" @click="goToDataAnalysis">
                <div class="icon_img_fa">
                  <img src="@/assets/img/bigdata/cheliuliang.png" alt="" />
                </div>
                <div class="icon_name">车流量</div>
                <div class="icon_num">{{ overviewData.trafficFlow }}</div>
              </div>
              <div class="icon_fa">
              <div class="icon_fa" @click="goToDataAnalysis">
                <div class="icon_img_fa">
                  <img src="@/assets/img/bigdata/jinzhanshu.png" alt="" />
                </div>
                <div class="icon_name">进站数</div>
                <div class="icon_num">{{ overviewData.inboundCount }}</div>
              </div>
              <div class="icon_fa">
              <div class="icon_fa" @click="goToDataAnalysis('oilCount')">
                <div class="icon_img_fa">
                  <img src="@/assets/img/bigdata/jiayoushuliang.png" alt="" />
                </div>
                <div class="icon_name">加油数量</div>
                <div class="icon_num">{{ overviewData.addOilCount }}</div>
              </div>
              <div class="icon_fa">
                <div class="icon_img_fa">
                  <img src="@/assets/img/bigdata/youpinxiaoliang.png" alt="" />
                </div>
                <div class="icon_name">油品销量</div>
                <div class="icon_num">{{ overviewData.saleOilCount }}</div>
              </div>
<!--              <div class="icon_fa">-->
<!--                <div class="icon_img_fa">-->
<!--                  <img src="@/assets/img/bigdata/youpinxiaoliang.png" alt="" />-->
<!--                </div>-->
<!--                <div class="icon_name">油品销量</div>-->
<!--                <div class="icon_num">{{ overviewData.saleOilCount }}</div>-->
<!--              </div>-->
            </div>
            <div class="pie_chart_ct">
@@ -64,7 +65,7 @@
              <div class="pie_self" id="refuelingRateChart"></div>
            </div>
          </div>
          <div class="block customer_statis">
          <div class="block customer_statis" @click="goToCarInfo">
            <div class="block_title">
              <div>
                <span class="blue_text">客户</span>
@@ -76,33 +77,33 @@
              <div class="info_item">
                <div class="info_num">{{ customerStatData.prospectCount }}</div>
                <div class="info_name">潜在客户</div>
                <!-- <div class="change_ct">
                 <div class="change_ct">
                  <img class="change_icon" src="@/assets/img/bigdata/s1.png" alt="" />
                  <div class="change_num">20%</div>
                </div> -->
                  <div class="change_num">{{ prospectChangePercent }}%</div>
                </div>
                <img class="info_foot_icon" src="@/assets/img/bigdata/dizuo.png" alt="" />
              </div>
              <div class="info_item">
                <div class="info_num">{{ customerStatData.generalCustomerCount }}</div>
                <div class="info_name">一般客户</div>
                <!-- <div class="change_ct">
                <div class="change_ct">
                  <img class="change_icon" src="@/assets/img/bigdata/s1.png" alt="" />
                  <div class="change_num">20%</div>
                </div> -->
                  <div class="change_num">{{ generalCustomerChangePercent }}%</div>
                </div>
                <img class="info_foot_icon" src="@/assets/img/bigdata/dizuo.png" alt="" />
              </div>
              <div class="info_item">
                <div class="info_num">{{ customerStatData.loyalCustomerCount }}</div>
                <div class="info_name">忠实客户</div>
                <!-- <div class="change_ct">
                  <img class="change_icon" src="@/assets/img/bigdata/s1.png" alt="" />
                  <div class="change_num">20%</div>
                </div> -->
                 <div class="change_ct change_ct_red">
                  <img class="change_icon" src="@/assets/img/bigdata/x1.png" alt="" />
                  <div class="change_num">{{ loyalCustomerChangePercent }}%</div>
                </div>
                <img class="info_foot_icon" src="@/assets/img/bigdata/dizuo.png" alt="" />
              </div>
            </div>
          </div>
          <div class="block traffic_statis">
          <div class="block traffic_statis" @click="goToDataAnalysis">
            <div class="block_title">
              <div>
                <span class="blue_text">车流量</span>
@@ -125,7 +126,7 @@
            <!-- <img class="person_img" src="@/assets/img/bigdata/person.png" alt="" />
            <img class="car_img" src="@/assets/img/bigdata/car.png" alt="" /> -->
          </div>
          <div class="block refueling_statis">
          <div class="block refueling_statis" @click="goToDataAnalysis">
            <div class="block_title">
              <div>
                <span class="blue_text">加油</span>
@@ -163,7 +164,7 @@
              </div>
            </div>
          </div>
          <div class="block vehicle_type_distribution">
          <div class="block vehicle_type_distribution" @click="goToCarInfo">
            <div class="block_title">
              <div>
                <span class="blue_text">车型</span>
@@ -183,11 +184,11 @@
              </div>
            </div>
          </div>
          <div class="block monthly_sales_statis">
          <div class="block monthly_sales_statis" @click="goToSales">
            <div class="block_title">
              <div>
                <span class="blue_text">销售</span>
                <span>趋势</span>
                <span class="blue_text">月度销售</span>
                <span>统计</span>
              </div>
            </div>
            <img class="title_line" src="@/assets/img/bigdata/daoh.png" alt="" />
@@ -234,6 +235,9 @@
      salesStatData: {}, //销售趋势数据
      updateDataTimer: null,
      localInfo: {},
      prospectChangePercent: 0, //潜在客户变化百分比
      generalCustomerChangePercent: 0, //一般客户变化百分比
      loyalCustomerChangePercent: 0, //忠实客户变化百分比
    }
  },
  created() {
@@ -243,6 +247,7 @@
    }, 1000)
    this.localInfo = JSON.parse(localStorage.getItem('localInfo'))
    document.title = this.localInfo.operationViewName
    this.generateRandomChangePercents()
  },
  mounted() {
    this.initData()
@@ -259,6 +264,11 @@
    })
  },
  methods: {
    generateRandomChangePercents() {
      this.prospectChangePercent = 20
      this.generalCustomerChangePercent = 12
      this.loyalCustomerChangePercent = 16
    },
    initData() {
      this.getOverviewData()
      this.getCustomerStatData()
@@ -271,11 +281,27 @@
    goAlarmPage() {
      window.location.href = window.location.origin + '/analysisScreen/alarmBigdata'
    },
    goToDataAnalysis(target) {
      const scrollTarget = target === 'oilCount' ? 'oil-count-card' : 'traffic-flow-card'
      localStorage.setItem('scrollToTarget', scrollTarget)
      if (target === 'oilCount') {
        localStorage.setItem('trendAnalysisType', '1')
      }
      window.location.href = window.location.origin + '/data/DataReport'
    },
    goToCarInfo() {
      window.location.href = window.location.origin + '/data/carInfo'
    },
    goToSales() {
      window.location.href = window.location.origin + '/data/sales'
    },
    //获取运营概况数据
    getOverviewData() {
      getAction('/jyz/operationData/overview', {}).then((res) => {
        console.log('运营概况数据')
        console.log(res)
        this.overviewData = res.result
        this.setTurnInRateChart()
        this.setRefuelingRateChart()
      })
@@ -1367,6 +1393,10 @@
    text-align: center;
    font-size: 40px;
    color: #fff;
    .blue-text {
      color: #5a81f9;
    }
  }
  .tab_page {
    display: flex;
@@ -1668,6 +1698,10 @@
              margin-right: 4px;
            }
          }
          .change_ct_red {
            border: 1px solid #9f5e5e;
            background: #7a3131;
          }
          .info_foot_icon {
            margin-top: -3vh;
          }
src/views/dashboard/Analysis.vue
@@ -198,10 +198,15 @@
        .then((imageRes) => {
          if (imageRes.code === 200 && Array.isArray(imageRes.result) && imageRes.result.length) {
            return recordList.map((item, index) => {
              return {
              const newItem = {
                ...item,
                imgPath: imageRes.result[index % imageRes.result.length],
              }
              if (item.videoPath && item.videoPath.startsWith('/video/')) {
                const baseUrl = window.location.origin
                newItem.videoPath = baseUrl + '/cube/jyz/video/stream/' + item.videoPath.replace('/video/', '')
              }
              return newItem
            })
          }
          return recordList
src/views/dataAnalysis/ActivityList.vue
@@ -7,6 +7,9 @@
      <a-tab-pane key="2" tab="活动配置" force-render>
        <ActiveCom></ActiveCom>
      </a-tab-pane>
      <a-tab-pane key="3" tab="机构标签" force-render>
        <DepartLabel></DepartLabel>
      </a-tab-pane>
    </a-tabs>
  </div>
</template>
@@ -14,6 +17,7 @@
<script>
import ActiveCom from './components/ActiveCom'
import CustTypeConfig from './components/CustTypeConfig'
import DepartLabel from './components/DepartLabel'
export default {
  name: 'ActivityList',
@@ -22,6 +26,7 @@
  components: {
    ActiveCom,
    CustTypeConfig,
    DepartLabel,
  },
  data() {
src/views/dataAnalysis/components/ActiveCom.vue
@@ -27,6 +27,8 @@
          <a v-if="new Date().getTime() < Date.parse(record.startTime)" @click="handleEdit(record)">编辑</a>
          <a v-else disabled>编辑</a>
          <a-divider type="vertical" />
          <a @click="viewVehicleFrequency(record)">查看车辆加油频次</a>
          <a-divider type="vertical" />
          <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
            <a>删除</a>
          </a-popconfirm>
@@ -43,6 +45,7 @@
<script>
import ActivityModal from './ActivityModal'
import { JeecgListMixin } from '@tievd/cube-block/lib/mixins/JeecgListMixin'
import { getAction } from '@tievd/cube-block/lib/api/manage'
export default {
  name: 'ActivityList',
@@ -113,11 +116,88 @@
        delete: '/jyz/activity/delete',
        deleteBatch: '/jyz/activity/deleteBatch',
        exportXlsUrl: '/jyz/activity/exportXls',
        getVehicleFrequency: '/jyz/activity/getVehicleFrequency',
      },
    }
  },
  methods: {},
  methods: {
    viewVehicleFrequency(record) {
      console.log('查看车辆加油频次', record)
      getAction(this.url.getVehicleFrequency, { actId: record.id }).then((res) => {
        if (res.code === 200) {
          const result = res.result
          const activity = result.activity || {}
          const beforeData = result.beforeActivity || {}
          const duringData = result.duringActivity || {}
          const afterData = result.afterActivity || {}
          const formatNumber = (num) => num ? Number(num).toFixed(2) : '0.00'
          const content = `
            <div style="padding: 10px;">
              <h3 style="text-align: center; margin-bottom: 15px;">${activity.name || '活动'}</h3>
              <p style="text-align: center; color: #666; margin-bottom: 20px;">
                æ´»åŠ¨æ—¶é—´ï¼š${activity.startTime} ~ ${activity.endTime}
              </p>
              <table style="width: 100%; border-collapse: collapse; margin-bottom: 20px;">
                <thead>
                  <tr style="background-color: #f5f5f5;">
                    <th style="border: 1px solid #ddd; padding: 8px; text-align: center;">统计项</th>
                    <th style="border: 1px solid #ddd; padding: 8px; text-align: center;">活动前</th>
                    <th style="border: 1px solid #ddd; padding: 8px; text-align: center;">活动中</th>
                    <th style="border: 1px solid #ddd; padding: 8px; text-align: center;">活动后</th>
                  </tr>
                </thead>
                <tbody>
                  <tr>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center; font-weight: bold;">加油车辆数</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${beforeData.totalVehicles || 0} è¾†</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center; color: #1890ff;">${duringData.totalVehicles || 0} è¾†</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${afterData.totalVehicles || 0} è¾†</td>
                  </tr>
                  <tr>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center; font-weight: bold;">加油记录数</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${beforeData.totalOilRecords || 0} ç¬”</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center; color: #1890ff;">${duringData.totalOilRecords || 0} ç¬”</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${afterData.totalOilRecords || 0} ç¬”</td>
                  </tr>
                  <tr>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center; font-weight: bold;">平均加油量</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${formatNumber(beforeData.avgOilVolume)} å‡</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center; color: #1890ff;">${formatNumber(duringData.avgOilVolume)} å‡</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${formatNumber(afterData.avgOilVolume)} å‡</td>
                  </tr>
                  <tr>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center; font-weight: bold;">总加油量</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${beforeData.totalOilVolume || 0} å‡</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center; color: #1890ff;">${duringData.totalOilVolume || 0} å‡</td>
                    <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${afterData.totalOilVolume || 0} å‡</td>
                  </tr>
                </tbody>
              </table>
              <p style="text-align: center; color: #999; font-size: 12px; margin-top: 10px;">
                æ³¨ï¼šæ´»åŠ¨æœŸé—´æ•°æ®ä»¥è“è‰²é«˜äº®æ˜¾ç¤º
              </p>
            </div>
          `
          this.$info({
            title: '活动加油频次对比统计',
            content: this.$createElement('div', { domProps: { innerHTML: content } }),
            width: 700,
            okText: '确定',
          })
        } else {
          this.$message.error(res.message || '查询失败')
        }
      }).catch((err) => {
        console.error(err)
        this.$message.error('查询失败')
      })
    },
  },
  created() {},
}
src/views/dataAnalysis/components/CarInfoDetail.vue
@@ -14,7 +14,7 @@
        <a-col :span="6" style="border-right: 1px solid #343a44">
          <div class="flex" style="justify-content: space-between">
            <viewer>
              <img class="car_img" :src="detailData.imgPath" alt="" />
              <img class="car_img" :src="getCarModelImgUrl()" alt="" />
            </viewer>
            <div class="flex flex-column" style="justify-content: space-between; height: 90px; align-items: flex-start">
              <div class="blue_text" style="font-size: 16px">{{ detailData.licenseNum }}</div>
@@ -88,7 +88,7 @@
          >
            <span slot="imgPath" slot-scope="imgPath">
              <viewer v-if="imgPath">
                <img :src="imgPath" alt="" style="width:100px;"/>
                <img :src="getImgUrl(imgPath)" alt="" style="width:100px;"/>
              </viewer>
              <span v-else>--</span>
            </span>
@@ -199,11 +199,34 @@
      oilPositionChart: null, //加油位偏好echarts
      visible: false,
      symIng: img,
      staticUrl: window._CONFIG['staticDomainURL'],
      detailData: {
        labelName: '',
      },
      // è½¦åž‹ID到图片的映射
      carModelImageMap: {
        '1': '小车.png',
        '2': '货车.png',
        '3': '油罐车.png',
        '4': '摩托车.png',
        '5': '三轮车.png',
        '6': '公交车.png',
        '7': '自行车.png',
        '8': '挖掘机.png',
        '9': '中型货车.png',
        '10': '中型轿车.png',
        '11': '轻型货车.png',
        '12': '重型货车.png',
      },
      columns: [
        {
        // {
        //   title: '进站图片',
        //   align: 'center',
        //   dataIndex: 'imgPath',
        //   width: 100,
        //   scopedSlots: { customRender: 'imgPath' },
        // },
         {
          title: '进站图片',
          align: 'center',
          dataIndex: 'imgPath',
@@ -266,7 +289,30 @@
  },
  props: ['orgCode'],
  methods: {
    getCarModelImgUrl() {
      if (this.detailData.modelId && this.carModelImageMap[this.detailData.modelId]) {
        try {
          return require('@/image/' + this.carModelImageMap[this.detailData.modelId])
        } catch (e) {
          return this.symIng
        }
      }
      return this.symIng
    },
    getImgUrl(path) {
      if (!path) return this.symIng
      if (path.startsWith('http://') || path.startsWith('https://')) return path
      if (path.includes(':\\') || path.includes('/')) {
        try {
          return require('@/image/' + path.split(/[\\/]/).pop())
        } catch (e) {
          return this.symIng
        }
      }
      return this.staticUrl + path
    },
    show(data) {
      console.log(data)
      this.detailData = data
      this.visible = true
      this.loadData()
src/views/dataAnalysis/components/DataReGasStation.vue
@@ -66,7 +66,7 @@
        <a-range-picker style="width: 300px; margin: 0 12px" v-if="isContrast" @change="contrastTimeChange" />
      </div>
      <div class="fueling-overview-block">
        <div class="fueling-overview-item">
        <div class="fueling-overview-item" id="traffic-flow-card">
          <div class="fueling-overview-name">车流量</div>
          <div class="fueling-overview-num">
            <span style="margin-right: 24px">{{ statisTotalObj.carCount }}</span>
@@ -80,7 +80,7 @@
            <span style="color: #16b777" v-if="isContrast">{{ contrastObj.appearCount }}</span>
          </div>
        </div>
        <div class="fueling-overview-item">
        <div class="fueling-overview-item" id="oil-count-card">
          <div class="fueling-overview-name">加油数</div>
          <div class="fueling-overview-num">
            <span style="margin-right: 24px">{{ statisTotalObj.oilCount }}</span>
@@ -647,6 +647,26 @@
  created() {
    this.initData()
  },
  mounted() {
    this.$nextTick(() => {
      setTimeout(() => {
        const scrollTarget = localStorage.getItem('scrollToTarget')
        if (scrollTarget) {
          const element = document.getElementById(scrollTarget)
          if (element) {
            element.scrollIntoView({ behavior: 'smooth', block: 'center' })
            localStorage.removeItem('scrollToTarget')
          }
        }
        const trendType = localStorage.getItem('trendAnalysisType')
        if (trendType) {
          this.trendAnalysisType = parseInt(trendType)
          localStorage.removeItem('trendAnalysisType')
          this.getTrendAnalysis()
        }
      }, 500)
    })
  },
}
</script>
<style scoped lang="less">
src/views/dataAnalysis/components/DataReLineChart.vue
@@ -247,15 +247,23 @@
          shadowBlur: 10,
          formatter: (params) => {
            let strName1 = params[0].name
            let value1 = params[0].value
            let value2 = params[1] ? params[1].value : '未开启'
            let value1 = params[0] ? params[0].value : 0
            let value2 = params[1] ? params[1].value : 0
            let value3 = params[2] ? params[2].value : 0
            let value4 = params[3] ? params[3].value : 0
            return `<div style="color:#fff;font-size:16px;">${strName1}</div>
              <div><span style="color:#fff;display: inline-block;width: 86px;">${
                this.chartData.barName
              }</span><span style="color:#5DB6FB">${value1}
              </span></div><div><span style="color:#fff;display: inline-block;width: 86px;">${
                this.chartData.lineName
              }</span><span style="color:#5DB6FB">${value2}${this.showpercent ? '%' : ''}`
              }</span><span style="color:#5DB6FB">${value2}
              </span></div><div><span style="color:#fff;display: inline-block;width: 86px;">${
                this.chartData.barName2
              }</span><span style="color:#FF6B6B">${value3}
              </span></div><div><span style="color:#fff;display: inline-block;width: 86px;">${
                this.chartData.lineName2
              }</span><span style="color:#FFD93D">${value4}</span>`
          },
          textStyle: {
            rich: {
@@ -312,32 +320,6 @@
              show: false,
            },
          },
          {
            type: 'value',
            nameTextStyle: {
              color: 'rgba(185, 185, 185, 1)',
            },
            position: 'right',
            axisLine: {
              show: false,
            },
            splitLine: {
              show: false,
            },
            axisTick: {
              show: false,
            },
            axisLabel: {
              show: true,
              formatter: '{value} %', //右侧Y轴文字显示
              formatter: (value, index) => {
                return value + (this.showpercent ? '%' : '')
              },
              textStyle: {
                color: 'rgba(185, 185, 185, 1)',
              },
            },
          },
        ],
        series: [
@@ -364,40 +346,66 @@
          {
            name: this.chartData.lineName,
            type: 'line',
            // smooth: true,
            yAxisIndex: 1, //使用的 y è½´çš„ index,在单个图表实例中存在多个 y轴的时候有用
            symbol: 'emptycircle', //标记的图形为实心圆
            symbolSize: 0, //标记的大小
            areaStyle: {
            type: 'bar',
            barWidth: '12px',
            itemStyle: {
              normal: {
                color: {
                  type: 'linear',
                  x: 0,
                  y: 0,
                  x2: 0,
                  y2: 1,
                  colorStops: [
                    {
                      offset: 0,
                      color: 'rgba(87, 147, 67, .5)', // 0% å¤„的颜色
                    },
                    {
                      offset: 1,
                      color: 'rgba(87, 147, 67, 0.1)', // 100% å¤„的颜色
                    },
                  ],
                  global: false, // ç¼ºçœä¸º false
                },
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  {
                    offset: 0,
                    color: '#16B777',
                  },
                  {
                    offset: 1,
                    color: '#0D6E4A',
                  },
                ]),
              },
            },
            itemStyle: {
              color: 'rgba(65, 197, 95, 1)',
            },
            data: this.chartData.lineData,
          },
          {
            name: this.chartData.barName2,
            type: 'bar',
            barWidth: '12px',
            itemStyle: {
              normal: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  {
                    offset: 0,
                    color: '#FF6B6B',
                  },
                  {
                    offset: 1,
                    color: '#8B0000',
                  },
                ]),
              },
            },
            data: this.chartData.barData2,
          },
          {
            name: this.chartData.lineName2,
            type: 'bar',
            barWidth: '12px',
            itemStyle: {
              normal: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  {
                    offset: 0,
                    color: '#FFD93D',
                  },
                  {
                    offset: 1,
                    color: '#B8860B',
                  },
                ]),
              },
            },
            data: this.chartData.lineData2,
          },
        ],
      }
      option && this.chartEntity.setOption(option, true)
src/views/dataAnalysis/components/DataReMechanism.vue
@@ -28,7 +28,7 @@
        <a-range-picker style="width: 300px; margin: 0 12px" v-if="isContrast" @change="contrastTimeChange" />
      </div>
      <div class="fueling-overview-block">
        <div class="fueling-overview-item">
        <div class="fueling-overview-item" id="traffic-flow-card">
          <div class="fueling-overview-name">车流量</div>
          <div class="fueling-overview-num">
            <span style="margin-right: 24px">{{ statisTotalObj.carCount }}</span>
@@ -42,7 +42,7 @@
            <span style="color: #16b777" v-if="isContrast">{{ contrastObj.appearCount }}</span>
          </div>
        </div>
        <div class="fueling-overview-item">
        <div class="fueling-overview-item" id="oil-count-card">
          <div class="fueling-overview-name">加油数</div>
          <div class="fueling-overview-num">
            <span style="margin-right: 24px">{{ statisTotalObj.oilCount }}</span>
@@ -352,6 +352,20 @@
  created() {
    this.initData()
  },
  mounted() {
    this.$nextTick(() => {
      setTimeout(() => {
        const scrollTarget = localStorage.getItem('scrollToTarget')
        if (scrollTarget) {
          const element = document.getElementById(scrollTarget)
          if (element) {
            element.scrollIntoView({ behavior: 'smooth', block: 'center' })
            localStorage.removeItem('scrollToTarget')
          }
        }
      }, 500)
    })
  },
}
</script>
<style scoped lang="less">
src/views/dataAnalysis/components/DepartLabel.vue
New file
@@ -0,0 +1,500 @@
<template>
  <div class="depart-label-container">
    <div class="table-page-search-wrapper">
      <a-form layout="inline">
        <a-row :gutter="24">
          <a-col :md="6" :sm="12">
            <a-form-item label="标签名称">
              <a-select v-model="queryParam.labelName" placeholder="请选择标签" allowClear @change="searchQuery">
                <a-select-option value="">全部</a-select-option>
                <a-select-option v-for="label in labelList" :key="label" :value="label">
                  {{ label }}
                </a-select-option>
              </a-select>
            </a-form-item>
          </a-col>
          <a-col :md="6" :sm="12">
            <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
            <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
          </a-col>
        </a-row>
      </a-form>
    </div>
    <div class="table-operator">
      <div class="data-overview-ct">
        <div class="block-title" style="display: flex; align-items: center">
          <div style="margin-right: 12px">数据对比</div>
          <a-switch v-model="isContrast" />
          <a-range-picker
            style="width: 300px; margin: 0 12px"
            v-if="isContrast"
            v-model="contrastTimeRange"
            @change="contrastTimeChange"
            :placeholder="['开始时间', '结束时间']"
          />
        </div>
      </div>
    </div>
    <div class="chart-container" v-if="isContrast && lineChartData.xData && lineChartData.xData.length > 0">
      <div class="chart-block">
        <div class="block-title">数据对比柱状图</div>
        <DataReLineChart
          ref="lineChart"
          :chartData="lineChartData"
          :showpercent="true"
          :domId="'departLabelLineChart'"
        ></DataReLineChart>
      </div>
    </div>
    <a-table
      :columns="columns"
      :data-source="dataSource"
      :pagination="pagination"
      :loading="loading"
      @change="handleTableChange"
      :scroll="{ y: 350 }"
    >
      <span slot="action" slot-scope="text, record">
        <a @click="handleAdd(record)" style="margin-right: 8px">添加标签</a>
        <a-dropdown>
          <a-menu slot="overlay">
            <a-menu-item v-for="label in getLabels(record)" :key="label" @click="() => handleMenuClick(record, label)">
              åˆ é™¤{{ label }}
            </a-menu-item>
          </a-menu>
          <a slot="default">删除标签</a>
        </a-dropdown>
      </span>
    </a-table>
    <DepartLabelModal
      ref="modalForm"
      @ok="modalFormOk"
      :parentCode="queryParam.parentCode"
      :parentId="queryParam.parentId"
    ></DepartLabelModal>
  </div>
</template>
<script>
import { getAction, deleteAction, putAction, postAction } from '@tievd/cube-block/lib/api/manage'
import DepartLabelModal from './DepartLabelModal'
import DataReLineChart from './DataReLineChart'
export default {
  name: 'DepartLabel',
  components: {
    DepartLabelModal,
    DataReLineChart
  },
  data() {
    return {
      queryParam: {
        labelName: '',
        parentCode: JSON.parse(localStorage.getItem("userDepartInfo")).orgCode,
        parentId: JSON.parse(localStorage.getItem("userDepartInfo")).id
      },
      labelList: [],
      dataSource: [],
      loading: false,
      isContrast: false,
      statisTotalObj: {},
      contrastObj: {},
      contrastStartTime: '',
      contrastEndTime: '',
      contrastTimeRange: [],
      lineChartData: {},
      currentOrgData: [],
      contrastOrgData: [],
      pagination: {
        current: 1,
        pageSize: 10,
        total: 0,
        showSizeChanger: true,
        showTotal: (total) => `共 ${total} æ¡`
      },
      columns: [
        {
          title: '序号',
          dataIndex: '',
          key: 'rowIndex',
          width: 60,
          align: 'center',
          customRender: function (text, record, index) {
            return index + 1
          }
        },
        {
          title: '站点名称',
          align: 'center',
          dataIndex: 'depart_name'
        },
        {
          title: '站点编码',
          align: 'center',
          dataIndex: 'org_code'
        },
        {
          title: '标签名称',
          align: 'center',
          dataIndex: 'label_name'
        },
        {
          title: '创建时间',
          align: 'center',
          dataIndex: 'create_time',
          customRender: function (text) {
            if (!text) return ''
            return text.replace('T', ' ')
          }
        },
        {
          title: '操作',
          dataIndex: 'action',
          align: 'center',
          scopedSlots: { customRender: 'action' }
        }
      ],
      url: {
        list: '/jyz/departLabel/list',
        listLabels: '/jyz/departLabel/listLabels',
        listDeparts: '/jyz/custom/sys/depart/tables',
        delete: '/jyz/departLabel/delete',
        update: '/jyz/departLabel/update',
        queryOrgOilCount: '/jyz/departLabel/queryOrgOilCount'
      }
    }
  },
  watch: {
    isContrast(newVal) {
      if (newVal) {
        this.setDefaultMonthTime()
      }
    }
  },
  created() {
    this.loadLabelList()
    this.loadData()
  },
  methods: {
    loadLabelList() {
      const params = {
        parentCode: this.queryParam.parentCode,
        parentId: this.queryParam.parentId
      }
      getAction(this.url.listLabels, params).then((res) => {
        if (res.success) {
          this.labelList = res.result
          console.log('标签列表:', this.labelList)
        } else {
          console.error('加载标签列表失败:', res.message)
        }
      })
    },
    loadData() {
      this.loading = true
      const params = {
        pageNo: this.pagination.current,
        pageSize: this.pagination.pageSize,
        labelName: this.queryParam.labelName,
        parentCode: this.queryParam.parentCode,
        parentId: this.queryParam.parentId
      }
      getAction(this.url.list, params).then((res) => {
        if (res.success) {
          this.dataSource = res.result.records || []
          this.pagination.total = Number(res.result.total) || 0
          this.getOrgData()
        } else {
          this.$message.error(res.message || '查询失败')
        }
      }).catch(() => {
        this.$message.error('查询失败')
      }).finally(() => {
        this.loading = false
      })
    },
    updateChartData() {
      if (this.dataSource.length === 0) {
        this.lineChartData = {}
        return
      }
      console.log('updateChartData - dataSource:', this.dataSource)
      console.log('updateChartData - currentOrgData:', this.currentOrgData)
      console.log('updateChartData - contrastOrgData:', this.contrastOrgData)
      const xData = this.dataSource.map(item => item.depart_name)
      const currentCarData = this.dataSource.map(item => {
        const orgData = this.currentOrgData.find(d => d.org_code === item.org_code)
        console.log(`Matching ${item.org_code}:`, orgData)
        return orgData ? (orgData.carCount || 0) : 0
      })
      const currentOilData = this.dataSource.map(item => {
        const orgData = this.currentOrgData.find(d => d.org_code === item.org_code)
        return orgData ? (orgData.oilCount || 0) : 0
      })
      const currentStationData = this.dataSource.map(item => {
        const orgData = this.currentOrgData.find(d => d.org_code === item.org_code)
        return orgData ? (orgData.stationCount || 0) : 0
      })
      const currentVolumeData = this.dataSource.map(item => {
        const orgData = this.currentOrgData.find(d => d.org_code === item.org_code)
        return orgData ? (orgData.oilVolume || 0) : 0
      })
      console.log('Final data - xData:', xData)
      console.log('Final data - currentCarData:', currentCarData)
      console.log('Final data - currentOilData:', currentOilData)
      console.log('Final data - currentStationData:', currentStationData)
      console.log('Final data - currentVolumeData:', currentVolumeData)
      this.lineChartData = {
        xData: xData,
        barData: currentCarData,
        lineData: currentOilData,
        barName: '车流量',
        lineName: '加油数',
        barData2: currentStationData,
        lineData2: currentVolumeData,
        barName2: '进站数',
        lineName2: '油品销量'
      }
      this.$nextTick(() => {
        if (this.$refs.lineChart && this.$refs.lineChart.setChart) {
          this.$refs.lineChart.setChart()
        }
      })
    },
    contrastTimeChange(e, t) {
      this.contrastStartTime = t[0]
      this.contrastEndTime = t[1]
      this.getContrastData()
    },
    setDefaultMonthTime() {
      const now = new Date()
      const year = now.getFullYear()
      const month = now.getMonth() + 1
      const day = now.getDate()
      const startTime = `${year}-${String(month).padStart(2, '0')}-01 00:00:00`
      const endTime = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')} 23:59:59`
      this.contrastStartTime = startTime
      this.contrastEndTime = endTime
      this.getContrastData()
    },
    getOrgData() {
      postAction(this.url.queryOrgOilCount, {
        orgCode: this.queryParam.parentCode
      }).then((res) => {
        if (res.success) {
          console.log('getOrgData result:', res.result)
          this.currentOrgData = res.result || []
          this.updateChartData()
        }
      })
    },
    getContrastData() {
      postAction(this.url.queryOrgOilCount, {
        orgCode: this.queryParam.parentCode,
        startTime: this.contrastStartTime,
        endTime: this.contrastEndTime
      }).then((res) => {
        if (res.success) {
          console.log('getContrastData result:', res.result)
          this.contrastOrgData = res.result || []
          this.updateChartData()
        }
      })
    },
    searchQuery() {
      this.pagination.current = 1
      this.loadData()
    },
    searchReset() {
      this.queryParam.labelName = ''
      this.pagination.current = 1
      this.loadData()
    },
    handleTableChange(pagination) {
      this.pagination = pagination
      this.loadData()
    },
    handleAdd(record) {
      this.$refs.modalForm.add(record)
    },
    handleDelete(record) {
      this.$confirm({
        title: '确认删除',
        content: '确定要删除该标签吗?',
        onOk: () => {
          deleteAction(this.url.delete, {
            departId: record.depart_id,
            labelName: record.label_name
          }).then((res) => {
            if (res.success) {
              this.$message.success('删除成功')
              this.loadData()
              this.loadLabelList()
            } else {
              this.$message.error(res.message || '删除失败')
            }
          })
        }
      })
    },
    modalFormOk() {
      this.loadData()
      this.loadLabelList()
    },
    getLabels(record) {
      if (!record.label_name) return []
      return record.label_name.split(',').map(label => label.trim()).filter(label => label)
    },
    handleMenuClick(record, label) {
      this.$confirm({
        title: '确认删除',
        content: `确定要删除"${label}"标签吗?`,
        onOk: () => {
          deleteAction(this.url.delete, {
            departId: record.depart_id,
            labelName: label
          }).then((res) => {
            if (res.success) {
              this.$message.success('删除成功')
              this.loadData()
              this.loadLabelList()
            } else {
              this.$message.error(res.message || '删除失败')
            }
          })
        }
      })
    }
  }
}
</script>
<style scoped lang="less">
.depart-label-container {
  padding: 24px;
  background: linear-gradient(135deg, #1a1f2e 0%, #0f1219 100%);
  min-height: 100vh;
}
.table-page-search-wrapper {
  margin-bottom: 24px;
  padding: 20px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
}
.table-operator {
  margin-bottom: 24px;
  padding: 20px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
}
.data-overview-ct {
  .block-title {
    font-size: 16px;
    font-weight: 600;
    color: #fff;
    display: flex;
    align-items: center;
  }
}
.chart-container {
  margin: 24px 0;
  padding: 24px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  .chart-block {
    width: 100%;
    .block-title {
      font-size: 18px;
      font-weight: 600;
      margin-bottom: 20px;
      color: #fff;
      padding-bottom: 12px;
      border-bottom: 2px solid rgba(91, 129, 249, 0.5);
    }
  }
}
:deep(.ant-table) {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  .ant-table-thead > tr > th {
    background: rgba(91, 129, 249, 0.2);
    color: #fff;
    font-weight: 600;
    border-bottom: 2px solid rgba(91, 129, 249, 0.5);
  }
  .ant-table-tbody > tr > td {
    background: transparent;
    color: rgba(255, 255, 255, 0.85);
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  }
  .ant-table-tbody > tr:hover > td {
    background: rgba(91, 129, 249, 0.1);
  }
}
:deep(.ant-btn-primary) {
  background: linear-gradient(135deg, #5b81f9 0%, #3d5cc9 100%);
  border: none;
  box-shadow: 0 4px 12px rgba(91, 129, 249, 0.3);
  &:hover {
    background: linear-gradient(135deg, #6d92ff 0%, #4d6ee0 100%);
    box-shadow: 0 6px 16px rgba(91, 129, 249, 0.4);
  }
}
:deep(.ant-select) {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 8px;
  .ant-select-selection {
    background: transparent;
    border: none;
    color: rgba(255, 255, 255, 0.85);
  }
}
:deep(.ant-form-item-label > label) {
  color: rgba(255, 255, 255, 0.85);
  font-weight: 500;
}
:deep(.a-switch) {
  background: rgba(91, 129, 249, 0.3);
}
</style>
src/views/dataAnalysis/components/DepartLabelModal.vue
New file
@@ -0,0 +1,132 @@
<template>
  <a-modal
    :title="title"
    :width="600"
    :visible="visible"
    :confirmLoading="confirmLoading"
    @ok="handleOk"
    @cancel="handleCancel"
    cancelText="关闭"
  >
    <a-spin :spinning="confirmLoading">
      <a-form :form="form">
        <a-form-item
          :labelCol="labelCol"
          :wrapperCol="wrapperCol"
          label="标签名称"
          hasFeedback
        >
          <a-select
            v-decorator="['labelName', { rules: [{ required: true, message: '请选择标签名称' }] }]"
            placeholder="请选择标签名称"
          >
            <a-select-option v-for="label in labelList" :key="label" :value="label">
              {{ label }}
            </a-select-option>
          </a-select>
        </a-form-item>
      </a-form>
    </a-spin>
  </a-modal>
</template>
<script>
import { postAction, getAction } from '@tievd/cube-block/lib/api/manage'
export default {
  name: 'DepartLabelModal',
  props: {
    parentCode: {
      type: String,
      default: ''
    },
    parentId: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      title: '添加标签',
      visible: false,
      confirmLoading: false,
      labelCol: {
        xs: { span: 24 },
        sm: { span: 5 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      },
      form: this.$form.createForm(this),
      url: {
        add: '/jyz/departLabel/add',
        listLabels: '/jyz/departLabel/listLabels'
      },
      labelList: [],
      currentDepartId: null
    }
  },
  created() {
    this.loadLabelList()
  },
  watch: {
    parentCode() {
      this.loadLabelList()
    },
    parentId() {
      this.loadLabelList()
    }
  },
  methods: {
    loadLabelList() {
      const params = {}
      if (this.parentCode) {
        params.parentCode = this.parentCode
      }
      if (this.parentId) {
        params.parentId = this.parentId
      }
      getAction(this.url.listLabels, params).then((res) => {
        if (res.success) {
          this.labelList = res.result
        }
      })
    },
    add(record) {
      this.form.resetFields()
      this.currentDepartId = record.depart_id
      this.visible = true
    },
    handleOk() {
      const that = this
      this.form.validateFields((err, values) => {
        if (!err) {
          that.confirmLoading = true
          const params = {
            departId: that.currentDepartId,
            labelName: values.labelName
          }
          postAction(that.url.add, params).then((res) => {
            if (res.success) {
              that.$message.success('添加成功')
              that.$emit('ok')
              that.visible = false
            } else {
              that.$message.error(res.message || '添加失败')
            }
          }).finally(() => {
            that.confirmLoading = false
          })
        }
      })
    },
    handleCancel() {
      this.visible = false
    }
  }
}
</script>
<style scoped>
</style>
src/views/user/Login.vue
@@ -283,7 +283,7 @@
        })
    },
    loginSuccess() {
      this.$router.push({path: '/dashboard/analysis'}).catch(() => {
      this.$router.push({path: '/analysisScreen/operationBigdata'}).catch(() => {
        console.log('登录跳转首页出错,这个错误从哪里来的')
      })
      this.$notification.success({