From 0c3ea2dc8699602e9025c115aa21d9ca05f941fd Mon Sep 17 00:00:00 2001 From: xlsea Date: Thu, 5 Sep 2024 11:06:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=81=E8=A3=85=E4=B8=8B=E8=BD=BDhoo?= =?UTF-8?q?ks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/hooks/src/index.ts | 1 + packages/hooks/src/use-loading.ts | 7 ++ pnpm-lock.yaml | 3 + src/components/common/app-provider.vue | 26 +++-- src/constants/common.ts | 7 ++ src/hooks/business/download.ts | 102 ++++++++++++++++++ src/service/api/tool/gen.ts | 34 ++++++ src/typings/common.d.ts | 3 + src/typings/global.d.ts | 2 + src/views/tool/gen/index.vue | 55 ++++++++-- .../gen/modules/gen-table-operate-drawer.vue | 1 + 11 files changed, 222 insertions(+), 19 deletions(-) create mode 100644 src/hooks/business/download.ts diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index a6a330bd..0ee84280 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -9,3 +9,4 @@ export { useBoolean, useLoading, useCountDown, useContext, useSvgIconRender, use export * from './use-signal'; export * from './use-table'; +export type { LoadingApiInst } from './use-loading'; diff --git a/packages/hooks/src/use-loading.ts b/packages/hooks/src/use-loading.ts index b8f89ad3..27e331e2 100644 --- a/packages/hooks/src/use-loading.ts +++ b/packages/hooks/src/use-loading.ts @@ -1,5 +1,12 @@ +import type { Ref } from 'vue'; import useBoolean from './use-boolean'; +export interface LoadingApiInst { + loading: Ref; + startLoading: () => void; + endLoading: () => void; +} + /** * Loading * diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4292e953..3b72f2d1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -202,6 +202,9 @@ importers: packages/materials: dependencies: + '@sa/hooks': + specifier: workspace:* + version: link:../hooks '@sa/utils': specifier: workspace:* version: link:../utils diff --git a/src/components/common/app-provider.vue b/src/components/common/app-provider.vue index 36a361a8..ab34a701 100644 --- a/src/components/common/app-provider.vue +++ b/src/components/common/app-provider.vue @@ -1,11 +1,14 @@ diff --git a/src/constants/common.ts b/src/constants/common.ts index 2d5e05e3..f4a45b1d 100644 --- a/src/constants/common.ts +++ b/src/constants/common.ts @@ -6,3 +6,10 @@ export const yesOrNoRecord: Record = { }; export const yesOrNoOptions = transformRecordToOption(yesOrNoRecord); + +export const errorCodeRecord: Record = { + '401': '认证失败,无法访问系统资源', + '403': '当前操作没有权限', + '404': '访问资源不存在', + default: '系统未知错误,请反馈给管理员' +}; diff --git a/src/hooks/business/download.ts b/src/hooks/business/download.ts new file mode 100644 index 00000000..fa6e8d0c --- /dev/null +++ b/src/hooks/business/download.ts @@ -0,0 +1,102 @@ +import { localStg } from '@/utils/storage'; +import { getServiceBaseURL } from '@/utils/service'; +import { errorCodeRecord } from '@/constants/common'; + +export function useDownload() { + const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y'; + const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy); + + function downloadByData(data: BlobPart, filename: string, type: string = 'application/octet-stream') { + const blobData = [data]; + const blob = new Blob(blobData, { type }); + + const blobURL = window.URL.createObjectURL(blob); + const tempLink = document.createElement('a'); + tempLink.style.display = 'none'; + tempLink.href = blobURL; + tempLink.setAttribute('download', filename); + if (typeof tempLink.download === 'undefined') { + tempLink.setAttribute('target', '_blank'); + } + document.body.appendChild(tempLink); + tempLink.click(); + document.body.removeChild(tempLink); + window.URL.revokeObjectURL(blobURL); + } + + function download(url: string, params: any, fileName: string) { + window.$loading?.startLoading(); + const token = localStg.get('token'); + const clientId = import.meta.env.VITE_APP_CLIENT_ID; + const now = new Date().getTime(); + const formData = new FormData(); + Object.keys(params).forEach(key => formData.append(key, params[key])); + fetch(`${baseURL}${url}?t=${now}`, { + method: 'post', + body: formData, + headers: { + Authorization: `Bearer ${token}`, + Clientid: clientId!, + 'Content-Type': 'application/x-www-form-urlencoded' + } + }) + .then(async response => { + if (response.headers.get('Content-Type')?.includes('application/json')) { + const res = await response.json(); + const code = res.code as CommonType.ErrorCode; + throw new Error(errorCodeRecord[code] || res.msg || errorCodeRecord.default); + } + return response.blob(); + }) + .then(data => downloadByData(data, fileName, 'application/zip')) + .catch(err => window.$message?.error(err.message)) + .finally(() => window.$loading?.endLoading()); + } + + function oss(ossId: CommonType.IdType) { + window.$loading?.startLoading(); + const token = localStg.get('token'); + const clientId = import.meta.env.VITE_APP_CLIENT_ID; + const url = `/resource/oss/download/${ossId}`; + const now = new Date().getTime(); + let fileName = String(`${ossId}-${now}`); + fetch(`${baseURL}${url}?t=${now}`, { + method: 'get', + headers: { + Authorization: `Bearer ${token}`, + Clientid: clientId! + } + }) + .then(async response => { + fileName = String(response.headers.get('Download-Filename')); + return response.blob(); + }) + .then(data => downloadByData(data, fileName)) + .catch(err => window.$message?.error(err.message)) + .finally(() => window.$loading?.endLoading()); + } + + function zip(url: string, fileName: string) { + window.$loading?.startLoading(); + const token = localStg.get('token'); + const clientId = import.meta.env.VITE_APP_CLIENT_ID; + const now = new Date().getTime(); + fetch(`${baseURL}${url}${url.includes('?') ? '&' : '?'}t=${now}`, { + method: 'get', + headers: { + Authorization: `Bearer ${token}`, + Clientid: clientId! + } + }) + .then(async response => response.blob()) + .then(data => downloadByData(data, fileName, 'application/zip')) + .catch(err => window.$message?.error(err.message)) + .finally(() => window.$loading?.endLoading()); + } + + return { + oss, + zip, + download + }; +} diff --git a/src/service/api/tool/gen.ts b/src/service/api/tool/gen.ts index 7c139ce2..f1792dc9 100644 --- a/src/service/api/tool/gen.ts +++ b/src/service/api/tool/gen.ts @@ -65,3 +65,37 @@ export function fetchGetGenDbList(params?: Api.Tool.GenTableDbSearchParams) { params }); } + +/** 同步数据库 */ +export function fetchSynchGenDbList(tableId: CommonType.IdType) { + return request({ + url: `/tool/gen/synchDb/${tableId}`, + method: 'get' + }); +} + +/** 预览代码 */ +export function fetchGetGenPreview(tableId: CommonType.IdType) { + return request({ + url: `/tool/gen/preview/${tableId}`, + method: 'get' + }); +} + +/** 生成代码(自定义路径) */ +export function fetchGenCode(tableId: CommonType.IdType) { + return request({ + url: `/tool/gen/genCode/${tableId}`, + method: 'get' + }); +} + +/** 批量生成代码 */ +export function fetchBatchGenCode(tableIds: CommonType.IdType[]) { + const tableIdStr = tableIds.join(','); + return request({ + url: '/tool/gen/genCode/', + method: 'get', + params: { tableIdStr } + }); +} diff --git a/src/typings/common.d.ts b/src/typings/common.d.ts index bb95d3b4..9ccc95ba 100644 --- a/src/typings/common.d.ts +++ b/src/typings/common.d.ts @@ -28,4 +28,7 @@ declare namespace CommonType { /** The id type */ type IdType = string | number; + + /** The res error code */ + type ErrorCode = '401' | '403' | '404' | 'default'; } diff --git a/src/typings/global.d.ts b/src/typings/global.d.ts index d53c4871..68bf07dc 100644 --- a/src/typings/global.d.ts +++ b/src/typings/global.d.ts @@ -12,6 +12,8 @@ declare global { $message?: import('naive-ui').MessageProviderInst; /** Notification instance */ $notification?: import('naive-ui').NotificationProviderInst; + /** Content loading */ + $loading?: import('@sa/hooks').LoadingApiInst; } interface ViewTransition { diff --git a/src/views/tool/gen/index.vue b/src/views/tool/gen/index.vue index 87aa5ffc..3250943b 100644 --- a/src/views/tool/gen/index.vue +++ b/src/views/tool/gen/index.vue @@ -2,17 +2,25 @@ import { NButton, NPopconfirm, NTooltip } from 'naive-ui'; import { useBoolean } from '@sa/hooks'; import { ref } from 'vue'; -import { fetchBatchDeleteGenTable, fetchGetGenDataNames, fetchGetGenTableList } from '@/service/api'; +import { + fetchBatchDeleteGenTable, + fetchGenCode, + fetchGetGenDataNames, + fetchGetGenTableList, + fetchSynchGenDbList +} from '@/service/api'; import { $t } from '@/locales'; import { useAppStore } from '@/store/modules/app'; import { useTable, useTableOperate } from '@/hooks/common/table'; import ButtonIcon from '@/components/custom/button-icon.vue'; import SvgIcon from '@/components/custom/svg-icon.vue'; +import { useDownload } from '@/hooks/business/download'; import GenTableSearch from './modules/gen-table-search.vue'; import TableImportDrawer from './modules/table-import-drawer.vue'; import GenTableOperateDrawer from './modules/gen-table-operate-drawer.vue'; const appStore = useAppStore(); +const { zip } = useDownload(); const { bool: importVisible, setTrue: openImportVisible } = useBoolean(); const { @@ -101,13 +109,19 @@ const { tooltipContent={$t('common.edit')} onClick={() => edit(row.tableId!)} /> - edit(row.tableId!)} /> + refresh(row.tableId!)} + /> edit(row.tableId!)} + onClick={() => handleGenCode(row)} /> {{ @@ -152,8 +166,6 @@ async function handleBatchDelete() { // request const { error } = await fetchBatchDeleteGenTable(checkedRowKeys.value); if (error) return; - window.$message?.success('删除成功'); - onBatchDeleted(); } @@ -161,8 +173,6 @@ async function handleDelete(id: CommonType.IdType) { // request const { error } = await fetchBatchDeleteGenTable([id]); if (error) return; - window.$message?.success('删除成功'); - onDeleted(); } @@ -170,11 +180,32 @@ function edit(id: CommonType.IdType) { handleEdit('tableId', id); } +async function refresh(id: CommonType.IdType) { + // request + const { error } = await fetchSynchGenDbList(id); + if (error) return; + window.$message?.success('同步成功'); +} + function handleImport() { openImportVisible(); } -function handleGenCode() {} +async function handleGenCode(row?: Api.Tool.GenTable) { + const tableIds = row?.tableId || checkedRowKeys.value.join(','); + if (!tableIds || tableIds === '') { + window.$message?.error('请选择要生成的数据'); + return; + } + // request + if (row?.genType === '1') { + const { error } = await fetchGenCode(row.tableId!); + if (error) return; + window.$message?.success('生成成功'); + } else { + await zip(`/tool/gen/batchGenCode?tableIdStr=${tableIds}`, `ruoyi-${new Date().getTime()}.zip`); + } +} const dataNameOptions = ref([]); @@ -207,7 +238,13 @@ getDataNames(); @refresh="getData" >