+ class="not-prose relative w-full overflow-x-auto rounded-t-lg px-4 py-6">
diff --git a/apps/vben5/docs/.vitepress/components/preview-group.vue b/apps/vben5/docs/.vitepress/components/preview-group.vue
index f816dd348..f22381d1c 100644
--- a/apps/vben5/docs/.vitepress/components/preview-group.vue
+++ b/apps/vben5/docs/.vitepress/components/preview-group.vue
@@ -49,15 +49,13 @@ const toggleOpen = () => {
+ @update:model-value="open = true">
+ class="absolute bottom-0 left-0 h-[2px] w-(--reka-tabs-indicator-size) translate-x-(--reka-tabs-indicator-position) rounded-full transition-[width,transform] duration-300">
{
:key="index"
:value="tab.label"
class="border-box px-4 py-3 text-foreground data-[state=active]:text-(--vp-c-indigo-1)"
- tabindex="-1"
- >
+ tabindex="-1">
{{ tab.label }}
@@ -76,14 +73,12 @@ const toggleOpen = () => {
:class="{
'py-2': !open,
}"
- class="flex items-center"
- >
+ class="flex items-center">
+ @click="toggleOpen" />
{{ open ? 'Collapse code' : 'Expand code' }}
@@ -92,15 +87,13 @@ const toggleOpen = () => {
diff --git a/apps/vben5/docs/src/components/common-ui/vben-api-component.md b/apps/vben5/docs/src/components/common-ui/vben-api-component.md
index b14e07258..d7ef529a4 100644
--- a/apps/vben5/docs/src/components/common-ui/vben-api-component.md
+++ b/apps/vben5/docs/src/components/common-ui/vben-api-component.md
@@ -116,8 +116,7 @@ function fetchApi(): Promise
> {
:immediate="false"
children-field="children"
loading-slot="suffixIcon"
- visible-event="onDropdownVisibleChange"
- />
+ visible-event="onDropdownVisibleChange" />
```
diff --git a/apps/vben5/docs/src/components/common-ui/vben-cropper.md b/apps/vben5/docs/src/components/common-ui/vben-cropper.md
index c25d32573..5fe60ee4c 100644
--- a/apps/vben5/docs/src/components/common-ui/vben-cropper.md
+++ b/apps/vben5/docs/src/components/common-ui/vben-cropper.md
@@ -163,8 +163,7 @@ const handleCropWithSize = async () => {
:img="imageUrl"
:width="500"
:height="400"
- aspect-ratio="1:1"
- />
+ aspect-ratio="1:1" />
diff --git a/apps/vben5/docs/src/components/common-ui/vben-table-action.md b/apps/vben5/docs/src/components/common-ui/vben-table-action.md
index 6ffe34dc7..b250921eb 100644
--- a/apps/vben5/docs/src/components/common-ui/vben-table-action.md
+++ b/apps/vben5/docs/src/components/common-ui/vben-table-action.md
@@ -92,8 +92,7 @@ import { VbenTableAction } from '#/adapter/vxe-table';
auth: ['AC_100100'],
},
]"
- align="center"
- />
+ align="center" />
@@ -118,8 +117,7 @@ function hasPermission(auth?: string | string[]) {
+ align="center" />
```
diff --git a/apps/vben5/docs/src/demos/vben-api-component/cascader/index.vue b/apps/vben5/docs/src/demos/vben-api-component/cascader/index.vue
index e7e856816..cb3716d94 100644
--- a/apps/vben5/docs/src/demos/vben-api-component/cascader/index.vue
+++ b/apps/vben5/docs/src/demos/vben-api-component/cascader/index.vue
@@ -95,6 +95,5 @@ function fetchApi(): Promise> {
:immediate="false"
children-field="children"
loading-slot="suffixIcon"
- visible-event="onDropdownVisibleChange"
- />
+ visible-event="onDropdownVisibleChange" />
diff --git a/apps/vben5/docs/src/demos/vben-count-to-animator/custom/index.vue b/apps/vben5/docs/src/demos/vben-count-to-animator/custom/index.vue
index 5a2434058..343da0b9e 100644
--- a/apps/vben5/docs/src/demos/vben-count-to-animator/custom/index.vue
+++ b/apps/vben5/docs/src/demos/vben-count-to-animator/custom/index.vue
@@ -7,6 +7,5 @@ import { VbenCountToAnimator } from '@vben/common-ui';
:end-val="2000000"
:start-val="1"
prefix="$"
- separator="/"
- />
+ separator="/" />
diff --git a/apps/vben5/docs/src/demos/vben-cropper/aspect-ratio/index.vue b/apps/vben5/docs/src/demos/vben-cropper/aspect-ratio/index.vue
index 8c28174ad..3b47c0dab 100644
--- a/apps/vben5/docs/src/demos/vben-cropper/aspect-ratio/index.vue
+++ b/apps/vben5/docs/src/demos/vben-cropper/aspect-ratio/index.vue
@@ -53,8 +53,7 @@ onBeforeUnmount(() => {
@@ -65,20 +64,17 @@ onBeforeUnmount(() => {
:img="imageUrl"
:width="500"
:height="300"
- :aspect-ratio="aspectRatio"
- />
+ :aspect-ratio="aspectRatio" />
diff --git a/apps/vben5/docs/src/demos/vben-cropper/basic/index.vue b/apps/vben5/docs/src/demos/vben-cropper/basic/index.vue
index 332a1c358..c9a65ee48 100644
--- a/apps/vben5/docs/src/demos/vben-cropper/basic/index.vue
+++ b/apps/vben5/docs/src/demos/vben-cropper/basic/index.vue
@@ -43,14 +43,12 @@ onBeforeUnmount(() => {
diff --git a/apps/vben5/docs/src/demos/vben-descriptions/size/index.vue b/apps/vben5/docs/src/demos/vben-descriptions/size/index.vue
index d75a7e6b2..bc0db2e2a 100644
--- a/apps/vben5/docs/src/demos/vben-descriptions/size/index.vue
+++ b/apps/vben5/docs/src/demos/vben-descriptions/size/index.vue
@@ -15,21 +15,18 @@ const items = [
bordered
title="Small"
:column="2"
- :items="items"
- />
+ :items="items" />
+ :items="items" />
+ :items="items" />
diff --git a/apps/vben5/docs/src/demos/vben-drawer/auto-height/drawer.vue b/apps/vben5/docs/src/demos/vben-drawer/auto-height/drawer.vue
index 41cb3c46b..36ab221f1 100644
--- a/apps/vben5/docs/src/demos/vben-drawer/auto-height/drawer.vue
+++ b/apps/vben5/docs/src/demos/vben-drawer/auto-height/drawer.vue
@@ -32,8 +32,7 @@ function handleUpdate(len: number) {
+ class="flex-center h-55 w-full bg-muted even:bg-heavy">
{{ item }}
diff --git a/apps/vben5/docs/src/demos/vben-modal/auto-height/modal.vue b/apps/vben5/docs/src/demos/vben-modal/auto-height/modal.vue
index 6a23fc87a..b3b041164 100644
--- a/apps/vben5/docs/src/demos/vben-modal/auto-height/modal.vue
+++ b/apps/vben5/docs/src/demos/vben-modal/auto-height/modal.vue
@@ -32,8 +32,7 @@ function handleUpdate(len: number) {
+ class="flex-center h-55 w-full bg-muted even:bg-heavy">
{{ item }}
diff --git a/apps/vben5/docs/src/demos/vben-table-action/dropdown/index.vue b/apps/vben5/docs/src/demos/vben-table-action/dropdown/index.vue
index b7664e51e..2d5261e5d 100644
--- a/apps/vben5/docs/src/demos/vben-table-action/dropdown/index.vue
+++ b/apps/vben5/docs/src/demos/vben-table-action/dropdown/index.vue
@@ -35,8 +35,7 @@ const dropdownActions: ActionItem[] = [
:dropdown-actions="dropdownActions"
align="start"
divider
- more-text="更多"
- />
+ more-text="更多" />
最近点击:{{ last }}
diff --git a/apps/vben5/docs/src/demos/vben-table-action/permission/index.vue b/apps/vben5/docs/src/demos/vben-table-action/permission/index.vue
index bce245ca8..28dde3963 100644
--- a/apps/vben5/docs/src/demos/vben-table-action/permission/index.vue
+++ b/apps/vben5/docs/src/demos/vben-table-action/permission/index.vue
@@ -23,6 +23,5 @@ const actions: ActionItem[] = [
+ align="start" />
diff --git a/apps/vben5/docs/src/demos/vben-tiptap/image-upload/index.vue b/apps/vben5/docs/src/demos/vben-tiptap/image-upload/index.vue
index db2bdf13d..e72d02ba7 100644
--- a/apps/vben5/docs/src/demos/vben-tiptap/image-upload/index.vue
+++ b/apps/vben5/docs/src/demos/vben-tiptap/image-upload/index.vue
@@ -30,8 +30,7 @@ const imageUpload: ImageUploadOptions = {
+ placeholder="尝试拖拽或粘贴图片..." />
提示:
diff --git a/apps/vben5/docs/src/en/components/common-ui/vben-api-component.md b/apps/vben5/docs/src/en/components/common-ui/vben-api-component.md
index a38a9e189..8df27c386 100644
--- a/apps/vben5/docs/src/en/components/common-ui/vben-api-component.md
+++ b/apps/vben5/docs/src/en/components/common-ui/vben-api-component.md
@@ -40,8 +40,7 @@ function fetchApi() {
:immediate="false"
children-field="children"
loading-slot="suffixIcon"
- visible-event="onDropdownVisibleChange"
- />
+ visible-event="onDropdownVisibleChange" />
```
diff --git a/apps/vben5/docs/src/en/components/common-ui/vben-cropper.md b/apps/vben5/docs/src/en/components/common-ui/vben-cropper.md
index ebddda318..5d1450d70 100644
--- a/apps/vben5/docs/src/en/components/common-ui/vben-cropper.md
+++ b/apps/vben5/docs/src/en/components/common-ui/vben-cropper.md
@@ -150,8 +150,7 @@ const handleCropWithSize = async () => {
:img="imageUrl"
:width="500"
:height="400"
- aspect-ratio="1:1"
- />
+ aspect-ratio="1:1" />
diff --git a/apps/vben5/docs/src/en/components/common-ui/vben-table-action.md b/apps/vben5/docs/src/en/components/common-ui/vben-table-action.md
index 7c1e76553..f04f55bb9 100644
--- a/apps/vben5/docs/src/en/components/common-ui/vben-table-action.md
+++ b/apps/vben5/docs/src/en/components/common-ui/vben-table-action.md
@@ -92,8 +92,7 @@ import { VbenTableAction } from '#/adapter/vxe-table';
auth: ['AC_100100'],
},
]"
- align="center"
- />
+ align="center" />
@@ -118,8 +117,7 @@ function hasPermission(auth?: string | string[]) {
+ align="center" />
```
diff --git a/apps/vben5/docs/src/en/guide/essentials/route.md b/apps/vben5/docs/src/en/guide/essentials/route.md
index 8fb0a6d1c..b637f2299 100644
--- a/apps/vben5/docs/src/en/guide/essentials/route.md
+++ b/apps/vben5/docs/src/en/guide/essentials/route.md
@@ -61,6 +61,13 @@ The configuration method of static routes and dynamic routes is the same. Below
### Secondary Routes
+::: tip
+
+- Only top-level routes should start their `path` with `/`; routes inside `children` should use relative segments such as `about` or `menu1`.
+- When a parent route does not define `redirect`, the framework automatically fills it with the first child route. This only works when child paths stay relative.
+
+:::
+
::: details Secondary Route Example Code
```ts
diff --git a/apps/vben5/docs/src/en/guide/in-depth/login.md b/apps/vben5/docs/src/en/guide/in-depth/login.md
index 7fdac2c6f..6cd0609bb 100644
--- a/apps/vben5/docs/src/en/guide/in-depth/login.md
+++ b/apps/vben5/docs/src/en/guide/in-depth/login.md
@@ -37,8 +37,7 @@ If you want to adjust the content of the login form, you can configure the `Auth
```vue
+ @submit="authStore.authLogin" />
```
::: details AuthenticationLogin Component Props
diff --git a/apps/vben5/docs/src/guide/essentials/route.md b/apps/vben5/docs/src/guide/essentials/route.md
index 8383e7620..91d544692 100644
--- a/apps/vben5/docs/src/guide/essentials/route.md
+++ b/apps/vben5/docs/src/guide/essentials/route.md
@@ -55,6 +55,13 @@ const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
### 二级路由
+::: tip
+
+- 只有顶级路由的 `path` 需要以 `/` 开头;写在 `children` 中的子路由请使用相对路径片段,例如 `about`、`menu1`。
+- 当父级路由未显式配置 `redirect` 时,框架会自动补全到第一个子路由的重定向;这依赖子路由使用相对路径。
+
+:::
+
::: details 二级路由示例代码
```ts
@@ -101,6 +108,7 @@ export default routes;
::: tip
+- 多级路由同样遵循“顶级绝对路径、子级相对路径”的组织方式,避免在 `children` 中重复写完整路径。
- 如果没有特殊情况,父级路由的 `redirect` 属性,不需要指定,默认会指向第一个子路由。
:::
diff --git a/apps/vben5/docs/src/guide/in-depth/login.md b/apps/vben5/docs/src/guide/in-depth/login.md
index adb89b75d..df09f6785 100644
--- a/apps/vben5/docs/src/guide/in-depth/login.md
+++ b/apps/vben5/docs/src/guide/in-depth/login.md
@@ -22,8 +22,7 @@ outline: deep
:app-name="appName"
:logo="logo"
:page-description="$t('authentication.pageDesc')"
- :page-title="$t('authentication.pageTitle')"
->
+ :page-title="$t('authentication.pageTitle')">
```
@@ -34,8 +33,7 @@ outline: deep
```vue
+ @submit="authStore.authLogin" />
```
::: details AuthenticationLogin 组件参数
diff --git a/apps/vben5/eslint.config.mjs b/apps/vben5/eslint.config.mjs
index 63bd9adc3..39b7d71dc 100644
--- a/apps/vben5/eslint.config.mjs
+++ b/apps/vben5/eslint.config.mjs
@@ -1,3 +1,15 @@
import { defineConfig } from '@vben/eslint-config';
-export default defineConfig();
+export default defineConfig({
+ "vue/html-closing-bracket-newline": [
+ "error",
+ {
+ "singleline": "never",
+ "multiline": "always",
+ "selfClosingTag": {
+ "singleline": "never",
+ "multiline": "never"
+ }
+ }
+ ]
+});
diff --git a/apps/vben5/internal/lint-configs/eslint-config/src/configs/javascript.ts b/apps/vben5/internal/lint-configs/eslint-config/src/configs/javascript.ts
index bd9bd852b..27e14371e 100644
--- a/apps/vben5/internal/lint-configs/eslint-config/src/configs/javascript.ts
+++ b/apps/vben5/internal/lint-configs/eslint-config/src/configs/javascript.ts
@@ -16,6 +16,7 @@ const rulesCoveredByOxlint = new Set([
'no-const-assign',
'no-constant-binary-expression',
'no-constant-condition',
+ 'no-control-regex',
'no-debugger',
'no-delete-var',
'no-dupe-args',
@@ -48,6 +49,8 @@ const rulesCoveredByOxlint = new Set([
'no-shadow-restricted-names',
'no-sparse-arrays',
'no-this-before-super',
+ 'no-unassigned-vars',
+ 'no-unexpected-multiline',
'no-unreachable',
'no-unsafe-finally',
'no-unsafe-negation',
@@ -59,6 +62,7 @@ const rulesCoveredByOxlint = new Set([
'no-useless-catch',
'no-useless-escape',
'no-with',
+ 'preserve-caught-error',
'require-yield',
'use-isnan',
'valid-typeof',
diff --git a/apps/vben5/internal/lint-configs/oxlint-config/src/configs/javascript.ts b/apps/vben5/internal/lint-configs/oxlint-config/src/configs/javascript.ts
index 4352c8017..89784dc36 100644
--- a/apps/vben5/internal/lint-configs/oxlint-config/src/configs/javascript.ts
+++ b/apps/vben5/internal/lint-configs/oxlint-config/src/configs/javascript.ts
@@ -41,7 +41,7 @@ const javascript: OxlintConfig = {
'no-caller': 'error',
'no-case-declarations': 'error',
'no-console': ['error', { allow: ['warn', 'error'] }],
- 'no-control-regex': 'off',
+ 'no-control-regex': 'error',
'no-debugger': 'error',
'no-empty': ['error', { allowEmptyCatch: true }],
'no-fallthrough': 'error',
@@ -68,6 +68,8 @@ const javascript: OxlintConfig = {
],
'no-template-curly-in-string': 'error',
'no-throw-literal': 'error',
+ 'no-unassigned-vars': 'error',
+ 'no-unexpected-multiline': 'error',
'no-unused-expressions': [
'error',
{
@@ -108,6 +110,12 @@ const javascript: OxlintConfig = {
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'prefer-template': 'error',
+ 'preserve-caught-error': [
+ 'error',
+ {
+ requireCatchParameter: false,
+ },
+ ],
'symbol-description': 'error',
'unicode-bom': ['error', 'never'],
'use-isnan': [
diff --git a/apps/vben5/internal/lint-configs/oxlint-config/src/configs/vue.ts b/apps/vben5/internal/lint-configs/oxlint-config/src/configs/vue.ts
index 172507d69..6e140b85d 100644
--- a/apps/vben5/internal/lint-configs/oxlint-config/src/configs/vue.ts
+++ b/apps/vben5/internal/lint-configs/oxlint-config/src/configs/vue.ts
@@ -2,6 +2,7 @@ import type { OxlintConfig } from 'oxlint';
const vue: OxlintConfig = {
rules: {
+ 'vue/no-reserved-component-names': 'off',
'vue/prefer-import-from-vue': 'error',
},
};
diff --git a/apps/vben5/internal/node-utils/src/git.ts b/apps/vben5/internal/node-utils/src/git.ts
index 88f159cc5..da6dc74cc 100644
--- a/apps/vben5/internal/node-utils/src/git.ts
+++ b/apps/vben5/internal/node-utils/src/git.ts
@@ -20,7 +20,13 @@ async function getStagedFiles(): Promise
{
'-z',
]);
- let changedList = stdout ? stdout.replace(/\0$/, '').split('\0') : [];
+ const nullSeparator = '\u0000';
+ const normalizedStdout = stdout.endsWith(nullSeparator)
+ ? stdout.slice(0, -1)
+ : stdout;
+ let changedList = normalizedStdout
+ ? normalizedStdout.split(nullSeparator)
+ : [];
changedList = changedList.map((item) => path.resolve(process.cwd(), item));
const changedSet = new Set(changedList);
changedSet.delete('');
diff --git a/apps/vben5/internal/vite-config/src/plugins/importmap.ts b/apps/vben5/internal/vite-config/src/plugins/importmap.ts
index 0ccda99f8..1cf3cb84f 100644
--- a/apps/vben5/internal/vite-config/src/plugins/importmap.ts
+++ b/apps/vben5/internal/vite-config/src/plugins/importmap.ts
@@ -180,7 +180,7 @@ async function viteImportMapPlugin(
},
injectTo: 'head-prepend',
tag: 'script',
- children: `${JSON.stringify(importmapJson)}`,
+ children: JSON.stringify(importmapJson),
},
],
};
diff --git a/apps/vben5/oxfmt.config.ts b/apps/vben5/oxfmt.config.ts
index 9ad7fe1bf..4db35686d 100644
--- a/apps/vben5/oxfmt.config.ts
+++ b/apps/vben5/oxfmt.config.ts
@@ -1,6 +1,7 @@
import { defineConfig } from '@vben/oxfmt-config';
export default defineConfig({
+ bracketSameLine: true,
ignorePatterns: [
'dist',
'dev-dist',
@@ -18,7 +19,7 @@ export default defineConfig({
'.output',
'**/*.svg',
'**/*.sh',
- 'public',
+ 'public/',
'.npmrc',
'*-lock.yaml',
'skills-lock.json',
diff --git a/apps/vben5/oxlint.config.ts b/apps/vben5/oxlint.config.ts
index 230ddd98b..21bf2ac5c 100644
--- a/apps/vben5/oxlint.config.ts
+++ b/apps/vben5/oxlint.config.ts
@@ -2,4 +2,15 @@ import { oxlintConfig } from '@vben/oxlint-config';
import { defineConfig } from 'oxlint';
-export default defineConfig(oxlintConfig);
+export default defineConfig({
+ ...oxlintConfig,
+ rules: {
+ 'no-unused-expressions': 'warn',
+ 'no-unused-vars': 'warn',
+ 'typescript/no-dynamic-delete': 'warn',
+ 'typescript/no-non-null-assertion': 'warn',
+ 'unicorn/no-useless-spread': 'warn',
+ 'vitest/hoisted-apis-on-top': 'warn',
+ 'vitest/require-mock-type-parameters': 'warn',
+ },
+});
diff --git a/apps/vben5/package.json b/apps/vben5/package.json
index dbe278a44..10b2fcdea 100644
--- a/apps/vben5/package.json
+++ b/apps/vben5/package.json
@@ -55,6 +55,7 @@
"dev:play": "pnpm -F @vben/playground run dev",
"format": "vsh lint --format",
"lint": "vsh lint",
+ "lint:check": "oxlint --quiet",
"postinstall": "pnpm -r run --if-present stub",
"preinstall": "npx only-allow pnpm",
"prepare": "is-ci || pnpm exec lefthook install",
diff --git a/apps/vben5/packages/@abp/account/src/components/MyProfile.vue b/apps/vben5/packages/@abp/account/src/components/MyProfile.vue
index a17f9b5eb..e7eda10ed 100644
--- a/apps/vben5/packages/@abp/account/src/components/MyProfile.vue
+++ b/apps/vben5/packages/@abp/account/src/components/MyProfile.vue
@@ -78,63 +78,53 @@ onMounted(onGet);
+ mode="inline" />
diff --git a/apps/vben5/packages/@abp/account/src/components/QrCodeLogin.vue b/apps/vben5/packages/@abp/account/src/components/QrCodeLogin.vue
index 192f28e54..db031e88a 100644
--- a/apps/vben5/packages/@abp/account/src/components/QrCodeLogin.vue
+++ b/apps/vben5/packages/@abp/account/src/components/QrCodeLogin.vue
@@ -165,8 +165,7 @@ onUnmounted(() => {