Files
fe.ems.vue3/src/views/logManage/logSet/index.vue
2023-11-28 21:08:26 +08:00

711 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { reactive, ref, onMounted, toRaw } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { Form, Modal, message } from 'ant-design-vue/lib';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import {
backupDownload,
backupFileList,
backupLog,
exportLog,
getFtpLogSet,
getLogSet,
getRemoteOut,
updateFtpLogSet,
updateLogSet,
updateRemoteOut,
} from '@/api/logManage/logSet';
import { regExpIPv4 } from '@/utils/regular-utils';
import useDictStore from '@/store/modules/dict';
import useI18n from '@/hooks/useI18n';
import saveAs from 'file-saver';
import { writeSheet } from '@/utils/execl-utils';
const { getDict } = useDictStore();
const { t } = useI18n();
/**对象信息状态类型 */
type ModalStateType = {
/**标题 */
title: string;
/**表单数据 */
from: Record<string, any>;
/**表单数据 loading */
fromLoading: boolean;
/**确定按钮 loading */
confirmLoading: boolean;
};
/**日志设置信息状态 */
let logSetState: ModalStateType = reactive({
title: '日志设置',
from: {
logDuration: 15,
logCapacity: 10,
},
fromLoading: true,
confirmLoading: true,
});
/**日志设置信息内表单属性和校验规则 */
const logSetStateFrom = Form.useForm(
logSetState.from,
reactive({
logDuration: [
{
required: true,
trigger: 'blur',
message: '请输入日志保存时间最少15天',
},
],
logCapacity: [
{
required: true,
message: '请输入日志最大容量最小10MB',
},
],
})
);
/**日志设置保存 */
function fnFormLogSetFinish() {
logSetStateFrom.validate().then(() => {
logSetState.confirmLoading = true;
const from = toRaw(logSetState.from);
updateLogSet({
logDuration: from.logDuration,
logCapacity: from.logCapacity,
})
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && res.data > 0) {
message.success(`日志设置保存成功`, 3);
} else {
message.warning(`日志设置无变更`, 3);
}
})
.finally(() => {
logSetState.confirmLoading = false;
});
});
}
/**FTP日志对象信息状态 */
let ftpState: ModalStateType = reactive({
title: 'FTP日志上报接口设置',
from: {
agreement: 'ftp',
directory: '',
ftpLog: 12,
toIp: '',
},
fromLoading: true,
confirmLoading: true,
});
/**FTP日志对象信息内表单属性和校验规则 */
const ftpStateFrom = Form.useForm(
ftpState.from,
reactive({
toIp: [
{
required: true,
pattern: regExpIPv4,
message: '请输入对端IP地址',
},
],
directory: [
{
required: true,
trigger: 'blur',
message: '请输入对端文件目录',
},
],
ftpLog: [
{
required: true,
trigger: 'blur',
message: '请输入日志生成周期最小12小时',
},
],
})
);
/**FTP日志对象保存 */
function fnFormFTPFinish() {
ftpStateFrom.validate().then(() => {
logSetState.confirmLoading = true;
const from = toRaw(ftpState.from);
updateFtpLogSet(from)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success(`FTP日志设置保存成功`, 3);
} else {
message.warning(`FTP日志设置无变更`, 3);
}
})
.finally(() => {
logSetState.confirmLoading = false;
});
});
}
/**日志远程输出对象信息状态 */
let remoteOutState: ModalStateType = reactive({
title: '日志远程输出',
from: {
logIp: '',
logDirectory: '',
},
fromLoading: true,
confirmLoading: true,
});
/**日志远程输出对象信息内表单属性和校验规则 */
const remoteOutStateFrom = Form.useForm(
remoteOutState.from,
reactive({
logIp: [
{
required: true,
pattern: regExpIPv4,
message: '请输入远程IP地址',
},
],
logDirectory: [
{
required: true,
trigger: 'blur',
message: '请输入远程日志目录',
},
],
})
);
/**日志远程输出对象保存 */
function fnFormRemoteOutFinish() {
remoteOutStateFrom.validate().then(() => {
remoteOutState.confirmLoading = true;
const from = toRaw(remoteOutState.from);
updateRemoteOut(from)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success(`日志远程输出设置保存成功`, 3);
} else {
message.warning(`日志远程输出设置无变更`, 3);
}
})
.finally(() => {
remoteOutState.confirmLoading = false;
});
});
}
/**字典数据 */
let dict: {
/**操作日志操作类型 */
operationLogType: DictType[];
} = reactive({
operationLogType: [],
});
/**日志范围开始结束时间 */
let queryRangePicker = ref<[string, string]>(['', '']);
/**开始结束时间选择对应修改 */
function fnRangePickerChange(_: any, item: any) {
logOutState.from.beginTime = item[0];
logOutState.from.endTime = item[1];
}
/**日志导出对象信息状态 */
let logOutState: ModalStateType = reactive({
title: '日志导出',
from: {
logType: 'security_log',
opType: 'View',
beginTime: '',
endTime: '',
},
fromLoading: false,
confirmLoading: false,
});
/**日志导出对象信息内表单属性和校验规则 */
const logOutStateFrom = Form.useForm(
logOutState.from,
reactive({
endTime: [
{
required: true,
message: '请输入日志时间范围',
},
],
})
);
/**日志导出对象保存 */
function fnFormLogOutFinish() {
logOutStateFrom.validate().then(() => {
logOutState.confirmLoading = true;
const from = toRaw(logOutState.from);
const key = 'exportLog';
message.loading({ content: t('common.loading'), key });
exportLog(from)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: `已完成导出`,
key,
duration: 3,
});
writeSheet(res.data, from.logType).then(fileBlob =>
saveAs(fileBlob, `${from.logType}_${Date.now()}.xlsx`)
);
} else {
message.error({
content: `${res.msg}`,
key,
duration: 3,
});
}
})
.finally(() => {
logOutState.confirmLoading = false;
});
});
}
/**日志备份对象信息状态 */
let backState: ModalStateType = reactive({
title: '日志备份',
from: {
logType: 'security_log',
backFileTree: [],
},
fromLoading: true,
confirmLoading: true,
});
/**日志备份对象保存 */
function fnFormBackFinish() {
Modal.confirm({
title: t('common.tipTitle'),
content: `确认手动备份该日志类型数据到文件吗?`,
onOk() {
backState.confirmLoading = true;
const key = 'backupLog';
message.loading({ content: t('common.loading'), key });
backupLog(backState.from.logType)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: `手动备份执行成功记录数:${res.data}`,
key,
duration: 10,
});
fnBackFileList();
} else {
message.error({
content: `${res.msg}`,
key: key,
duration: 3,
});
}
})
.finally(() => {
backState.confirmLoading = false;
});
},
});
}
/**日志手动备份文件列表 */
function fnBackFileList() {
backupFileList().then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
if (res.data.name === '') {
backState.from.backFileTree = [];
} else {
backState.from.backFileTree = [res.data];
}
backState.fromLoading = false;
backState.confirmLoading = false;
}
});
}
/**日志备份文件下载 */
function fnBackDownload(name: string, path: string) {
Modal.confirm({
title: t('common.tipTitle'),
content: `确认下载该文件吗?`,
onOk() {
backState.confirmLoading = true;
const key = 'backupDownload';
message.loading({ content: t('common.loading'), key });
backupDownload(path)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: `已完成下载`,
key,
duration: 3,
});
saveAs(res.data, name);
} else {
message.error({
content: `${res.msg}`,
key,
duration: 3,
});
}
})
.finally(() => {
backState.confirmLoading = false;
});
},
});
}
onMounted(() => {
Promise.allSettled([
getLogSet(),
getFtpLogSet(),
getRemoteOut(),
getDict('operation_log_type'),
fnBackFileList(),
]).then(resArr => {
// 查询日志设置
if (resArr[0].status === 'fulfilled') {
const result = resArr[0].value;
if (result.code === RESULT_CODE_SUCCESS) {
logSetState.from = Object.assign(logSetState.from, result.data);
logSetState.fromLoading = false;
logSetState.confirmLoading = false;
}
}
// 查询FTP日志设置
if (resArr[1].status === 'fulfilled') {
const result = resArr[1].value;
if (result.code === RESULT_CODE_SUCCESS) {
ftpState.from = Object.assign(ftpState.from, result.data);
ftpState.fromLoading = false;
ftpState.confirmLoading = false;
}
}
// 查询日志远程输出设置
if (resArr[2].status === 'fulfilled') {
const result = resArr[2].value;
if (result.code === RESULT_CODE_SUCCESS) {
remoteOutState.from = Object.assign(remoteOutState.from, result.data);
remoteOutState.fromLoading = false;
remoteOutState.confirmLoading = false;
}
}
// 初始字典数据 日志导出-操作日志
if (resArr[3].status === 'fulfilled') {
dict.operationLogType = resArr[3].value;
}
});
});
</script>
<template>
<PageContainer>
<a-row :gutter="16">
<a-col :span="8">
<!-- 日志设置 -->
<a-card :title="logSetState.title" :loading="logSetState.fromLoading">
<template #extra>
<a-space :size="8" align="center">
<a-button
type="primary"
:loading="logSetState.confirmLoading"
@click.prevent="fnFormLogSetFinish"
>
<template #icon><SaveOutlined /></template>
保存设置
</a-button>
</a-space>
</template>
<a-form
name="logSetState.from"
layout="horizontal"
autocomplete="off"
:label-col="{ span: 8 }"
>
<a-form-item
label="日志保存时间(天)"
name="logDuration"
v-bind="logSetStateFrom.validateInfos.logDuration"
>
<a-input-number
v-model:value="logSetState.from.logDuration"
placeholder="15"
:min="15"
/>
</a-form-item>
<a-form-item
label="日志最大容量(MB)"
name="logCapacity"
v-bind="logSetStateFrom.validateInfos.logCapacity"
>
<a-input-number
v-model:value="logSetState.from.logCapacity"
placeholder="10"
:min="10"
/>
</a-form-item>
</a-form>
</a-card>
<!-- 日志导出 -->
<a-card
:title="logOutState.title"
:loading="logOutState.fromLoading"
style="margin-top: 16px"
>
<template #extra>
<a-space :size="8" align="center">
<a-button
type="primary"
:loading="logOutState.confirmLoading"
@click.prevent="fnFormLogOutFinish"
>
<template #icon><ExportOutlined /></template>
导出
</a-button>
</a-space>
</template>
<a-form
name="logOutState.from"
layout="horizontal"
autocomplete="off"
:label-col="{ span: 5 }"
>
<a-form-item label="日志类型" name="logType">
<a-select v-model:value="logOutState.from.logType">
<a-select-option key="operation_log" value="operation_log">
操作日志
</a-select-option>
<a-select-option key="alarm_log" value="alarm_log">
告警日志
</a-select-option>
<a-select-option key="security_log" value="security_log">
安全日志
</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="操作类型"
name="opType"
v-show="logOutState.from.logType === 'operation_log'"
>
<a-select
v-model:value="logOutState.from.opType"
placeholder="请选择操作类型"
:options="dict.operationLogType"
>
</a-select>
</a-form-item>
<a-form-item
label="时间范围"
name="queryRangePicker"
v-bind="logOutStateFrom.validateInfos.endTime"
>
<a-range-picker
v-model:value="queryRangePicker"
@change="fnRangePickerChange"
allow-clear
bordered
show-time
value-format="YYYY-MM-DD HH:mm:ss"
format="YYYY-MM-DD HH:mm:ss"
:placeholder="['记录开始', '记录结束']"
style="width: 100%"
></a-range-picker>
</a-form-item>
</a-form>
</a-card>
</a-col>
<a-col :span="8">
<!-- FTP日志设置-->
<a-card :title="ftpState.title" :loading="ftpState.fromLoading">
<template #extra>
<a-space :size="8" align="center">
<a-button
type="primary"
:loading="ftpState.confirmLoading"
@click.prevent="fnFormFTPFinish"
>
<template #icon><SaveOutlined /></template>
保存设置
</a-button>
</a-space>
</template>
<a-form
name="fTPState"
layout="horizontal"
autocomplete="off"
:label-col="{ span: 8 }"
>
<a-form-item label="协议类型" name="agreement">
<a-select v-model:value="ftpState.from.agreement">
<a-select-option key="ftp" value="ftp">FTP</a-select-option>
<a-select-option key="sftp" value="sftp">SFTP</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="对端IP地址"
name="toIp"
v-bind="ftpStateFrom.validateInfos.toIp"
>
<a-input
v-model:value="ftpState.from.toIp"
allow-clear
placeholder="请输入对端IP地址"
></a-input>
</a-form-item>
<a-form-item
label="对端文件目录"
name="directory"
v-bind="ftpStateFrom.validateInfos.directory"
>
<a-input
v-model:value="ftpState.from.directory"
allow-clear
placeholder="请输入对端文件目录"
></a-input>
</a-form-item>
<a-form-item
label="日志生成周期(小时)"
name="ftpLog"
v-bind="ftpStateFrom.validateInfos.ftpLog"
>
<a-input-number
v-model:value="ftpState.from.ftpLog"
placeholder="12"
:min="12"
/>
</a-form-item>
</a-form>
</a-card>
</a-col>
<a-col :span="8">
<!-- 日志远程输出设置 -->
<a-card
:title="remoteOutState.title"
:loading="remoteOutState.fromLoading"
>
<template #extra>
<a-space :size="8" align="center">
<a-button
type="primary"
:loading="remoteOutState.confirmLoading"
@click.prevent="fnFormRemoteOutFinish"
>
<template #icon><SaveOutlined /></template>
保存设置
</a-button>
</a-space>
</template>
<a-form
name="remoteOutState.from"
layout="horizontal"
autocomplete="off"
:label-col="{ span: 6 }"
>
<a-form-item
label="远程IP地址"
name="logIp"
v-bind="remoteOutStateFrom.validateInfos.logIp"
>
<a-input
v-model:value="remoteOutState.from.logIp"
allow-clear
placeholder="请输入远程IP地址"
></a-input>
</a-form-item>
<a-form-item
label="远程日志目录"
name="logDirectory"
v-bind="remoteOutStateFrom.validateInfos.logDirectory"
>
<a-input
v-model:value="remoteOutState.from.logDirectory"
allow-clear
placeholder="请输入远程日志目录"
></a-input>
</a-form-item>
</a-form>
</a-card>
<!-- 日志备份 -->
<a-card
:title="backState.title"
:loading="backState.fromLoading"
style="margin-top: 16px"
>
<template #extra>
<a-space :size="8" align="center">
<a-button
type="primary"
:loading="backState.confirmLoading"
@click.prevent="fnFormBackFinish"
>
<template #icon><CloudServerOutlined /></template>
备份
</a-button>
</a-space>
</template>
<a-form name="backState.from" layout="horizontal" autocomplete="off">
<a-form-item label="日志类型" name="logType">
<a-select v-model:value="backState.from.logType">
<a-select-option key="operation_log" value="operation_log">
操作日志
</a-select-option>
<a-select-option key="alarm_log" value="alarm_log">
告警日志
</a-select-option>
<a-select-option key="security_log" value="security_log">
安全日志
</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="备份文件"
name="backFileTree"
v-show="backState.from.backFileTree.length > 0"
>
<a-directory-tree
:tree-data="backState.from.backFileTree"
:field-names="{ children: 'items', title: 'name', key: 'path' }"
>
<template #title="{ isDir, name, path }">
<span>{{ name }}</span>
<span
class="backFile-download"
v-if="!isDir"
@click.prevent="fnBackDownload(name, path)"
>
下载
</span>
</template>
</a-directory-tree>
</a-form-item>
</a-form>
</a-card>
</a-col>
</a-row>
</PageContainer>
</template>
<style lang="less" scoped>
.backFile-download {
margin-left: 12px;
color: #eb2f96;
text-decoration: underline;
}
</style>