index.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <template>
  2. <div class="performance-container">
  3. <div class="search-bar">
  4. <el-select v-model="searchForm.period" placeholder="统计周期">
  5. <el-option label="本月" :value="'month'" />
  6. <el-option label="本季度" :value="'quarter'" />
  7. <el-option label="本年" :value="'year'" />
  8. </el-select>
  9. <el-button type="primary" @click="handleSearch">查询</el-button>
  10. </div>
  11. <el-card title="租户业绩排行" class="ranking-card">
  12. <el-table :data="performanceList" border v-loading="loading">
  13. <el-table-column label="排名">
  14. <template slot-scope="scope">
  15. <span class="rank" :class="'rank-' + (scope.$index + 1)">{{ scope.$index + 1 }}</span>
  16. </template>
  17. </el-table-column>
  18. <el-table-column prop="tenantName" label="租户名称" />
  19. <el-table-column prop="totalAmount" label="消费总额" />
  20. <el-table-column prop="orderCount" label="订单数" />
  21. <el-table-column prop="newUserCount" label="新增用户" />
  22. <el-table-column prop="profitAmount" label="分账金额" />
  23. </el-table>
  24. </el-card>
  25. <el-row :gutter="20" style="margin-top: 20px;">
  26. <el-col :span="12">
  27. <el-card title="业绩趋势">
  28. <div id="trendChart" style="height: 250px;" />
  29. </el-card>
  30. </el-col>
  31. <el-col :span="12">
  32. <el-card title="消费类型分布">
  33. <div id="pieChart" style="height: 250px;" />
  34. </el-card>
  35. </el-col>
  36. </el-row>
  37. </div>
  38. </template>
  39. <script>
  40. import { getPerformanceList } from '@/api/performance'
  41. import echarts from 'echarts'
  42. export default {
  43. name: 'Performance',
  44. data() {
  45. return {
  46. searchForm: {
  47. period: 'month'
  48. },
  49. performanceList: [],
  50. loading: false
  51. }
  52. },
  53. mounted() {
  54. this.loadPerformanceList()
  55. },
  56. methods: {
  57. async loadPerformanceList() {
  58. this.loading = true
  59. try {
  60. const response = await getPerformanceList(this.searchForm)
  61. // 兼容多种后端返回格式:{rows,total} 或 {data:{list,total}} 或 {data:[...]}
  62. this.performanceList = response.rows || response.data?.list || (Array.isArray(response.data) ? response.data : null) || []
  63. this.$nextTick(() => {
  64. this.initCharts()
  65. })
  66. } finally {
  67. this.loading = false
  68. }
  69. },
  70. handleSearch() {
  71. this.loadPerformanceList()
  72. },
  73. initCharts() {
  74. const trendEl = document.getElementById('trendChart')
  75. const pieEl = document.getElementById('pieChart')
  76. if (!trendEl || !pieEl) return
  77. // 业绩趋势图:从API数据中提取
  78. const trendChart = echarts.init(trendEl)
  79. const trendData = this.performanceList.slice(0, 6)
  80. trendChart.setOption({
  81. tooltip: { trigger: 'axis' },
  82. xAxis: { type: 'category', data: trendData.map(t => t.tenantName || '') },
  83. yAxis: { type: 'value' },
  84. series: [{
  85. name: '消费总额',
  86. data: trendData.map(t => t.totalAmount || 0),
  87. type: 'bar',
  88. itemStyle: { color: '#3490dc' }
  89. }]
  90. })
  91. // 消费类型分布图
  92. const pieChart = echarts.init(pieEl)
  93. const consumeData = []
  94. if (this.performanceList.length > 0) {
  95. const totals = this.performanceList.reduce((acc, t) => {
  96. acc.totalAmount = (acc.totalAmount || 0) + (t.totalAmount || 0)
  97. acc.orderCount = (acc.orderCount || 0) + (t.orderCount || 0)
  98. acc.newUserCount = (acc.newUserCount || 0) + (t.newUserCount || 0)
  99. acc.profitAmount = (acc.profitAmount || 0) + (t.profitAmount || 0)
  100. return acc
  101. }, {})
  102. consumeData.push(
  103. { value: totals.totalAmount || 0, name: '消费总额' },
  104. { value: totals.orderCount || 0, name: '订单数' },
  105. { value: totals.newUserCount || 0, name: '新增用户' },
  106. { value: totals.profitAmount || 0, name: '分账金额' }
  107. )
  108. } else {
  109. consumeData.push(
  110. { value: 35, name: '消费总额' },
  111. { value: 25, name: '订单数' },
  112. { value: 20, name: '新增用户' },
  113. { value: 15, name: '分账金额' }
  114. )
  115. }
  116. pieChart.setOption({
  117. tooltip: { trigger: 'item' },
  118. series: [{
  119. type: 'pie',
  120. radius: '50%',
  121. data: consumeData
  122. }]
  123. })
  124. }
  125. }
  126. }
  127. </script>
  128. <style lang="scss" scoped>
  129. .performance-container {
  130. padding: 20px;
  131. }
  132. .search-bar {
  133. display: flex;
  134. align-items: center;
  135. margin-bottom: 20px;
  136. .el-select {
  137. width: 150px;
  138. margin-right: 10px;
  139. }
  140. }
  141. .ranking-card {
  142. .rank {
  143. display: inline-block;
  144. width: 24px;
  145. height: 24px;
  146. border-radius: 50%;
  147. background: #eee;
  148. text-align: center;
  149. line-height: 24px;
  150. font-size: 12px;
  151. &.rank-1 {
  152. background: #ffd700;
  153. color: #fff;
  154. }
  155. &.rank-2 {
  156. background: #c0c0c0;
  157. color: #fff;
  158. }
  159. &.rank-3 {
  160. background: #cd7f32;
  161. color: #fff;
  162. }
  163. }
  164. }
  165. </style>