diff --git a/apps/web-antd/package.json b/apps/web-antd/package.json
index c608b554d..164d7449a 100644
--- a/apps/web-antd/package.json
+++ b/apps/web-antd/package.json
@@ -45,6 +45,7 @@
"@vben/utils": "workspace:*",
"@vueuse/core": "catalog:",
"ant-design-vue": "catalog:",
+ "vxe-table": "catalog:",
"cropperjs": "catalog:",
"crypto-js": "catalog:",
"dayjs": "catalog:",
diff --git a/apps/web-antd/src/bootstrap.ts b/apps/web-antd/src/bootstrap.ts
index 68d19ee1a..c90d9f269 100644
--- a/apps/web-antd/src/bootstrap.ts
+++ b/apps/web-antd/src/bootstrap.ts
@@ -7,6 +7,7 @@ import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores';
import '@vben/styles';
import '@vben/styles/antd';
+import 'vxe-table/styles/cssvar.scss';
import { useTitle } from '@vueuse/core';
diff --git a/apps/web-antd/src/components/content-wrap/content-wrap.vue b/apps/web-antd/src/components/content-wrap/content-wrap.vue
new file mode 100644
index 000000000..026d7d23f
--- /dev/null
+++ b/apps/web-antd/src/components/content-wrap/content-wrap.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/components/content-wrap/index.ts b/apps/web-antd/src/components/content-wrap/index.ts
new file mode 100644
index 000000000..d4f95fddb
--- /dev/null
+++ b/apps/web-antd/src/components/content-wrap/index.ts
@@ -0,0 +1 @@
+export { default as ContentWrap } from './content-wrap.vue';
diff --git a/apps/web-antd/src/components/description/description.vue b/apps/web-antd/src/components/description/description.vue
new file mode 100644
index 000000000..411333778
--- /dev/null
+++ b/apps/web-antd/src/components/description/description.vue
@@ -0,0 +1,71 @@
+
diff --git a/apps/web-antd/src/components/description/index.ts b/apps/web-antd/src/components/description/index.ts
new file mode 100644
index 000000000..a707c4865
--- /dev/null
+++ b/apps/web-antd/src/components/description/index.ts
@@ -0,0 +1,3 @@
+export { default as Description } from './description.vue';
+export * from './typing';
+export { useDescription } from './use-description';
diff --git a/apps/web-antd/src/components/description/typing.ts b/apps/web-antd/src/components/description/typing.ts
new file mode 100644
index 000000000..98e3a52d1
--- /dev/null
+++ b/apps/web-antd/src/components/description/typing.ts
@@ -0,0 +1,18 @@
+import type { DescriptionsProps } from 'ant-design-vue';
+import type { CSSProperties, VNode } from 'vue';
+
+export interface DescriptionItemSchema {
+ label: string | VNode; // 内容的描述
+ field?: string; // 对应 data 中的字段名
+ content?: ((data: any) => string | VNode) | string | VNode; // 自定义需要展示的内容,比如说 dict-tag
+ span?: number; // 包含列的数量
+ labelStyle?: CSSProperties; // 自定义标签样式
+ contentStyle?: CSSProperties; // 自定义内容样式
+ hidden?: ((data: any) => boolean) | boolean; // 是否显示
+}
+
+export interface DescriptionsOptions {
+ data?: Record; // 数据
+ schema?: DescriptionItemSchema[]; // 描述项配置
+ componentProps?: DescriptionsProps; // antd Descriptions 组件参数
+}
diff --git a/apps/web-antd/src/components/description/use-description.ts b/apps/web-antd/src/components/description/use-description.ts
new file mode 100644
index 000000000..8cf44ccfa
--- /dev/null
+++ b/apps/web-antd/src/components/description/use-description.ts
@@ -0,0 +1,70 @@
+import type { DescriptionsOptions } from './typing';
+
+import { defineComponent, h, isReactive, reactive, watch } from 'vue';
+
+import { Description } from './index';
+
+/** 描述列表 api 定义 */
+class DescriptionApi {
+ private state = reactive>({});
+
+ constructor(options: DescriptionsOptions) {
+ this.state = { ...options };
+ }
+
+ getState(): DescriptionsOptions {
+ return this.state as DescriptionsOptions;
+ }
+
+ setState(newState: Partial) {
+ this.state = { ...this.state, ...newState };
+ }
+}
+
+export type ExtendedDescriptionApi = DescriptionApi;
+
+export function useDescription(options: DescriptionsOptions) {
+ const IS_REACTIVE = isReactive(options);
+ const api = new DescriptionApi(options);
+ // 扩展API
+ const extendedApi: ExtendedDescriptionApi = api as never;
+ const Desc = defineComponent({
+ name: 'UseDescription',
+ inheritAttrs: false,
+ setup(_, { attrs, slots }) {
+ // 合并props和attrs到state
+ api.setState({ ...attrs });
+
+ return () =>
+ h(
+ Description,
+ {
+ ...api.getState(),
+ ...attrs,
+ },
+ slots,
+ );
+ },
+ });
+
+ // 响应式支持
+ if (IS_REACTIVE) {
+ watch(
+ () => options.schema,
+ (newSchema) => {
+ api.setState({ schema: newSchema });
+ },
+ { immediate: true, deep: true },
+ );
+
+ watch(
+ () => options.data,
+ (newData) => {
+ api.setState({ data: newData });
+ },
+ { immediate: true, deep: true },
+ );
+ }
+
+ return [Desc, extendedApi] as const;
+}
diff --git a/apps/web-antd/src/utils/dict.ts b/apps/web-antd/src/utils/dict.ts
index c2c15b755..968974b6c 100644
--- a/apps/web-antd/src/utils/dict.ts
+++ b/apps/web-antd/src/utils/dict.ts
@@ -64,7 +64,7 @@ function getDictObj(dictType: string, value: any) {
function getDictOptions(
dictType: string,
valueType: 'boolean' | 'number' | 'string' = 'string',
-) {
+): any[] {
const dictStore = useDictStore();
const dictOpts = dictStore.getDictOptions(dictType);
const dictOptions: DefaultOptionType = [];
diff --git a/apps/web-antd/src/views/infra/demo/general/demo01/index.vue b/apps/web-antd/src/views/infra/demo/general/demo01/index.vue
new file mode 100644
index 000000000..01a8b5fab
--- /dev/null
+++ b/apps/web-antd/src/views/infra/demo/general/demo01/index.vue
@@ -0,0 +1,223 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formatDateTime(row.birthday) }}
+
+
+
+
+
+
+ {{ formatDateTime(row.createTime) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/infra/demo/general/demo01/modules/form.vue b/apps/web-antd/src/views/infra/demo/general/demo01/modules/form.vue
new file mode 100644
index 000000000..8f95c8044
--- /dev/null
+++ b/apps/web-antd/src/views/infra/demo/general/demo01/modules/form.vue
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+ {{ dict.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/system/notify/my/modules/detail.vue b/apps/web-antd/src/views/system/notify/my/modules/detail.vue
index cdad97dae..2c5275c35 100644
--- a/apps/web-antd/src/views/system/notify/my/modules/detail.vue
+++ b/apps/web-antd/src/views/system/notify/my/modules/detail.vue
@@ -1,18 +1,56 @@
-
-
-
- {{ formData?.templateNickname }}
-
-
- {{ formatDateTime(formData?.createTime) }}
-
-
-
-
-
-
-
-
- {{ formatDateTime(formData?.readTime || '') }}
-
-
- {{ formData?.templateContent }}
-
-
+
+
diff --git a/packages/@core/base/icons/src/lucide.ts b/packages/@core/base/icons/src/lucide.ts
index 2a5de70bd..21ac04e2e 100644
--- a/packages/@core/base/icons/src/lucide.ts
+++ b/packages/@core/base/icons/src/lucide.ts
@@ -69,4 +69,5 @@ export {
Upload,
UserRoundPen,
X,
+ RefreshCw,
} from 'lucide-vue-next';