refactor: 优化导出下载功能

This commit is contained in:
秋帆
2024-04-10 22:40:29 +08:00
parent 63da55ab03
commit 2f29a6e81c
6 changed files with 92 additions and 12 deletions

View File

@@ -12,3 +12,11 @@ export function listLog(query: System.LogQuery) {
export function getLog(id: string) { export function getLog(id: string) {
return http.get<System.LogDetailResp>(`${BASE_URL}/${id}`) return http.get<System.LogDetailResp>(`${BASE_URL}/${id}`)
} }
/** @desc 导出日志列表 */
export function exportLog(query: System.LogQuery) {
return http.download<any>(`${BASE_URL}/export/login`, query)
}
/**@desc 导出操作日志 */
export function exportOperateLog(query: System.LogQuery) {
return http.download<any>(`${BASE_URL}/export/operation`, query)
}

View File

@@ -7,3 +7,4 @@ export * from './modules/useForm'
export * from './modules/useDevice' export * from './modules/useDevice'
export * from './modules/useBreakpoint' export * from './modules/useBreakpoint'
export * from './modules/useBreakpointIndex' export * from './modules/useBreakpointIndex'
export * from './modules/useDownload'

View File

@@ -0,0 +1,55 @@
import { Message, Notification } from '@arco-design/web-vue'
/**
* @description 接收数据流生成 blob创建链接下载文件
* @param {Function} api 导出表格的api方法 (必传)
* @param {String} tempName 导出的文件名 (必传)
* @param {Object} params 导出的参数 (默认{})
* @param {Boolean} isNotify 是否有导出消息提示 (默认为 true)
* @param {String} fileType 导出的文件格式 (默认为.xlsx)
* */
interface NavigatorWithMsSaveOrOpenBlob extends Navigator {
msSaveOrOpenBlob(blob: Blob, fileName: string): void
}
export const useDownload = async (
api: (param: any) => Promise<any>,
tempName: string = '',
params: any = {},
isNotify = true,
fileType = '.xlsx'
) => {
try {
const res = await api(params)
if (res.headers['content-disposition']) {
tempName = decodeURI(res.headers['content-disposition'].split(';')[1].split('=')[1]);
} else {
tempName = tempName ? tempName : new Date().getTime() + fileType
}
if (isNotify && !res?.code) {
Notification.warning({
title: '温馨提示',
content: '如果数据庞大会导致下载缓慢哦,请您耐心等待!'
})
}
if (res.status !== 200 || res.data === null || !(res.data instanceof Blob)) {
Message.error('导出失败,请稍后再试!')
return
}
const blob = new Blob([res.data])
// 兼容 edge 不支持 createObjectURL 方法
if ('msSaveOrOpenBlob' in (navigator as unknown as NavigatorWithMsSaveOrOpenBlob)) {
; (window.navigator as unknown as NavigatorWithMsSaveOrOpenBlob).msSaveOrOpenBlob(blob, tempName + fileType)
}
const blobUrl = window.URL.createObjectURL(blob)
const exportFile = document.createElement('a')
exportFile.style.display = 'none'
exportFile.download = tempName
exportFile.href = blobUrl
document.body.appendChild(exportFile)
exportFile.click()
// 去除下载对 url 的影响
document.body.removeChild(exportFile)
window.URL.revokeObjectURL(blobUrl)
} catch (error) {
console.log(error)
}
}

View File

@@ -61,7 +61,9 @@ http.interceptors.response.use(
(response: AxiosResponse) => { (response: AxiosResponse) => {
const { data } = response const { data } = response
const { success, code, msg } = data const { success, code, msg } = data
if(response.request.responseType==='blob'){
return response
}
// 成功 // 成功
if (success) { if (success) {
NProgress.done() NProgress.done()
@@ -122,6 +124,7 @@ const requestNative = <T = unknown>(config: AxiosRequestConfig): Promise<AxiosRe
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
http http
.request<T>(config) .request<T>(config)
.then((res: AxiosResponse) => resolve(res))
.catch((err: { msg: string }) => reject(err)) .catch((err: { msg: string }) => reject(err))
}) })
} }
@@ -173,5 +176,13 @@ const del = <T = any>(url: string, params?: object, config?: AxiosRequestConfig)
...config ...config
}) })
} }
const download = <T = any>(url: string, params?: object, config?: AxiosRequestConfig): Promise<AxiosResponse> => {
export default { get, post, put, patch, del, request, requestNative } return requestNative({
method: 'get',
url,
responseType: 'blob',
params,
...config
})
}
export default { get, post, put, patch, del, request, requestNative,download }

