feat 登录日志

This commit is contained in:
xxm
2022-10-21 17:53:00 +08:00
parent fc085f9675
commit e5b1b50011
4 changed files with 287 additions and 0 deletions

View File

@@ -1,3 +1,5 @@
import { unref } from 'vue'
/**
* 树形数据转换
* @param data 数据
@@ -28,3 +30,35 @@ interface Tree {
value: unknown
children: undefined | unknown[] | null
}
/**
* 从列表中获取指定的对象
* @param list 列表
* @param fieldValue 要查询的字段值
* @param fieldName 字段名称
*/
export function findOneByField(list: any[], fieldValue: object, fieldName: string) {
const item = unref(list)?.filter((o) => {
return o[fieldName] === fieldValue
})
if (item && item.length > 0) {
return item[0]
} else {
return null
}
}
/**
* 转换成下拉框数据格式
* @param list 数据列表
* @param labelName label名称
* @param valueName 值名称
*/
export function dropdownTranslate(list: any[], labelName: string, valueName: string) {
return unref(list)?.map((o) => {
return {
label: o[labelName],
value: o[valueName],
}
})
}

View File

@@ -0,0 +1,51 @@
import { defHttp } from '/@/utils/http/axios'
import { PageResult, Result } from '/#/axios'
import { BaseEntity } from '/#/web'
/**
* 分页
*/
export const page = (params) => {
return defHttp.get<Result<PageResult<LoginLog>>>({
url: '/log/login/page',
params,
})
}
/**
* 获取单条
*/
export const get = (id) => {
return defHttp.get<Result<LoginLog>>({
url: '/log/login/findById',
params: { id },
})
}
/**
* 登陆日志
*/
export interface LoginLog extends BaseEntity {
// 用户id
userId: number
// 用户名称
account: string
// 登录成功状态
login: boolean
// 终端
client: string
// 登录方式
loginType: string
// 登录IP地址
ip: string
// 登录地点
loginLocation: string
// 操作系统
os: string
// 浏览器类型
browser: string
// 提示消息
msg: string
// 访问时间
loginTime: string
}

View File

