diff --git a/.gitignore b/.gitignore index c2a8a771f..3399f39c0 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ vite.config.ts.* *.sln *.sw? .history +.cursor diff --git a/apps/backend-mock/api/auth/codes.ts b/apps/backend-mock/api/auth/codes.ts index 7ba012705..e610b3381 100644 --- a/apps/backend-mock/api/auth/codes.ts +++ b/apps/backend-mock/api/auth/codes.ts @@ -1,5 +1,7 @@ +import { eventHandler } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; -import { unAuthorizedResponse } from '~/utils/response'; +import { MOCK_CODES } from '~/utils/mock-data'; +import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; export default eventHandler((event) => { const userinfo = verifyAccessToken(event); diff --git a/apps/backend-mock/api/auth/login.post.ts b/apps/backend-mock/api/auth/login.post.ts index df5737a25..e23942c46 100644 --- a/apps/backend-mock/api/auth/login.post.ts +++ b/apps/backend-mock/api/auth/login.post.ts @@ -1,9 +1,15 @@ +import { defineEventHandler, readBody, setResponseStatus } from 'h3'; import { clearRefreshTokenCookie, setRefreshTokenCookie, } from '~/utils/cookie-utils'; import { generateAccessToken, generateRefreshToken } from '~/utils/jwt-utils'; -import { forbiddenResponse } from '~/utils/response'; +import { MOCK_USERS } from '~/utils/mock-data'; +import { + forbiddenResponse, + useResponseError, + useResponseSuccess, +} from '~/utils/response'; export default defineEventHandler(async (event) => { const { password, username } = await readBody(event); diff --git a/apps/backend-mock/api/auth/logout.post.ts b/apps/backend-mock/api/auth/logout.post.ts index ac6afe940..74c8d3151 100644 --- a/apps/backend-mock/api/auth/logout.post.ts +++ b/apps/backend-mock/api/auth/logout.post.ts @@ -1,7 +1,9 @@ +import { defineEventHandler } from 'h3'; import { clearRefreshTokenCookie, getRefreshTokenFromCookie, } from '~/utils/cookie-utils'; +import { useResponseSuccess } from '~/utils/response'; export default defineEventHandler(async (event) => { const refreshToken = getRefreshTokenFromCookie(event); diff --git a/apps/backend-mock/api/auth/refresh.post.ts b/apps/backend-mock/api/auth/refresh.post.ts index 7df4d34f5..7d8d3a51e 100644 --- a/apps/backend-mock/api/auth/refresh.post.ts +++ b/apps/backend-mock/api/auth/refresh.post.ts @@ -1,9 +1,11 @@ +import { defineEventHandler } from 'h3'; import { clearRefreshTokenCookie, getRefreshTokenFromCookie, setRefreshTokenCookie, } from '~/utils/cookie-utils'; -import { verifyRefreshToken } from '~/utils/jwt-utils'; +import { generateAccessToken, verifyRefreshToken } from '~/utils/jwt-utils'; +import { MOCK_USERS } from '~/utils/mock-data'; import { forbiddenResponse } from '~/utils/response'; export default defineEventHandler(async (event) => { diff --git a/apps/backend-mock/api/demo/bigint.ts b/apps/backend-mock/api/demo/bigint.ts index 880cc5ea8..00d6c28c5 100644 --- a/apps/backend-mock/api/demo/bigint.ts +++ b/apps/backend-mock/api/demo/bigint.ts @@ -1,3 +1,7 @@ +import { eventHandler, setHeader } from 'h3'; +import { verifyAccessToken } from '~/utils/jwt-utils'; +import { unAuthorizedResponse } from '~/utils/response'; + export default eventHandler(async (event) => { const userinfo = verifyAccessToken(event); if (!userinfo) { diff --git a/apps/backend-mock/api/menu/all.ts b/apps/backend-mock/api/menu/all.ts index 580cee4f9..7923f7ca5 100644 --- a/apps/backend-mock/api/menu/all.ts +++ b/apps/backend-mock/api/menu/all.ts @@ -1,5 +1,7 @@ +import { eventHandler } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; -import { unAuthorizedResponse } from '~/utils/response'; +import { MOCK_MENUS } from '~/utils/mock-data'; +import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; export default eventHandler(async (event) => { const userinfo = verifyAccessToken(event); diff --git a/apps/backend-mock/api/status.ts b/apps/backend-mock/api/status.ts index 41773e1d5..43782095d 100644 --- a/apps/backend-mock/api/status.ts +++ b/apps/backend-mock/api/status.ts @@ -1,3 +1,6 @@ +import { eventHandler, getQuery, setResponseStatus } from 'h3'; +import { useResponseError } from '~/utils/response'; + export default eventHandler((event) => { const { status } = getQuery(event); setResponseStatus(event, Number(status)); diff --git a/apps/backend-mock/api/system/dept/.post.ts b/apps/backend-mock/api/system/dept/.post.ts index c529ea1bd..9a4896afa 100644 --- a/apps/backend-mock/api/system/dept/.post.ts +++ b/apps/backend-mock/api/system/dept/.post.ts @@ -1,3 +1,4 @@ +import { eventHandler } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; import { sleep, diff --git a/apps/backend-mock/api/system/dept/[id].delete.ts b/apps/backend-mock/api/system/dept/[id].delete.ts index e48f051cc..eac0f5846 100644 --- a/apps/backend-mock/api/system/dept/[id].delete.ts +++ b/apps/backend-mock/api/system/dept/[id].delete.ts @@ -1,3 +1,4 @@ +import { eventHandler } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; import { sleep, diff --git a/apps/backend-mock/api/system/dept/[id].put.ts b/apps/backend-mock/api/system/dept/[id].put.ts index aa55c0857..6805e1395 100644 --- a/apps/backend-mock/api/system/dept/[id].put.ts +++ b/apps/backend-mock/api/system/dept/[id].put.ts @@ -1,3 +1,4 @@ +import { eventHandler } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; import { sleep, diff --git a/apps/backend-mock/api/system/dept/list.ts b/apps/backend-mock/api/system/dept/list.ts index ae819b622..a649a0d2f 100644 --- a/apps/backend-mock/api/system/dept/list.ts +++ b/apps/backend-mock/api/system/dept/list.ts @@ -1,4 +1,5 @@ import { faker } from '@faker-js/faker'; +import { eventHandler } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; diff --git a/apps/backend-mock/api/system/menu/list.ts b/apps/backend-mock/api/system/menu/list.ts index 5328b2fdf..ce96bb14e 100644 --- a/apps/backend-mock/api/system/menu/list.ts +++ b/apps/backend-mock/api/system/menu/list.ts @@ -1,3 +1,4 @@ +import { eventHandler } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; import { MOCK_MENU_LIST } from '~/utils/mock-data'; import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; diff --git a/apps/backend-mock/api/system/menu/name-exists.ts b/apps/backend-mock/api/system/menu/name-exists.ts index 5599c22b3..7d5551b3b 100644 --- a/apps/backend-mock/api/system/menu/name-exists.ts +++ b/apps/backend-mock/api/system/menu/name-exists.ts @@ -1,6 +1,7 @@ +import { eventHandler, getQuery } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; import { MOCK_MENU_LIST } from '~/utils/mock-data'; -import { unAuthorizedResponse } from '~/utils/response'; +import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; const namesMap: Record = {}; diff --git a/apps/backend-mock/api/system/menu/path-exists.ts b/apps/backend-mock/api/system/menu/path-exists.ts index 64774f790..f3c3be997 100644 --- a/apps/backend-mock/api/system/menu/path-exists.ts +++ b/apps/backend-mock/api/system/menu/path-exists.ts @@ -1,6 +1,7 @@ +import { eventHandler, getQuery } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; import { MOCK_MENU_LIST } from '~/utils/mock-data'; -import { unAuthorizedResponse } from '~/utils/response'; +import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; const pathMap: Record = { '/': 0 }; diff --git a/apps/backend-mock/api/system/role/list.ts b/apps/backend-mock/api/system/role/list.ts index 4d5f923e9..bad29a513 100644 --- a/apps/backend-mock/api/system/role/list.ts +++ b/apps/backend-mock/api/system/role/list.ts @@ -1,4 +1,5 @@ import { faker } from '@faker-js/faker'; +import { eventHandler, getQuery } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; import { getMenuIds, MOCK_MENU_LIST } from '~/utils/mock-data'; import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response'; diff --git a/apps/backend-mock/api/table/list.ts b/apps/backend-mock/api/table/list.ts index 3e6f705b8..6664b583e 100644 --- a/apps/backend-mock/api/table/list.ts +++ b/apps/backend-mock/api/table/list.ts @@ -1,6 +1,11 @@ import { faker } from '@faker-js/faker'; +import { eventHandler, getQuery } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; -import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response'; +import { + sleep, + unAuthorizedResponse, + usePageResponseSuccess, +} from '~/utils/response'; function generateMockDataList(count: number) { const dataList = []; @@ -44,30 +49,69 @@ export default eventHandler(async (event) => { await sleep(600); const { page, pageSize, sortBy, sortOrder } = getQuery(event); + // 规范化分页参数,处理 string[] + const pageRaw = Array.isArray(page) ? page[0] : page; + const pageSizeRaw = Array.isArray(pageSize) ? pageSize[0] : pageSize; + const pageNumber = Math.max( + 1, + Number.parseInt(String(pageRaw ?? '1'), 10) || 1, + ); + const pageSizeNumber = Math.min( + 100, + Math.max(1, Number.parseInt(String(pageSizeRaw ?? '10'), 10) || 10), + ); const listData = structuredClone(mockData); - if (sortBy && Reflect.has(listData[0], sortBy as string)) { + + // 规范化 query 入参,兼容 string[] + const sortKeyRaw = Array.isArray(sortBy) ? sortBy[0] : sortBy; + const sortOrderRaw = Array.isArray(sortOrder) ? sortOrder[0] : sortOrder; + // 检查 sortBy 是否是 listData 元素的合法属性键 + if ( + typeof sortKeyRaw === 'string' && + listData[0] && + Object.prototype.hasOwnProperty.call(listData[0], sortKeyRaw) + ) { + // 定义数组元素的类型 + type ItemType = (typeof listData)[0]; + const sortKey = sortKeyRaw as keyof ItemType; // 将 sortBy 断言为合法键 + const isDesc = sortOrderRaw === 'desc'; listData.sort((a, b) => { - if (sortOrder === 'asc') { - if (sortBy === 'price') { - return ( - Number.parseFloat(a[sortBy as string]) - - Number.parseFloat(b[sortBy as string]) - ); + const aValue = a[sortKey] as unknown; + const bValue = b[sortKey] as unknown; + + let result = 0; + + if (typeof aValue === 'number' && typeof bValue === 'number') { + result = aValue - bValue; + } else if (aValue instanceof Date && bValue instanceof Date) { + result = aValue.getTime() - bValue.getTime(); + } else if (typeof aValue === 'boolean' && typeof bValue === 'boolean') { + if (aValue === bValue) { + result = 0; } else { - return a[sortBy as string] > b[sortBy as string] ? 1 : -1; + result = aValue ? 1 : -1; } } else { - if (sortBy === 'price') { - return ( - Number.parseFloat(b[sortBy as string]) - - Number.parseFloat(a[sortBy as string]) - ); - } else { - return a[sortBy as string] < b[sortBy as string] ? 1 : -1; - } + const aStr = String(aValue); + const bStr = String(bValue); + const aNum = Number(aStr); + const bNum = Number(bStr); + result = + Number.isFinite(aNum) && Number.isFinite(bNum) + ? aNum - bNum + : aStr.localeCompare(bStr, undefined, { + numeric: true, + sensitivity: 'base', + }); } + + return isDesc ? -result : result; }); } - return usePageResponseSuccess(page as string, pageSize as string, listData); + return usePageResponseSuccess( + String(pageNumber), + String(pageSizeNumber), + listData, + ); }); diff --git a/apps/backend-mock/api/test.get.ts b/apps/backend-mock/api/test.get.ts index ca4a500be..dc2ceef79 100644 --- a/apps/backend-mock/api/test.get.ts +++ b/apps/backend-mock/api/test.get.ts @@ -1 +1,3 @@ +import { defineEventHandler } from 'h3'; + export default defineEventHandler(() => 'Test get handler'); diff --git a/apps/backend-mock/api/test.post.ts b/apps/backend-mock/api/test.post.ts index 698cf211e..0e9e337a8 100644 --- a/apps/backend-mock/api/test.post.ts +++ b/apps/backend-mock/api/test.post.ts @@ -1 +1,3 @@ +import { defineEventHandler } from 'h3'; + export default defineEventHandler(() => 'Test post handler'); diff --git a/apps/backend-mock/api/upload.ts b/apps/backend-mock/api/upload.ts index 1bb9e602d..436b63cbf 100644 --- a/apps/backend-mock/api/upload.ts +++ b/apps/backend-mock/api/upload.ts @@ -1,5 +1,6 @@ +import { eventHandler } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; -import { unAuthorizedResponse } from '~/utils/response'; +import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; export default eventHandler((event) => { const userinfo = verifyAccessToken(event); diff --git a/apps/backend-mock/api/user/info.ts b/apps/backend-mock/api/user/info.ts index cfa2346cb..138cb4331 100644 --- a/apps/backend-mock/api/user/info.ts +++ b/apps/backend-mock/api/user/info.ts @@ -1,5 +1,6 @@ +import { eventHandler } from 'h3'; import { verifyAccessToken } from '~/utils/jwt-utils'; -import { unAuthorizedResponse } from '~/utils/response'; +import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; export default eventHandler((event) => { const userinfo = verifyAccessToken(event); diff --git a/apps/backend-mock/middleware/1.api.ts b/apps/backend-mock/middleware/1.api.ts index bad9a41a1..339cda4db 100644 --- a/apps/backend-mock/middleware/1.api.ts +++ b/apps/backend-mock/middleware/1.api.ts @@ -1,3 +1,4 @@ +import { defineEventHandler } from 'h3'; import { forbiddenResponse, sleep } from '~/utils/response'; export default defineEventHandler(async (event) => { diff --git a/apps/backend-mock/routes/[...].ts b/apps/backend-mock/routes/[...].ts index 99f544b66..5a22563dc 100644 --- a/apps/backend-mock/routes/[...].ts +++ b/apps/backend-mock/routes/[...].ts @@ -1,3 +1,5 @@ +import { defineEventHandler } from 'h3'; + export default defineEventHandler(() => { return `

Hello Vben Admin

diff --git a/apps/backend-mock/utils/cookie-utils.ts b/apps/backend-mock/utils/cookie-utils.ts index 78f3aab73..187ce2f00 100644 --- a/apps/backend-mock/utils/cookie-utils.ts +++ b/apps/backend-mock/utils/cookie-utils.ts @@ -1,5 +1,7 @@ import type { EventHandlerRequest, H3Event } from 'h3'; +import { deleteCookie, getCookie, setCookie } from 'h3'; + export function clearRefreshTokenCookie(event: H3Event) { deleteCookie(event, 'jwt', { httpOnly: true, diff --git a/apps/backend-mock/utils/jwt-utils.ts b/apps/backend-mock/utils/jwt-utils.ts index 8cfc68436..718583070 100644 --- a/apps/backend-mock/utils/jwt-utils.ts +++ b/apps/backend-mock/utils/jwt-utils.ts @@ -1,8 +1,11 @@ import type { EventHandlerRequest, H3Event } from 'h3'; +import type { UserInfo } from './mock-data'; + +import { getHeader } from 'h3'; import jwt from 'jsonwebtoken'; -import { UserInfo } from './mock-data'; +import { MOCK_USERS } from './mock-data'; // TODO: Replace with your own secret key const ACCESS_TOKEN_SECRET = 'access_token_secret'; @@ -31,12 +34,22 @@ export function verifyAccessToken( return null; } - const token = authHeader.split(' ')[1]; + const tokenParts = authHeader.split(' '); + if (tokenParts.length !== 2) { + return null; + } + const token = tokenParts[1] as string; try { - const decoded = jwt.verify(token, ACCESS_TOKEN_SECRET) as UserPayload; + const decoded = jwt.verify( + token, + ACCESS_TOKEN_SECRET, + ) as unknown as UserPayload; const username = decoded.username; const user = MOCK_USERS.find((item) => item.username === username); + if (!user) { + return null; + } const { password: _pwd, ...userinfo } = user; return userinfo; } catch { @@ -50,7 +63,12 @@ export function verifyRefreshToken( try { const decoded = jwt.verify(token, REFRESH_TOKEN_SECRET) as UserPayload; const username = decoded.username; - const user = MOCK_USERS.find((item) => item.username === username); + const user = MOCK_USERS.find( + (item) => item.username === username, + ) as UserInfo; + if (!user) { + return null; + } const { password: _pwd, ...userinfo } = user; return userinfo; } catch { diff --git a/apps/backend-mock/utils/response.ts b/apps/backend-mock/utils/response.ts index 2a5a908f2..2d4242e98 100644 --- a/apps/backend-mock/utils/response.ts +++ b/apps/backend-mock/utils/response.ts @@ -1,5 +1,7 @@ import type { EventHandlerRequest, H3Event } from 'h3'; +import { setResponseStatus } from 'h3'; + export function useResponseSuccess(data: T) { return { code: 0, diff --git a/apps/web-antd/package.json b/apps/web-antd/package.json index 547c8c5e7..2c1694a97 100644 --- a/apps/web-antd/package.json +++ b/apps/web-antd/package.json @@ -1,6 +1,6 @@ { "name": "@vben/web-antd", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://vben.pro", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/apps/web-ele/package.json b/apps/web-ele/package.json index 3651c1b87..ff2e2dd56 100644 --- a/apps/web-ele/package.json +++ b/apps/web-ele/package.json @@ -1,6 +1,6 @@ { "name": "@vben/web-ele", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://vben.pro", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/apps/web-naive/package.json b/apps/web-naive/package.json index 0a5b6b316..f186e541b 100644 --- a/apps/web-naive/package.json +++ b/apps/web-naive/package.json @@ -1,6 +1,6 @@ { "name": "@vben/web-naive", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://vben.pro", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/docs/package.json b/docs/package.json index 639ca07a4..864e450aa 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@vben/docs", - "version": "5.5.8", + "version": "5.5.9", "private": true, "scripts": { "build": "vitepress build", diff --git a/docs/src/components/common-ui/vben-form.md b/docs/src/components/common-ui/vben-form.md index aed2b9f85..0ed023845 100644 --- a/docs/src/components/common-ui/vben-form.md +++ b/docs/src/components/common-ui/vben-form.md @@ -90,30 +90,52 @@ import { h } from 'vue'; import { globalShareState, IconPicker } from '@vben/common-ui'; import { $t } from '@vben/locales'; -import { - AutoComplete, - Button, - Checkbox, - CheckboxGroup, - DatePicker, - Divider, - Input, - InputNumber, - InputPassword, - Mentions, - notification, - Radio, - RadioGroup, - RangePicker, - Rate, - Select, - Space, - Switch, - Textarea, - TimePicker, - TreeSelect, - Upload, -} from 'ant-design-vue'; +const AutoComplete = defineAsyncComponent( + () => import('ant-design-vue/es/auto-complete'), +); +const Button = defineAsyncComponent(() => import('ant-design-vue/es/button')); +const Checkbox = defineAsyncComponent( + () => import('ant-design-vue/es/checkbox'), +); +const CheckboxGroup = defineAsyncComponent(() => + import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup), +); +const DatePicker = defineAsyncComponent( + () => import('ant-design-vue/es/date-picker'), +); +const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider')); +const Input = defineAsyncComponent(() => import('ant-design-vue/es/input')); +const InputNumber = defineAsyncComponent( + () => import('ant-design-vue/es/input-number'), +); +const InputPassword = defineAsyncComponent(() => + import('ant-design-vue/es/input').then((res) => res.InputPassword), +); +const Mentions = defineAsyncComponent( + () => import('ant-design-vue/es/mentions'), +); +const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio')); +const RadioGroup = defineAsyncComponent(() => + import('ant-design-vue/es/radio').then((res) => res.RadioGroup), +); +const RangePicker = defineAsyncComponent(() => + import('ant-design-vue/es/date-picker').then((res) => res.RangePicker), +); +const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate')); +const Select = defineAsyncComponent(() => import('ant-design-vue/es/select')); +const Space = defineAsyncComponent(() => import('ant-design-vue/es/space')); +const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch')); +const Textarea = defineAsyncComponent(() => + import('ant-design-vue/es/input').then((res) => res.Textarea), +); +const TimePicker = defineAsyncComponent( + () => import('ant-design-vue/es/time-picker'), +); +const TreeSelect = defineAsyncComponent( + () => import('ant-design-vue/es/tree-select'), +); +const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload')); + const withDefaultPlaceholder = ( component: T, @@ -304,10 +326,12 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单 | 属性名 | 描述 | 类型 | 默认值 | | --- | --- | --- | --- | -| layout | 表单项布局 | `'horizontal' \| 'vertical'` | `horizontal` | +| layout | 表单项布局 | `'horizontal' \| 'vertical'\| 'inline'` | `horizontal` | | showCollapseButton | 是否显示折叠按钮 | `boolean` | `false` | | wrapperClass | 表单的布局,基于tailwindcss | `any` | - | | actionWrapperClass | 表单操作区域class | `any` | - | +| actionLayout | 表单操作按钮位置 | `'newLine' \| 'rowEnd' \| 'inline'` | `rowEnd` | +| actionPosition | 表单操作按钮对齐方式 | `'left' \| 'center' \| 'right'` | `right` | | handleReset | 表单重置回调 | `(values: Record,) => Promise \| void` | - | | handleSubmit | 表单提交回调 | `(values: Record,) => Promise \| void` | - | | handleValuesChange | 表单值变化回调 | `(values: Record, fieldsChanged: string[]) => void` | - | diff --git a/internal/lint-configs/commitlint-config/package.json b/internal/lint-configs/commitlint-config/package.json index 16984c2f9..0c3a3aa7c 100644 --- a/internal/lint-configs/commitlint-config/package.json +++ b/internal/lint-configs/commitlint-config/package.json @@ -1,6 +1,6 @@ { "name": "@vben/commitlint-config", - "version": "5.5.8", + "version": "5.5.9", "private": true, "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", diff --git a/internal/lint-configs/stylelint-config/package.json b/internal/lint-configs/stylelint-config/package.json index 00f9b1d18..f8bc1cce6 100644 --- a/internal/lint-configs/stylelint-config/package.json +++ b/internal/lint-configs/stylelint-config/package.json @@ -1,6 +1,6 @@ { "name": "@vben/stylelint-config", - "version": "5.5.8", + "version": "5.5.9", "private": true, "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", diff --git a/internal/node-utils/package.json b/internal/node-utils/package.json index 490df9e92..fe4a6bab9 100644 --- a/internal/node-utils/package.json +++ b/internal/node-utils/package.json @@ -1,6 +1,6 @@ { "name": "@vben/node-utils", - "version": "5.5.8", + "version": "5.5.9", "private": true, "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", diff --git a/internal/tailwind-config/package.json b/internal/tailwind-config/package.json index 72c63819c..07b26be4f 100644 --- a/internal/tailwind-config/package.json +++ b/internal/tailwind-config/package.json @@ -1,6 +1,6 @@ { "name": "@vben/tailwind-config", - "version": "5.5.8", + "version": "5.5.9", "private": true, "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", diff --git a/internal/tsconfig/package.json b/internal/tsconfig/package.json index 74cfb915f..143bd32cb 100644 --- a/internal/tsconfig/package.json +++ b/internal/tsconfig/package.json @@ -1,6 +1,6 @@ { "name": "@vben/tsconfig", - "version": "5.5.8", + "version": "5.5.9", "private": true, "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", diff --git a/internal/vite-config/package.json b/internal/vite-config/package.json index c37777f24..db1fb4924 100644 --- a/internal/vite-config/package.json +++ b/internal/vite-config/package.json @@ -1,6 +1,6 @@ { "name": "@vben/vite-config", - "version": "5.5.8", + "version": "5.5.9", "private": true, "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", diff --git a/package.json b/package.json index 487cff525..f7c29406c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vben-admin-monorepo", - "version": "5.5.8", + "version": "5.5.9", "private": true, "keywords": [ "monorepo", @@ -98,7 +98,7 @@ "node": ">=20.10.0", "pnpm": ">=9.12.0" }, - "packageManager": "pnpm@10.12.4", + "packageManager": "pnpm@10.14.0", "pnpm": { "peerDependencyRules": { "allowedVersions": { diff --git a/packages/@core/base/design/package.json b/packages/@core/base/design/package.json index 13d2fefcf..ed40f4b58 100644 --- a/packages/@core/base/design/package.json +++ b/packages/@core/base/design/package.json @@ -1,6 +1,6 @@ { "name": "@vben-core/design", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/packages/@core/base/icons/package.json b/packages/@core/base/icons/package.json index 1e6e5250c..3c6775fbc 100644 --- a/packages/@core/base/icons/package.json +++ b/packages/@core/base/icons/package.json @@ -1,6 +1,6 @@ { "name": "@vben-core/icons", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/packages/@core/base/shared/package.json b/packages/@core/base/shared/package.json index 528c0d725..e6fb260fc 100644 --- a/packages/@core/base/shared/package.json +++ b/packages/@core/base/shared/package.json @@ -1,6 +1,6 @@ { "name": "@vben-core/shared", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/packages/@core/base/shared/src/utils/window.ts b/packages/@core/base/shared/src/utils/window.ts index 4608f4be9..2d8697dee 100644 --- a/packages/@core/base/shared/src/utils/window.ts +++ b/packages/@core/base/shared/src/utils/window.ts @@ -30,7 +30,7 @@ function openWindow(url: string, options: OpenWindowOptions = {}): void { function openRouteInNewWindow(path: string) { const { hash, origin } = location; const fullPath = path.startsWith('/') ? path : `/${path}`; - const url = `${origin}${hash ? '/#' : ''}${fullPath}`; + const url = `${origin}${hash && !fullPath.startsWith('/#') ? '/#' : ''}${fullPath}`; openWindow(url, { target: '_blank' }); } diff --git a/packages/@core/base/typings/package.json b/packages/@core/base/typings/package.json index e0e2c3727..6464e695a 100644 --- a/packages/@core/base/typings/package.json +++ b/packages/@core/base/typings/package.json @@ -1,6 +1,6 @@ { "name": "@vben-core/typings", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/packages/@core/composables/package.json b/packages/@core/composables/package.json index 39ca108f4..be8ee337b 100644 --- a/packages/@core/composables/package.json +++ b/packages/@core/composables/package.json @@ -1,6 +1,6 @@ { "name": "@vben-core/composables", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/packages/@core/preferences/package.json b/packages/@core/preferences/package.json index 786e6c2ce..75a5a5a1b 100644 --- a/packages/@core/preferences/package.json +++ b/packages/@core/preferences/package.json @@ -1,6 +1,6 @@ { "name": "@vben-core/preferences", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/packages/@core/ui-kit/form-ui/package.json b/packages/@core/ui-kit/form-ui/package.json index 497da77a9..ce7466d1a 100644 --- a/packages/@core/ui-kit/form-ui/package.json +++ b/packages/@core/ui-kit/form-ui/package.json @@ -1,6 +1,6 @@ { "name": "@vben-core/form-ui", - "version": "5.5.8", + "version": "5.5.9", "homepage": "https://github.com/vbenjs/vue-vben-admin", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "repository": { diff --git a/packages/@core/ui-kit/form-ui/src/components/form-actions.vue b/packages/@core/ui-kit/form-ui/src/components/form-actions.vue index 189755960..42101c124 100644 --- a/packages/@core/ui-kit/form-ui/src/components/form-actions.vue +++ b/packages/@core/ui-kit/form-ui/src/components/form-actions.vue @@ -34,17 +34,6 @@ const submitButtonOptions = computed(() => { // return !!unref(rootProps).showCollapseButton; // }); -const queryFormStyle = computed(() => { - if (!unref(rootProps).actionWrapperClass) { - return { - 'grid-column': `-2 / -1`, - marginLeft: 'auto', - }; - } - - return {}; -}); - async function handleSubmit(e: Event) { e?.preventDefault(); e?.stopPropagation(); @@ -86,22 +75,59 @@ watch( }, ); +const actionWrapperClass = computed(() => { + const props = unref(rootProps); + const actionLayout = props.actionLayout || 'rowEnd'; + const actionPosition = props.actionPosition || 'right'; + + const cls = [ + 'flex', + 'items-center', + 'gap-3', + props.compact ? 'pb-2' : 'pb-4', + props.layout === 'vertical' ? 'self-end' : 'self-center', + props.layout === 'inline' ? '' : 'w-full', + props.actionWrapperClass, + ]; + + switch (actionLayout) { + case 'newLine': { + cls.push('col-span-full'); + break; + } + case 'rowEnd': { + cls.push('col-[-2/-1]'); + break; + } + // 'inline' 不需要额外类名,保持默认 + } + + switch (actionPosition) { + case 'center': { + cls.push('justify-center'); + break; + } + case 'left': { + cls.push('justify-start'); + break; + } + default: { + // case 'right': 默认右对齐 + cls.push('justify-end'); + break; + } + } + + return cls.join(' '); +}); + defineExpose({ handleReset, handleSubmit, });