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
dc8f0564
Commit
dc8f0564
authored
Aug 21, 2025
by
qinjianhui
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: amazon 属性分类
parent
70dd4a5c
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
841 additions
and
0 deletions
+841
-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
+827
-0
No files found.
package-lock.json
View file @
dc8f0564
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/router/index.js
View file @
dc8f0564
...
@@ -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
:
'Amazon attribute grouping'
}
},
{
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 @
dc8f0564
...
@@ -344,6 +344,14 @@ export default {
...
@@ -344,6 +344,14 @@ export default {
children
:
[]
children
:
[]
},
},
{
{
id
:
6
_3
,
path
:
''
,
label
:
'Amazon attribute grouping'
,
icon
:
'el-icon-s-check'
,
index
:
'/operation/amazonAttributeGrouping'
,
children
:
[]
},
{
id
:
9
,
id
:
9
,
path
:
''
,
path
:
''
,
label
:
'sql执行工具'
,
label
:
'sql执行工具'
,
...
...
src/views/operation/amazon/amazonAttributeGrouping.vue
0 → 100644
View file @
dc8f0564
<
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>
</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">
<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.marketplaceId"
></el-option>
</el-select>
</div>
<div
class=
"category-title"
>
<span>
Category
</span>
</div>
<div
style=
"flex: 1"
>
<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
v-model=
"productType"
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"
>
重置
</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=
"店铺"
>
<el-select
v-model=
"addForm.shopId"
placeholder=
"请选择店铺"
style=
"width: 100%"
@
change=
"shopChange"
>
<el-option
v-for=
"item in shopList"
:key=
"item.id"
:label=
"item.shopName"
:value=
"item.marketplaceId"
></el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"分类"
>
<el-cascader
style=
"width: 100%"
size=
"medium"
:options=
"amCateCascaders"
ref=
"addGroupCascaderRef"
placeholder=
"请选择分类"
v-model=
"addForm.productType"
filterable
:props=
"
{
label: 'browseNodeName',
value: 'browseNodeId',
lazy: true,
lazyLoad: lazyLoad
}">
</el-cascader>
</el-form-item>
-->
<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.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'
export
default
{
name
:
'amazonAttributeGrouping'
,
data
()
{
return
{
groupsList
:
[],
keyWord
:
''
,
productTypeList
:
[],
amCateCascaders
:
[],
aliCatePathIds
:
[],
jsonSchema
:
{},
productType
:
''
,
shopList
:
[],
shopId
:
''
,
addDialogVisible
:
false
,
addForm
:
{
cnName
:
''
,
enName
:
''
,
remark
:
''
},
addLoading
:
false
,
groupSearchForm
:
{
productType
:
''
},
selectedAttr
:
[],
dataGroupForm
:
{},
setGroupDialogVisible
:
false
,
setGroupLoading
:
false
,
groupingId
:
''
,
currentGroupId
:
0
,
cloneDataGroupForm
:
{}
}
},
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
=
{}
Object
.
keys
(
this
.
dataGroupForm
).
forEach
((
key
)
=>
{
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
:
''
}
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
}
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
.
marketplaceId
===
this
.
shopId
)
const
res
=
await
get
(
'amazon/category/getChildListByKeywords'
,
{
keywords
:
this
.
keyWord
,
shopId
:
find
.
id
})
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
()
}
},
getCateAttrs
(
id
,
categoryFullPath
,
callback
)
{
if
(
!
id
||
id
.
length
===
0
)
return
if
(
Array
.
isArray
(
id
))
id
=
id
[
id
.
length
-
1
]
const
find
=
this
.
shopList
.
find
(
(
item
)
=>
item
.
marketplaceId
===
this
.
shopId
)
const
loading
=
this
.
$loading
({
lock
:
true
})
get
(
'amazon/category/getAttributeByProductType'
,
{
productType
:
id
,
shopId
:
find
.
id
})
.
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
)
{
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
=
{}
}
},
async
initCate
(
marketplaceId
)
{
const
loading
=
this
.
$loading
({
lock
:
true
})
try
{
const
res
=
await
get
(
'amazon/category/getChildListByBrowseNodeId'
,
{
marketplaceId
})
if
(
res
.
code
!==
200
)
return
this
.
amCateCascaders
=
res
.
data
}
catch
(
e
)
{
console
.
error
(
e
)
}
finally
{
loading
.
close
()
}
},
lazyLoad
(
node
,
resolve
)
{
if
(
node
.
level
===
0
)
return
if
(
node
.
children
&&
node
.
children
.
length
>
0
)
{
resolve
([])
}
else
{
get
(
'amazon/category/getChildListByBrowseNodeId'
,
{
browseNodeId
:
node
.
value
,
marketplaceId
:
this
.
shopId
})
.
then
((
res
)
=>
{
res
.
data
.
forEach
((
e
)
=>
{
e
.
leaf
=
!
e
.
childId
})
resolve
(
res
.
data
)
})
.
catch
((
err
)
=>
{
console
.
error
(
err
)
resolve
([])
})
}
},
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
(
val
)
},
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
)
}
}
}
}
</
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
;
}
}
.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
;
}
}
.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
;
}
}
</
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