Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
小 白蛋
Cloudbase Extension Cms
Commits
8f53cdb0
Commit
8f53cdb0
authored
4 years ago
by
cwuyiqing
Browse files
Options
Download
Email Patches
Plain Diff
feat: support connect nest
parent
b5fc32fc
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
packages/admin/src/components/Fields/Connect.tsx
+43
-15
packages/admin/src/components/Fields/Connect.tsx
packages/service/src/modules/file/file.service.ts
+4
-5
packages/service/src/modules/file/file.service.ts
packages/service/src/modules/projects/contents/contents.service.ts
+48
-46
...service/src/modules/projects/contents/contents.service.ts
packages/service/src/modules/projects/schemas/schema.pipe.ts
+3
-3
packages/service/src/modules/projects/schemas/schema.pipe.ts
packages/service/src/modules/projects/schemas/types.ts
+0
-3
packages/service/src/modules/projects/schemas/types.ts
packages/service/src/utils/cloudbase.ts
+2
-1
packages/service/src/utils/cloudbase.ts
packages/service/src/utils/tools.ts
+15
-5
packages/service/src/utils/tools.ts
with
115 additions
and
78 deletions
+115
-78
packages/admin/src/components/Fields/Connect.tsx
+
43
-
15
View file @
8f53cdb0
...
...
@@ -5,6 +5,7 @@ import { useConcent } from 'concent'
import
{
getSchema
}
from
'
@/services/schema
'
import
{
getContents
,
Options
}
from
'
@/services/content
'
import
{
calculateFieldWidth
}
from
'
@/utils
'
import
{
ContentCtx
}
from
'
typings/store
'
const
{
Option
}
=
Select
const
{
Text
,
Paragraph
}
=
Typography
...
...
@@ -13,6 +14,7 @@ interface Doc {
_id
:
string
[
key
:
string
]:
any
}
type
IConnectSingleValue
=
string
|
Doc
type
IConnectMultiValue
=
string
[]
&
Doc
[]
type
IConnectValue
=
IConnectSingleValue
|
IConnectMultiValue
...
...
@@ -27,15 +29,17 @@ export const IConnectRender: React.FC<{
field
:
SchemaField
}
>
=
(
props
)
=>
{
const
{
value
,
field
}
=
props
const
{
connectField
,
connectMany
}
=
field
const
{
connectMany
}
=
field
const
width
=
calculateFieldWidth
(
field
)
const
ctx
=
useConcent
<
{},
ContentCtx
>
(
'
content
'
)
const
{
schemas
}
=
ctx
.
state
if
(
!
value
||
typeof
value
===
'
string
'
||
typeof
value
?.[
0
]
===
'
string
'
)
return
<
span
>
-
</
span
>
if
(
!
connectMany
)
{
return
(
<
Text
ellipsis
style
=
{
{
width
}
}
>
{
value
[
c
onnectField
]
}
{
getC
onnectField
DisplayText
(
value
,
schemas
,
field
)
}
</
Text
>
)
}
...
...
@@ -45,7 +49,7 @@ export const IConnectRender: React.FC<{
{
value
.
filter
((
_
:
any
)
=>
_
)
.
map
((
record
:
any
,
index
:
number
)
=>
(
<
Tag
key
=
{
index
}
>
{
record
?.[
c
onnectField
]
}
</
Tag
>
<
Tag
key
=
{
index
}
>
{
getC
onnectField
DisplayText
(
record
,
schemas
,
field
)
}
</
Tag
>
))
}
</
Paragraph
>
)
...
...
@@ -59,10 +63,11 @@ export const IConnectEditor: React.FC<{
field
:
SchemaField
onChange
?:
(
v
:
string
|
string
[])
=>
void
}
>
=
(
props
)
=>
{
const
{
projectId
}
=
useParams
<
any
>
()
const
ctx
=
useConcent
(
'
content
'
)
const
{
value
=
[],
onChange
,
field
}
=
props
const
{
projectId
}
=
useParams
<
any
>
()
const
ctx
=
useConcent
<
{},
ContentCtx
>
(
'
content
'
)
const
{
connectField
,
connectResource
,
connectMany
}
=
field
const
{
schemas
}
=
ctx
.
state
// 加载关联的文档列表
const
[
docs
,
setDocs
]
=
useState
<
Doc
[]
>
([])
...
...
@@ -72,13 +77,12 @@ export const IConnectEditor: React.FC<{
useRequest
(
async
()
=>
{
setLoading
(
true
)
const
{
schemas
}
=
ctx
.
state
let
schema
=
schemas
.
find
((
_
:
Schema
)
=>
_
.
_id
===
connectResource
)
let
connectSchema
=
schemas
.
find
((
_
:
Schema
)
=>
_
.
_id
===
connectResource
)
// 后台获取 Schema
if
(
!
s
chema
)
{
if
(
!
connectS
chema
)
{
const
{
data
}
=
await
getSchema
(
projectId
,
connectResource
)
s
chema
=
data
connectS
chema
=
data
}
const
fetchOptions
:
Options
=
{
...
...
@@ -92,7 +96,7 @@ export const IConnectEditor: React.FC<{
}
}
const
{
data
}
=
await
getContents
(
projectId
,
s
chema
.
collectionName
,
fetchOptions
)
const
{
data
}
=
await
getContents
(
projectId
,
connectS
chema
.
collectionName
,
fetchOptions
)
setDocs
(
data
)
setLoading
(
false
)
...
...
@@ -130,11 +134,14 @@ export const IConnectEditor: React.FC<{
<
Spin
size
=
"small"
/>
</
Option
>
)
:
docs
?.
length
?
(
docs
?.
map
((
doc
)
=>
(
<
Option
value
=
{
doc
.
_id
}
key
=
{
doc
.
_id
}
>
{
doc
[
connectField
]
}
</
Option
>
))
<>
<
Option
value
=
""
>
空
</
Option
>
{
docs
?.
map
((
doc
)
=>
(
<
Option
value
=
{
doc
.
_id
}
key
=
{
doc
.
_id
}
>
{
getConnectFieldDisplayText
(
doc
,
schemas
,
field
)
}
</
Option
>
))
}
</>
)
:
(
<
Option
value
=
""
disabled
>
空
...
...
@@ -144,6 +151,27 @@ export const IConnectEditor: React.FC<{
)
}
/**
* 处理关联字段的展示信息,可能为多层嵌套
*/
const
getConnectFieldDisplayText
=
(
doc
:
any
,
schemas
:
Schema
[],
field
:
SchemaField
)
=>
{
// 当前关联字段的信息
const
{
connectField
,
connectResource
}
=
field
// 当前关联字段 => 关联 schema 的信息
const
connectedSchema
=
schemas
.
find
((
_
:
Schema
)
=>
_
.
_id
===
connectResource
)
// 关联字段的信息
const
connectedFieldInfo
=
connectedSchema
?.
fields
.
find
((
_
)
=>
_
.
name
===
connectField
)
// 关联的字段,又是一个关联类型,则展示关联字段关联的字段
if
(
connectedFieldInfo
?.
connectResource
)
{
return
doc
[
connectField
][
connectedFieldInfo
.
connectField
]
}
else
{
return
doc
[
connectField
]
}
}
// 将关联的数据转换成关联数据对应的 _id 数据
const
transformConnectValues
=
(
value
:
IConnectValue
,
connectMany
:
boolean
):
string
|
string
[]
=>
{
if
(
connectMany
)
{
...
...
This diff is collapsed.
Click to expand it.
packages/service/src/modules/file/file.service.ts
+
4
-
5
View file @
8f53cdb0
import
path
from
'
path
'
import
dayjs
from
'
dayjs
'
import
{
nanoid
}
from
'
nanoid
'
import
{
IFile
}
from
'
./types
'
import
'
dayjs/locale/zh-cn
'
import
{
Injectable
}
from
'
@nestjs/common
'
import
{
CloudBaseService
}
from
'
@/services
'
import
'
dayjs/locale/zh-cn
'
import
{
randomId
}
from
'
@/utils
'
import
{
IFile
}
from
'
./types
'
// 本地时间
dayjs
.
locale
(
'
zh-cn
'
)
...
...
@@ -31,7 +30,7 @@ export class FileService {
const
day
=
dayjs
().
format
(
'
YYYY-MM-DD
'
)
// 上传文件
const
{
fileID
}
=
await
this
.
cloudbaseService
.
app
.
uploadFile
({
cloudPath
:
`cloudbase-cms/upload/
${
day
}
/
${
n
an
oi
d
(
16
)}
-
${
file
.
originalname
}
`
,
cloudPath
:
`cloudbase-cms/upload/
${
day
}
/
${
r
an
domI
d
(
16
)}
-
${
file
.
originalname
}
`
,
fileContent
:
file
.
buffer
,
})
return
{
...
...
This diff is collapsed.
Click to expand it.
packages/service/src/modules/projects/contents/contents.service.ts
+
48
-
46
View file @
8f53cdb0
...
...
@@ -2,10 +2,15 @@ import _ from 'lodash'
import
R
from
'
ramda
'
import
{
Injectable
}
from
'
@nestjs/common
'
import
{
CloudBaseService
}
from
'
@/services
'
import
{
dateToUnixTimestampInMs
,
formatPayloadDate
}
from
'
@/utils
'
import
{
dateToUnixTimestampInMs
,
formatPayloadDate
,
getCollectionSchema
,
isNotEmpty
,
}
from
'
@/utils
'
import
{
Collection
}
from
'
@/constants
'
import
{
Schema
,
SchemaField
}
from
'
../schemas/types
'
import
{
BadRequestException
,
RecordNotExistException
}
from
'
@/common
'
import
{
Schema
,
SchemaField
}
from
'
../schemas/types
'
@
Injectable
()
export
class
ContentsService
{
...
...
@@ -40,13 +45,7 @@ export class ContentsService {
where
.
_id
=
db
.
command
.
in
(
filter
.
ids
)
}
const
{
data
:
[
schema
],
}:
{
data
:
Schema
[]
}
=
await
this
.
collection
(
Collection
.
Schemas
)
.
where
({
collectionName
:
resource
,
})
.
get
()
const
schema
=
await
getCollectionSchema
(
resource
)
// 模糊搜索
if
(
fuzzyFilter
&&
schema
)
{
...
...
@@ -108,8 +107,7 @@ export class ContentsService {
if
(
schema
)
{
// 存在关联类型字段
const
connectFields
=
schema
.
fields
.
filter
((
field
)
=>
field
.
type
===
'
Connect
'
)
if
(
connectFields
?.
length
)
{
if
(
!
R
.
isEmpty
(
connectFields
))
{
res
.
data
=
await
this
.
transformConnectField
(
res
.
data
,
connectFields
)
}
}
...
...
@@ -358,10 +356,10 @@ export class ContentsService {
/**
* 处理数据返回结果
* 将数据中的关联字段
解析
后返回
* 将数据中的关联字段
转换成原始 Doc
后返回
*/
private
async
transformConnectField
(
rawData
:
any
[],
connectFields
:
SchemaField
[])
{
let
resData
=
rawData
private
async
transformConnectField
(
docs
:
any
[],
connectFields
:
SchemaField
[])
{
let
resData
:
any
[]
=
docs
const
$
=
this
.
cloudbaseService
.
db
.
command
// 获取所有 Schema 数据
...
...
@@ -375,59 +373,63 @@ export class ContentsService {
// 获取数据中所有的关联资源 Id
let
ids
=
[]
// 关联多个对象,将 Doc 数组中的 id 数组合并、去重
if
(
connectMany
)
{
// 合并数组
ids
=
resData
.
filter
((
record
)
=>
record
[
fieldName
]?.
length
)
.
map
((
record
)
=>
record
[
fieldName
])
.
reduce
((
ret
,
current
)
=>
[...
ret
,
...
current
],
[])
ids
=
R
.
pipe
(
R
.
reject
<
any
>
(
R
.
where
({
[
fieldName
]:
R
.
isEmpty
})),
R
.
map
(
R
.
prop
(
fieldName
)),
R
.
reduce
(
R
.
union
,
[]),
R
.
filter
(
isNotEmpty
)
)(
resData
)
}
else
{
ids
=
resData
.
map
((
record
)
=>
record
[
fieldName
]).
filter
((
_
)
=>
_
)
// 关联单个对象,取 Doc 数组中的 id,过滤
ids
=
R
.
pipe
(
R
.
map
(
R
.
prop
(
fieldName
)),
R
.
filter
(
isNotEmpty
))(
resData
)
}
// 集合名
const
collectionName
=
schemas
.
find
((
schema
)
=>
schema
.
_id
===
field
.
connectResource
)
.
collectionName
// 获取关联的数据,分页最大条数 50
const
{
data
:
connectData
}
=
await
this
.
collection
(
collectionName
)
.
where
({
_id
:
$
.
in
(
ids
)
})
.
limit
(
1000
)
.
get
()
// 关联的 Schema
const
connectSchema
=
schemas
.
find
((
schema
)
=>
schema
.
_id
===
field
.
connectResource
)
// 获取关联 id 对应的 Doc
// 使用 getMany 获取数据,自动转换 Connect 字段
const
{
data
:
connectData
}
=
await
this
.
getMany
(
connectSchema
.
collectionName
,
{
page
:
1
,
pageSize
:
1000
,
filter
:
{
ids
,
},
})
// 修改 resData 中的关联字段
resData
=
resData
.
map
((
record
)
=>
{
if
(
!
record
[
fieldName
])
return
record
let
connectRecord
// 关联字段的值:id 或 [id]
const
connectValue
=
record
[
fieldName
]
if
(
!
connectValue
)
return
record
// 关联的数据被删除
if
(
!
connectData
)
{
return
{
...
record
,
[
fieldName
]:
null
,
}
record
[
fieldName
]
=
null
return
record
}
let
connectRecord
// id 数组
if
(
connectMany
)
{
// id 数组
connectRecord
=
record
[
fieldName
]?.
length
?
record
[
fieldName
]?.
map
((
id
)
=>
connectData
.
find
((
_
)
=>
_
.
_id
===
id
))
connectRecord
=
connectValue
?.
length
?
connectValue
?.
map
((
id
)
=>
connectData
.
find
((
_
)
=>
_
.
_id
===
id
))
:
[]
}
else
{
connectRecord
=
connectData
.
find
((
_
)
=>
_
.
_id
===
record
[
fieldName
]
)
connectRecord
=
connectData
.
find
((
_
)
=>
_
.
_id
===
connectValue
)
}
return
{
...
record
,
[
fieldName
]:
connectRecord
,
}
record
[
fieldName
]
=
connectRecord
return
record
})
}
// 转换 connectField
const
promises
=
connectFields
.
map
(
transformDataByField
)
await
Promise
.
all
(
promises
)
const
tasks
=
connectFields
.
map
(
transformDataByField
)
await
Promise
.
all
(
tasks
)
return
resData
}
...
...
This diff is collapsed.
Click to expand it.
packages/service/src/modules/projects/schemas/schema.pipe.ts
+
3
-
3
View file @
8f53cdb0
import
{
dateToUnixTimestampInMs
,
n
an
oi
d
}
from
'
@/utils
'
import
{
dateToUnixTimestampInMs
,
r
an
domI
d
}
from
'
@/utils
'
import
{
PipeTransform
,
Injectable
,
ArgumentMetadata
}
from
'
@nestjs/common
'
@
Injectable
()
...
...
@@ -13,7 +13,7 @@ export class SchemaTransfromPipe implements PipeTransform {
if
(
this
.
action
===
'
create
'
)
{
value
.
fields
=
value
?.
fields
?.
map
((
v
)
=>
{
const
id
=
v
.
id
||
n
an
oi
d
()
const
id
=
v
.
id
||
r
an
domI
d
()
return
{
...
v
,
id
,
...
...
@@ -31,7 +31,7 @@ export class SchemaTransfromPipe implements PipeTransform {
if
(
value
.
fields
?.
length
)
{
// 为 field 添加 id
value
.
fields
=
value
?.
fields
?.
map
((
v
)
=>
{
const
id
=
v
.
id
||
n
an
oi
d
()
const
id
=
v
.
id
||
r
an
domI
d
()
return
{
...
v
,
id
,
...
...
This diff is collapsed.
Click to expand it.
packages/service/src/modules/projects/schemas/types.ts
+
0
-
3
View file @
8f53cdb0
...
...
@@ -84,7 +84,4 @@ export class Schema {
_creatTime
:
number
_updateTime
:
number
// Schema 协议版本 v2
_version
:
'
2.0
'
}
This diff is collapsed.
Click to expand it.
packages/service/src/utils/cloudbase.ts
+
2
-
1
View file @
8f53cdb0
...
...
@@ -114,7 +114,7 @@ export const getUserFromCredential = async (credential: string, origin: string)
/**
* 获取集合的 Schema
*/
export
const
getCollectionSchema
=
async
(
collection
:
string
)
=>
{
export
const
getCollectionSchema
=
async
(
collection
:
string
)
:
Promise
<
Schema
>
=>
{
const
app
=
getCloudBaseApp
()
const
{
data
:
[
schema
],
...
...
@@ -125,6 +125,7 @@ export const getCollectionSchema = async (collection: string) => {
collectionName
:
collection
,
})
.
get
()
return
schema
}
...
...
This diff is collapsed.
Click to expand it.
packages/service/src/utils/tools.ts
+
15
-
5
View file @
8f53cdb0
import
_
from
'
lodash
'
import
{
customAlphabet
}
from
'
nanoid
'
export
const
isDevEnv
=
()
=>
process
.
env
.
NODE_ENV
===
'
development
'
&&
!
process
.
env
.
TENCENTCLOUD_RUNENV
export
const
nanoid
=
customAlphabet
(
'
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-
'
,
32
)
/**
* 生成随机 id
*/
export
const
randomId
=
(
len
=
32
)
=>
customAlphabet
(
'
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-
'
,
len
)()
/**
* 检查 ele 不为 null,undefined,空数组,空对象,仅包含 null、undefined 的数组
*/
export
const
isNotEmpty
=
(
ele
:
any
|
any
[])
=>
{
if
(
Array
.
isArray
(
ele
))
{
return
!
_
.
isEmpty
(
ele
)
&&
!
_
.
isEmpty
(
ele
.
filter
((
_
)
=>
_
))
}
return
!
_
.
isEmpty
(
ele
)
}
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
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