diff --git a/apps/backend-mock/api/auth/login.post.ts b/apps/backend-mock/api/auth/login.post.ts index e002c97f..df5737a2 100644 --- a/apps/backend-mock/api/auth/login.post.ts +++ b/apps/backend-mock/api/auth/login.post.ts @@ -21,7 +21,7 @@ export default defineEventHandler(async (event) => { if (!findUser) { clearRefreshTokenCookie(event); - return forbiddenResponse(event); + return forbiddenResponse(event, 'Username or password is incorrect.'); } const accessToken = generateAccessToken(findUser); diff --git a/apps/backend-mock/utils/response.ts b/apps/backend-mock/utils/response.ts index 851f7830..2a5a908f 100644 --- a/apps/backend-mock/utils/response.ts +++ b/apps/backend-mock/utils/response.ts @@ -39,9 +39,12 @@ export function useResponseError(message: string, error: any = null) { }; } -export function forbiddenResponse(event: H3Event) { +export function forbiddenResponse( + event: H3Event, + message = 'Forbidden Exception', +) { setResponseStatus(event, 403); - return useResponseError('Forbidden Exception', 'Forbidden Exception'); + return useResponseError(message, message); } export function unAuthorizedResponse(event: H3Event) { diff --git a/apps/web-antd/src/api/request.ts b/apps/web-antd/src/api/request.ts index 83eef534..67ef35e4 100644 --- a/apps/web-antd/src/api/request.ts +++ b/apps/web-antd/src/api/request.ts @@ -79,8 +79,7 @@ function createRequestClient(baseURL: string) { return data; } - const error = { response }; - throw error; + throw Object.assign({}, response, { response }); }, }); diff --git a/apps/web-ele/src/api/request.ts b/apps/web-ele/src/api/request.ts index 438b4bdd..a9514c81 100644 --- a/apps/web-ele/src/api/request.ts +++ b/apps/web-ele/src/api/request.ts @@ -78,8 +78,7 @@ function createRequestClient(baseURL: string) { if (status >= 200 && status < 400 && code === 0) { return data; } - const error = { response }; - throw error; + throw Object.assign({}, response, { response }); }, }); diff --git a/apps/web-naive/src/api/request.ts b/apps/web-naive/src/api/request.ts index 6be11a11..72056e19 100644 --- a/apps/web-naive/src/api/request.ts +++ b/apps/web-naive/src/api/request.ts @@ -77,8 +77,7 @@ function createRequestClient(baseURL: string) { if (status >= 200 && status < 400 && code === 0) { return data; } - const error = { response }; - throw error; + throw Object.assign({}, response, { response }); }, }); diff --git a/docs/src/components/common-ui/vben-modal.md b/docs/src/components/common-ui/vben-modal.md index afdce8a1..1b8d7296 100644 --- a/docs/src/components/common-ui/vben-modal.md +++ b/docs/src/components/common-ui/vben-modal.md @@ -104,6 +104,7 @@ const [Modal, modalApi] = useVbenModal({ | contentClass | modal内容区域的class | `string` | - | | footerClass | modal底部区域的class | `string` | - | | headerClass | modal顶部区域的class | `string` | - | +| bordered | 是否显示border | `boolean` | `false` | ### Event diff --git a/docs/src/en/guide/essentials/server.md b/docs/src/en/guide/essentials/server.md index 2ef5a551..95d505c0 100644 --- a/docs/src/en/guide/essentials/server.md +++ b/docs/src/en/guide/essentials/server.md @@ -238,8 +238,7 @@ function createRequestClient(baseURL: string) { if (status >= 200 && status < 400 && code === 0) { return data; } - const error = { response }; - throw error; + throw Object.assign({}, response, { response }); }, }); diff --git a/docs/src/guide/essentials/route.md b/docs/src/guide/essentials/route.md index bc71e0a6..d73f2be0 100644 --- a/docs/src/guide/essentials/route.md +++ b/docs/src/guide/essentials/route.md @@ -386,6 +386,10 @@ interface RouteMeta { * 用于路由->菜单排序 */ order?: number; + /** + * 菜单所携带的参数 + */ + query?: Recordable; /** * 标题名称 */ @@ -542,6 +546,15 @@ interface RouteMeta { 用于配置页面的排序,用于路由到菜单排序。 +_注意:_ 排序仅针对一级菜单有效,二级菜单的排序需要在对应的一级菜单中按代码顺序设置。 + +### query + +- 类型:`Recordable` +- 默认值:`{}` + +用于配置页面的菜单参数,会在菜单中传递给页面。 + ## 路由刷新 路由刷新方式如下: diff --git a/docs/src/guide/essentials/server.md b/docs/src/guide/essentials/server.md index d01a1559..74a45d2e 100644 --- a/docs/src/guide/essentials/server.md +++ b/docs/src/guide/essentials/server.md @@ -241,8 +241,7 @@ function createRequestClient(baseURL: string) { if (status >= 200 && status < 400 && code === 0) { return data; } - const error = { response }; - throw error; + throw Object.assign({}, response, { response }); }, }); diff --git a/packages/@core/base/typings/src/vue-router.d.ts b/packages/@core/base/typings/src/vue-router.d.ts index 87349cd7..534358cc 100644 --- a/packages/@core/base/typings/src/vue-router.d.ts +++ b/packages/@core/base/typings/src/vue-router.d.ts @@ -102,6 +102,10 @@ interface RouteMeta { * 用于路由->菜单排序 */ order?: number; + /** + * 菜单所携带的参数 + */ + query?: Recordable; /** * 标题名称 */ diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts b/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts index 5ce5c7b1..10331660 100644 --- a/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts +++ b/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts @@ -29,6 +29,7 @@ export class ModalApi { } = options; const defaultState: ModalState = { + bordered: false, centered: false, class: '', closeOnClickModal: true, diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal.ts b/packages/@core/ui-kit/popup-ui/src/modal/modal.ts index 1ddffe9d..360647c1 100644 --- a/packages/@core/ui-kit/popup-ui/src/modal/modal.ts +++ b/packages/@core/ui-kit/popup-ui/src/modal/modal.ts @@ -3,15 +3,22 @@ import type { ModalApi } from './modal-api'; import type { Component, Ref } from 'vue'; export interface ModalProps { + /** + * 是否显示边框 + * @default false + */ + bordered?: boolean; /** * 取消按钮文字 */ cancelText?: string; + /** * 是否居中 * @default false */ centered?: boolean; + class?: string; /** * 是否显示右上角的关闭按钮 diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue index 5d409b94..33e489e2 100644 --- a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue +++ b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue @@ -52,6 +52,7 @@ const { isMobile } = useIsMobile(); const state = props.modalApi?.useStore?.(); const { + bordered, cancelText, centered, class: modalClass, @@ -170,9 +171,11 @@ function handleFocusOutside(e: Event) { ref="contentRef" :class=" cn( - 'border-border left-0 right-0 top-[10vh] mx-auto flex max-h-[80%] w-[520px] flex-col border p-0', + 'left-0 right-0 top-[10vh] mx-auto flex max-h-[80%] w-[520px] flex-col p-0 sm:rounded-2xl', modalClass, { + 'border-border border': bordered, + 'shadow-3xl': !bordered, 'left-0 top-0 size-full max-h-full !translate-x-0 !translate-y-0': shouldFullscreen, 'top-1/2 !-translate-y-1/2': centered && !shouldFullscreen, @@ -195,8 +198,9 @@ function handleFocusOutside(e: Event) { ref="headerRef" :class=" cn( - 'border-b px-5 py-4', + 'px-5 py-4', { + 'border-b': bordered, hidden: !header, 'cursor-move select-none': shouldDraggable, }, diff --git a/packages/effects/layouts/src/basic/menu/use-navigation.ts b/packages/effects/layouts/src/basic/menu/use-navigation.ts index 5efb3969..9ec9ea85 100644 --- a/packages/effects/layouts/src/basic/menu/use-navigation.ts +++ b/packages/effects/layouts/src/basic/menu/use-navigation.ts @@ -4,12 +4,24 @@ import { isHttpUrl, openWindow } from '@vben/utils'; function useNavigation() { const router = useRouter(); + const routes = router.getRoutes(); + + const routeMetaMap = new Map(); + + routes.forEach((route) => { + routeMetaMap.set(route.path, route.meta); + }); const navigation = async (path: string) => { if (isHttpUrl(path)) { openWindow(path, { target: '_blank' }); } else { - await router.push(path); + const meta = routeMetaMap.get(path); + const query = meta?.query ?? {}; + await router.push({ + path, + query, + }); } }; diff --git a/packages/effects/layouts/src/widgets/global-search/global-search.vue b/packages/effects/layouts/src/widgets/global-search/global-search.vue index 2f42d6bf..197251b8 100644 --- a/packages/effects/layouts/src/widgets/global-search/global-search.vue +++ b/packages/effects/layouts/src/widgets/global-search/global-search.vue @@ -95,7 +95,11 @@ onMounted(() => {