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
fdb057fe
Commit
fdb057fe
authored
Aug 27, 2025
by
qinjianhui
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' into 'master'
Dev See merge request
!62
parents
4a7fd873
6c6c8b3c
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1091 additions
and
0 deletions
+1091
-0
.eslintrc.js
+3
-0
package-lock.json
+0
-0
src/router/index.js
+6
-0
src/views/home/navMenu.vue
+8
-0
src/views/operation/amazon/amazonAttributeGrouping.vue
+1074
-0
No files found.
.eslintrc.js
View file @
fdb057fe
...
@@ -18,6 +18,9 @@ module.exports = {
...
@@ -18,6 +18,9 @@ module.exports = {
'multiline-ternary'
:
'off'
,
'multiline-ternary'
:
'off'
,
'vue/multi-word-component-names'
:
'off'
,
'vue/multi-word-component-names'
:
'off'
,
'eol-last'
:
0
,
'eol-last'
:
0
,
'node/no-callback-literal'
:
'off'
,
'no-trailing-spaces'
:
'off'
,
'no-unused-vars'
:
'off'
,
'vue/no-mutating-props'
:
'off'
'vue/no-mutating-props'
:
'off'
}
}
}
}
package-lock.json
View file @
fdb057fe
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/router/index.js
View file @
fdb057fe
...
@@ -176,6 +176,12 @@ const routes = [
...
@@ -176,6 +176,12 @@ const routes = [
meta
:
{
title
:
'异步任务'
}
meta
:
{
title
:
'异步任务'
}
},
},
{
{
path
:
'/operation/amazonAttributeGrouping'
,
component
:
()
=>
import
(
'@/views/operation/amazon/amazonAttributeGrouping.vue'
),
name
:
'amazonAttributeGrouping'
,
meta
:
{
title
:
'亚马逊属性分类'
}
},
{
path
:
'/saas/production/assistant/manage'
,
path
:
'/saas/production/assistant/manage'
,
component
:
()
=>
import
(
'@/views/production/AssistantManage.vue'
),
component
:
()
=>
import
(
'@/views/production/AssistantManage.vue'
),
name
:
'production_assistant_manage'
,
name
:
'production_assistant_manage'
,
...
...
src/views/home/navMenu.vue
View file @
fdb057fe
...
@@ -301,6 +301,14 @@ export default {
...
@@ -301,6 +301,14 @@ export default {
icon
:
'el-icon-box'
,
icon
:
'el-icon-box'
,
index
:
'/saas/import-template'
,
index
:
'/saas/import-template'
,
children
:
[]
children
:
[]
},
{
id
:
12
,
path
:
''
,
label
:
'亚马逊属性分类'
,
icon
:
'el-icon-s-check'
,
index
:
'/operation/amazonAttributeGrouping'
,
children
:
[]
}
}
// {
// {
// id: 11,
// id: 11,
...
...
src/views/operation/amazon/amazonAttributeGrouping.vue
0 → 100644
View file @
fdb057fe
<
template
>
<div
class=
"card amazon-attribute-grouping"
>
<div
class=
"left-group-status"
>
<div
class=
"add-group"
>
<el-button
size=
"small"
type=
"primary"
@
click=
"addGroup"
>
添加分组
</el-button>
<el-button
size=
"small"
type=
"danger"
@
click=
"batchDeleteGroups"
:disabled=
"selectedGroups.length === 0"
>
删除分组
</el-button>
</div>
<div
class=
"group-status-box"
v-if=
"groupsList.length > 0"
>
<div
class=
"group-status-item"
:class=
"
{
active: currentGroupId === 0
}"
@click="currentGroupId = 0">
<span
class=
"group-name"
>
全部(All)
</span>
</div>
<div
class=
"group-status-item"
v-for=
"item in groupsList"
:key=
"item.id"
:class=
"
{ active: currentGroupId === item.id }"
@click="currentGroupId = item.id">
<div
class=
"group-checkbox"
@
click
.
stop
>
<div
class=
"custom-checkbox"
:class=
"
{ active: selectedGroups.includes(item.id) }"
@click="toggleGroupSelection(item.id)">
</div>
</div>
<span
class=
"group-name"
>
{{
item
.
name
}}
(
{{
item
.
nameEn
}}
)
</span>
<div
class=
"operate-group"
>
<i
title=
"编辑"
style=
"color: #e6a23c; font-size: 14px; margin-right: 6px"
class=
"el-icon-edit"
@
click=
"editGroup(item)"
></i>
</div>
</div>
</div>
</div>
<div
class=
"right-group-content"
>
<div
class=
"category-box"
>
<div
class=
"category-item"
>
<div
class=
"category-title"
>
<span>
店铺
</span>
</div>
<div>
<el-select
v-model=
"shopId"
placeholder=
"请选择店铺"
@
change=
"shopChange"
>
<el-option
v-for=
"item in shopList"
:key=
"item.id"
:label=
"item.shopName"
:value=
"item.id"
></el-option>
</el-select>
</div>
<div
class=
"category-title"
>
<span>
Category
</span>
</div>
<div
style=
"flex: 1"
>
<!--
<CustomCascader
:options=
"amCateCascaders"
v-model=
"aliCatePathIds"
:loadData=
"customLazyLoad"
@
change=
"customCascaderChange"
></CustomCascader>
-->
<el-cascader
size=
"medium"
:options=
"amCateCascaders"
ref=
"amCateCascadersRef"
placeholder=
"请选择分类"
style=
"width: 100%"
v-model=
"aliCatePathIds"
filterable
:props=
"
{
label: 'browseNodeName',
value: 'browseNodeId',
lazy: true,
lazyLoad: lazyLoad
}"
@change="categoryTypeChange">
</el-cascader>
</div>
</div>
<div
class=
"category-item"
>
<div
class=
"category-title"
>
<span>
Search
</span>
</div>
<div>
<el-input
clearable
v-model=
"keyWord"
placeholder=
"请输入关键词"
>
<el-button
slot=
"append"
icon=
"el-icon-search"
@
click=
"searchCategory"
></el-button>
</el-input>
</div>
<div
style=
"flex: 1"
>
<el-select
style=
"width: 100%"
filterable
clearable
popper-class=
"custom-popper-select"
v-model=
"productType"
@
change=
"productTypeChange"
placeholder=
"请选择分类"
>
<el-option
v-for=
"item in productTypeList"
:key=
"item.id"
:label=
"item.browsePathByName"
:value=
"item.browseNodeId"
>
<div
class=
"custom-label"
>
<div>
Product Type:
{{
item
.
productType
}}
</div>
<div>
{{
item
.
browsePathByName
}}
</div>
</div>
</el-option>
</el-select>
</div>
</div>
</div>
<div
class=
"attribute-box"
>
<div
class=
"attribute-header"
>
<el-button
type=
"primary"
size=
"small"
@
click=
"setGrouping"
>
设置分组
</el-button>
<el-button
type=
"success"
size=
"small"
@
click=
"selectAll"
>
全选
</el-button>
<el-button
type=
"warning"
size=
"small"
@
click=
"selectNone"
>
取消全选
</el-button>
</div>
<div
class=
"attribute-content"
>
<div
style=
"height: 100%; overflow: auto"
>
<div
class=
"attribute"
v-if=
"showJsonSchema.length > 0"
>
<div
class=
"attribute-item"
:class=
"
{
'visible-item-properties': !visibleGroupList[item.name]
}"
v-for="item in showJsonSchema"
:key="item.name">
<div
class=
"attribute-item-title"
>
<span
class=
"attribute-item-title-text"
>
{{
item
.
title
}}
</span>
<i
:title=
"item.description"
class=
"el-icon-info"
style=
"font-size: 12px; color: #999; cursor: pointer"
></i>
</div>
<div
class=
"attribute-item-content"
>
<el-select
v-model=
"dataGroupForm[item.name]"
placeholder=
"请设置分组"
clearable
class=
"attribute-item-select"
style=
"width: 100%"
>
<el-option
v-for=
"group in groupsList"
:key=
"group.id"
:label=
"`$
{group.name} (${group.nameEn})`"
:value="group.id">
</el-option>
</el-select>
</div>
<div
class=
"select-group-icon"
@
click=
"selectAttr(item)"
>
<div
class=
"check-icon"
:class=
"
{ active: selectedAttrStatus(item) }">
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"attribute-footer"
>
<el-button
type=
"info"
size=
"small"
@
click=
"resetGrouping"
>
重置
</el-button>
<el-button
type=
"success"
size=
"small"
@
click=
"saveGrouping"
>
保存
</el-button>
</div>
</div>
</div>
<el-dialog
title=
"添加分组"
:visible
.
sync=
"addDialogVisible"
:close-on-click-modal=
"false"
width=
"50%"
>
<el-form
:model=
"addForm"
label-width=
"100px"
ref=
"addFormRef"
>
<el-form-item
label=
"中文名称"
prop=
"name"
:rules=
"[
{ required: true, message: '请输入中文名称' }]">
<el-input
v-model=
"addForm.name"
placeholder=
"请输入分组名称"
></el-input>
</el-form-item>
<el-form-item
label=
"英文名称"
prop=
"nameEn"
:rules=
"[
{ required: true, message: '请输入英文名称' }]">
<el-input
v-model=
"addForm.nameEn"
placeholder=
"请输入英文名称"
></el-input>
</el-form-item>
<el-form-item
label=
"排序"
>
<el-input
v-model=
"addForm.sort"
clearable
placeholder=
"请输入排序"
></el-input>
</el-form-item>
<el-form-item
label=
"备注"
>
<el-input
v-model=
"addForm.remark"
placeholder=
"请输入备注"
></el-input>
</el-form-item>
</el-form>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"addDialogVisible = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"submitAdd"
:loading=
"addLoading"
>
确 定
</el-button>
</div>
</el-dialog>
<el-dialog
title=
"设置分组"
:visible
.
sync=
"setGroupDialogVisible"
:close-on-click-modal=
"false"
width=
"500px"
>
<el-select
v-model=
"groupingId"
placeholder=
"请选择分组"
clearable
style=
"width: 100%"
>
<el-option
v-for=
"item in groupsList"
:key=
"item.id"
:label=
"`$
{item.name} (${item.nameEn})`"
:value="item.id">
</el-option>
</el-select>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"setGroupDialogVisible = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"submitSetGroup"
:loading=
"setGroupLoading"
>
确 定
</el-button>
</div>
</el-dialog>
</div>
</
template
>
<
script
>
import
{
get
,
post
}
from
'@/common/api/axios'
// import CustomCascader from '@/common/components/base/CustomCascader.vue'
export
default
{
name
:
'amazonAttributeGrouping'
,
components
:
{
// CustomCascader
},
data
()
{
return
{
groupsList
:
[],
keyWord
:
''
,
productTypeList
:
[],
amCateCascaders
:
[],
aliCatePathIds
:
[],
jsonSchema
:
{},
productType
:
''
,
shopList
:
[],
shopId
:
''
,
addDialogVisible
:
false
,
addForm
:
{
cnName
:
''
,
enName
:
''
,
remark
:
''
,
sort
:
''
},
addLoading
:
false
,
groupSearchForm
:
{
productType
:
''
},
selectedAttr
:
[],
dataGroupForm
:
{},
setGroupDialogVisible
:
false
,
setGroupLoading
:
false
,
groupingId
:
''
,
currentGroupId
:
0
,
cloneDataGroupForm
:
{},
selectedGroups
:
[]
}
},
mounted
()
{
this
.
getAmazonShopList
()
this
.
getGroupList
()
},
computed
:
{
showJsonSchema
()
{
return
(
Object
.
keys
(
this
.
jsonSchema
?.
properties
||
{}).
map
((
item
)
=>
{
return
{
name
:
item
,
title
:
this
.
jsonSchema
.
properties
[
item
].
title
,
description
:
this
.
jsonSchema
.
properties
[
item
].
description
}
})
||
[]
)
},
currentGroupPropertiesMap
()
{
const
groupedProperties
=
{}
const
result
=
{}
for
(
const
key
of
Object
.
keys
(
this
.
dataGroupForm
))
{
if
(
!
this
.
dataGroupForm
[
key
])
continue
result
[
this
.
dataGroupForm
[
key
]]
=
{
...
result
[
this
.
dataGroupForm
[
key
]],
[
key
]:
true
}
groupedProperties
[
key
]
=
true
}
if
(
this
.
jsonSchema
?.
properties
)
{
const
notGroupedProperties
=
Object
.
keys
(
this
.
jsonSchema
.
properties
)
.
filter
((
key
)
=>
!
groupedProperties
[
key
])
.
reduce
((
acc
,
key
)
=>
{
acc
[
key
]
=
true
return
acc
},
{})
result
[
0
]
=
notGroupedProperties
}
return
result
},
visibleGroupList
()
{
return
this
.
currentGroupPropertiesMap
[
this
.
currentGroupId
]
??
{}
}
},
methods
:
{
selectAll
()
{
this
.
selectedAttr
=
this
.
showJsonSchema
},
selectNone
()
{
this
.
selectedAttr
=
[]
},
selectedAttrStatus
(
item
)
{
const
status
=
this
.
selectedAttr
.
findIndex
((
e
)
=>
e
.
name
===
item
.
name
)
return
status
>
-
1
},
selectAttr
(
item
)
{
const
status
=
this
.
selectedAttrStatus
(
item
)
if
(
status
)
{
const
index
=
this
.
selectedAttr
.
findIndex
((
e
)
=>
e
.
name
===
item
.
name
)
this
.
selectedAttr
.
splice
(
index
,
1
)
}
else
{
this
.
selectedAttr
.
push
(
item
)
}
},
submitSetGroup
()
{
this
.
selectedAttr
.
forEach
((
item
)
=>
{
this
.
$set
(
this
.
dataGroupForm
,
item
.
name
,
this
.
groupingId
)
})
this
.
setGroupDialogVisible
=
false
this
.
selectedAttr
=
[]
},
addGroup
()
{
this
.
addForm
=
{
name
:
''
,
nameEn
:
''
,
remark
:
''
,
sort
:
''
}
this
.
$nextTick
(()
=>
{
this
.
$refs
.
addFormRef
.
clearValidate
()
})
this
.
addDialogVisible
=
true
},
editGroup
(
item
)
{
this
.
addForm
=
{
name
:
item
.
name
,
nameEn
:
item
.
nameEn
,
remark
:
item
.
remark
,
id
:
item
.
id
,
sort
:
item
.
sort
}
this
.
$nextTick
(()
=>
{
this
.
$refs
.
addFormRef
.
clearValidate
()
})
this
.
addDialogVisible
=
true
},
setGrouping
()
{
if
(
this
.
selectedAttr
.
length
===
0
)
{
this
.
$message
.
warning
(
'请选择属性'
)
return
}
this
.
groupingId
=
''
this
.
setGroupDialogVisible
=
true
},
async
getGroupList
()
{
try
{
const
res
=
await
post
(
'amazonProductTypeGroup/list'
,
this
.
groupSearchForm
)
if
(
res
.
code
!==
200
)
return
this
.
groupsList
=
[...
res
.
data
]
}
catch
(
e
)
{
console
.
error
(
e
)
}
},
async
submitAdd
()
{
try
{
await
this
.
$refs
.
addFormRef
.
validate
()
}
catch
(
e
)
{
console
.
error
(
e
)
return
}
const
url
=
this
.
addForm
.
id
?
'amazonProductTypeGroup/update'
:
'amazonProductTypeGroup/add'
try
{
const
res
=
await
post
(
url
,
{
...
this
.
addForm
})
if
(
res
.
code
!==
200
)
return
this
.
addDialogVisible
=
false
this
.
getGroupList
()
}
catch
(
e
)
{
console
.
error
(
e
)
}
finally
{
this
.
addLoading
=
false
}
},
async
searchCategory
()
{
if
(
!
this
.
keyWord
)
return
const
loading
=
this
.
$loading
({
lock
:
true
})
try
{
const
find
=
this
.
shopList
.
find
((
item
)
=>
item
.
id
===
this
.
shopId
)
const
res
=
await
get
(
'amazon/category/getChildListByKeywords'
,
{
keywords
:
this
.
keyWord
,
marketplaceId
:
find
.
marketplaceId
})
if
(
res
.
code
!==
200
)
return
this
.
productTypeList
=
res
.
data
.
map
((
item
)
=>
{
item
.
browsePathByName
=
item
.
browsePathByName
?.
split
(
','
).
join
(
' > '
)
return
item
})
}
catch
(
e
)
{
console
.
error
(
e
)
}
finally
{
loading
.
close
()
}
},
productTypeChange
(
val
)
{
if
(
!
val
)
return
const
item
=
this
.
productTypeList
.
find
(
(
item
)
=>
item
.
browseNodeId
===
val
)
if
(
!
item
)
return
const
categoryPath
=
item
.
browsePathById
?.
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
=
[]
}
})
},
getCateAttrs
(
id
,
categoryFullPath
,
callback
)
{
if
(
!
id
||
id
.
length
===
0
)
return
if
(
Array
.
isArray
(
id
))
id
=
id
[
id
.
length
-
1
]
const
loading
=
this
.
$loading
({
lock
:
true
})
get
(
'amazon/category/getAttributeByProductType'
,
{
productType
:
id
,
shopId
:
this
.
shopId
})
.
then
(
async
(
res
)
=>
{
if
(
res
.
code
!==
200
)
return
try
{
const
groupRes
=
await
post
(
'amazonProductTypeGroup/groupPropsList'
,
{
groupId
:
this
.
groupingId
,
productType
:
id
,
categoryFullPath
:
categoryFullPath
}
)
if
(
groupRes
.
code
!==
200
)
return
const
groupProps
=
groupRes
.
data
this
.
groupsList
=
groupProps
// eslint-disable-next-line node/no-callback-literal
callback
&&
callback
({
list
:
res
.
data
,
groupProps
})
}
catch
(
e
)
{
console
.
error
(
e
)
}
})
.
finally
(()
=>
{
loading
.
close
()
})
},
categoryTypeChange
(
val
)
{
this
.
$nextTick
(()
=>
{
const
nodes
=
this
.
$refs
.
amCateCascadersRef
.
getCheckedNodes
()
let
targetNode
if
(
this
.
aliCatePathIds
)
{
targetNode
=
nodes
[
nodes
.
length
-
1
]
}
this
.
dataGroupForm
=
{}
if
(
targetNode
)
{
const
{
data
}
=
targetNode
this
.
getCateAttrs
(
data
.
productTypeDefinitions
,
data
.
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
if
(
val
)
{
this
.
getCateAttrs
(
val
,
''
,
({
list
,
groupProps
})
=>
{
if
(
list
)
{
this
.
jsonSchema
=
list
groupProps
.
forEach
((
item
)
=>
{
item
.
propertyList
.
forEach
((
e
)
=>
{
this
.
$set
(
this
.
dataGroupForm
,
e
.
propertyNameEn
,
item
.
groupId
)
})
})
}
else
{
this
.
jsonSchema
=
{}
this
.
dataGroupForm
=
{}
}
})
}
else
{
this
.
jsonSchema
=
{}
this
.
dataGroupForm
=
{}
}
})
},
customCascaderChange
(
val
)
{
console
.
log
(
val
)
},
async
initCate
(
ids
,
callback
)
{
const
shopId
=
this
.
shopList
.
find
(
(
item
)
=>
item
.
id
===
this
.
shopId
)?.
marketplaceId
const
loading
=
this
.
$loading
({
lock
:
true
})
const
arr
=
[
get
(
'amazon/category/getChildListByBrowseNodeId'
,
{
marketplaceId
:
shopId
})
]
for
(
let
i
=
0
;
i
<
ids
.
length
-
1
;
i
++
)
{
arr
.
push
(
get
(
'amazon/category/getChildListByBrowseNodeId'
,
{
browseNodeId
:
ids
[
i
],
marketplaceId
:
shopId
})
)
}
Promise
.
all
(
arr
)
.
then
((
res
)
=>
{
const
catearr
=
res
[
0
].
data
.
map
((
e
)
=>
{
return
{
...
e
,
leaf
:
!
e
.
childId
}
})
let
arr1
=
catearr
for
(
let
i
=
0
;
i
<
ids
.
length
-
1
;
i
++
)
{
for
(
const
iterator
of
arr1
)
{
if
(
iterator
.
browseNodeId
===
ids
[
i
])
{
iterator
.
children
=
res
[
i
+
1
].
data
.
map
((
e
)
=>
{
return
{
...
e
,
leaf
:
!
e
.
childId
}
})
arr1
=
iterator
.
children
}
}
}
this
.
amCateCascaders
=
catearr
callback
&&
callback
(
catearr
)
})
.
finally
(()
=>
{
loading
.
close
()
})
},
lazyLoad
(
node
,
resolve
)
{
if
(
node
.
level
===
0
)
return
const
shopId
=
this
.
shopList
.
find
(
(
item
)
=>
item
.
id
===
this
.
shopId
)?.
marketplaceId
if
(
node
.
children
&&
node
.
children
.
length
>
0
)
{
resolve
([])
}
else
{
get
(
'amazon/category/getChildListByBrowseNodeId'
,
{
browseNodeId
:
node
.
value
,
marketplaceId
:
shopId
})
.
then
((
res
)
=>
{
res
.
data
.
forEach
((
e
)
=>
{
e
.
leaf
=
!
e
.
childId
})
resolve
(
res
.
data
)
})
.
catch
((
err
)
=>
{
console
.
error
(
err
)
resolve
([])
})
}
},
async
customLazyLoad
(
node
,
callback
)
{
try
{
const
res
=
await
get
(
'amazon/category/getChildListByBrowseNodeId'
,
{
browseNodeId
:
node
.
browseNodeId
,
marketplaceId
:
this
.
shopId
})
if
(
res
.
code
!==
200
)
return
callback
(
res
.
data
)
}
catch
(
e
)
{
console
.
error
(
e
)
}
},
async
getAmazonShopList
()
{
const
loading
=
this
.
$loading
({
lock
:
true
})
try
{
const
res
=
await
get
(
'business/shop/amazonList'
)
if
(
res
.
code
!==
200
)
return
this
.
shopList
=
res
.
data
}
catch
(
e
)
{
console
.
error
(
e
)
}
finally
{
loading
.
close
()
}
},
shopChange
(
val
)
{
if
(
!
val
)
return
this
.
initCate
([])
},
async
saveGrouping
()
{
const
nodes
=
this
.
$refs
.
amCateCascadersRef
.
getCheckedNodes
()
let
targetNode
if
(
this
.
aliCatePathIds
)
{
targetNode
=
nodes
[
nodes
.
length
-
1
]
}
const
updatePropertyList
=
[]
const
delPropertyList
=
[]
if
(
Object
.
keys
(
this
.
dataGroupForm
).
length
>
0
)
{
Object
.
keys
(
this
.
dataGroupForm
).
forEach
((
item
)
=>
{
if
(
this
.
dataGroupForm
[
item
]
!==
this
.
cloneDataGroupForm
[
item
])
{
updatePropertyList
.
push
({
propertyNameEn
:
item
,
groupId
:
this
.
dataGroupForm
[
item
]
||
undefined
,
productType
:
targetNode
.
data
.
productTypeDefinitions
,
categoryFullPath
:
targetNode
.
data
.
browsePathByName
})
}
else
{
updatePropertyList
.
push
({
propertyNameEn
:
item
,
groupId
:
this
.
dataGroupForm
[
item
]
||
undefined
,
productType
:
targetNode
.
data
.
productTypeDefinitions
,
categoryFullPath
:
targetNode
.
data
.
browsePathByName
})
}
})
}
if
(
Object
.
keys
(
this
.
cloneDataGroupForm
).
length
>
0
)
{
Object
.
keys
(
this
.
cloneDataGroupForm
)
.
filter
((
item
)
=>
{
return
!
this
.
dataGroupForm
[
item
]
})
.
forEach
((
item
)
=>
{
if
(
!
this
.
dataGroupForm
[
item
])
{
delPropertyList
.
push
({
propertyNameEn
:
item
,
productType
:
targetNode
.
data
.
productTypeDefinitions
,
categoryFullPath
:
targetNode
.
data
.
browsePathByName
,
groupId
:
this
.
cloneDataGroupForm
[
item
]
})
}
})
}
try
{
const
res
=
await
post
(
'amazonProductGroupProperty/batchUpdate'
,
{
updatePropertyList
,
delPropertyList
})
if
(
res
.
code
!==
200
)
return
this
.
selectedAttr
=
[]
this
.
$message
.
success
(
'设置分组成功'
)
}
catch
(
e
)
{
console
.
error
(
e
)
}
},
async
deleteGroup
(
item
)
{
this
.
$confirm
(
`确定要删除分组 "
${
item
.
name
}
" 吗?删除后该分组下的属性将移至全部分组。`
,
'提示'
,
{
confirmButtonText
:
'确定'
,
cancelButtonText
:
'取消'
,
type
:
'warning'
}
).
then
(
async
()
=>
{
try
{
// 先获取该分组下的所有属性
const
propertiesRes
=
await
post
(
'amazonProductTypeGroup/getGroupProperties'
,
{
groupId
:
item
.
id
}
)
if
(
propertiesRes
.
code
===
200
&&
propertiesRes
.
data
.
length
>
0
)
{
// 将该分组下的属性移至全部分组(groupId为0或null)
const
updatePropertyList
=
propertiesRes
.
data
.
map
((
prop
)
=>
({
propertyNameEn
:
prop
.
propertyNameEn
,
groupId
:
null
,
// 移至全部分组
productType
:
prop
.
productType
,
categoryFullPath
:
prop
.
categoryFullPath
}))
await
post
(
'amazonProductGroupProperty/batchUpdate'
,
{
updatePropertyList
,
delPropertyList
:
[]
})
}
// 删除分组
const
res
=
await
post
(
'amazonProductTypeGroup/delete'
,
{
id
:
item
.
id
})
if
(
res
.
code
!==
200
)
return
this
.
$message
.
success
(
'删除分组成功,该分组下的属性已移至全部分组'
)
this
.
getGroupList
()
// 如果当前选中的是被删除的分组,切换到全部分组
if
(
this
.
currentGroupId
===
item
.
id
)
{
this
.
currentGroupId
=
0
}
}
catch
(
e
)
{
console
.
error
(
e
)
this
.
$message
.
error
(
'删除分组失败'
)
}
})
},
async
batchDeleteGroups
()
{
if
(
this
.
selectedGroups
.
length
===
0
)
{
this
.
$message
.
warning
(
'请选择要删除的分组'
)
return
}
this
.
$confirm
(
`确定要批量删除选中的
${
this
.
selectedGroups
.
length
}
个分组吗?删除后这些分组下的属性将移至全部分组。`
,
'提示'
,
{
confirmButtonText
:
'确定'
,
cancelButtonText
:
'取消'
,
type
:
'warning'
}
).
then
(
async
()
=>
{
try
{
let
allProperties
=
[]
const
groups
=
this
.
groupsList
.
filter
((
item
)
=>
this
.
selectedGroups
.
includes
(
item
.
id
)
)
if
(
groups
.
length
>
0
)
{
allProperties
=
groups
.
map
((
e
)
=>
e
.
propertyList
).
flat
()
}
if
(
allProperties
.
length
>
0
)
{
allProperties
.
forEach
((
item
)
=>
{
this
.
$set
(
this
.
dataGroupForm
,
item
.
propertyNameEn
,
''
)
})
}
const
res
=
await
get
(
'amazonProductTypeGroup/delete'
,
{
ids
:
this
.
selectedGroups
.
join
(
','
)
})
if
(
res
.
code
!==
200
)
return
this
.
$message
.
success
(
'批量删除分组成功'
)
this
.
getGroupList
()
this
.
selectedGroups
=
[]
if
(
this
.
selectedGroups
.
includes
(
this
.
currentGroupId
))
{
this
.
currentGroupId
=
0
}
}
catch
(
e
)
{
console
.
error
(
e
)
this
.
$message
.
error
(
'批量删除分组失败'
)
}
})
},
toggleGroupSelection
(
groupId
)
{
const
index
=
this
.
selectedGroups
.
indexOf
(
groupId
)
if
(
index
>
-
1
)
{
this
.
selectedGroups
.
splice
(
index
,
1
)
}
else
{
this
.
selectedGroups
.
push
(
groupId
)
}
},
selectAllGroups
()
{
this
.
selectedGroups
=
this
.
groupsList
.
map
((
group
)
=>
group
.
id
)
},
clearAllGroups
()
{
this
.
selectedGroups
=
[]
},
resetGrouping
()
{
this
.
dataGroupForm
=
{}
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.amazon-attribute-grouping
{
height
:
100%
;
overflow
:
hidden
;
display
:
flex
;
gap
:
10px
;
}
.group-status-box
{
overflow
:
auto
;
}
.left-group-status
{
width
:
300px
;
height
:
100%
;
border-right
:
2px
solid
#e5e5e5
;
padding-right
:
10px
;
display
:
flex
;
flex-direction
:
column
;
.add-group
{
text-align
:
right
;
margin-bottom
:
10px
;
.group-select-actions
{
margin-top
:
5px
;
text-align
:
center
;
.selection-info
{
display
:
block
;
font-size
:
12px
;
color
:
#409eff
;
margin-top
:
3px
;
}
}
}
}
.right-group-content
{
flex
:
1
;
overflow
:
hidden
;
display
:
flex
;
flex-direction
:
column
;
gap
:
10px
;
.attribute-box
{
flex
:
1
;
overflow
:
hidden
;
border
:
1px
solid
#eee
;
display
:
flex
;
flex-direction
:
column
;
padding
:
6px
;
.attribute-content
{
flex
:
1
;
overflow
:
hidden
;
}
.attribute-footer
{
text-align
:
right
;
}
}
}
.group-status-item
{
cursor
:
pointer
;
font-size
:
14px
;
border-radius
:
4px
;
border
:
1px
solid
#e5e5e5
;
margin-bottom
:
6px
;
padding
:
6px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
position
:
relative
;
height
:
60px
;
.operate-group
{
position
:
absolute
;
right
:
2px
;
bottom
:
0
;
background-color
:
#fff
;
border-radius
:
4px
;
}
&
.active
{
border-color
:
#67c23a
;
color
:
#67c23a
;
border-width
:
2px
;
font-weight
:
bold
;
}
.group-checkbox
{
position
:
absolute
;
left
:
8px
;
top
:
8px
;
z-index
:
1
;
.custom-checkbox
{
width
:
14px
;
height
:
14px
;
border
:
1px
solid
#dcdfe6
;
border-radius
:
2px
;
background-color
:
#fff
;
cursor
:
pointer
;
position
:
relative
;
transition
:
all
0.3s
;
&:hover
{
border-color
:
#409eff
;
}
&
.active
{
background-color
:
#409eff
;
border-color
:
#409eff
;
&::after
{
content
:
''
;
position
:
absolute
;
top
:
0px
;
left
:
4px
;
width
:
4px
;
height
:
8px
;
border
:
2px
solid
#fff
;
border-top
:
none
;
border-left
:
none
;
transform
:
rotate
(
45deg
);
}
}
}
}
}
.category-item
{
display
:
flex
;
align-items
:
center
;
gap
:
10px
;
&:not(:last-child)
{
margin-bottom
:
10px
;
}
}
.category-title
{
width
:
60px
;
text-align
:
right
;
font-size
:
14px
;
color
:
#606266
;
}
.group-name
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.attribute
{
display
:
grid
;
grid-template-columns
:
repeat
(
4
,
minmax
(
100px
,
1
fr
));
gap
:
10px
;
/* padding: 10px; */
}
.attribute-item
{
border
:
1px
solid
#eee
;
border-radius
:
4px
;
padding
:
10px
;
display
:
flex
;
align-items
:
center
;
gap
:
5px
;
position
:
relative
;
.select-group-icon
{
position
:
absolute
;
left
:
2px
;
top
:
2px
;
width
:
10px
;
height
:
10px
;
}
.check-icon
{
width
:
16px
;
height
:
16px
;
border
:
1px
solid
#eee
;
box-shadow
:
0px
2px
3px
0px
rgba
(
0
,
0
,
0
,
0.4
)
inset
;
border-radius
:
50%
;
cursor
:
pointer
;
position
:
relative
;
&.active
{
background
:
#4168ff
;
position
:
relative
;
border-color
:
#4168ff
;
}
&
.active
::after
{
position
:
absolute
;
content
:
''
;
top
:
0px
;
left
:
4px
;
width
:
4px
;
height
:
8px
;
border-width
:
2px
;
border-style
:
solid
;
border-color
:
transparent
#fff
#fff
transparent
;
transform
:
rotate
(
45deg
)
scale
(
0.8
);
}
}
}
.visible-item-properties
{
display
:
none
;
}
.attribute-item-title
{
flex
:
1
;
font-size
:
14px
;
color
:
#606266
;
display
:
flex
;
align-items
:
center
;
overflow
:
hidden
;
gap
:
2px
;
.attribute-item-title-text
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
.attribute-item-content
{
width
:
100px
;
}
.attribute-header
{
text-align
:
right
;
margin-bottom
:
10px
;
}
.attribute-item-description
{
font-size
:
12px
;
color
:
#999
;
}
</
style
>
<
style
lang=
"scss"
>
.attribute-item-select
{
.el-input__inner
{
color
:
#e6a23c
;
font-weight
:
500
;
}
}
.custom-popper-select
{
.el-select-dropdown__item
{
border-bottom
:
1px
solid
#ddd
;
height
:
unset
;
}
}
.is-selected
{
color
:
#409eff
!important
;
font-weight
:
bold
;
}
</
style
>
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