mirror of
https://github.com/imdap/ruoyi-plus-vben5.git
synced 2026-04-23 08:48:35 +08:00
feat(common-ui): add labelFn support to ApiComponent (#7801)
* feat: allow api-component labels to be derived from option data ApiComponent already normalizes option records into the label/value shape used by consuming controls, but label text could only come from a single field. Add labelFn so callers can build labels from the full option record while keeping labelField as the fallback path. This keeps the change inside the existing component instead of introducing a wrapper, and it also normalizes direct options through the same transform path as API-loaded options for consistent behavior. Constraint: Must extend the existing ApiComponent API instead of adding a second Constraint: wrapper component Rejected: Add a separate ApiLabelComponent wrapper | Rejected: extra surface area for one option-mapping concern Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep labelFn as a presentation transform and preserve labelField Directive: fallback for existing callers Tested: pnpm exec eslint api-component.vue index.ts types.ts Tested: pnpm exec vue-tsc --noEmit -p packages/effects/common-ui/tsconfig.json Not-tested: runtime integration in consuming select/tree-select components * Update packages/effects/common-ui/src/components/api-component/api-component.vue Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -17,6 +17,7 @@ defineOptions({ name: 'ApiComponent', inheritAttrs: false });
|
|||||||
const props = withDefaults(defineProps<ApiComponentProps>(), {
|
const props = withDefaults(defineProps<ApiComponentProps>(), {
|
||||||
labelField: 'label',
|
labelField: 'label',
|
||||||
valueField: 'value',
|
valueField: 'value',
|
||||||
|
labelFn: undefined,
|
||||||
disabledField: 'disabled',
|
disabledField: 'disabled',
|
||||||
childrenField: '',
|
childrenField: '',
|
||||||
optionsPropName: 'options',
|
optionsPropName: 'options',
|
||||||
@@ -54,33 +55,37 @@ const hasPendingRequest = ref(false);
|
|||||||
const getOptions = computed(() => {
|
const getOptions = computed(() => {
|
||||||
const {
|
const {
|
||||||
labelField,
|
labelField,
|
||||||
|
labelFn,
|
||||||
valueField,
|
valueField,
|
||||||
disabledField,
|
disabledField,
|
||||||
childrenField,
|
childrenField,
|
||||||
numberToString,
|
numberToString,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const refOptionsData = unref(refOptions);
|
function transformData(data: OptionsItem[] = []): OptionsItem[] {
|
||||||
|
|
||||||
function transformData(data: OptionsItem[]): OptionsItem[] {
|
|
||||||
return data.map((item) => {
|
return data.map((item) => {
|
||||||
const value = get(item, valueField);
|
const value = get(item, valueField);
|
||||||
const disabled = get(item, disabledField);
|
const children = childrenField ? get(item, childrenField) : item.children;
|
||||||
return {
|
return {
|
||||||
...objectOmit(item, [labelField, valueField, disabled, childrenField]),
|
...objectOmit(item, [
|
||||||
label: get(item, labelField),
|
labelField,
|
||||||
|
valueField,
|
||||||
|
disabledField,
|
||||||
|
...(childrenField ? [childrenField] : []),
|
||||||
|
]),
|
||||||
|
label: labelFn ? labelFn(item) : get(item, labelField),
|
||||||
value: numberToString ? `${value}` : value,
|
value: numberToString ? `${value}` : value,
|
||||||
disabled: get(item, disabledField),
|
disabled: get(item, disabledField),
|
||||||
...(childrenField && item[childrenField]
|
...(Array.isArray(children) && children.length > 0
|
||||||
? { children: transformData(item[childrenField]) }
|
? { children: transformData(children) }
|
||||||
: {}),
|
: {}),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: OptionsItem[] = transformData(refOptionsData);
|
const data = transformData(unref(refOptions));
|
||||||
|
|
||||||
return data.length > 0 ? data : props.options;
|
return data.length > 0 ? data : transformData(props.options);
|
||||||
});
|
});
|
||||||
|
|
||||||
const bindProps = computed(() => {
|
const bindProps = computed(() => {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export { default as ApiComponent } from './api-component.vue';
|
export { default as ApiComponent } from './api-component.vue';
|
||||||
export type {
|
export type {
|
||||||
|
ApiComponentLabelFn,
|
||||||
ApiComponentOptionsItem,
|
ApiComponentOptionsItem,
|
||||||
ApiComponentProps,
|
ApiComponentProps,
|
||||||
ApiComponentSharedProps,
|
ApiComponentSharedProps,
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ export type ApiComponentOptionsItem = {
|
|||||||
value?: number | string;
|
value?: number | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApiComponentLabelFn = (item: ApiComponentOptionsItem) => string;
|
||||||
|
|
||||||
export interface ApiComponentProps {
|
export interface ApiComponentProps {
|
||||||
/** 组件 */
|
/** 组件 */
|
||||||
component: Component;
|
component: Component;
|
||||||
@@ -23,6 +25,8 @@ export interface ApiComponentProps {
|
|||||||
resultField?: string;
|
resultField?: string;
|
||||||
/** label字段名 */
|
/** label字段名 */
|
||||||
labelField?: string;
|
labelField?: string;
|
||||||
|
/** 通过选项数据自定义label */
|
||||||
|
labelFn?: ApiComponentLabelFn;
|
||||||
/** children字段名,需要层级数据的组件可用 */
|
/** children字段名,需要层级数据的组件可用 */
|
||||||
childrenField?: string;
|
childrenField?: string;
|
||||||
/** value字段名 */
|
/** value字段名 */
|
||||||
|
|||||||
Reference in New Issue
Block a user