diff --git a/apps/backend-mock/utils/mock-data.ts b/apps/backend-mock/utils/mock-data.ts index 71970a28..057588e3 100644 --- a/apps/backend-mock/utils/mock-data.ts +++ b/apps/backend-mock/utils/mock-data.ts @@ -4,6 +4,7 @@ export interface UserInfo { realName: string; roles: string[]; username: string; + homePath?: string; } export const MOCK_USERS: UserInfo[] = [ @@ -20,6 +21,7 @@ export const MOCK_USERS: UserInfo[] = [ realName: 'Admin', roles: ['admin'], username: 'admin', + homePath: '/workspace', }, { id: 2, @@ -27,6 +29,7 @@ export const MOCK_USERS: UserInfo[] = [ realName: 'Jack', roles: ['user'], username: 'jack', + homePath: '/analytics', }, ]; diff --git a/apps/web-antd/src/router/guard.ts b/apps/web-antd/src/router/guard.ts index 94213301..e7988eb8 100644 --- a/apps/web-antd/src/router/guard.ts +++ b/apps/web-antd/src/router/guard.ts @@ -54,7 +54,9 @@ function setupAccessGuard(router: Router) { if (coreRouteNames.includes(to.name as string)) { if (to.path === LOGIN_PATH && accessStore.accessToken) { return decodeURIComponent( - (to.query?.redirect as string) || DEFAULT_HOME_PATH, + (to.query?.redirect as string) || + userStore.userInfo?.homePath || + DEFAULT_HOME_PATH, ); } return true; @@ -72,7 +74,10 @@ function setupAccessGuard(router: Router) { return { path: LOGIN_PATH, // 如不需要,直接删除 query - query: { redirect: encodeURIComponent(to.fullPath) }, + query: + to.fullPath === DEFAULT_HOME_PATH + ? {} + : { redirect: encodeURIComponent(to.fullPath) }, // 携带当前跳转的页面,登录后重新跳转该页面 replace: true, }; @@ -104,7 +109,10 @@ function setupAccessGuard(router: Router) { accessStore.setAccessMenus(accessibleMenus); accessStore.setAccessRoutes(accessibleRoutes); accessStore.setIsAccessChecked(true); - const redirectPath = (from.query.redirect ?? to.fullPath) as string; + const redirectPath = (from.query.redirect ?? + (to.path === DEFAULT_HOME_PATH + ? userInfo.homePath || DEFAULT_HOME_PATH + : to.fullPath)) as string; return { ...router.resolve(decodeURIComponent(redirectPath)), diff --git a/apps/web-ele/src/router/guard.ts b/apps/web-ele/src/router/guard.ts index fce5a892..cbb5235e 100644 --- a/apps/web-ele/src/router/guard.ts +++ b/apps/web-ele/src/router/guard.ts @@ -54,7 +54,9 @@ function setupAccessGuard(router: Router) { if (coreRouteNames.includes(to.name as string)) { if (to.path === LOGIN_PATH && accessStore.accessToken) { return decodeURIComponent( - (to.query?.redirect as string) || DEFAULT_HOME_PATH, + (to.query?.redirect as string) || + userStore.userInfo?.homePath || + DEFAULT_HOME_PATH, ); } return true; @@ -72,7 +74,10 @@ function setupAccessGuard(router: Router) { return { path: LOGIN_PATH, // 如不需要,直接删除 query - query: { redirect: encodeURIComponent(to.fullPath) }, + query: + to.fullPath === DEFAULT_HOME_PATH + ? {} + : { redirect: encodeURIComponent(to.fullPath) }, // 携带当前跳转的页面,登录后重新跳转该页面 replace: true, }; @@ -102,7 +107,10 @@ function setupAccessGuard(router: Router) { accessStore.setAccessMenus(accessibleMenus); accessStore.setAccessRoutes(accessibleRoutes); accessStore.setIsAccessChecked(true); - const redirectPath = (from.query.redirect ?? to.fullPath) as string; + const redirectPath = (from.query.redirect ?? + (to.path === DEFAULT_HOME_PATH + ? userInfo.homePath || DEFAULT_HOME_PATH + : to.fullPath)) as string; return { ...router.resolve(decodeURIComponent(redirectPath)), diff --git a/apps/web-naive/src/router/guard.ts b/apps/web-naive/src/router/guard.ts index c95d994e..281ea31a 100644 --- a/apps/web-naive/src/router/guard.ts +++ b/apps/web-naive/src/router/guard.ts @@ -54,7 +54,9 @@ function setupAccessGuard(router: Router) { if (coreRouteNames.includes(to.name as string)) { if (to.path === LOGIN_PATH && accessStore.accessToken) { return decodeURIComponent( - (to.query?.redirect as string) || DEFAULT_HOME_PATH, + (to.query?.redirect as string) || + userStore.userInfo?.homePath || + DEFAULT_HOME_PATH, ); } return true; @@ -72,7 +74,10 @@ function setupAccessGuard(router: Router) { return { path: LOGIN_PATH, // 如不需要,直接删除 query - query: { redirect: encodeURIComponent(to.fullPath) }, + query: + to.fullPath === DEFAULT_HOME_PATH + ? {} + : { redirect: encodeURIComponent(to.fullPath) }, // 携带当前跳转的页面,登录后重新跳转该页面 replace: true, }; @@ -101,7 +106,10 @@ function setupAccessGuard(router: Router) { accessStore.setAccessMenus(accessibleMenus); accessStore.setAccessRoutes(accessibleRoutes); accessStore.setIsAccessChecked(true); - const redirectPath = (from.query.redirect ?? to.fullPath) as string; + const redirectPath = (from.query.redirect ?? + (to.path === DEFAULT_HOME_PATH + ? userInfo.homePath || DEFAULT_HOME_PATH + : to.fullPath)) as string; return { ...router.resolve(decodeURIComponent(redirectPath)), diff --git a/docs/.vitepress/config/zh.mts b/docs/.vitepress/config/zh.mts index 25e93ced..dff8ac28 100644 --- a/docs/.vitepress/config/zh.mts +++ b/docs/.vitepress/config/zh.mts @@ -186,6 +186,10 @@ function sidebarComponents(): DefaultTheme.SidebarItem[] { link: 'common-ui/vben-count-to-animator', text: 'CountToAnimator 数字动画', }, + { + link: 'common-ui/vben-ellipsis-text', + text: 'EllipsisText 省略文本', + }, ], }, ]; diff --git a/docs/src/components/common-ui/vben-api-component.md b/docs/src/components/common-ui/vben-api-component.md index f9db74e4..f275adfc 100644 --- a/docs/src/components/common-ui/vben-api-component.md +++ b/docs/src/components/common-ui/vben-api-component.md @@ -123,6 +123,8 @@ function fetchApi(): Promise> { ::: +## API + ### Props | 属性名 | 描述 | 类型 | 默认值 | diff --git a/docs/src/components/common-ui/vben-ellipsis-text.md b/docs/src/components/common-ui/vben-ellipsis-text.md new file mode 100644 index 00000000..109f1161 --- /dev/null +++ b/docs/src/components/common-ui/vben-ellipsis-text.md @@ -0,0 +1,56 @@ +--- +outline: deep +--- + +# Vben EllipsisText 省略文本 + +框架提供的文本展示组件,可配置超长省略、tooltip提示、展开收起等功能。 + +> 如果文档内没有参数说明,可以尝试在在线示例内寻找 + +## 基础用法 + +通过默认插槽设置文本内容,`maxWidth`属性设置最大宽度。 + + + +## 可折叠的文本块 + +通过`line`设置折叠后的行数,`expand`属性设置是否支持展开收起。 + + + +## 自定义提示浮层 + +通过名为`tooltip`的插槽定制提示信息。 + + + +## API + +### Props + +| 属性名 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| expand | 支持点击展开或收起 | `boolean` | `false` | +| line | 文本最大行数 | `number` | `1` | +| maxWidth | 文本区域最大宽度 | `number \| string` | `'100%'` | +| placement | 提示浮层的位置 | `'bottom'\|'left'\|'right'\|'top'` | `'top'` | +| tooltip | 启用文本提示 | `boolean` | `true` | +| tooltipBackgroundColor | 提示文本的背景颜色 | `string` | - | +| tooltipColor | 提示文本的颜色 | `string` | - | +| tooltipFontSize | 提示文本的大小 | `string` | - | +| tooltipMaxWidth | 提示浮层的最大宽度。如不设置则保持与文本宽度一致 | `number` | - | +| tooltipOverlayStyle | 提示框内容区域样式 | `CSSProperties` | `{ textAlign: 'justify' }` | + +### Events + +| 事件名 | 描述 | 类型 | +| ------------ | ------------ | -------------------------- | +| expandChange | 展开状态改变 | `(isExpand:boolean)=>void` | + +### Slots + +| 插槽名 | 描述 | +| ------- | -------------------------------- | +| tooltip | 启用文本提示时,用来定制提示内容 | diff --git a/docs/src/components/common-ui/vben-form.md b/docs/src/components/common-ui/vben-form.md index 618e3d3a..8d27c08d 100644 --- a/docs/src/components/common-ui/vben-form.md +++ b/docs/src/components/common-ui/vben-form.md @@ -287,6 +287,8 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单 | setValues | 设置表单值, 默认会过滤不在schema中定义的field, 可通过filterFields形参关闭过滤 | `(fields: Record, filterFields?: boolean, shouldValidate?: boolean) => Promise` | | getValues | 获取表单值 | `(fields:Record,shouldValidate: boolean = false)=>Promise` | | validate | 表单校验 | `()=>Promise` | +| validateField | 校验指定字段 | `(fieldName: string)=>Promise>` | +| isFieldValid | 检查某个字段是否已通过校验 | `(fieldName: string)=>Promise` | | resetValidate | 重置表单校验 | `()=>Promise` | | updateSchema | 更新formSchema | `(schema:FormSchema[])=>void` | | setFieldValue | 设置字段值 | `(field: string, value: any, shouldValidate?: boolean)=>Promise` | @@ -311,14 +313,14 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单 | resetButtonOptions | 重置按钮组件参数 | `ActionButtonOptions` | - | | submitButtonOptions | 提交按钮组件参数 | `ActionButtonOptions` | - | | showDefaultActions | 是否显示默认操作按钮 | `boolean` | `true` | -| collapsed | 是否折叠,在`是否展开,在showCollapseButton=true`时生效 | `boolean` | `false` | +| collapsed | 是否折叠,在`showCollapseButton`为`true`时生效 | `boolean` | `false` | | collapseTriggerResize | 折叠时,触发`resize`事件 | `boolean` | `false` | | collapsedRows | 折叠时保持的行数 | `number` | `1` | -| fieldMappingTime | 用于将表单内时间区域的应设成 2 个字段 | `[string, [string, string], string?][]` | - | +| fieldMappingTime | 用于将表单内时间区域组件的数组值映射成 2 个字段 | `[string, [string, string], string?][]` | - | | commonConfig | 表单项的通用配置,每个配置都会传递到每个表单项,表单项可覆盖 | `FormCommonConfig` | - | -| schema | 表单项的每一项配置 | `FormSchema` | - | +| schema | 表单项的每一项配置 | `FormSchema[]` | - | | submitOnEnter | 按下回车健时提交表单 | `boolean` | false | -| submitOnChange | 字段值改变时提交表单 | `boolean` | false | +| submitOnChange | 字段值改变时提交表单(内部防抖,这个属性一般用于表格的搜索表单) | `boolean` | false | ### TS 类型说明 @@ -355,10 +357,21 @@ export interface FormCommonConfig { * 所有表单项的props */ componentProps?: ComponentProps; + /** + * 是否紧凑模式(移除表单底部为显示校验错误信息所预留的空间)。 + * 在有设置校验规则的场景下,建议不要将其设置为true + * 默认为false。但用作表格的搜索表单时,默认为true + * @default false + */ + compact?: boolean; /** * 所有表单项的控件样式 */ controlClass?: string; + /** + * 在表单项的Label后显示一个冒号 + */ + colon?: boolean; /** * 所有表单项的禁用状态 * @default false @@ -418,7 +431,7 @@ export interface FormSchema< dependencies?: FormItemDependencies; /** 描述 */ description?: string; - /** 字段名 */ + /** 字段名,也作为自定义插槽的名称 */ fieldName: string; /** 帮助信息 */ help?: string; @@ -441,7 +454,7 @@ export interface FormSchema< ```ts dependencies: { - // 只有当 name 字段的值变化时,才会触发联动 + // 触发字段。只有这些字段值变动时,联动才会触发 triggerFields: ['name'], // 动态判断当前字段是否需要显示,不显示则直接销毁 if(values,formApi){}, @@ -462,11 +475,11 @@ dependencies: { ### 表单校验 -表单联动需要通过 schema 内的 `rules` 属性进行配置。 +表单校验需要通过 schema 内的 `rules` 属性进行配置。 -rules的值可以是一个字符串,也可以是一个zod的schema。 +rules的值可以是字符串(预定义的校验规则名称),也可以是一个zod的schema。 -#### 字符串 +#### 预定义的校验规则 ```ts // 表示字段必填,默认会根据适配器的required进行国际化 @@ -492,11 +505,16 @@ import { z } from '#/adapter/form'; rules: z.string().min(1, { message: '请输入字符串' }); } -// 可选,并且携带默认值 +// 可选(可以是undefined),并且携带默认值。注意zod的optional不包括空字符串'' { rules: z.string().default('默认值').optional(), } +// 可以是空字符串、undefined或者一个邮箱地址 +{ + rules: z.union(z.string().email().optional(), z.literal("")) +} + // 复杂校验 { z.string().min(1, { message: "请输入" }) diff --git a/docs/src/demos/vben-ellipsis-text/expand/index.vue b/docs/src/demos/vben-ellipsis-text/expand/index.vue new file mode 100644 index 00000000..842f6b32 --- /dev/null +++ b/docs/src/demos/vben-ellipsis-text/expand/index.vue @@ -0,0 +1,10 @@ + + diff --git a/docs/src/demos/vben-ellipsis-text/line/index.vue b/docs/src/demos/vben-ellipsis-text/line/index.vue new file mode 100644 index 00000000..dfbf20ef --- /dev/null +++ b/docs/src/demos/vben-ellipsis-text/line/index.vue @@ -0,0 +1,10 @@ + + diff --git a/docs/src/demos/vben-ellipsis-text/tooltip/index.vue b/docs/src/demos/vben-ellipsis-text/tooltip/index.vue new file mode 100644 index 00000000..e6287a12 --- /dev/null +++ b/docs/src/demos/vben-ellipsis-text/tooltip/index.vue @@ -0,0 +1,14 @@ + + diff --git a/packages/@core/ui-kit/form-ui/src/components/form-actions.vue b/packages/@core/ui-kit/form-ui/src/components/form-actions.vue index ac5505d5..b9a878e8 100644 --- a/packages/@core/ui-kit/form-ui/src/components/form-actions.vue +++ b/packages/@core/ui-kit/form-ui/src/components/form-actions.vue @@ -138,7 +138,11 @@ defineExpose({