You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
441 lines
12 KiB
Vue
441 lines
12 KiB
Vue
|
1 year ago
|
<template>
|
||
|
|
<div class="h-full">
|
||
|
|
<my-card title="搜索条件" search>
|
||
|
|
<n-form ref="formRef" inline label-width="auto" :model="formValue" size="medium">
|
||
|
|
<n-form-item label="系统模块">
|
||
|
|
<n-input v-model:value="formValue.title" placeholder="请输入系统模块" />
|
||
|
|
</n-form-item>
|
||
|
|
<n-form-item label="操作人员">
|
||
|
|
<n-input v-model:value="formValue.operName" placeholder="请输入操作人员" />
|
||
|
|
</n-form-item>
|
||
|
|
<n-form-item label="类型">
|
||
|
|
<n-select v-model:value="formValue.businessType" :options="businessTypeSelect.options" style="width: 200px" />
|
||
|
|
</n-form-item>
|
||
|
|
<n-form-item label="状态">
|
||
|
|
<n-select v-model:value="formValue.status" :options="statusSelect.options" style="width: 200px" />
|
||
|
|
</n-form-item>
|
||
|
|
<n-form-item label="操作时间">
|
||
|
|
<n-date-picker v-model:value="daterange" type="daterange" :format="format" />
|
||
|
|
</n-form-item>
|
||
|
|
|
||
|
|
<n-form-item>
|
||
|
|
<n-button type="primary" class="mr-10px" @click="handleValidateClick">
|
||
|
|
<icon-ic-round-search class="mr-4px text-20px" />
|
||
|
|
搜索
|
||
|
|
</n-button>
|
||
|
|
<n-button @click="reset">
|
||
|
|
<icon-ic-round-refresh class="mr-4px text-20px" />
|
||
|
|
重置
|
||
|
|
</n-button>
|
||
|
|
</n-form-item>
|
||
|
|
</n-form>
|
||
|
|
</my-card>
|
||
|
|
<my-card title="列表">
|
||
|
|
<template #right>
|
||
|
|
<div class="flex-center">
|
||
|
|
<n-button
|
||
|
|
type="error"
|
||
|
|
size="small"
|
||
|
|
class="mr-5px ml-5px"
|
||
|
|
:disabled="isBacthDelete"
|
||
|
|
@click="
|
||
|
|
showModal = true;
|
||
|
|
flag = 0;
|
||
|
|
"
|
||
|
|
>
|
||
|
|
<icon-ic-round-delete class="mr-4px text-20px" />
|
||
|
|
删除
|
||
|
|
</n-button>
|
||
|
|
<n-button
|
||
|
|
type="warning"
|
||
|
|
size="small"
|
||
|
|
class="mr-5px"
|
||
|
|
@click="
|
||
|
|
showModal = true;
|
||
|
|
flag = 1;
|
||
|
|
"
|
||
|
|
>
|
||
|
|
<icon-ic-round-delete class="mr-4px text-20px" />
|
||
|
|
清空
|
||
|
|
</n-button>
|
||
|
|
<n-button size="small" class="mr-5px" type="primary" color="#2cc2d9" @click="handleExport">
|
||
|
|
<icon-tdesign-arrow-right-up-circle class="mr-4px text-20px" />
|
||
|
|
导出
|
||
|
|
</n-button>
|
||
|
|
<n-button size="small" class="mr-5px" type="primary" @click="getOperaData">
|
||
|
|
<icon-mdi-refresh class="mr-4px text-16px" :class="{ 'animate-spin': loading }" />
|
||
|
|
刷新表格
|
||
|
|
</n-button>
|
||
|
|
<cx-columns v-model:columns="columns" size="small"></cx-columns>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
<div>
|
||
|
|
<n-data-table
|
||
|
|
:columns="columns"
|
||
|
|
:data="operaData"
|
||
|
|
:loading="loading"
|
||
|
|
:row-key="rowKey"
|
||
|
|
:max-height="dataTableConfig.maxHeight"
|
||
|
|
:scroll-x="dataTableConfig.scrollWidth(columns)"
|
||
|
|
@update:checked-row-keys="handleCheck"
|
||
|
|
/>
|
||
|
|
<n-pagination
|
||
|
|
:page="page"
|
||
|
|
:page-size="formValue.pageSize"
|
||
|
|
:page-sizes="[10, 20, 50, 100]"
|
||
|
|
show-size-picker
|
||
|
|
:item-count="total"
|
||
|
|
style="margin-top: 20px; float: right"
|
||
|
|
@update:page="changePage"
|
||
|
|
@update-page-size="changePageSize"
|
||
|
|
>
|
||
|
|
<template #prefix="{ itemCount }">共 {{ itemCount }} 条</template>
|
||
|
|
</n-pagination>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<n-modal
|
||
|
|
v-model:show="showModal"
|
||
|
|
:mask-closable="false"
|
||
|
|
preset="dialog"
|
||
|
|
title="用户退出"
|
||
|
|
:content="`你真的要${flag ? '清空' : '删除'}这些记录吗?`"
|
||
|
|
positive-text="确认"
|
||
|
|
negative-text="算了"
|
||
|
|
@positive-click="onPositiveClick"
|
||
|
|
/>
|
||
|
|
<n-drawer v-model:show="show" :width="502">
|
||
|
|
<n-drawer-content title="操作日志详情" closable>
|
||
|
|
<n-form ref="formRef" :label-width="80" :model="form">
|
||
|
|
<n-grid :cols="24" :x-gap="18">
|
||
|
|
<!-- <n-form-item-grid-item :span="12" label="操作模块">
|
||
|
|
{{ form.title }} / {{ typeFormat(form) }}
|
||
|
|
</n-form-item-grid-item> -->
|
||
|
|
<n-form-item-grid-item :span="12" label="请求地址">{{ form.operUrl }}</n-form-item-grid-item>
|
||
|
|
<n-form-item-grid-item :span="12" label="登录信息">
|
||
|
|
{{ form.operName }} / {{ form.operIp }}
|
||
|
|
</n-form-item-grid-item>
|
||
|
|
<n-form-item-grid-item :span="12" label="请求方式">{{ form.requestMethod }}</n-form-item-grid-item>
|
||
|
|
<n-form-item-grid-item :span="12" label="操作方法">{{ form.method }}</n-form-item-grid-item>
|
||
|
|
<n-form-item-grid-item v-if="form.operParam" :span="24" label="请求参数">
|
||
|
|
{{ form.operParam }}
|
||
|
|
</n-form-item-grid-item>
|
||
|
|
<n-form-item-grid-item :span="12" label="返回参数">{{ form.jsonResult }}</n-form-item-grid-item>
|
||
|
|
<n-form-item-grid-item :span="12" label="操作状态">
|
||
|
|
<div v-if="form.status === 0">正常</div>
|
||
|
|
<div v-else-if="form.status === 1">失败</div>
|
||
|
|
</n-form-item-grid-item>
|
||
|
|
<n-form-item-grid-item :span="12" label="消耗时间">{{ form.costTime }}毫秒</n-form-item-grid-item>
|
||
|
|
<n-form-item-grid-item :span="12" label="操作时间">
|
||
|
|
{{ form.operTime }}
|
||
|
|
</n-form-item-grid-item>
|
||
|
|
<n-form-item-grid-item v-if="form.status === 1" :span="12" label="操作时间">
|
||
|
|
{{ form.errorMsg }}
|
||
|
|
</n-form-item-grid-item>
|
||
|
|
</n-grid>
|
||
|
|
</n-form>
|
||
|
|
</n-drawer-content>
|
||
|
|
</n-drawer>
|
||
|
|
</my-card>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script lang="tsx" setup>
|
||
|
|
import { ref } from 'vue';
|
||
|
|
import type { Ref } from 'vue';
|
||
|
|
import { NButton, useMessage, NTag } from 'naive-ui';
|
||
|
|
import type { DataTableColumns, DataTableRowKey } from 'naive-ui';
|
||
|
|
// import { ReorderThreeOutline, Sync } from '@vicons/ionicons5';
|
||
|
|
import { operaBusinessLabels, operaStatusLabels } from '@/constants';
|
||
|
|
import { operaList, delOperlog, cleanOperlog } from '@/service';
|
||
|
|
import { useLoading } from '@/hooks';
|
||
|
|
import { formatDate, addDateRange } from '@/utils';
|
||
|
|
import { download } from '@/service/request/helpers';
|
||
|
|
import { dataTableConfig } from '@/config/dataTableConfig';
|
||
|
|
const operaData = ref();
|
||
|
|
const format = 'yyyy-MM-dd hh:mm:ss';
|
||
|
|
const message = useMessage();
|
||
|
|
const rowKey = row => row.operId;
|
||
|
|
const showModal = ref(false);
|
||
|
|
const isBacthDelete = ref(true);
|
||
|
|
const form = ref();
|
||
|
|
const flag = ref(1);
|
||
|
|
const delIds = ref();
|
||
|
|
const total = ref();
|
||
|
|
const page = ref(1);
|
||
|
|
const showExport = ref(false);
|
||
|
|
const daterange = ref();
|
||
|
|
const detailId = ref();
|
||
|
|
const show = ref(false);
|
||
|
|
const formValue = ref({
|
||
|
|
pageNum: 1,
|
||
|
|
pageSize: 10,
|
||
|
|
title: undefined,
|
||
|
|
operName: undefined,
|
||
|
|
businessType: undefined,
|
||
|
|
status: undefined
|
||
|
|
});
|
||
|
|
const statusSelect = ref({
|
||
|
|
options: [
|
||
|
|
{
|
||
|
|
label: '成功',
|
||
|
|
value: 0
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: '失败',
|
||
|
|
value: 1
|
||
|
|
}
|
||
|
|
]
|
||
|
|
});
|
||
|
|
const businessTypeSelect = ref({
|
||
|
|
options: [
|
||
|
|
{
|
||
|
|
label: '新增',
|
||
|
|
value: 1
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: '删除',
|
||
|
|
value: 3
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: '修改',
|
||
|
|
value: 2
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: '授权',
|
||
|
|
value: 4
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: '导出',
|
||
|
|
value: 5
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: '退出',
|
||
|
|
value: 7
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: '清空数据',
|
||
|
|
value: 9
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: '其他',
|
||
|
|
value: 0
|
||
|
|
}
|
||
|
|
]
|
||
|
|
});
|
||
|
|
const columns: Ref<DataTableColumns<OperaManagement.OperaType>> = ref([
|
||
|
|
{
|
||
|
|
type: 'selection',
|
||
|
|
align: 'center',
|
||
|
|
width: 60
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '日志编号',
|
||
|
|
key: 'operId',
|
||
|
|
align: 'center',
|
||
|
|
width: 140
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '系统模块',
|
||
|
|
key: 'title',
|
||
|
|
align: 'center',
|
||
|
|
width: 200
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '操作类型',
|
||
|
|
key: 'businessType',
|
||
|
|
width: 100,
|
||
|
|
render: row => {
|
||
|
|
if (row.businessType) {
|
||
|
|
const tagTypes: Record<OperaManagement.OperaBusinessTypeKey, NaiveUI.ThemeColor> = {
|
||
|
|
1: 'success',
|
||
|
|
2: 'warning',
|
||
|
|
3: 'error',
|
||
|
|
4: 'info',
|
||
|
|
5: 'primary',
|
||
|
|
6: 'info',
|
||
|
|
7: 'error',
|
||
|
|
9: 'success'
|
||
|
|
};
|
||
|
|
|
||
|
|
return <NTag type={tagTypes[row.businessType]}>{operaBusinessLabels[row.businessType]}</NTag>;
|
||
|
|
}
|
||
|
|
return <span></span>;
|
||
|
|
},
|
||
|
|
align: 'center'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '请求方式',
|
||
|
|
key: 'requestMethod',
|
||
|
|
align: 'center',
|
||
|
|
width: 120
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '操作人员',
|
||
|
|
key: 'operName',
|
||
|
|
align: 'center',
|
||
|
|
width: 100
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '主机',
|
||
|
|
key: 'operIp',
|
||
|
|
align: 'center',
|
||
|
|
width: 140
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '操作状态',
|
||
|
|
key: 'status',
|
||
|
|
width: 120,
|
||
|
|
render: row => {
|
||
|
|
if (row.status.toString()) {
|
||
|
|
const tagTypes: Record<OperaManagement.OperaStatusKey, NaiveUI.ThemeColor> = {
|
||
|
|
0: 'success',
|
||
|
|
1: 'error'
|
||
|
|
};
|
||
|
|
|
||
|
|
return <NTag type={tagTypes[row.status]}>{operaStatusLabels[row.status]}</NTag>;
|
||
|
|
}
|
||
|
|
return <span></span>;
|
||
|
|
},
|
||
|
|
align: 'center'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '消耗时间',
|
||
|
|
key: 'costTime',
|
||
|
|
align: 'center',
|
||
|
|
width: 120
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '操作日期',
|
||
|
|
key: 'operTime',
|
||
|
|
align: 'center',
|
||
|
|
defaultSortOrder: 'ascend',
|
||
|
|
sorter: 'default',
|
||
|
|
width: 180
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '操作',
|
||
|
|
key: 'action',
|
||
|
|
align: 'center',
|
||
|
|
render: row => {
|
||
|
|
return (
|
||
|
|
<n-space justify={'center'}>
|
||
|
|
<n-button
|
||
|
|
size={'small'}
|
||
|
|
type="primary"
|
||
|
|
onClick={() => {
|
||
|
|
show.value = true;
|
||
|
|
detailId.value = row.operId;
|
||
|
|
form.value = row;
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<icon-tdesign-file-import class="mr-2px text-15px " />
|
||
|
|
详情
|
||
|
|
</n-button>
|
||
|
|
</n-space>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
]) as Ref<DataTableColumns<OperaManagement.OperaType>>;
|
||
|
|
|
||
|
|
const { loading, startLoading, endLoading } = useLoading(false);
|
||
|
|
|
||
|
|
// 搜索
|
||
|
|
function handleValidateClick() {
|
||
|
|
getOperaData();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 重置
|
||
|
|
function reset() {
|
||
|
|
formValue.value.pageNum = 1;
|
||
|
|
page.value = 1;
|
||
|
|
daterange.value = null;
|
||
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||
|
|
const { pageNum, pageSize, ...rest } = formValue.value;
|
||
|
|
for (const key in rest) {
|
||
|
|
if (formValue.value[key] !== '') {
|
||
|
|
formValue.value[key] = '';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
getOperaData();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取用户信息
|
||
|
|
async function getOperaData() {
|
||
|
|
startLoading();
|
||
|
|
let dateArr;
|
||
|
|
if (daterange.value) {
|
||
|
|
dateArr = daterange.value.map(item => {
|
||
|
|
return formatDate(new Date(item), format);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
await operaList({ params: addDateRange(formValue.value, dateArr, undefined) }).then(res => {
|
||
|
|
operaData.value = res.rows;
|
||
|
|
total.value = res.total;
|
||
|
|
if (operaData.value) {
|
||
|
|
setTimeout(() => {
|
||
|
|
endLoading();
|
||
|
|
}, 200);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 确认删除
|
||
|
|
async function onPositiveClick() {
|
||
|
|
if (!flag.value) {
|
||
|
|
await delOperlog(delIds.value).then(() => {
|
||
|
|
message.success('删除成功');
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
cleanOperlog();
|
||
|
|
}
|
||
|
|
getOperaData();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 改变页签
|
||
|
|
function changePage(pageNum) {
|
||
|
|
formValue.value.pageNum = pageNum;
|
||
|
|
page.value = pageNum;
|
||
|
|
getOperaData();
|
||
|
|
}
|
||
|
|
function changePageSize(pageSize) {
|
||
|
|
formValue.value.pageSize = pageSize;
|
||
|
|
getOperaData();
|
||
|
|
}
|
||
|
|
// 导出数据
|
||
|
|
function handleExport() {
|
||
|
|
showExport.value = true;
|
||
|
|
download('system/logininfor/export', formValue.value, `operlog_${new Date().getTime()}.xlsx`, undefined)
|
||
|
|
.then(() => {
|
||
|
|
showExport.value = false;
|
||
|
|
})
|
||
|
|
.catch(() => {
|
||
|
|
showExport.value = false;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
// 弹出确认框
|
||
|
|
function handleCheck(rowKeys: DataTableRowKey[]) {
|
||
|
|
if (rowKeys.length > 0) {
|
||
|
|
isBacthDelete.value = false;
|
||
|
|
delIds.value = rowKeys;
|
||
|
|
} else {
|
||
|
|
isBacthDelete.value = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// function typeFormat(row, column) {
|
||
|
|
// return this.selectDictLabel(form, row.businessType);
|
||
|
|
// }
|
||
|
|
function init() {
|
||
|
|
getOperaData();
|
||
|
|
}
|
||
|
|
init();
|
||
|
|
</script>
|
||
|
|
<style scoped>
|
||
|
|
.n-form {
|
||
|
|
display: flex;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
}
|
||
|
|
.n-form .n-form-item-grid-item {
|
||
|
|
color: aqua;
|
||
|
|
}
|
||
|
|
</style>
|