From 086be7eae50e48ad554fd8a3f4cb1e333d587595 Mon Sep 17 00:00:00 2001
From: rk <94314517@qq.com>
Date: 星期二, 27 一月 2026 10:33:11 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 admin/src/views/index.vue |  611 +++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 523 insertions(+), 88 deletions(-)

diff --git a/admin/src/views/index.vue b/admin/src/views/index.vue
index 099186b..2cd5e29 100644
--- a/admin/src/views/index.vue
+++ b/admin/src/views/index.vue
@@ -1,93 +1,338 @@
 <template>
   <TableLayout>
     <div slot="search-form" class="data">
-        <div class="item-title">鏁版嵁鐪嬫澘</div>
+      <div class="top-tab">
+        <div class="tab-title">缁忚惀鏁版嵁鍒嗘瀽</div>
+        <div class="tab-item">
+          <span v-for="(item,index) in tabs" :key="'tab'+index"  :class="item.index==tabIndex?'active-tab tab-btn':'tab-btn'" @click="changeTab(item)">{{item.name}}</span>
+        </div>
+      </div>
+        <div class="item-title"> </div>
         <div class="data-summary">
-          <div class="data-item">
-            <div>浼氬憳鏁伴噺</div>
-            <div class="data-num">{{ countData.users }}</div>
+          <div class="data-item blue">
+            <div>{{tabName}}閿�鍞</div>
+            <div class="data-num">锟{ (topData.price ||0).toFixed(2) }}</div>
           </div>
           <div class="parting"></div>
-          <div class="data-item">
-            <div>浠婃棩娲昏穬鐢ㄦ埛</div>
-            <div class="data-num">{{ countData.activeUsers }}</div>
+          <div class="data-item yellow">
+            <div>{{tabName}}鎴愪氦璁㈠崟閲�</div>
+            <div class="data-num">{{ topData.num||0}}</div>
           </div>
           <div class="parting"></div>
-          <div class="data-item">
-            <div>璁㈠崟鎬绘暟</div>
-            <div class="data-num">{{ countData.orders }}</div>
+          <div class="data-item green">
+            <div>{{tabName}}閫�娆鹃噾棰�</div>
+            <div class="data-num">锟{( topData.price1 ||0).toFixed(2) }}</div>
           </div>
           <div class="parting"></div>
-          <div class="data-item">
-            <div>璁㈠崟鎬婚噾棰�</div>
-            <div class="data-num">{{ countData.money }}</div>
+          <div class="data-item orange">
+            <div>{{tabName}}閫�娆捐鍗曢噺</div>
+            <div class="data-num">{{ topData.num1 ||0 }}</div>
           </div>
           <div class="parting"></div>
-          <div class="data-item">
-            <div>鏈湀璁㈠崟鏁�</div>
-            <div class="data-num">{{ countData.mouthOrders }}</div>
-          </div>
-          <div class="parting"></div>
-          <div class="data-item">
-            <div>鏈湀璁㈠崟鎬婚噾棰�</div>
-            <div class="data-num">{{ countData.mouthMoney }}</div>
-          </div>
         </div>
       </div>
     <template v-slot:table-wrap>
       <div class="change-style">
-        <div class="item-title">璁㈠崟閲戦瓒嬪娍</div>
-        <div style="display: flex;">
-          <el-button type="text" @click="changeCount(7)">7鏃�</el-button>
-          <div style="margin: 0 5px;">|</div>
-          <el-button type="text" @click="changeCount(30)">30鏃�</el-button>
+        <div class="count-left">
+          <div class="item-title">璁㈠崟閲忎笌閿�鍞瓒嬪娍</div>
+          <div ref="orderCount" class="bottom"  ></div>
+        </div>
+        <div class="count-right">
+          <div class="item-title">鍚勫搧绫婚攢鍞鍗犳瘮</div>
+          <div ref="cateCount" class="bottom"></div>
         </div>
       </div>
