parent
							
								
									ea776aa710
								
							
						
					
					
						commit
						4102cc2211
					
				|  | @ -29,14 +29,25 @@ export type ValueType = boolean | number | string; | ||||||
| 
 | 
 | ||||||
| export interface VbenButtonGroupProps | export interface VbenButtonGroupProps | ||||||
|   extends Pick<VbenButtonProps, 'disabled'> { |   extends Pick<VbenButtonProps, 'disabled'> { | ||||||
|  |   /** 单选模式下允许清除选中 */ | ||||||
|  |   allowClear?: boolean; | ||||||
|  |   /** 值改变前的回调 */ | ||||||
|   beforeChange?: ( |   beforeChange?: ( | ||||||
|     value: ValueType, |     value: ValueType, | ||||||
|     isChecked: boolean, |     isChecked: boolean, | ||||||
|   ) => boolean | PromiseLike<boolean | undefined> | undefined; |   ) => boolean | PromiseLike<boolean | undefined> | undefined; | ||||||
|  |   /** 按钮样式 */ | ||||||
|   btnClass?: any; |   btnClass?: any; | ||||||
|  |   /** 按钮间隔距离 */ | ||||||
|   gap?: number; |   gap?: number; | ||||||
|  |   /** 多选模式下限制最多选择的数量。0表示不限制 */ | ||||||
|  |   maxCount?: number; | ||||||
|  |   /** 是否允许多选 */ | ||||||
|   multiple?: boolean; |   multiple?: boolean; | ||||||
|  |   /** 选项 */ | ||||||
|   options?: { [key: string]: any; label: CustomRenderType; value: ValueType }[]; |   options?: { [key: string]: any; label: CustomRenderType; value: ValueType }[]; | ||||||
|  |   /** 显示图标 */ | ||||||
|   showIcon?: boolean; |   showIcon?: boolean; | ||||||
|  |   /** 尺寸 */ | ||||||
|   size?: 'large' | 'middle' | 'small'; |   size?: 'large' | 'middle' | 'small'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,6 +19,8 @@ const props = withDefaults(defineProps<VbenButtonGroupProps>(), { | ||||||
|   multiple: false, |   multiple: false, | ||||||
|   showIcon: true, |   showIcon: true, | ||||||
|   size: 'middle', |   size: 'middle', | ||||||
|  |   allowClear: false, | ||||||
|  |   maxCount: 0, | ||||||
| }); | }); | ||||||
| const emit = defineEmits(['btnClick']); | const emit = defineEmits(['btnClick']); | ||||||
| const btnDefaultProps = computed(() => { | const btnDefaultProps = computed(() => { | ||||||
|  | @ -82,13 +84,23 @@ async function onBtnClick(value: ValueType) { | ||||||
|     if (innerValue.value.includes(value)) { |     if (innerValue.value.includes(value)) { | ||||||
|       innerValue.value = innerValue.value.filter((item) => item !== value); |       innerValue.value = innerValue.value.filter((item) => item !== value); | ||||||
|     } else { |     } else { | ||||||
|  |       if (props.maxCount > 0 && innerValue.value.length >= props.maxCount) { | ||||||
|  |         innerValue.value = innerValue.value.slice(0, props.maxCount - 1); | ||||||
|  |       } | ||||||
|       innerValue.value.push(value); |       innerValue.value.push(value); | ||||||
|     } |     } | ||||||
|     modelValue.value = innerValue.value; |     modelValue.value = innerValue.value; | ||||||
|  |   } else { | ||||||
|  |     if (props.allowClear && innerValue.value.includes(value)) { | ||||||
|  |       innerValue.value = []; | ||||||
|  |       modelValue.value = undefined; | ||||||
|  |       emit('btnClick', undefined); | ||||||
|  |       return; | ||||||
|     } else { |     } else { | ||||||
|       innerValue.value = [value]; |       innerValue.value = [value]; | ||||||
|       modelValue.value = value; |       modelValue.value = value; | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|   emit('btnClick', value); |   emit('btnClick', value); | ||||||
| } | } | ||||||
| </script> | </script> | ||||||
|  | @ -112,12 +124,18 @@ async function onBtnClick(value: ValueType) { | ||||||
|       @click="onBtnClick(btn.value)" |       @click="onBtnClick(btn.value)" | ||||||
|     > |     > | ||||||
|       <div class="icon-wrapper" v-if="props.showIcon"> |       <div class="icon-wrapper" v-if="props.showIcon"> | ||||||
|  |         <slot | ||||||
|  |           name="icon" | ||||||
|  |           :loading="loadingValues.includes(btn.value)" | ||||||
|  |           :checked="innerValue.includes(btn.value)" | ||||||
|  |         > | ||||||
|           <LoaderCircle |           <LoaderCircle | ||||||
|             class="animate-spin" |             class="animate-spin" | ||||||
|             v-if="loadingValues.includes(btn.value)" |             v-if="loadingValues.includes(btn.value)" | ||||||
|           /> |           /> | ||||||
|           <CircleCheckBig v-else-if="innerValue.includes(btn.value)" /> |           <CircleCheckBig v-else-if="innerValue.includes(btn.value)" /> | ||||||
|           <Circle v-else /> |           <Circle v-else /> | ||||||
|  |         </slot> | ||||||
|       </div> |       </div> | ||||||
|       <slot name="option" :label="btn.label" :value="btn.value" :data="btn"> |       <slot name="option" :label="btn.label" :value="btn.value" :data="btn"> | ||||||
|         <VbenRenderContent :content="btn.label" /> |         <VbenRenderContent :content="btn.label" /> | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ import { | ||||||
|   VbenButtonGroup, |   VbenButtonGroup, | ||||||
|   VbenCheckButtonGroup, |   VbenCheckButtonGroup, | ||||||
| } from '@vben/common-ui'; | } from '@vben/common-ui'; | ||||||
|  | import { LoaderCircle, Square, SquareCheckBig } from '@vben/icons'; | ||||||
| 
 | 
 | ||||||
| import { Button, Card, message } from 'ant-design-vue'; | import { Button, Card, message } from 'ant-design-vue'; | ||||||
| 
 | 
 | ||||||
|  | @ -51,6 +52,7 @@ const compProps = reactive({ | ||||||
|   gap: 0, |   gap: 0, | ||||||
|   showIcon: true, |   showIcon: true, | ||||||
|   size: 'middle', |   size: 'middle', | ||||||
|  |   allowClear: false, | ||||||
| } as Recordable<any>); | } as Recordable<any>); | ||||||
| 
 | 
 | ||||||
| const [Form] = useVbenForm({ | const [Form] = useVbenForm({ | ||||||
|  | @ -63,6 +65,9 @@ const [Form] = useVbenForm({ | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|   }, |   }, | ||||||
|  |   commonConfig: { | ||||||
|  |     labelWidth: 150, | ||||||
|  |   }, | ||||||
|   schema: [ |   schema: [ | ||||||
|     { |     { | ||||||
|       component: 'RadioGroup', |       component: 'RadioGroup', | ||||||
|  | @ -109,6 +114,20 @@ const [Form] = useVbenForm({ | ||||||
|       fieldName: 'beforeChange', |       fieldName: 'beforeChange', | ||||||
|       label: '前置回调', |       label: '前置回调', | ||||||
|     }, |     }, | ||||||
|  |     { | ||||||
|  |       component: 'Switch', | ||||||
|  |       defaultValue: false, | ||||||
|  |       fieldName: 'allowClear', | ||||||
|  |       label: '允许清除', | ||||||
|  |       help: '单选时是否允许取消选中(值为undefined)', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       defaultValue: 0, | ||||||
|  |       fieldName: 'maxCount', | ||||||
|  |       label: '最大选中数量', | ||||||
|  |       help: '多选时有效,0表示不限制', | ||||||
|  |     }, | ||||||
|   ], |   ], | ||||||
|   showDefaultActions: false, |   showDefaultActions: false, | ||||||
|   submitOnChange: true, |   submitOnChange: true, | ||||||
|  | @ -186,6 +205,21 @@ function onBtnClick(value: any) { | ||||||
|           v-bind="compProps" |           v-bind="compProps" | ||||||
|         /> |         /> | ||||||
|       </div> |       </div> | ||||||
|  |       <p class="mt-4">自定义图标{{ checkValue }}</p> | ||||||
|  |       <div class="mt-2 flex flex-col gap-2"> | ||||||
|  |         <VbenCheckButtonGroup | ||||||
|  |           v-model="checkValue" | ||||||
|  |           multiple | ||||||
|  |           :options="options" | ||||||
|  |           v-bind="compProps" | ||||||
|  |         > | ||||||
|  |           <template #icon="{ loading, checked }"> | ||||||
|  |             <LoaderCircle class="animate-spin" v-if="loading" /> | ||||||
|  |             <SquareCheckBig v-else-if="checked" /> | ||||||
|  |             <Square v-else /> | ||||||
|  |           </template> | ||||||
|  |         </VbenCheckButtonGroup> | ||||||
|  |       </div> | ||||||
|     </Card> |     </Card> | ||||||
| 
 | 
 | ||||||
|     <Card title="设置" class="mt-4"> |     <Card title="设置" class="mt-4"> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Netfan
						Netfan