|
|
@@ -0,0 +1,278 @@
|
|
|
+<!-- 表单示例 -->
|
|
|
+<template>
|
|
|
+ <div class="form-example">
|
|
|
+ <h2 class="title">表单组件示例</h2>
|
|
|
+
|
|
|
+ <ElCard class="art-custom-card" shadow="never">
|
|
|
+ <ArtForm
|
|
|
+ ref="formRef"
|
|
|
+ v-model="formData"
|
|
|
+ :items="formItems"
|
|
|
+ :rules="formRules"
|
|
|
+ :defaultExpanded="true"
|
|
|
+ :labelWidth="labelWidth"
|
|
|
+ :labelPosition="labelPosition"
|
|
|
+ :span="span"
|
|
|
+ :gutter="gutter"
|
|
|
+ @reset="handleReset"
|
|
|
+ @submit="handleSubmit"
|
|
|
+ >
|
|
|
+ <template #slots>
|
|
|
+ <ElInput v-model="formData.slots" placeholder="我是插槽渲染出来的组件" />
|
|
|
+ </template>
|
|
|
+ </ArtForm>
|
|
|
+ </ElCard>
|
|
|
+
|
|
|
+ <div class="code">
|
|
|
+ <pre><code>{{ formData }}</code></pre>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+ import { SearchFormItem } from '@/components/core/forms/art-search-bar/index.vue'
|
|
|
+ import { ElMessage, ElUpload, ElButton } from 'element-plus'
|
|
|
+ import type { UploadFile, UploadFiles, UploadUserFile } from 'element-plus'
|
|
|
+
|
|
|
+ interface Emits {
|
|
|
+ (e: 'update:modelValue', value: Record<string, any>): void
|
|
|
+ (e: 'search', params: Record<string, any>): void
|
|
|
+ (e: 'reset'): void
|
|
|
+ }
|
|
|
+ const emit = defineEmits<Emits>()
|
|
|
+
|
|
|
+ // 表单数据双向绑定
|
|
|
+ const formRef = ref()
|
|
|
+
|
|
|
+ // 表单数据
|
|
|
+ const formData = ref({
|
|
|
+ name: undefined,
|
|
|
+ phone: undefined,
|
|
|
+ level: undefined,
|
|
|
+ address: undefined,
|
|
|
+ slots: undefined,
|
|
|
+ date: undefined,
|
|
|
+ daterange: undefined,
|
|
|
+ cascader: undefined,
|
|
|
+ checkboxgroup: undefined,
|
|
|
+ userGender: undefined,
|
|
|
+ iconSelector: undefined,
|
|
|
+ status: undefined,
|
|
|
+ systemName: undefined,
|
|
|
+ fileUpload: [] as UploadUserFile[],
|
|
|
+ imageUpload: [] as UploadUserFile[],
|
|
|
+ multipleFiles: [] as UploadUserFile[],
|
|
|
+ richTextContent: ''
|
|
|
+ })
|
|
|
+
|
|
|
+ // 表单校验规则
|
|
|
+ const formRules = {
|
|
|
+ name: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
|
|
+ phone: [
|
|
|
+ { required: true, message: '请输入手机号', trigger: 'blur' },
|
|
|
+ { min: 11, max: 11, message: '请输入11位手机号', trigger: 'blur' },
|
|
|
+ { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+
|
|
|
+ const labelWidth = ref(100)
|
|
|
+ const labelPosition = ref<'right' | 'left' | 'top'>('right')
|
|
|
+ const span = ref(6)
|
|
|
+ const gutter = ref(12)
|
|
|
+
|
|
|
+ // 动态 options
|
|
|
+ const levelOptions = ref<{ label: string; value: string; disabled?: boolean }[]>([])
|
|
|
+
|
|
|
+ // 共享的选项数据
|
|
|
+ const LEVEL_OPTIONS = [
|
|
|
+ { label: '普通用户', value: 'normal' },
|
|
|
+ { label: 'VIP用户', value: 'vip' },
|
|
|
+ { label: '高级VIP', value: 'svip' },
|
|
|
+ { label: '企业用户', value: 'enterprise', disabled: true }
|
|
|
+ ]
|
|
|
+
|
|
|
+ const GENDER_OPTIONS = [
|
|
|
+ { label: '男', value: '1' },
|
|
|
+ { label: '女', value: '2' }
|
|
|
+ ]
|
|
|
+
|
|
|
+ const DATE_SHORTCUTS = [
|
|
|
+ { text: '今日', value: new Date() },
|
|
|
+ { text: '昨日', value: () => new Date(Date.now() - 86400000) },
|
|
|
+ { text: '一周前', value: () => new Date(Date.now() - 604800000) }
|
|
|
+ ]
|
|
|
+
|
|
|
+ // 创建表单项的工厂函数
|
|
|
+ const createFormItem = (config: any) => config
|
|
|
+
|
|
|
+ // 基础表单项配置
|
|
|
+ const baseFormItems = {
|
|
|
+ username: createFormItem({
|
|
|
+ label: '用户名',
|
|
|
+ key: 'name',
|
|
|
+ type: 'input',
|
|
|
+ placeholder: '请输入用户名',
|
|
|
+ clearable: true
|
|
|
+ }),
|
|
|
+ phone: createFormItem({
|
|
|
+ label: '手机号',
|
|
|
+ key: 'phone',
|
|
|
+ type: 'input',
|
|
|
+ props: { placeholder: '请输入手机号', maxlength: '11' }
|
|
|
+ }),
|
|
|
+ level: createFormItem({
|
|
|
+ label: '用户等级',
|
|
|
+ key: 'level',
|
|
|
+ type: 'select',
|
|
|
+ props: { placeholder: '请选择等级', options: LEVEL_OPTIONS }
|
|
|
+ }),
|
|
|
+ address: createFormItem({
|
|
|
+ label: '地址',
|
|
|
+ key: 'address',
|
|
|
+ type: 'input',
|
|
|
+ placeholder: '请输入地址'
|
|
|
+ }),
|
|
|
+ date: createFormItem({
|
|
|
+ label: '日期',
|
|
|
+ key: 'date',
|
|
|
+ type: 'datetime',
|
|
|
+ props: {
|
|
|
+ style: { width: '100%' },
|
|
|
+ placeholder: '请选择日期',
|
|
|
+ type: 'date',
|
|
|
+ valueFormat: 'YYYY-MM-DD',
|
|
|
+ shortcuts: DATE_SHORTCUTS
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ gender: createFormItem({
|
|
|
+ label: '性别',
|
|
|
+ key: 'userGender',
|
|
|
+ type: 'radiogroup',
|
|
|
+ props: {
|
|
|
+ options: GENDER_OPTIONS
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ const userItem = ref<SearchFormItem>({
|
|
|
+ label: '用户名',
|
|
|
+ key: 'name',
|
|
|
+ type: 'input',
|
|
|
+ props: {
|
|
|
+ placeholder: '请输入用户名',
|
|
|
+ clearable: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 控制用户名字段是否显示
|
|
|
+ const showUserName = ref(true)
|
|
|
+ // 表单配置
|
|
|
+ const formItems = computed(() => [
|
|
|
+ ...(showUserName.value ? [userItem.value] : []),
|
|
|
+ {
|
|
|
+ ...baseFormItems.phone
|
|
|
+ },
|
|
|
+ {
|
|
|
+ ...baseFormItems.level,
|
|
|
+ props: { placeholder: '请选择等级', options: levelOptions.value }
|
|
|
+ },
|
|
|
+ baseFormItems.address,
|
|
|
+ baseFormItems.date,
|
|
|
+
|
|
|
+ {
|
|
|
+ ...baseFormItems.gender
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ label: '是否启用',
|
|
|
+ key: 'isEnabled',
|
|
|
+ type: 'switch',
|
|
|
+ props: {
|
|
|
+ placeholder: '请选择是否启用'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '年龄',
|
|
|
+ key: 'age',
|
|
|
+ type: 'number',
|
|
|
+ slots: {
|
|
|
+ suffix: () => h('span', { style: 'color: #909399; font-size: 12px' }, '岁')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 文件上传示例 - 使用 h 函数渲染
|
|
|
+ {
|
|
|
+ label: '文件上传',
|
|
|
+ key: 'multipleFiles',
|
|
|
+ span: 12,
|
|
|
+ type: () =>
|
|
|
+ h(
|
|
|
+ ElUpload,
|
|
|
+ {
|
|
|
+ multiple: true,
|
|
|
+ limit: 5,
|
|
|
+ action: '#',
|
|
|
+ autoUpload: false,
|
|
|
+ showFileList: true,
|
|
|
+ accept: '.pdf,.mp4,.txt',
|
|
|
+ beforeUpload: (file: File) => {
|
|
|
+ console.log('准备上传文件:', file.name)
|
|
|
+ return true
|
|
|
+ },
|
|
|
+ onChange: (file: UploadFile, fileList: UploadFiles) => {
|
|
|
+ console.log('多文件变化:', file, fileList)
|
|
|
+ formData.value.multipleFiles = fileList as UploadUserFile[]
|
|
|
+ },
|
|
|
+ onRemove: (file: UploadFile, fileList: UploadFiles) => {
|
|
|
+ console.log('删除文件:', file, fileList)
|
|
|
+ formData.value.multipleFiles = fileList as UploadUserFile[]
|
|
|
+ },
|
|
|
+ onExceed: (files: File[], fileList: UploadUserFile[]) => {
|
|
|
+ ElMessage.warning(`最多只能上传 5 个文件,当前选择了 ${files.length + fileList.length} 个文件`)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { default: () => [h(ElButton, { type: 'primary' }, () => '点击上传')] }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ ])
|
|
|
+
|
|
|
+ // 表单处理函数
|
|
|
+ const handleReset = () => {
|
|
|
+ console.log('重置表单')
|
|
|
+ emit('reset')
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleSubmit = async () => {
|
|
|
+ await formRef.value.validate()
|
|
|
+ emit('search', formData.value)
|
|
|
+ console.log('表单数据', formData.value)
|
|
|
+ }
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+ .form-example {
|
|
|
+ padding-bottom: 20px;
|
|
|
+
|
|
|
+ .title {
|
|
|
+ margin-bottom: 5px;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 500;
|
|
|
+
|
|
|
+ &.m-15 {
|
|
|
+ margin-top: 15px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .code {
|
|
|
+ padding: 15px;
|
|
|
+ margin-top: 15px;
|
|
|
+ font-size: 14px;
|
|
|
+ background-color: var(--art-main-bg-color);
|
|
|
+ border: 1px solid var(--art-border-color);
|
|
|
+ border-radius: var(--el-border-radius-base);
|
|
|
+ }
|
|
|
+
|
|
|
+ .button-group {
|
|
|
+ margin-top: 15px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|