Form Basic 基础表单
详情 / 抽屉 / 弹窗中的基础表单控件示例。基础表单控件请直接使用 Element Plus;圆角、边框等视觉由 @rd-element/ui 全局 form-controls.css 统一。复合控件用库内 RdCreatableSelect / RdFilterCascader / RdOrgHierarchySearch 等。
基础控件
下拉(含选项图标)、多选、单选与开关。
单选下拉(图标组合)
<script setup lang="ts">
import { ref, computed } from 'vue'
import { Mail, Eye, CheckCircle, Archive, Search, X } from '@lucide/vue'
const demoSelect = ref('Communicated')
const demoCheckbox = ref(['a'])
const demoRadio = ref('a')
const demoSwitch = ref(true)
const demoSelectIconOptions = [
{ label: '已沟通', value: 'Communicated', icon: Mail },
{ label: '已识别', value: 'Identified', icon: Eye },
{ label: '已解决', value: 'Resolved', icon: CheckCircle },
{ label: '已关闭', value: 'Closed', icon: Archive },
{ label: '未识别', value: 'Not Identified', icon: Search },
{ label: '已取消', value: 'Cancelled', icon: X },
]
const demoSelectIconOption = computed(() =>
demoSelectIconOptions.find((o) => o.value === demoSelect.value),
)
</script>
<template>
<div class="demo-stack">
<div class="select-demo">
<span class="select-demo__label">单选下拉(图标组合)</span>
<el-select
v-model="demoSelect"
filterable
clearable
placeholder="请选择状态"
class="select-demo__control"
popper-class="app-select-icon-popper"
>
<template #prefix>
<component :is="demoSelectIconOption?.icon" v-if="demoSelectIconOption" :size="14" class="app-select-option__icon" />
</template>
<template #label="{ label }">
<span class="app-select-option app-select-option--trigger">
<span class="app-select-option__label">{{ label }}</span>
</span>
</template>
<el-option v-for="opt in demoSelectIconOptions" :key="opt.value" :label="opt.label" :value="opt.value">
<span class="app-select-option">
<component :is="opt.icon" :size="14" class="app-select-option__icon" />
<span class="app-select-option__label">{{ opt.label }}</span>
</span>
</el-option>
</el-select>
</div>
<el-checkbox-group v-model="demoCheckbox">
<el-checkbox value="a">选项 A</el-checkbox>
<el-checkbox value="b">选项 B</el-checkbox>
</el-checkbox-group>
<el-radio-group v-model="demoRadio">
<el-radio value="a">单选 A</el-radio>
<el-radio value="b">单选 B</el-radio>
</el-radio-group>
<el-switch v-model="demoSwitch" />
</div>
</template>表单验证
对齐业务「新建客户」弹窗:el-form + rules;控件换库内 RdDialog / RdCreatableSelect / RdFilterCascader / RdOrgHierarchySearch / RdGroupedCategorySelect / RdFileUpload。
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import {
RdDialog,
RdCreatableSelect,
RdFilterCascader,
RdOrgHierarchySearch,
RdGroupedCategorySelect,
RdFileUpload,
toast,
type OrgNode,
type CascaderOption,
type CategoryGroup,
type UploadFileItem,
} from '@rd-element/ui'
const visible = ref(false)
const formRef = ref<FormInstance>()
const submitting = ref(false)
const attachments = ref<UploadFileItem[]>([])
const form = reactive({
company: '',
contact: '',
email: '',
phone: '',
status: 'Prospect',
tier: 'Business',
industry: '',
regionPath: [] as string[],
ownerOrgPaths: null as string[][] | null,
productInterests: [] as string[],
materials: [] as (string | number)[],
isKeyAccount: false,
remark: '',
})
const rules: FormRules = {
company: [{ required: true, message: '请输入公司名称', trigger: 'blur' }],
contact: [{ required: true, message: '请输入联系人姓名', trigger: 'blur' }],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' },
],
status: [{ required: true, message: '请选择客户状态', trigger: 'change' }],
tier: [{ required: true, message: '请选择客户等级', trigger: 'change' }],
}
const regionOptions: CascaderOption[] = [
{ label: '亚太', value: 'apac', children: [{ label: 'Singapore', value: 'SG' }] },
]
const orgOptions: OrgNode[] = [
{ label: 'RD', value: '1-1', type: 'business_group', children: [
{ label: '财务部', value: '1-3', type: 'department' },
]},
]
const categoryGroups: CategoryGroup[] = [
{ key: 'metal', label: '金属', children: [{ value: 'gold', label: '黄金' }] },
]
async function submit() {
const valid = await formRef.value?.validate().catch(() => false)
if (!valid) return
toast.success('校验通过', form.company)
visible.value = false
}
</script>
<template>
<el-button type="primary" @click="visible = true">打开新建客户</el-button>
<RdDialog v-model:visible="visible" title="新增客户" description="填写客户基本信息" width="720px">
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" class="rd-form-validate">
<el-form-item label="公司名称" prop="company">
<el-input v-model="form.company" placeholder="请输入公司全称" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" type="email" placeholder="name@company.com" />
</el-form-item>
<el-form-item label="行业">
<RdCreatableSelect v-model="form.industry" :options="[{ label: 'Electronics', value: 'Electronics' }]" />
</el-form-item>
<el-form-item label="所在地区">
<RdFilterCascader v-model="form.regionPath" :options="regionOptions" />
</el-form-item>
<el-form-item label="负责人">
<RdOrgHierarchySearch v-model="form.ownerOrgPaths" :options="orgOptions" />
</el-form-item>
<el-form-item label="材料">
<RdGroupedCategorySelect v-model="form.materials" :options="categoryGroups" multiple />
</el-form-item>
<el-form-item label="附件">
<RdFileUpload v-model="attachments" :max-count="5" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" :loading="submitting" @click="submit">创建客户</el-button>
</template>
</RdDialog>
</template>推荐组件
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
el-form + rules | 表单校验(必填、邮箱等) | Element Plus | — |
el-select / el-input / el-radio / el-switch | 基础控件 | Element Plus | — |
RdDialog | 新建客户等弹层容器 | @rd-element/ui | — |
RdCreatableSelect | 可创建下拉 | @rd-element/ui | — |
RdFilterCascader | 地区级联 | @rd-element/ui | — |
RdOrgHierarchySearch | 组织负责人 | @rd-element/ui | — |
RdGroupedCategorySelect | 分组材料选择 | @rd-element/ui | — |
RdFileUpload | 附件上传 | @rd-element/ui | — |