Commit f09a1a4b8eeb1fd1a5266311b2ae0dabf58d4223
1 parent
4a692ed2
refactor: operatelog
Showing
8 changed files
with
183 additions
and
224 deletions
yudao-ui-admin-vue3/src/api/system/operatelog/index.ts
| 1 | 1 | import request from '@/config/axios' |
| 2 | 2 | |
| 3 | +export type OperateLogVO = { | |
| 4 | + id: number | |
| 5 | + userNickname: string | |
| 6 | + traceId: string | |
| 7 | + userId: number | |
| 8 | + module: string | |
| 9 | + name: string | |
| 10 | + type: number | |
| 11 | + content: string | |
| 12 | + exts: object | |
| 13 | + requestMethod: string | |
| 14 | + requestUrl: string | |
| 15 | + userIp: string | |
| 16 | + userAgent: string | |
| 17 | + javaMethod: string | |
| 18 | + javaMethodArgs: string | |
| 19 | + startTime: string | |
| 20 | + duration: number | |
| 21 | + resultCode: number | |
| 22 | + resultMsg: string | |
| 23 | + resultData: string | |
| 24 | +} | |
| 25 | +export interface OperateLogPageReqVO extends BasePage { | |
| 26 | + module?: string | |
| 27 | + userNickname?: string | |
| 28 | + type?: number | |
| 29 | + success?: boolean | |
| 30 | + startTime?: string[] | |
| 31 | +} | |
| 32 | + | |
| 3 | 33 | // 查询操作日志列表 |
| 4 | -export const getOperateLogPageApi = (params) => { | |
| 34 | +export const getOperateLogPageApi = (params: OperateLogPageReqVO) => { | |
| 5 | 35 | return request.get({ url: '/system/operate-log/page', params }) |
| 6 | 36 | } |
| 7 | 37 | // 导出操作日志 |
| 8 | -export const exportOperateLogApi = (params) => { | |
| 38 | +export const exportOperateLogApi = (params: OperateLogPageReqVO) => { | |
| 9 | 39 | return request.download({ url: '/system/operate-log/export', params }) |
| 10 | 40 | } | ... | ... |
yudao-ui-admin-vue3/src/api/system/operatelog/types.ts deleted
| 1 | -export type OperateLogVO = { | |
| 2 | - id: number | |
| 3 | - userNickname: string | |
| 4 | - traceId: string | |
| 5 | - userId: number | |
| 6 | - module: string | |
| 7 | - name: string | |
| 8 | - type: number | |
| 9 | - content: string | |
| 10 | - exts: object | |
| 11 | - requestMethod: string | |
| 12 | - requestUrl: string | |
| 13 | - userIp: string | |
| 14 | - userAgent: string | |
| 15 | - javaMethod: string | |
| 16 | - javaMethodArgs: string | |
| 17 | - startTime: string | |
| 18 | - duration: number | |
| 19 | - resultCode: number | |
| 20 | - resultMsg: string | |
| 21 | - resultData: string | |
| 22 | -} |
yudao-ui-admin-vue3/src/hooks/web/useVxeCrudSchemas.ts
| ... | ... | @@ -20,6 +20,7 @@ export type VxeCrudSchema = { |
| 20 | 20 | primaryType?: VxeColumnPropTypes.Type |
| 21 | 21 | // 是否开启操作栏插槽 |
| 22 | 22 | action?: boolean |
| 23 | + actionWidth?: string | |
| 23 | 24 | columns: VxeCrudColumns[] |
| 24 | 25 | } |
| 25 | 26 | type VxeCrudColumns = Omit<VxeTableColumn, 'children'> & { |
| ... | ... | @@ -204,7 +205,7 @@ const filterTableSchema = (crudSchema: VxeCrudSchema): VxeGridPropTypes.Columns |
| 204 | 205 | const tableSchemaItem = { |
| 205 | 206 | title: t('table.action'), |
| 206 | 207 | field: 'actionbtns', |
| 207 | - width: '240px', | |
| 208 | + width: crudSchema.actionWidth ? crudSchema.actionWidth : '240px', | |
| 208 | 209 | slots: { |
| 209 | 210 | default: 'actionbtns_default' |
| 210 | 211 | } | ... | ... |
yudao-ui-admin-vue3/src/views/system/dept/index.vue
| ... | ... | @@ -10,11 +10,6 @@ import { DeptVO } from '@/api/system/dept/types' |
| 10 | 10 | import { useMessage } from '@/hooks/web/useMessage' |
| 11 | 11 | import { getListSimpleUsersApi } from '@/api/system/user' |
| 12 | 12 | const message = useMessage() |
| 13 | -interface Tree { | |
| 14 | - id: number | |
| 15 | - name: string | |
| 16 | - children?: Tree[] | |
| 17 | -} | |
| 18 | 13 | |
| 19 | 14 | const defaultProps = { |
| 20 | 15 | children: 'children', | ... | ... |
yudao-ui-admin-vue3/src/views/system/loginlog/loginLog.data.ts
yudao-ui-admin-vue3/src/views/system/operatelog/index.vue
| 1 | -<script setup lang="ts"> | |
| 2 | -import dayjs from 'dayjs' | |
| 3 | -import { useTable } from '@/hooks/web/useTable' | |
| 4 | -import { allSchemas } from './operatelog.data' | |
| 5 | -import { DICT_TYPE } from '@/utils/dict' | |
| 6 | -import { useI18n } from '@/hooks/web/useI18n' | |
| 7 | -import type { OperateLogVO } from '@/api/system/operatelog/types' | |
| 8 | -import * as OperateLogApi from '@/api/system/operatelog' | |
| 9 | -import { ref } from 'vue' | |
| 10 | -const { t } = useI18n() // 国际化 | |
| 11 | -// ========== 列表相关 ========== | |
| 12 | -const { register, tableObject, methods } = useTable<OperateLogVO>({ | |
| 13 | - getListApi: OperateLogApi.getOperateLogPageApi, | |
| 14 | - exportListApi: OperateLogApi.exportOperateLogApi | |
| 15 | -}) | |
| 16 | -// ========== 详情相关 ========== | |
| 17 | -const detailRef = ref() // 详情 Ref | |
| 18 | -const dialogVisible = ref(false) // 是否显示弹出层 | |
| 19 | -const dialogTitle = ref(t('action.detail')) // 弹出层标题 | |
| 20 | -const { getList, setSearchParams, exportList } = methods | |
| 21 | -// 详情 | |
| 22 | -const handleDetail = (row: OperateLogVO) => { | |
| 23 | - // 设置数据 | |
| 24 | - detailRef.value = row | |
| 25 | - dialogVisible.value = true | |
| 26 | -} | |
| 27 | -getList() | |
| 28 | -</script> | |
| 29 | 1 | <template> |
| 30 | 2 | <ContentWrap> |
| 31 | - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" /> | |
| 32 | - </ContentWrap> | |
| 33 | - <ContentWrap> | |
| 34 | - <!-- 操作工具栏 --> | |
| 35 | - <div class="mb-10px"> | |
| 36 | - <el-button | |
| 37 | - type="warning" | |
| 38 | - v-hasPermi="['system:operate-log:export']" | |
| 39 | - :loading="tableObject.exportLoading" | |
| 40 | - @click="exportList('操作日志.xls')" | |
| 41 | - > | |
| 42 | - <Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }} | |
| 43 | - </el-button> | |
| 44 | - </div> | |
| 45 | - <Table | |
| 46 | - :columns="allSchemas.tableColumns" | |
| 47 | - :selection="false" | |
| 48 | - :data="tableObject.tableList" | |
| 49 | - :loading="tableObject.loading" | |
| 50 | - :pagination="{ | |
| 51 | - total: tableObject.total | |
| 52 | - }" | |
| 53 | - v-model:pageSize="tableObject.pageSize" | |
| 54 | - v-model:currentPage="tableObject.currentPage" | |
| 55 | - @register="register" | |
| 56 | - > | |
| 57 | - <template #type="{ row }"> | |
| 58 | - <DictTag :type="DICT_TYPE.SYSTEM_OPERATE_TYPE" :value="row.type" /> | |
| 3 | + <!-- 列表 --> | |
| 4 | + <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar"> | |
| 5 | + <!-- 操作:新增 --> | |
| 6 | + <template #toolbar_buttons> | |
| 7 | + <XButton | |
| 8 | + type="warning" | |
| 9 | + preIcon="ep:download" | |
| 10 | + :title="t('action.export')" | |
| 11 | + v-hasPermi="['system:operate-log:export']" | |
| 12 | + @click="handleExport()" | |
| 13 | + /> | |
| 59 | 14 | </template> |
| 60 | 15 | <template #duration="{ row }"> |
| 61 | 16 | <span>{{ row.duration + 'ms' }}</span> |
| ... | ... | @@ -63,35 +18,68 @@ getList() |
| 63 | 18 | <template #resultCode="{ row }"> |
| 64 | 19 | <span>{{ row.resultCode === 0 ? '成功' : '失败' }}</span> |
| 65 | 20 | </template> |
| 66 | - <template #startTime="{ row }"> | |
| 67 | - <span>{{ dayjs(row.startTime).format('YYYY-MM-DD HH:mm:ss') }}</span> | |
| 21 | + <template #actionbtns_default="{ row }"> | |
| 22 | + <!-- 操作:详情 --> | |
| 23 | + <XTextButton preIcon="ep:view" :title="t('action.detail')" @click="handleDetail(row)" /> | |
| 68 | 24 | </template> |
| 69 | - <template #action="{ row }"> | |
| 70 | - <el-button link type="primary" @click="handleDetail(row)"> | |
| 71 | - <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }} | |
| 72 | - </el-button> | |
| 73 | - </template> | |
| 74 | - </Table> | |
| 25 | + </vxe-grid> | |
| 75 | 26 | </ContentWrap> |
| 76 | - <Dialog v-model="dialogVisible" :title="dialogTitle"> | |
| 77 | - <!-- 对话框(详情) --> | |
| 78 | - <Descriptions :schema="allSchemas.detailSchema" :data="detailRef"> | |
| 79 | - <template #resultCode="{ row }"> | |
| 80 | - <span>{{ row.resultCode === 0 ? '成功' : '失败' }}</span> | |
| 81 | - </template> | |
| 82 | - <template #type="{ row }"> | |
| 83 | - <DictTag :type="DICT_TYPE.SYSTEM_OPERATE_TYPE" :value="row.type" /> | |
| 84 | - </template> | |
| 85 | - <template #duration="{ row }"> | |
| 86 | - <span>{{ row.duration + 'ms' }}</span> | |
| 87 | - </template> | |
| 88 | - <template #startTime="{ row }"> | |
| 89 | - <span>{{ dayjs(row.startTime).format('YYYY-MM-DD HH:mm:ss') }}</span> | |
| 90 | - </template> | |
| 91 | - </Descriptions> | |
| 92 | - <!-- 操作按钮 --> | |
| 27 | + <!-- 弹窗 --> | |
| 28 | + <XModal id="postModel" v-model="dialogVisible" :title="dialogTitle"> | |
| 29 | + <template #default> | |
| 30 | + <!-- 对话框(详情) --> | |
| 31 | + <Descriptions :schema="allSchemas.detailSchema" :data="detailRef"> | |
| 32 | + <template #resultCode="{ row }"> | |
| 33 | + <span>{{ row.resultCode === 0 ? '成功' : '失败' }}</span> | |
| 34 | + </template> | |
| 35 | + <template #duration="{ row }"> | |
| 36 | + <span>{{ row.duration + 'ms' }}</span> | |
| 37 | + </template> | |
| 38 | + </Descriptions> | |
| 39 | + </template> | |
| 93 | 40 | <template #footer> |
| 94 | - <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button> | |
| 41 | + <!-- 按钮:关闭 --> | |
| 42 | + <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" /> | |
| 95 | 43 | </template> |
| 96 | - </Dialog> | |
| 44 | + </XModal> | |
| 97 | 45 | </template> |
| 46 | +<script setup lang="ts"> | |
| 47 | +// 全局相关的 import | |
| 48 | +import { ref } from 'vue' | |
| 49 | +import { useI18n } from '@/hooks/web/useI18n' | |
| 50 | +import { useVxeGrid } from '@/hooks/web/useVxeGrid' | |
| 51 | +import { VxeGridInstance } from 'vxe-table' | |
| 52 | +// 业务相关的 import | |
| 53 | +import * as OperateLogApi from '@/api/system/operatelog' | |
| 54 | +import { allSchemas } from './operatelog.data' | |
| 55 | +import download from '@/utils/download' | |
| 56 | + | |
| 57 | +const { t } = useI18n() // 国际化 | |
| 58 | +// 列表相关的变量 | |
| 59 | +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref | |
| 60 | +const { gridOptions } = useVxeGrid<OperateLogApi.OperateLogVO>({ | |
| 61 | + allSchemas: allSchemas, | |
| 62 | + getListApi: OperateLogApi.getOperateLogPageApi | |
| 63 | +}) | |
| 64 | +// 弹窗相关的变量 | |
| 65 | +const dialogVisible = ref(false) // 是否显示弹出层 | |
| 66 | +const dialogTitle = ref('edit') // 弹出层标题 | |
| 67 | +const actionLoading = ref(false) // 按钮 Loading | |
| 68 | +const detailRef = ref() // 详情 Ref | |
| 69 | +// 详情 | |
| 70 | +const handleDetail = (row: OperateLogApi.OperateLogVO) => { | |
| 71 | + // 设置数据 | |
| 72 | + detailRef.value = row | |
| 73 | + dialogVisible.value = true | |
| 74 | +} | |
| 75 | + | |
| 76 | +// 导出操作 | |
| 77 | +const handleExport = async () => { | |
| 78 | + const queryParams = Object.assign( | |
| 79 | + {}, | |
| 80 | + JSON.parse(JSON.stringify(xGrid.value?.getRefMaps().refForm.value.data)) | |
| 81 | + ) | |
| 82 | + const res = await OperateLogApi.exportOperateLogApi(queryParams) | |
| 83 | + download.excel(res, '岗位列表.xls') | |
| 84 | +} | |
| 85 | +</script> | ... | ... |
yudao-ui-admin-vue3/src/views/system/operatelog/operatelog.data.ts
| 1 | 1 | import { reactive } from 'vue' |
| 2 | 2 | import { DICT_TYPE } from '@/utils/dict' |
| 3 | -import { useI18n } from '@/hooks/web/useI18n' | |
| 4 | -import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' | |
| 5 | -const { t } = useI18n() // 国际化 | |
| 6 | -const crudSchemas = reactive<CrudSchema[]>([ | |
| 7 | - { | |
| 8 | - label: t('common.index'), | |
| 9 | - field: 'id', | |
| 10 | - type: 'index', | |
| 11 | - form: { | |
| 12 | - show: false | |
| 13 | - } | |
| 14 | - }, | |
| 15 | - { | |
| 16 | - label: '操作模块', | |
| 17 | - field: 'module', | |
| 18 | - search: { | |
| 19 | - show: true | |
| 20 | - } | |
| 21 | - }, | |
| 22 | - { | |
| 23 | - label: '操作名', | |
| 24 | - field: 'name' | |
| 25 | - }, | |
| 26 | - { | |
| 27 | - label: '操作类型', | |
| 28 | - field: 'type', | |
| 29 | - dictType: DICT_TYPE.SYSTEM_OPERATE_TYPE, | |
| 30 | - search: { | |
| 31 | - show: true | |
| 32 | - } | |
| 33 | - }, | |
| 34 | - { | |
| 35 | - label: '请求方法名', | |
| 36 | - field: 'requestMethod' | |
| 37 | - }, | |
| 38 | - { | |
| 39 | - label: '请求地址', | |
| 40 | - field: 'requestUrl' | |
| 41 | - }, | |
| 42 | - { | |
| 43 | - label: '操作人员', | |
| 44 | - field: 'userNickname', | |
| 45 | - search: { | |
| 46 | - show: true | |
| 47 | - } | |
| 48 | - }, | |
| 49 | - { | |
| 50 | - label: '操作明细', | |
| 51 | - field: 'content', | |
| 52 | - table: { | |
| 53 | - show: false | |
| 54 | - } | |
| 55 | - }, | |
| 56 | - { | |
| 57 | - label: '用户 IP', | |
| 58 | - field: 'userIp', | |
| 59 | - table: { | |
| 60 | - show: false | |
| 61 | - } | |
| 62 | - }, | |
| 63 | - { | |
| 64 | - label: 'userAgent', | |
| 65 | - field: 'userAgent' | |
| 66 | - }, | |
| 67 | - { | |
| 68 | - label: '操作结果', | |
| 69 | - field: 'resultCode', | |
| 70 | - search: { | |
| 71 | - show: true, | |
| 72 | - component: 'Select', | |
| 73 | - componentProps: { | |
| 74 | - options: [ | |
| 75 | - { label: '成功', value: true }, | |
| 76 | - { label: '失败', value: false } | |
| 77 | - ] | |
| 3 | +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas' | |
| 4 | + | |
| 5 | +const crudSchemas = reactive<VxeCrudSchema>({ | |
| 6 | + primaryKey: 'id', | |
| 7 | + primaryType: 'seq', | |
| 8 | + action: true, | |
| 9 | + actionWidth: '80px', | |
| 10 | + columns: [ | |
| 11 | + { | |
| 12 | + title: '操作模块', | |
| 13 | + field: 'module', | |
| 14 | + isSearch: true | |
| 15 | + }, | |
| 16 | + { | |
| 17 | + title: '操作名', | |
| 18 | + field: 'name' | |
| 19 | + }, | |
| 20 | + { | |
| 21 | + title: '操作类型', | |
| 22 | + field: 'type', | |
| 23 | + dictType: DICT_TYPE.SYSTEM_OPERATE_TYPE, | |
| 24 | + isSearch: true | |
| 25 | + }, | |
| 26 | + { | |
| 27 | + title: '请求方法名', | |
| 28 | + field: 'requestMethod' | |
| 29 | + }, | |
| 30 | + { | |
| 31 | + title: '请求地址', | |
| 32 | + field: 'requestUrl' | |
| 33 | + }, | |
| 34 | + { | |
| 35 | + title: '操作人员', | |
| 36 | + field: 'userNickname', | |
| 37 | + isSearch: true | |
| 38 | + }, | |
| 39 | + { | |
| 40 | + title: '操作明细', | |
| 41 | + field: 'content', | |
| 42 | + isTable: false | |
| 43 | + }, | |
| 44 | + { | |
| 45 | + title: '用户 IP', | |
| 46 | + field: 'userIp', | |
| 47 | + isTable: false | |
| 48 | + }, | |
| 49 | + { | |
| 50 | + title: 'userAgent', | |
| 51 | + field: 'userAgent' | |
| 52 | + }, | |
| 53 | + { | |
| 54 | + title: '操作结果', | |
| 55 | + field: 'resultCode', | |
| 56 | + table: { | |
| 57 | + slots: { | |
| 58 | + default: 'resultCode' | |
| 59 | + } | |
| 78 | 60 | } |
| 79 | - } | |
| 80 | - }, | |
| 81 | - { | |
| 82 | - label: '操作日期', | |
| 83 | - field: 'startTime', | |
| 84 | - form: { | |
| 85 | - show: false | |
| 86 | 61 | }, |
| 87 | - search: { | |
| 88 | - show: true, | |
| 89 | - component: 'DatePicker', | |
| 90 | - componentProps: { | |
| 91 | - type: 'daterange', | |
| 92 | - valueFormat: 'YYYY-MM-DD HH:mm:ss', | |
| 93 | - defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] | |
| 62 | + { | |
| 63 | + title: '操作日期', | |
| 64 | + field: 'startTime', | |
| 65 | + formatter: 'formatDate', | |
| 66 | + isForm: false, | |
| 67 | + search: { | |
| 68 | + itemRender: { | |
| 69 | + name: 'XDataTimePicker' | |
| 70 | + } | |
| 94 | 71 | } |
| 95 | - } | |
| 96 | - }, | |
| 97 | - { | |
| 98 | - label: '执行时长', | |
| 99 | - field: 'duration' | |
| 100 | - }, | |
| 101 | - { | |
| 102 | - label: t('table.action'), | |
| 103 | - field: 'action', | |
| 104 | - width: '120px', | |
| 105 | - form: { | |
| 106 | - show: false | |
| 107 | 72 | }, |
| 108 | - detail: { | |
| 109 | - show: false | |
| 73 | + { | |
| 74 | + title: '执行时长', | |
| 75 | + field: 'duration', | |
| 76 | + table: { | |
| 77 | + slots: { | |
| 78 | + default: 'duration' | |
| 79 | + } | |
| 80 | + } | |
| 110 | 81 | } |
| 111 | - } | |
| 112 | -]) | |
| 113 | -export const { allSchemas } = useCrudSchemas(crudSchemas) | |
| 82 | + ] | |
| 83 | +}) | |
| 84 | +export const { allSchemas } = useVxeCrudSchemas(crudSchemas) | ... | ... |
yudao-ui-admin-vue3/src/views/system/user/index.vue
| ... | ... | @@ -39,11 +39,6 @@ import { getAccessToken, getTenantId } from '@/utils/auth' |
| 39 | 39 | import { useMessage } from '@/hooks/web/useMessage' |
| 40 | 40 | |
| 41 | 41 | const message = useMessage() |
| 42 | -interface Tree { | |
| 43 | - id: number | |
| 44 | - name: string | |
| 45 | - children?: Tree[] | |
| 46 | -} | |
| 47 | 42 | |
| 48 | 43 | const defaultProps = { |
| 49 | 44 | children: 'children', | ... | ... |