mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 00:57:13 +08:00 
			
		
		
		
	新增:个人中心新增查询操作日志功能,优化日志表结构,并支持关闭记录内网 IP 操作
This commit is contained in:
		
							
								
								
									
										34
									
								
								continew-admin-ui/src/api/monitor/operation-log.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								continew-admin-ui/src/api/monitor/operation-log.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| import axios from 'axios'; | ||||
| import qs from 'query-string'; | ||||
|  | ||||
| export interface OperationLogRecord { | ||||
|   logId: string; | ||||
|   description: string; | ||||
|   result: number, | ||||
|   requestIp: string, | ||||
|   location: string, | ||||
|   browser: string, | ||||
|   createUserString: string; | ||||
|   createTime: string; | ||||
| } | ||||
|  | ||||
| export interface OperationLogParams extends Partial<OperationLogRecord> { | ||||
|   page: number; | ||||
|   size: number; | ||||
|   sort: Array<string>; | ||||
|   uid: string; | ||||
| } | ||||
|  | ||||
| export interface OperationLogListRes { | ||||
|   list: OperationLogRecord[]; | ||||
|   total: number; | ||||
| } | ||||
|  | ||||
| export function queryOperationLogList(params: OperationLogParams) { | ||||
|   return axios.get<OperationLogListRes>('/monitor/log/operation', { | ||||
|     params, | ||||
|     paramsSerializer: (obj) => { | ||||
|       return qs.stringify(obj); | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| @@ -90,5 +90,8 @@ body { | ||||
|     &.pass { | ||||
|       background-color: rgb(var(--green-6)); | ||||
|     } | ||||
|     &.fail { | ||||
|       background-color: rgb(var(--red-6)); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ import useAppStore from '../app'; | ||||
|  | ||||
| const useLoginStore = defineStore('user', { | ||||
|   state: (): UserState => ({ | ||||
|     userId: 1, | ||||
|     userId: '', | ||||
|     username: '', | ||||
|     nickname: '', | ||||
|     gender: 0, | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| export type RoleType = '' | '*' | 'admin' | 'user'; | ||||
| export interface UserState { | ||||
|   userId: number; | ||||
|   userId: string; | ||||
|   username: string; | ||||
|   nickname: string; | ||||
|   gender: number; | ||||
|   | ||||
| @@ -133,7 +133,7 @@ | ||||
|     captchaImgBase64.value = data.img | ||||
|   } | ||||
|   onMounted(() => { | ||||
|     getCaptcha() | ||||
|     getCaptcha(); | ||||
|   }) | ||||
|  | ||||
|   // 记住我 | ||||
|   | ||||
| @@ -0,0 +1,142 @@ | ||||
| <template> | ||||
|   <div class="container"> | ||||
|     <a-table | ||||
|       row-key="id" | ||||
|       :loading="loading" | ||||
|       :pagination="pagination" | ||||
|       :columns="columns" | ||||
|       :data="renderData" | ||||
|       :bordered="false" | ||||
|       size="large" | ||||
|       @page-change="onPageChange" | ||||
|     > | ||||
|       <template #index="{ rowIndex }"> | ||||
|         {{ rowIndex + 1 + (pagination.current - 1) * pagination.pageSize }} | ||||
|       </template> | ||||
|       <template #result="{ record }"> | ||||
|         <a-space v-if="record.result === 1"> | ||||
|           <a-tag color="green"> | ||||
|             <span class="circle pass"></span> | ||||
|             成功 | ||||
|           </a-tag> | ||||
|         </a-space> | ||||
|         <a-space v-else> | ||||
|           <a-tag color="red"> | ||||
|             <span class="circle fail"></span> | ||||
|             失败 | ||||
|           </a-tag> | ||||
|         </a-space> | ||||
|       </template> | ||||
|       <template #pagination-left> | ||||
|         <a-tooltip content="刷新"> | ||||
|           <div class="action-icon" @click="onRefresh"> | ||||
|             <icon-refresh size="18" /> | ||||
|           </div> | ||||
|         </a-tooltip> | ||||
|       </template> | ||||
|     </a-table> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
|   import { computed, ref, reactive } from "vue"; | ||||
|   import { useLoginStore } from '@/store'; | ||||
|   import useLoading from '@/hooks/loading'; | ||||
|   import { queryOperationLogList, OperationLogRecord, OperationLogParams } from '@/api/monitor/operation-log'; | ||||
|   import { Pagination } from '@/types/global'; | ||||
|   import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'; | ||||
|  | ||||
|   const { loading, setLoading } = useLoading(true); | ||||
|   const loginStore = useLoginStore(); | ||||
|   const renderData = ref<OperationLogRecord[]>([]); | ||||
|  | ||||
|   const basePagination: Pagination = { | ||||
|     current: 1, | ||||
|     pageSize: 10, | ||||
|   }; | ||||
|   const pagination = reactive({ | ||||
|     ...basePagination, | ||||
|   }); | ||||
|   const columns = computed<TableColumnData[]>(() => [ | ||||
|     { | ||||
|       title: '序号', | ||||
|       dataIndex: 'index', | ||||
|       slotName: 'index', | ||||
|     }, | ||||
|     { | ||||
|       title: '操作时间', | ||||
|       dataIndex: 'createTime', | ||||
|     }, | ||||
|     { | ||||
|       title: '操作内容', | ||||
|       dataIndex: 'description', | ||||
|     }, | ||||
|     { | ||||
|       title: '操作结果', | ||||
|       dataIndex: 'result', | ||||
|       slotName: 'result', | ||||
|     }, | ||||
|     { | ||||
|       title: '操作IP', | ||||
|       dataIndex: 'requestIp', | ||||
|     }, | ||||
|     { | ||||
|       title: '操作地点', | ||||
|       dataIndex: 'location', | ||||
|     }, | ||||
|     { | ||||
|       title: '浏览器', | ||||
|       dataIndex: 'browser', | ||||
|     }, | ||||
|   ]); | ||||
|   const fetchData = async ( | ||||
|     params: OperationLogParams = { uid: loginStore.userId, page: 1, size: 10, sort: ['createTime,desc'] } | ||||
|   ) => { | ||||
|     setLoading(true); | ||||
|     try { | ||||
|       const { data } = await queryOperationLogList(params); | ||||
|       renderData.value = data.list; | ||||
|       pagination.current = params.page; | ||||
|       pagination.total = data.total; | ||||
|     } catch (err) { | ||||
|       // you can report use errorHandler or other | ||||
|     } finally { | ||||
|       setLoading(false); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   const onPageChange = (current: number) => { | ||||
|     fetchData({ uid: loginStore.userId, page: current, size: pagination.pageSize, sort: ['createTime,desc'] }); | ||||
|   }; | ||||
|  | ||||
|   const onRefresh = () => { | ||||
|     fetchData({ | ||||
|       uid: loginStore.userId, | ||||
|       page: pagination.current, | ||||
|       size: pagination.pageSize, | ||||
|       sort: ['createTime,desc'], | ||||
|     } as unknown as OperationLogParams); | ||||
|   }; | ||||
|  | ||||
|   fetchData(); | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
|   .container { | ||||
|     padding: 0 20px 20px 20px; | ||||
|   } | ||||
|   :deep(.arco-table-th) { | ||||
|     &:last-child { | ||||
|       .arco-table-th-item-title { | ||||
|         margin-left: 16px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .action-icon { | ||||
|     cursor: pointer; | ||||
|   } | ||||
|  | ||||
|   .action-icon:hover { | ||||
|     color: #0960bd; | ||||
|   } | ||||
| </style> | ||||
| @@ -15,6 +15,9 @@ | ||||
|           <a-tab-pane key="2" :title="$t('userCenter.tab.securitySettings')"> | ||||
|             <SecuritySettings /> | ||||
|           </a-tab-pane> | ||||
|           <a-tab-pane key="3" :title="$t('userCenter.tab.operationLog')"> | ||||
|             <OperationLog /> | ||||
|           </a-tab-pane> | ||||
|         </a-tabs> | ||||
|       </a-col> | ||||
|     </a-row> | ||||
| @@ -25,6 +28,7 @@ | ||||
|   import UserPanel from './components/user-panel.vue'; | ||||
|   import BasicInfo from './components/basic-info.vue'; | ||||
|   import SecuritySettings from './components/security-settings.vue'; | ||||
|   import OperationLog from './components/operation-log.vue'; | ||||
| </script> | ||||
|  | ||||
| <script lang="ts"> | ||||
|   | ||||
| @@ -2,6 +2,7 @@ export default { | ||||
|   'menu.user.center': 'User Center', | ||||
|   'userCenter.tab.basicInfo': 'Basic Information', | ||||
|   'userCenter.tab.securitySettings': 'Security Settings', | ||||
|   'userCenter.tab.operationLog': 'Operation Log', | ||||
|  | ||||
|   // user-panel | ||||
|   'userCenter.panel.avatar': 'Avatar', | ||||
|   | ||||
| @@ -2,6 +2,7 @@ export default { | ||||
|   'menu.user.center': '个人中心', | ||||
|   'userCenter.tab.basicInfo': '基础信息', | ||||
|   'userCenter.tab.securitySettings': '安全设置', | ||||
|   'userCenter.tab.operationLog': '操作日志', | ||||
|  | ||||
|   // user-panel | ||||
|   'userCenter.panel.avatar': '头像', | ||||
|   | ||||
		Reference in New Issue
	
	Block a user