Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
saas-manage
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
chehuidong
saas-manage
Commits
cfd7cac8
Commit
cfd7cac8
authored
Sep 11, 2025
by
qinjianhui
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 自定义cascader组件封装
parent
f916b74e
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
666 additions
and
28 deletions
+666
-28
src/common/components/base/CustomCascader.vue
+586
-0
src/views/operation/amazon/amazonAttributeGrouping.vue
+80
-28
No files found.
src/common/components/base/CustomCascader.vue
0 → 100644
View file @
cfd7cac8
<
template
>
<div
class=
"custom-cascader-wrapper"
>
<el-input
v-model=
"displayText"
placeholder=
"请选择分类"
size=
"medium"
:clearable=
"clearable"
@
focus=
"toggleDropdown"
>
<i
slot=
"suffix"
class=
"el-input__icon el-icon-arrow-up"
:style=
"
{
transform: isVisible ? 'rotate(0deg)' : 'rotate(180deg)',
transition: 'transform 0.2s'
}">
</i>
</el-input>
<transition
name=
"cascader-dropdown"
>
<div
v-show=
"isVisible"
class=
"cascader-dropdown"
>
<div
class=
"cascader-panels"
v-if=
"panels.length > 0"
>
<div
v-for=
"(panel, panelIndex) in panels"
:key=
"panelIndex"
class=
"cascader-panel"
>
<div
class=
"search-container"
>
<el-input
v-model=
"panel.searchText"
type=
"text"
class=
"search-input"
placeholder=
"搜索内容"
@
input=
"handleSearch(panelIndex)"
@
focus=
"handlePanelFocus"
size=
"small"
>
<i
slot=
"suffix"
class=
"el-input__icon el-icon-search"
></i>
</el-input>
</div>
<div
class=
"options-container"
>
<div
v-for=
"(option, optionIndex) in panel.filteredOptions"
:key=
"optionIndex"
class=
"option-item"
:class=
"
{
selected: panel.selectedIndex === optionIndex,
'has-children':
option.childId ||
(option.children
&&
option.children.length > 0)
}"
@click="handleOptionClick(panelIndex, optionIndex, option)">
<div
class=
"option-item-left"
>
<span
class=
"option-text"
>
{{
option
.
browseNodeName
}}
</span>
<div
v-if=
"option.productType"
class=
"product-type"
>
Product Type:
{{
option
.
productType
}}
</div>
</div>
<i
v-if=
"
option.childId ||
(option.children && option.children.length > 0)
"
class=
"el-icon-arrow-right expand-icon"
></i>
</div>
</div>
</div>
</div>
<div
v-else
class=
"no-data"
>
暂无数据
</div>
</div>
</transition>
</div>
</
template
>
<
script
>
export
default
{
name
:
'CustomCascader'
,
model
:
{
prop
:
'value'
,
event
:
'change'
},
props
:
{
value
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 数据源
options
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 是否支持搜索
searchable
:
{
type
:
Boolean
,
default
:
true
},
// 加载子节点的回调函数
loadData
:
{
type
:
Function
,
default
:
null
},
// 占位符
placeholder
:
{
type
:
String
,
default
:
'请选择'
},
// 是否禁用
disabled
:
{
type
:
Boolean
,
default
:
false
},
// 分隔符
separator
:
{
type
:
String
,
default
:
' / '
},
clearable
:
{
type
:
Boolean
,
default
:
true
}
},
data
()
{
return
{
panels
:
[],
selectedPath
:
[],
isVisible
:
false
,
selectedLabels
:
[],
displayText
:
''
,
lastSelectedPathId
:
''
,
isInternalChange
:
false
}
},
watch
:
{
options
:
{
handler
()
{
if
(
!
this
.
value
||
this
.
value
.
length
===
0
)
{
this
.
initPanels
()
}
else
{
this
.
updatePanelsFromValue
(
this
.
value
)
}
},
immediate
:
true
},
value
:
{
handler
(
newValue
)
{
if
(
!
this
.
isInternalChange
)
{
this
.
updatePanelsFromValue
(
newValue
)
}
this
.
isInternalChange
=
false
},
immediate
:
true
}
},
mounted
()
{
document
.
addEventListener
(
'click'
,
this
.
handleDocumentClick
,
true
)
},
methods
:
{
async
updatePanelsFromValue
(
value
)
{
if
(
!
value
||
value
.
length
===
0
)
{
this
.
panels
=
[]
this
.
selectedPath
=
[]
this
.
selectedLabels
=
[]
this
.
displayText
=
''
this
.
lastSelectedPathId
=
''
this
.
initPanels
()
return
}
// 清空所有状态
this
.
panels
=
[]
this
.
selectedPath
=
[]
this
.
selectedLabels
=
[]
this
.
displayText
=
''
if
(
!
this
.
options
||
this
.
options
.
length
===
0
)
{
return
}
this
.
initPanels
()
// 逐级构建面板
for
(
let
i
=
0
;
i
<
value
.
length
;
i
++
)
{
const
currentValue
=
value
[
i
]
const
currentPanel
=
this
.
panels
[
i
]
if
(
!
currentPanel
||
!
currentPanel
.
options
)
{
break
}
// 在当前面板中查找对应的选项
const
currentOption
=
currentPanel
.
options
.
find
(
(
option
)
=>
option
.
browseNodeId
===
currentValue
)
if
(
!
currentOption
)
{
break
}
// 更新选中状态
const
optionIndex
=
currentPanel
.
options
.
findIndex
(
(
option
)
=>
option
.
browseNodeId
===
currentValue
)
currentPanel
.
selectedIndex
=
optionIndex
// 更新路径和标签
this
.
selectedPath
=
this
.
selectedPath
.
slice
(
0
,
i
)
this
.
selectedPath
.
push
(
currentValue
)
this
.
selectedLabels
=
this
.
selectedLabels
.
slice
(
0
,
i
)
this
.
selectedLabels
.
push
(
currentOption
.
browseNodeName
)
if
(
i
<
value
.
length
-
1
&&
currentOption
.
childId
)
{
try
{
await
this
.
loadChildPanel
(
currentOption
)
}
catch
(
error
)
{
console
.
error
(
'加载子面板失败:'
,
error
)
break
}
}
else
{
// 最后一级或没有子节点
this
.
lastSelectedPathId
=
currentValue
this
.
$emit
(
'onUpdataValue'
,
{
val
:
this
.
selectedPath
,
resetCategoryAttributes
:
false
})
this
.
displayText
=
this
.
selectedLabels
.
join
(
this
.
separator
)
break
}
}
},
// 加载子面板
loadChildPanel
(
parentOption
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
this
.
loadData
)
{
reject
(
new
Error
(
'loadData方法未提供'
))
return
}
this
.
loadData
(
parentOption
,
(
children
)
=>
{
if
(
children
&&
children
.
length
>
0
)
{
const
currentPanelIndex
=
this
.
panels
.
length
-
1
const
expectedPanelIndex
=
this
.
selectedPath
.
length
if
(
currentPanelIndex
>=
expectedPanelIndex
)
{
this
.
panels
[
expectedPanelIndex
]
=
{
options
:
children
,
filteredOptions
:
[...
children
],
searchText
:
''
,
selectedIndex
:
-
1
}
}
else
{
this
.
addPanel
(
children
)
}
resolve
()
}
else
{
reject
(
new
Error
(
'没有子节点数据'
))
}
})
})
},
toggleDropdown
()
{
if
(
this
.
disabled
)
return
this
.
isVisible
=
true
},
handlePanelFocus
()
{
this
.
isVisible
=
true
},
// 初始化面板
initPanels
()
{
if
(
this
.
panels
.
length
===
0
&&
this
.
options
&&
this
.
options
.
length
>
0
)
{
this
.
panels
.
push
({
options
:
[...
this
.
options
],
filteredOptions
:
[...
this
.
options
],
searchText
:
''
,
selectedIndex
:
-
1
})
}
},
handleSearch
(
panelIndex
)
{
const
panel
=
this
.
panels
[
panelIndex
]
if
(
!
panel
.
searchText
.
trim
())
{
panel
.
filteredOptions
=
[...
panel
.
options
]
}
else
{
panel
.
filteredOptions
=
panel
.
options
.
filter
((
option
)
=>
option
.
browseNodeName
.
toLowerCase
()
.
includes
(
panel
.
searchText
.
toLowerCase
())
)
}
},
async
handleOptionClick
(
panelIndex
,
optionIndex
,
option
)
{
const
panel
=
this
.
panels
[
panelIndex
]
panel
.
selectedIndex
=
optionIndex
this
.
selectedPath
=
this
.
selectedPath
.
slice
(
0
,
panelIndex
)
this
.
selectedPath
.
push
(
option
.
browseNodeId
)
this
.
selectedLabels
=
this
.
selectedLabels
.
slice
(
0
,
panelIndex
)
this
.
selectedLabels
.
push
(
option
.
browseNodeName
)
this
.
panels
=
this
.
panels
.
slice
(
0
,
panelIndex
+
1
)
if
(
option
.
childId
&&
this
.
lastSelectedPathId
!==
option
.
browseNodeId
)
{
this
.
loadData
(
option
,
(
children
)
=>
{
if
(
children
&&
children
.
length
>
0
)
{
this
.
addPanel
(
children
)
}
else
{
this
.
lastSelectedPathId
=
option
.
browseNodeId
this
.
isInternalChange
=
true
this
.
$emit
(
'change'
,
this
.
selectedPath
)
this
.
displayText
=
this
.
selectedLabels
.
join
(
this
.
separator
)
this
.
isVisible
=
false
}
})
}
else
{
this
.
lastSelectedPathId
=
option
.
browseNodeId
this
.
isInternalChange
=
true
this
.
$emit
(
'change'
,
this
.
selectedPath
)
this
.
displayText
=
this
.
selectedLabels
.
join
(
this
.
separator
)
this
.
isVisible
=
false
}
},
addPanel
(
options
)
{
const
existingPanel
=
this
.
panels
.
find
(
(
panel
)
=>
panel
.
options
&&
panel
.
options
.
length
>
0
&&
panel
.
options
[
0
].
browseNodeId
===
options
[
0
].
browseNodeId
)
if
(
!
existingPanel
)
{
this
.
panels
.
push
({
options
:
options
,
filteredOptions
:
[...
options
],
searchText
:
''
,
selectedIndex
:
-
1
})
// 添加面板后自动滚动到新面板
this
.
$nextTick
(()
=>
{
this
.
scrollToNewPanel
()
})
}
},
// 滚动到新添加的面板
scrollToNewPanel
()
{
const
panelsContainer
=
this
.
$el
.
querySelector
(
'.cascader-panels'
)
if
(
panelsContainer
)
{
const
newPanel
=
panelsContainer
.
lastElementChild
if
(
newPanel
)
{
const
containerWidth
=
panelsContainer
.
clientWidth
const
newPanelLeft
=
newPanel
.
offsetLeft
if
(
newPanelLeft
+
newPanel
.
offsetWidth
>
panelsContainer
.
scrollLeft
+
containerWidth
)
{
panelsContainer
.
scrollTo
({
left
:
newPanelLeft
-
containerWidth
+
newPanel
.
offsetWidth
,
behavior
:
'smooth'
})
}
}
}
},
handleDocumentClick
(
event
)
{
if
(
this
.
$el
.
contains
(
event
.
target
))
{
return
}
const
target
=
event
.
target
const
isModal
=
target
.
closest
(
'.el-message-box'
)
||
target
.
closest
(
'.el-dialog'
)
||
target
.
closest
(
'.el-message'
)
||
target
.
closest
(
'[role="dialog"]'
)
||
target
.
closest
(
'.modal'
)
||
target
.
closest
(
'.error-modal'
)
if
(
isModal
)
{
return
}
// 其他情况关闭级联选择器
this
.
isVisible
=
false
},
getCheckedNodes
()
{
return
this
.
panels
.
map
((
panel
,
index
)
=>
{
return
panel
.
options
.
find
(
(
option
)
=>
option
.
browseNodeId
===
this
.
selectedPath
[
index
]
)
})
}
},
beforeDestroy
()
{
document
.
removeEventListener
(
'click'
,
this
.
handleDocumentClick
,
true
)
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.custom-cascader-wrapper
{
position
:
relative
;
display
:
inline-block
;
width
:
100%
;
}
.cascader-input
{
position
:
relative
;
display
:
flex
;
align-items
:
center
;
width
:
100%
;
height
:
32px
;
padding
:
0
12px
;
border
:
1px
solid
#dcdfe6
;
border-radius
:
4px
;
background-color
:
#fff
;
cursor
:
pointer
;
transition
:
border-color
0.2s
;
&:hover
{
border-color
:
#c0c4cc
;
}
&
.is-focus
{
border-color
:
#409eff
;
}
&
.is-disabled
{
background-color
:
#f5f7fa
;
border-color
:
#e4e7ed
;
color
:
#c0c4cc
;
cursor
:
not-allowed
;
}
}
.input-content
{
flex
:
1
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.selected-text
{
color
:
#606266
;
font-size
:
14px
;
}
.placeholder
{
color
:
#c0c4cc
;
font-size
:
14px
;
}
.arrow-icon
{
margin-left
:
8px
;
font-size
:
12px
;
color
:
#c0c4cc
;
transition
:
transform
0.2s
;
&.is-reverse
{
transform
:
rotate
(
180deg
);
}
}
.cascader-dropdown
{
position
:
absolute
;
top
:
100%
;
left
:
0
;
right
:
0
;
z-index
:
2000
;
margin-top
:
4px
;
border
:
1px
solid
#dcdfe6
;
border-radius
:
4px
;
background
:
#fff
;
box-shadow
:
0
2px
12px
0
rgba
(
0
,
0
,
0
,
0.1
);
}
.cascader-panels
{
display
:
flex
;
overflow-x
:
auto
;
}
.cascader-panel
{
//
flex
:
1
;
width
:
300px
;
min-width
:
300px
;
border-right
:
1px
solid
#ebeef5
;
}
.search-container
{
position
:
relative
;
padding
:
8px
;
border-bottom
:
1px
solid
#ebeef5
;
}
.search-icon
{
position
:
absolute
;
right
:
16px
;
top
:
50%
;
transform
:
translateY
(
-50%
);
font-size
:
12px
;
color
:
#c0c4cc
;
}
.options-container
{
max-height
:
360px
;
overflow-y
:
auto
;
}
.option-item
{
padding
:
8px
12px
;
cursor
:
pointer
;
display
:
flex
;
justify-content
:
space-between
;
&:hover
{
background-color
:
#f5f7fa
;
}
&
.selected
{
background-color
:
#e6f7ff
;
color
:
#1890ff
;
}
&
.selected
i
{
color
:
#1890ff
;
}
&
.has-children
{
.option-text
{
flex
:
1
;
}
}
}
.option-item-left
{
display
:
flex
;
flex-direction
:
column
;
flex
:
1
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.option-text
{
font-size
:
14px
;
line-height
:
1.4
;
}
.expand-icon
{
color
:
#333
;
font-size
:
14px
;
margin-left
:
8px
;
}
.product-type
{
font-size
:
10px
;
color
:
#909399
;
background
:
#f5f7fa
;
padding
:
1px
4px
;
border-radius
:
2px
;
}
//
滚动条样式
.options-container
::-webkit-scrollbar
{
width
:
6px
;
}
.options-container
::-webkit-scrollbar-track
{
background
:
#f1f1f1
;
}
.options-container
::-webkit-scrollbar-thumb
{
background
:
#c1c1c1
;
border-radius
:
3px
;
}
.options-container
::-webkit-scrollbar-thumb:hover
{
background
:
#a8a8a8
;
}
//
下拉动画
.cascader-dropdown-enter-active
,
.cascader-dropdown-leave-active
{
transition
:
opacity
0.2s
,
transform
0.2s
;
}
.cascader-dropdown-enter
,
.cascader-dropdown-leave-to
{
opacity
:
0
;
transform
:
translateY
(
-10px
);
}
.no-data
{
padding
:
10px
;
text-align
:
center
;
color
:
#999
;
}
</
style
>
src/views/operation/amazon/amazonAttributeGrouping.vue
View file @
cfd7cac8
...
...
@@ -68,12 +68,15 @@
</div>
<div
style=
"flex: 1"
>
<!--
<CustomCascader
<CustomCascader
ref=
"customCascaderRef"
:options=
"amCateCascaders"
v-model=
"aliCatePathIds"
:loadData=
"customLazyLoad"
@
change=
"customCascaderChange"
></CustomCascader>
-->
<el-cascader
:clearable=
"false"
@
onUpdataValue=
"onUpdataValue"
@
change=
"customCascaderChange"
></CustomCascader>
<!--
<el-cascader
size=
"medium"
:options=
"amCateCascaders"
ref=
"amCateCascadersRef"
...
...
@@ -87,7 +90,7 @@
lazy: true,
lazyLoad: lazyLoad
}"
@change="categoryTypeChange">
</el-cascader>
@change="categoryTypeChange">
</el-cascader>
-->
</div>
</div>
<div
class=
"category-item"
>
...
...
@@ -260,12 +263,12 @@
</
template
>
<
script
>
import
{
get
,
post
}
from
'@/common/api/axios'
//
import CustomCascader from '@/common/components/base/CustomCascader.vue'
import
CustomCascader
from
'@/common/components/base/CustomCascader.vue'
export
default
{
name
:
'amazonAttributeGrouping'
,
components
:
{
//
CustomCascader
CustomCascader
},
data
()
{
return
{
...
...
@@ -438,6 +441,10 @@ export default {
},
async
searchCategory
()
{
if
(
!
this
.
keyWord
)
return
if
(
!
this
.
shopId
)
{
this
.
$message
.
warning
(
'请选择店铺'
)
return
}
const
loading
=
this
.
$loading
({
lock
:
true
})
...
...
@@ -458,6 +465,10 @@ export default {
loading
.
close
()
}
},
onUpdataValue
()
{
console
.
log
(
'onUpdataValue'
)
this
.
customCascaderChange
()
},
productTypeChange
(
val
)
{
if
(
!
val
)
return
const
item
=
this
.
productTypeList
.
find
(
...
...
@@ -468,15 +479,15 @@ export default {
?.
split
(
','
)
?.
slice
(
1
)
?.
map
((
e
)
=>
Number
(
e
))
this
.
initCate
(
categoryPath
||
[],
()
=>
{
if
(
item
.
productType
&&
categoryPath
)
{
this
.
aliCatePathIds
=
categoryPath
this
.
categoryTypeChange
(
item
.
productType
,
true
)
}
else
{
this
.
jsonSchema
=
{}
this
.
groupList
=
[]
}
})
// this.initCate(
[], () => {
if
(
item
.
productType
&&
categoryPath
)
{
this
.
aliCatePathIds
=
categoryPath
//
this.categoryTypeChange(item.productType, true)
}
else
{
this
.
jsonSchema
=
{}
this
.
groupList
=
[]
}
//
})
},
getCateAttrs
(
id
,
categoryFullPath
,
callback
)
{
if
(
!
id
||
id
.
length
===
0
)
return
...
...
@@ -562,10 +573,43 @@ export default {
}
})
},
customCascaderChange
(
val
)
{
console
.
log
(
val
)
customCascaderChange
()
{
this
.
$nextTick
(()
=>
{
const
nodes
=
this
.
$refs
.
customCascaderRef
.
getCheckedNodes
()
let
targetNode
if
(
this
.
aliCatePathIds
)
{
targetNode
=
nodes
[
nodes
.
length
-
1
]
}
if
(
targetNode
)
{
const
{
productTypeDefinitions
,
browsePathByName
}
=
targetNode
this
.
getCateAttrs
(
productTypeDefinitions
,
browsePathByName
,
({
list
,
groupProps
})
=>
{
if
(
list
)
{
this
.
jsonSchema
=
list
groupProps
.
forEach
((
item
)
=>
{
item
.
propertyList
.
forEach
((
e
)
=>
{
this
.
$set
(
this
.
dataGroupForm
,
e
.
propertyNameEn
,
item
.
id
)
})
})
this
.
cloneDataGroupForm
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
dataGroupForm
)
)
}
else
{
this
.
jsonSchema
=
{}
this
.
dataGroupForm
=
{}
}
}
)
}
else
{
this
.
jsonSchema
=
{}
this
.
dataGroupForm
=
{}
}
})
},
async
initCate
(
ids
,
callback
)
{
console
.
log
(
'initCate'
,
ids
)
const
shopId
=
this
.
shopList
.
find
(
(
item
)
=>
item
.
id
===
this
.
shopId
)?.
marketplaceId
...
...
@@ -573,13 +617,13 @@ export default {
lock
:
true
})
const
arr
=
[
get
(
'amazon/category/getChildListByBrowseNodeId'
,
{
get
(
'
manage/rest/
amazon/category/getChildListByBrowseNodeId'
,
{
marketplaceId
:
shopId
})
]
for
(
let
i
=
0
;
i
<
ids
.
length
-
1
;
i
++
)
{
arr
.
push
(
get
(
'amazon/category/getChildListByBrowseNodeId'
,
{
get
(
'
manage/rest/
amazon/category/getChildListByBrowseNodeId'
,
{
browseNodeId
:
ids
[
i
],
marketplaceId
:
shopId
})
...
...
@@ -639,10 +683,13 @@ export default {
}
},
async
customLazyLoad
(
node
,
callback
)
{
const
shopId
=
this
.
shopList
.
find
(
(
item
)
=>
item
.
id
===
this
.
shopId
)?.
marketplaceId
try
{
const
res
=
await
get
(
'amazon/category/getChildListByBrowseNodeId'
,
{
const
res
=
await
get
(
'
manage/rest/
amazon/category/getChildListByBrowseNodeId'
,
{
browseNodeId
:
node
.
browseNodeId
,
marketplaceId
:
this
.
shopId
marketplaceId
:
shopId
})
if
(
res
.
code
!==
200
)
return
callback
(
res
.
data
)
...
...
@@ -669,7 +716,12 @@ export default {
this
.
initCate
([])
},
async
saveGrouping
()
{
const
nodes
=
this
.
$refs
.
amCateCascadersRef
.
getCheckedNodes
()
// const nodes = this.$refs.amCateCascadersRef.getCheckedNodes()
// let targetNode
// if (this.aliCatePathIds) {
// targetNode = nodes[nodes.length - 1]
// }
const
nodes
=
this
.
$refs
.
customCascaderRef
.
getCheckedNodes
()
let
targetNode
if
(
this
.
aliCatePathIds
)
{
targetNode
=
nodes
[
nodes
.
length
-
1
]
...
...
@@ -683,15 +735,15 @@ export default {
updatePropertyList
.
push
({
propertyNameEn
:
item
,
groupId
:
this
.
dataGroupForm
[
item
]
||
undefined
,
productType
:
targetNode
.
data
.
productTypeDefinitions
,
categoryFullPath
:
targetNode
.
data
.
browsePathByName
productType
:
targetNode
.
productTypeDefinitions
,
categoryFullPath
:
targetNode
.
browsePathByName
})
}
else
{
updatePropertyList
.
push
({
propertyNameEn
:
item
,
groupId
:
this
.
dataGroupForm
[
item
]
||
undefined
,
productType
:
targetNode
.
data
.
productTypeDefinitions
,
categoryFullPath
:
targetNode
.
data
.
browsePathByName
productType
:
targetNode
.
productTypeDefinitions
,
categoryFullPath
:
targetNode
.
browsePathByName
})
}
})
...
...
@@ -705,8 +757,8 @@ export default {
if
(
!
this
.
dataGroupForm
[
item
])
{
delPropertyList
.
push
({
propertyNameEn
:
item
,
productType
:
targetNode
.
data
.
productTypeDefinitions
,
categoryFullPath
:
targetNode
.
data
.
browsePathByName
,
productType
:
targetNode
.
productTypeDefinitions
,
categoryFullPath
:
targetNode
.
browsePathByName
,
groupId
:
this
.
cloneDataGroupForm
[
item
]
})
}
...
...
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