form-create: 完善 select 远程搜索
This commit is contained in:
parent
40fe87920b
commit
9cde488577
@ -46,43 +46,88 @@ export const useApiSelect = (option: ApiSelectProps) => {
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否远程搜索
|
||||
remote: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 远程搜索时携带的参数
|
||||
remoteField: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const attrs = useAttrs()
|
||||
const options = ref<any[]>([]) // 下拉数据
|
||||
const loading = ref(false) // 是否正在从远程获取数据
|
||||
const queryParam = ref<any>() // 当前输入的值
|
||||
const getOptions = async () => {
|
||||
options.value = []
|
||||
// 接口选择器
|
||||
if (isEmpty(props.url)) {
|
||||
return
|
||||
}
|
||||
let data = []
|
||||
switch (props.method) {
|
||||
case 'GET':
|
||||
data = await request.get({ url: props.url })
|
||||
let url: string = props.url
|
||||
if (props.remote) {
|
||||
url = `${url}?${props.remoteField}=${queryParam.value}`
|
||||
}
|
||||
parseOptions(await request.get({ url: url }))
|
||||
break
|
||||
case 'POST':
|
||||
data = await request.post({ url: props.url, data: jsonParse(props.data) })
|
||||
const data: any = jsonParse(props.data)
|
||||
if (props.remote) {
|
||||
data[props.remoteField] = queryParam.value
|
||||
}
|
||||
parseOptions(await request.post({ url: props.url, data: data }))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
let parse: any = null
|
||||
if (!!props.parseFunc) {
|
||||
// 解析字符串函数
|
||||
parse = new Function(`return ${props.parseFunc}`)()
|
||||
}
|
||||
options.value = data.map(
|
||||
(item: any) =>
|
||||
parse?.(item) ?? {
|
||||
label: parseExpression(item, props.labelField),
|
||||
value: parseExpression(item, props.valueField)
|
||||
}
|
||||
)
|
||||
function parseOptions(data: any) {
|
||||
// 情况一:如果有自定义解析函数优先使用自定义解析
|
||||
if (!isEmpty(props.parseFunc)) {
|
||||
options.value = parseFunc()?.(data)
|
||||
return
|
||||
}
|
||||
console.log(`接口[${props.url}] 返回结果不是一个数组`)
|
||||
// 情况二:返回的直接是一个列表
|
||||
if (Array.isArray(data)) {
|
||||
parseOptions0(data)
|
||||
return
|
||||
}
|
||||
// 情况二:返回的是分页数据,尝试读取 list
|
||||
data = data.list
|
||||
if (!!data && Array.isArray(data)) {
|
||||
parseOptions0(data)
|
||||
return
|
||||
}
|
||||
// 情况三:不是 yudao-vue-pro 标准返回
|
||||
console.warn(
|
||||
`接口[${props.url}] 返回结果不是 yudao-vue-pro 标准返回建议采用自定义解析函数处理`
|
||||
)
|
||||
}
|
||||
|
||||
function parseOptions0(data: any[]) {
|
||||
if (Array.isArray(data)) {
|
||||
options.value = data.map((item: any) => ({
|
||||
label: parseExpression(item, props.labelField),
|
||||
value: parseExpression(item, props.valueField)
|
||||
}))
|
||||
return
|
||||
}
|
||||
console.warn(`接口[${props.url}] 返回结果不是一个数组`)
|
||||
}
|
||||
|
||||
function parseFunc() {
|
||||
let parse: any = null
|
||||
if (!!props.parseFunc) {
|
||||
// 解析字符串函数
|
||||
parse = new Function(`return ${props.parseFunc}`)()
|
||||
}
|
||||
return parse
|
||||
}
|
||||
|
||||
function parseExpression(data: any, template: string) {
|
||||
@ -105,6 +150,19 @@ export const useApiSelect = (option: ApiSelectProps) => {
|
||||
})
|
||||
}
|
||||
|
||||
const remoteMethod = async (query: any) => {
|
||||
if (!query) {
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
queryParam.value = query
|
||||
await getOptions()
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await getOptions()
|
||||
})
|
||||
@ -113,15 +171,29 @@ export const useApiSelect = (option: ApiSelectProps) => {
|
||||
if (props.multiple) {
|
||||
// fix:多写此步是为了解决 multiple 属性问题
|
||||
return (
|
||||
<el-select class="w-1/1" {...attrs} multiple>
|
||||
<el-select
|
||||
class="w-1/1"
|
||||
multiple
|
||||
loading={loading.value}
|
||||
{...attrs}
|
||||
remote={props.remote}
|
||||
{...(props.remote && { remoteMethod: remoteMethod })}
|
||||
>
|
||||
{options.value.map((item, index) => (
|
||||
<el-option key={index} label={item.label} value={item.value} />
|
||||
))}
|
||||
</el-select>
|
||||
)
|
||||
}
|
||||
debugger
|
||||
return (
|
||||
<el-select class="w-1/1" {...attrs}>
|
||||
<el-select
|
||||
class="w-1/1"
|
||||
loading={loading.value}
|
||||
{...attrs}
|
||||
remote={props.remote}
|
||||
{...(props.remote && { remoteMethod: remoteMethod })}
|
||||
>
|
||||
{options.value.map((item, index) => (
|
||||
<el-option key={index} label={item.label} value={item.value} />
|
||||
))}
|
||||
|
@ -15,7 +15,20 @@ const selectRule = [
|
||||
value: 'select',
|
||||
condition: '==',
|
||||
method: 'hidden',
|
||||
rule: ['multiple']
|
||||
rule: [
|
||||
'multiple',
|
||||
'clearable',
|
||||
'collapseTags',
|
||||
'multipleLimit',
|
||||
'allowCreate',
|
||||
'filterable',
|
||||
'noMatchText',
|
||||
'remote',
|
||||
'remoteMethod',
|
||||
'reserveKeyword',
|
||||
'defaultFirstOption',
|
||||
'automaticDropdown'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -60,9 +73,10 @@ const selectRule = [
|
||||
title: '其中的选项是否从服务器远程加载'
|
||||
},
|
||||
{
|
||||
type: 'Struct',
|
||||
field: 'remoteMethod',
|
||||
title: '自定义远程搜索方法'
|
||||
type: 'input',
|
||||
field: 'remoteField',
|
||||
title: '请求参数',
|
||||
info: '远程请求时请求携带的参数名称,如:name'
|
||||
},
|
||||
{ type: 'input', field: 'noDataText', title: '选项为空时显示的文字' },
|
||||
{
|
||||
@ -130,6 +144,7 @@ const apiSelectRule = [
|
||||
type: 'input',
|
||||
field: 'labelField',
|
||||
title: 'label 属性',
|
||||
info: '可以使用 el 表达式:${属性},来实现复杂数据组合。如:${nickname}-${id}',
|
||||
props: {
|
||||
placeholder: 'nickname'
|
||||
}
|
||||
@ -138,6 +153,7 @@ const apiSelectRule = [
|
||||
type: 'input',
|
||||
field: 'valueField',
|
||||
title: 'value 属性',
|
||||
info: '可以使用 el 表达式:${属性},来实现复杂数据组合。如:${nickname}-${id}',
|
||||
props: {
|
||||
placeholder: 'id'
|
||||
}
|
||||
@ -146,11 +162,17 @@ const apiSelectRule = [
|
||||
type: 'input',
|
||||
field: 'parseFunc',
|
||||
title: '选项解析函数',
|
||||
info: '(data: any)=>{ label: string; value: any }',
|
||||
info: `data 为接口返回值,需要写一个匿名函数解析返回值为选择器 options 列表
|
||||
(data: any)=>{ label: string; value: any }[]`,
|
||||
props: {
|
||||
autosize: true,
|
||||
rows: { minRows: 2, maxRows: 6 },
|
||||
type: 'textarea'
|
||||
type: 'textarea',
|
||||
placeholder: `
|
||||
function (data) {
|
||||
console.log(data)
|
||||
return data.list.map(item=> ({label: item.nickname,value: item.id}))
|
||||
}`
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -2,6 +2,7 @@ import { generateUUID } from '@/utils'
|
||||
import * as DictDataApi from '@/api/system/dict/dict.type'
|
||||
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
|
||||
import { selectRule } from '@/components/FormCreate/src/config/selectRule'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
/**
|
||||
* 字典选择器规则,如果规则使用到动态数据则需要单独配置不能使用 useSelectRule
|
||||
@ -9,6 +10,7 @@ import { selectRule } from '@/components/FormCreate/src/config/selectRule'
|
||||
export const useDictSelectRule = () => {
|
||||
const label = '字典选择器'
|
||||
const name = 'DictSelect'
|
||||
const rules = cloneDeep(selectRule)
|
||||
const dictOptions = ref<{ label: string; value: string }[]>([]) // 字典类型下拉数据
|
||||
onMounted(async () => {
|
||||
const data = await DictDataApi.getSimpleDictTypeList()
|
||||
@ -55,7 +57,7 @@ export const useDictSelectRule = () => {
|
||||
{ label: '布尔值', value: 'bool' }
|
||||
]
|
||||
},
|
||||
...selectRule
|
||||
...rules
|
||||
])
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { generateUUID } from '@/utils'
|
||||
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
|
||||
import { selectRule } from '@/components/FormCreate/src/config/selectRule'
|
||||
import { SelectRuleOption } from '@/components/FormCreate/src/type'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
/**
|
||||
* 通用选择器规则 hook
|
||||
@ -10,6 +11,7 @@ import { SelectRuleOption } from '@/components/FormCreate/src/type'
|
||||
export const useSelectRule = (option: SelectRuleOption) => {
|
||||
const label = option.label
|
||||
const name = option.name
|
||||
const rules = cloneDeep(selectRule)
|
||||
return {
|
||||
icon: option.icon,
|
||||
label,
|
||||
@ -27,7 +29,7 @@ export const useSelectRule = (option: SelectRuleOption) => {
|
||||
if (!option.props) {
|
||||
option.props = []
|
||||
}
|
||||
return localeProps(t, name + '.props', [makeRequiredRule(), ...option.props, ...selectRule])
|
||||
return localeProps(t, name + '.props', [makeRequiredRule(), ...option.props, ...rules])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,63 +16,3 @@ export const localeProps = (t, prefix, rules) => {
|
||||
return rule
|
||||
})
|
||||
}
|
||||
|
||||
export function upper(str) {
|
||||
return str.replace(str[0], str[0].toLocaleUpperCase())
|
||||
}
|
||||
|
||||
export function makeOptionsRule(t, to, userOptions) {
|
||||
console.log(userOptions[0])
|
||||
const options = [
|
||||
{ label: t('props.optionsType.struct'), value: 0 },
|
||||
{ label: t('props.optionsType.json'), value: 1 },
|
||||
{ label: '用户数据', value: 2 }
|
||||
]
|
||||
|
||||
const control = [
|
||||
{
|
||||
value: 0,
|
||||
rule: [
|
||||
{
|
||||
type: 'TableOptions',
|
||||
field: 'formCreate' + upper(to).replace('.', '>'),
|
||||
props: { defaultValue: [] }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
rule: [
|
||||
{
|
||||
type: 'Struct',
|
||||
field: 'formCreate' + upper(to).replace('.', '>'),
|
||||
props: { defaultValue: [] }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
rule: [
|
||||
{
|
||||
type: 'TableOptions',
|
||||
field: 'formCreate' + upper(to).replace('.', '>'),
|
||||
props: { modelValue: [] }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
options.splice(0, 0)
|
||||
control.push()
|
||||
|
||||
return {
|
||||
type: 'radio',
|
||||
title: t('props.options'),
|
||||
field: '_optionType',
|
||||
value: 0,
|
||||
options,
|
||||
props: {
|
||||
type: 'button'
|
||||
},
|
||||
control
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user