1150 Commits

Author SHA1 Message Date
李琦
f15bf10553 feat: 优化了若干接口页面,可用性存疑、科室管理、处方发送成功页面 2026-08-12 12:43:30 +08:00
李琦
f622743661 feat: 优化了若干接口页面,可用性存疑 2026-08-12 08:57:15 +08:00
李琦
6db736a6f4 feat:
1. 更新框架
2. 修复框架更新后导致的问题
3. 消息系统升级
2026-08-11 13:30:21 +08:00
李琦
b82754e36b feat:
1. 更新框架
2. 修复框架更新后导致的问题
3. 消息系统升级
2026-08-10 20:08:50 +08:00
李琦
f0a33a628b feat:
1. 更新框架
2. 修复框架更新后导致的问题
2026-08-10 18:44:39 +08:00
李琦
3547c53f89 feat:
1. 更新框架
2026-08-10 17:56:36 +08:00
李琦
82b10bd122 Merge remote-tracking branch 'vben/main' into vben-dev
# Conflicts:
#	.gitignore
#	.husky/pre-commit
#	.vscode/extensions.json
#	.vscode/settings.json
#	README.ja-JP.md
#	README.md
#	README.zh-CN.md
#	apps/backend-mock/api/auth/codes.ts
#	apps/backend-mock/api/auth/login.post.ts
#	apps/backend-mock/api/auth/logout.post.ts
#	apps/backend-mock/api/auth/refresh.post.ts
#	apps/backend-mock/api/menu/all.ts
#	apps/backend-mock/api/status.ts
#	apps/backend-mock/api/table/list.ts
#	apps/backend-mock/api/test.get.ts
#	apps/backend-mock/api/test.post.ts
#	apps/backend-mock/api/user/info.ts
#	apps/backend-mock/middleware/1.api.ts
#	apps/backend-mock/nitro.config.ts
#	apps/backend-mock/package.json
#	apps/backend-mock/routes/[...].ts
#	apps/backend-mock/tsconfig.json
#	apps/backend-mock/utils/cookie-utils.ts
#	apps/backend-mock/utils/jwt-utils.ts
#	apps/backend-mock/utils/mock-data.ts
#	apps/backend-mock/utils/response.ts
#	apps/web-antd/.env
#	apps/web-antd/src/adapter/component/index.ts
#	apps/web-antd/src/adapter/form.ts
#	apps/web-antd/src/api/request.ts
#	apps/web-antd/src/layouts/auth.vue
#	apps/web-antd/src/layouts/basic.vue
#	apps/web-antd/src/preferences.ts
#	apps/web-antd/src/router/guard.ts
#	apps/web-antd/src/router/routes/modules/demos.ts
#	apps/web-antd/src/store/auth.ts
#	apps/web-antd/src/views/demos/antd/index.vue
#	apps/web-antdv-next/vite.config.ts
#	apps/web-ele/.env
#	apps/web-ele/index.html
#	apps/web-ele/package.json
#	apps/web-ele/src/adapter/component/index.ts
#	apps/web-ele/src/adapter/form.ts
#	apps/web-ele/src/adapter/vxe-table.ts
#	apps/web-ele/src/api/request.ts
#	apps/web-ele/src/bootstrap.ts
#	apps/web-ele/src/layouts/auth.vue
#	apps/web-ele/src/layouts/basic.vue
#	apps/web-ele/src/locales/index.ts
#	apps/web-ele/src/locales/langs/en-US/demos.json
#	apps/web-ele/src/locales/langs/en-US/page.json
#	apps/web-ele/src/locales/langs/zh-CN/demos.json
#	apps/web-ele/src/locales/langs/zh-CN/page.json
#	apps/web-ele/src/preferences.ts
#	apps/web-ele/src/router/guard.ts
#	apps/web-ele/src/router/routes/core.ts
#	apps/web-ele/src/router/routes/modules/dashboard.ts
#	apps/web-ele/src/router/routes/modules/demos.ts
#	apps/web-ele/src/router/routes/modules/vben.ts
#	apps/web-ele/src/store/auth.ts
#	apps/web-ele/src/views/_core/authentication/code-login.vue
#	apps/web-ele/src/views/_core/authentication/forget-password.vue
#	apps/web-ele/src/views/_core/authentication/register.vue
#	apps/web-ele/src/views/dashboard/analytics/analytics-trends.vue
#	apps/web-ele/src/views/dashboard/analytics/analytics-visits-data.vue
#	apps/web-ele/src/views/dashboard/analytics/analytics-visits-sales.vue
#	apps/web-ele/src/views/dashboard/analytics/analytics-visits-source.vue
#	apps/web-ele/src/views/dashboard/analytics/analytics-visits.vue
#	apps/web-ele/src/views/dashboard/analytics/index.vue
#	apps/web-ele/src/views/demos/element/index.vue
#	apps/web-ele/src/views/demos/form/basic.vue
#	apps/web-ele/tsconfig.json
#	apps/web-ele/tsconfig.node.json
#	apps/web-naive/.env
#	apps/web-naive/index.html
#	apps/web-naive/package.json
#	apps/web-naive/src/adapter/component/index.ts
#	apps/web-naive/src/adapter/form.ts
#	apps/web-naive/src/adapter/vxe-table.ts
#	apps/web-naive/src/api/request.ts
#	apps/web-naive/src/bootstrap.ts
#	apps/web-naive/src/layouts/auth.vue
#	apps/web-naive/src/layouts/basic.vue
#	apps/web-naive/src/locales/index.ts
#	apps/web-naive/src/locales/langs/en-US/demos.json
#	apps/web-naive/src/locales/langs/en-US/page.json
#	apps/web-naive/src/locales/langs/zh-CN/demos.json
#	apps/web-naive/src/locales/langs/zh-CN/page.json
#	apps/web-naive/src/preferences.ts
#	apps/web-naive/src/router/guard.ts
#	apps/web-naive/src/router/routes/core.ts
#	apps/web-naive/src/router/routes/modules/dashboard.ts
#	apps/web-naive/src/router/routes/modules/demos.ts
#	apps/web-naive/src/router/routes/modules/vben.ts
#	apps/web-naive/src/store/auth.ts
#	apps/web-naive/src/views/_core/authentication/code-login.vue
#	apps/web-naive/src/views/_core/authentication/forget-password.vue
#	apps/web-naive/src/views/_core/authentication/register.vue
#	apps/web-naive/src/views/dashboard/analytics/analytics-trends.vue
#	apps/web-naive/src/views/dashboard/analytics/analytics-visits-data.vue
#	apps/web-naive/src/views/dashboard/analytics/analytics-visits-sales.vue
#	apps/web-naive/src/views/dashboard/analytics/analytics-visits-source.vue
#	apps/web-naive/src/views/dashboard/analytics/analytics-visits.vue
#	apps/web-naive/src/views/dashboard/analytics/index.vue
#	apps/web-naive/src/views/demos/form/basic.vue
#	apps/web-naive/src/views/demos/naive/index.vue
#	apps/web-naive/tsconfig.json
#	apps/web-naive/tsconfig.node.json
#	apps/web-naive/vite.config.ts
#	docs/.vitepress/components/demo-preview.vue
#	docs/.vitepress/components/preview-group.vue
#	docs/.vitepress/config/en.mts
#	docs/.vitepress/config/index.mts
#	docs/.vitepress/config/plugins/demo-preview.ts
#	docs/.vitepress/config/shared.mts
#	docs/.vitepress/config/zh.mts
#	docs/.vitepress/theme/components/site-layout.vue
#	docs/.vitepress/theme/components/vben-contributors.vue
#	docs/.vitepress/theme/styles/variables.css
#	docs/package.json
#	docs/src/_env/adapter/component.ts
#	docs/src/_env/adapter/form.ts
#	docs/src/_env/adapter/vxe-table.ts
#	docs/src/commercial/community.md
#	docs/src/components/common-ui/vben-count-to-animator.md
#	docs/src/components/common-ui/vben-drawer.md
#	docs/src/components/common-ui/vben-form.md
#	docs/src/components/common-ui/vben-modal.md
#	docs/src/components/common-ui/vben-vxe-table.md
#	docs/src/components/layout-ui/page.md
#	docs/src/demos/vben-drawer/auto-height/drawer.vue
#	docs/src/demos/vben-drawer/basic/index.vue
#	docs/src/demos/vben-drawer/dynamic/index.vue
#	docs/src/demos/vben-drawer/shared-data/drawer.vue
#	docs/src/demos/vben-drawer/shared-data/index.vue
#	docs/src/demos/vben-form/api/index.vue
#	docs/src/demos/vben-form/basic/index.vue
#	docs/src/demos/vben-form/custom/index.vue
#	docs/src/demos/vben-form/dynamic/index.vue
#	docs/src/demos/vben-form/query/index.vue
#	docs/src/demos/vben-form/rules/index.vue
#	docs/src/demos/vben-modal/auto-height/modal.vue
#	docs/src/demos/vben-modal/basic/index.vue
#	docs/src/demos/vben-modal/dynamic/index.vue
#	docs/src/demos/vben-modal/shared-data/index.vue
#	docs/src/demos/vben-modal/shared-data/modal.vue
#	docs/src/demos/vben-vxe-table/basic/index.vue
#	docs/src/demos/vben-vxe-table/custom-cell/index.vue
#	docs/src/demos/vben-vxe-table/edit-row/index.vue
#	docs/src/demos/vben-vxe-table/fixed/index.vue
#	docs/src/demos/vben-vxe-table/form/index.vue
#	docs/src/demos/vben-vxe-table/remote/index.vue
#	docs/src/demos/vben-vxe-table/tree/index.vue
#	docs/src/demos/vben-vxe-table/virtual/index.vue
#	docs/src/en/guide/essentials/development.md
#	docs/src/en/guide/essentials/external-module.md
#	docs/src/en/guide/essentials/route.md
#	docs/src/en/guide/essentials/server.md
#	docs/src/en/guide/essentials/settings.md
#	docs/src/en/guide/in-depth/access.md
#	docs/src/en/guide/in-depth/loading.md
#	docs/src/en/guide/in-depth/locale.md
#	docs/src/en/guide/in-depth/theme.md
#	docs/src/en/guide/introduction/quick-start.md
#	docs/src/en/guide/introduction/thin.md
#	docs/src/en/guide/introduction/vben.md
#	docs/src/en/guide/other/faq.md
#	docs/src/en/guide/project/dir.md
#	docs/src/en/guide/project/standard.md
#	docs/src/en/guide/project/tailwindcss.md
#	docs/src/en/index.md
#	docs/src/friend-links/index.md
#	docs/src/guide/essentials/build.md
#	docs/src/guide/essentials/development.md
#	docs/src/guide/essentials/external-module.md
#	docs/src/guide/essentials/route.md
#	docs/src/guide/essentials/server.md
#	docs/src/guide/essentials/settings.md
#	docs/src/guide/in-depth/access.md
#	docs/src/guide/in-depth/check-updates.md
#	docs/src/guide/in-depth/loading.md
#	docs/src/guide/in-depth/locale.md
#	docs/src/guide/in-depth/theme.md
#	docs/src/guide/introduction/quick-start.md
#	docs/src/guide/introduction/thin.md
#	docs/src/guide/introduction/vben.md
#	docs/src/guide/introduction/why.md
#	docs/src/guide/other/faq.md
#	docs/src/guide/project/dir.md
#	docs/src/guide/project/standard.md
#	docs/src/guide/project/tailwindcss.md
#	docs/src/index.md
#	docs/tsconfig.json
#	package.json
#	packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue
#	packages/constants/src/core.ts
#	packages/effects/common-ui/src/components/index.ts
#	packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue
#	packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue
#	packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue
#	packages/effects/layouts/src/authentication/authentication.vue
#	packages/effects/layouts/src/basic/layout.vue
#	packages/effects/layouts/src/widgets/notification/notification.vue
#	packages/effects/layouts/src/widgets/notification/types.ts
#	packages/icons/src/iconify/index.ts
#	packages/icons/src/svg/index.ts
#	packages/stores/src/modules/user.ts
#	playground/src/adapter/component/index.ts
#	playground/src/store/auth.ts
#	pnpm-lock.yaml
#	vben-admin.code-workspace
2026-08-10 16:55:17 +08:00
JyQAQ
e8d35a7471 fix(@vben/styles): 修复弹窗内 tooltip 层级被遮挡问题 (#8240)
将 antd-tooltip 的 z-index 提升至 2001,避免在 Modal/弹窗等高 z-index 容器内的 tooltip 被遮挡
2026-08-07 06:08:20 +08:00
yshbyy
f038166681 chore: 更新.gitattributes文件配置 (#8178)
git 不支持 Shell 的花括号展开语法
2026-08-07 05:16:35 +08:00
dependabot[bot]
88cc837f6a build(deps): bump actions/stale from 10 to 11 (#8227)
Bumps [actions/stale](https://github.com/actions/stale) from 10 to 11.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v10...v11)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: '11'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-07 05:15:36 +08:00
金毛88
82d790a6ab Merge branch 'fork/dream-weave/fix/popup-route-reentry' 2026-08-07 05:14:52 +08:00
金毛88
9c3ba53990 Merge branch 'fork/ming4762/fix-transition-20260805' 2026-08-07 05:11:42 +08:00
金毛88
cb707c8c78 Merge branch 'fork/LayHuts/fix/lint-format' 2026-08-07 05:09:58 +08:00
Dream
98761dce98 fix(@vben-core/popup-ui): stabilize content popups across routes
Mount in-content drawers and modals to the persistent main content element.

Initialize drawer open state when mounted after the API opens.

Fixes vbenjs/vue-vben-admin#8210
2026-08-06 10:17:14 +08:00
zhongming4762
d3dc081b5d perf: 优化路由动画切换 1、切换出现双页面问题 2、切换出现横向和纵向滚动条问题 2026-08-05 19:14:12 +08:00
layhuts
2c1e643ab9 fix: 调整lint执行顺序
使用核心 no-nested-ternary 规则替代 Unicorn 自动修复,避免嵌套三元表达式被错误加括号
调整 oxlint、oxfmt、eslint 和 stylelint 的执行顺序,保证commit与format流程一致
2026-08-05 11:10:21 +08:00
Dream
0a47dc8a3d fix(@vben/playground): reset popup form state 2026-08-05 10:24:28 +08:00
Dream
d0c8c887fd docs: document typed popup data contracts 2026-08-05 09:54:01 +08:00
Dream
f16c780c2b refactor(@vben/web-naive): type modal shared data 2026-08-05 09:52:28 +08:00
Dream
ebe0eadee4 feat(@vben/playground): add typed popup data examples 2026-08-05 09:50:55 +08:00
Dream
3cbb1e8411 refactor(@vben/playground): type popup data consumers 2026-08-05 09:48:27 +08:00
Dream
21d9132703 feat(@vben-core/popup-ui)!: add typed popup data contracts
Bind shared data to modal and drawer APIs and infer it from exposed connected components.

BREAKING CHANGE: getData<T>() is replaced by getData().
Shared data defaults to unknown, and an unset payload returns undefined instead
of an empty object.
2026-08-05 09:46:37 +08:00
dream-weave
9f5b1cd9fb fix(@vben-core/form-ui)!: group field slot component props (#8215)
* refactor(@vben-core/form-ui)!: group field slot component props

* fix(@vben-core/form-ui): stabilize grouped field slot bindings

Resolve function-based common component props with field context.

Preserve internal model and event bindings when custom field slots spread componentProps.

Add regression coverage for array contexts, disabled precedence, and stale binding isolation.

* feat(@vben/vite-config): warn about field slot migration

Print the temporary field-slot migration warning when the development server starts.

Inject the same message into the browser console and keep the plugin serve-only.

* docs(@vben/docs): document field slot migration

Place the breaking field-slot notice at the start of both form documents.

Explain old and new bindings, development warnings, and planned notice removal.

* feat(@vben/playground): extend custom form example

Add a switchable input and select field to demonstrate schema component updates.

Update the composite phone field to emit new tuple values so validation observes changes.
2026-07-31 18:13:49 +08:00
dream-weave
32495e40b2 fix(@vben-core/popup-ui): rebind popup api after HMR (#8217)
* fix(@vben-core/popup-ui): rebind popup api after hmr

* fix(@vben-core/popup-ui): preserve options after remount
2026-07-31 06:13:10 +08:00
dream-weave
cb52807b27 fix(@vben-core/form-ui): correct field slot props (#8216) 2026-07-31 06:07:52 +08:00
MistyMoon
418c16e093 fix(@vben/locales): 修复锁屏弹窗按钮文案歧义 (#8211)
锁屏设置弹窗(lock-screen-modal)的确认按钮作用是输入密码后锁定屏幕,
但按钮文案 i18n key `ui.widgets.lockScreen.screenButton` 原值为「解锁」/「Unlock」,
与弹窗标题「锁定屏幕」及实际动作矛盾,存在歧义。

- zh-CN: 「解锁」->「锁定」
- en-US: 「Unlock」->「Lock」

(同段另有 `unlock` key 值「点击解锁」,用于已锁定后的全屏解锁界面,语义正确,保持不变)
2026-07-30 07:12:08 +08:00
JyQAQ
b04d728249 fix(@vben-core/form-ui): 兼容 zod v4 的 ZodArray,避免误用 unwrap() 丢失数组外壳导致数组校验失败 (#8207) 2026-07-28 15:50:15 +08:00
JyQAQ
44483db9af fix(project): 修复弹窗中表单上传组件预览图片层级问题 (#8205)
将 PreviewGroupComponent 的 hidden class 替换为通过 classes.popup.root
设置更高 z-index,避免在弹窗内被遮挡
2026-07-27 22:37:33 +08:00
layhuts
fbf0cebf4b style: 优化 vxe-table 类型组织结构,将 viewed-row 功能域相关类型进行模块化拆分,由全局类型声明调整为功能目录内聚管理,避免公共 types 文件持续膨胀。 (#8204) 2026-07-27 22:36:04 +08:00
金毛88
98344dfcec Merge branch 'fork/dream-weave/fix-layout-scroll-container' 2026-07-25 20:37:20 +08:00
Dream
6d5ccc7ac8 fix(@vben/layouts): scope hash targets to layout 2026-07-24 17:32:51 +08:00
Dream
b9c6d56f74 fix(@vben/layouts): restore internal scroll navigation 2026-07-24 16:58:39 +08:00
Dream
aaf0da582c fix(@vben-core/layout-ui): stabilize internal layout scrolling 2026-07-24 16:57:32 +08:00
Dream
9a5d052fa5 fix(@vben-core/composables): lock layout scroll container 2026-07-24 16:56:35 +08:00
Dream
baea741432 feat(@vben-core/shared): add layout scroll helpers 2026-07-24 16:55:36 +08:00
xingyu4j
33f4522bff fix: 补充 i18n 缺失的英文 2026-07-24 15:26:08 +08:00
xingyu4j
cb6b0a8872 fix: constrain popper content to available viewport width 2026-07-24 15:21:07 +08:00
xingyu4j
57e2a54219 fix: add missing Symbol descriptions 2026-07-24 15:17:55 +08:00
xingyu4j
4db254cd21 fix: Tailwindcss v4 new variable shorthand syntax 2026-07-24 15:07:17 +08:00
xingyu4j
255a76d79a feat: canonical tailwind class 2026-07-24 15:04:10 +08:00
dream-weave
dcdbfe5dfc fix(@vben-core/form-ui): restore lock screen form submission (#8195)
* fix(@vben-core/form-ui): avoid stale form context access

* fix(@vben/playground): constrain date range codec fields

* test(@vben-core/form-ui): harden benchmark fixtures

* docs(@vben/docs): document form runtime and benchmarks

* fix(@vben/docs): 明确 getValues/submit 返回值及 submit 参数类型
2026-07-24 10:05:27 +08:00
xingyu
0542b509ca chore: bump versions (#8192) 2026-07-23 20:41:13 +08:00
金毛88
eaf585d03a Merge branch 'fork/dream-weave/update-zod' 2026-07-23 20:35:00 +08:00
xingyu4j
0a45cb41fb fix: 添加 StyleProvider 以支持 Tailwind 样式覆盖;移除 InputNumber 组件的宽度样式,优化组件适配;antdv 暂不支持 2026-07-23 17:50:22 +08:00
Dream
517a42ec05 perf(@vben-core/form-ui): benchmark form hot paths 2026-07-23 17:47:57 +08:00
Dream
bacfdf5e42 perf(@vben-core/form-ui): optimize array field updates 2026-07-23 17:47:57 +08:00
Dream
2e69c3fefc fix(@vben/playground): address form codec edge cases 2026-07-23 17:47:57 +08:00
Dream
43b78da024 refactor(@vben/playground): share date range codecs 2026-07-23 17:47:57 +08:00
Dream
decbed20bc fix(@vben-core/form-ui): harden codec value boundaries 2026-07-23 17:47:57 +08:00
Dream
1ac5ac3e82 fix(@vben-core/form-ui): preserve array field focus 2026-07-23 17:47:57 +08:00
zhb410181
8d5a419c50 Merge branch 'vbenjs:main' into main 2026-07-23 15:25:16 +08:00
xingyu
2d82505330 fix: dropdown menu responsiveness and improve dialog handling (#8187)
* fix: 修复用户下拉框小部件菜单行点击无响应及弹框闪退

- 主题/时区/全屏/通知菜单行补充 @select 处理器,点击行任意位置即可触发
- 时区设置弹框宿主移出 DropdownMenu(showButton 模式),修复弹框随下拉框关闭而闪退
- 通知组件暴露 toggle 供下拉框调用
- 偏好设置小部件文案精简,positionMap 顺序调整

* feat: draggable-list.vue 直接复用 SelectItem,用法和 tabbar.vue 完全一致
2026-07-23 15:14:25 +08:00
dream-weave
98dea92225 feat(@vben-core/form-ui): add typed form value codecs (#8189)
* feat(@vben-core/form-ui): add typed form value codecs

* test(@vben-core/form-ui): cover codec value boundaries

* refactor(project): propagate form codec generics

* feat(@vben/plugins): propagate form codecs through vxe grids

* refactor(@vben/playground): migrate form codec examples

* refactor(@vben/playground): migrate query forms to codecs

* docs(@vben/docs): document form value codecs
2026-07-23 15:09:31 +08:00
hiss
e6a23479ee fix: 修复锁定屏幕和退出登录小部件,位置在 user-dropdown 时,使用快捷键唤出两个模态窗 2026-07-23 14:44:32 +08:00
zhb410181
294e9f2966 Merge branch 'vbenjs:main' into main 2026-07-23 13:44:17 +08:00
Harold Zhang
f43de252b5 fix: fixed the icon defect which cause to langauge button can not be clicked (#8184) 2026-07-23 12:20:38 +08:00
zhb410181
ebc0f23e64 Merge branch 'vbenjs:main' into main 2026-07-22 20:35:55 +08:00
dream-weave
28757fb9c8 refactor(@vben-core/form-ui): migrate to Zod 4 and TanStack Form (#8176)
* build(@vben-core/form-ui): update form validation dependencies

* refactor(@vben-core/form-ui): replace vee-validate with TanStack Form

* test(@vben-core/form-ui): cover TanStack Form migration

* docs(@vben/docs): document Zod 4 form migration

* refactor(project): update form adapters

* refactor(project): migrate application form consumers

* refactor(@vben/playground): migrate form examples

* docs(@vben/docs): fix validate return type and required rule empty check in form docs

* fix(@vben-core/form-ui): resolve oxlint and eslint errors

- rewrite nested ternary expressions as if/else in form-field-array.vue and form-runtime.ts
- sort @tanstack/vue-form before @vben-core/composables in package.json

* chore: fix merge artifacts and formatting

- move dependencies before devDependencies in root package.json
- update preferences snapshot for widget positioning fields
- format form-array demo README

* refactor(@vben-core/form-ui): optimize form runtime and value flow

- add fine-grained field selectors and atomic dependency resolution
- expose raw and formatted value snapshots with focused regression coverage

* fix(@vben/layouts): dispose sortable instance on unmount

* docs(@vben/docs): document form runtime API changes

- list added, changed, removed, and deprecated form APIs
- document atomic dependencies and raw versus formatted values
2026-07-22 19:47:07 +08:00
zhb410181
81f69d797d Merge branch 'vbenjs:main' into main 2026-07-22 18:06:57 +08:00
xingyu
6b6708bcf2 fix: 修复点击退出图标确认后不能退出 && 图标排序等数组字段需顺序敏感比较 (#8179)
* chore: 调整 sortablejs 的位置,只在用到的模块引入

* fix: non-null assertion lint error

* fix: 修复点击退出图标确认后不能退出

* fix: 图标排序等数组字段需顺序敏感比较

* feat: 配置中增加 refresh 并统一位置
2026-07-22 17:44:10 +08:00
zhb410181
5c1d31f680 Merge branch 'vbenjs:main' into main 2026-07-22 14:59:16 +08:00
金毛88
899910547f Merge branch 'fork/xingyu4j/deps' 2026-07-22 09:55:03 +08:00
金毛88
70a1d0a2e0 Merge branch 'fork/maoxuner/fix/system-menu-form' 2026-07-21 23:05:33 +08:00
MistyMoon
24eb67224d fix: message/notification demos not auto-dismissing due to wrong duration unit (#8168)
duration was written as 2500 (intended as ms), but ant-design-vue's
message/notification duration is in seconds, so it was interpreted as
2500s (~41min), making the popups appear to never close.
Changed to 2.5 with a comment documenting the unit.

Closes #8144
2026-07-21 22:57:17 +08:00
Jin Mao
e4e25028b5 Merge branch 'main' into fix/system-menu-form 2026-07-21 22:53:06 +08:00
金毛88
ef27b4e349 Merge branch 'fork/maoxuner/fix/lang-doc' 2026-07-21 22:48:41 +08:00
金毛88
b21563a89b feat: 顶栏与用户下拉框按钮样式统一与 tooltip 修复
- 修复 VbenTooltip 的 :content prop 类型错误,改用默认插槽
- 修复 VbenIconButton 的 onClick prop 支持数组合并
- VbenFullScreen 新增 tooltip prop,支持直接设置提示
- 统一顶栏与用户下拉框所有按钮样式,使用 VbenIconButton 包装
- 移除 i18n 中多余的"启用"字样(全局搜索/语言切换)
- 修复 VbenPopover PopoverTrigger 嵌套 button 导致 tooltip 不显示

Co-Authored-By: AtomCode (GLM-5.2) <noreply@atomgit.com>
2026-07-21 22:36:42 +08:00
zhb410181
d06451cdb7 Merge branch 'vbenjs:main' into main 2026-07-21 16:31:51 +08:00
xingyu4j
5318774efe fix: 优化命令执行逻辑,使用串行执行以提高错误可见性 2026-07-20 18:50:49 +08:00
xingyu4j
68a2717a26 fix: test error 2026-07-20 18:48:20 +08:00
xingyu4j
0a2c01e453 fix: 添加 oxlint 禁用注释以避免嵌套三元运算符警告 2026-07-20 18:45:38 +08:00
xingyu4j
b330f08ef4 fix: lint 2026-07-20 18:36:48 +08:00
xingyu4j
6676d962e9 fix: 修复Vben用户信息中的 homePath 属性定义 2026-07-20 18:36:37 +08:00
xingyu4j
dd8307dfe5 chore: update dependencies and refactor command execution 2026-07-20 18:36:09 +08:00
xingyu4j
d0c327e037 chore: update pnpm v11.15.1 2026-07-20 17:40:54 +08:00
xingyu4j
901a147abb Merge branch 'main' of https://github.com/xingyu4j/vue-vben-admin into deps 2026-07-20 17:39:20 +08:00
陆伯言
86e68bdde3 docs: 同步后端接入文档示例菜单地址
提升示例菜单数据的整体一致性,避免多处信息不一致的情况
2026-07-20 01:03:58 +08:00
陆伯言
054deae3bb fix: 菜单组件mock数据与实际保持一致 2026-07-20 01:03:58 +08:00
陆伯言
772286fb73 fix: 路由地址不强制以斜杠开头
兼容新dashboard路由配置
2026-07-20 00:46:27 +08:00
陆伯言
5936ff2e0f fix: 系统菜单管理上级菜单无法显示名称的问题
antdv-next TreeSelect组件没有title插槽
2026-07-20 00:20:00 +08:00
金毛88
f840d235ef feat: 偏好设置小部件支持位置选择与拖拽排序
- 顶栏各小部件按钮支持选择位置(header/user-dropdown/none),偏好设置按钮额外保留 auto/fixed 智能兜底,移动端/全屏内容模式下自动切 fixed 浮动保命,避免偏好入口死锁
- draggable-list.vue 的 listRef 未在模板绑定,Sortable 永不初始化导致小部件无法拖拽;加 ref 绑定与 data-key 让 onEnd 从 DOM 读真实新顺序
- preferences.ts 的 updatePreferences 用 defu(merge) 合并数组,对 widget.order 是 concat 语义,每次拖拽触发更新都会把当前 order 追加一次,localStorage 里膨胀到上百条;改用 mergeWithArrayOverride 整体替换,加载缓存时 sanitizeCachedArray 去重已存在的脏数据
- preferences 按钮之前在 widget.order 里因 labelMap 未登记显示成裸字符串,且 widgetChecks 缺 refresh 导致刷新按钮不按 order 渲染;统一 preferences 与其它 widget 的拖拽排序与位置 select,refresh 补进 rightSlots.widgetChecks 并补模板渲染
- 补 sortablejs 依赖、WidgetPreferences.order 类型字段、preferences-drawer.vue 的 widgetOrder 绑定
2026-07-19 21:34:11 +08:00
陆伯言
930597c605 docs: 更新新增语言包的说明
closed #8160
2026-07-19 02:27:09 +08:00
陆伯言
41c20a43af docs: 更正语言使用示例,确保可用
使用可用的语言配置
修复computed变量使用语法错误

closed #8159
2026-07-19 01:22:00 +08:00
陆伯言
fe65d548be docs: 修复英文语言文件路径错误
closed #8158
2026-07-19 01:17:22 +08:00
金毛88
0cd87c170f feat: 顶栏按钮支持位置选择(header/user-dropdown/none)
为顶栏所有部件按钮添加独立的位置配置,支持在顶栏、用户下拉菜单、不显示
三种选项间切换,每个按钮可独立设置。

- 新增 7 个位置偏好字段:globalSearchButtonPosition、
  themeToggleButtonPosition、languageToggleButtonPosition、
  fullscreenButtonPosition、notificationButtonPosition、
  refreshButtonPosition、timezoneButtonPosition
- 合并 lockScreenButtonPosition、logoutButtonPosition
- header.vue 按位置条件过滤按钮显示
- user-dropdown.vue 新增对应菜单项,支持在用户下拉菜单中显示
- 偏好设置界面仅保留位置选择器(不再需要独立的开关)
- 更新中英文国际化文案

Co-Authored-By: AtomCode (deepseek-v4-flash) <noreply@atomgit.com>
2026-07-18 22:46:31 +08:00
金毛88
b71ebbd673 Merge remote-tracking branch 'pr-8019-temp/main' 2026-07-18 19:21:36 +08:00
金毛88
31d3bd18f3 Merge branch 'fork/LayHuts/feature/form-field-arry' 2026-07-18 19:18:14 +08:00
Jin Mao
eae6771554 Merge branch 'main' into feature/fix_defects_router 2026-07-18 03:54:49 +08:00
JyQAQ
8ac66a96bc fix: 修复弹窗中使用裁剪图片会出现层级问题 (#8156)
* fix(@vben/playground): 弹窗中使用裁剪图片会出现层级问题

* fix(project): 修复弹窗中裁剪图片在 web-antd 与 web-antdv-next 的层级问题
2026-07-17 15:17:37 +08:00
zhb410181
822cec0f5c Merge branch 'vbenjs:main' into main 2026-07-16 13:13:38 +08:00
Guillermo Sagar
6910c691f7 修复动画导致的白屏Bug (#8148)
首次页面加载正常,但是当通过页面点击切换路由的时候白屏,无法正常渲染子页面

 Vue Transition + KeepAlive 空白页 bug**: `<Transition mode="out-in">` + 条件渲染会导致路由切换空白页。`mode="out-in"` 要求旧元素完成 leave 动画后新元素才进入,但路由切换时条件渲染可能在动画前就移除了旧元素,导致 `<Transition>` 永远等待一个不存在的元素 → 死锁。**解决方案**: 移除 `mode="out-in"`(保留 Transition 动画),或在 `apps/web-antd/src/preferences.ts` 设置 `transition: { enable: false }` 关闭动画走 `v-else` 分支。
2026-07-16 09:35:25 +08:00
zhb410181
71c30d3e18 Merge branch 'vbenjs:main' into main 2026-07-14 14:07:09 +08:00
Harold Zhang
263d8e5b52 Merge branch 'main' into feature/fix_defects_router 2026-07-14 09:47:34 +08:00
Harold Zhang
b79b82ecf0 feat: fixed the preference will hide all other button theme/timezone/lanague etc (#8147) 2026-07-13 21:31:06 +08:00
xingyu4j
91a2e80be8 fix: 优化代码格式,合并类型声明 2026-07-13 18:30:19 +08:00
xingyu4j
819ddd4ebb fix(style): 添加no-invalid-position-declaration规则到stylelint配置 2026-07-13 18:29:30 +08:00
xingyu4j
bb6403d513 chore: update deps 2026-07-13 18:29:01 +08:00
xingyu4j
45c3776ffd chore: update pnpm v11.12.0 2026-07-13 18:27:57 +08:00
zhb410181
1d23cd707c Merge branch 'vbenjs:main' into main 2026-07-13 11:22:06 +08:00
Harold Zhang
6eb79b8ef0 Merge branch 'main' into feature/fix_defects_router 2026-07-13 08:59:16 +08:00
zouawen
8b7c245bc7 fix: 修复首选项导航栏宽度问题 (#8136) 2026-07-11 11:43:47 +08:00
Harold Zhang
e416de3290 fix: fixed defects of router 2026-07-10 10:15:40 +08:00
zhb410181
398b445d35 Merge branch 'vbenjs:main' into main 2026-07-09 15:41:03 +08:00
luoqiz
14d03a1c2d fix: 统一BasicUserInfo (#8133) 2026-07-09 13:23:29 +08:00
zhb410181
9769c11de5 fix(style): 修复偏好设置功能tab栏宽度未自适应问题 (#8132) 2026-07-09 13:23:08 +08:00
hiss
cae47e8c7f fix(style): 修复偏好设置功能tab栏宽度未自适应问题 2026-07-08 16:42:04 +08:00
陆伯言
88918aad10 docs: fix typo of env demo (#8129)
closed #8125
2026-07-08 08:38:06 +08:00
陆伯言
75c3a7214b docs: update default home path perferences (#8121)
closed #8117
2026-07-07 21:41:51 +08:00
陆伯言
71bcabd118 docs: update nitro mock server url (#8119)
closed 8113
2026-07-03 17:12:43 +08:00
dream-weave
81619b6090 fix(lint): align eslint and oxlint rules (#8118)
* docs: 路由文档示例代码同步路由组织新规范

* fix(lint): align eslint and oxlint rules

* fix(lint): avoid control character regex
2026-07-03 17:12:13 +08:00
dream-weave
77468ce9a6 docs: 路由文档示例代码同步路由组织新规范 (#8114) 2026-07-02 18:35:54 +08:00
Evan
8779c00670 fix: 修复homePath的路径 (#8110)
* fix: 修复homePath的路径

* fix: 单元测试数据

* chore: 单元测试快照数据

---------

Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2026-07-01 17:31:37 +08:00
金毛88
61f1b53325 fix: 修改默认首页,以适配router重构 2026-07-01 17:02:55 +08:00
layhuts
c56bb7d320 docs: 更新文档 2026-07-01 15:07:56 +08:00
金毛88
1490a93f47 Merge branch 'fork/bnuephjx/refactor/router-redirect' 2026-07-01 13:31:27 +08:00
金毛88
e50296e3c5 Merge branch 'fork/zouawen/main' 2026-07-01 13:06:42 +08:00
陆伯言
5da38ccded fix: 调整mock默认路由 (#8108)
* fix: 调整mock默认路由

1. starting改为running 语义更明确
2. API地址修复
3. 列表顺序调整,登录接口靠前

* docs: 替换axios调用示例

原先/api/user接口地址不对,且是受认证保护的接口,响应异常容易造成误解
2026-07-01 13:02:44 +08:00
layhuts
20b69fa480 revert: 撤销修改 2026-07-01 11:49:27 +08:00
layhuts
fdf2abb702 refactor: 修改form-field-array支持dependencies 2026-07-01 11:08:35 +08:00
layhuts
9d36b34c4c docs: 修复错误的注释说明 2026-07-01 09:52:51 +08:00
dependabot[bot]
9b356d731d build(deps): bump actions/checkout from 6 to 7 (#8080)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-30 22:42:58 +08:00
Evan
18e2bbf969 Merge branch 'main' into refactor/router-redirect 2026-06-30 22:23:54 +08:00
layhuts
14bb94245c feat: 新增logo铺满显示和是否显示text配置 (#8102)
* feat: 新增logo铺满显示和是否显示text配置

* feat: logo.enable=false时隐藏logo区域占位;设置logoMode、showText为必填。

* style: 修复注释问题

* fix: 删除多余属性
2026-06-30 21:50:45 +08:00
Evan
feb0265744 Merge branch 'main' into refactor/router-redirect 2026-06-30 14:26:23 +08:00
xueyitt
7182405d24 fix: 修复弹框自定义宽度 class 被默认 max-w 覆盖的问题 (#8100)
将 modalClass 参数移至 cn() 末尾,确保用户通过 class 传入的宽度样式
优先于内置默认的 max-w-[calc(100vw-20px)] 生效,使 业务使用Modal 上的自定义的max-w-[50%] 等方式能正确控制弹框宽度。
2026-06-30 14:24:18 +08:00
陆伯言
d7d6d2e337 fix: lint issue from a8c3729 (#8098) 2026-06-30 14:23:52 +08:00
Harold Zhang
31c31b914b feat: fix check error (#8094) 2026-06-30 14:23:27 +08:00
Evan
f00a881295 refactor(@vben/access): 重构路由的重定向逻辑
@vben-core/shared
@vben/playground
@vben/backend-mock
@vben/web-antd
@vben/web-antdv-next
@vben/web-ele
@vben/naive
@vben/tdesign
2026-06-30 13:36:37 +08:00
zoumingjun
5ed867eb95 feat: 优化禁用的开关组件也可以查看help帮助信息 2026-06-30 09:39:32 +08:00
zoumingjun
ae5bd3afc5 feat: 首选项导航栏选项标题过长时显示省略号,且增加聚焦时文字提示 2026-06-30 09:37:28 +08:00
vben
a8c3729850 feat: add ICP filing number to copyright across app 2026-06-24 10:04:10 +08:00
gotounix
794edd419e fix: add includes in mock tsconfig (#8085) 2026-06-23 21:47:08 +08:00
layhuts
9a284ee385 style: 处理modal设置class="md:w-5/12"格式时Fullscreen时无法最大化问题 (#8084) 2026-06-23 21:46:43 +08:00
gotounix
e031457271 fix: add missing imports (#8082) 2026-06-23 21:46:19 +08:00
金毛88
0931599f96 chore: update deps 2026-06-21 14:48:51 +08:00
xingyu4j
dc3865f778 fix: 优化 lint 执行策略并修复 pre-commit 依赖解析
- vsh lint 按硬件自适应:CPU<=4 核串行(汇总错误),>4 核并行;
  CPU>4 且空闲内存>8GB 时 oxfmt/oxlint 默认线程数提升至 4,否则维持 2
- lefthook pre-commit 改为串行执行,避免与 check:type 并行导致低配机资源飙升
- pre-commit 仅对暂存文件 lint 并自动修复回填(stage_fixed)
- lint 命令统一加 pnpm exec 前缀,修复 lefthook 经 sh 调用时
  oxlint 找不到 workspace 局部依赖(eslint-plugin-eslint-comments)的问题
2026-06-18 16:35:27 +08:00
yshbyy
45399d0299 fix(@vben-core/shadcn-ui): 补全 ScrollArea onScroll 滚动事件透传 (#8069) 2026-06-18 16:10:21 +08:00
xingyu
dc3466d77a refactor: 将 unicorn / TypeScript 规则迁移至 oxlint,并完善 oxfmt 配置 (#8067)
* chore: update deps

* chore: update archiver v8

* fix: 还原 vue/html-closing-bracket-newline

* feat: 增加默认配置和配置注释

* feat: 增加oxlint默认插件配置和注释

* refactor: remove unicorn ESLint configuration and update dependencies

- Deleted the unicorn ESLint configuration file from the lint-configs package.
- Removed unicorn configuration from the main index file.
- Updated oxlint-config to include a comprehensive set of unicorn rules.
- Adjusted preferences and vxe-table files to disable specific unicorn rules.
- Removed references to eslint-plugin-unicorn from pnpm-lock.yaml and pnpm-workspace.yaml.

* refactor: 移除 eslint 的 @typescript-eslint/eslint-plugin 依赖,将 TypeScript 配置迁移到 oxlint

* feat: open typeAware

* fix: mac 和linux下报错
2026-06-18 16:10:01 +08:00
金毛88
65885ea74b chore: update lockfile 2026-06-16 16:47:33 +08:00
金毛88
769791351f chore: update deps && lint 2026-06-16 16:25:21 +08:00
金毛88
741cbb3794 Merge branch 'fork/xueyitt/feat/feat3' 2026-06-16 16:16:56 +08:00
金毛88
edd110ac4e Merge branch 'fork/xueyitt/feat/feat1' 2026-06-16 16:15:33 +08:00
xueyitt
7824219557 fix: 修正AppPreferences中defaultAvatar、dynamicTitle注释 (#8060) 2026-06-16 14:23:25 +08:00
雪忆天堂
dd4afec7ed feat: workbench公共组件增加支持slot方式进行自定义 2026-06-16 10:01:24 +08:00
雪忆天堂
ebebb42625 feat: 1、FieldMappingTime拆解独立FieldMappingTimeItem+集合形式,方便单独对象定义;
2、表单submitOnChange增加changeDebouncedTime防抖处理,允许自定义防抖周期;
3、handleValuesChange事件set增加cloneDeep,防止对象值污染;
2026-06-16 09:48:27 +08:00
雪忆天堂
d1e6d4a3da Merge remote-tracking branch 'origin/main' 2026-06-16 09:10:50 +08:00
Jefsky Wong
ad3f996bdb fix(@vben/common-ui): prevent footer slot from overlapping content when Page contains Grid (#8056)
The Page component's outer container used min-h-full, which doesn't
provide an explicit height for flex children. Combined with h-full on
the content div, this caused the footer slot to overlap table content
(Grid/vxe-table) because the content area didn't properly account for
footer space in the flex column layout.

Fix:
1. Change outer container from min-h-full to h-full — gives the flex
   container an explicit height so percentage heights resolve correctly.
2. Change content area from static h-full to flex-1 when autoContentHeight
   is false — lets the flex layout naturally distribute remaining space
   between content and footer.

Closes #5494

Co-authored-by: jefsky <jefsky@users.noreply.github.com>
2026-06-16 08:36:39 +08:00
HaroldZhangCode91
68877a7e97 Merge branch 'main' into feature/fix_confirm_regression 2026-06-15 17:46:19 +08:00
雪忆天堂
c5a839f652 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	packages/effects/plugins/src/vxe-table/use-vxe-grid.vue
2026-06-15 17:41:12 +08:00
HaroldZhangCode91
bf8c3d6411 feat: aligns ESLint with oxfmt's behavior (#8054) 2026-06-15 17:25:04 +08:00
HaroldZhangCode91
f753a3b75f Merge branch 'main' into feature/fix_confirm_regression 2026-06-15 16:45:08 +08:00
曾兴顺
fcf726f953 fix: 修复Tree组件不支持半选的问题(子节点全选时父节点选中图标为勾选状态,子节点部分选中时父节点图标为减号,也就是版勾选状态,子节点未被选中时,父节点不被选中) (#8050) 2026-06-15 16:38:21 +08:00
Harold Zhang
16ebc67796 feat: fixed useScrollLock() can not be unlock 2026-06-15 16:34:53 +08:00
Harold Zhang
6b109c9ae6 fix: fixed regression of confirm 2026-06-15 16:24:17 +08:00
xingyu
160114c5e0 fix: select and user-dropdown (#8042)
* fix: 偏好设置中下拉框无法选择的问题,原因: 同步 shadcn-vue 将 z-popup 同步为 shadcn 的 z-50

* fix: 鼠标hover到用户登录头像 下拉来回闪烁 隐藏 显示
2026-06-10 21:26:47 +08:00
金毛88
4b1fada0ab Merge branch 'fork/zhb410181/fix/style' 2026-06-09 11:22:58 +08:00
hiss
5c9daab2ff fix(style): 1.修复ToggleGroupItem边框样式问题 2.修复用户头像下拉框Badge背景颜色 2026-06-09 08:56:07 +08:00
Harold Zhang
c2a85f4ec2 feat: support unlocking scroll when modal dialog closes 2026-06-08 14:15:31 +08:00
abc_abc
e7f541f37e Merge branch 'main' into main 2026-06-08 10:31:39 +08:00
金毛88
f23c9f5e19 chore: update deps 2026-06-07 18:54:43 +08:00
ddfabc
4459389d4a feat: 将锁定屏幕和退出登录图标从用户下拉菜单移至头部栏
将锁定屏幕(LockKeyhole)和退出登录(LogOut)图标按钮从 UserDropdown 下拉菜单
移至 LayoutHeader 头部栏,位于通知图标的右侧。

变更内容:
- header.vue: 新增 lock-screen-btn 和 logout-btn 插槽,位于 notification 之后;
  添加 LockScreenModal/LogoutModal 及快捷键(Alt+L/Alt+Q)支持;
  新增 avatar/text props 用于锁屏弹窗显示
- layout.vue: 透传 avatar/text props 和 logout 事件
- user-dropdown.vue: 移除锁定屏幕和退出登录的菜单项、弹窗及快捷键逻辑
- 所有 5 个应用 basic.vue: 向 BasicLayout 传递 avatar/text,绑定 @logout 事件

头部右侧图标顺序: ... → 全屏 → 通知🔔 → 锁定🔒 → 退出🚪 → 用户头像
2026-06-06 23:24:54 +08:00
xingyu4j
8e0564cc42 chore: node v24 2026-06-06 21:07:55 +08:00
xingyu4j
017b3c3fce ci: bump actions/stale from 9 to 10 2026-06-06 20:49:34 +08:00
xingyu4j
126275b417 ci: bump dessant/lock-threads from 5 to 6 2026-06-06 20:48:51 +08:00
xingyu4j
bc908e29eb ci: bump amannn/action-semantic-pull-request from 5 to 6 2026-06-06 20:48:19 +08:00
xingyu4j
efe3c25310 chore: update deps 2026-06-06 19:36:39 +08:00
xingyu4j
d85ac2c976 feat: form 表单赋值 2026-06-06 19:33:31 +08:00
xingyu4j
c816591b69 fix: modal 下拉等不能选中 2026-06-06 19:32:31 +08:00
xingyu4j
564b349700 fix: vue/custom-event-name-casing 2026-06-06 16:21:25 +08:00
xingyu4j
ce495d67a0 feat: 同步 antdv-next 的组件 2026-06-06 16:20:36 +08:00
xingyu4j
8094d1ffb9 chore: update deps 2026-06-06 16:19:32 +08:00
afe1
748b182e44 fix: workflow (#8013)
* fix: catelog

* fix: system

* chore: sync upstream changes

* feat:  component and workflow error
2026-06-05 05:13:08 +08:00
金毛88
6544340d80 Merge branch 'fork/HaroldZhangCode91/feature/fix_freeze_scrollbar_of_modal' 2026-06-04 13:54:21 +08:00
Harold Zhang
6b7cb7b1fc feat: fixed the regression of changing Menu to MenuUI 2026-06-04 11:46:53 +08:00
Harold Zhang
d90d45a128 fix: fixed modal freeze issue 2026-06-04 11:19:38 +08:00
Harold Zhang
66077b3bcf Merge branch 'main' into feature/fix_freeze_scrollbar_of_modal 2026-06-03 18:07:37 +08:00
Harold Zhang
0328594747 feat: fixed the overlay layer can not work with reka-ui 2026-06-03 17:52:41 +08:00
金毛88
790e114d41 chore: 固定vite 8.0.10,避免编译后异常 2026-06-03 17:32:13 +08:00
Harold Zhang
cc60ca9592 feat: fixed the defects the scrollbar disapear when modal close 2026-06-03 16:10:17 +08:00
HaroldZhangCode91
79707a2ebd feat: fixed regression of modal for element plus (#7999) 2026-06-03 13:27:12 +08:00
金毛88
0eb72ca4fd feat: add useTDesignDesignTokens 2026-06-03 13:25:23 +08:00
金毛88
7fd4b1de04 Merge branch 'fork/SaleriHQ/feat/form-field-array' 2026-06-03 13:22:21 +08:00
Saleri
9ffd42f013 chore: add changeset for form field array 2026-05-31 23:06:00 +08:00
Saleri
40101911f0 style: format naive styles 2026-05-31 16:21:13 +08:00
xingyu
04fbb7a556 chore: 升级 shadcn-vue 组件到v4最新版 (#7972)
* fix: useStore is deprecated

* chore: update deps

* feat: 升级shadcn-ui v4

* fix: workbench style

* feat: 升级shadcn-ui v4 step2

* feat: 升级shadcn-ui v4 step3

* chore: 升级shadcn v4

* fix: pagination

* fix: dark style

* fix: doc import

* feat: 增加详情组件,参考 antdv-next

* docs: descriptions docs

* docs: Browser Support

* feat: add table action

* feat: icon use vbenIcon

* fix: type error

* fix: dropdown popConfirm

* feat: 使用默认的文字交互

* feat: 优化渲染性能
2026-05-31 15:18:46 +08:00
Saleri
e5f9106caa feat(@core/form-ui): 新增 useVbenForm 数组编辑器 VbenFormFieldArray 2026-05-31 15:03:55 +08:00
afe1
108d7ff335 chore: add commitlint config declaration (#7968)
* fix: catelog

* fix: system

* chore: sync upstream changes

* types: add commitlint config declaration
2026-05-28 15:50:47 +08:00
leo
1d6842fa69 build: change runtime config asset naming strategy for PWA compatibility (#7963)
replace query-based config url (_app.config.js?v=...)
with deterministic hashed filename (_app-config-v{version}-{hash}.js)
ensure service worker precache matches runtime injected asset
2026-05-28 12:53:51 +08:00
Saleri
d6a9eaf9e9 fix: 修复 web-naive 表单页 Input 输入 _ 不显示的问题 (#7962) (#7965)
* fix(@vben/web-naive): 修复 naive input 输入 _ 不显示的问题 (#7962)

* fix(@vben/web-naive): 限制 input 字体修复作用域,避免全局影响
2026-05-28 12:49:48 +08:00
boisduval
f7540c119b fix: 修复 useVbenModal useVbenDrawer 传入参数失效的问题 (#7964)
- 把provide的key值修改为与inject一致的options
2026-05-28 12:49:23 +08:00
过冬
acf289381e fix(@vben-core/popup-ui): modal 响应式适配,支持视口自适应 (#7951) 2026-05-25 13:27:17 +08:00
PanFu
f813245827 feat: 偏好设置的快捷键列表追加ESC快捷键的控制(关闭当前窗口) (#7947)
* feat: 快捷键追加ESC控制,关闭当前窗口

* feat: 偏好设置中,页面切换动画的颜色看不清的问题(使用当前主题色)

* feat: 三种弹出框支持快捷键ESC动作

* feat: 代码自动格式化(3个框架改动)

* feat: 代码自动格式化(3个框架改动)

* fix: 修正locale数据获取方式

* 单元测试问题修改

* 单元测试问题修改

* fix: 解决代码评论的问题

* fix: 解决代码评论的问题

* fix: 解决代码评论的问题

* fix: 解决代码评论的问题

* 单元测试问题修改

* fix: 解决评论问题

* fix: 解决代码格式导致pnpm run lint报错的问题

---------

Co-authored-by: PanFu <panfu@zhihuaai.com>
2026-05-23 09:50:35 +08:00
过冬
e98f0b7558 fix: 移动端禁用混合布局菜单拆分 (#7949) 2026-05-23 04:21:19 +08:00
Reese Wellin
cd86de54e1 fix(preferences): 修复主题等个性化信息持久化被初始化配置覆盖 (#7948)
调整 initPreferences 中 merge 顺序,使用户缓存优先于 initialPreferences。

Fixes #7943
2026-05-23 04:17:46 +08:00
Jin Mao
60eb1335f8 chore: vite 降级到8.0.10 2026-05-22 13:20:25 +08:00
xingyu
f2b3b12553 chore: pnpm v11 (#7942)
* chore: remove rolldown dep

* fix: issues-helper and maintain-one-comment are temporarily disabled due to security issues

* chore: update deps

* fix: change error type to TypeError for non-browser environment check in LocalStorageDriver

* chore: update pnpm v11
2026-05-22 12:02:14 +08:00
layhuts
c066889c37 Fix: 在isMobile=true时无法自定义Drawer的class问题 (#7941)
* fix: 在isMobile=true时无法自定义Drawer的class问题

* fix: 在ResizableHandle两边增加边距
2026-05-22 11:56:09 +08:00
928646789
6b81d1b0d5 fix: preferences-button click to show setting drawer (#7938) 2026-05-22 07:26:12 +08:00
afe1
126b33687a chore: vite config tsconfig include (#7936)
* fix: catelog

* fix: system

* fix(vite-config): include tsdown config in tsconfig
2026-05-22 07:25:50 +08:00
Jin Mao
5b67c2e740 chore: 更新pnpm-lock 2026-05-21 20:44:38 +08:00
Jin Mao
2d7c3c3072 chore: 更新pnpm-lock 2026-05-21 20:40:49 +08:00
Jin Mao
5cc68c9dd0 chore: 更新 vite 依赖版本
- 将 vite 版本从 ^8.0.13 降级到 ^8.0.10
- 保持其他依赖包版本不变
2026-05-21 20:22:28 +08:00
Jin Mao
63a38dce49 refactor(workflow): 优化发布工作流配置
- 简化触发条件,移除冗余的推送事件配置
- 更新标签创建输入参数描述,明确格式要求
- 移除 Husky 环境变量配置
- 重命名构建作业为发布作业,提高语义清晰度
- 移除 Node.js 版本矩阵策略配置
- 优化版本提取逻辑,支持工作流调度和推送事件
- 统一标签前缀处理,确保版本格式一致性
- 移除注释掉的冗余步骤配置
- 简化发布配置,移除不必要的发布操作注释块
2026-05-21 09:07:59 +08:00
Jin Mao
629f747795 feat(workflow): 添加手动触发release标签工作流
- 添加 workflow_dispatch 触发器支持手动运行
- 新增 tag 输入参数用于指定创建的标签
- 设置默认标签值为 staging
- 保留原有的 push tags 自动触发功能
2026-05-21 08:54:51 +08:00
Jin Mao
8585008f79 chore: release v5.7.0 2026-05-20 17:45:44 +08:00
xingyu
00990d9453 Merge branch 'main' into fix/lint 2026-05-20 17:38:19 +08:00
PanFu
2a84b590b5 feat: 偏好设置按钮,支持在右上角用户的下拉框中展示;偏好设置中支持设置时区(多一个入口); (#7931)
* feat: 偏好设置按钮支持显示在用户下拉窗中的特性

* feat: 时区设置功能支持在偏好设置列表进行配置

* feat: 偏好设置按钮支持显示在用户下拉窗中的特性 - 完善示例代码

* feat: 时区设置功能支持在偏好设置列表进行配置

* feat: 时区设置功能支持在偏好设置列表进行配置-单元测试报错问题

* feat: 时区设置功能支持在偏好设置列表进行配置-修改代码QC问题

---------

Co-authored-by: PanFu <panfu@zhihuaai.com>
2026-05-20 17:24:53 +08:00
PanFu
769c970e08 fix: 修复三个问题:偏好配置项修改后重启不会生效;锁屏弹出框的按钮文字错误;右上角偏好设置按钮排序问题优化; (#7930)
* fix: 修正偏好设置加载缓存的偏好设置并与初始配置合并的顺序

* fix: 修正锁屏弹出框的按钮文字

* fix: 偏好设置按钮排序优化(取第三个占位的数字,若是第三个占位不是数字,则自动分配排序索引)

* fix: 修正偏好设置加载缓存的偏好设置并与初始配置合并的顺序 - 代码QC问题修改

---------

Co-authored-by: PanFu <panfu@zhihuaai.com>
2026-05-20 17:24:18 +08:00
xingyu4j
4d3c481a93 fix: 当lint检查出问题后,不能在终端终止 2026-05-20 16:39:03 +08:00
xingyu4j
fda4b39c01 chore: update deps 2026-05-20 16:38:19 +08:00
xingyu4j
74d8942f39 chore: remove Unused deps 2026-05-20 16:24:59 +08:00
xingyu4j
9ec98f0846 refactor: replace depcheck with knip for dependency checking
Migrate vsh check-dep from depcheck to knip, reducing
315 transitive dependencies. Config is inlined in
DEFAULT_CONFIG, matching the check-circular pattern.
Also re-export CollapsibleParams from @vben/common-ui.
2026-05-20 16:14:21 +08:00
xingyu4j
f71094e878 refactor: migrate json-viewer from vue-json-viewer to vue-json-pretty
- Replace vue-json-viewer with vue-json-pretty (actively maintained, Vue 3 native)
- Map original props to vue-json-pretty API in bindProps for backward compatibility
- Implement copy functionality via renderNodeActions slot with i18n support
- Update style.scss from .jv-* to .vjs-* class names
2026-05-20 14:39:17 +08:00
xingyu4j
9badda3d11 chore: update deps 2026-05-20 11:30:03 +08:00
xingyu4j
03fcecadcc fix: lefthook config 2026-05-19 16:13:00 +08:00
xingyu4j
3a88adb8a6 feat: test 2026-05-19 16:10:18 +08:00
xingyu4j
c759cb2593 fix: lint config 2026-05-19 16:08:10 +08:00
xingyu4j
f77166b3a2 chore: update deps 2026-05-19 15:59:43 +08:00
xingyu4j
f7928b34b2 fix: lint 2026-05-19 15:58:34 +08:00
xingyu4j
454a5b54bd chore: lefthook config 2026-05-19 15:54:03 +08:00
Jin Mao
a4dd9d30ce chore: release 5.7.0 2026-05-19 14:39:46 +08:00
Jin Mao
76cfcda2e9 Merge branch 'fork/xingyu4j/antdv-next' 2026-05-19 14:14:28 +08:00
橙子
7ec4df4995 fix: search-panel when ArrowUp and ArrowDown (#7922) 2026-05-19 13:40:50 +08:00
leo
d71c81e8ff style: apply vsh lint formatting (#7923) 2026-05-19 13:40:13 +08:00
xingyu4j
aac626da32 feat: add system user view 2026-05-18 21:45:17 +08:00
xingyu4j
5db93a345a fix: doc build error 2026-05-18 20:17:35 +08:00
xingyu4j
7c943cc06b chore: disable oxc typeAware and add --threads option for oxlint
Type-aware linting was consuming excessive memory with nearly all
type-aware rules turned off. Add --threads CLI option to control
oxlint parallelism.
2026-05-18 18:46:13 +08:00
xingyu4j
5c8dd1a6da chore: docs config 2026-05-18 18:35:34 +08:00
xingyu4j
6592135cc5 chore: update vitepress v2 2026-05-18 18:23:10 +08:00
xingyu4j
2f16ee7cf5 docs: use antdv-next 2026-05-18 17:30:59 +08:00
xingyu4j
0c1b737325 fix: fix lint && typecheck 2026-05-18 16:50:14 +08:00
xingyu4j
5bbdcffb97 Merge branch 'main' into antdv-next 2026-05-18 16:38:56 +08:00
xingyu4j
1867015e97 Merge branch 'antdv-next' of https://github.com/xingyu4j/vue-vben-admin into antdv-next 2026-05-18 16:35:28 +08:00
xingyu
b6aeadd9a2 Merge branch 'main' into antdv-next 2026-05-18 16:35:18 +08:00
xingyu4j
1e44b87359 refactor: migrate playground deprecated antdv-next APIs
- Modal: destroyOnClose → destroyOnHidden
- Card: body-style → styles.body
- Alert: message prop/slot → title
- Spin: tip → description, wrapper-class-name → classes.root
2026-05-18 16:35:06 +08:00
xingyu4j
a1081bf7a6 fix: 修复 InputNumber 组件宽度在表单中不占满的问题 2026-05-18 16:28:19 +08:00
xingyu4j
9bb2026b4d fix: 修复 InputNumber 组件宽度在表单中不占满的问题 2026-05-18 16:25:49 +08:00
xingyu4j
4554cd016a fix: lint 2026-05-18 16:19:53 +08:00
xingyu4j
350d5ee60e refactor: playground use antdv-next 2026-05-18 16:18:46 +08:00
xingyu4j
1ec058cbe3 chore: update deps 2026-05-18 15:06:59 +08:00
xingyu4j
eb9cdbab9b fix: lint 2026-05-16 12:55:19 +08:00
xingyu4j
4907f281af chore: 更新 pnpm-workspace.yaml 配置,添加 publicHoistPattern 和 allowBuilds 设置 2026-05-16 11:56:39 +08:00
xingyu4j
aadf9b6e39 chore: update deps 2026-05-16 11:52:20 +08:00
Jin Mao
84e77f64ea Merge remote-tracking branch 'origin/main' 2026-05-16 11:18:52 +08:00
guoqiangui
3e89077d46 fix(deploy): use IMAGE_NAME variable in remove_image instead of hardcoded name (#7907)
The `remove_image` function was using a hardcoded image name `vben-admin-pro`
instead of the `$IMAGE_NAME` variable (`vben-admin-local`), so the old local
image was never actually cleaned up before each build.

Co-authored-by: guoqiangui <guoqiangui@zhongshitech.cn>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 11:18:09 +08:00
Jin Mao
c8c425538f Merge branch 'fork/xueyitt/main' 2026-05-16 10:49:33 +08:00
Jin Mao
b04c10aab6 Merge branch 'fork/LayHuts/feature/vxe-table-viewed' 2026-05-16 10:48:00 +08:00
JyQAQ
b5f79db321 fix(@vben/plugins): 修复 tiptap 重复注册扩展警告 (#7917)
StarterKit v3.22.0 已默认包含 Document、Link、Underline 扩展,
与单独导入产生重复注册,导致控制台警告:
[tiptap warn]: Duplicate extension names found: ['link', 'doc', 'underline']

- 移除 Document 单独导入和使用,StarterKit 已内置
- 移除 Underline 单独导入和使用,StarterKit 已内置
- StarterKit 配置中添加 link: false,禁用内置 Link,
  保留自定义配置的 Link.configure({...})
2026-05-16 10:45:30 +08:00
PanFu
42d82875ce feat: 1、完善tree组件的全选状态不正确、全选没有label、item内容超长导致复选框对齐错乱、item内容超长没有tips无法看到完整内容的问题 (#7915)
Co-authored-by: PanFu <panfu@zhihuaai.com>
2026-05-16 10:44:55 +08:00
Akuria
4d8d2de6ad fix: guard svg icon loading during docs SSR (#7912) 2026-05-16 10:43:47 +08:00
Akuria
294700a247 fix: skip fixed footer height in auto-content-height calculation (#7910)
* fix: skip fixed footer height in auto-content-height calculation

When the Page component's footer has position: fixed, it is removed
from the normal document flow and should not be subtracted from the
available content height. Previously, the footer's offsetHeight was
always subtracted, causing incorrect height calculation for fixed
footers.

Also reset shouldAutoHeight before recalculating to prevent stale
state on hot reload.

Fixes #4576

* fix: replace getComputedStyle footer height check with footerFixed prop

Use an explicit `footerFixed` boolean prop instead of runtime
getComputedStyle detection to determine whether the footer height
should be excluded from content height calculation. This avoids
unreliable style queries and makes the behavior deterministic.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 10:43:10 +08:00
Akuria
f55b18ffd7 fix: update primary color when toggling dark/light mode with custom theme (#7909)
When a custom theme is selected and the user toggles between dark and
light mode, the primary color was not being recalculated. This was caused
by a guard condition in the builtin theme watcher that skipped updating
themeColorPrimary for custom themes during mode changes.

Remove the guard so that the primary color is always recalculated from
the theme preset when the mode changes, ensuring Element Plus CSS
variables stay in sync.

Fixes #6615
2026-05-16 10:42:35 +08:00
Akuria
ca5931e8c4 fix: preserve tree default value when treeData starts empty (#7908)
When treeData is initially an empty array (e.g. before async data
arrives), updateTreeValue() would clear the modelValue because no
matching items could be found in the empty flattened data. This caused
default values to be lost.

Only call updateTreeValue() when flattenData has items, so that
modelValue is preserved until the actual tree data arrives.

Fixes #6522
2026-05-16 10:41:42 +08:00
JyQAQ
aac4e88353 docs(@vben/docs): 添加 VCropper 图片裁剪组件文档 (#7904)
* docs(@vben/docs): 添加 VCropper 图片裁剪组件文档

- 新增中文文档 docs/src/components/common-ui/vben-cropper.md
- 新增英文文档 docs/src/en/components/common-ui/vben-cropper.md
- 新增基础用法示例 demos/vben-cropper/basic
- 新增固定比例裁剪示例 demos/vben-cropper/aspect-ratio
- 更新侧边栏配置添加 Cropper 入口

* fix: 更正跨域图片描述并修复 demo 内存泄漏

- 文档更正:网络图片导出裁剪结果需服务端 CORS 支持
- 修复 URL.createObjectURL 内存泄漏:添加 revokeObjectURL 释放
2026-05-11 12:50:44 +08:00
雪忆天堂
9b54e50510 fix: 修正vxtable不存在formConfig时,直接变更data失效问题 2026-05-11 10:10:34 +08:00
xueyitt
30356a24e6 fix: 修正vxtable不存在formConfig时,直接变更data失效问题
修正vxtable不存在formConfig时,直接变更data失效问题
2026-05-11 10:09:47 +08:00
MistyMoon
ba60bc3c14 fix(@vben/layouts): correct logo theme in semi-dark sidebar (#7785) (#7902) 2026-05-10 10:41:43 +08:00
JyQAQ
f5feddc6c7 feat(@vben/plugins): tiptap 组件新增 maxHeight 属性支持及文档 (#7897)
* feat(@vben/plugins): tiptap 组件新增 maxHeight 属性支持

- 新增 maxHeight prop 支持限制编辑器最大高度
- 编辑器内容区超出最大高度时自动滚动
- 移除 style.css 中未使用的 CSS 规则

* docs(@vben/plugins): 添加 tiptap 富文本编辑器组件文档

- 新增中文文档 docs/src/components/common-ui/vben-tiptap.md
- 新增英文文档 docs/src/en/components/common-ui/vben-tiptap.md
- 新增基础用法示例 demos/vben-tiptap/basic
- 新增图片上传示例 demos/vben-tiptap/image-upload
- 更新文档侧边栏配置

* fix(@vben/plugins): extract URL from response in image upload callback

The upload callback was incorrectly passing the AxiosResponse object
to resolve() instead of extracting the actual image URL string.
This caused the editor to insert [object Object] as image src,
resulting in broken images.

* chore: add changeset for tiptap maxHeight feature

* Revert "chore: add changeset for tiptap maxHeight feature"

This reverts commit a28fc4441f14641f6af6c1a143aa6959591315b2.
2026-05-10 10:38:21 +08:00
Yanghai.Lin
0868deb82b fix: 修复 Input 组件 focus 边框被裁剪问题 (#7894)
* fix(other): 修复 oxlint ignorePatterns 导致 pre-commit hook 失败

* fix(@vben-core/shadcn-ui): 修复 Input 组件 focus 时边框被父容器 overflow hidden 裁剪

* fix(@vben-core/shadcn-ui): 修复 SelectTrigger 组件 focus 时边框被父容器 overflow hidden 裁剪
2026-05-10 10:37:39 +08:00
layhuts
1299acd8f9 fix: 获取已存在的 key,避免重复写入刷新过期时间 2026-05-09 23:27:25 +08:00
layhuts
43717807a4 style: reformat code 2026-05-09 23:18:44 +08:00
layhuts
1b4e126128 fix: 处理localStorageDriver在某些受限浏览器环境下报错导致无法使用 2026-05-09 23:10:05 +08:00
layhuts
d23b246aee fix: 处理localStorage prefix === ''时提醒用户可能会全部删除数据 2026-05-09 23:04:38 +08:00
layhuts
71f2e5f504 fix: 去除onConfirm中的setTimeout 2026-05-09 22:51:39 +08:00
layhuts
4bbd34fab9 fix: 修复 labelField 和 nameField 2026-05-09 22:28:03 +08:00
layhuts
08e4bb40b4 style: reformat code 2026-05-09 18:28:23 +08:00
layhuts
9c49f4bb1e refactor: 优化viewed实例初始化,rowStyle rowClassName 从最新的配置中读取 2026-05-09 18:27:09 +08:00
layhuts
28905b0bec style: reformat code 2026-05-09 14:08:19 +08:00
layhuts
bbcad709ca style: 修改注释 2026-05-09 14:07:30 +08:00
layhuts
a5f0537cb0 fix: 处理viewedKeys由于 FIFO 顺序,显式提供的值可能会被异步存储恢复静默地移除。 2026-05-09 13:38:50 +08:00
layhuts
c78d89f549 fix: 处理非原子性的先清除后写入操作会setKeys带来永久性数据丢失的风险 2026-05-09 13:16:50 +08:00
layhuts
f2a17cbe78 fix: 处理getViewedKeys()返回对内部可变对象的直接引用问题 2026-05-09 13:10:41 +08:00
layhuts
9667232684 fix: 加上 - 分隔符来避免跨前缀误匹配 2026-05-09 12:56:50 +08:00
layhuts
1f584ff0c9 fix: 处理window不可用时降级使用Memory 2026-05-09 12:49:21 +08:00
layhuts
75ed17a1f9 docs: 更正saveToCache所属组件 2026-05-09 12:41:10 +08:00
layhuts
cc6ccaab38 docs: 为符合 Markdown lint 规范,指定代码块语言。 2026-05-09 12:38:13 +08:00
layhuts
0be4b51eaa fix: 解决window在构造函数中进行访问破坏SSR/Node环境。 2026-05-09 12:33:15 +08:00
layhuts
b40822e3ed fix: 解决indexedDB的getDB在失败重试时永远返回错误Promise问题 2026-05-09 12:02:41 +08:00
layhuts
df5cb426d1 fix: 解决indexedDB的setItem、,removeItem以及clear在请求成功时而不是事务完成时触发resolve问题 2026-05-09 11:54:11 +08:00
layhuts
2d36d6b510 style: reformat code 2026-05-09 11:03:47 +08:00
layhuts
88d5661e0c refactor: 重构ViewedRowPersistOptions处理扁平化问题
改成按 type 字段区分的联合类型
2026-05-09 11:02:16 +08:00
layhuts
8ce773f264 feat: 在storage-manager添加keys方法 2026-05-09 10:58:41 +08:00
layhuts
329fa68207 fix: 手动操作行标记示例时动态获取列表前两行 2026-05-09 09:23:10 +08:00
layhuts
e1f6449073 feat: 表格已读行操作标记 2026-05-08 20:03:05 +08:00
layhuts
51e8b27d4c style(@vben-core/shared): formatting 2026-05-08 17:36:47 +08:00
layhuts
e555ee065e feat(@vben-core/shared): 新增indexedDB
在cache下新增indexedDB缓存
2026-05-08 17:34:54 +08:00
Lin
b5dacd992f feat: add time zone option to preference settings (#7871) 2026-05-03 12:16:58 +08:00
Jin Mao
d55f17670a chore: 更新依赖包版本
- 更新 pkg-types 从 2.3.0 到 2.3.1
- 更新 rolldown 从 1.0.0-rc.15 到 1.0.0-rc.17
- 更新 typescript 从 6.0.2 到 6.0.3
- 更新 vite 从 8.0.8 到 8.0.10
2026-05-01 06:55:42 +08:00
Jin Mao
9f20d52b4e chore: 更新 FTP 部署操作版本
- 将 SamKirkland/FTP-Deploy-Action 从 v4.3.6 升级到 v4.4.0
- 所有部署任务中的 FTP 操作均已更新到新版本
- 保持了所有现有配置和凭据不变
2026-05-01 06:53:06 +08:00
Jin Mao
86445a38e4 Merge branch 'fork/jyqwq/feature/富文本支持图片上传' 2026-05-01 06:49:48 +08:00
leo
9a73e961fc fix(@vben/stores): respect base URL when opening route in new window (#7837)
* fix(@vben/stores): respect base URL when opening route in new window

* fix(@vben/stores): respect base URL when opening route in new window
2026-05-01 06:49:05 +08:00
boisduval
c0b2ef980e fix: 修复 IconPicker 在手动输入时表单值不更新的问题 (#7869)
- 修复 IconPicker.vue 在 updateCurrentSelect 时未同步更新 modelValue 的 Bug
- 优化 IconPicker 适配器配置,使其兼容 Element Plus 的 ElInput 组件
2026-04-30 15:46:07 +08:00
mew
e8dc464e79 fix: issue in tab bar chrome height is not full due to wrapper element div (#7867)
Caused by PR #7858
2026-04-30 15:45:44 +08:00
mew
99c38c93c8 feat: refactor context menu to capture native events (#7858)
* feat: refactor context menu to capture native events

prevent context-menu to show in html input fields

* fix: refactor context-menu.vue for improved structure

* chore: fix format

* chore: remove dead code

* chore: fix lint

* fix: update contenteditable selector in context menu

proposed fixed by coderabitai
2026-04-28 13:36:13 +08:00
yuan.ji
244c0a5884 fix(@vben/plugins): 根据代码审查意见修复 tiptap 图片上传
- 提取 findPlaceholderPos 辅助函数,消除重复的 descendants 查找
- 添加 editor.isDestroyed 守卫,防止操作已销毁编辑器
- renderHTML 不输出上传状态属性,防止 blob URL 泄露到序列化 HTML
- uploadImage 命令返回 boolean,添加 Commands 类型增强,移除 as any
- 拖拽/粘贴多图时仅处理第一张并提示仅支持单图上传
- 自定义 extensions 时不传 imageUpload 给工具栏,toolbar action 加运行时守卫
2026-04-27 14:33:30 +08:00
yuan.ji
c6fd599784 feat(@vben/plugins): 补充 tiptap 图片上传类型、工具栏和示例
- 新增 ImageUploadOptions 类型定义和 imageUpload 属性
- 工具栏图片按钮支持上传/URL 双模式
- playground 添加图片上传 mock 示例
2026-04-27 13:42:56 +08:00
yuan.ji
4ca2f1c6e8 feat(@vben/plugins): tiptap 支持图片上传功能
- 新增 imageUpload 配置项,支持自定义上传接口
- 支持文件选择、拖拽、粘贴三种上传方式
- 上传中显示 blob 预览图 + loading spinner / 进度条
- 支持 accept 和 maxSize 文件校验
- 支持 onUploadError 自定义错误处理
- 未配置 imageUpload 时保持原有 URL 插入行为不变
- 使用 NodeView 实现实时 DOM 控制的进度展示
2026-04-27 13:42:36 +08:00
Jin Mao
36d7dc23fa Merge branch 'fork/zilvya/ta1' 2026-04-26 16:26:30 +08:00
Lgf
42317ddf41 feat(watermark): 添加暗黑模式水印颜色适配
为水印功能添加暗黑模式适配,根据当前主题自动切换水印颜色。在暗黑模式下使用浅色水印,在亮色模式下使用深色水印,提升视觉体验。
2026-04-24 15:42:07 +08:00
boisduval
c7fd6ffb0e feat: 添加日期格式化函数的空值处理
- 当传入的时间参数为 undefined、null 或空字符串时,直接返回空字符串而不是继续执行格式化逻辑,避免无效的时间值导致程序错误。
2026-04-23 17:25:10 +08:00
AxiosLeo
3a83fb0c3e fix: ensure trigger function is awaited in useDependencies (#7830) 2026-04-22 07:09:09 +08:00
AxiosLeo
5907c04e00 fix: update selector for active menu item in useMenuScroll hook (#7829) 2026-04-22 07:08:40 +08:00
Jin Mao
6885927441 chore: fix actions error 2026-04-15 18:49:07 +08:00
2ylllll
c8c589ae7e fix: type check (#7818) 2026-04-15 18:11:06 +08:00
Jin Mao
d0889b5cc4 chore: 更新依赖包版本
- 更新 @tsdown/css 从 0.21.7 到 0.21.8
- 更新 @vitejs/plugin-vue 从 6.0.5 到 6.0.6
- 更新 dotenv 从 17.4.1 到 17.4.2
- 更新 globals 从 17.4.0 到 17.5.0
- 更新 happy-dom 从 20.8.9 到 20.9.0
- 更新 oxlint 从 1.59.0 到 1.60.0
- 更新 tsdown 从 0.21.7 到 0.21.8
2026-04-15 17:28:17 +08:00
Jin Mao
2f1a866cb4 chore: 更新 pnpm action 版本
- 将 .github/actions/setup-node/action.yml 中的 pnpm/action-setup 从 v4 升级到 v6
- 将 .github/workflows/ci.yml 中的 pnpm/action-setup 从 v5 升级到 v6
- 移除重复的 pnpm 安装步骤配置
- 统一使用最新的 pnpm action 版本以获得更好的兼容性
- 保持 run_install 配置为 false 以跳过自动安装依赖
2026-04-15 17:27:57 +08:00
Jin Mao
fee32c1d12 chore: 优化通知组件逻辑
- 移除冗余的空值检查,简化数组长度判断条件
- 统一导入语句的引号格式为双引号
- 优化 VbenScrollbar 组件的显示条件逻辑
- 更新清除按钮的禁用状态判断逻辑
2026-04-15 17:22:39 +08:00
Jin Mao
f2652833a1 Merge branch 'fork/xueyitt/main' 2026-04-15 17:20:10 +08:00
allen
c3aa63982f fix: devtools warning 2026-04-15 16:44:13 +08:00
allen
4a968d9379 fix: devtools warning 2026-04-15 16:39:56 +08:00
allen
ec9b323195 docs: demo注释修改 2026-04-15 14:54:40 +08:00
allen
d69455e8ef fix: dependencies访问extendApi 2026-04-15 14:42:21 +08:00
allen
33e2582f60 fix: fix lint and add new form-ui features
feat(form-ui): 在 dependencies 里提供访问extendApi的能力
2026-04-15 14:21:39 +08:00
allen
991408b451 fix: default precision error 2026-04-13 21:08:03 +08:00
allen
a096073a8e fix: lint 2026-04-13 20:43:29 +08:00
allen
f30157fa59 fix: class 2026-04-13 20:41:43 +08:00
allen
12a81a7a7d fix: demo validator usage & types import 2026-04-13 20:15:47 +08:00
allen
e808fe74c1 Merge branch 'feature-collapsible-component' of https://github.com/2yllll/vue-vben-admin into feature-collapsible-component 2026-04-13 19:44:45 +08:00
allen
4665a787a0 fix: collapsible component css fix 2026-04-13 19:44:21 +08:00
2ylllll
b7774fc9d9 Merge branch 'main' into feature-collapsible-component 2026-04-13 19:26:23 +08:00
allen
6f18718c87 feat: add collapsible 组件,form表单增加单项可折叠,支持schema配置默认关闭/开启
feat: add collapsible 组件,form表单增加单项可折叠,支持schema配置默认关闭/开启
- shadcn-ui 增加 collapsible组件,collapsible-params组件
- form新增支持单项折叠
- collapsible-params组件在Form表单应用
2026-04-13 19:20:01 +08:00
Caisin
2a32715c99 feat: enable project-scoped preferences extension tabs (#7803)
* feat: enable project-scoped preferences extension tabs

Add a typed extension schema so subprojects can define extra settings,
render them in the shared preferences drawer only when configured, and
consume them in playground as a real feature demo. Extension labels now
follow locale keys instead of hardcoded app-specific strings.

Constraint: Reuse the shared preferences drawer and field blocks
Rejected: Add app-specific fields to core preferences | too tightly coupled
Rejected: Inline localized label objects | breaks existing locale-key flow
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep extension labels as locale keys rendered via $t in UI
Tested: Vitest preferences tests
Tested: Turbo typecheck for preferences, layouts, web-antd, and playground
Tested: ESLint for touched preferences and playground files
Not-tested: Manual browser interaction in playground preferences drawer

* fix: satisfy lint formatting for preferences extension demo

Adjust the playground preferences extension demo template so formatter and
Vue template lint rules agree on the rendered markup. This keeps CI green
without changing runtime behavior.

Constraint: Must preserve the existing demo behavior while fixing CI only
Rejected: Disable the Vue newline rule | would weaken shared lint guarantees
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Prefer computed/template structures that avoid formatter-vs-lint conflicts
Tested: pnpm run lint
Not-tested: Manual browser interaction in playground preferences extension demo

* fix: harden custom preferences validation and i18n labels

Tighten custom preferences handling so numeric extension fields respect
min, max, and step constraints. Number inputs now ignore NaN values,
and web-antd extension metadata uses locale keys instead of raw strings.
Also align tip-based hover guards in shared preference inputs/selects.

Constraint: Keep fixes scoped to verified findings only
Rejected: Broader refactor of preferences field components | not needed for these fixes
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Reuse the same validation path for updates and cache hydration
Tested: Vitest preferences tests
Tested: ESLint for touched preferences and widget files
Tested: Typecheck for web-antd, layouts, and core preferences
Not-tested: Manual browser interaction for all preference field variants

* fix: remove localized default from playground extension config

Drop the hardcoded Chinese default value from the playground extension
report title field and fall back to an empty string instead. This keeps
extension config locale-neutral while preserving localized labels and
placeholders through translation keys.

Constraint: Keep the fix limited to the verified localized default issue
Rejected: Compute the default from runtime locale in config | unnecessary for this finding
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Avoid embedding localized literals in extension default values
Tested: ESLint for playground/src/preferences.ts
Tested: Oxfmt check for playground/src/preferences.ts
Not-tested: Manual playground preferences interaction

* docs: document project-scoped preferences extension workflow

Add Chinese and English guide sections explaining how to define,
initialize, read, and update project-scoped preferences extensions.
Also document numeric field validation and point readers to the
playground demo for a complete example.

Constraint: Keep this docs-only and aligned with the shipped API
Rejected: Update only Chinese docs | would leave English docs inconsistent
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep zh/en examples and playground demo paths synchronized
Tested: git diff --check; pnpm build:docs
Not-tested: Manual browser review of the rendered docs site

* fix: harden custom preferences defaults and baselines

Use a locale-neutral default for the web-antd report title.
Also stop preference getters from exposing mutable baseline
or extension schema objects, and add a regression test for
external mutation attempts.

Constraint: Keep behavior compatible with the shipped preferences API
Rejected: Return raw refs with readonly typing only | callers could still mutate internals
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep defensive copies for baseline and schema getters unless storage semantics change
Tested: eslint, oxlint, targeted vitest, filtered typecheck, git diff --check
Not-tested: Full monorepo typecheck and test suite

* test: relax custom preference cache key matching

Avoid coupling the custom-number cache test to one exact
localStorage key string. Match the intended cache lookup
more loosely so the test still verifies filtering behavior
without depending on the full namespaced cache key.

Constraint: Focus the test on cache filtering behavior
Rejected: Assert one exact key | brittle with namespace changes
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Prefer behavior tests over literal storage keys
Tested: targeted vitest, eslint, git diff --check
Not-tested: Full monorepo test suite

---------

Co-authored-by: caisin <caisin@caisins-Mac-mini.local>
2026-04-13 17:52:17 +08:00
Caisin
46f323431c feat(form-ui): support schema valueFormat for getValues payload shaping (#7804)
* feat(@vben-core/form-ui): support schema valueFormat on getValues

Some form fields emit UI-friendly structures such as time-range arrays,
while consumers and backend APIs often need a different payload shape.
This adds schema-level `valueFormat` hooks so `getValues()` can
normalize field output at read time without forcing callers to
post-process every submission path.

Constraint: Must preserve existing range-time mapping and nested field behavior
Constraint: Must not mutate live vee-validate form state while formatting output
Rejected: Global formatter config | too coarse for per-field payload shaping
Rejected: Post-submit-only transform | misses reset/query/change handlers
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep `getValues()` output derivation side-effect free
Directive: Clone raw form values before formatting derived payloads
Tested: vitest form-api test for valueFormat and existing getValues paths
Tested: oxlint on changed form-ui source and test files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors

* fix(@vben-core/form-ui): restore mount compatibility and share field path parsing

Follow-up review found two real regressions and one missing assertion in the
new value formatting flow. `FormApi.mount()` had become breaking by requiring
`componentRefMap`, and delete path resolution duplicated field-name parsing
instead of sharing the reader grammar. This patch restores backward
compatibility, centralizes field-name path parsing, and extends the test to
prove formatting does not mutate live form values.

Constraint: Must preserve current valueFormat behavior and nested field support
Constraint: Must not reintroduce mutation of live vee-validate values
Rejected: Keep duplicated delete parsing | risks grammar drift from read path
Rejected: Only loosen mount tests | would leave consumer-facing API breakage
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Reuse shared field-name parsing for read/delete semantics in form-ui
Tested: vitest form-api test suite
Tested: oxlint on changed form-ui files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors
EOF && git push hekx feature-form-value-format

* fix(@vben-core/form-ui): clear stale component refs on unmount

A follow-up review found that `unmount()` left the private component ref map
populated. Because `mount()` now accepts an optional `componentRefMap`, a later
mount without a new map could silently reuse stale refs from a prior form
instance. This change clears the ref map on unmount and adds a regression test
covering remount behavior without a new ref map.

Constraint: Must preserve backward-compatible optional `mount()` ref map behavior
Constraint: Focus and field-ref lookups must not observe stale refs after unmount
Rejected: Clear refs only during next mount | stale state would still leak between lifecycle calls
Rejected: Remove mount fallback entirely | would undo the compatibility fix
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When mount falls back to internal refs, unmount must always reset that cache
Tested: vitest form-api test suite
Tested: oxlint on changed form-api source and test files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors

* refactor(@vben-core/form-ui): trim redundant valueFormat plumbing

Review feedback identified a few small cleanups in the value formatting path.
This removes an unnecessary shallow clone in `getValues()`, reuses the
already-parsed `rawKey` from `resolveFieldNamePath()` instead of re-resolving
it in multiple helpers, and clarifies the `FormValueFormat` contract for
undefined-as-delete decomposition behavior.

Constraint: Must not change runtime valueFormat behavior or payload shape
Constraint: Documentation and helper cleanup should stay behavior-preserving
Rejected: Leave duplicate raw-key resolution in place | adds needless parsing churn
Rejected: Expand the formatter API further | outside the scope of this cleanup
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep read/format helper plumbing lean and avoid duplicate field-name parsing
Tested: vitest form-api test suite
Tested: oxlint on changed form-ui source and test files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors

* feat(@vben-core/form-ui): document valueFormat with live examples

The new `valueFormat` feature needed a concrete usage path in both the
playground and the docs so users can understand how raw component values differ
from the final payload returned by `getValues()`. This adds a dedicated form
example, wires it into the playground menu, and documents the API with an
interactive docs demo. The preview panels now stay in sync when values are set,
reset, or submitted.

Constraint: Must demonstrate both return-value and setValue decomposition flows
Constraint: Example previews must react to setValues, reset, and manual edits
Rejected: Only document via markdown snippet | insufficient for verifying live payload behavior
Rejected: Reuse an existing basic form page | would bury feature-specific behavior
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep playground and docs demos behaviorally aligned when extending valueFormat examples
Tested: eslint on playground/docs valueFormat demo files and route module
Tested: oxlint on playground route module
Not-tested: Full docs/playground app runtime was not launched in this session

* chore(@vben-core/form-ui): normalize valueFormat demo formatting

The previous feature/docs commit left a few formatter-only adjustments unstaged
after hooks rewrote line wrapping in the new demo and docs pages. This commit
captures those final non-behavioral formatting updates so the branch matches the
current working tree.

Constraint: Must not change runtime behavior or docs meaning
Rejected: Leave post-hook diffs unstaged | branch would not reflect local state
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: After hook-driven rewrites, verify the working tree is clean before final push
Tested: Git diff inspection of remaining changes
Not-tested: No additional runtime verification needed; formatting-only follow-up
EOF && git push hekx feature-form-value-format

* fix(@vben-core/form-ui): remove docs demo dayjs dependency

The docs valueFormat demo imported `dayjs` directly even though the docs
package does not declare it as a dependency. That caused `@vben/docs:build`
to fail in CI during VitePress bundling. This change removes the direct
import, keeps the preview formatter generic for day-like values, and drops
the docs-only preset button that required constructing dayjs instances.

Constraint: Docs build must succeed without adding new package dependencies
Constraint: Playground example should remain unchanged and fully interactive
Rejected: Add dayjs to docs dependencies | unnecessary for a small display demo
Rejected: Externalize dayjs in VitePress build | hides a package boundary issue
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Docs demos should avoid imports only available through transitive deps
Tested: pnpm exec eslint docs/src/demos/vben-form/value-format/index.vue
Tested: pnpm --dir docs run build
Not-tested: No browser-side manual verification of the docs demo in this session

---------

Co-authored-by: caisin <caisin@caisins-Mac-mini.local>
2026-04-13 17:52:17 +08:00
Caisin
2b1fcb038b feat(common-ui): add labelFn support to ApiComponent (#7801)
* feat: allow api-component labels to be derived from option data

ApiComponent already normalizes option records into the label/value shape used by
consuming controls, but label text could only come from a single field. Add
labelFn so callers can build labels from the full option record while keeping
labelField as the fallback path.

This keeps the change inside the existing component instead of introducing a
wrapper, and it also normalizes direct options through the same transform path
as API-loaded options for consistent behavior.

Constraint: Must extend the existing ApiComponent API instead of adding a second
Constraint: wrapper component
Rejected: Add a separate ApiLabelComponent wrapper |
Rejected: extra surface area for one option-mapping concern
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep labelFn as a presentation transform and preserve labelField
Directive: fallback for existing callers
Tested: pnpm exec eslint api-component.vue index.ts types.ts
Tested: pnpm exec vue-tsc --noEmit -p packages/effects/common-ui/tsconfig.json
Not-tested: runtime integration in consuming select/tree-select components

* Update packages/effects/common-ui/src/components/api-component/api-component.vue

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-04-13 17:52:17 +08:00
过冬
d779a39862 fix: antdv-next message/notification 跟随暗色主题 (#7799) 2026-04-13 17:52:17 +08:00
Jin Mao
0c8db0f6be fix: 修复VITE_APP_TITLE变量替换语法
- 将index.html中的<%= VITE_APP_TITLE %>替换为%VITE_APP_TITLE%
- 更新web-antd、web-antdv-next、web-ele、web-naive、web-tdesign应用
- 修改文档中loading组件的VITE_APP_TITLE引用方式
- 修复vite-config插件中默认加载模板的变量语法
- 统一所有应用和模板中的环境变量引用格式
2026-04-13 17:52:17 +08:00
Jin Mao
37393e1820 chore: fix actions error 2026-04-13 17:52:16 +08:00
xingyu4j
93e23c6b05 chore: update deps 2026-04-13 17:52:16 +08:00
xingyu4j
e023a0852a fix: tailwindcss lint config 2026-04-13 17:52:16 +08:00
xingyu4j
306739cabb fix: lint 2026-04-13 17:52:16 +08:00
xingyu4j
093479bb33 chore: remove vite-plugin-html 2026-04-13 17:52:16 +08:00
xingyu4j
bd369df3bc fix: check deps 2026-04-13 17:52:16 +08:00
xingyu4j
4f7b396ebb chore: update deps 2026-04-13 17:52:16 +08:00
xingyu4j
d700b04841 fix: tailwindcss lint 2026-04-13 17:52:16 +08:00
xingyu4j
243456d928 fix: ts config 2026-04-13 17:52:16 +08:00
Jin Mao
7e8b9c2368 fix: 配置 TypeScript 构建根目录
- 添加 rootDir 编译选项指向 ./src 目录
- 保持现有编译配置不变
- 排除测试文件和 node_modules 目录
2026-04-13 17:52:15 +08:00
Jin Mao
92298bac2b chore: update deps 2026-04-13 17:52:15 +08:00
dullathanol
436a865bef chore: 修正注释 2026-04-13 17:52:15 +08:00
dullathanol
185011ee21 fix: tailwindcss config 2026-04-13 17:52:15 +08:00
过冬
feca01484b Merge branch 'vbenjs:main' into main 2026-04-13 17:52:15 +08:00
Jin Mao
35e1166b9f chore: fix lint 2026-04-13 17:52:15 +08:00
dullathanol
d0c17090ef fix: 修正 Modal/Drawer 中 loading 属性注释 2026-04-13 17:52:15 +08:00
dullathanol
cc32ebeb12 feat: 支持 overflow 配置以允许拖拽超出可视区 2026-04-13 17:52:15 +08:00
dullathanol
02372f12ba fix: 弹窗组件拖拽后全屏位置异常 2026-04-13 17:52:15 +08:00
Jin Mao
e9bdbb610a chore: fix lint
- 关闭 vitest/require-mock-type-parameters 规则
2026-04-13 17:52:15 +08:00
dullathanol
2013ba4de4 fix: 补全 ComponentPropsMap 与 Vxe 表格表单链路的类型 2026-04-13 17:52:15 +08:00
dullathanol
e417a2c209 fix: 修复 FormField 在 SFC 中的运行时异常 2026-04-13 17:52:14 +08:00
dullathanol
f1273571c7 fix: 修复部分情况 component 类型丢失问题 2026-04-13 17:52:14 +08:00
dullathanol
064a6a20f0 feat: 表单 Schema 支持组件 Props 映射泛型,同步适配VxeGrid 2026-04-13 17:52:14 +08:00
dullathanol
cb5e7e00f1 refactor: 简化 componentProps 回调的类型写法 2026-04-13 17:52:14 +08:00
dullathanol
5ed39c03a4 fix: 函数式 componentProps 按已注册 component 的 Props 校验返回值 2026-04-13 17:52:14 +08:00
dullathanol
794b103aa9 feat: Schema 中 componentProps 随注册组件联动类型提示 2026-04-13 17:52:14 +08:00
墨苒孤
c7b1bb3492 fix(form): 修复表单示例中 switch 组件无法切换的问题 (#7636) (#7763) 2026-04-13 17:52:14 +08:00
橙子
89349f8d91 fix: interface DropdownMenuProps don‘t have key prop (#7757) 2026-04-13 17:52:14 +08:00
HaroldZhangCode91
8e0b65a0e1 feat: fix oxlint error for oxlint upgrade (#7756)
1. remove unknown rule out of oxlint
2. add the corresponding back to eslint-config
3. fixed the eslint error for package.json
2026-04-13 17:52:13 +08:00
墨苒孤
b096e83f93 fix: make search case-insensitive (#7689) (#7755) 2026-04-13 17:52:13 +08:00
橙子
4a69c9e665 perf: replace onUnMounted to tryOnScopeDispose (#7747)
* perf: replace `onUnMounted` to `tryOnScopeDispose`

* perf: replace `onUnMounted` to `tryOnScopeDispose`
2026-04-13 17:52:13 +08:00
Jin Mao
7a60a081a2 chore: update deps 2026-04-13 17:52:13 +08:00
xingyu4j
c693c854a7 fix: extension-document 2026-04-13 17:52:13 +08:00
xingyu4j
5eca357a5c feat(@vben/plugins): add tiptap rich text editor 2026-04-13 17:52:13 +08:00
xingyu4j
2930dcd78e chore: typescript config is expired‌ 2026-04-13 17:52:13 +08:00
xingyu4j
e421d9d99b chore: update deps 2026-04-13 17:52:12 +08:00
xueyitt
6c029bfa32 Merge branch 'main' into main 2026-04-13 16:10:29 +08:00
雪忆天堂
fe77bc8bc9 feat: 通知模块自定义加强 2026-04-13 16:05:42 +08:00
Caisin
ccabbf0e97 feat: enable project-scoped preferences extension tabs (#7803)
* feat: enable project-scoped preferences extension tabs

Add a typed extension schema so subprojects can define extra settings,
render them in the shared preferences drawer only when configured, and
consume them in playground as a real feature demo. Extension labels now
follow locale keys instead of hardcoded app-specific strings.

Constraint: Reuse the shared preferences drawer and field blocks
Rejected: Add app-specific fields to core preferences | too tightly coupled
Rejected: Inline localized label objects | breaks existing locale-key flow
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep extension labels as locale keys rendered via $t in UI
Tested: Vitest preferences tests
Tested: Turbo typecheck for preferences, layouts, web-antd, and playground
Tested: ESLint for touched preferences and playground files
Not-tested: Manual browser interaction in playground preferences drawer

* fix: satisfy lint formatting for preferences extension demo

Adjust the playground preferences extension demo template so formatter and
Vue template lint rules agree on the rendered markup. This keeps CI green
without changing runtime behavior.

Constraint: Must preserve the existing demo behavior while fixing CI only
Rejected: Disable the Vue newline rule | would weaken shared lint guarantees
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Prefer computed/template structures that avoid formatter-vs-lint conflicts
Tested: pnpm run lint
Not-tested: Manual browser interaction in playground preferences extension demo

* fix: harden custom preferences validation and i18n labels

Tighten custom preferences handling so numeric extension fields respect
min, max, and step constraints. Number inputs now ignore NaN values,
and web-antd extension metadata uses locale keys instead of raw strings.
Also align tip-based hover guards in shared preference inputs/selects.

Constraint: Keep fixes scoped to verified findings only
Rejected: Broader refactor of preferences field components | not needed for these fixes
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Reuse the same validation path for updates and cache hydration
Tested: Vitest preferences tests
Tested: ESLint for touched preferences and widget files
Tested: Typecheck for web-antd, layouts, and core preferences
Not-tested: Manual browser interaction for all preference field variants

* fix: remove localized default from playground extension config

Drop the hardcoded Chinese default value from the playground extension
report title field and fall back to an empty string instead. This keeps
extension config locale-neutral while preserving localized labels and
placeholders through translation keys.

Constraint: Keep the fix limited to the verified localized default issue
Rejected: Compute the default from runtime locale in config | unnecessary for this finding
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Avoid embedding localized literals in extension default values
Tested: ESLint for playground/src/preferences.ts
Tested: Oxfmt check for playground/src/preferences.ts
Not-tested: Manual playground preferences interaction

* docs: document project-scoped preferences extension workflow

Add Chinese and English guide sections explaining how to define,
initialize, read, and update project-scoped preferences extensions.
Also document numeric field validation and point readers to the
playground demo for a complete example.

Constraint: Keep this docs-only and aligned with the shipped API
Rejected: Update only Chinese docs | would leave English docs inconsistent
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep zh/en examples and playground demo paths synchronized
Tested: git diff --check; pnpm build:docs
Not-tested: Manual browser review of the rendered docs site

* fix: harden custom preferences defaults and baselines

Use a locale-neutral default for the web-antd report title.
Also stop preference getters from exposing mutable baseline
or extension schema objects, and add a regression test for
external mutation attempts.

Constraint: Keep behavior compatible with the shipped preferences API
Rejected: Return raw refs with readonly typing only | callers could still mutate internals
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep defensive copies for baseline and schema getters unless storage semantics change
Tested: eslint, oxlint, targeted vitest, filtered typecheck, git diff --check
Not-tested: Full monorepo typecheck and test suite

* test: relax custom preference cache key matching

Avoid coupling the custom-number cache test to one exact
localStorage key string. Match the intended cache lookup
more loosely so the test still verifies filtering behavior
without depending on the full namespaced cache key.

Constraint: Focus the test on cache filtering behavior
Rejected: Assert one exact key | brittle with namespace changes
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Prefer behavior tests over literal storage keys
Tested: targeted vitest, eslint, git diff --check
Not-tested: Full monorepo test suite

---------

Co-authored-by: caisin <caisin@caisins-Mac-mini.local>
2026-04-13 15:11:57 +08:00
Caisin
5b84ac5b13 feat(form-ui): support schema valueFormat for getValues payload shaping (#7804)
* feat(@vben-core/form-ui): support schema valueFormat on getValues

Some form fields emit UI-friendly structures such as time-range arrays,
while consumers and backend APIs often need a different payload shape.
This adds schema-level `valueFormat` hooks so `getValues()` can
normalize field output at read time without forcing callers to
post-process every submission path.

Constraint: Must preserve existing range-time mapping and nested field behavior
Constraint: Must not mutate live vee-validate form state while formatting output
Rejected: Global formatter config | too coarse for per-field payload shaping
Rejected: Post-submit-only transform | misses reset/query/change handlers
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep `getValues()` output derivation side-effect free
Directive: Clone raw form values before formatting derived payloads
Tested: vitest form-api test for valueFormat and existing getValues paths
Tested: oxlint on changed form-ui source and test files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors

* fix(@vben-core/form-ui): restore mount compatibility and share field path parsing

Follow-up review found two real regressions and one missing assertion in the
new value formatting flow. `FormApi.mount()` had become breaking by requiring
`componentRefMap`, and delete path resolution duplicated field-name parsing
instead of sharing the reader grammar. This patch restores backward
compatibility, centralizes field-name path parsing, and extends the test to
prove formatting does not mutate live form values.

Constraint: Must preserve current valueFormat behavior and nested field support
Constraint: Must not reintroduce mutation of live vee-validate values
Rejected: Keep duplicated delete parsing | risks grammar drift from read path
Rejected: Only loosen mount tests | would leave consumer-facing API breakage
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Reuse shared field-name parsing for read/delete semantics in form-ui
Tested: vitest form-api test suite
Tested: oxlint on changed form-ui files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors
EOF && git push hekx feature-form-value-format

* fix(@vben-core/form-ui): clear stale component refs on unmount

A follow-up review found that `unmount()` left the private component ref map
populated. Because `mount()` now accepts an optional `componentRefMap`, a later
mount without a new map could silently reuse stale refs from a prior form
instance. This change clears the ref map on unmount and adds a regression test
covering remount behavior without a new ref map.

Constraint: Must preserve backward-compatible optional `mount()` ref map behavior
Constraint: Focus and field-ref lookups must not observe stale refs after unmount
Rejected: Clear refs only during next mount | stale state would still leak between lifecycle calls
Rejected: Remove mount fallback entirely | would undo the compatibility fix
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When mount falls back to internal refs, unmount must always reset that cache
Tested: vitest form-api test suite
Tested: oxlint on changed form-api source and test files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors

* refactor(@vben-core/form-ui): trim redundant valueFormat plumbing

Review feedback identified a few small cleanups in the value formatting path.
This removes an unnecessary shallow clone in `getValues()`, reuses the
already-parsed `rawKey` from `resolveFieldNamePath()` instead of re-resolving
it in multiple helpers, and clarifies the `FormValueFormat` contract for
undefined-as-delete decomposition behavior.

Constraint: Must not change runtime valueFormat behavior or payload shape
Constraint: Documentation and helper cleanup should stay behavior-preserving
Rejected: Leave duplicate raw-key resolution in place | adds needless parsing churn
Rejected: Expand the formatter API further | outside the scope of this cleanup
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep read/format helper plumbing lean and avoid duplicate field-name parsing
Tested: vitest form-api test suite
Tested: oxlint on changed form-ui source and test files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors

* feat(@vben-core/form-ui): document valueFormat with live examples

The new `valueFormat` feature needed a concrete usage path in both the
playground and the docs so users can understand how raw component values differ
from the final payload returned by `getValues()`. This adds a dedicated form
example, wires it into the playground menu, and documents the API with an
interactive docs demo. The preview panels now stay in sync when values are set,
reset, or submitted.

Constraint: Must demonstrate both return-value and setValue decomposition flows
Constraint: Example previews must react to setValues, reset, and manual edits
Rejected: Only document via markdown snippet | insufficient for verifying live payload behavior
Rejected: Reuse an existing basic form page | would bury feature-specific behavior
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep playground and docs demos behaviorally aligned when extending valueFormat examples
Tested: eslint on playground/docs valueFormat demo files and route module
Tested: oxlint on playground route module
Not-tested: Full docs/playground app runtime was not launched in this session

* chore(@vben-core/form-ui): normalize valueFormat demo formatting

The previous feature/docs commit left a few formatter-only adjustments unstaged
after hooks rewrote line wrapping in the new demo and docs pages. This commit
captures those final non-behavioral formatting updates so the branch matches the
current working tree.

Constraint: Must not change runtime behavior or docs meaning
Rejected: Leave post-hook diffs unstaged | branch would not reflect local state
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: After hook-driven rewrites, verify the working tree is clean before final push
Tested: Git diff inspection of remaining changes
Not-tested: No additional runtime verification needed; formatting-only follow-up
EOF && git push hekx feature-form-value-format

* fix(@vben-core/form-ui): remove docs demo dayjs dependency

The docs valueFormat demo imported `dayjs` directly even though the docs
package does not declare it as a dependency. That caused `@vben/docs:build`
to fail in CI during VitePress bundling. This change removes the direct
import, keeps the preview formatter generic for day-like values, and drops
the docs-only preset button that required constructing dayjs instances.

Constraint: Docs build must succeed without adding new package dependencies
Constraint: Playground example should remain unchanged and fully interactive
Rejected: Add dayjs to docs dependencies | unnecessary for a small display demo
Rejected: Externalize dayjs in VitePress build | hides a package boundary issue
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Docs demos should avoid imports only available through transitive deps
Tested: pnpm exec eslint docs/src/demos/vben-form/value-format/index.vue
Tested: pnpm --dir docs run build
Not-tested: No browser-side manual verification of the docs demo in this session

---------

Co-authored-by: caisin <caisin@caisins-Mac-mini.local>
2026-04-13 11:22:04 +08:00
Caisin
6be3a0e204 feat(common-ui): add labelFn support to ApiComponent (#7801)
* feat: allow api-component labels to be derived from option data

ApiComponent already normalizes option records into the label/value shape used by
consuming controls, but label text could only come from a single field. Add
labelFn so callers can build labels from the full option record while keeping
labelField as the fallback path.

This keeps the change inside the existing component instead of introducing a
wrapper, and it also normalizes direct options through the same transform path
as API-loaded options for consistent behavior.

Constraint: Must extend the existing ApiComponent API instead of adding a second
Constraint: wrapper component
Rejected: Add a separate ApiLabelComponent wrapper |
Rejected: extra surface area for one option-mapping concern
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep labelFn as a presentation transform and preserve labelField
Directive: fallback for existing callers
Tested: pnpm exec eslint api-component.vue index.ts types.ts
Tested: pnpm exec vue-tsc --noEmit -p packages/effects/common-ui/tsconfig.json
Not-tested: runtime integration in consuming select/tree-select components

* Update packages/effects/common-ui/src/components/api-component/api-component.vue

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-04-12 14:29:18 +08:00
过冬
a9b76ba2ed fix: antdv-next message/notification 跟随暗色主题 (#7799) 2026-04-12 11:51:23 +08:00
Jin Mao
53ccec1d80 fix: 修复VITE_APP_TITLE变量替换语法
- 将index.html中的<%= VITE_APP_TITLE %>替换为%VITE_APP_TITLE%
- 更新web-antd、web-antdv-next、web-ele、web-naive、web-tdesign应用
- 修改文档中loading组件的VITE_APP_TITLE引用方式
- 修复vite-config插件中默认加载模板的变量语法
- 统一所有应用和模板中的环境变量引用格式
2026-04-11 14:29:18 +08:00
Jin Mao
4af5d6152b chore: fix actions error 2026-04-11 14:13:13 +08:00
xingyu4j
307781f437 chore: update deps 2026-04-10 22:16:33 +08:00
xingyu4j
1326994d8e fix: tailwindcss lint config 2026-04-10 22:14:09 +08:00
xingyu4j
fd70a3f3e0 fix: lint 2026-04-10 22:01:01 +08:00
xingyu4j
298930b0d7 chore: remove vite-plugin-html 2026-04-10 22:00:33 +08:00
xingyu4j
54d95b8761 fix: check deps 2026-04-10 21:23:24 +08:00
xingyu4j
4a16040d3e chore: update deps 2026-04-10 21:18:26 +08:00
xingyu4j
ee95548340 fix: tailwindcss lint 2026-04-10 21:13:04 +08:00
xingyu4j
320e687bad fix: ts config 2026-04-10 21:08:54 +08:00
Jin Mao
ad43c6817e fix: 配置 TypeScript 构建根目录
- 添加 rootDir 编译选项指向 ./src 目录
- 保持现有编译配置不变
- 排除测试文件和 node_modules 目录
2026-04-09 14:48:26 +08:00
Jin Mao
c8747c079d chore: update deps 2026-04-08 18:25:39 +08:00
dullathanol
224bfe7fcb chore: 修正注释 2026-04-08 10:19:53 +08:00
dullathanol
f443bfbc7b fix: tailwindcss config 2026-04-08 10:11:05 +08:00
过冬
195b2ea0d2 Merge branch 'vbenjs:main' into main 2026-04-08 09:34:24 +08:00
Jin Mao
4150479549 chore: fix lint 2026-04-08 07:20:52 +08:00
dullathanol
5ebf513498 fix: 修正 Modal/Drawer 中 loading 属性注释 2026-04-07 12:28:57 +08:00
dullathanol
4e4ffc439c feat: 支持 overflow 配置以允许拖拽超出可视区 2026-04-07 11:41:39 +08:00
dullathanol
ad7ed50b52 fix: 弹窗组件拖拽后全屏位置异常 2026-04-06 22:26:27 +08:00
Jin Mao
92f8916225 chore: fix lint
- 关闭 vitest/require-mock-type-parameters 规则
2026-04-06 21:20:53 +08:00
dullathanol
7e4edd270d fix: 补全 ComponentPropsMap 与 Vxe 表格表单链路的类型 2026-04-05 19:03:03 +08:00
dullathanol
332ff44219 fix: 修复 FormField 在 SFC 中的运行时异常 2026-04-05 03:05:01 +08:00
dullathanol
834ce3efc0 fix: 修复部分情况 component 类型丢失问题 2026-04-05 01:59:17 +08:00
dullathanol
5211f5065d feat: 表单 Schema 支持组件 Props 映射泛型,同步适配VxeGrid 2026-04-04 23:40:27 +08:00
dullathanol
96d6f89732 refactor: 简化 componentProps 回调的类型写法 2026-04-03 15:02:32 +08:00
dullathanol
6ab06584eb fix: 函数式 componentProps 按已注册 component 的 Props 校验返回值 2026-04-03 13:36:03 +08:00
dullathanol
a6433c2b50 feat: Schema 中 componentProps 随注册组件联动类型提示 2026-04-03 01:39:49 +08:00
墨苒孤
128a131797 fix(form): 修复表单示例中 switch 组件无法切换的问题 (#7636) (#7763) 2026-04-02 18:18:56 +08:00
橙子
c775d7ed80 fix: interface DropdownMenuProps don‘t have key prop (#7757) 2026-04-02 08:33:26 +08:00
HaroldZhangCode91
b8b4308e1c feat: fix oxlint error for oxlint upgrade (#7756)
1. remove unknown rule out of oxlint
2. add the corresponding back to eslint-config
3. fixed the eslint error for package.json
2026-04-01 19:28:57 +08:00
墨苒孤
80d6e2255f fix: make search case-insensitive (#7689) (#7755) 2026-04-01 19:17:36 +08:00
橙子
4e0968d4b7 perf: replace onUnMounted to tryOnScopeDispose (#7747)
* perf: replace `onUnMounted` to `tryOnScopeDispose`

* perf: replace `onUnMounted` to `tryOnScopeDispose`
2026-04-01 10:30:54 +08:00
Jin Mao
44a5809a46 chore: update deps 2026-04-01 08:10:49 +08:00
xingyu4j
2428fb1407 fix: extension-document 2026-03-30 19:50:44 +08:00
xingyu4j
bb78882f72 feat(@vben/plugins): add tiptap rich text editor 2026-03-30 19:36:29 +08:00
xingyu4j
df88a23102 chore: typescript config is expired‌ 2026-03-30 18:26:07 +08:00
xingyu4j
ca5f360231 chore: update deps 2026-03-30 18:24:25 +08:00
Anonymouscen
147b50ec45 chore: 修复名称错误问题,帐户改为账户 (#7735) 2026-03-29 14:17:00 +08:00
橙子
34439dce4e fix: history search can not remove (#7732) 2026-03-29 14:16:32 +08:00
Jin Mao
9a22027b35 chore: 更新 GitHub Actions 依赖版本
- 将 pnpm/action-setup 从 v4 升级到 v5
- 将 release-drafter/release-drafter 从 v6 升级到 v7
- 更新所有工作流中的依赖版本以确保兼容性
2026-03-25 17:58:47 +08:00
Jin Mao
282a102826 chore: fix lint 2026-03-25 17:31:33 +08:00
Jin Mao
417e6c2ade chore: fix lint && typecheck 2026-03-25 16:33:41 +08:00
Jin Mao
9d69d7f46c Merge branch 'main' into chore/plugins 2026-03-25 15:19:21 +08:00
Jin Mao
87d1593a1f refactor(effects): 扩展 echarts 类型定义并优化插件配置合并逻辑
- 添加 PieSeriesOption 和 RadarSeriesOption 到 echarts 类型定义
- 添加 LegendComponentOption 和 ToolboxComponentOption 组件选项
- 重构 providePluginsOptions 函数实现深合并逻辑
- 优化 vxe-table 初始化中的表单工厂优先级处理
- 调整 playground 中的 import 语句顺序和格式
2026-03-25 15:16:24 +08:00
过冬
7fbdf3d914 fix(@vben/common-ui): 修复 JsonViewer 在 Vite 下因 CJS 默认导出未解包导致的渲染失败 (#7728)
* fix: lint

* fix(@vben/common-ui): 修复 JsonViewer 在 Vite 下因 CJS 默认导出未解包导致的渲染失败
2026-03-25 14:54:14 +08:00
JyQAQ
65287cf4b7 feat: Dockerfile构建调整 (#7727)
Co-authored-by: 吉远 <jiyuan@txhmo.com>
2026-03-25 14:53:26 +08:00
Jin Mao
6da3017dcf feat: 插件新增依赖注入功能 2026-03-25 14:46:55 +08:00
Jin Mao
5c02057198 refactor(effects): 替换上下文创建逻辑为全局选项管理
- 移除 createContext 依赖并实现全局插件选项存储
- 添加 providePluginsOptions 函数用于提供插件配置
- 添加 injectPluginsOptions 函数用于注入插件配置
- 添加 resetPluginsOptions 函数用于重置插件配置
- 更新 package.json 导出配置添加主入口点定义
2026-03-25 14:42:40 +08:00
Jin Mao
a7ca7cdb9f refactor(vxe-table): 重构 useTableForm 函数实现并优化初始化逻辑
- 将 useTableForm 从箭头函数改为普通函数声明
- 简化表单工厂函数的获取逻辑,支持上下文注入
- 移除初始化时的重复上下文注入代码
- 改进错误提示信息的准确性
- 调整代码结构以提高可读性和维护性
- 将 SetupVxeTable 接口中的 useVbenForm 字段改为可选参数
2026-03-25 14:42:31 +08:00
Jin Mao
79408d406d feat: 添加插件模块导出
- 导出 types 模块
- 导出 plugins-context 模块
2026-03-25 13:33:12 +08:00
Jin Mao
e555f71bf8 feat(vxe-table): 集成表格插件并优化初始化配置
- 添加了完整的 vxe-table 插件功能实现
- 实现了插件上下文选项注入机制
- 重构了 useTableForm 工厂函数的初始化逻辑
- 支持通过参数或上下文注入 useVbenForm 函数
- 优化了组件导入和类型定义
- 添加了插件使用文档说明
- 移除了未使用的组件注释代码
- 统一了字符串引号格式为双引号
2026-03-25 13:32:21 +08:00
Jin Mao
4c320346c3 docs(motion): 添加 motion 插件文档
- 创建了 Motion 插件的 README.md 文件
- 添加了插件导出组件和类型的说明表格
- 提供了插件的基本使用示例代码
- 包含了 MotionOptions 和 MotionVariants 类型导入说明
2026-03-25 13:27:10 +08:00
Jin Mao
e5ec88169a refactor: 重构 ECharts 插件类型定义和导出结构
- 将 ECOption 类型定义移至独立的 types.ts 文件
- 修改 echarts.ts 文件导入 ECOption 类型而不是定义
- 更新 index.ts 添加 types 导出
- 移除 echarts.ts 中冗余的类型导入和定义
- 添加完整的 README.md 文档说明插件使用方法
- 优化代码组织结构提高可维护性
2026-03-25 13:27:02 +08:00
Jin Mao
914711ae04 feat: 添加插件上下文和类型定义
- 创建了插件选项的 createContext 功能
- 定义了 VbenPluginsOptions 接口结构
- 添加了表单、模态框、消息和组件的插件选项接口
- 提供了插件选项的注入和提供功能
2026-03-25 13:25:19 +08:00
Jin Mao
4c1e3b9548 Merge branch 'fork/Voidlurk/fix-default' 2026-03-24 10:36:40 +08:00
Jin Mao
9cd3987475 Merge branch 'main' into fix 2026-03-24 10:24:18 +08:00
xueyitt
47a853330d feat: ApiSelect增加shouldFetch控制,在api请求之前的判断是否允许请求的回调函数 (#7713) 2026-03-24 10:22:02 +08:00
xueyitt
2aced2f659 feat: 增加table 帮助信息help通过表单values动态展示内容 (#7712) 2026-03-24 10:20:43 +08:00
Jin Mao
cd955df02f chore: fix lint 2026-03-24 10:19:24 +08:00
Bk201
0a819df2bf fix bug
[Vue warn]: Invalid prop: custom validator check failed for prop "variant".
2026-03-24 03:01:00 +08:00
xingyu4j
67afcadcf0 fix: rollup -> rolldown 2026-03-23 17:51:46 +08:00
xingyu4j
1128ef5acd chore: update deps 2026-03-23 17:13:39 +08:00
雪忆天堂
6b3506f128 feat: table 类型VxeTableGridColumns替代VxeTableGridOptions['columns']魔法值写法 2026-03-23 10:06:35 +08:00
雪忆天堂
5613dcef99 feat: table允许通过props动态变化data数据 2026-03-23 10:05:32 +08:00
MistyMoon
3528517fe0 fix(project): fix sub sidebar theme in two-column menu (#7708)
- Reset light tokens for nested sub sidebars.
- Align the extra title logo theme with sidebarThemeSub.
2026-03-22 09:15:56 +08:00
Jin Mao
2a5b520ec9 chore: update deps 2026-03-22 09:15:27 +08:00
lmx
e2fb3602f1 fix: 修复菜单项外部链接跳转问题
- 引入 isHttpUrl 工具函数用于判断 URL 类型
- 添加 isHttp 计算属性检测父路径是否为 HTTP 链接
- 修改菜单项渲染逻辑,对外部链接直接使用原地址跳转
- 调整 HTML 结构,将链接属性移到正确位置
- 确保内部路由和外部链接都能正常工作
2026-03-19 23:56:13 +08:00
lmx
da3580cbd7 Merge remote-tracking branch 'origin/main' 2026-03-19 22:07:20 +08:00
xingyu
0c300d040c fix: tailwindcss config (#7693)
* chore: update deps

* fix: tailwindcss config

* fix: lint

* fix: lint

* chore: update deps
2026-03-19 15:51:09 +08:00
橙子
d43a3729c3 fix: playground(drawer) comment (#7695) 2026-03-19 09:03:40 +08:00
Jin Mao
bed97a84d8 revert: "fix: sass-embedded@1.98.0 在 macOS 13 会直接崩 (#7692)" 2026-03-19 09:02:28 +08:00
afe1
b908076846 fix: sass-embedded@1.98.0 在 macOS 13 会直接崩 (#7692)
* fix: catelog

* fix: system
2026-03-18 20:18:25 +08:00
Noah Lan
885a0a9a00 fix: build.mjs commands could not be executed correctly. (#7682)
* fix: Fix issue where commands could not be executed correctly when they contained spaces

* chore: oxfmt
2026-03-17 18:59:35 +08:00
Jin Mao
340baf4f0b chore: 处理合并的一些问题 2026-03-16 20:50:01 +08:00
Jin Mao
82cda0edaa Merge branch 'fork/xingyu4j/tsdown'
# Conflicts:
#	pnpm-lock.yaml
2026-03-16 20:36:27 +08:00
Jin Mao
9fe875355a fix: 修复构建脚本中的进程执行问题
- 移除平台特定的 pnpm 命令路径检测逻辑
- 统一使用 'pnpm' 命令执行
- 启用 shell 模式以正确处理命令执行
- 确保子进程继承正确的标准输入输出流
2026-03-16 20:30:27 +08:00
Jin Mao
5f21bd2036 Merge branch 'fork/jyqwq/feature/antd上传组件支持拖拽排序' 2026-03-16 19:54:08 +08:00
Sun
5b5ea6d2d8 chore: Configure the ESLint auto-repair feature (#7670) 2026-03-16 18:26:42 +08:00
JyQAQ
3dcfd23036 perf: 裁剪组件默认输出格式调整 (#7673)
Co-authored-by: 吉远 <jiyuan@txhmo.com>
2026-03-16 18:25:04 +08:00
xingyu
186914bcac fix: vxe i18n (#7675)
* chore: engines node

* chore: update deps

* fix: oxlint

* chore: fix lint issues

* chore: update deps

* fix: vxe i18n
2026-03-16 18:24:28 +08:00
吉远
4b3205fee8 feat: antd Upload 组件上传文件组支持拖拽排序 2026-03-16 15:01:43 +08:00
lmx
e4453841db fix: 修复在vue-router 的模式hash复制路径不对 2026-03-16 01:32:11 +08:00
xingyu4j
32db4cbd11 fix: build warn 2026-03-15 23:11:59 +08:00
xingyu4j
5558249cd3 chore: unbuild 2026-03-15 23:11:41 +08:00
xingyu4j
86b636ae54 fix(@vben/vite-config): externalize node utils dependency 2026-03-15 22:47:28 +08:00
xingyu4j
c9f7154524 chore(tsdown): remove unbuild leftovers 2026-03-15 22:04:48 +08:00
xingyu4j
d72f872369 refactor(tsdown): migrate styled ui-kit packages 2026-03-15 21:42:44 +08:00
xingyu4j
b300011d07 refactor(tsdown): migrate ui-kit vue packages 2026-03-15 21:30:13 +08:00
xingyu4j
3946253d6e chore(tsdown): align stub scripts and package exports 2026-03-15 21:17:41 +08:00
xingyu4j
11fc367845 chore: migrate vite build to tsdown 2026-03-15 21:04:12 +08:00
xingyu4j
bdc65cc250 chore: update deps 2026-03-15 21:03:41 +08:00
xingyu4j
70dad0f600 fix(node-utils): avoid find-up sync API in monorepo root lookup 2026-03-15 20:50:07 +08:00
xingyu4j
26e9aa244b fix(vite): adapt rolldown workspace resolution 2026-03-15 20:27:01 +08:00
xingyu4j
913f77fd2f chore(pnpm): sync lockfile for tsdown migration 2026-03-15 19:41:17 +08:00
xingyu4j
dba774e1c7 chore(vsh): migrate build to tsdown 2026-03-15 19:41:00 +08:00
xingyu4j
af09d652a3 chore(turbo-run): migrate build to tsdown 2026-03-15 19:40:54 +08:00
xingyu4j
0babdfbc44 chore(core-preferences): migrate build to tsdown 2026-03-15 19:40:48 +08:00
xingyu4j
f154d53be9 chore(core-composables): migrate build to tsdown 2026-03-15 19:40:42 +08:00
xingyu4j
ed3cd2fe3b chore(core-typings): migrate build to tsdown 2026-03-15 19:40:36 +08:00
xingyu4j
59912a00bc chore(core-shared): migrate build to tsdown 2026-03-15 19:40:29 +08:00
xingyu4j
675d8b0179 chore(core-icons): migrate build to tsdown 2026-03-15 19:40:17 +08:00
xingyu4j
a1ca296fc0 chore(node-utils): migrate build to tsdown 2026-03-15 19:40:09 +08:00
xingyu4j
c1b1fe90fd chore(oxlint-config): migrate build to tsdown 2026-03-15 19:39:59 +08:00
xingyu4j
30b5610a73 chore(oxfmt-config): migrate build to tsdown 2026-03-15 19:39:51 +08:00
xingyu4j
db9b9df8f7 chore(eslint-config): migrate build to tsdown 2026-03-15 19:39:43 +08:00
xingyu4j
ae6a75e913 build: migrate core ts packages to tsdown 2026-03-15 18:13:49 +08:00
xingyu
37d72c1628 fix: oxlint config (#7661)
* chore: engines node

* chore: update deps

* fix: oxlint

* chore: fix lint issues
2026-03-15 17:41:47 +08:00
xingyu4j
ab3e6bb37c chore: fix lint issues 2026-03-15 16:35:34 +08:00
xingyu4j
9ddb899a1a fix: oxlint 2026-03-15 16:23:18 +08:00
xingyu4j
1f0cda8aee chore: update deps 2026-03-15 12:35:42 +08:00
xingyu4j
90ae85317c chore: engines node 2026-03-15 12:33:23 +08:00
Jin Mao
a8ae891aff chore: update pnpm-lock 2026-03-15 03:57:55 +08:00
Jin Mao
1f2df3e944 Merge branch 'fork/Lmx1220/main'
# Conflicts:
#	pnpm-lock.yaml
2026-03-15 03:53:43 +08:00
Jin Mao
e39a432210 Merge branch 'fork/caodachen/fix_useEcharts' 2026-03-15 03:50:21 +08:00
xingyu4j
6b3bcee582 docs(@vben/docs): sync component docs with current APIs 2026-03-14 21:34:48 +08:00
xingyu4j
6c274b75b8 docs(@vben/docs): align guide docs with current tooling 2026-03-14 21:33:55 +08:00
xingyu4j
278032c94b docs: remove docs 2026-03-14 20:29:49 +08:00
xingyu4j
23a8982f5c chore: add prepare 2026-03-14 20:19:34 +08:00
xingyu4j
5df6c32d04 fix: lint 2026-03-14 20:14:35 +08:00
xingyu4j
7cae330c3c chore: deps 2026-03-14 19:48:49 +08:00
xingyu4j
100aaa4cee chore: vsh lint 2026-03-14 19:48:40 +08:00
xingyu4j
ead0b73e7b fix: lint 2026-03-14 19:47:02 +08:00
xingyu4j
2ace846e38 chore: recommend vscode yaml extension 2026-03-14 19:41:28 +08:00
xingyu4j
1d98393f0c chore: recommend vscode eslint extension 2026-03-14 19:39:37 +08:00
xingyu4j
c48ee2a364 revert: restore vscode extensions comments 2026-03-14 19:38:09 +08:00
xingyu4j
95d1e8432f fix: surface eslint diagnostics in vscode 2026-03-14 19:36:27 +08:00
xingyu4j
4d59ac78bd fix: lint 2026-03-14 19:34:22 +08:00
xingyu4j
f1143e134e fix: match root json files in oxfmt overrides 2026-03-14 19:33:55 +08:00
xingyu4j
e3e869faee fix: align oxfmt json commas with lint 2026-03-14 19:31:01 +08:00
xingyu4j
8350e72393 fix: align json formatter with lint rules 2026-03-14 19:28:25 +08:00
xingyu4j
15f74b9d97 refactor: drop unused turbo eslint shim 2026-03-14 19:20:39 +08:00
xingyu4j
55b54e24fe refactor: migrate command lint to oxlint 2026-03-14 19:13:50 +08:00
xingyu4j
46b4ce81e4 refactor: shrink eslint fallback layer 2026-03-14 19:10:22 +08:00
xingyu4j
7a723d03d0 fix: tailwindcss 2026-03-14 18:48:30 +08:00
xingyu4j
9d6fbfd0d6 refactor: replace simple px utility styles 2026-03-14 18:43:00 +08:00
xingyu4j
8fd6bf47b1 revert: restore px-based calc utilities 2026-03-14 18:36:31 +08:00
xingyu4j
f25f3a34d0 refactor: replace px calc spacing utilities 2026-03-14 18:31:35 +08:00
xingyu4j
2823848fae refactor: migrate spacing utilities to tailwind v4 syntax 2026-03-14 18:27:16 +08:00
xingyu4j
b9467b2bc3 chore: configure tailwind v4 dynamic spacing 2026-03-14 18:14:44 +08:00
xingyu4j
fa190e0975 chore: checkpoint tailwind spacing updates 2026-03-14 18:11:08 +08:00
xingyu4j
90dc8cf997 chore: update deps 2026-03-14 17:52:40 +08:00
Jin Mao
a6a6efdf59 chore: release 5.7.0
- 更新 backend-mock 包版本
- 更新 web-antd 包版本
- 更新 web-antdv-next 包版本
- 更新 web-ele 包版本
- 更新 web-naive 包版本
- 更新 web-tdesign 包版本
- 更新 docs 包版本
- 更新 commitlint-config 包版本
- 更新 eslint-config 包版本
- 更新 oxfmt-config 包版本
- 更新 oxlint-config 包版本
- 更新 stylelint-config 包版本
- 更新 node-utils 包版本
- 更新 tsconfig 包版本
- 更新 vite-config 包版本
- 更新 @core/base/design 包版本
- 更新 @core/base/icons 包版本
- 更新 @core/base/shared 包版本
- 更新 @core/base/typings 包版本
- 更新 @core/composables 包版本
- 更新 @core/preferences 包版本
- 更新 @core/ui-kit/form-ui 包版本
- 更新 @core/ui-kit/layout-ui 包版本
- 更新 @core/ui-kit/menu-ui 包版本
- 更新 @core/ui-kit/popup-ui 包版本
- 更新 @core/ui-kit/shadcn-ui 包版本
- 更新 @core/ui-kit/tabs-ui 包版本
- 更新 constants 包版本
- 更新 access 包版本
- 更新 common-ui 包版本
- 更新 hooks 包版本
- 更新 layouts 包版本
- 更新 plugins 包版本
- 更新 request 包版本
- 更新 icons 包版本
- 更新 locales 包版本
- 更新 preferences 包版本
- 更新 stores 包版本
- 更新 styles 包版本
- 更新 types 包版本
- 更新 utils 包版本
- 更新 playground 包版本
- 更新 turbo-run 包版本
- 更新 vsh 包版本
- 更新根目录包版本
2026-03-14 09:14:23 +08:00
xingyu4j
8043faf6c7 docs: remove doc 2026-03-14 00:18:54 +08:00
xingyu4j
ebed9e64ed fix: lint 2026-03-14 00:17:06 +08:00
xingyu4j
913636ae44 refactor: simplify oxc eslint compatibility 2026-03-14 00:16:27 +08:00
xingyu4j
7b064e9f33 chore: vsh lint 2026-03-13 23:41:17 +08:00
xingyu4j
16da0eaca3 fix: vsh lint 2026-03-13 23:31:19 +08:00
xingyu4j
6acfee2737 fix: vsh lint 2026-03-13 23:26:29 +08:00
xingyu4j
92abf7edaa chore: oxlint-tsgolint 2026-03-13 23:22:52 +08:00
xingyu4j
395babc1f5 feat: tsgolint 2026-03-13 23:13:10 +08:00
xingyu4j
68cde54bad feat: add tsgolint 2026-03-13 23:13:01 +08:00
xingyu4j
c7d7529c00 chore: ts 2026-03-13 23:07:04 +08:00
xingyu4j
748f60c7bb chore: lint config 2026-03-13 22:12:15 +08:00
xingyu4j
ffee62e940 chore(vscode): update workspace editor settings 2026-03-13 22:02:50 +08:00
xingyu4j
a0ea221131 style(common-ui): normalize generic formatting 2026-03-13 21:57:18 +08:00
xingyu4j
2846bcb84e fix(common-ui): guard resize drag start state 2026-03-13 21:56:53 +08:00
xingyu4j
542ed6c08f refactor: rename formatter utilities 2026-03-13 21:56:23 +08:00
xingyu4j
6dabb848a5 build: migrate formatting pipeline to oxfmt 2026-03-13 21:56:08 +08:00
xingyu4j
de0181e0d9 fix: lint 2026-03-13 20:58:07 +08:00
xingyu4j
a850d426ef chore: fix lint and typecheck issues 2026-03-13 20:57:52 +08:00
xingyu4j
771277d5d9 fix: align oxlint compat config typing 2026-03-13 20:28:56 +08:00
xingyu4j
20b4f5c99f chore: oxlint config 2026-03-13 20:26:10 +08:00
xingyu4j
e7fa87b301 chore: finalize oxlint migration config 2026-03-13 20:25:25 +08:00
xingyu4j
40c66958bc chore: remove un use deps 2026-03-13 15:59:04 +08:00
xingyu4j
600fc71aed fix: eslint 2026-03-13 15:58:53 +08:00
xingyu4j
443e4b04cd chore: update vite 8 2026-03-13 15:51:28 +08:00
Lmx1220
556a3c0fab Update pnpm-lock.yaml 2026-03-13 15:25:14 +08:00
Lmx1220
1eca52f962 Update pnpm-lock.yaml
更新到使用vue3版本
2026-03-13 15:20:58 +08:00
Lmx1220
e21adb395b Merge branch 'main' into main 2026-03-13 15:08:24 +08:00
xingyu4j
0e4bf80bf4 chore: update deps 2026-03-13 10:33:23 +08:00
cdc
107750971b fix: fix useEcharts 2026-03-10 21:48:33 +08:00
橙子
24e1be47ca fix: fix component type (#7601) 2026-03-10 05:11:06 +08:00
Mr. Xie
7e0978c764 fix: 修复验证码登录发送逻辑,未校验手机号或发送失败仍开始倒计时的问题 (#7616) 2026-03-10 05:10:34 +08:00
Leo
83a0c9662d fix: 修复路由重复 (#7590)
* fix: 修复路由重复

优化mixed模式路由合并逻辑。以backend 为基础,并从frontend补充

* fix: 修复名称冲突时子项合并顺序/覆盖(后端子项可能会丢失)。

* fix: 优化可访问性判断逻辑

* fix: error Forbidden non-null assertion

* refactor(access): 调整可访问性判断逻辑
2026-03-10 05:09:48 +08:00
xingyu
a4736a49f8 feat: migrate to Tailwind CSS v4 (#7614)
* chore: update deps

* feat: use jsonc/x language

* chore: update eslint 10.0

* fix: no-useless-assignment

* feat: add CLAUDE.md

* chore: ignore

* feat: claude

* fix: lint

* chore: suppot eslint v10

* fix: lint

* fix: lint

* fix: type check

* fix: unit test

* fix: Suggested fix

* fix: unit test

* chore: update stylelint v17

* chore: update all major deps

* fix:  echarts console warn

* chore: update vitest v4

* feat: add skills ignores

* chore: update deps

* chore: update deps

* fix: cspell

* chore: update deps

* chore: update tailwindcss v4

* chore: remove postcss config

* fix: no use catalog

* chore: tailwind v4 config

* fix: tailwindcss v4 sort

* feat: use eslint-plugin-better-tailwindcss

* fix: Interference between enforce-consistent-line-wrapping, jsx-curly-brace-presence and Prettier

* fix: Interference between enforce-consistent-line-wrapping, jsx-curly-brace-presence and Prettier

* fix(lint): resolve prettier and better-tailwindcss formatting conflicts

* fix(tailwind): update theme references and lint sources

* style(format): normalize apps docs and playground vue files

* style(format): normalize core ui-kit components

* style(format): normalize effects ui and layout components
2026-03-10 05:08:45 +08:00
zouawen
aa7d8630b5 fix: 侧边菜单栏拖拽优化 (#7606)
* fix: 拖拽使用遮罩层实现,使得拖拽到min或max临界值时cursor显示not-allowed,同时拖拽线条颜色变浅,类似于disabled,提升用户体验

* fix: 修复代码审查建议;修复lint和test报错

* fix: 修复遮罩层挡住hover:bg-primary视觉效果问题
2026-03-07 05:32:09 +08:00
lmx
36313f378e chore: update package.json and cspell.json 2026-03-04 19:17:33 +08:00
lmx
45054d3238 chore: update pnpm-lock.yaml 2026-03-04 19:03:41 +08:00
lmx
173e6b08c9 fix: 修复执行: check:cspell 命令路径参数传入没有转义导致检测路径失效。添加菜单右键功能。优化:多余监听 activePath 变化,自动滚动到激活项 watch 2026-03-04 18:25:15 +08:00
zouawen
2a86404ba5 fix: 修复混合双列布局侧边栏拖拽线条位置显示bug,同步修复普通布局和混合双列布局切换时width计算导致侧边栏宽度显示异常问题,新增普通布局和混合双列布局侧边栏菜单折叠状态同步 (#7596) 2026-03-02 15:31:29 +08:00
han
b8a0199cde feat(preferences): add toggle for copy preferences button (#7594)
Co-authored-by: hl <hl@nmcsoft.com>
2026-03-02 15:30:38 +08:00
Bryan Qiu
a46ed55a86 fix: bump version to 5.6.0 (#7592) 2026-03-02 04:22:21 +08:00
Jin Mao
1a9fbddef4 Merge branch 'main' into main 2026-02-28 12:04:48 +08:00
zouawen
1209aaafb4 fix: 修复lint报错 2026-02-28 11:25:08 +08:00
zouawen
8e71261d49 fix: 侧边栏菜单拖拽功能在设置内增加开关 2026-02-28 11:19:24 +08:00
dependabot[bot]
49e45eab54 chore(deps): bump vue-router from 4.6.4 to 5.0.3 (#7583)
Bumps [vue-router](https://github.com/vuejs/router) from 4.6.4 to 5.0.3.
- [Release notes](https://github.com/vuejs/router/releases)
- [Commits](https://github.com/vuejs/router/compare/v4.6.4...v5.0.3)

---
updated-dependencies:
- dependency-name: vue-router
  dependency-version: 5.0.3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-27 17:06:18 +08:00
Jin Mao
bd22793ceb feat: add the attribute routeCached to route to control cache the DOM corresponding to the route 2026-02-27 16:04:01 +08:00
zouawen
b2013436c5 fix: 优化最大值限制 2026-02-27 11:12:51 +08:00
zouawen
cc808cb8c5 fix: 优化最小值限制 2026-02-27 11:07:28 +08:00
zouawen
afffc4b3f0 fix: 优化侧边栏拖拽逻辑,支持展开和折叠 2026-02-27 10:54:15 +08:00
zouawen
99710ef9dc feat: 优化侧边栏拖拽逻辑 2026-02-26 18:11:53 +08:00
zouawen
3d4ae04d9b Merge branch 'main' into main 2026-02-26 10:20:32 +08:00
zouawen
707b391449 feat: 侧边栏宽度拖拽改为composable实现,同时修复tabbar.ts文件lint报错 2026-02-26 10:09:57 +08:00
ming4762
45b843f344 fix: fix bug where renderEcharts gets stuck in a dead loop (#7561)
* 触发条件:echart所在页面开启keepalive 在其他页面切换颜色模式
2026-02-26 06:21:08 +08:00
Wu Clan
191fd90f06 chore: 更新表单描述显示样式 (#6938) 2026-02-26 06:17:04 +08:00
moil-xm
05920cd66d feat(vite-config): vite export typing (#7569)
* feat(vite-config): vite export typing

* feat(vite-config): add type

---------

Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2026-02-26 06:14:12 +08:00
Jin Mao
01508d5e42 fix: fix lint 2026-02-26 05:45:36 +08:00
zouawen
57cf6cbc9e feature: 简易版菜单宽度拖拽功能 2026-02-25 17:50:22 +08:00
AxiosLeo
03ebbea46a fix(menu): update hover color variable to use the correct reference (#7544)
* fix(menu): update hover color variable to use the correct reference

Medium Severity

In the horizontal .is-light menu section, --menu-item-hover-color is set to hsl(var(--menu-item-color)), but --menu-item-color is already defined as hsl(var(--accent-foreground)). This results in hsl(hsl(...)) at computed-value time, which is invalid CSS. The non-horizontal .is-light block correctly uses var(--menu-item-color) without the extra hsl() wrapper.

* fix(menu): simplify hover styles by removing redundant nested hover rules

Low Severity

The SCSS &:not(.is-active):hover { &:hover { ... } } compiles to a :hover:hover pseudo-class chain, which is functionally identical to a single :hover. The inner &:hover nesting is redundant and adds unnecessary complexity compared to placing styles directly inside the &:not(.is-active):hover block.
2026-02-12 22:22:53 +08:00
zouawen
8e7a5d1ec3 fix: Fix layout change, ensure div[ref="asideRef"] is contained within <aside> (#7551) 2026-02-12 22:22:34 +08:00
AxiosLeo
aa74a2535b fix(tabbar): visitHistory field (#7543)
High Severity

The visitHistory field is a Stack<string> class instance persisted to sessionStorage via pinia-plugin-persistedstate. There's no custom serializer or hydration hook. When the page reloads, JSON.parse(JSON.stringify(stack)) produces a plain object {dedup, items, maxSize} that lacks all Stack methods (push, pop, remove, retain, etc.) and the size getter. Pinia's $patch replaces the Stack instance with this plain object, so subsequent calls like this.visitHistory.push(...) will throw a TypeError.
2026-02-11 16:09:37 +08:00
zouawen
32379ba4b7 fix: 双列菜单模式下新增深色侧边栏和深色侧边栏子栏 (#7542)
* fix: 双列菜单模式下新增深色侧边栏和深色侧边栏子栏

* fix: 修复报错 config.test.ts.snap

* fix: 修复lint报错

* fix: 修复侧边栏菜单文本内容溢出问题

* fix: 修复lint报错
2026-02-11 16:08:32 +08:00
moil-xm
7fe8d7b4be fix: ts 错误: 类型实例化过深,且可能无限 2026-02-10 16:13:36 +08:00
Bin
aace726a91 feat(playground): add antdv-next router link (#7532)
Co-authored-by: fuwb <fuwb@sunsharing.com.cn>
2026-02-10 13:09:34 +08:00
Jin Mao
e6f6e5464a Merge branch 'main' into main 2026-02-10 12:08:16 +08:00
Aliner
7d04b600fb fix: correct updateDate to updateData in the echarts hook (#7538)
* fix(@vben/plugins): Fixed the misspelling of the data update method name in the echarts hook

Correct updateDate to updateData, ensuring that the API method name is correct and consistent

* Revert "fix(@vben/plugins): Fixed the misspelling of the data update method name in the echarts hook"

This reverts commit 86d679cf25631bd1abd56d4f971e6db3a9b9d6d5.

* fix(@vben/plugins): fixed the misspelling of the data update method name in the echarts hook

Correct updateDate to updateData, ensuring that the API method name is correct and consistent
2026-02-10 11:19:45 +08:00
zouawen
463bfde2ac fix: config.test.ts.snap新增showRefresh参数 2026-02-10 08:50:06 +08:00
zouawen
893f74dc3e fix: 优化横向布局时菜单激活或聚焦时背景色,标签工具栏新增刷新按钮,其他样式优化 2026-02-09 16:32:02 +08:00
Jin Mao
8a215fbcc7 chore: release 5.6.0 2026-02-09 05:09:57 +08:00
Jin Mao
ac5e4c4722 chore: update deps 2026-02-09 04:52:06 +08:00
Jin Mao
04d01b0bab chore: fix lint 2026-02-09 04:49:06 +08:00
Jin Mao
cb1d7565a3 Merge branch 'fork/ffgenius/antd-vue-next' 2026-02-09 03:09:01 +08:00
Jin Mao
1d9b6407a4 chore: 更新开发环境端口号配置
- 将 VITE_PORT 从 5555 修改为 5999
- 保持其他环境变量配置不变
2026-02-09 03:04:42 +08:00
MistyMoon
22ed522711 feat: support menuVisibleWithForbidden in generate-routes-backend (#7526)
当后端菜单项 `meta.menuVisibleWithForbidden` 为 true 时,将其路由组件替换为 403 页,菜单仍展示该项,访问时展示 403,便于用户知悉功能并申请权限。
2026-02-09 02:44:29 +08:00
Jin Mao
a3598ef859 chore: fix lint 2026-02-09 02:42:50 +08:00
Jin Mao
6fe09ec2dd perf: optimize the closing jump logic of tabs 2026-02-09 02:36:38 +08:00
Jin Mao
57911d9e09 Merge branch 'tab-2026020401' of https://github.com/ming4762/smart-boot-ui-vben into ming4762-tab-2026020401 2026-02-09 02:36:04 +08:00
Bin
3aee283495 Revert "feat(web): cancel pnpm-lock.yaml submission"
This reverts commit 54b24c2677.
2026-02-08 23:14:31 +08:00
Bin
54b24c2677 feat(web): cancel pnpm-lock.yaml submission 2026-02-08 23:12:40 +08:00
Bin
8cadad0a1e feat(web): add antdv-next model 2026-02-08 23:00:19 +08:00
zhongming4762
633c5f3cda perf: optimize the closing jump logic of tabs
* 依据tab访问历史回退上一个tab,原逻辑是返回一下个 或 上一个
 * 支持在配置中开启或关闭
2026-02-08 20:50:54 +08:00
zhongming4762
a8431e2040 perf: optimize the closing jump logic of tabs
* 依据tab访问历史回退上一个tab,原逻辑是返回一下个 或 上一个
 * 支持在配置中开启或关闭
2026-02-08 20:36:32 +08:00
zhongming4762
7a2b916387 perf: optimize the closing jump logic of tabs
* 依据tab访问历史回退上一个tab,原逻辑是返回一下个 或 上一个
 * 支持在配置中开启或关闭
2026-02-08 20:36:16 +08:00
Jin Mao
f4dfb68b7b Merge branch 'MrLeo-main' 2026-02-06 15:41:55 +08:00
Jin Mao
8f4f27d860 Merge branch 'main' of https://github.com/MrLeo/vue-vben-admin into MrLeo-main 2026-02-06 15:39:48 +08:00
tikitoki
e9eab29953 fix:fix password input icon visual bug in certain browser (#7521)
Co-authored-by: nick8799981325 <zc1078134211@163.com>
2026-02-06 15:28:48 +08:00
Leo Caan (陈栋)
4f1eeb7da5 fix: 修复设置default-expanded-level后无法check更低层级节点 logic and tree value updates (#7155)
假设缺省展开2级,当check 3级节点时,会触发effectWatch重新收缩到2级,并丢失check操作check操作andling.
2026-02-06 12:55:14 +08:00
Leo
6fd426d719 fix: 当 showToolbar 为 false 时禁用工具栏(vxe-table),减少无 Toolbar 的 Gird 留白 2026-02-04 22:20:17 +08:00
zhongming4762
331da3c8c7 perf: optimize the closing jump logic of tabs
* 依据tab访问历史回退上一个tab,原逻辑是返回一下个 或 上一个
2026-02-04 19:29:33 +08:00
ming4762
c48943bc67 fix: fix Nested Objects dependencies not effective (#7345) 2026-01-31 16:44:20 +08:00
xingyu
7680b33b99 fix: #7140 (#7153)
* chore: add yaml eslint validate

* chore: update deps

* fix: unused ts lint

* fix: 弹窗只能点击一次 #7140

* chore: update actions/checkout v6

* chore: update node version v22.22.0
2026-01-28 18:05:20 +08:00
Jin Mao
bb5d75bc7e fix: 修复表单展开无效 (#7148)
- 修正模板中 ref 属性的引用名称
2026-01-27 11:35:50 +08:00
ming4762
528395e2c3 perf: optimizing hidden fields cannot trigger dependencies (#7142) 2026-01-26 16:12:26 +08:00
programmer
6a9012e5e4 chore: 给个人中心的2个按钮加上 i18n (#7138)
* fix: 个人中心按钮i18n

* fix: eslint format

* fix: 调整label宽度让英文显示在一行

* chore: 调整label小点

* fix: import

---------

Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2026-01-26 16:12:09 +08:00
橙子
6e8315ab40 fix: arguments order update (#7132)
Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2026-01-26 16:11:37 +08:00
Jin Mao
7cb2699f19 chore: 更新pnpm工作区配置
- 移除 neverBuiltDependencies 配置
- 移除 peerDependencyRules.allowedVersions 配置
- 重新整理 overrides 和 catalog 部分
- 保持 @ast-grep/napi 等依赖的目录引用配置
- 维持 eslint 版本约束在目录顶层配置中
2026-01-25 19:55:53 +08:00
Jin Mao
4b5da81ba6 chore(deps): 更新项目依赖包版本
- 更新 @playwright/test 从 1.57.0 到 1.58.0
- 更新 @tanstack/vue-query 从 5.92.8 到 5.92.9
- 更新 cheerio 从 1.1.2 到 1.2.0
- 更新 eslint-config-turbo 从 2.7.5 到 2.7.6
- 更新 playwright 从 1.57.0 到 1.58.0
- 更新 turbo 从 2.7.5 到 2.7.6
- 更新 vxe-pc-ui 从 4.12.10 到 4.12.12
- 更新 @babel/helper-define-polyfill-provider 从 0.6.5 到 0.6.6
- 更新 @cspell/dict-fullstack 从 3.2.7 到 3.2.8
- 更新 @cspell/dict-git 从 3.0.7 到 3.1.0
- 更新 @cspell/dict-node 从 5.0.8 到 5.0.9
- 更新 @cspell/dict-npm 从 5.2.29 到 5.2.30
- 更新 @parcel/watcher 相关包从 2.5.4 到 2.5.6
- 更新 @tanstack/query-core 从 5.90.19 到 5.90.20
- 更新 babel-plugin-polyfill 相关包到最新版本
- 更新 baseline-browser-mapping 从 2.9.17 到 2.9.18
- 更新 caniuse-lite 从 1.0.30001765 到 1.0.30001766
- 更新 electron-to-chromium 从 1.5.277 到 1.5.278
- 更新 eslint-plugin-turbo 从 2.7.5 到 2.7.6
- 更新 playwright-core 从 1.57.0 到 1.58.0
- 更新 turbo 平台特定版本到 2.7.6
- 更新 undici 从 7.19.0 到 7.19.1
2026-01-25 15:05:14 +08:00
Jin Mao
6aca9a9c99 test(dom): 更新元素可见区域计算的测试用例
- 修正了getElementVisibleRect函数的期望值断言
- 将bottom值从800更正为0以匹配实际计算结果
- 将left值从1100更正为0以匹配实际计算结果
- 将right值从1000更正为0以匹配实际计算结果
- 将top值从900更正为0以匹配实际计算结果
2026-01-25 14:22:22 +08:00
xingyu4j
fa195fde8e fix: lint 2026-01-23 14:48:21 +08:00
xingyu4j
1057f2932b chore: update deps 2026-01-23 14:48:06 +08:00
Jin Mao
b9224fc379 Merge branch 'main' into fix 2026-01-23 13:48:54 +08:00
Jin Mao
57dd818170 Merge branch 'fork/kuchaguangjie/fix' 2026-01-23 13:47:54 +08:00
Jin Mao
49256ec1b7 Merge branch 'main' into fix 2026-01-23 13:46:59 +08:00
Jin Mao
f6f92e5403 Merge branch 'fork/kuchaguangjie/fix' 2026-01-23 13:45:38 +08:00
Jin Mao
613c311076 Merge branch 'fork/abcd0f/dev/sun-local' 2026-01-23 13:25:03 +08:00
Jin Mao
9ee7a7d9ff Merge branch 'fork/Child-qjj/patch-1' 2026-01-23 13:21:49 +08:00
橙子
44f8aed06d fix: timer not need reactivity (#7128) 2026-01-23 13:16:09 +08:00
Sun
d5d4a5c591 feat(effects-plugins): 添加 echarts 图表更新功能
新增 updateDate 方法用于更新 echarts 图表选项,支持合并配置、
完全替换和延迟更新等模式。该方法会在组件未初始化时自动执
行首次渲染,并能够合并全局配置如 backgroundColor 等选项。
2026-01-23 11:06:45 +08:00
yuhengshen
74381aa8c1 fix: 嵌套弹窗,错误 merge options (#7126) 2026-01-22 20:07:13 +08:00
橙子
203ee9b623 fix(@vben-core/shared): element outside viewport, the element visible rect each prop expect 0 (#7120)
* fix(@vben-core/shared): element outside viewport

* fix(@vben-core/shared): element outside viewport
2026-01-22 11:37:01 +08:00
JyQAQ
6c8c49966a Perf: 优化antd upload组件参数获取 (#7114)
* perf(antd upload params): 优化组件参数取值 确保不同调用场景配置参数可用

* perf(antd upload params): 优化组件参数取值 确保不同调用场景配置参数可用

* perf(antd upload params): 优化组件参数取值 确保不同调用场景配置参数可用

* perf(antd upload params): 优化组件参数取值 确保不同调用场景配置参数可用
2026-01-21 17:20:53 +08:00
Qiu
3862942e9f fix: chart instance disposal condition
dom has been disposed in vue3 v-if,but chartInstance exist
2026-01-21 11:47:01 +08:00
xingyu
8571fc43b0 Merge branch 'main' into fix 2026-01-19 15:28:12 +08:00
JyQAQ
59aabd956d Perf: Optimization of cropping component result acquisition & optimization of cropping frame prompts (#7111)
* perf(cropper): enhance image cropping functionality and add output type support

* perf(cropper): enhance image cropping functionality and add output type support
2026-01-19 14:18:36 +08:00
xingyu
9b09ba4483 Merge branch 'main' into fix 2026-01-19 10:54:43 +08:00
橙子
686c3f9208 docs(@vben-core/preferences): update comments (#7107) 2026-01-14 19:36:45 +08:00
MRSWC
8a7e2bd8e4 fix:修复默认默认首页如果携带参数时刷新页面参数丢失问题 (#7102)
Co-authored-by: chenwei <chenw@jiuzhekan.com>
2026-01-14 15:38:55 +08:00
JyQAQ
174c4ae749 fix(antd Upload onChange Event): rewrite onChange event to handle upl… (#7098)
* fix(antd Upload onChange Event): rewrite onChange event to handle upload success or error messages

* fix(antd Upload onChange Event): rewrite onChange event to handle upload success or error messages

* fix(antd Upload onChange Event): rewrite onChange event to handle upload success or error messages
2026-01-14 15:38:21 +08:00
JyQAQ
67da9417a8 feat(upload prop:crop,aspectRatio): from Upload component accept prop… (#7095)
* feat(upload prop:crop,aspectRatio): from Upload component accept prop crop,aspectRatio

* feat(upload prop:crop,aspectRatio): from Upload component accept prop crop,aspectRatio

* feat(upload prop:crop,aspectRatio): from Upload component accept prop crop,aspectRatio

* feat(upload prop:crop,aspectRatio): from Upload component accept prop crop,aspectRatio
2026-01-14 15:38:05 +08:00
ppxb
f4a4ced88d fix: header auto mode issue (#7096) 2026-01-12 21:40:26 +08:00
ppxb
19b2d7af41 fix: tdesign theme toggle and demos (#7087) 2026-01-10 14:11:08 +08:00
yuhengshen
343d8a1c1e fix: 切换时区后,页面不刷新 (#7085)
* fix: 切换时区后,页面不刷新

* fix: keep-alive 的页面,i18n 和 timezone 不更新
2026-01-10 14:10:27 +08:00
JyQAQ
9480f8272a feat(common-ui cropper): Implement the image cropping component VCropper (#7082)
* feat(common-ui cropper): Implement the image cropping component VCropper

* feat(common-ui cropper): Implement the image cropping component VCropper

* feat(common-ui cropper): Implement the image cropping component VCropper

* feat(common-ui cropper): Implement the image cropping component VCropper

* feat(common-ui cropper): Implement the image cropping component VCropper
2026-01-10 14:08:15 +08:00
ppxb
0d9e260a6a fix: vite.config.mts type error (#7081) 2026-01-10 14:07:28 +08:00
ppxb
51bca25345 fix(lint): pnpm format lint warning (#7080) 2026-01-10 14:06:03 +08:00
eric
694396dcfb refactor: move cleanup to finally block 2026-01-09 23:22:49 +08:00
eric
1cb53e943e refactor: 将跳转放到最后 2026-01-09 23:13:06 +08:00
eric
13c8318adc refactor: 1. 用 ref 包装 flag; 2. 在最后 清理 flag; 2026-01-09 23:05:05 +08:00
eric
48ed797055 fix: 防止 /logout 死循环 2026-01-09 22:38:11 +08:00
xingyu4j
3c2285141c chore: update deps 2026-01-06 13:58:42 +08:00
xingyu
49b884c0b1 Merge branch 'main' into fix 2026-01-06 13:50:26 +08:00
ppxb
24d20ca9ee refactor: preference manager and export (#7068)
* fix: preferences drawer outline z-index

* refactor: preferencesManager and exports
2026-01-06 12:42:32 +08:00
wyc001122
6f02181024 fix(layout): 修复双列模式下重复显示logo的问题(#7071) (#7072) 2026-01-05 21:13:06 +08:00
ppxb
ed3353a271 fix: preferences drawer outline z-index (#7067) 2026-01-04 14:44:33 +08:00
xingyu4j
965f5f96b7 chore: update deps 2026-01-04 11:03:19 +08:00
xingyu4j
61d9df7f58 feat: add cascader cspell:words 2026-01-04 11:00:07 +08:00
xingyu4j
231a5169ec fix: lint 2026-01-04 10:56:55 +08:00
xingyu4j
ce7b7b910a Merge branch 'main' of https://github.com/xingyu4j/vue-vben-admin into fix 2026-01-04 10:56:14 +08:00
JyQAQ
81a61558cb feat(upload prop:maxSize): from Upload component accept prop maxSize (AI prompt fixed) (#7059)
* feat(upload prop:maxSize): from component accept prop maxSize

* feat(upload prop:maxSize): from component accept prop maxSize

* feat(upload prop:maxSize): from component accept prop maxSize

* feat(upload prop:maxSize): from component accept prop maxSize
2026-01-03 13:19:40 +08:00
ppxb
7d2bc2e885 fix: dropdown raido menu type error (#7062)
* fix: dropdown raido menu type

* chore: format code
2026-01-02 14:25:19 +08:00
luoqiz
89b237f6b4 feat: 添加上下文菜单演示,添加菜单项隐藏性 (#7057)
Co-authored-by: luoqiz <851092732@qq.com>
2026-01-02 14:22:19 +08:00
JyQAQ
a1bb132233 feat(api-cascader): 添加联级组件ApiCascader (#7031) 2025-12-22 20:00:31 +08:00
zhenghaoyang24
022d538940 Fix formatting in thin.md for clarity (#7008)
修改一些语句错误
2025-12-22 19:58:05 +08:00
xueyitt
ccf70a1b76 feat: 修正菜单排序在二级菜单不生效问题 (#7007)
* treeUtil增加对树形结构数据进行递归排序

* 菜单sort排序各级菜单均生效
2025-12-22 19:57:21 +08:00
xingyu4j
af3fe53ec8 fix: type error 2025-12-22 17:50:06 +08:00
xingyu4j
e981fb159f chore: update deps 2025-12-22 17:49:51 +08:00
xingyu
79b9d55854 Merge branch 'main' into fix 2025-12-22 16:42:15 +08:00
xingyu4j
b2055a4457 chore: update deps 2025-12-17 13:47:37 +08:00
JyQAQ
1479f159aa feat(CellImage): CellImage组件支持图片属性写入 (#6992) 2025-12-06 10:12:58 +08:00
xingyu4j
7bf7e09002 fix: lint 2025-12-05 15:09:43 +08:00
xingyu4j
de8d39ffed chore: workspace file is deprecated 2025-12-05 15:07:39 +08:00
xingyu4j
543a7e3962 chore: update deps 2025-12-05 14:55:44 +08:00
xingyu4j
9dfe3f5af8 fix: type not find 2025-12-04 18:03:55 +08:00
xingyu4j
f11b08d8cb chore: update deps 2025-12-04 17:59:12 +08:00
xingyu4j
45b6f08984 chore: neverBuiltDependencies 2025-12-03 16:34:14 +08:00
xingyu4j
92a4676f8d chore: update version 2025-12-03 16:27:14 +08:00
xingyu4j
7bf7c0bb06 chore: remove unused deps 2025-12-03 16:26:58 +08:00
xingyu4j
8f8cf5b704 chore: update deps 2025-12-03 16:22:14 +08:00
xingyu4j
6be238430d chore: add cspell 2025-12-03 16:12:08 +08:00
xingyu4j
f77216d8f4 feat: lint add pnpm config 2025-12-03 16:11:51 +08:00
xingyu4j
d42a9b2409 feat: lint add yaml config 2025-12-03 16:01:27 +08:00
xingyu4j
6753834054 fix: lint 2025-12-03 15:37:33 +08:00
xingyu4j
77a4a64eb4 fix: stylelint 2025-12-03 15:37:20 +08:00
xingyu4j
49db40d557 feat: cspell sort 2025-12-03 15:37:04 +08:00
xingyu4j
0032c608f1 chore: update deps 2025-12-03 15:36:43 +08:00
xingyu4j
fa603b32b1 fix: locales 2025-12-03 13:51:30 +08:00
JyQAQ
9105d4d14a feat(api-component): api-component组件的options支持指定disabled值 (#6991) 2025-12-03 10:03:23 +08:00
luoqiz
c76db7d8d1 fix: 修复icon丢失根属性导致的样式错误 (#6986) 2025-12-01 09:51:27 +08:00
Jin Mao
6f39e9136e Merge branch 'main' into feature/antd上传组件支持调用Image组件查看图片 2025-11-24 21:59:34 +08:00
milletpeak
1f1ba16ead Merge branch 'main' into milletpeak-fontsize 2025-11-24 08:55:54 +08:00
panda7
b6edc5f574 fix: centered 为 true 时设置 draggable 无法拖拽 (#6948)
Co-authored-by: sqchen <chenshiqi@sshlx.com>
2025-11-24 08:38:10 +08:00
Jin Mao
8b0f138100 Merge branch 'main' into deps 2025-11-24 08:23:02 +08:00
ming4762
a810cd0b48 fix: fix IconPicker reporting an error when using search if no icon is found (#6944)
* 修复未搜索图标时分页报错的问题
 * 优化`IconPicker` 的分页逻辑,由total触发跳转到第一页,而不是用户控制
2025-11-24 07:56:55 +08:00
aonoa
b17fec41b0 fix: tree component cannot set a value (#6941)
Signed-off-by: aonoa <1991849113@qq.com>
2025-11-24 07:56:16 +08:00
Rex
5fcfabf1d4 fix: 修复菜单管理中标题栏样式异常问题 (#6934) 2025-11-24 07:00:08 +08:00
yuan.ji
1d77b018bb feat(function): add antd上传组件支持调用Image组件查看图片 2025-11-21 17:33:59 +08:00
米山
f7d9d1b1af chore: update package.json and app.vue imports, and ensure global styles are included 2025-11-19 11:13:06 +08:00
米山
aaf0274fe9 feat: add menu font size variable and update related components
- Introduced a new CSS variable `--menu-font-size` calculated from the base font size.
- Updated `PreferenceManager` to trigger CSS variable updates when `fontSize` is modified.
- Adjusted `updateCSSVariables` to set the new `--menu-font-size` based on the theme's font size.
- Ensured that the menu components utilize the updated font size with `!important` to maintain styling consistency.
2025-11-19 10:51:10 +08:00
米山
c142af482b fix: update snapshot for defaultPreferences immutability test to reflect fontSize change
- Adjusted the snapshot to ensure consistency with the updated defaultPreferences configuration, specifically retaining the fontSize property.
2025-11-19 10:19:16 +08:00
米山
cd7c11c7d0 fix: run 'pnpm format' update various components and improve layout structure
- Updated demo-preview and preview-group components for better error handling and layout.
- Enhanced drawer and modal components for improved auto-height functionality.
- Refactored layout components including header, footer, sidebar, and tabbar for better responsiveness and usability.
- Adjusted tooltip and help tooltip components for better user guidance.
- Fixed issues in various UI components to ensure consistent styling and functionality across the application.
2025-11-19 10:14:04 +08:00
milletpeak
fb8f36eeec Merge branch 'main' into milletpeak-fontsize 2025-11-19 09:41:55 +08:00
xingyu4j
9a4f0f6ab1 feat: Consider multi-line formatting for readability 2025-11-17 14:24:43 +08:00
xingyu4j
bed52983a0 fix: lint 2025-11-17 12:15:14 +08:00
xingyu4j
655ce2c2e8 chore: update node version >=20.12.0 2025-11-17 12:11:43 +08:00
xingyu4j
f841568e5a chore: update vue-tsc 2025-11-17 12:04:30 +08:00
xingyu4j
469697845c fix: sort 2025-11-17 11:21:49 +08:00
xingyu4j
273f3cbaf8 Merge branch 'main' of https://github.com/xingyu4j/vue-vben-admin into deps 2025-11-17 11:21:16 +08:00
xingyu4j
96f671908e chore: update deps 2025-11-17 11:17:47 +08:00
Jin Mao
f09aace765 fix: 更新依赖后的表格显示问题 2025-11-14 21:44:32 +08:00
Copilot
772529e2fb fix: rollback zod-defaults version to 0.1.3 (#6925)
* Initial plan

* fix: downgrade zod-defaults from 0.2.3 to 0.1.3 for Zod v3 compatibility

Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>
2025-11-14 16:16:45 +08:00
xingyu4j
eeff017b9f chore: add tdesign cspell 2025-11-14 10:22:18 +08:00
xingyu4j
22394ebdeb chore: move tdesign-vue-next to workspace 2025-11-14 10:21:48 +08:00
dependabot[bot]
ffbc9b22a7 chore(deps): bump the non-breaking-changes group across 1 directory with 26 updates (#6914)
Bumps the non-breaking-changes group with 20 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [vue](https://github.com/vuejs/core) | `3.5.23` | `3.5.24` |
| [@clack/prompts](https://github.com/bombshell-dev/clack/tree/HEAD/packages/prompts) | `0.10.1` | `0.11.0` |
| [@iconify/json](https://github.com/iconify/icon-sets) | `2.2.404` | `2.2.406` |
| [@pnpm/workspace.read-manifest](https://github.com/pnpm/pnpm) | `1000.2.5` | `1000.2.6` |
| [@tanstack/vue-query](https://github.com/TanStack/query/tree/HEAD/packages/vue-query) | `5.90.7` | `5.91.0` |
| [@tanstack/vue-store](https://github.com/TanStack/store/tree/HEAD/packages/vue-store) | `0.7.7` | `0.8.0` |
| [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.46.3` | `8.46.4` |
| [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.46.3` | `8.46.4` |
| [@vue/shared](https://github.com/vuejs/core/tree/HEAD/packages/shared) | `3.5.23` | `3.5.24` |
| [commitlint-plugin-function-rules](https://github.com/vidavidorra/commitlint-plugin-function-rules) | `4.1.0` | `4.1.1` |
| [eslint-config-turbo](https://github.com/vercel/turborepo/tree/HEAD/packages/eslint-config-turbo) | `2.6.0` | `2.6.1` |
| [lucide-vue-next](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-vue-next) | `0.507.0` | `0.553.0` |
| [prettier-plugin-tailwindcss](https://github.com/tailwindlabs/prettier-plugin-tailwindcss) | `0.6.14` | `0.7.1` |
| [sass](https://github.com/sass/dart-sass) | `1.93.3` | `1.94.0` |
| [typescript](https://github.com/microsoft/TypeScript) | `5.8.2` | `5.9.3` |
| [unplugin-element-plus](https://github.com/element-plus/unplugin-element-plus) | `0.10.0` | `0.11.1` |
| [vxe-pc-ui](https://github.com/x-extends/vxe-pc-ui) | `4.10.16` | `4.10.22` |
| [vxe-table](https://github.com/x-extends/vxe-table) | `4.17.10` | `4.17.14` |
| [zod-defaults](https://github.com/Ced-Sharp/zod-defaults) | `0.1.3` | `0.2.3` |
| [@ast-grep/napi](https://github.com/ast-grep/ast-grep) | `0.37.0` | `0.39.9` |



Updates `vue` from 3.5.23 to 3.5.24
- [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.23...v3.5.24)

Updates `@clack/prompts` from 0.10.1 to 0.11.0
- [Release notes](https://github.com/bombshell-dev/clack/releases)
- [Changelog](https://github.com/bombshell-dev/clack/blob/@clack/prompts@0.11.0/packages/prompts/CHANGELOG.md)
- [Commits](https://github.com/bombshell-dev/clack/commits/@clack/prompts@0.11.0/packages/prompts)

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

Updates `@pnpm/workspace.read-manifest` from 1000.2.5 to 1000.2.6
- [Release notes](https://github.com/pnpm/pnpm/releases)
- [Commits](https://github.com/pnpm/pnpm/commits)

Updates `@tanstack/vue-query` from 5.90.7 to 5.91.0
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/vue-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/vue-query@5.91.0/packages/vue-query)

Updates `@tanstack/vue-store` from 0.7.7 to 0.8.0
- [Release notes](https://github.com/TanStack/store/releases)
- [Commits](https://github.com/TanStack/store/commits/v0.8.0/packages/vue-store)

Updates `@typescript-eslint/eslint-plugin` from 8.46.3 to 8.46.4
- [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.46.4/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.46.3 to 8.46.4
- [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.46.4/packages/parser)

Updates `@vue/shared` from 3.5.23 to 3.5.24
- [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.24/packages/shared)

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

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

Updates `eslint-config-turbo` from 2.6.0 to 2.6.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.6.1/packages/eslint-config-turbo)

Updates `lodash.clonedeep` from 4.5.0 to 
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/commits)

Updates `lodash.get` from 4.4.2 to 
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/commits)

Updates `lodash.isequal` from 4.5.0 to 
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/commits)

Updates `lodash.set` from 4.3.2 to 
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/commits)

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

Updates `prettier-plugin-tailwindcss` from 0.6.14 to 0.7.1
- [Release notes](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/compare/v0.6.14...v0.7.1)

Updates `sass` from 1.93.3 to 1.94.0
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.93.3...1.94.0)

Updates `typescript` from 5.8.2 to 5.9.3
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release-publish.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.8.2...v5.9.3)

Updates `unplugin-element-plus` from 0.10.0 to 0.11.1
- [Release notes](https://github.com/element-plus/unplugin-element-plus/releases)
- [Commits](https://github.com/element-plus/unplugin-element-plus/compare/v0.10.0...v0.11.1)

Updates `vxe-pc-ui` from 4.10.16 to 4.10.22
- [Release notes](https://github.com/x-extends/vxe-pc-ui/releases)
- [Commits](https://github.com/x-extends/vxe-pc-ui/commits)

Updates `vxe-table` from 4.17.10 to 4.17.14
- [Release notes](https://github.com/x-extends/vxe-table/releases)
- [Commits](https://github.com/x-extends/vxe-table/compare/4.17.10...4.17.14)

Updates `zod-defaults` from 0.1.3 to 0.2.3
- [Commits](https://github.com/Ced-Sharp/zod-defaults/commits)

Updates `@ast-grep/napi` from 0.37.0 to 0.39.9
- [Release notes](https://github.com/ast-grep/ast-grep/releases)
- [Changelog](https://github.com/ast-grep/ast-grep/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ast-grep/ast-grep/compare/0.37.0...0.39.9)

Updates `@vue/reactivity` from 3.5.23 to 3.5.24
- [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.24/packages/reactivity)

---
updated-dependencies:
- dependency-name: vue
  dependency-version: 3.5.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@clack/prompts"
  dependency-version: 0.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@iconify/json"
  dependency-version: 2.2.406
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@pnpm/workspace.read-manifest"
  dependency-version: 1000.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@tanstack/vue-query"
  dependency-version: 5.91.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@tanstack/vue-store"
  dependency-version: 0.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.46.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.46.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: "@vue/shared"
  dependency-version: 3.5.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: autoprefixer
  dependency-version: 10.4.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: commitlint-plugin-function-rules
  dependency-version: 4.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: eslint-config-turbo
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: lodash.clonedeep
  dependency-version: 
  dependency-type: direct:production
  dependency-group: non-breaking-changes
- dependency-name: lodash.get
  dependency-version: 
  dependency-type: direct:production
  dependency-group: non-breaking-changes
- dependency-name: lodash.isequal
  dependency-version: 
  dependency-type: direct:production
  dependency-group: non-breaking-changes
- dependency-name: lodash.set
  dependency-version: 
  dependency-type: direct:production
  dependency-group: non-breaking-changes
- dependency-name: lucide-vue-next
  dependency-version: 0.553.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: prettier-plugin-tailwindcss
  dependency-version: 0.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: sass
  dependency-version: 1.94.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: typescript
  dependency-version: 5.9.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: unplugin-element-plus
  dependency-version: 0.11.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: vxe-pc-ui
  dependency-version: 4.10.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: vxe-table
  dependency-version: 4.17.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: non-breaking-changes
- dependency-name: zod-defaults
  dependency-version: 0.2.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@ast-grep/napi"
  dependency-version: 0.39.9
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: non-breaking-changes
- dependency-name: "@vue/reactivity"
  dependency-version: 3.5.24
  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>
2025-11-14 08:05:04 +08:00
Jin Mao
c3a7562e2c Merge branch 'main' into milletpeak-fontsize 2025-11-13 17:01:42 +08:00
Jin Mao
605e0ea128 chore: 更新依赖 2025-11-13 09:23:12 +08:00
dependabot[bot]
c89a83f980 chore(deps): bump stylelint-config-recommended from 14.0.1 to 17.0.0 (#6901)
Bumps [stylelint-config-recommended](https://github.com/stylelint/stylelint-config-recommended) from 14.0.1 to 17.0.0.
- [Release notes](https://github.com/stylelint/stylelint-config-recommended/releases)
- [Changelog](https://github.com/stylelint/stylelint-config-recommended/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint-config-recommended/compare/14.0.1...17.0.0)

---
updated-dependencies:
- dependency-name: stylelint-config-recommended
  dependency-version: 17.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-13 09:17:44 +08:00
Jin Mao
cfad88666b chore: 替换 lodash-es为 es-toolkit 并调整样式引入方式 (#6912) 2025-11-13 08:20:30 +08:00
Jin Mao
f918dc24c6 chore(@vben/utils): 移除冗余的 lodash 依赖 2025-11-13 07:47:48 +08:00
Jin Mao
e898993fe8 chore(@vben/utils): 替换 lodash 工具函数为 es-toolkit 实现 2025-11-13 07:45:10 +08:00
Jin Mao
5cafcb4a01 refactor(shared): 替换 lodash 工具函数为 es-toolkit 兼容版本
- 将 get 和 isEqual 方法从 lodash 替换为 es-toolkit/compat 导出
- 更新 package.json 添加 es-toolkit 依赖
- 注释掉原有的 lodash.get 和 lodash.isequal 导出语句- 锁定 es-toolkit 版本至1.41.0 并更新相关依赖配置
2025-11-13 07:28:52 +08:00
Jin Mao
03154cde88 chore: update depends 2025-11-13 07:16:28 +08:00
dependabot[bot]
a74bf7b63f chore(deps): bump echarts from 5.6.0 to 6.0.0 (#6859)
Bumps [echarts](https://github.com/apache/echarts) from 5.6.0 to 6.0.0.
- [Release notes](https://github.com/apache/echarts/releases)
- [Commits](https://github.com/apache/echarts/compare/5.6.0...6.0.0)

---
updated-dependencies:
- dependency-name: echarts
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2025-11-13 07:10:59 +08:00
米山
0bc7169698 feat: add global font size adjustment 2025-11-12 17:39:07 +08:00
米山
24b6e7a835 feat: add global font size adjustment 2025-11-12 17:38:41 +08:00
Jin Mao
f59e33682c Merge branch 'main' into main 2025-11-12 04:27:57 +08:00
Jin Mao
d811af37dd Merge branch 'main' into profile 2025-11-12 04:03:27 +08:00
Jin Mao
0e1a7d61f3 Merge branch 'main' into fix-downloader 2025-11-12 02:05:03 +08:00
panda7
573637222d feat: add form handleCollapsedChange event (#6893)
* feat: add form handleCollapsedChange event

* fix: ts lint

* fix: ts error

---------

Co-authored-by: sqchen <chenshiqi@sshlx.com>
2025-11-12 02:03:12 +08:00
shixi
05e9d65251 fix: for tdesign 2025-11-12 01:14:28 +08:00
shixi
0bbb20fee0 feat: sport notification link 2025-11-12 00:55:24 +08:00
shixi
dbc5ea32ae feat: add read and delete for each notification 2025-11-12 00:02:13 +08:00
xingyu4j
0319604863 feat: playground add profile 2025-11-10 18:00:50 +08:00
xingyu4j
acf99f2441 feat: tdesign add profile 2025-11-10 18:00:25 +08:00
xingyu4j
cbf2a02877 feat: naive add profile 2025-11-10 17:59:58 +08:00
xingyu4j
226d9bd1ad feat: ele add profile 2025-11-10 17:59:33 +08:00
xingyu4j
48b3d30088 fix: types 2025-11-10 17:54:01 +08:00
xingyu4j
e311cfb8da feat: route add profile 2025-11-10 17:51:10 +08:00
xingyu4j
4347fba80a feat: antdv add profile 2025-11-10 17:50:47 +08:00
xingyu4j
7dc68ed368 feat: add profile comps 2025-11-10 17:49:58 +08:00
Jin Mao
a4aa133db5 Merge branch 'main' into tdesign 2025-11-09 12:04:30 +08:00
Utopia
6bbe523f6f chore: 增强 util-formatDate ts 类型提示 (#6886)
* feat: 为 auth layout 添加 slot: logo, 提升组件的灵活性和可复用性

* feat: 增强 util-formatDate ts 类型提示
2025-11-09 12:00:49 +08:00
Copilot
fef1e35c54 fix: prevent JSONBigInt parsing error on non-string data (#6891)
* Initial plan

* Fix json-bigint serialization error when data is not a string

Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>
2025-11-09 11:49:38 +08:00
xingyu
20410aeb03 fix: updating Tailwind CSS variables from --radix-* to --reka-* (#6890)
* fix: radix => reka

* chore: add reka cspell

* fix: Composition url
2025-11-09 11:49:01 +08:00
Li Kui
83ea27af3e fix: fix lint 2025-11-06 23:16:23 +08:00
Li Kui
b7bfd69788 fix: fix lint 2025-11-06 23:10:03 +08:00
Li Kui
99d663a6f2 fix: fix typecheck 2025-11-06 23:02:24 +08:00
Li Kui
1af11240a6 chore: add tdesign logo 2025-11-06 22:37:55 +08:00
Li Kui
3e8e8690e3 chore: Merge branch 'main' into tdesign 2025-11-06 17:49:51 +08:00
Li Kui
be843300be chore: update demo routes 2025-11-06 17:44:34 +08:00
Li Kui
dc77721c11 chore: demo i18n 2025-11-06 16:42:25 +08:00
Li Kui
a38d081f17 chore: enable VITE_NITRO_MOCK 2025-11-06 16:37:15 +08:00
Copilot
1e09fa4642 feat: migrate from Radix Vue to Reka UI (#6870)
* Initial plan

* Update dependencies and imports from radix-vue to reka-ui

Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>

* Fix type errors after reka-ui migration

Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>

* Run formatter to fix code style

Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>
2025-11-06 16:22:24 +08:00
Li Kui
bd8ff73f9e fix: fix build error 2025-11-06 15:26:24 +08:00
Li Kui
57620dc2ea chore: apply coderabbitai suggestions 2025-11-06 15:11:28 +08:00
Li Kui
b472fbb72f Merge branch 'main' into tdesign 2025-11-06 14:36:27 +08:00
Copilot
04321b16c1 fix: replace ant-design-vue with tdesign components in web-tdesign app (#6880)
* Initial plan

* fix: replace ant-design-vue with tdesign components

Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>

* fix: remove trailing comma in package.json

Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: likui628 <90845831+likui628@users.noreply.github.com>
2025-11-06 14:35:50 +08:00
Olexandr88
7268824612 Update README.md (#6828)
Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2025-11-04 04:34:55 +08:00
dependabot[bot]
23c41a8059 chore(deps): bump @types/node from 12.20.55 to 24.9.2 (#6860)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 12.20.55 to 24.9.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.9.2
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-04 04:16:59 +08:00
dependabot[bot]
fdc78faa13 chore(deps): bump @vueuse/integrations from 12.8.2 to 14.0.0 (#6861)
Bumps [@vueuse/integrations](https://github.com/vueuse/vueuse/tree/HEAD/packages/integrations) from 12.8.2 to 14.0.0.
- [Release notes](https://github.com/vueuse/vueuse/releases)
- [Commits](https://github.com/vueuse/vueuse/commits/v14.0.0/packages/integrations)

---
updated-dependencies:
- dependency-name: "@vueuse/integrations"
  dependency-version: 14.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-04 04:16:37 +08:00
dependabot[bot]
c8af580866 chore(deps): bump SamKirkland/FTP-Deploy-Action (#6873)
Bumps the non-breaking-changes group with 1 update: [SamKirkland/FTP-Deploy-Action](https://github.com/samkirkland/ftp-deploy-action).


Updates `SamKirkland/FTP-Deploy-Action` from 4.3.5 to 4.3.6
- [Release notes](https://github.com/samkirkland/ftp-deploy-action/releases)
- [Commits](https://github.com/samkirkland/ftp-deploy-action/compare/v4.3.5...v4.3.6)

---
updated-dependencies:
- dependency-name: SamKirkland/FTP-Deploy-Action
  dependency-version: 4.3.6
  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>
2025-11-04 04:14:47 +08:00
Jin Mao
348c97710f Revert "refactor(jwt): 更新 JWT 工具函数实现方式 (#6869)"
This reverts commit a854760d26.
2025-11-03 19:34:45 +08:00
zengmingyong
a854760d26 refactor(jwt): 更新 JWT 工具函数实现方式 (#6869)
refactor(jwt): 更新 JWT 工具函数实现方式

- 将默认导入 jsonwebtoken 改为解构导入 sign 和 verify 方法
2025-11-03 13:08:06 +08:00
Copilot
c7c39047de feat: add theme-aware logo support via optional sourceDark configuration (#6866)
* Initial plan

* Initial exploration and setup

Co-authored-by: aonoa <32682251+aonoa@users.noreply.github.com>

* Add support for separate light and dark theme logos

Co-authored-by: aonoa <32682251+aonoa@users.noreply.github.com>

* Update documentation with dark theme logo configuration

Co-authored-by: aonoa <32682251+aonoa@users.noreply.github.com>

* feat: Add theme-aware logo support for authentication/login page

Co-authored-by: aonoa <32682251+aonoa@users.noreply.github.com>

* revert: .npmrc

Signed-off-by: aonoa <1991849113@qq.com>

---------

Signed-off-by: aonoa <1991849113@qq.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: aonoa <32682251+aonoa@users.noreply.github.com>
Co-authored-by: Li Kui <90845831+likui628@users.noreply.github.com>
Co-authored-by: aonoa <1991849113@qq.com>
2025-11-03 13:07:36 +08:00
Jin Mao
f8a7a0a9a2 chore: lint 2025-10-31 09:11:40 +08:00
Jin Mao
2cb3dcf499 Merge branch 'fork/ming4762/timezone-fix-20251030'
# Conflicts:
#	packages/stores/src/modules/timezone.ts
2025-10-31 09:08:08 +08:00
Jin Mao
b36d32b66d chore(timezone): 添加 $reset 方法并初始化时区存储
- 在时区存储中添加 `$reset` 方法
-修复导入语句引号为双引号
- 优化时区初始化错误处理逻辑- 导出 `$reset` 方法以便外部调用- 确保时区设置与默认选项同步
- 提升代码一致性和可维护性
2025-10-30 23:27:53 +08:00
zhongming4762
639ea96bb9 fix: resolve the issue of logout failure caused by the timezone store 2025-10-30 17:12:45 +08:00
zhongming4762
565be77e96 fix: resolve the issue of logout failure caused by the timezone store 2025-10-30 17:01:49 +08:00
Jin Mao
ac6de0324c Merge branch 'fork/ming4762/timezone-20251020' 2025-10-30 00:42:05 +08:00
zhongming4762
f46ae023ba feat: increase support for multiple time zones
* 优化实现方法
2025-10-29 20:14:48 +08:00
zhongming4762
212144feca feat: increase support for multiple time zones
* 优化实现方法
2025-10-29 20:10:25 +08:00
zhongming4762
3eed51fd3e feat: increase support for multiple time zones
* 优化实现方法
2025-10-29 20:03:21 +08:00
zhongming4762
4d713db546 feat: increase support for multiple time zones
* 优化实现方法
2025-10-29 19:47:10 +08:00
Jin Mao
0cd9f4615c Merge branch 'main' into fix-downloader 2025-10-26 15:28:34 +08:00
Jin Mao
cfbce0d737 chore: fix lint 2025-10-26 15:27:28 +08:00
Jin Mao
1d9cd88dd7 Merge branch 'main' into fix-downloader 2025-10-26 15:16:32 +08:00
Jin Mao
0e62862119 chore: fix lint 2025-10-26 15:01:58 +08:00
Jin Mao
6b6cdef42d chore: 一些调整 2025-10-26 15:00:47 +08:00
Jin Mao
33b7a605c0 chore: 一些调整和兼容性更新 2025-10-26 14:23:37 +08:00
zhongming4762
e01803ce9d feat: increase support for multiple time zones 2025-10-22 20:39:00 +08:00
zhongming4762
e3e5755903 feat: increase support for multiple time zones 2025-10-22 20:29:53 +08:00
zhongming4762
61ce53b686 feat: increase support for multiple time zones 2025-10-22 20:23:55 +08:00
zhongming4762
b029f77b6a feat: increase support for multiple time zones 2025-10-22 20:18:25 +08:00
zhongming4762
0a8339a405 feat: increase support for multiple time zones 2025-10-22 19:52:01 +08:00
Jin Mao
2264eaae18 feat: 新增集成tdesign组件的apps 2025-10-21 10:47:39 +08:00
zoumingjun
38f91da5af fix: 优化双列布局组件点击展开左侧按钮位置不居中问题 2025-10-18 21:22:58 +08:00
zoumingjun
8edea3aee5 fix: 调整zh-CN/system.json中<"title": "系统管理">配置位置,保持与en-US/system.json中位置一致 2025-10-18 21:20:54 +08:00
zoumingjun
08b6e7713e fix: 修复对话框modal组件方法名错误 2025-10-18 21:13:34 +08:00
zoumingjun
6a89814b83 chore: 优化侧边栏展开折叠图标 2025-10-18 20:59:14 +08:00
zoumingjun
52d3aa9315 fix: 优化Checkbox组件hover样式,Input组件placeholder样式,TabsList组件圆角样式 2025-10-18 20:58:48 +08:00
zoumingjun
4e264c503a fix: 锁屏和解锁密码输入框自动聚焦 2025-10-18 20:55:53 +08:00
zoumingjun
32051e9ca0 fix: 优化左侧和右侧认证面板动画效果 2025-10-18 20:52:27 +08:00
zoumingjun
2b0079580b fix: 修复mock-data.ts父id错误 2025-10-18 16:32:23 +08:00
lidongcheng88
03ce030e7c fix: 混合双列 onMounted 关闭二级侧边栏 (#6807)
Co-authored-by: ldc <lidchen@tencent.com>
2025-10-14 06:56:00 +08:00
zouawen
59097e2466 chore: 新增是否开启首选项导航栏(外观、布局、快捷键、通用)吸顶效果,调整部分样式 (#6804) 2025-10-14 06:55:11 +08:00
zouawen
2ce161e585 feat: 1、新增水印文案自定义功能;2、input-item输入框组件新增清除功能(可用于快捷清除水印文案);3、偏好设置、主题切换、语言选择、是否全屏按钮新增动画效果 (#6800)
* feature: 新增水印文案自定义功能;

* chore: 偏好设置、主题切换、语言选择、是否全屏按钮新增动画效果
2025-10-07 06:15:41 +08:00
zouawen
33306a5aff chore: 更换其他登录方式图标为彩色图标,新增其他登录方式tooltip文字提示 (#6799) 2025-10-06 06:56:54 +08:00
lw567
6e03de5011 fix: watermark create error #6788 (#6789)
Co-authored-by: liwei567 <liwei567@example.com>
2025-09-30 19:53:09 +08:00
HaHa
713281a8ba fix(theme-button): fix flicker during theme switch (#6782) 2025-09-30 05:10:51 +08:00
shierd
42e3de9e2c fix: 修复设置表单值时合并子对象的错误 (#6780)
Co-authored-by: shier <shier@shierd.com>
2025-09-30 05:10:39 +08:00
vent
1e029dbc9a fix: 修复部分场景 echarts 在使用 v-show 时获取不到 width 的问题 (#6776) 2025-09-30 05:09:33 +08:00
Cup_Of_Bread
81bb7456f8 fix: 修复注解错误 (#6763) 2025-09-23 23:49:25 +08:00
pangyajun123
26f8d2aa30 perf: 表单需要通过权限控制是否需要展示,dependencies.if 这种方式需要别triggerFields触发字段,不能满足要求 (#6756) 2025-09-23 23:48:27 +08:00
boisduval
a8b848d367 fix: 解决搜索表单中arrayToStringFields属性无法在搜索时生效的问题 (#6591)
- 合并handleArrayToStringFields与handleStringToArrayFields为handleMultiFields
- 在handleMultiFields判断arrayToString或stringToArray
- 删除两个方法在其他地方的引用 统一为在handleRangeTimeValue内调用handleMultiFields实现数据转换

Co-authored-by: 宛晴 <wanqing@mengtaigroup.com>
2025-09-23 23:45:26 +08:00
ming4762
482ce981ce chore: update deps vxe, vxe-table: 4.14.4 -> 4.16.11 vxe-pc-ui: 4.7.… (#6752)
* chore: update deps vxe, vxe-table: 4.14.4 -> 4.16.11  vxe-pc-ui: 4.7.12 -> 4.9.29

* fix: resolve the ESLint warning generated by #6317
2025-09-17 17:42:39 +08:00
Jin Mao
97ad93ab1f Merge branch 'zouawen-main' 2025-09-17 17:41:05 +08:00
Jin Mao
319b7fcdaa Merge branch 'main' of https://github.com/zouawen/vue-vben-admin into zouawen-main 2025-09-17 17:37:43 +08:00
Jin Mao
4de8220ce6 feat(common-ui): 添加 Tree 组件
- 在 common-ui 包中新增 Tree 组件
- 实现了基本的树形结构展示功能
- 集成了 VbenTree 组件和自定义样式- 添加了空数据时的占位展示
2025-09-17 17:28:39 +08:00
Jin Mao
9114692f95 Merge branch 'main' into main 2025-09-15 08:08:31 +08:00
Jin Mao
0f7731b611 Merge branch 'ming4762-stream-2025091101' 2025-09-15 08:03:52 +08:00
Jin Mao
8040bc1a22 Merge branch 'stream-2025091101' of https://github.com/ming4762/smart-boot-ui-vben into ming4762-stream-2025091101 2025-09-15 08:02:30 +08:00
oc
11d273cbb6 feat(authentication): 二维码登录和验证码登录组件增加返回按钮显隐配置 (#6713)
- 在 CodeLogin 和 QrcodeLogin 组件中添加 showBack 属性
- 根据 showBack 属性决定是否显示返回按钮
- 默认值为 true,即默认显示返回按钮
2025-09-15 07:43:18 +08:00
zouawen
a4b8f8f795 fix: 节点选中时过滤父节点禁用状态 2025-09-12 17:31:42 +08:00
zouawen
dfa2ac3435 fix: 全选时过滤disabled的节点 2025-09-11 18:16:10 +08:00
zouawen
39820c783c fix:
1、VbenTree新增是否全选、展开折叠功能;
2、解决当点击子节点label文字区域,而非checkbox时,关联父组件不能选中问题;
3、优化子节点选中时关联父节点选中功能:删除VbenTree中processParentSelection方法,改为在onSelect中实现,原因:processParentSelection在每次模型值更新时都会被调用,且计算复杂度为O(n^2),onSelect只在交互时触发,复杂度为O(n);
4、新增中间层tree组件,处理无数据时显示场景(显示图标Inbox和国际化comom.noData文本);
5、为防止父组件传值子组件boolean类型默认false问题,新增treePropsDefaults方法,为TreeProps赋默认值,Tree组件和VbenTree组件统一使用;
6、优化VbenTree组件整体样式(优化padding、margin、gap值,优化type为button时outline左右空白区域不对称问题),优化内部header、footer插槽样式。
2025-09-11 16:41:42 +08:00
zhongming4762
66822a5f95 feat: add SSE support to request-client 2025-09-11 11:22:47 +08:00
zhongming4762
eb4f1f8164 feat: add SSE support to request-client 2025-09-11 10:50:19 +08:00
谦元吉
6a85b3ab84 fix(@vben/common-ui): resolve #6698 (#6700)
* fix(@vben/common-ui): resolve #6698

* fix(@vben/common-ui): resolve #6698

* fix(@vben/common-ui): resolve conversation

* fix(@vben/common-ui): resolve #6698
2025-09-02 17:02:11 +08:00
谦元吉
c57592f3a6 fix(@vben-core/shadcn-ui): 修复VbenPinInput组件在点击获取验证码和回车同时进行时会重复触发计时器的问题 (#6705) 2025-09-02 16:56:46 +08:00
Ken Hai
b0d7b177be fix: 角色管理,授权的树形组件,取消勾选叶子节点,父级节点状态错误 (#6680)
Co-authored-by: haiyinlong <haiyinlong@uhigame.com>
2025-08-25 21:32:01 +08:00
LinaBell
566d3bdf7c fix: appendToMain warning (#6684) 2025-08-25 21:25:29 +08:00
螃蟹
adbf793e79 fix(@vben/web-ele): the main color tone for switching between dark and light themes has been reset (#6678) 2025-08-25 11:03:54 +08:00
LinaBell
cf6c4c9aae fix: cannot read properties of null (reading 'nextSibling') (#6667) 2025-08-21 22:26:10 +08:00
Ken Hai
ffaf85c8f3 fix: 修复角色修改时VbenTree组件没有回显选中 (#6662)
* fix: 修复角色修改时VbenTree组件没有回显选中

* chore: use nextTick

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix: merge

* chore: 更新

---------

Co-authored-by: haiyinlong <haiyinlong@uhigame.com>
Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-21 15:30:58 +08:00
panda7
2cc78f925f fix: the bug in the lock method of the vbenModal component (#6648) 2025-08-21 15:17:55 +08:00
ming4762
93f0eea4e7 fix: fix the issue of excessive line spacing in vbenForm (#6653)
* gap-2和 pb-4/2 重叠导致间距过宽,gap-x只保留列间距
2025-08-21 12:41:04 +08:00
lighua
fddfc6d494 fix: 增加对不支持的 HTTP 方法的错误处理 2025-08-21 11:13:02 +08:00
谦元吉
58e3941810 chore(docs): update the component import of the form adapter description in the document (#6656) 2025-08-19 16:48:10 +08:00
Svend
3ad433a50b fix: 修复在 hash 路由模式下无法在新窗口打开路由的问题 (#6652)
此问题是由于 PR #6583 中新增的 `resolveHref` 函数导致的。其在 hash 路由模式下,得到的 URL 会包含 #/ 前缀。在经过 openRouteInNewWindow 的逻辑后就会出现两次 /# 前缀
2025-08-19 16:47:45 +08:00
ming4762
8ac2db5b7c fix: fix the issue of VbenForm compact reactive failure (#6654) 2025-08-19 16:46:14 +08:00
Elm1992
a441dcebae fix: meta.link invalid issue 2025-08-19 16:40:16 +08:00
Vben
ff4704d5ea chore: Upgrade vite to version 7.x (#6645) 2025-08-16 22:50:31 +08:00
菠萝吹雪
6ddfbd84b0 chore: modify the contributor showcase in the README (#6636) 2025-08-16 22:47:08 +08:00
ming4762
1e6417f95b feat: vBenForm add layout: inline (#6644) 2025-08-16 22:41:08 +08:00
vben
e147a9d2fd chore: release 5.5.9 2025-08-16 22:16:02 +08:00
谦元吉
4efebb8c0b fix:update (#6635) 2025-08-14 22:01:12 +08:00
gxc685
9ce0df88ae fix: 修复mock里面eventHandler重复导致无法启动 (#6631) 2025-08-14 22:00:54 +08:00
谦元吉
3cf0c0eb04 fix(@vben/backend-mock): go back to the last modification (#6634)
* fix(@vben/backend-mock): the version went back to the last submission, and the latest submission was completely useless.

* fix: resolve conflicts
2025-08-14 12:06:41 +08:00
谦元吉
ab7e363279 fix(@vben/backend-mock): fix all ts type errors in this module (#6613)
* fix(@vben/backend-mock): 修复所有 ts 类型报错

* fix(@vben/backend-mock): 修复该模块所有 ts 类型报错

* fix(@vben/backend-mock): 解决 coderabbitai

* fix(@vben/backend-mock): 解决 coderabbitai

* fix(@vben/backend-mock): 解决 coderabbitai
2025-08-12 17:23:39 +08:00
lighua
df655015b1 fix: 优化文件下载器方法 2025-08-08 15:31:31 +08:00
xueyang
9fc594434f perf: 优化useVbenForm样式 (#6611)
* perf(style): 优化useVbenForm垂直布局 actions 样式

* perf(style): 优化useVbenForm actions 布局样式

- 操作按钮组显示位置
```
actionPosition?: 'center' | 'left' | 'right';
```
- 操作按钮组的样式
```
actionType?: 'block' | 'inline'
inline: 行类显示,block: 新一行单独显示
```

* perf: 优化useVbenForm actions 布局样式

删除 actionType
增加 actionLayout
- actionLayout?: 'inline' | 'newLine' | 'rowEnd';
- newLine: 在新行显示。rowEnd: 在行内显示,靠右对齐(默认)。inline: 使用grid默认样式
- 删除无用代码 queryFormStyle

* perf: 优化useVbenForm使用案例

* perf: 优化form组件样式

去掉padding,改为gap

* docs: update vben-form.md

* fix: 修复FormMessage位置

* perf: Avoid direct mutation of props object.

-  props.actionLayout = props.actionLayout || 'rowEnd';
-  props.actionPosition = props.actionPosition || 'right';
+  const actionLayout = props.actionLayout || 'rowEnd';
+  const actionPosition = props.actionPosition || 'right';

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix: 修复 wrapperClass 权重

* fix: 全局搜索结果不匹配 #6603

* fix: 避免FormMessage溢出

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-07 23:48:34 +08:00
leo
b93e22c45a fix(@vben/layouts): respect base URL when opening route in new window (#6583)
Previously, the generated URL for opening routes in a new window did not include the router base,
which led to incorrect paths when the app was deployed under a subdirectory (e.g., /admin/).
This change ensures that the resolved path includes the configured base by using
router.resolve(path).href.
2025-07-29 13:46:05 +08:00
Jin Mao
193f5b6512 Merge branch 'main' into 2025072604 2025-07-28 15:53:04 +08:00
Jin Mao
cb3f96683f fix: 修复双列布局模式下,路由为hideInMenu时,空白右列 2025-07-28 15:50:21 +08:00
zhongming4762
06ffdf164a feat: add dingding login 2025-07-25 22:02:55 +08:00
ming4762
5b75e5e917 perf: perf the control logic of VbenModal full screen and header (#6566)
* resolve the issue of header=false and full screen button display but not operable
2025-07-25 21:45:45 +08:00
aonoa
fad0b49841 fix: adding roles does not automatically refresh (#6548)
* fix: adding roles does not automatically refresh

* style: fix code style err
2025-07-25 21:35:57 +08:00
Jin Mao
260e45cd7b Merge branch 'main' into feat/add-vben-modal-animation 2025-07-25 21:33:11 +08:00
vben
1575619d53 chore: release v5.5.8 2025-07-19 22:19:50 +08:00
Jin Mao
d5a36a167d fix: fix vxeTable commit proxy (#6536)
* fix: 修正use-vxe-grid中的代理配置提交类型

* chore: change config
2025-07-19 16:07:15 +08:00
panda7
fc9ea347ca Merge branch 'main' into feat/add-vben-modal-animation 2025-07-18 00:38:54 +08:00
 panda7
1a9b0509d5 feat: add animation effects to VbenModal component 2025-07-18 00:15:40 +08:00
panda7
07b64ad384 feat: add function support for formItemClass prop (#6511)
* feat: add function support for formItemClass prop

* feat: add try-catch to formItemClass function

* fix: formItemClass function ts error

---------

Co-authored-by: sqchen <chenshiqi@sshlx.com>
2025-07-17 09:37:39 +08:00
Jin Mao
1bc5d2986b chore: update-vxe-table (#6516)
* chore: update vxe-pc-ui,vxe-table

* fix(ui): 修复代理配置初始化方法名错误

* fix(ui): 修改远程表格刷新配置

* chroe: update vxeTable

更新到最新
2025-07-16 19:15:39 +08:00
HamWong
bb36cca315 fix: 锁定屏幕页面样式自适应 (#6480) 2025-07-15 09:08:08 +08:00
Jin Mao
b8bf482c6a Merge branch 'main' into form 2025-07-07 09:16:54 +08:00
Jin Mao
3b673ca915 Merge branch 'main' into feature/scroll_to_the_error_field 2025-07-07 08:21:50 +08:00
Jin Mao
bbf0287511 chore: fix lint warning (#6487) 2025-07-07 08:21:25 +08:00
panda7
d4786f3f75 Merge branch 'main' into feature/scroll_to_the_error_field 2025-07-06 21:19:52 +08:00
xue-jn
b333fd676d docs: update vben-drawer.md (#6478)
* docs: update vben-drawer.md

* docs: update vben-drawer.md

---------

Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2025-07-06 20:26:06 +08:00
sqchen
f1051c8773 feat: add scrollToFirstError to the form component 2025-07-05 00:50:53 +08:00
sqchen
243f3a201d feat: add scrollToFirstError to the form component 2025-07-05 00:19:12 +08:00
陈蔚然
2f7de243f6 Merge branch 'vbenjs:main' into slider-translate-captcha 2025-07-04 10:28:40 +08:00
chenweiran
1aafb43103 feat: 增加基于图片拼图切片平移的验证码 2025-07-04 10:26:02 +08:00
chenweiran
8ccd01ade5 feat: 增加基于图片拼图切片平移的验证码 2025-07-04 10:23:47 +08:00
Netfan
e6bfbce6cb revert: page height fixed,revert #6422 2025-07-03 22:29:48 +08:00
someone-cool
1f63aed64c fix(@vben/common-ui): add page footer's height to calc contentstyle (#6422) 2025-07-03 18:36:42 +08:00
xue-jn
253b0da7d2 fix: 接口返回子节点为空数组时,还会显示折叠箭头 (#6463) 2025-07-03 18:35:03 +08:00
RanMaoting
33a4d524db feat(@vben/plugins): 新增VxeGrid组件插槽类型定义 (#6452)
* feat(@vben/plugins): 新增VxeGrid组件插槽类型定义

Closes: #6451

* fix(@vben/plugins): 优化vxe-table组件的插槽类型定义

修复Omit导致的类型丢失
2025-07-03 18:34:37 +08:00
chenweiran
bbd8a53d9d feat: 增加基于图片拼图切片平移的验证码 2025-07-03 18:20:20 +08:00
chenweiran
8554924cb9 feat: 增加基于图片拼图切片平移的验证码 2025-07-03 17:43:19 +08:00
RanMaoting
fee811d950 fix: 优化组件方法透传并新增表单弹窗示例 (#6443) 2025-07-02 19:58:48 +08:00
Netfan
78076e70b4 chore: update deps 2025-07-02 16:55:55 +08:00
chewenye
b78bc65ce7 feat: 组件json-viewer支持bigint数据显示 cwy (#6377)
Co-authored-by: 车文烨 <chewy@china-lehua.com>
2025-06-29 04:32:30 +08:00
Utopia
b1fb623113 feat: 为 auth layout 添加 slot: logo, 提升组件的灵活性和可复用性 (#6442) 2025-06-27 19:23:24 +08:00
Stephen Chang
de14908fd3 fix(icon-picker): 解决icon-picker组件切换分页后,关键词检索失效问题 (#6437)
当icon-picker组件切换分页后,在输入关键词检索,但是分页没有重置,导致检索结果异常
2025-06-27 19:21:23 +08:00
Li Kui
5c3972196a fix: Add $t import to login expired modal (#6429)
closes #6230
2025-06-27 19:20:25 +08:00
CG.gatspy
3230781538 feat: [vben-tree]增加数据disabled (#6343)
* feat: [vben-tree]增加数据disabled

* Update packages/@core/ui-kit/shadcn-ui/src/ui/tree/tree.vue

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-06-27 19:09:30 +08:00
broBinChen
e7fd0e3b6a feat(hooks): useHoverToggle的入参refElement支持传入响应式数组 (#6333)
* feat(hooks): useHoverToggle的入参refElement支持传入响应式数组

* feat(hooks): 1、增加 useHoverToggle 中 refElement 参数关于传入响应式数组的注释说明。 2、修改 watch 监听深度,仅需浅层监听 refs 变化。 3、使用 effectScope 管理 useElementHover 实例,避免 refs 变化时事件监听器累积导致的内存泄漏问题

* feat(hooks): 在useHoverToggle中增强 updateHovers  的边界处理,优化watch方案,只监听元素数量变化而不是整个数组变化,避免过度依赖收集

---------

Co-authored-by: xiaobin <xiaobin_chen@fzzixun.com>
2025-06-27 19:08:41 +08:00
yuhengshen
2f7d1f009d fix: 全屏状态下弹窗圆角优化 (#6413) 2025-06-24 23:41:54 +08:00
yuhengshen
946f91f387 feat: optimize modal dragging range(#6414)
* 当弹窗指定了容器时,拖拽将被限制在容器范围内
2025-06-24 17:05:59 +08:00
lghuahua
986eacae9a fix: improve request logic in api-component
* 修复某些情况下updateParam设置的参数可能不会提交给api的问题
* 修复在上一个请求尚未完成前如果params发生了变更,将不会再触发新的api请求
---------

Co-authored-by: Netfan <netfan@foxmail.com>
2025-06-20 08:42:45 +08:00
Netfan
97b8e28a2b docs: fix delete request usage (#6389) 2025-06-17 08:52:59 +08:00
Netfan
c0962fec18 fix: auto close popup on deactivated (#6368)
* 修复挂载到内容区域的弹窗和抽屉被意外关闭的问题
2025-06-11 12:20:52 +08:00
XiaoHetitu
8ba7bdf2bd fix(button): 为按钮添加type属性防止表单提交意外触发表单验证机制 (#6340)
在按钮组件中,按钮元素缺少type="button"属性可能导致在表单中意外提交。添加此属性以确保按钮行为符合预期。

Co-authored-by: yuanwj <ywj6792341@qq.com>
2025-06-08 17:56:24 +08:00
zyy
b015fbc9fc fix: [adapter] 表格配置类型报错 (#6327)
配置toolbarConfig中的search时会有类型报错
2025-06-08 17:53:55 +08:00
broBinChen
b69320c070 feat(hooks): support separate enter/leave delays in useHoverToggle (#6325)
Co-authored-by: xiaobin <xiaobin_chen@fzzixun.com>
2025-06-08 17:53:29 +08:00
zhang
dcccc213ce fix: requestClient.upload会将vbenform中value为undefined的值转为字符串undefined’提… (#6300)
* fix: requestClient.upload会将vbenform中value为undefined的值转为字符串undefined’提交给后台保存

* fix: requestClient.upload会将vbenform中value为undefined的值转为字符串'undefined’提交给后台保存
2025-06-08 17:51:16 +08:00
ali-pay
c0e601c020 fix: menu type is not 'button' (#6277)
Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2025-06-08 17:50:44 +08:00
RanMaoting
017ed1a9e1 types: 为useVbenVxeGrid添加泛型声明,使grid实例上能正确获取到行数据的类型 (#5653)
Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2025-06-08 17:43:02 +08:00
vben
b9aef618fe chore: release 5.5.7 2025-06-04 05:33:06 +08:00
Netfan
4102cc2211 feat: improve vbenCheckButtonGroup (#6329)
* 按钮组支持单选清除和多选限制最大选项数

* 按钮组支持icon插槽来定制图标
2025-06-03 23:11:56 +08:00
chewenye
ea776aa710 types: 扩展user-dropdown组件的menus类型,支持iconify (#6283)
Co-authored-by: 车文烨 <chewy@china-lehua.com>
2025-06-03 06:07:06 +08:00
huanghezhen
feb96dc8ea fix: resolve onClosed method failure in connectedComponent of useVbenModal (#6309) 2025-06-02 08:16:48 +08:00
wyc001122
470fd43b49 fix: 修复使用useVbenVxeGrid配置hasEmptyText、hasEmptyRender不生效的问题 (#6310) 2025-06-02 08:16:26 +08:00
zhang
76d106e474 fix: When defaultHomePage is inconsistent with user.homePath, the pa… (#6299)
* fix:  When defaultHomePage is inconsistent with user.homePath, the page refresh route jump will be abnormal

* fix:  When defaultHomePage is inconsistent with user.homePath, the page refresh route jump will be abnormal
2025-06-02 08:07:06 +08:00
wyc001122
78c3c9da6f docs(settings): 完善'生产环境动态配置'步骤 (#6297) 2025-06-02 08:05:23 +08:00
Netfan
081d08a7f8 fix: alert width fixed in small screen (#6312) 2025-05-30 19:54:26 +08:00
Netfan
96a10ca83f style: fix lint error (#6298) 2025-05-28 19:23:21 +08:00
wyc001122
f31360ba4e feat: support for hybrid permission access control mode (#6294)
* feat: 添加混合权限访问控制模式

* feat: 文档补充
2025-05-28 17:01:58 +08:00
wyc001122
4eb16d6d3a fix: fix table-title slot not work (#6295) 2025-05-28 17:01:11 +08:00
liqiang0330
53304514b6 fix: Update index.ts (#6268)
* Update index.ts

VxeGridPropTypes.原文件缺少这个,现在补全!

* Update index.ts

增加空格!
2025-05-26 13:29:27 +08:00
Netfan
6fbf1387f5 fix: reset slider-captcha after login failed (#6275) 2025-05-25 16:04:56 +08:00
Netfan
e5c937396d fix: json-bigint parse used in vxeTable (#6271)
* 修复vxeTable不能加载json-bigint解析的数据的问题
2025-05-24 13:01:58 +08:00
littlesparklet
af186f878d fix: repair the unexpected form default value (#5567)
* fix: Fix inconsistent spacing around search form (issue #5429)

* fix: repair the unexpected default value in validated form.(issue #5451)

* Update packages/@core/ui-kit/form-ui/src/use-form-context.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-05-23 16:05:11 +08:00
wyc001122
97894a940e feat: optimize logo display (#6267)
* feat(VbenAvatar): add fit property to VbenAvatar component

* feat(VbenLogo): add fit property to VbenLogo component

* feat(VbenLogo): add logo fit preference configuration

- Add preferences.logo.fit setting for logo display control
- Include corresponding documentation for the new preference

* feat(preferences): add default value for logo.fit preference

- Set default configuration for logo fit behavior
- Ensures consistent logo display across applications

* test(preferences): update configuration snapshots

---------

Co-authored-by: wyc001122 <wangyongchao@testor.com.cn>
2025-05-23 15:24:01 +08:00
yingzi2019
48d70182b4 feat: improve check updates (#6257)
Co-authored-by: monkey <maotao@tutamail.com>
2025-05-23 15:23:06 +08:00
Netfan
a1091bad46 feat: enhances compatibility with APIs returning large numeric values (#6250) 2025-05-23 15:22:18 +08:00
zhang
9f9be21e2a fix: component Input is not registered when initialize page (#6246)
* fix: Component Input is not registered when initialize page

* fix: Component Input is not registered when initialize page
2025-05-23 15:21:09 +08:00
panda7
a2bdcd6e49 feat: ellipsis text automatically displays tooltip based on ellipsis (#6244)
* feat: ellipsis text automatically displays tooltip based on ellipsis

* feat: ellipsis text automatically displays tooltip based on ellipsis

---------

Co-authored-by: sqchen <9110848@qq.com>
Co-authored-by: sqchen <chenshiqi@sshlx.com>
2025-05-23 15:20:38 +08:00
ali-pay
11b2b5bcc2 fix: 修复菜单管理中按钮类型值错误的问题 (#6255) 2025-05-22 09:09:31 +08:00
LinaBell
ebef2c91e2 fix: tab cannot be displayed correctly after browser refresh (#6256) 2025-05-22 09:04:40 +08:00
Netfan
0c3edb10b0 fix: getFieldComponentRef will return actual ref within AsyncComponentWrapper (#6252)
修复异步加载组件时,表单的getFieldComponentRef方法没能获取到正确的组件实例
2025-05-21 14:48:51 +08:00
zwtvip
f7bae8ac0f chore: export framework components for use in independent pages 2025-05-21 00:37:26 +08:00
wyc001122
8ac97688da fix(preferences): 更新内容内边距默认值 (#6233)
Co-authored-by: wyc001122 <wangyongchao@testor.com.cn>
2025-05-20 09:50:23 +08:00
李轻舟
2efacb3e5b docs: Update build.md (#6228) 2025-05-19 16:30:39 +08:00
wyc001122
dae46abb71 feat: additional-settings (#6225)
* feat(preferences): 补充VbenAdminLayout传入属性(来自偏好设置)

* docs(@vben/docs):update settings doc

---------

Co-authored-by: wyc001122 <wangyongchao@testor.com.cn>
2025-05-19 16:29:15 +08:00
wyc001122
5ee2a74e2d fix(use-design-tokens): 完善element-plus暗色主题颜色 (#6224)
Co-authored-by: wyc001122 <wangyongchao@testor.com.cn>
2025-05-19 16:27:34 +08:00
afe1
d0b8349a2d perf: stub unbuild params (#6210) 2025-05-18 10:35:20 +08:00
wyc001122
34c4ecb047 fix: in mixed layout mode, the sidebar does not display when the first child node is an external link (#6219)
Co-authored-by: wyc001122 <wangyongchao@testor.com.cn>
2025-05-18 10:34:41 +08:00
ming4762
3d9dba965f perf: perf the control logic of Tab (#6220)
* perf: perf the control logic of Tab

* 每个标签页Tab使用唯一的key来控制关闭打开等逻辑
* 统一函数获取tab的key
* 通过3种方式设置tab key:1、使用router query参数pageKey 2、使用路由meta参数fullPathKey设置使用fullPath或path作为key
* 单个路由可以打开多个标签页
* 如果设置fullPathKey为false,则query变更不会打开新的标签(这很实用)

* perf: perf the control logic of Tab

* perf: perf the control logic of Tab

* 测试用例适配

* perf: perf the control logic of Tab

* 解决AI提示的警告
2025-05-18 10:33:02 +08:00
wyc001122
024c01d350 fix(@vben-core/shadcn-ui): fix disabled functionality not working in VbenTree component (#6205)
* fix(@vben-core/shadcn-ui): fix disabled functionality not working in VbenTree component

* fix(@vben-core/shadcn-ui): add cursor-not-allowed className when disabled and disable onfocus

---------

Co-authored-by: wyc001122 <wangyongchao@testor.com.cn>
Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2025-05-16 14:13:43 +08:00
afe1
2adb8acd80 fix: css style (#6176) 2025-05-16 09:40:40 +08:00
panda7
a23bc4cb5c fix: the mobile terminal can wrap lines and expand slot attributes (#6165)
Co-authored-by: sqchen <chenshiqi@sshlx.com>
2025-05-16 09:40:05 +08:00
XiaoHetitu
cf17a45d8d feat(tabs): 支持计算属性作为标签标题,解决 #6170 的问题 (#6163)
* feat(tabs): 支持动态函数作为标签标题

修改 `setTabTitle` 和 `tabsView` 逻辑,允许传入函数作为标签标题,以便动态生成标题内容

* feat(tabbar): 添加动态设置标签页标题功能

允许设置静态字符串或动态函数作为标签标题,支持根据状态或语言变化动态更新标题

* refactor(tabs): 移除冗余的newTabTitle2变量并优化标题设置逻辑

移除tabs组件中冗余的newTabTitle2变量,直接使用newTabTitle作为标题来源。同时,优化use-tabs和tabbar模块的标题设置逻辑,支持ComputedRef作为动态标题,提升代码简洁性和可维护性。

---------

Co-authored-by: yuanwj <ywj6792341@qq.com>
2025-05-16 09:37:50 +08:00
chewenye
b46ebe756e types: 导出authentication组件的type,自定义toolbarList时类型使用ToolbarType (#6158)
Co-authored-by: 车文烨 <chewy@china-lehua.com>
2025-05-16 09:36:49 +08:00
Netfan
e89cf400c0 fix: refresh command of tabbar issue, fixed: #6162 (#6169) 2025-05-12 23:34:08 +08:00
anyup
9e67929ee7 feat: support to refresh the tab page by route name (#6153)
Co-authored-by: anyup <anyupxing@163.com>
2025-05-10 22:33:31 +08:00
afe1
90625782c0 fix: delete useless code (#6143) 2025-05-08 16:51:12 +08:00
wyc001122
84ef207d9c docs(@vben/docs): update settings doc (#6128)
Co-authored-by: wyc001122 <wangyongchao@testor.com.cn>
2025-05-07 12:04:48 +08:00
zyf0624
e68fff58e8 fix: tsconfig moduleResolution (#6122)
Co-authored-by: pzzyf <2279948211@qq.com>
2025-05-07 12:04:15 +08:00
Netfan
bf70539221 fix: missing argument for getPopupContainer 2025-05-06 22:48:03 +08:00
Leeson
5949c73a30 fix: delete Popconfirm being obscured by fixed columns (#6118)
* fix: delete Popconfirm being obscured by fixed columns

* fix: opened popConfirm will prevent the table from scrolling

---------

Co-authored-by: Netfan <netfan@foxmail.com>
2025-05-06 22:33:17 +08:00
vben
cc6c9bf7a0 chore: release v5.5.6 2025-05-06 22:32:58 +08:00
Jin Mao
6b1aab9c67 fix: handle undefined children in generate-menus (#6117)
When children is undefined, use empty array as fallback to prevent potential runtime errors. This matches the behavior when hideChildrenInMenu is true.
2025-05-06 14:29:50 +08:00
LinaBell
8f4d3d418d fix: when keepAlive is enabled, returning directly through browser buttons/gestures will not close pop ups (#6113) 2025-05-06 14:02:23 +08:00
ming4762
3b3f8e4e44 fix: fix IconPicker props warning (#6108)
Invalid prop: type check failed for prop "onUpdate:value". Expected Function, got Array
2025-05-06 09:30:37 +08:00
vben
f94ca10adf chore: remove prepare script from package.json 2025-05-04 07:33:36 +08:00
vben
4471bc7a5d chore: update prepare script in package.json to remove lefthook installation 2025-05-04 00:05:29 +08:00
Vben
5689ac60ff feat(project): migrate from husky and lint-staged to lefthook (#6104) 2025-05-03 19:43:12 +08:00
Vben
045bc4e5ee feat: support smooth auto-scroll to active menu item (#6102) 2025-05-03 18:05:26 +08:00
Vben
17a18fc9ba chore: close eslint object sorting (#6101) 2025-05-03 16:06:36 +08:00
aonoa
41152d1722 refactor: modify the default homepage path loaded from the preference… (#6099)
* refactor: modify the default homepage path loaded from the preferences.ts

Signed-off-by: aonoa <1991849113@qq.com>

* refactor: modify the default homepage path loaded from the preferences.ts

Signed-off-by: aonoa <1991849113@qq.com>

---------

Signed-off-by: aonoa <1991849113@qq.com>
2025-05-03 16:03:08 +08:00
Netfan
f1af9f8f6e fix: add triggerClass binding to PopoverTrigger and update icon-picker styles (#6095)
* Popover支持设置trigger的样式
* 修正icon-picker的input值更新
2025-05-01 21:40:45 +08:00
Netfan
0517a7014f fix: add missing translation for preferences drawer (#6094) 2025-05-01 20:08:44 +08:00
Netfan
3e6d608a2f fix: destroyOnClose incorrect default value, fixed #6092 (#6093) 2025-05-01 14:09:37 +08:00
ming4762
5de954baa4 fix: fix LoginExpiredModal in some cases, message may be obscured (#6086) 2025-05-01 10:40:42 +08:00
Netfan
add1e61b6f fix: show validation message as tooltip in compact form (#6087)
* 紧凑模式表单的校验消息将显示为一个tooltip
2025-04-30 23:41:44 +08:00
Jin Mao
20c15f352f perf: page componet supports custom height offset for flexible content height … (#6081)
* perf: Page supports custom height offset for flexible content height control.

允许通过 height 属性调整页面内容高度计算。修改了 Page 组件以支持自定义高度偏移量,用于更灵活的内容高度控制。

* chore: typo

* perf(page): replace height with heightOffset for flexible content sizing

The `height` prop was replaced with `heightOffset` to better describe its purpose when used with `autoContentHeight`. The new prop allows custom offset values (in pixels) to adjust content area sizing, with clearer documentation.
2025-04-29 18:15:12 +08:00
Netfan
8aa7dabeff fix: calculation for collapsing search form is incorrect while initially hidden (#6068)
* 修复当默认隐藏搜索表单时,折叠位置的计算不正确的问题
2025-04-28 23:20:33 +08:00
vben
78c7c1589a chore: update readme.md 2025-04-28 23:11:34 +08:00
Vben
dd833ca56b chore: update dependencies and documentation, optimize build toolchain (#6060)
* chore: update packageManager version to pnpm@10.9.0 for compatibility improvements

* chore: Update dependent versions and configurations to improve compatibility and stability

- Update Node version to 22.1.0
- Updated pnpm version to 10.10.0
- Fixed syntax error in prettier command in lintstagedrc
- Update dependent versions in pnpm-lock.yaml to ensure consistency
- Update format and content in README documents to improve readability

* fix: lint error
2025-04-28 23:08:05 +08:00
vem
681c1dc267 fix: Update existing route index to prevent 404 on user switch (#6003)
Co-authored-by: tars-macmini <vem@qq.com>
2025-04-28 18:19:47 +08:00
Netfan
4545422ee0 fix: lock state will not change overflow style in drawer and modal (#6067)
* Modal和Drawer的锁定状态不再修改overflow样式
2025-04-28 17:02:54 +08:00
Gahotx
ca94ca906f fix: add rounded corners to project and quick nav items (#5296) 2025-04-27 22:50:42 +08:00
Vben
76de450c71 chore: update dependency version for improved stability and compatibility (#6023)
* chore: update dependency version for improved stability and compatibility

* fix: optimize clearPoints function in useCaptchaPoints hook to improve performance

* fix: make several props optional in various components for better flexibility
2025-04-27 22:06:49 +08:00
Trivikram Kamat
dd2b1ed580 fix: install corepack from npm (#5905)
* fix: install corepack from npm

* docs: install corepack from npm
2025-04-27 22:03:35 +08:00
ming4762
baec89f896 perf: resolve duplicate component names (#6039) 2025-04-27 22:02:38 +08:00
vben
7c7051a11e chore: release v5.5.5 2025-04-27 21:45:10 +08:00
Netfan
aa27a2f7a1 feat: encrypt the privacy data when it is persisted (#6056)
* 对私密数据持久化时执行加密
* 将锁屏密码合并到accessStore中进行加密
2025-04-27 20:59:10 +08:00
Jin Mao
9ee6d06d50 docs: add deepWiki doc link (#6057) 2025-04-27 20:54:07 +08:00
ming4762
0cc1cb5a7b perf: improve destroyOnClose for VbenDrawer&VbenModal (#6051)
* fix: fix that the default value of modal destroyOnClose does not take effect

* perf: improve destroyOnClose for VbenDrawer
2025-04-27 11:26:50 +08:00
Netfan
0a9fc4e02d fix: title of search button in vxeTable toolbar (#6046)
* 修改vxeTable工具栏里的搜索按钮的提示文案
2025-04-26 01:08:41 +08:00
Netfan
be840460d8 feat: vbenSelect support prop allowClear (#6043) 2025-04-25 23:37:03 +08:00
Netfan
cb45987fe2 docs: update example (#6036)
* 跟进后端菜单逻辑的修改,现已无需传递basicLayout布局
2025-04-25 11:44:47 +08:00
panda7
5ffd7db8e0 fix: the initial value echo for the check-button-group (#6029)
Co-authored-by: sqchen <9110848@qq.com>
2025-04-25 08:35:03 +08:00
Netfan
14377705e7 fix: alert confirm state in beforeClose callback (#6019) 2025-04-23 12:20:52 +08:00
pangyajun123
b985ff0584 fix: vxe-table theme token follow primary color (#6007) 2025-04-21 19:15:05 +08:00
wyc001122
b148b8ec92 fix: fix geader menu activation path (#5997)
Co-authored-by: 王泳超 <wangyongchao@testor.com.cn>
2025-04-19 14:35:33 +08:00
Netfan
79de6bcbf7 fix: alert send wrong confirm state to beforeClose (#5991)
* 修复alert在按下Esc或者点击遮罩关闭时,可能发送错误的isConfirm状态
2025-04-17 22:23:05 +08:00
Netfan
14bd6dd25d fix: destroyOnClose works within connectedComponent (#5989)
* 修复destroyOnClose没能销毁connectedComponent自身的问题
2025-04-17 20:25:49 +08:00
PIPEDREA_WZJ
7f269e0d69 Update tailwindcss.md (#5602)
tailwindcss最新的版本已经是v4.x,vben中使用的是3.x的tailwindcss。在未进行兼容前,会出现运行失败的问题
2025-04-17 14:01:39 +08:00
yuh
4baec83db5 feat: add examples: form-upload (#5955)
* feat: add examples: form-upload

* fix: upload: accept and label

* fix: upload: 设置表单值、图片预览
2025-04-17 14:00:46 +08:00
Netfan
f7a4d13a4c fix: fixed arguments of callbacks in formApi (#5970)
* 修复 `handleValuesChange` 传递的参数不是处理后的表单值的问题

* 修复 `handleReset` 未能传递正确参数的问题
2025-04-16 14:11:04 +08:00
Netfan
0936861da1 feat: pass fieldsChanged into the handleValuesChange callback function (#5968)
* fieldsChanged(已被改变值的字段名)将传入handleValuesChange回调函数
2025-04-16 11:29:01 +08:00
ming4762
3318d76bab perf: improve destroyOnClose for VbenModal (#5964) 2025-04-16 11:28:36 +08:00
LinaBell
8f3881eabf perf: beforeClose of drawer support promise (#5932)
* perf: the beforeClose function of drawer is consistent with that of modal

* refactor: drawer test update
2025-04-16 11:27:13 +08:00
zhouda1fu
5252480b09 fix: missing await in department form(#5967) 2025-04-16 11:22:59 +08:00
Netfan
d18f56177c docs: update alert and apiComponent docs (#5961) 2025-04-15 20:52:23 +08:00
wyc001122
333998b518 fix: determine if scrollbar has been totally scrolled (#5934)
* 修复在系统屏幕缩放比例不为100%的情况下,滚动组件对是否已滚动到边界的判断可能不正确的问题
2025-04-15 20:51:38 +08:00
ming4762
3fb4fba1cb fix: modal closing animation (#5960) 2025-04-15 18:49:57 +08:00
ming4762
c7e6210c8d feat: modal&drawer support center-footer slot (#5956) 2025-04-15 16:04:44 +08:00
lztb
d864085c13 feat: vben-form添加arrayToStringFields属性 (#5957)
* feat: vben-form添加arrayToStringFields属性

* feat: 修改handleArrayToStringFields和handleStringToArrayFields中嵌套数组格式的处理不一致

---------

Co-authored-by: 米山 <17726957223@189.cn>
2025-04-15 16:03:20 +08:00
Netfan
fcdc1a1602 feat: add more expose methods for apiComponent (#5958)
* 为ApiComponent组件添加getOptions和getValue导出方法。
2025-04-15 15:32:30 +08:00
Netfan
bf7496f0d5 feat: add useAlertContext for Alert component (#5947)
* 新增Alert的子组件中获取弹窗上下文的能力
2025-04-15 00:00:05 +08:00
Netfan
9700150653 fix: table actions in fixed column (#5945) 2025-04-14 19:56:52 +08:00
Netfan
f0e9e55af2 feat: alert support customize footer (#5940)
* Alert组件支持自定义footer
2025-04-14 11:48:21 +08:00
Netfan
ff88274554 fix: long navigation menu can be scrolled (#5939)
* 修复超长的导航菜单无法纵向滚动的问题
2025-04-14 11:18:33 +08:00
ming4762
afce9dc5c0 perf: improve destroyOnClose for VbenModal (#5935)
* perf: 优化Vben Modal destroyOnClose,解决destroyOnClose=false,Modal依旧会被销毁的问题

影响范围(重要):destroyOnClose默认为true,这会导致所有的modal都会默认渲染到body
radix-vue Dialog组件默认会销毁挂载的组件,所以即使destroyOnClose=false,Modal依旧会被销毁的问题
对于一些大表单重复渲染导致卡顿,ApiComponent也会频繁的加载数据

* fix: modal closing animation

---------

Co-authored-by: Netfan <netfan@foxmail.com>
2025-04-13 23:02:07 +08:00
ming4762
b5700bd0b1 perf: improve autoSelect of ApiComponent (#5936)
* fix: 修复autoSelect不生效的问题,props.valueField已经被omit了

* feat: ApiComponent autoSelect支持使用函数,可以满足灵活性要求更高的场景
2025-04-13 20:03:18 +08:00
Netfan
a8c4786311 feat: api-component support autoSelect prop (#5931)
* feat: api-component support autoSelect prop

* docs: add version requirement
2025-04-12 14:02:35 +08:00
Netfan
2971ccc0b7 docs: docs modal z-index fixed, update alert docs (#5930) 2025-04-12 13:41:40 +08:00
Netfan
4a2c7b313f fix: alert animation (#5927) 2025-04-12 10:37:47 +08:00
Netfan
36bf6fc149 fix: builtin color change throttled in preference drawer (#5924)
修复偏好设置中的自定义主题色拖动选择颜色时页面会明显卡顿的问题
2025-04-12 01:44:08 +08:00
Netfan
f46ec30995 fix: theme mode follow the system only auto (#5923)
* 修复主题在未设置为auto时,仍然会跟随系统主题变化的问题。
2025-04-12 01:16:57 +08:00
Netfan
9bd5a190c2 fix: alert action button focus, fixed #5921 (#5922)
* 修复Alert组件的按钮焦点切换问题
2025-04-12 00:59:56 +08:00
zhang
86da3cedc2 chore: 导出框架自带的组件,方便独立页面使用 (#5876) 2025-04-09 16:16:56 +08:00
Netfan
329a176a5c perf: optimize bootstrap modules to speed up first-screen loading (#5899)
优化首屏加载速度
2025-04-09 01:05:20 +08:00
Netfan
9379093a4f feat: customizable table separator (#5898)
* 表格的分隔条支持定制背景色或完全移除
2025-04-08 20:28:50 +08:00
ming4762
c9014d0338 perf: 优化关闭页面切换动画的tab切换性能 (#5883) 2025-04-08 20:27:03 +08:00
Netfan
ed26dca64e chore: update pnpm-lock.yaml 2025-04-08 16:31:41 +08:00
Netfan
08c6496e24 chore: update deps 2025-04-08 14:56:40 +08:00
Netfan
a8c5df38e9 fix: possible circular reference issue during build (#5894)
* 修复构建期间出现的循环引用警告
2025-04-08 14:50:05 +08:00
Netfan
71e8d12b70 fix: improve prompt component (#5879)
* fix: prompt component render fixed

* fix: alert buttonAlign default value
2025-04-07 01:21:30 +08:00
Netfan
d216fdca44 feat: support logo text slot (#5872)
* 基础布局中的LOGO的文字区域允许通过插槽logo-text定制
2025-04-05 13:07:52 +08:00
wyc001122
384c5d7dbb fix: 布局为双列菜单或者水平模式下, 一级菜单高亮问题 (#5870)
Co-authored-by: 王泳超 <wangyongchao@testor.com.cn>
2025-04-05 11:04:59 +08:00
Netfan
b0ad08dbbc feat: use the not-found component instead of the invalid route component in the backend mode (#5871)
* 后端菜单模式下,使用not-found组件代替无效的路由组件
2025-04-04 15:21:09 +08:00
Rascal-Coder
3600603016 fix: vxeGrid height fixed #5861 (#5862) 2025-04-04 13:16:31 +08:00
superdl1996
cde1a85394 docs: typo (#5855) 2025-04-03 19:11:40 +08:00
Netfan
c623604ea9 docs: fix alert demo in docs 2025-04-02 20:37:41 +08:00
Netfan
7933da8f66 chore: update deps (#5854) 2025-04-02 18:07:06 +08:00
Netfan
ecf518bb02 fix: alert beforeClose callback arguments fixed (#5845) 2025-04-01 22:55:29 +08:00
ming4762
1d9f1be004 fix: 解决AccessModeType:backend登录过期,重新登录不会重新生成路由的问题,重现步骤分析: (#5830)
1、长时间未登录登录过期,再次打开页面构开始生成动态路由
2、fetchMenuListAsync后台返回401登录过期:doReAuthenticate函数跳转到登录页面
3、异常被拦截,return []
4、gurad.ts accessStore.setIsAccessChecked(true); 被错误的标识为已生成路由
5、重新登录后,accessStore.isAccessChecked=true未能正确的重新生成路由
2025-04-01 15:50:45 +08:00
Netfan
44138f578f feat: add preset alert, confirm, prompt components that can be simple called (#5843)
* feat: add preset alert, confirm, prompt components that can be simple called

* fix: type define
2025-04-01 15:10:18 +08:00
Joeshu
0e3abc2b53 docs: add third-party libraries to check update methods (#5819) 2025-03-31 19:28:28 +08:00
Arthur Darkstone
a96be3db98 docs: add explanation and related script configuration to distinguish build environment (#5826)
* docs: add explanation and related script configuration to distinguish build environment

* docs: fix spell error
2025-03-31 19:28:02 +08:00
Netfan
d6f239c564 docs: fix api-component demo link (#5828) 2025-03-31 12:08:45 +08:00
Netfan
166e9a0e82 chore: add demo for apiComponent with caching and concurrency (#5827)
* chore: add demo for apiComponent with caching and concurrency

* docs: update api component docs
2025-03-31 11:51:57 +08:00
Netfan
06ccad9db0 fix: vbenTree modelValue synchronization (#5825) 2025-03-31 10:18:35 +08:00
Jin Mao
18722ce434 feat: sidebar button config (#5818)
* feat: 新增 PreferenceCheckboxItem 组件

* feat(preferences): 添加侧边栏按钮配置功能

* feat: 新增按钮点击事件触发功能

* feat(SidebarPreferences): 新增侧边栏折叠按钮与固定按钮配置

* feat(ui): 新增侧边栏固定按钮及配置选项

* fix(test): 修正侧边栏配置项缺失问题
2025-03-31 10:17:42 +08:00
Netfan
a0feeb1966 fix: watermark settings in the preferences modified accidentally (#5823) 2025-03-31 09:06:02 +08:00
Jin Mao
df6341f0b8 feat(tabbar): 添加右键菜单过滤功能 (#5820) 2025-03-30 16:23:24 +08:00
anyup
dbc0b7e4a9 fix: route root.children duplicate problem (#5755)
Co-authored-by: anyup <anyupxing@163.com>
2025-03-29 22:38:30 +08:00
zhang
aa2907323f style: 更正引用格式 (#5784) 2025-03-29 22:29:16 +08:00
Netfan
96d2bc52e9 feat: pre-set serialization methods for request parameters (#5814)
添加快捷设置请求参数序列化方法的配置
2025-03-29 19:21:21 +08:00
Netfan
e91e4e0eea docs: fix form compact docs (#5811)
* docs: fix form `compact` docs

* docs: remove `compact` from FormCommonConfig
2025-03-28 16:15:35 +08:00
Netfan
c2b5f6497d fix: vben tree component warning (#5809) 2025-03-28 16:01:30 +08:00
Netfan
3c2d325d8c perf: improve api-component for using in form (#5796) 2025-03-27 15:51:11 +08:00
Netfan
a77bb8e68d perf: improve component packaging to enable instance method retrieval (#5795)
改进组件适配器里的包装函数,使得组件暴露的方法可以透传
2025-03-27 15:13:13 +08:00
Netfan
870cd86393 fix: auto check parent after node selected (#5794) 2025-03-27 14:22:05 +08:00
Netfan
0b650367f3 fix: popover background color in dark mode (#5783)
* 修复dark主题下的弹出层背景色在某些浏览器上表现为完全透明的问题
2025-03-25 21:17:55 +08:00
zhang
1616a06bfd perf: 优化多文件上传入参是数组的情况 (#5757)
Co-authored-by: Jin Mao <50581550+jinmao88@users.noreply.github.com>
2025-03-25 10:26:19 +08:00
Netfan
3f0d30897f fix: menu drawer can not be closed after a successful submitting (#5770) 2025-03-23 11:34:21 +08:00
Jin Mao
66c1d390b9 feat(ui): logo icon support click events (#5725)
* feat(ui): 扩展auth页面添加点击 Logo 的事件处理

在 `authentication.vue` 中新增 `clickLogo` 属性,允许在点击 Logo 时执行自定义操作。在 `auth.vue` 中实现了一个示例的点击事件处理函数,用于测试该功能。

* feat(layout): 添加点击 logo 的事件处理函数

在 BasicLayout 组件中添加了 clickLogo 事件处理函数,并通过 emit 方法触发 clickLogo 事件。同时,在 basic.vue 中实现了 handleClickLogo 函数,用于处理 logo 点击事件。

* fix(ui): 移除logo点击事件的控制台日志
2025-03-23 10:02:22 +08:00
Netfan
03ceb2aac5 fix: default value for nested fields (#5763) 2025-03-21 16:06:14 +08:00
Netfan
39888cebaa fix: base component focus color in form (#5760) 2025-03-21 09:41:42 +08:00
Netfan
efb69fc75f feat: add form-is-required class for required items. fixed: #5739 (#5759) 2025-03-21 09:25:38 +08:00
Jin Mao
711a179c69 chore: update codeowners (#5750) 2025-03-21 08:37:21 +08:00
Netfan
3133f8f8b9 fix: table form reset will trigger reload twice while submitOnChange set (#5756)
* 修复表格的搜索表单在重置时,可能会触发2次表格刷新的问题
2025-03-20 19:42:22 +08:00
anyup
f0a43912d1 fix: sort the menu so that it doesn't get replaced with 999 when order=0 (#5753)
Co-authored-by: anyup <anyupxing@163.com>
2025-03-20 19:41:46 +08:00
vben
b92ac5c36d chore: release 5.5.4 2025-03-18 21:43:27 +08:00
chen-d-yu
504070f3eb fix: vsh stylelint script fixed (#5729) 2025-03-17 09:23:27 +08:00
Netfan
feab6b3b30 fix: form item style adjustment (#5694) 2025-03-11 02:47:06 +08:00
Netfan
2d4ac33046 fix: miss default value in vbenLayout 2025-03-10 18:59:56 +08:00
Netfan
17e2a02281 feat: auto set component name for keep-alive (#5690)
* fix: auto set component name for keep-alive

* fix: type define
2025-03-10 16:25:30 +08:00
Netfan
096545c5a1 docs: update table slots docs 2025-03-10 10:53:17 +08:00
Netfan
04dff33ac5 feat: improved formApi for component instance support
* 改进表单API以支持组件实例的获取,以及焦点字段的获取
2025-03-10 02:56:44 +08:00
Netfan
cfa18c2b8e fix: improve component repackaging 2025-03-10 02:56:44 +08:00
Netfan
13354955db chore: update depts 2025-03-10 02:56:44 +08:00
ijackwu
bb683804f4 fix: live-server set port use [--port=PORT] (#5687) 2025-03-09 08:49:06 +08:00
Netfan
e2a577de24 feat: add size prop to avatar component and update logo component for size handling (#5684) 2025-03-08 11:37:02 +08:00
Netfan
89d963c81a fix: vxeTable search button not working with slot (#5678) 2025-03-07 22:35:09 +08:00
Netfan
b37ed48b9d feat: role management page with component tree (#5675)
* feat: add shadcn tree

* fix: update vbenTree component

* feat: role management demo page

* feat: add cellSwitch renderer for vxeTable

* chore: remove tree examples
2025-03-07 16:03:08 +08:00
Netfan
4b9cfcb867 fix: demo nested menu path (#5667)
* 修复演示的嵌套菜单path配置导致的面包屑跳转问题
2025-03-06 22:48:54 +08:00
Netfan
f86c9f90ad fix: keepAlive not working for popup appendToMain (#5666)
* 修复弹窗和抽屉 `appendToMain` 时且启用`keepAlive` 时未能正确缓存的问题
2025-03-06 22:22:45 +08:00
Netfan
31a6ab59fb feat: vben checkbox support indeterminate state and transition animation (#5662) 2025-03-06 16:11:02 +08:00
Netfan
34789645f7 fix: nitro server cookie maxAge fixed 2025-03-04 22:29:27 +08:00
Netfan
f380452ef0 feat: modal and drawer locking improve (#5648)
* feat: add `unlock` for modalApi

* fix: modal's close button style in locking

* fix: fix modal's close button disabled on locking

* feat: add `lock` and `unlock` for drawerApi
2025-03-04 22:00:32 +08:00
jasonz18
decd9c55e5 docs: typo 2025-03-04 21:40:34 +08:00
Netfan
e815f0ff89 docs: vbenVxeTable slots docs update 2025-03-01 22:16:36 +08:00
Netfan
5ea6b4a8d8 fix: logo style in login page is affected by the globally-imported antd styles
* 修复登录页左上角LOGO部分的文字在全局导入antd样式的时候位置不正确的问题
2025-02-28 22:39:42 +08:00
Netfan
a53ca3faf1 chore: update depts 2025-02-28 20:30:59 +08:00
Netfan
86fdd6c93b fix: drawer close icon placement default value 2025-02-28 14:54:11 +08:00
Netfan
0e0661fe02 fix: breadcrumb style is affected by the globally-imported antd styles (#5627)
* 修复全局引入Antd时,面包屑的样式会受到影响的问题
2025-02-27 22:28:59 +08:00
Netfan
86ce65e0ea fix: hideChildrenInMenu demo code (#5626) 2025-02-27 20:21:48 +08:00
Netfan
c3eb4fab13 docs: fix zod rules docs 2025-02-27 17:27:00 +08:00
jinmao88
7a476372e1 fix: useDrawer中closeIconPlacement设置无效 (#5624) 2025-02-27 14:34:42 +08:00
Netfan
5e421ce607 chore: demo page menu management (#5619)
* 添加菜单管理演示页面
2025-02-27 01:22:25 +08:00
Netfan
1d8676f456 chore: remove sleep in department list api 2025-02-25 22:15:27 +08:00
Netfan
0c3dd92592 fix: getPopupContainer will return closet form first (#5612) 2025-02-25 22:07:56 +08:00
Netfan
d33261d0c2 chore: demo page for system/department (#5611)
* feat: department management demo

* perf: department page improve

* feat: demo api middleware

* fix: add losing import
2025-02-25 19:47:45 +08:00
Netfan
7041c6a106 chore: output console error for invalid route component (#5593) 2025-02-24 16:03:52 +08:00
littlesparklet
12ffb310bf fix: Fix inconsistent spacing around search form (issue #5429) (#5495) 2025-02-24 15:57:50 +08:00
Netfan
d9799fec70 fix: search take no effect in icon-picker with antd (#5592) 2025-02-24 14:13:53 +08:00
Netfan
4570d5b54b feat: add VbenButtonGroup and VbenCheckButtonGroup with demo (#5591)
* 添加按钮组、选择按钮组以及相应的Demo
2025-02-24 13:50:50 +08:00
Netfan
d49e3e81a4 fix: loading and spinner style fixed and improved (#5588) 2025-02-23 15:30:17 +08:00
Netfan
579b1b486c feat: loading and spinner component with directive (#5587)
* 添加loading和spinner组件,以及对应的vue指令
2025-02-23 12:41:54 +08:00
Netfan
eba372062e feat: improve form demo (#5582) 2025-02-21 12:07:32 +08:00
Netfan
c9ccd2bbab fix: form label and control style (#5580)
* fix: form label and control style

* fix: empty label mark with required rules
2025-02-21 11:14:59 +08:00
handsomeFu
5aff8bac10 fix: CountTo component resolve separator prop not taking effect (#5578) 2025-02-21 11:06:18 +08:00
Netfan
1a12687027 fix: vben count to animator event name fixed (#5573) 2025-02-20 23:53:47 +08:00
Netfan
a221d2b491 fix: form item overflow fixed and layout improved (#5572)
* fix: form item overflow fixed and layout improved

* fix: basic form demo update

* feat: form label support render

* fix: form docs update
2025-02-20 23:05:08 +08:00
anyup
ccd99eb24d fix: solve the problem of inconsistent returns of formSchema custom field names when code login (#5563) 2025-02-20 09:09:32 +08:00
Netfan
c5c6760b5d chore: eslint rules update 2025-02-18 15:41:16 +08:00
Netfan
c07281bf41 fix: form item slot context fixed (#5552)
* 修复表单插槽
2025-02-17 21:37:05 +08:00
Netfan
24bad09c74 refactor: new CountTo component with demo (#5551) 2025-02-17 21:16:10 +08:00
Netfan
cddf71e600 fix: playground route missing 2025-02-17 17:57:15 +08:00
Netfan
9f82052c71 feat: demo of motion plugin (#5550)
添加Motion的用法例子
2025-02-17 15:25:45 +08:00
Netfan
e0eb57d38d fix: nitro server cors support with cookie (#5549)
* 修复nitro server在使用cookie时的跨域配置
2025-02-17 15:17:31 +08:00
Netfan
b6b97accb1 feat: add more event for jsonViewer (#5546)
* 为JsonViewer添加事件支持
2025-02-17 10:41:09 +08:00
Netfan
799934171a style: code style fixed 2025-02-16 23:32:06 +08:00
Netfan
10ebf03698 fix: auth api definition 2025-02-16 23:06:20 +08:00
Netfan
cd258fbb52 chore: update deps 2025-02-16 23:03:41 +08:00
Netfan
6cba181fad feat: new component jsonViewer (#5544)
* 添加新组件JsonViewer用于展示JSON结构数据
2025-02-16 22:57:00 +08:00
jinmao88
f9504cece3 chore: add qq group 5 (#5530) 2025-02-13 14:45:51 +08:00
Netfan
182f1c9da8 fix: userDropdown triggered unnecessary while overlay shown (#5520)
* 修复顶部的用户资料下拉在弹窗被打开时,仍然可以被触发的问题
2025-02-12 17:59:59 +08:00
Netfan
e7b009786b fix: width for ellipsisText tooltip in popover content (#5517)
* 修复省略文本用在气泡中时,提示弹出层的宽度计算有误的问题
2025-02-12 14:25:12 +08:00
Netfan
5262233312 feat: tabbar support max count limit (#5490)
* 标签栏支持限制打开的最大数量
2025-02-06 19:33:10 +08:00
Netfan
a9f9031f49 docs: update form docs (#5485) 2025-02-06 09:45:28 +08:00
Netfan
061fcf926d chore: update deps 2025-02-04 17:14:14 +08:00
Netfan
7e7a5f3fd4 chore: remove testing code 2025-02-04 15:07:10 +08:00
Netfan
f8bb396dc4 fix: ant tag icon default style (#5473) 2025-02-04 10:19:39 +08:00
jsxz
a832edce0d docs: update request and access docs (#5468)
* fix: Update server.md

* docs: update request and access docs
2025-02-03 16:29:34 +08:00
Netfan
67d1f299b3 fix: renderComponentContent lose slot props data (#5466)
* 修复FormItem传递插槽时丢失插槽props的问题
2025-01-26 22:33:16 +08:00
Netfan
cb7c0ecaa2 fix: menu data for backend mode fixed (#5465) 2025-01-26 20:37:37 +08:00
Netfan
e225159cce fix: request download and upload not support responseReturn (#5456)
* fix: request download and upload not support `responseReturn`

* docs: update

* fix: type of request client upload result
2025-01-22 00:59:10 +08:00
vben
195ceec9b4 chore: release 5.5.3 2025-01-21 22:07:55 +08:00
Netfan
5bd73867b6 feat: auto fetch icon list in iconPicker (#5446)
* feat: auto fetch icon list in iconPicker

* fix: add timeout controller for fetching

* feat: add pending controller

* fix: icon demo prefix
2025-01-21 13:09:42 +08:00
Netfan
22e6f28464 perf: easy to define fieldName of response data (#5442) 2025-01-20 18:38:49 +08:00
Netfan
5611f6c7f5 perf: request support to set how to return response (#5436)
* feat: request support to set how to return response

* docs: typo

* fix: test unit

* test: add request responseReturn test
2025-01-19 17:41:26 +08:00
Netfan
3f0f4d50a1 fix: antd button icon style (#5421) 2025-01-17 14:30:49 +08:00
Netfan
2d0859a727 fix: mouse events ignored on modal loading (#5409) 2025-01-16 12:17:08 +08:00
Netfan
509b268fba docs: update docs (#5408) 2025-01-16 11:30:03 +08:00
Netfan
c3129663eb fix: form update state error before form mounted (#5406) 2025-01-15 20:11:32 +08:00
Netfan
816d1f5a69 fix: demos route fixed (#5405) 2025-01-15 19:24:02 +08:00
Netfan
8cc903c0e1 feat: modal state locked on submitting (#5401)
* feat: modal state locked on submitting

* docs: 更新modal文档
2025-01-15 17:00:46 +08:00
Netfan
13087a10b7 refactor: fix popup component zIndex (#5397) 2025-01-15 12:32:03 +08:00
Netfan
27a3888e35 style: element plus loading style fixed (#5393)
* Element Plus的loading组件默认zIndex太高
2025-01-15 00:49:11 +08:00
Netfan
fb0ec05ff8 perf: improve fieldMappingTime to support format function (#5392) 2025-01-14 18:15:00 +08:00
Netfan
76c4aa2c55 fix: hide root route in breadcrumb 2025-01-14 17:51:39 +08:00
Netfan
e1c503e51e feat: support set default props for drawer and modal (#5390)
* feat: support set default props for drawer and modal

* docs: fix typo
2025-01-14 17:11:18 +08:00
Netfan
5965755caa fix: root router config fixed (#5389) 2025-01-14 15:15:02 +08:00
Netfan
1ad54561b0 feat: add noBasicLayout in route meta (#5386)
所有菜单数据无需配置component为BasicLayout,它们将会默认使用基础布局,也可以通过meta.noBasicLayout来阻止这一行为
2025-01-14 12:12:08 +08:00
Netfan
42e322012c fix: spinner may stop playing animation after dismiss (#5365)
* fix: spinner may stop playing animation after dismiss

* fix: animation paused more safely
2025-01-12 15:43:44 +08:00
Netfan
8cf6e8ec75 style: popover bgColor is too close to common (#5364)
修复Dark主题下,弹出层的背景色与主体背景色太过接近的问题
2025-01-12 14:48:05 +08:00
Netfan
79d4d2fb22 ci: retry deploy while faild 2025-01-12 11:58:07 +08:00
Netfan
b785bc5704 fix: useEcharts return invalid instance (#5360) 2025-01-12 09:54:37 +08:00
Netfan
6719e2679f feat: popup component support overlay blur effect (#5359) 2025-01-11 23:37:17 +08:00
Netfan
cb9c8db5ba feat: improve tippy demo (#5357) 2025-01-11 20:42:38 +08:00
Netfan
a2637313f8 feat: integrate new component Tippy with demo (#5355)
* 添加新的工具提示组件Tippy
2025-01-11 17:35:59 +08:00
Netfan
467689525f perf: add nested modal demo (#5353) 2025-01-11 12:12:50 +08:00
Netfan
1a04a05b79 perf: modal and drawer api support chain calls (#5351)
* perf: modal and drawer api support chain calls

* fix: typo
2025-01-11 10:56:54 +08:00
Netfan
b8bffd884c feat: allow close tab when mouse middle button click (#5347)
* 偏好设置增加鼠标中键关闭标签页的设置
2025-01-10 20:52:31 +08:00
Netfan
624beb6fa0 fix: locale switching logic correction (#5344)
* 修复语言切换后的数据更新逻辑

* 表单默认按钮的content属性可提供computed类型的值
2025-01-10 14:32:21 +08:00
Netfan
7606b86854 fix: vxeGrid init without search form (#5342)
* 修复vxeGrid在未使用表单的情况下,自动加载数据失效的问题。

* 暂时将vxeGrid版本锁定在4.10.0,新版本尺寸计算尚有问题
2025-01-10 11:53:06 +08:00
Netfan
e10cbe23b9 chore: update deps 2025-01-10 09:22:32 +08:00
Netfan
d34838bdd8 fix: primaryColor calculation (#5337) 2025-01-10 01:51:38 +08:00
Netfan
c979c23e6b fix: form valid-error style in naive (#5336) 2025-01-10 01:15:30 +08:00
Netfan
516d0b8dc8 fix: form fieldMappingTime improve and modelPropName support (#5335)
* 表单的fieldMappingTime支持将格式化掩码设为null以便原值映射,这样可以支持非日期时间类型的组件;
* 表单增加modelPropName设置组件的双向绑定属性名,用于支持未提前注册的双向绑定属性为非默认名称的组件。
* 增加一些经常会有人提到的组合字段演示,
2025-01-09 22:49:28 +08:00
Netfan
99c7fd72f8 fix: code lint 2025-01-09 13:04:14 +08:00
Netfan
2828e7a7b6 fix: form fieldMappingTime is not working (#5333)
* fix: form option `fieldMappingTime` is not working

* fix: form merge support `fieldMappingTime`
2025-01-09 12:28:33 +08:00
王文庭
16162c01ed fix: download from url triggered twice sometimes (#5319)
解决Chrome、Safari通过路径一次下载两个文件的BUG
2025-01-08 16:01:23 +08:00
clddup
bbbdbfa912 feat: useEcharts exports echarts instance#5294 (#5299) 2025-01-05 15:54:13 +08:00
John
06cccc53fa chore: update quick-start.md (#5303)
change COREPACK_REGISTRY to COREPACK_NPM_REGISTRY
2025-01-05 15:52:27 +08:00
Netfan
801c640724 fix: vben select placeholder color (#5286) 2025-01-02 10:19:20 +08:00
Vben
081d2aed23 perf: format code with better style (#5283) 2025-01-01 11:39:49 +08:00
Netfan
4d81b9d18d fix: sidebar preferences fixed (#5276) 2024-12-31 12:36:45 +08:00
Netfan
e9dc613548 fix: breadcrumb setting not valid for header-sidebar-nav layout (#5275) 2024-12-31 12:00:50 +08:00
Netfan
3af22f7e91 fix: header logo may not be collapsed in header-sidebar-nav layout (#5274) 2024-12-31 11:35:58 +08:00
Netfan
2135cb8ece feat: new layout sidebar nav with full header (#5270) 2024-12-31 00:30:15 +08:00
Netfan
376aad5d26 feat: drawer close icon placement (#5269) 2024-12-30 23:30:53 +08:00
Netfan
27ba45aa75 docs: update dialog and drawer docs 2024-12-30 22:21:01 +08:00
Netfan
de17007788 feat: drawer support destroy on close 2024-12-30 22:21:01 +08:00
Netfan
e86a7906fe feat: drawer support onOpened & onClosed 2024-12-30 22:21:01 +08:00
Netfan
4a8e6abc06 feat: modal support destroy on close 2024-12-30 22:21:01 +08:00
Netfan
2eb7fed9f4 fix: header-mixed layout side-menu active (#5265)
* fix: header-mixed layout side-menu active

* fix: config test
2024-12-30 15:24:01 +08:00
Netfan
ff8d5ca351 feat: header mixed layout (#5263)
* feat: new layout header-mixed

* fix: header-mixed layout update

* feat: layout preference update

* fix: extra menus follow layout setting
2024-12-30 14:01:17 +08:00
vben
07c4ad05f4 chore: release 5.5.2 2024-12-28 22:15:00 +08:00
Netfan
548c2e5500 chore: downgrade vue-tsc version 2024-12-28 17:53:39 +08:00
Netfan
ec2c6eff6f feat: header menu align support (#5256)
* feat: header menu align support

* fix: typo
2024-12-28 16:16:48 +08:00
Netfan
15fe82c62f chore: update deps 2024-12-28 16:15:39 +08:00
Netfan
cb5ecf4a8a chore: add apiSelect remote search demo (#5246) 2024-12-26 19:23:59 +08:00
1521 changed files with 86801 additions and 20952 deletions

View File

@@ -0,0 +1,3 @@
{
"singleQuote": true
}

View File

@@ -0,0 +1,7 @@
---
'@vben/styles': patch
'@vben-core/form-ui': patch
'@vben/web-naive': patch
---
feat(@core/form-ui): 新增 useVbenForm 数组编辑器 VbenFormFieldArray

16
.gitattributes vendored
View File

@@ -4,8 +4,18 @@
* text=auto eol=lf * text=auto eol=lf
# Declare files that will always have CRLF line endings on checkout. # Declare files that will always have CRLF line endings on checkout.
*.{cmd,[cC][mM][dD]} text eol=crlf *.cmd text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf *.[cC][mM][dD] text eol=crlf
*.bat text eol=crlf
*.[bB][aA][tT] text eol=crlf
# Denote all files that are truly binary and should not be modified. # Denote all files that are truly binary and should not be modified.
*.{ico,png,jpg,jpeg,gif,webp,svg,woff,woff2} binary *.ico binary
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.webp binary
*.svg binary
*.woff binary
*.woff2 binary

18
.github/CODEOWNERS vendored
View File

@@ -1,14 +1,14 @@
# default onwer # default onwer
* anncwb@126.com vince292007@gmail.com netfan@foxmail.com * anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
# vben core onwer # vben core onwer
/.github/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com /.github/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/.vscode/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com /.vscode/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/packages/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com /packages/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/packages/@core/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com /packages/@core/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/internal/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com /internal/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
/scripts/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com /scripts/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com jinmao88@qq.com
# vben team onwer # vben team onwer
apps/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com @vbenjs/team-v5 apps/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com @vbenjs/team-v5 jinmao88@qq.com
docs/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com @vbenjs/team-v5 docs/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com @vbenjs/team-v5 jinmao88@qq.com

View File

@@ -6,10 +6,10 @@ runs:
using: 'composite' using: 'composite'
steps: steps:
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v6
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v6
with: with:
node-version-file: .node-version node-version-file: .node-version
cache: 'pnpm' cache: 'pnpm'

3
.github/config.yml vendored
View File

@@ -21,12 +21,10 @@ newPRWelcomeComment: |
firstPRMergeComment: > firstPRMergeComment: >
Thanks for your contribution! 🎉🎉🎉 Thanks for your contribution! 🎉🎉🎉
# Comment to be posted to on first time issues # Comment to be posted to on first time issues
newIssueWelcomeComment: > newIssueWelcomeComment: >
Thanks for opening your first issue! Be sure to follow the issue template and provide every bit of information to help the developers! Thanks for opening your first issue! Be sure to follow the issue template and provide every bit of information to help the developers!
# *OPTIONAL* default titles to check against for lack of descriptiveness # *OPTIONAL* default titles to check against for lack of descriptiveness
# MUST BE ALL LOWERCASE # MUST BE ALL LOWERCASE
requestInfoDefaultTitles: requestInfoDefaultTitles:
@@ -36,4 +34,3 @@ requestInfoDefaultTitles:
# *Required* Comment to reply with # *Required* Comment to reply with
requestInfoReplyComment: > requestInfoReplyComment: >
Thanks for filing this issue/PR! It would be much appreciated if you could provide us with more information so we can effectively analyze the situation in context. Thanks for filing this issue/PR! It would be much appreciated if you could provide us with more information so we can effectively analyze the situation in context.

View File

@@ -19,11 +19,9 @@ Project maintainers have the right and responsibility to remove, edit, or reject
- Checkout a topic branch from the relevant branch, e.g. main, and merge back against that branch. - Checkout a topic branch from the relevant branch, e.g. main, and merge back against that branch.
- If adding a new feature: - If adding a new feature:
- Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it. - Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
- If fixing bug: - If fixing bug:
- Provide a detailed description of the bug in the PR. Live demo preferred. - Provide a detailed description of the bug in the PR. Live demo preferred.
- It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging. - It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging.

View File

@@ -30,7 +30,7 @@ jobs:
- windows-latest - windows-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -25,7 +25,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -28,12 +28,12 @@ jobs:
timeout-minutes: 20 timeout-minutes: 20
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v6
with: with:
run_install: false run_install: false
@@ -67,7 +67,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -90,7 +90,7 @@ jobs:
- windows-latest - windows-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -57,11 +57,11 @@ jobs:
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v7
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v4
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }} build-mode: ${{ matrix.build-mode }}
@@ -89,6 +89,6 @@ jobs:
exit 1 exit 1
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3 uses: github/codeql-action/analyze@v4
with: with:
category: '/language:${{matrix.language}}' category: '/language:${{matrix.language}}'

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -30,7 +30,7 @@ jobs:
run: pnpm build:play run: pnpm build:play
- name: Sync Playground files - name: Sync Playground files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5 uses: SamKirkland/FTP-Deploy-Action@v4.4.0
with: with:
server: ${{ secrets.PRO_FTP_HOST }} server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEB_PLAYGROUND_FTP_ACCOUNT }} username: ${{ secrets.WEB_PLAYGROUND_FTP_ACCOUNT }}
@@ -43,7 +43,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -54,7 +54,7 @@ jobs:
run: pnpm build:docs run: pnpm build:docs
- name: Sync Docs files - name: Sync Docs files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5 uses: SamKirkland/FTP-Deploy-Action@v4.4.0
with: with:
server: ${{ secrets.PRO_FTP_HOST }} server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEBSITE_FTP_ACCOUNT }} username: ${{ secrets.WEBSITE_FTP_ACCOUNT }}
@@ -67,7 +67,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -85,7 +85,7 @@ jobs:
run: pnpm run build:antd run: pnpm run build:antd
- name: Sync files - name: Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5 uses: SamKirkland/FTP-Deploy-Action@v4.4.0
with: with:
server: ${{ secrets.PRO_FTP_HOST }} server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEB_ANTD_FTP_ACCOUNT }} username: ${{ secrets.WEB_ANTD_FTP_ACCOUNT }}
@@ -98,7 +98,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -116,7 +116,7 @@ jobs:
run: pnpm run build:ele run: pnpm run build:ele
- name: Sync files - name: Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5 uses: SamKirkland/FTP-Deploy-Action@v4.4.0
with: with:
server: ${{ secrets.PRO_FTP_HOST }} server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEB_ELE_FTP_ACCOUNT }} username: ${{ secrets.WEB_ELE_FTP_ACCOUNT }}
@@ -129,7 +129,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -147,9 +147,26 @@ jobs:
run: pnpm run build:naive run: pnpm run build:naive
- name: Sync files - name: Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5 uses: SamKirkland/FTP-Deploy-Action@v4.4.0
with: with:
server: ${{ secrets.PRO_FTP_HOST }} server: ${{ secrets.PRO_FTP_HOST }}
username: ${{ secrets.WEB_NAIVE_FTP_ACCOUNT }} username: ${{ secrets.WEB_NAIVE_FTP_ACCOUNT }}
password: ${{ secrets.WEB_NAIVE_FTP_PASSWORD }} password: ${{ secrets.WEB_NAIVE_FTP_PASSWORD }}
local-dir: ./apps/web-naive/dist/ local-dir: ./apps/web-naive/dist/
rerun-on-failure:
name: Rerun on failure
needs:
- deploy-playground-ftp
- deploy-docs-ftp
- deploy-antd-ftp
- deploy-ele-ftp
- deploy-naive-ftp
if: failure() && fromJSON(github.run_attempt) < 10
runs-on: ubuntu-latest
steps:
- name: Retry ${{ fromJSON(github.run_attempt) }} of 10
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: gh workflow run rerun.yml -F run_id=${{ github.run_id }}

View File

@@ -20,6 +20,6 @@ jobs:
if: github.repository == 'vbenjs/vue-vben-admin' if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: release-drafter/release-drafter@v6 - uses: release-drafter/release-drafter@v7
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -19,7 +19,7 @@ jobs:
steps: steps:
# 关闭未活动的 Issues # 关闭未活动的 Issues
- name: Close Inactive Issues - name: Close Inactive Issues
uses: actions/stale@v9 uses: actions/stale@v11
with: with:
days-before-stale: -1 # Issues and PR will never be flagged stale automatically. days-before-stale: -1 # Issues and PR will never be flagged stale automatically.
stale-issue-label: needs-reproduction # Label that flags an issue as stale. stale-issue-label: needs-reproduction # Label that flags an issue as stale.

View File

@@ -18,7 +18,7 @@ jobs:
steps: steps:
- name: remove enhancement pending - name: remove enhancement pending
if: github.event.label.name == 'enhancement' if: github.event.label.name == 'enhancement'
uses: actions-cool/issues-helper@v3 uses: actions-cool/issues-helper-backup@d65454423c6fbbd20026b9b499d403f79422ac69
with: with:
actions: 'remove-labels' actions: 'remove-labels'
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
@@ -27,7 +27,7 @@ jobs:
- name: remove bug pending - name: remove bug pending
if: github.event.label.name == 'bug' if: github.event.label.name == 'bug'
uses: actions-cool/issues-helper@v3 uses: actions-cool/issues-helper-backup@d65454423c6fbbd20026b9b499d403f79422ac69
with: with:
actions: 'remove-labels' actions: 'remove-labels'
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
@@ -36,7 +36,7 @@ jobs:
- name: needs reproduction - name: needs reproduction
if: github.event.label.name == 'needs reproduction' if: github.event.label.name == 'needs reproduction'
uses: actions-cool/issues-helper@v3 uses: actions-cool/issues-helper-backup@d65454423c6fbbd20026b9b499d403f79422ac69
with: with:
actions: 'create-comment, remove-labels' actions: 'create-comment, remove-labels'
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -14,7 +14,7 @@ jobs:
if: github.repository == 'vbenjs/vue-vben-admin' if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: dessant/lock-threads@v5 - uses: dessant/lock-threads@v6
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
issue-inactive-days: '14' issue-inactive-days: '14'

View File

@@ -3,78 +3,48 @@ name: Create Release Tag
on: on:
push: push:
tags: tags:
- 'v*.*.*' # Push events to matching v*, i.e. v1.0, v20.15.10 - 'v*.*.*'
workflow_dispatch:
env: inputs:
HUSKY: '0' tag:
description: 'Tag to create (e.g. v1.2.3)'
required: true
type: string
permissions: permissions:
pull-requests: write
contents: write contents: write
jobs: jobs:
build: release:
name: Create Release name: Create Release
if: github.repository == 'vbenjs/vue-vben-admin' if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20]
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
# - name: Checkout code - name: Extract version
# uses: actions/checkout@v4
# with:
# fetch-depth: 0
# - name: Install pnpm
# uses: pnpm/action-setup@v4
# - name: Use Node.js ${{ matrix.node-version }}
# uses: actions/setup-node@v4
# with:
# node-version: ${{ matrix.node-version }}
# cache: "pnpm"
# - name: Install dependencies
# run: pnpm install --frozen-lockfile
# - name: Test and Build
# run: |
# pnpm run test
# pnpm run build
- name: version
id: version id: version
run: | run: |
tag=${GITHUB_REF/refs\/tags\//} if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
version=${tag#v} raw_tag="${{ inputs.tag }}"
major=${version%%.*} else
echo "tag=${tag}" >> $GITHUB_OUTPUT raw_tag="${GITHUB_REF_NAME}"
echo "version=${version}" >> $GITHUB_OUTPUT fi
echo "major=${major}" >> $GITHUB_OUTPUT # Normalize: ensure v prefix
tag="${raw_tag}"
[[ "${tag:0:1}" != "v" ]] && tag="v${tag}"
version="${tag#v}"
major="${version%%.*}"
echo "tag=${tag}" >> "${GITHUB_OUTPUT}"
echo "version=${version}" >> "${GITHUB_OUTPUT}"
echo "major=${major}" >> "${GITHUB_OUTPUT}"
- uses: release-drafter/release-drafter@v6 - uses: release-drafter/release-drafter@v7
with: with:
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
publish: true publish: true
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# - name: force update major tag
# run: |
# git tag v${{ steps.version.outputs.major }} ${{ steps.version.outputs.tag }} -f
# git push origin refs/tags/v${{ steps.version.outputs.major }} -f
# - name: Create Release for Tag
# id: release_tag
# uses: ncipollo/release-action@v1
# with:
# token: ${{ secrets.GITHUB_TOKEN }}
# generateReleaseNotes: "true"
# body: |
# > Please refer to [CHANGELOG.md](https://github.com/vbenjs/vue-vben-admin/blob/main/CHANGELOG.md) for details.

19
.github/workflows/rerun.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Rerun workflow
on:
workflow_dispatch:
inputs:
run_id:
description: The workflow id to relanch
required: true
jobs:
rerun:
runs-on: ubuntu-latest
steps:
- name: rerun ${{ inputs.run_id }}
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: |
gh run watch ${{ inputs.run_id }} > /dev/null 2>&1
gh run rerun ${{ inputs.run_id }} --failed

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Validate PR title - name: Validate PR title
uses: amannn/action-semantic-pull-request@v5 uses: amannn/action-semantic-pull-request@v6
with: with:
wip: true wip: true
subjectPattern: ^(?![A-Z]).+$ subjectPattern: ^(?![A-Z]).+$

View File

@@ -9,7 +9,7 @@ jobs:
if: github.repository == 'vbenjs/vue-vben-admin' if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v11
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days' stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'

14
.gitignore vendored
View File

@@ -22,7 +22,8 @@ yarn.lock
package-lock.json package-lock.json
.VSCodeCounter .VSCodeCounter
**/backend-mock/data **/backend-mock/data
.omx
.pnpm-store
# local env files # local env files
.env.local .env.local
.env.*.local .env.*.local
@@ -51,3 +52,14 @@ vite.config.ts.*
.history .history
/.mimocode/ /.mimocode/
/.cursor/skills/ /.cursor/skills/
.cursor
# AI
.agent
.agents
.claude
.codex
skills-lock.json
.atomcode
datalog
.playwright-mcp

View File

@@ -2,5 +2,5 @@ ports:
- port: 5555 - port: 5555
onOpen: open-preview onOpen: open-preview
tasks: tasks:
- init: corepack enable && pnpm install - init: npm i -g corepack && pnpm install
command: pnpm run dev:play command: pnpm run dev:play

View File

@@ -1,6 +0,0 @@
echo Start running commit-msg hook...
# Check whether the git commit information is standardized
pnpm exec commitlint --edit "$1"
echo Run commit-msg hook done.

View File

@@ -1,3 +0,0 @@
# 每次 git pull 之后, 安装依赖
pnpm install

View File

@@ -1,20 +0,0 @@
export default {
'*.{js,jsx,ts,tsx}': [
'prettier --cache --ignore-unknown --write',
'eslint --cache --fix',
],
'*.{scss,less,styl,html,vue,css}': [
'prettier --cache --ignore-unknown --write',
'stylelint --fix --allow-empty-input',
],
'*.md': ['prettier --cache --ignore-unknown --write'],
'*.vue': [
'prettier --write',
'eslint --cache --fix',
'stylelint --fix --allow-empty-input',
],
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [
'prettier --cache --write--parser json',
],
'package.json': ['prettier --cache --write'],
};

View File

@@ -1 +1 @@
20.14.0 24.16.0

14
.npmrc
View File

@@ -1,13 +1 @@
registry = "https://registry.npmmirror.com" registry=https://registry.npmmirror.com
public-hoist-pattern[]=husky
public-hoist-pattern[]=eslint
public-hoist-pattern[]=prettier
public-hoist-pattern[]=prettier-plugin-tailwindcss
public-hoist-pattern[]=stylelint
public-hoist-pattern[]=*postcss*
public-hoist-pattern[]=@commitlint/*
public-hoist-pattern[]=czg
strict-peer-dependencies=false
auto-install-peers=true
dedupe-peer-dependents=true

View File

@@ -1,18 +0,0 @@
dist
dev-dist
.local
.output.js
node_modules
.nvmrc
coverage
CODEOWNERS
.nitro
.output
**/*.svg
**/*.sh
public
.npmrc
*-lock.yaml

View File

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

View File

@@ -2,3 +2,7 @@ dist
public public
__tests__ __tests__
coverage coverage
.codex
.claude
.agent
.agents

View File

@@ -0,0 +1,32 @@
import { eventHandler, setHeader } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse } from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const data = `
{
"code": 0,
"message": "success",
"data": [
{
"id": 123456789012345678901234567890123456789012345678901234567890,
"name": "John Doe",
"age": 30,
"email": "john-doe@demo.com"
},
{
"id": 987654321098765432109876543210987654321098765432109876543210,
"name": "Jane Smith",
"age": 25,
"email": "jane@demo.com"
}
]
}
`;
setHeader(event, 'Content-Type', 'application/json');
return data;
});

View File

@@ -0,0 +1,16 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
useResponseSuccess,
} from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(600);
return useResponseSuccess(null);
});

View File

@@ -0,0 +1,16 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
useResponseSuccess,
} from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(1000);
return useResponseSuccess(null);
});

View File

@@ -0,0 +1,16 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
useResponseSuccess,
} from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(2000);
return useResponseSuccess(null);
});

View File

@@ -0,0 +1,62 @@
import { faker } from '@faker-js/faker';
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
const formatterCN = new Intl.DateTimeFormat('zh-CN', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
function generateMockDataList(count: number) {
const dataList = [];
for (let i = 0; i < count; i++) {
const dataItem: Record<string, any> = {
id: faker.string.uuid(),
pid: 0,
name: faker.commerce.department(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2021-01-01', to: '2022-12-31' }),
),
remark: faker.lorem.sentence(),
};
if (faker.datatype.boolean()) {
dataItem.children = Array.from(
{ length: faker.number.int({ min: 1, max: 5 }) },
() => ({
id: faker.string.uuid(),
pid: dataItem.id,
name: faker.commerce.department(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2023-01-01', to: '2023-12-31' }),
),
remark: faker.lorem.sentence(),
}),
);
}
dataList.push(dataItem);
}
return dataList;
}
const mockData = generateMockDataList(10);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const listData = structuredClone(mockData);
return useResponseSuccess(listData);
});

View File

@@ -0,0 +1,13 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess(MOCK_MENU_LIST);
});

View File

@@ -0,0 +1,29 @@
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
const namesMap: Record<string, any> = {};
function getNames(menus: any[]) {
menus.forEach((menu) => {
namesMap[menu.name] = String(menu.id);
if (menu.children) {
getNames(menu.children);
}
});
}
getNames(MOCK_MENU_LIST);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const { id, name } = getQuery(event);
return (name as string) in namesMap &&
(!id || namesMap[name as string] !== String(id))
? useResponseSuccess(true)
: useResponseSuccess(false);
});

View File

@@ -0,0 +1,29 @@
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
const pathMap: Record<string, any> = { '/': 0 };
function getPaths(menus: any[]) {
menus.forEach((menu) => {
pathMap[menu.path] = String(menu.id);
if (menu.children) {
getPaths(menu.children);
}
});
}
getPaths(MOCK_MENU_LIST);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const { id, path } = getQuery(event);
return (path as string) in pathMap &&
(!id || pathMap[path as string] !== String(id))
? useResponseSuccess(true)
: useResponseSuccess(false);
});

View File

@@ -0,0 +1,84 @@
import { faker } from '@faker-js/faker';
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { getMenuIds, MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
const formatterCN = new Intl.DateTimeFormat('zh-CN', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
const menuIds = getMenuIds(MOCK_MENU_LIST);
function generateMockDataList(count: number) {
const dataList = [];
for (let i = 0; i < count; i++) {
const dataItem: Record<string, any> = {
id: faker.string.uuid(),
name: faker.commerce.product(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2022-01-01', to: '2025-01-01' }),
),
permissions: faker.helpers.arrayElements(menuIds),
remark: faker.lorem.sentence(),
};
dataList.push(dataItem);
}
return dataList;
}
const mockData = generateMockDataList(100);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const {
page = 1,
pageSize = 20,
name,
id,
remark,
startTime,
endTime,
status,
} = getQuery(event);
let listData = structuredClone(mockData);
if (name) {
listData = listData.filter((item) =>
item.name.toLowerCase().includes(String(name).toLowerCase()),
);
}
if (id) {
listData = listData.filter((item) =>
item.id.toLowerCase().includes(String(id).toLowerCase()),
);
}
if (remark) {
listData = listData.filter((item) =>
item.remark?.toLowerCase()?.includes(String(remark).toLowerCase()),
);
}
if (startTime) {
listData = listData.filter((item) => item.createTime >= startTime);
}
if (endTime) {
listData = listData.filter((item) => item.createTime <= endTime);
}
if (['0', '1'].includes(status as string)) {
listData = listData.filter((item) => item.status === Number(status));
}
return usePageResponseSuccess(page as string, pageSize as string, listData);
});

View File

@@ -0,0 +1,85 @@
import { faker } from '@faker-js/faker';
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
const formatterCN = new Intl.DateTimeFormat('zh-CN', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
function generateMockDataList(count: number) {
const dataList = [];
for (let i = 0; i < count; i++) {
const dataItem: Record<string, any> = {
id: faker.string.uuid(),
name: faker.commerce.product(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2022-01-01', to: '2025-01-01' }),
),
deptId: faker.string.uuid(),
remark: faker.lorem.sentence(),
};
dataList.push(dataItem);
}
return dataList;
}
const mockData = generateMockDataList(100);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const {
page = 1,
pageSize = 20,
name,
id,
remark,
startTime,
endTime,
deptId,
status,
} = getQuery(event);
let listData = structuredClone(mockData);
if (name) {
listData = listData.filter((item) =>
item.name.toLowerCase().includes(String(name).toLowerCase()),
);
}
if (id) {
listData = listData.filter((item) =>
item.id.toLowerCase().includes(String(id).toLowerCase()),
);
}
if (remark) {
listData = listData.filter((item) =>
item.remark?.toLowerCase()?.includes(String(remark).toLowerCase()),
);
}
if (startTime) {
listData = listData.filter((item) => item.createTime >= startTime);
}
if (endTime) {
listData = listData.filter((item) => item.createTime <= endTime);
}
if (['0', '1'].includes(status as string)) {
listData = listData.filter((item) => item.status === Number(status));
}
if (deptId) {
listData = listData.filter((item) => item.deptId === deptId);
}
return usePageResponseSuccess(page as string, pageSize as string, listData);
});

View File

@@ -0,0 +1,12 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
import { getTimezone } from '~/utils/timezone-utils';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess(getTimezone());
});

View File

@@ -0,0 +1,11 @@
import { eventHandler } from 'h3';
import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
import { useResponseSuccess } from '~/utils/response';
export default eventHandler(() => {
const data = TIME_ZONE_OPTIONS.map((o) => ({
label: `${o.timezone} (GMT${o.offset >= 0 ? `+${o.offset}` : o.offset})`,
value: o.timezone,
}));
return useResponseSuccess(data);
});

View File

@@ -0,0 +1,26 @@
import { eventHandler, readBody, setResponseStatus } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
import {
unAuthorizedResponse,
useResponseError,
useResponseSuccess,
} from '~/utils/response';
import { setTimezone } from '~/utils/timezone-utils';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const body = await readBody<{ timezone?: unknown }>(event);
const timezone =
typeof body?.timezone === 'string' ? body.timezone : undefined;
const allowed = TIME_ZONE_OPTIONS.some((o) => o.timezone === timezone);
if (!timezone || !allowed) {
setResponseStatus(event, 400);
return useResponseError('Bad Request', 'Invalid timezone');
}
setTimezone(timezone);
return useResponseSuccess({});
});

View File

@@ -0,0 +1,14 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess({
url: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
});
// return useResponseError("test")
});

View File

@@ -0,0 +1,9 @@
let mockTimeZone: null | string = null;
export const setTimezone = (timeZone: string) => {
mockTimeZone = timeZone;
};
export const getTimezone = () => {
return mockTimeZone;
};

View File

@@ -12,7 +12,7 @@
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/> />
<!-- 由 vite 注入 VITE_APP_TITLE 变量,在 .env 文件内配置 --> <!-- 由 vite 注入 VITE_APP_TITLE 变量,在 .env 文件内配置 -->
<title><%= VITE_APP_TITLE %></title> <title>%VITE_APP_TITLE%</title>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<script> <script>
// 生产环境下注入百度统计 // 生产环境下注入百度统计

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vben/web-antd", "name": "@vben/web-antd",
"version": "5.5.1", "version": "5.7.0",
"homepage": "https://vben.pro", "homepage": "https://vben.pro",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues", "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": { "repository": {
@@ -27,6 +27,7 @@
}, },
"dependencies": { "dependencies": {
"@ant-design/icons-vue": "^7.0.1", "@ant-design/icons-vue": "^7.0.1",
"@fortawesome/fontawesome-free": "^6.7.2",
"@vben/access": "workspace:*", "@vben/access": "workspace:*",
"@vben/common-ui": "workspace:*", "@vben/common-ui": "workspace:*",
"@vben/constants": "workspace:*", "@vben/constants": "workspace:*",
@@ -41,15 +42,23 @@
"@vben/styles": "workspace:*", "@vben/styles": "workspace:*",
"@vben/types": "workspace:*", "@vben/types": "workspace:*",
"@vben/utils": "workspace:*", "@vben/utils": "workspace:*",
"@vueup/vue-quill": "^1.2.0",
"@vueuse/core": "catalog:", "@vueuse/core": "catalog:",
"ant-design-vue": "catalog:", "ant-design-vue": "catalog:",
"axios": "^1.10.0",
"dayjs": "catalog:", "dayjs": "catalog:",
"exceljs": "^4.4.0", "exceljs": "^4.4.0",
"html2canvas": "^1.4.1",
"js-base64": "^3.7.7",
"lodash-es": "^4.17.21",
"lucide-vue-next": "^0.487.0",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"md-editor-v3": "^5.4.5",
"pinia": "catalog:", "pinia": "catalog:",
"sortablejs": "catalog:", "sortablejs": "catalog:",
"vue": "catalog:", "vue": "catalog:",
"vue-router": "catalog:", "vue-router": "catalog:",
"xgplayer": "^3.0.24",
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {

View File

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

View File

@@ -3,55 +3,616 @@
* 可用于 vben-form、vben-modal、vben-drawer 等组件使用, * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
*/ */
import type { BaseFormComponentType } from '@vben/common-ui'; /* eslint-disable vue/one-component-per-file */
import type { Component, SetupContext } from 'vue'; import type {
import { h } from 'vue'; AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadChangeParam,
UploadFile,
UploadProps,
} from 'ant-design-vue';
import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; import type { Component, Ref } from 'vue';
import { $t } from '@vben/locales';
import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Sortable } from '@vben/hooks';
import type { Recordable } from '@vben/types';
import { import {
AutoComplete, computed,
Button, defineAsyncComponent,
Cascader, defineComponent,
Checkbox, h,
CheckboxGroup, nextTick,
DatePicker, onMounted,
Divider, onUnmounted,
Input, ref,
InputNumber, render,
InputPassword, unref,
Mentions, watch,
notification, } from 'vue';
Radio,
RadioGroup, import {
RangePicker, ApiComponent,
Rate, globalShareState,
Select, IconPicker,
Space, VCropper,
Switch, } from '@vben/common-ui';
Textarea, import { useSortable } from '@vben/hooks';
TimePicker, import { IconifyIcon } from '@vben/icons';
TreeSelect, import { $t } from '@vben/locales';
Upload, import { isEmpty } from '@vben/utils';
} from 'ant-design-vue';
import { message, Modal, notification } from 'ant-design-vue';
import { registerComponent } from '#/components/form/component-map'; import { registerComponent } from '#/components/form/component-map';
const withDefaultPlaceholder = <T extends Component>( type AdapterUploadProps = UploadProps & {
component: T, aspectRatio?: string;
type: 'input' | 'select', crop?: boolean;
) => { draggable?: boolean;
return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => { handleChange?: (event: UploadChangeParam) => void;
const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`); maxSize?: number;
return h(component, { ...props, ...attrs, placeholder }, slots); onDragSort?: (oldIndex: number, newIndex: number) => void;
onHandleChange?: (event: UploadChangeParam) => void;
}; };
// ============================================================
// 所有 antd 组件统一用 defineAsyncComponent 异步加载
// ⚠️ 不要再从 'ant-design-vue' 同步 import 这些组件!
// 否则会和下面的 const 声明冲突,导致
// "Identifier 'Xxx' has already been declared"
// ============================================================
const AutoComplete = defineAsyncComponent(
() => import('ant-design-vue/es/auto-complete'),
);
const Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));
const Checkbox = defineAsyncComponent(
() => import('ant-design-vue/es/checkbox'),
);
const CheckboxGroup = defineAsyncComponent(() =>
import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),
);
const DatePicker = defineAsyncComponent(
() => import('ant-design-vue/es/date-picker'),
);
const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));
const Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));
const InputNumber = defineAsyncComponent(
() => import('ant-design-vue/es/input-number'),
);
const InputPassword = defineAsyncComponent(() =>
import('ant-design-vue/es/input').then((res) => res.InputPassword),
);
const Mentions = defineAsyncComponent(
() => import('ant-design-vue/es/mentions'),
);
const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));
const RadioGroup = defineAsyncComponent(() =>
import('ant-design-vue/es/radio').then((res) => res.RadioGroup),
);
const RangePicker = defineAsyncComponent(() =>
import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),
);
const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));
const Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));
const Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));
const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));
const Textarea = defineAsyncComponent(() =>
import('ant-design-vue/es/input').then((res) => res.Textarea),
);
const TimePicker = defineAsyncComponent(
() => import('ant-design-vue/es/time-picker'),
);
const TreeSelect = defineAsyncComponent(
() => import('ant-design-vue/es/tree-select'),
);
const Cascader = defineAsyncComponent(
() => import('ant-design-vue/es/cascader'),
);
const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));
const Image = defineAsyncComponent(() => import('ant-design-vue/es/image'));
const PreviewGroup = defineAsyncComponent(() =>
import('ant-design-vue/es/image').then((res) => res.ImagePreviewGroup),
);
// ============================================================
// withDefaultPlaceholder给组件注入 i18n placeholder + ref 透传
// ============================================================
const withDefaultPlaceholder = <T extends Component>(
component: Component,
type: 'input' | 'select',
componentProps: Recordable<any> = {},
) => {
return defineComponent({
name: (component as any).name,
inheritAttrs: false,
setup: (props: any, { attrs, expose, slots }) => {
const placeholder =
props?.placeholder ||
attrs?.placeholder ||
$t(`ui.placeholder.${type}`);
// 透传组件暴露的方法
const innerRef = ref();
expose(
new Proxy(
{},
{
get: (_target, key) => innerRef.value?.[key],
has: (_target, key) => key in (innerRef.value || {}),
},
),
);
return () =>
h(
component,
{ ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },
slots,
);
},
});
};
const IMAGE_EXTENSIONS = new Set([
'bmp',
'gif',
'jpeg',
'jpg',
'png',
'svg',
'webp',
]);
/**
* 检查是否为图片文件
*/
function isImageFile(file: UploadFile): boolean {
if (file.url) {
try {
const pathname = new URL(file.url, 'http://localhost').pathname;
const ext = pathname.split('.').pop()?.toLowerCase();
return ext ? IMAGE_EXTENSIONS.has(ext) : false;
} catch {
const ext = file.url?.split('.').pop()?.toLowerCase();
return ext ? IMAGE_EXTENSIONS.has(ext) : false;
}
}
if (!file.type) {
const ext = file.name?.split('.').pop()?.toLowerCase();
return ext ? IMAGE_EXTENSIONS.has(ext) : false;
}
return file.type.startsWith('image/');
}
/**
* 创建默认的上传按钮插槽
*/
function createDefaultUploadSlots(listType: string, placeholder: string) {
if (listType === 'picture-card') {
return { default: () => placeholder };
}
return {
default: () =>
h(
Button,
{
icon: h(IconifyIcon, {
icon: 'ant-design:upload-outlined',
class: 'mb-1 size-4',
}),
},
() => placeholder,
),
};
}
/**
* 获取文件的 Base64
*/
function getBase64(file: File): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.addEventListener('load', () => resolve(reader.result as string));
reader.addEventListener('error', reject);
});
}
/**
* 预览图片
*/
async function previewImage(
file: UploadFile,
visible: Ref<boolean>,
fileList: Ref<UploadProps['fileList']>,
) {
// 非图片文件直接打开链接
if (!isImageFile(file)) {
const url = file.url || file.preview;
if (url) {
window.open(url, '_blank');
} else {
message.error($t('ui.formRules.previewWarning'));
}
return;
}
const [ImageComponent, PreviewGroupComponent] = await Promise.all([
Image,
PreviewGroup,
]);
// 过滤图片文件并生成预览
const imageFiles = (unref(fileList) || []).filter((f) => isImageFile(f));
for (const imgFile of imageFiles) {
if (!imgFile.url && !imgFile.preview && imgFile.originFileObj) {
imgFile.preview = await getBase64(imgFile.originFileObj);
}
}
const container = document.createElement('div');
document.body.append(container);
let isUnmounted = false;
const currentIndex = imageFiles.findIndex((f) => f.uid === file.uid);
const PreviewWrapper = {
setup() {
return () => {
if (isUnmounted) return null;
return h(
PreviewGroupComponent,
{
class: 'hidden',
preview: {
visible: visible.value,
current: currentIndex,
onVisibleChange: (value: boolean) => {
visible.value = value;
if (!value) {
setTimeout(() => {
if (!isUnmounted && container) {
isUnmounted = true;
render(null, container);
container.remove();
}
}, 300);
}
},
},
},
() =>
imageFiles.map((imgFile) =>
h(ImageComponent, {
key: imgFile.uid,
src: imgFile.url || imgFile.preview,
}),
),
);
};
},
};
render(h(PreviewWrapper), container);
}
/**
* 图片裁剪操作
*/
function cropImage(file: File, aspectRatio: string | undefined) {
return new Promise<Blob | string | undefined>((resolve, reject) => {
const container = document.createElement('div');
document.body.append(container);
let isUnmounted = false;
let objectUrl: null | string = null;
const open = ref(true);
const cropperRef = ref<InstanceType<typeof VCropper> | null>(null);
const closeModal = () => {
open.value = false;
setTimeout(() => {
if (!isUnmounted && container) {
if (objectUrl) {
URL.revokeObjectURL(objectUrl);
}
isUnmounted = true;
render(null, container);
container.remove();
}
}, 300);
};
const CropperWrapper = {
setup() {
return () => {
if (isUnmounted) return null;
if (!objectUrl) {
objectUrl = URL.createObjectURL(file);
}
return h(
Modal,
{
open: open.value,
title: h('div', {}, [
$t('ui.crop.title'),
h(
'span',
{
class: `${aspectRatio ? '' : 'hidden'} ml-2 text-sm text-gray-400 font-normal`,
},
$t('ui.crop.titleTip', [aspectRatio]),
),
]),
centered: true,
width: 548,
zIndex: 9999,
keyboard: false,
maskClosable: false,
closable: false,
cancelText: $t('common.cancel'),
okText: $t('ui.crop.confirm'),
destroyOnClose: true,
onOk: async () => {
const cropper = cropperRef.value;
if (!cropper) {
reject(new Error('Cropper not found'));
closeModal();
return;
}
try {
const dataUrl = await cropper.getCropImage();
if (dataUrl) {
resolve(dataUrl);
} else {
reject(new Error($t('ui.crop.errorTip')));
}
} catch {
reject(new Error($t('ui.crop.errorTip')));
} finally {
closeModal();
}
},
onCancel() {
resolve('');
closeModal();
},
},
() =>
h(VCropper, {
ref: (refValue: any) => (cropperRef.value = refValue),
img: objectUrl as string,
aspectRatio,
}),
);
};
},
};
render(h(CropperWrapper), container);
});
}
/**
* 带预览功能的上传组件
*/
const withPreviewUpload = () => {
return defineComponent({
name: 'Upload',
emits: ['update:modelValue'],
setup(
props: any,
{ attrs, slots, emit }: { attrs: any; emit: any; slots: any },
) {
const previewVisible = ref<boolean>(false);
const placeholder = attrs?.placeholder || $t('ui.placeholder.upload');
const listType = attrs?.listType || attrs?.['list-type'] || 'text';
const fileList = ref<UploadProps['fileList']>(
attrs?.fileList || attrs?.['file-list'] || [],
);
const maxSize = computed(() => attrs?.maxSize ?? attrs?.['max-size']);
const aspectRatio = computed(
() => attrs?.aspectRatio ?? attrs?.['aspect-ratio'],
);
const handleBeforeUpload = async (
file: UploadFile,
originFileList: Array<File>,
) => {
// 文件大小限制
if (maxSize.value && (file.size || 0) / 1024 / 1024 > maxSize.value) {
message.error($t('ui.formRules.sizeLimit', [maxSize.value]));
file.status = 'removed';
return false;
}
// 图片裁剪处理
if (
attrs.crop &&
!attrs.multiple &&
originFileList[0] &&
isImageFile(file)
) {
file.status = 'removed';
const blob = await cropImage(originFileList[0], aspectRatio.value);
if (!blob) {
throw new Error($t('ui.crop.errorTip'));
}
return blob;
}
return attrs.beforeUpload?.(file) ?? true;
};
const handleChange = (event: UploadChangeParam) => {
try {
attrs.handleChange?.(event);
attrs.onHandleChange?.(event);
} catch (error) {
console.error(error);
}
fileList.value = event.fileList.filter(
(file) => file.status !== 'removed',
);
emit(
'update:modelValue',
event.fileList?.length ? fileList.value : undefined,
);
};
const handlePreview = async (file: UploadFile) => {
previewVisible.value = true;
await previewImage(file, previewVisible, fileList);
};
const renderUploadButton = () => {
if (attrs.disabled) return null;
return isEmpty(slots)
? createDefaultUploadSlots(listType, placeholder)
: slots;
};
// 拖拽排序
const draggable = computed(
() => (attrs.draggable ?? false) && !attrs.disabled,
);
const uploadId = `upload-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
const sortableInstance = ref<null | Sortable>(null);
const styleId = `upload-drag-style-${uploadId}`;
function injectDragStyle() {
if (!document.querySelector(`[id="${styleId}"]`)) {
const style = document.createElement('style');
style.id = styleId;
style.textContent = `
[data-upload-id="${uploadId}"] .ant-upload-list-item { cursor: move; }
[data-upload-id="${uploadId}"] .ant-upload-list-item:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.15); }
`;
document.head?.append(style);
}
}
function removeDragStyle() {
document.querySelector(`[id="${styleId}"]`)?.remove();
}
async function initSortable(retryCount = 0) {
if (!draggable.value) return;
injectDragStyle();
await nextTick();
await new Promise((resolve) => setTimeout(resolve, 100));
const container = document.querySelector(
`[data-upload-id="${uploadId}"] .ant-upload-list`,
) as HTMLElement | null;
if (!container) {
if (retryCount < 5) {
setTimeout(() => initSortable(retryCount + 1), 200);
}
return;
}
const { initializeSortable } = useSortable(container, {
animation: 300,
delay: 400,
delayOnTouchOnly: true,
filter:
'.ant-upload-select, .ant-upload-list-item-error, .ant-upload-list-item-uploading',
onEnd: (evt: { oldIndex?: number; newIndex?: number }) => {
const { oldIndex, newIndex } = evt;
if (
oldIndex === undefined ||
newIndex === undefined ||
oldIndex === newIndex
) {
return;
}
const list = [...(fileList.value || [])];
const [movedItem] = list.splice(oldIndex, 1);
if (movedItem) {
list.splice(newIndex, 0, movedItem);
fileList.value = list;
}
attrs.onDragSort?.(oldIndex, newIndex);
emit('update:modelValue', fileList.value);
},
});
sortableInstance.value = await initializeSortable();
}
// 监听表单值变化
watch(
() => attrs.modelValue,
(res) => {
fileList.value = res;
},
);
onMounted(initSortable);
onUnmounted(() => {
sortableInstance.value?.destroy();
removeDragStyle();
});
return () =>
h(
'div',
{ 'data-upload-id': uploadId, class: 'w-full' },
h(
Upload,
{
...props,
...attrs,
fileList: fileList.value,
beforeUpload: handleBeforeUpload,
onChange: handleChange,
onPreview: handlePreview,
},
renderUploadButton() as any,
),
);
},
});
}; };
// 表单组件在这里加 // 表单组件在这里加
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明 // 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type ComponentType = export type ComponentType =
| 'ApiCascader'
| 'ApiSelect' | 'ApiSelect'
| 'ApiTreeSelect' | 'ApiTreeSelect'
| 'AutoComplete' | 'AutoComplete'
@@ -61,7 +622,8 @@ export type ComponentType =
| 'DatePicker' | 'DatePicker'
| 'DefaultButton' | 'DefaultButton'
| 'Divider' | 'Divider'
| 'GalleryPickLink' // OA 场景表单的图片/文件素材选择(透传 acceptTypes 过滤类型) /** OA 场景表单的图片/文件素材选择(透传 acceptTypes 过滤类型) */
| 'GalleryPickLink'
| 'IconPicker' | 'IconPicker'
| 'Input' | 'Input'
| 'InputNumber' | 'InputNumber'
@@ -85,66 +647,89 @@ export type ComponentType =
| 'UploadDraggerPaste' | 'UploadDraggerPaste'
| BaseFormComponentType; | BaseFormComponentType;
/**
* 与 {@link ComponentType} 中注册的组件名一一对应,便于 Schema 上 `component` + `componentProps` 联动提示
*/
export interface ComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: AdapterUploadProps;
}
async function initComponentAdapter() { async function initComponentAdapter() {
const components: Partial<Record<ComponentType, Component>> = { const components: Partial<Record<ComponentType, Component>> = {
// 如果你的组件体积比较大,可以使用异步加载 // 如果你的组件体积比较大,可以使用异步加载
// Button: () => // Button: () =>
// import('xxx').then((res) => res.Button), // import('xxx').then((res) => res.Button),
ApiSelect: (props, { attrs, slots }) => {
return h( ApiCascader: withDefaultPlaceholder(ApiComponent, 'select', {
ApiComponent, component: Cascader,
{ fieldNames: { label: 'label', value: 'value', children: 'children' },
placeholder: $t('ui.placeholder.select'), loadingSlot: 'suffixIcon',
...props, modelPropName: 'value',
...attrs, visibleEvent: 'onVisibleChange',
}),
ApiSelect: withDefaultPlaceholder(ApiComponent, 'select', {
component: Select, component: Select,
loadingSlot: 'suffixIcon', loadingSlot: 'suffixIcon',
visibleEvent: 'onDropdownVisibleChange',
modelPropName: 'value', modelPropName: 'value',
}, visibleEvent: 'onVisibleChange',
slots, }),
); ApiTreeSelect: withDefaultPlaceholder(ApiComponent, 'select', {
},
ApiTreeSelect: (props, { attrs, slots }) => {
return h(
ApiComponent,
{
placeholder: $t('ui.placeholder.select'),
...props,
...attrs,
component: TreeSelect, component: TreeSelect,
fieldNames: { label: 'label', value: 'value', children: 'children' }, fieldNames: { label: 'label', value: 'value', children: 'children' },
loadingSlot: 'suffixIcon', loadingSlot: 'suffixIcon',
modelPropName: 'value', modelPropName: 'value',
optionsPropName: 'treeData', optionsPropName: 'treeData',
visibleEvent: 'onVisibleChange', visibleEvent: 'onVisibleChange',
}, }),
slots,
);
},
AutoComplete, AutoComplete,
Cascader, Cascader,
Checkbox, Checkbox,
CheckboxGroup, CheckboxGroup,
DatePicker, DatePicker,
// 自定义默认按钮 // 自定义默认按钮
DefaultButton: (props, { attrs, slots }) => { DefaultButton: (props: any, { attrs, slots }: any) => {
return h(Button, { ...props, attrs, type: 'default' }, slots); return h(Button, { ...props, attrs, type: 'default' }, slots);
}, },
Divider, Divider,
IconPicker: (props, { attrs, slots }) => { IconPicker: withDefaultPlaceholder(IconPicker, 'select', {
return h( iconSlot: 'addonAfter',
IconPicker, inputComponent: Input,
{ iconSlot: 'addonAfter', inputComponent: Input, ...props, ...attrs }, modelValueProp: 'value',
slots, }),
);
},
Input: withDefaultPlaceholder(Input, 'input'), Input: withDefaultPlaceholder(Input, 'input'),
InputNumber: withDefaultPlaceholder(InputNumber, 'input'), InputNumber: withDefaultPlaceholder(InputNumber, 'input', {
style: { width: '100%' },
}),
InputPassword: withDefaultPlaceholder(InputPassword, 'input'), InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
Mentions: withDefaultPlaceholder(Mentions, 'input'), Mentions: withDefaultPlaceholder(Mentions, 'input'),
// 自定义主要按钮 // 自定义主要按钮
PrimaryButton: (props, { attrs, slots }) => { PrimaryButton: (props: any, { attrs, slots }: any) => {
return h(Button, { ...props, attrs, type: 'primary' }, slots); return h(Button, { ...props, attrs, type: 'primary' }, slots);
}, },
Radio, Radio,
@@ -157,10 +742,10 @@ async function initComponentAdapter() {
Textarea: withDefaultPlaceholder(Textarea, 'input'), Textarea: withDefaultPlaceholder(Textarea, 'input'),
TimePicker, TimePicker,
TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'), TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
Upload, Upload: withPreviewUpload(),
}; };
// 自动注册自定义组件 // 自动注册 components/form 与 views/**/components/form 下的业务表单组件(如 Editor、Avatar
registerComponent(components); registerComponent(components);
// 将组件注册到全局共享状态中 // 将组件注册到全局共享状态中
globalShareState.setComponents(components); globalShareState.setComponents(components);

View File

@@ -1,13 +1,15 @@
import type { import type {
VbenFormProps as FormProps,
VbenFormSchema as FormSchema, VbenFormSchema as FormSchema,
VbenFormProps, FormValues,
} from '@vben/common-ui'; } from '@vben/common-ui';
import type { ComponentType } from './component'; import type { ComponentPropsMap, ComponentType } from './component';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
async function initSetupVbenForm() {
setupVbenForm<ComponentType>({ setupVbenForm<ComponentType>({
config: { config: {
// ant design vue组件库默认都是 v-model:value // ant design vue组件库默认都是 v-model:value
@@ -23,7 +25,7 @@ setupVbenForm<ComponentType>({
UploadOssFile: 'modelValue', UploadOssFile: 'modelValue',
}, },
}, },
defineRules: { rules: {
// 输入项目必填国际化适配 // 输入项目必填国际化适配
required: (value, _params, ctx) => { required: (value, _params, ctx) => {
if (value === undefined || value === null || value.length === 0) { if (value === undefined || value === null || value.length === 0) {
@@ -38,12 +40,45 @@ setupVbenForm<ComponentType>({
} }
return true; return true;
}, },
/**
* 大陆手机号:必填 + 11 位且号段 13-19与后端 UtilsService::checkPhone 一致)
* 表单字段 rules: 'mobile' 即可,无需再叠 required
*/
mobile: (value, _params, ctx) => {
const phone = typeof value === 'string' ? value.trim() : value;
if (phone === undefined || phone === null || phone === '') {
return $t('ui.formRules.required', [ctx.label]);
}
if (!/^1[3456789]\d{9}$/.test(String(phone))) {
return $t('ui.formRules.mobile', [ctx.label]);
}
return true;
},
}, },
}); });
}
const useVbenForm = useForm<ComponentType>; function useVbenForm<
TFormValues extends FormValues = FormValues,
TSubmitValues extends FormValues = TFormValues,
>(
options: FormProps<
ComponentType,
ComponentPropsMap,
TFormValues,
TSubmitValues
>,
) {
return useForm<TFormValues, ComponentType, ComponentPropsMap, TSubmitValues>(
options,
);
}
export { useVbenForm, z }; export { initSetupVbenForm, useVbenForm, z };
export type VbenFormSchema = FormSchema<ComponentType>; export type VbenFormSchema<TValues extends FormValues = FormValues> =
export type { VbenFormProps }; FormSchema<ComponentType, ComponentPropsMap, TValues>;
export type VbenFormProps<
TFormValues extends FormValues = FormValues,
TSubmitValues extends FormValues = TFormValues,
> = FormProps<ComponentType, ComponentPropsMap, TFormValues, TSubmitValues>;

View File

@@ -1,6 +1,14 @@
import type { FormValues } from '@vben/common-ui';
import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
import type { ComponentPropsMap, ComponentType } from './component';
import { h } from 'vue'; import { h } from 'vue';
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; import {
setupVbenVxeTable,
useVbenVxeGrid as useGrid,
} from '@vben/plugins/vxe-table';
import { Button, Image } from 'ant-design-vue'; import { Button, Image } from 'ant-design-vue';
@@ -33,14 +41,15 @@ setupVbenVxeTable({
round: true, round: true,
showOverflow: true, showOverflow: true,
size: 'small', size: 'small',
}, } as VxeTableGridOptions,
}); });
// 表格配置项可以用 cellRender: { name: 'CellImage' }, // 表格配置项可以用 cellRender: { name: 'CellImage' },
vxeUI.renderer.add('CellImage', { vxeUI.renderer.add('CellImage', {
renderTableDefault(_renderOpts, params) { renderTableDefault(renderOpts, params) {
const { props } = renderOpts;
const { column, row } = params; const { column, row } = params;
return h(Image, { src: row[column.field] }); return h(Image, { src: row[column.field], ...props });
}, },
}); });
@@ -62,6 +71,23 @@ setupVbenVxeTable({
useVbenForm, useVbenForm,
}); });
export { useVbenVxeGrid }; export const useVbenVxeGrid = <
T extends Record<string, any>,
TFormValues extends FormValues = FormValues,
TSubmitValues extends FormValues = TFormValues,
>(
...rest: Parameters<
typeof useGrid<
T,
ComponentType,
ComponentPropsMap,
TFormValues,
TSubmitValues
>
>
) =>
useGrid<T, ComponentType, ComponentPropsMap, TFormValues, TSubmitValues>(
...rest,
);
export type * from '@vben/plugins/vxe-table'; export type * from '@vben/plugins/vxe-table';

View File

@@ -1,12 +1,13 @@
/** /**
* 该文件可自行根据业务逻辑进行调整 * 该文件可自行根据业务逻辑进行调整
*/ */
import type { HttpResponse } from '@vben/request'; import type { RequestClientOptions } from '@vben/request';
import { useAppConfig } from '@vben/hooks'; import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences'; import { preferences } from '@vben/preferences';
import { import {
authenticateResponseInterceptor, authenticateResponseInterceptor,
defaultResponseInterceptor,
errorMessageResponseInterceptor, errorMessageResponseInterceptor,
RequestClient, RequestClient,
} from '@vben/request'; } from '@vben/request';
@@ -29,8 +30,9 @@ import {downloadByData} from "#/util/tool";
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
function createRequestClient(baseURL: string) { function createRequestClient(baseURL: string, options?: RequestClientOptions) {
const client = new RequestClient({ const client = new RequestClient({
...options,
baseURL, baseURL,
}); });
@@ -174,7 +176,9 @@ function createRequestClient(baseURL: string) {
return client; return client;
} }
export const requestClient = createRequestClient(apiURL); export const requestClient = createRequestClient(apiURL, {
responseReturn: 'result',
});
export const baseRequestClient = new RequestClient({ baseURL: apiURL }); export const baseRequestClient = new RequestClient({ baseURL: apiURL });

View File

@@ -1,6 +1,7 @@
import { createApp, watchEffect } from 'vue'; import { createApp, watchEffect } from 'vue';
import { registerAccessDirective } from '@vben/access'; import { registerAccessDirective } from '@vben/access';
import { registerLoadingDirective } from '@vben/common-ui/es/loading';
import { preferences } from '@vben/preferences'; import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores'; import { initStores } from '@vben/stores';
import '@vben/styles'; import '@vben/styles';
@@ -11,6 +12,7 @@ import { useTitle } from '@vueuse/core';
import { $t, setupI18n } from '#/locales'; import { $t, setupI18n } from '#/locales';
import { initComponentAdapter } from './adapter/component'; import { initComponentAdapter } from './adapter/component';
import { initSetupVbenForm } from './adapter/form';
import App from './app.vue'; import App from './app.vue';
import { router } from './router'; import { router } from './router';
@@ -18,8 +20,26 @@ async function bootstrap(namespace: string) {
// 初始化组件适配器 // 初始化组件适配器
await initComponentAdapter(); await initComponentAdapter();
// 初始化表单组件
await initSetupVbenForm();
// // 设置弹窗的默认配置
// setDefaultModalProps({
// fullscreenButton: false,
// });
// // 设置抽屉的默认配置
// setDefaultDrawerProps({
// zIndex: 1020,
// });
const app = createApp(App); const app = createApp(App);
// 注册v-loading指令
registerLoadingDirective(app, {
loading: 'loading', // 在这里可以自定义指令名称也可以明确提供false表示不注册这个指令
spinning: 'spinning',
});
// 国际化 i18n 配置 // 国际化 i18n 配置
await setupI18n(app); await setupI18n(app);
@@ -29,9 +49,17 @@ async function bootstrap(namespace: string) {
// 安装权限指令 // 安装权限指令
registerAccessDirective(app); registerAccessDirective(app);
// 初始化 tippy
const { initTippy } = await import('@vben/common-ui/es/tippy');
initTippy(app);
// 配置路由及路由守卫 // 配置路由及路由守卫
app.use(router); app.use(router);
// 配置Motion插件
const { MotionPlugin } = await import('@vben/plugins/motion');
app.use(MotionPlugin);
// 动态更新标题 // 动态更新标题
watchEffect(() => { watchEffect(() => {
if (preferences.app.dynamicTitle) { if (preferences.app.dynamicTitle) {

View File

@@ -1,7 +1,7 @@
import type { CustomComponentType } from './types';
import type { Component } from 'vue'; import type { Component } from 'vue';
import type { CustomComponentType } from './types';
import { getFileNameWithoutExtension, toPascalCase } from '#/util/tool'; import { getFileNameWithoutExtension, toPascalCase } from '#/util/tool';
const componentMap = new Map<CustomComponentType | string, Component>(); const componentMap = new Map<CustomComponentType | string, Component>();

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { preferences } from '@vben/preferences';
import { QuillEditor } from '@vueup/vue-quill'; import { QuillEditor } from '@vueup/vue-quill';
// eslint-disable-next-line n/no-extraneous-import
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { useVModel } from '@vueuse/core'; import { useVModel } from '@vueuse/core';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
@@ -11,7 +11,9 @@ import { message } from 'ant-design-vue';
import { uploadFile } from '#/api/core/upload'; import { uploadFile } from '#/api/core/upload';
import { uploadToOss } from '#/utils/oss-upload'; import { uploadToOss } from '#/utils/oss-upload';
import { prepareImageForUpload } from '#/utils/prepare-image-upload'; import { prepareImageForUpload } from '#/utils/prepare-image-upload';
import { preferences } from '@vben/preferences';
// eslint-disable-next-line n/no-extraneous-import
import '@vueup/vue-quill/dist/vue-quill.snow.css';
const props = defineProps({ const props = defineProps({
value: { value: {

View File

@@ -0,0 +1,87 @@
<script setup lang="ts">
/**
* Markdown 编辑器表单组件(封装 md-editor-v3
* 经 component-map 自动注册schema 中以 component: 'MarkdownEditor' 使用vben form 默认 v-model:value 绑定)
* 为什么封装:统一精简工具栏(轻量备注场景不需要图片/公式等重型功能)+ 主题跟随系统亮暗切换,避免各表单重复配置
*/
import type { ToolbarNames } from 'md-editor-v3';
import { computed, defineAsyncComponent } from 'vue';
import { usePreferences } from '@vben/preferences';
import { useVModel } from '@vueuse/core';
import 'md-editor-v3/lib/style.css';
// 本文件经 component-map 的 eager glob 全量打进主包md-editor-v3含 CodeMirror体积大
// 必须异步加载:外壳进主包、库本体在编辑器真正渲染时才拉取,避免拖累全站首屏
const MdEditor = defineAsyncComponent(() =>
import('md-editor-v3').then((m) => m.MdEditor),
);
const props = defineProps({
value: {
type: String,
default: '',
},
placeholder: {
type: String,
default: '请输入内容(支持 Markdown 格式)',
},
/** 编辑器整体高度px弹窗场景建议 200-300 */
height: {
type: Number,
default: 240,
},
});
const emits = defineEmits(['update:value']);
const mValue = useVModel(props, 'value', emits, {
defaultValue: props.value,
passive: true,
});
/** 主题必须跟随系统亮/暗切换,不能写死(与消息详情 MdPreview 的处理一致) */
const { isDark } = usePreferences();
const theme = computed(() => (isDark.value ? 'dark' : 'light'));
/** 同页面可能挂载多个编辑器实例(如弹窗嵌套),随机 id 避免内部 DOM id 冲突 */
const editorId = `md-form-${Math.random().toString(36).slice(2, 9)}`;
/** 精简工具栏:加粗/斜体/删除线、标题/引用/列表/任务、代码/链接/表格,右侧仅保留预览切换 */
const toolbars: ToolbarNames[] = [
'bold',
'italic',
'strikeThrough',
'-',
'title',
'quote',
'unorderedList',
'orderedList',
'task',
'-',
'code',
'link',
'table',
'=',
'preview',
];
</script>
<template>
<MdEditor
:id="editorId"
v-model="mValue"
:theme="theme"
:placeholder="placeholder"
:toolbars="toolbars"
:footers="[]"
:preview="false"
:style="{ height: `${height}px` }"
class="md-form-editor"
/>
</template>
<style scoped>
/* 圆角与边框贴近 antd 输入组件,融入表单视觉 */
.md-form-editor {
width: 100%;
border: 1px solid hsl(var(--border));
border-radius: 6px;
}
</style>

View File

@@ -1,12 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
/** /**
* 门店多选搜索组件 * 门店多选搜索(对齐开方关键字气泡交互)
* - 普通输入框输入,下方气泡卡片展示匹配结果(名称 / 拼音首拼) * - Teleport + fixed 锚定,避免搜索栏 overflow 裁切导致「气泡不见」
* - 选中后在输入框下方用可关闭 Tag 展示「名称【id】」 * - 多选:点选后不关闭面板,已选项从列表剔除并以 Tag 展示
* - 搜索结果默认高亮第一项Enter 可直接选中 * - Enter / ↑↓ 键盘选用Esc 关闭
* - 样式使用主题 CSS 变量,自动适配暗色
*/ */
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'; import {
computed,
nextTick,
onMounted,
onUnmounted,
ref,
watch,
} from 'vue';
import { LoadingOutlined, SearchOutlined } from '@ant-design/icons-vue'; import { LoadingOutlined, SearchOutlined } from '@ant-design/icons-vue';
import { useDebounceFn, useVModel } from '@vueuse/core'; import { useDebounceFn, useVModel } from '@vueuse/core';
@@ -28,16 +34,11 @@ export type StoreSearchItem = {
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
/** 已选门店 ID 列表 */
value?: number[]; value?: number[];
/** 限定类型:0诊所 1药店不传则诊所+药店都可搜 */ /** 0诊所 1药店不传则诊所+药店 */
storeType?: 0 | 1; storeType?: 0 | 1;
placeholder?: string; placeholder?: string;
disabled?: boolean; disabled?: boolean;
/**
* 外部已选门店详情(打开绑定弹窗时回填名称用)
* 仅用于 Tag 展示,不改变 value
*/
initialItems?: StoreSearchItem[]; initialItems?: StoreSearchItem[];
}>(), }>(),
{ {
@@ -59,13 +60,15 @@ const mValue = useVModel(props, 'value', emits, {
}); });
const containerRef = ref<HTMLElement | null>(null); const containerRef = ref<HTMLElement | null>(null);
const panelRef = ref<HTMLElement | null>(null);
const listRef = ref<HTMLElement | null>(null);
const searchKeyword = ref(''); const searchKeyword = ref('');
const loading = ref(false); const loading = ref(false);
const showDropdown = ref(false); const showDropdown = ref(false);
const highlightIndex = ref(-1); const highlightIndex = ref(-1);
const options = ref<StoreSearchItem[]>([]); const options = ref<StoreSearchItem[]>([]);
/** 已选门店详情(用于 Tag 展示名称) */
const selectedMap = ref<Record<number, StoreSearchItem>>({}); const selectedMap = ref<Record<number, StoreSearchItem>>({});
const panelStyle = ref<Record<string, string>>({});
const selectedIds = computed(() => const selectedIds = computed(() =>
Array.isArray(mValue.value) ? mValue.value.map(Number) : [], Array.isArray(mValue.value) ? mValue.value.map(Number) : [],
@@ -78,28 +81,68 @@ const selectedItems = computed(() =>
}), }),
); );
/** 下拉中过滤掉已选 */ /** 下拉中过滤掉已选,方便连续多选 */
const visibleOptions = computed(() => const visibleOptions = computed(() =>
options.value.filter((item) => !selectedIds.value.includes(item.id)), options.value.filter((item) => !selectedIds.value.includes(item.id)),
); );
/**
* 将初始/回填门店写入 selectedMap便于 Tag 显示真实名称
*/
function mergeInitialItems(items: StoreSearchItem[]) { function mergeInitialItems(items: StoreSearchItem[]) {
if (!items?.length) return; if (!items?.length) return;
const next = { ...selectedMap.value }; const next = { ...selectedMap.value };
for (const item of items) { for (const item of items) {
if (item?.id) { if (item?.id) next[item.id] = item;
next[item.id] = item;
}
} }
selectedMap.value = next; selectedMap.value = next;
} }
/** /**
* 请求后端门店搜索;有结果时默认高亮第一项 * 相对输入框视口坐标放置面板(与 EntryKeywordBubble 同思路)
*/ */
function updatePanelPlacement() {
const el = containerRef.value;
if (!el) return;
const rect = el.getBoundingClientRect();
const vw = window.innerWidth;
const vh = window.innerHeight;
const gap = 4;
const pad = 8;
const spaceBelow = vh - rect.bottom - pad;
const spaceAbove = rect.top - pad;
const placeTop = spaceBelow < 200 && spaceAbove > spaceBelow;
const avail = Math.max(160, placeTop ? spaceAbove : spaceBelow);
const maxH = Math.min(320, avail);
const width = Math.min(Math.max(rect.width, 360), vw - pad * 2);
let left = rect.left;
if (left + width > vw - pad) left = vw - pad - width;
if (left < pad) left = pad;
const base: Record<string, string> = {
position: 'fixed',
zIndex: '4000',
width: `${width}px`,
maxHeight: `${maxH}px`,
left: `${left}px`,
right: 'auto',
};
panelStyle.value = placeTop
? {
...base,
top: 'auto',
bottom: `${Math.max(pad, vh - rect.top + gap)}px`,
}
: {
...base,
top: `${rect.bottom + gap}px`,
bottom: 'auto',
};
}
async function openPanel() {
showDropdown.value = true;
await nextTick();
updatePanelPlacement();
}
async function fetchOptions() { async function fetchOptions() {
const keyword = searchKeyword.value.trim(); const keyword = searchKeyword.value.trim();
if (!keyword) { if (!keyword) {
@@ -109,7 +152,7 @@ async function fetchOptions() {
return; return;
} }
loading.value = true; loading.value = true;
showDropdown.value = true; await openPanel();
try { try {
const res = await searchStoreOption({ const res = await searchStoreOption({
keyword, keyword,
@@ -119,8 +162,9 @@ async function fetchOptions() {
limit: 20, limit: 20,
}); });
options.value = res?.items ?? []; options.value = res?.items ?? [];
// 默认高亮第一项Enter 可直接选中 highlightIndex.value = visibleOptions.value.length > 0 ? 0 : -1;
highlightIndex.value = options.value.length > 0 ? 0 : -1; await nextTick();
updatePanelPlacement();
} catch { } catch {
options.value = []; options.value = [];
highlightIndex.value = -1; highlightIndex.value = -1;
@@ -136,30 +180,36 @@ function handleInput() {
} }
function handleFocus() { function handleFocus() {
if (visibleOptions.value.length > 0) { if (searchKeyword.value.trim() && options.value.length > 0) {
showDropdown.value = true; openPanel();
if (highlightIndex.value < 0) { if (highlightIndex.value < 0 && visibleOptions.value.length > 0) {
highlightIndex.value = 0; highlightIndex.value = 0;
} }
} }
} }
/** /**
* 选中一项:追加到 value缓存名称清空输入继续搜 * 多选:追加 ID保留关键词与面板不关闭气泡
*/ */
function selectOption(item: StoreSearchItem) { function selectOption(item: StoreSearchItem) {
if (selectedIds.value.includes(item.id)) return; if (selectedIds.value.includes(item.id)) return;
selectedMap.value = { ...selectedMap.value, [item.id]: item }; selectedMap.value = { ...selectedMap.value, [item.id]: item };
mValue.value = [...selectedIds.value, item.id]; mValue.value = [...selectedIds.value, item.id];
searchKeyword.value = ''; // 高亮下一项(列表已剔除刚选的)
options.value = []; nextTick(() => {
showDropdown.value = false; if (visibleOptions.value.length === 0) {
highlightIndex.value = -1; highlightIndex.value = -1;
return;
}
highlightIndex.value = Math.min(
Math.max(highlightIndex.value, 0),
visibleOptions.value.length - 1,
);
updatePanelPlacement();
scrollHighlightIntoView();
});
} }
/**
* 取消某个已选门店
*/
function removeSelected(id: number) { function removeSelected(id: number) {
mValue.value = selectedIds.value.filter((x) => x !== id); mValue.value = selectedIds.value.filter((x) => x !== id);
const next = { ...selectedMap.value }; const next = { ...selectedMap.value };
@@ -167,19 +217,52 @@ function removeSelected(id: number) {
selectedMap.value = next; selectedMap.value = next;
} }
function closePanel() {
showDropdown.value = false;
highlightIndex.value = -1;
}
/** 仅改 list 的 scrollTop表头固定不动 */
function scrollHighlightIntoView() {
nextTick(() => {
const listEl = listRef.value;
if (!listEl || highlightIndex.value < 0) return;
const el = listEl.querySelector(
`[data-store-opt-index="${highlightIndex.value}"]`,
) as HTMLElement | null;
if (!el) return;
const listRect = listEl.getBoundingClientRect();
const elRect = el.getBoundingClientRect();
const deltaTop = elRect.top - listRect.top;
const deltaBottom = elRect.bottom - listRect.bottom;
if (deltaTop < 0) {
listEl.scrollTop += deltaTop;
} else if (deltaBottom > 0) {
listEl.scrollTop += deltaBottom;
}
});
}
function handleKeydown(e: KeyboardEvent) { function handleKeydown(e: KeyboardEvent) {
if (!showDropdown.value || visibleOptions.value.length === 0) return; if (!showDropdown.value || visibleOptions.value.length === 0) {
if (e.key === 'Escape') closePanel();
return;
}
const len = visibleOptions.value.length;
switch (e.key) { switch (e.key) {
case 'ArrowDown': case 'ArrowDown':
e.preventDefault(); e.preventDefault();
highlightIndex.value = Math.min( // 头尾循环:最后一项再按下 → 回到第一项
Math.max(highlightIndex.value, 0) + 1, highlightIndex.value =
visibleOptions.value.length - 1, highlightIndex.value < 0 ? 0 : (highlightIndex.value + 1) % len;
); scrollHighlightIntoView();
break; break;
case 'ArrowUp': case 'ArrowUp':
e.preventDefault(); e.preventDefault();
highlightIndex.value = Math.max(highlightIndex.value - 1, 0); // 头尾循环:第一项再按上 → 跳到最后一项
highlightIndex.value =
highlightIndex.value <= 0 ? len - 1 : highlightIndex.value - 1;
scrollHighlightIntoView();
break; break;
case 'Enter': case 'Enter':
e.preventDefault(); e.preventDefault();
@@ -190,35 +273,42 @@ function handleKeydown(e: KeyboardEvent) {
} }
break; break;
case 'Escape': case 'Escape':
showDropdown.value = false; e.preventDefault();
highlightIndex.value = -1; closePanel();
break; break;
} }
} }
function handleClickOutside(e: MouseEvent) { function handleClickOutside(e: MouseEvent) {
if (containerRef.value && !containerRef.value.contains(e.target as Node)) { if (!showDropdown.value) return;
showDropdown.value = false; const t = e.target as Node;
highlightIndex.value = -1; if (containerRef.value?.contains(t) || panelRef.value?.contains(t)) return;
closePanel();
} }
function onWinChange() {
if (showDropdown.value) updatePanelPlacement();
} }
onMounted(() => { onMounted(() => {
document.addEventListener('click', handleClickOutside); document.addEventListener('mousedown', handleClickOutside);
window.addEventListener('resize', onWinChange);
window.addEventListener('scroll', onWinChange, true);
mergeInitialItems(props.initialItems || []); mergeInitialItems(props.initialItems || []);
}); });
onUnmounted(() => { onUnmounted(() => {
document.removeEventListener('click', handleClickOutside); document.removeEventListener('mousedown', handleClickOutside);
window.removeEventListener('resize', onWinChange);
window.removeEventListener('scroll', onWinChange, true);
}); });
watch( watch(
() => props.storeType, () => props.storeType,
() => { () => {
options.value = []; options.value = [];
showDropdown.value = false; closePanel();
searchKeyword.value = ''; searchKeyword.value = '';
highlightIndex.value = -1;
}, },
); );
@@ -227,6 +317,17 @@ watch(
(items) => mergeInitialItems(items || []), (items) => mergeInitialItems(items || []),
{ deep: true }, { deep: true },
); );
watch(visibleOptions, (list) => {
if (!showDropdown.value) return;
if (list.length === 0) {
highlightIndex.value = -1;
return;
}
if (highlightIndex.value >= list.length) {
highlightIndex.value = list.length - 1;
}
});
</script> </script>
<template> <template>
@@ -246,20 +347,35 @@ watch(
</template> </template>
</Input> </Input>
<!-- 气泡建议列表 --> <Teleport to="body">
<div v-if="showDropdown" class="store-multi-search__dropdown"> <div
v-if="showDropdown"
ref="panelRef"
class="store-multi-search__panel"
:style="panelStyle"
>
<div class="store-multi-search__hint">
<span> 循环切换 · Enter 选用 · Esc 关闭 · 可连续多选</span>
<span class="store-multi-search__count">
{{ visibleOptions.length }} 条可选
</span>
</div>
<div class="store-multi-search__body">
<Spin :spinning="loading"> <Spin :spinning="loading">
<Empty <Empty
v-if="!loading && visibleOptions.length === 0" v-if="!loading && visibleOptions.length === 0"
:image="Empty.PRESENTED_IMAGE_SIMPLE" :image="Empty.PRESENTED_IMAGE_SIMPLE"
description="暂无匹配门店" description="暂无匹配门店(或已全部选中)"
class="py-3" class="py-3"
/> />
<div <div ref="listRef" class="store-multi-search__list">
<button
v-for="(item, index) in visibleOptions" v-for="(item, index) in visibleOptions"
:key="item.id" :key="item.id"
type="button"
class="store-multi-search__option" class="store-multi-search__option"
:class="{ 'is-active': index === highlightIndex }" :class="{ 'is-active': index === highlightIndex }"
:data-store-opt-index="index"
@mousedown.prevent="selectOption(item)" @mousedown.prevent="selectOption(item)"
> >
<div class="store-multi-search__option-name"> <div class="store-multi-search__option-name">
@@ -268,11 +384,13 @@ watch(
<div v-if="item.shouzimu" class="store-multi-search__option-sub"> <div v-if="item.shouzimu" class="store-multi-search__option-sub">
首拼{{ item.shouzimu }} 首拼{{ item.shouzimu }}
</div> </div>
</button>
</div> </div>
</Spin> </Spin>
</div> </div>
</div>
</Teleport>
<!-- 已选 Tag -->
<div v-if="selectedItems.length > 0" class="store-multi-search__tags"> <div v-if="selectedItems.length > 0" class="store-multi-search__tags">
<Tag <Tag
v-for="item in selectedItems" v-for="item in selectedItems"
@@ -288,40 +406,93 @@ watch(
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
/* 只用框架主题变量,随亮暗/主题色自动适配 */
.store-multi-search { .store-multi-search {
position: relative; position: relative;
width: 100%; width: 100%;
} }
.store-multi-search__dropdown { .store-multi-search__tags {
position: absolute; display: flex;
z-index: 1050; flex-wrap: wrap;
top: calc(100% + 4px); gap: 6px;
left: 0; margin-top: 8px;
right: 0; }
max-height: 280px; </style>
overflow-y: auto;
padding: 6px; <style lang="scss">
border-radius: 8px; /* Teleport 到 body非 scoped避免气泡被裁切/丢样式 */
background: hsl(var(--card)); .store-multi-search__panel {
overflow: hidden;
display: flex;
flex-direction: column;
border-radius: 10px;
background: hsl(var(--card, var(--background)));
border: 1px solid hsl(var(--border)); border: 1px solid hsl(var(--border));
box-shadow: box-shadow:
0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 8px 24px hsl(0 0% 0% / 0.12),
0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 2px 8px hsl(0 0% 0% / 0.06);
0 9px 28px 8px rgba(0, 0, 0, 0.05); }
.store-multi-search__hint {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
flex-shrink: 0;
padding: 8px 12px;
font-size: 12px;
color: hsl(var(--muted-foreground));
border-bottom: 1px solid hsl(var(--border));
background: hsl(var(--muted) / 0.35);
}
.store-multi-search__count {
flex-shrink: 0;
font-variant-numeric: tabular-nums;
}
/* 表头固定,仅 body/list 滚动 */
.store-multi-search__body {
flex: 1;
min-height: 0;
overflow: hidden;
display: flex;
flex-direction: column;
}
.store-multi-search__body .ant-spin-nested-loading,
.store-multi-search__body .ant-spin-container {
flex: 1;
min-height: 0;
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
.store-multi-search__list {
flex: 1;
min-height: 0;
overflow-x: hidden;
overflow-y: auto;
padding: 6px;
} }
.store-multi-search__option { .store-multi-search__option {
display: block;
width: 100%;
text-align: left;
padding: 8px 10px; padding: 8px 10px;
border: 0;
border-radius: 6px; border-radius: 6px;
cursor: pointer; cursor: pointer;
background: transparent;
transition: background 0.15s; transition: background 0.15s;
&:hover,
&.is-active {
background: hsl(var(--accent-hover));
} }
.store-multi-search__option:hover,
.store-multi-search__option.is-active {
background: hsl(var(--accent) / 0.85);
} }
.store-multi-search__option-name { .store-multi-search__option-name {
@@ -336,11 +507,4 @@ watch(
font-size: 12px; font-size: 12px;
color: hsl(var(--muted-foreground)); color: hsl(var(--muted-foreground));
} }
.store-multi-search__tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 8px;
}
</style> </style>

View File

@@ -145,8 +145,9 @@ function openRecords() {
> >
<template #content> <template #content>
<div class="header-vip-bubble"> <div class="header-vip-bubble">
<!-- 诊所端风格会员卡头图 --> <!-- 黑金会员卡头图与诊所设置/小程序会员卡同一视觉语言 -->
<div class="header-vip-hero"> <div class="header-vip-hero">
<div class="header-vip-hero__glow"></div>
<VipBadgeCombo <VipBadgeCombo
v-if="hasVipVisual" v-if="hasVipVisual"
size="lg" size="lg"
@@ -157,8 +158,10 @@ function openRecords() {
/> />
<div v-else class="header-vip-hero__placeholder">V</div> <div v-else class="header-vip-hero__placeholder">V</div>
<div class="header-vip-hero__info"> <div class="header-vip-hero__info">
<div class="header-vip-hero__title">{{ levelName }}</div> <div class="header-vip-hero__title-row">
<div class="header-vip-hero__sub">{{ durationLabel }}</div> <span class="header-vip-hero__title">{{ levelName }}</span>
<span class="header-vip-hero__chip">{{ durationLabel }}</span>
</div>
<div class="header-vip-hero__expire">{{ expireText }}</div> <div class="header-vip-hero__expire">{{ expireText }}</div>
</div> </div>
</div> </div>
@@ -244,19 +247,37 @@ function openRecords() {
background: hsl(var(--card, var(--background))); background: hsl(var(--card, var(--background)));
box-shadow: 0 8px 24px hsl(var(--foreground) / 0.12); box-shadow: 0 8px 24px hsl(var(--foreground) / 0.12);
} }
/* 黑金卡头:深色卡面亮暗主题通用 */
.header-vip-hero { .header-vip-hero {
position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 14px; gap: 14px;
padding: 16px 18px; padding: 16px 18px;
background: linear-gradient(135deg, #2c3e50 0%, #3d5a40 50%, #6acdbb 100%); overflow: hidden;
background:
radial-gradient(120% 160% at 100% 0%, rgba(212, 175, 55, 0.22) 0%, rgba(212, 175, 55, 0) 45%),
linear-gradient(135deg, #23201a 0%, #12100c 55%, #1f1a12 100%);
border-bottom: 1px solid rgba(220, 186, 110, 0.3);
}
.header-vip-hero__glow {
position: absolute;
top: -50px;
right: -40px;
width: 160px;
height: 160px;
border-radius: 50%;
background: radial-gradient(circle, rgba(240, 217, 168, 0.26) 0%, rgba(240, 217, 168, 0) 70%);
pointer-events: none;
} }
.header-vip-hero__placeholder { .header-vip-hero__placeholder {
width: 72px; width: 72px;
height: 72px; height: 72px;
border-radius: 50%; border-radius: 50%;
background: rgba(255, 255, 255, 0.18); background: radial-gradient(circle, rgba(212, 175, 55, 0.16) 0%, rgba(212, 175, 55, 0.04) 100%);
color: #fff; border: 1px solid rgba(220, 186, 110, 0.4);
color: #f0d9a8;
text-shadow: 0 2px 8px rgba(212, 175, 55, 0.4);
font-size: 28px; font-size: 28px;
font-weight: 700; font-weight: 700;
display: flex; display: flex;
@@ -265,23 +286,36 @@ function openRecords() {
flex-shrink: 0; flex-shrink: 0;
} }
.header-vip-hero__info { .header-vip-hero__info {
position: relative;
min-width: 0; min-width: 0;
color: #fff; }
.header-vip-hero__title-row {
display: flex;
align-items: center;
gap: 8px;
} }
.header-vip-hero__title { .header-vip-hero__title {
font-size: 18px; font-size: 18px;
font-weight: 700; font-weight: 700;
line-height: 1.3; line-height: 1.3;
color: #f5e3bd;
letter-spacing: 1px;
text-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
} }
.header-vip-hero__sub { .header-vip-hero__chip {
margin-top: 4px; flex-shrink: 0;
font-size: 13px; padding: 0 8px;
opacity: 0.9; font-size: 11px;
line-height: 18px;
color: #e8cf9a;
background: rgba(212, 175, 55, 0.1);
border: 1px solid rgba(232, 207, 154, 0.5);
border-radius: 999px;
} }
.header-vip-hero__expire { .header-vip-hero__expire {
margin-top: 4px; margin-top: 6px;
font-size: 12px; font-size: 12px;
opacity: 0.78; color: rgba(240, 224, 190, 0.75);
} }
.header-vip-body { .header-vip-body {
padding: 12px 14px 14px; padding: 12px 14px 14px;
@@ -342,8 +376,4 @@ function openRecords() {
font-size: 12px; font-size: 12px;
color: hsl(var(--muted-foreground)); color: hsl(var(--muted-foreground));
} }
html.dark .header-vip-hero,
.dark .header-vip-hero {
background: linear-gradient(135deg, #1a2332 0%, #243528 50%, #2d6b5f 100%);
}
</style> </style>

View File

@@ -1,16 +1,22 @@
<script lang="ts" setup> <script lang="ts" setup>
/** /**
* 诊所列表 VIP 单元格:徽标+会员名,点击打开 VIP 入口弹窗 * 诊所列表 VIP 单元格:徽标+会员名+到期时间,点击打开 VIP 入口弹窗
*/ */
import VipBadgeCombo from '#/components/vip/VipBadgeCombo.vue'; import { computed } from 'vue';
defineProps<{ import VipBadgeCombo from '#/components/vip/VipBadgeCombo.vue';
import { formatVipDurationExpireLine } from '#/utils/vip';
const props = defineProps<{
vip?: Record<string, any> | null; vip?: Record<string, any> | null;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
click: []; click: [];
}>(); }>();
/** 副行展示时长类型与到期,方便列表一眼看到过期时间 */
const subText = computed(() => formatVipDurationExpireLine(props.vip));
</script> </script>
<template> <template>
<div <div
@@ -29,9 +35,7 @@ const emit = defineEmits<{
/> />
<div class="store-vip-cell__text"> <div class="store-vip-cell__text">
<div class="store-vip-cell__name">{{ vip?.level_name || '普通会员' }}</div> <div class="store-vip-cell__name">{{ vip?.level_name || '普通会员' }}</div>
<div class="store-vip-cell__sub"> <div class="store-vip-cell__sub">{{ subText }}</div>
{{ vip?.duration_label || '点击管理' }}
</div>
</div> </div>
</div> </div>
</template> </template>
@@ -56,14 +60,14 @@ const emit = defineEmits<{
.store-vip-cell__name { .store-vip-cell__name {
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: var(--foreground, #1f1f1f); color: hsl(var(--foreground));
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.store-vip-cell__sub { .store-vip-cell__sub {
font-size: 11px; font-size: 11px;
color: #8c8c8c; color: hsl(var(--muted-foreground));
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -72,12 +76,4 @@ html.dark .store-vip-cell:hover,
.dark .store-vip-cell:hover { .dark .store-vip-cell:hover {
background: rgba(106, 205, 187, 0.2); background: rgba(106, 205, 187, 0.2);
} }
html.dark .store-vip-cell__name,
.dark .store-vip-cell__name {
color: #f4f4f5;
}
html.dark .store-vip-cell__sub,
.dark .store-vip-cell__sub {
color: #a1a1aa;
}
</style> </style>

View File

@@ -34,7 +34,10 @@ const expireText = computed(() => {
}); });
</script> </script>
<template> <template>
<!-- 黑金会员卡与小程序端 vip-member-card 同一套视觉语言深色卡面亮暗主题通用 -->
<div class="store-vip-card"> <div class="store-vip-card">
<div class="store-vip-card__glow"></div>
<div class="store-vip-card__sheen"></div>
<VipBadgeCombo <VipBadgeCombo
v-if="hasVipVisual" v-if="hasVipVisual"
size="xl" size="xl"
@@ -45,11 +48,9 @@ const expireText = computed(() => {
/> />
<div v-else class="store-vip-card__placeholder">V</div> <div v-else class="store-vip-card__placeholder">V</div>
<div class="store-vip-card__info"> <div class="store-vip-card__info">
<div class="store-vip-card__title"> <div class="store-vip-card__title-row">
{{ vip?.level_name || '普通会员' }} <span class="store-vip-card__title">{{ vip?.level_name || '普通会员' }}</span>
</div> <span class="store-vip-card__chip">{{ vip?.duration_label || '普通会员' }}</span>
<div class="store-vip-card__sub">
{{ vip?.duration_label || '普通会员' }}
</div> </div>
<div class="store-vip-card__expire">{{ expireText }}</div> <div class="store-vip-card__expire">{{ expireText }}</div>
</div> </div>
@@ -57,50 +58,96 @@ const expireText = computed(() => {
</template> </template>
<style scoped> <style scoped>
.store-vip-card { .store-vip-card {
position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 24px; gap: 24px;
padding: 20px 28px; padding: 20px 28px;
border-radius: 16px;
background: linear-gradient(135deg, #2c3e50 0%, #3d5a40 50%, #6acdbb 100%);
box-shadow: 0 8px 24px rgba(44, 62, 80, 0.16);
margin-bottom: 24px; margin-bottom: 24px;
overflow: hidden;
border-radius: 18px;
/* 深色曜石底 + 右上暗金光晕,比单一渐变更有实体卡层次 */
background:
radial-gradient(120% 160% at 100% 0%, rgba(212, 175, 55, 0.22) 0%, rgba(212, 175, 55, 0) 45%),
linear-gradient(135deg, #23201a 0%, #12100c 55%, #1f1a12 100%);
border: 1px solid rgba(220, 186, 110, 0.35);
box-shadow:
0 12px 32px rgba(0, 0, 0, 0.28),
0 2px 8px rgba(212, 175, 55, 0.12);
}
/* 右上金色光晕:模拟灯光打在卡面的高光 */
.store-vip-card__glow {
position: absolute;
top: -70px;
right: -50px;
width: 220px;
height: 220px;
border-radius: 50%;
background: radial-gradient(circle, rgba(240, 217, 168, 0.26) 0%, rgba(240, 217, 168, 0) 70%);
pointer-events: none;
}
/* 斜切静态流光条:金属光泽感 */
.store-vip-card__sheen {
position: absolute;
top: 0;
bottom: 0;
left: 32%;
width: 90px;
transform: skewX(-24deg);
background: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.05) 50%,
rgba(255, 255, 255, 0) 100%
);
pointer-events: none;
} }
.store-vip-card__placeholder { .store-vip-card__placeholder {
width: 120px;
height: 120px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.18);
color: #fff;
font-size: 48px;
font-weight: 700;
display: flex; display: flex;
flex-shrink: 0;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-shrink: 0; width: 120px;
height: 120px;
font-size: 48px;
font-weight: 700;
color: #f0d9a8;
text-shadow: 0 2px 8px rgba(212, 175, 55, 0.4);
background: radial-gradient(circle, rgba(212, 175, 55, 0.16) 0%, rgba(212, 175, 55, 0.04) 100%);
border: 1px solid rgba(220, 186, 110, 0.4);
border-radius: 50%;
box-shadow: inset 0 0 16px rgba(212, 175, 55, 0.15);
} }
.store-vip-card__info { .store-vip-card__info {
position: relative;
min-width: 0; min-width: 0;
color: #fff; }
.store-vip-card__title-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
} }
.store-vip-card__title { .store-vip-card__title {
font-size: 22px; font-size: 22px;
font-weight: 700; font-weight: 700;
line-height: 1.3; line-height: 1.3;
margin-bottom: 6px; color: #f5e3bd;
letter-spacing: 1px;
text-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
} }
.store-vip-card__sub { /* 期限徽章:金字描边小胶囊 */
font-size: 14px; .store-vip-card__chip {
opacity: 0.9; flex-shrink: 0;
margin-bottom: 6px; padding: 1px 10px;
font-size: 12px;
color: #e8cf9a;
background: rgba(212, 175, 55, 0.1);
border: 1px solid rgba(232, 207, 154, 0.5);
border-radius: 999px;
} }
.store-vip-card__expire { .store-vip-card__expire {
font-size: 13px; font-size: 13px;
opacity: 0.78; color: rgba(240, 224, 190, 0.75);
}
html.dark .store-vip-card,
.dark .store-vip-card {
background: linear-gradient(135deg, #1a2332 0%, #243528 50%, #2d6b5f 100%);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
} }
</style> </style>

View File

@@ -10,6 +10,7 @@ import { useVbenModal } from '@vben/common-ui';
import VipBadgeCombo from '#/components/vip/VipBadgeCombo.vue'; import VipBadgeCombo from '#/components/vip/VipBadgeCombo.vue';
import VipStoreRecordsModal from '#/components/vip/VipStoreRecordsModal.vue'; import VipStoreRecordsModal from '#/components/vip/VipStoreRecordsModal.vue';
import VipUpgradeModal from '#/components/vip/VipUpgradeModal.vue'; import VipUpgradeModal from '#/components/vip/VipUpgradeModal.vue';
import { formatVipExpireAt } from '#/utils/vip';
const gridApi = ref<any>(); const gridApi = ref<any>();
const onSuccess = ref<null | (() => void)>(null); const onSuccess = ref<null | (() => void)>(null);
@@ -21,6 +22,7 @@ const title = computed(
() => `VIP管理 - ${storeName.value || storeId.value || ''}`, () => `VIP管理 - ${storeName.value || storeId.value || ''}`,
); );
/** 当前等级 + 时长类型 */
const currentLevelText = computed(() => { const currentLevelText = computed(() => {
const v = vip.value; const v = vip.value;
if (!v) return '当前:普通会员'; if (!v) return '当前:普通会员';
@@ -32,6 +34,20 @@ const currentLevelText = computed(() => {
return duration ? `当前:${level} · ${duration}` : `当前:${level}`; return duration ? `当前:${level} · ${duration}` : `当前:${level}`;
}); });
/** 到期时间独立一行,打开弹窗时一眼可见 */
const currentExpireText = computed(() => {
const v = vip.value;
if (!v) return '';
const code = String(v.level_code || 'V0').trim() || 'V0';
if (code === 'V0') return '';
const expire = formatVipExpireAt(v, {
lifetimeText: '终身',
withPrefix: false,
});
if (!expire) return '';
return expire === '终身' ? '到期时间:终身' : `到期时间:${expire}`;
});
const [UpgradeModalComp, upgradeModalApi] = useVbenModal({ const [UpgradeModalComp, upgradeModalApi] = useVbenModal({
connectedComponent: VipUpgradeModal, connectedComponent: VipUpgradeModal,
}); });
@@ -107,7 +123,12 @@ function openRecords() {
:level-name="vip?.level_name" :level-name="vip?.level_name"
:duration-label="vip?.duration_label" :duration-label="vip?.duration_label"
/> />
<div class="vip-hub-current__meta">
<div class="vip-hub-current__text">{{ currentLevelText }}</div> <div class="vip-hub-current__text">{{ currentLevelText }}</div>
<div v-if="currentExpireText" class="vip-hub-current__expire">
{{ currentExpireText }}
</div>
</div>
</div> </div>
<div class="vip-hub-grid"> <div class="vip-hub-grid">
<button type="button" class="vip-hub-card" @click="openUpgrade"> <button type="button" class="vip-hub-card" @click="openUpgrade">
@@ -140,11 +161,21 @@ function openRecords() {
border-radius: 10px; border-radius: 10px;
background: hsl(var(--muted) / 0.25); background: hsl(var(--muted) / 0.25);
} }
.vip-hub-current__meta {
min-width: 0;
display: flex;
flex-direction: column;
gap: 4px;
}
.vip-hub-current__text { .vip-hub-current__text {
font-size: 13px; font-size: 13px;
font-weight: 500; font-weight: 500;
color: hsl(var(--foreground)); color: hsl(var(--foreground));
} }
.vip-hub-current__expire {
font-size: 12px;
color: hsl(var(--muted-foreground));
}
.vip-hub-grid { .vip-hub-grid {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;

View File

@@ -17,7 +17,7 @@ import {
openVipStore, openVipStore,
} from '#/views/system/vip/store/api'; } from '#/views/system/vip/store/api';
/** 时长预设 → 时效类型 code与后端 VipDurationHelper 对齐) */ /** 时长预设 → 时效类型 code与后端 VipDurationHelper 对齐keep 走当前会员 duration_type */
const PRESET_TO_DURATION: Record<string, string> = { const PRESET_TO_DURATION: Record<string, string> = {
'7d': 'trial', '7d': 'trial',
'1w': 'week', '1w': 'week',
@@ -33,6 +33,8 @@ const gridApi = ref<any>();
const onSuccess = ref<null | (() => void)>(null); const onSuccess = ref<null | (() => void)>(null);
const storeId = ref(0); const storeId = ref(0);
const storeName = ref(''); const storeName = ref('');
/** 打开弹窗时带入的当前门店 VIP用于判断能否「继承剩余时间」 */
const currentVip = ref<Record<string, any> | null>(null);
const levelId = ref<number | undefined>(); const levelId = ref<number | undefined>();
const durationPreset = ref<string | undefined>(); const durationPreset = ref<string | undefined>();
const customYears = ref<number | undefined>(); const customYears = ref<number | undefined>();
@@ -46,8 +48,28 @@ const selectedLevel = computed(() =>
levels.value.find((i) => i.id === levelId.value), levels.value.find((i) => i.id === levelId.value),
); );
/**
* 是否可继承剩余时间:非普通会员(非 V0且未过期
* 普通会员没有可继承的到期时间,不展示/不默认 keep
*/
const canKeepDuration = computed(() => {
const v = currentVip.value;
if (!v) return false;
const code = String(v.level_code || 'V0').trim() || 'V0';
if (code === 'V0') return false;
const expireAt = Number(v.expire_at || 0);
// expire_at=0 表示终身,视为可继承;>0 须未过期
if (expireAt > 0 && expireAt * 1000 <= Date.now()) return false;
return true;
});
/** 按时长预设解析对应丝带资源 */ /** 按时长预设解析对应丝带资源 */
function ribbonByPreset(preset?: string) { function ribbonByPreset(preset?: string) {
if (preset === 'keep') {
const code = String(currentVip.value?.duration_type || '').trim();
if (!code) return null;
return durationTypes.value.find((i) => i.code === code) || null;
}
const code = PRESET_TO_DURATION[preset || ''] || ''; const code = PRESET_TO_DURATION[preset || ''] || '';
if (!code) return null; if (!code) return null;
return durationTypes.value.find((i) => i.code === code) || null; return durationTypes.value.find((i) => i.code === code) || null;
@@ -57,9 +79,11 @@ const selectedDurationType = computed(() =>
ribbonByPreset(durationPreset.value), ribbonByPreset(durationPreset.value),
); );
/** 时长卡片数据:附带丝带图,避免模板重复查找 */ /** 时长卡片:普通会员隐藏 keep其它预设照常 */
const durationCards = computed(() => const durationCards = computed(() =>
presets.value.map((p) => { presets.value
.filter((p) => p.value !== 'keep' || canKeepDuration.value)
.map((p) => {
const ribbon = ribbonByPreset(p.value); const ribbon = ribbonByPreset(p.value);
return { return {
...p, ...p,
@@ -78,10 +102,36 @@ const previewLevelName = computed(
); );
const previewDurationLabel = computed(() => { const previewDurationLabel = computed(() => {
if (!durationPreset.value) return '请选择时长'; if (!durationPreset.value) return '请选择时长';
if (durationPreset.value === 'keep') {
const label = String(currentVip.value?.duration_label || '').trim();
const expireHint = formatVipExpireHint(currentVip.value);
if (label && expireHint) return `继承剩余:${label}${expireHint}`;
if (label) return `继承剩余:${label}`;
return '继承剩余时间(不改动)';
}
const preset = presets.value.find((p) => p.value === durationPreset.value); const preset = presets.value.find((p) => p.value === durationPreset.value);
return preset?.label || selectedDurationType.value?.name || '请选择时长'; return preset?.label || selectedDurationType.value?.name || '请选择时长';
}); });
/**
* 格式化当前会员到期提示(终身 / 已格式化字符串 / 时间戳)
*/
function formatVipExpireHint(v: Record<string, any> | null | undefined): string {
if (!v) return '';
if (v.is_lifetime) return '终身';
const raw = v.expire_at;
if (raw == null || raw === '' || raw === 0) return '';
if (typeof raw === 'string' && Number.isNaN(Number(raw))) {
return `${raw}`;
}
const n = Number(raw);
if (!(n > 0)) return '';
const d = new Date(n * 1000);
if (Number.isNaN(d.getTime())) return '';
const pad = (x: number) => String(x).padStart(2, '0');
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
const title = computed(() => `升级VIP - ${storeName.value || storeId.value}`); const title = computed(() => `升级VIP - ${storeName.value || storeId.value}`);
/** 选择会员等级 */ /** 选择会员等级 */
@@ -139,6 +189,7 @@ const [Modal, modalApi] = useVbenModal({
durationPreset.value = undefined; durationPreset.value = undefined;
customYears.value = undefined; customYears.value = undefined;
remark.value = ''; remark.value = '';
currentVip.value = null;
return; return;
} }
const data = modalApi.getData<Record<string, any>>() || {}; const data = modalApi.getData<Record<string, any>>() || {};
@@ -146,6 +197,7 @@ const [Modal, modalApi] = useVbenModal({
onSuccess.value = data.onSuccess || null; onSuccess.value = data.onSuccess || null;
storeId.value = Number(data.store_id || 0); storeId.value = Number(data.store_id || 0);
storeName.value = data.store_name || ''; storeName.value = data.store_name || '';
currentVip.value = data.vip || null;
const [levelList, presetList, durationList] = await Promise.all([ const [levelList, presetList, durationList] = await Promise.all([
getVipLevelOption(), getVipLevelOption(),
getVipDurationPresets(), getVipDurationPresets(),
@@ -157,10 +209,14 @@ const [Modal, modalApi] = useVbenModal({
value: i.value, value: i.value,
})); }));
durationTypes.value = durationList || []; durationTypes.value = durationList || [];
// 回填当前 VIP 等级(便于续期) // 回填当前 VIP 等级(便于续期/改档
if (data.vip?.level_id) { if (data.vip?.level_id) {
levelId.value = Number(data.vip.level_id); levelId.value = Number(data.vip.level_id);
} }
// 非普通会员:默认选「继承剩余时间」,到期日不改动
if (canKeepDuration.value) {
durationPreset.value = 'keep';
}
}, },
}); });
@@ -170,8 +226,9 @@ watch(durationPreset, (v) => {
</script> </script>
<template> <template>
<Modal :title="title" class="w-[50%]"> <Modal :title="title" class="w-[50%]">
<!-- 预览徽标卡片 + 丝带随时长自动适配 --> <!-- 预览黑金卡面 + 徽标丝带随时长自动适配 -->
<div class="vip-upgrade-preview mb-5"> <div class="vip-upgrade-preview mb-5">
<div class="vip-upgrade-preview__glow"></div>
<VipBadgeCombo <VipBadgeCombo
size="xl" size="xl"
:badge-url="previewBadgeUrl" :badge-url="previewBadgeUrl"
@@ -273,28 +330,53 @@ watch(durationPreset, (v) => {
</Modal> </Modal>
</template> </template>
<style scoped> <style scoped>
/* 黑金预览卡:与会员卡组件同一视觉语言,深色卡面亮暗主题通用 */
.vip-upgrade-preview { .vip-upgrade-preview {
position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 20px; gap: 20px;
padding: 20px 24px; padding: 20px 24px;
border-radius: 14px; overflow: hidden;
background: linear-gradient(135deg, #2c3e50 0%, #3d5a40 50%, #6acdbb 100%); border-radius: 16px;
color: #fff; background:
radial-gradient(120% 160% at 100% 0%, rgba(212, 175, 55, 0.22) 0%, rgba(212, 175, 55, 0) 45%),
linear-gradient(135deg, #23201a 0%, #12100c 55%, #1f1a12 100%);
border: 1px solid rgba(220, 186, 110, 0.35);
box-shadow:
0 10px 26px rgba(0, 0, 0, 0.24),
0 2px 8px rgba(212, 175, 55, 0.12);
color: #f5e3bd;
}
.vip-upgrade-preview__glow {
position: absolute;
top: -60px;
right: -40px;
width: 200px;
height: 200px;
border-radius: 50%;
background: radial-gradient(circle, rgba(240, 217, 168, 0.26) 0%, rgba(240, 217, 168, 0) 70%);
pointer-events: none;
}
.vip-upgrade-preview__text {
position: relative;
min-width: 0;
} }
.vip-upgrade-preview__title { .vip-upgrade-preview__title {
font-size: 20px; font-size: 20px;
font-weight: 700; font-weight: 700;
margin-bottom: 4px; margin-bottom: 4px;
letter-spacing: 1px;
text-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
} }
.vip-upgrade-preview__sub { .vip-upgrade-preview__sub {
font-size: 13px; font-size: 13px;
opacity: 0.9; color: rgba(240, 224, 190, 0.85);
margin-bottom: 6px; margin-bottom: 6px;
} }
.vip-upgrade-preview__price { .vip-upgrade-preview__price {
font-size: 12px; font-size: 12px;
opacity: 0.8; color: rgba(240, 224, 190, 0.68);
} }
/* 两行 + 横向滑动的单选卡片轨道 */ /* 两行 + 横向滑动的单选卡片轨道 */
.vip-pick-scroll { .vip-pick-scroll {
@@ -397,11 +479,7 @@ watch(durationPreset, (v) => {
white-space: nowrap; white-space: nowrap;
} }
/* ========== 暗色适配html.dark / .dark========== */ /* ========== 暗色适配html.dark / .dark========== */
html.dark .vip-upgrade-preview, /* 黑金预览卡为深色卡面,亮暗主题通用,无需暗色分支 */
.dark .vip-upgrade-preview {
background: linear-gradient(135deg, #1a2332 0%, #243528 50%, #2d6b5f 100%);
box-shadow: inset 0 0 0 1px rgba(106, 205, 187, 0.18);
}
html.dark .vip-pick-scroll::-webkit-scrollbar-thumb, html.dark .vip-pick-scroll::-webkit-scrollbar-thumb,
.dark .vip-pick-scroll::-webkit-scrollbar-thumb { .dark .vip-pick-scroll::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.22); background: rgba(255, 255, 255, 0.22);

View File

@@ -8,6 +8,7 @@ import { $t } from '#/locales';
const appName = computed(() => preferences.app.name); const appName = computed(() => preferences.app.name);
const logo = computed(() => preferences.logo.source); const logo = computed(() => preferences.logo.source);
const logoDark = computed(() => preferences.logo.sourceDark);
// const logo = 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/logo.png?Expires=1734595037&OSSAccessKeyId=TMP.3KhpnCAjxkdTGWSj1ZCdYe3e9c6MBfEVZwN1CiHdUKUAT2D1mPEpACYgYMkUiQDVqy9Zqb7VqgUoh21W37FC3CztogHJPN&Signature=KmymeelO2OZxaAmvm2ACDK5UfF8%3D'; // const logo = 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/logo.png?Expires=1734595037&OSSAccessKeyId=TMP.3KhpnCAjxkdTGWSj1ZCdYe3e9c6MBfEVZwN1CiHdUKUAT2D1mPEpACYgYMkUiQDVqy9Zqb7VqgUoh21W37FC3CztogHJPN&Signature=KmymeelO2OZxaAmvm2ACDK5UfF8%3D';
</script> </script>
@@ -15,6 +16,7 @@ const logo = computed(() => preferences.logo.source);
<AuthPageLayout <AuthPageLayout
:app-name="appName" :app-name="appName"
:logo="logo" :logo="logo"
:logo-dark="logoDark"
:page-description="$t('authentication.pageDesc')" :page-description="$t('authentication.pageDesc')"
:page-title="$t('authentication.pageTitle')" :page-title="$t('authentication.pageTitle')"
:version="preferences.app.version" :version="preferences.app.version"

View File

@@ -1,187 +1,183 @@
<script lang="ts" setup> <script lang="ts" setup>
/**
* 管理端基础布局:铃铛站内信轮询 + 动作宿主挂载
*/
import type { NotificationItem } from '@vben/layouts'; import type { NotificationItem } from '@vben/layouts';
import { computed, onUnmounted, ref, watch } from 'vue'; import { computed, onUnmounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { AuthenticationLoginExpiredModal } from '@vben/common-ui'; import { AuthenticationLoginExpiredModal, VbenIcon } from '@vben/common-ui';
// import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';
import { useWatermark } from '@vben/hooks'; import { useWatermark } from '@vben/hooks';
// import { BookOpenText, CircleHelp, MdiGithub } from '@vben/icons'; import { $t } from '@vben/locales';
// import { CircleHelp } from '@vben/icons';
import { import {
BasicLayout, BasicLayout,
LockScreen, LockScreen,
Notification, Notification,
UserDropdown, UserDropdown,
} from '@vben/layouts'; } from '@vben/layouts';
import { preferences } from '@vben/preferences'; import { preferences, usePreferences } from '@vben/preferences';
import { useAccessStore, useUserStore } from '@vben/stores'; import { useAccessStore, useUserStore } from '@vben/stores';
// import { openWindow } from '@vben/utils';
import { import { notification } from 'ant-design-vue';
Bell, import { Bell, Users } from 'lucide-vue-next';
CalendarClock,
Megaphone,
Users,
} from 'lucide-vue-next';
// import { $t } from '#/locales';
import DoctorTransferFloat from '#/components/doctor-transfer-float/DoctorTransferFloat.vue'; import DoctorTransferFloat from '#/components/doctor-transfer-float/DoctorTransferFloat.vue';
import HeaderVipBadge from '#/components/vip/HeaderVipBadge.vue'; import HeaderVipBadge from '#/components/vip/HeaderVipBadge.vue';
import { useAuthStore } from '#/store';
import LoginForm from '#/views/_core/authentication/login.vue';
import SwitchAccountModal from '#/layouts/components/SwitchAccountModal.vue'; import SwitchAccountModal from '#/layouts/components/SwitchAccountModal.vue';
import { useRouter } from 'vue-router'; import { useAuthStore } from '#/store';
import {getNoticeListApi, readAllApi} from "#/views/notice/api"; import { formatTimeToRelative } from '#/util/tool';
import {formatTimeToRelative} from "#/util/tool"; import LoginForm from '#/views/_core/authentication/login.vue';
import {notification} from "ant-design-vue"; import NoticeActionHost from '#/views/notice/action/NoticeActionHost.vue';
import {
emitNoticeRefresh,
onNoticeRefresh,
openNoticeAction,
} from '#/views/notice/action/bus';
import { resolveNoticeColor } from '#/views/notice/action/types';
import {
getNoticeListApi,
getNoticeUnreadCountApi,
readAllApi,
readApi,
} from '#/views/notice/api';
const router = useRouter(); const router = useRouter();
const switchAccountModalRef = ref<InstanceType<typeof SwitchAccountModal>>(); const switchAccountModalRef = ref<InstanceType<typeof SwitchAccountModal>>();
// 样式相关
const typeIcons = {
0: Megaphone,
1: Bell,
2: CalendarClock,
};
const typeColors = {
0: 'text-sky-500',
1: 'text-amber-500',
2: 'text-emerald-500',
};
const typeBgColors = {
0: 'bg-sky-50',
1: 'bg-amber-50',
2: 'bg-emerald-50',
};
const typeBorderColors = {
0: 'border-sky-200',
1: 'border-amber-200',
2: 'border-emerald-200',
};
const notifications = ref<NotificationItem[]>([]); const notifications = ref<NotificationItem[]>([]);
const unreadCount = ref(0);
// 获取消息列表数据 /** 拉取未读列表 + 角标数字 */
const getNoticeList = async () => { const getNoticeList = async () => {
try { try {
const res = await getNoticeListApi({ const [res, countRes] = await Promise.all([
status: 0, getNoticeListApi({ status: 0, page: 1, pageSize: 20 }),
}); getNoticeUnreadCountApi().catch(() => null),
let message = '未读消息'; ]);
if (res.items.length > 0) { const items = res?.items || [];
if (res.items.length > notifications.value.length) { const prevLen = notifications.value.length;
if (notifications.value.length === 0) { if (items.length > prevLen && prevLen > 0) {
message = '新消息';
}
notification.info({ notification.info({
message: `您有${message}`, message: '您有新消息',
description: `您有 ${res.items.length}${message}请注意查收`, description: `您有 ${items.length}未读消息请注意查收`,
duration: 5, duration: 5,
}); });
} }
notifications.value = items.map((item: any) => {
notifications.value = res.items.map(item => ({ const color = resolveNoticeColor(item.type_color);
return {
id: item.id, id: item.id,
icon: typeIcons[item.type], // Notification 默认用组件当 icon我们走自定义 content 槽,这里占位即可
// 将API返回的数据映射到组件需要的格式 icon: Bell as any,
message: item.title, message: item.detail || item.type_name || '',
title: getMessageTypeName(item.type), title: item.title || '通知',
date: formatTimeToRelative(item.created_at), date: formatTimeToRelative(item.created_at),
color: typeColors[item.type], color: color.text,
isRead: item.status colorBg: color.bg,
})); isRead: Number(item.status) === 1,
} else { status: item.status,
notifications.value = []; type_code: item.type_code,
} type_name: item.type_name,
type_icon: item.type_icon,
type_color: item.type_color,
action_type: item.action_type,
action_payload: item.action_payload,
detail: item.detail,
content: item.content,
edit_type: item.edit_type,
priority: item.priority,
raw: item,
};
});
unreadCount.value = Number(
countRes?.count ?? res?.unread_total ?? items.length,
);
} catch (error) { } catch (error) {
console.error('获取消息列表失败:', error); console.error('获取消息列表失败:', error);
} }
}; };
getNoticeList(); getNoticeList();
// 每隔二十秒刷新一次
let intervalId = setInterval(getNoticeList, 20_000); let intervalId = setInterval(getNoticeList, 20_000);
// 封装定时器重启逻辑
const restartInterval = () => { const restartInterval = () => {
clearInterval(intervalId); clearInterval(intervalId);
getNoticeList(); // 立即获取最新数据 getNoticeList();
intervalId = setInterval(getNoticeList, 20_000); intervalId = setInterval(getNoticeList, 20_000);
}; };
// 处理跨标签页修改 const handleStorageChange = (event: StorageEvent) => {
const handleStorageChange = (event) => {
if (event.key === 'readStatus') { if (event.key === 'readStatus') {
restartInterval(); restartInterval();
} }
}; };
// 处理当前标签页修改(核心新增部分)
const handleLocalChange = () => {
restartInterval();
};
// 添加双重监听
window.addEventListener('storage', handleStorageChange); // 跨标签页监听
const originalSetItem = localStorage.setItem.bind(localStorage); const originalSetItem = localStorage.setItem.bind(localStorage);
// 拦截当前页的 localStorage.setItem 操作
localStorage.setItem = (key, value) => { localStorage.setItem = (key, value) => {
originalSetItem(key, value); originalSetItem(key, value);
if (key === 'readStatus') { if (key === 'readStatus') {
handleLocalChange(); // 手动触发当前页回调 restartInterval();
} }
}; };
// 组件卸载时清理 window.addEventListener('storage', handleStorageChange);
const stopRefreshListen = onNoticeRefresh(() => restartInterval());
onUnmounted(() => { onUnmounted(() => {
clearInterval(intervalId); clearInterval(intervalId);
window.removeEventListener('storage', handleStorageChange); window.removeEventListener('storage', handleStorageChange);
localStorage.setItem = originalSetItem; // 恢复原始方法 localStorage.setItem = originalSetItem;
stopRefreshListen();
}); });
// 消息类型定义
const messageTypes = [
{ id: -1, name: '全部消息' },
{ id: 0, name: '系统公告', icon: Megaphone },
{ id: 1, name: '系统通知', icon: Bell },
{ id: 2, name: '周报提醒', icon: CalendarClock },
];
// 根据类型ID获取类型名称
const getMessageTypeName = (typeId) => {
const type = messageTypes.find(t => t.id === typeId);
return type ? type.name : '未知类型';
};
const goNoticeList = () => { const goNoticeList = () => {
// TODO 跳转通知列表
router.push('/notice/list'); router.push('/notice/list');
}; };
// 处理消息点击 /** 从铃铛列表移除并扣减角标 */
const handleItemClick = (item) => { function removeFromBell(item: NotificationItem) {
notifications.value.forEach((value) => { notifications.value = notifications.value.filter((n) => n.id !== item.id);
if (value.id === item.id) { unreadCount.value = Math.max(0, unreadCount.value - 1);
value.status = 1;
value.isRead = 1;
} }
/** 行点击:立刻取消未读并打开场景 */
const handleItemClick = async (item: NotificationItem) => {
const raw = (item as any).raw || item;
const wasUnread = !item.isRead;
item.isRead = true;
if (wasUnread) {
removeFromBell(item);
}
await openNoticeAction({
...raw,
id: item.id,
status: wasUnread ? 0 : 1,
}); });
router.push(`/notice/detail/${item.id}`);
}; };
const handleClick = async (item: NotificationItem) => {
await handleItemClick(item);
};
/** 勾选已读:只标已读,不打开详情 */
async function handleMarkRead(item: NotificationItem) {
if (item.isRead) return;
item.isRead = true;
removeFromBell(item);
try {
await readApi(Number(item.id));
emitNoticeRefresh();
} catch {
/* ignore */
}
}
const userStore = useUserStore(); const userStore = useUserStore();
const authStore = useAuthStore(); const authStore = useAuthStore();
const accessStore = useAccessStore(); const accessStore = useAccessStore();
const { destroyWatermark, updateWatermark } = useWatermark(); const { destroyWatermark, updateWatermark } = useWatermark();
const showDot = computed(() => const { isDark } = usePreferences();
notifications.value.some((item) => !item.isRead), const showDot = computed(() => unreadCount.value > 0);
);
/** 与原先悬浮窗一致:有 doctor_id 且绑定门店才显示传方入口 */
const showDoctorTransfer = computed(() => { const showDoctorTransfer = computed(() => {
const info = userStore.userInfo as Record<string, any> | null | undefined; const info = userStore.userInfo as Record<string, any> | null | undefined;
if (!info) return false; if (!info) return false;
@@ -189,6 +185,13 @@ const showDoctorTransfer = computed(() => {
}); });
const menus = computed(() => [ const menus = computed(() => [
{
handler: () => {
router.push({ name: 'Profile' });
},
icon: 'lucide:user',
text: $t('page.auth.profile'),
},
{ {
handler: () => { handler: () => {
switchAccountModalRef.value?.openModal(); switchAccountModalRef.value?.openModal();
@@ -210,7 +213,20 @@ async function handleLogout() {
function handleNoticeClear() { function handleNoticeClear() {
readAllApi().then(() => { readAllApi().then(() => {
notifications.value = []; notifications.value = [];
// 成功后可以重新获取数据或者直接更新本地状态 unreadCount.value = 0;
notification.success({
message: '标记成功',
duration: 2,
});
emitNoticeRefresh();
});
}
/** 全部已读:必须走后端 API */
function handleMakeAll() {
readAllApi().then(() => {
notifications.value = [];
unreadCount.value = 0;
notification.success({ notification.success({
message: '标记成功', message: '标记成功',
duration: 2, duration: 2,
@@ -218,43 +234,45 @@ function handleNoticeClear() {
}); });
} }
function handleMakeAll() {
notifications.value.forEach((item) => (item.isRead = true));
}
watch( watch(
() => preferences.app.watermark, () => ({
async (enable) => { enable: preferences.app.watermark,
isDark: isDark.value,
}),
async ({ enable }) => {
if (enable) { if (enable) {
await updateWatermark({ await updateWatermark({
// 这里更改水印内容
// content: `${userStore.userInfo?.nick_name || import.meta.env.VITE_APP_TITLE}`,
content: `${userStore.userInfo?.nick_name}\r\n${userStore.userInfo?.phone || import.meta.env.VITE_APP_TITLE}`, content: `${userStore.userInfo?.nick_name}\r\n${userStore.userInfo?.phone || import.meta.env.VITE_APP_TITLE}`,
}); });
} else { } else {
destroyWatermark(); destroyWatermark();
} }
}, },
{ { immediate: true },
immediate: true,
},
); );
</script> </script>
<template> <template>
<BasicLayout @clear-preferences-and-logout="handleLogout"> <BasicLayout
<!-- index=55紧挨全局搜索(50)右侧 --> :avatar
:text="userStore.userInfo?.realName"
@clear-preferences-and-logout="handleLogout"
@logout="handleLogout"
>
<template #header-right-55> <template #header-right-55>
<DoctorTransferFloat v-if="showDoctorTransfer" /> <DoctorTransferFloat v-if="showDoctorTransfer" />
</template> </template>
<template #user-dropdown> <template #user-dropdown>
<!-- VIP 徽标放在头像左侧与用户下拉并排 -->
<div class="flex items-center"> <div class="flex items-center">
<HeaderVipBadge /> <HeaderVipBadge />
<UserDropdown <UserDropdown
:avatar :avatar
:description="userStore.userInfo?.email"
:menus :menus
:tag-text="userStore.userInfo?.roles?.name"
:text="userStore.userInfo?.nick_name" :text="userStore.userInfo?.nick_name"
:description="userStore.userInfo?.email"
:tag-text="userStore.userInfo?.roles?.name"
@clear-preferences-and-logout="handleLogout"
@logout="handleLogout" @logout="handleLogout"
/> />
</div> </div>
@@ -262,12 +280,54 @@ watch(
<template #notification> <template #notification>
<Notification <Notification
:dot="showDot" :dot="showDot"
:count="unreadCount"
:notifications="notifications" :notifications="notifications"
@clear="handleNoticeClear" @clear="handleNoticeClear"
@make-all="handleMakeAll" @make-all="handleMakeAll"
@read="handleItemClick" @read="handleMarkRead"
@view-all="goNoticeList" @view-all="goNoticeList"
@on-click="handleClick"
>
<template #content="{ item }">
<span
v-if="!item.isRead"
class="absolute top-2 right-2 size-2 rounded-sm bg-primary"
></span>
<span
class="relative flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-xl"
:class="[(item as any).colorBg || 'bg-muted', (item as any).color]"
>
<VbenIcon
v-if="(item as any).type_icon"
:icon="(item as any).type_icon"
class="size-5"
/> />
<Bell v-else class="size-5" />
</span>
<div class="min-w-0 flex-1 pr-8 leading-none">
<div class="mb-1 flex items-center gap-2">
<span
v-if="(item as any).type_name"
class="truncate text-[11px] font-semibold"
:class="(item as any).color"
>
{{ (item as any).type_name }}
</span>
</div>
<p class="truncate text-sm font-semibold text-foreground">
{{ item.title }}
</p>
<p
v-if="item.message"
class="mt-1 line-clamp-2 text-xs text-muted-foreground"
>
{{ item.message }}
</p>
<p class="mt-1 text-xs text-muted-foreground">{{ item.date }}</p>
</div>
</template>
</Notification>
<NoticeActionHost />
</template> </template>
<template #extra> <template #extra>
<AuthenticationLoginExpiredModal <AuthenticationLoginExpiredModal

View File

@@ -1,7 +1,9 @@
import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
import type { Locale } from 'ant-design-vue/es/locale'; import type { Locale } from 'ant-design-vue/es/locale';
import type { App } from 'vue'; import type { App } from 'vue';
import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
import { ref } from 'vue'; import { ref } from 'vue';
import { import {

View File

@@ -6,7 +6,9 @@
"about": "About", "about": "About",
"document": "Document", "document": "Document",
"antdv": "Ant Design Vue Version", "antdv": "Ant Design Vue Version",
"antdv-next": "Antdv Next Version",
"naive-ui": "Naive UI Version", "naive-ui": "Naive UI Version",
"element-plus": "Element Plus Version" "element-plus": "Element Plus Version",
"tdesign": "TDesign Vue Version"
} }
} }

View File

@@ -4,7 +4,8 @@
"register": "Register", "register": "Register",
"codeLogin": "Code Login", "codeLogin": "Code Login",
"qrcodeLogin": "Qr Code Login", "qrcodeLogin": "Qr Code Login",
"forgetPassword": "Forget Password" "forgetPassword": "Forget Password",
"profile": "Profile"
}, },
"dashboard": { "dashboard": {
"title": "Dashboard", "title": "Dashboard",

View File

@@ -6,7 +6,9 @@
"about": "关于", "about": "关于",
"document": "文档", "document": "文档",
"antdv": "Ant Design Vue 版本", "antdv": "Ant Design Vue 版本",
"antdv-next": "Antdv Next 版本",
"naive-ui": "Naive UI 版本", "naive-ui": "Naive UI 版本",
"element-plus": "Element Plus 版本" "element-plus": "Element Plus 版本",
"tdesign": "TDesign Vue 版本"
} }
} }

View File

@@ -4,7 +4,8 @@
"register": "注册", "register": "注册",
"codeLogin": "验证码登录", "codeLogin": "验证码登录",
"qrcodeLogin": "二维码登录", "qrcodeLogin": "二维码登录",
"forgetPassword": "忘记密码" "forgetPassword": "忘记密码",
"profile": "个人中心"
}, },
"dashboard": { "dashboard": {
"title": "概览", "title": "概览",

View File

@@ -1,7 +1,7 @@
import { initPreferences } from '@vben/preferences'; import { initPreferences } from '@vben/preferences';
import { unmountGlobalLoading } from '@vben/utils'; import { unmountGlobalLoading } from '@vben/utils';
import { overridesPreferences } from './preferences'; import { overridesPreferences, preferencesExtension } from './preferences';
// eslint-disable-next-line n/no-extraneous-import // eslint-disable-next-line n/no-extraneous-import
import '@fortawesome/fontawesome-free/css/all.min.css'; import '@fortawesome/fontawesome-free/css/all.min.css';
@@ -18,6 +18,7 @@ async function initApplication() {
// app偏好设置初始化 // app偏好设置初始化
await initPreferences({ await initPreferences({
extension: preferencesExtension,
namespace, namespace,
overrides: overridesPreferences, overrides: overridesPreferences,
}); });

View File

@@ -1,4 +1,3 @@
import { defineOverridesPreferences } from '@vben/preferences';
// { // {
// "app": { // "app": {
// "layout": "sidebar-nav" // "layout": "sidebar-nav"
@@ -8,6 +7,19 @@ import { defineOverridesPreferences } from '@vben/preferences';
// "enable": false // "enable": false
// } // }
// } // }
import {
appCopyrightPreferences,
defineOverridesPreferences,
definePreferencesExtension,
} from '@vben/preferences';
interface WebAntdPreferencesExtension {
defaultTableSize: number;
enableFormFullscreen: boolean;
reportTitle: string;
tenantMode: 'multi' | 'single';
}
/** /**
* @description 项目配置文件 * @description 项目配置文件
* 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置 * 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置
@@ -80,4 +92,54 @@ export const overridesPreferences = defineOverridesPreferences({
tabbar: { tabbar: {
enable: true, enable: true,
}, },
copyright: appCopyrightPreferences,
});
export const preferencesExtension =
definePreferencesExtension<WebAntdPreferencesExtension>({
tabLabel: 'preferences.antd.tabLabel',
title: 'preferences.antd.title',
fields: [
{
component: 'switch',
defaultValue: true,
key: 'enableFormFullscreen',
label: 'preferences.antd.fields.enableFormFullscreen.label',
tip: 'preferences.antd.fields.enableFormFullscreen.tip',
},
{
component: 'select',
defaultValue: 'single',
key: 'tenantMode',
label: 'preferences.antd.fields.tenantMode.label',
options: [
{
label: 'preferences.antd.fields.tenantMode.options.single.label',
value: 'single',
},
{
label: 'preferences.antd.fields.tenantMode.options.multi.label',
value: 'multi',
},
],
},
{
component: 'number',
componentProps: {
max: 200,
min: 10,
step: 10,
},
defaultValue: 20,
key: 'defaultTableSize',
label: 'preferences.antd.fields.defaultTableSize.label',
},
{
component: 'input',
defaultValue: '',
key: 'reportTitle',
label: 'preferences.antd.fields.reportTitle.label',
placeholder: 'preferences.antd.fields.reportTitle.placeholder',
},
],
}); });

View File

@@ -18,7 +18,7 @@ function setupCommonGuard(router: Router) {
// 记录已经加载的页面 // 记录已经加载的页面
const loadedPaths = new Set<string>(); const loadedPaths = new Set<string>();
router.beforeEach(async (to) => { router.beforeEach((to) => {
to.meta.loaded = loadedPaths.has(to.path); to.meta.loaded = loadedPaths.has(to.path);
// 页面加载进度条 // 页面加载进度条

View File

@@ -1,11 +1,12 @@
import type { RouteRecordRaw } from 'vue-router'; import type { RouteRecordRaw } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; import { LOGIN_PATH } from '@vben/constants';
import { preferences } from '@vben/preferences';
import { AuthPageLayout } from '#/layouts';
import { $t } from '#/locales'; import { $t } from '#/locales';
import Login from '#/views/_core/authentication/login.vue';
const BasicLayout = () => import('#/layouts/basic.vue');
const AuthPageLayout = () => import('#/layouts/auth.vue');
/** 全局404页面 */ /** 全局404页面 */
const fallbackNotFoundRoute: RouteRecordRaw = { const fallbackNotFoundRoute: RouteRecordRaw = {
component: () => import('#/views/_core/fallback/not-found.vue'), component: () => import('#/views/_core/fallback/not-found.vue'),
@@ -21,13 +22,21 @@ const fallbackNotFoundRoute: RouteRecordRaw = {
/** 基本路由,这些路由是必须存在的 */ /** 基本路由,这些路由是必须存在的 */
const coreRoutes: RouteRecordRaw[] = [ const coreRoutes: RouteRecordRaw[] = [
/**
* 根路由
* 使用基础布局作为所有页面的父级容器子级就不必配置BasicLayout。
* 此路由必须存在,且不应修改
*/
{ {
component: BasicLayout,
meta: { meta: {
hideInBreadcrumb: true,
title: 'Root', title: 'Root',
}, },
name: 'Root', name: 'Root',
path: '/', path: '/',
redirect: DEFAULT_HOME_PATH, redirect: preferences.app.defaultHomePath,
children: [],
}, },
{ {
component: AuthPageLayout, component: AuthPageLayout,
@@ -42,7 +51,7 @@ const coreRoutes: RouteRecordRaw[] = [
{ {
name: 'Login', name: 'Login',
path: 'login', path: 'login',
component: Login, component: () => import('#/views/_core/authentication/login.vue'),
meta: { meta: {
title: $t('page.auth.login'), title: $t('page.auth.login'),
}, },

View File

@@ -1,22 +1,20 @@
import type { RouteRecordRaw } from 'vue-router'; import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
import { $t } from '#/locales'; import { $t } from '#/locales';
const routes: RouteRecordRaw[] = [ const routes: RouteRecordRaw[] = [
{ {
component: BasicLayout,
meta: { meta: {
icon: 'lucide:layout-dashboard', icon: 'lucide:layout-dashboard',
order: -1, order: -1,
title: $t('page.dashboard.title'), title: $t('page.dashboard.title'),
}, },
name: 'Dashboard', name: 'Dashboard',
path: '/', path: '/dashboard',
children: [ children: [
{ {
name: 'Analytics', name: 'Analytics',
path: '/analytics', path: 'analytics',
component: () => import('#/views/dashboard/analytics/index.vue'), component: () => import('#/views/dashboard/analytics/index.vue'),
meta: { meta: {
affixTab: true, affixTab: true,
@@ -26,7 +24,7 @@ const routes: RouteRecordRaw[] = [
}, },
{ {
name: 'Workspace', name: 'Workspace',
path: '/workspace', path: 'workspace',
component: () => import('#/views/dashboard/workspace/index.vue'), component: () => import('#/views/dashboard/workspace/index.vue'),
meta: { meta: {
icon: 'carbon:workspace', icon: 'carbon:workspace',

View File

@@ -1,40 +1,33 @@
import type { RouteRecordRaw } from 'vue-router'; import type { RouteRecordRaw } from 'vue-router';
import { import {
VBEN_ANTDV_NEXT_PREVIEW_URL,
VBEN_DOC_URL, VBEN_DOC_URL,
VBEN_ELE_PREVIEW_URL, VBEN_ELE_PREVIEW_URL,
VBEN_GITHUB_URL, VBEN_GITHUB_URL,
VBEN_LOGO_URL, VBEN_LOGO_URL,
VBEN_NAIVE_PREVIEW_URL, VBEN_NAIVE_PREVIEW_URL,
VBEN_TD_PREVIEW_URL,
} from '@vben/constants'; } from '@vben/constants';
import { SvgAntdvNextLogoIcon, SvgTDesignIcon } from '@vben/icons';
import { BasicLayout, IFrameView } from '#/layouts'; import { IFrameView } from '#/layouts';
import { $t } from '#/locales'; import { $t } from '#/locales';
const routes: RouteRecordRaw[] = [ const routes: RouteRecordRaw[] = [
{ {
component: BasicLayout,
meta: { meta: {
badgeType: 'dot', badgeType: 'dot',
icon: VBEN_LOGO_URL, icon: VBEN_LOGO_URL,
order: 9999, order: 9998,
title: $t('demos.vben.title'), title: $t('demos.vben.title'),
}, },
name: 'VbenProject', name: 'VbenProject',
path: '/vben-admin', path: '/vben-admin',
children: [ children: [
{
name: 'VbenAbout',
path: '/vben-admin/about',
component: () => import('#/views/_core/about/index.vue'),
meta: {
icon: 'lucide:copyright',
title: $t('demos.vben.about'),
},
},
{ {
name: 'VbenDocument', name: 'VbenDocument',
path: '/vben-admin/document', path: 'document',
component: IFrameView, component: IFrameView,
meta: { meta: {
icon: 'lucide:book-open-text', icon: 'lucide:book-open-text',
@@ -44,7 +37,7 @@ const routes: RouteRecordRaw[] = [
}, },
{ {
name: 'VbenGithub', name: 'VbenGithub',
path: '/vben-admin/github', path: 'github',
component: IFrameView, component: IFrameView,
meta: { meta: {
icon: 'mdi:github', icon: 'mdi:github',
@@ -52,9 +45,20 @@ const routes: RouteRecordRaw[] = [
title: 'Github', title: 'Github',
}, },
}, },
{
name: 'VbenAntdVNext',
path: 'antdv-next',
component: IFrameView,
meta: {
badgeType: 'dot',
icon: SvgAntdvNextLogoIcon,
link: VBEN_ANTDV_NEXT_PREVIEW_URL,
title: $t('demos.vben.antdv-next'),
},
},
{ {
name: 'VbenNaive', name: 'VbenNaive',
path: '/vben-admin/naive', path: 'naive',
component: IFrameView, component: IFrameView,
meta: { meta: {
badgeType: 'dot', badgeType: 'dot',
@@ -63,9 +67,20 @@ const routes: RouteRecordRaw[] = [
title: $t('demos.vben.naive-ui'), title: $t('demos.vben.naive-ui'),
}, },
}, },
{
name: 'VbenTDesign',
path: 'tdesign',
component: IFrameView,
meta: {
badgeType: 'dot',
icon: SvgTDesignIcon,
link: VBEN_TD_PREVIEW_URL,
title: $t('demos.vben.tdesign'),
},
},
{ {
name: 'VbenElementPlus', name: 'VbenElementPlus',
path: '/vben-admin/ele', path: 'ele',
component: IFrameView, component: IFrameView,
meta: { meta: {
badgeType: 'dot', badgeType: 'dot',
@@ -76,6 +91,26 @@ const routes: RouteRecordRaw[] = [
}, },
], ],
}, },
{
name: 'VbenAbout',
path: '/vben-admin/about',
component: () => import('#/views/_core/about/index.vue'),
meta: {
icon: 'lucide:copyright',
title: $t('demos.vben.about'),
order: 9999,
},
},
{
name: 'Profile',
path: '/profile',
component: () => import('#/views/_core/profile/index.vue'),
meta: {
icon: 'lucide:user',
hideInMenu: true,
title: $t('page.auth.profile'),
},
},
]; ];
export default routes; export default routes;

View File

@@ -3,6 +3,7 @@ import type { Recordable, UserInfo } from '@vben/types';
import { ref } from 'vue'; import { ref } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { preferences } from '@vben/preferences';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { useWatermark } from '@vben/hooks'; import { useWatermark } from '@vben/hooks';
import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'; import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
@@ -32,6 +33,7 @@ export const useAuthStore = defineStore('auth', () => {
params: Recordable<any>, params: Recordable<any>,
onSuccess?: () => Promise<void> | void, onSuccess?: () => Promise<void> | void,
) { ) {
// 异步处理用户登录操作并获取 accessToken
let userInfo: null | UserInfo = null; let userInfo: null | UserInfo = null;
try { try {
loginLoading.value = true; loginLoading.value = true;

View File

@@ -144,3 +144,58 @@ export function useVipPermission(
export function useVipGate() { export function useVipGate() {
return useVipPermission(); return useVipPermission();
} }
/**
* 格式化 VIP 到期时间文案(列表/弹窗共用)
* @param vip 门店 VIP 信息
* @param options.emptyText 普通会员/无数据时的文案,默认空串
* @param options.lifetimeText 终身文案,默认「终身」
* @param options.withPrefix 是否加「至」前缀(非终身时)
*/
export function formatVipExpireAt(
vip?: StoreVipInfo | Record<string, any> | null,
options?: {
emptyText?: string;
lifetimeText?: string;
withPrefix?: boolean;
},
): string {
const emptyText = options?.emptyText ?? '';
const lifetimeText = options?.lifetimeText ?? '终身';
const withPrefix = options?.withPrefix ?? false;
if (!vip) return emptyText;
const code = String(vip.level_code || 'V0').trim() || 'V0';
if (code === 'V0') return emptyText;
if (vip.is_lifetime) return lifetimeText;
const raw = vip.expire_at as unknown;
if (raw == null || raw === '' || raw === 0) {
// 无到期日且非 V0按终身展示与列表列逻辑一致
return lifetimeText;
}
// 后端偶发已格式化成 Y-m-d H:i:s
if (typeof raw === 'string' && Number.isNaN(Number(raw))) {
return withPrefix ? `${raw}` : raw;
}
const n = Number(raw);
if (!(n > 0)) return lifetimeText;
const d = new Date(n * 1000);
if (Number.isNaN(d.getTime())) return emptyText;
const pad = (x: number) => String(x).padStart(2, '0');
const text = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
return withPrefix ? `${text}` : text;
}
/**
* 列表副文案:时长类型 + 到期(如「月卡 · 至 2026-08-10 …」)
*/
export function formatVipDurationExpireLine(
vip?: StoreVipInfo | Record<string, any> | null,
): string {
if (!vip) return '点击管理';
const code = String(vip.level_code || 'V0').trim() || 'V0';
if (code === 'V0') return '点击管理';
const duration = String(vip.duration_label || '').trim();
const expire = formatVipExpireAt(vip, { withPrefix: true, lifetimeText: '终身' });
if (duration && expire) return `${duration} · ${expire}`;
return duration || expire || '点击管理';
}

View File

@@ -53,8 +53,7 @@ const formSchema = computed((): VbenFormSchema[] => {
* @param values 登录表单数据 * @param values 登录表单数据
*/ */
async function handleLogin(values: Recordable<any>) { async function handleLogin(values: Recordable<any>) {
// eslint-disable-next-line no-console void values;
console.log(values);
} }
</script> </script>

View File

@@ -29,8 +29,7 @@ const formSchema = computed((): VbenFormSchema[] => {
}); });
function handleSubmit(value: Recordable<any>) { function handleSubmit(value: Recordable<any>) {
// eslint-disable-next-line no-console void value;
console.log('reset email:', value);
} }
</script> </script>

View File

@@ -46,7 +46,7 @@ const formSchema = computed((): VbenFormSchema[] => {
rules(values) { rules(values) {
const { password } = values; const { password } = values;
return z return z
.string({ required_error: $t('authentication.passwordTip') }) .string({ error: $t('authentication.passwordTip') })
.min(1, { message: $t('authentication.passwordTip') }) .min(1, { message: $t('authentication.passwordTip') })
.refine((value) => value === password, { .refine((value) => value === password, {
message: $t('authentication.confirmPasswordTip'), message: $t('authentication.confirmPasswordTip'),
@@ -82,8 +82,7 @@ const formSchema = computed((): VbenFormSchema[] => {
}); });
function handleSubmit(value: Recordable<any>) { function handleSubmit(value: Recordable<any>) {
// eslint-disable-next-line no-console void value;
console.log('register submit:', value);
} }
</script> </script>

View File

@@ -0,0 +1,20 @@
import { requestClient } from '#/api/request';
// 个人中心接口(后端 routes/admin.php 的 auth 分组AdminController → common AdminProfileService
const prefix = 'auth/';
/**
* 获取我的个人中心资料
* 与 auth/my-infoRedis 会话快照)不同,这里返回实时库数据 + 只读展示字段(登录账号/所属门店/最后登录时间等)
*/
export async function getMyProfile() {
return requestClient.get<any>(`${prefix}my-profile`);
}
/**
* 修改我的资料(后端白名单:仅昵称 nick_name、头像 avatar
* 保存成功后后端会同步刷新 Redis 会话,前端只需重拉 my-info 即可让顶栏生效
*/
export async function updateMyProfile(data: any) {
return requestClient.post<any>(`${prefix}update-my-profile`, data);
}

View File

@@ -0,0 +1,184 @@
<script setup lang="ts">
/**
* 个人中心 - 基本资料
* 可编辑:头像(复用表单 Avatar 上传组件)、昵称(与后端 update-my-profile 白名单一致)
* 只读展示:登录账号/手机号/角色/所属门店/最后登录时间等(账号身份信息不允许自助修改)
* 保存成功后重拉 my-info 刷新全局登录态,顶栏/工作台头像昵称立即生效
*/
import { computed, ref, watch } from 'vue';
import { Button, message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { useAuthStore } from '#/store/auth';
import { updateMyProfile } from './api';
const props = defineProps({
profile: {
type: Object,
default: () => ({}),
},
});
const emits = defineEmits(['saved']);
const authStore = useAuthStore();
/** 可编辑字段表单:仅头像 + 昵称,其余字段一律只读展示 */
const [Form, formApi] = useVbenForm({
wrapperClass: 'grid-cols-12',
commonConfig: {
formItemClass: 'col-span-12',
labelWidth: 80,
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
component: 'Avatar',
fieldName: 'avatar',
label: '头像',
},
{
component: 'VbenInput',
fieldName: 'nick_name',
label: '昵称',
rules: 'required',
componentProps: {
placeholder: '请输入昵称',
maxlength: 20,
},
},
],
showDefaultActions: false,
});
// 父组件拉取到实时资料后回填表单(保存成功刷新后同样走这里)
watch(
() => props.profile,
(val: any) => {
if (val && val.id) {
formApi.setValues({
avatar: val.avatar,
nick_name: val.nick_name,
});
}
},
{ deep: true, immediate: true },
);
/** 只读信息行:为空的可选字段(门店/工号/邮箱)不展示,避免一排「-」 */
const readonlyRows = computed(() => {
const p: any = props.profile || {};
const rows: { label: string; value: string }[] = [
{ label: '登录账号', value: p.login_account },
{ label: '手机号', value: p.phone },
{ label: '角色', value: p.role_name },
];
if (p.store_name) {
rows.push({ label: '所属门店', value: p.store_name });
}
if (p.job_number) {
rows.push({ label: '工号', value: p.job_number });
}
if (p.email) {
rows.push({ label: '邮箱', value: p.email });
}
rows.push({ label: '最后登录', value: p.last_login_time });
rows.push({ label: '创建时间', value: p.created_at });
return rows.map((row) => ({ ...row, value: row.value || '-' }));
});
const saving = ref(false);
/**
* 保存资料:校验 → 提交白名单字段 → 重拉全局登录态 → 通知父组件刷新
* 为什么要 fetchUserInfo后端已刷新 Redis 会话,前端重拉 my-info 才能让顶栏/工作台立即显示新头像昵称
*/
function handleSave() {
formApi.validate().then(async (e: any) => {
if (!e.valid) return;
const values = await formApi.getValues();
saving.value = true;
try {
await updateMyProfile({
nick_name: values.nick_name,
avatar: values.avatar || '',
});
message.success('保存成功');
await authStore.fetchUserInfo();
emits('saved');
} finally {
saving.value = false;
}
});
}
</script>
<template>
<div class="profile-base w-full lg:w-2/3">
<Form />
<Button type="primary" :loading="saving" @click="handleSave">
保存资料
</Button>
<div class="profile-base__section-title">账号信息</div>
<div class="profile-base__grid">
<div
v-for="row in readonlyRows"
:key="row.label"
class="profile-base__row"
>
<span class="profile-base__label">{{ row.label }}</span>
<span class="profile-base__value">{{ row.value }}</span>
</div>
</div>
</div>
</template>
<style scoped>
/* 只读信息区:全部走主题变量,暗色模式自动适配 */
.profile-base__section-title {
padding-bottom: 10px;
margin-top: 28px;
margin-bottom: 4px;
font-size: 14px;
font-weight: 600;
color: hsl(var(--foreground));
border-bottom: 1px solid hsl(var(--border));
}
.profile-base__grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0 24px;
}
.profile-base__row {
display: flex;
gap: 12px;
align-items: center;
padding: 10px 0;
border-bottom: 1px dashed hsl(var(--border) / 0.6);
}
.profile-base__label {
flex-shrink: 0;
width: 72px;
font-size: 13px;
color: hsl(var(--muted-foreground));
}
.profile-base__value {
overflow: hidden;
font-size: 13px;
color: hsl(var(--foreground));
text-overflow: ellipsis;
white-space: nowrap;
}
@media (max-width: 768px) {
.profile-base__grid {
grid-template-columns: 1fr;
}
}
</style>

View File

@@ -0,0 +1,67 @@
<script setup lang="ts">
/**
* 个人中心:左侧账号卡(头像/昵称/角色)+ 右侧 Tab基本资料 / 修改密码)
* 入口:顶栏头像下拉「个人中心」、工作台问候头;静态路由 /profilehideInMenu不走 xk_menu
* 资料数据统一从 auth/my-profile 实时接口拉取,子组件保存成功后回调刷新
*/
import { computed, onMounted, ref } from 'vue';
import { Profile } from '@vben/common-ui';
import { getMyProfile } from './api';
import ProfileBase from './base-setting.vue';
import ProfilePasswordSetting from './password-setting.vue';
const tabsValue = ref<string>('basic');
const tabs = ref([
{
label: '基本资料',
value: 'basic',
},
{
label: '修改密码',
value: 'password',
},
]);
/** 个人中心资料basic tab 编辑 + 左侧账号卡展示共用一份数据) */
const profile = ref<any>({});
/**
* 左侧账号卡数据映射
* Profile 壳组件展示 realName大字与 username小字这里映射为 昵称 + 角色名
* avatar 为空时必须传 undefined不能传空串Profile 内部才会 ?? 兜底系统默认头像
*/
const cardUserInfo = computed(() => ({
avatar: profile.value.avatar || undefined,
nick_name: profile.value.nick_name || '',
userId: String(profile.value.id || ''),
username: profile.value.role_name || '',
realName: profile.value.nick_name || '',
}));
/** 拉取实时资料(初始化 + 保存成功后刷新) */
async function loadProfile() {
profile.value = (await getMyProfile()) || {};
}
onMounted(loadProfile);
</script>
<template>
<Profile
v-model:model-value="tabsValue"
title="个人中心"
:user-info="cardUserInfo"
:tabs="tabs"
>
<template #content>
<ProfileBase
v-if="tabsValue === 'basic'"
:profile="profile"
@saved="loadProfile"
/>
<ProfilePasswordSetting v-if="tabsValue === 'password'" />
</template>
</Profile>
</template>

View File

@@ -0,0 +1,50 @@
<script setup lang="ts">
/**
* 个人中心 - 修改密码
* 复用顶栏「修改密码」弹窗同一份表单配置layouts/config/form.ts 的 passwordModalForm
* 与同一个接口admin/update-password保证两个入口口径完全一致不重复造轮子
*/
import { ref } from 'vue';
import { Button, message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { passwordModalForm } from '#/layouts/config/form';
import { updatePassword } from '#/views/system/admin/api';
const [Form, formApi] = useVbenForm(passwordModalForm);
const submitting = ref(false);
/**
* 提交改密:校验 → 调 admin/update-password → 清空表单
* 成功提示与顶栏弹窗一致token 仍有效,下次登录使用新密码)
*/
function handleSubmit() {
formApi.validate().then(async (e: any) => {
if (!e.valid) return;
const values = await formApi.getValues();
submitting.value = true;
try {
await updatePassword(values);
message.success('修改成功,请重新登录');
formApi.resetForm();
} finally {
submitting.value = false;
}
});
}
</script>
<template>
<div class="w-full lg:w-1/2">
<Form />
<Button
class="mt-4"
type="primary"
:loading="submitting"
@click="handleSubmit"
>
修改密码
</Button>
</div>
</template>

View File

@@ -56,7 +56,7 @@ export const gridOptions: VxeGridProps<RowType> = {
// custom: true, // 自定义列 // custom: true, // 自定义列
zoom: true, // 最大化最小化 zoom: true, // 最大化最小化
slots: { slots: {
buttons: 'toolbar-buttons', buttons: 'toolbar-actions',
}, },
custom: { custom: {
// 自定义列-图标 // 自定义列-图标

View File

@@ -68,7 +68,7 @@ const deleteApi = (row: any) => {
<Page auto-content-height title="快递公司管理"> <Page auto-content-height title="快递公司管理">
<FormModal /> <FormModal />
<Grid> <Grid>
<template #toolbar-buttons> <template #toolbar-actions>
<TableAction <TableAction
:actions="[ :actions="[
{ {

View File

@@ -74,7 +74,7 @@ export const gridOptions: VxeGridProps<RowType> = {
// custom: true, // 自定义列 // custom: true, // 自定义列
zoom: true, // 最大化最小化 zoom: true, // 最大化最小化
slots: { slots: {
buttons: 'toolbar-buttons', buttons: 'toolbar-actions',
}, },
custom: { custom: {
// 自定义列-图标 // 自定义列-图标

View File

@@ -102,7 +102,7 @@ const openPrescriptionSourceModal = (id: number) => {
</Tabs> </Tabs>
</div> </div>
<Grid> <Grid>
<template #toolbar-buttons> <template #toolbar-actions>
<TableAction :actions="[]" :drop-down-actions="[]"> <TableAction :actions="[]" :drop-down-actions="[]">
<template #more> <template #more>
<Button style="margin-left: 16px"> <Button style="margin-left: 16px">

View File

@@ -121,7 +121,7 @@ export const gridOptions: VxeGridProps<RowType> = {
export: false, export: false,
zoom: true, zoom: true,
slots: { slots: {
buttons: 'toolbar-buttons', buttons: 'toolbar-actions',
}, },
custom: { custom: {
icon: 'vxe-icon-menu', icon: 'vxe-icon-menu',

View File

@@ -867,9 +867,9 @@ const openOrderAmountVerify = () => {
<PrescriptionDetailModal /> <PrescriptionDetailModal />
<TraceDrawer /> <TraceDrawer />
<ChinaErpSyncDrawer @synced="() => gridApi.query()" /> <ChinaErpSyncDrawer @synced="() => gridApi.query()" />
<AnalysisOverview :items="overviewItems" :my-card="false" /> <AnalysisOverview :items="overviewItems" />
<Grid> <Grid>
<template #toolbar-buttons> <template #toolbar-actions>
<TableAction <TableAction
:flex="false" :flex="false"
:actions="[ :actions="[

View File

@@ -68,7 +68,7 @@ export const gridOptions: VxeGridProps<RegisterOrderItem> = {
// custom: true, // 自定义列 // custom: true, // 自定义列
zoom: true, // 最大化最小化 zoom: true, // 最大化最小化
slots: { slots: {
buttons: 'toolbar-buttons', buttons: 'toolbar-actions',
}, },
custom: { custom: {
// 自定义列-图标 // 自定义列-图标

View File

@@ -121,7 +121,7 @@ function formatRegisterPrice(price: unknown) {
<RefundModal /> <RefundModal />
<StoreCardModalComp /> <StoreCardModalComp />
<Grid> <Grid>
<template #toolbar-buttons> <template #toolbar-actions>
<TableAction :actions="[]" :drop-down-actions="[]"> <TableAction :actions="[]" :drop-down-actions="[]">
<template #more> <template #more>
<Button style="margin-left: 16px"> <Button style="margin-left: 16px">

View File

@@ -69,7 +69,7 @@ export const gridOptions: VxeGridProps<RowType> = {
export: false, export: false,
zoom: true, zoom: true,
slots: { slots: {
buttons: 'toolbar-buttons', buttons: 'toolbar-actions',
}, },
custom: { custom: {
icon: 'vxe-icon-menu', icon: 'vxe-icon-menu',

View File

@@ -78,7 +78,7 @@ const deleteDictApi = (row: any) => {
/> />
<Grid> <Grid>
<template #toolbar-buttons> <template #toolbar-actions>
<Button <Button
v-if="hasTopTableDropDownActions" v-if="hasTopTableDropDownActions"
danger danger

View File

@@ -62,7 +62,7 @@ export const gridOptions: VxeGridProps<RowType> = {
// custom: true, // 自定义列 // custom: true, // 自定义列
zoom: true, // 最大化最小化 zoom: true, // 最大化最小化
slots: { slots: {
buttons: 'toolbar-buttons', buttons: 'toolbar-actions',
}, },
custom: { custom: {
// 自定义列-图标 // 自定义列-图标

View File

@@ -143,7 +143,7 @@ const openDrugNumberBatchModal = () => {
<DrugDetailModalComp /> <DrugDetailModalComp />
<FormModal /> <FormModal />
<Grid> <Grid>
<template #toolbar-buttons> <template #toolbar-actions>
<TableAction <TableAction
:actions="[ :actions="[
{ {

View File

@@ -77,7 +77,7 @@ export const gridOptions: VxeGridProps<RowType> = {
export: false, export: false,
zoom: true, zoom: true,
slots: { slots: {
buttons: 'toolbar-buttons', buttons: 'toolbar-actions',
}, },
custom: { custom: {
icon: 'vxe-icon-menu', icon: 'vxe-icon-menu',

View File

@@ -77,7 +77,7 @@ const collapseAll = () => {
<Page auto-content-height title="商品分类管理"> <Page auto-content-height title="商品分类管理">
<FormModal /> <FormModal />
<Grid> <Grid>
<template #toolbar-buttons> <template #toolbar-actions>
<TableAction <TableAction
:flex="false" :flex="false"
:actions="[ :actions="[

View File

@@ -89,7 +89,7 @@ export const gridOptions: VxeGridProps<RowType> = {
export: false, export: false,
zoom: true, zoom: true,
slots: { slots: {
buttons: 'toolbar-buttons', buttons: 'toolbar-actions',
}, },
custom: { custom: {
icon: 'vxe-icon-menu', icon: 'vxe-icon-menu',

View File

@@ -280,7 +280,7 @@ const openExcelUploadModal = () => {
<CentralStockInModalComp /> <CentralStockInModalComp />
<WarehousePriceModalComp /> <WarehousePriceModalComp />
<Grid> <Grid>
<template #toolbar-buttons> <template #toolbar-actions>
<TableAction <TableAction
:flex="false" :flex="false"
:actions="[ :actions="[

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