diff --git a/package.json b/package.json index 5221abc2..3850ffbf 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@antv/g2": "5.2.5", "@better-scroll/core": "2.5.1", "@iconify/vue": "4.1.2", - "@sa/axios": "workspace:*", + "@sa/alova": "workspace:*", "@sa/color": "workspace:*", "@sa/hooks": "workspace:*", "@sa/materials": "workspace:*", diff --git a/packages/hooks/src/use-table.ts b/packages/hooks/src/use-table.ts index f861009e..56862e3d 100644 --- a/packages/hooks/src/use-table.ts +++ b/packages/hooks/src/use-table.ts @@ -1,12 +1,13 @@ import { computed, reactive, ref } from 'vue'; import type { Ref } from 'vue'; import { jsonClone } from '@sa/utils'; +import { usePagination } from '@sa/alova/client'; +import type { AlovaGenerics, Method } from '@sa/alova'; import useBoolean from './use-boolean'; -import useLoading from './use-loading'; export type MaybePromise = T | Promise; -export type ApiFn = (args: any) => Promise; +export type ApiFn = (args: any) => Method; export type TableColumnCheck = { key: string; @@ -16,14 +17,7 @@ export type TableColumnCheck = { export type TableDataWithIndex = T & { index: number }; -export type TransformedData = { - data: TableDataWithIndex[]; - pageNum: number; - pageSize: number; - total: number; -}; - -export type Transformer = (response: Response) => TransformedData; +export type Transformer = (response: Response) => TableDataWithIndex[]; export type TableConfig = { /** api function to get table data */ @@ -31,7 +25,7 @@ export type TableConfig = { /** api params */ apiParams?: Parameters[0]; /** transform api response to table data */ - transformer: Transformer>>; + transformer: Transformer['send']>>>; /** columns factory */ columns: () => C[]; /** @@ -46,12 +40,6 @@ export type TableConfig = { * @param columns */ getColumns: (columns: C[], checks: TableColumnCheck[]) => C[]; - /** - * callback when response fetched - * - * @param transformed transformed data - */ - onFetched?: (transformed: TransformedData) => MaybePromise; /** * whether to get data immediately * @@ -61,7 +49,6 @@ export type TableConfig = { }; export default function useHookTable(config: TableConfig) { - const { loading, startLoading, endLoading } = useLoading(); const { bool: empty, setBool: setEmpty } = useBoolean(); const { apiFn, apiParams, transformer, immediate = true, getColumnChecks, getColumns } = config; @@ -70,12 +57,22 @@ export default function useHookTable(config: TableConfig< const allColumns = ref(config.columns()) as Ref; - const data: Ref[]> = ref([]); - const columnChecks: Ref = ref(getColumnChecks(config.columns())); const columns = computed(() => getColumns(allColumns.value, columnChecks.value)); + const states = usePagination extends Method ? AG : never, ReturnType>( + (page, size) => apiFn({ ...formatSearchParams(searchParams), page, size }) as any, + { + immediate, + data: transformer, + total: res => res.total + } + ).onSuccess(({ data }) => { + setEmpty(data.length === 0); + }); + Reflect.deleteProperty(states, 'uploading'); + function reloadColumns() { allColumns.value = config.columns(); @@ -89,33 +86,13 @@ export default function useHookTable(config: TableConfig< })); } - async function getData() { - startLoading(); - - const formattedParams = formatSearchParams(searchParams); - - const response = await apiFn(formattedParams); - - const transformed = transformer(response as Awaited>); - - data.value = transformed.data; - - setEmpty(transformed.data.length === 0); - - await config.onFetched?.(transformed); - - endLoading(); - } - function formatSearchParams(params: Record) { const formattedParams: Record = {}; - Object.entries(params).forEach(([key, value]) => { if (value !== null && value !== undefined) { formattedParams[key] = value; } }); - return formattedParams; } @@ -133,18 +110,13 @@ export default function useHookTable(config: TableConfig< Object.assign(searchParams, jsonClone(apiParams)); } - if (immediate) { - getData(); - } - return { - loading, + ...states, empty, - data, columns, columnChecks, reloadColumns, - getData, + getData: states.send, searchParams, updateSearchParams, resetSearchParams diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 638ffa05..683ad809 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,9 +20,9 @@ importers: '@iconify/vue': specifier: 4.1.2 version: 4.1.2(vue@3.5.11(typescript@5.6.3)) - '@sa/axios': + '@sa/alova': specifier: workspace:* - version: link:packages/axios + version: link:packages/alova '@sa/color': specifier: workspace:* version: link:packages/color diff --git a/src/hooks/common/table.ts b/src/hooks/common/table.ts index 6619f8b3..665d7620 100644 --- a/src/hooks/common/table.ts +++ b/src/hooks/common/table.ts @@ -7,10 +7,10 @@ import { useAppStore } from '@/store/modules/app'; import { $t } from '@/locales'; type TableData = NaiveUI.TableData; -type GetTableData = NaiveUI.GetTableData; +type GetTableData = NaiveUI.GetTableData; type TableColumn = NaiveUI.TableColumn; -export function useTable(config: NaiveUI.NaiveTableConfig) { +export function useTable(config: NaiveUI.NaiveTableConfig) { const scope = effectScope(); const appStore = useAppStore(); @@ -21,41 +21,24 @@ export function useTable(config: NaiveUI.NaiveTabl const SELECTION_KEY = '__selection__'; const EXPAND_KEY = '__expand__'; - - const { - loading, - empty, - data, - columns, - columnChecks, - reloadColumns, - getData, - searchParams, - updateSearchParams, - resetSearchParams - } = useHookTable, TableColumn>>>({ + const { reloadColumns, page, pageSize, total, getData, update, ...rest } = useHookTable< + A, + GetTableData, + TableColumn>> + >({ apiFn, apiParams, columns: config.columns, transformer: res => { - const { records = [], current = 1, size = 10, total = 0 } = res.data || {}; + const { records = [], current = 1, size = 10 } = res || {}; // Ensure that the size is greater than 0, If it is less than 0, it will cause paging calculation errors. - const pageSize = size <= 0 ? 10 : size; + const pageSizeValue = size <= 0 ? 10 : size; - const recordsWithIndex = records.map((item, index) => { - return { - ...item, - index: (current - 1) * pageSize + index + 1 - }; - }); - - return { - data: recordsWithIndex, - pageNum: current, - pageSize, - total - }; + return records.map((item, index) => ({ + ...item, + index: (current - 1) * pageSizeValue + index + 1 + })); }, getColumnChecks: cols => { const checks: NaiveUI.TableColumnCheck[] = []; @@ -103,64 +86,56 @@ export function useTable(config: NaiveUI.NaiveTabl return filteredColumns; }, - onFetched: async transformed => { - const { pageNum, pageSize, total } = transformed; - - updatePagination({ - page: pageNum, - pageSize, - itemCount: total - }); - }, immediate }); - const pagination: PaginationProps = reactive({ - page: 1, - pageSize: 10, + const paginationBase: PaginationProps = reactive({ showSizePicker: true, pageSizes: [10, 15, 20, 25, 30], - onUpdatePage: async (page: number) => { - pagination.page = page; - - updateSearchParams({ - current: page, - size: pagination.pageSize! - }); - - getData(); + onUpdatePage: async pageValue => { + page.value = pageValue; }, - onUpdatePageSize: async (pageSize: number) => { - pagination.pageSize = pageSize; - pagination.page = 1; - - updateSearchParams({ - current: pagination.page, - size: pageSize - }); - - getData(); + onUpdatePageSize: async pageSizeValue => { + pageSize.value = pageSizeValue; }, ...(showTotal ? { - prefix: page => $t('datatable.itemCount', { total: page.itemCount }) + prefix: pageProps => $t('datatable.itemCount', { total: pageProps.itemCount }) } : {}) }); + const pagination = computed( + () => + { + ...paginationBase, + page: page.value, + pageSize: pageSize.value, + itemCount: total.value + } + ); + // this is for mobile, if the system does not support mobile, you can use `pagination` directly const mobilePagination = computed(() => { const p: PaginationProps = { - ...pagination, + ...pagination.value, pageSlot: isMobile.value ? 3 : 9, - prefix: !isMobile.value && showTotal ? pagination.prefix : undefined + prefix: !isMobile.value && showTotal ? pagination.value.prefix : undefined }; return p; }); - function updatePagination(update: Partial) { - Object.assign(pagination, update); + function updatePagination(updateProps: Partial) { + const innerPageStates = ['page', 'pageSize', 'itemCount'] as const; + innerPageStates.forEach(key => { + if (updateProps[key]) { + update({ + [key]: updateProps[key] + }); + } + }); + Object.assign(paginationBase, updateProps); } /** @@ -169,16 +144,8 @@ export function useTable(config: NaiveUI.NaiveTabl * @param pageNum the page number. default is 1 */ async function getDataByPage(pageNum: number = 1) { - updatePagination({ - page: pageNum - }); - - updateSearchParams({ - current: pageNum, - size: pagination.pageSize! - }); - - await getData(); + page.value = pageNum; + return getData(); } scope.run(() => { @@ -195,24 +162,17 @@ export function useTable(config: NaiveUI.NaiveTabl }); return { - loading, - empty, - data, - columns, - columnChecks, + ...rest, + getData, reloadColumns, pagination, mobilePagination, updatePagination, - getData, - getDataByPage, - searchParams, - updateSearchParams, - resetSearchParams + getDataByPage }; } -export function useTableOperate(data: Ref, getData: () => Promise) { +export function useTableOperate(data: Ref, getData: () => Promise | void) { const { bool: drawerVisible, setTrue: openDrawer, setFalse: closeDrawer } = useBoolean(); const operateType = ref('add'); diff --git a/src/layouts/modules/global-menu/modules/vertical-mix-menu.vue b/src/layouts/modules/global-menu/modules/vertical-mix-menu.vue index 07631086..3a84bb3d 100644 --- a/src/layouts/modules/global-menu/modules/vertical-mix-menu.vue +++ b/src/layouts/modules/global-menu/modules/vertical-mix-menu.vue @@ -14,7 +14,7 @@ import FirstLevelMenu from '../components/first-level-menu.vue'; import GlobalLogo from '../../global-logo/index.vue'; defineOptions({ - name: 'VerticalMixMenu' + name: 'VerticalMenuMix' }); const route = useRoute(); diff --git a/src/service/api/auth.ts b/src/service/api/auth.ts index 1ffcf2bf..5e1ba708 100644 --- a/src/service/api/auth.ts +++ b/src/service/api/auth.ts @@ -1,4 +1,4 @@ -import { request } from '../request'; +import { alova } from '../request'; /** * Login @@ -7,19 +7,12 @@ import { request } from '../request'; * @param password Password */ export function fetchLogin(userName: string, password: string) { - return request({ - url: '/auth/login', - method: 'post', - data: { - userName, - password - } - }); + return alova.Post('/auth/login', { userName, password }); } /** Get user info */ export function fetchGetUserInfo() { - return request({ url: '/auth/getUserInfo' }); + return alova.Get('/auth/getUserInfo'); } /** @@ -28,13 +21,15 @@ export function fetchGetUserInfo() { * @param refreshToken Refresh token */ export function fetchRefreshToken(refreshToken: string) { - return request({ - url: '/auth/refreshToken', - method: 'post', - data: { - refreshToken + return alova.Post( + '/auth/refreshToken', + { refreshToken }, + { + meta: { + authRole: 'refreshToken' + } } - }); + ); } /** @@ -44,5 +39,8 @@ export function fetchRefreshToken(refreshToken: string) { * @param msg error message */ export function fetchCustomBackendError(code: string, msg: string) { - return request({ url: '/auth/error', params: { code, msg } }); + return alova.Get('/auth/error', { + params: { code, msg }, + shareRequest: false + }); } diff --git a/src/service/api/route.ts b/src/service/api/route.ts index 0956a7a8..94f1c983 100644 --- a/src/service/api/route.ts +++ b/src/service/api/route.ts @@ -1,13 +1,13 @@ -import { request } from '../request'; +import { alova } from '../request'; /** get constant routes */ export function fetchGetConstantRoutes() { - return request({ url: '/route/getConstantRoutes' }); + return alova.Get('/route/getConstantRoutes'); } /** get user routes */ export function fetchGetUserRoutes() { - return request({ url: '/route/getUserRoutes' }); + return alova.Get('/route/getUserRoutes'); } /** @@ -16,5 +16,5 @@ export function fetchGetUserRoutes() { * @param routeName route name */ export function fetchIsRouteExist(routeName: string) { - return request({ url: '/route/isRouteExist', params: { routeName } }); + return alova.Get('/route/isRouteExist', { params: { routeName } }); } diff --git a/src/service/api/system-manage.ts b/src/service/api/system-manage.ts index cb975b2c..c06c54b5 100644 --- a/src/service/api/system-manage.ts +++ b/src/service/api/system-manage.ts @@ -1,12 +1,8 @@ -import { request } from '../request'; +import { alova } from '../request'; /** get role list */ export function fetchGetRoleList(params?: Api.SystemManage.RoleSearchParams) { - return request({ - url: '/systemManage/getRoleList', - method: 'get', - params - }); + return alova.Get('/systemManage/getRoleList', { params }); } /** @@ -15,41 +11,25 @@ export function fetchGetRoleList(params?: Api.SystemManage.RoleSearchParams) { * these roles are all enabled */ export function fetchGetAllRoles() { - return request({ - url: '/systemManage/getAllRoles', - method: 'get' - }); + return alova.Get('/systemManage/getAllRoles'); } /** get user list */ export function fetchGetUserList(params?: Api.SystemManage.UserSearchParams) { - return request({ - url: '/systemManage/getUserList', - method: 'get', - params - }); + return alova.Get('/systemManage/getUserList', { params }); } /** get menu list */ export function fetchGetMenuList() { - return request({ - url: '/systemManage/getMenuList/v2', - method: 'get' - }); + return alova.Get('/systemManage/getMenuList/v2'); } /** get all pages */ export function fetchGetAllPages() { - return request({ - url: '/systemManage/getAllPages', - method: 'get' - }); + return alova.Get('/systemManage/getAllPages'); } /** get menu tree */ export function fetchGetMenuTree() { - return request({ - url: '/systemManage/getMenuTree', - method: 'get' - }); + return alova.Get('/systemManage/getMenuTree'); } diff --git a/src/service/request/index.ts b/src/service/request/index.ts index 7d0c6a7f..80409ad8 100644 --- a/src/service/request/index.ts +++ b/src/service/request/index.ts @@ -1,67 +1,86 @@ -import type { AxiosResponse } from 'axios'; -import { BACKEND_ERROR_CODE, createFlatRequest, createRequest } from '@sa/axios'; +import { createAlovaRequest } from '@sa/alova'; import { useAuthStore } from '@/store/modules/auth'; import { $t } from '@/locales'; -import { localStg } from '@/utils/storage'; import { getServiceBaseURL } from '@/utils/service'; -import { getAuthorization, handleExpiredRequest, showErrorMsg } from './shared'; +import { getAuthorization, handleRefreshToken, showErrorMsg } from './shared'; import type { RequestInstanceState } from './type'; const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y'; -const { baseURL, otherBaseURL } = getServiceBaseURL(import.meta.env, isHttpProxy); +const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy); -export const request = createFlatRequest( +const state: RequestInstanceState = { + errMsgStack: [] +}; +export const alova = createAlovaRequest( { - baseURL, - headers: { - apifoxToken: 'XL299LiMEDZ0H5h3A29PxwQXdMJqWyY2' - } + baseURL }, { - async onRequest(config) { + onRequest({ config }) { const Authorization = getAuthorization(); - Object.assign(config.headers, { Authorization }); - - return config; + config.headers.Authorization = Authorization; + config.headers.apifoxToken = 'XL299LiMEDZ0H5h3A29PxwQXdMJqWyY2'; }, - isBackendSuccess(response) { + tokenRefresher: { + async isExpired(response) { + const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || []; + const { code } = await response.clone().json(); + return expiredTokenCodes.includes(String(code)); + }, + async handler() { + await handleRefreshToken(); + } + }, + async isBackendSuccess(response) { // when the backend response code is "0000"(default), it means the request is success // to change this logic by yourself, you can modify the `VITE_SERVICE_SUCCESS_CODE` in `.env` file - return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE; + const resp = response.clone(); + const data = await resp.json(); + return String(data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE; }, - async onBackendFail(response, instance) { + async transformBackendResponse(response) { + return (await response.clone().json()).data; + }, + async onError(error, response) { const authStore = useAuthStore(); - const responseCode = String(response.data.code); + + let message = error.message; + let responseCode = ''; + if (response) { + const data = await response?.clone().json(); + message = data.msg; + responseCode = String(data.code); + } function handleLogout() { + showErrorMsg(state, message); authStore.resetStore(); } function logoutAndCleanup() { handleLogout(); window.removeEventListener('beforeunload', handleLogout); - - request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg); + state.errMsgStack = state.errMsgStack.filter(msg => msg !== message); } // when the backend response code is in `logoutCodes`, it means the user will be logged out and redirected to login page const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || []; if (logoutCodes.includes(responseCode)) { handleLogout(); - return null; + throw error; } // when the backend response code is in `modalLogoutCodes`, it means the user will be logged out by displaying a modal const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || []; - if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) { - request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg]; + if (modalLogoutCodes.includes(responseCode) && !state.errMsgStack?.includes(message)) { + state.errMsgStack = [...(state.errMsgStack || []), message]; // prevent the user from refreshing the page window.addEventListener('beforeunload', handleLogout); window.$dialog?.error({ title: $t('common.error'), - content: response.data.msg, + content: message, positiveText: $t('common.confirm'), maskClosable: false, closeOnEsc: false, @@ -72,95 +91,10 @@ export const request = createFlatRequest; - } - } - - return null; - }, - transformBackendResponse(response) { - return response.data.data; - }, - onError(error) { - // when the request is fail, you can show error message - - let message = error.message; - let backendErrorCode = ''; - - // get backend error message and code - if (error.code === BACKEND_ERROR_CODE) { - message = error.response?.data?.msg || message; - backendErrorCode = String(error.response?.data?.code || ''); - } - - // the error message is displayed in the modal - const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || []; - if (modalLogoutCodes.includes(backendErrorCode)) { - return; - } - - // when the token is expired, refresh token and retry request, so no need to show error message - const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || []; - if (expiredTokenCodes.includes(backendErrorCode)) { - return; - } - - showErrorMsg(request.state, message); - } - } -); - -export const demoRequest = createRequest( - { - baseURL: otherBaseURL.demo - }, - { - async onRequest(config) { - const { headers } = config; - - // set token - const token = localStg.get('token'); - const Authorization = token ? `Bearer ${token}` : null; - Object.assign(headers, { Authorization }); - - return config; - }, - isBackendSuccess(response) { - // when the backend response code is "200", it means the request is success - // you can change this logic by yourself - return response.data.status === '200'; - }, - async onBackendFail(_response) { - // when the backend response code is not "200", it means the request is fail - // for example: the token is expired, refresh token and retry request - }, - transformBackendResponse(response) { - return response.data.result; - }, - onError(error) { - // when the request is fail, you can show error message - - let message = error.message; - - // show backend error message - if (error.code === BACKEND_ERROR_CODE) { - message = error.response?.data?.message || message; - } - - window.$message?.error(message); + showErrorMsg(state, message); + throw error; } } ); diff --git a/src/service/request/shared.ts b/src/service/request/shared.ts index 162d4706..8d3cf38f 100644 --- a/src/service/request/shared.ts +++ b/src/service/request/shared.ts @@ -11,34 +11,23 @@ export function getAuthorization() { } /** refresh token */ -async function handleRefreshToken() { +export async function handleRefreshToken() { const { resetStore } = useAuthStore(); const rToken = localStg.get('refreshToken') || ''; - const { error, data } = await fetchRefreshToken(rToken); - if (!error) { + const refreshTokenMethod = fetchRefreshToken(rToken); + + // set the refreshToken role, so that the request will not be intercepted + refreshTokenMethod.meta.authRole = 'refreshToken'; + + try { + const data = await refreshTokenMethod; localStg.set('token', data.token); localStg.set('refreshToken', data.refreshToken); - return true; + } catch (error) { + resetStore(); + throw error; } - - resetStore(); - - return false; -} - -export async function handleExpiredRequest(state: RequestInstanceState) { - if (!state.refreshTokenFn) { - state.refreshTokenFn = handleRefreshToken(); - } - - const success = await state.refreshTokenFn; - - setTimeout(() => { - state.refreshTokenFn = null; - }, 1000); - - return success; } export function showErrorMsg(state: RequestInstanceState, message: string) { diff --git a/src/service/request/type.ts b/src/service/request/type.ts index 4e4a2f71..5f5ce5c8 100644 --- a/src/service/request/type.ts +++ b/src/service/request/type.ts @@ -1,6 +1,4 @@ export interface RequestInstanceState { - /** whether the request is refreshing token */ - refreshTokenFn: Promise | null; /** the request error message stack */ errMsgStack: string[]; } diff --git a/src/store/modules/auth/index.ts b/src/store/modules/auth/index.ts index 8fcdebed..017ca1e3 100644 --- a/src/store/modules/auth/index.ts +++ b/src/store/modules/auth/index.ts @@ -63,9 +63,8 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => { async function login(userName: string, password: string, redirect = true) { startLoading(); - const { data: loginToken, error } = await fetchLogin(userName, password); - - if (!error) { + try { + const loginToken = await fetchLogin(userName, password); const pass = await loginByToken(loginToken); if (pass) { @@ -81,7 +80,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => { }); } } - } else { + } catch { resetStore(); } @@ -106,16 +105,15 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => { } async function getUserInfo() { - const { data: info, error } = await fetchGetUserInfo(); - - if (!error) { + try { + const info = await fetchGetUserInfo(); // update store Object.assign(userInfo, info); return true; + } catch { + return false; } - - return false; } async function initUserInfo() { diff --git a/src/store/modules/route/index.ts b/src/store/modules/route/index.ts index d3feea55..971bb9c9 100644 --- a/src/store/modules/route/index.ts +++ b/src/store/modules/route/index.ts @@ -201,11 +201,10 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => { if (authRouteMode.value === 'static') { addConstantRoutes(staticRoute.constantRoutes); } else { - const { data, error } = await fetchGetConstantRoutes(); - - if (!error) { + try { + const data = await fetchGetConstantRoutes(); addConstantRoutes(data); - } else { + } catch { // if fetch constant routes failed, use static constant routes addConstantRoutes(staticRoute.constantRoutes); } @@ -246,9 +245,9 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => { /** Init dynamic auth route */ async function initDynamicAuthRoute() { - const { data, error } = await fetchGetUserRoutes(); + try { + const data = await fetchGetUserRoutes(); - if (!error) { const { routes, home } = data; addAuthRoutes(routes); @@ -260,7 +259,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => { handleUpdateRootRouteRedirect(home); setIsInitAuthRoute(true); - } else { + } catch { // if fetch user routes failed, reset store authStore.resetStore(); } @@ -340,9 +339,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => { return isRouteExistByRouteName(routeName, staticAuthRoutes); } - const { data } = await fetchIsRouteExist(routeName); - - return data; + return fetchIsRouteExist(routeName); } /** diff --git a/src/store/modules/route/shared.ts b/src/store/modules/route/shared.ts index 0686d27e..e7a6c7f9 100644 --- a/src/store/modules/route/shared.ts +++ b/src/store/modules/route/shared.ts @@ -19,7 +19,7 @@ export function filterAuthRoutesByRoles(routes: ElegantConstRoute[], roles: stri * @param route Auth route * @param roles Roles */ -function filterAuthRouteByRoles(route: ElegantConstRoute, roles: string[]): ElegantConstRoute[] { +function filterAuthRouteByRoles(route: ElegantConstRoute, roles: string[]) { const routeRoles = (route.meta && route.meta.roles) || []; // if the route's "roles" is empty, then it is allowed to access @@ -34,11 +34,6 @@ function filterAuthRouteByRoles(route: ElegantConstRoute, roles: string[]): Eleg filterRoute.children = filterRoute.children.flatMap(item => filterAuthRouteByRoles(item, roles)); } - // Exclude the route if it has no children after filtering - if (filterRoute.children?.length === 0) { - return []; - } - return hasPermission || isEmptyRoles ? [filterRoute] : []; } @@ -288,7 +283,8 @@ export function getBreadcrumbsByRoute( for (const menu of menus) { if (menu.key === key) { - return [transformMenuToBreadcrumb(menu)]; + const breadcrumbMenu = menu; + return [transformMenuToBreadcrumb(breadcrumbMenu)]; } if (menu.key === activeKey) { diff --git a/src/typings/components.d.ts b/src/typings/components.d.ts index 09f7cdd1..dbedf91c 100644 --- a/src/typings/components.d.ts +++ b/src/typings/components.d.ts @@ -87,6 +87,7 @@ declare module 'vue' { NSelect: typeof import('naive-ui')['NSelect'] NSkeleton: typeof import('naive-ui')['NSkeleton'] NSpace: typeof import('naive-ui')['NSpace'] + NSpin: typeof import('naive-ui')['NSpin'] NStatistic: typeof import('naive-ui')['NStatistic'] NSwitch: typeof import('naive-ui')['NSwitch'] NTab: typeof import('naive-ui')['NTab'] diff --git a/src/typings/global.d.ts b/src/typings/global.d.ts index 081c8bde..d53c4871 100644 --- a/src/typings/global.d.ts +++ b/src/typings/global.d.ts @@ -14,6 +14,14 @@ declare global { $notification?: import('naive-ui').NotificationProviderInst; } + interface ViewTransition { + ready: Promise; + } + + export interface Document { + startViewTransition?: (callback: () => Promise | void) => ViewTransition; + } + /** Build time of the project */ export const BUILD_TIME: string; } diff --git a/src/typings/naive-ui.d.ts b/src/typings/naive-ui.d.ts index d9ffb778..ace99331 100644 --- a/src/typings/naive-ui.d.ts +++ b/src/typings/naive-ui.d.ts @@ -9,7 +9,6 @@ declare namespace NaiveUI { type PaginationProps = import('naive-ui').PaginationProps; type TableColumnCheck = import('@sa/hooks').TableColumnCheck; type TableDataWithIndex = import('@sa/hooks').TableDataWithIndex; - type FlatResponseData = import('@sa/axios').FlatResponseData; /** * the custom column key @@ -26,9 +25,9 @@ declare namespace NaiveUI { type TableColumn = TableColumnWithKey | DataTableSelectionColumn | DataTableExpandColumn; - type TableApiFn = ( + type TableAlovaApiFn = ( params: R - ) => Promise>>; + ) => import('@sa/alova').Method>>; /** * the type of table operation @@ -38,9 +37,9 @@ declare namespace NaiveUI { */ type TableOperateType = 'add' | 'edit'; - type GetTableData = A extends TableApiFn ? T : never; + type GetTableData = A extends TableAlovaApiFn ? T : never; - type NaiveTableConfig = Pick< + type NaiveTableConfig = Pick< import('@sa/hooks').TableConfig, TableColumn>>>, 'apiFn' | 'apiParams' | 'columns' | 'immediate' > & { diff --git a/src/views/_builtin/login/modules/code-login.vue b/src/views/_builtin/login/modules/code-login.vue index a95c3936..68b536bc 100644 --- a/src/views/_builtin/login/modules/code-login.vue +++ b/src/views/_builtin/login/modules/code-login.vue @@ -40,7 +40,7 @@ async function handleSubmit() {