|
|
|
|
@ -1,117 +1,155 @@
|
|
|
|
|
<template>
|
|
|
|
|
<!-- 主卡片容器,包含整个在线用户页面内容 -->
|
|
|
|
|
<el-card class="main-card">
|
|
|
|
|
<!-- 页面标题,显示当前路由名称 -->
|
|
|
|
|
<div class="title">{{ this.$route.name }}</div>
|
|
|
|
|
|
|
|
|
|
<!-- 操作区域容器,包含搜索功能 -->
|
|
|
|
|
<div class="operation-container">
|
|
|
|
|
<div style="margin-left: auto">
|
|
|
|
|
<!-- 搜索输入框,用于根据用户昵称搜索在线用户 -->
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="keywords"
|
|
|
|
|
prefix-icon="el-icon-search"
|
|
|
|
|
size="small"
|
|
|
|
|
placeholder="请输入用户昵称"
|
|
|
|
|
style="width: 200px"
|
|
|
|
|
@keyup.enter.native="listOnlineUsers" />
|
|
|
|
|
v-model="keywords"
|
|
|
|
|
prefix-icon="el-icon-search"
|
|
|
|
|
size="small"
|
|
|
|
|
placeholder="请输入用户昵称"
|
|
|
|
|
style="width: 200px"
|
|
|
|
|
@keyup.enter.native="listOnlineUsers" /> <!-- 回车触发搜索 -->
|
|
|
|
|
|
|
|
|
|
<!-- 搜索按钮,点击触发搜索 -->
|
|
|
|
|
<el-button type="primary" size="small" icon="el-icon-search" style="margin-left: 1rem" @click="listOnlineUsers">
|
|
|
|
|
搜索
|
|
|
|
|
</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 在线用户表格,加载状态由loading控制 -->
|
|
|
|
|
<el-table v-loading="loading" :data="users">
|
|
|
|
|
<!-- 选择列,用于批量操作 -->
|
|
|
|
|
<el-table-column type="selection" width="55" align="center" />
|
|
|
|
|
|
|
|
|
|
<!-- 头像列,展示用户头像 -->
|
|
|
|
|
<el-table-column prop="avatar" label="头像" align="center" width="100">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<img :src="scope.row.avatar" width="40" height="40" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
|
|
<!-- 昵称列,展示用户昵称 -->
|
|
|
|
|
<el-table-column prop="nickname" label="昵称" align="center" />
|
|
|
|
|
|
|
|
|
|
<!-- IP地址列,展示用户登录IP -->
|
|
|
|
|
<el-table-column prop="ipAddress" label="ip地址" align="center" />
|
|
|
|
|
|
|
|
|
|
<!-- 登录地址列,展示IP对应的地理位置 -->
|
|
|
|
|
<el-table-column prop="ipSource" label="登录地址" align="center" width="200" />
|
|
|
|
|
|
|
|
|
|
<!-- 浏览器列,展示用户使用的浏览器 -->
|
|
|
|
|
<el-table-column prop="browser" label="浏览器" align="center" width="160" />
|
|
|
|
|
|
|
|
|
|
<!-- 操作系统列,展示用户使用的操作系统 -->
|
|
|
|
|
<el-table-column prop="os" label="操作系统" align="center" />
|
|
|
|
|
|
|
|
|
|
<!-- 登录时间列,展示用户最后登录时间(使用日期过滤器格式化) -->
|
|
|
|
|
<el-table-column prop="lastLoginTime" label="登录时间" align="center" width="200">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<i class="el-icon-time" style="margin-right: 5px" />
|
|
|
|
|
{{ scope.row.lastLoginTime | dateTime }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
|
|
<!-- 操作列,包含下线功能 -->
|
|
|
|
|
<el-table-column label="操作" align="center" width="150">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<!-- 下线确认弹窗,点击确认后执行下线操作 -->
|
|
|
|
|
<el-popconfirm title="确定下线吗?" style="margin-left: 10px" @confirm="removeOnlineUser(scope.row)">
|
|
|
|
|
<el-button size="mini" type="text" slot="reference"> <i class="el-icon-delete" /> 下线 </el-button>
|
|
|
|
|
</el-popconfirm>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
<!-- 分页组件 -->
|
|
|
|
|
<el-pagination
|
|
|
|
|
class="pagination-container"
|
|
|
|
|
background
|
|
|
|
|
@size-change="sizeChange"
|
|
|
|
|
@current-change="currentChange"
|
|
|
|
|
:current-page="current"
|
|
|
|
|
:page-size="size"
|
|
|
|
|
:total="count"
|
|
|
|
|
:page-sizes="[10, 20]"
|
|
|
|
|
layout="total, sizes, prev, pager, next, jumper" />
|
|
|
|
|
class="pagination-container"
|
|
|
|
|
background
|
|
|
|
|
@size-change="sizeChange" <!-- 每页条数变化事件 -->
|
|
|
|
|
@current-change="currentChange" <!-- 当前页码变化事件 -->
|
|
|
|
|
:current-page="current" <!-- 当前页码 -->
|
|
|
|
|
:page-size="size" <!-- 每页条数 -->
|
|
|
|
|
:total="count" <!-- 总条数 -->
|
|
|
|
|
:page-sizes="[10, 20]" <!-- 可选每页条数 -->
|
|
|
|
|
layout="total, sizes, prev, pager, next, jumper" /> <!-- 分页布局 -->
|
|
|
|
|
</el-card>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import router from '@/router'
|
|
|
|
|
import router from '@/router' // 导入路由实例
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
// 页面创建时执行的钩子函数
|
|
|
|
|
created() {
|
|
|
|
|
// 从Vuex中获取保存的当前页码,用于页面刷新后保持分页状态
|
|
|
|
|
this.current = this.$store.state.pageState.online
|
|
|
|
|
// 加载在线用户列表数据
|
|
|
|
|
this.listOnlineUsers()
|
|
|
|
|
},
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
loading: true,
|
|
|
|
|
users: [],
|
|
|
|
|
keywords: null,
|
|
|
|
|
current: 1,
|
|
|
|
|
size: 10,
|
|
|
|
|
count: 0,
|
|
|
|
|
isCheck: false,
|
|
|
|
|
optLog: {}
|
|
|
|
|
loading: true, // 表格加载状态
|
|
|
|
|
users: [], // 在线用户列表数据
|
|
|
|
|
keywords: null, // 搜索关键词(用户昵称)
|
|
|
|
|
current: 1, // 当前页码
|
|
|
|
|
size: 10, // 每页显示条数
|
|
|
|
|
count: 0, // 总记录数
|
|
|
|
|
isCheck: false, // 未使用的复选状态标识
|
|
|
|
|
optLog: {} // 未使用的操作日志对象
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
// 获取在线用户列表数据
|
|
|
|
|
listOnlineUsers() {
|
|
|
|
|
this.axios
|
|
|
|
|
.get('/api/admin/users/online', {
|
|
|
|
|
params: {
|
|
|
|
|
current: this.current,
|
|
|
|
|
size: this.size,
|
|
|
|
|
keywords: this.keywords
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.then(({ data }) => {
|
|
|
|
|
this.users = data.data.records
|
|
|
|
|
this.count = data.data.count
|
|
|
|
|
this.loading = false
|
|
|
|
|
})
|
|
|
|
|
.get('/api/admin/users/online', {
|
|
|
|
|
params: {
|
|
|
|
|
current: this.current, // 当前页码
|
|
|
|
|
size: this.size, // 每页条数
|
|
|
|
|
keywords: this.keywords // 搜索关键词
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.then(({ data }) => {
|
|
|
|
|
this.users = data.data.records // 赋值在线用户列表
|
|
|
|
|
this.count = data.data.count // 赋值总记录数
|
|
|
|
|
this.loading = false // 关闭加载状态
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 每页条数变化时触发
|
|
|
|
|
sizeChange(size) {
|
|
|
|
|
this.size = size
|
|
|
|
|
this.listOnlineUsers()
|
|
|
|
|
this.size = size // 更新每页条数
|
|
|
|
|
this.listOnlineUsers() // 重新加载列表
|
|
|
|
|
},
|
|
|
|
|
// 当前页码变化时触发
|
|
|
|
|
currentChange(current) {
|
|
|
|
|
this.current = current
|
|
|
|
|
this.current = current // 更新当前页码
|
|
|
|
|
// 将当前页码保存到Vuex,用于页面刷新后恢复
|
|
|
|
|
this.$store.commit('updateOnlinePageState', current)
|
|
|
|
|
this.listOnlineUsers()
|
|
|
|
|
this.listOnlineUsers() // 重新加载列表
|
|
|
|
|
},
|
|
|
|
|
// 下线指定用户
|
|
|
|
|
removeOnlineUser(user) {
|
|
|
|
|
this.axios.delete('/api/admin/users/' + user.userInfoId + '/online').then(({ data }) => {
|
|
|
|
|
if (data.flag) {
|
|
|
|
|
if (data.flag) { // 下线成功
|
|
|
|
|
this.$notify.success({
|
|
|
|
|
title: '成功',
|
|
|
|
|
message: data.message
|
|
|
|
|
})
|
|
|
|
|
// 如果下线的是当前登录用户,跳转至登录页并清除token
|
|
|
|
|
if (user.userInfoId == this.$store.state.userInfo.id) {
|
|
|
|
|
router.push({ path: '/login' })
|
|
|
|
|
sessionStorage.removeItem('token')
|
|
|
|
|
}
|
|
|
|
|
this.listOnlineUsers()
|
|
|
|
|
} else {
|
|
|
|
|
this.listOnlineUsers() // 重新加载列表
|
|
|
|
|
} else { // 下线失败
|
|
|
|
|
this.$notify.error({
|
|
|
|
|
title: '失败',
|
|
|
|
|
message: data.message
|
|
|
|
|
@ -121,6 +159,7 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
// 未使用的标签类型计算属性(可能为预留功能)
|
|
|
|
|
tagType() {
|
|
|
|
|
return function (type) {
|
|
|
|
|
switch (type) {
|
|
|
|
|
@ -140,7 +179,8 @@ export default {
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
/* 标签样式,设置为粗体 */
|
|
|
|
|
label {
|
|
|
|
|
font-weight: bold !important;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</style>
|