feat: 新增 FaCheckboxGrou 组件,并重构 FaCheckbox API

This commit is contained in:
Hooray
2026-04-29 16:15:10 +08:00
parent c0bc31f7f4
commit 5ba6d08df3
21 changed files with 704 additions and 65 deletions
@@ -53,6 +53,14 @@ const routes: RouteRecordRaw = {
title: '复选框',
},
},
{
path: 'checkbox_group',
name: 'componentExampleCheckboxGroup',
component: () => import('@/views/component_example/checkbox_group/index.vue'),
meta: {
title: '复选框组',
},
},
{
path: 'collapsible',
name: 'componentExampleCollapsible',
+2
View File
@@ -24,6 +24,7 @@ declare module 'vue' {
FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
FaCard: typeof import('@fantastic-admin/components')['FaCard']
FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
@@ -76,6 +77,7 @@ declare global {
const FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
const FaCard: typeof import('@fantastic-admin/components')['FaCard']
const FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
const FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
const FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
const FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
const FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
+1 -1
View File
@@ -5,7 +5,7 @@ const checked = ref(false)
<template>
<div class="flex gap-4">
<FaCheckbox v-model="checked">
Checkbox
同意协议
</FaCheckbox>
</div>
</template>
+1 -1
View File
@@ -4,6 +4,6 @@ const checked = ref<'indeterminate' | boolean>('indeterminate')
<template>
<FaCheckbox v-model="checked">
Checkbox
部分选中
</FaCheckbox>
</template>
View File
@@ -0,0 +1,26 @@
<script setup lang="ts">
const value = ref(['music'])
const options = [
{ label: '阅读', value: 'reading' },
{ label: '音乐', value: 'music' },
{ label: '运动', value: 'sports' },
]
const currentText = computed(() =>
options
.filter(option => value.value.includes(option.value))
.map(option => option.label)
.join('、'),
)
</script>
<template>
<div class="gap-4 grid">
<FaCheckboxGroup v-model="value" :options="options" />
<FaCheckboxGroup v-model="value" :options="options" class="flex" />
<div class="text-sm text-muted-foreground">
当前值:{{ currentText }}
</div>
</div>
</template>
@@ -0,0 +1,38 @@
<script setup lang="ts">
const value = ref(['dashboard', 'report'])
const options = [
{
label: '看板订阅',
value: 'dashboard',
description: '每天 8:00 推送核心经营指标。',
},
{
label: '周报摘要',
value: 'report',
description: '每周一汇总关键数据变化。',
},
{
label: '系统告警',
value: 'alarm',
description: '异常波动时立即通知处理人。',
disabled: true,
},
]
const currentText = computed(() =>
options
.filter(option => value.value.includes(option.value))
.map(option => option.label)
.join('、'),
)
</script>
<template>
<div class="gap-4 grid">
<FaCheckboxGroup v-model="value" :options="options" />
<div class="text-sm text-muted-foreground">
当前值:{{ currentText }}
</div>
</div>
</template>
@@ -0,0 +1,68 @@
<script setup lang="ts">
const value = ref(['focus', 'balanced'])
const options = [
{
label: '专注模式',
value: 'focus',
description: '突出主任务,弱化辅助信息,适合录入和审批场景。',
},
{
label: '平衡模式',
value: 'balanced',
description: '信息密度与可读性保持平衡,适合作为默认配置。',
},
{
label: '高密度模式',
value: 'dense',
description: '在大屏中同时承载更多信息,适合运营与监控看板。',
},
]
const currentText = computed(() =>
options
.filter(option => value.value.includes(option.value))
.map(option => option.label)
.join('、'),
)
</script>
<template>
<FaCheckboxGroup
v-model="value"
:options="options"
class="gap-2 md:grid-cols-3"
option-class="rounded-xl border border-transparent px-1 py-1"
>
<template #option="{ option, checked, disabled }">
<div
class="px-4 py-3 border rounded-xl flex gap-3 w-full transition-colors items-start justify-between" :class="[
checked ? 'border-primary bg-primary/5' : 'border-border hover:border-primary/40',
disabled && 'opacity-60',
]"
>
<div class="gap-1 grid min-w-0">
<div class="text-sm font-medium truncate">
{{ option.label }}
</div>
<div
v-if="option.description"
class="text-xs text-muted-foreground leading-5"
>
{{ option.description }}
</div>
</div>
<span
class="text-xs font-medium shrink-0" :class="[
checked ? 'text-primary' : 'text-muted-foreground',
]"
>
{{ checked ? '已选中' : '可选择' }}
</span>
</div>
</template>
</FaCheckboxGroup>
<div class="text-sm text-muted-foreground">
当前模式:{{ currentText }}
</div>
</template>
@@ -0,0 +1,33 @@
<script setup lang="ts">
const value = ref(['dashboard'])
const options = [
{ label: '看板订阅', value: 'dashboard' },
{ label: '周报摘要', value: 'report' },
{ label: '系统告警', value: 'alarm' },
]
const currentText = computed(() =>
options
.filter(option => value.value.includes(option.value))
.map(option => option.label)
.join('、'),
)
</script>
<template>
<div class="gap-4 grid">
<FaCheckboxGroup
v-model="value"
:options="options"
:min="1"
:max="2"
/>
<div class="text-sm text-muted-foreground">
当前值:{{ currentText }}
</div>
<div class="text-xs text-muted-foreground leading-5">
已选数量小于等于 1 时,已选项会被禁用;已选数量大于等于 2 时,未选项会被禁用。
</div>
</div>
</template>
@@ -0,0 +1,24 @@
<script setup lang="ts">
import Demo1 from './_demo1.vue'
import Demo2 from './_demo2.vue'
import Demo3 from './_demo3.vue'
import Demo4 from './_demo4.vue'
</script>
<template>
<div>
<FaPageHeader title="复选框组" description="FaCheckboxGroup" />
<FaPageMain main-class="p-4">
<Demo1 />
</FaPageMain>
<FaPageMain title="带描述和禁用态" main-class="p-4">
<Demo2 />
</FaPageMain>
<FaPageMain title="自定义选项内容" main-class="p-4">
<Demo3 />
</FaPageMain>
<FaPageMain title="最少 / 最多选择" main-class="p-4">
<Demo4 />
</FaPageMain>
</div>
</template>
@@ -11,6 +11,7 @@ const options = [
<template>
<div class="gap-4 grid">
<FaRadioGroup v-model="value" :options="options" />
<FaRadioGroup v-model="value" :options="options" class="flex" />
<div class="text-sm text-muted-foreground">
当前值:{{ value }}
</div>
@@ -32,7 +32,6 @@ const currentLabel = computed(() =>
:options="options"
class="gap-4 md:grid-cols-3"
option-class="rounded-xl border border-transparent px-1 py-1"
item-class="mt-1"
>
<template #option="{ option, checked, disabled }">
<div