|
@@ -5,8 +5,11 @@ import * as echarts from 'echarts';
|
|
|
import useUserStore from '@/store/modules/user';
|
|
|
import { dashboardApi } from '@/api/voice/dashboard';
|
|
|
import { getEchartLineOption, getEchart3dOption, getEchartBarOption } from './echartConfig';
|
|
|
+import NumberAnimation from '@/components/NumberAnimation';
|
|
|
+import usePermissionStore from '@/store/modules/permission';
|
|
|
|
|
|
const userStore = useUserStore();
|
|
|
+const permissionStore = usePermissionStore();
|
|
|
|
|
|
const screenData = ref({});
|
|
|
|
|
@@ -17,6 +20,7 @@ const dateInfo = ref({
|
|
|
})
|
|
|
|
|
|
let timer = null;
|
|
|
+let dataTimer = null;
|
|
|
let myLineChart = null;
|
|
|
let my3dChart = null;
|
|
|
let myBarChart = null;
|
|
@@ -49,6 +53,7 @@ const formatSeconds = (seconds, num) => {
|
|
|
return formattedMinutes;
|
|
|
}
|
|
|
|
|
|
+// 将秒转换为小时、分钟和秒 00:12 d的函数
|
|
|
const formatSecondsToTime = (seconds) => {
|
|
|
// 计算完整的分钟数和剩余的秒数
|
|
|
let minutes = Math.floor(seconds / 60);
|
|
@@ -76,41 +81,40 @@ const initEchart = async() => {
|
|
|
const {
|
|
|
recent7DayAndCounts, recent7DayAndCountsLastYear,
|
|
|
recent7MonthAndCounts, recent7MonthAndCountsLastYear,
|
|
|
- businessTop7
|
|
|
+ businessTop7,
|
|
|
+ ai7DayAndCounts
|
|
|
} = data;
|
|
|
|
|
|
screenData.value = {
|
|
|
...data,
|
|
|
- inTimes: formatSeconds(data.inTimes, 60),
|
|
|
- inTimesAvg: formatSecondsToTime(data.inTimesAvg),
|
|
|
- totalTimes: formatSeconds(data.totalTimes, 3600),
|
|
|
- robotInTimes: formatSeconds(data.robotInTimes, 60),
|
|
|
- robotTimesAvg: formatSecondsToTime(data.robotTimesAvg),
|
|
|
- humanTimesAvg: formatSecondsToTime(data.humanTimesAvg),
|
|
|
- humanInTimes: formatSeconds(data.humanInTimes, 60)
|
|
|
+ todayInTimesAvg: formatSecondsToTime(data.todayInTimesAvg),
|
|
|
+ // inTimes: formatSeconds(data.inTimes, 60),
|
|
|
+ // inTimesAvg: formatSecondsToTime(data.inTimesAvg),
|
|
|
+ // totalTimes: formatSeconds(data.totalTimes, 3600),
|
|
|
+ // robotInTimes: formatSeconds(data.robotInTimes, 60),
|
|
|
+ // robotTimesAvg: formatSecondsToTime(data.robotTimesAvg),
|
|
|
+ // humanTimesAvg: formatSecondsToTime(data.humanTimesAvg),
|
|
|
+ // humanInTimes: formatSeconds(data.humanInTimes, 60)
|
|
|
};
|
|
|
|
|
|
// 近7日电话呼入量 - 折线图
|
|
|
const lineSeriesData = [
|
|
|
{ name: '近七日', data:recent7DayAndCounts },
|
|
|
- { name: '同比', data:recent7DayAndCountsLastYear }
|
|
|
+ // { name: '同比', data:recent7DayAndCountsLastYear }
|
|
|
];
|
|
|
const lineXAxisData = recent7DayAndCounts.map(item => dayjs(item.date).format('MM.DD'))
|
|
|
|
|
|
- // 近七日呼入电话量趋势
|
|
|
- const barXAxisData = recent7MonthAndCounts.map(item => dayjs(item.date).format('MM-DD'))
|
|
|
- const seriesData = recent7MonthAndCounts.map(item => item.count)
|
|
|
- const seriesData1 = recent7MonthAndCountsLastYear.map(item => item.count)
|
|
|
-
|
|
|
- myLineChart = echarts.init(echartLineRef.value);
|
|
|
- my3dChart = echarts.init(echart3dRef.value);
|
|
|
- myBarChart = echarts.init(echartBarRef.value);
|
|
|
+ // 近七日Ai处理情况
|
|
|
+ const barXAxisData = ai7DayAndCounts.map(item => dayjs(item.date).format('MM.DD'))
|
|
|
+ const seriesData = ai7DayAndCounts.map(item => item.aiCounts)
|
|
|
+ const seriesData1 = ai7DayAndCounts.map(item => item.totalCounts)
|
|
|
|
|
|
myLineChart.setOption(getEchartLineOption({
|
|
|
xAxisData: lineXAxisData,
|
|
|
seriesData: lineSeriesData
|
|
|
}));
|
|
|
|
|
|
+ // 本月业务类型 TOP7
|
|
|
my3dChart.setOption(getEchart3dOption(businessTop7));
|
|
|
|
|
|
myBarChart.setOption(getEchartBarOption({
|
|
@@ -123,11 +127,17 @@ const initEchart = async() => {
|
|
|
const windowResize = () => {
|
|
|
setTimeout(() => {
|
|
|
myLineChart.resize();
|
|
|
- // my3dChart.resize();
|
|
|
- // myBarChart.resize();
|
|
|
+ my3dChart.resize();
|
|
|
+ myBarChart.resize();
|
|
|
}, 300)
|
|
|
}
|
|
|
|
|
|
+const hasRouterAuth = () => {
|
|
|
+ return permissionStore.routes.some(route => {
|
|
|
+ return route.path === '/voice/dashboard'
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
autofit.init({
|
|
|
dw: 1920,
|
|
@@ -136,8 +146,13 @@ onMounted(() => {
|
|
|
resize: true,
|
|
|
})
|
|
|
|
|
|
- timer = setInterval(updateTime, 1000);
|
|
|
+ myLineChart = echarts.init(echartLineRef.value);
|
|
|
+ my3dChart = echarts.init(echart3dRef.value);
|
|
|
+ myBarChart = echarts.init(echartBarRef.value);
|
|
|
|
|
|
+ timer = setInterval(updateTime, 1000);
|
|
|
+ dataTimer = setInterval(initEchart, 5 * 60 * 1000);
|
|
|
+
|
|
|
updateTime();
|
|
|
|
|
|
initEchart();
|
|
@@ -148,6 +163,7 @@ onMounted(() => {
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
clearInterval(timer);
|
|
|
+ clearInterval(dataTimer);
|
|
|
})
|
|
|
</script>
|
|
|
|
|
@@ -168,15 +184,27 @@ onUnmounted(() => {
|
|
|
<span>{{ userStore.nickName }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="main space-y-[20px]">
|
|
|
+ <div class="main">
|
|
|
<div class="top">
|
|
|
<div class="count-list">
|
|
|
- <div class="count-item"><p class="num">{{ screenData.inTotal }}</p><p>近7天呼入总量</p></div>
|
|
|
- <div class="count-item"><p class="num">{{ screenData.successRate }}%</p><p>近7天接通率</p></div>
|
|
|
- <div class="count-item"><p class="num">{{ screenData.inTimes }}<span class="text-[14px] text-[#fff] opacity-70">分钟</span></p><p>近7天呼入时长</p></div>
|
|
|
- <div class="count-item"><p class="num">{{ screenData.inTimesAvg }}</p><p>近7天平均呼入时长</p></div>
|
|
|
- <div class="count-item"><p class="num">{{ screenData.totalTimes }}<span class="text-[14px] text-[#fff] opacity-70">小时</span></p><p>累计呼入时长</p></div>
|
|
|
- <div class="count-item"><p class="num">{{ screenData.totalCounts }}</p><p>累计呼入总量</p></div>
|
|
|
+ <div class="count-item">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.todayInTotal"></NumberAnimation></p>
|
|
|
+ <p>进入呼入总量</p>
|
|
|
+ </div>
|
|
|
+ <div class="count-item">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.todayAiTotal"></NumberAnimation></p>
|
|
|
+ <p>今日AI处理量<span class="text-[#00FCFF]">「占比{{screenData.todayAiRate || 0}}%」</span></p>
|
|
|
+ </div>
|
|
|
+ <div class="count-item">
|
|
|
+ <p class="num">{{ screenData.todayInTimesAvg || "00:00" }}</p>
|
|
|
+ <p>今日平均呼入时长</p>
|
|
|
+ </div>
|
|
|
+ <div class="count-item">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.totalCounts"></NumberAnimation></p>
|
|
|
+ <p>累计呼入总量</p>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="count-item"><p class="num">{{ screenData.totalTimes }}<span class="text-[14px] text-[#fff] opacity-70">小时</span></p><p>累计呼入时长</p></div>
|
|
|
+ <div class="count-item"><p class="num">{{ screenData.totalCounts }}</p><p>累计呼入总量</p></div> -->
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="middle">
|
|
@@ -194,23 +222,77 @@ onUnmounted(() => {
|
|
|
</div>
|
|
|
<div class="bottom">
|
|
|
<div class="left">
|
|
|
+ <div class="title-status">当前在线人工坐席:3人 机器人坐席:10个</div>
|
|
|
<ul class="statistic-list">
|
|
|
- <li class="statistic-item"><p class="title">今日呼入总量</p><p class="num">{{ screenData.robotInTotal }}</p></li>
|
|
|
- <li class="statistic-item"><p class="title">通话时长</p><p class="num space-x-[4px]"><span>{{ screenData.robotInTimes }}</span><span class="unit">分钟</span></p></li>
|
|
|
+ <li class="statistic-item">
|
|
|
+ <p class="title">AI处理量</p>
|
|
|
+ <div class="numeric-stats-box">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.todayAiTotal"></NumberAnimation></p>
|
|
|
+ <span class="ratio green">占比 {{screenData.todayAiRate || 0}}%</span>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <li class="statistic-item">
|
|
|
+ <p class="title">人工处理量</p>
|
|
|
+ <div class="numeric-stats-box">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.todayHumanTotal"></NumberAnimation></p>
|
|
|
+ <span class="ratio green">占比 {{screenData.todayHumanRate || 0}}%</span>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <li class="statistic-item">
|
|
|
+ <p class="title">电话接通量</p>
|
|
|
+ <div class="numeric-stats-box">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.todaySuccessCounts"></NumberAnimation></p>
|
|
|
+ <span class="ratio green">占比 {{screenData.todaySuccessRate || 0}}%</span>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <li class="statistic-item">
|
|
|
+ <p class="title">今日呼入总量</p>
|
|
|
+ <div class="numeric-stats-box">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.todayInTotal"></NumberAnimation></p>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <!-- <li class="statistic-item"><p class="title">通话时长</p><p class="num space-x-[4px]"><span>{{ screenData.robotInTimes }}</span><span class="unit">分钟</span></p></li>
|
|
|
<li class="statistic-item"><p class="title">平均通话时长</p><p class="num">{{ screenData.robotTimesAvg }}</p></li>
|
|
|
<li class="statistic-item"><p class="title">转人工总量</p><p class="num">{{ screenData.transfer2Human }}</p></li>
|
|
|
<li class="statistic-item"><p class="title">当前排队总数</p><p class="num">300</p></li>
|
|
|
- <li class="statistic-item"><p class="title">分流比例</p><p class="num">{{ screenData.robotStreamRate }}%</p></li>
|
|
|
+ <li class="statistic-item"><p class="title">分流比例</p><p class="num">{{ screenData.robotStreamRate }}%</p></li> -->
|
|
|
</ul>
|
|
|
</div>
|
|
|
<div class="right">
|
|
|
<ul class="statistic-list">
|
|
|
- <li class="statistic-item"><p class="title">今日呼入总量</p><p class="num">{{ screenData.humanInTotal }}</p></li>
|
|
|
+ <li class="statistic-item">
|
|
|
+ <p class="title">AI处理量</p>
|
|
|
+ <div class="numeric-stats-box">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.yesterdayAiTotal"></NumberAnimation></p>
|
|
|
+ <span class="ratio red">占比 {{screenData.yesterdayAiRate || 0}}%</span>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <li class="statistic-item">
|
|
|
+ <p class="title">人工处理量</p>
|
|
|
+ <div class="numeric-stats-box">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.yesterdayHumanTotal"></NumberAnimation></p>
|
|
|
+ <span class="ratio red">占比 {{screenData.yesterdayHumanRate || 0}}%</span>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <li class="statistic-item">
|
|
|
+ <p class="title">电话接通量</p>
|
|
|
+ <div class="numeric-stats-box">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.yesterdaySuccessCounts"></NumberAnimation></p>
|
|
|
+ <span class="ratio red">占比 {{screenData.yesterdaySuccessRate || 0}}%</span>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <li class="statistic-item">
|
|
|
+ <p class="title">今日呼入总量</p>
|
|
|
+ <div class="numeric-stats-box">
|
|
|
+ <p class="num"><NumberAnimation :to="screenData.yesterdayInTotal"></NumberAnimation></p>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <!-- <li class="statistic-item"><p class="title">今日呼入总量</p><p class="num">{{ screenData.humanInTotal }}</p></li>
|
|
|
<li class="statistic-item"><p class="title">通话时长</p><p class="num space-x-[4px]"><span>{{ screenData.humanInTimes }}</span><span class="unit">分钟</span></p></li>
|
|
|
<li class="statistic-item"><p class="title">平均通话时长</p><p class="num">{{ screenData.humanTimesAvg }}</p></li>
|
|
|
<li class="statistic-item"><p class="title">置闲人数</p><p class="num">{{ screenData.onlineTotal }}</p></li>
|
|
|
<li class="statistic-item"><p class="title">当前排队总数</p><p class="num"></p></li>
|
|
|
- <li class="statistic-item"><p class="title">分流比例</p><p class="num">{{ screenData.humanStreamRate }}%</p></li>
|
|
|
+ <li class="statistic-item"><p class="title">分流比例</p><p class="num">{{ screenData.humanStreamRate }}%</p></li> -->
|
|
|
</ul>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -291,31 +373,33 @@ onUnmounted(() => {
|
|
|
}
|
|
|
|
|
|
.main {
|
|
|
- justify-content: space-between;
|
|
|
- padding: 30px 50px 18px 50px;
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-flow: column;
|
|
|
+ padding: 20px 50px 18px 50px;
|
|
|
.top {
|
|
|
height: 120px;
|
|
|
flex-shrink: 0;
|
|
|
.count-list {
|
|
|
display: grid;
|
|
|
gap: 12px;
|
|
|
- grid-template-columns: repeat(6, minmax(260px, 1fr));
|
|
|
+ grid-template-columns: repeat(4, minmax(260px, 1fr));
|
|
|
height: 100%;
|
|
|
.count-item:nth-child(1) {
|
|
|
background: url("@/assets/images/dashboard/bg-count-01.png") no-repeat;
|
|
|
- background-size: contain;
|
|
|
+ background-size: 100% 100%;
|
|
|
}
|
|
|
.count-item:nth-child(2) {
|
|
|
background: url("@/assets/images/dashboard/bg-count-02.png") no-repeat;
|
|
|
- background-size: contain;
|
|
|
+ background-size: 100% 100%;
|
|
|
}
|
|
|
.count-item:nth-child(3) {
|
|
|
background: url("@/assets/images/dashboard/bg-count-03.png") no-repeat;
|
|
|
- background-size: contain;
|
|
|
+ background-size: 100% 100%;
|
|
|
}
|
|
|
.count-item:nth-child(4) {
|
|
|
background: url("@/assets/images/dashboard/bg-count-04.png") no-repeat;
|
|
|
- background-size: contain;
|
|
|
+ background-size: 100% 100%;
|
|
|
}
|
|
|
.count-item:nth-child(5) {
|
|
|
background: url("@/assets/images/dashboard/bg-count-05.png") no-repeat;
|
|
@@ -326,7 +410,7 @@ onUnmounted(() => {
|
|
|
background-size: contain;
|
|
|
}
|
|
|
.count-item {
|
|
|
- padding: 20px 0 0 22px;
|
|
|
+ padding: 10px 0 0 22px;
|
|
|
color: #FFF;
|
|
|
.num {
|
|
|
font-family: D-DIN-PRO;
|
|
@@ -342,13 +426,11 @@ onUnmounted(() => {
|
|
|
}
|
|
|
}
|
|
|
.middle {
|
|
|
- height: 346px;
|
|
|
+ height: 350px;
|
|
|
+ margin-top: 36px;
|
|
|
.echart-list {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- // display: grid;
|
|
|
- // grid-template-columns: repeat(3, 1fr);
|
|
|
- // gap: 12px;
|
|
|
height: 100%;
|
|
|
.echart-item:nth-child(1) {
|
|
|
margin-right: 12px;
|
|
@@ -386,28 +468,60 @@ onUnmounted(() => {
|
|
|
grid-template-columns: repeat(2, 1fr);
|
|
|
gap: 12px;
|
|
|
height: 350px;
|
|
|
+ margin-top: 24px;
|
|
|
.left {
|
|
|
+ position: relative;
|
|
|
padding-top: 44px;
|
|
|
background: url('@/assets/images/dashboard/bg-middle-title-04.png') left top no-repeat, url('@/assets/images/dashboard/bg-bottom.png') left center no-repeat;
|
|
|
- background-size: 598px 44px, 100% 100%;
|
|
|
+ background-size: 100% 44px, 100% 100%;
|
|
|
+ .title-status {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ right: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-end;
|
|
|
+ width: 100%;
|
|
|
+ height: 44px;
|
|
|
+ padding-right: 30px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
+ }
|
|
|
}
|
|
|
.right {
|
|
|
padding-top: 44px;
|
|
|
background: url('@/assets/images/dashboard/bg-middle-title-05.png') left top no-repeat, url('@/assets/images/dashboard/bg-bottom.png') left center no-repeat;
|
|
|
- background-size: 598px 44px, 100% 100%;
|
|
|
+ background-size: 100% 44px, 100% 100%;
|
|
|
}
|
|
|
.statistic-list {
|
|
|
display: grid;
|
|
|
- grid-template-columns: repeat(3, 1fr);
|
|
|
+ grid-template-columns: repeat(2, 1fr);
|
|
|
grid-template-rows: repeat(2, 1fr);
|
|
|
gap: 15px;
|
|
|
height: 100%;
|
|
|
padding: 30px 42px;
|
|
|
.statistic-item {
|
|
|
height: 100%;
|
|
|
- padding: 20px 0 0 36px;
|
|
|
+ padding: 20px 36px 0 36px;
|
|
|
background: url('@/assets/images/dashboard/bg-bottom-item.png') center center no-repeat;
|
|
|
background-size: 100% 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ .numeric-stats-box {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: flex-end;
|
|
|
+ height: 50px;
|
|
|
+ .ratio {
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 24px;
|
|
|
+ }
|
|
|
+ .green {
|
|
|
+ color: #00F040;
|
|
|
+ }
|
|
|
+ .red {
|
|
|
+ color: #FF7300
|
|
|
+ }
|
|
|
+ }
|
|
|
.title {
|
|
|
color: #E6FFF5;
|
|
|
font-size: 18px;
|
|
@@ -420,6 +534,7 @@ onUnmounted(() => {
|
|
|
font-family: D-DIN-PRO;
|
|
|
font-size: 36px;
|
|
|
font-weight: bold;
|
|
|
+ line-height: 50px;
|
|
|
}
|
|
|
.unit {
|
|
|
color: #9c9c9c;
|