-      <div ref="orderChange" class="bottom">
-        
+      <div class="change-style">
+          <div class="tab-title" style="display: flex;align-items: center; ">
+            <span style="">鎺掑悕鍒嗘瀽</span>
+            <div class="tab-item" style="margin-left: 20px;" >
+              <el-date-picker  style="width: 110px;height: 22px;margin-right: 10px;"   v-model="searchForm.topYear"  type="year" @change="changeYearMonth"
+                  clearable  value-format="yyyy"     format="yyyy'骞�'"   placeholder="骞翠唤" ></el-date-picker>
+              <el-date-picker  style="width: 100px;height: 22px;"   v-model="searchForm.topMonth"  type="month"  @change="changeYearMonth"
+                               clearable  value-format="MM"     format="MM'鏈�'"   placeholder="鏈堜唤" ></el-date-picker>
+            </div>
+          </div>
+      </div>
+      <div class="change-style">
+        <div class="count-left">
+          <div class="item-title" style="display: flex;">
+            <span style="flex: 1">缁忛攢鍟員OP10</span>
+            <div class="tab-item" style="text-align: right;flex: 1.5; ">
+              <span v-for="(item,index) in tabs1" :key="'tab'+index"  :class="item.index==tabIndex1?'active-tab tab-btn':'tab-btn'" @click="changeTab1(item)">{{item.name}}</span>
+            </div>
+          </div>
+          <div class="bottom1">
+            <el-table  :data="dataList1||[]"  stripe  border inline >
+              <el-table-column prop="sortnum" label="鎺掑悕"  align="center">
+                <template slot-scope="scope">{{scope.$index +1}}</template>
+              </el-table-column>
+              <el-table-column prop="name" label="缁忛攢鍟嗗悕绉�"   align="center" >  </el-table-column>
+              <el-table-column prop="num" label="璁㈠崟閲�"   align="center" >  </el-table-column>
+              <el-table-column prop="price" label="閿�鍞锛堝厓锛�" align="center" ></el-table-column>
+              <el-table-column prop="num1" label="浼氬憳鏁�" align="center"  ></el-table-column>
+            </el-table>
+          </div>
+        </div>
+        <div class="count-right">
+          <div class="item-title">
+            <div class="item-title" style="display: flex;">
+              <span style="flex: 1">鍗曚竴鍟嗗搧TOP10</span>
+              <div class="tab-item" style="text-align: right;flex: 1.5; ">
+                <span v-for="(item,index) in tabs2" :key="'tab'+index"  :class="item.index==tabIndex2?'active-tab tab-btn':'tab-btn'" @click="changeTab2(item)">{{item.name}}</span>
+              </div>
+            </div>
+          </div>
+          <div class="bottom1">
+            <el-table  :data="dataList2||[]"  stripe  border >
+              <el-table-column prop="sortnum" label="鎺掑悕"   align="center">
+                <template slot-scope="scope">{{scope.$index +1}}</template>
+              </el-table-column>
+              <el-table-column prop="name" label="鍟嗗搧鍚嶇О"   align="center" >  </el-table-column>
+              <el-table-column prop="num" label="閿�閲�"   align="center" >  </el-table-column>
+              <el-table-column prop="price" label="閿�鍞锛堝厓锛�" align="center"  ></el-table-column>
+            </el-table>
+          </div>
+        </div>
+      </div>
+      <div class="change-style">
+        <div class="tab-title" style="display: flex;align-items: center; ">
+          <span style="">钀ラ攢鏁版嵁鍒嗘瀽</span>
+          <div class="tab-item" style="margin-left: 20px;" >
+            <el-date-picker  style="width: 110px;height: 22px;margin-right: 10px;"   v-model="searchForm.topYear2"  type="year" @change="changeYear"
+                             clearable  value-format="yyyy"     format="yyyy'骞�'"   placeholder="骞翠唤" ></el-date-picker>
+          </div>
+        </div>
+      </div>
+      <div class="change-style">
+        <div class="count-left">
+          <div class="item-title">绉垎鍙戞斁绫诲瀷鍗犳瘮</div>
+          <div  class="bottom2" style="display: flex;align-items: center">
+              <div ref="integralCount" style="flex: 1;min-height: 200px;"></div>
+              <div style="flex: 1;font-size: 14px;font-weight: 500;margin-left: 20px;">
+                  <div>绱鍙戞斁鏁伴噺锛歿{( dataList4.num || 0 ) +( dataList4.num1 || 0 )+( dataList4.num2 || 0 )+( dataList4.num3 || 0 )}}</div>
+                  <div>绱娑堣�楋細{{ dataList4.useNum || 0 }}</div>
+                  <div>绱浼樻儬閲戦锛氾骏{{(dataList4.price || 0 ).toFixed(2) }}</div>
+              </div>
+          </div>
+        </div>
+        <div class="count-right">
+          <div class="item-title">浼樻儬鍒稿彂鏀剧被鍨嬪崰姣�</div>
+            <div  class="bottom2" style="display: flex;align-items: center">
+              <div ref="couponCount" style="flex: 1;min-height: 200px;"></div>
+              <div style="flex: 1;font-size: 14px;font-weight: 500;margin-left: 20px;">
+                <div>绱鍙戞斁鏁伴噺锛歿{( dataList3.num || 0 ) +( dataList3.num1 || 0 )}}</div>
+                <div>宸蹭娇鐢ㄤ紭鎯犲埜锛歿{ dataList3.useNum || 0 }}</div>
+                <div>绱浼樻儬閲戦锛氾骏{{(dataList3.price || 0 ).toFixed(2) }}</div>
+                <div>淇冩垚浜ゆ槗閲戦锛氾骏{{(dataList3.orderPrice || 0 ).toFixed(2) }}</div>
+              </div>
+            </div>
+        </div>
+      </div>
+      <div class="change-style" v-if="1==2">
+          <div class="item-title">钀ラ攢鎶曞叆璐圭敤涓庨攢鍞鍒嗘瀽</div>
+          <div ref="feeCount" class="bottom"></div>
       </div>
     </template>
