物业代码生成
This commit is contained in:
92
apps/web-antd/src/views/monitor/operlog/data.tsx
Normal file
92
apps/web-antd/src/views/monitor/operlog/data.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
import type { FormSchemaGetter } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { DictEnum } from '@vben/constants';
|
||||
|
||||
import { getDictOptions } from '#/utils/dict';
|
||||
import { renderDict } from '#/utils/render';
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'title',
|
||||
label: '系统模块',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'operName',
|
||||
label: '操作人员',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: getDictOptions(DictEnum.SYS_OPER_TYPE),
|
||||
},
|
||||
fieldName: 'businessType',
|
||||
label: '操作类型',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'operIp',
|
||||
label: '操作IP',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: getDictOptions(DictEnum.SYS_COMMON_STATUS),
|
||||
},
|
||||
fieldName: 'status',
|
||||
label: '状态',
|
||||
},
|
||||
{
|
||||
component: 'RangePicker',
|
||||
fieldName: 'createTime',
|
||||
label: '操作时间',
|
||||
componentProps: {
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const columns: VxeGridProps['columns'] = [
|
||||
{ type: 'checkbox', width: 60 },
|
||||
{ field: 'title', title: '系统模块' },
|
||||
{
|
||||
title: '操作类型',
|
||||
field: 'businessType',
|
||||
slots: {
|
||||
default: ({ row }) => {
|
||||
return renderDict(row.businessType, DictEnum.SYS_OPER_TYPE);
|
||||
},
|
||||
},
|
||||
},
|
||||
{ field: 'operName', title: '操作人员' },
|
||||
{ field: 'operIp', title: 'IP地址' },
|
||||
{ field: 'operLocation', title: 'IP信息' },
|
||||
{
|
||||
field: 'status',
|
||||
title: '操作状态',
|
||||
slots: {
|
||||
default: ({ row }) => {
|
||||
return renderDict(row.status, DictEnum.SYS_COMMON_STATUS);
|
||||
},
|
||||
},
|
||||
},
|
||||
{ field: 'operTime', title: '操作日期', sortable: true },
|
||||
{
|
||||
field: 'costTime',
|
||||
title: '操作耗时',
|
||||
sortable: true,
|
||||
formatter({ cellValue }) {
|
||||
return `${cellValue} ms`;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
resizable: false,
|
||||
width: 'auto',
|
||||
},
|
||||
];
|
184
apps/web-antd/src/views/monitor/operlog/index.vue
Normal file
184
apps/web-antd/src/views/monitor/operlog/index.vue
Normal file
@@ -0,0 +1,184 @@
|
||||
<script setup lang="ts">
|
||||
import type { VbenFormProps } from '@vben/common-ui';
|
||||
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
import type { PageQuery } from '#/api/common';
|
||||
import type { OperationLog } from '#/api/monitor/operlog/model';
|
||||
|
||||
import { Page, useVbenDrawer } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { Modal, Space } from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
addSortParams,
|
||||
useVbenVxeGrid,
|
||||
vxeCheckboxChecked,
|
||||
} from '#/adapter/vxe-table';
|
||||
import {
|
||||
operLogClean,
|
||||
operLogDelete,
|
||||
operLogExport,
|
||||
operLogList,
|
||||
} from '#/api/monitor/operlog';
|
||||
import { commonDownloadExcel } from '#/utils/file/download';
|
||||
import { confirmDeleteModal } from '#/utils/modal';
|
||||
|
||||
import { columns, querySchema } from './data';
|
||||
import operationPreviewDrawer from './operation-preview-drawer.vue';
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
commonConfig: {
|
||||
labelWidth: 80,
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
// 日期选择格式化
|
||||
fieldMappingTime: [
|
||||
[
|
||||
'createTime',
|
||||
['params[beginTime]', 'params[endTime]'],
|
||||
['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps<OperationLog> = {
|
||||
checkboxConfig: {
|
||||
// 高亮
|
||||
highlight: true,
|
||||
// 翻页时保留选中状态
|
||||
reserve: true,
|
||||
// 点击行选中
|
||||
trigger: 'row',
|
||||
},
|
||||
columns,
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page, sorts }, formValues = {}) => {
|
||||
const params: PageQuery = {
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
};
|
||||
// 添加排序参数
|
||||
addSortParams(params, sorts);
|
||||
return await operLogList(params);
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'operId',
|
||||
},
|
||||
sortConfig: {
|
||||
// 远程排序
|
||||
remote: true,
|
||||
// 支持多字段排序 默认关闭
|
||||
multiple: true,
|
||||
},
|
||||
id: 'monitor-operlog-index',
|
||||
};
|
||||
|
||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions,
|
||||
gridEvents: {
|
||||
// 排序 重新请求接口
|
||||
sortChange: () => tableApi.query(),
|
||||
},
|
||||
});
|
||||
|
||||
const [OperationPreviewDrawer, drawerApi] = useVbenDrawer({
|
||||
connectedComponent: operationPreviewDrawer,
|
||||
});
|
||||
|
||||
/**
|
||||
* 预览
|
||||
* @param record 操作日志记录
|
||||
*/
|
||||
function handlePreview(record: OperationLog) {
|
||||
drawerApi.setData({ record });
|
||||
drawerApi.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空全部日志
|
||||
*/
|
||||
function handleClear() {
|
||||
confirmDeleteModal({
|
||||
onValidated: async () => {
|
||||
await operLogClean();
|
||||
await tableApi.reload();
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除日志
|
||||
*/
|
||||
async function handleDelete() {
|
||||
const rows = tableApi.grid.getCheckboxRecords();
|
||||
const ids = rows.map((row: OperationLog) => row.operId);
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
okType: 'danger',
|
||||
content: `确认删除选中的${ids.length}条操作日志吗?`,
|
||||
onOk: async () => {
|
||||
await operLogDelete(ids);
|
||||
await tableApi.query();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
commonDownloadExcel(operLogExport, '操作日志', tableApi.formApi.form.values, {
|
||||
fieldMappingTime: formOptions.fieldMappingTime,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="操作日志列表">
|
||||
<template #toolbar-tools>
|
||||
<Space>
|
||||
<a-button
|
||||
v-access:code="['monitor:operlog:remove']"
|
||||
@click="handleClear"
|
||||
>
|
||||
{{ $t('pages.common.clear') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
v-access:code="['monitor:operlog:export']"
|
||||
@click="handleDownloadExcel"
|
||||
>
|
||||
{{ $t('pages.common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
:disabled="!vxeCheckboxChecked(tableApi)"
|
||||
danger
|
||||
type="primary"
|
||||
v-access:code="['monitor:operlog:remove']"
|
||||
@click="handleDelete"
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</a-button>
|
||||
</Space>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<ghost-button
|
||||
v-access:code="['monitor:operlog:list']"
|
||||
@click.stop="handlePreview(row)"
|
||||
>
|
||||
{{ $t('pages.common.preview') }}
|
||||
</ghost-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<OperationPreviewDrawer />
|
||||
</Page>
|
||||
</template>
|
@@ -0,0 +1,94 @@
|
||||
<script setup lang="ts">
|
||||
import type { OperationLog } from '#/api/monitor/operlog/model';
|
||||
|
||||
import { computed, shallowRef } from 'vue';
|
||||
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
import { DictEnum } from '@vben/constants';
|
||||
|
||||
import { Descriptions, DescriptionsItem, Tag } from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
renderDict,
|
||||
renderHttpMethodTag,
|
||||
renderJsonPreview,
|
||||
} from '#/utils/render';
|
||||
|
||||
const [BasicDrawer, drawerApi] = useVbenDrawer({
|
||||
onOpenChange: handleOpenChange,
|
||||
onClosed() {
|
||||
currentLog.value = null;
|
||||
},
|
||||
});
|
||||
|
||||
const currentLog = shallowRef<null | OperationLog>(null);
|
||||
function handleOpenChange(open: boolean) {
|
||||
if (!open) {
|
||||
return null;
|
||||
}
|
||||
const { record } = drawerApi.getData() as { record: OperationLog };
|
||||
currentLog.value = record;
|
||||
}
|
||||
|
||||
const actionInfo = computed(() => {
|
||||
if (!currentLog.value) {
|
||||
return '-';
|
||||
}
|
||||
const data = currentLog.value;
|
||||
return `账号: ${data.operName} / ${data.deptName} / ${data.operIp} / ${data.operLocation}`;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicDrawer :footer="false" class="w-[600px]" title="查看日志">
|
||||
<Descriptions v-if="currentLog" size="small" bordered :column="1">
|
||||
<DescriptionsItem label="日志编号" :label-style="{ minWidth: '120px' }">
|
||||
{{ currentLog.operId }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="操作结果">
|
||||
<component
|
||||
:is="renderDict(currentLog.status, DictEnum.SYS_COMMON_STATUS)"
|
||||
/>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="操作模块">
|
||||
<div class="flex items-center">
|
||||
<Tag>{{ currentLog.title }}</Tag>
|
||||
<component
|
||||
:is="renderDict(currentLog.businessType, DictEnum.SYS_OPER_TYPE)"
|
||||
/>
|
||||
</div>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="操作信息">
|
||||
{{ actionInfo }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="请求信息">
|
||||
<component :is="renderHttpMethodTag(currentLog.requestMethod)" />
|
||||
{{ currentLog.operUrl }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem v-if="currentLog.errorMsg" label="异常信息">
|
||||
<span class="font-semibold text-red-600">
|
||||
{{ currentLog.errorMsg }}
|
||||
</span>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="方法">
|
||||
{{ currentLog.method }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="请求参数">
|
||||
<div class="max-h-[300px] overflow-y-auto">
|
||||
<component :is="renderJsonPreview(currentLog.operParam)" />
|
||||
</div>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem v-if="currentLog.jsonResult" label="响应参数">
|
||||
<div class="max-h-[300px] overflow-y-auto">
|
||||
<component :is="renderJsonPreview(currentLog.jsonResult)" />
|
||||
</div>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="请求耗时">
|
||||
{{ `${currentLog.costTime} ms` }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="操作时间">
|
||||
{{ `${currentLog.operTime}` }}
|
||||
</DescriptionsItem>
|
||||
</Descriptions>
|
||||
</BasicDrawer>
|
||||
</template>
|
Reference in New Issue
Block a user