529 lines
15 KiB
Vue
529 lines
15 KiB
Vue
<template>
|
||
<section class="AppAiStatistics">
|
||
<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="getTotal"></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: 280px; width: 100%;" v-if="trendData.length" class="chart"></div>
|
||
<ai-empty v-else style="height: 200px; 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: 280px;">
|
||
</ai-table>
|
||
<ai-empty v-else style="height: 200px; 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 AiDetail from "dui/packages/layout/AiDetail.vue";
|
||
import AiTitle from "dui/packages/basic/AiTitle.vue";
|
||
import "echarts-wordcloud";
|
||
|
||
export default {
|
||
name: "AppAiStatistics",
|
||
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.getTotal()
|
||
this.getStatistics()
|
||
},
|
||
methods: {
|
||
getTotal() {
|
||
// var totalDepartmentId = this.totalDeptList.length ? this.totalDeptList[this.totalDeptList.length-1] : ''
|
||
this.instance.post(`/app/appmasssendingtaskbaidu/statistics1?areaId=${this.totalAreaId || ''}`).then(res => {
|
||
if (res?.data) {
|
||
console.log(res)
|
||
this.totalInfo = res.data
|
||
}
|
||
})
|
||
},
|
||
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/statistics2', null, {
|
||
params: {
|
||
// deptFullId: departmentId,
|
||
areaId: this.areaId,
|
||
type: this.type,
|
||
startTime: this.startTime,
|
||
endTime: this.endTime,
|
||
}
|
||
}).then(res => {
|
||
if (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.instance.post('/app/appmasssendingtaskbaidu/statistics3', null, {
|
||
params: {
|
||
areaId: this.areaId,
|
||
type: this.type,
|
||
startTime: this.startTime,
|
||
endTime: this.endTime,
|
||
}
|
||
}).then(res => {
|
||
if (res?.data) {
|
||
this.info.ranking = res.data.ranking
|
||
this.info.ranking.map((item, index)=> {
|
||
if(index < 100) {
|
||
item.rank = index+1
|
||
this.tableData.push(item)
|
||
}
|
||
})
|
||
|
||
}
|
||
})
|
||
|
||
this.instance.post('/app/appmasssendingtaskbaidu/statistics5', null, {
|
||
params: {
|
||
areaId: this.areaId,
|
||
type: this.type,
|
||
startTime: this.startTime,
|
||
endTime: this.endTime,
|
||
}
|
||
}).then(res => {
|
||
if (res?.data) {
|
||
if(res.data.length) {
|
||
var barX = []
|
||
res.data.map((item, index) => {
|
||
if(index < 10) {
|
||
barX.push(item.tag)
|
||
this.barData.push(item.c)
|
||
}
|
||
var i = { name: item.tag, value: item.c };
|
||
this.wordData.push(i);
|
||
})
|
||
if(this.barData.length) {
|
||
this.$nextTick(() => {
|
||
this.barChartInit(barX, this.barData)
|
||
})
|
||
}
|
||
if(this.wordData.length) {
|
||
this.$nextTick(() => {
|
||
this.wordChartInit(this.wordData)
|
||
})
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
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,
|
||
axisLabel: {
|
||
show: true, // 是否显示刻度标签,默认显示
|
||
interval: 0, // 坐标轴刻度标签的显示间隔,在类目轴中有效;默认会采用标签不重叠的策略间隔显示标签;可以设置成0强制显示所有标签;如果设置为1,表示『隔一个标签显示一个标签』,如果值为2,表示隔两个标签显示一个标签,以此类推。
|
||
rotate: -60, // 刻度标签旋转的角度,在类目轴的类目标签显示不下的时候可以通过旋转防止标签之间重叠;旋转的角度从-90度到90度
|
||
inside: false, // 刻度标签是否朝内,默认朝外
|
||
margin: 6, // 刻度标签与轴线之间的距离
|
||
},
|
||
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.getTotal()
|
||
},
|
||
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>
|
||
.AppAiStatistics {
|
||
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>
|