diff --git a/apps/web-antd/src/locales/langs/en-US/demos.json b/apps/web-antd/src/locales/langs/en-US/demos.json
index 12a3b718..859718e1 100644
--- a/apps/web-antd/src/locales/langs/en-US/demos.json
+++ b/apps/web-antd/src/locales/langs/en-US/demos.json
@@ -6,6 +6,7 @@
"about": "About",
"document": "Document",
"antdv": "Ant Design Vue Version",
+ "antdv-next": "Antdv Next Version",
"naive-ui": "Naive UI Version",
"element-plus": "Element Plus Version",
"tdesign": "TDesign Vue Version"
diff --git a/apps/web-antd/src/locales/langs/zh-CN/demos.json b/apps/web-antd/src/locales/langs/zh-CN/demos.json
index b5007ea7..29910cdf 100644
--- a/apps/web-antd/src/locales/langs/zh-CN/demos.json
+++ b/apps/web-antd/src/locales/langs/zh-CN/demos.json
@@ -6,6 +6,7 @@
"about": "关于",
"document": "文档",
"antdv": "Ant Design Vue 版本",
+ "antdv-next": "Antdv Next 版本",
"naive-ui": "Naive UI 版本",
"element-plus": "Element Plus 版本",
"tdesign": "TDesign Vue 版本"
diff --git a/apps/web-antd/src/router/routes/modules/vben.ts b/apps/web-antd/src/router/routes/modules/vben.ts
index 631facc0..283d83e5 100644
--- a/apps/web-antd/src/router/routes/modules/vben.ts
+++ b/apps/web-antd/src/router/routes/modules/vben.ts
@@ -1,6 +1,7 @@
import type { RouteRecordRaw } from 'vue-router';
import {
+ VBEN_ANTDV_NEXT_PREVIEW_URL,
VBEN_DOC_URL,
VBEN_ELE_PREVIEW_URL,
VBEN_GITHUB_URL,
@@ -8,7 +9,7 @@ import {
VBEN_NAIVE_PREVIEW_URL,
VBEN_TD_PREVIEW_URL,
} from '@vben/constants';
-import { SvgTDesignIcon } from '@vben/icons';
+import { SvgAntdvNextLogoIcon, SvgTDesignIcon } from '@vben/icons';
import { IFrameView } from '#/layouts';
import { $t } from '#/locales';
@@ -44,6 +45,17 @@ const routes: RouteRecordRaw[] = [
title: 'Github',
},
},
+ {
+ name: 'VbenAntdVNext',
+ path: '/vben-admin/antdv-next',
+ component: IFrameView,
+ meta: {
+ badgeType: 'dot',
+ icon: SvgAntdvNextLogoIcon,
+ link: VBEN_ANTDV_NEXT_PREVIEW_URL,
+ title: $t('demos.vben.antdv-next'),
+ },
+ },
{
name: 'VbenNaive',
path: '/vben-admin/naive',
diff --git a/apps/web-antdv-next/.env b/apps/web-antdv-next/.env
new file mode 100644
index 00000000..40b046d2
--- /dev/null
+++ b/apps/web-antdv-next/.env
@@ -0,0 +1,8 @@
+# 应用标题
+VITE_APP_TITLE=Vben Admin Antdv Next
+
+# 应用命名空间,用于缓存、store等功能的前缀,确保隔离
+VITE_APP_NAMESPACE=vben-web-antdv-next
+
+# 对store进行加密的密钥,在将store持久化到localStorage时会使用该密钥进行加密
+VITE_APP_STORE_SECURE_KEY=please-replace-me-with-your-own-key
diff --git a/apps/web-antdv-next/.env.analyze b/apps/web-antdv-next/.env.analyze
new file mode 100644
index 00000000..ffafa8dd
--- /dev/null
+++ b/apps/web-antdv-next/.env.analyze
@@ -0,0 +1,7 @@
+# public path
+VITE_BASE=/
+
+# Basic interface address SPA
+VITE_GLOB_API_URL=/api
+
+VITE_VISUALIZER=true
diff --git a/apps/web-antdv-next/.env.development b/apps/web-antdv-next/.env.development
new file mode 100644
index 00000000..f2b44428
--- /dev/null
+++ b/apps/web-antdv-next/.env.development
@@ -0,0 +1,16 @@
+# 端口号
+VITE_PORT=5999
+
+VITE_BASE=/
+
+# 接口地址
+VITE_GLOB_API_URL=/api
+
+# 是否开启 Nitro Mock服务,true 为开启,false 为关闭
+VITE_NITRO_MOCK=true
+
+# 是否打开 devtools,true 为打开,false 为关闭
+VITE_DEVTOOLS=false
+
+# 是否注入全局loading
+VITE_INJECT_APP_LOADING=true
diff --git a/apps/web-antdv-next/.env.production b/apps/web-antdv-next/.env.production
new file mode 100644
index 00000000..5375847a
--- /dev/null
+++ b/apps/web-antdv-next/.env.production
@@ -0,0 +1,19 @@
+VITE_BASE=/
+
+# 接口地址
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+
+# 是否开启压缩,可以设置为 none, brotli, gzip
+VITE_COMPRESS=none
+
+# 是否开启 PWA
+VITE_PWA=false
+
+# vue-router 的模式
+VITE_ROUTER_HISTORY=hash
+
+# 是否注入全局loading
+VITE_INJECT_APP_LOADING=true
+
+# 打包后是否生成dist.zip
+VITE_ARCHIVER=true
diff --git a/apps/web-antdv-next/index.html b/apps/web-antdv-next/index.html
new file mode 100644
index 00000000..480eb84d
--- /dev/null
+++ b/apps/web-antdv-next/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+ <%= VITE_APP_TITLE %>
+
+
+
+
+
+
+
+
diff --git a/apps/web-antdv-next/package.json b/apps/web-antdv-next/package.json
new file mode 100644
index 00000000..acbb5e95
--- /dev/null
+++ b/apps/web-antdv-next/package.json
@@ -0,0 +1,50 @@
+{
+ "name": "@vben/web-antdv-next",
+ "version": "5.5.9",
+ "homepage": "https://vben.pro",
+ "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+ "directory": "apps/web-antdv-next"
+ },
+ "license": "MIT",
+ "author": {
+ "name": "vben",
+ "email": "ann.vben@gmail.com",
+ "url": "https://github.com/anncwb"
+ },
+ "type": "module",
+ "scripts": {
+ "build": "pnpm vite build --mode production",
+ "build:analyze": "pnpm vite build --mode analyze",
+ "dev": "pnpm vite --mode development",
+ "preview": "vite preview",
+ "typecheck": "vue-tsc --noEmit --skipLibCheck"
+ },
+ "imports": {
+ "#/*": "./src/*"
+ },
+ "dependencies": {
+ "@vben/access": "workspace:*",
+ "@vben/common-ui": "workspace:*",
+ "@vben/constants": "workspace:*",
+ "@vben/hooks": "workspace:*",
+ "@vben/icons": "workspace:*",
+ "@vben/layouts": "workspace:*",
+ "@vben/locales": "workspace:*",
+ "@vben/plugins": "workspace:*",
+ "@vben/preferences": "workspace:*",
+ "@vben/request": "workspace:*",
+ "@vben/stores": "workspace:*",
+ "@vben/styles": "workspace:*",
+ "@vben/types": "workspace:*",
+ "@vben/utils": "workspace:*",
+ "@vueuse/core": "catalog:",
+ "antdv-next": "catalog:",
+ "dayjs": "catalog:",
+ "pinia": "catalog:",
+ "vue": "catalog:",
+ "vue-router": "catalog:"
+ }
+}
diff --git a/apps/web-antdv-next/postcss.config.mjs b/apps/web-antdv-next/postcss.config.mjs
new file mode 100644
index 00000000..3d807045
--- /dev/null
+++ b/apps/web-antdv-next/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/apps/web-antdv-next/public/favicon.ico b/apps/web-antdv-next/public/favicon.ico
new file mode 100644
index 00000000..fcf9818e
Binary files /dev/null and b/apps/web-antdv-next/public/favicon.ico differ
diff --git a/apps/web-antdv-next/src/adapter/component/index.ts b/apps/web-antdv-next/src/adapter/component/index.ts
new file mode 100644
index 00000000..4ce4f57a
--- /dev/null
+++ b/apps/web-antdv-next/src/adapter/component/index.ts
@@ -0,0 +1,603 @@
+/**
+ * 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用
+ * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
+ */
+
+/* eslint-disable vue/one-component-per-file */
+
+import type { UploadChangeParam, UploadFile, UploadProps } from 'antdv-next';
+
+import type { Component, Ref } from 'vue';
+
+import type { BaseFormComponentType } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import {
+ computed,
+ defineAsyncComponent,
+ defineComponent,
+ h,
+ ref,
+ render,
+ unref,
+ watch,
+} from 'vue';
+
+import {
+ ApiComponent,
+ globalShareState,
+ IconPicker,
+ VCropper,
+} from '@vben/common-ui';
+import { IconifyIcon } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { isEmpty } from '@vben/utils';
+
+import { message, Modal, notification } from 'antdv-next';
+
+const AutoComplete = defineAsyncComponent(
+ () => import('antdv-next/dist/auto-complete/index'),
+);
+const Button = defineAsyncComponent(
+ () => import('antdv-next/dist/button/index'),
+);
+const Checkbox = defineAsyncComponent(
+ () => import('antdv-next/dist/checkbox/index'),
+);
+const CheckboxGroup = defineAsyncComponent(
+ () => import('antdv-next/dist/checkbox/Group'),
+);
+const DatePicker = defineAsyncComponent(
+ () => import('antdv-next/dist/date-picker/index'),
+);
+const Divider = defineAsyncComponent(
+ () => import('antdv-next/dist/divider/index'),
+);
+const Input = defineAsyncComponent(() => import('antdv-next/dist/input/index'));
+const InputNumber = defineAsyncComponent(
+ () => import('antdv-next/dist/input-number/index'),
+);
+const InputPassword = defineAsyncComponent(() =>
+ import('antdv-next/dist/input/index').then((res) => res.InputPassword),
+);
+const Mentions = defineAsyncComponent(
+ () => import('antdv-next/dist/mentions/index'),
+);
+const Radio = defineAsyncComponent(() => import('antdv-next/dist/radio/index'));
+const RadioGroup = defineAsyncComponent(() =>
+ import('antdv-next/dist/radio/index').then((res) => res.RadioGroup),
+);
+const RangePicker = defineAsyncComponent(() =>
+ import('antdv-next/dist/date-picker/index').then(
+ (res) => res.DateRangePicker,
+ ),
+);
+const Rate = defineAsyncComponent(() => import('antdv-next/dist/rate/index'));
+const Select = defineAsyncComponent(
+ () => import('antdv-next/dist/select/index'),
+);
+const Space = defineAsyncComponent(() => import('antdv-next/dist/space/index'));
+const Switch = defineAsyncComponent(
+ () => import('antdv-next/dist/switch/index'),
+);
+const Textarea = defineAsyncComponent(
+ () => import('antdv-next/dist/input/TextArea'),
+);
+const TimePicker = defineAsyncComponent(
+ () => import('antdv-next/dist/time-picker/index'),
+);
+const TreeSelect = defineAsyncComponent(
+ () => import('antdv-next/dist/tree-select/index'),
+);
+const Cascader = defineAsyncComponent(
+ () => import('antdv-next/dist/cascader/index'),
+);
+const Upload = defineAsyncComponent(
+ () => import('antdv-next/dist/upload/index'),
+);
+const Image = defineAsyncComponent(() => import('antdv-next/dist/image/index'));
+const PreviewGroup = defineAsyncComponent(() =>
+ import('antdv-next/dist/image/index').then((res) => res.ImagePreviewGroup),
+);
+
+const withDefaultPlaceholder = (
+ component: T,
+ type: 'input' | 'select',
+ componentProps: Recordable = {},
+) => {
+ return defineComponent({
+ name: component.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 withPreviewUpload = () => {
+ // 检查是否为图片文件的辅助函数
+ const isImageFile = (file: UploadFile): boolean => {
+ const imageExtensions = new Set([
+ 'bmp',
+ 'gif',
+ 'jpeg',
+ 'jpg',
+ 'png',
+ 'svg',
+ 'webp',
+ ]);
+ if (file.url) {
+ try {
+ const pathname = new URL(file.url, 'http://localhost').pathname;
+ const ext = pathname.split('.').pop()?.toLowerCase();
+ return ext ? imageExtensions.has(ext) : false;
+ } catch {
+ const ext = file.url?.split('.').pop()?.toLowerCase();
+ return ext ? imageExtensions.has(ext) : false;
+ }
+ }
+ if (!file.type) {
+ const ext = file.name?.split('.').pop()?.toLowerCase();
+ return ext ? imageExtensions.has(ext) : false;
+ }
+ return file.type.startsWith('image/');
+ };
+ // 创建默认的上传按钮插槽
+ const createDefaultSlotsWithUpload = (
+ listType: string,
+ placeholder: string,
+ ) => {
+ switch (listType) {
+ case 'picture-card': {
+ return {
+ default: () => placeholder,
+ };
+ }
+ default: {
+ return {
+ default: () =>
+ h(
+ Button,
+ {
+ icon: h(IconifyIcon, {
+ icon: 'ant-design:upload-outlined',
+ class: 'mb-1 size-4',
+ }),
+ },
+ () => placeholder,
+ ),
+ };
+ }
+ }
+ };
+ // 构建预览图片组
+ const previewImage = async (
+ file: UploadFile,
+ visible: Ref,
+ fileList: Ref,
+ ) => {
+ // 如果当前文件不是图片,直接打开
+ if (!isImageFile(file)) {
+ if (file.url) {
+ window.open(file.url, '_blank');
+ } else if (file.preview) {
+ window.open(file.preview, '_blank');
+ } else {
+ message.error($t('ui.formRules.previewWarning'));
+ }
+ return;
+ }
+
+ // 对于图片文件,继续使用预览组
+ const [ImageComponent, PreviewGroupComponent] = await Promise.all([
+ Image,
+ PreviewGroup,
+ ]);
+
+ const getBase64 = (file: File) => {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.readAsDataURL(file);
+ reader.addEventListener('load', () => resolve(reader.result));
+ reader.addEventListener('error', (error) => reject(error));
+ });
+ };
+ // 从fileList中过滤出所有图片文件
+ const imageFiles = (unref(fileList) || []).filter((element) =>
+ isImageFile(element),
+ );
+
+ // 为所有没有预览地址的图片生成预览
+ for (const imgFile of imageFiles) {
+ if (!imgFile.url && !imgFile.preview && imgFile.originFileObj) {
+ imgFile.preview = (await getBase64(imgFile.originFileObj)) as string;
+ }
+ }
+ const container: HTMLElement | null = document.createElement('div');
+ document.body.append(container);
+
+ // 用于追踪组件是否已卸载
+ let isUnmounted = false;
+
+ const PreviewWrapper = {
+ setup() {
+ return () => {
+ if (isUnmounted) return null;
+ return h(
+ PreviewGroupComponent,
+ {
+ class: 'hidden',
+ preview: {
+ open: visible.value,
+ // 设置初始显示的图片索引
+ current: imageFiles.findIndex((f) => f.uid === file.uid),
+ onOpenChange: (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);
+ };
+
+ // 图片裁剪操作
+ const cropImage = (file: File, aspectRatio: string | undefined) => {
+ return new Promise((resolve, reject) => {
+ const container: HTMLElement | null = document.createElement('div');
+ document.body.append(container);
+
+ // 用于追踪组件是否已卸载
+ let isUnmounted = false;
+ let objectUrl: null | string = null;
+
+ const open = ref(true);
+ const cropperRef = ref | 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,
+ keyboard: false,
+ maskClosable: false,
+ closable: false,
+ cancelText: $t('common.cancel'),
+ okText: $t('ui.crop.confirm'),
+ destroyOnHidden: true,
+ onOk: async () => {
+ const cropper = cropperRef.value;
+ if (!cropper) {
+ reject(new Error('Cropper not found'));
+ closeModal();
+ return;
+ }
+ try {
+ const dataUrl = await cropper.getCropImage();
+ resolve(dataUrl);
+ } catch {
+ reject(new Error($t('ui.crop.errorTip')));
+ } finally {
+ closeModal();
+ }
+ },
+ onCancel() {
+ resolve('');
+ closeModal();
+ },
+ },
+ () =>
+ h(VCropper, {
+ ref: (ref: any) => (cropperRef.value = ref),
+ img: objectUrl as string,
+ aspectRatio,
+ }),
+ );
+ };
+ },
+ };
+
+ render(h(CropperWrapper), container);
+ });
+ };
+
+ return defineComponent({
+ name: 'AUpload',
+ emits: ['update:modelValue'],
+ setup: (
+ props: any,
+ { attrs, slots, emit }: { attrs: any; emit: any; slots: any },
+ ) => {
+ const previewVisible = ref(false);
+
+ const placeholder = attrs?.placeholder || $t(`ui.placeholder.upload`);
+
+ const listType = attrs?.listType || attrs?.['list-type'] || 'text';
+
+ const fileList = ref(
+ 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,
+ ) => {
+ 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';
+ // antd Upload组件问题 file参数获取的是UploadFile类型对象无法取到File类型 所以通过originFileList[0]获取
+ const blob = await cropImage(originFileList[0], aspectRatio.value);
+ return new Promise((resolve, reject) => {
+ if (!blob) {
+ return reject(new Error($t('ui.crop.errorTip')));
+ }
+ resolve(blob);
+ });
+ }
+
+ return attrs.beforeUpload?.(file) ?? true;
+ };
+
+ const handleChange = (event: UploadChangeParam) => {
+ try {
+ // 行内写法 handleChange: (event) => {}
+ attrs.handleChange?.(event);
+ // template写法 @handle-change="(event) => {}"
+ attrs.onHandleChange?.(event);
+ } catch (error) {
+ // Avoid breaking internal v-model sync on user handler errors
+ 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 = (): any => {
+ const isDisabled = attrs.disabled;
+
+ // 如果禁用,不渲染上传按钮
+ if (isDisabled) {
+ return null;
+ }
+
+ // 否则渲染默认上传按钮
+ return isEmpty(slots)
+ ? createDefaultSlotsWithUpload(listType, placeholder)
+ : slots;
+ };
+
+ // 可以监听到表单API设置的值
+ watch(
+ () => attrs.modelValue,
+ (res) => {
+ fileList.value = res;
+ },
+ );
+
+ return () =>
+ h(
+ Upload,
+ {
+ ...props,
+ ...attrs,
+ fileList: fileList.value,
+ beforeUpload: handleBeforeUpload,
+ onChange: handleChange,
+ onPreview: handlePreview,
+ },
+ renderUploadButton(),
+ );
+ },
+ });
+};
+
+// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
+export type ComponentType =
+ | 'ApiCascader'
+ | 'ApiSelect'
+ | 'ApiTreeSelect'
+ | 'AutoComplete'
+ | 'Cascader'
+ | 'Checkbox'
+ | 'CheckboxGroup'
+ | 'DatePicker'
+ | 'DefaultButton'
+ | 'Divider'
+ | 'IconPicker'
+ | 'Input'
+ | 'InputNumber'
+ | 'InputPassword'
+ | 'Mentions'
+ | 'PrimaryButton'
+ | 'Radio'
+ | 'RadioGroup'
+ | 'RangePicker'
+ | 'Rate'
+ | 'Select'
+ | 'Space'
+ | 'Switch'
+ | 'Textarea'
+ | 'TimePicker'
+ | 'TreeSelect'
+ | 'Upload'
+ | BaseFormComponentType;
+
+async function initComponentAdapter() {
+ const components: Partial> = {
+ // 如果你的组件体积比较大,可以使用异步加载
+ // Button: () =>
+ // import('xxx').then((res) => res.Button),
+
+ ApiCascader: withDefaultPlaceholder(ApiComponent, 'select', {
+ component: Cascader,
+ fieldNames: { label: 'label', value: 'value', children: 'children' },
+ loadingSlot: 'suffixIcon',
+ modelPropName: 'value',
+ visibleEvent: 'onVisibleChange',
+ }),
+ ApiSelect: withDefaultPlaceholder(ApiComponent, 'select', {
+ component: Select,
+ loadingSlot: 'suffixIcon',
+ modelPropName: 'value',
+ visibleEvent: 'onVisibleChange',
+ }),
+ ApiTreeSelect: withDefaultPlaceholder(ApiComponent, 'select', {
+ component: TreeSelect,
+ fieldNames: { label: 'label', value: 'value', children: 'children' },
+ loadingSlot: 'suffixIcon',
+ modelPropName: 'value',
+ optionsPropName: 'treeData',
+ visibleEvent: 'onVisibleChange',
+ }),
+ AutoComplete,
+ Cascader,
+ Checkbox,
+ CheckboxGroup,
+ DatePicker,
+ // 自定义默认按钮
+ DefaultButton: (props, { attrs, slots }) => {
+ return h(Button, { ...props, attrs, type: 'default' }, slots);
+ },
+ Divider,
+ IconPicker: withDefaultPlaceholder(IconPicker, 'select', {
+ iconSlot: 'addonAfter',
+ inputComponent: Input,
+ modelValueProp: 'value',
+ }),
+ Input: withDefaultPlaceholder(Input, 'input'),
+ InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
+ InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
+ Mentions: withDefaultPlaceholder(Mentions, 'input'),
+ // 自定义主要按钮
+ PrimaryButton: (props, { attrs, slots }) => {
+ return h(Button, { ...props, attrs, type: 'primary' }, slots);
+ },
+ Radio,
+ RadioGroup,
+ RangePicker,
+ Rate,
+ Select: withDefaultPlaceholder(Select, 'select'),
+ Space,
+ Switch,
+ Textarea: withDefaultPlaceholder(Textarea, 'input'),
+ TimePicker,
+ TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
+ Upload: withPreviewUpload(),
+ };
+
+ // 将组件注册到全局共享状态中
+ globalShareState.setComponents(components);
+
+ // 定义全局共享状态中的消息提示
+ globalShareState.defineMessage({
+ // 复制成功消息提示
+ copyPreferencesSuccess: (title, content) => {
+ notification.success({
+ description: content,
+ title,
+ placement: 'bottomRight',
+ });
+ },
+ });
+}
+
+export { initComponentAdapter };
diff --git a/apps/web-antdv-next/src/adapter/form.ts b/apps/web-antdv-next/src/adapter/form.ts
new file mode 100644
index 00000000..983a7f51
--- /dev/null
+++ b/apps/web-antdv-next/src/adapter/form.ts
@@ -0,0 +1,49 @@
+import type {
+ VbenFormSchema as FormSchema,
+ VbenFormProps,
+} from '@vben/common-ui';
+
+import type { ComponentType } from './component';
+
+import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+async function initSetupVbenForm() {
+ setupVbenForm({
+ config: {
+ // ant design vue组件库默认都是 v-model:value
+ baseModelPropName: 'value',
+
+ // 一些组件是 v-model:checked 或者 v-model:fileList
+ modelPropNameMap: {
+ Checkbox: 'checked',
+ Radio: 'checked',
+ Switch: 'checked',
+ Upload: 'fileList',
+ },
+ },
+ defineRules: {
+ // 输入项目必填国际化适配
+ required: (value, _params, ctx) => {
+ if (value === undefined || value === null || value.length === 0) {
+ return $t('ui.formRules.required', [ctx.label]);
+ }
+ return true;
+ },
+ // 选择项目必填国际化适配
+ selectRequired: (value, _params, ctx) => {
+ if (value === undefined || value === null) {
+ return $t('ui.formRules.selectRequired', [ctx.label]);
+ }
+ return true;
+ },
+ },
+ });
+}
+
+const useVbenForm = useForm;
+
+export { initSetupVbenForm, useVbenForm, z };
+
+export type VbenFormSchema = FormSchema;
+export type { VbenFormProps };
diff --git a/apps/web-antdv-next/src/adapter/vxe-table.ts b/apps/web-antdv-next/src/adapter/vxe-table.ts
new file mode 100644
index 00000000..3b5d83b3
--- /dev/null
+++ b/apps/web-antdv-next/src/adapter/vxe-table.ts
@@ -0,0 +1,70 @@
+import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
+
+import { h } from 'vue';
+
+import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
+
+import { Button, Image } from 'antdv-next';
+
+import { useVbenForm } from './form';
+
+setupVbenVxeTable({
+ configVxeTable: (vxeUI) => {
+ vxeUI.setConfig({
+ grid: {
+ align: 'center',
+ border: false,
+ columnConfig: {
+ resizable: true,
+ },
+ minHeight: 180,
+ formConfig: {
+ // 全局禁用vxe-table的表单配置,使用formOptions
+ enabled: false,
+ },
+ proxyConfig: {
+ autoLoad: true,
+ response: {
+ result: 'items',
+ total: 'total',
+ list: 'items',
+ },
+ showActiveMsg: true,
+ showResponseMsg: false,
+ },
+ round: true,
+ showOverflow: true,
+ size: 'small',
+ } as VxeTableGridOptions,
+ });
+
+ // 表格配置项可以用 cellRender: { name: 'CellImage' },
+ vxeUI.renderer.add('CellImage', {
+ renderTableDefault(renderOpts, params) {
+ const { props } = renderOpts;
+ const { column, row } = params;
+ return h(Image, { src: row[column.field], ...props });
+ },
+ });
+
+ // 表格配置项可以用 cellRender: { name: 'CellLink' },
+ vxeUI.renderer.add('CellLink', {
+ renderTableDefault(renderOpts) {
+ const { props } = renderOpts;
+ return h(
+ Button,
+ { size: 'small', type: 'link' },
+ { default: () => props?.text },
+ );
+ },
+ });
+
+ // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
+ // vxeUI.formats.add
+ },
+ useVbenForm,
+});
+
+export { useVbenVxeGrid };
+
+export type * from '@vben/plugins/vxe-table';
diff --git a/apps/web-antdv-next/src/api/core/auth.ts b/apps/web-antdv-next/src/api/core/auth.ts
new file mode 100644
index 00000000..71d9f994
--- /dev/null
+++ b/apps/web-antdv-next/src/api/core/auth.ts
@@ -0,0 +1,51 @@
+import { baseRequestClient, requestClient } from '#/api/request';
+
+export namespace AuthApi {
+ /** 登录接口参数 */
+ export interface LoginParams {
+ password?: string;
+ username?: string;
+ }
+
+ /** 登录接口返回值 */
+ export interface LoginResult {
+ accessToken: string;
+ }
+
+ export interface RefreshTokenResult {
+ data: string;
+ status: number;
+ }
+}
+
+/**
+ * 登录
+ */
+export async function loginApi(data: AuthApi.LoginParams) {
+ return requestClient.post('/auth/login', data);
+}
+
+/**
+ * 刷新accessToken
+ */
+export async function refreshTokenApi() {
+ return baseRequestClient.post('/auth/refresh', {
+ withCredentials: true,
+ });
+}
+
+/**
+ * 退出登录
+ */
+export async function logoutApi() {
+ return baseRequestClient.post('/auth/logout', {
+ withCredentials: true,
+ });
+}
+
+/**
+ * 获取用户权限码
+ */
+export async function getAccessCodesApi() {
+ return requestClient.get('/auth/codes');
+}
diff --git a/apps/web-antdv-next/src/api/core/index.ts b/apps/web-antdv-next/src/api/core/index.ts
new file mode 100644
index 00000000..28a5aef4
--- /dev/null
+++ b/apps/web-antdv-next/src/api/core/index.ts
@@ -0,0 +1,3 @@
+export * from './auth';
+export * from './menu';
+export * from './user';
diff --git a/apps/web-antdv-next/src/api/core/menu.ts b/apps/web-antdv-next/src/api/core/menu.ts
new file mode 100644
index 00000000..9ef60b11
--- /dev/null
+++ b/apps/web-antdv-next/src/api/core/menu.ts
@@ -0,0 +1,10 @@
+import type { RouteRecordStringComponent } from '@vben/types';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 获取用户所有菜单
+ */
+export async function getAllMenusApi() {
+ return requestClient.get('/menu/all');
+}
diff --git a/apps/web-antdv-next/src/api/core/user.ts b/apps/web-antdv-next/src/api/core/user.ts
new file mode 100644
index 00000000..7e28ea84
--- /dev/null
+++ b/apps/web-antdv-next/src/api/core/user.ts
@@ -0,0 +1,10 @@
+import type { UserInfo } from '@vben/types';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 获取用户信息
+ */
+export async function getUserInfoApi() {
+ return requestClient.get('/user/info');
+}
diff --git a/apps/web-antdv-next/src/api/index.ts b/apps/web-antdv-next/src/api/index.ts
new file mode 100644
index 00000000..4b0e0413
--- /dev/null
+++ b/apps/web-antdv-next/src/api/index.ts
@@ -0,0 +1 @@
+export * from './core';
diff --git a/apps/web-antdv-next/src/api/request.ts b/apps/web-antdv-next/src/api/request.ts
new file mode 100644
index 00000000..d97a2163
--- /dev/null
+++ b/apps/web-antdv-next/src/api/request.ts
@@ -0,0 +1,113 @@
+/**
+ * 该文件可自行根据业务逻辑进行调整
+ */
+import type { RequestClientOptions } from '@vben/request';
+
+import { useAppConfig } from '@vben/hooks';
+import { preferences } from '@vben/preferences';
+import {
+ authenticateResponseInterceptor,
+ defaultResponseInterceptor,
+ errorMessageResponseInterceptor,
+ RequestClient,
+} from '@vben/request';
+import { useAccessStore } from '@vben/stores';
+
+import { message } from 'antdv-next';
+
+import { useAuthStore } from '#/store';
+
+import { refreshTokenApi } from './core';
+
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+
+function createRequestClient(baseURL: string, options?: RequestClientOptions) {
+ const client = new RequestClient({
+ ...options,
+ baseURL,
+ });
+
+ /**
+ * 重新认证逻辑
+ */
+ async function doReAuthenticate() {
+ console.warn('Access token or refresh token is invalid or expired. ');
+ const accessStore = useAccessStore();
+ const authStore = useAuthStore();
+ accessStore.setAccessToken(null);
+ if (
+ preferences.app.loginExpiredMode === 'modal' &&
+ accessStore.isAccessChecked
+ ) {
+ accessStore.setLoginExpired(true);
+ } else {
+ await authStore.logout();
+ }
+ }
+
+ /**
+ * 刷新token逻辑
+ */
+ async function doRefreshToken() {
+ const accessStore = useAccessStore();
+ const resp = await refreshTokenApi();
+ const newToken = resp.data;
+ accessStore.setAccessToken(newToken);
+ return newToken;
+ }
+
+ function formatToken(token: null | string) {
+ return token ? `Bearer ${token}` : null;
+ }
+
+ // 请求头处理
+ client.addRequestInterceptor({
+ fulfilled: async (config) => {
+ const accessStore = useAccessStore();
+
+ config.headers.Authorization = formatToken(accessStore.accessToken);
+ config.headers['Accept-Language'] = preferences.app.locale;
+ return config;
+ },
+ });
+
+ // 处理返回的响应数据格式
+ client.addResponseInterceptor(
+ defaultResponseInterceptor({
+ codeField: 'code',
+ dataField: 'data',
+ successCode: 0,
+ }),
+ );
+
+ // token过期的处理
+ client.addResponseInterceptor(
+ authenticateResponseInterceptor({
+ client,
+ doReAuthenticate,
+ doRefreshToken,
+ enableRefreshToken: preferences.app.enableRefreshToken,
+ formatToken,
+ }),
+ );
+
+ // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
+ client.addResponseInterceptor(
+ errorMessageResponseInterceptor((msg: string, error) => {
+ // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
+ // 当前mock接口返回的错误字段是 error 或者 message
+ const responseData = error?.response?.data ?? {};
+ const errorMessage = responseData?.error ?? responseData?.message ?? '';
+ // 如果没有错误信息,则会根据状态码进行提示
+ message.error(errorMessage || msg);
+ }),
+ );
+
+ return client;
+}
+
+export const requestClient = createRequestClient(apiURL, {
+ responseReturn: 'data',
+});
+
+export const baseRequestClient = new RequestClient({ baseURL: apiURL });
diff --git a/apps/web-antdv-next/src/app.vue b/apps/web-antdv-next/src/app.vue
new file mode 100644
index 00000000..59ca8618
--- /dev/null
+++ b/apps/web-antdv-next/src/app.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/bootstrap.ts b/apps/web-antdv-next/src/bootstrap.ts
new file mode 100644
index 00000000..8c161703
--- /dev/null
+++ b/apps/web-antdv-next/src/bootstrap.ts
@@ -0,0 +1,76 @@
+import { createApp, watchEffect } from 'vue';
+
+import { registerAccessDirective } from '@vben/access';
+import { registerLoadingDirective } from '@vben/common-ui/es/loading';
+import { preferences } from '@vben/preferences';
+import { initStores } from '@vben/stores';
+import '@vben/styles';
+import '@vben/styles/antdv-next';
+
+import { useTitle } from '@vueuse/core';
+
+import { $t, setupI18n } from '#/locales';
+
+import { initComponentAdapter } from './adapter/component';
+import { initSetupVbenForm } from './adapter/form';
+import App from './app.vue';
+import { router } from './router';
+
+async function bootstrap(namespace: string) {
+ // 初始化组件适配器
+ await initComponentAdapter();
+
+ // 初始化表单组件
+ await initSetupVbenForm();
+
+ // // 设置弹窗的默认配置
+ // setDefaultModalProps({
+ // fullscreenButton: false,
+ // });
+ // // 设置抽屉的默认配置
+ // setDefaultDrawerProps({
+ // zIndex: 1020,
+ // });
+
+ const app = createApp(App);
+
+ // 注册v-loading指令
+ registerLoadingDirective(app, {
+ loading: 'loading', // 在这里可以自定义指令名称,也可以明确提供false表示不注册这个指令
+ spinning: 'spinning',
+ });
+
+ // 国际化 i18n 配置
+ await setupI18n(app);
+
+ // 配置 pinia-tore
+ await initStores(app, { namespace });
+
+ // 安装权限指令
+ registerAccessDirective(app);
+
+ // 初始化 tippy
+ const { initTippy } = await import('@vben/common-ui/es/tippy');
+ initTippy(app);
+
+ // 配置路由及路由守卫
+ app.use(router);
+
+ // 配置Motion插件
+ const { MotionPlugin } = await import('@vben/plugins/motion');
+ app.use(MotionPlugin);
+
+ // 动态更新标题
+ watchEffect(() => {
+ if (preferences.app.dynamicTitle) {
+ const routeTitle = router.currentRoute.value.meta?.title;
+ const pageTitle =
+ (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;
+ useTitle(pageTitle);
+ }
+ });
+
+ app.mount('#app');
+}
+
+export { bootstrap };
diff --git a/apps/web-antdv-next/src/layouts/auth.vue b/apps/web-antdv-next/src/layouts/auth.vue
new file mode 100644
index 00000000..8ba66e85
--- /dev/null
+++ b/apps/web-antdv-next/src/layouts/auth.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/layouts/basic.vue b/apps/web-antdv-next/src/layouts/basic.vue
new file mode 100644
index 00000000..2226c68a
--- /dev/null
+++ b/apps/web-antdv-next/src/layouts/basic.vue
@@ -0,0 +1,206 @@
+
+
+
+
+
+
+
+
+ item.id && markRead(item.id)"
+ @remove="(item) => item.id && remove(item.id)"
+ @make-all="handleMakeAll"
+ />
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/layouts/index.ts b/apps/web-antdv-next/src/layouts/index.ts
new file mode 100644
index 00000000..a4320780
--- /dev/null
+++ b/apps/web-antdv-next/src/layouts/index.ts
@@ -0,0 +1,6 @@
+const BasicLayout = () => import('./basic.vue');
+const AuthPageLayout = () => import('./auth.vue');
+
+const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
+
+export { AuthPageLayout, BasicLayout, IFrameView };
diff --git a/apps/web-antdv-next/src/locales/README.md b/apps/web-antdv-next/src/locales/README.md
new file mode 100644
index 00000000..7b451032
--- /dev/null
+++ b/apps/web-antdv-next/src/locales/README.md
@@ -0,0 +1,3 @@
+# locale
+
+每个app使用的国际化可能不同,这里用于扩展国际化的功能,例如扩展 dayjs、antd组件库的多语言切换,以及app本身的国际化文件。
diff --git a/apps/web-antdv-next/src/locales/index.ts b/apps/web-antdv-next/src/locales/index.ts
new file mode 100644
index 00000000..2586d859
--- /dev/null
+++ b/apps/web-antdv-next/src/locales/index.ts
@@ -0,0 +1,102 @@
+import type { Locale } from 'antdv-next/dist/locale/index';
+
+import type { App } from 'vue';
+
+import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
+
+import { ref } from 'vue';
+
+import {
+ $t,
+ setupI18n as coreSetup,
+ loadLocalesMapFromDir,
+} from '@vben/locales';
+import { preferences } from '@vben/preferences';
+
+import antdEnLocale from 'antdv-next/dist/locale/en_US';
+import antdDefaultLocale from 'antdv-next/dist/locale/zh_CN';
+import dayjs from 'dayjs';
+
+const antdLocale = ref(antdDefaultLocale);
+
+const modules = import.meta.glob('./langs/**/*.json');
+
+const localesMap = loadLocalesMapFromDir(
+ /\.\/langs\/([^/]+)\/(.*)\.json$/,
+ modules,
+);
+/**
+ * 加载应用特有的语言包
+ * 这里也可以改造为从服务端获取翻译数据
+ * @param lang
+ */
+async function loadMessages(lang: SupportedLanguagesType) {
+ const [appLocaleMessages] = await Promise.all([
+ localesMap[lang]?.(),
+ loadThirdPartyMessage(lang),
+ ]);
+ return appLocaleMessages?.default;
+}
+
+/**
+ * 加载第三方组件库的语言包
+ * @param lang
+ */
+async function loadThirdPartyMessage(lang: SupportedLanguagesType) {
+ await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);
+}
+
+/**
+ * 加载dayjs的语言包
+ * @param lang
+ */
+async function loadDayjsLocale(lang: SupportedLanguagesType) {
+ let locale;
+ switch (lang) {
+ case 'en-US': {
+ locale = await import('dayjs/locale/en');
+ break;
+ }
+ case 'zh-CN': {
+ locale = await import('dayjs/locale/zh-cn');
+ break;
+ }
+ // 默认使用英语
+ default: {
+ locale = await import('dayjs/locale/en');
+ }
+ }
+ if (locale) {
+ dayjs.locale(locale);
+ } else {
+ console.error(`Failed to load dayjs locale for ${lang}`);
+ }
+}
+
+/**
+ * 加载antd的语言包
+ * @param lang
+ */
+async function loadAntdLocale(lang: SupportedLanguagesType) {
+ switch (lang) {
+ case 'en-US': {
+ antdLocale.value = antdEnLocale;
+ break;
+ }
+ case 'zh-CN': {
+ antdLocale.value = antdDefaultLocale;
+ break;
+ }
+ }
+}
+
+async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
+ await coreSetup(app, {
+ defaultLocale: preferences.app.locale,
+ loadMessages,
+ missingWarn: !import.meta.env.PROD,
+ ...options,
+ });
+}
+
+export { $t, antdLocale, setupI18n };
diff --git a/apps/web-antdv-next/src/locales/langs/en-US/demos.json b/apps/web-antdv-next/src/locales/langs/en-US/demos.json
new file mode 100644
index 00000000..551f22b4
--- /dev/null
+++ b/apps/web-antdv-next/src/locales/langs/en-US/demos.json
@@ -0,0 +1,14 @@
+{
+ "title": "Demos",
+ "antd": "Antdv Next",
+ "vben": {
+ "title": "Project",
+ "about": "About",
+ "document": "Document",
+ "antdv": "Ant Design Vue Version",
+ "antdv-next": "Antdv Next Version",
+ "naive-ui": "Naive UI Version",
+ "element-plus": "Element Plus Version",
+ "tdesign": "TDesign Vue Version"
+ }
+}
diff --git a/apps/web-antdv-next/src/locales/langs/en-US/page.json b/apps/web-antdv-next/src/locales/langs/en-US/page.json
new file mode 100644
index 00000000..39f1641c
--- /dev/null
+++ b/apps/web-antdv-next/src/locales/langs/en-US/page.json
@@ -0,0 +1,15 @@
+{
+ "auth": {
+ "login": "Login",
+ "register": "Register",
+ "codeLogin": "Code Login",
+ "qrcodeLogin": "Qr Code Login",
+ "forgetPassword": "Forget Password",
+ "profile": "Profile"
+ },
+ "dashboard": {
+ "title": "Dashboard",
+ "analytics": "Analytics",
+ "workspace": "Workspace"
+ }
+}
diff --git a/apps/web-antdv-next/src/locales/langs/zh-CN/demos.json b/apps/web-antdv-next/src/locales/langs/zh-CN/demos.json
new file mode 100644
index 00000000..ef4e43fd
--- /dev/null
+++ b/apps/web-antdv-next/src/locales/langs/zh-CN/demos.json
@@ -0,0 +1,14 @@
+{
+ "title": "演示",
+ "antd": "Antdv Next",
+ "vben": {
+ "title": "项目",
+ "about": "关于",
+ "document": "文档",
+ "antdv": "Ant Design Vue 版本",
+ "antdv-next": "Antdv Next 版本",
+ "naive-ui": "Naive UI 版本",
+ "element-plus": "Element Plus 版本",
+ "tdesign": "TDesign Vue 版本"
+ }
+}
diff --git a/apps/web-antdv-next/src/locales/langs/zh-CN/page.json b/apps/web-antdv-next/src/locales/langs/zh-CN/page.json
new file mode 100644
index 00000000..2192d1d5
--- /dev/null
+++ b/apps/web-antdv-next/src/locales/langs/zh-CN/page.json
@@ -0,0 +1,15 @@
+{
+ "auth": {
+ "login": "登录",
+ "register": "注册",
+ "codeLogin": "验证码登录",
+ "qrcodeLogin": "二维码登录",
+ "forgetPassword": "忘记密码",
+ "profile": "个人中心"
+ },
+ "dashboard": {
+ "title": "概览",
+ "analytics": "分析页",
+ "workspace": "工作台"
+ }
+}
diff --git a/apps/web-antdv-next/src/main.ts b/apps/web-antdv-next/src/main.ts
new file mode 100644
index 00000000..5d728a02
--- /dev/null
+++ b/apps/web-antdv-next/src/main.ts
@@ -0,0 +1,31 @@
+import { initPreferences } from '@vben/preferences';
+import { unmountGlobalLoading } from '@vben/utils';
+
+import { overridesPreferences } from './preferences';
+
+/**
+ * 应用初始化完成之后再进行页面加载渲染
+ */
+async function initApplication() {
+ // name用于指定项目唯一标识
+ // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据
+ const env = import.meta.env.PROD ? 'prod' : 'dev';
+ const appVersion = import.meta.env.VITE_APP_VERSION;
+ const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;
+
+ // app偏好设置初始化
+ await initPreferences({
+ namespace,
+ overrides: overridesPreferences,
+ });
+
+ // 启动应用并挂载
+ // vue应用主要逻辑及视图
+ const { bootstrap } = await import('./bootstrap');
+ await bootstrap(namespace);
+
+ // 移除并销毁loading
+ unmountGlobalLoading();
+}
+
+initApplication();
diff --git a/apps/web-antdv-next/src/preferences.ts b/apps/web-antdv-next/src/preferences.ts
new file mode 100644
index 00000000..b2e9ace4
--- /dev/null
+++ b/apps/web-antdv-next/src/preferences.ts
@@ -0,0 +1,13 @@
+import { defineOverridesPreferences } from '@vben/preferences';
+
+/**
+ * @description 项目配置文件
+ * 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置
+ * !!! 更改配置后请清空缓存,否则可能不生效
+ */
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+ app: {
+ name: import.meta.env.VITE_APP_TITLE,
+ },
+});
diff --git a/apps/web-antdv-next/src/router/access.ts b/apps/web-antdv-next/src/router/access.ts
new file mode 100644
index 00000000..e9e98511
--- /dev/null
+++ b/apps/web-antdv-next/src/router/access.ts
@@ -0,0 +1,42 @@
+import type {
+ ComponentRecordType,
+ GenerateMenuAndRoutesOptions,
+} from '@vben/types';
+
+import { generateAccessible } from '@vben/access';
+import { preferences } from '@vben/preferences';
+
+import { message } from 'antdv-next';
+
+import { getAllMenusApi } from '#/api';
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
+
+async function generateAccess(options: GenerateMenuAndRoutesOptions) {
+ const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
+
+ const layoutMap: ComponentRecordType = {
+ BasicLayout,
+ IFrameView,
+ };
+
+ return await generateAccessible(preferences.app.accessMode, {
+ ...options,
+ fetchMenuListAsync: async () => {
+ message.loading({
+ content: `${$t('common.loadingMenu')}...`,
+ duration: 1.5,
+ });
+ return await getAllMenusApi();
+ },
+ // 可以指定没有权限跳转403页面
+ forbiddenComponent,
+ // 如果 route.meta.menuVisibleWithForbidden = true
+ layoutMap,
+ pageMap,
+ });
+}
+
+export { generateAccess };
diff --git a/apps/web-antdv-next/src/router/guard.ts b/apps/web-antdv-next/src/router/guard.ts
new file mode 100644
index 00000000..a1ad6d88
--- /dev/null
+++ b/apps/web-antdv-next/src/router/guard.ts
@@ -0,0 +1,133 @@
+import type { Router } from 'vue-router';
+
+import { LOGIN_PATH } from '@vben/constants';
+import { preferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+import { startProgress, stopProgress } from '@vben/utils';
+
+import { accessRoutes, coreRouteNames } from '#/router/routes';
+import { useAuthStore } from '#/store';
+
+import { generateAccess } from './access';
+
+/**
+ * 通用守卫配置
+ * @param router
+ */
+function setupCommonGuard(router: Router) {
+ // 记录已经加载的页面
+ const loadedPaths = new Set();
+
+ router.beforeEach((to) => {
+ to.meta.loaded = loadedPaths.has(to.path);
+
+ // 页面加载进度条
+ if (!to.meta.loaded && preferences.transition.progress) {
+ startProgress();
+ }
+ return true;
+ });
+
+ router.afterEach((to) => {
+ // 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
+
+ loadedPaths.add(to.path);
+
+ // 关闭页面加载进度条
+ if (preferences.transition.progress) {
+ stopProgress();
+ }
+ });
+}
+
+/**
+ * 权限访问守卫配置
+ * @param router
+ */
+function setupAccessGuard(router: Router) {
+ router.beforeEach(async (to, from) => {
+ const accessStore = useAccessStore();
+ const userStore = useUserStore();
+ const authStore = useAuthStore();
+
+ // 基本路由,这些路由不需要进入权限拦截
+ if (coreRouteNames.includes(to.name as string)) {
+ if (to.path === LOGIN_PATH && accessStore.accessToken) {
+ return decodeURIComponent(
+ (to.query?.redirect as string) ||
+ userStore.userInfo?.homePath ||
+ preferences.app.defaultHomePath,
+ );
+ }
+ return true;
+ }
+
+ // accessToken 检查
+ if (!accessStore.accessToken) {
+ // 明确声明忽略权限访问权限,则可以访问
+ if (to.meta.ignoreAccess) {
+ return true;
+ }
+
+ // 没有访问权限,跳转登录页面
+ if (to.fullPath !== LOGIN_PATH) {
+ return {
+ path: LOGIN_PATH,
+ // 如不需要,直接删除 query
+ query:
+ to.fullPath === preferences.app.defaultHomePath
+ ? {}
+ : { redirect: encodeURIComponent(to.fullPath) },
+ // 携带当前跳转的页面,登录后重新跳转该页面
+ replace: true,
+ };
+ }
+ return to;
+ }
+
+ // 是否已经生成过动态路由
+ if (accessStore.isAccessChecked) {
+ return true;
+ }
+
+ // 生成路由表
+ // 当前登录用户拥有的角色标识列表
+ const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
+ const userRoles = userInfo.roles ?? [];
+
+ // 生成菜单和路由
+ const { accessibleMenus, accessibleRoutes } = await generateAccess({
+ roles: userRoles,
+ router,
+ // 则会在菜单中显示,但是访问会被重定向到403
+ routes: accessRoutes,
+ });
+
+ // 保存菜单信息和路由信息
+ accessStore.setAccessMenus(accessibleMenus);
+ accessStore.setAccessRoutes(accessibleRoutes);
+ accessStore.setIsAccessChecked(true);
+ const redirectPath = (from.query.redirect ??
+ (to.path === preferences.app.defaultHomePath
+ ? userInfo.homePath || preferences.app.defaultHomePath
+ : to.fullPath)) as string;
+
+ return {
+ ...router.resolve(decodeURIComponent(redirectPath)),
+ replace: true,
+ };
+ });
+}
+
+/**
+ * 项目守卫配置
+ * @param router
+ */
+function createRouterGuard(router: Router) {
+ /** 通用 */
+ setupCommonGuard(router);
+ /** 权限访问 */
+ setupAccessGuard(router);
+}
+
+export { createRouterGuard };
diff --git a/apps/web-antdv-next/src/router/index.ts b/apps/web-antdv-next/src/router/index.ts
new file mode 100644
index 00000000..48402303
--- /dev/null
+++ b/apps/web-antdv-next/src/router/index.ts
@@ -0,0 +1,37 @@
+import {
+ createRouter,
+ createWebHashHistory,
+ createWebHistory,
+} from 'vue-router';
+
+import { resetStaticRoutes } from '@vben/utils';
+
+import { createRouterGuard } from './guard';
+import { routes } from './routes';
+
+/**
+ * @zh_CN 创建vue-router实例
+ */
+const router = createRouter({
+ history:
+ import.meta.env.VITE_ROUTER_HISTORY === 'hash'
+ ? createWebHashHistory(import.meta.env.VITE_BASE)
+ : createWebHistory(import.meta.env.VITE_BASE),
+ // 应该添加到路由的初始路由列表。
+ routes,
+ scrollBehavior: (to, _from, savedPosition) => {
+ if (savedPosition) {
+ return savedPosition;
+ }
+ return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };
+ },
+ // 是否应该禁止尾部斜杠。
+ // strict: true,
+});
+
+const resetRoutes = () => resetStaticRoutes(router, routes);
+
+// 创建路由守卫
+createRouterGuard(router);
+
+export { resetRoutes, router };
diff --git a/apps/web-antdv-next/src/router/routes/core.ts b/apps/web-antdv-next/src/router/routes/core.ts
new file mode 100644
index 00000000..949b0b65
--- /dev/null
+++ b/apps/web-antdv-next/src/router/routes/core.ts
@@ -0,0 +1,97 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { LOGIN_PATH } from '@vben/constants';
+import { preferences } from '@vben/preferences';
+
+import { $t } from '#/locales';
+
+const BasicLayout = () => import('#/layouts/basic.vue');
+const AuthPageLayout = () => import('#/layouts/auth.vue');
+/** 全局404页面 */
+const fallbackNotFoundRoute: RouteRecordRaw = {
+ component: () => import('#/views/_core/fallback/not-found.vue'),
+ meta: {
+ hideInBreadcrumb: true,
+ hideInMenu: true,
+ hideInTab: true,
+ title: '404',
+ },
+ name: 'FallbackNotFound',
+ path: '/:path(.*)*',
+};
+
+/** 基本路由,这些路由是必须存在的 */
+const coreRoutes: RouteRecordRaw[] = [
+ /**
+ * 根路由
+ * 使用基础布局,作为所有页面的父级容器,子级就不必配置BasicLayout。
+ * 此路由必须存在,且不应修改
+ */
+ {
+ component: BasicLayout,
+ meta: {
+ hideInBreadcrumb: true,
+ title: 'Root',
+ },
+ name: 'Root',
+ path: '/',
+ redirect: preferences.app.defaultHomePath,
+ children: [],
+ },
+ {
+ component: AuthPageLayout,
+ meta: {
+ hideInTab: true,
+ title: 'Authentication',
+ },
+ name: 'Authentication',
+ path: '/auth',
+ redirect: LOGIN_PATH,
+ children: [
+ {
+ name: 'Login',
+ path: 'login',
+ component: () => import('#/views/_core/authentication/login.vue'),
+ meta: {
+ title: $t('page.auth.login'),
+ },
+ },
+ {
+ name: 'CodeLogin',
+ path: 'code-login',
+ component: () => import('#/views/_core/authentication/code-login.vue'),
+ meta: {
+ title: $t('page.auth.codeLogin'),
+ },
+ },
+ {
+ name: 'QrCodeLogin',
+ path: 'qrcode-login',
+ component: () =>
+ import('#/views/_core/authentication/qrcode-login.vue'),
+ meta: {
+ title: $t('page.auth.qrcodeLogin'),
+ },
+ },
+ {
+ name: 'ForgetPassword',
+ path: 'forget-password',
+ component: () =>
+ import('#/views/_core/authentication/forget-password.vue'),
+ meta: {
+ title: $t('page.auth.forgetPassword'),
+ },
+ },
+ {
+ name: 'Register',
+ path: 'register',
+ component: () => import('#/views/_core/authentication/register.vue'),
+ meta: {
+ title: $t('page.auth.register'),
+ },
+ },
+ ],
+ },
+];
+
+export { coreRoutes, fallbackNotFoundRoute };
diff --git a/apps/web-antdv-next/src/router/routes/index.ts b/apps/web-antdv-next/src/router/routes/index.ts
new file mode 100644
index 00000000..e6fb1440
--- /dev/null
+++ b/apps/web-antdv-next/src/router/routes/index.ts
@@ -0,0 +1,37 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
+
+import { coreRoutes, fallbackNotFoundRoute } from './core';
+
+const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
+ eager: true,
+});
+
+// 有需要可以自行打开注释,并创建文件夹
+// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
+// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });
+
+/** 动态路由 */
+const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
+
+/** 外部路由列表,访问这些页面可以不需要Layout,可能用于内嵌在别的系统(不会显示在菜单中) */
+// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
+// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);
+const staticRoutes: RouteRecordRaw[] = [];
+const externalRoutes: RouteRecordRaw[] = [];
+
+/** 路由列表,由基本路由、外部路由和404兜底路由组成
+ * 无需走权限验证(会一直显示在菜单中) */
+const routes: RouteRecordRaw[] = [
+ ...coreRoutes,
+ ...externalRoutes,
+ fallbackNotFoundRoute,
+];
+
+/** 基本路由列表,这些路由不需要进入权限拦截 */
+const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
+
+/** 有权限校验的路由列表,包含动态路由和静态路由 */
+const accessRoutes = [...dynamicRoutes, ...staticRoutes];
+export { accessRoutes, coreRouteNames, routes };
diff --git a/apps/web-antdv-next/src/router/routes/modules/dashboard.ts b/apps/web-antdv-next/src/router/routes/modules/dashboard.ts
new file mode 100644
index 00000000..5254dc65
--- /dev/null
+++ b/apps/web-antdv-next/src/router/routes/modules/dashboard.ts
@@ -0,0 +1,38 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+ {
+ meta: {
+ icon: 'lucide:layout-dashboard',
+ order: -1,
+ title: $t('page.dashboard.title'),
+ },
+ name: 'Dashboard',
+ path: '/dashboard',
+ children: [
+ {
+ name: 'Analytics',
+ path: '/analytics',
+ component: () => import('#/views/dashboard/analytics/index.vue'),
+ meta: {
+ affixTab: true,
+ icon: 'lucide:area-chart',
+ title: $t('page.dashboard.analytics'),
+ },
+ },
+ {
+ name: 'Workspace',
+ path: '/workspace',
+ component: () => import('#/views/dashboard/workspace/index.vue'),
+ meta: {
+ icon: 'carbon:workspace',
+ title: $t('page.dashboard.workspace'),
+ },
+ },
+ ],
+ },
+];
+
+export default routes;
diff --git a/apps/web-antdv-next/src/router/routes/modules/demos.ts b/apps/web-antdv-next/src/router/routes/modules/demos.ts
new file mode 100644
index 00000000..4605d91c
--- /dev/null
+++ b/apps/web-antdv-next/src/router/routes/modules/demos.ts
@@ -0,0 +1,28 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+ {
+ meta: {
+ icon: 'ic:baseline-view-in-ar',
+ keepAlive: true,
+ order: 1000,
+ title: $t('demos.title'),
+ },
+ name: 'Demos',
+ path: '/demos',
+ children: [
+ {
+ meta: {
+ title: $t('demos.antd'),
+ },
+ name: 'AntDesignDemos',
+ path: '/demos/ant-design-next',
+ component: () => import('#/views/demos/antd/index.vue'),
+ },
+ ],
+ },
+];
+
+export default routes;
diff --git a/apps/web-antdv-next/src/router/routes/modules/vben.ts b/apps/web-antdv-next/src/router/routes/modules/vben.ts
new file mode 100644
index 00000000..96f741ef
--- /dev/null
+++ b/apps/web-antdv-next/src/router/routes/modules/vben.ts
@@ -0,0 +1,116 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import {
+ VBEN_ANT_PREVIEW_URL,
+ VBEN_DOC_URL,
+ VBEN_ELE_PREVIEW_URL,
+ VBEN_GITHUB_URL,
+ VBEN_LOGO_URL,
+ VBEN_NAIVE_PREVIEW_URL,
+ VBEN_TD_PREVIEW_URL,
+} from '@vben/constants';
+import { SvgAntdvLogoIcon, SvgTDesignIcon } from '@vben/icons';
+
+import { IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+ {
+ meta: {
+ badgeType: 'dot',
+ icon: VBEN_LOGO_URL,
+ order: 9998,
+ title: $t('demos.vben.title'),
+ },
+ name: 'VbenProject',
+ path: '/vben-admin',
+ children: [
+ {
+ name: 'VbenDocument',
+ path: '/vben-admin/document',
+ component: IFrameView,
+ meta: {
+ icon: 'lucide:book-open-text',
+ link: VBEN_DOC_URL,
+ title: $t('demos.vben.document'),
+ },
+ },
+ {
+ name: 'VbenGithub',
+ path: '/vben-admin/github',
+ component: IFrameView,
+ meta: {
+ icon: 'mdi:github',
+ link: VBEN_GITHUB_URL,
+ title: 'Github',
+ },
+ },
+ {
+ name: 'VbenAntd',
+ path: '/vben-admin/antd',
+ component: IFrameView,
+ meta: {
+ badgeType: 'dot',
+ icon: SvgAntdvLogoIcon,
+ link: VBEN_ANT_PREVIEW_URL,
+ title: $t('demos.vben.antdv'),
+ },
+ },
+ {
+ name: 'VbenNaive',
+ path: '/vben-admin/naive',
+ component: IFrameView,
+ meta: {
+ badgeType: 'dot',
+ icon: 'logos:naiveui',
+ link: VBEN_NAIVE_PREVIEW_URL,
+ title: $t('demos.vben.naive-ui'),
+ },
+ },
+ {
+ name: 'VbenTDesign',
+ path: '/vben-admin/tdesign',
+ component: IFrameView,
+ meta: {
+ badgeType: 'dot',
+ icon: SvgTDesignIcon,
+ link: VBEN_TD_PREVIEW_URL,
+ title: $t('demos.vben.tdesign'),
+ },
+ },
+ {
+ name: 'VbenElementPlus',
+ path: '/vben-admin/ele',
+ component: IFrameView,
+ meta: {
+ badgeType: 'dot',
+ icon: 'logos:element',
+ link: VBEN_ELE_PREVIEW_URL,
+ title: $t('demos.vben.element-plus'),
+ },
+ },
+ ],
+ },
+ {
+ 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;
diff --git a/apps/web-antdv-next/src/store/auth.ts b/apps/web-antdv-next/src/store/auth.ts
new file mode 100644
index 00000000..6f7a3750
--- /dev/null
+++ b/apps/web-antdv-next/src/store/auth.ts
@@ -0,0 +1,118 @@
+import type { Recordable, UserInfo } from '@vben/types';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { LOGIN_PATH } from '@vben/constants';
+import { preferences } from '@vben/preferences';
+import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
+
+import { notification } from 'antdv-next';
+import { defineStore } from 'pinia';
+
+import { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';
+import { $t } from '#/locales';
+
+export const useAuthStore = defineStore('auth', () => {
+ const accessStore = useAccessStore();
+ const userStore = useUserStore();
+ const router = useRouter();
+
+ const loginLoading = ref(false);
+
+ /**
+ * 异步处理登录操作
+ * Asynchronously handle the login process
+ * @param params 登录表单数据
+ */
+ async function authLogin(
+ params: Recordable,
+ onSuccess?: () => Promise | void,
+ ) {
+ // 异步处理用户登录操作并获取 accessToken
+ let userInfo: null | UserInfo = null;
+ try {
+ loginLoading.value = true;
+ const { accessToken } = await loginApi(params);
+
+ // 如果成功获取到 accessToken
+ if (accessToken) {
+ accessStore.setAccessToken(accessToken);
+
+ // 获取用户信息并存储到 accessStore 中
+ const [fetchUserInfoResult, accessCodes] = await Promise.all([
+ fetchUserInfo(),
+ getAccessCodesApi(),
+ ]);
+
+ userInfo = fetchUserInfoResult;
+
+ userStore.setUserInfo(userInfo);
+ accessStore.setAccessCodes(accessCodes);
+
+ if (accessStore.loginExpired) {
+ accessStore.setLoginExpired(false);
+ } else {
+ onSuccess
+ ? await onSuccess?.()
+ : await router.push(
+ userInfo.homePath || preferences.app.defaultHomePath,
+ );
+ }
+
+ if (userInfo?.realName) {
+ notification.success({
+ description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,
+ duration: 3,
+ title: $t('authentication.loginSuccess'),
+ });
+ }
+ }
+ } finally {
+ loginLoading.value = false;
+ }
+
+ return {
+ userInfo,
+ };
+ }
+
+ async function logout(redirect: boolean = true) {
+ try {
+ await logoutApi();
+ } catch {
+ // 不做任何处理
+ }
+ resetAllStores();
+ accessStore.setLoginExpired(false);
+
+ // 回登录页带上当前路由地址
+ await router.replace({
+ path: LOGIN_PATH,
+ query: redirect
+ ? {
+ redirect: encodeURIComponent(router.currentRoute.value.fullPath),
+ }
+ : {},
+ });
+ }
+
+ async function fetchUserInfo() {
+ let userInfo: null | UserInfo = null;
+ userInfo = await getUserInfoApi();
+ userStore.setUserInfo(userInfo);
+ return userInfo;
+ }
+
+ function $reset() {
+ loginLoading.value = false;
+ }
+
+ return {
+ $reset,
+ authLogin,
+ fetchUserInfo,
+ loginLoading,
+ logout,
+ };
+});
diff --git a/apps/web-antdv-next/src/store/index.ts b/apps/web-antdv-next/src/store/index.ts
new file mode 100644
index 00000000..269586ee
--- /dev/null
+++ b/apps/web-antdv-next/src/store/index.ts
@@ -0,0 +1 @@
+export * from './auth';
diff --git a/apps/web-antdv-next/src/views/_core/README.md b/apps/web-antdv-next/src/views/_core/README.md
new file mode 100644
index 00000000..8248afe6
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/README.md
@@ -0,0 +1,3 @@
+# \_core
+
+此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。
diff --git a/apps/web-antdv-next/src/views/_core/about/index.vue b/apps/web-antdv-next/src/views/_core/about/index.vue
new file mode 100644
index 00000000..0ee52433
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/about/index.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/authentication/code-login.vue b/apps/web-antdv-next/src/views/_core/authentication/code-login.vue
new file mode 100644
index 00000000..acfd1fd7
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/authentication/code-login.vue
@@ -0,0 +1,69 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/authentication/forget-password.vue b/apps/web-antdv-next/src/views/_core/authentication/forget-password.vue
new file mode 100644
index 00000000..fef0d427
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/authentication/forget-password.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/authentication/login.vue b/apps/web-antdv-next/src/views/_core/authentication/login.vue
new file mode 100644
index 00000000..099e4c8c
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/authentication/login.vue
@@ -0,0 +1,98 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/authentication/qrcode-login.vue b/apps/web-antdv-next/src/views/_core/authentication/qrcode-login.vue
new file mode 100644
index 00000000..23f5f2da
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/authentication/qrcode-login.vue
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/authentication/register.vue b/apps/web-antdv-next/src/views/_core/authentication/register.vue
new file mode 100644
index 00000000..b1a5de72
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/authentication/register.vue
@@ -0,0 +1,96 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/fallback/coming-soon.vue b/apps/web-antdv-next/src/views/_core/fallback/coming-soon.vue
new file mode 100644
index 00000000..f394930f
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/fallback/coming-soon.vue
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/fallback/forbidden.vue b/apps/web-antdv-next/src/views/_core/fallback/forbidden.vue
new file mode 100644
index 00000000..8ea65fed
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/fallback/forbidden.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/fallback/internal-error.vue b/apps/web-antdv-next/src/views/_core/fallback/internal-error.vue
new file mode 100644
index 00000000..819a47d5
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/fallback/internal-error.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/fallback/not-found.vue b/apps/web-antdv-next/src/views/_core/fallback/not-found.vue
new file mode 100644
index 00000000..4d178e9c
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/fallback/not-found.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/fallback/offline.vue b/apps/web-antdv-next/src/views/_core/fallback/offline.vue
new file mode 100644
index 00000000..5de4a88d
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/fallback/offline.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/profile/base-setting.vue b/apps/web-antdv-next/src/views/_core/profile/base-setting.vue
new file mode 100644
index 00000000..aa8a4c26
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/profile/base-setting.vue
@@ -0,0 +1,65 @@
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/profile/index.vue b/apps/web-antdv-next/src/views/_core/profile/index.vue
new file mode 100644
index 00000000..8740894e
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/profile/index.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/profile/notification-setting.vue b/apps/web-antdv-next/src/views/_core/profile/notification-setting.vue
new file mode 100644
index 00000000..324a4b39
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/profile/notification-setting.vue
@@ -0,0 +1,31 @@
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/profile/password-setting.vue b/apps/web-antdv-next/src/views/_core/profile/password-setting.vue
new file mode 100644
index 00000000..adb065a2
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/profile/password-setting.vue
@@ -0,0 +1,63 @@
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/_core/profile/security-setting.vue b/apps/web-antdv-next/src/views/_core/profile/security-setting.vue
new file mode 100644
index 00000000..be30db58
--- /dev/null
+++ b/apps/web-antdv-next/src/views/_core/profile/security-setting.vue
@@ -0,0 +1,43 @@
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/analytics-trends.vue b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-trends.vue
new file mode 100644
index 00000000..f1f0b232
--- /dev/null
+++ b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-trends.vue
@@ -0,0 +1,98 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits-data.vue b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits-data.vue
new file mode 100644
index 00000000..190fb41f
--- /dev/null
+++ b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits-data.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits-sales.vue b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits-sales.vue
new file mode 100644
index 00000000..6ff52086
--- /dev/null
+++ b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits-sales.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits-source.vue b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits-source.vue
new file mode 100644
index 00000000..0915c7af
--- /dev/null
+++ b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits-source.vue
@@ -0,0 +1,65 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits.vue b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits.vue
new file mode 100644
index 00000000..7e0f1013
--- /dev/null
+++ b/apps/web-antdv-next/src/views/dashboard/analytics/analytics-visits.vue
@@ -0,0 +1,55 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/index.vue b/apps/web-antdv-next/src/views/dashboard/analytics/index.vue
new file mode 100644
index 00000000..5e3d6d28
--- /dev/null
+++ b/apps/web-antdv-next/src/views/dashboard/analytics/index.vue
@@ -0,0 +1,90 @@
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/dashboard/workspace/index.vue b/apps/web-antdv-next/src/views/dashboard/workspace/index.vue
new file mode 100644
index 00000000..b95d6138
--- /dev/null
+++ b/apps/web-antdv-next/src/views/dashboard/workspace/index.vue
@@ -0,0 +1,266 @@
+
+
+
+
+
+
+ 早安, {{ userStore.userInfo?.realName }}, 开始您一天的工作吧!
+
+ 今日晴,20℃ - 32℃!
+
+
+
+
+
diff --git a/apps/web-antdv-next/src/views/demos/antd/index.vue b/apps/web-antdv-next/src/views/demos/antd/index.vue
new file mode 100644
index 00000000..6fb1998d
--- /dev/null
+++ b/apps/web-antdv-next/src/views/demos/antd/index.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antdv-next/tailwind.config.mjs b/apps/web-antdv-next/tailwind.config.mjs
new file mode 100644
index 00000000..f17f556f
--- /dev/null
+++ b/apps/web-antdv-next/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/apps/web-antdv-next/tsconfig.json b/apps/web-antdv-next/tsconfig.json
new file mode 100644
index 00000000..02c287fe
--- /dev/null
+++ b/apps/web-antdv-next/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "extends": "@vben/tsconfig/web-app.json",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "#/*": ["./src/*"]
+ }
+ },
+ "references": [{ "path": "./tsconfig.node.json" }],
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
+}
diff --git a/apps/web-antdv-next/tsconfig.node.json b/apps/web-antdv-next/tsconfig.node.json
new file mode 100644
index 00000000..c2f0d86c
--- /dev/null
+++ b/apps/web-antdv-next/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "extends": "@vben/tsconfig/node.json",
+ "compilerOptions": {
+ "composite": true,
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "noEmit": false
+ },
+ "include": ["vite.config.mts"]
+}
diff --git a/apps/web-antdv-next/vite.config.mts b/apps/web-antdv-next/vite.config.mts
new file mode 100644
index 00000000..b6360f1d
--- /dev/null
+++ b/apps/web-antdv-next/vite.config.mts
@@ -0,0 +1,20 @@
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+ return {
+ application: {},
+ vite: {
+ server: {
+ proxy: {
+ '/api': {
+ changeOrigin: true,
+ rewrite: (path) => path.replace(/^\/api/, ''),
+ // mock代理目标地址
+ target: 'http://localhost:5320/api',
+ ws: true,
+ },
+ },
+ },
+ },
+ };
+});
diff --git a/apps/web-ele/src/locales/langs/en-US/demos.json b/apps/web-ele/src/locales/langs/en-US/demos.json
index cc404511..e379d22a 100644
--- a/apps/web-ele/src/locales/langs/en-US/demos.json
+++ b/apps/web-ele/src/locales/langs/en-US/demos.json
@@ -7,6 +7,7 @@
"about": "About",
"document": "Document",
"antdv": "Ant Design Vue Version",
+ "antdv-next": "Antdv Next Version",
"naive-ui": "Naive UI Version",
"element-plus": "Element Plus Version",
"tdesign": "TDesign Vue Version"
diff --git a/apps/web-ele/src/locales/langs/zh-CN/demos.json b/apps/web-ele/src/locales/langs/zh-CN/demos.json
index f8379c36..054c447c 100644
--- a/apps/web-ele/src/locales/langs/zh-CN/demos.json
+++ b/apps/web-ele/src/locales/langs/zh-CN/demos.json
@@ -7,6 +7,7 @@
"about": "关于",
"document": "文档",
"antdv": "Ant Design Vue 版本",
+ "antdv-next": "Antdv Next 版本",
"naive-ui": "Naive UI 版本",
"element-plus": "Element Plus 版本",
"tdesign": "TDesign Vue 版本"
diff --git a/apps/web-ele/src/router/routes/modules/vben.ts b/apps/web-ele/src/router/routes/modules/vben.ts
index 5c522f30..1e8176ea 100644
--- a/apps/web-ele/src/router/routes/modules/vben.ts
+++ b/apps/web-ele/src/router/routes/modules/vben.ts
@@ -2,13 +2,18 @@ import type { RouteRecordRaw } from 'vue-router';
import {
VBEN_ANT_PREVIEW_URL,
+ VBEN_ANTDV_NEXT_PREVIEW_URL,
VBEN_DOC_URL,
VBEN_GITHUB_URL,
VBEN_LOGO_URL,
VBEN_NAIVE_PREVIEW_URL,
VBEN_TD_PREVIEW_URL,
} from '@vben/constants';
-import { SvgAntdvLogoIcon, SvgTDesignIcon } from '@vben/icons';
+import {
+ SvgAntdvLogoIcon,
+ SvgAntdvNextLogoIcon,
+ SvgTDesignIcon,
+} from '@vben/icons';
import { IFrameView } from '#/layouts';
import { $t } from '#/locales';
@@ -66,6 +71,17 @@ const routes: RouteRecordRaw[] = [
title: $t('demos.vben.antdv'),
},
},
+ {
+ name: 'VbenAntdVNext',
+ path: '/vben-admin/antdv-next',
+ component: IFrameView,
+ meta: {
+ badgeType: 'dot',
+ icon: SvgAntdvNextLogoIcon,
+ link: VBEN_ANTDV_NEXT_PREVIEW_URL,
+ title: $t('demos.vben.antdv-next'),
+ },
+ },
{
name: 'VbenTDesign',
path: '/vben-admin/tdesign',
diff --git a/apps/web-naive/src/locales/langs/en-US/demos.json b/apps/web-naive/src/locales/langs/en-US/demos.json
index 3128b0be..5be6cdd5 100644
--- a/apps/web-naive/src/locales/langs/en-US/demos.json
+++ b/apps/web-naive/src/locales/langs/en-US/demos.json
@@ -8,6 +8,7 @@
"about": "About",
"document": "Document",
"antdv": "Ant Design Vue Version",
+ "antdv-next": "Antdv Next Version",
"naive-ui": "Naive UI Version",
"element-plus": "Element Plus Version",
"tdesign": "TDesign Vue Version"
diff --git a/apps/web-naive/src/locales/langs/zh-CN/demos.json b/apps/web-naive/src/locales/langs/zh-CN/demos.json
index 3c3957a9..d818cb5c 100644
--- a/apps/web-naive/src/locales/langs/zh-CN/demos.json
+++ b/apps/web-naive/src/locales/langs/zh-CN/demos.json
@@ -8,6 +8,7 @@
"about": "关于",
"document": "文档",
"antdv": "Ant Design Vue 版本",
+ "antdv-next": "Antdv Next 版本",
"naive-ui": "Naive UI 版本",
"element-plus": "Element Plus 版本",
"tdesign": "TDesign Vue 版本"
diff --git a/apps/web-naive/src/router/routes/modules/vben.ts b/apps/web-naive/src/router/routes/modules/vben.ts
index 32c21ca4..888ff4cb 100644
--- a/apps/web-naive/src/router/routes/modules/vben.ts
+++ b/apps/web-naive/src/router/routes/modules/vben.ts
@@ -2,13 +2,18 @@ import type { RouteRecordRaw } from 'vue-router';
import {
VBEN_ANT_PREVIEW_URL,
+ VBEN_ANTDV_NEXT_PREVIEW_URL,
VBEN_DOC_URL,
VBEN_ELE_PREVIEW_URL,
VBEN_GITHUB_URL,
VBEN_LOGO_URL,
VBEN_TD_PREVIEW_URL,
} from '@vben/constants';
-import { SvgAntdvLogoIcon, SvgTDesignIcon } from '@vben/icons';
+import {
+ SvgAntdvLogoIcon,
+ SvgAntdvNextLogoIcon,
+ SvgTDesignIcon,
+} from '@vben/icons';
import { IFrameView } from '#/layouts';
import { $t } from '#/locales';
@@ -55,6 +60,17 @@ const routes: RouteRecordRaw[] = [
title: $t('demos.vben.antdv'),
},
},
+ {
+ name: 'VbenAntdVNext',
+ path: '/vben-admin/antdv-next',
+ component: IFrameView,
+ meta: {
+ badgeType: 'dot',
+ icon: SvgAntdvNextLogoIcon,
+ link: VBEN_ANTDV_NEXT_PREVIEW_URL,
+ title: $t('demos.vben.antdv-next'),
+ },
+ },
{
name: 'VbenTDesign',
path: '/vben-admin/tdesign',
diff --git a/apps/web-tdesign/src/locales/langs/en-US/demos.json b/apps/web-tdesign/src/locales/langs/en-US/demos.json
index e7bcea12..0cb50b7f 100644
--- a/apps/web-tdesign/src/locales/langs/en-US/demos.json
+++ b/apps/web-tdesign/src/locales/langs/en-US/demos.json
@@ -6,6 +6,7 @@
"about": "About",
"document": "Document",
"antdv": "Ant Design Vue Version",
+ "antdv-next": "Antdv Next Version",
"naive-ui": "Naive UI Version",
"element-plus": "Element Plus Version"
}
diff --git a/apps/web-tdesign/src/locales/langs/zh-CN/demos.json b/apps/web-tdesign/src/locales/langs/zh-CN/demos.json
index 843a1f30..25e2a0f9 100644
--- a/apps/web-tdesign/src/locales/langs/zh-CN/demos.json
+++ b/apps/web-tdesign/src/locales/langs/zh-CN/demos.json
@@ -6,6 +6,7 @@
"about": "关于",
"document": "文档",
"antdv": "Ant Design Vue 版本",
+ "antdv-next": "Antdv Next 版本",
"naive-ui": "Naive UI 版本",
"element-plus": "Element Plus 版本"
}
diff --git a/apps/web-tdesign/src/router/routes/modules/vben.ts b/apps/web-tdesign/src/router/routes/modules/vben.ts
index a5f0aa4d..db555083 100644
--- a/apps/web-tdesign/src/router/routes/modules/vben.ts
+++ b/apps/web-tdesign/src/router/routes/modules/vben.ts
@@ -2,13 +2,14 @@ import type { RouteRecordRaw } from 'vue-router';
import {
VBEN_ANT_PREVIEW_URL,
+ VBEN_ANTDV_NEXT_PREVIEW_URL,
VBEN_DOC_URL,
VBEN_ELE_PREVIEW_URL,
VBEN_GITHUB_URL,
VBEN_LOGO_URL,
VBEN_NAIVE_PREVIEW_URL,
} from '@vben/constants';
-import { SvgAntdvLogoIcon } from '@vben/icons';
+import { SvgAntdvLogoIcon, SvgAntdvNextLogoIcon } from '@vben/icons';
import { IFrameView } from '#/layouts';
import { $t } from '#/locales';
@@ -66,6 +67,17 @@ const routes: RouteRecordRaw[] = [
title: $t('demos.vben.antdv'),
},
},
+ {
+ name: 'VbenAntdVNext',
+ path: '/vben-admin/antdv-next',
+ component: IFrameView,
+ meta: {
+ badgeType: 'dot',
+ icon: SvgAntdvNextLogoIcon,
+ link: VBEN_ANTDV_NEXT_PREVIEW_URL,
+ title: $t('demos.vben.antdv-next'),
+ },
+ },
{
name: 'VbenElementPlus',
path: '/vben-admin/ele',
diff --git a/docs/src/en/guide/introduction/quick-start.md b/docs/src/en/guide/introduction/quick-start.md
index 757679c3..12793c60 100644
--- a/docs/src/en/guide/introduction/quick-start.md
+++ b/docs/src/en/guide/introduction/quick-start.md
@@ -85,6 +85,7 @@ You will see an output similar to the following, allowing you to select the proj
│
◆ Select the app you need to run [dev]:
│ ● @vben/web-antd
+│ ○ @vben/web-antdv-next
│ ○ @vben/web-ele
│ ○ @vben/web-naive
│ ○ @vben/docs
diff --git a/docs/src/guide/introduction/quick-start.md b/docs/src/guide/introduction/quick-start.md
index 6b451ddf..f940672d 100644
--- a/docs/src/guide/introduction/quick-start.md
+++ b/docs/src/guide/introduction/quick-start.md
@@ -88,7 +88,8 @@ pnpm dev
```bash
│
◆ Select the app you need to run [dev]:
-│ ○ @vben/web-antd
+│ ● @vben/web-antd
+│ ○ @vben/web-antdv-next
│ ○ @vben/web-ele
│ ○ @vben/web-naive
│ ○ @vben/docs
diff --git a/package.json b/package.json
index aa438664..cf616d16 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
"commit": "czg",
"dev": "turbo-run dev",
"dev:antd": "pnpm -F @vben/web-antd run dev",
+ "dev:antdv-next": "pnpm -F @vben/web-antdv-next run dev",
"dev:docs": "pnpm -F @vben/docs run dev",
"dev:ele": "pnpm -F @vben/web-ele run dev",
"dev:naive": "pnpm -F @vben/web-naive run dev",
diff --git a/packages/@core/base/shared/src/constants/vben.ts b/packages/@core/base/shared/src/constants/vben.ts
index 5ba78f46..37b8cd09 100644
--- a/packages/@core/base/shared/src/constants/vben.ts
+++ b/packages/@core/base/shared/src/constants/vben.ts
@@ -19,6 +19,8 @@ export const VBEN_LOGO_URL =
*/
export const VBEN_PREVIEW_URL = 'https://www.vben.pro';
+export const VBEN_ANTDV_NEXT_PREVIEW_URL = 'https://antdv-next.vben.pro';
+
export const VBEN_ELE_PREVIEW_URL = 'https://ele.vben.pro';
export const VBEN_NAIVE_PREVIEW_URL = 'https://naive.vben.pro';
diff --git a/packages/icons/src/svg/icons/antdv-next-logo.svg b/packages/icons/src/svg/icons/antdv-next-logo.svg
new file mode 100644
index 00000000..b335be1d
--- /dev/null
+++ b/packages/icons/src/svg/icons/antdv-next-logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/icons/src/svg/index.ts b/packages/icons/src/svg/index.ts
index af83e317..5044a37f 100644
--- a/packages/icons/src/svg/index.ts
+++ b/packages/icons/src/svg/index.ts
@@ -17,9 +17,11 @@ const SvgQQChatIcon = createIconifyIcon('svg:qqchat');
const SvgWeChatIcon = createIconifyIcon('svg:wechat');
const SvgDingDingIcon = createIconifyIcon('svg:dingding');
const SvgTDesignIcon = createIconifyIcon('svg:tdesign-logo');
+const SvgAntdvNextLogoIcon = createIconifyIcon('svg:antdv-next-logo');
export {
SvgAntdvLogoIcon,
+ SvgAntdvNextLogoIcon,
SvgAvatar1Icon,
SvgAvatar2Icon,
SvgAvatar3Icon,
diff --git a/packages/styles/package.json b/packages/styles/package.json
index 0716a5e5..b7297495 100644
--- a/packages/styles/package.json
+++ b/packages/styles/package.json
@@ -18,6 +18,9 @@
"./antd": {
"default": "./src/antd/index.css"
},
+ "./antdv-next": {
+ "default": "./src/antdv-next/index.css"
+ },
"./ele": {
"default": "./src/ele/index.css"
},
diff --git a/packages/styles/src/antdv-next/index.css b/packages/styles/src/antdv-next/index.css
new file mode 100644
index 00000000..420dfe96
--- /dev/null
+++ b/packages/styles/src/antdv-next/index.css
@@ -0,0 +1,77 @@
+/* antdv-next 组件库的一些样式重置 */
+
+.ant-app {
+ width: 100%;
+ height: 100%;
+ overscroll-behavior: none;
+ color: inherit;
+}
+
+.ant-btn {
+ .anticon {
+ display: inline-flex;
+ }
+
+ /* * 修复按钮添加图标时的位置问题 */
+ > .ant-btn-icon {
+ svg {
+ display: inline-block;
+ }
+
+ svg + span {
+ margin-inline-start: 6px;
+ }
+ }
+}
+
+.ant-tag {
+ > svg {
+ display: inline-block;
+ }
+
+ > svg + span {
+ margin-inline-start: 4px;
+ }
+}
+
+.ant-message-notice-content,
+.ant-notification-notice {
+ @apply dark:border-border/60 dark:border;
+}
+
+.form-valid-error {
+ /** select 选择器的样式 */
+
+ .ant-select:not(.valid-success) {
+ border-color: hsl(var(--destructive)) !important;
+ }
+
+ .ant-select-focused {
+ box-shadow: 0 0 0 2px rgb(255 38 5 / 6%) !important;
+ }
+
+ /** 数字输入框样式 */
+ .ant-input-number-focused {
+ box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
+ }
+
+ /** 密码输入框样式 */
+ .ant-input-affix-wrapper:hover {
+ border-color: hsl(var(--destructive));
+ box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
+ }
+
+ .ant-input:not(.valid-success) {
+ border-color: hsl(var(--destructive)) !important;
+ }
+}
+
+/** 区间选择器下面来回切换时的样式 */
+.ant-app .form-valid-error .ant-picker-active-bar {
+ background-color: hsl(var(--destructive));
+}
+
+/** 时间选择器的样式 */
+.ant-app .form-valid-error .ant-picker-focused {
+ box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
+}
diff --git a/playground/src/locales/langs/en-US/demos.json b/playground/src/locales/langs/en-US/demos.json
index 8697ea3c..6b2fcfb9 100644
--- a/playground/src/locales/langs/en-US/demos.json
+++ b/playground/src/locales/langs/en-US/demos.json
@@ -64,6 +64,7 @@
"about": "About",
"document": "Document",
"antdv": "Ant Design Vue Version",
+ "antdv-next": "Antdv Next Version",
"naive-ui": "Naive UI Version",
"element-plus": "Element Plus Version",
"tdesign": "TDesign Vue Version"
diff --git a/playground/src/locales/langs/zh-CN/demos.json b/playground/src/locales/langs/zh-CN/demos.json
index b7823b72..9191a8ee 100644
--- a/playground/src/locales/langs/zh-CN/demos.json
+++ b/playground/src/locales/langs/zh-CN/demos.json
@@ -65,6 +65,7 @@
"about": "关于",
"document": "文档",
"antdv": "Ant Design Vue 版本",
+ "antdv-next": "Antdv Next 版本",
"naive-ui": "Naive UI 版本",
"element-plus": "Element Plus 版本",
"tdesign": "TDesign Vue 版本"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 26cee672..9525dc2a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -147,6 +147,9 @@ catalogs:
ant-design-vue:
specifier: ^4.2.6
version: 4.2.6
+ antdv-next:
+ specifier: ^1.0.2
+ version: 1.0.2
archiver:
specifier: ^7.0.1
version: 7.0.1
@@ -712,6 +715,69 @@ importers:
specifier: 'catalog:'
version: 4.6.4(vue@3.5.27(typescript@5.9.3))
+ apps/web-antdv-next:
+ dependencies:
+ '@vben/access':
+ specifier: workspace:*
+ version: link:../../packages/effects/access
+ '@vben/common-ui':
+ specifier: workspace:*
+ version: link:../../packages/effects/common-ui
+ '@vben/constants':
+ specifier: workspace:*
+ version: link:../../packages/constants
+ '@vben/hooks':
+ specifier: workspace:*
+ version: link:../../packages/effects/hooks
+ '@vben/icons':
+ specifier: workspace:*
+ version: link:../../packages/icons
+ '@vben/layouts':
+ specifier: workspace:*
+ version: link:../../packages/effects/layouts
+ '@vben/locales':
+ specifier: workspace:*
+ version: link:../../packages/locales
+ '@vben/plugins':
+ specifier: workspace:*
+ version: link:../../packages/effects/plugins
+ '@vben/preferences':
+ specifier: workspace:*
+ version: link:../../packages/preferences
+ '@vben/request':
+ specifier: workspace:*
+ version: link:../../packages/effects/request
+ '@vben/stores':
+ specifier: workspace:*
+ version: link:../../packages/stores
+ '@vben/styles':
+ specifier: workspace:*
+ version: link:../../packages/styles
+ '@vben/types':
+ specifier: workspace:*
+ version: link:../../packages/types
+ '@vben/utils':
+ specifier: workspace:*
+ version: link:../../packages/utils
+ '@vueuse/core':
+ specifier: 'catalog:'
+ version: 14.1.0(vue@3.5.27(typescript@5.9.3))
+ antdv-next:
+ specifier: 'catalog:'
+ version: 1.0.2(date-fns@4.1.0)(vue@3.5.27(typescript@5.9.3))
+ dayjs:
+ specifier: 'catalog:'
+ version: 1.11.19
+ pinia:
+ specifier: ^3.0.4
+ version: 3.0.4(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))
+ vue:
+ specifier: ^3.5.27
+ version: 3.5.27(typescript@5.9.3)
+ vue-router:
+ specifier: 'catalog:'
+ version: 4.6.4(vue@3.5.27(typescript@5.9.3))
+
apps/web-ele:
dependencies:
'@vben/access':
@@ -958,7 +1024,7 @@ importers:
dependencies:
'@commitlint/cli':
specifier: 'catalog:'
- version: 19.8.1(@types/node@24.10.9)(typescript@5.9.3)
+ version: 19.8.1(@types/node@25.0.10)(typescript@5.9.3)
'@commitlint/config-conventional':
specifier: 'catalog:'
version: 19.8.1
@@ -2082,6 +2148,17 @@ packages:
'@ant-design/colors@6.0.0':
resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==}
+ '@ant-design/colors@7.2.1':
+ resolution: {integrity: sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ==}
+
+ '@ant-design/fast-color@2.0.6':
+ resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==}
+ engines: {node: '>=8.x'}
+
+ '@ant-design/fast-color@3.0.1':
+ resolution: {integrity: sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw==}
+ engines: {node: '>=8.x'}
+
'@ant-design/icons-svg@4.4.2':
resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==}
@@ -2090,6 +2167,16 @@ packages:
peerDependencies:
vue: ^3.5.27
+ '@antdv-next/cssinjs@1.0.1':
+ resolution: {integrity: sha512-9C7f2dZ7seDLuRU7dy23dmyxsWGZyHl9OriDQvamYHjqpKf6WdJhdUkQpTZ7q63t6h5JXrDgX4VYZH3JD6hX3g==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@antdv-next/icons@1.0.0':
+ resolution: {integrity: sha512-O3gxRGEYOYsNbyPuhEqZ+HIDTakl6v3ukBDQwZ3ZvbzOPBorgdhMhHQ1WFjlLBCo72bdx5/wKyjz6oFRhk0G+g==}
+ peerDependencies:
+ vue: ^3.5.27
+
'@antfu/install-pkg@1.1.0':
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
@@ -3436,6 +3523,9 @@ packages:
'@emotion/hash@0.9.2':
resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==}
+ '@emotion/unitless@0.7.5':
+ resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==}
+
'@emotion/unitless@0.8.1':
resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==}
@@ -4789,6 +4879,220 @@ packages:
cpu: [x64]
os: [win32]
+ '@v-c/async-validator@1.0.0':
+ resolution: {integrity: sha512-nwi4hW/V3L5M4qY8cwScEuUonGfm1KRmN6aPwGpG9zhy7UDTEXKA3Tv4pdfjY9ryXKQc5TYo78TLSX9EjAPLUA==}
+
+ '@v-c/cascader@1.0.0':
+ resolution: {integrity: sha512-GoDcocPUnIgJOVknk96nxzx7Jkf9kFKJ+sjcZPT45pBynZvaMOFJ9ZLGMB2ZMOYtRr0SfXeqZ09lLy9c8PtwZw==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/checkbox@1.0.0':
+ resolution: {integrity: sha512-2abQmtpdYpQjb9+Xe9w1iPjdgSKDyQ1TpVq2QfTMdcj656S9npfDT2AH6HOgQV76oezV86dxgi1QG+lmXnDm0Q==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/collapse@1.0.0':
+ resolution: {integrity: sha512-y4NAl3j4mka193ZMDLHdISA8to61qoROG6/kTQ0myM2ZuEsonnEK1QWlqoEw3gveMsa6a4RdyoXLxdGdcJyp0Q==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/color-picker@1.0.4':
+ resolution: {integrity: sha512-VwNowJREYp25C6M39EHyTQ1nrxN2Usg96xGPupV2XiZs6wyKpXpXSjMbDXzD5/NKW1PKu/BTZOnrdLsrmY0mxg==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/dialog@1.0.1':
+ resolution: {integrity: sha512-8+HqvlDXGcgie4Z+sQB3HnMkkFN0N1zfIxdQwtpXTl+gWu9ue8tz+zI7pNXMq7XdM3DU6A+x+qeNRstJ2poCbw==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/drawer@1.0.0':
+ resolution: {integrity: sha512-1FhalqOqDmdvEfXGmlEZtwbeZBMKeK3+LIeDfXfqUiLy38QMMDTxMARmnHCxUGhuj20zFxrZUl0sxNEaTjTkEA==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/dropdown@1.0.2':
+ resolution: {integrity: sha512-D6TACf3jUiRWx4xW5h2+wVT9SMYxUasFlAHESYJr4ZMjLTLLM1Q8iBjkjhGF+vA0eYR5zqRTwlaacN0DNDZBPw==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/image@1.0.2':
+ resolution: {integrity: sha512-uTAhX+SRWjQHIUPJ0DAYUSzOEVnVDAmZazJNP5OqCqLuncrS7hUN37CQ1XgNKaF2Dt8b1aPFZlpXYb/zXfQdXw==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/input-number@1.0.2':
+ resolution: {integrity: sha512-9wbAmdC0Nt18XlLLgfVbmulY50K7tc5RZsNeZuWnmqluTK3JTgZRSbPdRkzl308x8vtGyCOufnepsMrFei1NoQ==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/input@1.0.2':
+ resolution: {integrity: sha512-NzBor6XbUYP42zRrcaBUgWtQI1aIaN3oylmMdvSZ5UMcWsAXRNC8XKsedkFF/LLOEJBJ2NaTbomHRwkIjmtQAA==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/mentions@1.0.0':
+ resolution: {integrity: sha512-trkG1lvfiaIY7UnHn0gx6B01o3rFLEMin3KGp1q4oU6zOCRWde4ejZ+EHSvmXzOz2N+FlRMTE4EMJFi4w0oOlQ==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/menu@1.0.10':
+ resolution: {integrity: sha512-iKXuPpZteVjPlg3nQ+4YbAlYa3/I21N/5RswKLai61IRO/8IcfRLc+YBEoG3n5xV+I5b2Yby2iJjsA8lU1En/w==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/mini-decimal@1.0.1':
+ resolution: {integrity: sha512-76wZLdlkI017iDlaZMNOWZyDCv29YVabUJn5urQgIKtW4dnI5AkNXWtmLyhl/mu/OS7ZGisRi5ai/558QhLQxQ==}
+
+ '@v-c/mutate-observer@1.0.1':
+ resolution: {integrity: sha512-84+9KGORX8LY9u+K0DEGyRwRCJaky0sjRkXxBC7X/jahHJl8NQGQ0Gxve5IVwaxRTfZ9eftlRmHs90JD6Utfqg==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/notification@1.0.0':
+ resolution: {integrity: sha512-aU5g+ZiYxp0KVdKuho067wJRF38Mv7MrQS95dwSJLsbDmVFBpjO3Lo3ptakfPkwn+7uwRytHKIf39t9QVGk+sg==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/overflow@1.0.3':
+ resolution: {integrity: sha512-GVWxd2gk9T0t9kO7EH1fMy2DgYULle/D+GBXiEeB5j/V1b9Gj39pvFLA1EHuiiyJW56Lr/P/uJ/ZM38WFh755w==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/pagination@1.0.0':
+ resolution: {integrity: sha512-uYIMkvHKMtY+nwHTu5rXxiq6KPf0zGpZbtQTn1nDPng0tOyA1vLQ+R6OfE+1LOwuQqvFTEDnAq4vb90By+eBfw==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/picker@1.0.2':
+ resolution: {integrity: sha512-Lf9qPZ/hODaIBEoXpkpGmHK5oXubquia8bYN8zVWigr312jbl/bI6txRF4p+zci0UTtJQsOX1zp9fqX8rg0vSA==}
+ peerDependencies:
+ date-fns: '>= 2.x'
+ dayjs: '>= 1.x'
+ luxon: '>= 3.x'
+ moment: '>= 2.x'
+ vue: ^3.5.27
+ peerDependenciesMeta:
+ date-fns:
+ optional: true
+ dayjs:
+ optional: true
+ luxon:
+ optional: true
+ moment:
+ optional: true
+
+ '@v-c/portal@1.0.7':
+ resolution: {integrity: sha512-iIcU+9C8GNas7BWMXlWkwz9RoB8E7B4f0D+qPNTPLUbdwDvKRNypATYImkIWK/BSGDHOkxu1kIBshxgolaODfA==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/progress@1.0.0':
+ resolution: {integrity: sha512-kWDTU1uXnPDMmoezwyAECxuSH+WKn92OjSdk/GgDbQgZ0qNy9woOiRe5fOsrcy61agHdJxzf0MvsUy1b6bZVlA==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/qrcode@1.0.0':
+ resolution: {integrity: sha512-OSMrYDhP/NQiUcO6J0X2X8BskHPRqX/E/F9npH3oayZgjCo5Aom+63Ja3J0u6SOmKP1JgLSgjrm5karc0671jw==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/rate@1.0.0':
+ resolution: {integrity: sha512-H2cj/dS3guxq9s79HlTzu8uUzH/dQM8Ko5zlPosWrBI33YvySqoxcShY8cZS/tcq8I4xDE/SjeAmBe7rHd9VEA==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/resize-observer@1.0.8':
+ resolution: {integrity: sha512-VH8WBsNfZA5KQ+CXVaQ1PK5B6FIHnuTdqOLrjRWiZTrIYDZi/MyREi9b21YDj55fbFWMRx4yapnO9tiZX1RNxA==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/segmented@1.0.0':
+ resolution: {integrity: sha512-HWo8Ck6Lg0epTEvw5d2yhE+mU/SOxTN6/ngMXLz7iwGI2TwskKu8l+atOSNcJ7XqS/QgsqIHpL26GATPOS8qvQ==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/select@1.0.9':
+ resolution: {integrity: sha512-RpZMtjKi3BIWj2+SKJKFKhydBE0Q0vZYyJduJZ6GioBi7JF26JPQuwZOsthaHDVr6oaOoc9ejlSAQqP92tFIKA==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/slick@1.0.0':
+ resolution: {integrity: sha512-Pzb4bahxbXvXTCmgOJ9OX6Ek1joUHx0EFUxmjDSAfrvaAkHWv2pSqGLDF0CJvm+/uG+rcdT2YQUNcxMtKInQ3A==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/slider@1.0.10':
+ resolution: {integrity: sha512-KMIVytBm8K8RQ+aPPraS28GmBptGHESF/gDRbGjOLD7xyivuQDJeEqVaUFY3EcCWsERjh4VP/L96gUbMTF0uag==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/steps@1.0.0':
+ resolution: {integrity: sha512-DPL0OOb8pDLlTPZB93b8+Saxiz6V5zEpGXKaCnsbXUuOhimkc7089AuEKfpMw+8x1SrVe+gapWf5RRHWXUm2pg==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/switch@1.0.0':
+ resolution: {integrity: sha512-VIem244KJkYfqDgofpgHjK00sGL9rJ/9OtmK4Gbs4hnPsrTtzHDBRltYxR4IT7HQleathZfj6NhcZ1bjdWKYUw==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/table@1.0.0':
+ resolution: {integrity: sha512-1/TMEppX3BpLYYSXzAcwrD5Os6O1VX5OGZsvGyqIp9A8Iy8QeI4Vb54XizGyooHNMs378RIWzX4yDe9JxYMm/A==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/tabs@1.0.1':
+ resolution: {integrity: sha512-6G6cWKdxb8l3IuR802mZGV+l8GAvCEJCoVQcyG3BwiBYOeOii6eyET5D+yMp7mC7dsFRxc2y7q0krxyo97CosQ==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/textarea@1.0.3':
+ resolution: {integrity: sha512-oCpqdOyiNPFgLRUw913IjTdIMVtryy9maJEaSz+ledn/cVO4OJ44dEP8eCnhxlHTfduLKesKIlDoRIBhLu4qqQ==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/tooltip@1.0.2':
+ resolution: {integrity: sha512-EwKbftSPCBrp+D40qMXV0/IzOIshQ6Wm5a+yYBZKJxF03uR0sUkQP+/cj7V55Gr9rDJ5G1EaxQjCuQAezwhzig==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/tour@1.0.3':
+ resolution: {integrity: sha512-y4DVJPP7jvL+MWUMAKQWxLAMXSWJEfZXaKASPn3DKbSQ8drBhsjMXwcep3glAfrCjCKfj/QD3OrUMxqydi4qFw==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/tree-select@1.0.0':
+ resolution: {integrity: sha512-EOUt3zBFMm2wCCDgY5pYU2mjff7NQiGss0uM/J2dOw8JP3LgPjhCuT2/0ZgXt6HkqK+Fl5AdhzxYujGbgTw6Ow==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/tree@1.0.2':
+ resolution: {integrity: sha512-Z/x1DuazauoPtuKWaL6iaNdTq6t/c+6j8dbOxQN7kAJOW4RJ8BKKx8DA0fq49R7OCUH/YQLOWTrWI5gyQ0169A==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/trigger@1.0.10':
+ resolution: {integrity: sha512-wPX/RBzJ7JzSShqBZlX8IWFPpa9c5jHvxzGdGTukBRukuPDBuXLLKHgt9IIpkqukuJuN3HLU39m+uuUK1rZ4Lg==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/upload@1.0.0':
+ resolution: {integrity: sha512-W92PNCD61aM/B5w8oUzHQSDHur1T8484726Ls0IoNMO5nPiF/15eEE3RuuI/t7xXQVP/fA06hNSwzXwGWdDg1w==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/util@1.0.13':
+ resolution: {integrity: sha512-/CUsbqrgqMz2TGqdzUnq1jwNFwX6lqy+HsYzmGH8auTUly9buIQiDmoxLxnjsI2XO6IryCqhzOP2Ii1213zqtA==}
+ peerDependencies:
+ vue: ^3.5.27
+
+ '@v-c/virtual-list@1.0.5':
+ resolution: {integrity: sha512-hv+ZIXkT7Bprv4pRloa/EYfWsJjOL2hI6wRSWX/XOxMcra+eq9uFvTY5GSOzYURPyzA/ExGq4607+fl1vEhwZQ==}
+ peerDependencies:
+ vue: ^3.5.27
+
'@vee-validate/zod@4.15.1':
resolution: {integrity: sha512-329Z4TDBE5Vx0FdbA8S4eR9iGCFFUNGbxjpQ20ff5b5wGueScjocUIx9JHPa79LTG06RnlUR4XogQsjN4tecKA==}
peerDependencies:
@@ -4984,6 +5288,11 @@ packages:
peerDependencies:
vue: ^3.5.27
+ '@vueuse/core@14.2.0':
+ resolution: {integrity: sha512-tpjzVl7KCQNVd/qcaCE9XbejL38V6KJAEq/tVXj7mDPtl6JtzmUdnXelSS+ULRkkrDgzYVK7EerQJvd2jR794Q==}
+ peerDependencies:
+ vue: ^3.5.27
+
'@vueuse/integrations@12.8.2':
resolution: {integrity: sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==}
peerDependencies:
@@ -5079,6 +5388,9 @@ packages:
'@vueuse/metadata@14.1.0':
resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==}
+ '@vueuse/metadata@14.2.0':
+ resolution: {integrity: sha512-i3axTGjU8b13FtyR4Keeama+43iD+BwX9C2TmzBVKqjSHArF03hjkp2SBZ1m72Jk2UtrX0aYCugBq2R1fhkuAQ==}
+
'@vueuse/motion@3.0.3':
resolution: {integrity: sha512-4B+ITsxCI9cojikvrpaJcLXyq0spj3sdlzXjzesWdMRd99hhtFI6OJ/1JsqwtF73YooLe0hUn/xDR6qCtmn5GQ==}
peerDependencies:
@@ -5100,6 +5412,11 @@ packages:
peerDependencies:
vue: ^3.5.27
+ '@vueuse/shared@14.2.0':
+ resolution: {integrity: sha512-Z0bmluZTlAXgUcJ4uAFaML16JcD8V0QG00Db3quR642I99JXIDRa2MI2LGxiLVhcBjVnL1jOzIvT5TT2lqJlkA==}
+ peerDependencies:
+ vue: ^3.5.27
+
'@vxe-ui/core@4.3.1':
resolution: {integrity: sha512-sr2WdFDWM3IKID02HbSaDxxRDvj1LZ5ZkOnH2POvGkkCfCWItkx3avkizfRUk8RtjNU+wXozaPbYTNha5kjSdg==}
peerDependencies:
@@ -5215,6 +5532,9 @@ packages:
peerDependencies:
vue: ^3.5.27
+ antdv-next@1.0.2:
+ resolution: {integrity: sha512-JkPXDLk7MfAtye2pS3z/heLiUeow1K3JJCAnmaM+vzZhCds+wXUCNNHJ03qUIQvKCNbFdko4OJ9p0dY/pDJncg==}
+
any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
@@ -5716,6 +6036,9 @@ packages:
compute-scroll-into-view@1.0.20:
resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==}
+ compute-scroll-into-view@3.1.1:
+ resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
+
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@@ -6355,6 +6678,9 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
+ es-toolkit@1.43.0:
+ resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==}
+
es-toolkit@1.44.0:
resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==}
@@ -9362,6 +9688,9 @@ packages:
scroll-into-view-if-needed@2.2.31:
resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==}
+ scroll-into-view-if-needed@3.1.0:
+ resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==}
+
scslre@0.3.0:
resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
engines: {node: ^14.0.0 || >=16.0.0}
@@ -10978,6 +11307,16 @@ snapshots:
dependencies:
'@ctrl/tinycolor': 4.2.0
+ '@ant-design/colors@7.2.1':
+ dependencies:
+ '@ant-design/fast-color': 2.0.6
+
+ '@ant-design/fast-color@2.0.6':
+ dependencies:
+ '@babel/runtime': 7.28.6
+
+ '@ant-design/fast-color@3.0.1': {}
+
'@ant-design/icons-svg@4.4.2': {}
'@ant-design/icons-vue@7.0.1(vue@3.5.27(typescript@5.9.3))':
@@ -10986,6 +11325,24 @@ snapshots:
'@ant-design/icons-svg': 4.4.2
vue: 3.5.27(typescript@5.9.3)
+ '@antdv-next/cssinjs@1.0.1(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@emotion/hash': 0.8.0
+ '@emotion/unitless': 0.7.5
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ csstype: 3.2.3
+ defu: 6.1.4
+ stylis: 4.3.6
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@antdv-next/icons@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@ant-design/colors': 7.2.1
+ '@ant-design/icons-svg': 4.4.2
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ es-toolkit: 1.43.0
+ vue: 3.5.27(typescript@5.9.3)
+
'@antfu/install-pkg@1.1.0':
dependencies:
package-manager-detector: 1.6.0
@@ -11926,11 +12283,11 @@ snapshots:
'@cloudflare/kv-asset-handler@0.4.2': {}
- '@commitlint/cli@19.8.1(@types/node@24.10.9)(typescript@5.9.3)':
+ '@commitlint/cli@19.8.1(@types/node@25.0.10)(typescript@5.9.3)':
dependencies:
'@commitlint/format': 19.8.1
'@commitlint/lint': 19.8.1
- '@commitlint/load': 19.8.1(@types/node@24.10.9)(typescript@5.9.3)
+ '@commitlint/load': 19.8.1(@types/node@25.0.10)(typescript@5.9.3)
'@commitlint/read': 19.8.1
'@commitlint/types': 19.8.1
tinyexec: 1.0.2
@@ -11977,7 +12334,7 @@ snapshots:
'@commitlint/rules': 19.8.1
'@commitlint/types': 19.8.1
- '@commitlint/load@19.8.1(@types/node@24.10.9)(typescript@5.9.3)':
+ '@commitlint/load@19.8.1(@types/node@25.0.10)(typescript@5.9.3)':
dependencies:
'@commitlint/config-validator': 19.8.1
'@commitlint/execute-rule': 19.8.1
@@ -11985,7 +12342,7 @@ snapshots:
'@commitlint/types': 19.8.1
chalk: 5.6.2
cosmiconfig: 9.0.0(typescript@5.9.3)
- cosmiconfig-typescript-loader: 6.2.0(@types/node@24.10.9)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3)
+ cosmiconfig-typescript-loader: 6.2.0(@types/node@25.0.10)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3)
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
lodash.uniq: 4.5.0
@@ -12627,6 +12984,8 @@ snapshots:
'@emotion/hash@0.9.2': {}
+ '@emotion/unitless@0.7.5': {}
+
'@emotion/unitless@0.8.1': {}
'@epic-web/invariant@1.0.0': {}
@@ -13968,6 +14327,249 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true
+ '@v-c/async-validator@1.0.0': {}
+
+ '@v-c/cascader@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/select': 1.0.9(vue@3.5.27(typescript@5.9.3))
+ '@v-c/tree': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/checkbox@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/collapse@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/color-picker@1.0.4(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@ant-design/fast-color': 3.0.1
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/dialog@1.0.1(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/portal': 1.0.7(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/drawer@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/portal': 1.0.7(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/dropdown@1.0.2(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/trigger': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/image@1.0.2(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/portal': 1.0.7(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/input-number@1.0.2(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/input': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/mini-decimal': 1.0.1
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/input@1.0.2(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/mentions@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/input': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/menu': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/textarea': 1.0.3(vue@3.5.27(typescript@5.9.3))
+ '@v-c/trigger': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/menu@1.0.10(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/overflow': 1.0.3(vue@3.5.27(typescript@5.9.3))
+ '@v-c/trigger': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/mini-decimal@1.0.1': {}
+
+ '@v-c/mutate-observer@1.0.1(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/resize-observer': 1.0.8(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/notification@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/overflow@1.0.3(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/resize-observer': 1.0.8(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/pagination@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/picker@1.0.2(date-fns@4.1.0)(dayjs@1.11.19)(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/overflow': 1.0.3(vue@3.5.27(typescript@5.9.3))
+ '@v-c/resize-observer': 1.0.8(vue@3.5.27(typescript@5.9.3))
+ '@v-c/trigger': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+ optionalDependencies:
+ date-fns: 4.1.0
+ dayjs: 1.11.19
+
+ '@v-c/portal@1.0.7(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/progress@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/qrcode@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/rate@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/resize-observer@1.0.8(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ resize-observer-polyfill: 1.5.1
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/segmented@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/select@1.0.9(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/overflow': 1.0.3(vue@3.5.27(typescript@5.9.3))
+ '@v-c/trigger': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ '@v-c/virtual-list': 1.0.5(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/slick@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ es-toolkit: 1.44.0
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/slider@1.0.10(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/steps@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/switch@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/table@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/resize-observer': 1.0.8(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ '@v-c/virtual-list': 1.0.5(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/tabs@1.0.1(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/dropdown': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/menu': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/overflow': 1.0.3(vue@3.5.27(typescript@5.9.3))
+ '@v-c/resize-observer': 1.0.8(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/textarea@1.0.3(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/input': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/resize-observer': 1.0.8(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/tooltip@1.0.2(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/trigger': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/tour@1.0.3(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/portal': 1.0.7(vue@3.5.27(typescript@5.9.3))
+ '@v-c/trigger': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/tree-select@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/select': 1.0.9(vue@3.5.27(typescript@5.9.3))
+ '@v-c/tree': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/tree@1.0.2(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ '@v-c/virtual-list': 1.0.5(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/trigger@1.0.10(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/portal': 1.0.7(vue@3.5.27(typescript@5.9.3))
+ '@v-c/resize-observer': 1.0.8(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/upload@1.0.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/util@1.0.13(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ vue: 3.5.27(typescript@5.9.3)
+
+ '@v-c/virtual-list@1.0.5(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@v-c/resize-observer': 1.0.8(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
'@vee-validate/zod@4.15.1(vue@3.5.27(typescript@5.9.3))(zod@3.25.76)':
dependencies:
type-fest: 4.41.0
@@ -14318,6 +14920,13 @@ snapshots:
'@vueuse/shared': 14.1.0(vue@3.5.27(typescript@5.9.3))
vue: 3.5.27(typescript@5.9.3)
+ '@vueuse/core@14.2.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ '@types/web-bluetooth': 0.0.21
+ '@vueuse/metadata': 14.2.0
+ '@vueuse/shared': 14.2.0(vue@3.5.27(typescript@5.9.3))
+ vue: 3.5.27(typescript@5.9.3)
+
'@vueuse/integrations@12.8.2(async-validator@4.2.5)(axios@1.13.4)(change-case@5.4.4)(focus-trap@7.8.0)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.6)(typescript@5.9.3)':
dependencies:
'@vueuse/core': 12.8.2(typescript@5.9.3)
@@ -14356,6 +14965,8 @@ snapshots:
'@vueuse/metadata@14.1.0': {}
+ '@vueuse/metadata@14.2.0': {}
+
'@vueuse/motion@3.0.3(magicast@0.5.1)(vue@3.5.27(typescript@5.9.3))':
dependencies:
'@vueuse/core': 13.9.0(vue@3.5.27(typescript@5.9.3))
@@ -14391,6 +15002,10 @@ snapshots:
dependencies:
vue: 3.5.27(typescript@5.9.3)
+ '@vueuse/shared@14.2.0(vue@3.5.27(typescript@5.9.3))':
+ dependencies:
+ vue: 3.5.27(typescript@5.9.3)
+
'@vxe-ui/core@4.3.1(vue@3.5.27(typescript@5.9.3))':
dependencies:
dom-zindex: 1.0.6
@@ -14527,6 +15142,62 @@ snapshots:
vue-types: 3.0.2(vue@3.5.27(typescript@5.9.3))
warning: 4.0.3
+ antdv-next@1.0.2(date-fns@4.1.0)(vue@3.5.27(typescript@5.9.3)):
+ dependencies:
+ '@ant-design/colors': 7.2.1
+ '@ant-design/fast-color': 3.0.1
+ '@antdv-next/cssinjs': 1.0.1(vue@3.5.27(typescript@5.9.3))
+ '@antdv-next/icons': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/async-validator': 1.0.0
+ '@v-c/cascader': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/checkbox': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/collapse': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/color-picker': 1.0.4(vue@3.5.27(typescript@5.9.3))
+ '@v-c/dialog': 1.0.1(vue@3.5.27(typescript@5.9.3))
+ '@v-c/drawer': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/dropdown': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/image': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/input': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/input-number': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/mentions': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/menu': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/mutate-observer': 1.0.1(vue@3.5.27(typescript@5.9.3))
+ '@v-c/notification': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/pagination': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/picker': 1.0.2(date-fns@4.1.0)(dayjs@1.11.19)(vue@3.5.27(typescript@5.9.3))
+ '@v-c/progress': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/qrcode': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/rate': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/resize-observer': 1.0.8(vue@3.5.27(typescript@5.9.3))
+ '@v-c/segmented': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/select': 1.0.9(vue@3.5.27(typescript@5.9.3))
+ '@v-c/slick': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/slider': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/steps': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/switch': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/table': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/tabs': 1.0.1(vue@3.5.27(typescript@5.9.3))
+ '@v-c/textarea': 1.0.3(vue@3.5.27(typescript@5.9.3))
+ '@v-c/tooltip': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/tour': 1.0.3(vue@3.5.27(typescript@5.9.3))
+ '@v-c/tree': 1.0.2(vue@3.5.27(typescript@5.9.3))
+ '@v-c/tree-select': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/trigger': 1.0.10(vue@3.5.27(typescript@5.9.3))
+ '@v-c/upload': 1.0.0(vue@3.5.27(typescript@5.9.3))
+ '@v-c/util': 1.0.13(vue@3.5.27(typescript@5.9.3))
+ '@v-c/virtual-list': 1.0.5(vue@3.5.27(typescript@5.9.3))
+ '@vueuse/core': 14.2.0(vue@3.5.27(typescript@5.9.3))
+ dayjs: 1.11.19
+ defu: 6.1.4
+ es-toolkit: 1.43.0
+ scroll-into-view-if-needed: 3.1.0
+ throttle-debounce: 5.0.2
+ transitivePeerDependencies:
+ - date-fns
+ - luxon
+ - moment
+ - vue
+
any-promise@1.3.0: {}
anymatch@3.1.3:
@@ -15064,6 +15735,8 @@ snapshots:
compute-scroll-into-view@1.0.20: {}
+ compute-scroll-into-view@3.1.1: {}
+
concat-map@0.0.1: {}
confbox@0.1.8: {}
@@ -15125,9 +15798,9 @@ snapshots:
core-util-is@1.0.3: {}
- cosmiconfig-typescript-loader@6.2.0(@types/node@24.10.9)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3):
+ cosmiconfig-typescript-loader@6.2.0(@types/node@25.0.10)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3):
dependencies:
- '@types/node': 24.10.9
+ '@types/node': 25.0.10
cosmiconfig: 9.0.0(typescript@5.9.3)
jiti: 2.6.1
typescript: 5.9.3
@@ -15780,6 +16453,8 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
+ es-toolkit@1.43.0: {}
+
es-toolkit@1.44.0: {}
esbuild@0.25.12:
@@ -18950,6 +19625,10 @@ snapshots:
dependencies:
compute-scroll-into-view: 1.0.20
+ scroll-into-view-if-needed@3.1.0:
+ dependencies:
+ compute-scroll-into-view: 3.1.1
+
scslre@0.3.0:
dependencies:
'@eslint-community/regexpp': 4.12.2
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 0460629b..b2d70f29 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -72,6 +72,7 @@ catalog:
'@vueuse/integrations': ^14.1.0
'@vueuse/motion': ^3.0.3
ant-design-vue: ^4.2.6
+ antdv-next: ^1.0.2
archiver: ^7.0.1
autoprefixer: ^10.4.23
axios: ^1.13.4
diff --git a/vben-admin.code-workspace b/vben-admin.code-workspace
index 33df5a75..a18a9f48 100644
--- a/vben-admin.code-workspace
+++ b/vben-admin.code-workspace
@@ -8,6 +8,10 @@
"name": "@vben/web-antd",
"path": "apps/web-antd",
},
+ {
+ "name": "@vben/web-antdv-next",
+ "path": "apps/web-antdv-next",
+ },
{
"name": "@vben/web-ele",
"path": "apps/web-ele",