Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev-v5
commit
8463f5e51f
|
@ -9,7 +9,7 @@
|
||||||
"url": "http://localhost:5555",
|
"url": "http://localhost:5555",
|
||||||
"env": { "NODE_ENV": "development" },
|
"env": { "NODE_ENV": "development" },
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"webRoot": "${workspaceFolder}"
|
"webRoot": "${workspaceFolder}/playground"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
"url": "http://localhost:5666",
|
"url": "http://localhost:5666",
|
||||||
"env": { "NODE_ENV": "development" },
|
"env": { "NODE_ENV": "development" },
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"webRoot": "${workspaceFolder}"
|
"webRoot": "${workspaceFolder}/apps/web-antd"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
"url": "http://localhost:5777",
|
"url": "http://localhost:5777",
|
||||||
"env": { "NODE_ENV": "development" },
|
"env": { "NODE_ENV": "development" },
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"webRoot": "${workspaceFolder}"
|
"webRoot": "${workspaceFolder}/apps/web-ele"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
"url": "http://localhost:5888",
|
"url": "http://localhost:5888",
|
||||||
"env": { "NODE_ENV": "development" },
|
"env": { "NODE_ENV": "development" },
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"webRoot": "${workspaceFolder}"
|
"webRoot": "${workspaceFolder}/apps/web-naive"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,31 @@ export default eventHandler(async (event) => {
|
||||||
|
|
||||||
await sleep(600);
|
await sleep(600);
|
||||||
|
|
||||||
const { page, pageSize } = getQuery(event);
|
const { page, pageSize, sortBy, sortOrder } = getQuery(event);
|
||||||
return usePageResponseSuccess(page as string, pageSize as string, mockData);
|
const listData = structuredClone(mockData);
|
||||||
|
if (sortBy && Reflect.has(listData[0], sortBy as string)) {
|
||||||
|
listData.sort((a, b) => {
|
||||||
|
if (sortOrder === 'asc') {
|
||||||
|
if (sortBy === 'price') {
|
||||||
|
return (
|
||||||
|
Number.parseFloat(a[sortBy as string]) -
|
||||||
|
Number.parseFloat(b[sortBy as string])
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return a[sortBy as string] > b[sortBy as string] ? 1 : -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sortBy === 'price') {
|
||||||
|
return (
|
||||||
|
Number.parseFloat(b[sortBy as string]) -
|
||||||
|
Number.parseFloat(a[sortBy as string])
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return a[sortBy as string] < b[sortBy as string] ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return usePageResponseSuccess(page as string, pageSize as string, listData);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/web-antd",
|
"name": "@vben/web-antd",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://vben.pro",
|
"homepage": "https://vben.pro",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { $t } from '@vben/locales';
|
||||||
defineOptions({ name: 'CodeLogin' });
|
defineOptions({ name: 'CodeLogin' });
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const CODE_LENGTH = 6;
|
||||||
|
|
||||||
const formSchema = computed((): VbenFormSchema[] => {
|
const formSchema = computed((): VbenFormSchema[] => {
|
||||||
return [
|
return [
|
||||||
|
@ -30,6 +31,7 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||||
{
|
{
|
||||||
component: 'VbenPinInput',
|
component: 'VbenPinInput',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
|
codeLength: CODE_LENGTH,
|
||||||
createText: (countdown: number) => {
|
createText: (countdown: number) => {
|
||||||
const text =
|
const text =
|
||||||
countdown > 0
|
countdown > 0
|
||||||
|
@ -41,7 +43,9 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||||
},
|
},
|
||||||
fieldName: 'code',
|
fieldName: 'code',
|
||||||
label: $t('authentication.code'),
|
label: $t('authentication.code'),
|
||||||
rules: z.string().min(1, { message: $t('authentication.codeTip') }),
|
rules: z.string().length(CODE_LENGTH, {
|
||||||
|
message: $t('authentication.codeTip', [CODE_LENGTH]),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/web-ele",
|
"name": "@vben/web-ele",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://vben.pro",
|
"homepage": "https://vben.pro",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { $t } from '@vben/locales';
|
||||||
defineOptions({ name: 'CodeLogin' });
|
defineOptions({ name: 'CodeLogin' });
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const CODE_LENGTH = 6;
|
||||||
|
|
||||||
const formSchema = computed((): VbenFormSchema[] => {
|
const formSchema = computed((): VbenFormSchema[] => {
|
||||||
return [
|
return [
|
||||||
|
@ -30,6 +31,7 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||||
{
|
{
|
||||||
component: 'VbenPinInput',
|
component: 'VbenPinInput',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
|
codeLength: CODE_LENGTH,
|
||||||
createText: (countdown: number) => {
|
createText: (countdown: number) => {
|
||||||
const text =
|
const text =
|
||||||
countdown > 0
|
countdown > 0
|
||||||
|
@ -41,7 +43,9 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||||
},
|
},
|
||||||
fieldName: 'code',
|
fieldName: 'code',
|
||||||
label: $t('authentication.code'),
|
label: $t('authentication.code'),
|
||||||
rules: z.string().min(1, { message: $t('authentication.codeTip') }),
|
rules: z.string().length(CODE_LENGTH, {
|
||||||
|
message: $t('authentication.codeTip', [CODE_LENGTH]),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
|
@ -139,6 +139,7 @@ const [Form, formApi] = useVbenForm({
|
||||||
fieldName: 'select',
|
fieldName: 'select',
|
||||||
label: 'Select',
|
label: 'Select',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
|
filterable: true,
|
||||||
options: [
|
options: [
|
||||||
{ value: 'A', label: '选项A' },
|
{ value: 'A', label: '选项A' },
|
||||||
{ value: 'B', label: '选项B' },
|
{ value: 'B', label: '选项B' },
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/web-naive",
|
"name": "@vben/web-naive",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://vben.pro",
|
"homepage": "https://vben.pro",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -10,8 +10,6 @@ import { $t } from '@vben/locales';
|
||||||
|
|
||||||
setupVbenForm<ComponentType>({
|
setupVbenForm<ComponentType>({
|
||||||
config: {
|
config: {
|
||||||
// naive-ui组件不接受onChang事件,所以需要禁用
|
|
||||||
disabledOnChangeListener: true,
|
|
||||||
// naive-ui组件的空值为null,不能是undefined,否则重置表单时不生效
|
// naive-ui组件的空值为null,不能是undefined,否则重置表单时不生效
|
||||||
emptyStateValue: null,
|
emptyStateValue: null,
|
||||||
baseModelPropName: 'value',
|
baseModelPropName: 'value',
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { $t } from '@vben/locales';
|
||||||
defineOptions({ name: 'CodeLogin' });
|
defineOptions({ name: 'CodeLogin' });
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const CODE_LENGTH = 6;
|
||||||
|
|
||||||
const formSchema = computed((): VbenFormSchema[] => {
|
const formSchema = computed((): VbenFormSchema[] => {
|
||||||
return [
|
return [
|
||||||
|
@ -30,6 +31,7 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||||
{
|
{
|
||||||
component: 'VbenPinInput',
|
component: 'VbenPinInput',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
|
codeLength: CODE_LENGTH,
|
||||||
createText: (countdown: number) => {
|
createText: (countdown: number) => {
|
||||||
const text =
|
const text =
|
||||||
countdown > 0
|
countdown > 0
|
||||||
|
@ -41,7 +43,9 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||||
},
|
},
|
||||||
fieldName: 'code',
|
fieldName: 'code',
|
||||||
label: $t('authentication.code'),
|
label: $t('authentication.code'),
|
||||||
rules: z.string().min(1, { message: $t('authentication.codeTip') }),
|
rules: z.string().length(CODE_LENGTH, {
|
||||||
|
message: $t('authentication.codeTip', [CODE_LENGTH]),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/docs",
|
"name": "@vben/docs",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vitepress build",
|
"build": "vitepress build",
|
||||||
|
|
|
@ -14,8 +14,6 @@ initComponentAdapter();
|
||||||
setupVbenForm<ComponentType>({
|
setupVbenForm<ComponentType>({
|
||||||
config: {
|
config: {
|
||||||
baseModelPropName: 'value',
|
baseModelPropName: 'value',
|
||||||
// naive-ui组件不接受onChang事件,所以需要禁用
|
|
||||||
disabledOnChangeListener: true,
|
|
||||||
// naive-ui组件的空值为null,不能是undefined,否则重置表单时不生效
|
// naive-ui组件的空值为null,不能是undefined,否则重置表单时不生效
|
||||||
emptyStateValue: null,
|
emptyStateValue: null,
|
||||||
modelPropNameMap: {
|
modelPropNameMap: {
|
||||||
|
|
|
@ -165,6 +165,8 @@ vxeUI.renderer.add('CellLink', {
|
||||||
|
|
||||||
**表单搜索** 部分采用了`Vben Form 表单`,参考 [Vben Form 表单文档](/components/common-ui/vben-form)。
|
**表单搜索** 部分采用了`Vben Form 表单`,参考 [Vben Form 表单文档](/components/common-ui/vben-form)。
|
||||||
|
|
||||||
|
当启用了表单搜索时,可以在toolbarConfig中配置`search`为`true`来让表格在工具栏区域显示一个搜索表单控制按钮。
|
||||||
|
|
||||||
<DemoPreview dir="demos/vben-vxe-table/form" />
|
<DemoPreview dir="demos/vben-vxe-table/form" />
|
||||||
|
|
||||||
## 单元格编辑
|
## 单元格编辑
|
||||||
|
@ -215,14 +217,15 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
|
|
||||||
useVbenVxeGrid 返回的第二个参数,是一个对象,包含了一些表单的方法。
|
useVbenVxeGrid 返回的第二个参数,是一个对象,包含了一些表单的方法。
|
||||||
|
|
||||||
| 方法名 | 描述 | 类型 |
|
| 方法名 | 描述 | 类型 | 说明 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| setLoading | 设置loading状态 | `(loading)=>void` |
|
| setLoading | 设置loading状态 | `(loading)=>void` | - |
|
||||||
| setGridOptions | 设置vxe-table grid组件参数 | `(options: Partial<VxeGridProps['gridOptions'])=>void` |
|
| setGridOptions | 设置vxe-table grid组件参数 | `(options: Partial<VxeGridProps['gridOptions'])=>void` | - |
|
||||||
| reload | 重载表格,会进行初始化 | `(params:any)=>void` |
|
| reload | 重载表格,会进行初始化 | `(params:any)=>void` | - |
|
||||||
| query | 重载表格,会保留当前分页 | `(params:any)=>void` |
|
| query | 重载表格,会保留当前分页 | `(params:any)=>void` | - |
|
||||||
| grid | vxe-table grid实例 | `VxeGridInstance` |
|
| grid | vxe-table grid实例 | `VxeGridInstance` | - |
|
||||||
| formApi | vbenForm api实例 | `FormApi` |
|
| formApi | vbenForm api实例 | `FormApi` | - |
|
||||||
|
| toggleSearchForm | 设置搜索表单显示状态 | `(show?: boolean)=>boolean` | 当省略参数时,则将表单在显示和隐藏两种状态之间切换 |
|
||||||
|
|
||||||
## Props
|
## Props
|
||||||
|
|
||||||
|
@ -236,3 +239,4 @@ useVbenVxeGrid 返回的第二个参数,是一个对象,包含了一些表
|
||||||
| gridOptions | grid组件的参数 | `VxeTableGridProps` |
|
| gridOptions | grid组件的参数 | `VxeTableGridProps` |
|
||||||
| gridEvents | grid组件的触发的⌚️ | `VxeGridListeners` |
|
| gridEvents | grid组件的触发的⌚️ | `VxeGridListeners` |
|
||||||
| formOptions | 表单参数 | `VbenFormProps` |
|
| formOptions | 表单参数 | `VbenFormProps` |
|
||||||
|
| showSearchForm | 是否显示搜索表单 | `boolean` |
|
||||||
|
|
|
@ -110,6 +110,11 @@ const gridOptions: VxeGridProps<RowType> = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
toolbarConfig: {
|
||||||
|
// 是否显示搜索表单控制按钮
|
||||||
|
// @ts-ignore 正式环境时有完整的类型声明
|
||||||
|
search: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const [Grid] = useVbenVxeGrid({ formOptions, gridOptions });
|
const [Grid] = useVbenVxeGrid({ formOptions, gridOptions });
|
||||||
|
|
|
@ -217,6 +217,7 @@ const defaultPreferences: Preferences = {
|
||||||
globalSearch: true,
|
globalSearch: true,
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
|
autoActivateChild: false,
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
collapsedShowTitle: false,
|
collapsedShowTitle: false,
|
||||||
enable: true,
|
enable: true,
|
||||||
|
|
|
@ -240,6 +240,7 @@ const defaultPreferences: Preferences = {
|
||||||
globalSearch: true,
|
globalSearch: true,
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
|
autoActivateChild: false,
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
collapsedShowTitle: false,
|
collapsedShowTitle: false,
|
||||||
enable: true,
|
enable: true,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/commitlint-config",
|
"name": "@vben/commitlint-config",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/stylelint-config",
|
"name": "@vben/stylelint-config",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/node-utils",
|
"name": "@vben/node-utils",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/tailwind-config",
|
"name": "@vben/tailwind-config",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/tsconfig",
|
"name": "@vben/tsconfig",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/vite-config",
|
"name": "@vben/vite-config",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "vben-admin-monorepo",
|
"name": "vben-admin-monorepo",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"monorepo",
|
"monorepo",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/design",
|
"name": "@vben-core/design",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/icons",
|
"name": "@vben-core/icons",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/shared",
|
"name": "@vben-core/shared",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/typings",
|
"name": "@vben-core/typings",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/composables",
|
"name": "@vben-core/composables",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -65,6 +65,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
|
||||||
"globalSearch": true,
|
"globalSearch": true,
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
|
"autoActivateChild": false,
|
||||||
"collapsed": false,
|
"collapsed": false,
|
||||||
"collapsedShowTitle": false,
|
"collapsedShowTitle": false,
|
||||||
"enable": true,
|
"enable": true,
|
||||||
|
@ -83,6 +84,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
|
||||||
"showMaximize": true,
|
"showMaximize": true,
|
||||||
"showMore": true,
|
"showMore": true,
|
||||||
"styleType": "chrome",
|
"styleType": "chrome",
|
||||||
|
"wheelable": true,
|
||||||
},
|
},
|
||||||
"theme": {
|
"theme": {
|
||||||
"builtinType": "default",
|
"builtinType": "default",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/preferences",
|
"name": "@vben-core/preferences",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -65,6 +65,7 @@ const defaultPreferences: Preferences = {
|
||||||
globalSearch: true,
|
globalSearch: true,
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
|
autoActivateChild: false,
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
collapsedShowTitle: false,
|
collapsedShowTitle: false,
|
||||||
enable: true,
|
enable: true,
|
||||||
|
@ -83,6 +84,7 @@ const defaultPreferences: Preferences = {
|
||||||
showMaximize: true,
|
showMaximize: true,
|
||||||
showMore: true,
|
showMore: true,
|
||||||
styleType: 'chrome',
|
styleType: 'chrome',
|
||||||
|
wheelable: true,
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
builtinType: 'default',
|
builtinType: 'default',
|
||||||
|
|
|
@ -125,6 +125,8 @@ interface NavigationPreferences {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SidebarPreferences {
|
interface SidebarPreferences {
|
||||||
|
/** 点击目录时自动激活子菜单 */
|
||||||
|
autoActivateChild: boolean;
|
||||||
/** 侧边栏是否折叠 */
|
/** 侧边栏是否折叠 */
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
/** 侧边栏折叠时,是否显示title */
|
/** 侧边栏折叠时,是否显示title */
|
||||||
|
@ -173,6 +175,8 @@ interface TabbarPreferences {
|
||||||
showMore: boolean;
|
showMore: boolean;
|
||||||
/** 标签页风格 */
|
/** 标签页风格 */
|
||||||
styleType: TabsStyleType;
|
styleType: TabsStyleType;
|
||||||
|
/** 是否开启鼠标滚轮响应 */
|
||||||
|
wheelable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ThemePreferences {
|
interface ThemePreferences {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/form-ui",
|
"name": "@vben-core/form-ui",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -44,11 +44,15 @@ export function setupVbenForm<
|
||||||
>(options: VbenFormAdapterOptions<T>) {
|
>(options: VbenFormAdapterOptions<T>) {
|
||||||
const { config, defineRules } = options;
|
const { config, defineRules } = options;
|
||||||
|
|
||||||
const { disabledOnChangeListener = false, emptyStateValue = undefined } =
|
const {
|
||||||
(config || {}) as FormCommonConfig;
|
disabledOnChangeListener = true,
|
||||||
|
disabledOnInputListener = true,
|
||||||
|
emptyStateValue = undefined,
|
||||||
|
} = (config || {}) as FormCommonConfig;
|
||||||
|
|
||||||
Object.assign(DEFAULT_FORM_COMMON_CONFIG, {
|
Object.assign(DEFAULT_FORM_COMMON_CONFIG, {
|
||||||
disabledOnChangeListener,
|
disabledOnChangeListener,
|
||||||
|
disabledOnInputListener,
|
||||||
emptyStateValue,
|
emptyStateValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ const {
|
||||||
description,
|
description,
|
||||||
disabled,
|
disabled,
|
||||||
disabledOnChangeListener,
|
disabledOnChangeListener,
|
||||||
|
disabledOnInputListener,
|
||||||
emptyStateValue,
|
emptyStateValue,
|
||||||
fieldName,
|
fieldName,
|
||||||
formFieldProps,
|
formFieldProps,
|
||||||
|
@ -236,10 +237,13 @@ function fieldBindEvent(slotProps: Record<string, any>) {
|
||||||
|
|
||||||
return onChange?.(e?.target?.[bindEventField] ?? e);
|
return onChange?.(e?.target?.[bindEventField] ?? e);
|
||||||
},
|
},
|
||||||
onInput: () => {},
|
...(disabledOnInputListener ? { onInput: undefined } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return {
|
||||||
|
...(disabledOnInputListener ? { onInput: undefined } : {}),
|
||||||
|
...(disabledOnChangeListener ? { onChange: undefined } : {}),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createComponentProps(slotProps: Record<string, any>) {
|
function createComponentProps(slotProps: Record<string, any>) {
|
||||||
|
|
|
@ -89,7 +89,8 @@ const computedSchema = computed(
|
||||||
componentProps = {},
|
componentProps = {},
|
||||||
controlClass = '',
|
controlClass = '',
|
||||||
disabled,
|
disabled,
|
||||||
disabledOnChangeListener = false,
|
disabledOnChangeListener = true,
|
||||||
|
disabledOnInputListener = true,
|
||||||
emptyStateValue = undefined,
|
emptyStateValue = undefined,
|
||||||
formFieldProps = {},
|
formFieldProps = {},
|
||||||
formItemClass = '',
|
formItemClass = '',
|
||||||
|
@ -111,6 +112,7 @@ const computedSchema = computed(
|
||||||
return {
|
return {
|
||||||
disabled,
|
disabled,
|
||||||
disabledOnChangeListener,
|
disabledOnChangeListener,
|
||||||
|
disabledOnInputListener,
|
||||||
emptyStateValue,
|
emptyStateValue,
|
||||||
hideLabel,
|
hideLabel,
|
||||||
hideRequiredMark,
|
hideRequiredMark,
|
||||||
|
|
|
@ -160,9 +160,14 @@ export interface FormCommonConfig {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
/**
|
/**
|
||||||
* 是否禁用所有表单项的change事件监听
|
* 是否禁用所有表单项的change事件监听
|
||||||
* @default false
|
* @default true
|
||||||
*/
|
*/
|
||||||
disabledOnChangeListener?: boolean;
|
disabledOnChangeListener?: boolean;
|
||||||
|
/**
|
||||||
|
* 是否禁用所有表单项的input事件监听
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
disabledOnInputListener?: boolean;
|
||||||
/**
|
/**
|
||||||
* 所有表单项的空状态值,默认都是undefined,naive-ui的空状态值是null
|
* 所有表单项的空状态值,默认都是undefined,naive-ui的空状态值是null
|
||||||
*/
|
*/
|
||||||
|
@ -382,6 +387,7 @@ export interface VbenFormAdapterOptions<
|
||||||
config?: {
|
config?: {
|
||||||
baseModelPropName?: string;
|
baseModelPropName?: string;
|
||||||
disabledOnChangeListener?: boolean;
|
disabledOnChangeListener?: boolean;
|
||||||
|
disabledOnInputListener?: boolean;
|
||||||
emptyStateValue?: null | undefined;
|
emptyStateValue?: null | undefined;
|
||||||
modelPropNameMap?: Partial<Record<T, string>>;
|
modelPropNameMap?: Partial<Record<T, string>>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,9 @@ 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 { toRaw, useTemplateRef, watch } from 'vue';
|
import { nextTick, onMounted, useTemplateRef, watch } from 'vue';
|
||||||
|
|
||||||
|
import { cloneDeep } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { useDebounceFn } from '@vueuse/core';
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
|
|
||||||
|
@ -59,14 +61,16 @@ function handleKeyDownEnter(event: KeyboardEvent) {
|
||||||
formActionsRef.value?.handleSubmit?.();
|
formActionsRef.value?.handleSubmit?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
const handleValuesChangeDebounced = useDebounceFn((newVal) => {
|
||||||
() => form.values,
|
forward.value.handleValuesChange?.(cloneDeep(newVal));
|
||||||
useDebounceFn(() => {
|
state.value.submitOnChange && formActionsRef.value?.handleSubmit?.();
|
||||||
forward.value.handleValuesChange?.(toRaw(form.values));
|
}, 300);
|
||||||
state.value.submitOnChange && props.formApi?.submitForm();
|
|
||||||
}, 300),
|
onMounted(async () => {
|
||||||
{ deep: true },
|
// 只在挂载后开始监听,form.values会有一个初始化的过程
|
||||||
);
|
await nextTick();
|
||||||
|
watch(() => form.values, handleValuesChangeDebounced, { deep: true });
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/layout-ui",
|
"name": "@vben-core/layout-ui",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/menu-ui",
|
"name": "@vben-core/menu-ui",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/shadcn-ui",
|
"name": "@vben-core/shadcn-ui",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"#main": "./dist/index.mjs",
|
"#main": "./dist/index.mjs",
|
||||||
"#module": "./dist/index.mjs",
|
"#module": "./dist/index.mjs",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
|
|
|
@ -47,6 +47,10 @@ watch(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(inputValue, (val) => {
|
||||||
|
modelValue.value = val.join('');
|
||||||
|
});
|
||||||
|
|
||||||
function handleComplete(e: string[]) {
|
function handleComplete(e: string[]) {
|
||||||
modelValue.value = e.join('');
|
modelValue.value = e.join('');
|
||||||
emit('complete');
|
emit('complete');
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben-core/tabs-ui",
|
"name": "@vben-core/tabs-ui",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -19,6 +19,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
contentClass: 'vben-tabs-content',
|
contentClass: 'vben-tabs-content',
|
||||||
draggable: true,
|
draggable: true,
|
||||||
styleType: 'chrome',
|
styleType: 'chrome',
|
||||||
|
wheelable: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<TabsEmits>();
|
const emit = defineEmits<TabsEmits>();
|
||||||
|
@ -27,6 +28,7 @@ const forward = useForwardPropsEmits(props, emit);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleScrollAt,
|
handleScrollAt,
|
||||||
|
handleWheel,
|
||||||
scrollbarRef,
|
scrollbarRef,
|
||||||
scrollDirection,
|
scrollDirection,
|
||||||
scrollIsAtLeft,
|
scrollIsAtLeft,
|
||||||
|
@ -34,6 +36,14 @@ const {
|
||||||
showScrollButton,
|
showScrollButton,
|
||||||
} = useTabsViewScroll(props);
|
} = useTabsViewScroll(props);
|
||||||
|
|
||||||
|
function onWheel(e: WheelEvent) {
|
||||||
|
if (props.wheelable) {
|
||||||
|
handleWheel(e);
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useTabsDrag(props, emit);
|
useTabsDrag(props, emit);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -69,6 +79,7 @@ useTabsDrag(props, emit);
|
||||||
shadow-left
|
shadow-left
|
||||||
shadow-right
|
shadow-right
|
||||||
@scroll-at="handleScrollAt"
|
@scroll-at="handleScrollAt"
|
||||||
|
@wheel="onWheel"
|
||||||
>
|
>
|
||||||
<TabsChrome
|
<TabsChrome
|
||||||
v-if="styleType === 'chrome'"
|
v-if="styleType === 'chrome'"
|
||||||
|
|
|
@ -33,7 +33,6 @@ export interface TabsProps {
|
||||||
* 仅限 tabs-chrome
|
* 仅限 tabs-chrome
|
||||||
*/
|
*/
|
||||||
maxWidth?: number;
|
maxWidth?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @zh_CN tab最小宽度
|
* @zh_CN tab最小宽度
|
||||||
* 仅限 tabs-chrome
|
* 仅限 tabs-chrome
|
||||||
|
@ -44,15 +43,20 @@ export interface TabsProps {
|
||||||
* @zh_CN 是否显示图标
|
* @zh_CN 是否显示图标
|
||||||
*/
|
*/
|
||||||
showIcon?: boolean;
|
showIcon?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @zh_CN 标签页风格
|
* @zh_CN 标签页风格
|
||||||
*/
|
*/
|
||||||
styleType?: TabsStyleType;
|
styleType?: TabsStyleType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @zh_CN 选项卡数据
|
* @zh_CN 选项卡数据
|
||||||
*/
|
*/
|
||||||
tabs?: TabDefinition[];
|
tabs?: TabDefinition[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @zh_CN 是否响应滚轮事件
|
||||||
|
*/
|
||||||
|
wheelable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TabConfig extends TabDefinition {
|
export interface TabConfig extends TabDefinition {
|
||||||
|
|
|
@ -142,6 +142,13 @@ export function useTabsViewScroll(props: TabsProps) {
|
||||||
scrollIsAtRight.value = right;
|
scrollIsAtRight.value = right;
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
|
function handleWheel({ deltaY }: WheelEvent) {
|
||||||
|
scrollViewportEl.value?.scrollBy({
|
||||||
|
behavior: 'smooth',
|
||||||
|
left: deltaY * 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.active,
|
() => props.active,
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -184,6 +191,7 @@ export function useTabsViewScroll(props: TabsProps) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleScrollAt,
|
handleScrollAt,
|
||||||
|
handleWheel,
|
||||||
initScrollbar,
|
initScrollbar,
|
||||||
scrollbarRef,
|
scrollbarRef,
|
||||||
scrollDirection,
|
scrollDirection,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/constants",
|
"name": "@vben/constants",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/access",
|
"name": "@vben/access",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/common-ui",
|
"name": "@vben/common-ui",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AuthenticationProps } from './types';
|
import type { AuthenticationProps } from './types';
|
||||||
|
|
||||||
import { watch } from 'vue';
|
import { computed, watch } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben-core/popup-ui';
|
import { useVbenModal } from '@vben-core/popup-ui';
|
||||||
import { Slot, VbenAvatar } from '@vben-core/shadcn-ui';
|
import { Slot, VbenAvatar } from '@vben-core/shadcn-ui';
|
||||||
|
|
||||||
interface Props extends AuthenticationProps {
|
interface Props extends AuthenticationProps {
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
|
zIndex?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'LoginExpiredModal',
|
name: 'LoginExpiredModal',
|
||||||
});
|
});
|
||||||
|
|
||||||
withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
avatar: '',
|
avatar: '',
|
||||||
|
zIndex: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const open = defineModel<boolean>('open');
|
const open = defineModel<boolean>('open');
|
||||||
|
@ -28,6 +30,26 @@ watch(
|
||||||
modalApi.setState({ isOpen: val });
|
modalApi.setState({ isOpen: val });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const getZIndex = computed(() => {
|
||||||
|
return props.zIndex || calcZIndex();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最大的zIndex值
|
||||||
|
*/
|
||||||
|
function calcZIndex() {
|
||||||
|
let maxZ = 0;
|
||||||
|
const elements = document.querySelectorAll('*');
|
||||||
|
[...elements].forEach((element) => {
|
||||||
|
const style = window.getComputedStyle(element);
|
||||||
|
const zIndex = style.getPropertyValue('z-index');
|
||||||
|
if (zIndex && !Number.isNaN(Number.parseInt(zIndex))) {
|
||||||
|
maxZ = Math.max(maxZ, Number.parseInt(zIndex));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return maxZ + 1;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -39,6 +61,7 @@ watch(
|
||||||
:footer="false"
|
:footer="false"
|
||||||
:fullscreen-button="false"
|
:fullscreen-button="false"
|
||||||
:header="false"
|
:header="false"
|
||||||
|
:z-index="getZIndex"
|
||||||
class="border-none px-10 py-6 text-center shadow-xl sm:w-[600px] sm:rounded-2xl md:h-[unset]"
|
class="border-none px-10 py-6 text-center shadow-xl sm:w-[600px] sm:rounded-2xl md:h-[unset]"
|
||||||
>
|
>
|
||||||
<VbenAvatar :src="avatar" class="mx-auto mb-6 size-20" />
|
<VbenAvatar :src="avatar" class="mx-auto mb-6 size-20" />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/hooks",
|
"name": "@vben/hooks",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
"@vben/stores": "workspace:*",
|
"@vben/stores": "workspace:*",
|
||||||
"@vben/types": "workspace:*",
|
"@vben/types": "workspace:*",
|
||||||
"@vben/utils": "workspace:*",
|
"@vben/utils": "workspace:*",
|
||||||
|
"@vueuse/core": "catalog:",
|
||||||
"vue": "catalog:",
|
"vue": "catalog:",
|
||||||
"vue-router": "catalog:",
|
"vue-router": "catalog:",
|
||||||
"watermark-js-plus": "catalog:"
|
"watermark-js-plus": "catalog:"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
export * from './use-app-config';
|
export * from './use-app-config';
|
||||||
export * from './use-content-maximize';
|
export * from './use-content-maximize';
|
||||||
export * from './use-design-tokens';
|
export * from './use-design-tokens';
|
||||||
|
export * from './use-hover-toggle';
|
||||||
export * from './use-pagination';
|
export * from './use-pagination';
|
||||||
export * from './use-refresh';
|
export * from './use-refresh';
|
||||||
export * from './use-tabs';
|
export * from './use-tabs';
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import type { Arrayable, MaybeElementRef } from '@vueuse/core';
|
||||||
|
|
||||||
|
import { computed, onUnmounted, ref, watch } from 'vue';
|
||||||
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
|
import { isFunction } from '@vben/utils';
|
||||||
|
|
||||||
|
import { useMouseInElement } from '@vueuse/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监测鼠标是否在元素内部,如果在元素内部则返回 true,否则返回 false
|
||||||
|
* @param refElement 所有需要检测的元素。如果提供了一个数组,那么鼠标在任何一个元素内部都会返回 true
|
||||||
|
* @param delay 延迟更新状态的时间
|
||||||
|
* @returns 返回一个数组,第一个元素是一个 ref,表示鼠标是否在元素内部,第二个元素是一个控制器,可以通过 enable 和 disable 方法来控制监听器的启用和禁用
|
||||||
|
*/
|
||||||
|
export function useHoverToggle(
|
||||||
|
refElement: Arrayable<MaybeElementRef>,
|
||||||
|
delay: (() => number) | number = 500,
|
||||||
|
) {
|
||||||
|
const isOutsides: Array<Ref<boolean>> = [];
|
||||||
|
const value = ref(false);
|
||||||
|
const timer = ref<ReturnType<typeof setTimeout> | undefined>();
|
||||||
|
const refs = Array.isArray(refElement) ? refElement : [refElement];
|
||||||
|
refs.forEach((refEle) => {
|
||||||
|
const listener = useMouseInElement(refEle, { handleOutside: true });
|
||||||
|
isOutsides.push(listener.isOutside);
|
||||||
|
});
|
||||||
|
const isOutsideAll = computed(() => isOutsides.every((v) => v.value));
|
||||||
|
|
||||||
|
function setValueDelay(val: boolean) {
|
||||||
|
timer.value && clearTimeout(timer.value);
|
||||||
|
timer.value = setTimeout(
|
||||||
|
() => {
|
||||||
|
value.value = val;
|
||||||
|
timer.value = undefined;
|
||||||
|
},
|
||||||
|
isFunction(delay) ? delay() : delay,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const watcher = watch(
|
||||||
|
isOutsideAll,
|
||||||
|
(val) => {
|
||||||
|
setValueDelay(!val);
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
const controller = {
|
||||||
|
enable() {
|
||||||
|
watcher.resume();
|
||||||
|
},
|
||||||
|
disable() {
|
||||||
|
watcher.pause();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
timer.value && clearTimeout(timer.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return [value, controller] as [typeof value, typeof controller];
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/layouts",
|
"name": "@vben/layouts",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -103,6 +103,7 @@ const {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleMenuSelect,
|
handleMenuSelect,
|
||||||
|
handleMenuOpen,
|
||||||
headerActive,
|
headerActive,
|
||||||
headerMenus,
|
headerMenus,
|
||||||
sidebarActive,
|
sidebarActive,
|
||||||
|
@ -260,6 +261,7 @@ const headerSlots = computed(() => {
|
||||||
:rounded="isMenuRounded"
|
:rounded="isMenuRounded"
|
||||||
:theme="sidebarTheme"
|
:theme="sidebarTheme"
|
||||||
mode="vertical"
|
mode="vertical"
|
||||||
|
@open="handleMenuOpen"
|
||||||
@select="handleMenuSelect"
|
@select="handleMenuSelect"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -14,12 +14,17 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
open: [string, string[]];
|
||||||
select: [string, string?];
|
select: [string, string?];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
function handleMenuSelect(key: string) {
|
function handleMenuSelect(key: string) {
|
||||||
emit('select', key, props.mode);
|
emit('select', key, props.mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleMenuOpen(key: string, path: string[]) {
|
||||||
|
emit('open', key, path);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -32,6 +37,7 @@ function handleMenuSelect(key: string) {
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
:rounded="rounded"
|
:rounded="rounded"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
|
@open="handleMenuOpen"
|
||||||
@select="handleMenuSelect"
|
@select="handleMenuSelect"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -15,6 +15,9 @@ function useExtraMenu() {
|
||||||
|
|
||||||
const menus = computed(() => accessStore.accessMenus);
|
const menus = computed(() => accessStore.accessMenus);
|
||||||
|
|
||||||
|
/** 记录当前顶级菜单下哪个子菜单最后激活 */
|
||||||
|
const defaultSubMap = new Map<string, string>();
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const extraMenus = ref<MenuRecordRaw[]>([]);
|
const extraMenus = ref<MenuRecordRaw[]>([]);
|
||||||
const sidebarExtraVisible = ref<boolean>(false);
|
const sidebarExtraVisible = ref<boolean>(false);
|
||||||
|
@ -32,6 +35,12 @@ function useExtraMenu() {
|
||||||
sidebarExtraVisible.value = hasChildren;
|
sidebarExtraVisible.value = hasChildren;
|
||||||
if (!hasChildren) {
|
if (!hasChildren) {
|
||||||
await navigation(menu.path);
|
await navigation(menu.path);
|
||||||
|
} else if (preferences.sidebar.autoActivateChild) {
|
||||||
|
await navigation(
|
||||||
|
defaultSubMap.has(menu.path)
|
||||||
|
? (defaultSubMap.get(menu.path) as string)
|
||||||
|
: menu.path,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,6 +98,7 @@ function useExtraMenu() {
|
||||||
menus.value,
|
menus.value,
|
||||||
currentPath,
|
currentPath,
|
||||||
);
|
);
|
||||||
|
if (rootMenuPath) defaultSubMap.set(rootMenuPath, currentPath);
|
||||||
extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? '';
|
extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? '';
|
||||||
extraMenus.value = rootMenu?.children ?? [];
|
extraMenus.value = rootMenu?.children ?? [];
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,7 +15,8 @@ function useMixedMenu() {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const splitSideMenus = ref<MenuRecordRaw[]>([]);
|
const splitSideMenus = ref<MenuRecordRaw[]>([]);
|
||||||
const rootMenuPath = ref<string>('');
|
const rootMenuPath = ref<string>('');
|
||||||
|
/** 记录当前顶级菜单下哪个子菜单最后激活 */
|
||||||
|
const defaultSubMap = new Map<string, string>();
|
||||||
const { isMixedNav } = usePreferences();
|
const { isMixedNav } = usePreferences();
|
||||||
|
|
||||||
const needSplit = computed(
|
const needSplit = computed(
|
||||||
|
@ -86,6 +87,25 @@ function useMixedMenu() {
|
||||||
splitSideMenus.value = rootMenu?.children ?? [];
|
splitSideMenus.value = rootMenu?.children ?? [];
|
||||||
if (splitSideMenus.value.length === 0) {
|
if (splitSideMenus.value.length === 0) {
|
||||||
navigation(key);
|
navigation(key);
|
||||||
|
} else if (rootMenu && preferences.sidebar.autoActivateChild) {
|
||||||
|
navigation(
|
||||||
|
defaultSubMap.has(rootMenu.path)
|
||||||
|
? (defaultSubMap.get(rootMenu.path) as string)
|
||||||
|
: rootMenu.path,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 侧边菜单展开事件
|
||||||
|
* @param key 路由路径
|
||||||
|
* @param parentsPath 父级路径
|
||||||
|
*/
|
||||||
|
const handleMenuOpen = (key: string, parentsPath: string[]) => {
|
||||||
|
if (parentsPath.length <= 1 && preferences.sidebar.autoActivateChild) {
|
||||||
|
navigation(
|
||||||
|
defaultSubMap.has(key) ? (defaultSubMap.get(key) as string) : key,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,6 +127,8 @@ function useMixedMenu() {
|
||||||
(path) => {
|
(path) => {
|
||||||
const currentPath = (route?.meta?.activePath as string) ?? path;
|
const currentPath = (route?.meta?.activePath as string) ?? path;
|
||||||
calcSideMenus(currentPath);
|
calcSideMenus(currentPath);
|
||||||
|
if (rootMenuPath.value)
|
||||||
|
defaultSubMap.set(rootMenuPath.value, currentPath);
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
);
|
);
|
||||||
|
@ -118,6 +140,7 @@ function useMixedMenu() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleMenuSelect,
|
handleMenuSelect,
|
||||||
|
handleMenuOpen,
|
||||||
headerActive,
|
headerActive,
|
||||||
headerMenus,
|
headerMenus,
|
||||||
sidebarActive,
|
sidebarActive,
|
||||||
|
|
|
@ -55,6 +55,7 @@ if (!preferences.tabbar.persist) {
|
||||||
:show-icon="showIcon"
|
:show-icon="showIcon"
|
||||||
:style-type="preferences.tabbar.styleType"
|
:style-type="preferences.tabbar.styleType"
|
||||||
:tabs="currentTabs"
|
:tabs="currentTabs"
|
||||||
|
:wheelable="preferences.tabbar.wheelable"
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
@sort-tabs="tabbarStore.sortTabs"
|
@sort-tabs="tabbarStore.sortTabs"
|
||||||
@unpin="unpinTab"
|
@unpin="unpinTab"
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { LayoutType } from '@vben/types';
|
||||||
|
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
import NumberFieldItem from '../number-field-item.vue';
|
import NumberFieldItem from '../number-field-item.vue';
|
||||||
import SwitchItem from '../switch-item.vue';
|
import SwitchItem from '../switch-item.vue';
|
||||||
|
|
||||||
defineProps<{ disabled: boolean }>();
|
defineProps<{ currentLayout?: LayoutType; disabled: boolean }>();
|
||||||
|
|
||||||
const sidebarEnable = defineModel<boolean>('sidebarEnable');
|
const sidebarEnable = defineModel<boolean>('sidebarEnable');
|
||||||
const sidebarWidth = defineModel<number>('sidebarWidth');
|
const sidebarWidth = defineModel<number>('sidebarWidth');
|
||||||
const sidebarCollapsedShowTitle = defineModel<boolean>(
|
const sidebarCollapsedShowTitle = defineModel<boolean>(
|
||||||
'sidebarCollapsedShowTitle',
|
'sidebarCollapsedShowTitle',
|
||||||
);
|
);
|
||||||
|
const sidebarAutoActivateChild = defineModel<boolean>(
|
||||||
|
'sidebarAutoActivateChild',
|
||||||
|
);
|
||||||
const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
|
const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
|
||||||
|
const sidebarExpandOnHover = defineModel<boolean>('sidebarExpandOnHover');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -21,12 +27,32 @@ const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
|
||||||
<SwitchItem v-model="sidebarCollapsed" :disabled="!sidebarEnable || disabled">
|
<SwitchItem v-model="sidebarCollapsed" :disabled="!sidebarEnable || disabled">
|
||||||
{{ $t('preferences.sidebar.collapsed') }}
|
{{ $t('preferences.sidebar.collapsed') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
|
<SwitchItem
|
||||||
|
v-model="sidebarExpandOnHover"
|
||||||
|
:disabled="!sidebarEnable || disabled || !sidebarCollapsed"
|
||||||
|
:tip="$t('preferences.sidebar.expandOnHoverTip')"
|
||||||
|
>
|
||||||
|
{{ $t('preferences.sidebar.expandOnHover') }}
|
||||||
|
</SwitchItem>
|
||||||
<SwitchItem
|
<SwitchItem
|
||||||
v-model="sidebarCollapsedShowTitle"
|
v-model="sidebarCollapsedShowTitle"
|
||||||
:disabled="!sidebarEnable || disabled || !sidebarCollapsed"
|
:disabled="!sidebarEnable || disabled || !sidebarCollapsed"
|
||||||
>
|
>
|
||||||
{{ $t('preferences.sidebar.collapsedShowTitle') }}
|
{{ $t('preferences.sidebar.collapsedShowTitle') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
|
<SwitchItem
|
||||||
|
v-model="sidebarAutoActivateChild"
|
||||||
|
:disabled="
|
||||||
|
!sidebarEnable ||
|
||||||
|
!['sidebar-mixed-nav', 'mixed-nav', 'sidebar-nav'].includes(
|
||||||
|
currentLayout as string,
|
||||||
|
) ||
|
||||||
|
disabled
|
||||||
|
"
|
||||||
|
:tip="$t('preferences.sidebar.autoActivateChildTip')"
|
||||||
|
>
|
||||||
|
{{ $t('preferences.sidebar.autoActivateChild') }}
|
||||||
|
</SwitchItem>
|
||||||
<NumberFieldItem
|
<NumberFieldItem
|
||||||
v-model="sidebarWidth"
|
v-model="sidebarWidth"
|
||||||
:disabled="!sidebarEnable || disabled"
|
:disabled="!sidebarEnable || disabled"
|
||||||
|
|
|
@ -18,6 +18,7 @@ const tabbarEnable = defineModel<boolean>('tabbarEnable');
|
||||||
const tabbarShowIcon = defineModel<boolean>('tabbarShowIcon');
|
const tabbarShowIcon = defineModel<boolean>('tabbarShowIcon');
|
||||||
const tabbarPersist = defineModel<boolean>('tabbarPersist');
|
const tabbarPersist = defineModel<boolean>('tabbarPersist');
|
||||||
const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
|
const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
|
||||||
|
const tabbarWheelable = defineModel<boolean>('tabbarWheelable');
|
||||||
const tabbarStyleType = defineModel<string>('tabbarStyleType');
|
const tabbarStyleType = defineModel<string>('tabbarStyleType');
|
||||||
const tabbarShowMore = defineModel<boolean>('tabbarShowMore');
|
const tabbarShowMore = defineModel<boolean>('tabbarShowMore');
|
||||||
const tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');
|
const tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');
|
||||||
|
@ -53,6 +54,13 @@ const styleItems = computed((): SelectOption[] => [
|
||||||
<SwitchItem v-model="tabbarDraggable" :disabled="!tabbarEnable">
|
<SwitchItem v-model="tabbarDraggable" :disabled="!tabbarEnable">
|
||||||
{{ $t('preferences.tabbar.draggable') }}
|
{{ $t('preferences.tabbar.draggable') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
|
<SwitchItem
|
||||||
|
v-model="tabbarWheelable"
|
||||||
|
:disabled="!tabbarEnable"
|
||||||
|
:tip="$t('preferences.tabbar.wheelableTip')"
|
||||||
|
>
|
||||||
|
{{ $t('preferences.tabbar.wheelable') }}
|
||||||
|
</SwitchItem>
|
||||||
<SwitchItem v-model="tabbarShowIcon" :disabled="!tabbarEnable">
|
<SwitchItem v-model="tabbarShowIcon" :disabled="!tabbarEnable">
|
||||||
{{ $t('preferences.tabbar.icon') }}
|
{{ $t('preferences.tabbar.icon') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
|
|
|
@ -8,8 +8,9 @@ defineOptions({
|
||||||
name: 'PreferenceSwitchItem',
|
name: 'PreferenceSwitchItem',
|
||||||
});
|
});
|
||||||
|
|
||||||
withDefaults(defineProps<{ disabled?: boolean }>(), {
|
withDefaults(defineProps<{ disabled?: boolean; tip?: string }>(), {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
tip: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const checked = defineModel<boolean>();
|
const checked = defineModel<boolean>();
|
||||||
|
@ -32,11 +33,17 @@ function handleClick() {
|
||||||
<span class="flex items-center text-sm">
|
<span class="flex items-center text-sm">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|
||||||
<VbenTooltip v-if="slots.tip" side="bottom">
|
<VbenTooltip v-if="slots.tip || tip" side="bottom">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<CircleHelp class="ml-1 size-3 cursor-help" />
|
<CircleHelp class="ml-1 size-3 cursor-help" />
|
||||||
</template>
|
</template>
|
||||||
<slot name="tip"></slot>
|
<slot name="tip">
|
||||||
|
<template v-if="tip">
|
||||||
|
<p v-for="(line, index) in tip.split('\n')" :key="index">
|
||||||
|
{{ line }}
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
</slot>
|
||||||
</VbenTooltip>
|
</VbenTooltip>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="$slots.shortcut" class="ml-auto mr-2 text-xs opacity-60">
|
<span v-if="$slots.shortcut" class="ml-auto mr-2 text-xs opacity-60">
|
||||||
|
|
|
@ -87,6 +87,10 @@ const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
|
||||||
const sidebarCollapsedShowTitle = defineModel<boolean>(
|
const sidebarCollapsedShowTitle = defineModel<boolean>(
|
||||||
'sidebarCollapsedShowTitle',
|
'sidebarCollapsedShowTitle',
|
||||||
);
|
);
|
||||||
|
const sidebarAutoActivateChild = defineModel<boolean>(
|
||||||
|
'sidebarAutoActivateChild',
|
||||||
|
);
|
||||||
|
const SidebarExpandOnHover = defineModel<boolean>('sidebarExpandOnHover');
|
||||||
|
|
||||||
const headerEnable = defineModel<boolean>('headerEnable');
|
const headerEnable = defineModel<boolean>('headerEnable');
|
||||||
const headerMode = defineModel<LayoutHeaderModeType>('headerMode');
|
const headerMode = defineModel<LayoutHeaderModeType>('headerMode');
|
||||||
|
@ -105,6 +109,7 @@ const tabbarShowMore = defineModel<boolean>('tabbarShowMore');
|
||||||
const tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');
|
const tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');
|
||||||
const tabbarPersist = defineModel<boolean>('tabbarPersist');
|
const tabbarPersist = defineModel<boolean>('tabbarPersist');
|
||||||
const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
|
const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
|
||||||
|
const tabbarWheelable = defineModel<boolean>('tabbarWheelable');
|
||||||
const tabbarStyleType = defineModel<string>('tabbarStyleType');
|
const tabbarStyleType = defineModel<string>('tabbarStyleType');
|
||||||
|
|
||||||
const navigationStyleType = defineModel<NavigationStyleType>(
|
const navigationStyleType = defineModel<NavigationStyleType>(
|
||||||
|
@ -298,10 +303,13 @@ async function handleReset() {
|
||||||
|
|
||||||
<Block :title="$t('preferences.sidebar.title')">
|
<Block :title="$t('preferences.sidebar.title')">
|
||||||
<Sidebar
|
<Sidebar
|
||||||
|
v-model:sidebar-auto-activate-child="sidebarAutoActivateChild"
|
||||||
v-model:sidebar-collapsed="sidebarCollapsed"
|
v-model:sidebar-collapsed="sidebarCollapsed"
|
||||||
v-model:sidebar-collapsed-show-title="sidebarCollapsedShowTitle"
|
v-model:sidebar-collapsed-show-title="sidebarCollapsedShowTitle"
|
||||||
v-model:sidebar-enable="sidebarEnable"
|
v-model:sidebar-enable="sidebarEnable"
|
||||||
|
v-model:sidebar-expand-on-hover="SidebarExpandOnHover"
|
||||||
v-model:sidebar-width="sidebarWidth"
|
v-model:sidebar-width="sidebarWidth"
|
||||||
|
:current-layout="appLayout"
|
||||||
:disabled="!isSideMode"
|
:disabled="!isSideMode"
|
||||||
/>
|
/>
|
||||||
</Block>
|
</Block>
|
||||||
|
@ -345,6 +353,7 @@ async function handleReset() {
|
||||||
v-model:tabbar-show-maximize="tabbarShowMaximize"
|
v-model:tabbar-show-maximize="tabbarShowMaximize"
|
||||||
v-model:tabbar-show-more="tabbarShowMore"
|
v-model:tabbar-show-more="tabbarShowMore"
|
||||||
v-model:tabbar-style-type="tabbarStyleType"
|
v-model:tabbar-style-type="tabbarStyleType"
|
||||||
|
v-model:tabbar-wheelable="tabbarWheelable"
|
||||||
/>
|
/>
|
||||||
</Block>
|
</Block>
|
||||||
<Block :title="$t('preferences.widget.title')">
|
<Block :title="$t('preferences.widget.title')">
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
import type { AnyFunction } from '@vben/types';
|
import type { AnyFunction } from '@vben/types';
|
||||||
|
|
||||||
import type { Component } from 'vue';
|
import type { Component } from 'vue';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, useTemplateRef, watch } from 'vue';
|
||||||
|
|
||||||
|
import { useHoverToggle } from '@vben/hooks';
|
||||||
import { LockKeyhole, LogOut } from '@vben/icons';
|
import { LockKeyhole, LogOut } from '@vben/icons';
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
import { preferences, usePreferences } from '@vben/preferences';
|
import { preferences, usePreferences } from '@vben/preferences';
|
||||||
|
@ -53,6 +54,10 @@ interface Props {
|
||||||
* 文本
|
* 文本
|
||||||
*/
|
*/
|
||||||
text?: string;
|
text?: string;
|
||||||
|
/** 触发方式 */
|
||||||
|
trigger?: 'both' | 'click' | 'hover';
|
||||||
|
/** hover触发时,延迟响应的时间 */
|
||||||
|
hoverDelay?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
|
@ -67,10 +72,11 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
showShortcutKey: true,
|
showShortcutKey: true,
|
||||||
tagText: '',
|
tagText: '',
|
||||||
text: '',
|
text: '',
|
||||||
|
trigger: 'click',
|
||||||
|
hoverDelay: 500,
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{ logout: [] }>();
|
const emit = defineEmits<{ logout: [] }>();
|
||||||
const openPopover = ref(false);
|
|
||||||
|
|
||||||
const { globalLockScreenShortcutKey, globalLogoutShortcutKey } =
|
const { globalLockScreenShortcutKey, globalLogoutShortcutKey } =
|
||||||
usePreferences();
|
usePreferences();
|
||||||
|
@ -84,6 +90,27 @@ const [LogoutModal, logoutModalApi] = useVbenModal({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const refTrigger = useTemplateRef('refTrigger');
|
||||||
|
const refContent = useTemplateRef('refContent');
|
||||||
|
const [openPopover, hoverWatcher] = useHoverToggle(
|
||||||
|
[refTrigger, refContent],
|
||||||
|
() => props.hoverDelay,
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.trigger === 'hover' || props.trigger === 'both',
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
hoverWatcher.enable();
|
||||||
|
} else {
|
||||||
|
hoverWatcher.disable();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
|
const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
|
||||||
|
|
||||||
const enableLogoutShortcutKey = computed(() => {
|
const enableLogoutShortcutKey = computed(() => {
|
||||||
|
@ -155,8 +182,8 @@ if (enableShortcutKey.value) {
|
||||||
{{ $t('ui.widgets.logoutTip') }}
|
{{ $t('ui.widgets.logoutTip') }}
|
||||||
</LogoutModal>
|
</LogoutModal>
|
||||||
|
|
||||||
<DropdownMenu>
|
<DropdownMenu v-model:open="openPopover">
|
||||||
<DropdownMenuTrigger>
|
<DropdownMenuTrigger ref="refTrigger" :disabled="props.trigger === 'hover'">
|
||||||
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full p-1.5">
|
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full p-1.5">
|
||||||
<div class="hover:text-accent-foreground flex-center">
|
<div class="hover:text-accent-foreground flex-center">
|
||||||
<VbenAvatar :alt="text" :src="avatar" class="size-8" dot />
|
<VbenAvatar :alt="text" :src="avatar" class="size-8" dot />
|
||||||
|
@ -164,64 +191,66 @@ if (enableShortcutKey.value) {
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent class="mr-2 min-w-[240px] p-0 pb-1">
|
<DropdownMenuContent class="mr-2 min-w-[240px] p-0 pb-1">
|
||||||
<DropdownMenuLabel class="flex items-center p-3">
|
<div ref="refContent">
|
||||||
<VbenAvatar
|
<DropdownMenuLabel class="flex items-center p-3">
|
||||||
:alt="text"
|
<VbenAvatar
|
||||||
:src="avatar"
|
:alt="text"
|
||||||
class="size-12"
|
:src="avatar"
|
||||||
dot
|
class="size-12"
|
||||||
dot-class="bottom-0 right-1 border-2 size-4 bg-green-500"
|
dot
|
||||||
/>
|
dot-class="bottom-0 right-1 border-2 size-4 bg-green-500"
|
||||||
<div class="ml-2 w-full">
|
/>
|
||||||
<div
|
<div class="ml-2 w-full">
|
||||||
v-if="tagText || text || $slots.tagText"
|
<div
|
||||||
class="text-foreground mb-1 flex items-center text-sm font-medium"
|
v-if="tagText || text || $slots.tagText"
|
||||||
>
|
class="text-foreground mb-1 flex items-center text-sm font-medium"
|
||||||
{{ text }}
|
>
|
||||||
<slot name="tagText">
|
{{ text }}
|
||||||
<Badge v-if="tagText" class="ml-2 text-green-400">
|
<slot name="tagText">
|
||||||
{{ tagText }}
|
<Badge v-if="tagText" class="ml-2 text-green-400">
|
||||||
</Badge>
|
{{ tagText }}
|
||||||
</slot>
|
</Badge>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted-foreground text-xs font-normal">
|
||||||
|
{{ description }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-muted-foreground text-xs font-normal">
|
</DropdownMenuLabel>
|
||||||
{{ description }}
|
<DropdownMenuSeparator v-if="menus?.length" />
|
||||||
</div>
|
<DropdownMenuItem
|
||||||
</div>
|
v-for="menu in menus"
|
||||||
</DropdownMenuLabel>
|
:key="menu.text"
|
||||||
<DropdownMenuSeparator v-if="menus?.length" />
|
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||||
<DropdownMenuItem
|
@click="menu.handler"
|
||||||
v-for="menu in menus"
|
>
|
||||||
:key="menu.text"
|
<VbenIcon :icon="menu.icon" class="mr-2 size-4" />
|
||||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
{{ menu.text }}
|
||||||
@click="menu.handler"
|
</DropdownMenuItem>
|
||||||
>
|
<DropdownMenuSeparator />
|
||||||
<VbenIcon :icon="menu.icon" class="mr-2 size-4" />
|
<DropdownMenuItem
|
||||||
{{ menu.text }}
|
v-if="preferences.widget.lockScreen"
|
||||||
</DropdownMenuItem>
|
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||||
<DropdownMenuSeparator />
|
@click="handleOpenLock"
|
||||||
<DropdownMenuItem
|
>
|
||||||
v-if="preferences.widget.lockScreen"
|
<LockKeyhole class="mr-2 size-4" />
|
||||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
{{ $t('ui.widgets.lockScreen.title') }}
|
||||||
@click="handleOpenLock"
|
<DropdownMenuShortcut v-if="enableLockScreenShortcutKey">
|
||||||
>
|
{{ altView }} L
|
||||||
<LockKeyhole class="mr-2 size-4" />
|
</DropdownMenuShortcut>
|
||||||
{{ $t('ui.widgets.lockScreen.title') }}
|
</DropdownMenuItem>
|
||||||
<DropdownMenuShortcut v-if="enableLockScreenShortcutKey">
|
<DropdownMenuSeparator v-if="preferences.widget.lockScreen" />
|
||||||
{{ altView }} L
|
<DropdownMenuItem
|
||||||
</DropdownMenuShortcut>
|
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||||
</DropdownMenuItem>
|
@click="handleLogout"
|
||||||
<DropdownMenuSeparator v-if="preferences.widget.lockScreen" />
|
>
|
||||||
<DropdownMenuItem
|
<LogOut class="mr-2 size-4" />
|
||||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
{{ $t('common.logout') }}
|
||||||
@click="handleLogout"
|
<DropdownMenuShortcut v-if="enableLogoutShortcutKey">
|
||||||
>
|
{{ altView }} Q
|
||||||
<LogOut class="mr-2 size-4" />
|
</DropdownMenuShortcut>
|
||||||
{{ $t('common.logout') }}
|
</DropdownMenuItem>
|
||||||
<DropdownMenuShortcut v-if="enableLogoutShortcutKey">
|
</div>
|
||||||
{{ altView }} Q
|
|
||||||
</DropdownMenuShortcut>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/plugins",
|
"name": "@vben/plugins",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { toRaw } from 'vue';
|
||||||
import { Store } from '@vben-core/shared/store';
|
import { Store } from '@vben-core/shared/store';
|
||||||
import {
|
import {
|
||||||
bindMethods,
|
bindMethods,
|
||||||
|
isBoolean,
|
||||||
isFunction,
|
isFunction,
|
||||||
mergeWithArrayOverride,
|
mergeWithArrayOverride,
|
||||||
StateHandler,
|
StateHandler,
|
||||||
|
@ -20,6 +21,7 @@ function getDefaultState(): VxeGridProps {
|
||||||
gridOptions: {},
|
gridOptions: {},
|
||||||
gridEvents: {},
|
gridEvents: {},
|
||||||
formOptions: undefined,
|
formOptions: undefined,
|
||||||
|
showSearchForm: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +110,16 @@ export class VxeGridApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleSearchForm(show?: boolean) {
|
||||||
|
this.setState({
|
||||||
|
showSearchForm: isBoolean(show) ? show : !this.state?.showSearchForm,
|
||||||
|
});
|
||||||
|
// nextTick(() => {
|
||||||
|
// this.grid.recalculate();
|
||||||
|
// });
|
||||||
|
return this.state?.showSearchForm;
|
||||||
|
}
|
||||||
|
|
||||||
unmount() {
|
unmount() {
|
||||||
this.isMounted = false;
|
this.isMounted = false;
|
||||||
this.stateHandler.reset();
|
this.stateHandler.reset();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
export { setupVbenVxeTable } from './init';
|
export { setupVbenVxeTable } from './init';
|
||||||
|
export type { VxeTableGridOptions } from './types';
|
||||||
export * from './use-vxe-grid';
|
export * from './use-vxe-grid';
|
||||||
export { default as VbenVxeGrid } from './use-vxe-grid.vue';
|
|
||||||
|
|
||||||
|
export { default as VbenVxeGrid } from './use-vxe-grid.vue';
|
||||||
export type { VxeGridListeners, VxeGridProps } from 'vxe-table';
|
export type { VxeGridListeners, VxeGridProps } from 'vxe-table';
|
||||||
|
|
|
@ -2,6 +2,7 @@ import type { ClassType, DeepPartial } from '@vben/types';
|
||||||
import type { VbenFormProps } from '@vben-core/form-ui';
|
import type { VbenFormProps } from '@vben-core/form-ui';
|
||||||
import type {
|
import type {
|
||||||
VxeGridListeners,
|
VxeGridListeners,
|
||||||
|
VxeGridPropTypes,
|
||||||
VxeGridProps as VxeTableGridProps,
|
VxeGridProps as VxeTableGridProps,
|
||||||
VxeUIExport,
|
VxeUIExport,
|
||||||
} from 'vxe-table';
|
} from 'vxe-table';
|
||||||
|
@ -18,6 +19,16 @@ export interface VxePaginationInfo {
|
||||||
total: number;
|
total: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ToolbarConfigOptions extends VxeGridPropTypes.ToolbarConfig {
|
||||||
|
/** 是否显示切换搜索表单的按钮 */
|
||||||
|
search?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VxeTableGridOptions<T = any> extends VxeTableGridProps<T> {
|
||||||
|
/** 工具栏配置 */
|
||||||
|
toolbarConfig?: ToolbarConfigOptions;
|
||||||
|
}
|
||||||
|
|
||||||
export interface VxeGridProps {
|
export interface VxeGridProps {
|
||||||
/**
|
/**
|
||||||
* 标题
|
* 标题
|
||||||
|
@ -38,7 +49,7 @@ export interface VxeGridProps {
|
||||||
/**
|
/**
|
||||||
* vxe-grid 配置
|
* vxe-grid 配置
|
||||||
*/
|
*/
|
||||||
gridOptions?: DeepPartial<VxeTableGridProps>;
|
gridOptions?: DeepPartial<VxeTableGridOptions>;
|
||||||
/**
|
/**
|
||||||
* vxe-grid 事件
|
* vxe-grid 事件
|
||||||
*/
|
*/
|
||||||
|
@ -47,6 +58,10 @@ export interface VxeGridProps {
|
||||||
* 表单配置
|
* 表单配置
|
||||||
*/
|
*/
|
||||||
formOptions?: VbenFormProps;
|
formOptions?: VbenFormProps;
|
||||||
|
/**
|
||||||
|
* 显示搜索表单
|
||||||
|
*/
|
||||||
|
showSearchForm?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExtendedVxeGridApi = {
|
export type ExtendedVxeGridApi = {
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { VbenFormProps } from '@vben-core/form-ui';
|
import type { VbenFormProps } from '@vben-core/form-ui';
|
||||||
import type {
|
import type {
|
||||||
|
VxeGridDefines,
|
||||||
VxeGridInstance,
|
VxeGridInstance,
|
||||||
|
VxeGridListeners,
|
||||||
|
VxeGridPropTypes,
|
||||||
VxeGridProps as VxeTableGridProps,
|
VxeGridProps as VxeTableGridProps,
|
||||||
} from 'vxe-table';
|
} from 'vxe-table';
|
||||||
|
|
||||||
|
@ -57,6 +60,7 @@ const {
|
||||||
formOptions,
|
formOptions,
|
||||||
tableTitle,
|
tableTitle,
|
||||||
tableTitleHelp,
|
tableTitleHelp,
|
||||||
|
showSearchForm,
|
||||||
} = usePriorityValues(props, state);
|
} = usePriorityValues(props, state);
|
||||||
|
|
||||||
const { isMobile } = usePreferences();
|
const { isMobile } = usePreferences();
|
||||||
|
@ -103,21 +107,37 @@ const toolbarOptions = computed(() => {
|
||||||
const slotActions = slots[TOOLBAR_ACTIONS]?.();
|
const slotActions = slots[TOOLBAR_ACTIONS]?.();
|
||||||
const slotTools = slots[TOOLBAR_TOOLS]?.();
|
const slotTools = slots[TOOLBAR_TOOLS]?.();
|
||||||
|
|
||||||
|
const toolbarConfig: VxeGridPropTypes.ToolbarConfig = {
|
||||||
|
tools:
|
||||||
|
gridOptions.value?.toolbarConfig?.search && !!formOptions.value
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
code: 'search',
|
||||||
|
icon: 'vxe-icon--search',
|
||||||
|
circle: true,
|
||||||
|
status: showSearchForm.value ? 'primary' : undefined,
|
||||||
|
title: $t('common.search'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
};
|
||||||
|
|
||||||
if (!showToolbar.value) {
|
if (!showToolbar.value) {
|
||||||
return {};
|
return { toolbarConfig };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (gridOptions.value?.toolbarConfig?.search) {
|
||||||
|
// }
|
||||||
// 强制使用固定的toolbar配置,不允许用户自定义
|
// 强制使用固定的toolbar配置,不允许用户自定义
|
||||||
// 减少配置的复杂度,以及后续维护的成本
|
// 减少配置的复杂度,以及后续维护的成本
|
||||||
return {
|
toolbarConfig.slots = {
|
||||||
toolbarConfig: {
|
...(slotActions || showTableTitle.value
|
||||||
slots: {
|
? { buttons: TOOLBAR_ACTIONS }
|
||||||
...(slotActions || showTableTitle.value
|
: {}),
|
||||||
? { buttons: TOOLBAR_ACTIONS }
|
...(slotTools ? { tools: TOOLBAR_TOOLS } : {}),
|
||||||
: {}),
|
|
||||||
...(slotTools ? { tools: TOOLBAR_TOOLS } : {}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return { toolbarConfig };
|
||||||
});
|
});
|
||||||
|
|
||||||
const options = computed(() => {
|
const options = computed(() => {
|
||||||
|
@ -173,9 +193,19 @@ const options = computed(() => {
|
||||||
return mergedOptions;
|
return mergedOptions;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function onToolbarToolClick(event: VxeGridDefines.ToolbarToolClickEventParams) {
|
||||||
|
if (event.code === 'search') {
|
||||||
|
props.api?.toggleSearchForm?.();
|
||||||
|
}
|
||||||
|
(
|
||||||
|
gridEvents.value?.toolbarToolClick as VxeGridListeners['toolbarToolClick']
|
||||||
|
)?.(event);
|
||||||
|
}
|
||||||
|
|
||||||
const events = computed(() => {
|
const events = computed(() => {
|
||||||
return {
|
return {
|
||||||
...gridEvents.value,
|
...gridEvents.value,
|
||||||
|
toolbarToolClick: onToolbarToolClick,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -213,7 +243,8 @@ async function init() {
|
||||||
const autoLoad = defaultGridOptions.proxyConfig?.autoLoad;
|
const autoLoad = defaultGridOptions.proxyConfig?.autoLoad;
|
||||||
const enableProxyConfig = options.value.proxyConfig?.enabled;
|
const enableProxyConfig = options.value.proxyConfig?.enabled;
|
||||||
if (enableProxyConfig && autoLoad) {
|
if (enableProxyConfig && autoLoad) {
|
||||||
props.api.reload(formApi.form?.values ?? {});
|
props.api.grid.commitProxy?.('_init', formApi.form?.values ?? {});
|
||||||
|
// props.api.reload(formApi.form?.values ?? {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// form 由 vben-form代替,所以不适配formConfig,这里给出警告
|
// form 由 vben-form代替,所以不适配formConfig,这里给出警告
|
||||||
|
@ -304,7 +335,11 @@ onUnmounted(() => {
|
||||||
|
|
||||||
<!-- form表单 -->
|
<!-- form表单 -->
|
||||||
<template #form>
|
<template #form>
|
||||||
<div v-if="formOptions" class="relative rounded py-3 pb-4">
|
<div
|
||||||
|
v-if="formOptions"
|
||||||
|
v-show="showSearchForm !== false"
|
||||||
|
class="relative rounded py-3 pb-4"
|
||||||
|
>
|
||||||
<slot name="form">
|
<slot name="form">
|
||||||
<Form>
|
<Form>
|
||||||
<template
|
<template
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/request",
|
"name": "@vben/request",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/icons",
|
"name": "@vben/icons",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/locales",
|
"name": "@vben/locales",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
"qrcodeLogin": "QR Code Login",
|
"qrcodeLogin": "QR Code Login",
|
||||||
"codeSubtitle": "Enter your phone number to start managing your project",
|
"codeSubtitle": "Enter your phone number to start managing your project",
|
||||||
"code": "Security code",
|
"code": "Security code",
|
||||||
"codeTip": "Security code is required",
|
"codeTip": "Security code required {0} characters",
|
||||||
"mobile": "Mobile",
|
"mobile": "Mobile",
|
||||||
"mobileLogin": "Mobile Login",
|
"mobileLogin": "Mobile Login",
|
||||||
"mobileTip": "Please enter mobile number",
|
"mobileTip": "Please enter mobile number",
|
||||||
|
|
|
@ -9,5 +9,6 @@
|
||||||
"noData": "No Data",
|
"noData": "No Data",
|
||||||
"refresh": "Refresh",
|
"refresh": "Refresh",
|
||||||
"loadingMenu": "Loading Menu",
|
"loadingMenu": "Loading Menu",
|
||||||
"query": "Search"
|
"query": "Search",
|
||||||
|
"search": "Search"
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,11 @@
|
||||||
"width": "Width",
|
"width": "Width",
|
||||||
"visible": "Show Sidebar",
|
"visible": "Show Sidebar",
|
||||||
"collapsed": "Collpase Menu",
|
"collapsed": "Collpase Menu",
|
||||||
"collapsedShowTitle": "Show Menu Title"
|
"collapsedShowTitle": "Show Menu Title",
|
||||||
|
"autoActivateChild": "Auto Activate SubMenu",
|
||||||
|
"autoActivateChildTip": "`Enabled` to automatically activate the submenu while click menu.",
|
||||||
|
"expandOnHover": "Expand On Hover",
|
||||||
|
"expandOnHoverTip": "When the mouse hovers over menu, \n `Enabled` to expand children menus \n `Disabled` to expand whole sidebar."
|
||||||
},
|
},
|
||||||
"tabbar": {
|
"tabbar": {
|
||||||
"title": "Tabbar",
|
"title": "Tabbar",
|
||||||
|
@ -55,6 +59,8 @@
|
||||||
"showMaximize": "Show Maximize Button",
|
"showMaximize": "Show Maximize Button",
|
||||||
"persist": "Persist Tabs",
|
"persist": "Persist Tabs",
|
||||||
"draggable": "Enable Draggable Sort",
|
"draggable": "Enable Draggable Sort",
|
||||||
|
"wheelable": "Support Mouse Wheel",
|
||||||
|
"wheelableTip": "When enabled, the Tabbar area responds to vertical scrolling events of the scroll wheel.",
|
||||||
"styleType": {
|
"styleType": {
|
||||||
"title": "Tabs Style",
|
"title": "Tabs Style",
|
||||||
"chrome": "Chrome",
|
"chrome": "Chrome",
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
"qrcodeLogin": "扫码登录",
|
"qrcodeLogin": "扫码登录",
|
||||||
"codeSubtitle": "请输入您的手机号码以开始管理您的项目",
|
"codeSubtitle": "请输入您的手机号码以开始管理您的项目",
|
||||||
"code": "验证码",
|
"code": "验证码",
|
||||||
"codeTip": "请输入验证码",
|
"codeTip": "请输入{0}位验证码",
|
||||||
"mobile": "手机号码",
|
"mobile": "手机号码",
|
||||||
"mobileTip": "请输入手机号",
|
"mobileTip": "请输入手机号",
|
||||||
"mobileErrortip": "手机号码格式错误",
|
"mobileErrortip": "手机号码格式错误",
|
||||||
|
|
|
@ -9,5 +9,6 @@
|
||||||
"noData": "暂无数据",
|
"noData": "暂无数据",
|
||||||
"refresh": "刷新",
|
"refresh": "刷新",
|
||||||
"loadingMenu": "加载菜单中",
|
"loadingMenu": "加载菜单中",
|
||||||
"query": "查询"
|
"query": "查询",
|
||||||
|
"search": "搜索"
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,11 @@
|
||||||
"width": "宽度",
|
"width": "宽度",
|
||||||
"visible": "显示侧边栏",
|
"visible": "显示侧边栏",
|
||||||
"collapsed": "折叠菜单",
|
"collapsed": "折叠菜单",
|
||||||
"collapsedShowTitle": "折叠显示菜单名"
|
"collapsedShowTitle": "折叠显示菜单名",
|
||||||
|
"autoActivateChild": "自动激活子菜单",
|
||||||
|
"autoActivateChildTip": "点击顶层菜单时,自动激活第一个子菜单或者上一次激活的子菜单",
|
||||||
|
"expandOnHover": "鼠标悬停展开",
|
||||||
|
"expandOnHoverTip": "鼠标在折叠区域悬浮时,`启用`则展开当前子菜单,`禁用`则展开整个侧边栏"
|
||||||
},
|
},
|
||||||
"tabbar": {
|
"tabbar": {
|
||||||
"title": "标签栏",
|
"title": "标签栏",
|
||||||
|
@ -55,6 +59,8 @@
|
||||||
"showMaximize": "显示最大化按钮",
|
"showMaximize": "显示最大化按钮",
|
||||||
"persist": "持久化标签页",
|
"persist": "持久化标签页",
|
||||||
"draggable": "启动拖拽排序",
|
"draggable": "启动拖拽排序",
|
||||||
|
"wheelable": "启用纵向滚轮响应",
|
||||||
|
"wheelableTip": "开启后,标签栏区域可以响应滚轮的纵向滚动事件。\n关闭时,只能响应系统的横向滚动事件(需要按下Shift再滚动滚轮)",
|
||||||
"styleType": {
|
"styleType": {
|
||||||
"title": "标签页风格",
|
"title": "标签页风格",
|
||||||
"chrome": "谷歌",
|
"chrome": "谷歌",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/preferences",
|
"name": "@vben/preferences",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/stores",
|
"name": "@vben/stores",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/styles",
|
"name": "@vben/styles",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,3 +1,40 @@
|
||||||
.el-card {
|
.el-card {
|
||||||
--el-card-border-radius: var(--radius) !important;
|
--el-card-border-radius: var(--radius) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-valid-error {
|
||||||
|
/** select 选择器的样式 */
|
||||||
|
.el-select .el-select__wrapper {
|
||||||
|
box-shadow: 0 0 0 1px var(--el-color-danger) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** input 选择器的样式 */
|
||||||
|
.el-input .el-input__wrapper {
|
||||||
|
box-shadow: 0 0 0 1px var(--el-color-danger) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** radio和checkbox 选择器的样式 */
|
||||||
|
.el-radio .el-radio__inner,
|
||||||
|
.el-checkbox .el-checkbox__inner {
|
||||||
|
border: 1px solid var(--el-color-danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-checkbox-button .el-checkbox-button__inner,
|
||||||
|
.el-radio-button .el-radio-button__inner {
|
||||||
|
border: 1px solid var(--el-color-danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-checkbox-button:first-child .el-checkbox-button__inner,
|
||||||
|
.el-radio-button:first-child .el-radio-button__inner {
|
||||||
|
border-left: 1px solid var(--el-color-danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-checkbox-button:not(:first-child) .el-checkbox-button__inner,
|
||||||
|
.el-radio-button:not(:first-child) .el-radio-button__inner {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea .el-textarea__inner {
|
||||||
|
border: 1px solid var(--el-color-danger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/types",
|
"name": "@vben/types",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/utils",
|
"name": "@vben/utils",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/playground",
|
"name": "@vben/playground",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"homepage": "https://vben.pro",
|
"homepage": "https://vben.pro",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -132,6 +132,7 @@ watch(
|
||||||
:text="userStore.userInfo?.realName"
|
:text="userStore.userInfo?.realName"
|
||||||
description="ann.vben@gmail.com"
|
description="ann.vben@gmail.com"
|
||||||
tag-text="Pro"
|
tag-text="Pro"
|
||||||
|
trigger="both"
|
||||||
@logout="handleLogout"
|
@logout="handleLogout"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { $t } from '@vben/locales';
|
||||||
defineOptions({ name: 'CodeLogin' });
|
defineOptions({ name: 'CodeLogin' });
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const CODE_LENGTH = 6;
|
||||||
|
|
||||||
const formSchema = computed((): VbenFormSchema[] => {
|
const formSchema = computed((): VbenFormSchema[] => {
|
||||||
return [
|
return [
|
||||||
|
@ -30,6 +31,7 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||||
{
|
{
|
||||||
component: 'VbenPinInput',
|
component: 'VbenPinInput',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
|
codeLength: CODE_LENGTH,
|
||||||
createText: (countdown: number) => {
|
createText: (countdown: number) => {
|
||||||
const text =
|
const text =
|
||||||
countdown > 0
|
countdown > 0
|
||||||
|
@ -41,7 +43,9 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||||
},
|
},
|
||||||
fieldName: 'code',
|
fieldName: 'code',
|
||||||
label: $t('authentication.code'),
|
label: $t('authentication.code'),
|
||||||
rules: z.string().min(1, { message: $t('authentication.codeTip') }),
|
rules: z.string().length(CODE_LENGTH, {
|
||||||
|
message: $t('authentication.codeTip', [CODE_LENGTH]),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
|
@ -82,6 +82,7 @@ const gridOptions: VxeGridProps<RowType> = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
showOverflow: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const [Grid] = useVbenVxeGrid({ gridOptions });
|
const [Grid] = useVbenVxeGrid({ gridOptions });
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { VbenFormProps } from '#/adapter/form';
|
import type { VbenFormProps } from '#/adapter/form';
|
||||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
|
|
||||||
import { Page } from '@vben/common-ui';
|
import { Page } from '@vben/common-ui';
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ const formOptions: VbenFormProps = {
|
||||||
submitOnEnter: false,
|
submitOnEnter: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const gridOptions: VxeGridProps<RowType> = {
|
const gridOptions: VxeTableGridOptions<RowType> = {
|
||||||
checkboxConfig: {
|
checkboxConfig: {
|
||||||
highlight: true,
|
highlight: true,
|
||||||
labelField: 'name',
|
labelField: 'name',
|
||||||
|
@ -85,6 +85,7 @@ const gridOptions: VxeGridProps<RowType> = {
|
||||||
{ field: 'price', title: 'Price' },
|
{ field: 'price', title: 'Price' },
|
||||||
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
|
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
|
||||||
],
|
],
|
||||||
|
exportConfig: {},
|
||||||
height: 'auto',
|
height: 'auto',
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
pagerConfig: {},
|
pagerConfig: {},
|
||||||
|
@ -100,9 +101,20 @@ const gridOptions: VxeGridProps<RowType> = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
toolbarConfig: {
|
||||||
|
custom: true,
|
||||||
|
export: true,
|
||||||
|
refresh: true,
|
||||||
|
resizable: true,
|
||||||
|
search: true,
|
||||||
|
zoom: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const [Grid] = useVbenVxeGrid({ formOptions, gridOptions });
|
const [Grid] = useVbenVxeGrid({
|
||||||
|
formOptions,
|
||||||
|
gridOptions,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -25,10 +25,10 @@ const gridOptions: VxeGridProps<RowType> = {
|
||||||
columns: [
|
columns: [
|
||||||
{ title: '序号', type: 'seq', width: 50 },
|
{ title: '序号', type: 'seq', width: 50 },
|
||||||
{ align: 'left', title: 'Name', type: 'checkbox', width: 100 },
|
{ align: 'left', title: 'Name', type: 'checkbox', width: 100 },
|
||||||
{ field: 'category', title: 'Category' },
|
{ field: 'category', sortable: true, title: 'Category' },
|
||||||
{ field: 'color', title: 'Color' },
|
{ field: 'color', sortable: true, title: 'Color' },
|
||||||
{ field: 'productName', title: 'Product Name' },
|
{ field: 'productName', sortable: true, title: 'Product Name' },
|
||||||
{ field: 'price', title: 'Price' },
|
{ field: 'price', sortable: true, title: 'Price' },
|
||||||
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },
|
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },
|
||||||
],
|
],
|
||||||
exportConfig: {},
|
exportConfig: {},
|
||||||
|
@ -36,19 +36,26 @@ const gridOptions: VxeGridProps<RowType> = {
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }) => {
|
query: async ({ page, sort }) => {
|
||||||
return await getExampleTableApi({
|
return await getExampleTableApi({
|
||||||
page: page.currentPage,
|
page: page.currentPage,
|
||||||
pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
|
sortBy: sort.field,
|
||||||
|
sortOrder: sort.order,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
sort: true,
|
||||||
|
},
|
||||||
|
sortConfig: {
|
||||||
|
defaultSort: { field: 'category', order: 'desc' },
|
||||||
|
remote: true,
|
||||||
},
|
},
|
||||||
toolbarConfig: {
|
toolbarConfig: {
|
||||||
custom: true,
|
custom: true,
|
||||||
export: true,
|
export: true,
|
||||||
// import: true,
|
// import: true,
|
||||||
refresh: true,
|
refresh: { code: 'query' },
|
||||||
zoom: true,
|
zoom: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1578,6 +1578,9 @@ importers:
|
||||||
'@vben/utils':
|
'@vben/utils':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../utils
|
version: link:../../utils
|
||||||
|
'@vueuse/core':
|
||||||
|
specifier: 'catalog:'
|
||||||
|
version: 12.0.0(typescript@5.7.2)
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.13
|
specifier: ^3.5.13
|
||||||
version: 3.5.13(typescript@5.7.2)
|
version: 3.5.13(typescript@5.7.2)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/turbo-run",
|
"name": "@vben/turbo-run",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vben/vsh",
|
"name": "@vben/vsh",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
Loading…
Reference in New Issue