Skip to content

Commit 9ede8ff

Browse files
YunaiVgitee-org
authored andcommitted
!413 form-create-designer: 表单组件新增字典选择器和用户选择器
Merge pull request !413 from puhui999/dev-crm
2 parents d05c67f + d16bed4 commit 9ede8ff

File tree

10 files changed

+387
-7
lines changed

10 files changed

+387
-7
lines changed

src/components/DictSelect/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import DictSelect from './src/DictSelect.vue'
2+
3+
export { DictSelect }
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<template>
2+
<el-select class="w-1/1" v-bind="attrs">
3+
<template v-if="valueType === 'int'">
4+
<el-option
5+
v-for="(dict, index) in getIntDictOptions(dictType)"
6+
:key="index"
7+
:label="dict.label"
8+
:value="dict.value"
9+
/>
10+
</template>
11+
<template v-if="valueType === 'str'">
12+
<el-option
13+
v-for="(dict, index) in getStrDictOptions(dictType)"
14+
:key="index"
15+
:label="dict.label"
16+
:value="dict.value"
17+
/>
18+
</template>
19+
<template v-if="valueType === 'bool'">
20+
<el-option
21+
v-for="(dict, index) in getBoolDictOptions(dictType)"
22+
:key="index"
23+
:label="dict.label"
24+
:value="dict.value"
25+
/>
26+
</template>
27+
</el-select>
28+
</template>
29+
30+
<script lang="ts" setup>
31+
import { getBoolDictOptions, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
32+
33+
// 接受父组件参数
34+
interface Props {
35+
modelValue?: any //
36+
dictType: string // 字典类型
37+
valueType: string // 字典值类型
38+
}
39+
40+
withDefaults(defineProps<Props>(), {
41+
dictType: '',
42+
valueType: 'str'
43+
})
44+
const attrs = useAttrs()
45+
defineOptions({ name: 'DictSelect' })
46+
</script>
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { useUploadFileRule } from './useUploadFileRule'
22
import { useUploadImgRule } from './useUploadImgRule'
33
import { useUploadImgsRule } from './useUploadImgsRule'
4+
import { useDictSelectRule } from './useDictSelectRule'
5+
import { useUserSelectRule } from './useUserSelectRule'
46

5-
export { useUploadFileRule, useUploadImgRule, useUploadImgsRule }
7+
export {
8+
useUploadFileRule,
9+
useUploadImgRule,
10+
useUploadImgsRule,
11+
useDictSelectRule,
12+
useUserSelectRule
13+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { generateUUID } from '@/utils'
2+
import * as DictDataApi from '@/api/system/dict/dict.type'
3+
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
4+
5+
export const useDictSelectRule = () => {
6+
const label = '字典选择器'
7+
const name = 'DictSelect'
8+
const dictOptions = ref<{ label: string; value: string }[]>([]) // 字典类型下拉数据
9+
onMounted(async () => {
10+
const data = await DictDataApi.getSimpleDictTypeList()
11+
if (!data || data.length === 0) {
12+
return
13+
}
14+
dictOptions.value =
15+
data?.map((item: DictDataApi.DictTypeVO) => ({
16+
label: item.name,
17+
value: item.type
18+
})) ?? []
19+
})
20+
return {
21+
icon: 'icon-select',
22+
label,
23+
name,
24+
rule() {
25+
return {
26+
type: name,
27+
field: generateUUID(),
28+
title: label,
29+
info: '',
30+
$required: false
31+
}
32+
},
33+
props(_, { t }) {
34+
return localeProps(t, name + '.props', [
35+
makeRequiredRule(),
36+
{
37+
type: 'select',
38+
field: 'dictType',
39+
title: '字典类型',
40+
value: '',
41+
options: dictOptions.value
42+
},
43+
{
44+
type: 'select',
45+
field: 'valueType',
46+
title: '字典值类型',
47+
value: 'str',
48+
options: [
49+
{ label: '数字', value: 'int' },
50+
{ label: '字符串', value: 'str' },
51+
{ label: '布尔值', value: 'bool' }
52+
]
53+
},
54+
{ type: 'switch', field: 'multiple', title: '是否多选' },
55+
{
56+
type: 'switch',
57+
field: 'disabled',
58+
title: '是否禁用'
59+
},
60+
{ type: 'switch', field: 'clearable', title: '是否可以清空选项' },
61+
{
62+
type: 'switch',
63+
field: 'collapseTags',
64+
title: '多选时是否将选中值按文字的形式展示'
65+
},
66+
{
67+
type: 'inputNumber',
68+
field: 'multipleLimit',
69+
title: '多选时用户最多可以选择的项目数,为 0 则不限制',
70+
props: { min: 0 }
71+
},
72+
{
73+
type: 'input',
74+
field: 'autocomplete',
75+
title: 'autocomplete 属性'
76+
},
77+
{ type: 'input', field: 'placeholder', title: '占位符' },
78+
{
79+
type: 'switch',
80+
field: 'filterable',
81+
title: '是否可搜索'
82+
},
83+
{ type: 'switch', field: 'allowCreate', title: '是否允许用户创建新条目' },
84+
{
85+
type: 'input',
86+
field: 'noMatchText',
87+
title: '搜索条件无匹配时显示的文字'
88+
},
89+
{
90+
type: 'switch',
91+
field: 'remote',
92+
title: '其中的选项是否从服务器远程加载'
93+
},
94+
{
95+
type: 'Struct',
96+
field: 'remoteMethod',
97+
title: '自定义远程搜索方法'
98+
},
99+
{ type: 'input', field: 'noDataText', title: '选项为空时显示的文字' },
100+
{
101+
type: 'switch',
102+
field: 'reserveKeyword',
103+
title: '多选且可搜索时,是否在选中一个选项后保留当前的搜索关键词'
104+
},
105+
{
106+
type: 'switch',
107+
field: 'defaultFirstOption',
108+
title: '在输入框按下回车,选择第一个匹配项'
109+
},
110+
{
111+
type: 'switch',
112+
field: 'popperAppendToBody',
113+
title: '是否将弹出框插入至 body 元素',
114+
value: true
115+
},
116+
{
117+
type: 'switch',
118+
field: 'automaticDropdown',
119+
title: '对于不可搜索的 Select,是否在输入框获得焦点后自动弹出选项菜单'
120+
}
121+
])
122+
}
123+
}
124+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { generateUUID } from '@/utils'
2+
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
3+
4+
export const useUserSelectRule = () => {
5+
const label = '用户选择器'
6+
const name = 'UserSelect'
7+
return {
8+
icon: 'icon-select',
9+
label,
10+
name,
11+
rule() {
12+
return {
13+
type: name,
14+
field: generateUUID(),
15+
title: label,
16+
info: '',
17+
$required: false
18+
}
19+
},
20+
props(_, { t }) {
21+
return localeProps(t, name + '.props', [
22+
makeRequiredRule(),
23+
{ type: 'switch', field: 'multiple', title: '是否多选' },
24+
{
25+
type: 'switch',
26+
field: 'disabled',
27+
title: '是否禁用'
28+
},
29+
{ type: 'switch', field: 'clearable', title: '是否可以清空选项' },
30+
{
31+
type: 'switch',
32+
field: 'collapseTags',
33+
title: '多选时是否将选中值按文字的形式展示'
34+
},
35+
{
36+
type: 'inputNumber',
37+
field: 'multipleLimit',
38+
title: '多选时用户最多可以选择的项目数,为 0 则不限制',
39+
props: { min: 0 }
40+
},
41+
{
42+
type: 'input',
43+
field: 'autocomplete',
44+
title: 'autocomplete 属性'
45+
},
46+
{ type: 'input', field: 'placeholder', title: '占位符' },
47+
{
48+
type: 'switch',
49+
field: 'filterable',
50+
title: '是否可搜索'
51+
},
52+
{ type: 'switch', field: 'allowCreate', title: '是否允许用户创建新条目' },
53+
{
54+
type: 'input',
55+
field: 'noMatchText',
56+
title: '搜索条件无匹配时显示的文字'
57+
},
58+
{
59+
type: 'switch',
60+
field: 'remote',
61+
title: '其中的选项是否从服务器远程加载'
62+
},
63+
{
64+
type: 'Struct',
65+
field: 'remoteMethod',
66+
title: '自定义远程搜索方法'
67+
},
68+
{ type: 'input', field: 'noDataText', title: '选项为空时显示的文字' },
69+
{
70+
type: 'switch',
71+
field: 'reserveKeyword',
72+
title: '多选且可搜索时,是否在选中一个选项后保留当前的搜索关键词'
73+
},
74+
{
75+
type: 'switch',
76+
field: 'defaultFirstOption',
77+
title: '在输入框按下回车,选择第一个匹配项'
78+
},
79+
{
80+
type: 'switch',
81+
field: 'popperAppendToBody',
82+
title: '是否将弹出框插入至 body 元素',
83+
value: true
84+
},
85+
{
86+
type: 'switch',
87+
field: 'automaticDropdown',
88+
title: '对于不可搜索的 Select,是否在输入框获得焦点后自动弹出选项菜单'
89+
}
90+
])
91+
}
92+
}
93+
}

src/components/FormCreate/src/useFormCreateDesigner.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { useUploadFileRule, useUploadImgRule, useUploadImgsRule } from './config'
1+
import {
2+
useDictSelectRule,
3+
useUploadFileRule,
4+
useUploadImgRule,
5+
useUploadImgsRule,
6+
useUserSelectRule
7+
} from './config'
28
import { Ref } from 'vue'
39

410
/**
@@ -12,11 +18,19 @@ export const useFormCreateDesigner = (designer: Ref) => {
1218
const uploadFileRule = useUploadFileRule()
1319
const uploadImgRule = useUploadImgRule()
1420
const uploadImgsRule = useUploadImgsRule()
21+
const dictSelectRule = useDictSelectRule()
22+
const userSelectRule = useUserSelectRule()
1523

1624
onMounted(() => {
1725
// 移除自带的上传组件规则,使用 uploadFileRule、uploadImgRule、uploadImgsRule 替代
1826
designer.value?.removeMenuItem('upload')
19-
const components = [uploadFileRule, uploadImgRule, uploadImgsRule]
27+
const components = [
28+
uploadFileRule,
29+
uploadImgRule,
30+
uploadImgsRule,
31+
dictSelectRule,
32+
userSelectRule
33+
]
2034
components.forEach((component) => {
2135
// 插入组件规则
2236
designer.value?.addComponent(component)

src/components/FormCreate/src/utils/index.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,63 @@ export const localeProps = (t, prefix, rules) => {
1717
return rule
1818
})
1919
}
20+
21+
export function upper(str) {
22+
return str.replace(str[0], str[0].toLocaleUpperCase())
23+
}
24+
25+
export function makeOptionsRule(t, to, userOptions) {
26+
console.log(userOptions[0])
27+
const options = [
28+
{ label: t('props.optionsType.struct'), value: 0 },
29+
{ label: t('props.optionsType.json'), value: 1 },
30+
{ label: '用户数据', value: 2 }
31+
]
32+
33+
const control = [
34+
{
35+
value: 0,
36+
rule: [
37+
{
38+
type: 'TableOptions',
39+
field: 'formCreate' + upper(to).replace('.', '>'),
40+
props: { defaultValue: [] }
41+
}
42+
]
43+
},
44+
{
45+
value: 1,
46+
rule: [
47+
{
48+
type: 'Struct',
49+
field: 'formCreate' + upper(to).replace('.', '>'),
50+
props: { defaultValue: [] }
51+
}
52+
]
53+
},
54+
{
55+
value: 2,
56+
rule: [
57+
{
58+
type: 'TableOptions',
59+
field: 'formCreate' + upper(to).replace('.', '>'),
60+
props: { modelValue: [] }
61+
}
62+
]
63+
}
64+
]
65+
options.splice(0, 0)
66+
control.push()
67+
68+
return {
69+
type: 'radio',
70+
title: t('props.options'),
71+
field: '_optionType',
72+
value: 0,
73+
options,
74+
props: {
75+
type: 'button'
76+
},
77+
control
78+
}
79+
}

0 commit comments

Comments
 (0)