feat: 新增后台全量导出excel

This commit is contained in:
valarchie 2023-07-16 13:56:17 +08:00
parent 61a980a37d
commit bc4d29cba0
5 changed files with 131 additions and 21 deletions

View File

@ -42,6 +42,15 @@ export const getOperationLogListApi = (params?: OperationLogsQuery) => {
);
};
export const exportOperationLogExcelApi = (
params: OperationLogsQuery,
fileName: string
) => {
return http.download("/logs/operationLogs/excel", fileName, {
params
});
};
export const deleteOperationLogApi = (data: Array<number>) => {
return http.request<ResponseData<void>>("delete", "/logs/operationLogs", {
params: {

View File

@ -16,6 +16,7 @@ import { message } from "../message";
import { ElMessageBox } from "element-plus";
import { router } from "@/router";
import { removeToken } from "@/utils/auth";
import { downloadByData } from "@pureadmin/utils";
// console.log("Utils:" + router);
const { VITE_APP_BASE_API } = import.meta.env;
@ -104,7 +105,34 @@ class PureHttp {
private httpInterceptorsResponse(): void {
const instance = PureHttp.axiosInstance;
instance.interceptors.response.use(
(response: PureHttpResponse) => {
async (response: PureHttpResponse) => {
let code = undefined;
let msg = undefined;
// 后台返回的二进制流
if (response.data instanceof Blob) {
// 返回二进制流的时候 可能出错 这时候返回的错误是Json格式
if (response.data.type === "application/json") {
const text = await this.readBlobAsText(response.data);
const json = JSON.parse(text);
// 提取错误消息中的code和msg
code = json.code;
msg = json.msg;
} else {
NProgress.done();
return response.data;
}
// 正常的返回类型 直接获取code和msg字段
} else {
code = response.data.code;
msg = response.data.msg;
}
// 如果不存在code说明后端格式有问题
if (!code) {
msg = "服务器返回数据结构有误";
}
// 请求返回失败时,有业务错误时,弹出错误提示
if (response.data.code !== 0) {
// token失效时弹出过期提示
@ -126,12 +154,12 @@ class PureHttp {
message("取消重新登录", { type: "info" });
});
NProgress.done();
return Promise.reject(response.data.msg);
return Promise.reject(msg);
} else {
// 其余情况弹出错误提示框
message(response.data.msg, { type: "error" });
message(msg, { type: "error" });
NProgress.done();
return Promise.reject(response.data.msg);
return Promise.reject(msg);
}
}
@ -200,6 +228,19 @@ class PureHttp {
});
}
/** 从二进制流中读取文本 */
async readBlobAsText(blob: Blob): Promise<string> {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
const text = reader.result as string;
resolve(text);
};
reader.onerror = reject;
reader.readAsText(blob, "UTF-8");
});
}
/** 单独抽离的post工具函数 */
public post<T, P>(
url: string,
@ -217,6 +258,54 @@ class PureHttp {
): Promise<P> {
return this.request<P>("get", url, params, config);
}
/** download文件方法 从后端获取文件流 */
public download(
url: string,
fileName: string,
params?: AxiosRequestConfig
): void {
this.get(url, params, {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
responseType: "blob"
}).then((data: Blob) => {
downloadByData(data, fileName);
});
}
// .post(url, params, {
// transformRequest: [params => encodeURIParams(params)],
// headers: { "Content-Type": "application/x-www-form-urlencoded" },
// responseType: "blob"
// })
// .then(async data => {
// const isLogin = await isBlobData(data);
// if (isLogin) {
// const blob = new Blob([data]);
// saveAs(blob, filename);
// } else {
// const resText = await data.text();
// const rspObj = JSON.parse(resText);
// const errMsg =
// errorCode[rspObj.code] || rspObj.msg || errorCode.default;
// ElMessage.error(errMsg);
// }
// downloadLoadingInstance.close();
// })
// .catch(r => {
// console.error(r);
// ElMessage.error("下载文件出现错误,请联系管理员!");
// downloadLoadingInstance.close();
// });
// axios
// .get("https://pure-admin.github.io/pure-admin-doc/img/pure.png", {
// responseType: "blob"
// })
// .then(({ data }) => {
// downloadByData(data, "test-data.png");
// });
// }
}
export const http = new PureHttp();

View File

@ -9,7 +9,7 @@ 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";
//
// TODO
import { CommonUtils } from "../../../../utils/common";
/** 组件name最好和菜单表中的router_name一致 */
@ -35,6 +35,7 @@ const {
multipleSelection,
onSearch,
resetForm,
exportAllExcel,
openDialog,
getOperationLogList,
handleDelete,
@ -147,11 +148,7 @@ const {
@click="CommonUtils.exportExcel(columns, dataList, '操作日志列表')"
>单页导出</el-button
>
<el-button
type="primary"
@click="CommonUtils.exportExcel(columns, dataList, '操作日志列表')"
>全部导出</el-button
>
<el-button type="primary" @click="exportAllExcel">全部导出</el-button>
</template>
<template v-slot="{ size, dynamicColumns }">
<pure-table

View File

@ -3,10 +3,14 @@ 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 {
OperationLogsQuery,
getOperationLogListApi,
deleteOperationLogApi,
exportOperationLogExcelApi
} 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 =
@ -154,13 +158,23 @@ export function useOperationLogHook() {
CommonUtils.fillPaginationParams(searchFormParams, pagination);
CommonUtils.fillTimeRangeParams(searchFormParams, timeRange.value);
const { data } = await getOperationLogListApi(toRaw(searchFormParams));
const { data } = await getOperationLogListApi(
toRaw(searchFormParams)
).finally(() => {
pageLoading.value = false;
});
dataList.value = data.rows;
pagination.total = data.total;
}
setTimeout(() => {
pageLoading.value = false;
}, 500);
async function exportAllExcel(sort: Sort = defaultSort) {
if (sort != null) {
CommonUtils.fillSortParams(searchFormParams, sort);
}
CommonUtils.fillPaginationParams(searchFormParams, pagination);
CommonUtils.fillTimeRangeParams(searchFormParams, timeRange.value);
exportOperationLogExcelApi(toRaw(searchFormParams), "操作日志.xls");
}
async function handleDelete(row) {
@ -244,6 +258,7 @@ export function useOperationLogHook() {
timeRange,
multipleSelection,
onSearch,
exportAllExcel,
// exportExcel,
getOperationLogList,
resetForm,

View File

@ -153,14 +153,14 @@ export function useNoticeHook() {
CommonUtils.fillPaginationParams(searchFormParams, pagination);
pageLoading.value = true;
const { data } = await getSystemNoticeListApi(toRaw(searchFormParams));
const { data } = await getSystemNoticeListApi(
toRaw(searchFormParams)
).finally(() => {
pageLoading.value = false;
});
dataList.value = data.rows;
pagination.total = data.total;
setTimeout(() => {
pageLoading.value = false;
}, 500);
}
async function handleDelete(row) {