@@ -0,0 +1,62 @@
<template>
<basic-modal v-bind="$attrs" :loading="confirmLoading" width="50%" title="查看" :visible="visible" @cancel="visible = false">
<description :column="2" :data="data" :schema="schema" />
<template #footer>
<a-button key="cancel" @click="visible = false">取消</a-button>
</template>
</basic-modal>
</template>
<script lang="ts" setup>
import { Description } from '/@/components/Description'
import { Client } from '/@/views/modules/system/client/Client.api'
import { $ref } from 'vue/macros'
import { get, LoginLog } from './LoginLog.api'
import { DescItem } from '/@/components/Description'
import BasicModal from '/@/components/Modal/src/BasicModal.vue'
import { LoginType } from '/@/views/modules/system/loginType/LoginType.api'
import { findOneByField } from '/@/utils/dataUtil'
const props = defineProps<{
clients: Client[]
loginTypes: LoginType[]
}>()
let data = $ref<LoginLog>()
let visible = $ref(false)
let confirmLoading = $ref(false)
let schema = [
{ field: 'id', label: '主键' },
{ field: 'account', label: '登录账号' },
{ field: 'login', label: '登录成功状态', render: (curVal) => (curVal ? '成功' : '失败') },
{ field: 'client', label: '登录终端', render: (curVal) => getClient(curVal) },
{ field: 'loginType', label: '登录方式', render: (curVal) => getLoginType(curVal) },
{ field: 'ip', label: '登录IP地址' },
{ field: 'browser', label: '浏览器类型' },
{ field: 'os', label: '操作系统' },
{ field: 'msg', label: '提示消息' },
{ field: 'loginTime', label: '访问时间' },
] as DescItem[]
function show(id) {
visible = true
confirmLoading = true
get(id).then((res) => {
data = res.data
confirmLoading = false
})
}
// 获取终端信息
function getClient(code) {
return findOneByField(props.clients, code, 'code')?.['name']
}
// 获取登录方式信息
function getLoginType(code) {
return findOneByField(props.loginTypes, code, 'code')?.['name']
}
defineExpose({
show,
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,140 @@
<template>
<div>
<div class="m-3 p-3 pt-5 bg-white">
<b-query :query-params="model.queryParam" :fields="fields" @query="queryPage" @reset="resetQueryParams" />
</div>
<div class="m-3 p-3 bg-white">
<vxe-toolbar ref="xToolbar" custom :refresh="{ query: queryPage }" />
<vxe-table row-id="id" ref="xTable" :data="pagination.records" :loading="loading">
<vxe-column type="seq" width="60" />
<vxe-column field="userId" title="用户id" />
<vxe-column field="account" title="用户名称" />
<vxe-column field="login" title="登录成功状态">
<template #default="{ row }">
<a-tag v-if="row.login" color="green">成功</a-tag>
<a-tag v-else color="red">失败</a-tag>
</template>
</vxe-column>
<vxe-column field="client" title="终端">
<template #default="{ row }">
{{ getClient(row.client) }}
</template>
</vxe-column>
<vxe-column field="loginType" title="登录方式">
<template #default="{ row }">
{{ getLoginType(row.loginType) }}
</template>
</vxe-column>
<vxe-column field="ip" title="登录IP地址" />
<vxe-column field="os" title="操作系统" />
<vxe-column field="browser" title="浏览器类型" />
<vxe-column field="msg" title="提示消息" />
<vxe-column field="loginTime" title="访问时间" />
<vxe-column fixed="right" width="60" :showOverflow="false" title="操作">
<template #default="{ row }">
<span>
<a href="javascript:" @click="show(row)">查看</a>
</span>
</template>
</vxe-column>
</vxe-table>
<vxe-pager
size="medium"
:loading="loading"
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@page-change="handleTableChange"
/>
<login-log-info :clients="clients" :login-types="loginTypes" ref="loginLogInfo" />
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue'
import { $ref } from 'vue/macros'
import { page } from './LoginLog.api'
import useTablePage from '/@/hooks/bootx/useTablePage'
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
import { useMessage } from '/@/hooks/web/useMessage'
import { QueryField } from '/@/components/Bootx/Query/Query'
import { Client, findAll as findClients } from '/@/views/modules/system/client/Client.api'
import { findAll as findLoginTypes, LoginType } from '/@/views/modules/system/loginType/LoginType.api'
import { dropdownTranslate, findOneByField } from '/@/utils/dataUtil'
import LoginLogInfo from './LoginLogInfo.vue'
// 使用hooks
const { handleTableChange, pageQueryResHandel, resetQueryParams, pagination, pages, model, loading } = useTablePage(queryPage)
const { notification, createMessage } = useMessage()
let clients = $ref<Client[]>()
let loginTypes = $ref<LoginType[]>()
const xTable = $ref<VxeTableInstance>()
const xToolbar = $ref<VxeToolbarInstance>()
const loginLogInfo = $ref<any>()
// 查询条件
const fields = computed(() => {
return [
{ field: 'code', type: 'string', name: '账号', placeholder: '请输入账号名称' },
{ field: 'client', type: 'list', name: '终端', placeholder: '请选择终端', selectList: dropdownTranslate(clients, 'name', 'code') },
{
field: 'loginType',
type: 'list',
name: '登录方式',
placeholder: '请选择登录方式',
selectList: dropdownTranslate(loginTypes, 'name', 'code'),
},
] as QueryField[]
})
onMounted(() => {
vxeBind()
initClientAndLoginType()
queryPage()
})
/**
* 初始化 终端列表和登录方式列表
*/
function initClientAndLoginType() {
findClients().then(({ data }) => {
clients = data
})
findLoginTypes().then(({ data }) => {
loginTypes = data
})
}
function vxeBind() {
xTable.connect(xToolbar)
}
// 分页查询
function queryPage() {
loading.value = true
page({
...model.queryParam,
...pages,
}).then(({ data }) => {
data.records[0].loginTime
pageQueryResHandel(data)
})
}
// 查看
function show(record) {
loginLogInfo.show(record.id)
}
// 获取终端信息
function getClient(code) {
return findOneByField(clients, code, 'code')?.['name']
}
// 获取登录方式信息
function getLoginType(code) {
return findOneByField(loginTypes, code, 'code')?.['name']
}
</script>
<style lang="less" scoped></style>