mirror of
				https://github.com/pure-admin/pure-admin-thin.git
				synced 2025-11-04 17:44:48 +08:00 
			
		
		
		
	feat: 新增操作日志列表
This commit is contained in:
		
							parent
							
								
									b262de72fb
								
							
						
					
					
						commit
						61a980a37d
					
				@ -7,6 +7,7 @@
 | 
				
			|||||||
const include = [
 | 
					const include = [
 | 
				
			||||||
  "qs",
 | 
					  "qs",
 | 
				
			||||||
  "mitt",
 | 
					  "mitt",
 | 
				
			||||||
 | 
					  "xlsx",
 | 
				
			||||||
  "dayjs",
 | 
					  "dayjs",
 | 
				
			||||||
  "axios",
 | 
					  "axios",
 | 
				
			||||||
  "pinia",
 | 
					  "pinia",
 | 
				
			||||||
 | 
				
			|||||||
@ -55,7 +55,8 @@
 | 
				
			|||||||
    "typeit": "^8.7.1",
 | 
					    "typeit": "^8.7.1",
 | 
				
			||||||
    "vue": "^3.3.4",
 | 
					    "vue": "^3.3.4",
 | 
				
			||||||
    "vue-router": "^4.2.2",
 | 
					    "vue-router": "^4.2.2",
 | 
				
			||||||
    "vue-types": "^5.1.0"
 | 
					    "vue-types": "^5.1.0",
 | 
				
			||||||
 | 
					    "xlsx": "^0.18.5"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@commitlint/cli": "^17.6.6",
 | 
					    "@commitlint/cli": "^17.6.6",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										89
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										89
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							@ -88,6 +88,7 @@ specifiers:
 | 
				
			|||||||
  vue-router: ^4.2.2
 | 
					  vue-router: ^4.2.2
 | 
				
			||||||
  vue-tsc: ^1.8.1
 | 
					  vue-tsc: ^1.8.1
 | 
				
			||||||
  vue-types: ^5.1.0
 | 
					  vue-types: ^5.1.0
 | 
				
			||||||
 | 
					  xlsx: ^0.18.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies:
 | 
					dependencies:
 | 
				
			||||||
  "@pureadmin/descriptions": 1.1.1_element-plus@2.3.6
 | 
					  "@pureadmin/descriptions": 1.1.1_element-plus@2.3.6
 | 
				
			||||||
@ -117,6 +118,7 @@ dependencies:
 | 
				
			|||||||
  vue: 3.3.4
 | 
					  vue: 3.3.4
 | 
				
			||||||
  vue-router: 4.2.2_vue@3.3.4
 | 
					  vue-router: 4.2.2_vue@3.3.4
 | 
				
			||||||
  vue-types: 5.1.0_vue@3.3.4
 | 
					  vue-types: 5.1.0_vue@3.3.4
 | 
				
			||||||
 | 
					  xlsx: 0.18.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
devDependencies:
 | 
					devDependencies:
 | 
				
			||||||
  "@commitlint/cli": 17.6.6
 | 
					  "@commitlint/cli": 17.6.6
 | 
				
			||||||
@ -2310,6 +2312,14 @@ packages:
 | 
				
			|||||||
    engines: { node: ">=0.4.0" }
 | 
					    engines: { node: ">=0.4.0" }
 | 
				
			||||||
    hasBin: true
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /adler-32/1.3.1:
 | 
				
			||||||
 | 
					    resolution:
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    engines: { node: ">=0.8" }
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /agent-base/6.0.2:
 | 
					  /agent-base/6.0.2:
 | 
				
			||||||
    resolution:
 | 
					    resolution:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -2732,6 +2742,17 @@ packages:
 | 
				
			|||||||
        integrity: sha512-sdQZOJdmt3GJs1UMNpCCCyeuS2IEGLXnHyAo9yIO5JJDjbjoVRij4M1qep6P6gFpptD1PqIYgzM+gwJbOi92mw==
 | 
					        integrity: sha512-sdQZOJdmt3GJs1UMNpCCCyeuS2IEGLXnHyAo9yIO5JJDjbjoVRij4M1qep6P6gFpptD1PqIYgzM+gwJbOi92mw==
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /cfb/1.2.2:
 | 
				
			||||||
 | 
					    resolution:
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    engines: { node: ">=0.8" }
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      adler-32: 1.3.1
 | 
				
			||||||
 | 
					      crc-32: 1.2.2
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /chalk/2.4.2:
 | 
					  /chalk/2.4.2:
 | 
				
			||||||
    resolution:
 | 
					    resolution:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -2870,6 +2891,14 @@ packages:
 | 
				
			|||||||
    hasBin: true
 | 
					    hasBin: true
 | 
				
			||||||
    dev: true
 | 
					    dev: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /codepage/1.15.0:
 | 
				
			||||||
 | 
					    resolution:
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    engines: { node: ">=0.8" }
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /color-convert/1.9.3:
 | 
					  /color-convert/1.9.3:
 | 
				
			||||||
    resolution:
 | 
					    resolution:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -3105,6 +3134,15 @@ packages:
 | 
				
			|||||||
      path-type: 4.0.0
 | 
					      path-type: 4.0.0
 | 
				
			||||||
    dev: true
 | 
					    dev: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /crc-32/1.2.2:
 | 
				
			||||||
 | 
					    resolution:
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    engines: { node: ">=0.8" }
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /create-require/1.1.1:
 | 
					  /create-require/1.1.1:
 | 
				
			||||||
    resolution:
 | 
					    resolution:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -4343,6 +4381,14 @@ packages:
 | 
				
			|||||||
      mime-types: 2.1.35
 | 
					      mime-types: 2.1.35
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /frac/1.1.2:
 | 
				
			||||||
 | 
					    resolution:
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    engines: { node: ">=0.8" }
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /fraction.js/4.2.0:
 | 
					  /fraction.js/4.2.0:
 | 
				
			||||||
    resolution:
 | 
					    resolution:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -7965,6 +8011,16 @@ packages:
 | 
				
			|||||||
      readable-stream: 3.6.2
 | 
					      readable-stream: 3.6.2
 | 
				
			||||||
    dev: true
 | 
					    dev: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /ssf/0.11.2:
 | 
				
			||||||
 | 
					    resolution:
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    engines: { node: ">=0.8" }
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      frac: 1.1.2
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /stable/0.1.8:
 | 
					  /stable/0.1.8:
 | 
				
			||||||
    resolution:
 | 
					    resolution:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -9210,6 +9266,14 @@ packages:
 | 
				
			|||||||
      isexe: 2.0.0
 | 
					      isexe: 2.0.0
 | 
				
			||||||
    dev: true
 | 
					    dev: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /wmf/1.0.2:
 | 
				
			||||||
 | 
					    resolution:
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    engines: { node: ">=0.8" }
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /word-wrap/1.2.3:
 | 
					  /word-wrap/1.2.3:
 | 
				
			||||||
    resolution:
 | 
					    resolution:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -9218,6 +9282,14 @@ packages:
 | 
				
			|||||||
    engines: { node: ">=0.10.0" }
 | 
					    engines: { node: ">=0.10.0" }
 | 
				
			||||||
    dev: true
 | 
					    dev: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /word/0.3.0:
 | 
				
			||||||
 | 
					    resolution:
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    engines: { node: ">=0.8" }
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /wrap-ansi/6.2.0:
 | 
					  /wrap-ansi/6.2.0:
 | 
				
			||||||
    resolution:
 | 
					    resolution:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -9271,6 +9343,23 @@ packages:
 | 
				
			|||||||
      signal-exit: 4.0.2
 | 
					      signal-exit: 4.0.2
 | 
				
			||||||
    dev: true
 | 
					    dev: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /xlsx/0.18.5:
 | 
				
			||||||
 | 
					    resolution:
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    engines: { node: ">=0.8" }
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      adler-32: 1.3.1
 | 
				
			||||||
 | 
					      cfb: 1.2.2
 | 
				
			||||||
 | 
					      codepage: 1.15.0
 | 
				
			||||||
 | 
					      crc-32: 1.2.2
 | 
				
			||||||
 | 
					      ssf: 0.11.2
 | 
				
			||||||
 | 
					      wmf: 1.0.2
 | 
				
			||||||
 | 
					      word: 0.3.0
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /xml-name-validator/4.0.0:
 | 
					  /xml-name-validator/4.0.0:
 | 
				
			||||||
    resolution:
 | 
					    resolution:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										52
									
								
								src/api/system/log.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/api/system/log.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					import { http } from "@/utils/http";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface OperationLogsQuery extends BasePageQuery {
 | 
				
			||||||
 | 
					  businessType?: string;
 | 
				
			||||||
 | 
					  requestModule?: string;
 | 
				
			||||||
 | 
					  status?: string;
 | 
				
			||||||
 | 
					  username?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface OperationLogDTO {
 | 
				
			||||||
 | 
					  businessType?: number;
 | 
				
			||||||
 | 
					  businessTypeStr?: string;
 | 
				
			||||||
 | 
					  calledMethod?: string;
 | 
				
			||||||
 | 
					  deptId?: number;
 | 
				
			||||||
 | 
					  deptName?: string;
 | 
				
			||||||
 | 
					  errorStack?: string;
 | 
				
			||||||
 | 
					  operationId?: number;
 | 
				
			||||||
 | 
					  operationParam?: string;
 | 
				
			||||||
 | 
					  operationResult?: string;
 | 
				
			||||||
 | 
					  operationTime?: Date;
 | 
				
			||||||
 | 
					  operatorIp?: string;
 | 
				
			||||||
 | 
					  operatorLocation?: string;
 | 
				
			||||||
 | 
					  operatorType?: number;
 | 
				
			||||||
 | 
					  operatorTypeStr?: string;
 | 
				
			||||||
 | 
					  requestMethod?: string;
 | 
				
			||||||
 | 
					  requestModule?: string;
 | 
				
			||||||
 | 
					  requestUrl?: string;
 | 
				
			||||||
 | 
					  status?: number;
 | 
				
			||||||
 | 
					  statusStr?: string;
 | 
				
			||||||
 | 
					  userId?: number;
 | 
				
			||||||
 | 
					  username?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 获取操作日志列表 */
 | 
				
			||||||
 | 
					export const getOperationLogListApi = (params?: OperationLogsQuery) => {
 | 
				
			||||||
 | 
					  return http.request<ResponseData<PageDTO<OperationLogDTO>>>(
 | 
				
			||||||
 | 
					    "get",
 | 
				
			||||||
 | 
					    "/logs/operationLogs",
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      params
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const deleteOperationLogApi = (data: Array<number>) => {
 | 
				
			||||||
 | 
					  return http.request<ResponseData<void>>("delete", "/logs/operationLogs", {
 | 
				
			||||||
 | 
					    params: {
 | 
				
			||||||
 | 
					      // 需要将数组转换为字符串  否则Axios会将参数变成 noticeIds[0]:1  noticeIds[1]:2 这种格式,后端接收参数不成功
 | 
				
			||||||
 | 
					      operationIds: data.toString()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -9,7 +9,7 @@ import { MotionPlugin } from "@vueuse/motion";
 | 
				
			|||||||
import { injectResponsiveStorage } from "@/utils/responsive";
 | 
					import { injectResponsiveStorage } from "@/utils/responsive";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Table from "@pureadmin/table";
 | 
					import Table from "@pureadmin/table";
 | 
				
			||||||
// import PureDescriptions from "@pureadmin/descriptions";
 | 
					import PureDescriptions from "@pureadmin/descriptions";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 引入重置样式
 | 
					// 引入重置样式
 | 
				
			||||||
import "./style/reset.scss";
 | 
					import "./style/reset.scss";
 | 
				
			||||||
@ -53,7 +53,7 @@ getServerConfig(app).then(async config => {
 | 
				
			|||||||
    .use(MotionPlugin)
 | 
					    .use(MotionPlugin)
 | 
				
			||||||
    .use(ElementPlus)
 | 
					    .use(ElementPlus)
 | 
				
			||||||
    // .use(useEcharts);
 | 
					    // .use(useEcharts);
 | 
				
			||||||
    .use(Table);
 | 
					    .use(Table)
 | 
				
			||||||
  // .use(PureDescriptions);
 | 
					    .use(PureDescriptions);
 | 
				
			||||||
  app.mount("#app");
 | 
					  app.mount("#app");
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
import { PaginationProps } from "@pureadmin/table";
 | 
					import { PaginationProps, TableColumn } from "@pureadmin/table";
 | 
				
			||||||
import { Sort } from "element-plus";
 | 
					import { Sort } from "element-plus";
 | 
				
			||||||
 | 
					import { utils, writeFile } from "xlsx";
 | 
				
			||||||
 | 
					import { message } from "./message";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class CommonUtils {
 | 
					export class CommonUtils {
 | 
				
			||||||
  static getBeginTimeSafely(timeRange: string[]): string {
 | 
					  static getBeginTimeSafely(timeRange: string[]): string {
 | 
				
			||||||
@ -50,6 +52,68 @@ export class CommonUtils {
 | 
				
			|||||||
    baseQuery.orderDirection = sort.order;
 | 
					    baseQuery.orderDirection = sort.order;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** 适用于BaseQuery中固定的时间参数  beginTime和endTime参数 */
 | 
				
			||||||
 | 
					  static fillTimeRangeParams(baseQuery: any, timeRange: string[]) {
 | 
				
			||||||
 | 
					    if (timeRange == null || timeRange.length == 0 || timeRange === undefined) {
 | 
				
			||||||
 | 
					      baseQuery["beginTime"] = undefined;
 | 
				
			||||||
 | 
					      baseQuery["endTime"] = undefined;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (baseQuery == null || baseQuery === undefined) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    baseQuery["beginTime"] = CommonUtils.getBeginTimeSafely(timeRange);
 | 
				
			||||||
 | 
					    baseQuery["endTime"] = CommonUtils.getEndTimeSafely(timeRange);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static exportExcel(
 | 
				
			||||||
 | 
					    columns: TableColumnList,
 | 
				
			||||||
 | 
					    originalDataList: any[],
 | 
				
			||||||
 | 
					    excelName: string
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      !Array.isArray(columns) ||
 | 
				
			||||||
 | 
					      !Array.isArray(originalDataList) ||
 | 
				
			||||||
 | 
					      typeof excelName !== "string"
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      message("参数异常,导出失败", { type: "error" });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // columns和dataList为空的话 弹出提示 不执行导出
 | 
				
			||||||
 | 
					    if (columns.length === 0 || originalDataList.length === 0) {
 | 
				
			||||||
 | 
					      message("无法导出空列表", { type: "warning" });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const titleList: string[] = [];
 | 
				
			||||||
 | 
					    const dataKeyList: string[] = [];
 | 
				
			||||||
 | 
					    // 把columns里面的label取出来作为excel的列标题,把prop取出来等下从dataList里面根据作为key取对象中的值
 | 
				
			||||||
 | 
					    columns.forEach((column: TableColumn) => {
 | 
				
			||||||
 | 
					      if (column.label && column.prop) {
 | 
				
			||||||
 | 
					        titleList.push(column.label);
 | 
				
			||||||
 | 
					        dataKeyList.push(column.prop as string);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const excelDataList: string[][] = originalDataList.map(item => {
 | 
				
			||||||
 | 
					      const arr = [];
 | 
				
			||||||
 | 
					      dataKeyList.forEach(dataKey => {
 | 
				
			||||||
 | 
					        arr.push(item[dataKey]);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return arr;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    excelDataList.unshift(titleList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const workSheet = utils.aoa_to_sheet(excelDataList);
 | 
				
			||||||
 | 
					    const workBook = utils.book_new();
 | 
				
			||||||
 | 
					    utils.book_append_sheet(workBook, workSheet, excelName);
 | 
				
			||||||
 | 
					    writeFile(workBook, `${excelName}.xlsx`);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 私有构造函数,防止类被实例化
 | 
					  // 私有构造函数,防止类被实例化
 | 
				
			||||||
  private constructor() {}
 | 
					  private constructor() {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -125,6 +125,8 @@ class PureHttp {
 | 
				
			|||||||
              .catch(() => {
 | 
					              .catch(() => {
 | 
				
			||||||
                message("取消重新登录", { type: "info" });
 | 
					                message("取消重新登录", { type: "info" });
 | 
				
			||||||
              });
 | 
					              });
 | 
				
			||||||
 | 
					            NProgress.done();
 | 
				
			||||||
 | 
					            return Promise.reject(response.data.msg);
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            // 其余情况弹出错误提示框
 | 
					            // 其余情况弹出错误提示框
 | 
				
			||||||
            message(response.data.msg, { type: "error" });
 | 
					            message(response.data.msg, { type: "error" });
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										93
									
								
								src/views/system/log/operationLog/description.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/views/system/log/operationLog/description.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,93 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { useUserStoreHook } from "@/store/modules/user";
 | 
				
			||||||
 | 
					import { OperationLogDTO } from "../../../../api/system/log";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** TODO 有其他方式  来换掉这个props 父子组件传值吗? */
 | 
				
			||||||
 | 
					const props = defineProps<OperationLogDTO>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const operationLogStatusMap =
 | 
				
			||||||
 | 
					  useUserStoreHook().dictionaryMap["sysOperationLog.status"];
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <el-descriptions
 | 
				
			||||||
 | 
					    direction="horizontal"
 | 
				
			||||||
 | 
					    :column="2"
 | 
				
			||||||
 | 
					    :labelStyle="'white-space:nowrap;'"
 | 
				
			||||||
 | 
					    :contentStyle="'word-break:break-all;'"
 | 
				
			||||||
 | 
					    :size="'large'"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <!-- 开头前两列设置宽度 -->
 | 
				
			||||||
 | 
					    <el-descriptions-item label="操作编号:" :width="'25%'">{{
 | 
				
			||||||
 | 
					      props.operationId
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item label="请求模块:" :width="'25%'">{{
 | 
				
			||||||
 | 
					      props.requestModule
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item :span="2" label="操作类型:">{{
 | 
				
			||||||
 | 
					      props.businessTypeStr
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item label="操作人:">{{
 | 
				
			||||||
 | 
					      props.username
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item label="操作人ID:">{{
 | 
				
			||||||
 | 
					      props.userId
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item label="操作人类型:">{{
 | 
				
			||||||
 | 
					      props.operatorTypeStr
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item label="操作人部门:">{{
 | 
				
			||||||
 | 
					      props.deptName
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item label="操作人IP:">{{
 | 
				
			||||||
 | 
					      props.operatorIp
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item :span="2" label="操作人地址:">{{
 | 
				
			||||||
 | 
					      props.operatorLocation
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <el-descriptions-item label="请求链接:">{{
 | 
				
			||||||
 | 
					      props.requestUrl
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item label="请求方式:">{{
 | 
				
			||||||
 | 
					      props.requestMethod
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item :span="2" label="请求参数:">
 | 
				
			||||||
 | 
					      <!-- 长度可能较长的字符串使用el-text包住 避免超出框 -->
 | 
				
			||||||
 | 
					      <el-text>
 | 
				
			||||||
 | 
					        {{ props.operationParam }}
 | 
				
			||||||
 | 
					      </el-text>
 | 
				
			||||||
 | 
					    </el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item :span="2" label="调用方法:">
 | 
				
			||||||
 | 
					      <el-text>
 | 
				
			||||||
 | 
					        {{ props.calledMethod }}
 | 
				
			||||||
 | 
					      </el-text>
 | 
				
			||||||
 | 
					    </el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item :span="2" label="返回结果:">
 | 
				
			||||||
 | 
					      <el-text>
 | 
				
			||||||
 | 
					        {{ props.operationResult }}
 | 
				
			||||||
 | 
					      </el-text>
 | 
				
			||||||
 | 
					    </el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item :span="2" label="错误详情:">
 | 
				
			||||||
 | 
					      <el-text>
 | 
				
			||||||
 | 
					        {{ props.errorStack }}
 | 
				
			||||||
 | 
					      </el-text>
 | 
				
			||||||
 | 
					    </el-descriptions-item>
 | 
				
			||||||
 | 
					    <el-descriptions-item label="状态:"
 | 
				
			||||||
 | 
					      ><el-tag
 | 
				
			||||||
 | 
					        :type="operationLogStatusMap[props.status].cssTag"
 | 
				
			||||||
 | 
					        effect="plain"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {{ operationLogStatusMap[props.status].label }}
 | 
				
			||||||
 | 
					      </el-tag></el-descriptions-item
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					    <el-descriptions-item label="操作时间:">{{
 | 
				
			||||||
 | 
					      props.operationTime
 | 
				
			||||||
 | 
					    }}</el-descriptions-item>
 | 
				
			||||||
 | 
					  </el-descriptions>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					.el-descriptions {
 | 
				
			||||||
 | 
					  margin-top: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										226
									
								
								src/views/system/log/operationLog/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								src/views/system/log/operationLog/index.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,226 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { ref } from "vue";
 | 
				
			||||||
 | 
					import { useOperationLogHook } from "./utils/hook";
 | 
				
			||||||
 | 
					import { PureTableBar } from "@/components/RePureTableBar";
 | 
				
			||||||
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Delete from "@iconify-icons/ep/delete";
 | 
				
			||||||
 | 
					import View from "@iconify-icons/ep/view";
 | 
				
			||||||
 | 
					import Search from "@iconify-icons/ep/search";
 | 
				
			||||||
 | 
					import Refresh from "@iconify-icons/ep/refresh";
 | 
				
			||||||
 | 
					import { useUserStoreHook } from "@/store/modules/user";
 | 
				
			||||||
 | 
					// 这个导入声明好长  看看如何优化
 | 
				
			||||||
 | 
					import { CommonUtils } from "../../../../utils/common";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 组件name最好和菜单表中的router_name一致 */
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: "SystemOperationLog"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const businessTypeList =
 | 
				
			||||||
 | 
					  useUserStoreHook().dictionaryList["sysOperationLog.businessType"];
 | 
				
			||||||
 | 
					const operationStatusList =
 | 
				
			||||||
 | 
					  useUserStoreHook().dictionaryList["sysOperationLog.status"];
 | 
				
			||||||
 | 
					const tableRef = ref();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const searchFormRef = ref();
 | 
				
			||||||
 | 
					const {
 | 
				
			||||||
 | 
					  searchFormParams,
 | 
				
			||||||
 | 
					  pageLoading,
 | 
				
			||||||
 | 
					  columns,
 | 
				
			||||||
 | 
					  dataList,
 | 
				
			||||||
 | 
					  pagination,
 | 
				
			||||||
 | 
					  timeRange,
 | 
				
			||||||
 | 
					  defaultSort,
 | 
				
			||||||
 | 
					  multipleSelection,
 | 
				
			||||||
 | 
					  onSearch,
 | 
				
			||||||
 | 
					  resetForm,
 | 
				
			||||||
 | 
					  openDialog,
 | 
				
			||||||
 | 
					  getOperationLogList,
 | 
				
			||||||
 | 
					  handleDelete,
 | 
				
			||||||
 | 
					  handleBulkDelete
 | 
				
			||||||
 | 
					} = useOperationLogHook();
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="main">
 | 
				
			||||||
 | 
					    <!-- 搜索栏 -->
 | 
				
			||||||
 | 
					    <el-form
 | 
				
			||||||
 | 
					      ref="searchFormRef"
 | 
				
			||||||
 | 
					      :inline="true"
 | 
				
			||||||
 | 
					      :model="searchFormParams"
 | 
				
			||||||
 | 
					      class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <el-form-item label="系统模块:" prop="requestModule">
 | 
				
			||||||
 | 
					        <el-input
 | 
				
			||||||
 | 
					          v-model="searchFormParams.requestModule"
 | 
				
			||||||
 | 
					          placeholder="请输入系统模块"
 | 
				
			||||||
 | 
					          clearable
 | 
				
			||||||
 | 
					          class="!w-[200px]"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <el-form-item label="操作类型:" prop="businessType">
 | 
				
			||||||
 | 
					        <el-select
 | 
				
			||||||
 | 
					          v-model="searchFormParams.businessType"
 | 
				
			||||||
 | 
					          placeholder="请选择状态"
 | 
				
			||||||
 | 
					          clearable
 | 
				
			||||||
 | 
					          class="!w-[180px]"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <el-option
 | 
				
			||||||
 | 
					            v-for="dict in businessTypeList"
 | 
				
			||||||
 | 
					            :key="dict.value"
 | 
				
			||||||
 | 
					            :label="dict.label"
 | 
				
			||||||
 | 
					            :value="dict.value"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </el-select>
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					      <el-form-item label="操作人员:" prop="username">
 | 
				
			||||||
 | 
					        <el-input
 | 
				
			||||||
 | 
					          v-model="searchFormParams.username"
 | 
				
			||||||
 | 
					          placeholder="请输入创建者"
 | 
				
			||||||
 | 
					          clearable
 | 
				
			||||||
 | 
					          class="!w-[180px]"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					      <el-form-item label="状态:" prop="status">
 | 
				
			||||||
 | 
					        <el-select
 | 
				
			||||||
 | 
					          v-model="searchFormParams.status"
 | 
				
			||||||
 | 
					          placeholder="请选择状态"
 | 
				
			||||||
 | 
					          clearable
 | 
				
			||||||
 | 
					          class="!w-[180px]"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <el-option
 | 
				
			||||||
 | 
					            v-for="dict in operationStatusList"
 | 
				
			||||||
 | 
					            :key="dict.value"
 | 
				
			||||||
 | 
					            :label="dict.label"
 | 
				
			||||||
 | 
					            :value="dict.value"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </el-select>
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					      <el-form-item>
 | 
				
			||||||
 | 
					        <label class="el-form-item__label is-required font-bold"
 | 
				
			||||||
 | 
					          >操作时间:</label
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					        <!-- TODO 如何消除这个v-model的warning -->
 | 
				
			||||||
 | 
					        <el-date-picker
 | 
				
			||||||
 | 
					          class="!w-[240px]"
 | 
				
			||||||
 | 
					          v-model="timeRange"
 | 
				
			||||||
 | 
					          value-format="YYYY-MM-DD"
 | 
				
			||||||
 | 
					          type="daterange"
 | 
				
			||||||
 | 
					          range-separator="-"
 | 
				
			||||||
 | 
					          start-placeholder="开始日期"
 | 
				
			||||||
 | 
					          end-placeholder="结束日期"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					      <el-form-item>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          :icon="useRenderIcon(Search)"
 | 
				
			||||||
 | 
					          :loading="pageLoading"
 | 
				
			||||||
 | 
					          @click="onSearch"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          搜索
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          :icon="useRenderIcon(Refresh)"
 | 
				
			||||||
 | 
					          @click="resetForm(searchFormRef, tableRef)"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          重置
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					    </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- table bar 包裹  table -->
 | 
				
			||||||
 | 
					    <PureTableBar title="通知列表" :columns="columns" @refresh="onSearch">
 | 
				
			||||||
 | 
					      <!-- 表格操作栏 -->
 | 
				
			||||||
 | 
					      <template #buttons>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="danger"
 | 
				
			||||||
 | 
					          :icon="useRenderIcon(Delete)"
 | 
				
			||||||
 | 
					          @click="handleBulkDelete(tableRef)"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          批量删除
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          @click="CommonUtils.exportExcel(columns, dataList, '操作日志列表')"
 | 
				
			||||||
 | 
					          >单页导出</el-button
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          @click="CommonUtils.exportExcel(columns, dataList, '操作日志列表')"
 | 
				
			||||||
 | 
					          >全部导出</el-button
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					      <template v-slot="{ size, dynamicColumns }">
 | 
				
			||||||
 | 
					        <pure-table
 | 
				
			||||||
 | 
					          border
 | 
				
			||||||
 | 
					          ref="tableRef"
 | 
				
			||||||
 | 
					          align-whole="center"
 | 
				
			||||||
 | 
					          showOverflowTooltip
 | 
				
			||||||
 | 
					          table-layout="auto"
 | 
				
			||||||
 | 
					          :loading="pageLoading"
 | 
				
			||||||
 | 
					          :size="size"
 | 
				
			||||||
 | 
					          adaptive
 | 
				
			||||||
 | 
					          :data="dataList"
 | 
				
			||||||
 | 
					          :columns="dynamicColumns"
 | 
				
			||||||
 | 
					          :default-sort="defaultSort"
 | 
				
			||||||
 | 
					          :pagination="pagination"
 | 
				
			||||||
 | 
					          :paginationSmall="size === 'small' ? true : false"
 | 
				
			||||||
 | 
					          :header-cell-style="{
 | 
				
			||||||
 | 
					            background: 'var(--el-table-row-hover-bg-color)',
 | 
				
			||||||
 | 
					            color: 'var(--el-text-color-primary)'
 | 
				
			||||||
 | 
					          }"
 | 
				
			||||||
 | 
					          @page-size-change="getOperationLogList"
 | 
				
			||||||
 | 
					          @page-current-change="getOperationLogList"
 | 
				
			||||||
 | 
					          @sort-change="getOperationLogList"
 | 
				
			||||||
 | 
					          @selection-change="
 | 
				
			||||||
 | 
					            rows => (multipleSelection = rows.map(item => item.operationId))
 | 
				
			||||||
 | 
					          "
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <template #operation="{ row }">
 | 
				
			||||||
 | 
					            <el-button
 | 
				
			||||||
 | 
					              class="reset-margin"
 | 
				
			||||||
 | 
					              link
 | 
				
			||||||
 | 
					              type="primary"
 | 
				
			||||||
 | 
					              :size="size"
 | 
				
			||||||
 | 
					              :icon="useRenderIcon(View)"
 | 
				
			||||||
 | 
					              @click="openDialog(row)"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              详情
 | 
				
			||||||
 | 
					            </el-button>
 | 
				
			||||||
 | 
					            <el-popconfirm
 | 
				
			||||||
 | 
					              :title="`是否确认删除编号为${row.operationId}的这条日志`"
 | 
				
			||||||
 | 
					              @confirm="handleDelete(row)"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <template #reference>
 | 
				
			||||||
 | 
					                <el-button
 | 
				
			||||||
 | 
					                  class="reset-margin"
 | 
				
			||||||
 | 
					                  link
 | 
				
			||||||
 | 
					                  type="danger"
 | 
				
			||||||
 | 
					                  :size="size"
 | 
				
			||||||
 | 
					                  :icon="useRenderIcon(Delete)"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  删除
 | 
				
			||||||
 | 
					                </el-button>
 | 
				
			||||||
 | 
					              </template>
 | 
				
			||||||
 | 
					            </el-popconfirm>
 | 
				
			||||||
 | 
					          </template>
 | 
				
			||||||
 | 
					        </pure-table>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </PureTableBar>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped lang="scss">
 | 
				
			||||||
 | 
					:deep(.el-dropdown-menu__item i) {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-form {
 | 
				
			||||||
 | 
					  :deep(.el-form-item) {
 | 
				
			||||||
 | 
					    margin-bottom: 12px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										254
									
								
								src/views/system/log/operationLog/utils/hook.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								src/views/system/log/operationLog/utils/hook.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,254 @@
 | 
				
			|||||||
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
 | 
					import descriptionForm from "../description.vue";
 | 
				
			||||||
 | 
					import { message } from "@/utils/message";
 | 
				
			||||||
 | 
					import { addDialog, closeDialog } from "@/components/ReDialog";
 | 
				
			||||||
 | 
					import { ElMessageBox, Sort } from "element-plus";
 | 
				
			||||||
 | 
					import { OperationLogsQuery, getOperationLogListApi } from "@/api/system/log";
 | 
				
			||||||
 | 
					import { reactive, ref, onMounted, h, toRaw } from "vue";
 | 
				
			||||||
 | 
					import { useUserStoreHook } from "@/store/modules/user";
 | 
				
			||||||
 | 
					import { deleteOperationLogApi } from "@/api/system/log";
 | 
				
			||||||
 | 
					import { CommonUtils } from "@/utils/common";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const operationLogStatusMap =
 | 
				
			||||||
 | 
					  useUserStoreHook().dictionaryMap["sysOperationLog.status"];
 | 
				
			||||||
 | 
					const businessTypeMap =
 | 
				
			||||||
 | 
					  useUserStoreHook().dictionaryMap["sysOperationLog.businessType"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useOperationLogHook() {
 | 
				
			||||||
 | 
					  const defaultSort: Sort = {
 | 
				
			||||||
 | 
					    prop: "operationTime",
 | 
				
			||||||
 | 
					    order: "descending"
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const pagination: PaginationProps = {
 | 
				
			||||||
 | 
					    total: 0,
 | 
				
			||||||
 | 
					    pageSize: 10,
 | 
				
			||||||
 | 
					    currentPage: 1,
 | 
				
			||||||
 | 
					    background: true
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const timeRange = ref([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const searchFormParams = reactive<OperationLogsQuery>({
 | 
				
			||||||
 | 
					    beginTime: undefined,
 | 
				
			||||||
 | 
					    endTime: undefined,
 | 
				
			||||||
 | 
					    businessType: undefined,
 | 
				
			||||||
 | 
					    requestModule: undefined,
 | 
				
			||||||
 | 
					    status: undefined,
 | 
				
			||||||
 | 
					    username: undefined,
 | 
				
			||||||
 | 
					    timeRangeColumn: defaultSort.prop
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const dataList = ref([]);
 | 
				
			||||||
 | 
					  const pageLoading = ref(true);
 | 
				
			||||||
 | 
					  const multipleSelection = ref([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const columns: TableColumnList = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: "selection",
 | 
				
			||||||
 | 
					      align: "left"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "操作编号",
 | 
				
			||||||
 | 
					      prop: "operationId",
 | 
				
			||||||
 | 
					      minWidth: 100
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "业务模块",
 | 
				
			||||||
 | 
					      prop: "requestModule",
 | 
				
			||||||
 | 
					      minWidth: 120
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "操作类型",
 | 
				
			||||||
 | 
					      prop: "businessType",
 | 
				
			||||||
 | 
					      minWidth: 120,
 | 
				
			||||||
 | 
					      cellRenderer: ({ row, props }) => (
 | 
				
			||||||
 | 
					        <el-tag
 | 
				
			||||||
 | 
					          size={props.size}
 | 
				
			||||||
 | 
					          type={businessTypeMap[row.businessType].cssTag}
 | 
				
			||||||
 | 
					          effect="plain"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          {businessTypeMap[row.businessType].label}
 | 
				
			||||||
 | 
					        </el-tag>
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "请求方式",
 | 
				
			||||||
 | 
					      prop: "requestMethod",
 | 
				
			||||||
 | 
					      minWidth: 120
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "操作人员",
 | 
				
			||||||
 | 
					      prop: "username",
 | 
				
			||||||
 | 
					      minWidth: 120
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "登录地址",
 | 
				
			||||||
 | 
					      prop: "operatorIp",
 | 
				
			||||||
 | 
					      minWidth: 120
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "状态",
 | 
				
			||||||
 | 
					      prop: "status",
 | 
				
			||||||
 | 
					      minWidth: 120,
 | 
				
			||||||
 | 
					      cellRenderer: ({ row, props }) => (
 | 
				
			||||||
 | 
					        <el-tag
 | 
				
			||||||
 | 
					          size={props.size}
 | 
				
			||||||
 | 
					          type={operationLogStatusMap[row.status].cssTag}
 | 
				
			||||||
 | 
					          effect="plain"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          {operationLogStatusMap[row.status].label}
 | 
				
			||||||
 | 
					        </el-tag>
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "状态名",
 | 
				
			||||||
 | 
					      prop: "statusStr",
 | 
				
			||||||
 | 
					      minWidth: 120,
 | 
				
			||||||
 | 
					      hide: true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "操作时间",
 | 
				
			||||||
 | 
					      minWidth: 160,
 | 
				
			||||||
 | 
					      prop: "operationTime",
 | 
				
			||||||
 | 
					      sortable: "custom",
 | 
				
			||||||
 | 
					      formatter: ({ operationTime }) =>
 | 
				
			||||||
 | 
					        dayjs(operationTime).format("YYYY-MM-DD HH:mm:ss")
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "操作",
 | 
				
			||||||
 | 
					      fixed: "right",
 | 
				
			||||||
 | 
					      width: 140,
 | 
				
			||||||
 | 
					      slot: "operation"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function onSearch() {
 | 
				
			||||||
 | 
					    // 点击搜索的时候 需要重置分页
 | 
				
			||||||
 | 
					    pagination.currentPage = 1;
 | 
				
			||||||
 | 
					    getOperationLogList();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function resetForm(formEl, tableRef) {
 | 
				
			||||||
 | 
					    if (!formEl) return;
 | 
				
			||||||
 | 
					    // 清空查询参数
 | 
				
			||||||
 | 
					    formEl.resetFields();
 | 
				
			||||||
 | 
					    // 清空排序
 | 
				
			||||||
 | 
					    searchFormParams.orderColumn = undefined;
 | 
				
			||||||
 | 
					    searchFormParams.orderDirection = undefined;
 | 
				
			||||||
 | 
					    // 清空时间查询  TODO  这块有点繁琐  有可以优化的地方吗?
 | 
				
			||||||
 | 
					    // Form组件的resetFields方法无法清除datepicker里面的数据。
 | 
				
			||||||
 | 
					    timeRange.value = [];
 | 
				
			||||||
 | 
					    searchFormParams.beginTime = undefined;
 | 
				
			||||||
 | 
					    searchFormParams.endTime = undefined;
 | 
				
			||||||
 | 
					    tableRef.getTableRef().clearSort();
 | 
				
			||||||
 | 
					    // 重置分页并查询
 | 
				
			||||||
 | 
					    onSearch();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function getOperationLogList(sort: Sort = defaultSort) {
 | 
				
			||||||
 | 
					    pageLoading.value = true;
 | 
				
			||||||
 | 
					    if (sort != null) {
 | 
				
			||||||
 | 
					      CommonUtils.fillSortParams(searchFormParams, sort);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CommonUtils.fillPaginationParams(searchFormParams, pagination);
 | 
				
			||||||
 | 
					    CommonUtils.fillTimeRangeParams(searchFormParams, timeRange.value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await getOperationLogListApi(toRaw(searchFormParams));
 | 
				
			||||||
 | 
					    dataList.value = data.rows;
 | 
				
			||||||
 | 
					    pagination.total = data.total;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      pageLoading.value = false;
 | 
				
			||||||
 | 
					    }, 500);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function handleDelete(row) {
 | 
				
			||||||
 | 
					    await deleteOperationLogApi([row.operationId]).then(() => {
 | 
				
			||||||
 | 
					      message(`您删除了操作编号为${row.operationId}的这条数据`, {
 | 
				
			||||||
 | 
					        type: "success"
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      // 刷新列表
 | 
				
			||||||
 | 
					      getOperationLogList();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function handleBulkDelete(tableRef) {
 | 
				
			||||||
 | 
					    if (multipleSelection.value.length === 0) {
 | 
				
			||||||
 | 
					      message("请选择需要删除的数据", { type: "warning" });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ElMessageBox.confirm(
 | 
				
			||||||
 | 
					      `确认要<strong>删除</strong>编号为<strong style='color:var(--el-color-primary)'>[ ${multipleSelection.value} ]</strong>的日志吗?`,
 | 
				
			||||||
 | 
					      "系统提示",
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        confirmButtonText: "确定",
 | 
				
			||||||
 | 
					        cancelButtonText: "取消",
 | 
				
			||||||
 | 
					        type: "warning",
 | 
				
			||||||
 | 
					        dangerouslyUseHTMLString: true,
 | 
				
			||||||
 | 
					        draggable: true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					      .then(async () => {
 | 
				
			||||||
 | 
					        await deleteOperationLogApi(multipleSelection.value).then(() => {
 | 
				
			||||||
 | 
					          message(`您删除了日志编号为[ ${multipleSelection.value} ]的数据`, {
 | 
				
			||||||
 | 
					            type: "success"
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          // 刷新列表
 | 
				
			||||||
 | 
					          getOperationLogList();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch(() => {
 | 
				
			||||||
 | 
					        message("取消删除", {
 | 
				
			||||||
 | 
					          type: "info"
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        // 清空checkbox选择的数据
 | 
				
			||||||
 | 
					        tableRef.getTableRef().clearSelection();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function openDialog(row) {
 | 
				
			||||||
 | 
					    addDialog({
 | 
				
			||||||
 | 
					      title: "日志详情",
 | 
				
			||||||
 | 
					      width: "60%",
 | 
				
			||||||
 | 
					      draggable: true,
 | 
				
			||||||
 | 
					      fullscreenIcon: false,
 | 
				
			||||||
 | 
					      closeOnClickModal: true,
 | 
				
			||||||
 | 
					      contentRenderer: () => h(descriptionForm, toRaw(row)),
 | 
				
			||||||
 | 
					      footerButtons: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          label: "关闭",
 | 
				
			||||||
 | 
					          text: true,
 | 
				
			||||||
 | 
					          size: "large",
 | 
				
			||||||
 | 
					          bg: true,
 | 
				
			||||||
 | 
					          btnClick: ({ dialog: { options, index } }) => {
 | 
				
			||||||
 | 
					            closeDialog(options, index);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onMounted(() => {
 | 
				
			||||||
 | 
					    getOperationLogList();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    searchFormParams,
 | 
				
			||||||
 | 
					    pageLoading,
 | 
				
			||||||
 | 
					    columns,
 | 
				
			||||||
 | 
					    dataList,
 | 
				
			||||||
 | 
					    pagination,
 | 
				
			||||||
 | 
					    defaultSort,
 | 
				
			||||||
 | 
					    timeRange,
 | 
				
			||||||
 | 
					    multipleSelection,
 | 
				
			||||||
 | 
					    onSearch,
 | 
				
			||||||
 | 
					    // exportExcel,
 | 
				
			||||||
 | 
					    getOperationLogList,
 | 
				
			||||||
 | 
					    resetForm,
 | 
				
			||||||
 | 
					    openDialog,
 | 
				
			||||||
 | 
					    handleDelete,
 | 
				
			||||||
 | 
					    handleBulkDelete
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -190,7 +190,7 @@ export function useNoticeHook() {
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
      .then(async () => {
 | 
					      .then(async () => {
 | 
				
			||||||
        await deleteSystemNoticeApi(multipleSelection.value).then(() => {
 | 
					        await deleteSystemNoticeApi(multipleSelection.value).then(() => {
 | 
				
			||||||
          message(`您删除了通知编号为[ ${multipleSelection.value} ]的条数据`, {
 | 
					          message(`您删除了通知编号为[ ${multipleSelection.value} ]的数据`, {
 | 
				
			||||||
            type: "success"
 | 
					            type: "success"
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
          // 刷新列表
 | 
					          // 刷新列表
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user