From 73e0b3791990bd60c06c2c0388aae9f9faf538a6 Mon Sep 17 00:00:00 2001
From: zxl <763096477@qq.com>
Date: 星期三, 25 三月 2026 09:16:50 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/show-demo' into show_demo

---
 src/views/dataAnalysis/components/DataReGasStation.vue |  300 ++++++++++++++++++++++
 src/views/dataAnalysis/components/CustTypeModal.vue    |  180 +++++++++++--
 src/components/tools/Logo.vue                          |   12 
 src/views/dataAnalysis/components/CustTypeConfig.vue   |   32 ++
 src/assets/img/sdjt.jpg                                |    0 
 src/views/dataAnalysis/CarInfoList.vue                 |   29 ++
 src/views/dataAnalysis/components/DataReLineChart.vue  |  202 +++++++++++++++
 src/views/dataAnalysis/components/DataRePieChart.vue   |   10 
 8 files changed, 720 insertions(+), 45 deletions(-)

diff --git a/src/assets/img/sdjt.jpg b/src/assets/img/sdjt.jpg
new file mode 100644
index 0000000..598d16f
--- /dev/null
+++ b/src/assets/img/sdjt.jpg
Binary files differ
diff --git a/src/components/tools/Logo.vue b/src/components/tools/Logo.vue
index 43a74f3..48b4230 100644
--- a/src/components/tools/Logo.vue
+++ b/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>
-
diff --git a/src/views/dataAnalysis/CarInfoList.vue b/src/views/dataAnalysis/CarInfoList.vue
index 67cc7c5..bfd9e60 100644
--- a/src/views/dataAnalysis/CarInfoList.vue
+++ b/src/views/dataAnalysis/CarInfoList.vue
@@ -44,12 +44,17 @@
           />
         </a-form-item>
         <a-form-item label="瀹㈡埛绫诲瀷">
-          <j-dict-select-tag
+          <a-select
             style="width: 180px"
             v-model="queryParam.clientType"
             placeholder="璇烽�夋嫨"
