chore: base form (#23101)

This commit is contained in:
zxhlyh
2025-07-29 15:37:16 +08:00
committed by GitHub
parent 27f400e13f
commit 4c65a8091a
5 changed files with 58 additions and 5 deletions

View File

@@ -11,6 +11,7 @@ import PureSelect from '@/app/components/base/select/pure'
import type { FormSchema } from '@/app/components/base/form/types' import type { FormSchema } from '@/app/components/base/form/types'
import { FormTypeEnum } from '@/app/components/base/form/types' import { FormTypeEnum } from '@/app/components/base/form/types'
import { useRenderI18nObject } from '@/hooks/use-i18n' import { useRenderI18nObject } from '@/hooks/use-i18n'
import RadioE from '@/app/components/base/radio/ui'
export type BaseFieldProps = { export type BaseFieldProps = {
fieldClassName?: string fieldClassName?: string
@@ -57,8 +58,27 @@ const BaseField = ({
if (typeof placeholder === 'object' && placeholder !== null) if (typeof placeholder === 'object' && placeholder !== null)
return renderI18nObject(placeholder as Record<string, string>) return renderI18nObject(placeholder as Record<string, string>)
}, [placeholder, renderI18nObject]) }, [placeholder, renderI18nObject])
const optionValues = useStore(field.form.store, (s) => {
const result: Record<string, any> = {}
options?.forEach((option) => {
if (option.show_on?.length) {
option.show_on.forEach((condition) => {
result[condition.variable] = s.values[condition.variable]
})
}
})
return result
})
const memorizedOptions = useMemo(() => { const memorizedOptions = useMemo(() => {
return options?.map((option) => { return options?.filter((option) => {
if (!option.show_on?.length)
return true
return option.show_on.every((condition) => {
const conditionValue = optionValues[condition.variable]
return conditionValue === condition.value
})
}).map((option) => {
return { return {
label: typeof option.label === 'string' ? option.label : renderI18nObject(option.label), label: typeof option.label === 'string' ? option.label : renderI18nObject(option.label),
value: option.value, value: option.value,
@@ -151,17 +171,28 @@ const BaseField = ({
} }
{ {
formSchema.type === FormTypeEnum.radio && ( formSchema.type === FormTypeEnum.radio && (
<div className='flex items-center space-x-2'> <div className={cn(
memorizedOptions.length < 3 ? 'flex items-center space-x-2' : 'space-y-2',
)}>
{ {
memorizedOptions.map(option => ( memorizedOptions.map(option => (
<div <div
key={option.value} key={option.value}
className={cn( className={cn(
'system-sm-regular hover:bg-components-option-card-option-hover-bg hover:border-components-option-card-option-hover-border flex h-8 grow cursor-pointer items-center justify-center rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg p-2 text-text-secondary', 'system-sm-regular hover:bg-components-option-card-option-hover-bg hover:border-components-option-card-option-hover-border flex h-8 flex-[1] grow cursor-pointer items-center justify-center rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg p-2 text-text-secondary',
value === option.value && 'border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary shadow-xs', value === option.value && 'border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary shadow-xs',
inputClassName,
)} )}
onClick={() => field.handleChange(option.value)} onClick={() => field.handleChange(option.value)}
> >
{
formSchema.showRadioUI && (
<RadioE
className='mr-2'
isChecked={value === option.value}
/>
)
}
{option.label} {option.label}
</div> </div>
)) ))

View File

@@ -2,6 +2,7 @@ import {
memo, memo,
useCallback, useCallback,
useImperativeHandle, useImperativeHandle,
useMemo,
} from 'react' } from 'react'
import type { import type {
AnyFieldApi, AnyFieldApi,
@@ -45,8 +46,18 @@ const BaseForm = ({
disabled, disabled,
formFromProps, formFromProps,
}: BaseFormProps) => { }: BaseFormProps) => {
const initialDefaultValues = useMemo(() => {
if (defaultValues)
return defaultValues
return formSchemas.reduce((acc, schema) => {
if (schema.default)
acc[schema.name] = schema.default
return acc
}, {} as Record<string, any>)
}, [defaultValues])
const formFromHook = useForm({ const formFromHook = useForm({
defaultValues, defaultValues: initialDefaultValues,
}) })
const form: any = formFromProps || formFromHook const form: any = formFromProps || formFromHook
const { getFormValues } = useGetFormValues(form, formSchemas) const { getFormValues } = useGetFormValues(form, formSchemas)

View File

@@ -7,6 +7,7 @@ const AuthForm = ({
defaultValues, defaultValues,
ref, ref,
formFromProps, formFromProps,
...rest
}: BaseFormProps) => { }: BaseFormProps) => {
return ( return (
<BaseForm <BaseForm
@@ -16,6 +17,7 @@ const AuthForm = ({
formClassName='space-y-4' formClassName='space-y-4'
labelClassName='h-6 flex items-center mb-1 system-sm-medium text-text-secondary' labelClassName='h-6 flex items-center mb-1 system-sm-medium text-text-secondary'
formFromProps={formFromProps} formFromProps={formFromProps}
{...rest}
/> />
) )
} }

View File

@@ -58,6 +58,7 @@ export type FormSchema = {
options?: FormOption[] options?: FormOption[]
labelClassName?: string labelClassName?: string
validators?: AnyValidators validators?: AnyValidators
showRadioUI?: boolean
} }
export type FormValues = Record<string, any> export type FormValues = Record<string, any>

View File

@@ -5,13 +5,21 @@ import cn from '@/utils/classnames'
type Props = { type Props = {
isChecked: boolean isChecked: boolean
className?: string
} }
const RadioUI: FC<Props> = ({ const RadioUI: FC<Props> = ({
isChecked, isChecked,
className,
}) => { }) => {
return ( return (
<div className={cn(isChecked ? 'border-[5px] border-components-radio-border-checked' : 'border-[2px] border-components-radio-border', 'h-4 w-4 rounded-full')}> <div
className={cn(
isChecked ? 'border-[5px] border-components-radio-border-checked' : 'border-[2px] border-components-radio-border',
'h-4 w-4 rounded-full',
className,
)}
>
</div> </div>
) )
} }