-    
+
   </TableLayout>
 </template>
 
 <script>
 import TableLayout from '@/layouts/TableLayout'
-import * as echarts from 'echarts';
-import { findAllList, createCoffeeTask } from '@/api/business/taskRule'
+import BaseTable from '@/components/base/BaseTable'
+import * as echarts from 'echarts'
 export default {
+  extends: BaseTable,
   components: {
     TableLayout
   },
-  data() {
+  data () {
     return {
-      countData: {
-        users: 1000,
-        activeUsers: 1000,
-        mouthOrders: 10,
-        mouthMoney: 100000,
-        orders: 10,
-        money: 100000
+      loading1: false,
+      loading2: false,
+      loading3: false,
+      loading4: false,
+      loading5: false,
+      tabs2: [{ index: 0, name: '鎸夐攢閲�' }, { index: 1, name: '鎸夐攢鍞' }],
+      tabs1: [{ index: 0, name: '鎸夎鍗曢噺' }, { index: 1, name: '鎸夐攢鍞' }, { index: 2, name: '鎸変細鍛樻暟' }],
+      tabs: [{ index: 0, name: '浠婃棩' }, { index: 1, name: '杩�7鏃�' }, { index: 2, name: '杩�30鏃�' }, { index: 3, name: '杩�12鏈�' }],
+      tabName: '浠婃棩',
+      tabIndex: 0,
+      tabIndex1: 0,
+      tabIndex2: 0,
+      searchForm: {
+        topYear: null,
+        topMonth: null,
+        topYear2: null
       },
-      orderCorderCount: [10,10,20,10,40,10,30],
-      opinionData: ['3.20', '3.21', '3.22', '3.23', '3.24', '3.25', '3.26'],
-      myChart: null
+      topData: {
+        num: 0,
+        num1: 0,
+        price: 0,
+        price1: 0,
+        dateStrList: [],
+        dataList: [],
+        dataList2: [],
+        cateList: [],
+        numList: []
+      },
+      countData: {
+        totalPrice: 1000,
+        totalNum: 1000,
+        totalRefundPrice: 10000,
+        totalRefundNum: 100
+      },
+      dataList1: [],
+      dataList2: [],
+      dataList4: [],
+      dataList3: [],
+      myChart0: null,
+      myChart1: null,
+      myChart2: null,
+      myChart3: null
     }
   },
-  mounted() {
-    this.myChart = echarts.init(this.$refs.orderChange)
-    window.addEventListener('resize', () => {
-      this.myChart.resize()
+  created () {
+    this.config({
+      module: '宸ヤ綔鍙版暟鎹粺璁�',
+      api: '/business/workbench',
+      'field.id': 'id',
+      'field.main': 'id'
     })
-    this.renderOrderChange()
-    findAllList({})
-
+  },
+  mounted () {
+    this.initTopData()
+    this.initShopRankData()
+    this.initGoodsRankData()
+    this.initIntegralData()
+    this.initCouponData()
   },
   methods: {
-    renderOrderChange() {
-      this.myChart.setOption({
+    changeYearMonth(){
+      this.initGoodsRankData()
+      this.initShopRankData()
+    },
+    changeYear(){
+      this.initIntegralData()
+      this.initCouponData()
+    },
+    initCouponData () {
+      this.loading4 = true
+      this.api.couponData({year: this.searchForm.topYear2}).then(res => {
+        res = res || {}
+        this.dataList3 = res
+        this.renderEchartOption3()
+      }).finally(() => {
+        this.loading4 = false
+      })
+    },
+    initIntegralData () {
+      this.loading5 = true
+      this.api.integralData({ year: this.searchForm.topYear2}).then(res => {
+        res = res || {}
+        this.dataList4 = res
+        this.renderEchartOption2()
+      }).finally(() => {
+        this.loading5 = false
+      })
+    },
+    initShopRankData () {
+      this.loading2 = true
+      this.api.shopRankList10({ year: this.searchForm.topYear, month: this.searchForm.topMonth ,type:this.tabIndex1}).then(res => {
+        res = res || []
+        this.dataList1 = res
+      }).finally(() => {
+        this.loading2 = false
+      })
+    },
+    initGoodsRankData () {
+      this.loading3 = true
+      this.api.goodsRankList10({ year: this.searchForm.topYear, month: this.searchForm.topMonth ,type:this.tabIndex2}).then(res => {
+        res = res || []
+        this.dataList2 = res
+      }).finally(() => {
+        this.loading3 = false
+      })
+    },
+    initTopData () {
+      this.loading1 = true
+      this.initTopEcharts()
+      this.api.businessData({ dateType: this.tabIndex }).then(res => {
+        res = res || {}
+        res.num = res.num || 0
+        res.num1 = res.num1 || 0
+        res.price = res.price || 0
+        res.price1 = res.price1 || 0
+        res.dateStrList = res.dateStrList || []
+        res.datalist2 = res.datalist2 || []
+        res.dataList = res.dataList || []
+        res.cateList = res.cateList || []
+        this.topData = res
+        this.renderEchartOption0()
+        this.renderEchartOption1()
+      }).finally(() => {
+        this.loading1 = false
+      })
+    },
+    initTopEcharts () {
+      this.myChart0 = echarts.init(this.$refs.orderCount)
+      window.addEventListener('resize', () => {
+        this.myChart0.resize()
+      })
+      this.myChart1 = echarts.init(this.$refs.cateCount)
+      window.addEventListener('resize', () => {
+        this.myChart1.resize()
+      })
+      this.myChart2 = echarts.init(this.$refs.integralCount)
+      window.addEventListener('resize', () => {
+        this.myChart2.resize()
+      })
+      this.myChart3 = echarts.init(this.$refs.couponCount)
+      window.addEventListener('resize', () => {
+        this.myChart3.resize()
+      })
+      this.renderEchartOption0()
+      this.renderEchartOption1()
+      this.renderEchartOption2()
+      this.renderEchartOption3()
+    },
+    changeTab (item) {
+      if (this.loading1) {
+        return
+      }
+      if (item.index !== this.tabIndex) {
+        this.tabName = item.name
+        this.tabIndex = item.index
+        this.initTopData()
+      }
+    },
+    changeTab1 (item) {
+      if (this.loading2) {
+        return
+      }
+      if (item.index !== this.tabIndex1) {
+        this.tabName = item.name
+        this.tabIndex1 = item.index
+        this.initShopRankData()
+      }
+    },
+    changeTab2 (item) {
+      if (this.loading3) {
+        return
+      }
+      if (item.index !== this.tabIndex2) {
+        this.tabName = item.name
+        this.tabIndex2 = item.index
+        this.initGoodsRankData()
+      }
+    },
+    renderEchartOption0 () {
+      this.myChart0.setOption({
         tooltip: {
-          trigger: 'axis'
+          trigger: 'axis',
+          axisPointer: {
+            type: 'cross'
+          }
         },
         grid: {
           left: '3%',
@@ -97,55 +342,209 @@
         },
         toolbox: {
           feature: {
-            
           }
+        },
+        legend: {
+          data: ['璁㈠崟閲�', '閿�鍞(鍏�)']
         },
         xAxis: {
           type: 'category',
           boundaryGap: false,
-          data: this.opinionData
+          data: this.topData.dateStrList || []
         },
-        yAxis: {
-          type: 'value'
-        },
-        series: [{
-          name: '璁㈠崟',
-          type: 'line',
-          stack: '鎬婚噺',
-          data: this.orderCorderCount
-        }]
+        yAxis: [
+          {
+            type: 'value',
+            name: '璁㈠崟閲�',
+            min: 0
+          },
+          {
+            type: 'value',
+            name: '閿�鍞(鍏�)',
+            min: 0
+          }
+        ],
+        series: [
+          {
+            name: '璁㈠崟閲�',
+            data: this.topData.dataList || [],
+            type: 'bar'
+          },
+          {
+            name: '閿�鍞(鍏�)',
+            yAxisIndex: 1,
+            data: this.topData.dataList2 || [],
+            type: 'line'
+          }
+        ]
       })
-      
     },
-    changeCount(page) {
-      if (page == 7) {
-        this.orderCorderCount = [10,10,20,10,40,10,30]
-        this.opinionData = ['3.20', '3.21', '3.22', '3.23', '3.24', '3.25', '3.26']
-      } else {
-        this.orderCorderCount = [11,10,20,10,40,10,30,20,10,20,10,40,10,30,10,10,20,10,40,10,30,10,10,20,10,40,10,30,20,40]
-        this.opinionData = ['3.01','3.02','3.03','3.04','3.05','3.06','3.07','3.08','3.09','3.10','3.11','3.12','3.13','3.14','3.15','3.16','3.17','3.18','3.19','3.20', '3.21', '3.22', '3.23', '3.24', '3.25', '3.26', '3.27','3.28','3.28','3.30',]
-      }
-      // this.orderCorderCount.push(1)
-      // this.opinionData.push(1)
-      this.renderOrderChange()
-
-    }
-  },
+    renderEchartOption1 () {
+      const series = []
+      this.topData.cateList.forEach((item, index) => {
+        series.push( {
+          name: item.name,
+          type: 'bar',
+          stack: 'total',
+          barWidth: '60%',
+          label: {
+            // show: true
+          },
+          data: item.data || []
+        })
+      })
+      this.myChart1.setOption({
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'cross'
+          }
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+        },
+        toolbox: {
+          feature: {
+          }
+        },
+        legend: {
+          data: this.topData.cateList || []
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: this.topData.dateStrList || []
+        },
+        yAxis: { type: 'value' },
+        series
+      })
+    },
+    renderEchartOption2() {
+      this.myChart2.setOption({
+        tooltip: {
+          trigger: 'item'
+        },
+        series: [
+          {
+            name: 'Access From',
+            type: 'pie',
+            radius: '50%',
+            data: [
+              { value: this.dataList4.num || 0, name: '鎵嬪姩澧炲姞' },
+              { value: this.dataList4.num1 || 0, name: '閭�璇峰ソ鍙�' },
+              { value: this.dataList4.num2 || 0, name: '娑堣垂杩斿埄' },
+              { value: this.dataList4.num3 || 0, name: '娉ㄥ唽璧犻��' }
+            ],
+            emphasis: {
+              itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: 'rgba(0, 0, 0, 0.5)'
+              }
+            }
+          }
+        ]
+      })
+    },
+    renderEchartOption3() {
+      this.myChart3.setOption({
+        tooltip: {
+          trigger: 'item'
+        },
+        series: [
+          {
+            name: '浼樻儬鍒稿彂鏀�',
+            type: 'pie',
+            radius: '50%',
+            data: [
+              { value: this.dataList3.num1 || 0, name: '鎶樻墸鍒�' },
+              { value: this.dataList3.num || 0, name: '婊″噺鍒�' }
+            ],
+            emphasis: {
+              itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: 'rgba(0, 0, 0, 0.5)'
+              }
+            }
+          }
+        ]
+      })
+    },
+  }
 }
 </script>
 
 <style lang="scss" scoped>
+::v-deep .el-input--small .el-input__inner{
+  height: 22px;
+  line-height: 22px;
+  border-radius: 0;
+}
+::v-deep .el-input--small .el-input__icon{
+  height: 22px;
+  line-height: 22px;
+}
+.top-tab{
+  margin-bottom: 30px;
+  display: block;
+}
+.tab-title{
+  font-weight: 600;
+  font-size: 16px;
+  color: #222222;
+  line-height: 22px;
+  display: inline;
+}
+.tab-item{
+  display: inline;
+  margin-left: 50px;
+  .active-tab{
+    border: 1px solid #216EEE !important;
+    color: #216EEE !important;
+  }
+  .tab-btn{
+    font-weight: normal;
+    cursor: pointer;
+    border-radius: 0px;
+    margin: 0px 5px;
+    font-size: 12px;
+    border: 1px solid #999;
+    color: #999;
+    padding: 1px 5px;
+    background-color: #f2f2f2;
+  }
+}
 .data {
   padding-bottom: 10px;
 }
 .item-title {
-  font-weight: 500;
-  
+  font-weight: 600;
+  font-size: 14px;
+  color: #222222;
+  margin-left: 20px;
+  line-height: 22px;
 }
 .data-summary {
   display: flex;
   justify-content: space-between;
   margin-top: 10px;
+  margin-bottom: 20px;
+  .green{
+    border-left: 8px solid #12bb8b;
+  }
+  .yellow{
+    border-left: 8px solid #f6cf46;
+  }
+  .blue{
+    border-left: 8px solid #216EEE;
+  }
+  .orange{
+    border-left: 8px solid #ff9e56;
+  }
   .data-item {
     flex: 1;
     height: 80px;
@@ -153,12 +552,15 @@
     box-sizing: border-box;
     padding: 15px;
     display: flex;
+    font-size: 14px;
     flex-direction: column;
     justify-content: space-between;
+    background-color: #f4f7fc;
+    color: #666;
     .data-num {
       font-size: 20px;
-      font-weight: 700;
-      color:aqua
+      font-weight: 800;
+      color: #333;
     }
   }
   .parting {
@@ -169,9 +571,42 @@
   display: flex;
   justify-content: space-between;
   line-height: 31px;
-}
-.bottom {
-  height: 500px;
-}
-</style>
+  margin-bottom: 50px;
+  .count-left{
+    display: inline-block;
+    margin-right: 10px;
+    flex: 1;
+    .bottom {
+      height: 500px;
+      width: 100%;
+    }
+    .bottom2 {
+      height: 300px;
+      width: 100%;
+    }
+    .bottom1 {
+      height: auto;
+      width: 100%;
+    }
+  }
+  .count-right{
+    display: inline-block;
+    margin-left: 10px;
+    flex: 1;
+    .bottom {
+      height: 500px;
+      width: 100%;
+    }
+    .bottom2 {
+      height: 300px;
+      width: 100%;
+    }
+    .bottom1 {
+      height: auto;
+      width: 100%;
+    }
+  }
 
+}
+
+</style>

--
Gitblit v1.9.3