统计
This commit is contained in:
		
							
								
								
									
										467
									
								
								packages/xbot/AppAiStatisticsTest/AppAiStatisticsTest.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										467
									
								
								packages/xbot/AppAiStatisticsTest/AppAiStatisticsTest.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,467 @@ | ||||
| <template> | ||||
|   <section class="AppAiStatisticsTest"> | ||||
|     <ai-detail list> | ||||
|       <ai-title slot="title" title="AI调用统计"> | ||||
|         <template #rightBtn> | ||||
|           <el-row type="flex" align="middle"> | ||||
|             <!-- <el-cascader ref="cascader1" clearable v-model="totalDeptList" :options="deptOptions" placeholder="所属部门" size="small" | ||||
|               :props="defaultProps" :show-all-levels="false" @change="totalDeptSelect"></el-cascader> --> | ||||
|               <AiAreaGet style="width: 250px" clearable always-show :instance="instance" v-model="totalAreaId" placeholder="所属地区" @change="getStatistics"></AiAreaGet> | ||||
|           </el-row> | ||||
|         </template> | ||||
|       </ai-title> | ||||
|       <template #content> | ||||
|         <div class="card_list"> | ||||
|           <div class="card"> | ||||
|             <h2>累计调用次数</h2> | ||||
|             <p class="color1">{{ totalInfo['累计'] || 0 }}</p> | ||||
|           </div> | ||||
|           <div class="card"> | ||||
|             <h2>本月调用次数</h2> | ||||
|             <p class="color1">{{ totalInfo['本月'] || 0 }}</p> | ||||
|           </div> | ||||
|           <div class="card"> | ||||
|             <h2>本周调用次数</h2> | ||||
|             <p class="color1">{{ totalInfo['本周'] || 0 }}</p> | ||||
|           </div> | ||||
|           <div class="card"> | ||||
|             <h2>昨日调用次数</h2> | ||||
|             <p class="color1">{{ totalInfo['昨日'] || 0 }}</p> | ||||
|           </div> | ||||
|         </div> | ||||
|         <ai-title slot="title" :title="`AI调用分析(${totalEcount}次)`"> | ||||
|           <template #rightBtn> | ||||
|             <el-row type="flex" align="middle"> | ||||
|               <span class="shortcut" v-for="(item,i) in timeCheck" :key="i" :class="{active:type==i}" | ||||
|                 @click="timeChange(i)" v-text="item"/> | ||||
|               <!-- <el-cascader ref="cascader2" clearable v-model="deptList" :options="deptOptions" placeholder="所属部门" size="small" | ||||
|                 :props="defaultProps" :show-all-levels="false" @change="deptSelect"></el-cascader> --> | ||||
|               <AiAreaGet style="width: 250px" clearable always-show :instance="instance" v-model="areaId" placeholder="所属地区" @change="getStatistics"></AiAreaGet> | ||||
|             </el-row> | ||||
|           </template> | ||||
|         </ai-title> | ||||
|         <el-row type="flex" class="mar-t4 gap-20 chart-content"> | ||||
|           <div class="chartBox fill"> | ||||
|             <b>AI调用趋势图</b> | ||||
|             <div id="trendChart" style="height: 480px; width: 100%;" v-if="trendData.length" class="chart"></div> | ||||
|             <ai-empty v-else style="height: 400px; width: 100%;" id="empty"/> | ||||
|           </div> | ||||
|           <div class="chartBox fill"> | ||||
|             <b>AI调用群聊排行榜</b> | ||||
|             <ai-table v-if="tableData.length" | ||||
|               :tableData="tableData" | ||||
|               :col-configs="colConfigs" | ||||
|               :isShowPagination="false" | ||||
|               style="margin-top: 6px; width: 100%; height: 480px;"> | ||||
|             </ai-table> | ||||
|             <ai-empty v-else style="height: 400px; width: 100%;" id="empty"/> | ||||
|           </div> | ||||
|         </el-row> | ||||
|         <!-- <el-row type="flex" class="mar-t4 gap-20"> | ||||
|           <div class="chartBox fill"> | ||||
|             <b>问答分类统计</b> | ||||
|             <div> | ||||
|               <div id="barChart" style="height: 260px; width: 100%;" v-if="barData.length"></div> | ||||
|               <ai-empty v-else style="height: 200px; width: 100%;" id="empty"/> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="chartBox fill"> | ||||
|             <b>问答分类词云</b> | ||||
|             <div> | ||||
|               <div id="wordChart" style="height: 260px; width: 100%;" v-if="wordData.length"/> | ||||
|               <ai-empty v-else style="height: 200px; width: 100%;" id="empty"/> | ||||
|             </div> | ||||
|           </div> | ||||
|         </el-row> --> | ||||
|         <ai-dialog :visible.sync="dialogDate" title="选择时间" width="500px" customFooter> | ||||
|           <el-date-picker v-model="timeList" size="small" type="daterange" value-format="yyyy-MM-dd" | ||||
|             range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"> | ||||
|           </el-date-picker> | ||||
|           <el-button slot="footer" @click="selectDete" type="primary">确认</el-button> | ||||
|         </ai-dialog> | ||||
|       </template> | ||||
|     </ai-detail> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
| import * as echarts from 'echarts'; | ||||
| import AiDetail from "dui/packages/layout/AiDetail.vue"; | ||||
| import AiTitle from "dui/packages/basic/AiTitle.vue"; | ||||
| import "echarts-wordcloud"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppAiStatisticsTest", | ||||
|   components: {AiTitle, AiDetail}, | ||||
|   label: "AI调用统计", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       defaultProps: { | ||||
|         label: 'name', | ||||
|         value: 'fullId', | ||||
|         checkStrictly: true, | ||||
|       }, | ||||
|       deptOptions: [], | ||||
|       info: {}, | ||||
|       trendData: [], | ||||
|       trendChart: null, | ||||
|       barData: [], | ||||
|       barChart: null, | ||||
|       wordData: [], | ||||
|       wordChart: null, | ||||
|       tableData: [], | ||||
|       totalInfo: {}, | ||||
|       type: '0', | ||||
|       timeCheck: ['近7天', '近30天', '近1年', '自定义'], | ||||
|       dialog: false, | ||||
|       dialogDate: false, | ||||
|       timeList: [], | ||||
|       startTime: '', | ||||
|       endTime: '', | ||||
|       totalDeptList: [], | ||||
|       deptList: [], | ||||
|       time: [], | ||||
|       totalAreaId: '', | ||||
|       areaId: '', | ||||
|       totalEcount: 0 | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         {prop: "rank", label: '排名', align: "center", width: "80px"}, | ||||
|         {prop: "roomName", label: '群名称', align: "center"}, | ||||
|         // {prop: "ownerName", label: '群主', align: "center", width: "100px"}, | ||||
|         {prop: "c", label: '触发数', align: "center", width: "100px"}, | ||||
|       ] | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDeptList() | ||||
|     this.getStatistics() | ||||
|   }, | ||||
|   methods: { | ||||
|     getStatistics() { | ||||
|       this.trendData = [], this.barData = [], this.wordData = [], this.tableData = [] | ||||
|       // var departmentId = this.deptList.length ? this.deptList[this.deptList.length-1] : '' | ||||
|       this.instance.post('/app/appmasssendingtaskbaidu/tmpStatistics', null, { | ||||
|         params: { | ||||
|           // deptFullId: departmentId, | ||||
|           areaId: this.areaId, | ||||
|           type: this.type, | ||||
|           startTime: this.startTime, | ||||
|           endTime: this.endTime, | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.totalInfo = res.data | ||||
|           this.info.trend = res.data.trend | ||||
|           var trendX = [] | ||||
|           this.totalEcount = 0 | ||||
|           this.info.trend.map((item) => { | ||||
|             trendX.push(item.ymd) | ||||
|             this.totalEcount = this.totalEcount + item.eCount | ||||
|             this.trendData.push(item.eCount) | ||||
|           }) | ||||
|           if(this.trendData.length) { | ||||
|             this.$nextTick(() => { | ||||
|               this.trendChartInit(trendX, this.trendData) | ||||
|             }) | ||||
|           } | ||||
|  | ||||
|           this.info.ranking = res.data.ranking | ||||
|           this.info.ranking.map((item, index)=> { | ||||
|             if(index < 100) { | ||||
|               item.rank = index+1 | ||||
|               this.tableData.push(item) | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|  | ||||
|     }, | ||||
|     trendChartInit(xData, yData) { | ||||
|       this.trendChart = echarts.init(document.getElementById('trendChart')) | ||||
|       let option = { | ||||
|         xAxis: { | ||||
|           type: 'category', | ||||
|           data: xData | ||||
|         }, | ||||
|         yAxis: { | ||||
|           type: 'value' | ||||
|         }, | ||||
|         grid: { | ||||
|           left: '10px', | ||||
|           right: '28px', | ||||
|           bottom: '14px', | ||||
|           top: '30px', | ||||
|           containLabel: true | ||||
|         }, | ||||
|         tooltip: { | ||||
|           trigger: 'axis' | ||||
|         }, | ||||
|         legend: { | ||||
|           type: "plain" | ||||
|         }, | ||||
|         color: '#2891FF', | ||||
|         series: [ | ||||
|           { | ||||
|             data: yData, | ||||
|             type: 'line' | ||||
|           } | ||||
|         ] | ||||
|       } | ||||
|       this.trendChart.setOption(option) | ||||
|     }, | ||||
|     barChartInit(xData, yData) { | ||||
|       this.barChart = echarts.init(document.getElementById('barChart')) | ||||
|       var option = { | ||||
|         color: ['#2891FF'], | ||||
|         grid: { | ||||
|           top: '10%', | ||||
|           left: '2%', | ||||
|           right: '2%', | ||||
|           bottom: '3%', | ||||
|           containLabel: true | ||||
|         }, | ||||
|         tooltip: { | ||||
|           trigger: 'axis', | ||||
|           axisPointer: { | ||||
|             type: 'shadow' | ||||
|           }, | ||||
|         }, | ||||
|         xAxis: { | ||||
|           data: xData, | ||||
|           silent: false, | ||||
|           splitLine: { | ||||
|             show: false | ||||
|           }, | ||||
|           splitArea: { | ||||
|             show: false | ||||
|           } | ||||
|         }, | ||||
|         yAxis: { | ||||
|           splitArea: { | ||||
|             show: false | ||||
|           } | ||||
|         }, | ||||
|         series: [ | ||||
|           { | ||||
|             type: 'bar', | ||||
|             data: yData, | ||||
|             barWidth: 20, | ||||
|             barGap: '250%', | ||||
|             large: true | ||||
|           } | ||||
|         ] | ||||
|       }; | ||||
|       this.barChart.setOption(option) | ||||
|     }, | ||||
|     wordChartInit(data) { | ||||
|       this.wordChart = echarts.init(document.getElementById('wordChart')) | ||||
|       var option = { | ||||
|         series: [ | ||||
|           { | ||||
|             type: "wordCloud", | ||||
|             sizeRange: [15, 80], | ||||
|             rotationRange: [0, 0], | ||||
|             rotationStep: 45, | ||||
|             gridSize: 8, | ||||
|             shape: "pentagon", | ||||
|             width: "100%", | ||||
|             height: "100%", | ||||
|             textStyle: { | ||||
|               normal: { | ||||
|                 color: function () { | ||||
|                   return ( | ||||
|                     "rgb(" + | ||||
|                     [ | ||||
|                       Math.round(Math.random() * 160), | ||||
|                       Math.round(Math.random() * 160), | ||||
|                       Math.round(Math.random() * 160), | ||||
|                     ].join(",") + | ||||
|                     ")" | ||||
|                   ); | ||||
|                 }, | ||||
|                 fontFamily: "sans-serif", | ||||
|                 fontWeight: "normal", | ||||
|               }, | ||||
|               emphasis: { | ||||
|                 shadowBlur: 10, | ||||
|                 shadowColor: "#333", | ||||
|               }, | ||||
|             }, | ||||
|             data, | ||||
|           }, | ||||
|         ], | ||||
|       } | ||||
|       this.wordChart.setOption(option) | ||||
|     }, | ||||
|     getDeptList() { | ||||
|       this.instance.post(`/app/wxcp/wxdepartment/listAll`).then((res) => { | ||||
|         if (res.code == 0) { | ||||
|           this.deptOptions = this.toTree(res.data) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     toTree(data) { | ||||
|       let result = []; | ||||
|       if (!Array.isArray(data)) { | ||||
|         return result | ||||
|       } | ||||
|       let map = {}; | ||||
|       data.forEach(item => { | ||||
|         map[item.id] = item; | ||||
|       }); | ||||
|       data.forEach(item => { | ||||
|         let parent = map[item.parentid]; | ||||
|         if (parent) { | ||||
|           (parent.children || (parent.children = [])).push(item); | ||||
|         } else { | ||||
|           result.push(item); | ||||
|         } | ||||
|       }); | ||||
|       return result; | ||||
|     }, | ||||
|     totalDeptSelect() { | ||||
|       this.getStatistics() | ||||
|     }, | ||||
|     deptSelect() { | ||||
|       this.getStatistics() | ||||
|     }, | ||||
|     timeChange(index) { | ||||
|       this.type = index | ||||
|       if (index == 3) { | ||||
|         this.dialogDate = true | ||||
|       } else { | ||||
|         this.startTime = '' | ||||
|         this.endTime = '' | ||||
|         this.getStatistics() | ||||
|       } | ||||
|     }, | ||||
|     selectDete() { | ||||
|       if (!this.timeList || !this.timeList.length) { | ||||
|         return this.$message.error('请选择自定义时间'); | ||||
|       } | ||||
|       this.startTime = this.timeList?.[0] | ||||
|       this.endTime = this.timeList?.[1] | ||||
|       this.dialogDate = false | ||||
|       this.getStatistics() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AppAiStatisticsTest { | ||||
|   height: 100%; | ||||
|   box-sizing: border-box; | ||||
|  | ||||
|   .shortcut { | ||||
|     display: inline-block; | ||||
|     width: 70px; | ||||
|     height: 32px; | ||||
|     line-height: 32px; | ||||
|     border-radius: 2px; | ||||
|     border: 1px solid #D0D4DC; | ||||
|     margin-right: 8px; | ||||
|     text-align: center; | ||||
|     cursor: pointer; | ||||
|  | ||||
|     &.active { | ||||
|       color: #2266FF; | ||||
|       border: 1px solid #2266FF; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   :deep .ai-detail__content--wrapper { | ||||
|     height: 100%; | ||||
|   } | ||||
|   .chart-content { | ||||
|     // height: calc(100% - 140px); | ||||
|   } | ||||
|  | ||||
|   :deep .ai-table { | ||||
|     height: calc(100% - 40px); | ||||
|     overflow-y: scroll; | ||||
|   } | ||||
|  | ||||
|   .chartBox { | ||||
|     background: #F9F9F9; | ||||
|     box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.1500); | ||||
|     border-radius: 4px; | ||||
|     padding: 16px; | ||||
|     box-sizing: border-box; | ||||
|     margin-top: 6px; | ||||
|     // height: 300px; | ||||
|  | ||||
|     .chart { | ||||
|       width: 100%; | ||||
|       height: 100%; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .card_list { | ||||
|     display: flex; | ||||
|     margin-bottom: 4px; | ||||
|  | ||||
|     .card { | ||||
|       flex: 1; | ||||
|       height: 76px; | ||||
|       background: #F9F9F9; | ||||
|       border-radius: 2px; | ||||
|       margin-right: 20px; | ||||
|       padding: 8px 24px; | ||||
|       box-sizing: border-box; | ||||
|  | ||||
|       h2 { | ||||
|         color: #888888; | ||||
|         font-weight: 600; | ||||
|         font-size: 16px; | ||||
|       } | ||||
|  | ||||
|       p { | ||||
|         margin-top: 8px; | ||||
|         font-size: 24px; | ||||
|         font-weight: 600; | ||||
|       } | ||||
|  | ||||
|       .color1 { | ||||
|         color: #2891FF; | ||||
|       } | ||||
|  | ||||
|       .color2 { | ||||
|         color: #22AA99; | ||||
|       } | ||||
|  | ||||
|       .color3 { | ||||
|         color: #F8B425; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .card:last-child { | ||||
|       margin-right: 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
|   :deep( .el-dialog__footer ) { | ||||
|     text-align: center; | ||||
|   } | ||||
|  | ||||
|   :deep( .el-dialog__header ) { | ||||
|     border-bottom: 1px solid #DDD; | ||||
|   } | ||||
|  | ||||
|   :deep( .ai-detail ) { | ||||
|     background: #FFF; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
		Reference in New Issue
	
	Block a user