View File

@@ -22,7 +22,7 @@
</template> </template>
<template #custom-right> <template #custom-right>
<a-tooltip content="导出"> <a-tooltip content="导出">
<a-button> <a-button @click="onExportFile">
<template #icon> <template #icon>
<icon-download /> <icon-download />
</template> </template>
@@ -45,13 +45,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { listLog } from '@/apis' import { listLog,exportLog } from '@/apis'
import type { TableInstance } from '@arco-design/web-vue' import type { TableInstance } from '@arco-design/web-vue'
import DateRangePicker from '@/components/DateRangePicker/index.vue' import DateRangePicker from '@/components/DateRangePicker/index.vue'
import { useTable } from '@/hooks' import { useTable } from '@/hooks'
import {useDownload} from '@/hooks'
defineOptions({ name: 'LoginLog' }) defineOptions({ name: 'LoginLog' })
const filterChange = (values,record)=>{ const filterChange = (values,record)=>{
try { try {
const slotName = columns[values.split('_').pop()].slotName as string const slotName = columns[values.split('_').pop()].slotName as string
@@ -96,7 +95,10 @@ const columns: TableInstance['columns'] = [
{ title: '浏览器', dataIndex: 'browser', ellipsis: true, tooltip: true }, { title: '浏览器', dataIndex: 'browser', ellipsis: true, tooltip: true },
{ title: '终端系统', dataIndex: 'os', ellipsis: true, tooltip: true } { title: '终端系统', dataIndex: 'os', ellipsis: true, tooltip: true }
] ]
//导出登录日志
const onExportFile = ()=>{
useDownload(exportLog,'',queryForm)
}
const queryForm = reactive({ const queryForm = reactive({
module: '登录', module: '登录',
ip: undefined, ip: undefined,

View File

@@ -22,7 +22,7 @@
<a-button @click="reset">重置</a-button> <a-button @click="reset">重置</a-button>
</template> </template>
<template #custom-right> <template #custom-right>
<a-tooltip content="导出"> <a-tooltip content="导出" @click="onExportFile">
<a-button> <a-button>
<template #icon> <template #icon>
<icon-download /> <icon-download />
@@ -56,11 +56,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { listLog, type LogResp } from '@/apis' import { listLog, type LogResp,exportOperateLog } from '@/apis'
import type { TableInstance } from '@arco-design/web-vue' import type { TableInstance } from '@arco-design/web-vue'
import DateRangePicker from '@/components/DateRangePicker/index.vue' import DateRangePicker from '@/components/DateRangePicker/index.vue'
import OperationLogDetailDrawer from './OperationLogDetailDrawer.vue' import OperationLogDetailDrawer from './OperationLogDetailDrawer.vue'
import { useTable } from '@/hooks' import { useDownload, useTable } from '@/hooks'
defineOptions({ name: 'OperationLog' }) defineOptions({ name: 'OperationLog' })
const filterChange = (values,record)=>{ const filterChange = (values,record)=>{
@@ -109,7 +109,10 @@ const columns: TableInstance['columns'] = [
{ title: '浏览器', dataIndex: 'browser', ellipsis: true, tooltip: true }, { title: '浏览器', dataIndex: 'browser', ellipsis: true, tooltip: true },
{ title: '终端系统', dataIndex: 'os', ellipsis: true, tooltip: true } { title: '终端系统', dataIndex: 'os', ellipsis: true, tooltip: true }
] ]
//导出操作日志
const onExportFile = ()=>{
useDownload(exportOperateLog,'',queryForm)
}
const queryForm = reactive({ const queryForm = reactive({
description: undefined, description: undefined,
ip: undefined, ip: undefined,