mirror of
https://gitee.com/bootx/dax-pay-ui.git
synced 2025-09-04 03:16:02 +00:00
feat 登录日志
This commit is contained in:
@@ -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],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
51
src/views/modules/monitor/login/LoginLog.api.ts
Normal file
51
src/views/modules/monitor/login/LoginLog.api.ts
Normal 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
|
||||
}
|
62
src/views/modules/monitor/login/LoginLogInfo.vue
Normal file
62
src/views/modules/monitor/login/LoginLogInfo.vue
Normal 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>
|
140
src/views/modules/monitor/login/LoginLogList.vue
Normal file
140
src/views/modules/monitor/login/LoginLogList.vue
Normal 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>
|
Reference in New Issue
Block a user