This commit is contained in:
dap 2024-10-11 08:43:19 +08:00
commit f707fcb3da
46 changed files with 176 additions and 107 deletions

View File

@ -95,9 +95,13 @@ function createRequestClient(baseURL: string) {
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里 // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
client.addResponseInterceptor( client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, _error) => { errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
ElMessage.error(msg); // 当前mock接口返回的错误字段是 error 或者 message
const responseData = error?.response?.data ?? {};
const errorMessage = responseData?.error ?? responseData?.message ?? '';
// 如果没有错误信息,则会根据状态码进行提示
ElMessage.error(errorMessage || msg);
}), }),
); );

View File

@ -94,9 +94,13 @@ function createRequestClient(baseURL: string) {
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里 // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
client.addResponseInterceptor( client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, _error) => { errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
message.error(msg); // 当前mock接口返回的错误字段是 error 或者 message
const responseData = error?.response?.data ?? {};
const errorMessage = responseData?.error ?? responseData?.message ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}), }),
); );

View File

@ -255,9 +255,13 @@ function createRequestClient(baseURL: string) {
// Generic error handling; if none of the above error handling logic is triggered, it will fall back to this. // Generic error handling; if none of the above error handling logic is triggered, it will fall back to this.
client.addResponseInterceptor( client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, _error) => { errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
message.error(msg); // 当前mock接口返回的错误字段是 error 或者 message
const responseData = error?.response?.data ?? {};
const errorMessage = responseData?.error ?? responseData?.message ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}), }),
); );

View File