-            dictCode="client_type"
-          />
+            allowClear
+          >
+            <a-select-option v-for="item in clientTypeOptions" :key="item.id" :value="item.id">
+              {{ item.clientName }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
           <!-- <a-select style="width: 180px" allowClear v-model="queryParam.clientType" placeholder="璇烽�夋嫨瀹㈡埛绫诲瀷">
             <a-select-option :value="1"> 鏅�氬鎴� </a-select-option>
             <a-select-option :value="2"> 娼滃湪瀹㈡埛 </a-select-option>
@@ -158,6 +163,7 @@
       description: 'CarInfo鍒楄〃',
       queryParam: {},
       tagList: [], //鎵�鏈夋爣绛鹃泦鍚�
+      clientTypeOptions: [], //瀹㈡埛绫诲瀷鍒楄〃
       // 琛ㄥご
       columns: [
         {
@@ -244,6 +250,14 @@
   },
 
   methods: {
+    // 鑾峰彇瀹㈡埛绫诲瀷鍒楄〃
+    getClientTypeOptions() {
+      getAction('/jyz/client/listClientType').then((res) => {
+        if (res.code === 200) {
+          this.clientTypeOptions = res.result
+        }
+      })
+    },
     delSlectTag(item) {
       console.log(item)
       let index = this.selectTagList.findIndex((el) => el == item)
@@ -321,10 +335,19 @@
       this.queryParam.orgCode = node.node.dataRef.orgCode
       this.loadData()
     },
+    // 鑾峰彇瀹㈡埛绫诲瀷鍒楄〃
+    getClientTypeOptions() {
+      getAction('/jyz/client/listClientType').then((res) => {
+        if (res.code === 200) {
+          this.clientTypeOptions = res.result
+        }
+      })
+    },
   },
 
   created() {
     this.getTagInfo(true)
+    this.getClientTypeOptions()
   },
 }
 </script>
diff --git a/src/views/dataAnalysis/components/CustTypeConfig.vue b/src/views/dataAnalysis/components/CustTypeConfig.vue
index ddca895..3b12660 100644
--- a/src/views/dataAnalysis/components/CustTypeConfig.vue
+++ b/src/views/dataAnalysis/components/CustTypeConfig.vue
@@ -46,6 +46,9 @@
 <script>
 import CustTypeModal from './CustTypeModal'
 import { JeecgListMixin } from '@tievd/cube-block/lib/mixins/JeecgListMixin'
+import { UI_CACHE_DB_DICT_DATA } from '@tievd/cube-block/lib/store/mutation-types'
+import { deleteAction, getAction } from '@tievd/cube-block/lib/api/manage'
+import Vue from 'vue'
 
 export default {
   name: 'ActivityList',
@@ -123,6 +126,35 @@
   },
 
   methods: {
+    modalFormOk() {
+      this.loadData()
+      this.refreshDictCache()
+    },
+    refreshDictCache() {
+      getAction('/sys/dict/queryAllDictItems').then((res) => {
+        if (res.success) {
+          Vue.ls.remove(UI_CACHE_DB_DICT_DATA)
+          Vue.ls.set(UI_CACHE_DB_DICT_DATA, res.result, 7 * 24 * 60 * 60 * 1000)
+        }
+      })
+    },
+    handleDelete(id) {
+      // 鍒犻櫎鍓嶆竻闄ゅ墠绔瓧鍏哥紦瀛�
+      // 鍒犻櫎鍚庡埛鏂伴〉闈互鏇存柊瀛楀吀缂撳瓨
+      deleteAction(this.url.delete, { id: id })
+        .then((res) => {
+          if (res.success) {
+            this.$message.success(res.message)
+            this.loadData()
+            this.refreshDictCache()
+          } else {
+            this.$message.warning(res.message)
+          }
+        })
+        .finally(() => {
+          this.loading = false
+        })
+    },
     transformConfigText(obj) {
       var text = ''
       if (obj.timeStr == '1,YEARS') {
diff --git a/src/views/dataAnalysis/components/CustTypeModal.vue b/src/views/dataAnalysis/components/CustTypeModal.vue
index 6f675b4..169830c 100644
--- a/src/views/dataAnalysis/components/CustTypeModal.vue
+++ b/src/views/dataAnalysis/components/CustTypeModal.vue
@@ -17,6 +17,9 @@
             v-model="clientConfigsList.clientName"
           ></a-input>
         </a-form-item>
+        <div v-if="!clientConfigsList.clientConfigs || clientConfigsList.clientConfigs.length === 0" style="text-align: center">
+          <a-button type="primary" @click="addConditions"> 娣诲姞瑙勫垯 </a-button>
+        </div>
         <div v-for="(subItem, subIndex) in clientConfigsList.clientConfigs" :key="subIndex">
           <div style="display: flex">
             <div>鏉′欢{{ subIndex + 1 }}锛�</div>
@@ -44,34 +47,100 @@
               <a-select-option value="1,YEARS"> 杩�1骞� </a-select-option>
             </a-select>
           </a-form-item>
-          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="鍔犳补棰戞">
+          <!-- 瑙勫垯绫诲瀷閫夋嫨锛氬姞娌归娆� OR 鍔犳补瓒嬪娍 -->
+          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="瑙勫垯绫诲瀷">
             <a-select
-              :disabled="subItem.timeStr == '7,DAYS' || subItem.timeStr == '30,DAYS'"
               style="width: 300px"
-              v-model="subItem.countType"
+              v-model="subItem.ruleType"
               placeholder="璇烽�夋嫨"
+              @change="ruleTypeChange($event, subIndex)"
             >
-              <a-select-option :value="1"> 绱 </a-select-option>
-              <a-select-option :value="2"> 姣忔湀 </a-select-option>
+              <a-select-option :value="1"> 鍔犳补棰戞 </a-select-option>
+              <a-select-option :value="2"> 鍔犳补瓒嬪娍 </a-select-option>
             </a-select>
-            <div style="display: flex">
-              <a-select style="width: 150px" v-model="subItem.countRef" placeholder="璇烽�夋嫨">
-                <a-select-option :value="1"> 澶т簬 </a-select-option>
-                <a-select-option :value="0"> 绛変簬 </a-select-option>
-                <a-select-option :value="-1"> 灏忎簬 </a-select-option>
+          </a-form-item>
+          <!-- 鍔犳补棰戞閰嶇疆锛坮uleType=1鏃舵樉绀猴級 -->
+          <div v-show="subItem.ruleType == 1">
+            <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="鍔犳补棰戞">
+              <a-select
+                :disabled="subItem.timeStr == '7,DAYS' || subItem.timeStr == '30,DAYS'"
+                style="width: 300px"
+                v-model="subItem.countType"
+                placeholder="璇烽�夋嫨"
+              >
+                <a-select-option :value="1"> 绱 </a-select-option>
+                <a-select-option :value="2"> 姣忔湀 </a-select-option>
               </a-select>
+              <div style="display: flex">
+                <a-select style="width: 150px" v-model="subItem.countRef" placeholder="璇烽�夋嫨">
+                  <a-select-option :value="1"> 澶т簬 </a-select-option>
+                  <a-select-option :value="0"> 绛変簬 </a-select-option>
+                  <a-select-option :value="-1"> 灏忎簬 </a-select-option>
+                </a-select>
+                <a-input
+                  style="width: 150px"
+                  placeholder="璇疯緭鍏ユ鏁�"
+                  onkeyup="if(this.value.length==1){this.value=this.value.replace(/[^1-9]/g,'')}else{this.value=this.value.replace(/\D/g,'')}"
+                  onafterpaste="if(this.value.length==1){this.value=this.value.replace(/[^1-9]/g,'0')}else{this.value=this.value.replace(/\D/g,'')}"
+                  v-model="subItem.countNum"
+                ></a-input>
+              </div>
+            </a-form-item>
+          </div>
+          <!-- 鍔犳补瓒嬪娍閰嶇疆锛坮uleType=2鏃舵樉绀猴級 -->
+          <div v-show="subItem.ruleType == 2">
+            <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="鍔犳补瓒嬪娍">
+              <a-select
+                style="width: 300px"
+                v-model="subItem.countTrend"
+                placeholder="璇烽�夋嫨"
+              >
+                <a-select-option :value="1"> 绋冲畾 </a-select-option>
+                <a-select-option :value="2"> 鍑忓皯 </a-select-option>
+              </a-select>
+              <div v-if="subItem.countTrend == 1" style="color: #999; font-size: 12px; margin-top: 5px;">
+                绋冲畾锛氬巻鍙叉湀鍔犳补娆℃暟鈮ユ鏁� 涓� 杩戞湡鏈堝姞娌规鏁扳墺娆℃暟
+              </div>
+              <div v-if="subItem.countTrend == 2" style="color: #999; font-size: 12px; margin-top: 5px;">
+                鍑忓皯锛氬巻鍙叉湀鍔犳补娆℃暟鈮ユ鏁� 浣� 杩戞湡鏈堝姞娌规鏁�<娆℃暟
+              </div>
+            </a-form-item>
+            <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="鍘嗗彶鏈堟暟">
+              <a-select
+                style="width: 140px"
+                v-model="subItem.historyMonths"
+                placeholder="鍘嗗彶鏈堟暟"
+              >
+                <a-select-option :value="3"> 3涓湀 </a-select-option>
+                <a-select-option :value="6"> 6涓湀 </a-select-option>
+                <a-select-option :value="9"> 9涓湀 </a-select-option>
+                <a-select-option :value="12"> 12涓湀 </a-select-option>
+              </a-select>
+            </a-form-item>
+            <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="杩戞湡鏈堟暟">
+              <a-select
+                style="width: 140px"
+                v-model="subItem.recentMonths"
+                placeholder="杩戞湡鏈堟暟"
+              >
+                <a-select-option :value="1"> 1涓湀 </a-select-option>
+                <a-select-option :value="2"> 2涓湀 </a-select-option>
+                <a-select-option :value="3"> 3涓湀 </a-select-option>
+              </a-select>
+            </a-form-item>
+            <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="鍥哄畾鍔犳补娆℃暟">
               <a-input
                 style="width: 150px"
-                placeholder="璇疯緭鍏ユ鏁�"
+                placeholder="姣忔湀鍥哄畾娆℃暟"
                 onkeyup="if(this.value.length==1){this.value=this.value.replace(/[^1-9]/g,'')}else{this.value=this.value.replace(/\D/g,'')}"
                 onafterpaste="if(this.value.length==1){this.value=this.value.replace(/[^1-9]/g,'0')}else{this.value=this.value.replace(/\D/g,'')}"
                 v-model="subItem.countNum"
               ></a-input>
-            </div>
-          </a-form-item>
-        </div>
-        <div style="text-align: center">
-          <a-button type="primary" @click="addConditions"> 澧炲姞鏉′欢 </a-button>
+            </a-form-item>
+          </div>
+          <div style="text-align: center" v-if="subIndex === clientConfigsList.clientConfigs.length - 1">
+            <a-button type="primary" @click="addConditions"> 澧炲姞鏉′欢 </a-button>
+          </div>
         </div>
       </div>
     </a-spin>
@@ -119,6 +188,21 @@
 
   methods: {
     moment,
+    buildCondition(condition = {}) {
+      return Object.assign(
+        {
+          ruleType: 1,
+          timeStr: '3,MONTHS',
+          countType: 2,
+          countRef: 1,
+          countNum: 3,
+          countTrend: null,
+          historyMonths: null,
+          recentMonths: null,
+        },
+        condition
+      )
+    },
     //鍒犻櫎鏉′欢
     delConditions(index) {
       console.log(index)
@@ -129,10 +213,46 @@
         this.clientConfigsList.clientConfigs[index].countType = 1
       }
     },
+    trendChange(e, index) {
+      // 閫夋嫨瓒嬪娍鏃讹紝璁剧疆榛樿鍊�
+      if (e > 0) {
+        this.clientConfigsList.clientConfigs[index].historyMonths = 3
+        this.clientConfigsList.clientConfigs[index].recentMonths = 3
+      } else {
+        // 娓呴櫎瓒嬪娍閰嶇疆
+        this.clientConfigsList.clientConfigs[index].historyMonths = null
+        this.clientConfigsList.clientConfigs[index].recentMonths = null
+      }
+    },
+    ruleTypeChange(e, index) {
+      let target = this.clientConfigsList.clientConfigs[index]
+      // 鍒囨崲瑙勫垯绫诲瀷鏃讹紝娓呯┖瀵瑰簲鐨勯厤缃�
+      if (e == 1) {
+        // 鍔犳补棰戞锛氭竻闄よ秼鍔块厤缃�
+        Object.assign(target, {
+          ruleType: 1,
+          countTrend: null,
+          historyMonths: null,
+          recentMonths: null,
+          countType: target.countType || 2,
+          countRef: target.countRef || 1,
+        })
+      } else if (e == 2) {
+        // 鍔犳补瓒嬪娍锛氭竻闄ら娆¢厤缃紝璁剧疆榛樿鍊�
+        Object.assign(target, {
+          ruleType: 2,
+          countType: 2,
+          countRef: 1,
+          countTrend: target.countTrend || 1,
+          historyMonths: target.historyMonths || 3,
+          recentMonths: target.recentMonths || 3,
+        })
+      }
+    },
     //鏂板鏉′欢
     addConditions(index) {
       console.log(index)
-      this.clientConfigsList.clientConfigs.push({})
+      this.clientConfigsList.clientConfigs.push(this.buildCondition())
     },
     disabledDate(current) {
       // Can not select days before today and today
@@ -151,7 +271,7 @@
     add() {
       this.edit({
         clientName: '',
-        clientConfigs: [{}],
+        clientConfigs: [this.buildCondition()],
       })
     },
     edit(record) {
@@ -163,7 +283,11 @@
       // }
       this.visible = true
       this.model = Object.assign({}, record)
-      this.clientConfigsList = record
+      this.clientConfigsList = Object.assign({}, record, {
+        clientConfigs: (record.clientConfigs || []).length
+          ? record.clientConfigs.map((item) => this.buildCondition(item))
+          : [],
+      })
     },
     close() {
       this.$emit('close')
@@ -183,16 +307,20 @@
         if (JSON.stringify(el) == '{}') {
           isEmpty = true
         }
-        for (let k in el) {
-          if (el[k] == '' || el[k].length == '0') {
+        // 鏍规嵁瑙勫垯绫诲瀷鏍¢獙
+        if (el.ruleType == 1) {
+          // 鍔犳补棰戞锛氭鏌ユ椂闂磋寖鍥淬�佹鏁扮被鍨嬨�佸叧绯汇�佹鏁�
+          if (!el.timeStr || !el.countRef || !el.countType || !el.countNum) {
             isEmpty = true
           }
-        }
-        if (!el.timeStr || !el.countRef || !el.countType || !el.countNum) {
-          isEmpty = true
-          if (el.countRef == 0 || el.countNum == 0) {
-            isEmpty = false
+        } else if (el.ruleType == 2) {
+          // 鍔犳补瓒嬪娍锛氭鏌ユ椂闂磋寖鍥淬�佽秼鍔裤�佸巻鍙叉湀鏁般�佽繎鏈熸湀鏁般�佹鏁�
+          if (!el.timeStr || !el.countTrend || !el.historyMonths || !el.recentMonths || !el.countNum) {
+            isEmpty = true
           }
+        } else {
+          // 鏈�夋嫨瑙勫垯绫诲瀷
+          isEmpty = true
         }
       })
       if (isEmpty) {
diff --git a/src/views/dataAnalysis/components/DataReGasStation.vue b/src/views/dataAnalysis/components/DataReGasStation.vue
index bb3ed28..a76e57c 100644
--- a/src/views/dataAnalysis/components/DataReGasStation.vue
+++ b/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>
@@ -122,6 +124,41 @@
         </div>
       </div>
     </div>
+    <div class="oil-freq-compare-ct">
+      <div class="block-title">娲诲姩鍓嶅悗杞﹁締鍔犳补棰戞</div>
+      <div class="oil-freq-compare-operator">
+        <span>娲诲姩鍓嶆椂娈�</span>
+        <a-range-picker
+          style="width: 360px; margin: 0 12px"
+          :value="beforeTimeRange"
+          format="YYYY-MM-DD HH:mm:ss"
+          valueFormat="YYYY-MM-DD HH:mm:ss"
+          :show-time="{ defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')] }"
+          @change="beforeTimeChange"
+        />
+        <span>娲诲姩鍚庢椂娈�</span>
+        <a-range-picker
+          style="width: 360px; margin: 0 12px"
+          :value="afterTimeRange"
+          format="YYYY-MM-DD HH:mm:ss"
+          valueFormat="YYYY-MM-DD HH:mm:ss"
+          :show-time="{ defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')] }"
+          @change="afterTimeChange"
+        />
+        <a-button type="primary" @click="getOilFreqCompareData"> 缁熻棰戞 </a-button>
+      </div>
+      <a-table
+        class="oil-freq-compare-table"
+        rowKey="licenseNum"
+        size="middle"
+        :columns="oilFreqCompareColumns"
+        :dataSource="oilFreqCompareData"
+        :loading="oilFreqCompareLoading"
+        :scroll="{ y: 420 }"
+        :pagination="{ pageSize: 10, showSizeChanger: true, pageSizeOptions: ['10', '20', '50'] }"
+      >
+      </a-table>
+    </div>
     <div>
       <div class="block-title">杞﹀瀷鍒嗘瀽</div>
       <div style="display: flex">
@@ -175,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>
 
@@ -183,6 +247,7 @@
 import DataReLineChart from './DataReLineChart'
 import DataRePieChart from './DataRePieChart'
 import { getAction, postAction } from '@tievd/cube-block/lib/api/manage'
+import moment from 'moment'
 export default {
   name: 'DataReMechanism',
   components: {
@@ -228,10 +293,131 @@
       trendAnalysisUnit: 'DAYS', //瓒嬪娍鍒嗘瀽閫夋嫨鏃堕棿
       trendAnalysisData: {}, //瓒嬪娍鍒嗘瀽鏁版嵁
       trendAnalysisChart: null, //瓒嬪娍鍒嗘瀽鍥捐〃
+      trendDetailVisible: false,
+      trendDetailTitle: '瓒嬪娍鍒嗘瀽鏄庣粏',
+      trendDetailLoading: false,
+      trendDetailData: [],
+      trendDetailColumns: [],
+      beforeStartTime: '',
+      beforeEndTime: '',
+      afterStartTime: '',
+      afterEndTime: '',
+      beforeTimeRange: [],
+      afterTimeRange: [],
+      oilFreqCompareLoading: false,
+      oilFreqCompareData: [],
+      oilFreqCompareColumns: [
+        {
+          title: '杞︾墝鍙�',
+          align: 'center',
+          dataIndex: 'licenseNum',
+        },
+        {
+          title: '娲诲姩鍓嶅姞娌规鏁�',
+          align: 'center',
+          dataIndex: 'beforeOilCount',
+        },
+        {
+          title: '娲诲姩鍚庡姞娌规鏁�',
+          align: 'center',
+          dataIndex: 'afterOilCount',
+        },
+        {
+          title: '鍙樺寲鍊�',
+          align: 'center',
+          dataIndex: 'diffOilCount',
+        },
+        {
+          title: '鍙樺寲鐜�',
+          align: 'center',
+          dataIndex: 'diffRate',
+          customRender: function (t) {
+            if (t === null || t === undefined) {
+              return '--'
+            }
+            return t + '%'
+          },
+        },
+      ],
     }
   },
 
   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', {
@@ -340,15 +526,70 @@
         this.contrastObj = res.result
       })
     },
+    beforeTimeChange(e, t) {
+      this.beforeTimeRange = t
+      this.beforeStartTime = t && t.length ? t[0] : ''
+      this.beforeEndTime = t && t.length ? t[1] : ''
+    },
+    afterTimeChange(e, t) {
+      this.afterTimeRange = t
+      this.afterStartTime = t && t.length ? t[0] : ''
+      this.afterEndTime = t && t.length ? t[1] : ''
+    },
+    setOilFreqDefaultRangeByActivity(activity) {
+      if (!activity || !activity.startTime || !activity.endTime) {
+        return
+      }
+      this.afterStartTime = activity.startTime
+      this.afterEndTime = activity.endTime
+      this.afterTimeRange = [this.afterStartTime, this.afterEndTime]
+      let startMoment = moment(activity.startTime)
+      let endMoment = moment(activity.endTime)
+      let spanSeconds = endMoment.diff(startMoment, 'seconds')
+      if (spanSeconds <= 0) {
+        return
+      }
+      this.beforeEndTime = startMoment.format('YYYY-MM-DD HH:mm:ss')
+      this.beforeStartTime = startMoment.clone().subtract(spanSeconds, 'seconds').format('YYYY-MM-DD HH:mm:ss')
+      this.beforeTimeRange = [this.beforeStartTime, this.beforeEndTime]
+    },
+    getOilFreqCompareData() {
+      if (!this.beforeStartTime || !this.beforeEndTime || !this.afterStartTime || !this.afterEndTime) {
+        this.oilFreqCompareData = []
+        return
+      }
+      this.oilFreqCompareLoading = true
+      postAction('/jyz/dataTable/statisOilFreqCompare', {
+        orgCode: this.selectTreeObj.orgCode,
+        beforeStartTime: this.beforeStartTime,
+        beforeEndTime: this.beforeEndTime,
+        afterStartTime: this.afterStartTime,
+        afterEndTime: this.afterEndTime,
+      })
+        .then((res) => {
+          this.oilFreqCompareData = res.result || []
+        })
+        .finally(() => {
+          this.oilFreqCompareLoading = false
+        })
+    },
     activeTimeChange(e) {
       console.log(e)
       if (e) {
         let item = this.activeOptions.find((el) => el.id == e)
         this.startTime = item.startTime
         this.endTime = item.endTime
+        this.setOilFreqDefaultRangeByActivity(item)
       } else {
         this.startTime = ''
         this.endTime = ''
+        this.beforeStartTime = ''
+        this.beforeEndTime = ''
+        this.afterStartTime = ''
+        this.afterEndTime = ''
+        this.beforeTimeRange = []
+        this.afterTimeRange = []
+        this.oilFreqCompareData = []
       }
     },
     activeChange() {},
@@ -390,6 +631,7 @@
       this.getVehicleStationPieData()
       this.getFuelingStationPieData()
       this.getTrendAnalysis()
+      this.getOilFreqCompareData()
     },
     initData() {
       this.getCustomerData()
@@ -430,7 +672,7 @@
 <style scoped lang="less">
 @import '~@assets/less/common.less';
 /deep/ .ant-table-content {
-  height: 500px;
+  height: auto;
   .ant-table-placeholder {
     background: none;
     border: none;
@@ -440,7 +682,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 {
@@ -448,6 +712,8 @@
     font-size: 16px;
   }
   .fueling-overview-ct {
+    position: relative;
+    z-index: 2;
     // margin: 0 12px;
     .fueling-overview-block {
       display: flex;
@@ -463,5 +729,33 @@
       }
     }
   }
+  .oil-freq-compare-ct {
+    position: relative;
+    z-index: 2;
+    margin: 8px 12px 24px 12px;
+    .oil-freq-compare-operator {
+      display: flex;
+      align-items: center;
+      flex-wrap: wrap;
+      gap: 8px 0;
+      margin: 12px 0;
+    }
+    .oil-freq-compare-table {
+      /deep/ .ant-table-body {
+        min-height: 240px;
+      }
+      /deep/ .ant-table-pagination.ant-pagination {
+        margin: 12px 0 4px 0;
+      }
+    }
+  }
+}
+</style>
+<style lang="less">
+.trend-detail-modal-wrap {
+  z-index: 5000 !important;
+}
+.trend-detail-modal-wrap + .ant-modal-mask {
+  z-index: 4999 !important;
 }
 </style>
diff --git a/src/views/dataAnalysis/components/DataReLineChart.vue b/src/views/dataAnalysis/components/DataReLineChart.vue
index 782f712..857fd8d 100644
--- a/src/views/dataAnalysis/components/DataReLineChart.vue
+++ b/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'
@@ -216,6 +409,7 @@
         ],
       }
       option && this.chartEntity.setOption(option, true)
+      this.bindChartClick()
     },
     setPieUpChart() {
       if (!this.chartEntity) {
@@ -241,6 +435,8 @@
       var option = {
         tooltip: {
           trigger: 'axis',
+          confine: true,
+          extraCssText: 'pointer-events:none;',
           axisPointer: {
             // 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
             type: 'line', // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
@@ -299,6 +495,7 @@
         series: [...data],
       }
       option && this.chartEntity.setOption(option, true)
+      this.bindChartClick()
     },
     setOnlyLineChart() {
       if (!this.chartEntity) {
@@ -309,6 +506,8 @@
       var option = {
         tooltip: {
           trigger: 'axis',
+          confine: true,
+          extraCssText: 'pointer-events:none;',
           axisPointer: {
             // 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
             type: 'line', // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
@@ -442,6 +641,7 @@
         ],
       }
       option && this.chartEntity.setOption(option, true)
+      this.bindChartClick()
     },
   },
 }
@@ -449,5 +649,7 @@
 <style lang="less" scoped>
 .line-chart {
   height: 20vh;
+  position: relative;
+  overflow: hidden;
 }
 </style>
diff --git a/src/views/dataAnalysis/components/DataRePieChart.vue b/src/views/dataAnalysis/components/DataRePieChart.vue
index b6db6bf..2adee7e 100644
--- a/src/views/dataAnalysis/components/DataRePieChart.vue
+++ b/src/views/dataAnalysis/components/DataRePieChart.vue
@@ -65,10 +65,10 @@
         legend: {
           orient: 'vertical',
           icon: 'circle',
-          right: '0',
-          top: '10%',
+          right: '2%',
+          top: 'middle',
           itemWidth: 14,
-          itemGap: 20,
+          itemGap: 12,
           textStyle: {
             rich: {
               a: {
@@ -106,9 +106,9 @@
             emphasis: {
               scale: false,
             },
-            center: ['40%', '50%'],
+            center: ['28%', '52%'],
             top: 'center',
-            right: '60%',
+            right: '62%',
             label: {
               show: true,
               position: 'inside',

--
Gitblit v1.8.0