|
|
@@ -11,6 +11,17 @@
|
|
|
<el-switch v-model="isSoundOn" active-color="#13ce66" @change="handleSoundChange" />
|
|
|
</div>
|
|
|
|
|
|
+ <!-- 在线用户统计 -->
|
|
|
+ <div class="online-stats-pill">
|
|
|
+ <span class="online-stats">在线用户:</span>
|
|
|
+ <div class="online-content">
|
|
|
+ <svg-icon icon-class="Iphone" class="stats-icon" />{{ onlineCounts.mobile }}
|
|
|
+ <svg-icon icon-class="Devices" class="stats-icon" />{{ onlineCounts.pc }}
|
|
|
+ <svg-icon icon-class="Android" class="stats-icon" />{{ onlineCounts.android }}
|
|
|
+ <svg-icon icon-class="Apple" class="stats-icon" />{{ onlineCounts.ios }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
<el-popover placement="bottom" width="170" trigger="hover">
|
|
|
<div style="padding: 10px 5px;">
|
|
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
|
|
|
@@ -81,7 +92,7 @@ import { mapGetters } from 'vuex'
|
|
|
import Breadcrumb from '@/components/Breadcrumb'
|
|
|
import Hamburger from '@/components/Hamburger'
|
|
|
import setPassword from './setPassword.vue'
|
|
|
-import { getPaymentOrderUnProcessed } from '@/api/data'
|
|
|
+import { getPaymentOrderUnProcessed, getOnlineUsers } from '@/api/data'
|
|
|
|
|
|
export default {
|
|
|
components: {
|
|
|
@@ -105,7 +116,8 @@ export default {
|
|
|
},
|
|
|
intervalSeconds: 3, // 轮询秒数变量
|
|
|
timer: null, // 定时器
|
|
|
- audi: require('@/assets/masg.mp3')
|
|
|
+ audi: require('@/assets/masg.mp3'),
|
|
|
+ onlineCounts: { mobile: 0, pc: 0, ios: 0, android: 0 }
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -127,9 +139,11 @@ export default {
|
|
|
created() {
|
|
|
// 初始化调用一次
|
|
|
this.fetchPendingData()
|
|
|
+ this.fetchOnlineCounts()
|
|
|
// 开启定时器
|
|
|
this.timer = setInterval(() => {
|
|
|
this.fetchPendingData()
|
|
|
+ this.fetchOnlineCounts()
|
|
|
}, this.intervalSeconds * 1000)
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
@@ -158,6 +172,23 @@ export default {
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
+ // 拉取在线用户并按平台统计
|
|
|
+ fetchOnlineCounts() {
|
|
|
+ getOnlineUsers({ page: 1, limit: 200 })
|
|
|
+ .then(res => {
|
|
|
+ const counts = { mobile: 0, pc: 0, ios: 0, android: 0 }
|
|
|
+ const rows = (res.data && res.data.data) || []
|
|
|
+ rows.forEach(r => {
|
|
|
+ const p = String(r.platform || '').toLowerCase()
|
|
|
+ if (p === 'pc') counts.pc++
|
|
|
+ else if (p === 'ios') counts.ios++
|
|
|
+ else if (p === 'android') counts.android++
|
|
|
+ else counts.mobile++ // Mobile / WeChat 等归入移动
|
|
|
+ })
|
|
|
+ this.onlineCounts = counts
|
|
|
+ })
|
|
|
+ .catch(() => {})
|
|
|
+ },
|
|
|
playSound() {
|
|
|
const audio = new Audio(this.audi)
|
|
|
audio.currentTime = 0 // 重置播放位置
|
|
|
@@ -258,6 +289,38 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ .online-stats-pill {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 6px;
|
|
|
+ margin-right: 15px;
|
|
|
+ line-height: 1;
|
|
|
+ font-size: 13px;
|
|
|
+
|
|
|
+ .online-stats {
|
|
|
+ white-space: nowrap;
|
|
|
+ display: flex;
|
|
|
+ color: #fff;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ .online-content {
|
|
|
+ padding: 4px 6px;
|
|
|
+ background: #D7D8D3;
|
|
|
+ color: #666666;
|
|
|
+ border-radius: 10px;
|
|
|
+ }
|
|
|
+ .stats-icon {
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ margin: 0 3px 0 6px;
|
|
|
+ vertical-align: -0.15em;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stats-icon:first-of-type {
|
|
|
+ margin-left: 4px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
.avatar-container {
|
|
|
margin-right: 30px;
|
|
|
|