Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
This commit is contained in:
commit
59e039896e
@ -4,6 +4,7 @@ export interface UserInfo {
|
|||||||
realName: string;
|
realName: string;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
username: string;
|
username: string;
|
||||||
|
homePath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MOCK_USERS: UserInfo[] = [
|
export const MOCK_USERS: UserInfo[] = [
|
||||||
@ -20,6 +21,7 @@ export const MOCK_USERS: UserInfo[] = [
|
|||||||
realName: 'Admin',
|
realName: 'Admin',
|
||||||
roles: ['admin'],
|
roles: ['admin'],
|
||||||
username: 'admin',
|
username: 'admin',
|
||||||
|
homePath: '/workspace',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
@ -27,6 +29,7 @@ export const MOCK_USERS: UserInfo[] = [
|
|||||||
realName: 'Jack',
|
realName: 'Jack',
|
||||||
roles: ['user'],
|
roles: ['user'],
|
||||||
username: 'jack',
|
username: 'jack',
|
||||||
|
homePath: '/analytics',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -54,7 +54,9 @@ function setupAccessGuard(router: Router) {
|
|||||||
if (coreRouteNames.includes(to.name as string)) {
|
if (coreRouteNames.includes(to.name as string)) {
|
||||||
if (to.path === LOGIN_PATH && accessStore.accessToken) {
|
if (to.path === LOGIN_PATH && accessStore.accessToken) {
|
||||||
return decodeURIComponent(
|
return decodeURIComponent(
|
||||||
(to.query?.redirect as string) || DEFAULT_HOME_PATH,
|
(to.query?.redirect as string) ||
|
||||||
|
userStore.userInfo?.homePath ||
|
||||||
|
DEFAULT_HOME_PATH,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -72,7 +74,10 @@ function setupAccessGuard(router: Router) {
|
|||||||
return {
|
return {
|
||||||
path: LOGIN_PATH,
|
path: LOGIN_PATH,
|
||||||
// 如不需要,直接删除 query
|
// 如不需要,直接删除 query
|
||||||
query: { redirect: encodeURIComponent(to.fullPath) },
|
query:
|
||||||
|
to.fullPath === DEFAULT_HOME_PATH
|
||||||
|
? {}
|
||||||
|
: { redirect: encodeURIComponent(to.fullPath) },
|
||||||
// 携带当前跳转的页面,登录后重新跳转该页面
|
// 携带当前跳转的页面,登录后重新跳转该页面
|
||||||
replace: true,
|
replace: true,
|
||||||
};
|
};
|
||||||
@ -102,7 +107,10 @@ function setupAccessGuard(router: Router) {
|
|||||||
accessStore.setAccessMenus(accessibleMenus);
|
accessStore.setAccessMenus(accessibleMenus);
|
||||||
accessStore.setAccessRoutes(accessibleRoutes);
|
accessStore.setAccessRoutes(accessibleRoutes);
|
||||||
accessStore.setIsAccessChecked(true);
|
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 {
|
return {
|
||||||
...router.resolve(decodeURIComponent(redirectPath)),
|
...router.resolve(decodeURIComponent(redirectPath)),
|
||||||
|
@ -54,7 +54,9 @@ function setupAccessGuard(router: Router) {
|
|||||||
if (coreRouteNames.includes(to.name as string)) {
|
if (coreRouteNames.includes(to.name as string)) {
|
||||||
if (to.path === LOGIN_PATH && accessStore.accessToken) {
|
if (to.path === LOGIN_PATH && accessStore.accessToken) {
|
||||||
return decodeURIComponent(
|
return decodeURIComponent(
|
||||||
(to.query?.redirect as string) || DEFAULT_HOME_PATH,
|
(to.query?.redirect as string) ||
|
||||||
|
userStore.userInfo?.homePath ||
|
||||||
|
DEFAULT_HOME_PATH,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -72,7 +74,10 @@ function setupAccessGuard(router: Router) {
|
|||||||
return {
|
return {
|
||||||
path: LOGIN_PATH,
|
path: LOGIN_PATH,
|
||||||
// 如不需要,直接删除 query
|
// 如不需要,直接删除 query
|
||||||
query: { redirect: encodeURIComponent(to.fullPath) },
|
query:
|
||||||
|
to.fullPath === DEFAULT_HOME_PATH
|
||||||
|
? {}
|
||||||
|
: { redirect: encodeURIComponent(to.fullPath) },
|
||||||
// 携带当前跳转的页面,登录后重新跳转该页面
|
// 携带当前跳转的页面,登录后重新跳转该页面
|
||||||
replace: true,
|
replace: true,
|
||||||
};
|
};
|
||||||
@ -102,7 +107,10 @@ function setupAccessGuard(router: Router) {
|
|||||||
accessStore.setAccessMenus(accessibleMenus);
|
accessStore.setAccessMenus(accessibleMenus);
|
||||||
accessStore.setAccessRoutes(accessibleRoutes);
|
accessStore.setAccessRoutes(accessibleRoutes);
|
||||||
accessStore.setIsAccessChecked(true);
|
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 {
|
return {
|
||||||
...router.resolve(decodeURIComponent(redirectPath)),
|
...router.resolve(decodeURIComponent(redirectPath)),
|
||||||
|
@ -54,7 +54,9 @@ function setupAccessGuard(router: Router) {
|
|||||||
if (coreRouteNames.includes(to.name as string)) {
|
if (coreRouteNames.includes(to.name as string)) {
|
||||||
if (to.path === LOGIN_PATH && accessStore.accessToken) {
|
if (to.path === LOGIN_PATH && accessStore.accessToken) {
|
||||||
return decodeURIComponent(
|
return decodeURIComponent(
|
||||||
(to.query?.redirect as string) || DEFAULT_HOME_PATH,
|
(to.query?.redirect as string) ||
|
||||||
|
userStore.userInfo?.homePath ||
|
||||||
|
DEFAULT_HOME_PATH,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -72,7 +74,10 @@ function setupAccessGuard(router: Router) {
|
|||||||
return {
|
return {
|
||||||
path: LOGIN_PATH,
|
path: LOGIN_PATH,
|
||||||
// 如不需要,直接删除 query
|
// 如不需要,直接删除 query
|
||||||
query: { redirect: encodeURIComponent(to.fullPath) },
|
query:
|
||||||
|
to.fullPath === DEFAULT_HOME_PATH
|
||||||
|
? {}
|
||||||
|
: { redirect: encodeURIComponent(to.fullPath) },
|
||||||
// 携带当前跳转的页面,登录后重新跳转该页面
|
// 携带当前跳转的页面,登录后重新跳转该页面
|
||||||
replace: true,
|
replace: true,
|
||||||
};
|
};
|
||||||
@ -101,7 +106,10 @@ function setupAccessGuard(router: Router) {
|
|||||||
accessStore.setAccessMenus(accessibleMenus);
|
accessStore.setAccessMenus(accessibleMenus);
|
||||||
accessStore.setAccessRoutes(accessibleRoutes);
|
accessStore.setAccessRoutes(accessibleRoutes);
|
||||||
accessStore.setIsAccessChecked(true);
|
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 {
|
return {
|
||||||
...router.resolve(decodeURIComponent(redirectPath)),
|
...router.resolve(decodeURIComponent(redirectPath)),
|
||||||
|
@ -186,6 +186,10 @@ function sidebarComponents(): DefaultTheme.SidebarItem[] {
|
|||||||
link: 'common-ui/vben-count-to-animator',
|
link: 'common-ui/vben-count-to-animator',
|
||||||
text: 'CountToAnimator 数字动画',
|
text: 'CountToAnimator 数字动画',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
link: 'common-ui/vben-ellipsis-text',
|
||||||
|
text: 'EllipsisText 省略文本',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -123,6 +123,8 @@ function fetchApi(): Promise<Record<string, any>> {
|
|||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
|
|
||||||
| 属性名 | 描述 | 类型 | 默认值 |
|
| 属性名 | 描述 | 类型 | 默认值 |
|
||||||
|
56
docs/src/components/common-ui/vben-ellipsis-text.md
Normal file
56
docs/src/components/common-ui/vben-ellipsis-text.md
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# Vben EllipsisText 省略文本
|
||||||
|
|
||||||
|
框架提供的文本展示组件,可配置超长省略、tooltip提示、展开收起等功能。
|
||||||
|
|
||||||
|
> 如果文档内没有参数说明,可以尝试在在线示例内寻找
|
||||||
|
|
||||||
|
## 基础用法
|
||||||
|
|
||||||
|
通过默认插槽设置文本内容,`maxWidth`属性设置最大宽度。
|
||||||
|
|
||||||
|
<DemoPreview dir="demos/vben-ellipsis-text/line" />
|
||||||
|
|
||||||
|
## 可折叠的文本块
|
||||||
|
|
||||||
|
通过`line`设置折叠后的行数,`expand`属性设置是否支持展开收起。
|
||||||
|
|
||||||
|
<DemoPreview dir="demos/vben-ellipsis-text/expand" />
|
||||||
|
|
||||||
|
## 自定义提示浮层
|
||||||
|
|
||||||
|
通过名为`tooltip`的插槽定制提示信息。
|
||||||
|
|
||||||
|
<DemoPreview dir="demos/vben-ellipsis-text/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 | 启用文本提示时,用来定制提示内容 |
|
@ -357,6 +357,13 @@ export interface FormCommonConfig {
|
|||||||
* 所有表单项的props
|
* 所有表单项的props
|
||||||
*/
|
*/
|
||||||
componentProps?: ComponentProps;
|
componentProps?: ComponentProps;
|
||||||
|
/**
|
||||||
|
* 是否紧凑模式(移除表单底部为显示校验错误信息所预留的空间)。
|
||||||
|
* 在有设置校验规则的场景下,建议不要将其设置为true
|
||||||
|
* 默认为false。但用作表格的搜索表单时,默认为true
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
compact?: boolean;
|
||||||
/**
|
/**
|
||||||
* 所有表单项的控件样式
|
* 所有表单项的控件样式
|
||||||
*/
|
*/
|
||||||
|
10
docs/src/demos/vben-ellipsis-text/expand/index.vue
Normal file
10
docs/src/demos/vben-ellipsis-text/expand/index.vue
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { EllipsisText } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const text = `
|
||||||
|
Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。
|
||||||
|
`;
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<EllipsisText :line="3" expand>{{ text }}</EllipsisText>
|
||||||
|
</template>
|
10
docs/src/demos/vben-ellipsis-text/line/index.vue
Normal file
10
docs/src/demos/vben-ellipsis-text/line/index.vue
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { EllipsisText } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const text = `
|
||||||
|
Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。
|
||||||
|
`;
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<EllipsisText :max-width="500">{{ text }}</EllipsisText>
|
||||||
|
</template>
|
14
docs/src/demos/vben-ellipsis-text/tooltip/index.vue
Normal file
14
docs/src/demos/vben-ellipsis-text/tooltip/index.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { EllipsisText } from '@vben/common-ui';
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<EllipsisText :max-width="240">
|
||||||
|
住在我心里孤独的 孤独的海怪 痛苦之王 开始厌倦 深海的光 停滞的海浪
|
||||||
|
<template #tooltip>
|
||||||
|
<div style="text-align: center">
|
||||||
|
《秦皇岛》<br />住在我心里孤独的<br />孤独的海怪 痛苦之王<br />开始厌倦
|
||||||
|
深海的光 停滞的海浪
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</EllipsisText>
|
||||||
|
</template>
|
@ -138,7 +138,11 @@ defineExpose({
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="
|
:class="
|
||||||
cn('col-span-full w-full pb-6 text-right', rootProps.actionWrapperClass)
|
cn(
|
||||||
|
'col-span-full w-full text-right',
|
||||||
|
rootProps.compact ? 'pb-2' : 'pb-6',
|
||||||
|
rootProps.actionWrapperClass,
|
||||||
|
)
|
||||||
"
|
"
|
||||||
:style="queryFormStyle"
|
:style="queryFormStyle"
|
||||||
>
|
>
|
||||||
|
@ -55,7 +55,7 @@ const values = useFormValues();
|
|||||||
const errors = useFieldError(fieldName);
|
const errors = useFieldError(fieldName);
|
||||||
const fieldComponentRef = useTemplateRef<HTMLInputElement>('fieldComponentRef');
|
const fieldComponentRef = useTemplateRef<HTMLInputElement>('fieldComponentRef');
|
||||||
const formApi = formRenderProps.form;
|
const formApi = formRenderProps.form;
|
||||||
|
const compact = formRenderProps.compact;
|
||||||
const isInValid = computed(() => errors.value?.length > 0);
|
const isInValid = computed(() => errors.value?.length > 0);
|
||||||
|
|
||||||
const FieldComponent = computed(() => {
|
const FieldComponent = computed(() => {
|
||||||
@ -281,8 +281,10 @@ function autofocus() {
|
|||||||
'form-valid-error': isInValid,
|
'form-valid-error': isInValid,
|
||||||
'flex-col': isVertical,
|
'flex-col': isVertical,
|
||||||
'flex-row items-center': !isVertical,
|
'flex-row items-center': !isVertical,
|
||||||
|
'pb-6': !compact,
|
||||||
|
'pb-2': compact,
|
||||||
}"
|
}"
|
||||||
class="flex pb-6"
|
class="flex"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
>
|
>
|
||||||
<FormLabel
|
<FormLabel
|
||||||
|
@ -273,6 +273,10 @@ export interface FormRenderProps<
|
|||||||
* 表单项通用后备配置,当子项目没配置时使用这里的配置,子项目配置优先级高于此配置
|
* 表单项通用后备配置,当子项目没配置时使用这里的配置,子项目配置优先级高于此配置
|
||||||
*/
|
*/
|
||||||
commonConfig?: FormCommonConfig;
|
commonConfig?: FormCommonConfig;
|
||||||
|
/**
|
||||||
|
* 紧凑模式(移除表单每一项底部为校验信息预留的空间)
|
||||||
|
*/
|
||||||
|
compact?: boolean;
|
||||||
/**
|
/**
|
||||||
* 组件v-model事件绑定
|
* 组件v-model事件绑定
|
||||||
*/
|
*/
|
||||||
|
@ -6,7 +6,7 @@ import type { ExtendedFormApi, VbenFormProps } from './types';
|
|||||||
import { useForwardPriorityValues } from '@vben-core/composables';
|
import { useForwardPriorityValues } from '@vben-core/composables';
|
||||||
// import { isFunction } from '@vben-core/shared/utils';
|
// import { isFunction } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { nextTick, onMounted, useTemplateRef, watch } from 'vue';
|
import { nextTick, onMounted, watch } from 'vue';
|
||||||
|
|
||||||
import { cloneDeep } from '@vben-core/shared/utils';
|
import { cloneDeep } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
@ -27,8 +27,6 @@ interface Props extends VbenFormProps {
|
|||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
|
|
||||||
const formActionsRef = useTemplateRef<typeof FormActions>('formActionsRef');
|
|
||||||
|
|
||||||
const state = props.formApi?.useStore?.();
|
const state = props.formApi?.useStore?.();
|
||||||
|
|
||||||
const forward = useForwardPriorityValues(props, state);
|
const forward = useForwardPriorityValues(props, state);
|
||||||
@ -44,11 +42,7 @@ const handleUpdateCollapsed = (value: boolean) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function handleKeyDownEnter(event: KeyboardEvent) {
|
function handleKeyDownEnter(event: KeyboardEvent) {
|
||||||
if (
|
if (!state.value.submitOnEnter || !forward.value.formApi?.isMounted) {
|
||||||
!state.value.submitOnEnter ||
|
|
||||||
!formActionsRef.value ||
|
|
||||||
!formActionsRef.value.handleSubmit
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 如果是 textarea 不阻止默认行为,否则会导致无法换行。
|
// 如果是 textarea 不阻止默认行为,否则会导致无法换行。
|
||||||
@ -58,12 +52,12 @@ function handleKeyDownEnter(event: KeyboardEvent) {
|
|||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
formActionsRef.value?.handleSubmit?.();
|
forward.value.formApi.validateAndSubmitForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleValuesChangeDebounced = useDebounceFn((newVal) => {
|
const handleValuesChangeDebounced = useDebounceFn((newVal) => {
|
||||||
forward.value.handleValuesChange?.(cloneDeep(newVal));
|
forward.value.handleValuesChange?.(cloneDeep(newVal));
|
||||||
state.value.submitOnChange && formActionsRef.value?.handleSubmit?.();
|
state.value.submitOnChange && forward.value.formApi?.validateAndSubmitForm();
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
@ -94,7 +88,6 @@ onMounted(async () => {
|
|||||||
<slot v-bind="slotProps">
|
<slot v-bind="slotProps">
|
||||||
<FormActions
|
<FormActions
|
||||||
v-if="forward.showDefaultActions"
|
v-if="forward.showDefaultActions"
|
||||||
ref="formActionsRef"
|
|
||||||
:model-value="state.collapsed"
|
:model-value="state.collapsed"
|
||||||
@update:model-value="handleUpdateCollapsed"
|
@update:model-value="handleUpdateCollapsed"
|
||||||
>
|
>
|
||||||
|
@ -68,6 +68,7 @@ const { isMobile } = usePreferences();
|
|||||||
const slots = useSlots();
|
const slots = useSlots();
|
||||||
|
|
||||||
const [Form, formApi] = useTableForm({
|
const [Form, formApi] = useTableForm({
|
||||||
|
compact: true,
|
||||||
handleSubmit: async () => {
|
handleSubmit: async () => {
|
||||||
const formValues = formApi.form.values;
|
const formValues = formApi.form.values;
|
||||||
formApi.setLatestSubmissionValues(toRaw(formValues));
|
formApi.setLatestSubmissionValues(toRaw(formValues));
|
||||||
@ -286,6 +287,10 @@ watch(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isCompactForm = computed(() => {
|
||||||
|
return formApi.getState()?.compact;
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
props.api?.mount?.(gridRef.value, formApi);
|
props.api?.mount?.(gridRef.value, formApi);
|
||||||
init();
|
init();
|
||||||
@ -340,7 +345,7 @@ onUnmounted(() => {
|
|||||||
<div
|
<div
|
||||||
v-if="formOptions"
|
v-if="formOptions"
|
||||||
v-show="showSearchForm !== false"
|
v-show="showSearchForm !== false"
|
||||||
class="relative rounded py-3 pb-4"
|
:class="cn('relative rounded py-3', isCompactForm ? 'pb-6' : 'pb-4')"
|
||||||
>
|
>
|
||||||
<slot name="form">
|
<slot name="form">
|
||||||
<Form>
|
<Form>
|
||||||
|
@ -52,7 +52,9 @@ function setupAccessGuard(router: Router) {
|
|||||||
if (coreRouteNames.includes(to.name as string)) {
|
if (coreRouteNames.includes(to.name as string)) {
|
||||||
if (to.path === LOGIN_PATH && accessStore.accessToken) {
|
if (to.path === LOGIN_PATH && accessStore.accessToken) {
|
||||||
return decodeURIComponent(
|
return decodeURIComponent(
|
||||||
(to.query?.redirect as string) || DEFAULT_HOME_PATH,
|
(to.query?.redirect as string) ||
|
||||||
|
userStore.userInfo?.homePath ||
|
||||||
|
DEFAULT_HOME_PATH,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -70,7 +72,10 @@ function setupAccessGuard(router: Router) {
|
|||||||
return {
|
return {
|
||||||
path: LOGIN_PATH,
|
path: LOGIN_PATH,
|
||||||
// 如不需要,直接删除 query
|
// 如不需要,直接删除 query
|
||||||
query: { redirect: encodeURIComponent(to.fullPath) },
|
query:
|
||||||
|
to.fullPath === DEFAULT_HOME_PATH
|
||||||
|
? {}
|
||||||
|
: { redirect: encodeURIComponent(to.fullPath) },
|
||||||
// 携带当前跳转的页面,登录后重新跳转该页面
|
// 携带当前跳转的页面,登录后重新跳转该页面
|
||||||
replace: true,
|
replace: true,
|
||||||
};
|
};
|
||||||
@ -100,7 +105,10 @@ function setupAccessGuard(router: Router) {
|
|||||||
accessStore.setAccessMenus(accessibleMenus);
|
accessStore.setAccessMenus(accessibleMenus);
|
||||||
accessStore.setAccessRoutes(accessibleRoutes);
|
accessStore.setAccessRoutes(accessibleRoutes);
|
||||||
accessStore.setIsAccessChecked(true);
|
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 {
|
return {
|
||||||
...router.resolve(decodeURIComponent(redirectPath)),
|
...router.resolve(decodeURIComponent(redirectPath)),
|
||||||
|
@ -7,7 +7,13 @@ import { Button } from 'ant-design-vue';
|
|||||||
const props = defineProps<{ path: string }>();
|
const props = defineProps<{ path: string }>();
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
openWindow(VBEN_DOC_URL + props.path);
|
// 如果没有.html,打开页面时可能会出现404
|
||||||
|
const path =
|
||||||
|
VBEN_DOC_URL +
|
||||||
|
(props.path.toLowerCase().endsWith('.html')
|
||||||
|
? props.path
|
||||||
|
: `${props.path}.html`);
|
||||||
|
openWindow(path);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ import { EllipsisText, Page } from '@vben/common-ui';
|
|||||||
|
|
||||||
import { Card } from 'ant-design-vue';
|
import { Card } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import DocButton from '../doc-button.vue';
|
||||||
|
|
||||||
const longText = `Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。`;
|
const longText = `Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。`;
|
||||||
|
|
||||||
const text = ref(longText);
|
const text = ref(longText);
|
||||||
@ -15,6 +17,9 @@ const text = ref(longText);
|
|||||||
description="用于多行文本省略,支持点击展开和自定义内容。"
|
description="用于多行文本省略,支持点击展开和自定义内容。"
|
||||||
title="文本省略组件示例"
|
title="文本省略组件示例"
|
||||||
>
|
>
|
||||||
|
<template #extra>
|
||||||
|
<DocButton class="mb-2" path="/components/common-ui/vben-ellipsis-text" />
|
||||||
|
</template>
|
||||||
<Card class="mb-4" title="基本使用">
|
<Card class="mb-4" title="基本使用">
|
||||||
<EllipsisText :max-width="500">{{ text }}</EllipsisText>
|
<EllipsisText :max-width="500">{{ text }}</EllipsisText>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -395,7 +395,7 @@ function handleSetFormValue() {
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
</template>
|
</template>
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<DocButton path="/components/common-ui/vben-form" />
|
<DocButton class="mb-2" path="/components/common-ui/vben-form" />
|
||||||
</template>
|
</template>
|
||||||
<Card v-show="activeTab === 'basic'" title="基础示例">
|
<Card v-show="activeTab === 'basic'" title="基础示例">
|
||||||
<template #extra>
|
<template #extra>
|
||||||
|
Loading…
Reference in New Issue
Block a user