@ -226,7 +226,7 @@ const defaultPreferences: Preferences = {
width: 230, width: 230,
}, },
tabbar: { tabbar: {
dragable: true, draggable: true,
enable: true, enable: true,
height: 36, height: 36,
keepAlive: true, keepAlive: true,
@ -406,7 +406,7 @@ interface ShortcutKeyPreferences {
interface TabbarPreferences { interface TabbarPreferences {
/** Whether dragging of multiple tabs is enabled */ /** Whether dragging of multiple tabs is enabled */
dragable: boolean; draggable: boolean;
/** Whether multiple tabs are enabled */ /** Whether multiple tabs are enabled */
enable: boolean; enable: boolean;
/** Tab height */ /** Tab height */

View File

@ -258,9 +258,13 @@ function createRequestClient(baseURL: string) {
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里 // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
client.addResponseInterceptor( client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, _error) => { errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
message.error(msg); // 当前mock接口返回的错误字段是 error 或者 message
const responseData = error?.response?.data ?? {};
const errorMessage = responseData?.error ?? responseData?.message ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}), }),
); );

View File

@ -248,7 +248,7 @@ const defaultPreferences: Preferences = {
width: 230, width: 230,
}, },
tabbar: { tabbar: {
dragable: true, draggable: true,
enable: true, enable: true,
height: 36, height: 36,
keepAlive: true, keepAlive: true,
@ -430,7 +430,7 @@ interface ShortcutKeyPreferences {
interface TabbarPreferences { interface TabbarPreferences {
/** 是否开启多标签页拖拽 */ /** 是否开启多标签页拖拽 */
dragable: boolean; draggable: boolean;
/** 是否开启多标签页 */ /** 是否开启多标签页 */
enable: boolean; enable: boolean;
/** 标签页高度 */ /** 标签页高度 */

View File

@ -12,7 +12,7 @@ outline: deep
```bash ```bash
apps/web-ele apps/web-ele
apps/web-native apps/web-naive
``` ```

View File

@ -1,6 +1,5 @@
import type { Config } from 'tailwindcss'; import type { Config } from 'tailwindcss';
import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import { getPackagesSync } from '@vben/node-utils'; import { getPackagesSync } from '@vben/node-utils';
@ -19,9 +18,9 @@ const tailwindPackages: string[] = [];
packages.forEach((pkg) => { packages.forEach((pkg) => {
// apps目录下和 @vben-core/tailwind-ui 包需要使用到 tailwindcss ui // apps目录下和 @vben-core/tailwind-ui 包需要使用到 tailwindcss ui
if (fs.existsSync(path.join(pkg.dir, 'tailwind.config.mjs'))) { // if (fs.existsSync(path.join(pkg.dir, 'tailwind.config.mjs'))) {
tailwindPackages.push(pkg.dir); tailwindPackages.push(pkg.dir);
} // }
}); });
const shadcnUiColors = { const shadcnUiColors = {

View File

@ -40,6 +40,7 @@
"vite-plugin-vue-devtools": "catalog:" "vite-plugin-vue-devtools": "catalog:"
}, },
"devDependencies": { "devDependencies": {
"@pnpm/workspace.read-manifest": "catalog:",
"@types/archiver": "catalog:", "@types/archiver": "catalog:",
"@types/html-minifier-terser": "catalog:", "@types/html-minifier-terser": "catalog:",
"@vben/node-utils": "workspace:*", "@vben/node-utils": "workspace:*",

View File

@ -1,20 +1,35 @@
import type { PluginOption } from 'vite'; import type { PluginOption } from 'vite';
import { dateUtil, getPackages, readPackageJSON } from '@vben/node-utils'; import {
dateUtil,
findMonorepoRoot,
getPackages,
readPackageJSON,
} from '@vben/node-utils';
import { readWorkspaceManifest } from '@pnpm/workspace.read-manifest';
function resolvePackageVersion( function resolvePackageVersion(
pkgsMeta: Record<string, string>, pkgsMeta: Record<string, string>,
name: string, name: string,
value: string, value: string,
catalog: Record<string, string>,
) { ) {
if (value.includes('catalog:')) {
return catalog[name];
}
if (value.includes('workspace')) { if (value.includes('workspace')) {
return pkgsMeta[name]; return pkgsMeta[name];
} }
return value; return value;
} }
async function resolveMonorepoDependencies() { async function resolveMonorepoDependencies() {
const { packages } = await getPackages(); const { packages } = await getPackages();
const manifest = await readWorkspaceManifest(findMonorepoRoot());
const catalog = manifest?.catalog || {};
const resultDevDependencies: Record<string, string | undefined> = {}; const resultDevDependencies: Record<string, string | undefined> = {};
const resultDependencies: Record<string, string | undefined> = {}; const resultDependencies: Record<string, string | undefined> = {};
@ -27,10 +42,20 @@ async function resolveMonorepoDependencies() {
for (const { packageJson } of packages) { for (const { packageJson } of packages) {
const { dependencies = {}, devDependencies = {} } = packageJson; const { dependencies = {}, devDependencies = {} } = packageJson;
for (const [key, value] of Object.entries(dependencies)) { for (const [key, value] of Object.entries(dependencies)) {
resultDependencies[key] = resolvePackageVersion(pkgsMeta, key, value); resultDependencies[key] = resolvePackageVersion(
pkgsMeta,
key,
value,
catalog,
);
} }
for (const [key, value] of Object.entries(devDependencies)) { for (const [key, value] of Object.entries(devDependencies)) {
resultDevDependencies[key] = resolvePackageVersion(pkgsMeta, key, value); resultDevDependencies[key] = resolvePackageVersion(
pkgsMeta,
key,
value,
catalog,
);
} }
} }
return { return {

View File

@ -37,6 +37,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
"enable": true, "enable": true,
"icp": "", "icp": "",
"icpLink": "", "icpLink": "",
"settingShow": true,
}, },
"footer": { "footer": {
"enable": false, "enable": false,
@ -73,7 +74,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
"width": 224, "width": 224,
}, },
"tabbar": { "tabbar": {
"dragable": true, "draggable": true,
"enable": true, "enable": true,
"height": 38, "height": 38,
"keepAlive": true, "keepAlive": true,

View File

@ -37,6 +37,7 @@ const defaultPreferences: Preferences = {
enable: true, enable: true,
icp: '', icp: '',
icpLink: '', icpLink: '',
settingShow: true,
}, },
footer: { footer: {
enable: false, enable: false,
@ -73,7 +74,7 @@ const defaultPreferences: Preferences = {
width: 224, width: 224,
}, },
tabbar: { tabbar: {
dragable: true, draggable: true,
enable: true, enable: true,
height: 38, height: 38,
keepAlive: true, keepAlive: true,

View File

@ -88,6 +88,8 @@ interface CopyrightPreferences {
icp: string; icp: string;
/** 备案号链接 */ /** 备案号链接 */
icpLink: string; icpLink: string;
/** 设置面板是否显示*/
settingShow?: boolean;
} }
interface FooterPreferences { interface FooterPreferences {
@ -154,7 +156,7 @@ interface ShortcutKeyPreferences {
interface TabbarPreferences { interface TabbarPreferences {
/** 是否开启多标签页拖拽 */ /** 是否开启多标签页拖拽 */
dragable: boolean; draggable: boolean;
/** 是否开启多标签页 */ /** 是否开启多标签页 */
enable: boolean; enable: boolean;
/** 标签页高度 */ /** 标签页高度 */

View File

@ -69,7 +69,7 @@ const tabsView = computed((): TabConfig[] => {
v-for="(tab, i) in tabsView" v-for="(tab, i) in tabsView"
:key="tab.key" :key="tab.key"
ref="tabRef" ref="tabRef"
:class="[{ 'is-active': tab.key === active, dragable: !tab.affixTab }]" :class="[{ 'is-active': tab.key === active, draggable: !tab.affixTab }]"
:data-active-tab="active" :data-active-tab="active"
:data-index="i" :data-index="i"
class="tabs-chrome__item draggable translate-all group relative -mr-3 flex h-full select-none items-center" class="tabs-chrome__item draggable translate-all group relative -mr-3 flex h-full select-none items-center"

View File

@ -75,7 +75,7 @@ const tabsView = computed((): TabConfig[] => {
:class="[ :class="[
{ {
'is-active dark:bg-accent bg-primary/15': tab.key === active, 'is-active dark:bg-accent bg-primary/15': tab.key === active,
dragable: !tab.affixTab, draggable: !tab.affixTab,
}, },
typeWithClass.content, typeWithClass.content,
]" ]"

View File

@ -17,7 +17,7 @@ defineOptions({
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
contentClass: 'vben-tabs-content', contentClass: 'vben-tabs-content',
dragable: true, draggable: true,
styleType: 'chrome', styleType: 'chrome',
}); });

View File

@ -21,7 +21,7 @@ export interface TabsProps {
/** /**
* @zh_CN * @zh_CN
*/ */
dragable?: boolean; draggable?: boolean;
/** /**
* @zh_CN * @zh_CN
* @default 7 * @default 7

View File

@ -42,8 +42,8 @@ export function useTabsDrag(props: TabsProps, emit: EmitType) {
const { initializeSortable } = useSortable(el, { const { initializeSortable } = useSortable(el, {
filter: (_evt, target: HTMLElement) => { filter: (_evt, target: HTMLElement) => {
const parent = findParentElement(target); const parent = findParentElement(target);
const dragable = parent?.classList.contains('dragable'); const draggable = parent?.classList.contains('draggable');
return !dragable || !props.dragable; return !draggable || !props.draggable;
}, },
onEnd(evt) { onEnd(evt) {
const { newIndex, oldIndex } = evt; const { newIndex, oldIndex } = evt;
@ -62,7 +62,7 @@ export function useTabsDrag(props: TabsProps, emit: EmitType) {
return; return;
} }
if (!srcParent.classList.contains('dragable')) { if (!srcParent.classList.contains('draggable')) {
resetElState(); resetElState();
return; return;
@ -81,7 +81,7 @@ export function useTabsDrag(props: TabsProps, emit: EmitType) {
}, },
onMove(evt) { onMove(evt) {
const parent = findParentElement(evt.related); const parent = findParentElement(evt.related);
return parent?.classList.contains('dragable') && props.dragable; return parent?.classList.contains('draggable') && props.draggable;
}, },
onStart: () => { onStart: () => {
el.style.cursor = 'grabbing'; el.style.cursor = 'grabbing';

View File

@ -1 +0,0 @@
export { default } from '@vben/tailwind-config/postcss';

View File

@ -1 +0,0 @@
export { default } from '@vben/tailwind-config';

View File

@ -1 +0,0 @@
export { default } from '@vben/tailwind-config/postcss';

View File

@ -1 +0,0 @@
export { default } from '@vben/tailwind-config';

View File

@ -1 +0,0 @@
export { default } from '@vben/tailwind-config/postcss';

View File

@ -118,7 +118,7 @@ function clearPreferencesAndLogout() {
> >
<slot :name="slot.name"> <slot :name="slot.name">
<template v-if="slot.name === 'refresh'"> <template v-if="slot.name === 'refresh'">
<VbenIconButton class="my-0 rounded-md" @click="refresh"> <VbenIconButton class="my-0 mr-1 rounded-md" @click="refresh">
<RotateCw class="size-4" /> <RotateCw class="size-4" />
</VbenIconButton> </VbenIconButton>
</template> </template>

View File

@ -51,7 +51,7 @@ if (!preferences.tabbar.persist) {
:active="currentActive" :active="currentActive"
:class="theme" :class="theme"
:context-menus="createContextMenus" :context-menus="createContextMenus"
:dragable="preferences.tabbar.dragable" :draggable="preferences.tabbar.draggable"
:show-icon="showIcon" :show-icon="showIcon"
:style-type="preferences.tabbar.styleType" :style-type="preferences.tabbar.styleType"
:tabs="currentTabs" :tabs="currentTabs"

View File

@ -6,10 +6,6 @@ import { $t } from '@vben/locales';
import InputItem from '../input-item.vue'; import InputItem from '../input-item.vue';
import SwitchItem from '../switch-item.vue'; import SwitchItem from '../switch-item.vue';
defineOptions({
name: 'PreferenceBreadcrumbConfig',
});
const props = defineProps<{ disabled: boolean }>(); const props = defineProps<{ disabled: boolean }>();
const copyrightEnable = defineModel<boolean>('copyrightEnable'); const copyrightEnable = defineModel<boolean>('copyrightEnable');

View File

@ -3,10 +3,6 @@ import { $t } from '@vben/locales';
import SwitchItem from '../switch-item.vue'; import SwitchItem from '../switch-item.vue';
defineOptions({
name: 'PreferenceBreadcrumbConfig',
});
const footerEnable = defineModel<boolean>('footerEnable'); const footerEnable = defineModel<boolean>('footerEnable');
const footerFixed = defineModel<boolean>('footerFixed'); const footerFixed = defineModel<boolean>('footerFixed');
</script> </script>

View File

@ -6,10 +6,6 @@ import { $t } from '@vben/locales';
import SelectItem from '../select-item.vue'; import SelectItem from '../select-item.vue';
import SwitchItem from '../switch-item.vue'; import SwitchItem from '../switch-item.vue';
defineOptions({
name: 'PreferenceBreadcrumbConfig',
});
defineProps<{ disabled: boolean }>(); defineProps<{ disabled: boolean }>();
const headerEnable = defineModel<boolean>('headerEnable'); const headerEnable = defineModel<boolean>('headerEnable');

View File

@ -4,10 +4,6 @@ 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';
defineOptions({
name: 'PreferenceBreadcrumbConfig',
});
defineProps<{ disabled: boolean }>(); defineProps<{ disabled: boolean }>();
const sidebarEnable = defineModel<boolean>('sidebarEnable'); const sidebarEnable = defineModel<boolean>('sidebarEnable');

View File

@ -17,7 +17,7 @@ defineProps<{ disabled?: boolean }>();
const tabbarEnable = defineModel<boolean>('tabbarEnable'); 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 tabbarDragable = defineModel<boolean>('tabbarDragable'); const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
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');
@ -50,8 +50,8 @@ const styleItems = computed((): SelectOption[] => [
<SwitchItem v-model="tabbarPersist" :disabled="!tabbarEnable"> <SwitchItem v-model="tabbarPersist" :disabled="!tabbarEnable">
{{ $t('preferences.tabbar.persist') }} {{ $t('preferences.tabbar.persist') }}
</SwitchItem> </SwitchItem>
<SwitchItem v-model="tabbarDragable" :disabled="!tabbarEnable"> <SwitchItem v-model="tabbarDraggable" :disabled="!tabbarEnable">
{{ $t('preferences.tabbar.dragable') }} {{ $t('preferences.tabbar.draggable') }}
</SwitchItem> </SwitchItem>
<SwitchItem v-model="tabbarShowIcon" :disabled="!tabbarEnable"> <SwitchItem v-model="tabbarShowIcon" :disabled="!tabbarEnable">
{{ $t('preferences.tabbar.icon') }} {{ $t('preferences.tabbar.icon') }}

View File

@ -102,7 +102,7 @@ const tabbarShowIcon = defineModel<boolean>('tabbarShowIcon');
const tabbarShowMore = defineModel<boolean>('tabbarShowMore'); 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 tabbarDragable = defineModel<boolean>('tabbarDragable'); const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
const tabbarStyleType = defineModel<string>('tabbarStyleType'); const tabbarStyleType = defineModel<string>('tabbarStyleType');
const navigationStyleType = defineModel<NavigationStyleType>( const navigationStyleType = defineModel<NavigationStyleType>(
@ -116,6 +116,7 @@ const navigationAccordion = defineModel<boolean>('navigationAccordion');
const footerEnable = defineModel<boolean>('footerEnable'); const footerEnable = defineModel<boolean>('footerEnable');
const footerFixed = defineModel<boolean>('footerFixed'); const footerFixed = defineModel<boolean>('footerFixed');
const copyrightSettingShow = defineModel<boolean>('copyrightSettingShow');
const copyrightEnable = defineModel<boolean>('copyrightEnable'); const copyrightEnable = defineModel<boolean>('copyrightEnable');
const copyrightCompanyName = defineModel<string>('copyrightCompanyName'); const copyrightCompanyName = defineModel<string>('copyrightCompanyName');
const copyrightCompanySiteLink = defineModel<string>( const copyrightCompanySiteLink = defineModel<string>(
@ -339,7 +340,7 @@ async function handleReset() {
</Block> </Block>
<Block :title="$t('preferences.tabbar.title')"> <Block :title="$t('preferences.tabbar.title')">
<Tabbar <Tabbar
v-model:tabbar-dragable="tabbarDragable" v-model:tabbar-draggable="tabbarDraggable"
v-model:tabbar-enable="tabbarEnable" v-model:tabbar-enable="tabbarEnable"
v-model:tabbar-persist="tabbarPersist" v-model:tabbar-persist="tabbarPersist"
v-model:tabbar-show-icon="tabbarShowIcon" v-model:tabbar-show-icon="tabbarShowIcon"
@ -369,7 +370,10 @@ async function handleReset() {
v-model:footer-fixed="footerFixed" v-model:footer-fixed="footerFixed"
/> />
</Block> </Block>
<Block :title="$t('preferences.copyright.title')"> <Block
v-if="copyrightSettingShow"
:title="$t('preferences.copyright.title')"
>
<Copyright <Copyright
v-model:copyright-company-name="copyrightCompanyName" v-model:copyright-company-name="copyrightCompanyName"
v-model:copyright-company-site-link="copyrightCompanySiteLink" v-model:copyright-company-site-link="copyrightCompanySiteLink"

View File

@ -1 +0,0 @@
export { default } from '@vben/tailwind-config';

View File

@ -1 +0,0 @@
export { default } from '@vben/tailwind-config/postcss';

View File

@ -0,0 +1,50 @@
import type { VxeGridProps } from 'vxe-table';
import type { VxeGridApi } from './api';
import { isFunction } from '@vben/utils';
export function extendProxyOptions(
api: VxeGridApi,
options: VxeGridProps,
getFormValues: () => Record<string, any>,
) {
[
'query',
'querySuccess',
'queryError',
'queryAll',
'queryAllSuccess',
'queryAllError',
].forEach((key) => {
extendProxyOption(key, api, options, getFormValues);
});
}
function extendProxyOption(
key: string,
api: VxeGridApi,
options: VxeGridProps,
getFormValues: () => Record<string, any>,
) {
const { proxyConfig } = options;
const configFn = (proxyConfig?.ajax as any)?.[key];
if (!isFunction(configFn)) {
return options;
}
const wrapperFn = async (params: any, _formValues: any, ...args: any[]) => {
const formValues = getFormValues();
const data = await configFn(params, formValues, ...args);
return data;
};
api.setState({
gridOptions: {
proxyConfig: {
ajax: {
[key]: wrapperFn,
},
},
},
});
}

View File

@ -26,6 +26,7 @@ import { VbenLoading } from '@vben-core/shadcn-ui';
import { VxeGrid, VxeUI } from 'vxe-table'; import { VxeGrid, VxeUI } from 'vxe-table';
import { extendProxyOptions } from './extends';
import { useTableForm } from './init'; import { useTableForm } from './init';
import 'vxe-table/styles/cssvar.scss'; import 'vxe-table/styles/cssvar.scss';
@ -38,6 +39,8 @@ interface Props extends VxeGridProps {
const props = withDefaults(defineProps<Props>(), {}); const props = withDefaults(defineProps<Props>(), {});
const FORM_SLOT_PREFIX = 'form-';
const gridRef = useTemplateRef<VxeGridInstance>('gridRef'); const gridRef = useTemplateRef<VxeGridInstance>('gridRef');
const state = props.api?.useStore?.(); const state = props.api?.useStore?.();
@ -172,11 +175,11 @@ const delegatedFormSlots = computed(() => {
const resultSlots: string[] = []; const resultSlots: string[] = [];
for (const key of Object.keys(slots)) { for (const key of Object.keys(slots)) {
if (key.startsWith('form-')) { if (key.startsWith(FORM_SLOT_PREFIX)) {
resultSlots.push(key); resultSlots.push(key);
} }
} }
return resultSlots; return resultSlots.map((key) => key.replace(FORM_SLOT_PREFIX, ''));
}); });
async function init() { async function init() {
@ -191,7 +194,7 @@ 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.reload(formApi.form?.values ?? {});
} }
// form vben-formformConfig // form vben-formformConfig
@ -201,6 +204,9 @@ async function init() {
'[Vben Vxe Table]: The formConfig in the grid is not supported, please use the `formOptions` props', '[Vben Vxe Table]: The formConfig in the grid is not supported, please use the `formOptions` props',
); );
} }
// form vben-form query
extendProxyOptions(props.api, defaultGridOptions, () => formApi.form.values);
} }
watch( watch(

View File

@ -1 +0,0 @@
export { default } from '@vben/tailwind-config';

View File

@ -91,7 +91,7 @@ export const errorMessageResponseInterceptor = (
return Promise.reject(error); return Promise.reject(error);
} }
let errorMessage = error?.response?.data?.error?.message ?? ''; let errorMessage = '';
const status = error?.response?.status; const status = error?.response?.status;
switch (status) { switch (status) {

View File

@ -215,7 +215,7 @@
"showMore": "Show More Button", "showMore": "Show More Button",
"showMaximize": "Show Maximize Button", "showMaximize": "Show Maximize Button",
"persist": "Persist Tabs", "persist": "Persist Tabs",
"dragable": "Enable Dragable Sort", "draggable": "Enable Draggable Sort",
"styleType": { "styleType": {
"title": "Tabs Style", "title": "Tabs Style",
"chrome": "Chrome", "chrome": "Chrome",

View File

@ -215,7 +215,7 @@
"showMore": "显示更多按钮", "showMore": "显示更多按钮",
"showMaximize": "显示最大化按钮", "showMaximize": "显示最大化按钮",
"persist": "持久化标签页", "persist": "持久化标签页",
"dragable": "启动拖拽排序", "draggable": "启动拖拽排序",
"styleType": { "styleType": {
"title": "标签页风格", "title": "标签页风格",
"chrome": "谷歌", "chrome": "谷歌",

View File

@ -96,9 +96,13 @@ function createRequestClient(baseURL: string) {
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里 // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
client.addResponseInterceptor( client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, _error) => { errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
message.error(msg); // 当前mock接口返回的错误字段是 error 或者 message
const responseData = error?.response?.data ?? {};
const errorMessage = responseData?.error ?? responseData?.message ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}), }),
); );

View File

@ -29,6 +29,9 @@ const gridOptions: VxeGridProps<RowType> = {
{ field: 'address', showOverflow: true, title: 'Address' }, { field: 'address', showOverflow: true, title: 'Address' },
], ],
data: MOCK_TABLE_DATA, data: MOCK_TABLE_DATA,
pagerConfig: {
enabled: false,
},
sortConfig: { sortConfig: {
multiple: true, multiple: true,
}, },

View File

@ -30,12 +30,6 @@ const gridOptions: VxeGridProps<RowType> = {
title: 'DateTime', title: 'DateTime',
width: 500, width: 500,
}, },
{
field: 'releaseDate',
formatter: 'formatDate',
title: 'Date',
width: 300,
},
{ {
field: 'action', field: 'action',
fixed: 'right', fixed: 'right',

View File

@ -3,7 +3,7 @@ import type { VbenFormProps, VxeGridProps } from '#/adapter';
import { Page } from '@vben/common-ui'; import { Page } from '@vben/common-ui';
import { Button, message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter'; import { useVbenVxeGrid } from '#/adapter';
import { getExampleTableApi } from '#/api'; import { getExampleTableApi } from '#/api';
@ -60,6 +60,8 @@ const formOptions: VbenFormProps = {
label: 'Date', label: 'Date',
}, },
], ],
//
showCollapseButton: true,
}; };
const gridOptions: VxeGridProps<RowType> = { const gridOptions: VxeGridProps<RowType> = {
@ -93,26 +95,11 @@ const gridOptions: VxeGridProps<RowType> = {
}, },
}; };
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions }); const [Grid] = useVbenVxeGrid({ formOptions, gridOptions });
function toggleFormCollspae() {
gridApi.formApi.setState((prev) => {
return {
...prev,
showCollapseButton: !prev.showCollapseButton,
};
});
}
</script> </script>
<template> <template>
<Page auto-content-height> <Page auto-content-height>
<Grid> <Grid />
<template #toolbar-tools>
<Button type="primary" @click="toggleFormCollspae">
切换表单折叠按钮
</Button>
</template>
</Grid>
</Page> </Page>
</template> </template>

View File

@ -30,7 +30,6 @@ const gridOptions: VxeGridProps<RowType> = {
{ field: 'productName', title: 'Product Name' }, { field: 'productName', title: 'Product Name' },
{ field: 'price', title: 'Price' }, { field: 'price', title: 'Price' },
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' }, { field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },
{ field: 'releaseDate', formatter: 'formatDate', title: 'Date' },
], ],
height: 'auto', height: 'auto',
keepSource: true, keepSource: true,

View File

@ -22,19 +22,20 @@ catalog:
'@ctrl/tinycolor': ^4.1.0 '@ctrl/tinycolor': ^4.1.0
'@eslint/js': ^9.12.0 '@eslint/js': ^9.12.0
'@faker-js/faker': ^9.0.3 '@faker-js/faker': ^9.0.3
'@iconify/json': ^2.2.257 '@iconify/json': ^2.2.258
'@iconify/tailwind': ^1.1.3 '@iconify/tailwind': ^1.1.3
'@iconify/vue': ^4.1.2 '@iconify/vue': ^4.1.2
'@intlify/core-base': ^10.0.4 '@intlify/core-base': ^10.0.4
'@intlify/unplugin-vue-i18n': ^5.2.0 '@intlify/unplugin-vue-i18n': ^5.2.0
'@jspm/generator': ^2.3.1 '@jspm/generator': ^2.3.1
'@manypkg/get-packages': ^2.2.2 '@manypkg/get-packages': ^2.2.2
'@nolebase/vitepress-plugin-git-changelog': ^2.5.0 '@nolebase/vitepress-plugin-git-changelog': ^2.6.0
'@playwright/test': ^1.48.0 '@playwright/test': ^1.48.0
'@pnpm/workspace.read-manifest': ^2.2.1
'@stylistic/stylelint-plugin': ^3.1.1 '@stylistic/stylelint-plugin': ^3.1.1
'@tailwindcss/nesting': 0.0.0-insiders.565cd3e '@tailwindcss/nesting': 0.0.0-insiders.565cd3e
'@tailwindcss/typography': ^0.5.15 '@tailwindcss/typography': ^0.5.15
'@tanstack/vue-query': ^5.59.1 '@tanstack/vue-query': ^5.59.6
'@tanstack/vue-store': ^0.5.5 '@tanstack/vue-store': ^0.5.5
'@types/archiver': ^6.0.2 '@types/archiver': ^6.0.2
'@types/chalk': ^2.2.0 '@types/chalk': ^2.2.0
@ -62,7 +63,7 @@ catalog:
archiver: ^7.0.1 archiver: ^7.0.1
autoprefixer: ^10.4.20 autoprefixer: ^10.4.20
axios: ^1.7.7 axios: ^1.7.7
axios-mock-adapter: ^2.0.0 axios-mock-adapter: ^2.1.0
cac: ^6.7.14 cac: ^6.7.14
chalk: ^5.3.0 chalk: ^5.3.0
cheerio: 1.0.0 cheerio: 1.0.0
@ -89,7 +90,7 @@ catalog:
eslint-plugin-import-x: ^4.3.1 eslint-plugin-import-x: ^4.3.1
eslint-plugin-jsdoc: ^50.3.1 eslint-plugin-jsdoc: ^50.3.1
eslint-plugin-jsonc: ^2.16.0 eslint-plugin-jsonc: ^2.16.0
eslint-plugin-n: ^17.10.3 eslint-plugin-n: ^17.11.1
eslint-plugin-no-only-tests: ^3.3.0 eslint-plugin-no-only-tests: ^3.3.0
eslint-plugin-perfectionist: ^3.8.0 eslint-plugin-perfectionist: ^3.8.0
eslint-plugin-prettier: ^5.2.1 eslint-plugin-prettier: ^5.2.1
@ -101,7 +102,7 @@ catalog:
execa: ^9.4.0 execa: ^9.4.0
find-up: ^7.0.0 find-up: ^7.0.0
get-port: ^7.1.0 get-port: ^7.1.0
globals: ^15.10.0 globals: ^15.11.0
h3: ^1.13.0 h3: ^1.13.0
happy-dom: ^15.7.4 happy-dom: ^15.7.4
html-minifier-terser: ^7.2.0 html-minifier-terser: ^7.2.0
@ -126,7 +127,7 @@ catalog:
postcss-antd-fixes: ^0.2.0 postcss-antd-fixes: ^0.2.0
postcss-html: ^1.7.0 postcss-html: ^1.7.0
postcss-import: ^16.1.0 postcss-import: ^16.1.0
postcss-preset-env: ^10.0.6 postcss-preset-env: ^10.0.7
postcss-scss: ^4.0.9 postcss-scss: ^4.0.9
prettier: ^3.3.3 prettier: ^3.3.3
prettier-plugin-tailwindcss: ^0.6.8 prettier-plugin-tailwindcss: ^0.6.8
@ -153,7 +154,7 @@ catalog:
tailwindcss-animate: ^1.0.7 tailwindcss-animate: ^1.0.7
theme-colors: ^0.1.0 theme-colors: ^0.1.0
turbo: ^2.1.3 turbo: ^2.1.3
typescript: ^5.6.2 typescript: ^5.6.3
unbuild: ^2.0.0 unbuild: ^2.0.0
unplugin-element-plus: ^0.8.0 unplugin-element-plus: ^0.8.0
vee-validate: ^4.13.2 vee-validate: ^4.13.2
@ -173,7 +174,7 @@ catalog:
vue-i18n: ^10.0.4 vue-i18n: ^10.0.4
vue-router: ^4.4.5 vue-router: ^4.4.5
vue-tsc: ^2.1.6 vue-tsc: ^2.1.6
vxe-pc-ui: ^4.2.18 vxe-pc-ui: ^4.2.19
vxe-table: ^4.7.86 vxe-table: ^4.7.86
watermark-js-plus: ^1.5.7 watermark-js-plus: ^1.5.7
zod: ^3.23.8 zod: ^3.23.8