feat: 主机连接日志.

This commit is contained in:
lijiahang
2023-12-27 12:31:18 +08:00
parent 459002f666
commit 6fdd29b3fe
18 changed files with 147 additions and 97 deletions

View File

@@ -11,8 +11,10 @@ Authorization: {{token}}
"type": "",
"token": "",
"status": "",
"startTimeStart": "",
"endTimeEnd": ""
"startTimeRange": [
"",
""
]
}

View File

@@ -36,6 +36,10 @@ public class HostConnectLogDO extends BaseDO {
@TableField("user_id")
private Long userId;
@Schema(description = "用户名")
@TableField("username")
private String username;
@Schema(description = "主机id")
@TableField("host_id")
private Long hostId;

View File

@@ -24,9 +24,18 @@ public class HostConnectLogCreateRequest extends PageRequest {
@Schema(description = "用户id")
private Long userId;
@Schema(description = "用户名")
private String username;
@Schema(description = "主机id")
private Long hostId;
@Schema(description = "主机名称")
private String hostName;
@Schema(description = "主机地址")
private String hostAddress;
@Size(max = 128)
@Schema(description = "token")
private String token;

View File

@@ -45,12 +45,8 @@ public class HostConnectLogQueryRequest extends PageRequest {
@Schema(description = "状态")
private String status;
@Schema(description = "开始时间-区间")
@Schema(description = "开始时间-区间")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date startTimeStart;
@Schema(description = "开始时间-闭区间")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date startTimeEnd;
private Date[] startTimeRange;
}

View File

@@ -31,6 +31,9 @@ public class HostConnectLogVO implements Serializable {
@Schema(description = "用户id")
private Long userId;
@Schema(description = "用户名")
private String username;
@Schema(description = "主机id")
private Long hostId;

View File

@@ -2,6 +2,7 @@ package com.orion.ops.module.asset.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.lang.define.wrapper.DataGrid;
import com.orion.lang.utils.Arrays1;
import com.orion.ops.framework.mybatis.core.query.Conditions;
import com.orion.ops.module.asset.convert.HostConnectLogConvert;
import com.orion.ops.module.asset.dao.HostConnectLogDAO;
@@ -74,8 +75,8 @@ public class HostConnectLogServiceImpl implements HostConnectLogService {
.eq(HostConnectLogDO::getType, request.getType())
.like(HostConnectLogDO::getToken, request.getToken())
.eq(HostConnectLogDO::getStatus, request.getStatus())
.ge(HostConnectLogDO::getStartTime, request.getStartTimeStart())
.le(HostConnectLogDO::getStartTime, request.getStartTimeEnd());
.ge(HostConnectLogDO::getStartTime, Arrays1.getIfPresent(request.getStartTimeRange(), 0))
.le(HostConnectLogDO::getStartTime, Arrays1.getIfPresent(request.getStartTimeRange(), 1));
}
}

View File

@@ -6,6 +6,7 @@
<resultMap id="BaseResultMap" type="com.orion.ops.module.asset.entity.domain.HostConnectLogDO">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="username" property="username"/>
<result column="host_id" property="hostId"/>
<result column="host_name" property="hostName"/>
<result column="host_address" property="hostAddress"/>
@@ -22,7 +23,7 @@
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, user_id, host_id, host_name, host_address, type, token, status, start_time, end_time, extra_info, create_time, update_time, deleted
id, user_id, username, host_id, host_name, host_address, type, token, status, start_time, end_time, extra_info, create_time, update_time, deleted
</sql>
</mapper>

View File

@@ -44,12 +44,8 @@ public class OperatorLogQueryRequest extends PageRequest {
@Schema(description = "操作结果 0失败 1成功")
private Integer result;
@Schema(description = "开始时间-区间")
@Schema(description = "开始时间-区间")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date startTimeStart;
@Schema(description = "开始时间-闭区间")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date startTimeEnd;
private Date[] startTimeRange;
}

View File

@@ -2,6 +2,7 @@ package com.orion.ops.module.infra.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.lang.define.wrapper.DataGrid;
import com.orion.lang.utils.Arrays1;
import com.orion.ops.framework.biz.operator.log.core.model.OperatorLogModel;
import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.module.infra.convert.OperatorLogConvert;
@@ -77,8 +78,8 @@ public class OperatorLogServiceImpl implements OperatorLogService {
.eq(OperatorLogDO::getModule, request.getModule())
.eq(OperatorLogDO::getType, request.getType())
.eq(OperatorLogDO::getResult, request.getResult())
.ge(OperatorLogDO::getStartTime, request.getStartTimeStart())
.le(OperatorLogDO::getStartTime, request.getStartTimeEnd())
.ge(OperatorLogDO::getStartTime, Arrays1.getIfPresent(request.getStartTimeRange(), 0))
.le(OperatorLogDO::getStartTime, Arrays1.getIfPresent(request.getStartTimeRange(), 1))
.orderByDesc(OperatorLogDO::getId);
}

View File

@@ -12,8 +12,7 @@ export interface HostConnectLogQueryRequest extends Pagination {
type?: string;
token?: string;
status?: string;
startTimeStart?: string;
startTimeEnd?: string;
startTimeRange?: string[];
}
/**

View File

@@ -11,8 +11,7 @@ export interface OperatorLogQueryRequest extends Pagination {
type?: string;
riskLevel?: string;
result?: number;
startTimeStart?: string;
startTimeEnd?: string;
startTimeRange?: string[];
}
/**

View File

@@ -0,0 +1,65 @@
<template>
<a-select v-model:model-value="value"
:options="optionData"
:loading="loading"
placeholder="请选择主机"
allow-clear />
</template>
<script lang="ts">
export default {
name: 'host-selector'
};
</script>
<script lang="ts" setup>
import type { SelectOptionData } from '@arco-design/web-vue';
import { computed, onBeforeMount, ref } from 'vue';
import { useCacheStore } from '@/store';
import useLoading from '@/hooks/loading';
const props = defineProps({
modelValue: Number
});
const emits = defineEmits(['update:modelValue']);
const { loading, setLoading } = useLoading();
const cacheStore = useCacheStore();
const value = computed<number>({
get() {
return props.modelValue as number;
},
set(e) {
if (e) {
emits('update:modelValue', e);
} else {
emits('update:modelValue', null);
}
}
});
const optionData = ref<Array<SelectOptionData>>([]);
// 初始化选项
onBeforeMount(async () => {
setLoading(true);
try {
const hosts = await cacheStore.loadHosts();
optionData.value = hosts.map(s => {
return {
label: `${s.name} - ${s.address}`,
value: s.id,
};
});
} catch (e) {
} finally {
setLoading(false);
}
});
</script>
<style lang="less" scoped>
</style>

View File

@@ -15,11 +15,13 @@
</template>
<!-- 数据 -->
<template #item="{ item }">
<a-list-item :title="`${item.name}(${item.code}) - ${item.address}`">
<icon-desktop class="host-list-icon" />
<span>{{ `${item.name}(${item.code}) - ` }}</span>
<span class="span-blue">{{ item.address }}</span>
</a-list-item>
<a-tooltip :content="`${item.name} - ${item.address}`">
<a-list-item>
<icon-desktop class="host-list-icon" />
<span>{{ `${item.name} - ` }}</span>
<span class="span-blue">{{ item.address }}</span>
</a-list-item>
</a-tooltip>
</template>
</a-list>
</template>

View File

@@ -3,21 +3,21 @@
<a-card class="general-card table-search-card">
<a-query-header :model="formModel"
label-align="left"
:itemOptions="{ 5: { span: 2 } }"
@submit="fetchTableData"
@reset="reset"
@reset="fetchTableData"
@keyup.enter="() => fetchTableData()">
<!-- 用户 -->
<a-form-item field="userId" label="用户" label-col-flex="50px">
<!-- 连接用户 -->
<a-form-item field="userId" label="连接用户" label-col-flex="50px">
<user-selector v-model="formModel.userId"
placeholder="请选择用户"
allow-clear />
</a-form-item>
<!-- 主机 -->
<a-form-item field="hostId" label="主机" label-col-flex="50px">
<a-input-number v-model="formModel.hostId"
placeholder="FIXME 请输入主机"
allow-clear
hide-button />
<!-- 连接主机 -->
<a-form-item field="hostId" label="连接主机" label-col-flex="50px">
<host-selector v-model="formModel.hostId"
placeholder="请选择主机"
allow-clear />
</a-form-item>
<!-- 主机地址 -->
<a-form-item field="hostAddress" label="主机地址" label-col-flex="50px">
@@ -35,12 +35,12 @@
<a-input v-model="formModel.token" placeholder="请输入token" allow-clear />
</a-form-item>
<!-- 开始时间 -->
<a-form-item field="startTime" label="开始时间" label-col-flex="50px">
<a-range-picker v-model="timeRange"
<a-form-item field="startTimeRange" label="开始时间" label-col-flex="50px">
<a-range-picker v-model="formModel.startTimeRange"
style="width: 100%"
:time-picker-props="{ defaultValue: ['00:00:00', '23:59:59'] }"
show-time
format="YYYY-MM-DD HH:mm:ss"
@ok="timeRangePicked" />
format="YYYY-MM-DD HH:mm:ss" />
</a-form-item>
</a-query-header>
</a-card>
@@ -69,6 +69,14 @@
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
@page-size-change="(size) => fetchTableData(1, size)"
:bordered="false">
<!-- 连接用户 -->
<template #username="{ record }">
{{ record.userId }} - {{ record.username }}
</template>
<!-- 连接主机 -->
<template #hostName="{ record }">
{{ record.hostId }} - {{ record.hostName }}
</template>
<!-- 主机地址 -->
<template #hostAddress="{ record }">
<span class="copy-left" title="复制" @click="copy(record.hostAddress)">
@@ -104,6 +112,7 @@
import { useDictStore } from '@/store';
import useCopy from '@/hooks/copy';
import UserSelector from '@/components/user/user/user-selector.vue';
import HostSelector from '@/components/asset/host/host-selector.vue';
const emits = defineEmits(['openAdd', 'openUpdate']);
@@ -114,7 +123,6 @@
const { toOptions, getDictValue } = useDictStore();
const { copy } = useCopy();
const timeRange = ref<string[]>([]);
const formModel = reactive<HostConnectLogQueryRequest>({
userId: undefined,
hostId: undefined,
@@ -122,16 +130,9 @@
type: undefined,
token: undefined,
status: undefined,
startTimeStart: undefined,
startTimeEnd: undefined,
startTimeRange: undefined,
});
// 选择时间
const timeRangePicked = (e: string[]) => {
formModel.startTimeStart = e[0];
formModel.startTimeEnd = e[1];
};
// 加载数据
const doFetchTableData = async (request: HostConnectLogQueryRequest) => {
try {
@@ -152,14 +153,6 @@
doFetchTableData({ page, limit, ...form });
};
// 重置
const reset = () => {
timeRange.value = [];
formModel.startTimeStart = undefined;
formModel.startTimeEnd = undefined;
fetchTableData();
};
onMounted(() => {
fetchTableData();
});

View File

@@ -10,19 +10,14 @@ const columns = [
align: 'left',
fixed: 'left',
}, {
title: '用户id',
dataIndex: 'userId',
slotName: 'userId',
width: 110,
title: '连接用户',
dataIndex: 'username',
slotName: 'username',
align: 'left',
ellipsis: true,
tooltip: true,
}, {
title: '主机id',
dataIndex: 'hostId',
slotName: 'hostId',
width: 110,
align: 'left',
}, {
title: '主机名称',
title: '连接主机',
dataIndex: 'hostName',
slotName: 'hostName',
align: 'left',
@@ -48,8 +43,7 @@ const columns = [
dataIndex: 'status',
slotName: 'status',
align: 'left',
ellipsis: true,
tooltip: true,
width: 90,
}, {
title: '开始时间',
dataIndex: 'startTime',

View File

@@ -94,8 +94,8 @@
const renderLabel = (label: string) => {
const last = label.lastIndexOf('-');
const prefix = label.substring(0, last - 1);
const ip = label.substring(last + 2, label.length);
return `${prefix} - <span class="span-blue">${ip}</span>`;
const address = label.substring(last + 2, label.length);
return `${prefix} - <span class="span-blue">${address}</span>`;
};
// 查询组内数据
@@ -121,7 +121,7 @@
data.value = hosts.map(s => {
return {
value: String(s.id),
label: `${s.name} (${s.code}) - ${s.address}`,
label: `${s.name} - ${s.address}`,
disabled: false
};
});

View File

@@ -33,7 +33,7 @@
<!-- 返回 -->
<a-tab-pane key="back" v-if="userId">
<template #title>
<icon-arrow-left style="font-size: 16px" />
<icon-left style="font-size: 16px; padding-top: 2px;" />
返回
</template>
</a-tab-pane>

View File

@@ -1,8 +1,9 @@
<template>
<a-query-header :model="formModel"
label-align="left"
:itemOptions="{ [visibleUser ? 5 : 4]: { span: 2 } }"
@submit="submit"
@reset="reset"
@reset="submit"
@keyup.enter="submit">
<!-- 操作用户 -->
<a-form-item v-if="visibleUser"
@@ -47,12 +48,12 @@
allow-clear />
</a-form-item>
<!-- 执行时间 -->
<a-form-item field="startTime" label="执行时间" label-col-flex="50px">
<a-range-picker v-model="timeRange"
<a-form-item field="startTimeRange" label="执行时间" label-col-flex="50px">
<a-range-picker v-model="formModel.startTimeRange"
style="width: 100%"
:time-picker-props="{ defaultValue: ['00:00:00', '23:59:59'] }"
show-time
format="YYYY-MM-DD HH:mm:ss"
@ok="timeRangePicked" />
format="YYYY-MM-DD HH:mm:ss" />
</a-form-item>
</a-query-header>
</template>
@@ -84,23 +85,15 @@
const { loading, setLoading } = useLoading();
const { $state: dictState, toOptions } = useDictStore();
const timeRange = ref<string[]>([]);
const typeOptions = ref<SelectOptionData[]>(toOptions(operatorLogTypeKey));
const formModel = reactive<OperatorLogQueryRequest>({
module: undefined,
type: undefined,
riskLevel: undefined,
result: undefined,
startTimeStart: undefined,
startTimeEnd: undefined,
startTimeRange: undefined,
});
// 选择时间
const timeRangePicked = (e: string[]) => {
formModel.startTimeStart = e[0];
formModel.startTimeEnd = e[1];
};
// 选择类型
const selectedModule = (module: string) => {
if (!module) {
@@ -118,14 +111,6 @@
}
};
// 重置
const reset = () => {
timeRange.value = [];
formModel.startTimeStart = undefined;
formModel.startTimeEnd = undefined;
submit();
};
// 切换页码
const submit = () => {
emits('submit', { ...formModel });