diff --git a/src/shared/components/charts/chart-card-shell.tsx b/src/shared/components/charts/chart-card-shell.tsx index 6f404a8..0695655 100644 --- a/src/shared/components/charts/chart-card-shell.tsx +++ b/src/shared/components/charts/chart-card-shell.tsx @@ -46,6 +46,8 @@ interface ChartCardShellProps { className?: string /** CardContent 额外类名 */ contentClassName?: string + /** 卡片头部右侧操作区(如"查看全部"链接) */ + action?: ReactNode } export function ChartCardShell({ @@ -62,15 +64,19 @@ export function ChartCardShell({ children, className, contentClassName, + action, }: ChartCardShellProps) { const EmptyIcon = emptyIcon ?? Icon return ( - - {Icon ? : null} - {title} - +
+ + {Icon ? : null} + {title} + + {action} +
{description ? {description} : null}
diff --git a/src/shared/components/charts/simple-bar-chart.tsx b/src/shared/components/charts/simple-bar-chart.tsx index 230e6e7..7533c0c 100644 --- a/src/shared/components/charts/simple-bar-chart.tsx +++ b/src/shared/components/charts/simple-bar-chart.tsx @@ -66,6 +66,8 @@ interface SimpleBarChartProps { tooltipFormatter?: (payload: unknown) => ReactNode /** 按数据项着色的映射(key = xKey 值, value = 颜色);用于单 Bar 分桶着色 */ cellColors?: Record + /** 自定义 SVG defs(如 patterns、gradients),渲染在 BarChart 内部 */ + defs?: ReactNode /** 容器额外类名 */ className?: string } @@ -93,6 +95,7 @@ export function SimpleBarChart({ tooltipClassName = "w-[200px]", tooltipFormatter, cellColors, + defs, className, }: SimpleBarChartProps) { const chartConfig: ChartConfig = {} @@ -115,6 +118,7 @@ export function SimpleBarChart({ return ( + {defs} = FieldPath +> { + /** react-hook-form control 实例 */ + control: Control + /** 字段路径 */ + name: TName + /** 标签文本 */ + label: string + /** 占位符 */ + placeholder?: string + /** 描述文本 */ + description?: React.ReactNode + /** 选项列表 */ + options: SelectOption[] + /** 是否禁用 */ + disabled?: boolean + /** FormItem 的 className */ + itemClassName?: string + /** FormLabel 右侧的额外节点(如"新建"按钮) */ + labelSlot?: React.ReactNode + /** + * 自定义 value 转换:从 field.value → Select 的 value(string)。 + * 常用于 number 字段:`(v) => String(v)` + */ + toSelectValue?: (value: unknown) => string + /** + * 自定义 onChange 转换:从 Select 的 string value → field.onChange 的值。 + * 常用于 number 字段:`(val) => parseInt(val, 10)` + */ + fromSelectValue?: (val: string) => unknown +} + +/** + * 通用选择字段组件,封装 FormField + FormItem + FormLabel + Select + SelectContent + SelectItem + FormMessage。 + * + * 用于替代各表单中重复的 ` field.onChange(fromSelectValue(val)) : field.onChange} + disabled={disabled} + > + + + + + + + {options.map((opt) => ( + + {opt.label} + + ))} + + + {description ? {description} : null} + + + )} + /> + ) +} diff --git a/src/shared/components/form-fields/text-field.tsx b/src/shared/components/form-fields/text-field.tsx new file mode 100644 index 0000000..91fa044 --- /dev/null +++ b/src/shared/components/form-fields/text-field.tsx @@ -0,0 +1,117 @@ +"use client" + +import * as React from "react" +import { + type Control, + type FieldPath, + type FieldValues, +} from "react-hook-form" + +import { + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/shared/components/ui/form" +import { Input } from "@/shared/components/ui/input" + +export interface TextFieldProps< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +> { + /** react-hook-form control 实例 */ + control: Control + /** 字段路径 */ + name: TName + /** 标签文本 */ + label: string + /** 占位符 */ + placeholder?: string + /** 描述文本(显示在标签下) */ + description?: React.ReactNode + /** Input 类型,默认 "text" */ + type?: "text" | "number" | "password" | "email" | "datetime-local" | "tel" | "url" + /** 是否禁用 */ + disabled?: boolean + /** FormItem 的 className(用于布局,如 "col-span-2") */ + itemClassName?: string + /** Input 的额外 className */ + inputClassName?: string + /** 透传到 Input 的其他 props(如 min/max/step) */ + inputProps?: Omit< + React.InputHTMLAttributes, + "name" | "value" | "onChange" | "onBlur" | "disabled" | "type" | "placeholder" | "className" + > + /** + * 自定义 value 转换:从 field.value → input value。 + * 常用于 number 字段处理 null/undefined → ""。 + */ + toInputValue?: (value: unknown) => string | number | readonly string[] + /** + * 自定义 onChange 转换:从 input event → field.onChange 的值。 + * 常用于 number 字段处理空字符串 → null。 + */ + fromInputValue?: (e: React.ChangeEvent) => unknown +} + +/** + * 通用文本字段组件,封装 FormField + FormItem + FormLabel + FormControl + Input + FormMessage。 + * + * 用于替代各表单中重复的 ` }>` 模式。 + * + * @example + * + * + * @example 数值字段 + * + */ +export function TextField< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +>({ + control, + name, + label, + placeholder, + description, + type = "text", + disabled, + itemClassName, + inputClassName, + inputProps, + toInputValue, + fromInputValue, +}: TextFieldProps) { + return ( + ( + + {label} + + + + {description ? {description} : null} + + + )} + /> + ) +} diff --git a/src/shared/components/form-fields/textarea-field.tsx b/src/shared/components/form-fields/textarea-field.tsx new file mode 100644 index 0000000..d2d8ab6 --- /dev/null +++ b/src/shared/components/form-fields/textarea-field.tsx @@ -0,0 +1,97 @@ +"use client" + +import * as React from "react" +import { + type Control, + type FieldPath, + type FieldValues, +} from "react-hook-form" + +import { + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/shared/components/ui/form" +import { Textarea } from "@/shared/components/ui/textarea" + +export interface TextareaFieldProps< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +> { + /** react-hook-form control 实例 */ + control: Control + /** 字段路径 */ + name: TName + /** 标签文本 */ + label: string + /** 占位符 */ + placeholder?: string + /** 描述文本 */ + description?: React.ReactNode + /** 是否禁用 */ + disabled?: boolean + /** FormItem 的 className */ + itemClassName?: string + /** Textarea 的额外 className(如 "min-h-[200px]") */ + textareaClassName?: string + /** 透传到 Textarea 的其他 props(如 rows、maxLength) */ + textareaProps?: Omit< + React.TextareaHTMLAttributes, + "name" | "value" | "onChange" | "onBlur" | "disabled" | "placeholder" | "className" + > +} + +/** + * 通用多行文本字段组件,封装 FormField + FormItem + FormLabel + FormControl + Textarea + FormMessage。 + * + * 用于替代各表单中重复的 `