diff --git a/package.json b/package.json index bd937293f..e62297128 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ }, "type": "module", "scripts": { + "bootstrap": "pnpm install", "build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build", "build:analyze": "turbo build:analyze", "build:antd": "pnpm run build --filter=@vben/web-antd", diff --git a/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue b/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue index 5bfa1b96e..af831cce4 100644 --- a/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue +++ b/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue @@ -48,6 +48,7 @@ const { modelPropName, renderComponentContent, rules, + help, } = defineProps< Props & { commonComponentProps: MaybeComponentProps; @@ -174,6 +175,18 @@ const computedProps = computed(() => { }; }); +// 自定义帮助信息 +const computedHelp = computed(() => { + return help ? onHelpFunc : undefined; +}); + +const onHelpFunc = () => { + if (!help) { + return undefined; + } + return isFunction(help) ? help(values.value, formApi!) : help; +}; + watch( () => computedProps.value?.autofocus, (value) => { @@ -322,7 +335,7 @@ onUnmounted(() => { labelClass, ) " - :help="help" + :help="computedHelp" :colon="colon" :label="label" :required="shouldRequired && !hideRequiredMark" diff --git a/packages/@core/ui-kit/form-ui/src/types.ts b/packages/@core/ui-kit/form-ui/src/types.ts index b5c5a4fbc..2238abd1c 100644 --- a/packages/@core/ui-kit/form-ui/src/types.ts +++ b/packages/@core/ui-kit/form-ui/src/types.ts @@ -67,6 +67,14 @@ export type FormActions = FormContext; export type CustomRenderType = (() => Component | string) | string; +// 动态渲染参数 +export type CustomParamsRenderType = + | (( + value: Partial>, + actions: FormActions, + ) => Component | string) + | string; + export type FormSchemaRuleType = | 'required' | 'selectRequired' @@ -254,7 +262,7 @@ export interface FormSchema< /** 字段名 */ fieldName: string; /** 帮助信息 */ - help?: CustomRenderType; + help?: CustomParamsRenderType; /** 是否隐藏表单项 */ hide?: boolean; /** 表单项 */ diff --git a/packages/effects/common-ui/src/components/api-component/api-component.vue b/packages/effects/common-ui/src/components/api-component/api-component.vue index 19f51f526..682cd16b8 100644 --- a/packages/effects/common-ui/src/components/api-component/api-component.vue +++ b/packages/effects/common-ui/src/components/api-component/api-component.vue @@ -46,6 +46,8 @@ interface Props { alwaysLoad?: boolean; /** 在api请求之前的回调函数 */ beforeFetch?: AnyPromiseFunction; + /** 在api请求之前的判断是否允许请求的回调函数 */ + shouldFetch?: AnyPromiseFunction; /** 在api请求之后的回调函数 */ afterFetch?: AnyPromiseFunction; /** 直接传入选项数据,也作为api返回空数据时的后备数据 */ @@ -88,6 +90,7 @@ const props = withDefaults(defineProps(), { alwaysLoad: false, loadingSlot: '', beforeFetch: undefined, + shouldFetch: undefined, afterFetch: undefined, modelPropName: 'modelValue', api: undefined, @@ -159,7 +162,7 @@ const bindProps = computed(() => { }); async function fetchApi() { - const { api, beforeFetch, afterFetch, resultField } = props; + const { api, beforeFetch, shouldFetch, afterFetch, resultField } = props; if (!api || !isFunction(api)) { return; @@ -178,6 +181,14 @@ async function fetchApi() { if (beforeFetch && isFunction(beforeFetch)) { finalParams = (await beforeFetch(cloneDeep(finalParams))) || finalParams; } + // 判断是否需要控制执行中断 + if ( + shouldFetch && + isFunction(shouldFetch) && + !(await shouldFetch(finalParams)) + ) { + return; + } let res = await api(finalParams); if (afterFetch && isFunction(afterFetch)) { res = (await afterFetch(res)) || res; diff --git a/packages/effects/plugins/src/vxe-table/index.ts b/packages/effects/plugins/src/vxe-table/index.ts index a19f2b8fc..6f0efe442 100644 --- a/packages/effects/plugins/src/vxe-table/index.ts +++ b/packages/effects/plugins/src/vxe-table/index.ts @@ -1,5 +1,5 @@ export { setupVbenVxeTable } from './init'; -export type { VxeTableGridOptions } from './types'; +export type { VxeTableGridColumns, VxeTableGridOptions } from './types'; export * from './use-vxe-grid'; export { default as VbenVxeGrid } from './use-vxe-grid.vue'; diff --git a/packages/effects/plugins/src/vxe-table/types.ts b/packages/effects/plugins/src/vxe-table/types.ts index 8b9aea47d..8e56ce418 100644 --- a/packages/effects/plugins/src/vxe-table/types.ts +++ b/packages/effects/plugins/src/vxe-table/types.ts @@ -26,6 +26,8 @@ interface ToolbarConfigOptions extends VxeGridPropTypes.ToolbarConfig { search?: boolean; } +export type VxeTableGridColumns = VxeTableGridOptions['columns']; + export interface VxeTableGridOptions extends VxeTableGridProps { /** 工具栏配置 */ toolbarConfig?: ToolbarConfigOptions; @@ -40,6 +42,10 @@ export interface VxeGridProps< T extends Record = any, D extends BaseFormComponentType = BaseFormComponentType, > { + /** + * 数据 + */ + tableData?: any[]; /** * 标题 */ diff --git a/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue b/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue index 4cb2d03bb..ddde3d30a 100644 --- a/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue +++ b/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue @@ -72,6 +72,7 @@ const { gridEvents, formOptions, tableTitle, + tableData, tableTitleHelp, showSearchForm, separator, @@ -229,6 +230,9 @@ const options = computed(() => { } if (mergedOptions.formConfig) { mergedOptions.formConfig.enabled = false; + if (tableData.value && tableData.value.length > 0) { + mergedOptions.data = tableData.value; + } } return mergedOptions; }); diff --git a/playground/src/views/examples/form/basic.vue b/playground/src/views/examples/form/basic.vue index 81fda07e1..4474df943 100644 --- a/playground/src/views/examples/form/basic.vue +++ b/playground/src/views/examples/form/basic.vue @@ -113,6 +113,10 @@ const [BaseForm, baseFormApi] = useVbenForm({ params: { keyword: keyword.value || undefined, }, + // 远程搜索判断。当为true时,才允许调用api + shouldFetch: (params: any) => { + return !!params?.keyword; + }, showSearch: true, }; }, @@ -120,6 +124,7 @@ const [BaseForm, baseFormApi] = useVbenForm({ fieldName: 'remoteSearch', // 界面显示的label label: '远程搜索', + help: '远程查询,仅有输入时方进行查询', renderComponentContent: () => { return { notFoundContent: fetching.value ? h(Spin) : undefined, @@ -281,6 +286,8 @@ const [BaseForm, baseFormApi] = useVbenForm({ { component: 'DatePicker', fieldName: 'datePicker', + help: (values) => + [`这是一个可输出其他字段值的帮助信息${values?.rate}`].map((v) => h('p', v)), label: '日期选择框', }, { diff --git a/playground/src/views/system/dept/data.ts b/playground/src/views/system/dept/data.ts index 48773625a..b0699e7a6 100644 --- a/playground/src/views/system/dept/data.ts +++ b/playground/src/views/system/dept/data.ts @@ -1,4 +1,4 @@ -import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; +import type { VxeTableGridColumns } from '@vben/plugins/vxe-table'; import type { VbenFormSchema } from '#/adapter/form'; import type { OnActionClickFn } from '#/adapter/vxe-table'; @@ -76,7 +76,7 @@ export function useSchema(): VbenFormSchema[] { */ export function useColumns( onActionClick?: OnActionClickFn, -): VxeTableGridOptions['columns'] { +): VxeTableGridColumns { return [ { align: 'left', diff --git a/playground/src/views/system/menu/data.ts b/playground/src/views/system/menu/data.ts index 75190b4ac..11aa2bd37 100644 --- a/playground/src/views/system/menu/data.ts +++ b/playground/src/views/system/menu/data.ts @@ -1,4 +1,4 @@ -import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { OnActionClickFn, VxeTableGridColumns } from '#/adapter/vxe-table'; import type { SystemMenuApi } from '#/api/system/menu'; import { $t } from '#/locales'; @@ -23,7 +23,7 @@ export function getMenuTypeOptions() { export function useColumns( onActionClick: OnActionClickFn, -): VxeTableGridOptions['columns'] { +): VxeTableGridColumns { return [ { align: 'left', diff --git a/playground/src/views/system/role/data.ts b/playground/src/views/system/role/data.ts index 255b6cc72..9c9d0fbab 100644 --- a/playground/src/views/system/role/data.ts +++ b/playground/src/views/system/role/data.ts @@ -1,5 +1,5 @@ import type { VbenFormSchema } from '#/adapter/form'; -import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { OnActionClickFn, VxeTableGridColumns } from '#/adapter/vxe-table'; import type { SystemRoleApi } from '#/api'; import { $t } from '#/locales'; @@ -77,7 +77,7 @@ export function useGridFormSchema(): VbenFormSchema[] { export function useColumns( onActionClick: OnActionClickFn, onStatusChange?: (newStatus: any, row: T) => PromiseLike, -): VxeTableGridOptions['columns'] { +): VxeTableGridColumns { return [ { field: 'name', diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 72d5adde5..de80ea01b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,12 +12,14 @@ packages: - scripts/* - docs - playground + overrides: '@ast-grep/napi': 'catalog:' '@ctrl/tinycolor': 'catalog:' clsx: 'catalog:' pinia: 'catalog:' vue: 'catalog:' + catalog: '@ast-grep/napi': ^0.42.0 '@changesets/changelog-github': ^0.6.0 @@ -185,3 +187,4 @@ catalog: yaml-eslint-parser: ^2.0.0 zod: ^3.25.76 zod-defaults: 0.1.3 +