Browse Source

Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin

# Conflicts:
#	.env.development
#	.env.production
#	pnpm-lock.yaml
shizhongming 2 years ago
parent
commit
054c09fb53
  1. 2
      .commitlintrc.cjs
  2. 6
      .env.analyze
  3. 7
      .env.development
  4. 6
      .env.docker
  5. 6
      .env.production
  6. 8
      .env.test
  7. 28
      .github/workflows/deploy.yml
  8. 2
      .github/workflows/linter.yml
  9. 22
      .github/workflows/release-tag.yml
  10. 24
      .github/workflows/release.yml
  11. 20
      .github/workflows/stale.yml
  12. 1
      .npmrc
  13. 4
      .vscode/extensions.json
  14. 2
      .vscode/launch.json
  15. 28
      .vscode/settings.json
  16. 2
      CHANGELOG.en_US.md
  17. 248
      CHANGELOG.md
  18. 6
      internal/stylelint-config/package.json
  19. 4
      internal/ts-config/package.json
  20. 14
      internal/vite-config/package.json
  21. 72
      package.json
  22. 4
      packages/hooks/package.json
  23. 16788
      pnpm-lock.yaml
  24. 8
      src/components/Application/src/search/useMenuSearch.ts
  25. 2
      src/components/Form/src/hooks/useAdvanced.ts
  26. 68
      src/components/Form/src/hooks/useFormEvents.ts
  27. 7
      src/components/Modal/src/BasicModal.vue
  28. 10
      src/components/Modal/src/index.less
  29. 21
      src/components/Page/src/PageWrapper.vue
  30. 20
      src/components/Table/src/BasicTable.vue
  31. 4
      src/components/Table/src/hooks/useTableScroll.ts
  32. 4
      src/components/Upload/src/BasicUpload.vue
  33. 6
      src/components/Upload/src/components/FileList.vue
  34. 18
      src/components/Upload/src/components/ImageUpload.vue
  35. 3
      src/components/Upload/src/components/UploadModal.vue
  36. 31
      src/components/Upload/src/components/UploadPreviewModal.vue
  37. 11
      src/components/Upload/src/helper.ts
  38. 18
      src/components/Upload/src/props.ts
  39. 13
      src/hooks/web/useWatermark.ts
  40. 239
      src/layouts/default/header/components/Breadcrumb.vue
  41. 3
      src/router/guard/index.ts
  42. 2
      src/router/helper/routeHelper.ts
  43. 1
      src/utils/http/axios/index.ts
  44. 223
      src/views/demo/comp/upload/index.vue
  45. 11
      src/views/demo/form/AdvancedForm.vue
  46. 82
      src/views/demo/form/AppendForm.vue
  47. 3
      src/views/demo/form/index.vue
  48. 57
      src/views/demo/steps/index.vue
  49. 6
      vite.config.ts

2
.commitlintrc.cjs

@ -51,7 +51,7 @@ module.exports = {
],
},
prompt: {
/** @use `yarn commit :f` */
/** @use `pnpm commit :f` */
alias: {
f: 'docs: fix typos',
r: 'docs: update README',

6
.env.analyze

@ -11,13 +11,13 @@ VITE_BUILD_COMPRESS = 'none'
# Basic interface address SPA
VITE_GLOB_API_URL=/basic-api
VITE_GLOB_API_URL = /basic-api
# File upload address, optional
# It can be forwarded by nginx or write the actual address directly
VITE_GLOB_UPLOAD_URL=/upload
VITE_GLOB_UPLOAD_URL = /upload
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
VITE_GLOB_API_URL_PREFIX =
VITE_ENABLE_ANALYZE = true

7
.env.development

@ -5,13 +5,14 @@ VITE_USE_MOCK = true
VITE_PUBLIC_PATH = /
# Basic interface address SPA
VITE_GLOB_API_URL=/basic-api
VITE_GLOB_API_URL = /basic-api
# File upload address, optional
VITE_GLOB_UPLOAD_URL=/upload
VITE_GLOB_UPLOAD_URL = /upload
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
VITE_GLOB_API_URL_PREFIX =
# 单体架构
VITE_GLOB_API_MODE=standalone

6
.env.docker

@ -13,10 +13,10 @@ VITE_DROP_CONSOLE = true
# Optional: gzip | brotli | none
# If you need multiple forms, you can use `,` to separate
VITE_BUILD_COMPRESS = 'none'
VITE_GLOB_API_URL="__vg_base_url"
VITE_GLOB_API_URL = "__vg_base_url"
# File upload address, optional
# It can be forwarded by nginx or write the actual address directly
VITE_GLOB_UPLOAD_URL=/files/upload
VITE_GLOB_UPLOAD_URL = /files/upload
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
VITE_GLOB_API_URL_PREFIX =

6
.env.production

@ -11,11 +11,11 @@ VITE_BUILD_COMPRESS = 'none'
# Basic interface address SPA
VITE_GLOB_API_URL=/
VITE_GLOB_API_URL = /basic-api
# File upload address, optional
# It can be forwarded by nginx or write the actual address directly
VITE_GLOB_UPLOAD_URL=/upload
VITE_GLOB_UPLOAD_URL = /upload
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
VITE_GLOB_API_URL_PREFIX =

8
.env.test

@ -1,4 +1,4 @@
NODE_ENV=production
NODE_ENV = production
# Whether to open mock
VITE_USE_MOCK = true
@ -11,11 +11,11 @@ VITE_PUBLIC_PATH = /
VITE_BUILD_COMPRESS = 'none'
# Basic interface address SPA
VITE_GLOB_API_URL=/basic-api
VITE_GLOB_API_URL = /basic-api
# File upload address, optional
# It can be forwarded by nginx or write the actual address directly
VITE_GLOB_UPLOAD_URL=/upload
VITE_GLOB_UPLOAD_URL = /upload
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
VITE_GLOB_API_URL_PREFIX =

28
.github/workflows/deploy.yml

@ -60,7 +60,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
# - uses: NullVoxPopuli/action-setup-pnpm@v2
# - uses: NullVoxPopuli/action-setup-pnpm@v2
- name: Sed Config Base
shell: bash
@ -72,25 +72,25 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
version: 9
run_install: false
- name: use Node.js 16
- name: use Node.js 20
uses: actions/setup-node@v3
with:
node-version: '20.x'
# - name: Get yarn cache directory path
# id: yarn-cache-dir-path
# run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
#
# - name: Cache dependencies
# uses: actions/cache@v3
# with:
# path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-yarn-
# - name: Get yarn cache directory path
# id: yarn-cache-dir-path
# run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
#
# - name: Cache dependencies
# uses: actions/cache@v3
# with:
# path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-yarn-
- name: Set SSH Environment
env:

2
.github/workflows/linter.yml

@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
node-version: [16.x, 18.x]
node-version: [18.x, 20.x]
steps:
- name: Checkout code

22
.github/workflows/release-tag.yml

@ -0,0 +1,22 @@
name: Create Release Tag
on:
push:
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
build:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Create Release for Tag
id: release_tag
uses: ncipollo/release-action@v1
with:
generateReleaseNotes: 'true'
body: |
> Please refer to [CHANGELOG.md](https://github.com/anncwb/vue-vben-admin/blob/main/CHANGELOG.md) for details.

24
.github/workflows/release.yml

@ -1,24 +0,0 @@
name: Create Release
on:
push:
tags:
- v*
jobs:
build:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Create Release for Tag
id: release_tag
uses: yyx990803/release-tag@master
env:
GITHUB_TOKEN: ${{ secrets.OPER_TOKEN }}
with:
tag_name: ${{ github.ref }}
body: |
Please refer to [CHANGELOG.md](https://github.com/anncwb/vue-vben-admin/blob/main/CHANGELOG.md) for details.

20
.github/workflows/stale.yml

@ -1,18 +1,18 @@
name: "Close stale issues"
name: 'Close stale issues'
on:
schedule:
- cron: "30 1 * * *"
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.OPER_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
exempt-issue-labels: 'bug,enhancement'
days-before-stale: 60
days-before-close: 7
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.OPER_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
exempt-issue-labels: 'bug,enhancement'
days-before-stale: 60
days-before-close: 7

1
.npmrc

@ -5,3 +5,4 @@ public-hoist-pattern[]=lint-staged
public-hoist-pattern[]=*stylelint*
public-hoist-pattern[]=@commitlint/cli
public-hoist-pattern[]=@vben/eslint-config
package-manager-strict=false

4
.vscode/extensions.json

@ -9,6 +9,6 @@
"antfu.iconify",
"antfu.unocss",
"mikestead.dotenv",
"warmthsea.vscode-custom-code-color",
"warmthsea.vscode-custom-code-color"
]
}
}

2
.vscode/launch.json

@ -10,4 +10,4 @@
"sourceMaps": true
}
]
}
}

28
.vscode/settings.json

@ -55,14 +55,7 @@
"**/yarn.lock": true
},
"stylelint.enable": true,
"stylelint.validate": [
"css",
"less",
"postcss",
"scss",
"vue",
"sass"
],
"stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"],
"path-intellisense.mappings": {
"@/": "${workspaceRoot}/src"
},
@ -101,24 +94,15 @@
},
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"i18n-ally.localesPaths": [
"src/locales/lang"
],
"i18n-ally.localesPaths": ["src/locales/lang"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.namespace": true,
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
"i18n-ally.enabledParsers": [
"json",
"ts",
"js"
],
"i18n-ally.enabledParsers": ["json", "ts", "js"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": [
"vue",
"react"
],
"i18n-ally.enabledFrameworks": ["vue", "react"],
"cSpell.words": [
"antd",
"antv",
@ -188,5 +172,5 @@
"terminal.integrated.scrollback": 10000,
"nuxt.isNuxtApp": false,
"vscodeCustomCodeColor.highlightValue": "v-auth",
"vscodeCustomCodeColor.highlightValueColor": "#6366f1",
}
"vscodeCustomCodeColor.highlightValueColor": "#6366f1"
}

2
CHANGELOG.en_US.md

@ -308,7 +308,7 @@
- Fix the height issue of the lock screen pop-up window
- Fixed the problem that the half-selected state of the `Column Display` checkbox of `BaiscTable` was incorrectly displayed
- Fixed the problem that the preview list of the `BasicUpload` component could not be displayed in some cases
- Fix the problem that the `options` setting of ` RadioButtonGroup``disabled ` does not take effect
- Fix the problem that the `options` setting of `RadioButtonGroup``disabled` does not take effect
- Fix the problem that the button for uploading pictures in the read-only mode of the `Tinymce` component is still available
- Fix the stuttering problem of `BasicForm` under certain circumstances
- Fix the problem that "directory" routing does not work

248
CHANGELOG.md

