refactor: user login log list for admin is ready

This commit is contained in:
RockYang 2023-06-21 06:53:41 +08:00
parent feff1684c4
commit 0e6606e469
9 changed files with 170 additions and 26 deletions

View File

@ -8,9 +8,10 @@ import (
"chatplus/store/vo" "chatplus/store/vo"
"chatplus/utils" "chatplus/utils"
"chatplus/utils/resp" "chatplus/utils/resp"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
"time"
) )
type ApiKeyHandler struct { type ApiKeyHandler struct {
@ -61,7 +62,7 @@ func (h *ApiKeyHandler) Save(c *gin.Context) {
func (h *ApiKeyHandler) List(c *gin.Context) { func (h *ApiKeyHandler) List(c *gin.Context) {
userId := h.GetInt(c, "user_id", -1) userId := h.GetInt(c, "user_id", -1)
query := h.db.Debug().Session(&gorm.Session{}) query := h.db.Session(&gorm.Session{})
if userId >= 0 { if userId >= 0 {
query = query.Where("user_id", userId) query = query.Where("user_id", userId)
} }

View File

@ -118,6 +118,32 @@ func (h *UserHandler) Remove(c *gin.Context) {
resp.SUCCESS(c) resp.SUCCESS(c)
} }
func (h *UserHandler) LoginLog(c *gin.Context) {
page := h.GetInt(c, "page", 1)
pageSize := h.GetInt(c, "page_size", 20)
var total int64
h.db.Model(&model.UserLoginLog{}).Count(&total)
offset := (page - 1) * pageSize
var items []model.UserLoginLog
res := h.db.Offset(offset).Limit(pageSize).Find(&items)
if res.Error != nil {
resp.ERROR(c, "获取数据失败")
return
}
var logs []vo.UserLoginLog
for _, v := range items {
var log vo.UserLoginLog
err := utils.CopyObject(v, &log)
if err == nil {
log.Id = v.Id
log.CreatedAt = v.CreatedAt.Unix()
logs = append(logs, log)
}
}
resp.SUCCESS(c, vo.NewPage(total, page, pageSize, logs))
}
func (h *UserHandler) InitUser(c *gin.Context) { func (h *UserHandler) InitUser(c *gin.Context) {
var users []model.User var users []model.User
h.db.Find(&users) h.db.Find(&users)

View File

@ -137,6 +137,7 @@ func main() {
group.GET("list", h.List) group.GET("list", h.List)
group.POST("update", h.Update) group.POST("update", h.Update)
group.GET("remove", h.Remove) group.GET("remove", h.Remove)
group.GET("loginLog", h.LoginLog)
group.GET("test", h.InitUser) group.GET("test", h.InitUser)
}), }),
fx.Invoke(func(s *core.AppServer, h *admin.ChatRoleHandler) { fx.Invoke(func(s *core.AppServer, h *admin.ChatRoleHandler) {

View File

@ -0,0 +1,9 @@
package vo
type UserLoginLog struct {
BaseVo
UserId uint `json:"user_id"`
Username string `json:"username"`
LoginIp string `json:"login_ip"`
LoginAddress string `json:"login_address"`
}

View File

@ -87,6 +87,9 @@
<el-tab-pane label="API KEY" name="apikey" v-if="arrayContains(tabs, 'apikey')"> <el-tab-pane label="API KEY" name="apikey" v-if="arrayContains(tabs, 'apikey')">
<api-key v-if="curTab==='apikey'"/> <api-key v-if="curTab==='apikey'"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="登录日志" name="loginLog" v-if="arrayContains(tabs, 'loginLog')">
<login-log v-if="curTab==='loginLog'"/>
</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
</div> </div>
@ -108,10 +111,10 @@ import {httpGet} from "@/utils/http";
import {ElMessage} from "element-plus"; import {ElMessage} from "element-plus";
import {useRouter} from "vue-router"; import {useRouter} from "vue-router";
import ApiKey from "@/views/admin/ApiKey.vue"; import ApiKey from "@/views/admin/ApiKey.vue";
import LoginLog from "@/views/admin/LoginLog.vue";
const title = ref('Chat-Plus 控制台') const title = ref('Chat-Plus 控制台')
const logo = ref('images/logo.png') const logo = ref('images/logo.png')
const user = ref({})
const navs = ref([ const navs = ref([
{ {
id: 1, id: 1,
@ -136,6 +139,12 @@ const navs = ref([
title: 'API KEY', title: 'API KEY',
tab: 'apikey', tab: 'apikey',
active: false, active: false,
},
{
id: 5,
title: '登录日志',
tab: 'loginLog',
active: false,
} }
]) ])
const tabs = ref([]) const tabs = ref([])
@ -155,22 +164,22 @@ const nodeListPaddingLeft = computed(() => {
}) })
const router = useRouter() const router = useRouter()
onMounted(() => { //
window.addEventListener("resize", function () { httpGet("/api/admin/session").then(() => {
winHeight.value = window.innerHeight
})
//
httpGet("/api/admin/session").catch(() => {
router.push('/admin/login')
})
// //
httpGet('/api/admin/config/get?key=system').then(res => { httpGet('/api/admin/config/get?key=system').then(res => {
title.value = res.data['admin_title']; title.value = res.data['admin_title'];
}).catch(e => { }).catch(e => {
ElMessage.error("加载系统配置失败: " + e.message) ElMessage.error("加载系统配置失败: " + e.message)
}) })
}).catch(() => {
router.push('/admin/login')
})
onMounted(() => {
window.addEventListener("resize", function () {
winHeight.value = window.innerHeight
})
}) })
const logout = function () { const logout = function () {
@ -354,3 +363,12 @@ $borderColor = #4676d0;
</style> </style>
<style lang="stylus">
.pagination {
padding 20px;
display flex
justify-content center
width 100%
}
</style>

View File

@ -1,11 +1,11 @@
<template> <template>
<div class="list" v-loading="loading"> <div class="list" v-loading="loading">
<el-row class="opt-box"> <el-row class="opt-box">
<el-button type="primary" @click="add"> <el-button type="primary" @click="add" size="small">
<el-icon> <el-icon>
<Plus/> <Plus/>
</el-icon> </el-icon>
新增角色 新增
</el-button> </el-button>
</el-row> </el-row>
@ -150,6 +150,8 @@ const remove = function (row) {
.opt-box { .opt-box {
padding-bottom: 10px; padding-bottom: 10px;
display flex;
justify-content end
.el-icon { .el-icon {
margin-right: 5px; margin-right: 5px;

View File

@ -0,0 +1,92 @@
<template>
<div class="list" v-loading="loading">
<el-row>
<el-table :data="items" :row-key="row => row.id">
<el-table-column label="用户名" prop="username"/>
<el-table-column label="登录IP" prop="login_ip"/>
<el-table-column label="登录地址" prop="login_address"/>
<el-table-column label="登录时间">
<template #default="scope">
<span>{{ dateFormat(scope.row['created_at']) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template #default="scope">
<el-popconfirm title="确定要删除当前记录吗?" @confirm="remove(scope.row)">
<template #reference>
<el-button size="small" type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-row>
<div class="pagination">
<el-pagination v-if="total > 0" background
layout="prev, pager, next"
:hide-on-single-page="true"
v-model:current-page="page"
v-model:page-size="pageSize"
@current-change="fetchList(page, pageSize)"
:total="total"/>
</div>
</div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import {httpGet} from "@/utils/http";
import {ElMessage} from "element-plus";
import {dateFormat} from "@/utils/libs";
//
const items = ref([])
const loading = ref(true)
const total = ref(0)
const page = ref(0)
const pageSize = ref(0)
onMounted(() => {
fetchList(1, 15)
})
//
const fetchList = function (_page, _pageSize) {
console.log(_page, _pageSize)
httpGet(`/api/admin/user/loginLog?page=${_page}&page_size=${_pageSize}`).then((res) => {
if (res.data) {
items.value = res.data.items
total.value = res.data.total
page.value = res.data.page
pageSize.value = res.data.page_size
}
loading.value = false
}).catch(() => {
ElMessage.error("获取数据失败");
})
}
</script>
<style lang="stylus" scoped>
.list {
.opt-box {
padding-bottom: 10px;
display flex;
justify-content end
.el-icon {
margin-right: 5px;
}
}
.el-select {
width: 100%
}
}
</style>

View File

@ -1,11 +1,11 @@
<template> <template>
<div class="role-list"> <div class="role-list">
<el-row class="opt-box"> <el-row class="opt-box">
<el-button type="primary" @click="addRole"> <el-button type="primary" @click="addRole" size="small">
<el-icon> <el-icon>
<Plus/> <Plus/>
</el-icon> </el-icon>
新增角色 新增
</el-button> </el-button>
</el-row> </el-row>
@ -292,6 +292,8 @@ const removeContext = function (index) {
.role-list { .role-list {
.opt-box { .opt-box {
padding-bottom: 10px; padding-bottom: 10px;
display flex;
justify-content end
.el-icon { .el-icon {
margin-right 5px; margin-right 5px;

View File

@ -39,7 +39,7 @@
:hide-on-single-page="true" :hide-on-single-page="true"
v-model:current-page="users.page" v-model:current-page="users.page"
v-model:page-size="users.page_size" v-model:page-size="users.page_size"
@update:current-change="fetchUserList(users.page, users.page_size)" @current-change="fetchUserList(users.page, users.page_size)"
:total="users.total"/> :total="users.total"/>
</div> </div>
@ -126,7 +126,7 @@ const loading = ref(true)
const userEditFormRef = ref(null) const userEditFormRef = ref(null)
onMounted(() => { onMounted(() => {
fetchUserList(1, 20) fetchUserList(1, 10)
// //
httpGet('/api/admin/role/list').then((res) => { httpGet('/api/admin/role/list').then((res) => {
roles.value = res.data; roles.value = res.data;
@ -219,13 +219,6 @@ const handleSelectionChange = function (rows) {
} }
} }
.pagination {
padding-top 20px;
display flex
justify-content center
width 100%
}
.el-select { .el-select {
width: 100% width: 100%
} }