Compare commits

..

34 Commits

Author SHA1 Message Date
vben
f3e7438a49 chore: release v5.3.0-beta.1 2024-09-10 22:07:54 +08:00
dependabot[bot]
b417ac2469 chore(deps): bump the non-breaking-changes group with 14 updates (#4347)
* chore(deps): bump the non-breaking-changes group with 14 updates

Bumps the non-breaking-changes group with 14 updates:

| Package | From | To |
| --- | --- | --- |
| [typescript](https://github.com/microsoft/TypeScript) | `5.5.4` | `5.6.2` |
| [@iconify/json](https://github.com/iconify/icon-sets) | `2.2.245` | `2.2.246` |
| [postcss-preset-env](https://github.com/csstools/postcss-plugins/tree/HEAD/plugin-packs/postcss-preset-env) | `10.0.2` | `10.0.3` |
| [@jspm/generator](https://github.com/jspm/generator) | `2.2.0` | `2.3.0` |
| [vite-plugin-dts](https://github.com/qmhc/vite-plugin-dts) | `4.1.1` | `4.2.1` |
| [eslint-plugin-command](https://github.com/antfu/eslint-plugin-command) | `0.2.3` | `0.2.4` |
| [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) | `9.9.1` | `9.10.0` |
| [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.4.0` | `8.5.0` |
| [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.4.0` | `8.5.0` |
| [eslint](https://github.com/eslint/eslint) | `9.9.1` | `9.10.0` |
| [eslint-plugin-perfectionist](https://github.com/azat-io/eslint-plugin-perfectionist) | `3.4.0` | `3.5.0` |
| [watermark-js-plus](https://github.com/zhensherlock/watermark-js-plus) | `1.5.5` | `1.5.6` |
| [circular-dependency-scanner](https://github.com/emosheeep/circular-dependency-scanner) | `2.2.2` | `2.3.0` |
| [@tanstack/vue-query](https://github.com/TanStack/query/tree/HEAD/packages/vue-query) | `5.54.2` | `5.55.4` |


Updates `typescript` from 5.5.4 to 5.6.2
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.5.4...v5.6.2)

Updates `@iconify/json` from 2.2.245 to 2.2.246
- [Commits](https://github.com/iconify/icon-sets/compare/2.2.245...2.2.246)

Updates `postcss-preset-env` from 10.0.2 to 10.0.3
- [Changelog](https://github.com/csstools/postcss-plugins/blob/main/plugin-packs/postcss-preset-env/CHANGELOG.md)
- [Commits](https://github.com/csstools/postcss-plugins/commits/HEAD/plugin-packs/postcss-preset-env)

Updates `@jspm/generator` from 2.2.0 to 2.3.0
- [Release notes](https://github.com/jspm/generator/releases)
- [Commits](https://github.com/jspm/generator/compare/2.2.0...2.3.0)

Updates `vite-plugin-dts` from 4.1.1 to 4.2.1
- [Release notes](https://github.com/qmhc/vite-plugin-dts/releases)
- [Changelog](https://github.com/qmhc/vite-plugin-dts/blob/main/CHANGELOG.md)
- [Commits](https://github.com/qmhc/vite-plugin-dts/compare/v4.1.1...v4.2.1)

Updates `eslint-plugin-command` from 0.2.3 to 0.2.4
- [Release notes](https://github.com/antfu/eslint-plugin-command/releases)
- [Commits](https://github.com/antfu/eslint-plugin-command/compare/v0.2.3...v0.2.4)

Updates `@eslint/js` from 9.9.1 to 9.10.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.10.0/packages/js)

Updates `@typescript-eslint/eslint-plugin` from 8.4.0 to 8.5.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.5.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.4.0 to 8.5.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.5.0/packages/parser)

Updates `eslint` from 9.9.1 to 9.10.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.9.1...v9.10.0)

Updates `eslint-plugin-perfectionist` from 3.4.0 to 3.5.0
- [Release notes](https://github.com/azat-io/eslint-plugin-perfectionist/releases)
- [Changelog](https://github.com/azat-io/eslint-plugin-perfectionist/blob/main/changelog.md)
- [Commits](https://github.com/azat-io/eslint-plugin-perfectionist/compare/v3.4.0...v3.5.0)

Updates `watermark-js-plus` from 1.5.5 to 1.5.6
- [Release notes](https://github.com/zhensherlock/watermark-js-plus/releases)
- [Changelog](https://github.com/zhensherlock/watermark-js-plus/blob/main/CHANGELOG.md)
- [Commits](https://github.com/zhensherlock/watermark-js-plus/compare/v1.5.5...v1.5.6)

Updates `circular-dependency-scanner` from 2.2.2 to 2.3.0
- [Release notes](https://github.com/emosheeep/circular-dependency-scanner/releases)
- [Changelog](https://github.com/emosheeep/circular-dependency-scanner/blob/master/CHANGELOG.md)
- [Commits](https://github.com/emosheeep/circular-dependency-scanner/compare/v2.2.2...v2.3.0)

Updates `@tanstack/vue-query` from 5.54.2 to 5.55.4
- [Release notes](https://github.com/TanStack/query/releases)
- [Commits](https://github.com/TanStack/query/commits/v5.55.4/packages/vue-query)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@iconify/json"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: postcss-preset-env
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@jspm/generator"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: vite-plugin-dts
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: eslint-plugin-command
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@eslint/js"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: eslint-plugin-perfectionist
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: watermark-js-plus
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: circular-dependency-scanner
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@tanstack/vue-query"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: update deps

* chore: typo

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-10 22:05:11 +08:00
Vben
524b9badf2 feat: add VbenForm component (#4352)
* feat: add form component

* fix: build error

* feat: add form adapter

* feat: add some component

* feat: add some component

* feat: add example

* feat: suppoer custom action button

* chore: update

* feat: add example

* feat: add formModel,formDrawer demo

* fix: build error

* fix: typo

* fix: ci error

---------

Co-authored-by: jinmao <jinmao88@qq.com>
Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>
2024-09-10 21:48:51 +08:00
Li Kui
86ed732ca8 feat: tanstack query demos (#4276)
* chore(@vben/request): add axios-retry

* feat: error retry

* feat: paginated queries

* feat: infinite queries

* chore: update

* chore: update

* fix: ci error

* chore: update

* chore: remove axios-retry

* chore: update deps

* chore: update deps

* chore: update deps

* chore: update pnpm.lock

---------

Co-authored-by: vince <vince292007@gmail.com>
2024-09-08 19:39:19 +08:00
Li Kui
56e66193fc fix: module is not listed in package. json dependencies (#4338) 2024-09-08 09:55:20 +08:00
Squall2017
b1636405fc feat: captcha example (#4330)
* feat: captcha example

* fix: fix lint errors

* chore: event handling and methods

* chore: add accessibility features ARIA labels and roles

---------

Co-authored-by: vince <vince292007@gmail.com>
2024-09-07 20:33:33 +08:00
dependabot[bot]
ad89ea7a75 chore(deps): bump the non-breaking-changes group with 6 updates (#4332)
Bumps the non-breaking-changes group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [vue](https://github.com/vuejs/core) | `3.5.2` | `3.5.3` |
| [@iconify/json](https://github.com/iconify/icon-sets) | `2.2.244` | `2.2.245` |
| [vite-plugin-dts](https://github.com/qmhc/vite-plugin-dts) | `4.1.0` | `4.1.1` |
| [lucide-vue-next](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next) | `0.438.0` | `0.439.0` |
| [@vue/shared](https://github.com/vuejs/core/tree/HEAD/packages/shared) | `3.5.2` | `3.5.3` |
| [element-plus](https://github.com/element-plus/element-plus) | `2.8.1` | `2.8.2` |


Updates `vue` from 3.5.2 to 3.5.3
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.5.2...v3.5.3)

Updates `@iconify/json` from 2.2.244 to 2.2.245
- [Commits](https://github.com/iconify/icon-sets/compare/2.2.244...2.2.245)

Updates `vite-plugin-dts` from 4.1.0 to 4.1.1
- [Release notes](https://github.com/qmhc/vite-plugin-dts/releases)
- [Changelog](https://github.com/qmhc/vite-plugin-dts/blob/main/CHANGELOG.md)
- [Commits](https://github.com/qmhc/vite-plugin-dts/compare/v4.1.0...v4.1.1)

Updates `lucide-vue-next` from 0.438.0 to 0.439.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.439.0/packages/lucide-vue-next)

Updates `@vue/shared` from 3.5.2 to 3.5.3
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/commits/v3.5.3/packages/shared)

Updates `element-plus` from 2.8.1 to 2.8.2
- [Release notes](https://github.com/element-plus/element-plus/releases)
- [Changelog](https://github.com/element-plus/element-plus/blob/dev/CHANGELOG.en-US.md)
- [Commits](https://github.com/element-plus/element-plus/compare/2.8.1...2.8.2)

---
updated-dependencies:
- dependency-name: vue
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@iconify/json"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vite-plugin-dts
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: lucide-vue-next
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@vue/shared"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: element-plus
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-07 17:35:31 +08:00
Li Kui
7b3c9d56be fix: resolve lint fail (#4335) 2024-09-07 14:03:13 +08:00
dependabot[bot]
1cff0b9753 chore(deps): bump the non-breaking-changes group with 8 updates (#4326)
Bumps the non-breaking-changes group with 8 updates:

| Package | From | To |
| --- | --- | --- |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.5.3` | `22.5.4` |
| [vue](https://github.com/vuejs/core) | `3.5.1` | `3.5.2` |
| [vue-tsc](https://github.com/vuejs/language-tools/tree/HEAD/packages/tsc) | `2.1.4` | `2.1.6` |
| [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa) | `0.20.4` | `0.20.5` |
| [eslint-plugin-perfectionist](https://github.com/azat-io/eslint-plugin-perfectionist) | `3.3.0` | `3.4.0` |
| [@vue/shared](https://github.com/vuejs/core/tree/HEAD/packages/shared) | `3.5.1` | `3.5.2` |
| [watermark-js-plus](https://github.com/zhensherlock/watermark-js-plus) | `1.5.4` | `1.5.5` |
| [@vite-pwa/vitepress](https://github.com/vite-pwa/vitepress) | `0.5.2` | `0.5.3` |


Updates `@types/node` from 22.5.3 to 22.5.4
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `vue` from 3.5.1 to 3.5.2
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.5.1...v3.5.2)

Updates `vue-tsc` from 2.1.4 to 2.1.6
- [Release notes](https://github.com/vuejs/language-tools/releases)
- [Changelog](https://github.com/vuejs/language-tools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vuejs/language-tools/commits/v2.1.6/packages/tsc)

Updates `vite-plugin-pwa` from 0.20.4 to 0.20.5
- [Release notes](https://github.com/vite-pwa/vite-plugin-pwa/releases)
- [Commits](https://github.com/vite-pwa/vite-plugin-pwa/compare/v0.20.4...v0.20.5)

Updates `eslint-plugin-perfectionist` from 3.3.0 to 3.4.0
- [Release notes](https://github.com/azat-io/eslint-plugin-perfectionist/releases)
- [Changelog](https://github.com/azat-io/eslint-plugin-perfectionist/blob/main/changelog.md)
- [Commits](https://github.com/azat-io/eslint-plugin-perfectionist/compare/v3.3.0...v3.4.0)

Updates `@vue/shared` from 3.5.1 to 3.5.2
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/commits/v3.5.2/packages/shared)

Updates `watermark-js-plus` from 1.5.4 to 1.5.5
- [Release notes](https://github.com/zhensherlock/watermark-js-plus/releases)
- [Changelog](https://github.com/zhensherlock/watermark-js-plus/blob/main/CHANGELOG.md)
- [Commits](https://github.com/zhensherlock/watermark-js-plus/compare/v1.5.4...v1.5.5)

Updates `@vite-pwa/vitepress` from 0.5.2 to 0.5.3
- [Release notes](https://github.com/vite-pwa/vitepress/releases)
- [Commits](https://github.com/vite-pwa/vitepress/compare/v0.5.2...v0.5.3)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vue
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vue-tsc
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vite-plugin-pwa
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: eslint-plugin-perfectionist
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@vue/shared"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: watermark-js-plus
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@vite-pwa/vitepress"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-06 10:28:22 +08:00
afe1
31d5f03b45 fix: external link jump (#4319)
* fix: external link jump

* fix: external link jump

* chore: update deps

---------

Co-authored-by: Li Kui <90845831+likui628@users.noreply.github.com>
2024-09-06 10:15:56 +08:00
Li Kui
2b65e935c1 fix: improve the lock-screen password validation logic (#4324)
* fix: after entering the password correctly, the verification still shows' failed ', resulting in the inability to enter the system

* chore: update

---------

Co-authored-by: zyy <532612154@qq.com>
2024-09-05 22:25:44 +08:00
jinmao88
58f2b17bde chore: add qq group [skip ci] #4 (#4321)
* Update community.md

添加4群链接

* chore: add old qq group
2024-09-05 22:25:16 +08:00
dependabot[bot]
46a9fac38e chore(deps): bump the non-breaking-changes group with 5 updates (#4320)
Bumps the non-breaking-changes group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [vue](https://github.com/vuejs/core) | `3.5.0` | `3.5.1` |
| [cssnano](https://github.com/cssnano/cssnano) | `7.0.5` | `7.0.6` |
| [vite-plugin-vue-devtools](https://github.com/vuejs/devtools-next/tree/HEAD/packages/vite) | `7.4.0` | `7.4.4` |
| [eslint-plugin-import-x](https://github.com/un-ts/eslint-plugin-import-x) | `4.2.0` | `4.2.1` |
| [@vite-pwa/vitepress](https://github.com/vite-pwa/vitepress) | `0.5.1` | `0.5.2` |


Updates `vue` from 3.5.0 to 3.5.1
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.5.0...v3.5.1)

Updates `cssnano` from 7.0.5 to 7.0.6
- [Release notes](https://github.com/cssnano/cssnano/releases)
- [Commits](https://github.com/cssnano/cssnano/compare/cssnano@7.0.5...cssnano@7.0.6)

Updates `vite-plugin-vue-devtools` from 7.4.0 to 7.4.4
- [Release notes](https://github.com/vuejs/devtools-next/releases)
- [Commits](https://github.com/vuejs/devtools-next/commits/v7.4.4/packages/vite)

Updates `eslint-plugin-import-x` from 4.2.0 to 4.2.1
- [Release notes](https://github.com/un-ts/eslint-plugin-import-x/releases)
- [Changelog](https://github.com/un-ts/eslint-plugin-import-x/blob/master/CHANGELOG.md)
- [Commits](https://github.com/un-ts/eslint-plugin-import-x/compare/v4.2.0...v4.2.1)

Updates `@vite-pwa/vitepress` from 0.5.1 to 0.5.2
- [Release notes](https://github.com/vite-pwa/vitepress/releases)
- [Commits](https://github.com/vite-pwa/vitepress/compare/v0.5.1...v0.5.2)

---
updated-dependencies:
- dependency-name: vue
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: cssnano
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vite-plugin-vue-devtools
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: eslint-plugin-import-x
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@vite-pwa/vitepress"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-05 09:54:05 +08:00
vben
41612f7723 chore: release v5.2.2 2024-09-04 22:59:43 +08:00
dependabot[bot]
83ecae7c4e chore(deps): bump the non-breaking-changes group across 1 directory with 22 updates (#4314)
* chore(deps): bump the non-breaking-changes group across 1 directory with 22 updates

Bumps the non-breaking-changes group with 22 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.5.1` | `22.5.2` |
| [lint-staged](https://github.com/lint-staged/lint-staged) | `15.2.9` | `15.2.10` |
| [turbo](https://github.com/vercel/turborepo) | `2.1.0` | `2.1.1` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `5.4.2` | `5.4.3` |
| [vue](https://github.com/vuejs/core) | `3.4.38` | `3.5.0` |
| [vue-tsc](https://github.com/vuejs/language-tools/tree/HEAD/packages/tsc) | `2.1.2` | `2.1.4` |
| [@iconify/json](https://github.com/iconify/icon-sets) | `2.2.242` | `2.2.243` |
| [postcss](https://github.com/postcss/postcss) | `8.4.41` | `8.4.44` |
| [@jspm/generator](https://github.com/jspm/generator) | `2.1.3` | `2.2.0` |
| [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa) | `0.20.2` | `0.20.3` |
| [vite-plugin-vue-devtools](https://github.com/vuejs/devtools-next/tree/HEAD/packages/vite) | `7.3.9` | `7.4.0` |
| [vite-plugin-dts](https://github.com/qmhc/vite-plugin-dts) | `4.0.3` | `4.1.0` |
| [eslint-config-turbo](https://github.com/vercel/turborepo/tree/HEAD/packages/eslint-config-turbo) | `2.1.0` | `2.1.1` |
| [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.3.0` | `8.4.0` |
| [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.3.0` | `8.4.0` |
| [eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue) | `9.27.0` | `9.28.0` |
| [lucide-vue-next](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next) | `0.436.0` | `0.438.0` |
| [@vue/shared](https://github.com/vuejs/core/tree/HEAD/packages/shared) | `3.4.38` | `3.5.0` |
| [sortablejs](https://github.com/SortableJS/Sortable) | `1.15.2` | `1.15.3` |
| [axios](https://github.com/axios/axios) | `1.7.5` | `1.7.7` |
| [@nolebase/vitepress-plugin-git-changelog](https://github.com/nolebase/integrations/tree/HEAD/packages/vitepress-plugin-git-changelog) | `2.4.0` | `2.5.0` |
| [@vite-pwa/vitepress](https://github.com/vite-pwa/vitepress) | `0.5.0` | `0.5.1` |



Updates `@types/node` from 22.5.1 to 22.5.2
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `lint-staged` from 15.2.9 to 15.2.10
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/master/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v15.2.9...v15.2.10)

Updates `turbo` from 2.1.0 to 2.1.1
- [Release notes](https://github.com/vercel/turborepo/releases)
- [Changelog](https://github.com/vercel/turborepo/blob/main/release.md)
- [Commits](https://github.com/vercel/turborepo/compare/v2.1.0...v2.1.1)

Updates `vite` from 5.4.2 to 5.4.3
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.3/packages/vite)

Updates `vue` from 3.4.38 to 3.5.0
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.4.38...v3.5.0)

Updates `vue-tsc` from 2.1.2 to 2.1.4
- [Release notes](https://github.com/vuejs/language-tools/releases)
- [Changelog](https://github.com/vuejs/language-tools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vuejs/language-tools/commits/v2.1.4/packages/tsc)

Updates `@iconify/json` from 2.2.242 to 2.2.243
- [Commits](https://github.com/iconify/icon-sets/compare/2.2.242...2.2.243)

Updates `postcss` from 8.4.41 to 8.4.44
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.41...8.4.44)

Updates `@jspm/generator` from 2.1.3 to 2.2.0
- [Release notes](https://github.com/jspm/generator/releases)
- [Commits](https://github.com/jspm/generator/compare/2.1.3...2.2.0)

Updates `vite-plugin-pwa` from 0.20.2 to 0.20.3
- [Release notes](https://github.com/vite-pwa/vite-plugin-pwa/releases)
- [Commits](https://github.com/vite-pwa/vite-plugin-pwa/compare/v0.20.2...v0.20.3)

Updates `vite-plugin-vue-devtools` from 7.3.9 to 7.4.0
- [Release notes](https://github.com/vuejs/devtools-next/releases)
- [Commits](https://github.com/vuejs/devtools-next/commits/v7.4.0/packages/vite)

Updates `vite-plugin-dts` from 4.0.3 to 4.1.0
- [Release notes](https://github.com/qmhc/vite-plugin-dts/releases)
- [Changelog](https://github.com/qmhc/vite-plugin-dts/blob/main/CHANGELOG.md)
- [Commits](https://github.com/qmhc/vite-plugin-dts/compare/v4.0.3...v4.1.0)

Updates `eslint-config-turbo` from 2.1.0 to 2.1.1
- [Release notes](https://github.com/vercel/turborepo/releases)
- [Changelog](https://github.com/vercel/turborepo/blob/main/release.md)
- [Commits](https://github.com/vercel/turborepo/commits/v2.1.1/packages/eslint-config-turbo)

Updates `@typescript-eslint/eslint-plugin` from 8.3.0 to 8.4.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.4.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.3.0 to 8.4.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.4.0/packages/parser)

Updates `eslint-plugin-vue` from 9.27.0 to 9.28.0
- [Release notes](https://github.com/vuejs/eslint-plugin-vue/releases)
- [Commits](https://github.com/vuejs/eslint-plugin-vue/compare/v9.27.0...v9.28.0)

Updates `lucide-vue-next` from 0.436.0 to 0.438.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.438.0/packages/lucide-vue-next)

Updates `@vue/shared` from 3.4.38 to 3.5.0
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/commits/v3.5.0/packages/shared)

Updates `sortablejs` from 1.15.2 to 1.15.3
- [Release notes](https://github.com/SortableJS/Sortable/releases)
- [Commits](https://github.com/SortableJS/Sortable/compare/1.15.2...1.15.3)

Updates `axios` from 1.7.5 to 1.7.7
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.7.5...v1.7.7)

Updates `@nolebase/vitepress-plugin-git-changelog` from 2.4.0 to 2.5.0
- [Release notes](https://github.com/nolebase/integrations/releases)
- [Commits](https://github.com/nolebase/integrations/commits/v2.5.0/packages/vitepress-plugin-git-changelog)

Updates `@vite-pwa/vitepress` from 0.5.0 to 0.5.1
- [Release notes](https://github.com/vite-pwa/vitepress/releases)
- [Commits](https://github.com/vite-pwa/vitepress/compare/v0.5.0...v0.5.1)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: turbo
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vite
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vue
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: vue-tsc
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@iconify/json"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: postcss
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@jspm/generator"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: vite-plugin-pwa
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vite-plugin-vue-devtools
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: vite-plugin-dts
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: eslint-config-turbo
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: eslint-plugin-vue
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: lucide-vue-next
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@vue/shared"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: sortablejs
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@nolebase/vitepress-plugin-git-changelog"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@vite-pwa/vitepress"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: update deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-04 22:57:31 +08:00
wangxiaoer5200
3332b20fd0 docs: typo (#4309) (#4315) 2024-09-04 13:56:45 +08:00
afe1
2d0153a841 chore: the sidebar title is not displayed in mobile mode (#4312) 2024-09-04 09:56:37 +08:00
invalid w
95a4a85c3b chore(@vben-core/tabs-ui): cancel drag and drop function on mobile devices (#4303)
resolve  #4301
2024-09-03 13:02:19 +08:00
Vben
3f2dcb8281 fix(@vben/web-ele): fixed some style issues in dark mode (#4298) 2024-09-01 22:33:11 +08:00
afe1
67f3d63066 fix: the fixedbutton changes state and the view cannot scroll (#4297)
* fix: change fixbutton content can't scroll

* fix: change fixbutton content can't scroll
2024-09-01 16:15:21 +08:00
vben
277e98c42c style: improve loading overlay in dark display 2024-08-31 23:23:35 +08:00
vben
1063b2268e chore: release v5.2.1 2024-08-31 21:55:10 +08:00
Vben
8404c12129 refactor: refactor AuthLayout to configure the login page more freely (#4294) 2024-08-31 21:38:24 +08:00
afe1
a7d322019e style: optimize dashboard in small screen styles and demo (#4293) 2024-08-31 21:24:48 +08:00
Li Kui
f23821ff46 fix: redundant border on the sidebar in two column layout mode (#4291) 2024-08-31 17:37:37 +08:00
Vben
2b0aedbaba style: optimizing style issues (#4289) 2024-08-31 14:11:01 +08:00
afe1
071cc0dcec style: optimize dashboard in small screen styles (#4288)
Co-authored-by: afe1 <yunfei.zhu@nwowtec.com>
2024-08-31 13:06:53 +08:00
dependabot[bot]
7db7d6ec5f chore(deps): bump the non-breaking-changes group with 5 updates (#4285)
Bumps the non-breaking-changes group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue) | `5.1.2` | `5.1.3` |
| [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa) | `0.20.1` | `0.20.2` |
| [rollup](https://github.com/rollup/rollup) | `4.21.1` | `4.21.2` |
| [eslint-plugin-import-x](https://github.com/un-ts/eslint-plugin-import-x) | `4.1.0` | `4.1.1` |
| [watermark-js-plus](https://github.com/zhensherlock/watermark-js-plus) | `1.5.3` | `1.5.4` |


Updates `@vitejs/plugin-vue` from 5.1.2 to 5.1.3
- [Release notes](https://github.com/vitejs/vite-plugin-vue/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-vue/commits/plugin-vue@5.1.3/packages/plugin-vue)

Updates `vite-plugin-pwa` from 0.20.1 to 0.20.2
- [Release notes](https://github.com/vite-pwa/vite-plugin-pwa/releases)
- [Commits](https://github.com/vite-pwa/vite-plugin-pwa/compare/v0.20.1...v0.20.2)

Updates `rollup` from 4.21.1 to 4.21.2
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.21.1...v4.21.2)

Updates `eslint-plugin-import-x` from 4.1.0 to 4.1.1
- [Release notes](https://github.com/un-ts/eslint-plugin-import-x/releases)
- [Changelog](https://github.com/un-ts/eslint-plugin-import-x/blob/master/CHANGELOG.md)
- [Commits](https://github.com/un-ts/eslint-plugin-import-x/compare/v4.1.0...v4.1.1)

Updates `watermark-js-plus` from 1.5.3 to 1.5.4
- [Release notes](https://github.com/zhensherlock/watermark-js-plus/releases)
- [Changelog](https://github.com/zhensherlock/watermark-js-plus/blob/main/CHANGELOG.md)
- [Commits](https://github.com/zhensherlock/watermark-js-plus/compare/v1.5.3...v1.5.4)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-vue"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vite-plugin-pwa
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: eslint-plugin-import-x
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: watermark-js-plus
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-31 07:38:40 +08:00
Vben
b3e3e05990 perf: axios default error interceptor allows you to customize error handling (#4283) 2024-08-30 22:06:02 +08:00
handsomeFu
cc678a2b51 fix: ensure left panel element spans full width on small screens (#4281) 2024-08-30 21:33:02 +08:00
dependabot[bot]
7d2bcf476f chore(deps): bump the non-breaking-changes group with 2 updates (#4275)
Bumps the non-breaking-changes group with 2 updates: [vue-tsc](https://github.com/vuejs/language-tools/tree/HEAD/packages/tsc) and [pinia-plugin-persistedstate](https://github.com/prazdevs/pinia-plugin-persistedstate).


Updates `vue-tsc` from 2.0.29 to 2.1.2
- [Release notes](https://github.com/vuejs/language-tools/releases)
- [Changelog](https://github.com/vuejs/language-tools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vuejs/language-tools/commits/v2.1.2/packages/tsc)

Updates `pinia-plugin-persistedstate` from 3.2.1 to 3.2.3
- [Release notes](https://github.com/prazdevs/pinia-plugin-persistedstate/releases)
- [Commits](https://github.com/prazdevs/pinia-plugin-persistedstate/compare/v3.2.1...v3.2.3)

---
updated-dependencies:
- dependency-name: vue-tsc
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: pinia-plugin-persistedstate
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-30 13:47:18 +08:00
handsomeFu
cfbe379ee4 fix: correct button layout in English locale (#4277)
Co-authored-by: vince <vince292007@gmail.com>
2024-08-30 13:36:36 +08:00
afe1
388e5b5cb3 update vscode config (#4274)
Co-authored-by: vince <vince292007@gmail.com>
2024-08-30 13:34:32 +08:00
vince
c1dfbc1ebf fix: ci error [skip ci] (#4280) 2024-08-30 13:08:24 +08:00
377 changed files with 9179 additions and 4146 deletions

16
.github/labeler.yml vendored
View File

@@ -1,16 +0,0 @@
# Add 'feature' label to any PR where the head branch name starts with `feature` or has a `feature` section in the name
feature:
- head-branch: ["^feat", "feat"]
bug:
- head-branch: ["^fix", "fix"]
chore:
- head-branch: ["^chore", "chore"]
perf:
- head-branch: ["^perf", "perf"]
documentation:
- changed-files:
- any-glob-to-any-file: ["**/*.md", "docs/**"]

View File

@@ -1,22 +0,0 @@
name: PR Labeler
on:
pull_request:
types: [opened, edited, synchronize]
jobs:
label:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Label PR based on title or file changes
uses: actions/labeler@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/labeler.yml

View File

@@ -1,28 +0,0 @@
ls:
.js: kebab-case | pointcase
.vue: kebab-case | pointcase
.ts: kebab-case | pointcase
.tsx: kebab-case | pointcase
.jsx: kebab-case | pointcase
.css: kebab-case | pointcase
.d.ts: kebab-case | pointcase
# shadcn 自动生成文件为 PascalCase 格式
packages/@core/ui-kit/shadcn-ui/src/components/ui:
.vue: PascalCase
ignore:
- "**/*.png"
- "**/*.jpg"
- "**/*.jpeg"
- "**/*.jpeg"
- "**/*.gif"
- "**/_util.ts"
- "**/deps/**"
- "**/dist/**"
- "**/node_modules/**"
- "**/.turbo/**"
- .git
- .vscode
- .idea
- node_modules
- .cache

8
.vscode/launch.json vendored
View File

@@ -9,7 +9,7 @@
"url": "http://localhost:5555",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}/playground/src"
"webRoot": "${workspaceFolder}"
},
{
"type": "chrome",
@@ -18,7 +18,7 @@
"url": "http://localhost:5666",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}/apps/web-antd/src"
"webRoot": "${workspaceFolder}"
},
{
"type": "chrome",
@@ -27,7 +27,7 @@
"url": "http://localhost:5777",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}/apps/web-ele/src"
"webRoot": "${workspaceFolder}"
},
{
"type": "chrome",
@@ -36,7 +36,7 @@
"url": "http://localhost:5888",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}/apps/web-naive/src"
"webRoot": "${workspaceFolder}"
}
]
}

View File

@@ -213,7 +213,7 @@
"README.md": "README*,CHANGELOG*,LICENSE,CNAME",
"package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,.gitattributes,.gitignore,.gitpod.yml,.npmrc,.browserslistrc,.node-version,.git*,.tazerc.json",
"Dockerfile": "Dockerfile,.docker*,docker-entrypoint.sh,build-local-docker*,nginx.conf",
"eslint.config.mjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,stylelint.config.*,.lintstagedrc.mjs,.ls-lint*,cspell.json",
"eslint.config.mjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,stylelint.config.*,.lintstagedrc.mjs,cspell.json",
"tailwind.config.mjs": "postcss.*"
},
"commentTranslate.hover.enabled": false,

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/web-antd",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"homepage": "https://vben.pro",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -44,7 +44,7 @@
"ant-design-vue": "^4.2.3",
"dayjs": "^1.11.13",
"pinia": "2.2.2",
"vue": "^3.4.38",
"vue": "^3.5.4",
"vue-router": "^4.4.3"
}
}

View File

@@ -0,0 +1,114 @@
import type {
BaseFormComponentType,
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import { h } from 'vue';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import {
AutoComplete,
Button,
Checkbox,
CheckboxGroup,
DatePicker,
Divider,
Input,
InputNumber,
InputPassword,
Mentions,
Radio,
RadioGroup,
RangePicker,
Rate,
Select,
Space,
Switch,
TimePicker,
TreeSelect,
Upload,
} from 'ant-design-vue';
// 业务表单组件适配
export type FormComponentType =
| 'AutoComplete'
| 'Checkbox'
| 'CheckboxGroup'
| 'DatePicker'
| 'Divider'
| 'Input'
| 'InputNumber'
| 'InputPassword'
| 'Mentions'
| 'Radio'
| 'RadioGroup'
| 'RangePicker'
| 'Rate'
| 'Select'
| 'Space'
| 'Switch'
| 'TimePicker'
| 'TreeSelect'
| 'Upload'
| BaseFormComponentType;
// 初始化表单组件并注册到form组件内部
setupVbenForm<FormComponentType>({
components: {
AutoComplete,
Checkbox,
CheckboxGroup,
DatePicker,
// 自定义默认的重置按钮
DefaultResetActionButton: (props, { attrs, slots }) => {
return h(Button, { ...props, attrs, type: 'default' }, slots);
},
// 自定义默认的提交按钮
DefaultSubmitActionButton: (props, { attrs, slots }) => {
return h(Button, { ...props, attrs, type: 'primary' }, slots);
},
Divider,
Input,
InputNumber,
InputPassword,
Mentions,
Radio,
RadioGroup,
RangePicker,
Rate,
Select,
Space,
Switch,
TimePicker,
TreeSelect,
Upload,
},
config: {
baseModelPropName: 'value',
modelPropNameMap: {
Checkbox: 'checked',
Radio: 'checked',
Switch: 'checked',
Upload: 'fileList',
},
},
defineRules: {
required: (value, _params, ctx) => {
if ((!value && value !== 0) || value.length === 0) {
return $t('formRules.required', [ctx.label]);
}
return true;
},
},
});
const useVbenForm = useForm<FormComponentType>;
export { useVbenForm, z };
export type VbenFormSchema = FormSchema<FormComponentType>;
export type { VbenFormProps };

View File

@@ -0,0 +1 @@
export * from './form';

View File

@@ -0,0 +1,23 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { AuthPageLayout } from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { $t } from '#/locales';
const appName = computed(() => preferences.app.name);
const logo = computed(() => preferences.logo.source);
</script>
<template>
<AuthPageLayout
:app-name="appName"
:logo="logo"
:page-description="$t('authentication.pageDesc')"
:page-title="$t('authentication.pageTitle')"
>
<!-- 自定义工具栏 -->
<!-- <template #toolbar></template> -->
</AuthPageLayout>
</template>

View File

@@ -13,11 +13,12 @@ import {
UserDropdown,
} from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { storeToRefs, useAccessStore, useUserStore } from '@vben/stores';
import { useAccessStore, useUserStore } from '@vben/stores';
import { openWindow } from '@vben/utils';
import { $t } from '#/locales';
import { useAuthStore } from '#/store';
import LoginForm from '#/views/_core/authentication/login.vue';
const notifications = ref<NotificationItem[]>([
{
@@ -87,8 +88,6 @@ const menus = computed(() => [
},
]);
const { loginLoading } = storeToRefs(authStore);
const avatar = computed(() => {
return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
});
@@ -130,11 +129,9 @@ function handleMakeAll() {
<AuthenticationLoginExpiredModal
v-model:open="accessStore.loginExpired"
:avatar
:loading="loginLoading"
password-placeholder="123456"
username-placeholder="vben"
@submit="authStore.authLogin"
/>
>
<LoginForm />
</AuthenticationLoginExpiredModal>
</template>
<template #lock-screen>
<LockScreen :avatar @to-login="handleLogout" />

View File

@@ -1,8 +1,6 @@
const BasicLayout = () => import('./basic.vue');
const AuthPageLayout = () => import('./auth.vue');
const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
const AuthPageLayout = () =>
import('@vben/layouts').then((m) => m.AuthPageLayout);
export { AuthPageLayout, BasicLayout, IFrameView };

View File

@@ -1,15 +1,49 @@
<script lang="ts" setup>
import type { LoginCodeParams } from '@vben/common-ui';
import type { LoginCodeParams, VbenFormSchema } from '@vben/common-ui';
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { AuthenticationCodeLogin } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
import { AuthenticationCodeLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
defineOptions({ name: 'CodeLogin' });
const loading = ref(false);
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
placeholder: $t('authentication.mobile'),
},
fieldName: 'phoneNumber',
label: $t('authentication.mobile'),
rules: z
.string()
.min(1, { message: $t('authentication.mobileTip') })
.refine((v) => /^\d{11}$/.test(v), {
message: $t('authentication.mobileErrortip'),
}),
},
{
component: 'VbenPinInput',
componentProps: {
createText: (countdown: number) => {
const text =
countdown > 0
? $t('authentication.sendText', [countdown])
: $t('authentication.sendCode');
return text;
},
placeholder: $t('authentication.code'),
},
fieldName: 'code',
label: $t('authentication.code'),
rules: z.string().min(1, { message: $t('authentication.codeTip') }),
},
];
});
/**
* 异步处理登录操作
* Asynchronously handle the login process
@@ -23,8 +57,8 @@ async function handleLogin(values: LoginCodeParams) {
<template>
<AuthenticationCodeLogin
:form-schema="formSchema"
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleLogin"
/>
</template>

View File

@@ -1,13 +1,32 @@
<script lang="ts" setup>
import { ref } from 'vue';
import type { VbenFormSchema } from '@vben/common-ui';
import { AuthenticationForgetPassword } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
import { computed, ref } from 'vue';
import { AuthenticationForgetPassword, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
defineOptions({ name: 'ForgetPassword' });
const loading = ref(false);
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
placeholder: 'example@example.com',
},
fieldName: 'email',
label: $t('authentication.email'),
rules: z
.string()
.min(1, { message: $t('authentication.emailTip') })
.email($t('authentication.emailValidErrorTip')),
},
];
});
function handleSubmit(value: string) {
// eslint-disable-next-line no-console
console.log('reset email:', value);
@@ -16,8 +35,8 @@ function handleSubmit(value: string) {
<template>
<AuthenticationForgetPassword
:form-schema="formSchema"
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@@ -1,18 +1,91 @@
<script lang="ts" setup>
import { AuthenticationLogin } from '@vben/common-ui';
import type { VbenFormSchema } from '@vben/common-ui';
import type { BasicOption } from '@vben/types';
import { computed } from 'vue';
import { AuthenticationLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useAuthStore } from '#/store';
defineOptions({ name: 'Login' });
const authStore = useAuthStore();
const MOCK_USER_OPTIONS: BasicOption[] = [
{
label: '超级管理员',
value: 'vben',
},
{
label: '管理员',
value: 'admin',
},
{
label: '用户',
value: 'jack',
},
];
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenSelect',
componentProps: {
options: MOCK_USER_OPTIONS,
placeholder: $t('authentication.selectAccount'),
},
fieldName: 'selectAccount',
label: $t('authentication.selectAccount'),
rules: z
.string()
.min(1, { message: $t('authentication.selectAccount') })
.optional()
.default('vben'),
},
{
component: 'VbenInput',
componentProps: {
placeholder: $t('authentication.usernameTip'),
},
dependencies: {
trigger(values, form) {
if (values.selectAccount) {
const findUser = MOCK_USER_OPTIONS.find(
(item) => item.value === values.selectAccount,
);
if (findUser) {
form.setValues({
password: '123456',
username: findUser.value,
});
}
}
},
triggerFields: ['selectAccount'],
},
fieldName: 'username',
label: $t('authentication.username'),
rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
placeholder: $t('authentication.password'),
},
fieldName: 'password',
label: $t('authentication.password'),
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
];
});
</script>
<template>
<AuthenticationLogin
:form-schema="formSchema"
:loading="authStore.loginLoading"
password-placeholder="123456"
username-placeholder="vben"
@submit="authStore.authLogin"
/>
</template>

View File

@@ -1,15 +1,91 @@
<script lang="ts" setup>
import type { LoginAndRegisterParams } from '@vben/common-ui';
import type { LoginAndRegisterParams, VbenFormSchema } from '@vben/common-ui';
import { ref } from 'vue';
import { computed, h, ref } from 'vue';
import { AuthenticationRegister } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
import { AuthenticationRegister, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
defineOptions({ name: 'Register' });
const loading = ref(false);
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
placeholder: $t('authentication.usernameTip'),
},
fieldName: 'username',
label: $t('authentication.username'),
rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
passwordStrength: true,
placeholder: $t('authentication.password'),
},
fieldName: 'password',
label: $t('authentication.password'),
renderComponentContent() {
return {
strengthText: () => $t('authentication.passwordStrength'),
};
},
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
placeholder: $t('authentication.confirmPassword'),
},
dependencies: {
rules(values) {
const { password } = values;
return z
.string()
.min(1, { message: $t('authentication.passwordTip') })
.refine((value) => value === password, {
message: $t('authentication.confirmPasswordTip'),
});
},
triggerFields: ['password'],
},
fieldName: 'confirmPassword',
label: $t('authentication.confirmPassword'),
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
{
component: 'VbenCheckbox',
fieldName: 'agreePolicy',
renderComponentContent: () => ({
default: () =>
h('span', [
$t('authentication.agree'),
h(
'a',
{
class:
'cursor-pointer text-primary ml-1 hover:text-primary-hover',
href: '',
},
[
$t('authentication.privacyPolicy'),
'&',
$t('authentication.terms'),
],
),
]),
}),
rules: z.boolean().refine((value) => !!value, {
message: $t('authentication.agreeTip'),
}),
},
];
});
function handleSubmit(value: LoginAndRegisterParams) {
// eslint-disable-next-line no-console
console.log('register submit:', value);
@@ -18,8 +94,8 @@ function handleSubmit(value: LoginAndRegisterParams) {
<template>
<AuthenticationRegister
:form-schema="formSchema"
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@@ -55,12 +55,27 @@ onMounted(() => {
},
trigger: 'axis',
},
// xAxis: {
// axisTick: {
// show: false,
// },
// boundaryGap: false,
// data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
// type: 'category',
// },
xAxis: {
axisTick: {
show: false,
},
boundaryGap: false,
data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
splitLine: {
lineStyle: {
type: 'solid',
width: 1,
},
show: true,
},
type: 'category',
},
yAxis: [
@@ -69,7 +84,10 @@ onMounted(() => {
show: false,
},
max: 80_000,
splitArea: {
show: true,
},
splitNumber: 4,
type: 'value',
},
],

View File

@@ -214,7 +214,11 @@ const trendItems: WorkbenchTrendItem[] = [
<WorkbenchTrends :items="trendItems" class="mt-5" title="最新动态" />
</div>
<div class="w-full lg:w-2/5">
<WorkbenchQuickNav :items="quickNavItems" title="快捷导航" />
<WorkbenchQuickNav
:items="quickNavItems"
class="mt-5 lg:mt-0"
title="快捷导航"
/>
<WorkbenchTodo :items="todoItems" class="mt-5" title="待办事项" />
<AnalysisChartCard class="mt-5" title="访问来源">
<AnalyticsVisitsSource />

View File

@@ -37,7 +37,7 @@ function notify(type: NotificationType) {
description="支持多语言,主题功能集成切换等"
title="Ant Design Vue组件使用演示"
>
<Card title="按钮">
<Card class="mb-5" title="按钮">
<Space>
<Button>Default</Button>
<Button type="primary"> Primary </Button>

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/web-ele",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"homepage": "https://vben.pro",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -42,9 +42,9 @@
"@vben/utils": "workspace:*",
"@vueuse/core": "^11.0.3",
"dayjs": "^1.11.13",
"element-plus": "^2.8.1",
"element-plus": "^2.8.2",
"pinia": "2.2.2",
"vue": "^3.4.38",
"vue": "^3.5.4",
"vue-router": "^4.4.3"
},
"devDependencies": {

View File

@@ -0,0 +1,89 @@
import type {
BaseFormComponentType,
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import { h } from 'vue';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import {
ElButton,
ElCheckbox,
ElCheckboxGroup,
ElDivider,
ElInput,
ElInputNumber,
ElRadioGroup,
ElSelect,
ElSpace,
ElSwitch,
ElTimePicker,
ElTreeSelect,
ElUpload,
} from 'element-plus';
// 业务表单组件适配
export type FormComponentType =
| 'Checkbox'
| 'CheckboxGroup'
| 'DatePicker'
| 'Divider'
| 'Input'
| 'InputNumber'
| 'RadioGroup'
| 'Select'
| 'Space'
| 'Switch'
| 'TimePicker'
| 'TreeSelect'
| 'Upload'
| BaseFormComponentType;
// 初始化表单组件并注册到form组件内部
setupVbenForm<FormComponentType>({
components: {
Checkbox: ElCheckbox,
CheckboxGroup: ElCheckboxGroup,
// 自定义默认的重置按钮
DefaultResetActionButton: (props, { attrs, slots }) => {
return h(ElButton, { ...props, attrs, type: 'info' }, slots);
},
// 自定义默认的提交按钮
DefaultSubmitActionButton: (props, { attrs, slots }) => {
return h(ElButton, { ...props, attrs, type: 'primary' }, slots);
},
Divider: ElDivider,
Input: ElInput,
InputNumber: ElInputNumber,
RadioGroup: ElRadioGroup,
Select: ElSelect,
Space: ElSpace,
Switch: ElSwitch,
TimePicker: ElTimePicker,
TreeSelect: ElTreeSelect,
Upload: ElUpload,
},
config: {
modelPropNameMap: {
Upload: 'fileList',
},
},
defineRules: {
required: (value, _params, ctx) => {
if ((!value && value !== 0) || value.length === 0) {
return $t('formRules.required', [ctx.label]);
}
return true;
},
},
});
const useVbenForm = useForm<FormComponentType>;
export { useVbenForm, z };
export type VbenFormSchema = FormSchema<FormComponentType>;
export type { VbenFormProps };

View File

@@ -0,0 +1 @@
export * from './form';

View File

@@ -0,0 +1,23 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { AuthPageLayout } from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { $t } from '#/locales';
const appName = computed(() => preferences.app.name);
const logo = computed(() => preferences.logo.source);
</script>
<template>
<AuthPageLayout
:app-name="appName"
:logo="logo"
:page-description="$t('authentication.pageDesc')"
:page-title="$t('authentication.pageTitle')"
>
<!-- 自定义工具栏 -->
<!-- <template #toolbar></template> -->
</AuthPageLayout>
</template>

View File

@@ -13,11 +13,12 @@ import {
UserDropdown,
} from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { storeToRefs, useAccessStore, useUserStore } from '@vben/stores';
import { useAccessStore, useUserStore } from '@vben/stores';
import { openWindow } from '@vben/utils';
import { $t } from '#/locales';
import { useAuthStore } from '#/store';
import LoginForm from '#/views/_core/authentication/login.vue';
const notifications = ref<NotificationItem[]>([
{
@@ -87,8 +88,6 @@ const menus = computed(() => [
},
]);
const { loginLoading } = storeToRefs(authStore);
const avatar = computed(() => {
return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
});
@@ -130,11 +129,9 @@ function handleMakeAll() {
<AuthenticationLoginExpiredModal
v-model:open="accessStore.loginExpired"
:avatar
:loading="loginLoading"
password-placeholder="123456"
username-placeholder="vben"
@submit="authStore.authLogin"
/>
>
<LoginForm />
</AuthenticationLoginExpiredModal>
</template>
<template #lock-screen>
<LockScreen :avatar @to-login="handleLogout" />

View File

@@ -1,8 +1,6 @@
const BasicLayout = () => import('./basic.vue');
const AuthPageLayout = () => import('./auth.vue');
const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
const AuthPageLayout = () =>
import('@vben/layouts').then((m) => m.AuthPageLayout);
export { AuthPageLayout, BasicLayout, IFrameView };

View File

@@ -1,15 +1,49 @@
<script lang="ts" setup>
import type { LoginCodeParams } from '@vben/common-ui';
import type { LoginCodeParams, VbenFormSchema } from '@vben/common-ui';
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { AuthenticationCodeLogin } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
import { AuthenticationCodeLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
defineOptions({ name: 'CodeLogin' });
const loading = ref(false);
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
placeholder: $t('authentication.mobile'),
},
fieldName: 'phoneNumber',
label: $t('authentication.mobile'),
rules: z
.string()
.min(1, { message: $t('authentication.mobileTip') })
.refine((v) => /^\d{11}$/.test(v), {
message: $t('authentication.mobileErrortip'),
}),
},
{
component: 'VbenPinInput',
componentProps: {
createText: (countdown: number) => {
const text =
countdown > 0
? $t('authentication.sendText', [countdown])
: $t('authentication.sendCode');
return text;
},
placeholder: $t('authentication.code'),
},
fieldName: 'code',
label: $t('authentication.code'),
rules: z.string().min(1, { message: $t('authentication.codeTip') }),
},
];
});
/**
* 异步处理登录操作
* Asynchronously handle the login process
@@ -23,8 +57,8 @@ async function handleLogin(values: LoginCodeParams) {
<template>
<AuthenticationCodeLogin
:form-schema="formSchema"
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleLogin"
/>
</template>

View File

@@ -1,13 +1,32 @@
<script lang="ts" setup>
import { ref } from 'vue';
import type { VbenFormSchema } from '@vben/common-ui';
import { AuthenticationForgetPassword } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
import { computed, ref } from 'vue';
import { AuthenticationForgetPassword, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
defineOptions({ name: 'ForgetPassword' });
const loading = ref(false);
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
placeholder: 'example@example.com',
},
fieldName: 'email',
label: $t('authentication.email'),
rules: z
.string()
.min(1, { message: $t('authentication.emailTip') })
.email($t('authentication.emailValidErrorTip')),
},
];
});
function handleSubmit(value: string) {
// eslint-disable-next-line no-console
console.log('reset email:', value);
@@ -16,8 +35,8 @@ function handleSubmit(value: string) {
<template>
<AuthenticationForgetPassword
:form-schema="formSchema"
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@@ -1,18 +1,91 @@
<script lang="ts" setup>
import { AuthenticationLogin } from '@vben/common-ui';
import type { VbenFormSchema } from '@vben/common-ui';
import type { BasicOption } from '@vben/types';
import { computed } from 'vue';
import { AuthenticationLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useAuthStore } from '#/store';
defineOptions({ name: 'Login' });
const authStore = useAuthStore();
const MOCK_USER_OPTIONS: BasicOption[] = [
{
label: '超级管理员',
value: 'vben',
},
{
label: '管理员',
value: 'admin',
},
{
label: '用户',
value: 'jack',
},
];
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenSelect',
componentProps: {
options: MOCK_USER_OPTIONS,
placeholder: $t('authentication.selectAccount'),
},
fieldName: 'selectAccount',
label: $t('authentication.selectAccount'),
rules: z
.string()
.min(1, { message: $t('authentication.selectAccount') })
.optional()
.default('vben'),
},
{
component: 'VbenInput',
componentProps: {
placeholder: $t('authentication.usernameTip'),
},
dependencies: {
trigger(values, form) {
if (values.selectAccount) {
const findUser = MOCK_USER_OPTIONS.find(
(item) => item.value === values.selectAccount,
);
if (findUser) {
form.setValues({
password: '123456',
username: findUser.value,
});
}
}
},
triggerFields: ['selectAccount'],
},
fieldName: 'username',
label: $t('authentication.username'),
rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
placeholder: $t('authentication.password'),
},
fieldName: 'password',
label: $t('authentication.password'),
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
];
});
</script>
<template>
<AuthenticationLogin
:form-schema="formSchema"
:loading="authStore.loginLoading"
password-placeholder="123456"
username-placeholder="vben"
@submit="authStore.authLogin"
/>
</template>

View File

@@ -1,15 +1,91 @@
<script lang="ts" setup>
import type { LoginAndRegisterParams } from '@vben/common-ui';
import type { LoginAndRegisterParams, VbenFormSchema } from '@vben/common-ui';
import { ref } from 'vue';
import { computed, h, ref } from 'vue';
import { AuthenticationRegister } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
import { AuthenticationRegister, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
defineOptions({ name: 'Register' });
const loading = ref(false);
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
placeholder: $t('authentication.usernameTip'),
},
fieldName: 'username',
label: $t('authentication.username'),
rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
passwordStrength: true,
placeholder: $t('authentication.password'),
},
fieldName: 'password',
label: $t('authentication.password'),
renderComponentContent() {
return {
strengthText: () => $t('authentication.passwordStrength'),
};
},
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
placeholder: $t('authentication.confirmPassword'),
},
dependencies: {
rules(values) {
const { password } = values;
return z
.string()
.min(1, { message: $t('authentication.passwordTip') })
.refine((value) => value === password, {
message: $t('authentication.confirmPasswordTip'),
});
},
triggerFields: ['password'],
},
fieldName: 'confirmPassword',
label: $t('authentication.confirmPassword'),
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
{
component: 'VbenCheckbox',
fieldName: 'agreePolicy',
renderComponentContent: () => ({
default: () =>
h('span', [
$t('authentication.agree'),
h(
'a',
{
class:
'cursor-pointer text-primary ml-1 hover:text-primary-hover',
href: '',
},
[
$t('authentication.privacyPolicy'),
'&',
$t('authentication.terms'),
],
),
]),
}),
rules: z.boolean().refine((value) => !!value, {
message: $t('authentication.agreeTip'),
}),
},
];
});
function handleSubmit(value: LoginAndRegisterParams) {
// eslint-disable-next-line no-console
console.log('register submit:', value);
@@ -18,8 +94,8 @@ function handleSubmit(value: LoginAndRegisterParams) {
<template>
<AuthenticationRegister
:form-schema="formSchema"
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@@ -55,12 +55,27 @@ onMounted(() => {
},
trigger: 'axis',
},
// xAxis: {
// axisTick: {
// show: false,
// },
// boundaryGap: false,
// data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
// type: 'category',
// },
xAxis: {
axisTick: {
show: false,
},
boundaryGap: false,
data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
splitLine: {
lineStyle: {
type: 'solid',
width: 1,
},
show: true,
},
type: 'category',
},
yAxis: [
@@ -69,7 +84,10 @@ onMounted(() => {
show: false,
},
max: 80_000,
splitArea: {
show: true,
},
splitNumber: 4,
type: 'value',
},
],

View File

@@ -214,7 +214,11 @@ const trendItems: WorkbenchTrendItem[] = [
<WorkbenchTrends :items="trendItems" class="mt-5" title="最新动态" />
</div>
<div class="w-full lg:w-2/5">
<WorkbenchQuickNav :items="quickNavItems" title="快捷导航" />
<WorkbenchQuickNav
:items="quickNavItems"
class="mt-5 lg:mt-0"
title="快捷导航"
/>
<WorkbenchTodo :items="todoItems" class="mt-5" title="待办事项" />
<AnalysisChartCard class="mt-5" title="访问来源">
<AnalyticsVisitsSource />

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/web-naive",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"homepage": "https://vben.pro",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -43,7 +43,7 @@
"@vueuse/core": "^11.0.3",
"naive-ui": "^2.39.0",
"pinia": "2.2.2",
"vue": "^3.4.38",
"vue": "^3.5.4",
"vue-router": "^4.4.3"
}
}

View File

@@ -0,0 +1,98 @@
import type {
BaseFormComponentType,
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import { h } from 'vue';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import {
NButton,
NCheckbox,
NCheckboxGroup,
NDatePicker,
NDivider,
NInput,
NInputNumber,
NRadioGroup,
NSelect,
NSpace,
NSwitch,
NTimePicker,
NTreeSelect,
NUpload,
} from 'naive-ui';
// 业务表单组件适配
export type FormComponentType =
| 'Checkbox'
| 'CheckboxGroup'
| 'DatePicker'
| 'Divider'
| 'Input'
| 'InputNumber'
| 'RadioGroup'
| 'Select'
| 'Space'
| 'Switch'
| 'TimePicker'
| 'TreeSelect'
| 'Upload'
| BaseFormComponentType;
// 初始化表单组件并注册到form组件内部
setupVbenForm<FormComponentType>({
components: {
Checkbox: NCheckbox,
CheckboxGroup: NCheckboxGroup,
DatePicker: NDatePicker,
// 自定义默认的重置按钮
DefaultResetActionButton: (props, { attrs, slots }) => {
return h(NButton, { ...props, attrs, text: false, type: 'info' }, slots);
},
// 自定义默认的提交按钮
DefaultSubmitActionButton: (props, { attrs, slots }) => {
return h(
NButton,
{ ...props, attrs, text: false, type: 'primary' },
slots,
);
},
Divider: NDivider,
Input: NInput,
InputNumber: NInputNumber,
RadioGroup: NRadioGroup,
Select: NSelect,
Space: NSpace,
Switch: NSwitch,
TimePicker: NTimePicker,
TreeSelect: NTreeSelect,
Upload: NUpload,
},
config: {
baseModelPropName: 'value',
modelPropNameMap: {
Checkbox: 'checked',
Radio: 'checked',
Upload: 'fileList',
},
},
defineRules: {
required: (value, _params, ctx) => {
if ((!value && value !== 0) || value.length === 0) {
return $t('formRules.required', [ctx.label]);
}
return true;
},
},
});
const useVbenForm = useForm<FormComponentType>;
export { useVbenForm, z };
export type VbenFormSchema = FormSchema<FormComponentType>;
export type { VbenFormProps };

View File

@@ -0,0 +1 @@
export * from './form';

View File

@@ -0,0 +1,23 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { AuthPageLayout } from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { $t } from '#/locales';
const appName = computed(() => preferences.app.name);
const logo = computed(() => preferences.logo.source);
</script>
<template>
<AuthPageLayout
:app-name="appName"
:logo="logo"
:page-description="$t('authentication.pageDesc')"
:page-title="$t('authentication.pageTitle')"
>
<!-- 自定义工具栏 -->
<!-- <template #toolbar></template> -->
</AuthPageLayout>
</template>

View File

@@ -13,11 +13,12 @@ import {
UserDropdown,
} from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { storeToRefs, useAccessStore, useUserStore } from '@vben/stores';
import { useAccessStore, useUserStore } from '@vben/stores';
import { openWindow } from '@vben/utils';
import { $t } from '#/locales';
import { useAuthStore } from '#/store';
import LoginForm from '#/views/_core/authentication/login.vue';
const notifications = ref<NotificationItem[]>([
{
@@ -87,8 +88,6 @@ const menus = computed(() => [
},
]);
const { loginLoading } = storeToRefs(authStore);
const avatar = computed(() => {
return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
});
@@ -130,11 +129,9 @@ function handleMakeAll() {
<AuthenticationLoginExpiredModal
v-model:open="accessStore.loginExpired"
:avatar
:loading="loginLoading"
password-placeholder="123456"
username-placeholder="vben"
@submit="authStore.authLogin"
/>
>
<LoginForm />
</AuthenticationLoginExpiredModal>
</template>
<template #lock-screen>
<LockScreen :avatar @to-login="handleLogout" />

View File

@@ -1,8 +1,6 @@
const BasicLayout = () => import('./basic.vue');
const AuthPageLayout = () => import('./auth.vue');
const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
const AuthPageLayout = () =>
import('@vben/layouts').then((m) => m.AuthPageLayout);
export { AuthPageLayout, BasicLayout, IFrameView };

View File

@@ -1,15 +1,49 @@
<script lang="ts" setup>
import type { LoginCodeParams } from '@vben/common-ui';
import type { LoginCodeParams, VbenFormSchema } from '@vben/common-ui';
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { AuthenticationCodeLogin } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
import { AuthenticationCodeLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
defineOptions({ name: 'CodeLogin' });
const loading = ref(false);
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
placeholder: $t('authentication.mobile'),
},
fieldName: 'phoneNumber',
label: $t('authentication.mobile'),
rules: z
.string()
.min(1, { message: $t('authentication.mobileTip') })
.refine((v) => /^\d{11}$/.test(v), {
message: $t('authentication.mobileErrortip'),
}),
},
{
component: 'VbenPinInput',
componentProps: {
createText: (countdown: number) => {
const text =
countdown > 0
? $t('authentication.sendText', [countdown])
: $t('authentication.sendCode');
return text;
},
placeholder: $t('authentication.code'),
},
fieldName: 'code',
label: $t('authentication.code'),
rules: z.string().min(1, { message: $t('authentication.codeTip') }),
},
];
});
/**
* 异步处理登录操作
* Asynchronously handle the login process
@@ -23,8 +57,8 @@ async function handleLogin(values: LoginCodeParams) {
<template>
<AuthenticationCodeLogin
:form-schema="formSchema"
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleLogin"
/>
</template>

View File

@@ -1,13 +1,32 @@
<script lang="ts" setup>
import { ref } from 'vue';
import type { VbenFormSchema } from '@vben/common-ui';
import { AuthenticationForgetPassword } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
import { computed, ref } from 'vue';
import { AuthenticationForgetPassword, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
defineOptions({ name: 'ForgetPassword' });
const loading = ref(false);
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
placeholder: 'example@example.com',
},
fieldName: 'email',
label: $t('authentication.email'),
rules: z
.string()
.min(1, { message: $t('authentication.emailTip') })
.email($t('authentication.emailValidErrorTip')),
},
];
});
function handleSubmit(value: string) {
// eslint-disable-next-line no-console
console.log('reset email:', value);
@@ -16,8 +35,8 @@ function handleSubmit(value: string) {
<template>
<AuthenticationForgetPassword
:form-schema="formSchema"
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@@ -1,18 +1,91 @@
<script lang="ts" setup>
import { AuthenticationLogin } from '@vben/common-ui';
import type { VbenFormSchema } from '@vben/common-ui';
import type { BasicOption } from '@vben/types';
import { computed } from 'vue';
import { AuthenticationLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useAuthStore } from '#/store';
defineOptions({ name: 'Login' });
const authStore = useAuthStore();
const MOCK_USER_OPTIONS: BasicOption[] = [
{
label: '超级管理员',
value: 'vben',
},
{
label: '管理员',
value: 'admin',
},
{
label: '用户',
value: 'jack',
},
];
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenSelect',
componentProps: {
options: MOCK_USER_OPTIONS,
placeholder: $t('authentication.selectAccount'),
},
fieldName: 'selectAccount',
label: $t('authentication.selectAccount'),
rules: z
.string()
.min(1, { message: $t('authentication.selectAccount') })
.optional()
.default('vben'),
},
{
component: 'VbenInput',
componentProps: {
placeholder: $t('authentication.usernameTip'),
},
dependencies: {
trigger(values, form) {
if (values.selectAccount) {
const findUser = MOCK_USER_OPTIONS.find(
(item) => item.value === values.selectAccount,
);
if (findUser) {
form.setValues({
password: '123456',
username: findUser.value,
});
}
}
},
triggerFields: ['selectAccount'],
},
fieldName: 'username',
label: $t('authentication.username'),
rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
placeholder: $t('authentication.password'),
},
fieldName: 'password',
label: $t('authentication.password'),
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
];
});
</script>
<template>
<AuthenticationLogin
:form-schema="formSchema"
:loading="authStore.loginLoading"
password-placeholder="123456"
username-placeholder="vben"
@submit="authStore.authLogin"
/>
</template>

View File

@@ -1,15 +1,91 @@
<script lang="ts" setup>
import type { LoginAndRegisterParams } from '@vben/common-ui';
import type { LoginAndRegisterParams, VbenFormSchema } from '@vben/common-ui';
import { ref } from 'vue';
import { computed, h, ref } from 'vue';
import { AuthenticationRegister } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
import { AuthenticationRegister, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
defineOptions({ name: 'Register' });
const loading = ref(false);
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
placeholder: $t('authentication.usernameTip'),
},
fieldName: 'username',
label: $t('authentication.username'),
rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
passwordStrength: true,
placeholder: $t('authentication.password'),
},
fieldName: 'password',
label: $t('authentication.password'),
renderComponentContent() {
return {
strengthText: () => $t('authentication.passwordStrength'),
};
},
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
placeholder: $t('authentication.confirmPassword'),
},
dependencies: {
rules(values) {
const { password } = values;
return z
.string()
.min(1, { message: $t('authentication.passwordTip') })
.refine((value) => value === password, {
message: $t('authentication.confirmPasswordTip'),
});
},
triggerFields: ['password'],
},
fieldName: 'confirmPassword',
label: $t('authentication.confirmPassword'),
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
{
component: 'VbenCheckbox',
fieldName: 'agreePolicy',
renderComponentContent: () => ({
default: () =>
h('span', [
$t('authentication.agree'),
h(
'a',
{
class:
'cursor-pointer text-primary ml-1 hover:text-primary-hover',
href: '',
},
[
$t('authentication.privacyPolicy'),
'&',
$t('authentication.terms'),
],
),
]),
}),
rules: z.boolean().refine((value) => !!value, {
message: $t('authentication.agreeTip'),
}),
},
];
});
function handleSubmit(value: LoginAndRegisterParams) {
// eslint-disable-next-line no-console
console.log('register submit:', value);
@@ -18,8 +94,8 @@ function handleSubmit(value: LoginAndRegisterParams) {
<template>
<AuthenticationRegister
:form-schema="formSchema"
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@@ -55,12 +55,27 @@ onMounted(() => {
},
trigger: 'axis',
},
// xAxis: {
// axisTick: {
// show: false,
// },
// boundaryGap: false,
// data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
// type: 'category',
// },
xAxis: {
axisTick: {
show: false,
},
boundaryGap: false,
data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
splitLine: {
lineStyle: {
type: 'solid',
width: 1,
},
show: true,
},
type: 'category',
},
yAxis: [
@@ -69,7 +84,10 @@ onMounted(() => {
show: false,
},
max: 80_000,
splitArea: {
show: true,
},
splitNumber: 4,
type: 'value',
},
],

View File

@@ -214,7 +214,11 @@ const trendItems: WorkbenchTrendItem[] = [
<WorkbenchTrends :items="trendItems" class="mt-5" title="最新动态" />
</div>
<div class="w-full lg:w-2/5">
<WorkbenchQuickNav :items="quickNavItems" title="快捷导航" />
<WorkbenchQuickNav
:items="quickNavItems"
class="mt-5 lg:mt-0"
title="快捷导航"
/>
<WorkbenchTodo :items="todoItems" class="mt-5" title="待办事项" />
<AnalysisChartCard class="mt-5" title="访问来源">
<AnalyticsVisitsSource />

View File

@@ -160,6 +160,10 @@ function sidebarComponents(): DefaultTheme.SidebarItem[] {
link: 'common-ui/vben-drawer',
text: 'Vben Drawer 抽屉',
},
{
link: 'common-ui/vben-form',
text: 'Vben Form 表单',
},
],
},
];

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/docs",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"private": true,
"scripts": {
"build": "vitepress build",
@@ -11,15 +11,15 @@
"@vben-core/shadcn-ui": "workspace:*",
"@vben/common-ui": "workspace:*",
"@vben/styles": "workspace:*",
"lucide-vue-next": "^0.436.0",
"lucide-vue-next": "^0.439.0",
"medium-zoom": "^1.1.0",
"radix-vue": "^1.9.5"
},
"devDependencies": {
"@nolebase/vitepress-plugin-git-changelog": "^2.4.0",
"@nolebase/vitepress-plugin-git-changelog": "^2.5.0",
"@vben/vite-config": "workspace:*",
"@vite-pwa/vitepress": "^0.5.0",
"@vite-pwa/vitepress": "^0.5.3",
"vitepress": "^1.3.4",
"vue": "^3.4.38"
"vue": "^3.5.4"
}
}

View File

@@ -2,10 +2,14 @@
社区交流群主要是为了方便大家交流,提问,解答问题,分享经验等。偏自助方式,如果你有问题,可以通过以下方式加入社区交流群:
- [QQ频道](https://pd.qq.com/s/16p8lvvob):推荐主要提供问题解答,分享经验等。
- QQ群[1群(满)](https://qm.qq.com/q/YacMHPYAMu)、[2群(满)](https://qm.qq.com/q/ajVKZvFICk)、[3群](https://qm.qq.com/q/36zdwThP2E),主要使用者的交流群。
- [QQ频道](https://pd.qq.com/s/16p8lvvob):推荐主要提供问题解答,分享经验等。
- QQ群[1群](https://qm.qq.com/q/YacMHPYAMu)、[2群](https://qm.qq.com/q/ajVKZvFICk)、[3群](https://qm.qq.com/q/36zdwThP2E)[4群](https://qm.qq.com/q/sCzSlm3504)[老群](https://qm.qq.com/q/MEmHoCLbG0)主要使用者的交流群。
- [Discord](https://discord.com/invite/VU62jTecad): 主要提供问题解答,分享经验等。
::: tip
免费QQ群人数上限200将会不定期清理。推荐加入QQ频道进行交流
## 微信群
::: tip

View File

@@ -74,6 +74,8 @@ const [Drawer, drawerApi] = useVbenDrawer({
| closeOnPressEscape | esc 关闭弹窗 | `boolean` | `true` |
| confirmText | 确认按钮文本 | `string\|slot` | `确认` |
| cancelText | 取消按钮文本 | `string\|slot` | `取消` |
| showCancelButton | 显示取消按钮 | `boolean` | `true` |
| showConfirmButton | 显示确认按钮文本 | `boolean` | `true` |
| class | modal的class宽度通过这个配置 | `string` | - |
| contentClass | modal内容区域的class | `string` | - |
| footerClass | modal底部区域的class | `string` | - |

View File

@@ -0,0 +1,11 @@
---
outline: deep
---
# Vben Form 表单
框架提供的表单组件,可适配 `Element Plus``Ant Design Vue``Naive`UI 框架。
# 使用
TODO

View File

@@ -84,6 +84,8 @@ const [Modal, modalApi] = useVbenModal({
| closeOnPressEscape | esc 关闭弹窗 | `boolean` | `true` |
| confirmText | 确认按钮文本 | `string\|slot` | `确认` |
| cancelText | 取消按钮文本 | `string\|slot` | `取消` |
| showCancelButton | 显示取消按钮 | `boolean` | `true` |
| showConfirmButton | 显示确认按钮文本 | `boolean` | `true` |
| class | modal的class宽度通过这个配置 | `string` | - |
| contentClass | modal内容区域的class | `string` | - |
| footerClass | modal底部区域的class | `string` | - |

View File

@@ -240,7 +240,7 @@ const defaultPreferences: Preferences = {
theme: {
builtinType: 'default',
colorDestructive: 'hsl(348 100% 61%)',
colorPrimary: 'hsl(231 98% 65%)',
colorPrimary: 'hsl(212 100% 45%)',
colorSuccess: 'hsl(144 57% 58%)',
colorWarning: 'hsl(42 84% 61%)',
mode: 'dark',

View File

@@ -35,7 +35,7 @@ import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
loginExpiredMode: 'model',
loginExpiredMode: 'modal',
},
});
```

View File

@@ -18,7 +18,7 @@ You just need to configure the `props` parameter of `AuthPageLayout` in `src/rou
pageTitle: "开箱即用的大型中后台管理系统",
pageDescription: "工程化、高性能、跨组件库的前端模版",
toolbar: true,
toolbarList: () => ['color', 'language', 'layout', 'theme'],
toolbarList: ['color', 'language', 'layout', 'theme'],
}
// ...
},
@@ -61,11 +61,6 @@ If you want to adjust the content of the login form, you can configure the `Auth
*/
loading?: boolean;
/**
* @en Password placeholder
*/
passwordPlaceholder?: string;
/**
* @en QR code login path
*/
@@ -114,11 +109,6 @@ If you want to adjust the content of the login form, you can configure the `Auth
* @en Login box title
*/
title?: string;
/**
* @en Username placeholder
*/
usernamePlaceholder?: string;
}
```

View File

@@ -36,7 +36,7 @@ You can check the list below to understand all the available variables.
--background: 0 0% 100%;
/* Main area background color */
--background-deep: 210 11.11% 96.47%;
--background-deep: 216 20.11% 95.47%;
--foreground: 210 6% 21%;
/* Background color for <Card /> */
@@ -53,7 +53,7 @@ You can check the list below to understand all the available variables.
/* Theme Colors */
--primary: 231 98% 65%;
--primary: 212 100% 45%;
--primary-foreground: 0 0% 98%;
/* Used for destructive actions such as <Button variant="destructive"> */
@@ -111,7 +111,7 @@ You can check the list below to understand all the available variables.
/* menu */
--sidebar: 0 0% 100%;
--sidebar-deep: 210 11.11% 96.47%;
--sidebar-deep: 216 20.11% 95.47%;
--menu: var(--sidebar);
/* header */
@@ -264,7 +264,7 @@ export const overridesPreferences = defineOverridesPreferences({
// Error color
colorDestructive: 'hsl(348 100% 61%)',
// Primary color
colorPrimary: 'hsl(231 98% 65%)',
colorPrimary: 'hsl(212 100% 45%)',
// Success color
colorSuccess: 'hsl(144 57% 58%)',
// Warning color
@@ -330,7 +330,7 @@ type BuiltinThemeType =
--background: 0 0% 100%;
/* Main area background color */
--background-deep: 210 11.11% 96.47%;
--background-deep: 216 20.11% 95.47%;
--foreground: 222 84% 5%;
/* Background color for <Card /> */
@@ -351,7 +351,7 @@ type BuiltinThemeType =
/* Theme Colors */
--primary: 231 98% 65%;
--primary: 212 100% 45%;
--primary-foreground: 0 0% 98%;
/* Used for destructive actions such as <Button variant="destructive"> */

View File

@@ -262,7 +262,7 @@ const defaultPreferences: Preferences = {
theme: {
builtinType: 'default',
colorDestructive: 'hsl(348 100% 61%)',
colorPrimary: 'hsl(231 98% 65%)',
colorPrimary: 'hsl(212 100% 45%)',
colorSuccess: 'hsl(144 57% 58%)',
colorWarning: 'hsl(42 84% 61%)',
mode: 'dark',

View File

@@ -35,7 +35,7 @@ import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
loginExpiredMode: 'model',
loginExpiredMode: 'modal',
},
});
```

View File

@@ -8,28 +8,21 @@
![login](/guide/login.png)
只需要在应用下的 `src/router/routes/core.ts` 内,配置`AuthPageLayout``props`参数即可:
只需要在应用下的 `src/layouts/auth.vue` 内,配置`AuthPageLayout``props`参数即可:
```ts {4-8}
{
component: AuthPageLayout,
props: {
sloganImage: "xxx/xxx.png",
pageTitle: "开箱即用的大型中后台管理系统",
pageDescription: "工程化、高性能、跨组件库的前端模版",
toolbar: true,
toolbarList: () => ['color', 'language', 'layout', 'theme'],
}
// ...
},
```vue {2-7}
<AuthPageLayout
:copyright="true"
:toolbar="true"
:toolbarList="['color', 'language', 'layout', 'theme']"
:app-name="appName"
:logo="logo"
:page-description="$t('authentication.pageDesc')"
:page-title="$t('authentication.pageTitle')"
>
</AuthPageLayout>
```
::: tip
如果这些配置不能满足你的需求,你可以自行实现登录页面。直接实现自己的 `AuthPageLayout`即可。
:::
## 登录表单调整
如果你想调整登录表单的相关内容,你可以在应用下的 `src/views/_core/authentication/login.vue` 内,配置`AuthenticationLogin` 组件参数即可:
@@ -61,11 +54,6 @@
*/
loading?: boolean;
/**
* @zh_CN 密码占位符
*/
passwordPlaceholder?: string;
/**
* @zh_CN 二维码登录路径
*/
@@ -115,10 +103,6 @@
*/
title?: string;
/**
* @zh_CN 用户名占位符
*/
usernamePlaceholder?: string;
}
```

View File

@@ -36,7 +36,7 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
--background: 0 0% 100%;
/* 主体区域背景色 */
--background-deep: 210 11.11% 96.47%;
--background-deep: 216 20.11% 95.47%;
--foreground: 210 6% 21%;
/* Background color for <Card /> */
@@ -53,7 +53,7 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
/* 主题颜色 */
--primary: 231 98% 65%;
--primary: 212 100% 45%;
--primary-foreground: 0 0% 98%;
/* Used for destructive actions such as <Button variant="destructive"> */
@@ -111,7 +111,7 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
/* menu */
--sidebar: 0 0% 100%;
--sidebar-deep: 210 11.11% 96.47%;
--sidebar-deep: 216 20.11% 95.47%;
--menu: var(--sidebar);
/* header */
@@ -264,7 +264,7 @@ export const overridesPreferences = defineOverridesPreferences({
// 错误色
colorDestructive: 'hsl(348 100% 61%)',
// 主题色
colorPrimary: 'hsl(231 98% 65%)',
colorPrimary: 'hsl(212 100% 45%)',
// 成功色
colorSuccess: 'hsl(144 57% 58%)',
// 警告色
@@ -330,7 +330,7 @@ type BuiltinThemeType =
--background: 0 0% 100%;
/* 主体区域背景色 */
--background-deep: 210 11.11% 96.47%;
--background-deep: 216 20.11% 95.47%;
--foreground: 222 84% 5%;
/* Background color for <Card /> */
@@ -351,7 +351,7 @@ type BuiltinThemeType =
/* 主题颜色 */
--primary: 231 98% 65%;
--primary: 212 100% 45%;
--primary-foreground: 0 0% 98%;
/* Used for destructive actions such as <Button variant="destructive"> */

View File

@@ -10,7 +10,7 @@ outline: deep
在启动项目前,你需要确保你的环境满足以下要求:
- [Node.js](https://nodejs.org/en) 20 及以上版本,推荐使用 [fnm](https://github.com/Schniz/fnm) 或者 [nvm](https://github.com/nvm-sh/nvm) 进行版本管理。
- [Node.js](https://nodejs.org/en) 20.15.0 及以上版本,推荐使用 [fnm](https://github.com/Schniz/fnm) 或者 [nvm](https://github.com/nvm-sh/nvm) 进行版本管理。
- [Git](https://git-scm.com/) 任意版本。
验证你的环境是否满足以上要求,你可以通过以下命令查看版本:

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/commitlint-config",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",

View File

@@ -27,29 +27,29 @@
}
},
"dependencies": {
"eslint-config-turbo": "^2.1.0",
"eslint-plugin-command": "^0.2.3",
"eslint-plugin-import-x": "^4.1.0"
"eslint-config-turbo": "^2.1.1",
"eslint-plugin-command": "^0.2.4",
"eslint-plugin-import-x": "^4.2.1"
},
"devDependencies": {
"@eslint/js": "^9.9.1",
"@eslint/js": "^9.10.0",
"@types/eslint": "^9.6.1",
"@typescript-eslint/eslint-plugin": "^8.3.0",
"@typescript-eslint/parser": "^8.3.0",
"eslint": "^9.9.1",
"@typescript-eslint/eslint-plugin": "^8.5.0",
"@typescript-eslint/parser": "^8.5.0",
"eslint": "^9.10.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-jsdoc": "^50.2.2",
"eslint-plugin-jsonc": "^2.16.0",
"eslint-plugin-n": "^17.10.2",
"eslint-plugin-no-only-tests": "^3.3.0",
"eslint-plugin-perfectionist": "^3.3.0",
"eslint-plugin-perfectionist": "^3.5.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-regexp": "^2.6.0",
"eslint-plugin-unicorn": "^55.0.0",
"eslint-plugin-unused-imports": "^4.1.3",
"eslint-plugin-vitest": "^0.5.4",
"eslint-plugin-vue": "^9.27.0",
"eslint-plugin-vue": "^9.28.0",
"globals": "^15.9.0",
"jsonc-eslint-parser": "^2.4.0",
"vue-eslint-parser": "^9.4.3"

View File

@@ -15,12 +15,14 @@ export async function unicorn(): Promise<Linter.Config[]> {
rules: {
...pluginUnicorn.configs.recommended.rules,
'unicorn/better-regex': 'off',
'unicorn/consistent-destructuring': 'off',
'unicorn/consistent-function-scoping': 'off',
'unicorn/filename-case': 'off',
'unicorn/import-style': 'off',
'unicorn/no-array-for-each': 'off',
'unicorn/no-null': 'off',
'unicorn/no-useless-undefined': 'off',
'unicorn/prefer-at': 'off',
'unicorn/prefer-dom-node-text-content': 'off',
'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }],

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/stylelint-config",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
@@ -28,7 +28,7 @@
"stylelint-scss": "^6.5.1"
},
"devDependencies": {
"postcss": "^8.4.41",
"postcss": "^8.4.45",
"postcss-html": "^1.7.0",
"postcss-scss": "^4.0.9",
"prettier": "^3.3.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/node-utils",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
@@ -28,7 +28,7 @@
}
},
"dependencies": {
"@changesets/git": "^3.0.0",
"@changesets/git": "^3.0.1",
"@manypkg/get-packages": "^2.2.2",
"chalk": "^5.3.0",
"consola": "^3.2.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/tailwind-config",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
@@ -46,16 +46,16 @@
"tailwindcss": "^3.4.3"
},
"dependencies": {
"@iconify/json": "^2.2.242",
"@iconify/json": "^2.2.246",
"@iconify/tailwind": "^1.1.3",
"@tailwindcss/nesting": "0.0.0-insiders.565cd3e",
"@tailwindcss/typography": "^0.5.15",
"autoprefixer": "^10.4.20",
"cssnano": "^7.0.5",
"postcss": "^8.4.41",
"cssnano": "^7.0.6",
"postcss": "^8.4.45",
"postcss-antd-fixes": "^0.2.0",
"postcss-import": "^16.1.0",
"postcss-preset-env": "^10.0.2",
"postcss-preset-env": "^10.0.3",
"tailwindcss": "^3.4.10",
"tailwindcss-animate": "^1.0.7"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/tsconfig",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
@@ -20,6 +20,6 @@
],
"dependencies": {
"@vben/types": "workspace:*",
"vite": "^5.4.2"
"vite": "^5.4.3"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/vite-config",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
@@ -28,7 +28,7 @@
},
"dependencies": {
"@intlify/unplugin-vue-i18n": "^4.0.0",
"@jspm/generator": "^2.1.3",
"@jspm/generator": "^2.3.0",
"archiver": "^7.0.1",
"cheerio": "1.0.0",
"get-port": "^7.1.0",
@@ -36,23 +36,23 @@
"nitropack": "^2.9.7",
"resolve.exports": "^2.0.2",
"vite-plugin-lib-inject-css": "^2.1.1",
"vite-plugin-pwa": "^0.20.1",
"vite-plugin-vue-devtools": "^7.3.9"
"vite-plugin-pwa": "^0.20.5",
"vite-plugin-vue-devtools": "^7.4.4"
},
"devDependencies": {
"@types/archiver": "^6.0.2",
"@types/html-minifier-terser": "^7.0.2",
"@vben/node-utils": "workspace:*",
"@vitejs/plugin-vue": "^5.1.2",
"@vitejs/plugin-vue": "^5.1.3",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"dayjs": "^1.11.13",
"dotenv": "^16.4.5",
"rollup": "^4.21.1",
"rollup": "^4.21.2",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.77.8",
"vite": "^5.4.2",
"sass": "^1.78.0",
"vite": "^5.4.3",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-dts": "4.0.3",
"vite-plugin-dts": "4.2.1",
"vite-plugin-html": "^3.2.2"
}
}

View File

@@ -81,7 +81,11 @@ function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) {
port,
warmup: {
// 预热文件
clientFiles: ['./index.html', './src/{views,layouts,router,store}/*'],
clientFiles: [
'./index.html',
'./bootstrap.ts',
'./src/{views,layouts,router,store,api}/*',
],
},
},
};

View File

@@ -3,6 +3,7 @@ import type { PluginOption } from 'vite';
import type { ArchiverPluginOptions } from '../typing';
import fs from 'node:fs';
import fsp from 'node:fs/promises';
import { join } from 'node:path';
import archiver from 'archiver';
@@ -18,7 +19,14 @@ export const viteArchiverPlugin = (
setTimeout(async () => {
const folderToZip = 'dist';
const zipOutputPath = join(process.cwd(), outputDir, `${name}.zip`);
const zipOutputDir = join(process.cwd(), outputDir);
const zipOutputPath = join(zipOutputDir, `${name}.zip`);
try {
await fsp.mkdir(zipOutputDir, { recursive: true });
} catch {
// ignore
}
try {
await zipFolder(folderToZip, zipOutputPath);

View File

@@ -1,6 +1,6 @@
{
"name": "vben-admin-pro",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"private": true,
"keywords": [
"monorepo",
@@ -62,10 +62,9 @@
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.7",
"@ls-lint/ls-lint": "^2.2.3",
"@changesets/cli": "^2.27.8",
"@types/jsdom": "^21.1.7",
"@types/node": "^22.5.1",
"@types/node": "^22.5.4",
"@vben/commitlint-config": "workspace:*",
"@vben/eslint-config": "workspace:*",
"@vben/prettier-config": "workspace:*",
@@ -75,7 +74,7 @@
"@vben/turbo-run": "workspace:*",
"@vben/vite-config": "workspace:*",
"@vben/vsh": "workspace:*",
"@vitejs/plugin-vue": "^5.1.2",
"@vitejs/plugin-vue": "^5.1.3",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"@vue/test-utils": "^2.4.6",
"autoprefixer": "^10.4.20",
@@ -84,22 +83,22 @@
"husky": "^9.1.5",
"is-ci": "^3.0.1",
"jsdom": "^25.0.0",
"lint-staged": "^15.2.9",
"lint-staged": "^15.2.10",
"rimraf": "^6.0.1",
"tailwindcss": "^3.4.10",
"turbo": "^2.1.0",
"typescript": "^5.5.4",
"turbo": "^2.1.1",
"typescript": "^5.6.2",
"unbuild": "^2.0.0",
"vite": "^5.4.2",
"vite": "^5.4.3",
"vitest": "^2.0.5",
"vue": "^3.4.38",
"vue-tsc": "^2.0.29"
"vue": "^3.5.4",
"vue-tsc": "^2.1.6"
},
"engines": {
"node": ">=20",
"pnpm": ">=9"
},
"packageManager": "pnpm@9.9.0",
"packageManager": "pnpm@9.10.0",
"pnpm": {
"peerDependencyRules": {
"allowedVersions": {
@@ -110,7 +109,7 @@
"@ctrl/tinycolor": "4.1.0",
"clsx": "2.1.1",
"pinia": "2.2.2",
"vue": "3.4.38"
"vue": "3.5.3"
},
"neverBuiltDependencies": [
"canvas",

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/design",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -23,12 +23,15 @@
scroll-behavior: smooth;
text-rendering: optimizelegibility;
-webkit-tap-highlight-color: transparent;
/* -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; */
}
#app,
body,
html {
@apply !pointer-events-auto size-full overscroll-none;
@apply size-full overscroll-none;
}
body {
@@ -136,7 +139,7 @@
}
.card-box {
@apply bg-card text-card-foreground border-border rounded-xl border shadow;
@apply bg-card text-card-foreground border-border rounded-xl border;
}
}

View File

@@ -7,7 +7,7 @@
--background: 0 0% 100%;
/* 主体区域背景色 */
--background-deep: 210 11.11% 96.47%;
--background-deep: 216 20.11% 95.47%;
--foreground: 210 6% 21%;
/* Background color for <Card /> */
@@ -28,7 +28,7 @@
/* 主题颜色 */
--primary: 231 98% 65%;
--primary: 212 100% 45%;
--primary-foreground: 0 0% 98%;
/* Used for destructive actions such as <Button variant="destructive"> */
@@ -77,7 +77,8 @@
/* ============= custom ============= */
/* 遮罩颜色 */
--overlay: 0 0% 0% / 30%;
--overlay: 0 0% 0% / 45%;
--overlay-light: 0 0% 95% / 45%;
/* 基本文字大小 */
--font-size-base: 16px;

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/icons",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -35,7 +35,7 @@
},
"dependencies": {
"@iconify/vue": "^4.1.2",
"lucide-vue-next": "^0.436.0",
"vue": "^3.4.38"
"lucide-vue-next": "^0.439.0",
"vue": "^3.5.4"
}
}

View File

@@ -18,7 +18,6 @@ export {
CircleHelp,
Copy,
CornerDownLeft,
Disc as IconDefault,
Ellipsis,
Expand,
ExternalLink,
@@ -35,6 +34,7 @@ export {
LogOut,
MailCheck,
Maximize,
Menu as IconDefault,
Menu,
Minimize,
Minimize2,

View File

@@ -4,7 +4,6 @@ export default defineBuildConfig({
clean: true,
declaration: true,
entries: [
'src/index',
'src/store',
'src/constants/index',
'src/utils/index',

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/shared",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -17,14 +17,7 @@
"dist"
],
"sideEffects": false,
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"exports": {
".": {
"types": "./src/index.ts",
"development": "./src/index.ts",
"default": "./dist/index.mjs"
},
"./constants": {
"types": "./src/constants/index.ts",
"development": "./src/constants/index.ts",
@@ -53,16 +46,32 @@
},
"publishConfig": {
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
"./constants": {
"types": "./dist/constants/index.d.ts",
"default": "./dist/constants/index.mjs"
},
"./utils": {
"types": "./dist/utils/index.d.ts",
"default": "./dist/utils/index.mjs"
},
"./color": {
"types": "./dist/color/index.d.ts",
"default": "./dist/color/index.mjs"
},
"./cache": {
"types": "./dist/cache/index.d.ts",
"default": "./dist/cache/index.mjs"
},
"./store": {
"types": "./dist/store/index.d.ts",
"default": "./dist/store.mjs"
}
}
},
"dependencies": {
"@ctrl/tinycolor": "^4.1.0",
"@tanstack/vue-store": "^0.5.5",
"@vue/shared": "^3.4.38",
"@vue/shared": "^3.5.4",
"clsx": "^2.1.1",
"defu": "^6.1.4",
"lodash.clonedeep": "^4.5.0",

View File

@@ -1,5 +0,0 @@
export * from './cache';
export * from './color';
export * from './constants';
export * from './store';
export * from './utils';

View File

@@ -0,0 +1,60 @@
import { describe, expect, it } from 'vitest';
import { StateHandler } from '../state-handler';
describe('stateHandler', () => {
it('should resolve when condition is set to true', async () => {
const handler = new StateHandler();
// 模拟异步设置 condition 为 true
setTimeout(() => {
handler.setConditionTrue(); // 明确触发 condition 为 true
}, 10);
// 等待条件被设置为 true
await handler.waitForCondition();
expect(handler.isConditionTrue()).toBe(true);
});
it('should resolve immediately if condition is already true', async () => {
const handler = new StateHandler();
handler.setConditionTrue(); // 提前设置为 true
// 立即 resolve因为 condition 已经是 true
await handler.waitForCondition();
expect(handler.isConditionTrue()).toBe(true);
});
it('should reject when condition is set to false after waiting', async () => {
const handler = new StateHandler();
// 模拟异步设置 condition 为 false
setTimeout(() => {
handler.setConditionFalse(); // 明确触发 condition 为 false
}, 10);
// 等待过程中,期望 Promise 被 reject
await expect(handler.waitForCondition()).rejects.toThrow();
expect(handler.isConditionTrue()).toBe(false);
});
it('should reset condition to false', () => {
const handler = new StateHandler();
handler.setConditionTrue(); // 设置为 true
handler.reset(); // 重置为 false
expect(handler.isConditionTrue()).toBe(false);
});
it('should resolve when condition is set to true after reset', async () => {
const handler = new StateHandler();
handler.reset(); // 确保初始为 false
setTimeout(() => {
handler.setConditionTrue(); // 重置后设置为 true
}, 10);
await handler.waitForCondition();
expect(handler.isConditionTrue()).toBe(true);
});
});

View File

@@ -0,0 +1,80 @@
import { describe, expect, it } from 'vitest';
import { bindMethods } from '../util';
class TestClass {
public value: string;
constructor(value: string) {
this.value = value;
bindMethods(this); // 调用通用方法
}
getValue() {
return this.value;
}
setValue(newValue: string) {
this.value = newValue;
}
}
describe('bindMethods', () => {
it('should bind methods to the instance correctly', () => {
const instance = new TestClass('initial');
// 解构方法
const { getValue } = instance;
// 检查 getValue 是否能正确调用,并且 this 绑定了 instance
expect(getValue()).toBe('initial');
});
it('should bind multiple methods', () => {
const instance = new TestClass('initial');
const { getValue, setValue } = instance;
// 检查 getValue 和 setValue 方法是否正确绑定了 this
setValue('newValue');
expect(getValue()).toBe('newValue');
});
it('should not bind non-function properties', () => {
const instance = new TestClass('initial');
// 检查普通属性是否保持原样
expect(instance.value).toBe('initial');
});
it('should not bind constructor method', () => {
const instance = new TestClass('test');
// 检查 constructor 是否没有被绑定
expect(instance.constructor.name).toBe('TestClass');
});
it('should not bind getter/setter properties', () => {
class TestWithGetterSetter {
private _value: string = 'test';
constructor() {
bindMethods(this);
}
get value() {
return this._value;
}
set value(newValue: string) {
this._value = newValue;
}
}
const instance = new TestWithGetterSetter();
const { value } = instance;
// Getter 和 setter 不应被绑定
expect(value).toBe('test');
});
});

View File

@@ -5,9 +5,11 @@ export * from './inference';
export * from './letter';
export * from './merge';
export * from './nprogress';
export * from './state-handler';
export * from './to';
export * from './tree';
export * from './unique';
export * from './update-css-variables';
export * from './util';
export * from './window';
export { default as cloneDeep } from 'lodash.clonedeep';

View File

@@ -0,0 +1,50 @@
export class StateHandler {
private condition: boolean = false;
private rejectCondition: (() => void) | null = null;
private resolveCondition: (() => void) | null = null;
// 清理 resolve/reject 函数
private clearPromises() {
this.resolveCondition = null;
this.rejectCondition = null;
}
isConditionTrue(): boolean {
return this.condition;
}
reset() {
this.condition = false;
this.clearPromises();
}
// 触发状态为 false 时reject
setConditionFalse() {
this.condition = false;
if (this.rejectCondition) {
this.rejectCondition();
this.clearPromises();
}
}
// 触发状态为 true 时resolve
setConditionTrue() {
this.condition = true;
if (this.resolveCondition) {
this.resolveCondition();
this.clearPromises();
}
}
// 返回一个 Promise等待 condition 变为 true
waitForCondition(): Promise<void> {
return new Promise((resolve, reject) => {
if (this.condition) {
resolve(); // 如果 condition 已经为 true立即 resolve
} else {
this.resolveCondition = resolve;
this.rejectCondition = reject;
}
});
}
}

View File

@@ -0,0 +1,19 @@
export function bindMethods<T extends object>(instance: T): void {
const prototype = Object.getPrototypeOf(instance);
const propertyNames = Object.getOwnPropertyNames(prototype);
propertyNames.forEach((propertyName) => {
const descriptor = Object.getOwnPropertyDescriptor(prototype, propertyName);
const propertyValue = instance[propertyName as keyof T];
if (
typeof propertyValue === 'function' &&
propertyName !== 'constructor' &&
descriptor &&
!descriptor.get &&
!descriptor.set
) {
instance[propertyName as keyof T] = propertyValue.bind(instance);
}
});
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/typings",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -38,7 +38,7 @@
}
},
"dependencies": {
"vue": "^3.4.38",
"vue": "^3.5.4",
"vue-router": "^4.4.3"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/composables",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -38,8 +38,8 @@
"@vben-core/shared": "workspace:*",
"@vueuse/core": "^11.0.3",
"radix-vue": "^1.9.5",
"sortablejs": "^1.15.2",
"vue": "^3.4.38"
"sortablejs": "^1.15.3",
"vue": "^3.5.4"
},
"devDependencies": {
"@types/sortablejs": "^1.15.8"

View File

@@ -4,9 +4,11 @@ import { computed, onMounted, onUnmounted, ref } from 'vue';
import {
CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT,
CSS_VARIABLE_LAYOUT_CONTENT_WIDTH,
} from '@vben-core/shared/constants';
import {
getElementVisibleRect,
type VisibleDomRect,
} from '@vben-core/shared';
} from '@vben-core/shared/utils';
import { useCssVar, useDebounceFn } from '@vueuse/core';

View File

@@ -1,4 +1,4 @@
import { DEFAULT_NAMESPACE } from '@vben-core/shared';
import { DEFAULT_NAMESPACE } from '@vben-core/shared/constants';
/**
* @see copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-namespace/index.ts

View File

@@ -1,10 +1,10 @@
import type { Ref } from 'vue';
import { computed, getCurrentInstance, useAttrs, useSlots } from 'vue';
import type { ComputedRef, Ref } from 'vue';
import { computed, getCurrentInstance, unref, useAttrs, useSlots } from 'vue';
import {
getFirstNonNullOrUndefined,
kebabToCamelCase,
} from '@vben-core/shared';
} from '@vben-core/shared/utils';
/**
* 依次从插槽、attrs、props、state 中获取值
@@ -45,3 +45,49 @@ export function usePriorityValue<
return value;
}
/**
* 批量获取state中的值每个值都是ref
* @param props
* @param state
*/
export function usePriorityValues<
T extends Record<string, any>,
S extends Ref<Record<string, any>> = Readonly<Ref<NoInfer<T>, NoInfer<T>>>,
>(props: T, state: S | undefined) {
const result: { [K in keyof T]: ComputedRef<T[K]> } = {} as never;
(Object.keys(props) as (keyof T)[]).forEach((key) => {
result[key] = usePriorityValue(key as keyof typeof props, props, state);
});
return result;
}
/**
* 批量获取state中的值集中在一个computed用于透传
* @param props
* @param state
*/
export function useForwardPriorityValues<
T extends Record<string, any>,
S extends Ref<Record<string, any>> = Readonly<Ref<NoInfer<T>, NoInfer<T>>>,
>(props: T, state: S | undefined) {
const computedResult: { [K in keyof T]: ComputedRef<T[K]> } = {} as never;
(Object.keys(props) as (keyof T)[]).forEach((key) => {
computedResult[key] = usePriorityValue(
key as keyof typeof props,
props,
state,
);
});
return computed(() => {
const unwrapResult: Record<string, any> = {};
Object.keys(props).forEach((key) => {
unwrapResult[key] = unref(computedResult[key]);
});
return unwrapResult as { [K in keyof T]: T[K] };
});
}

View File

@@ -3,11 +3,19 @@ export type Locale = 'en-US' | 'zh-CN';
export const messages: Record<Locale, Record<string, string>> = {
'en-US': {
cancel: 'Cancel',
collapse: 'Collapse',
confirm: 'Confirm',
expand: 'Expand',
reset: 'Reset',
submit: 'Submit',
},
'zh-CN': {
cancel: '取消',
collapse: '收起',
confirm: '确认',
expand: '展开',
reset: '重置',
submit: '提交',
},
};

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/preferences",
"version": "5.2.0",
"version": "5.3.0-beta.1",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -32,6 +32,6 @@
"@vben-core/shared": "workspace:*",
"@vben-core/typings": "workspace:*",
"@vueuse/core": "^11.0.3",
"vue": "^3.4.38"
"vue": "^3.5.4"
}
}

View File

@@ -70,12 +70,12 @@ const defaultPreferences: Preferences = {
expandOnHover: true,
extraCollapse: true,
hidden: false,
width: 230,
width: 224,
},
tabbar: {
dragable: true,
enable: true,
height: 36,
height: 38,
keepAlive: true,
persist: true,
showIcon: true,
@@ -87,7 +87,7 @@ const defaultPreferences: Preferences = {
theme: {
builtinType: 'default',
colorDestructive: 'hsl(348 100% 61%)',
colorPrimary: 'hsl(231 98% 65%)',
colorPrimary: 'hsl(212 100% 45%)',
colorSuccess: 'hsl(144 57% 58%)',
colorWarning: 'hsl(42 84% 61%)',
mode: 'dark',

View File

@@ -9,7 +9,7 @@ interface BuiltinThemePreset {
const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [
{
color: 'hsl(231 98% 65%)',
color: 'hsl(212 100% 45%)',
type: 'default',
},
{
@@ -25,7 +25,7 @@ const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [
type: 'yellow',
},
{
color: 'hsl(212 100% 45%)',
color: 'hsl(231 98% 65%)',
type: 'sky-blue',
},
{

View File

@@ -4,7 +4,8 @@ import type { InitialOptions, Preferences } from './types';
import { markRaw, reactive, readonly, watch } from 'vue';
import { isMacOs, merge, StorageManager } from '@vben-core/shared';
import { StorageManager } from '@vben-core/shared/cache';
import { isMacOs, merge } from '@vben-core/shared/utils';
import {
breakpointsTailwind,

View File

@@ -1,9 +1,7 @@
import type { Preferences } from './types';
import {
updateCSSVariables as executeUpdateCSSVariables,
generatorColorVariables,
} from '@vben-core/shared';
import { generatorColorVariables } from '@vben-core/shared/color';
import { updateCSSVariables as executeUpdateCSSVariables } from '@vben-core/shared/utils';
import { BUILT_IN_THEME_PRESETS } from './constants';

View File

@@ -1,6 +1,6 @@
import { computed } from 'vue';
import { diff } from '@vben-core/shared';
import { diff } from '@vben-core/shared/utils';
import { preferencesManager } from './preferences';
import { isDarkTheme } from './update-css-variables';

View File

@@ -0,0 +1,21 @@
import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
clean: true,
declaration: true,
entries: [
{
builder: 'mkdist',
input: './src',
loaders: ['vue'],
pattern: ['**/*.vue'],
},
{
builder: 'mkdist',
format: 'esm',
input: './src',
loaders: ['js'],
pattern: ['**/*.ts'],
},
],
});

View File

@@ -0,0 +1,50 @@
{
"name": "@vben-core/form-ui",
"version": "5.2.1",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
"type": "git",
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
"directory": "packages/@vben-core/uikit/form-ui"
},
"license": "MIT",
"type": "module",
"scripts": {
"build": "pnpm unbuild",
"prepublishOnly": "npm run build"
},
"files": [
"dist"
],
"sideEffects": [
"**/*.css"
],
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"exports": {
".": {
"types": "./src/index.ts",
"development": "./src/index.ts",
"default": "./dist/index.mjs"
}
},
"publishConfig": {
"exports": {
".": {
"default": "./dist/index.mjs"
}
}
},
"dependencies": {
"@vben-core/composables": "workspace:*",
"@vben-core/shadcn-ui": "workspace:*",
"@vben-core/shared": "workspace:*",
"@vee-validate/zod": "^4.13.2",
"@vueuse/core": "^11.0.3",
"vee-validate": "^4.13.2",
"vue": "^3.5.4",
"zod": "^3.23.8",
"zod-defaults": "^0.1.3"
}
}

View File

@@ -0,0 +1 @@
export { default } from '@vben/tailwind-config/postcss';

View File

@@ -0,0 +1,103 @@
<script setup lang="ts">
import { computed, toRaw, unref } from 'vue';
import { useSimpleLocale } from '@vben-core/composables';
import { VbenExpandableArrow } from '@vben-core/shadcn-ui';
import { cn, isFunction } from '@vben-core/shared/utils';
import { COMPONENT_MAP } from '../config';
import { injectFormProps } from '../use-form-context';
const { $t } = useSimpleLocale();
const [rootProps, form] = injectFormProps();
const collapsed = defineModel({ default: false });
const resetButtonOptions = computed(() => {
return {
show: true,
text: `${$t.value('reset')}`,
...unref(rootProps).resetButtonOptions,
};
});
const submitButtonOptions = computed(() => {
return {
show: true,
text: `${$t.value('submit')}`,
...unref(rootProps).submitButtonOptions,
};
});
const isQueryForm = computed(() => {
return !!unref(rootProps).showCollapseButton;
});
const queryFormStyle = computed(() => {
if (isQueryForm.value) {
return {
'grid-column': `-2 / -1`,
marginLeft: 'auto',
};
}
return {};
});
async function handleSubmit(e: Event) {
e?.preventDefault();
e?.stopPropagation();
const { valid } = await form.validate();
if (!valid) {
return;
}
await unref(rootProps).handleSubmit?.(toRaw(form.values));
}
async function handleReset(e: Event) {
e?.preventDefault();
e?.stopPropagation();
const props = unref(rootProps);
if (isFunction(props.handleReset)) {
await props.handleReset?.(form.values);
} else {
form.resetForm();
}
}
</script>
<template>
<div
:class="cn('col-span-full w-full text-right', rootProps.actionWrapperClass)"
:style="queryFormStyle"
>
<component
:is="COMPONENT_MAP.DefaultResetActionButton"
v-if="resetButtonOptions.show"
class="mr-3"
type="button"
@click="handleReset"
v-bind="resetButtonOptions"
>
{{ resetButtonOptions.text }}
</component>
<component
:is="COMPONENT_MAP.DefaultSubmitActionButton"
v-if="submitButtonOptions.show"
type="button"
@click="handleSubmit"
v-bind="submitButtonOptions"
>
{{ submitButtonOptions.text }}
</component>
<VbenExpandableArrow
v-if="rootProps.showCollapseButton"
v-model:model-value="collapsed"
class="ml-2"
>
<span>{{ collapsed ? $t('expand') : $t('collapse') }}</span>
</VbenExpandableArrow>
</div>
</template>

View File

@@ -0,0 +1,65 @@
import type { BaseFormComponentType, VbenFormAdapterOptions } from './types';
import type { Component } from 'vue';
import { h } from 'vue';
import {
VbenButton,
VbenCheckbox,
Input as VbenInput,
VbenInputPassword,
VbenPinInput,
VbenSelect,
} from '@vben-core/shadcn-ui';
import { defineRule } from 'vee-validate';
const DEFAULT_MODEL_PROP_NAME = 'modelValue';
export const COMPONENT_MAP: Record<BaseFormComponentType, Component> = {
DefaultResetActionButton: h(VbenButton, { size: 'sm', variant: 'outline' }),
DefaultSubmitActionButton: h(VbenButton, { size: 'sm', variant: 'default' }),
VbenCheckbox,
VbenInput,
VbenInputPassword,
VbenPinInput,
VbenSelect,
};
export const COMPONENT_BIND_EVENT_MAP: Partial<
Record<BaseFormComponentType, string>
> = {
VbenCheckbox: 'checked',
};
export function setupVbenForm<
T extends BaseFormComponentType = BaseFormComponentType,
>(options: VbenFormAdapterOptions<T>) {
const { components, config, defineRules } = options;
if (defineRules) {
for (const key of Object.keys(defineRules)) {
defineRule(key, defineRules[key as never]);
}
}
const baseModelPropName =
config?.baseModelPropName ?? DEFAULT_MODEL_PROP_NAME;
const modelPropNameMap = config?.modelPropNameMap as
| Record<BaseFormComponentType, string>
| undefined;
for (const component of Object.keys(components)) {
const key = component as BaseFormComponentType;
COMPONENT_MAP[key] = components[component as never];
if (baseModelPropName !== DEFAULT_MODEL_PROP_NAME) {
COMPONENT_BIND_EVENT_MAP[key] = baseModelPropName;
}
// 覆盖特殊组件的modelPropName
if (modelPropNameMap && modelPropNameMap[key]) {
COMPONENT_BIND_EVENT_MAP[key] = modelPropNameMap[key];
}
}
}

View File

@@ -0,0 +1,175 @@
import type {
FormState,
GenericObject,
ResetFormOpts,
ValidationOptions,
} from 'vee-validate';
import type { FormActions, VbenFormProps } from './types';
import { toRaw } from 'vue';
import { Store } from '@vben-core/shared/store';
import { bindMethods, isFunction, StateHandler } from '@vben-core/shared/utils';
function getDefaultState(): VbenFormProps {
return {
actionWrapperClass: '',
collapsed: false,
collapsedRows: 1,
commonConfig: {},
handleReset: undefined,
handleSubmit: undefined,
layout: 'horizontal',
resetButtonOptions: {},
schema: [],
showCollapseButton: false,
showDefaultActions: true,
submitButtonOptions: {},
wrapperClass: 'grid-cols-1',
};
}
export class FormApi {
// private prevState!: ModalState;
private state: null | VbenFormProps = null;
// private api: Pick<VbenFormProps, 'handleReset' | 'handleSubmit'>;
public form = {} as FormActions;
isMounted = false;
stateHandler: StateHandler;
public store: Store<VbenFormProps>;
constructor(options: VbenFormProps = {}) {
const { ...storeState } = options;
const defaultState = getDefaultState();
this.store = new Store<VbenFormProps>(
{
...defaultState,
...storeState,
},
{
onUpdate: () => {
this.state = this.store.state;
},
},
);
this.state = this.store.state;
this.stateHandler = new StateHandler();
bindMethods(this);
}
private async getForm() {
if (!this.isMounted) {
// 等待form挂载
await this.stateHandler.waitForCondition();
}
if (!this.form?.meta) {
throw new Error('<VbenForm /> is not mounted');
}
return this.form;
}
// 如果需要多次更新状态,可以使用 batch 方法
batchStore(cb: () => void) {
this.store.batch(cb);
}
async getValues() {
const form = await this.getForm();
return form.values;
}
mount(formActions: FormActions) {
if (!this.isMounted) {
Object.assign(this.form, formActions);
this.stateHandler.setConditionTrue();
this.isMounted = true;
}
}
/**
* 根据字段名移除表单项
* @param fields
*/
async removeSchemaByFields(fields: string[]) {
const fieldSet = new Set(fields);
const schema = this.state?.schema ?? [];
const filterSchema = schema.filter((item) => fieldSet.has(item.fieldName));
this.setState({
schema: filterSchema,
});
}
/**
* 重置表单
*/
async resetForm(
state?: Partial<FormState<GenericObject>> | undefined,
opts?: Partial<ResetFormOpts>,
) {
const form = await this.getForm();
return form.resetForm(state, opts);
}
async resetValidate() {
const form = await this.getForm();
const fields = Object.keys(form.errors.value);
fields.forEach((field) => {
form.setFieldError(field, undefined);
});
}
async setFieldValue(field: string, value: any, shouldValidate?: boolean) {
const form = await this.getForm();
form.setFieldValue(field, value, shouldValidate);
}
setState(
stateOrFn:
| ((prev: VbenFormProps) => Partial<VbenFormProps>)
| Partial<VbenFormProps>,
) {
if (isFunction(stateOrFn)) {
this.store.setState(stateOrFn as (prev: VbenFormProps) => VbenFormProps);
} else {
this.store.setState((prev) => ({ ...prev, ...stateOrFn }));
}
}
async setValues(
fields: Record<string, any>,
shouldValidate: boolean = false,
) {
const form = await this.getForm();
form.setValues(fields, shouldValidate);
}
async submitForm(e?: Event) {
e?.preventDefault();
e?.stopPropagation();
const form = await this.getForm();
await form.submitForm();
const rawValues = toRaw(form.values || {});
await this.state?.handleSubmit?.(rawValues);
return rawValues;
}
unmounted() {
this.state = null;
this.isMounted = false;
this.stateHandler.reset();
}
async validate(opts?: Partial<ValidationOptions>) {
const form = await this.getForm();
return await form.validate(opts);
}
}

View File

@@ -0,0 +1,24 @@
import type { FormRenderProps } from '../types';
import { computed } from 'vue';
import { createContext } from '@vben-core/shadcn-ui';
export const [injectRenderFormProps, provideFormRenderProps] =
createContext<FormRenderProps>('FormRenderProps');
export const useFormContext = () => {
const formRenderProps = injectRenderFormProps();
const isVertical = computed(() => formRenderProps.layout === 'vertical');
const componentMap = computed(() => formRenderProps.componentMap);
const componentBindEventMap = computed(
() => formRenderProps.componentBindEventMap,
);
return {
componentBindEventMap,
componentMap,
isVertical,
};
};

Some files were not shown because too many files have changed in this diff Show More