@ -1,3 +1,251 @@
## [2.11.2](https://github.com/vbenjs/vue-vben-admin/compare/v2.11.1...v2.11.2) (2024-04-23)
### Bug Fixes
- **BasicForm:** solve the error about setFieldValue array ([#3775](https://github.com/vbenjs/vue-vben-admin/issues/3775)) ([f5cd3ad](https://github.com/vbenjs/vue-vben-admin/commit/f5cd3ad593ded10a9702cf342d788c4b1540944a))
- **ci:** use for package-manager-strict ([d53a5b2](https://github.com/vbenjs/vue-vben-admin/commit/d53a5b22ccadc28f99fc5e9751e3177d349ba8b9))
## [2.11.1](https://github.com/vbenjs/vue-vben-admin/compare/v2.11.0...v2.11.1) (2024-04-20)
### Bug Fixes
- the form not working when setFieldsValue through form-groups and add a demo with form groups ([#3765](https://github.com/vbenjs/vue-vben-admin/issues/3765)) ([65e5e71](https://github.com/vbenjs/vue-vben-admin/commit/65e5e71f5ee44eac221721de2c8c1d03e622e34a))
# [2.11.0](https://github.com/vbenjs/vue-vben-admin/compare/2.10.1...2.11.0) (2024-04-20)
### Bug Fixes
- (demo->page>form>high) expose getDataSource close [#3529](https://github.com/vbenjs/vue-vben-admin/issues/3529) ([#3530](https://github.com/vbenjs/vue-vben-admin/issues/3530)) ([0c1235e](https://github.com/vbenjs/vue-vben-admin/commit/0c1235e75aa6a855d774435ef08d3ffae19d1272))
- [#2744](https://github.com/vbenjs/vue-vben-admin/issues/2744)tabs选项卡渲染问题,以及完善路由中affix=true时处理逻辑。 ([#3127](https://github.com/vbenjs/vue-vben-admin/issues/3127)) ([b43d306](https://github.com/vbenjs/vue-vben-admin/commit/b43d3069e1ec731e339ed28c17325620f1fe9a6e))
- [#3077](https://github.com/vbenjs/vue-vben-admin/issues/3077) 最新代码 ApiTransfer编辑后无法正常显示数据 ([#3083](https://github.com/vbenjs/vue-vben-admin/issues/3083)) ([c0c3116](https://github.com/vbenjs/vue-vben-admin/commit/c0c31161939027f64fa44a57084acafa0c6c2a8b))
- [#3144](https://github.com/vbenjs/vue-vben-admin/issues/3144) Drawer的footer样式错位问题 ([#3148](https://github.com/vbenjs/vue-vben-admin/issues/3148)) ([8e9d4f0](https://github.com/vbenjs/vue-vben-admin/commit/8e9d4f0a5758bf414b2885f02563a3b24f5cf6f1))
- 1.修正ImageUpload直接使用时无法正常回传value 2.修正ImageUpload无法正常初始化第一次传值 ([#3704](https://github.com/vbenjs/vue-vben-admin/issues/3704)) ([b5c87cf](https://github.com/vbenjs/vue-vben-admin/commit/b5c87cf6abc46ccd9b9bb8795b235b738e8bb376))
- 菜单搜索功能修复 ([#3688](https://github.com/vbenjs/vue-vben-admin/issues/3688)) ([c1809cd](https://github.com/vbenjs/vue-vben-admin/commit/c1809cd6c59228d7932f24a2b1f8e4933654238d))
- 当TableAction的actions属性中的ActionItem传递了color属性时,PopConfirm的指示箭头颜色异常问题 ([#3597](https://github.com/vbenjs/vue-vben-admin/issues/3597)) ([e6a7384](https://github.com/vbenjs/vue-vben-admin/commit/e6a73840ab7c7cbd5a5a534bd248f5ed5df11e5c))
- 多选框必填选中校验异常,close [#3097](https://github.com/vbenjs/vue-vben-admin/issues/3097) ([#3103](https://github.com/vbenjs/vue-vben-admin/issues/3103)) ([18f5583](https://github.com/vbenjs/vue-vben-admin/commit/18f55833e282206c1ca650a7c62654d45e819759))
- 解决 'Cannot find module uncss' 的问题 ([#3334](https://github.com/vbenjs/vue-vben-admin/issues/3334)) ([3a5f406](https://github.com/vbenjs/vue-vben-admin/commit/3a5f4062602f8394523a82cd807a27580e96a42a))
- 解决table复选框点击无法勾选状态问题 ([#3370](https://github.com/vbenjs/vue-vben-admin/issues/3370)) ([dde3652](https://github.com/vbenjs/vue-vben-admin/commit/dde3652b7d8b68b7f8ac669bd96a55c7b9b1b1fa))
- 设置 baseurl 后不生效的问题 ([#3318](https://github.com/vbenjs/vue-vben-admin/issues/3318)) ([4305f58](https://github.com/vbenjs/vue-vben-admin/commit/4305f58d201382c71f41fcd2625bc45ae09a2ae0))
- 使用suffix时,label没有垂直居中 ([#3384](https://github.com/vbenjs/vue-vben-admin/issues/3384)) ([6b6b790](https://github.com/vbenjs/vue-vben-admin/commit/6b6b790f87edab31cb8e0dff730a1490903a3048))
- 修复表单按钮的类型定义外部无法修改重置或者提交按钮的文字的问题 ([141f3bd](https://github.com/vbenjs/vue-vben-admin/commit/141f3bdbd06f4d32e3d0e871072f876c29a8d68b))
- 修复表单设计的右侧属性配置面板中部分表单错乱的问题 ([#3300](https://github.com/vbenjs/vue-vben-admin/issues/3300)). close [#3268](https://github.com/vbenjs/vue-vben-admin/issues/3268) ([cb13986](https://github.com/vbenjs/vue-vben-admin/commit/cb13986a170815c5a21c86033057a8a56d608388))
- 修复菜单在MIX_SIDEBAR模式下title显示为name的问题 ([#3682](https://github.com/vbenjs/vue-vben-admin/issues/3682)) ([264f34e](https://github.com/vbenjs/vue-vben-admin/commit/264f34e49d413783d6d23715ebd9ab721b03d01c))
- 修复黑暗模式下一些样式问题 ([#3201](https://github.com/vbenjs/vue-vben-admin/issues/3201)) ([054a476](https://github.com/vbenjs/vue-vben-admin/commit/054a476d25b2d8322b238a6da6028051bcfdab84))
- 修复确认弹出框样式错乱的问题 ([#3742](https://github.com/vbenjs/vue-vben-admin/issues/3742)) ([a00725b](https://github.com/vbenjs/vue-vben-admin/commit/a00725be571e90fa5d807ec2bc1e23b160c824ff))
- 修复设置抽屉弹框滚动条样式异常 ([#3193](https://github.com/vbenjs/vue-vben-admin/issues/3193)) ([4755017](https://github.com/vbenjs/vue-vben-admin/commit/4755017bcc2dc0aee2f98b46d929a060a5b1bb62))
- 修复BasicForm使用componentProps函数返回valueFormat时DatePicker无法正确格式化的问题 ([#3357](https://github.com/vbenjs/vue-vben-admin/issues/3357)) ([beee351](https://github.com/vbenjs/vue-vben-admin/commit/beee35173b84dfb4c27bcd403df689e102379303))
- 修复index.html加载文字偏移的问题 ([#3306](https://github.com/vbenjs/vue-vben-admin/issues/3306)) ([c715d35](https://github.com/vbenjs/vue-vben-admin/commit/c715d35ad5754dd78135073ddbea86e43e17be91))
- 修复Modal.confirm的返回类型问题,需要有destroy,update的方法 ([#3161](https://github.com/vbenjs/vue-vben-admin/issues/3161)) ([a0e43ab](https://github.com/vbenjs/vue-vben-admin/commit/a0e43abeab2930097209a0cf6c21f3de687435ca))
- 修复notice样式绑定路径错误 ([#3218](https://github.com/vbenjs/vue-vben-admin/issues/3218)) ([ee8ec9e](https://github.com/vbenjs/vue-vben-admin/commit/ee8ec9eacfbfe1c5dc3a842da126dbaf5d54b126))
- 修复rule validator类型默认为string,导致 radio 等组件在 setFormValues 时,如果值不是string类型,提示校验错误 ([a63a10c](https://github.com/vbenjs/vue-vben-admin/commit/a63a10c047cda32d92f35780163772fb20a6fe7a))
- 英文版本时提示中的单词没有分开 ([eb26650](https://github.com/vbenjs/vue-vben-admin/commit/eb2665059eb5fdcb8299032dc1a49c73f1675156))
- **ApiCascader:** apiParamKey not working ([c42ba1c](https://github.com/vbenjs/vue-vben-admin/commit/c42ba1cc1b2fba7179701cb1f918443523a9fc70))
- **ApiCascader:** wrong api reload ([#3536](https://github.com/vbenjs/vue-vben-admin/issues/3536)) resolve [#3534](https://github.com/vbenjs/vue-vben-admin/issues/3534) ([83f16da](https://github.com/vbenjs/vue-vben-admin/commit/83f16da2d35716f94f1837ab9bee41c5878ab3b0))
- **ApiSelect:** 移除watchEffect引发的重复请求 ([#3107](https://github.com/vbenjs/vue-vben-admin/issues/3107)) ([1519f47](https://github.com/vbenjs/vue-vben-admin/commit/1519f47f7d7785a93be51ce9da0f9ef2e78705c9))
- **ApiSelect:** 修复监听不到params的变动 ([ccf4027](https://github.com/vbenjs/vue-vben-admin/commit/ccf4027533d2adabd21bade025ca7bc7d34d75f6))
- **ApiSelect:** ApiSelect的isFirstLoaded赋值逻辑,只有当加载报错时才能恢复未初次加载状态 ([#3671](https://github.com/vbenjs/vue-vben-admin/issues/3671)) ([3d733de](https://github.com/vbenjs/vue-vben-admin/commit/3d733de3995a667782fa3219a0e0b171327c5b6f))
- **ApiSelect:** BasicForm emit ield-value-change twice ([0f2c2ea](https://github.com/vbenjs/vue-vben-admin/commit/0f2c2eabd671af457febbb16fa3996c845bae145))
- **ApiSelect:** Incorrect value type definition. close [#3168](https://github.com/vbenjs/vue-vben-admin/issues/3168) ([0cf79d4](https://github.com/vbenjs/vue-vben-admin/commit/0cf79d4ce2786e71444d4d9483ed77a99f57169c))
- **ApiSelect:** type warning ([8f6153f](https://github.com/vbenjs/vue-vben-admin/commit/8f6153fd2a73b9537e7f9ba0f2326388745bc232))
- ApiTransfer 不支持disabled ([#3149](https://github.com/vbenjs/vue-vben-admin/issues/3149)) ([95ca2c3](https://github.com/vbenjs/vue-vben-admin/commit/95ca2c3ae6085d97f24546e24117ee2518f33e2d))
- **ApiTree:** 多触发一次onchange ([882270d](https://github.com/vbenjs/vue-vben-admin/commit/882270d5baff92eb8f51ccb80758c68ef8babe51))
- **ApiTree:** Modify Trigger Selection Event Name ([094a33c](https://github.com/vbenjs/vue-vben-admin/commit/094a33c0c2511816079c935eb83e60ad93c9289c))
- async validator ([#3194](https://github.com/vbenjs/vue-vben-admin/issues/3194)) ([405ef9e](https://github.com/vbenjs/vue-vben-admin/commit/405ef9e2b3e61bd6195b58996504b9cb3939ef6f))
- **BackTop:** repair BackTup comp ([#3581](https://github.com/vbenjs/vue-vben-admin/issues/3581)) ([6f4bdae](https://github.com/vbenjs/vue-vben-admin/commit/6f4bdae5c2a5455cb924e1903612f9fe96cf4481))
- basemodal 无法透传 attributes 至 Modal.tsx ([#3637](https://github.com/vbenjs/vue-vben-admin/issues/3637)) ([89830ec](https://github.com/vbenjs/vue-vben-admin/commit/89830ec7e69a7cab55e6ccf90b74377bcbadf44c))
- **BasicDrawer:** remove toRaw props ([#3399](https://github.com/vbenjs/vue-vben-admin/issues/3399)) ([57e6e4f](https://github.com/vbenjs/vue-vben-admin/commit/57e6e4f00435637c545c58de3cd84c102003032a))
- **BasicForm->ApiRadioGroup:** when options click, duplicate requests. resolve [#3387](https://github.com/vbenjs/vue-vben-admin/issues/3387) ([fdde6f0](https://github.com/vbenjs/vue-vben-admin/commit/fdde6f06b2d388bbdcc7f0de2b5419593cd686c3))
- **BasicForm->FormItem:** model should update before event call ([#3573](https://github.com/vbenjs/vue-vben-admin/issues/3573)). resolve [#3570](https://github.com/vbenjs/vue-vben-admin/issues/3570) ([43aa743](https://github.com/vbenjs/vue-vben-admin/commit/43aa7430324a7f390c31ea9e8a2f1e00fad8a1d0))
- **BasicForm:** 修复 useComponentRegister 方法无法添加自定义的组件,添加时爆类型错误的问题 ([#3483](https://github.com/vbenjs/vue-vben-admin/issues/3483)) ([98e2e4c](https://github.com/vbenjs/vue-vben-admin/commit/98e2e4c89a859e67c911134652d4b005be51e2d1))
- **BasicForm:** script setup defineExpose ([#3316](https://github.com/vbenjs/vue-vben-admin/issues/3316)) ([f58ef67](https://github.com/vbenjs/vue-vben-admin/commit/f58ef6777c4dd8ac905919637410ea5373eb770b))
- **BasicForm:** type instantiation is excessively deep and possibly infinite. ([#3128](https://github.com/vbenjs/vue-vben-admin/issues/3128)) ([5a388be](https://github.com/vbenjs/vue-vben-admin/commit/5a388be15e44d86c87d76dc8829a5286ac1818e0))
- **BasicForm:** useForm 中 scheme 选项 slot 与 component冲突 ([#3133](https://github.com/vbenjs/vue-vben-admin/issues/3133)) ([0bb76a8](https://github.com/vbenjs/vue-vben-admin/commit/0bb76a86d25cbd1de1c672f5cc5e63d0ae478b68))
- **BasicForm:** validate Form tip height ([#3286](https://github.com/vbenjs/vue-vben-admin/issues/3286)). close [#3281](https://github.com/vbenjs/vue-vben-admin/issues/3281) ([100f3cf](https://github.com/vbenjs/vue-vben-admin/commit/100f3cf26c2b124bf94f3bb4913dd3d6d15aed3e))
- **BasicModal:** 修复BasicModal添加wrapClassName样式异常问题 ([#3726](https://github.com/vbenjs/vue-vben-admin/issues/3726)) ([13b031e](https://github.com/vbenjs/vue-vben-admin/commit/13b031eef9b8d4e8333c9397ff26e4875bf9816a))
- **BasicTable->rowKey&scroll:** declear and usage about rowKey and scroll ([#3541](https://github.com/vbenjs/vue-vben-admin/issues/3541)) ([e23e338](https://github.com/vbenjs/vue-vben-admin/commit/e23e3383dd73b20a479977d29bab999c51334a1a))
- **BasicTable->useColumns:** handle deep colunm hidden ([#3561](https://github.com/vbenjs/vue-vben-admin/issues/3561)) resolve [#3559](https://github.com/vbenjs/vue-vben-admin/issues/3559) ([54af5bb](https://github.com/vbenjs/vue-vben-admin/commit/54af5bb42ddd04a56a7da3becf325dd9cfbccc48))
- **BasicTable:** 滑动表格内容合计行不跟随滑动bug ([#3438](https://github.com/vbenjs/vue-vben-admin/issues/3438)) resolve [#2166](https://github.com/vbenjs/vue-vben-admin/issues/2166) ([7ba83e7](https://github.com/vbenjs/vue-vben-admin/commit/7ba83e71bf718b6c896eac892f3b66cd266747af))
- **BasicTable:** 修复BasicTable数据为空时,重置后高度不能自适应问题 ([#3724](https://github.com/vbenjs/vue-vben-admin/issues/3724)) ([6054fa2](https://github.com/vbenjs/vue-vben-admin/commit/6054fa2ffac7ff0206a4e0138da16a548d2d25a2))
- **BasicTable:** avoid select when edit cell ([#3484](https://github.com/vbenjs/vue-vben-admin/issues/3484)) ([2f921cf](https://github.com/vbenjs/vue-vben-admin/commit/2f921cfb88b969fb8bd361c46ddf2f41a9e363b0))
- **BasicTable:** BasicTable resize wrong in modal ([#3549](https://github.com/vbenjs/vue-vben-admin/issues/3549)) ([a121b32](https://github.com/vbenjs/vue-vben-admin/commit/a121b32252cf4b0570c937a1ab86d8b924b229ce))
- **BasicTable:** column setting about action fixed and default not cache ([#3441](https://github.com/vbenjs/vue-vben-admin/issues/3441)) ([86ecb27](https://github.com/vbenjs/vue-vben-admin/commit/86ecb2729ef15bb0bb3fc7347a84ffa83487eec8))
- **BasicTable:** ColumnSetting about selectedRowKeys override ([#3446](https://github.com/vbenjs/vue-vben-admin/issues/3446)) ([65122ea](https://github.com/vbenjs/vue-vben-admin/commit/65122ea1a52e2f06463dc15f7ee06aba4e29d104))
- **BasicTable:** ColumnSetting mistake when use setColumns ([#3408](https://github.com/vbenjs/vue-vben-admin/issues/3408)) ([fec67b4](https://github.com/vbenjs/vue-vben-admin/commit/fec67b4d53ce82d156f4683f2c436f31dd3b4f7a))
- **BasicTable:** getSelectRows return duplicate records ([#3545](https://github.com/vbenjs/vue-vben-admin/issues/3545)) ([974c1fa](https://github.com/vbenjs/vue-vben-admin/commit/974c1fad7fb2767429eeb50680cbae8e17b80f1f))
- **BasicTable:** headerCell slot title not exist ([8df2590](https://github.com/vbenjs/vue-vben-admin/commit/8df2590aae8d646880e8c064e6b4ba48cb54086d))
- **BasicTable:** index still show when set showIndexColumn false ([#3455](https://github.com/vbenjs/vue-vben-admin/issues/3455)) ([75f5b7a](https://github.com/vbenjs/vue-vben-admin/commit/75f5b7ac4dda840ce0098ed528e0b161d99d9b09))
- **BasicTable:** keep rowSelection onChange call outside ([#3461](https://github.com/vbenjs/vue-vben-admin/issues/3461)). resolve [#3453](https://github.com/vbenjs/vue-vben-admin/issues/3453) ([a7b2f14](https://github.com/vbenjs/vue-vben-admin/commit/a7b2f14b900771186ee126cf60e8841ecc0cb8c1))
- **BasicTable:** pagination exceeds page height. close [#3185](https://github.com/vbenjs/vue-vben-admin/issues/3185) ([41451f4](https://github.com/vbenjs/vue-vben-admin/commit/41451f4fa3495be1d1ea4088cad77322dcde57de))
- **BasicTable:** ref table ([#3327](https://github.com/vbenjs/vue-vben-admin/issues/3327)) ([c8744a0](https://github.com/vbenjs/vue-vben-admin/commit/c8744a057e0da407ab929c91b46e638d196d82cc))
- **BasicTable:** selection wrong by click input when cross pages ([#3540](https://github.com/vbenjs/vue-vben-admin/issues/3540)). resolve [#3539](https://github.com/vbenjs/vue-vben-admin/issues/3539) ([69c3602](https://github.com/vbenjs/vue-vben-admin/commit/69c36021fa5558097c4fc7b9f63e29816e478cb9))
- **BasicTable:** showIndexColumn/showRowSelection cache should by route name ([#3489](https://github.com/vbenjs/vue-vben-admin/issues/3489)) ([d88f455](https://github.com/vbenjs/vue-vben-admin/commit/d88f455cd3530cd7cc7450e8f0fe7744ca0cb313))
- **BasicTable:** table表格宽度自适应,隐藏的列导致宽度增加 ([#3388](https://github.com/vbenjs/vue-vben-admin/issues/3388)) ([bca5154](https://github.com/vbenjs/vue-vben-admin/commit/bca5154a9d3d020a70cd332ac19c853ea94405e2))
- **BasicTree:** not inherit slot and not show icon slot. close [#1902](https://github.com/vbenjs/vue-vben-admin/issues/1902) ([a0b2a9e](https://github.com/vbenjs/vue-vben-admin/commit/a0b2a9e949dbf1e149da8be757f78fa6b1cebec0))
- breadcrumb is displayed despite the menu being hidden ([#3733](https://github.com/vbenjs/vue-vben-admin/issues/3733)) ([e8a86ec](https://github.com/vbenjs/vue-vben-admin/commit/e8a86ec8b996387c9c2d167344eb1e7a010d94fb)), closes [#3690](https://github.com/vbenjs/vue-vben-admin/issues/3690)
- **breadcrumb:** 修复面包屑跳转外链时,导致当前页面404问题 ([#3337](https://github.com/vbenjs/vue-vben-admin/issues/3337)). close [#3336](https://github.com/vbenjs/vue-vben-admin/issues/3336) ([895352a](https://github.com/vbenjs/vue-vben-admin/commit/895352ad221f91bdb57fdfd0396925fb7901c2df))
- breakpoint ([#3242](https://github.com/vbenjs/vue-vben-admin/issues/3242)) ([b6f8379](https://github.com/vbenjs/vue-vben-admin/commit/b6f8379e936df3743c5b9514e88a02148b08a5d1))
- bug RangePicker with componentProps valueFormat ('YYYY-MM-DD') does not return the formatted value when using form validate() method [#3690](https://github.com/vbenjs/vue-vben-admin/issues/3690) ([#3691](https://github.com/vbenjs/vue-vben-admin/issues/3691)) ([09f795e](https://github.com/vbenjs/vue-vben-admin/commit/09f795e00ed8d56d6b1e028fc40974d3292eed5f))
- change salesProductPie.vue's data name to '成交占比'. ([#3524](https://github.com/vbenjs/vue-vben-admin/issues/3524)) ([0589458](https://github.com/vbenjs/vue-vben-admin/commit/0589458b2d120b5c6ee0ab10cd8b2d3f13318911))
- checkedKeys use unref bug ([#3198](https://github.com/vbenjs/vue-vben-admin/issues/3198)) ([ae61fa1](https://github.com/vbenjs/vue-vben-admin/commit/ae61fa11865b2d7b0337b1fd2edcb20bf559a71f))
- **ci:** update node version for linter ([a5565bf](https://github.com/vbenjs/vue-vben-admin/commit/a5565bf9cf361e38057d8ca34fe2542ea1c39873))
- **ci:** update use pnpm version for deploy ([83455a0](https://github.com/vbenjs/vue-vben-admin/commit/83455a07a0821142864b4668d89a51057d74330b))
- column setting index column sort ([#3463](https://github.com/vbenjs/vue-vben-admin/issues/3463)) ([fc002d3](https://github.com/vbenjs/vue-vben-admin/commit/fc002d3db327a432259eb02e2a72b9b81381eb6e))
- **component->markdown:** 浏览器媒体获取兼容 ([#3470](https://github.com/vbenjs/vue-vben-admin/issues/3470)) ([f0ca8d5](https://github.com/vbenjs/vue-vben-admin/commit/f0ca8d5a03e994c9948b055dc5f69dad40d96922))
- **component:** insertNextAt is not a function ([#3656](https://github.com/vbenjs/vue-vben-admin/issues/3656)) ([#3657](https://github.com/vbenjs/vue-vben-admin/issues/3657)) ([c827ffb](https://github.com/vbenjs/vue-vben-admin/commit/c827ffb8e680df13dae0c75b19634b6474aa5897))
- **component:** resolve the defaultValue error in setting the date type ([#3652](https://github.com/vbenjs/vue-vben-admin/issues/3652)) ([d42acb4](https://github.com/vbenjs/vue-vben-admin/commit/d42acb477c577c0f855403bff371e0780e630cdc)), closes [#3651](https://github.com/vbenjs/vue-vben-admin/issues/3651)
- **component:** resolve the error when clicking on a row when clickRowToExpand is true ([#3714](https://github.com/vbenjs/vue-vben-admin/issues/3714)) ([38d58ab](https://github.com/vbenjs/vue-vben-admin/commit/38d58ab47af3611cebade960dbcbd60f165f3a72))
- **component:** resolve the issue of "vxe-table" export function not being able to be used ([#3646](https://github.com/vbenjs/vue-vben-admin/issues/3646)) ([bc5e5fa](https://github.com/vbenjs/vue-vben-admin/commit/bc5e5fa015f8c5f1d69f3f8572a1957d83cfe44e)), closes [#3614](https://github.com/vbenjs/vue-vben-admin/issues/3614)
- **component:** resovle fullscreen content issues with "fixedHeight" and "contentFullHeight" combined ([#3721](https://github.com/vbenjs/vue-vben-admin/issues/3721)) ([212e78f](https://github.com/vbenjs/vue-vben-admin/commit/212e78fa76132b4239e81d3432f7f3c15d7e5254))
- **components->Upload:** 修复文件上传过程中删除文件终止上传时,上传状态未改变不能关闭Modal的bug ([#3761](https://github.com/vbenjs/vue-vben-admin/issues/3761)) ([04d4c5c](https://github.com/vbenjs/vue-vben-admin/commit/04d4c5cd665f52cb287b5059b301e71aed75b3df))
- **config:** vite:html warning ([#3518](https://github.com/vbenjs/vue-vben-admin/issues/3518)) ([6978517](https://github.com/vbenjs/vue-vben-admin/commit/6978517a3a0b522a466fc248d0ed4384cdcfecb7))
- content fixed mode with blank page ([#3523](https://github.com/vbenjs/vue-vben-admin/issues/3523)) ([49fdb6c](https://github.com/vbenjs/vue-vben-admin/commit/49fdb6c986f36e45fc9f9e206af371f8eb3581f6))
- contextmenu location not right when body with scroll ([#3516](https://github.com/vbenjs/vue-vben-admin/issues/3516)) ([c2c9f4f](https://github.com/vbenjs/vue-vben-admin/commit/c2c9f4f556d65eb768a5202a398dc9684c08d577))
- Correct spelling error in comments ([#3678](https://github.com/vbenjs/vue-vben-admin/issues/3678)) ([54f8584](https://github.com/vbenjs/vue-vben-admin/commit/54f85844436d95ce290a2f3b5db5b7c4fd14cc0d))
- **CropperAvatar:** wrong type about the prop size ([#3635](https://github.com/vbenjs/vue-vben-admin/issues/3635)) ([aef90aa](https://github.com/vbenjs/vue-vben-admin/commit/aef90aa2a0b43c3fc72596d9aecf408a594cb6fd))
- **CropperModal:** beforeUpload should return false ([#3601](https://github.com/vbenjs/vue-vben-admin/issues/3601)) ([b6bcf8d](https://github.com/vbenjs/vue-vben-admin/commit/b6bcf8d36dc348af7b51782e43c09c5e1cfeed68))
- **customExport:** Failure to export ([#3137](https://github.com/vbenjs/vue-vben-admin/issues/3137)) ([4d02205](https://github.com/vbenjs/vue-vben-admin/commit/4d02205839aad840bbb247b26b7e1dcdbc8b3a67))
- **dark:** fix --text-color light color not work ([#3228](https://github.com/vbenjs/vue-vben-admin/issues/3228)) ([2e632e4](https://github.com/vbenjs/vue-vben-admin/commit/2e632e4d4d8af4b8766396b340f9996832310853))
- **DatePicker:** date show is wrong and setup script defineExpose ([#3324](https://github.com/vbenjs/vue-vben-admin/issues/3324)) ([f62043b](https://github.com/vbenjs/vue-vben-admin/commit/f62043b1fca82234e04aa04629ba4bbcc624b0ee))
- **DatePicker:** zh-CN is not work in DatePicker ([#3273](https://github.com/vbenjs/vue-vben-admin/issues/3273)) ([6d047fb](https://github.com/vbenjs/vue-vben-admin/commit/6d047fb53fb113a4c6fc5c46c5b4195e50744eb0))
- defaultValue类型为number时的bug ([#3288](https://github.com/vbenjs/vue-vben-admin/issues/3288)) ([3b2760c](https://github.com/vbenjs/vue-vben-admin/commit/3b2760ca3ae5b51989ea7e97713f629a567fe53a))
- **demo->customerForm:** FormItem下有多个受控组件控制台显示错误提示的bug ([#3238](https://github.com/vbenjs/vue-vben-admin/issues/3238)) ([ec646c5](https://github.com/vbenjs/vue-vben-admin/commit/ec646c57b8c2d365f5ce298c496e1efaad8456b7))
- **demo:** 修复引导页文件名问题 ([#3352](https://github.com/vbenjs/vue-vben-admin/issues/3352)) ([be935eb](https://github.com/vbenjs/vue-vben-admin/commit/be935eb44e363665b99288f78f03cb3053274200))
- **demo:** 修复form demo的远程搜索不会触发的bug ([#3770](https://github.com/vbenjs/vue-vben-admin/issues/3770)) ([44b1877](https://github.com/vbenjs/vue-vben-admin/commit/44b1877eaedca1716aa40b8d819d5fe7cbd26ba0))
- **demo:** account page table without dept ([#3164](https://github.com/vbenjs/vue-vben-admin/issues/3164)) ([40aac65](https://github.com/vbenjs/vue-vben-admin/commit/40aac6544cb9b22e2362f2a2d99c0a9cc2f7fb57))
- **demo:** useForm中DatePicker,RangePicker 日期控件位置不对 ([ae58ada](https://github.com/vbenjs/vue-vben-admin/commit/ae58ada82e2f62cea8e89a18c9f2ab18d6dba52a))
- **dept:** no parentDept can edit parentDept ([#3255](https://github.com/vbenjs/vue-vben-admin/issues/3255)) ([2142506](https://github.com/vbenjs/vue-vben-admin/commit/2142506ce5225dbe19118fcedb2cb48612c58fa7))
- Docker 打包逻辑改进,彻底解决缓存问题 ([#3473](https://github.com/vbenjs/vue-vben-admin/issues/3473)) ([dcbe551](https://github.com/vbenjs/vue-vben-admin/commit/dcbe5510d42c3dc5e93b68704a5fa24c88d4de69))
- EditableCell about checked/unChecked Value, getDisable, rowKey missing for updating ([#3418](https://github.com/vbenjs/vue-vben-admin/issues/3418)). resolve [#3419](https://github.com/vbenjs/vue-vben-admin/issues/3419) ([404a472](https://github.com/vbenjs/vue-vben-admin/commit/404a4720b016abb6da93cb0b03271ebea6cca976))
- **EditCellTable:** 表格编辑行在使用Switch,checkedValue为数字时无法切换开关.close [#2560](https://github.com/vbenjs/vue-vben-admin/issues/2560) ([71c4394](https://github.com/vbenjs/vue-vben-admin/commit/71c43945a5e95fda6daddbb90af51f6d149547f5))
- **Editor:** ts类型错误 ([8b13f62](https://github.com/vbenjs/vue-vben-admin/commit/8b13f62995cb7f080eabf2e22d530959d4b79e0b))
- Failed to resolve component EllipsisText ([#3330](https://github.com/vbenjs/vue-vben-admin/issues/3330)) ([42e9de5](https://github.com/vbenjs/vue-vben-admin/commit/42e9de50a2bb150556a0eb8098acb2d2d3662c3c))
- FormItem won't render when a component is not provided ([9e055ad](https://github.com/vbenjs/vue-vben-admin/commit/9e055ad2734819c2778c0db1990e69b67c95022f))
- **FormItem:** use getPopupContainer default value ([#3215](https://github.com/vbenjs/vue-vben-admin/issues/3215)) ([ed267d9](https://github.com/vbenjs/vue-vben-admin/commit/ed267d9c016e50b4d9a7886209bad2432a88ad9b))
- **FormTable:** Invert select bug ([#3412](https://github.com/vbenjs/vue-vben-admin/issues/3412)) ([595b1ce](https://github.com/vbenjs/vue-vben-admin/commit/595b1ce680d8b315589d98036a70333055123b18))
- **full-screen:** dom fullscreen status text ([#3130](https://github.com/vbenjs/vue-vben-admin/issues/3130)) ([e161c14](https://github.com/vbenjs/vue-vben-admin/commit/e161c1449ac3d097cd6eab9441b25de25d3aa27e))
- fullscreen-modal width wrong ([#3321](https://github.com/vbenjs/vue-vben-admin/issues/3321)) ([617b013](https://github.com/vbenjs/vue-vben-admin/commit/617b01338cf4a8d88da529dae7da878b52b30c3b))
- handleFormValues 不再将所有空字符串转换为undefined ([#3496](https://github.com/vbenjs/vue-vben-admin/issues/3496)) ([6fbb576](https://github.com/vbenjs/vue-vben-admin/commit/6fbb57621e6ff79f93830969ab388549cbec5d32))
- **koa->upload:** fix the error that occurs when uploading files in the `test server` of Koa. ([#3698](https://github.com/vbenjs/vue-vben-admin/issues/3698)) ([954f04f](https://github.com/vbenjs/vue-vben-admin/commit/954f04f1c8e941e45c2bd4ab55df331ba13cb89c))
- **layout->menu:** can`t hover when menu is colappsed ([#3499](https://github.com/vbenjs/vue-vben-admin/issues/3499)) resolve [#3492](https://github.com/vbenjs/vue-vben-admin/issues/3492) ([7ffe172](https://github.com/vbenjs/vue-vben-admin/commit/7ffe1726b9ac0ac1f90c20b53996636f31af5c31))
- **layout->user-dropdown:** resolve warning "Invalid prop name: key is a reserved property" ([#3640](https://github.com/vbenjs/vue-vben-admin/issues/3640)) ([eae68bb](https://github.com/vbenjs/vue-vben-admin/commit/eae68bb029864d5f1af4e0c6b57038d0c96e4faf)), closes [#3639](https://github.com/vbenjs/vue-vben-admin/issues/3639)
- **layout:** 修复切换导航栏模式,分割菜单的状态不同步,导致页面内容区域存在被遮挡的问题 ([#3519](https://github.com/vbenjs/vue-vben-admin/issues/3519)) ([50276cb](https://github.com/vbenjs/vue-vben-admin/commit/50276cb60275d15c2d370c5a1be2705067c7b275))
- **LayoutSidre:** resolve the breakpoint conflict. resolve [#3605](https://github.com/vbenjs/vue-vben-admin/issues/3605) ([1a7ae0e](https://github.com/vbenjs/vue-vben-admin/commit/1a7ae0e81071876fe6a5cf2ef00bb61cbca70736))
- **LockModal:** Cannot unlock ([#3143](https://github.com/vbenjs/vue-vben-admin/issues/3143)) ([cdac147](https://github.com/vbenjs/vue-vben-admin/commit/cdac147bc8d09fba6ac14ff1ed31ab4d5b5cb28b))
- **Login:** avoid infinite loop when query redirect to next route redirect ([#3630](https://github.com/vbenjs/vue-vben-admin/issues/3630)). resolve [#3620](https://github.com/vbenjs/vue-vben-admin/issues/3620) [#3627](https://github.com/vbenjs/vue-vben-admin/issues/3627) ([ab55cbf](https://github.com/vbenjs/vue-vben-admin/commit/ab55cbf99bd9891f10546176e203eb4ea8cafaa4))
- **Menu:** tab标签切换选中状态焦点重复. fix [#1681](https://github.com/vbenjs/vue-vben-admin/issues/1681) ([2ec5f63](https://github.com/vbenjs/vue-vben-admin/commit/2ec5f6322d036ea5d6968c16961d2c253e1cef06))
- **menu:** top menu and breadcrumb show wrong ([#3703](https://github.com/vbenjs/vue-vben-admin/issues/3703)) ([573fd53](https://github.com/vbenjs/vue-vben-admin/commit/573fd53b4e287524ffa6ec205b68812b657dde71))
- modal open logic missing ([#3462](https://github.com/vbenjs/vue-vben-admin/issues/3462)) ([cc97f06](https://github.com/vbenjs/vue-vben-admin/commit/cc97f0635438c102b97102a1e0a9d5550961d6fa))
- **Modal:** 修复BasicModal跟原生Modal样式冲突问题 ([#3720](https://github.com/vbenjs/vue-vben-admin/issues/3720)) ([ade6d4c](https://github.com/vbenjs/vue-vben-admin/commit/ade6d4c22dd62aa666fe934a747e2a3764feb7cd))
- modalElIterator可能为空,导致报错 ([#3738](https://github.com/vbenjs/vue-vben-admin/issues/3738)) ([162a0d0](https://github.com/vbenjs/vue-vben-admin/commit/162a0d025252ff954f081d126c381e5fefd06e83))
- navigator.clipboard 兼容问题 [#3372](https://github.com/vbenjs/vue-vben-admin/issues/3372) ([#3403](https://github.com/vbenjs/vue-vben-admin/issues/3403)) ([d3600da](https://github.com/vbenjs/vue-vben-admin/commit/d3600daf5c55cc884f4a0311ee7335bdad529a1a))
- **PageWrapper:** 修复headerSticky样式 ([#3569](https://github.com/vbenjs/vue-vben-admin/issues/3569)) ([778ebe1](https://github.com/vbenjs/vue-vben-admin/commit/778ebe1f44bc4929f34fad41b5fec13e9270b517))
- **PopConfirmButton:** avoid type lint error ([#3600](https://github.com/vbenjs/vue-vben-admin/issues/3600)) ([5ec4446](https://github.com/vbenjs/vue-vben-admin/commit/5ec444644384c6a1b8d559e0e21dfa814e5af635))
- remove duplicate code ([#3674](https://github.com/vbenjs/vue-vben-admin/issues/3674)) ([c33ee66](https://github.com/vbenjs/vue-vben-admin/commit/c33ee66473159a0322b7c4489538dd5309587e45))
- repair login about redirect query ([#3592](https://github.com/vbenjs/vue-vben-admin/issues/3592)) ([236ddf3](https://github.com/vbenjs/vue-vben-admin/commit/236ddf3471a7851ff6541f5709e9cbb6105b58f7))
- resolve conflicts between eslint and prettier and bump prettier-plugin-packagejson version to 2.4.6([#3328](https://github.com/vbenjs/vue-vben-admin/issues/3328)) ([8a00070](https://github.com/vbenjs/vue-vben-admin/commit/8a000705d1c89194647a11d01a620c1a893d2643))
- **router:** resolve menu loading failure when permission is in "role mode" ([#3660](https://github.com/vbenjs/vue-vben-admin/issues/3660)) ([c7631fe](https://github.com/vbenjs/vue-vben-admin/commit/c7631fed681da0dd51583cf3ecba60ebfd76ec4d)), closes [#3655](https://github.com/vbenjs/vue-vben-admin/issues/3655)
- **router:** resolve the next function being called twice ([#3643](https://github.com/vbenjs/vue-vben-admin/issues/3643)) ([7ec9344](https://github.com/vbenjs/vue-vben-admin/commit/7ec9344be8e80899749f41d173c1a11db267354e)), closes [#3642](https://github.com/vbenjs/vue-vben-admin/issues/3642)
- **router:** the issue of blank page navigation during repair of non-LAYOUT first-level route component ([#3764](https://github.com/vbenjs/vue-vben-admin/issues/3764)) ([c58c192](https://github.com/vbenjs/vue-vben-admin/commit/c58c1929c1e8a41c15ff2f4f4398eba0fd375b69))
- scroll back to top when tab switch ([#3498](https://github.com/vbenjs/vue-vben-admin/issues/3498)). resolve [#3490](https://github.com/vbenjs/vue-vben-admin/issues/3490) ([d709dd6](https://github.com/vbenjs/vue-vben-admin/commit/d709dd67b50a2e2b88cbcce48f19085ce528f971))
- scrollbar is obscured ([#3331](https://github.com/vbenjs/vue-vben-admin/issues/3331)) ([3f65baf](https://github.com/vbenjs/vue-vben-admin/commit/3f65baf503bee677bde70535525ae514d0585d69))
- ScrollContainer的一个问题 [#3046](https://github.com/vbenjs/vue-vben-admin/issues/3046) ([#3119](https://github.com/vbenjs/vue-vben-admin/issues/3119)) ([aa03c87](https://github.com/vbenjs/vue-vben-admin/commit/aa03c87383c703ddce7759bd7ba114709f2f5241))
- **ScrollContainer:** enable x scroll ([#3564](https://github.com/vbenjs/vue-vben-admin/issues/3564)) ([a1e862b](https://github.com/vbenjs/vue-vben-admin/commit/a1e862bde7a29420fd1de6083c5bde02bef8e9fd))
- **SimpleMenuTag:** SimpleMenuTag的引用都改为动态组件引用,以消除打包警告.close [#3121](https://github.com/vbenjs/vue-vben-admin/issues/3121) ([6e33c26](https://github.com/vbenjs/vue-vben-admin/commit/6e33c268930ad2a99311f0f2b6eb4b90f3cf61ce))
- **StrengthMeter:** change事件应随handleChange一起抛出。close [#3118](https://github.com/vbenjs/vue-vben-admin/issues/3118) ([f5ce480](https://github.com/vbenjs/vue-vben-admin/commit/f5ce480f0fb2f97de57e26a01945b715938f6e18))
- **style:** 修复黑暗模式下弹框、demo目录下、按钮样式问题 ([#3208](https://github.com/vbenjs/vue-vben-admin/issues/3208)) ([06a6c94](https://github.com/vbenjs/vue-vben-admin/commit/06a6c947a980530be6654f05357bc3c721c1140b))
- tabel取消编辑单元格后会回到初始值. close [#2739](https://github.com/vbenjs/vue-vben-admin/issues/2739) ([#3108](https://github.com/vbenjs/vue-vben-admin/issues/3108)) ([9864305](https://github.com/vbenjs/vue-vben-admin/commit/986430513bc2da9a2ad88d40c026b0373bf22d07))
- table height calc when fullcontent and footer visible change ([#3392](https://github.com/vbenjs/vue-vben-admin/issues/3392)) ([20698c0](https://github.com/vbenjs/vue-vben-admin/commit/20698c052c2b696587ac77ba7c85d74abc974ed5))
- table index column width is not enough in english ([#3342](https://github.com/vbenjs/vue-vben-admin/issues/3342)) ([0f13758](https://github.com/vbenjs/vue-vben-admin/commit/0f137585542ee2cf3b542a4ca4d94e76aadfb3d0))
- TableAction设置icon显示iconify关键字 ([#3608](https://github.com/vbenjs/vue-vben-admin/issues/3608)) ([b233973](https://github.com/vbenjs/vue-vben-admin/commit/b2339739746740eaaf4adee3ef16757f3b05ec86))
- **test-server:** test-server can not lanuch ([#3554](https://github.com/vbenjs/vue-vben-admin/issues/3554)) ([e679704](https://github.com/vbenjs/vue-vben-admin/commit/e6797043c53abb8280ff9c86e32663450a650076))
- **tree:** remove expandedKeys prop default value ([#3184](https://github.com/vbenjs/vue-vben-admin/issues/3184)) ([92875cb](https://github.com/vbenjs/vue-vben-admin/commit/92875cbeccf6213bcad9acd4e322cdee59e35266))
- turbo run lint ([#3332](https://github.com/vbenjs/vue-vben-admin/issues/3332)) ([064922d](https://github.com/vbenjs/vue-vben-admin/commit/064922dd4c3ae674a463e4b9453a4ca8bf2a52a0)), closes [#3277](https://github.com/vbenjs/vue-vben-admin/issues/3277)
- **type:** type:check error ([#3309](https://github.com/vbenjs/vue-vben-admin/issues/3309)) ([2cd5a40](https://github.com/vbenjs/vue-vben-admin/commit/2cd5a40322e9b7946e789d7c5023fda0e712af4d))
- typo in locale ([#3659](https://github.com/vbenjs/vue-vben-admin/issues/3659)) ([a4cc1d5](https://github.com/vbenjs/vue-vben-admin/commit/a4cc1d53169bc26e01862ca4ff88e28d5329ab8f))
- typo substract -> subtract ([#3551](https://github.com/vbenjs/vue-vben-admin/issues/3551)) ([f3fbb57](https://github.com/vbenjs/vue-vben-admin/commit/f3fbb57dc944a11a06be2eff376d77f9cef29813))
- **typo:** fileservice class name ([#3625](https://github.com/vbenjs/vue-vben-admin/issues/3625)) ([b794469](https://github.com/vbenjs/vue-vben-admin/commit/b7944690d118377a32e694fa30081b1e43c71719))
- Update TableAction.vue ([#3619](https://github.com/vbenjs/vue-vben-admin/issues/3619)) ([76ffd8f](https://github.com/vbenjs/vue-vben-admin/commit/76ffd8fdf1ecc37a30f33c901ff199ba21f88ad4))
- **Upload:** The file name is too long bug ([#3182](https://github.com/vbenjs/vue-vben-admin/issues/3182)) ([e7fbd74](https://github.com/vbenjs/vue-vben-admin/commit/e7fbd742287928112b318bf966e57c74f6a8ee72))
- **useFormEvent:** 修复表单项存在defaultValue时,updateSchema方法会将setFieldsValue设置的值覆盖问题 ([#3287](https://github.com/vbenjs/vue-vben-admin/issues/3287)) ([72ef3df](https://github.com/vbenjs/vue-vben-admin/commit/72ef3df57fe978c0b8e185f0d632a59e128a390f))
- **useFormEvents:** 修复setFieldsValue 方法设置完值后,函数 componentProps丢失formActionType 的bug ([#3301](https://github.com/vbenjs/vue-vben-admin/issues/3301)) ([82671d0](https://github.com/vbenjs/vue-vben-admin/commit/82671d07502adbaa06decbe0caa51ca2ba2e5149))
- **util:** resolve executing retry even when HTTP status code is 401 ([#3756](https://github.com/vbenjs/vue-vben-admin/issues/3756)) ([3627402](https://github.com/vbenjs/vue-vben-admin/commit/36274025d6a19de978bcaaae3f0ddb42f31ecd2f))
- validateFields await missing ([#3254](https://github.com/vbenjs/vue-vben-admin/issues/3254)) ([71c3fea](https://github.com/vbenjs/vue-vben-admin/commit/71c3fea88afa9209f080458bbd7429b1d37baa2c))
- **VFormDesign:** findIndex === -1 ([#3305](https://github.com/vbenjs/vue-vben-admin/issues/3305)) ([d7472b8](https://github.com/vbenjs/vue-vben-admin/commit/d7472b8a2e480299888ffeac6ac95466b27afa0f))
- **vxe-table:** theme dark is not work ([#3239](https://github.com/vbenjs/vue-vben-admin/issues/3239)) ([031d613](https://github.com/vbenjs/vue-vben-admin/commit/031d613b18125c877ebaa4a3241c3b4bf9c7624a))
- watch open logic lost after build ([#3421](https://github.com/vbenjs/vue-vben-admin/issues/3421)) ([089a989](https://github.com/vbenjs/vue-vben-admin/commit/089a98953e01d6b7cb0003f33d321035e19311c5))
### Features
- 解决Form updateSchema后执行setProps导致schemaRef被重置的问题 ([#3354](https://github.com/vbenjs/vue-vben-admin/issues/3354)) ([b0e8154](https://github.com/vbenjs/vue-vben-admin/commit/b0e8154f9f23db71dba7302395cc7d3db4b4a339))
- 新增表单只读功能 ([#3335](https://github.com/vbenjs/vue-vben-admin/issues/3335)) ([342328c](https://github.com/vbenjs/vue-vben-admin/commit/342328ce5f06b33dabdbd4a3bdd2c846f011eb03))
- 修复 vxetable 实例中缺少的 getRefMaps 和 getComputeMaps 方法 ([#3361](https://github.com/vbenjs/vue-vben-admin/issues/3361)) ([2376e8f](https://github.com/vbenjs/vue-vben-admin/commit/2376e8f67d154fe902452c6c1af19248402602b7))
- 增加文本省略组件 ([#3180](https://github.com/vbenjs/vue-vben-admin/issues/3180)) ([8722471](https://github.com/vbenjs/vue-vben-admin/commit/87224715c3983227866f148d858276c1234f77e0))
- 支持设置多重水印,增加清除所有水印方法. close [#2610](https://github.com/vbenjs/vue-vben-admin/issues/2610) ([#3084](https://github.com/vbenjs/vue-vben-admin/issues/3084)) ([64b8128](https://github.com/vbenjs/vue-vben-admin/commit/64b812802f5ca053c8f0ae9c9f159cbfedb32d5d))
- add pinia persist plugin ([#3173](https://github.com/vbenjs/vue-vben-admin/issues/3173)) ([2152b3f](https://github.com/vbenjs/vue-vben-admin/commit/2152b3f779b47f70e4442ff4c850db10048733d3))
- **ApiTree:** 完善ApiTree组件的重置回显功能. close [#2307](https://github.com/vbenjs/vue-vben-admin/issues/2307) ([a0d4b10](https://github.com/vbenjs/vue-vben-admin/commit/a0d4b10a1f0f858925ce7fff3f9b686308fd3ada))
- **BasicButton:** BasicButton组件支持icon插槽. close [#1377](https://github.com/vbenjs/vue-vben-admin/issues/1377) ([5aac032](https://github.com/vbenjs/vue-vben-admin/commit/5aac032acc294e087e45d5787cbae843d5a86f28))
- **BasicForm:** 新增监听表单收缩方法传值进行判断 ([#3745](https://github.com/vbenjs/vue-vben-admin/issues/3745)) ([e9c6dd8](https://github.com/vbenjs/vue-vben-admin/commit/e9c6dd83b1b21bd46fbb7b16f159733761b49fd2))
- **BasicForm:** Improve ts types for BasicForm ([#3426](https://github.com/vbenjs/vue-vben-admin/issues/3426)) ([6bb7918](https://github.com/vbenjs/vue-vben-admin/commit/6bb79180fc798b1a0b1a6c22f7c13ddb3a45a3b5))
- **BasicTable:** 新增表格搜索获取参数的方法 ([#3715](https://github.com/vbenjs/vue-vben-admin/issues/3715)) ([de5f9e3](https://github.com/vbenjs/vue-vben-admin/commit/de5f9e304791ce131a589683282b42f77d10238c))
- **BasicTable:** table enable accordion expand ([#3533](https://github.com/vbenjs/vue-vben-admin/issues/3533)). resolve [#3525](https://github.com/vbenjs/vue-vben-admin/issues/3525) ([abae7f3](https://github.com/vbenjs/vue-vben-admin/commit/abae7f3295846f10b69c591739bbec22d176b6fe))
- **BasicTree:** BasicTree组件暴露treeData数据 ([caf1783](https://github.com/vbenjs/vue-vben-admin/commit/caf178352537650f603aca441386b377f7cf8821))
- ColumnSetting and SizeSetting persist ([#3398](https://github.com/vbenjs/vue-vben-admin/issues/3398)) ([f4df2d5](https://github.com/vbenjs/vue-vben-admin/commit/f4df2d5a4bd23f346af10580e5ab7de64933bb4c))
- **components->Upload:** 修正图片上传组件允许自定义上传格式限制 ([#3755](https://github.com/vbenjs/vue-vben-admin/issues/3755)) ([302e212](https://github.com/vbenjs/vue-vben-admin/commit/302e2125ba1c7e63e7db47ef6e1ee256da9f81d4))
- **demo->BasicTable:** add TableSelectionBar and enable checkbox rowSelection demo ([#3477](https://github.com/vbenjs/vue-vben-admin/issues/3477)) ([816553b](https://github.com/vbenjs/vue-vben-admin/commit/816553bfcd5a88988c6e7b93cc3378f4a5b17fee))
- **demo->useRequest:** 更新错误重试示例 ([#3456](https://github.com/vbenjs/vue-vben-admin/issues/3456)) ([7fa2578](https://github.com/vbenjs/vue-vben-admin/commit/7fa2578e6d578e7ab44793fcb2b41189a7ba9af3))
- **demo->useRequest:** 更新useRequest 依赖 Effect 函数案例 ([#3460](https://github.com/vbenjs/vue-vben-admin/issues/3460)) ([b57d9fc](https://github.com/vbenjs/vue-vben-admin/commit/b57d9fc60dd113607cd381dff1f88c47671fc434))
- **demo:** hooks useRequest 异步数据管理 ([#3447](https://github.com/vbenjs/vue-vben-admin/issues/3447)) ([d6d1120](https://github.com/vbenjs/vue-vben-admin/commit/d6d1120d00a24b7a97bd37f6a0786c1265fa870d))
- **deps:** update vite version to 5.x ([#3508](https://github.com/vbenjs/vue-vben-admin/issues/3508)) ([e6c7b5f](https://github.com/vbenjs/vue-vben-admin/commit/e6c7b5f9282adbdd9429495d5918c1eafbffde7d))
- fix ellipsis bug ([#3644](https://github.com/vbenjs/vue-vben-admin/issues/3644)) ([9372f1d](https://github.com/vbenjs/vue-vben-admin/commit/9372f1d159bb3236810e469defe6986b924d2264))
- **Form:** 新增Transfer、CropperAvatar、BasicTitle 组件至Form中,并添加至演示页面 ([#3362](https://github.com/vbenjs/vue-vben-admin/issues/3362)) ([f6147fa](https://github.com/vbenjs/vue-vben-admin/commit/f6147fa44985d149692b5c6053a49b76d24767cc))
- **Form:** 在Form将BasicTitle识做为Divider一样的处理 ([#3371](https://github.com/vbenjs/vue-vben-admin/issues/3371)) ([cd71e60](https://github.com/vbenjs/vue-vben-admin/commit/cd71e60dd16e87706deb2d06310bc507c55d6a99))
- Form增加ImageUpload组件 ([#3172](https://github.com/vbenjs/vue-vben-admin/issues/3172)) ([b776ac4](https://github.com/vbenjs/vue-vben-admin/commit/b776ac4cd8a4895804b554949f39c82c03382006))
- **hooks:** useWatermark添加水印防篡改功能([#3395](https://github.com/vbenjs/vue-vben-admin/issues/3395)) ([#3397](https://github.com/vbenjs/vue-vben-admin/issues/3397)) ([0a1a5ff](https://github.com/vbenjs/vue-vben-admin/commit/0a1a5ffedc58190529617c9267c6510dc7e17ca9))
- **IconPicker:** IconPicker could allowClear and readonly for form ([#3414](https://github.com/vbenjs/vue-vben-admin/issues/3414)) ([e23f294](https://github.com/vbenjs/vue-vben-admin/commit/e23f29464bd609d6bc7228a5940032d693b006aa))
- iframe expose postmessage function ([#3368](https://github.com/vbenjs/vue-vben-admin/issues/3368)) ([05bc4ac](https://github.com/vbenjs/vue-vben-admin/commit/05bc4acb9b2107bfad8200c0f1942a76367d7a00))
- **input:** add auto-trimming for vxe-table input components ([#3684](https://github.com/vbenjs/vue-vben-admin/issues/3684)) ([9882e8d](https://github.com/vbenjs/vue-vben-admin/commit/9882e8df86cc68373cf0f1fa4f4aa04a9773825e))
- **layout->tabs:** support insert new tab after current tab ([#3471](https://github.com/vbenjs/vue-vben-admin/issues/3471)) ([1e34d3e](https://github.com/vbenjs/vue-vben-admin/commit/1e34d3e9e4c79a62a16c6209639f5394dea61148))
- **layout:** move setting button to tabs when fold ([#3264](https://github.com/vbenjs/vue-vben-admin/issues/3264)) ([83426b5](https://github.com/vbenjs/vue-vben-admin/commit/83426b5c96a88c3a6aa399eb6100ea5fb494fd0e))
- **Menu:** Add custom images to menu ([#3158](https://github.com/vbenjs/vue-vben-admin/issues/3158)) ([b3a6ef6](https://github.com/vbenjs/vue-vben-admin/commit/b3a6ef63bb500d8103bde17d588b3c0c4c77efd6))
- **menu:** Restore side bar settings and added menu mouse move in mode light style ([#3295](https://github.com/vbenjs/vue-vben-admin/issues/3295)) ([003a951](https://github.com/vbenjs/vue-vben-admin/commit/003a951befb9ef2878a35fbe3054252d0bc8e77e))
- **MultipleTab:** add tabs auto collapse interaction in fold mode and setting ([#3256](https://github.com/vbenjs/vue-vben-admin/issues/3256)) ([191e809](https://github.com/vbenjs/vue-vben-admin/commit/191e809b6d696d6e0b72c67ba1c7e89c721f2642))
- pinia persist plugin custom serializer ([#3244](https://github.com/vbenjs/vue-vben-admin/issues/3244)) ([ea51c49](https://github.com/vbenjs/vue-vben-admin/commit/ea51c492c2ba56aa6693217e24f60dc143f124f1))
- RefForm页面新增只读功能按钮 ([#3346](https://github.com/vbenjs/vue-vben-admin/issues/3346)) ([97b76ea](https://github.com/vbenjs/vue-vben-admin/commit/97b76ea6bc902d00c87c5cbd1cb2d67aa9a88347))
- **search:** adjust the menu search function to recognize lowercase input ([#3736](https://github.com/vbenjs/vue-vben-admin/issues/3736)) ([96ac362](https://github.com/vbenjs/vue-vben-admin/commit/96ac362fa6a89af256cf8a84e4b667c195c6ea2e))
- **Table-> CustomerCell:** helpMessage支持传递 tsx 和 h函数的数据 ([c373ffd](https://github.com/vbenjs/vue-vben-admin/commit/c373ffd3bfb7db454e0501b2f7b138ed1a9ec657))
- table搜索表单值发生改变可以触发reload ([#3378](https://github.com/vbenjs/vue-vben-admin/issues/3378)) ([1ca3f7c](https://github.com/vbenjs/vue-vben-admin/commit/1ca3f7c2c0c0c00e8395e26c59796c875d34e12c))
- **treeTable:** add function collapseRows and demo ([#3375](https://github.com/vbenjs/vue-vben-admin/issues/3375)) ([e656b5d](https://github.com/vbenjs/vue-vben-admin/commit/e656b5d8dcde38deeedc73d713d2367e54d2893b))
- **type->api:** resultField推断api的返回值应该包含recordbale类型 ([#3699](https://github.com/vbenjs/vue-vben-admin/issues/3699)) ([c7ab4a5](https://github.com/vbenjs/vue-vben-admin/commit/c7ab4a52989256ccae996191cc249d9cbb36e6d6))
- **Upload:** file list add drag func ([#3227](https://github.com/vbenjs/vue-vben-admin/issues/3227)). resolve [#3179](https://github.com/vbenjs/vue-vben-admin/issues/3179) ([beed7f2](https://github.com/vbenjs/vue-vben-admin/commit/beed7f2e1172531fe691384a50c8b0457f3a80d8))
- **VirtualScroll:** 虚拟滚动增加滚动到顶部, 底部, 指定项方法 ([#3687](https://github.com/vbenjs/vue-vben-admin/issues/3687)) ([7c52f08](https://github.com/vbenjs/vue-vben-admin/commit/7c52f083db30f7e68c3e10a88cbc47d41cf9de20))
- vxeTable searchInfo demo ([#3223](https://github.com/vbenjs/vue-vben-admin/issues/3223)) close [#3011](https://github.com/vbenjs/vue-vben-admin/issues/3011) ([59145ad](https://github.com/vbenjs/vue-vben-admin/commit/59145ade255ee752a7c8d8995634ec172a7f60c8))
- **vxetable:** 新增 clearEdit 方法 ([#3369](https://github.com/vbenjs/vue-vben-admin/issues/3369)) ([522e892](https://github.com/vbenjs/vue-vben-admin/commit/522e892d7947807f7d500a2bace23880729df204))
- **watermark:** support custom style ([#3634](https://github.com/vbenjs/vue-vben-admin/issues/3634)) ([ca3ddd1](https://github.com/vbenjs/vue-vben-admin/commit/ca3ddd19f7811cbf32fd87b6c1cfd6681c08fc69))
### Performance Improvements
- 解决ts文件通过alias引入vue文件后, vscode调转不到正确vue文件路径 ([#3099](https://github.com/vbenjs/vue-vben-admin/issues/3099)) ([033d882](https://github.com/vbenjs/vue-vben-admin/commit/033d8828a9545770e98909291dcb6fd8db90ee41))
- 优化水印在控制台可以hide的问题 ([#3732](https://github.com/vbenjs/vue-vben-admin/issues/3732)) ([9784cdc](https://github.com/vbenjs/vue-vben-admin/commit/9784cdc840336d5c2bb006fa3ababfa7fa4056af))
- **BasicTree:** 获取treeData改写成函数 ([748b99b](https://github.com/vbenjs/vue-vben-admin/commit/748b99b18f5fc4e313add38ad457f0a5f064db70))
- **BasicTree:** 外部获取treeData不必通过treeDataRef.value ([#3353](https://github.com/vbenjs/vue-vben-admin/issues/3353)) ([943f500](https://github.com/vbenjs/vue-vben-admin/commit/943f50051ca80b6646ed44a2117b7c9ef632ed6d))
- **breakpointEnum:** 修改enum与breakpoint.less内一致 ([#3276](https://github.com/vbenjs/vue-vben-admin/issues/3276)) ([8932318](https://github.com/vbenjs/vue-vben-admin/commit/89323186b56b06b148664ae7483c490cf7eadefa))
- **component:** formItem: label支持函数渲染 ([#3504](https://github.com/vbenjs/vue-vben-admin/issues/3504)) ([e6a7e4c](https://github.com/vbenjs/vue-vben-admin/commit/e6a7e4c4fcdc5ad94f55c4f19000d6767773691e))
- **ConfigProvider:** 配置antdv主题色, 使其与modifyVars配置一致 ([#3219](https://github.com/vbenjs/vue-vben-admin/issues/3219)) ([bb3d5b8](https://github.com/vbenjs/vue-vben-admin/commit/bb3d5b8ae8e8ae0e91acb3022f51572daf3210c6))
- **darkMode:** 深色模式颜色定义以及切换方式优化 ([#3436](https://github.com/vbenjs/vue-vben-admin/issues/3436)) ([b008c44](https://github.com/vbenjs/vue-vben-admin/commit/b008c44246bec32def74c6ae1dd3522bf8c1ca2e))
- **darkMode:** 优化深色模式颜色切换相关方法; 增加根据主题更新自定义颜色方法和示例 ([#3216](https://github.com/vbenjs/vue-vben-admin/issues/3216)) ([e497721](https://github.com/vbenjs/vue-vben-admin/commit/e497721e9b3d03de07a61808012d0d6e04fd9663))
- **IconPicker:** input trigger popover by click ([#3278](https://github.com/vbenjs/vue-vben-admin/issues/3278)) ([2bbc2d2](https://github.com/vbenjs/vue-vben-admin/commit/2bbc2d28119c7f7cadbf5411b9ea886fb8965de0))
- **ImageUpload:** 根据官方示例设置图片回显格式 ([#3252](https://github.com/vbenjs/vue-vben-admin/issues/3252)) ([2991bb1](https://github.com/vbenjs/vue-vben-admin/commit/2991bb1670d44633d1f571374553d027e0dad8a2))
- Modify i18 file format to JSON ([#3171](https://github.com/vbenjs/vue-vben-admin/issues/3171)) ([c24e0ef](https://github.com/vbenjs/vue-vben-admin/commit/c24e0efd1d2c7148a3df9c8b12a2a500910a3590))
- **useForm:** If the args of the setFieldsValue is empty, it will not be executed. close [#3209](https://github.com/vbenjs/vue-vben-admin/issues/3209) ([8f90087](https://github.com/vbenjs/vue-vben-admin/commit/8f900871ace30895d9fee84c4eb9018c0ad0450e))
### Reverts
- Revert "chore(deps): update ant-design-vue version to 4.1.0. resolve #3495" ([f9fc369](https://github.com/vbenjs/vue-vben-admin/commit/f9fc369637d1588aa5eebf5fee1f3526de14e0cb)), closes [#3495](https://github.com/vbenjs/vue-vben-admin/issues/3495)
- Revert "feat: table搜索表单值发生改变可以触发reload (#3378)" (#3407) ([2828ed3](https://github.com/vbenjs/vue-vben-admin/commit/2828ed304a778bb16b52223607428dac926d73bf)), closes [#3378](https://github.com/vbenjs/vue-vben-admin/issues/3378) [#3407](https://github.com/vbenjs/vue-vben-admin/issues/3407)
- Revert "chore: update `unplugin-config` (#3116)" (#3117) ([f0550f2](https://github.com/vbenjs/vue-vben-admin/commit/f0550f20438a4c11f51fcf3e4a4286692bcf7d9f)), closes [#3116](https://github.com/vbenjs/vue-vben-admin/issues/3116) [#3117](https://github.com/vbenjs/vue-vben-admin/issues/3117)
- Revert "chore: Update Dependencies" ([ae09d3c](https://github.com/vbenjs/vue-vben-admin/commit/ae09d3cfd6b11689620565b57b506826626d09e9))
- Revert "refactor: use `unplugin-config` (#3106)" ([694dead](https://github.com/vbenjs/vue-vben-admin/commit/694dead3115a535782b7dd3a3c2dc4eaa9f32d76)), closes [#3106](https://github.com/vbenjs/vue-vben-admin/issues/3106)
## [2.8.0](https://github.com/anncwb/vue-vben-admin/compare/v2.7.2...v2.8.0) (2021-11-03)
### Bug Fixes

6
internal/stylelint-config/package.json

@ -32,17 +32,17 @@
"stub": "pnpm unbuild --stub"
},
"devDependencies": {
"postcss": "^8.4.35",
"postcss": "^8.4.38",
"postcss-html": "^1.6.0",
"postcss-less": "^6.0.0",
"postcss-scss": "^4.0.9",
"prettier": "^3.2.5",
"stylelint": "^16.2.1",
"stylelint": "^16.3.1",
"stylelint-config-property-sort-order-smacss": "^10.0.0",
"stylelint-config-recommended-scss": "^14.0.0",
"stylelint-config-recommended-vue": "^1.5.0",
"stylelint-config-standard": "^36.0.0",
"stylelint-config-standard-scss": "^13.0.0",
"stylelint-config-standard-scss": "^13.1.0",
"stylelint-order": "^6.0.4",
"stylelint-prettier": "^5.0.0"
}

4
internal/ts-config/package.json

@ -20,7 +20,7 @@
"node-server.json"
],
"dependencies": {
"@types/node": "^20.11.19",
"vite": "^5.1.3"
"@types/node": "^20.12.7",
"vite": "^5.2.10"
}
}

14
internal/vite-config/package.json

@ -33,24 +33,24 @@
},
"dependencies": {
"@ant-design/colors": "^7.0.2",
"vite": "^5.1.3"
"vite": "^5.2.10"
},
"devDependencies": {
"@types/fs-extra": "^11.0.4",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"ant-design-vue": "^4.1.2",
"ant-design-vue": "^4.2.0",
"dayjs": "^1.11.10",
"dotenv": "^16.4.4",
"dotenv": "^16.4.5",
"fs-extra": "^11.2.0",
"less": "^4.2.0",
"picocolors": "^1.0.0",
"pkg-types": "^1.0.3",
"pkg-types": "^1.1.0",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.71.0",
"unocss": "0.58.5",
"sass": "^1.75.0",
"unocss": "0.59.4",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-dts": "^3.7.2",
"vite-plugin-dts": "^3.8.3",
"vite-plugin-html": "^3.2.2",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-purge-icons": "^0.10.0",

72
package.json

@ -1,6 +1,6 @@
{
"name": "vben-admin",
"version": "2.10.1",
"version": "2.11.2",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": {
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
@ -32,6 +32,7 @@
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
"lint:prettier": "prettier --write .",
"lint:stylelint": "stylelint \"**/*.{vue,css,less,scss}\" --fix --cache --cache-location node_modules/.cache/stylelint/",
"log": "conventional-changelog -p angular -i CHANGELOG.md -s",
"prepare": "husky install",
"preview": "npm run build && vite preview",
"reinstall": "rimraf pnpm-lock.yaml && rimraf package.lock.json && rimraf node_modules && npm run bootstrap",
@ -71,51 +72,50 @@
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"@iconify/iconify": "^3.1.1",
"@logicflow/core": "^1.2.22",
"@logicflow/extension": "^1.2.22",
"@logicflow/core": "^1.2.26",
"@logicflow/extension": "^1.2.26",
"@vben/hooks": "workspace:*",
"@vue/shared": "^3.4.19",
"@vueuse/core": "^10.7.2",
"@vue/shared": "^3.4.24",
"@vueuse/core": "^10.9.0",
"@zxcvbn-ts/core": "^3.0.4",
"ant-design-vue": "^4.1.2",
"axios": "^1.6.7",
"ant-design-vue": "^4.2.0",
"axios": "^1.6.8",
"codemirror": "^5.65.16",
"cropperjs": "^1.6.1",
"cropperjs": "^1.6.2",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10",
"driver.js": "^1.3.1",
"echarts": "^5.4.3",
"echarts": "^5.5.0",
"exceljs": "^4.4.0",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.1",
"path-to-regexp": "^6.2.2",
"pinia": "2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"print-js": "^1.6.0",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"qs": "^6.12.1",
"resize-observer-polyfill": "^1.5.1",
"showdown": "^2.1.0",
"sortablejs": "^1.15.2",
"tinymce": "^5.10.9",
"unocss": "^0.58.5",
"vditor": "^3.9.9",
"vue": "^3.4.19",
"vue-i18n": "^9.9.1",
"vue-json-pretty": "^2.3.0",
"vue-router": "^4.2.5",
"unocss": "^0.59.4",
"vditor": "^3.10.4",
"vue": "^3.4.24",
"vue-i18n": "^9.13.1",
"vue-json-pretty": "^2.4.0",
"vue-router": "^4.3.2",
"vue-types": "^5.1.1",
"vuedraggable": "^4.1.0",
"vxe-table": "^4.5.18",
"vxe-table": "^4.6.0",
"vxe-table-plugin-export-xlsx": "^4.0.1",
"xe-utils": "^3.5.20",
"xe-utils": "^3.5.25",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@commitlint/cli": "^18.6.1",
"@commitlint/config-conventional": "^18.6.2",
"@iconify/json": "^2.2.183",
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"@iconify/json": "^2.2.203",
"@purge-icons/generated": "^0.10.0",
"@types/codemirror": "^5.60.15",
"@types/crypto-js": "^4.2.2",
@ -123,7 +123,7 @@
"@types/mockjs": "^1.0.10",
"@types/nprogress": "^0.2.3",
"@types/qrcode": "^1.5.5",
"@types/qs": "^6.9.11",
"@types/qs": "^6.9.15",
"@types/showdown": "^2.0.6",
"@types/sortablejs": "^1.15.8",
"@vben/eslint-config": "workspace:*",
@ -131,26 +131,28 @@
"@vben/ts-config": "workspace:*",
"@vben/types": "workspace:*",
"@vben/vite-config": "workspace:*",
"@vue/compiler-sfc": "^3.4.19",
"@vue/test-utils": "^2.4.4",
"@vue/compiler-sfc": "^3.4.24",
"@vue/test-utils": "^2.4.5",
"conventional-changelog-cli": "^4.1.0",
"cross-env": "^7.0.3",
"cz-git": "^1.8.0",
"czg": "^1.8.0",
"cz-git": "^1.9.1",
"czg": "^1.9.1",
"husky": "^9.0.11",
"lint-staged": "15.2.2",
"prettier": "^3.2.5",
"prettier-plugin-packagejson": "^2.4.11",
"prettier-plugin-packagejson": "^2.5.0",
"rimraf": "^5.0.5",
"turbo": "^1.12.4",
"typescript": "^5.3.3",
"turbo": "^1.13.2",
"typescript": "^5.4.5",
"unbuild": "^2.0.0",
"vite": "^5.1.3",
"vite": "^5.2.10",
"vite-plugin-mock": "^2.9.6",
"vue-tsc": "^1.8.27"
"vite-plugin-vue-inspector": "^5.0.1",
"vue-tsc": "^2.0.14"
},
"packageManager": "pnpm@8.10.0",
"packageManager": "pnpm@9.0.4",
"engines": {
"node": ">=18.12.0",
"pnpm": ">=8.10.0"
"pnpm": ">=9.0.2"
}
}

4
packages/hooks/package.json

@ -30,9 +30,9 @@
"lint": "pnpm eslint ."
},
"dependencies": {
"@vueuse/core": "^10.7.2",
"@vueuse/core": "^10.9.0",
"lodash-es": "^4.17.21",
"vue": "^3.4.19"
"vue": "^3.4.24"
},
"devDependencies": {
"@vben/types": "workspace:*"

16788
pnpm-lock.yaml

File diff suppressed because it is too large

8
src/components/Application/src/search/useMenuSearch.ts

@ -56,7 +56,7 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref, emit: A
}
const reg = createSearchReg(unref(keyword));
const filterMenu = filter(menuList, (item) => {
return reg.test(item.name) && !item.hideMenu;
return reg.test(item.name?.toLowerCase()) && !item.hideMenu;
});
searchResult.value = handlerSearchResult(filterMenu, reg);
activeIndex.value = 0;
@ -66,7 +66,11 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref, emit: A
const ret: SearchResult[] = [];
filterMenu.forEach((item) => {
const { name, path, icon, children, hideMenu, meta } = item;
if (!hideMenu && reg.test(name) && (!children?.length || meta?.hideChildrenInMenu)) {
if (
!hideMenu &&
reg.test(name?.toLowerCase()) &&
(!children?.length || meta?.hideChildrenInMenu)
) {
ret.push({
name: parent?.name ? `${parent.name} > ${name}` : name,
path,

2
src/components/Form/src/hooks/useAdvanced.ts

@ -160,7 +160,7 @@ export default function ({
getAdvanced(unref(getProps).actionColOptions || { span: BASIC_COL_LEN }, itemColSum, true);
emit('advanced-change');
emit('advanced-change', advanceState.isAdvanced);
}
function handleToggleAdvanced() {

68
src/components/Form/src/hooks/useFormEvents.ts

@ -11,7 +11,7 @@ import {
isIncludeSimpleComponents,
} from '../helper';
import { dateUtil } from '@/utils/dateUtil';
import { cloneDeep, set, uniqBy, get } from 'lodash-es';
import { cloneDeep, has, uniqBy, get } from 'lodash-es';
import { error } from '@/utils/log';
interface UseFormActionContext {
@ -25,46 +25,6 @@ interface UseFormActionContext {
handleFormValues: Fn;
}
function tryConstructArray(field: string, values: Recordable = {}): any[] | undefined {
const pattern = /^\[(.+)\]$/;
if (pattern.test(field)) {
const match = field.match(pattern);
if (match && match[1]) {
const keys = match[1].split(',');
if (!keys.length) {
return undefined;
}
const result = [];
keys.forEach((k, index) => {
set(result, index, values[k.trim()]);
});
return result.filter(Boolean).length ? result : undefined;
}
}
}
function tryConstructObject(field: string, values: Recordable = {}): Recordable | undefined {
const pattern = /^\{(.+)\}$/;
if (pattern.test(field)) {
const match = field.match(pattern);
if (match && match[1]) {
const keys = match[1].split(',');
if (!keys.length) {
return;
}
const result = {};
keys.forEach((k) => {
set(result, k.trim(), values[k.trim()]);
});
return Object.values(result).filter(Boolean).length ? result : undefined;
}
}
}
export function useFormEvents({
emit,
getProps,
@ -114,15 +74,11 @@ export function useFormEvents({
const fields = getAllFields();
// key 支持 a.b.c 的嵌套写法
const delimiter = '.';
const nestKeyArray = fields.filter((item) => String(item).indexOf(delimiter) >= 0);
const validKeys: string[] = [];
fields.forEach((key) => {
const schema = unref(getSchema).find((item) => item.field === key);
let value = get(values, key);
const hasKey = Reflect.has(values, key);
const hasKey = has(values, key);
value = handleInputNumberValue(schema?.component, value);
const { componentProps } = schema || {};
@ -134,7 +90,7 @@ export function useFormEvents({
});
}
const constructValue = tryConstructArray(key, values) || tryConstructObject(key, values);
const constructValue = get(value, key);
const setDateFieldValue = (v) => {
return v ? (_props?.valueFormat ? v : dateUtil(v)) : null;
};
@ -161,20 +117,10 @@ export function useFormEvents({
}
validKeys.push(key);
} else {
nestKeyArray.forEach((nestKey: string) => {
try {
const value = nestKey.split('.').reduce((out, item) => out[item], values);
if (isDef(value)) {
unref(formModel)[nestKey] = unref(value);
validKeys.push(nestKey);
}
} catch (e) {
// key not exist
if (isDef(defaultValueRef.value[nestKey])) {
unref(formModel)[nestKey] = cloneDeep(unref(defaultValueRef.value[nestKey]));
}
}
});
// key not exist
if (isDef(get(defaultValueRef.value, key))) {
unref(formModel)[key] = cloneDeep(unref(get(defaultValueRef.value, key)));
}
}
});
validateFields(validKeys).catch((_) => {});

7
src/components/Modal/src/BasicModal.vue

@ -157,8 +157,11 @@
...unref(getMergeProps),
open: unref(openRef),
};
attr['wrapClassName'] =
`${attr?.['wrapClassName'] || ''} ${unref(getWrapClassName)}` + 'vben-basic-modal-wrap';
if (attr?.['wrapClassName'] === unref(getWrapClassName)) {
attr['wrapClassName'] = `${attr?.['wrapClassName'] || ''} ` + prefixCls;
} else {
attr['wrapClassName'] = `${unref(getWrapClassName) || ''}` + prefixCls;
}
if (unref(fullScreenRef)) {
return omit(attr, ['height', 'title']);
}

10
src/components/Modal/src/index.less

@ -1,4 +1,4 @@
@prefix-cls: ~'@{namespace}-basic-modal-wrap';
@modal-prefix-cls: ~'@{namespace}-basic-modal';
.fullscreen-modal {
overflow: hidden;
@ -20,7 +20,7 @@
}
}
.@{prefix-cls} {
.@{modal-prefix-cls} {
.ant-modal {
width: 520px;
padding-bottom: 0;
@ -121,10 +121,10 @@
}
}
}
}
.ant-modal-confirm .ant-modal-body {
padding: 24px !important;
.ant-modal-confirm .ant-modal-body {
padding: 24px !important;
}
}
@media screen and (max-height: 600px) {

21
src/components/Page/src/PageWrapper.vue

@ -1,5 +1,5 @@
<template>
<div :class="getClass" ref="wrapperRef">
<div :class="getClass" :style="getStyle" ref="wrapperRef">
<PageHeader
:ghost="ghost"
:title="title"
@ -39,7 +39,8 @@
import { useDesign } from '@/hooks/web/useDesign';
import { propTypes } from '@/utils/propTypes';
import { PageHeader } from 'ant-design-vue';
import { omit } from 'lodash-es';
import { omit, debounce } from 'lodash-es';
import { useElementSize } from '@vueuse/core';
import {
CSSProperties,
PropType,
@ -82,6 +83,9 @@
const headerRef = ref(null);
const contentRef = ref(null);
const footerRef = ref(null);
const { height } = useElementSize(wrapperRef);
const { prefixCls } = useDesign('page-wrapper');
provide(
@ -101,6 +105,7 @@
[contentRef],
getUpwardSpace,
);
const debounceRedoHeight = debounce(redoHeight, 50);
setCompensation({ useLayoutFooter: true, elements: [footerRef] });
const getClass = computed(() => {
@ -113,6 +118,13 @@
];
});
const getStyle = computed(() => {
const { contentFullHeight, fixedHeight } = props;
return {
...(contentFullHeight && fixedHeight ? { height: '100%' } : {}),
};
});
const getHeaderStyle = computed((): CSSProperties => {
const { headerSticky } = props;
if (!headerSticky) {
@ -172,6 +184,11 @@
immediate: true,
},
);
watch(height, () => {
const { contentFullHeight, fixedHeight } = props;
contentFullHeight && fixedHeight && debounceRedoHeight();
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-page-wrapper';

20
src/components/Table/src/BasicTable.vue

@ -49,7 +49,7 @@
SizeType,
ColumnChangeParam,
} from './types/table';
import { ref, computed, unref, toRaw, inject, watchEffect, useAttrs, useSlots } from 'vue';
import { ref, computed, unref, toRaw, inject, watch, useAttrs, useSlots } from 'vue';
import { Table } from 'ant-design-vue';
import { BasicForm, useForm } from '@/components/Form';
import { PageWrapperFixedHeightKey } from '@/enums/pageEnum';
@ -70,10 +70,10 @@
import { useTableFooter } from './hooks/useTableFooter';
import { useTableForm } from './hooks/useTableForm';
import { useDesign } from '@/hooks/web/useDesign';
import { omit } from 'lodash-es';
import { omit, debounce } from 'lodash-es';
import { useElementSize } from '@vueuse/core';
import { basicProps } from './props';
import { isFunction } from '@/utils/is';
import { warn } from '@/utils/log';
defineOptions({ name: 'BasicTable' });
@ -108,6 +108,8 @@
const formRef = ref(null);
const innerPropsRef = ref<Partial<BasicTableProps>>();
const { height } = useElementSize(wrapRef);
const { prefixCls } = useDesign('basic-table');
const [registerForm, formActions] = useForm();
@ -116,13 +118,6 @@
});
const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false);
watchEffect(() => {
unref(isFixedHeightPage) &&
props.canResize &&
warn(
"'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)",
);
});
const { getLoading, setLoading } = useLoading(getProps);
const { getPaginationInfo, getPagination, setPagination, setShowPagination, getShowPagination } =
@ -196,6 +191,7 @@
wrapRef,
formRef,
);
const debounceRedoHeight = debounce(redoHeight, 50);
const { scrollTo } = useTableScrollTo(tableElRef, getDataSourceRef);
@ -278,6 +274,10 @@
return !!unref(getDataSourceRef).length;
});
watch(height, () => {
unref(isFixedHeightPage) && props.canResize && debounceRedoHeight();
});
function setProps(props: Partial<BasicTableProps>) {
innerPropsRef.value = { ...unref(innerPropsRef), ...props };
}

4
src/components/Table/src/hooks/useTableScroll.ts

@ -115,7 +115,8 @@ export function useTableScroll(
}
if (paginationEl) {
// 分页 margin-top
const paginationElMarginTop = parseInt(getComputedStyle(paginationEl).marginTop);
const paginationElMarginTop =
parseInt(getComputedStyle(paginationEl)?.marginTop) || 10 + 24;
// 分页高度
const offsetHeight = paginationEl.offsetHeight;
paginationHeight = offsetHeight + paginationElMarginTop;
@ -193,6 +194,7 @@ export function useTableScroll(
let modalElIterator: HTMLElement = tableEl.parentElement!;
let modalIsFullscreen = false;
while (modalElIterator !== document.body) {
if (!modalElIterator) break;
if (modalElIterator.classList.contains('ant-modal')) {
modalEl = modalElIterator;
modalWrapEl = modalEl.parentElement;

4
src/components/Upload/src/BasicUpload.vue

@ -34,8 +34,8 @@
@register="registerPreviewModal"
@list-change="handlePreviewChange"
@delete="handlePreviewDelete"
v-bind:preview-columns="props.previewColumns"
v-bind:before-preview-data="props.beforePreviewData"
:preview-columns="props.previewColumns"
:before-preview-data="props.beforePreviewData"
/>
</div>
</template>

6
src/components/Upload/src/components/FileList.vue

@ -53,8 +53,10 @@
return () => {
const { columns, actionColumn, dataSource } = props;
let columnList: FileBasicColumn[];
columnList = (actionColumn ? [...columns, actionColumn] : [...columns]) as FileBasicColumn[];
columnList = (
actionColumn ? [...columns, actionColumn] : [...columns]
) as FileBasicColumn[];
return (
// x scrollbar
<div class="overflow-x-auto">

18
src/components/Upload/src/components/ImageUpload.vue

@ -35,14 +35,15 @@
import { useI18n } from '@/hooks/web/useI18n';
import { useUploadType } from '../hooks/useUpload';
import { uploadContainerProps } from '../props';
import { isImgTypeByName } from '../helper';
import { checkFileType } from '../helper';
import { UploadResultStatus } from '@/components/Upload/src/types/typing';
import { get,omit } from 'lodash-es';
import { get, omit } from 'lodash-es';
defineOptions({ name: 'ImageUpload' });
const emit = defineEmits(['change', 'update:value', 'delete']);
const props = defineProps({
...omit(uploadContainerProps,["previewColumns","beforePreviewData"]),
...omit(uploadContainerProps, ['previewColumns', 'beforePreviewData']),
});
const { t } = useI18n();
const { createMessage } = useMessage();
@ -138,8 +139,7 @@
const beforeUpload = (file: File) => {
const { maxSize, accept } = props;
const { name } = file;
const isAct = isImgTypeByName(name);
const isAct = checkFileType(file, accept);
if (!isAct) {
createMessage.error(t('component.upload.acceptUpload', [accept]));
isActMsg.value = false;
@ -170,9 +170,9 @@
name: props.name,
filename: props.filename,
});
if(props.resultField){
if (props.resultField) {
info.onSuccess!(res);
}else{
} else {
// resultField
info.onSuccess!(res.data);
}
@ -190,8 +190,8 @@
const list = (fileList.value || [])
.filter((item) => item?.status === UploadResultStatus.DONE)
.map((item: any) => {
if(props.resultField){
return get(item?.response, props.resultField)
if (props.resultField) {
return get(item?.response, props.resultField);
}
return item?.url || item?.response?.url;
});

3
src/components/Upload/src/components/UploadModal.vue

@ -164,6 +164,9 @@
function handleRemove(record: FileItem) {
const index = fileListRef.value.findIndex((item) => item.uuid === record.uuid);
index !== -1 && fileListRef.value.splice(index, 1);
isUploadingRef.value = fileListRef.value.some(
(item) => item.status === UploadResultStatus.UPLOADING,
);
emit('delete', record);
}

31
src/components/Upload/src/components/UploadPreviewModal.vue

@ -26,24 +26,23 @@
const emit = defineEmits(['list-change', 'register', 'delete']);
let columns : BasicColumn[] | FileBasicColumn[] = createPreviewColumns();
let actionColumn :any;
let columns: BasicColumn[] | FileBasicColumn[] = createPreviewColumns();
let actionColumn: any;
const [register] = useModalInner();
const { t } = useI18n();
const fileListRef = ref<PreviewFileItem[] | Array<any>>([]);
watch(
watch(
() => props.previewColumns,
() => {
if (props.previewColumns.length) {
columns = props.previewColumns;
actionColumn = null
}else{
columns=createPreviewColumns();
actionColumn = createPreviewActionColumn({ handleRemove, handleDownload })
};
actionColumn = null;
} else {
columns = createPreviewColumns();
actionColumn = createPreviewActionColumn({ handleRemove, handleDownload });
}
},
{ immediate: true },
);
@ -52,17 +51,17 @@
() => props.value,
(value) => {
if (!isArray(value)) value = [];
if(props.beforePreviewData){
value = props.beforePreviewData(value) as any
fileListRef.value = value
return
if (props.beforePreviewData) {
value = props.beforePreviewData(value) as any;
fileListRef.value = value;
return;
}
fileListRef.value = value
.filter((item) => !!item)
.map((item) => {
if(typeof item!="string"){
console.error("return value should be string")
return
if (typeof item != 'string') {
console.error('return value should be string');
return;
}
return {
url: item,

11
src/components/Upload/src/helper.ts

@ -1,8 +1,11 @@
export function checkFileType(file: File, accepts: string[]) {
const newTypes = accepts.join('|');
// const reg = /\.(jpg|jpeg|png|gif|txt|doc|docx|xls|xlsx|xml)$/i;
const reg = new RegExp('\\.(' + newTypes + ')$', 'i');
let reg;
if (!accepts || accepts.length === 0) {
reg = /.(jpg|jpeg|png|gif|webp)$/i;
} else {
const newTypes = accepts.join('|');
reg = new RegExp('\\.(' + newTypes + ')$', 'i');
}
return reg.test(file.name);
}

18
src/components/Upload/src/props.ts

@ -16,17 +16,17 @@ type SortableOptions = Merge<
>;
export const previewType = {
previewColumns:{
type: Array as (PropType<BasicColumn[] | FileBasicColumn[]>),
previewColumns: {
type: Array as PropType<BasicColumn[] | FileBasicColumn[]>,
default: [],
required: false,
},
beforePreviewData:{
type: Function as PropType<(arg:string[])=>Recordable<any>>,
beforePreviewData: {
type: Function as PropType<(arg: string[]) => Recordable<any>>,
default: null,
required: false,
},
}
};
type ListType = 'text' | 'picture' | 'picture-card';
@ -90,7 +90,7 @@ export const basicProps = {
export const uploadContainerProps = {
value: {
type: Array as (PropType<string[]>),
type: Array as PropType<string[]>,
default: () => [],
},
...basicProps,
@ -102,7 +102,7 @@ export const uploadContainerProps = {
type: Boolean as PropType<boolean>,
default: false,
},
...previewType
...previewType,
};
export const previewProps = {
@ -110,12 +110,12 @@ export const previewProps = {
type: Array as PropType<string[]>,
default: () => [],
},
...previewType
...previewType,
};
export const fileListProps = {
columns: {
type: Array as (PropType<BasicColumn[] | FileBasicColumn[]> ),
type: Array as PropType<BasicColumn[] | FileBasicColumn[]>,
default: null,
},
actionColumn: {

13
src/hooks/web/useWatermark.ts

@ -93,16 +93,15 @@ const obFn = () => {
target?.parentElement?.appendChild(node as HTMLElement);
}
}
if (mutation.attributeName === 'style' && mutation.target) {
if (mutation.type === 'attributes' && mutation.target) {
// 修复控制台可以”Hide element” 的问题
const _target = mutation.target as HTMLElement;
const target = findTargetNode(_target);
if (target) {
const { waterMarkOptions = {} } = target;
resetWatermarkStyle(
_target as HTMLElement,
_target?.['data-watermark-text'],
waterMarkOptions,
);
// 禁止改属性 包括class 修改以后 mutation.type 也等于 'attributes'
// 先解除监听 再加一下
clearAll();
target.setWatermark(target.targetElement?.['data-watermark-text']);
}
}
}

239
src/layouts/default/header/components/Breadcrumb.vue

@ -1,26 +1,45 @@
<template>
<div :class="[prefixCls, `${prefixCls}--${theme}`]">
<a-breadcrumb :routes="routes">
<template #itemRender="{ route, routes: routesMatched, paths }">
<Icon :icon="getIcon(route)" v-if="getShowBreadCrumbIcon && getIcon(route)" />
<span v-if="!hasRedirect(routesMatched, route)">
{{ t(route.meta.title || route.name) }}
</span>
<router-link v-else to="" @click="handleClick(route, paths, $event as Event)">
{{ t(route.meta.title || route.name) }}
</router-link>
<Breadcrumb>
<template v-for="routeItem in routes" :key="routeItem.name">
<BreadcrumbItem>
<Icon :icon="getIcon(routeItem)" v-if="getShowBreadCrumbIcon && getIcon(routeItem)" />
<span v-if="!hasRedirect(routes, routeItem)">
{{ t((routeItem.meta.title || routeItem.name) as string) }}
</span>
<router-link v-else to="" @click="handleClick(routeItem)">
{{ t((routeItem.meta.title || routeItem.name) as string) }}
</router-link>
<template v-if="routeItem.children" #overlay>
<Menu>
<template v-for="childItem in routeItem.children" :key="childItem.name">
<MenuItem>
<Icon
:icon="getIcon(childItem)"
v-if="getShowBreadCrumbIcon && getIcon(childItem)"
/>
<span v-if="!hasRedirect(routes, childItem)">
{{ t((childItem.meta?.title || childItem.name) as string) }}
</span>
<router-link v-else to="" @click="handleClick(childItem)">
{{ t((childItem.meta?.title || childItem.name) as string) }}
</router-link>
</MenuItem>
</template>
</Menu>
</template>
</BreadcrumbItem>
</template>
</a-breadcrumb>
</Breadcrumb>
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import type { RouteLocationMatched } from 'vue-router';
import { useRouter } from 'vue-router';
import type { Menu } from '@/router/types';
import { defineComponent, ref, watchEffect } from 'vue';
import { ref, watchEffect } from 'vue';
import { Breadcrumb } from 'ant-design-vue';
import { Breadcrumb, BreadcrumbItem, Menu, MenuItem } from 'ant-design-vue';
import Icon from '@/components/Icon/Icon.vue';
import { useDesign } from '@/hooks/web/useDesign';
@ -36,118 +55,114 @@
import { REDIRECT_NAME } from '@/router/constant';
import { getAllParentPath } from '@/router/helper/menuHelper';
export default defineComponent({
name: 'LayoutBreadcrumb',
components: { Icon, [Breadcrumb.name]: Breadcrumb },
props: {
theme: propTypes.oneOf(['dark', 'light']),
},
setup() {
const routes = ref<RouteLocationMatched[]>([]);
const { currentRoute } = useRouter();
const { prefixCls } = useDesign('layout-breadcrumb');
const { getShowBreadCrumbIcon } = useRootSetting();
const go = useGo();
const { t } = useI18n();
watchEffect(async () => {
if (currentRoute.value.name === REDIRECT_NAME) return;
const menus = await getMenus();
const routeMatched = currentRoute.value.matched;
const cur = routeMatched?.[routeMatched.length - 1];
let path = currentRoute.value.path;
if (cur && cur?.meta?.currentActiveMenu) {
path = cur.meta.currentActiveMenu as string;
}
defineOptions({ name: 'LayoutBreadcrumb' });
const parent = getAllParentPath(menus, path);
const filterMenus = menus.filter((item) => item.path === parent[0]);
const matched = getMatched(filterMenus, parent) as any;
defineProps({
theme: propTypes.oneOf(['dark', 'light']),
});
if (!matched || matched.length === 0) return;
const routes = ref<RouteLocationMatched[]>([]);
const { currentRoute } = useRouter();
const { prefixCls } = useDesign('layout-breadcrumb');
const { getShowBreadCrumbIcon } = useRootSetting();
const go = useGo();
const breadcrumbList = filterItem(matched);
const { t } = useI18n();
watchEffect(async () => {
if (currentRoute.value.name === REDIRECT_NAME) return;
const menus = await getMenus();
if (currentRoute.value.meta?.currentActiveMenu) {
breadcrumbList.push({
...currentRoute.value,
name: currentRoute.value.meta?.title || currentRoute.value.name,
} as unknown as RouteLocationMatched);
}
routes.value = breadcrumbList;
});
function getMatched(menus: Menu[], parent: string[]) {
const metched: Menu[] = [];
menus.forEach((item) => {
if (parent.includes(item.path)) {
metched.push({
...item,
name: item.meta?.title || item.name,
});
}
if (item.children?.length) {
metched.push(...getMatched(item.children, parent));
}
});
return metched;
}
const routeMatched = currentRoute.value.matched;
const cur = routeMatched?.[routeMatched.length - 1];
let path = currentRoute.value.path;
function filterItem(list: RouteLocationMatched[]) {
return filter(list, (item) => {
const { meta, name } = item;
if (!meta) {
return !!name;
}
const { title, hideBreadcrumb, hideMenu } = meta;
if (!title || hideBreadcrumb || hideMenu) {
return false;
}
return true;
}).filter((item) => !item.meta?.hideBreadcrumb);
}
if (cur && cur?.meta?.currentActiveMenu) {
path = cur.meta.currentActiveMenu as string;
}
function handleClick(route: RouteLocationMatched, paths: string[], e: Event) {
e?.preventDefault();
const { children, redirect, meta } = route;
const parent = getAllParentPath(menus, path);
const filterMenus = menus.filter((item) => item.path === parent[0]);
const matched = getMatched(filterMenus, parent) as any;
if (children?.length && !redirect) {
e?.stopPropagation();
return;
}
if (meta?.carryParam) {
return;
}
if (!matched || matched.length === 0) {
routes.value = [];
return;
}
if (redirect && isString(redirect)) {
go(redirect);
} else {
let goPath = '';
if (paths.length === 1) {
goPath = paths[0];
} else {
const ps = paths.slice(1);
const lastPath = ps.pop() || '';
goPath = `${lastPath}`;
}
goPath = /^\//.test(goPath) ? goPath : `/${goPath}`;
go(goPath);
}
const breadcrumbList = filterItem(matched);
if (currentRoute.value.meta?.currentActiveMenu) {
breadcrumbList.push({
...currentRoute.value,
name: currentRoute.value.meta?.title || currentRoute.value.name,
} as unknown as RouteLocationMatched);
}
routes.value = breadcrumbList;
});
function getMatched(menus, parent: string[]) {
const matched: any[] = [];
menus.forEach((item) => {
if (parent.includes(item.path)) {
matched.push({
...item,
name: item.meta?.title || item.name,
});
}
if (item.children?.length) {
matched.push(...getMatched(item.children, parent));
}
});
return matched;
}
function hasRedirect(routes: RouteLocationMatched[], route: RouteLocationMatched) {
return routes.indexOf(route) !== routes.length - 1;
function filterItem(list: RouteLocationMatched[]) {
return filter(list, (item) => {
const { meta, name } = item;
if (!meta) {
return !!name;
}
const { title, hideBreadcrumb, hideMenu } = meta;
if (!title || hideBreadcrumb || hideMenu) {
return false;
}
return true;
}).filter((item) => !item.meta?.hideBreadcrumb);
}
function getIcon(route) {
return route.icon || route.meta?.icon;
function handleClick(route) {
console.log(route);
const { children, redirect, meta } = route;
if (children?.length && !redirect) {
return;
}
if (meta?.carryParam) {
return;
}
if (redirect && isString(redirect)) {
go(redirect);
} else {
let goPath = '';
if (route.path) {
goPath = route.path;
} else {
const lastPath = '';
goPath = `${lastPath}`;
}
goPath = /^\//.test(goPath) ? goPath : `/${goPath}`;
go(goPath);
}
}
return { routes, t, prefixCls, getIcon, getShowBreadCrumbIcon, handleClick, hasRedirect };
},
});
function hasRedirect(routes, route) {
return routes.indexOf(route) !== routes.length - 1;
}
function getIcon(route) {
return route.icon || route.meta?.icon;
}
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-layout-breadcrumb';

3
src/router/guard/index.ts

@ -6,6 +6,7 @@ import { AxiosCanceler } from '@/utils/http/axios/axiosCancel';
import { Modal, notification } from 'ant-design-vue';
import { warn } from '@/utils/log';
import { unref } from 'vue';
import { prefixCls } from '@/settings/designSetting';
import { setRouteChange } from '@/logics/mitt/routeChange';
import { createPermissionGuard } from './permissionGuard';
import { createStateGuard } from './stateGuard';
@ -104,7 +105,7 @@ function createScrollGuard(router: Router) {
router.afterEach(async (to) => {
// scroll top
isHash((to as RouteLocationNormalized & { href: string })?.href) &&
document.querySelector('.vben-layout-content')?.scrollTo(0, 0);
document.querySelector(`.${prefixCls}-layout-content`)?.scrollTo(0, 0);
return true;
});
}

2
src/router/helper/routeHelper.ts

@ -96,6 +96,8 @@ export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModul
warn('找不到菜单对应的name, 请检查数据!' + JSON.stringify(route));
}
route.name = `${route.name}Parent`;
// 重定向到当前路由,以防空白页面
route.redirect = route.path;
route.path = '';
const meta = route.meta || {};
meta.single = true;

1
src/utils/http/axios/index.ts

@ -240,6 +240,7 @@ const transform: AxiosTransform = {
const { isOpenRetry } = config.requestOptions.retryRequest;
config.method?.toUpperCase() === RequestEnum.GET &&
isOpenRetry &&
error?.response?.status !== 401 &&
// @ts-ignore
retryRequest.retry(axiosInstance, error);
return Promise.reject(error);

223
src/views/demo/comp/upload/index.vue

@ -19,7 +19,6 @@
<Alert message="嵌入表单,自定义预览内容" />
<BasicForm @register="registerPreview" class="my-5" />
</PageWrapper>
</template>
<script lang="ts" setup>
@ -27,9 +26,9 @@
import { useMessage } from '@/hooks/web/useMessage';
import { BasicForm, FormSchema, useForm } from '@/components/Form';
import { PageWrapper } from '@/components/Page';
import { Alert,Button } from 'ant-design-vue';
import { Alert, Button } from 'ant-design-vue';
import { uploadApi } from '@/api/sys/upload';
import { createVNode } from "vue"
import { createVNode } from 'vue';
const schemasValiate: FormSchema[] = [
{
@ -40,16 +39,17 @@
componentProps: {
api: uploadApi,
},
},{
},
{
field: 'field2',
component: "ImageUpload",
component: 'ImageUpload',
label: '字段2(ImageUpload)',
colProps: {
span: 8,
},
componentProps: {
api: uploadApi,
}
},
},
];
const schemasCustom: FormSchema[] = [
@ -58,41 +58,41 @@
component: 'Upload',
label: '字段3',
componentProps: {
resultField:"data3.url",
api: (file,progress)=>{
return new Promise((resolve)=>{
uploadApi(file,progress).then((uploadApiResponse)=>{
resultField: 'data3.url',
api: (file, progress) => {
return new Promise((resolve) => {
uploadApi(file, progress).then((uploadApiResponse) => {
resolve({
code:200,
data3:{
url:uploadApiResponse.data.url
}
})
})
})
code: 200,
data3: {
url: uploadApiResponse.data.url,
},
});
});
});
},
},
},
{
field: 'field4',
component: "ImageUpload",
component: 'ImageUpload',
label: '字段4(ImageUpload)',
colProps: {
span: 8,
},
componentProps: {
resultField:"data4.url",
api: (file,progress)=>{
return new Promise((resolve)=>{
uploadApi(file,progress).then((uploadApiResponse)=>{
resultField: 'data4.url',
api: (file, progress) => {
return new Promise((resolve) => {
uploadApi(file, progress).then((uploadApiResponse) => {
resolve({
code:200,
data4:{
url:uploadApiResponse.data.url
}
})
})
})
code: 200,
data4: {
url: uploadApiResponse.data.url,
},
});
});
});
},
},
},
@ -103,117 +103,124 @@
component: 'Upload',
label: '字段5',
componentProps: {
previewColumns:[{
title:"url5",
dataIndex:"url5"
},{
title:"type5",
dataIndex:"type5"
},{
title:"name5",
dataIndex:"name5"
},
{
title:"operation",
dataIndex:"",
customRender: ({ record })=>{
return createVNode(Button,{
onclick:()=>{
console.log(record)
createMessage.success(`请到控制台查看该行输出结果`);
previewColumns: [
{
title: 'url5',
dataIndex: 'url5',
},
{
title: 'type5',
dataIndex: 'type5',
},
{
title: 'name5',
dataIndex: 'name5',
},
{
title: 'operation',
dataIndex: '',
customRender: ({ record }) => {
return createVNode(
Button,
{
onclick: () => {
console.log(record);
createMessage.success(`请到控制台查看该行输出结果`);
},
},
'点我',
);
},
},
],
beforePreviewData: (arg) => {
let data = arg
.filter((item) => !!item)
.map((item) => {
if (typeof item !== 'string') {
console.error('return value should be string');
return;
}
},"点我")
}
},
],
beforePreviewData:(arg)=>{
let data = arg.filter((item) => !!item).map((item) => {
if(typeof item !== "string"){
console.error("return value should be string")
return
}
return {
url5: item,
type5: item.split('.').pop() || '',
name5: item.split('/').pop() || '',
};
})
return data
return {
url5: item,
type5: item.split('.').pop() || '',
name5: item.split('/').pop() || '',
};
});
return data;
},
resultField:"data5.url",
api: (file,progress)=>{
return new Promise((resolve)=>{
uploadApi(file,progress).then((uploadApiResponse)=>{
resultField: 'data5.url',
api: (file, progress) => {
return new Promise((resolve) => {
uploadApi(file, progress).then((uploadApiResponse) => {
resolve({
code:200,
data5:{
url:uploadApiResponse.data.url
}
})
})
})
code: 200,
data5: {
url: uploadApiResponse.data.url,
},
});
});
});
},
},
},
];
const { createMessage } = useMessage();
function handleChange(list: string[]) {
createMessage.success(`已上传文件${JSON.stringify(list)}`);
}
const [registerValiate,{getFieldsValue:getFieldsValueValiate,validate}] = useForm({
const [registerValiate, { getFieldsValue: getFieldsValueValiate, validate }] = useForm({
labelWidth: 160,
schemas:schemasValiate,
schemas: schemasValiate,
actionColOptions: {
span: 18,
},
submitFunc:()=>{
return new Promise((resolve)=>{
validate().then((e)=>{
resolve()
console.log(getFieldsValueValiate())
createMessage.success(`请到控制台查看结果`);
}).catch(()=>{
createMessage.error(`请输入必填项`);
})
})
}
submitFunc: () => {
return new Promise((resolve) => {
validate()
.then(() => {
resolve();
console.log(getFieldsValueValiate());
createMessage.success(`请到控制台查看结果`);
})
.catch(() => {
createMessage.error(`请输入必填项`);
});
});
},
});
// resultFields
const [registerCustom,{getFieldsValue:getFieldsValueCustom}] = useForm({
const [registerCustom, { getFieldsValue: getFieldsValueCustom }] = useForm({
labelWidth: 160,
schemas:schemasCustom,
schemas: schemasCustom,
actionColOptions: {
span: 18,
},
submitFunc:()=>{
return new Promise((resolve)=>{
console.log(getFieldsValueCustom())
resolve()
submitFunc: () => {
return new Promise((resolve) => {
console.log(getFieldsValueCustom());
resolve();
createMessage.success(`请到控制台查看结果`);
})
}
});
},
});
// registerPreview
const [registerPreview,{getFieldsValue:getFieldsValuePreview}] = useForm({
const [registerPreview, { getFieldsValue: getFieldsValuePreview }] = useForm({
labelWidth: 160,
schemas:schemasPreview,
schemas: schemasPreview,
actionColOptions: {
span: 18,
},
submitFunc:()=>{
return new Promise((resolve)=>{
console.log(getFieldsValuePreview())
resolve()
submitFunc: () => {
return new Promise((resolve) => {
console.log(getFieldsValuePreview());
resolve();
createMessage.success(`请到控制台查看结果`);
})
}
});
},
});
</script>

11
src/views/demo/form/AdvancedForm.vue

@ -5,7 +5,7 @@
</CollapseContainer>
<CollapseContainer title="超过3行自动收起,折叠时保留2行" class="mt-4">
<BasicForm @register="register1" />
<BasicForm @register="register1" @advanced-change="onAdvancedChange" />
</CollapseContainer>
</PageWrapper>
</template>
@ -182,4 +182,13 @@
showAdvancedButton: true,
alwaysShowLines: 2,
});
function onAdvancedChange(isAdvanced: boolean) {
console.log('isAdvanced: ' + isAdvanced);
if (isAdvanced) {
// do something
} else {
// do something
}
}
</script>

82
src/views/demo/form/AppendForm.vue

@ -1,6 +1,6 @@
<template>
<PageWrapper title="表单增删示例">
<CollapseContainer title="表单增删">
<CollapseContainer title="表单增删">
<BasicForm @register="register" @submit="handleSubmit">
<template #add="{ field }">
<a-button v-if="Number(field) === 0" @click="add">+</a-button>
@ -11,6 +11,12 @@
</template>
</BasicForm>
</CollapseContainer>
<CollapseContainer title="表单组增删" class="my-3">
<a-button @click="setGroup">设置初始值</a-button>
<a-button class="m-2" @click="addGroup"> 批量添加表单 </a-button>
<a-button @click="delGroup">批量减少表单</a-button>
<BasicForm @register="registerGroup" @submit="handleSubmitGroup" />
</CollapseContainer>
</PageWrapper>
</template>
<script lang="ts" setup>
@ -19,6 +25,10 @@
import { CollapseContainer } from '@/components/Container';
import { PageWrapper } from '@/components/Page';
import { useMessage } from '@/hooks/web/useMessage';
const { createMessage } = useMessage();
const count = ref(0);
const [register, { appendSchemaByField, removeSchemaByField, validate }] = useForm({
schemas: [
{
@ -48,6 +58,7 @@
async function handleSubmit() {
try {
const data = await validate();
createMessage.success('请前往控制台查看输出');
console.log(data);
} catch (e) {
console.log(e);
@ -121,4 +132,73 @@
removeSchemaByField([`field${field}a`, `field${field}b`, `${field}`]);
n.value--;
}
const [
registerGroup,
{
appendSchemaByField: appendSchemaByFieldGroup,
removeSchemaByField: removeSchemaByFieldGroup,
getFieldsValue: getFieldsValueGroup,
setFieldsValue,
},
] = useForm({
schemas: [
{
field: `field[${count.value}].a`,
component: 'Input',
label: '字段a',
colProps: { span: 9 },
},
{
field: `field[${count.value}].b`,
colProps: { span: 9 },
component: 'Input',
label: '字段b',
},
],
labelWidth: 100,
actionColOptions: { span: 24 },
baseColProps: { span: 8 },
});
function addGroup() {
count.value++;
appendSchemaByFieldGroup(
[
{
field: `field[${count.value}].a`,
component: 'Input',
colProps: { span: 9 },
label: '字段a',
},
{
field: `field[${count.value}].b`,
component: 'Input',
colProps: { span: 9 },
label: '字段b',
},
],
'',
);
}
function delGroup() {
removeSchemaByFieldGroup([`field[${count.value}].a`, `field[${count.value}].b`]);
count.value--;
}
function setGroup() {
setFieldsValue({
field: [
{
a: '默认a',
b: '默认b',
},
],
});
}
function handleSubmitGroup() {
createMessage.success('请前往控制台查看输出');
console.log(getFieldsValueGroup());
}
</script>

3
src/views/demo/form/index.vue

@ -48,7 +48,7 @@
labelField="name"
valueField="id"
:params="searchParams"
@search="useDebounceFn(onSearch, 300)"
@search="debounceOptionsFn"
/>
</template>
</BasicForm>
@ -71,6 +71,7 @@
import { areaRecord } from '@/api/demo/cascader';
import { uploadApi } from '@/api/sys/upload';
let debounceOptionsFn = useDebounceFn(onSearch, 300);
const valueSelectA = ref<string[]>([]);
const valueSelectB = ref<string[]>([]);
const options = ref<Required<SelectProps>['options']>([]);

57
src/views/demo/steps/index.vue

@ -1,41 +1,38 @@
<template>
<PageWrapper title="引导页" content="用于给用户的指引操作">
<a-button type="primary" @click="handleStart">开始</a-button>
<a-button type="primary" @click="handleOpen(true)">开始</a-button>
<Tour v-model:current="current" :open="open" :steps="steps" @close="handleOpen(false)" />
</PageWrapper>
</template>
<script lang="ts" setup>
import { PageWrapper } from '@/components/Page';
import { useDesign } from '@/hooks/web/useDesign';
import { driver } from 'driver.js';
import 'driver.js/dist/driver.css';
import { ref } from 'vue';
import { Tour, TourProps } from 'ant-design-vue';
const open = ref<boolean>(false);
const { prefixVar } = useDesign('');
function handleStart() {
driver({
showProgress: true,
steps: [
{
popover: {
title: 'Welcome',
description: 'Hello World! 👋',
},
},
{
element: `.${prefixVar}-layout-header-trigger`,
popover: {
title: 'Collapse Button',
description: 'This is the menu collapse button.',
},
},
{
element: `.${prefixVar}-layout-header-action`,
popover: {
title: 'User Action',
description: 'This is the user function area.',
},
},
],
}).drive();
}
const current = ref(0);
const steps: TourProps['steps'] = [
{
title: 'Welcome',
description: 'Hello World! 👋',
},
{
title: 'Collapse Button',
description: 'This is the menu collapse button.',
target: () => document.querySelector(`.${prefixVar}-layout-header-trigger`) as HTMLElement,
},
{
title: 'User Action',
description: 'This is the user function area.',
target: () => document.querySelector(`.${prefixVar}-layout-header-action`) as HTMLElement,
},
];
const handleOpen = (val: boolean): void => {
current.value = 0;
open.value = val;
};
</script>

6
vite.config.ts

@ -1,4 +1,5 @@
import { defineApplicationConfig } from '@vben/vite-config';
import Inspector from 'vite-plugin-vue-inspector';
export default defineApplicationConfig({
overrides: {
@ -38,5 +39,10 @@ export default defineApplicationConfig({
clientFiles: ['./index.html', './src/{views,components}/*'],
},
},
plugins: [
Inspector({
openInEditorHost: 'http://localhost:5173',
}),
],
},
});

Loading…
Cancel
Save