Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
be13eb1d
authored
May 10, 2024
by
芋道源码
Committed by
Gitee
May 10, 2024
Browse files
Options
Browse Files
Download
Plain Diff
!446 form-create: 优化 select options 解析,增加 el 表达式解析、自定义函数解析
Merge pull request !446 from puhui999/dev-crm
parents
02fe7e31
cb82578b
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
170 additions
and
88 deletions
+170
-88
src/components/FormCreate/src/components/useApiSelect.tsx
+113
-8
src/components/FormCreate/src/config/selectRule.ts
+51
-17
src/components/FormCreate/src/config/useDictSelectRule.ts
+3
-1
src/components/FormCreate/src/config/useSelectRule.ts
+3
-1
src/components/FormCreate/src/utils/index.ts
+0
-61
No files found.
src/components/FormCreate/src/components/useApiSelect.tsx
View file @
be13eb1d
...
@@ -27,6 +27,11 @@ export const useApiSelect = (option: ApiSelectProps) => {
...
@@ -27,6 +27,11 @@ export const useApiSelect = (option: ApiSelectProps) => {
type
:
String
,
type
:
String
,
default
:
'GET'
default
:
'GET'
},
},
// 选项解析函数
parseFunc
:
{
type
:
String
,
default
:
''
},
// 请求参数
// 请求参数
data
:
{
data
:
{
type
:
String
,
type
:
String
,
...
@@ -41,35 +46,121 @@ export const useApiSelect = (option: ApiSelectProps) => {
...
@@ -41,35 +46,121 @@ export const useApiSelect = (option: ApiSelectProps) => {
multiple
:
{
multiple
:
{
type
:
Boolean
,
type
:
Boolean
,
default
:
false
default
:
false
},
// 是否远程搜索
remote
:
{
type
:
Boolean
,
default
:
false
},
// 远程搜索时携带的参数
remoteField
:
{
type
:
String
,
default
:
'label'
}
}
},
},
setup
(
props
)
{
setup
(
props
)
{
const
attrs
=
useAttrs
()
const
attrs
=
useAttrs
()
const
options
=
ref
<
any
[]
>
([])
// 下拉数据
const
options
=
ref
<
any
[]
>
([])
// 下拉数据
const
loading
=
ref
(
false
)
// 是否正在从远程获取数据
const
queryParam
=
ref
<
any
>
()
// 当前输入的值
const
getOptions
=
async
()
=>
{
const
getOptions
=
async
()
=>
{
options
.
value
=
[]
options
.
value
=
[]
// 接口选择器
// 接口选择器
if
(
isEmpty
(
props
.
url
))
{
if
(
isEmpty
(
props
.
url
))
{
return
return
}
}
let
data
=
[]
switch
(
props
.
method
)
{
switch
(
props
.
method
)
{
case
'GET'
:
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
break
case
'POST'
:
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
break
}
}
}
function
parseOptions
(
data
:
any
)
{
// 情况一:如果有自定义解析函数优先使用自定义解析
if
(
!
isEmpty
(
props
.
parseFunc
))
{
options
.
value
=
parseFunc
()?.(
data
)
return
}
// 情况二:返回的直接是一个列表
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
))
{
if
(
Array
.
isArray
(
data
))
{
options
.
value
=
data
.
map
((
item
:
any
)
=>
({
options
.
value
=
data
.
map
((
item
:
any
)
=>
({
label
:
item
[
props
.
labelField
]
,
label
:
parseExpression
(
item
,
props
.
labelField
)
,
value
:
item
[
props
.
valueField
]
value
:
parseExpression
(
item
,
props
.
valueField
)
}))
}))
return
return
}
}
console
.
error
(
`接口[
${
props
.
url
}
] 返回结果不是一个数组`
)
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
)
{
// 检测是否使用了表达式
if
(
template
.
indexOf
(
'${'
)
===
-
1
)
{
return
data
[
template
]
}
// 正则表达式匹配模板字符串中的 ${...}
const
pattern
=
/
\$\{([^
}
]
*
)
}/g
// 使用replace函数配合正则表达式和回调函数来进行替换
return
template
.
replace
(
pattern
,
(
_
,
expr
)
=>
{
// expr 是匹配到的 ${} 内的表达式(这里是属性名),从 data 中获取对应的值
const
result
=
data
[
expr
.
trim
()]
// 去除前后空白,以防用户输入带空格的属性名
if
(
!
result
)
{
console
.
warn
(
`接口选择器选项模版[
${
template
}
][
${
expr
.
trim
()}
] 解析值失败结果为[
${
result
}
], 请检查属性名称是否存在于接口返回值中,存在则忽略此条!!!`
)
}
return
result
})
}
const
remoteMethod
=
async
(
query
:
any
)
=>
{
if
(
!
query
)
{
return
}
loading
.
value
=
true
try
{
queryParam
.
value
=
query
await
getOptions
()
}
finally
{
loading
.
value
=
false
}
}
}
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
...
@@ -80,15 +171,29 @@ export const useApiSelect = (option: ApiSelectProps) => {
...
@@ -80,15 +171,29 @@ export const useApiSelect = (option: ApiSelectProps) => {
if
(
props
.
multiple
)
{
if
(
props
.
multiple
)
{
// fix:多写此步是为了解决 multiple 属性问题
// fix:多写此步是为了解决 multiple 属性问题
return
(
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
)
=>
(
{
options
.
value
.
map
((
item
,
index
)
=>
(
<
el
-
option
key=
{
index
}
label=
{
item
.
label
}
value=
{
item
.
value
}
/>
<
el
-
option
key=
{
index
}
label=
{
item
.
label
}
value=
{
item
.
value
}
/>
))
}
))
}
</
el
-
select
>
</
el
-
select
>
)
)
}
}
debugger
return
(
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
)
=>
(
{
options
.
value
.
map
((
item
,
index
)
=>
(
<
el
-
option
key=
{
index
}
label=
{
item
.
label
}
value=
{
item
.
value
}
/>
<
el
-
option
key=
{
index
}
label=
{
item
.
label
}
value=
{
item
.
value
}
/>
))
}
))
}
...
...
src/components/FormCreate/src/config/selectRule.ts
View file @
be13eb1d
...
@@ -13,12 +13,30 @@ const selectRule = [
...
@@ -13,12 +13,30 @@ const selectRule = [
control
:
[
control
:
[
{
{
value
:
'select'
,
value
:
'select'
,
condition
:
'='
,
condition
:
'=
=
'
,
method
:
'hidden'
,
method
:
'hidden'
,
rule
:
[
'multiple'
]
rule
:
[
'multiple'
,
'clearable'
,
'collapseTags'
,
'multipleLimit'
,
'allowCreate'
,
'filterable'
,
'noMatchText'
,
'remote'
,
'remoteMethod'
,
'reserveKeyword'
,
'defaultFirstOption'
,
'automaticDropdown'
]
}
}
]
]
},
},
{
type
:
'switch'
,
field
:
'filterable'
,
title
:
'是否可搜索'
},
{
type
:
'switch'
,
field
:
'multiple'
,
title
:
'是否多选'
},
{
type
:
'switch'
,
field
:
'multiple'
,
title
:
'是否多选'
},
{
{
type
:
'switch'
,
type
:
'switch'
,
...
@@ -43,27 +61,12 @@ const selectRule = [
...
@@ -43,27 +61,12 @@ const selectRule = [
title
:
'autocomplete 属性'
title
:
'autocomplete 属性'
},
},
{
type
:
'input'
,
field
:
'placeholder'
,
title
:
'占位符'
},
{
type
:
'input'
,
field
:
'placeholder'
,
title
:
'占位符'
},
{
type
:
'switch'
,
field
:
'filterable'
,
title
:
'是否可搜索'
},
{
type
:
'switch'
,
field
:
'allowCreate'
,
title
:
'是否允许用户创建新条目'
},
{
type
:
'switch'
,
field
:
'allowCreate'
,
title
:
'是否允许用户创建新条目'
},
{
{
type
:
'input'
,
type
:
'input'
,
field
:
'noMatchText'
,
field
:
'noMatchText'
,
title
:
'搜索条件无匹配时显示的文字'
title
:
'搜索条件无匹配时显示的文字'
},
},
{
type
:
'switch'
,
field
:
'remote'
,
title
:
'其中的选项是否从服务器远程加载'
},
{
type
:
'Struct'
,
field
:
'remoteMethod'
,
title
:
'自定义远程搜索方法'
},
{
type
:
'input'
,
field
:
'noDataText'
,
title
:
'选项为空时显示的文字'
},
{
type
:
'input'
,
field
:
'noDataText'
,
title
:
'选项为空时显示的文字'
},
{
{
type
:
'switch'
,
type
:
'switch'
,
...
@@ -130,6 +133,7 @@ const apiSelectRule = [
...
@@ -130,6 +133,7 @@ const apiSelectRule = [
type
:
'input'
,
type
:
'input'
,
field
:
'labelField'
,
field
:
'labelField'
,
title
:
'label 属性'
,
title
:
'label 属性'
,
info
:
'可以使用 el 表达式:${属性},来实现复杂数据组合。如:${nickname}-${id}'
,
props
:
{
props
:
{
placeholder
:
'nickname'
placeholder
:
'nickname'
}
}
...
@@ -138,9 +142,39 @@ const apiSelectRule = [
...
@@ -138,9 +142,39 @@ const apiSelectRule = [
type
:
'input'
,
type
:
'input'
,
field
:
'valueField'
,
field
:
'valueField'
,
title
:
'value 属性'
,
title
:
'value 属性'
,
info
:
'可以使用 el 表达式:${属性},来实现复杂数据组合。如:${nickname}-${id}'
,
props
:
{
props
:
{
placeholder
:
'id'
placeholder
:
'id'
}
}
},
{
type
:
'input'
,
field
:
'parseFunc'
,
title
:
'选项解析函数'
,
info
:
`data 为接口返回值,需要写一个匿名函数解析返回值为选择器 options 列表
(data: any)=>{ label: string; value: any }[]`
,
props
:
{
autosize
:
true
,
rows
:
{
minRows
:
2
,
maxRows
:
6
},
type
:
'textarea'
,
placeholder
:
`
function (data) {
console.log(data)
return data.list.map(item=> ({label: item.nickname,value: item.id}))
}`
}
},
{
type
:
'switch'
,
field
:
'remote'
,
info
:
'是否可搜索'
,
title
:
'其中的选项是否从服务器远程加载'
},
{
type
:
'input'
,
field
:
'remoteField'
,
title
:
'请求参数'
,
info
:
'远程请求时请求携带的参数名称,如:name'
}
}
]
]
...
...
src/components/FormCreate/src/config/useDictSelectRule.ts
View file @
be13eb1d
...
@@ -2,6 +2,7 @@ import { generateUUID } from '@/utils'
...
@@ -2,6 +2,7 @@ import { generateUUID } from '@/utils'
import
*
as
DictDataApi
from
'@/api/system/dict/dict.type'
import
*
as
DictDataApi
from
'@/api/system/dict/dict.type'
import
{
localeProps
,
makeRequiredRule
}
from
'@/components/FormCreate/src/utils'
import
{
localeProps
,
makeRequiredRule
}
from
'@/components/FormCreate/src/utils'
import
{
selectRule
}
from
'@/components/FormCreate/src/config/selectRule'
import
{
selectRule
}
from
'@/components/FormCreate/src/config/selectRule'
import
{
cloneDeep
}
from
'lodash-es'
/**
/**
* 字典选择器规则,如果规则使用到动态数据则需要单独配置不能使用 useSelectRule
* 字典选择器规则,如果规则使用到动态数据则需要单独配置不能使用 useSelectRule
...
@@ -9,6 +10,7 @@ import { selectRule } from '@/components/FormCreate/src/config/selectRule'
...
@@ -9,6 +10,7 @@ import { selectRule } from '@/components/FormCreate/src/config/selectRule'
export
const
useDictSelectRule
=
()
=>
{
export
const
useDictSelectRule
=
()
=>
{
const
label
=
'字典选择器'
const
label
=
'字典选择器'
const
name
=
'DictSelect'
const
name
=
'DictSelect'
const
rules
=
cloneDeep
(
selectRule
)
const
dictOptions
=
ref
<
{
label
:
string
;
value
:
string
}[]
>
([])
// 字典类型下拉数据
const
dictOptions
=
ref
<
{
label
:
string
;
value
:
string
}[]
>
([])
// 字典类型下拉数据
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
const
data
=
await
DictDataApi
.
getSimpleDictTypeList
()
const
data
=
await
DictDataApi
.
getSimpleDictTypeList
()
...
@@ -55,7 +57,7 @@ export const useDictSelectRule = () => {
...
@@ -55,7 +57,7 @@ export const useDictSelectRule = () => {
{
label
:
'布尔值'
,
value
:
'bool'
}
{
label
:
'布尔值'
,
value
:
'bool'
}
]
]
},
},
...
selectRule
...
rules
])
])
}
}
}
}
...
...
src/components/FormCreate/src/config/useSelectRule.ts
View file @
be13eb1d
...
@@ -2,6 +2,7 @@ import { generateUUID } from '@/utils'
...
@@ -2,6 +2,7 @@ import { generateUUID } from '@/utils'
import
{
localeProps
,
makeRequiredRule
}
from
'@/components/FormCreate/src/utils'
import
{
localeProps
,
makeRequiredRule
}
from
'@/components/FormCreate/src/utils'
import
{
selectRule
}
from
'@/components/FormCreate/src/config/selectRule'
import
{
selectRule
}
from
'@/components/FormCreate/src/config/selectRule'
import
{
SelectRuleOption
}
from
'@/components/FormCreate/src/type'
import
{
SelectRuleOption
}
from
'@/components/FormCreate/src/type'
import
{
cloneDeep
}
from
'lodash-es'
/**
/**
* 通用选择器规则 hook
* 通用选择器规则 hook
...
@@ -11,6 +12,7 @@ import { SelectRuleOption } from '@/components/FormCreate/src/type'
...
@@ -11,6 +12,7 @@ import { SelectRuleOption } from '@/components/FormCreate/src/type'
export
const
useSelectRule
=
(
option
:
SelectRuleOption
)
=>
{
export
const
useSelectRule
=
(
option
:
SelectRuleOption
)
=>
{
const
label
=
option
.
label
const
label
=
option
.
label
const
name
=
option
.
name
const
name
=
option
.
name
const
rules
=
cloneDeep
(
selectRule
)
return
{
return
{
icon
:
option
.
icon
,
icon
:
option
.
icon
,
label
,
label
,
...
@@ -28,7 +30,7 @@ export const useSelectRule = (option: SelectRuleOption) => {
...
@@ -28,7 +30,7 @@ export const useSelectRule = (option: SelectRuleOption) => {
if
(
!
option
.
props
)
{
if
(
!
option
.
props
)
{
option
.
props
=
[]
option
.
props
=
[]
}
}
return
localeProps
(
t
,
name
+
'.props'
,
[
makeRequiredRule
(),
...
option
.
props
,
...
selectRule
])
return
localeProps
(
t
,
name
+
'.props'
,
[
makeRequiredRule
(),
...
option
.
props
,
...
rules
])
}
}
}
}
}
}
src/components/FormCreate/src/utils/index.ts
View file @
be13eb1d
// TODO puhui999: 借鉴一下 form-create-designer utils 方法 🤣 (导入不了只能先 copy 过来用下)
export
function
makeRequiredRule
()
{
export
function
makeRequiredRule
()
{
return
{
return
{
type
:
'Required'
,
type
:
'Required'
,
...
@@ -17,63 +16,3 @@ export const localeProps = (t, prefix, rules) => {
...
@@ -17,63 +16,3 @@ export const localeProps = (t, prefix, rules) => {
return
rule
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
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment