From a08d73b0341b49699bcd449de86be653ba48d714 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 29 Mar 2025 20:00:00 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=B2=97=E4=BD=8D=20post=20?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0=20100%=EF=BC=88export=20=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/api/system/post/index.ts | 4 +- apps/web-antd/src/utils/base64Conver.ts | 48 +++++++ apps/web-antd/src/utils/download.ts | 126 ++++++++++++++++++ apps/web-antd/src/views/system/post/index.vue | 14 +- packages/@core/base/icons/src/lucide.ts | 1 + packages/locales/src/langs/en-US/ui.json | 3 +- packages/locales/src/langs/zh-CN/ui.json | 3 +- 7 files changed, 194 insertions(+), 5 deletions(-) create mode 100644 apps/web-antd/src/utils/base64Conver.ts create mode 100644 apps/web-antd/src/utils/download.ts diff --git a/apps/web-antd/src/api/system/post/index.ts b/apps/web-antd/src/api/system/post/index.ts index 848941e23..5caa023ff 100644 --- a/apps/web-antd/src/api/system/post/index.ts +++ b/apps/web-antd/src/api/system/post/index.ts @@ -48,5 +48,7 @@ export function deletePost(id: number) { /** 导出岗位 */ export function exportPost(params: any) { - return requestClient.download('/system/post/export', params); + return requestClient.download('/system/post/export', { + params + }); } diff --git a/apps/web-antd/src/utils/base64Conver.ts b/apps/web-antd/src/utils/base64Conver.ts new file mode 100644 index 000000000..7cd4e298a --- /dev/null +++ b/apps/web-antd/src/utils/base64Conver.ts @@ -0,0 +1,48 @@ +// TODO @芋艿:需要优化下 +// TODO @芋艿:是不是可以共用么? +/** + * @description: base64 to blob + */ +export function dataURLtoBlob(base64Buf: string): Blob { + const arr = base64Buf.split(','); + const typeItem = arr[0]; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const mime = typeItem!.match(/:(.*?);/)![1]; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const bstr = window.atob(arr[1]!); + let n = bstr.length; + const u8arr = new Uint8Array(n); + while (n--) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + u8arr[n] = bstr.codePointAt(n)!; + } + return new Blob([u8arr], { type: mime }); +} + +/** + * img url to base64 + * @param url + */ +export function urlToBase64(url: string, mineType?: string): Promise { + return new Promise((resolve, reject) => { + let canvas = document.createElement('CANVAS') as HTMLCanvasElement | null; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const ctx = canvas!.getContext('2d'); + + const img = new Image(); + img.crossOrigin = ''; + img.addEventListener('load', () => { + if (!canvas || !ctx) { + // eslint-disable-next-line prefer-promise-reject-errors + return reject(); + } + canvas.height = img.height; + canvas.width = img.width; + ctx.drawImage(img, 0, 0); + const dataURL = canvas.toDataURL(mineType || 'image/png'); + canvas = null; + resolve(dataURL); + }); + img.src = url; + }); +} diff --git a/apps/web-antd/src/utils/download.ts b/apps/web-antd/src/utils/download.ts new file mode 100644 index 000000000..96790b062 --- /dev/null +++ b/apps/web-antd/src/utils/download.ts @@ -0,0 +1,126 @@ +// TODO @芋艿:需要优化下每个方法 +// TODO @芋艿:是不是可以共用么? +import { dataURLtoBlob, urlToBase64 } from './base64Conver'; + +/** + * Download online pictures + * @param url + * @param filename + * @param mime + * @param bom + */ +export function downloadByOnlineUrl( + url: string, + filename: string, + mime?: string, + bom?: BlobPart, +) { + urlToBase64(url).then((base64) => { + downloadByBase64(base64, filename, mime, bom); + }); +} + +/** + * Download pictures based on base64 + * @param buf + * @param filename + * @param mime + * @param bom + */ +export function downloadByBase64( + buf: string, + filename: string, + mime?: string, + bom?: BlobPart, +) { + const base64Buf = dataURLtoBlob(buf); + downloadByData(base64Buf, filename, mime, bom); +} + +/** + * Download according to the background interface file stream + * @param {*} data + * @param {*} filename + * @param {*} mime + * @param {*} bom + */ +export function downloadByData( + data: BlobPart, + filename: string, + mime?: string, + bom?: BlobPart, +) { + const blobData = bom === undefined ? [data] : [bom, data]; + const blob = new Blob(blobData, { type: mime || 'application/octet-stream' }); + + const blobURL = window.URL.createObjectURL(blob); + const tempLink = document.createElement('a'); + tempLink.style.display = 'none'; + tempLink.href = blobURL; + tempLink.setAttribute('download', filename); + if (tempLink.download === undefined) + tempLink.setAttribute('target', '_blank'); + + document.body.append(tempLink); + tempLink.click(); + tempLink.remove(); + window.URL.revokeObjectURL(blobURL); +} + +/** + * Download file according to file address + * @param {*} sUrl + */ +export function downloadByUrl({ + url, + target = '_blank', + fileName, +}: { + fileName?: string; + target?: '_blank' | '_self'; + url: string; +}): boolean { + const isChrome = window.navigator.userAgent.toLowerCase().includes('chrome'); + const isSafari = window.navigator.userAgent.toLowerCase().includes('safari'); + + if (/iP/.test(window.navigator.userAgent)) { + console.error('Your browser does not support download!'); + return false; + } + if (isChrome || isSafari) { + const link = document.createElement('a'); + link.href = url; + link.target = target; + + if (link.download !== undefined) + link.download = fileName || url.slice(url.lastIndexOf('/') + 1); + + if (document.createEvent) { + const e = document.createEvent('MouseEvents'); + e.initEvent('click', true, true); + link.dispatchEvent(e); + return true; + } + } + if (!url.includes('?')) url += '?download'; + + openWindow(url, { target }); + return true; +} + +export function openWindow( + url: string, + opt?: { + noopener?: boolean; + noreferrer?: boolean; + target?: '_blank' | '_self' | string; + }, +) { + const { noopener = true, noreferrer = true, target = '__blank' } = opt || {}; + const feature: string[] = []; + + noopener && feature.push('noopener=yes'); + noreferrer && feature.push('noreferrer=yes'); + + window.open(url, target, feature.join(',')); +} diff --git a/apps/web-antd/src/views/system/post/index.vue b/apps/web-antd/src/views/system/post/index.vue index f014c6cef..17d1de062 100644 --- a/apps/web-antd/src/views/system/post/index.vue +++ b/apps/web-antd/src/views/system/post/index.vue @@ -11,10 +11,11 @@ import { getPostPage, deletePost, exportPost } from '#/api/system/post'; import { Page, useVbenModal } from '@vben/common-ui'; import { Button, message } from 'ant-design-vue'; -import { Plus } from '@vben/icons'; +import { Plus, Download } from '@vben/icons'; import { useGridColumns, useGridFormSchema } from './data'; import Form from './modules/form.vue'; +import {downloadByData} from '#/utils/download'; const [FormModal, formModalApi] = useVbenModal({ connectedComponent: Form, @@ -90,7 +91,6 @@ const [Grid, gridApi] = useVbenVxeGrid({ keyField: 'id', }, toolbarConfig: { - export: true, // TODO @芋艿:导出 refresh: { code: 'query' }, search: true, }, @@ -101,6 +101,12 @@ const [Grid, gridApi] = useVbenVxeGrid({ function refreshGrid() { gridApi.query(); } + +/** 导出表格 */ +async function onExport() { + const data = await exportPost(await gridApi.formApi.getValues()); + downloadByData(data, '导出岗位.xls'); +} diff --git a/packages/@core/base/icons/src/lucide.ts b/packages/@core/base/icons/src/lucide.ts index 44d07f941..f4b038468 100644 --- a/packages/@core/base/icons/src/lucide.ts +++ b/packages/@core/base/icons/src/lucide.ts @@ -63,4 +63,5 @@ export { SwatchBook, UserRoundPen, X, + Download, } from 'lucide-vue-next'; diff --git a/packages/locales/src/langs/en-US/ui.json b/packages/locales/src/langs/en-US/ui.json index 5bfd5d07a..84d8410ef 100644 --- a/packages/locales/src/langs/en-US/ui.json +++ b/packages/locales/src/langs/en-US/ui.json @@ -13,7 +13,8 @@ "edit": "Modify {0}", "create": "Create {0}", "delete": "Delete {0}", - "view": "View {0}" + "view": "View {0}", + "export": "Export" }, "actionMessage": { "deleteConfirm": "Are you sure to delete {0}?", diff --git a/packages/locales/src/langs/zh-CN/ui.json b/packages/locales/src/langs/zh-CN/ui.json index c0679581a..0899cfa21 100644 --- a/packages/locales/src/langs/zh-CN/ui.json +++ b/packages/locales/src/langs/zh-CN/ui.json @@ -13,7 +13,8 @@ "edit": "修改{0}", "create": "新增{0}", "delete": "删除{0}", - "view": "查看{0}" + "view": "查看{0}", + "export": "导出" }, "actionMessage": { "deleteConfirm": "确定删除 {0} 吗?",