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
758d58ae
Commit
758d58ae
authored
Dec 09, 2024
by
zhuzhequan
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'zzq' into 'dev'
产品模板提交 See merge request
!52
parents
f7e43382
31564197
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
771 additions
and
1 deletions
+771
-1
src/router/index.js
+5
-0
src/views/home/navMenu.vue
+8
-0
src/views/import-template/index.vue
+757
-0
vue.config.js
+1
-1
No files found.
src/router/index.js
View file @
758d58ae
...
@@ -149,6 +149,11 @@ const routes = [
...
@@ -149,6 +149,11 @@ const routes = [
component
:
()
=>
import
(
'@/views/production/AssistantManage.vue'
),
component
:
()
=>
import
(
'@/views/production/AssistantManage.vue'
),
name
:
'production_assistant_manage'
,
name
:
'production_assistant_manage'
,
meta
:
{
title
:
'应用版本管理'
}
meta
:
{
title
:
'应用版本管理'
}
},
{
path
:
'/saas/import-template'
,
component
:
()
=>
import
(
'@/views/import-template/index.vue'
),
name
:
'import-template'
,
meta
:
{
title
:
'亚马逊导入模板'
}
},
},
{
{
path
:
'/dynamicForm'
,
path
:
'/dynamicForm'
,
...
...
src/views/home/navMenu.vue
View file @
758d58ae
...
@@ -315,6 +315,14 @@ export default {
...
@@ -315,6 +315,14 @@ export default {
icon
:
'el-icon-box'
,
icon
:
'el-icon-box'
,
index
:
'/saas/sku-manage'
,
index
:
'/saas/sku-manage'
,
children
:
[]
children
:
[]
},
{
id
:
11
,
path
:
''
,
label
:
'亚马逊导入模板'
,
icon
:
'el-icon-box'
,
index
:
'/saas/import-template'
,
children
:
[]
}
}
// {
// {
// id: 11,
// id: 11,
...
...
src/views/import-template/index.vue
0 → 100644
View file @
758d58ae
<
template
>
<div
class=
"wraper"
>
<el-form
:inline=
"true"
size=
"mini"
>
<el-form-item>
<el-button
type=
"primary"
@
click=
"create"
>
新增
</el-button>
</el-form-item>
</el-form>
<div
class=
"table_wrap"
v-loading=
"loading"
>
<table-vue
:sourceData=
"sourceData"
ref=
"multipleTable"
:tableColumns=
"tableColumns"
@
currentChange=
"currentTabFn"
:rowclass=
"cellClass"
@
selectionChange=
"selectionChange"
></table-vue>
</div>
<div
class=
"pagination"
>
<el-pagination
layout=
"sizes, total, prev, pager, next, jumper"
background
:total=
"paginationOptions.total"
:page-size=
"paginationOptions.pageSize"
:current-page=
"paginationOptions.currentPage"
@
size-change=
"sizeChange"
@
current-change=
"onCurrentChange"
>
</el-pagination>
</div>
<!-- 弹出层 -->
<el-dialog
:close-on-click-modal=
"false"
:title=
"is_title == 1 ? '新增' : '编辑'"
:visible
.
sync=
"dialogVisible"
width=
"400px"
>
<el-form
label-position=
"right"
label-width=
"80px"
size=
"mini"
:inline=
"true"
:model=
"templateform"
:rules=
"addRules"
ref=
"templateform"
>
<el-form-item
label=
"模板名称"
prop=
"templateName"
>
<el-input
style=
"width: 100%;"
v-model=
"templateform.templateName"
placeholder=
"请输入模板名称"
></el-input>
</el-form-item>
<el-form-item
label=
"产品类型"
prop=
"productType"
>
<el-select
placeholder=
"请选择产品类型"
style=
"width: 100%;"
clearable
filterable
v-model=
"templateform.productType"
>
<el-option
:label=
"item"
:value=
"item"
v-for=
"item in productTypeList"
:key=
"item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"分组索引"
prop=
"typeGroupIdx"
>
<el-input
v-model=
"templateform.typeGroupIdx"
placeholder=
"请输入分组索引"
></el-input>
</el-form-item>
<el-form-item
label=
"属性索引"
prop=
"typeNameIdx"
>
<el-input
v-model=
"templateform.typeNameIdx"
placeholder=
"请输入属性索引"
></el-input>
</el-form-item>
<el-form-item
label=
"模板"
prop=
"file"
>
<el-upload
action=
""
:show-file-list=
"true"
:before-upload=
"beforeUpload"
:file-list=
"fileList"
>
<el-button
type=
"primary"
>
点击上传
</el-button>
</el-upload>
</el-form-item>
</el-form>
<span
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"dialogVisible = false"
size=
"mini"
style=
"width: 100px"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"template()"
size=
"mini"
style=
"width: 100px"
>
确认
</el-button>
</span>
</el-dialog>
<el-dialog
v-loading=
"dialogLoading"
:close-on-click-modal=
"false"
title=
"属性管理"
:visible
.
sync=
"attrVisible"
width=
"80%"
>
<el-form
v-if=
"attrList.length===0"
label-position=
"right"
label-width=
"80px"
size=
"mini"
:inline=
"true"
:model=
"attrform"
ref=
"templateform"
>
<el-form-item
label=
"文件"
required
prop=
"file"
>
<el-upload
action=
""
:show-file-list=
"true"
:before-upload=
"beforeUploadAttr"
:file-list=
"fileListAttr"
>
<el-button
type=
"primary"
>
点击上传
</el-button>
</el-upload>
</el-form-item>
</el-form>
<span
v-if=
"attrList.length===0"
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"attrVisible = false"
size=
"mini"
style=
"width: 100px"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"attrFileSave()"
size=
"mini"
style=
"width: 100px"
>
确认
</el-button>
</span>
<div
class=
"attr-list"
>
<el-tabs>
<el-tab-pane
v-for=
"it in attrList"
:key=
"it.id"
:label=
"it.propGroup"
>
<el-row
:gutter=
"10"
>
<el-col
:span=
"4"
v-for=
"(item,index) in it.children"
:key=
"item.id"
>
<div
class=
"li"
>
<span
class=
"name"
v-if=
"!item.isEdit"
@
click=
"setEdit(item)"
>
{{
item
.
propName
}}
</span>
<div
class=
"input"
v-else
>
<el-input
size=
"mini"
v-model=
"item.propName"
clearable
></el-input>
<i
@
click=
"setEdit(item)"
style=
"color: green"
class=
"el-icon-circle-check"
></i>
</div>
<div
class=
"right"
>
<i
@
click=
"it.children.splice(index,1)"
style=
"color: red"
class=
"el-icon-close"
></i>
<el-popover
placement=
"right"
width=
"400"
v-model=
"item.show"
trigger=
"manual"
>
<el-form
:model=
"item"
>
<el-form-item
label=
"数据类型"
>
<el-radio-group
v-model=
"item.inputType"
>
<el-radio
label=
"input"
>
输入框
</el-radio>
<el-radio
label=
"radio"
>
单选
</el-radio>
<el-radio
label=
"select"
>
多选
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if=
"item.inputType!=='input'"
label=
"选项"
>
<el-button
@
click=
"setChildrenAdd(item)"
type=
"primary"
size=
"mini"
>
添加
</el-button>
<ul
style=
"max-height: 200px;overflow-y: scroll"
>
<li
style=
"display: flex;align-items: center"
v-for=
"(o,io) in item.children"
:key=
"io"
>
<el-input
size=
"mini"
style=
"width: 80%;margin-right: 15px"
placeholder=
"选项"
clearable
v-model=
"o.inputValue"
></el-input>
<i
@
click=
"item.children.splice(io,1)"
class=
"el-icon-close"
style=
"color: red;margin-left: 10px;cursor:pointer;"
></i>
</li>
</ul>
</el-form-item>
<el-form-item>
<div
class=
"btn"
style=
"display: flex;justify-content: center"
>
<el-button
@
click=
"cancelSave(item)"
style=
"margin-right: 20px"
size=
"mini"
>
取消
</el-button>
<el-button
@
click=
"saveItem(item)"
size=
"mini"
type=
"primary"
>
保存
</el-button>
</div>
</el-form-item>
</el-form>
<i
@
click=
"$set(item,'show',!item.show)"
slot=
"reference"
class=
"el-icon-setting"
></i>
</el-popover>
<el-checkbox
style=
"margin-right: 5px"
v-model=
"item.required"
></el-checkbox>
</div>
</div>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</div>
<span
v-if=
"attrList.length"
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"attrVisible = false"
size=
"mini"
style=
"width: 100px"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"saveAttr()"
size=
"mini"
style=
"width: 100px"
>
确认
</el-button>
</span>
</el-dialog>
</div>
</
template
>
<
script
>
import
axios
,
{
get
,
post
}
from
'../../common/api/axios'
import
tableVue
from
'@/common/components/base/tableView.vue'
export
default
{
name
:
'basics_currency'
,
components
:
{
tableVue
},
data
()
{
return
{
is_title
:
1
,
select
:
''
,
sourceData
:
[],
fileList
:
[],
productTypeList
:
[],
attrList
:
[],
fileListAttr
:
[],
searchForm
:
{},
attrform
:
{},
dialogVisible
:
false
,
dialogLoading
:
false
,
attrVisible
:
false
,
templateform
:
{},
templateform2
:
null
,
formId
:
null
,
paginationOptions
:
{
pageSize
:
10
,
currentPage
:
1
,
total
:
0
},
loading
:
false
}
},
created
()
{
this
.
getList
()
this
.
getProductType
()
this
.
templateform2
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
templateform
)
)
},
computed
:
{
addRules
()
{
const
obj
=
{
templateName
:
[
{
required
:
true
,
message
:
'请输入模板名称'
,
trigger
:
'blur'
}
],
productType
:
[
{
required
:
true
,
message
:
'请选择产品类型'
,
trigger
:
'change'
}
],
typeGroupIdx
:
[
{
required
:
true
,
message
:
'请输入分组索引'
,
trigger
:
'blur'
}
],
typeNameIdx
:
[
{
required
:
true
,
message
:
'请输入属性索引'
,
trigger
:
'blur'
}
]
}
if
(
this
.
is_title
!==
0
)
{
obj
.
file
=
[
{
required
:
true
,
message
:
'请上传模板'
,
trigger
:
'blur'
}
]
}
return
obj
},
tableColumns
()
{
return
[
{
label
:
'模板名称'
,
key
:
'templateName'
},
{
label
:
'产品类型'
,
key
:
'productType'
},
{
label
:
'分组索引'
,
key
:
'typeGroupIdx'
},
{
label
:
'属性索引'
,
key
:
'typeNameIdx'
},
{
label
:
'操作'
,
width
:
120
,
render
:
(
item
)
=>
(
<
div
>
{(
<
span
class
=
"icon-view icon-tools-view"
title
=
"属性管理"
onClick
=
{()
=>
this
.
getAttr
(
item
)}
>
<
i
class
=
"el-icon-tickets"
><
/i
>
<
/span
>
)
}
{
(
<
span
class
=
"icon-view icon-edit-view"
title
=
"编辑"
onClick
=
{()
=>
this
.
edit
(
item
)}
>
<
i
class
=
"el-icon-edit"
><
/i
>
<
/span
>
)}
{(
<
span
class
=
"icon-view icon-del-view"
title
=
"删除"
onClick
=
{()
=>
this
.
deleteAnnounces
(
item
)}
>
<
i
class
=
"el-icon-delete"
><
/i
>
<
/span
>
)}
<
/div
>
)
}
]
}
},
methods
:
{
async
deleteAnnounces
(
item
)
{
this
.
$confirm
(
'确定删除选中的数据?'
,
'提示'
,
{
confirmButtonText
:
'确定'
,
cancelButtonText
:
'取消'
,
type
:
'warning'
})
.
then
(
async
()
=>
{
try
{
const
res
=
await
get
(
'amazonProductTypeTemplate/delete?ids='
+
item
.
id
)
if
(
res
.
code
!==
200
)
return
this
.
$message
.
success
(
res
.
message
)
this
.
getList
()
}
catch
(
e
)
{
console
.
error
(
e
)
}
})
},
saveAttr
()
{
const
attrList
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
attrList
))
attrList
.
forEach
(
item
=>
{
item
.
children
.
forEach
(
el
=>
{
if
(
el
.
children
&&
el
.
children
.
length
>
0
)
{
el
.
inputValue
=
el
.
children
.
map
(
el
=>
el
.
inputValue
).
join
()
}
delete
el
.
children
})
})
post
(
'amazonProductTemplateProp/saveOrUpdatePropList'
,
attrList
).
then
(
res
=>
{
if
(
res
.
code
===
200
)
{
this
.
attrVisible
=
false
this
.
$message
.
success
(
'操作成功'
)
}
})
},
saveItem
(
item
)
{
if
(
!
item
.
inputType
)
{
return
this
.
$message
.
warning
(
'请选择数据类型'
)
}
if
(
item
.
inputType
!==
'input'
)
{
const
len
=
item
.
children
.
filter
(
el
=>
!
el
.
inputValue
)
if
(
item
.
children
.
length
===
0
)
{
return
this
.
$message
.
warning
(
'选项不能为空'
)
}
if
(
len
.
length
>
0
)
{
return
this
.
$message
.
warning
(
'输入不能为空'
)
}
}
this
.
$set
(
item
,
'show'
,
!
item
.
show
)
},
cancelSave
(
item
)
{
this
.
$set
(
item
,
'inputType'
,
null
)
this
.
$set
(
item
,
'children'
,
[])
this
.
$set
(
item
,
'show'
,
!
item
.
show
)
},
setChildrenAdd
(
item
)
{
if
(
!
item
.
children
)
item
.
children
=
[]
const
arr
=
item
.
children
arr
.
push
({
inputValue
:
''
})
this
.
$set
(
item
,
'children'
,
arr
)
},
setEdit
(
item
)
{
this
.
$set
(
item
,
'isEdit'
,
!
item
.
isEdit
)
},
edit
(
item
)
{
this
.
templateform
=
JSON
.
parse
(
JSON
.
stringify
(
item
))
this
.
dialogVisible
=
true
this
.
is_title
=
0
if
(
item
.
path
)
{
this
.
fileList
=
[
{
name
:
item
.
path
}
]
delete
this
.
templateform
.
file
delete
this
.
templateform
.
createTime
delete
this
.
templateform
.
updateTime
delete
this
.
templateform
.
_id
}
},
getAttr
(
item
)
{
post
(
`amazonProductTemplateProp/productTypePropList?productType=
${
item
.
productType
}
`
).
then
(
res
=>
{
console
.
log
(
res
)
if
(
res
.
data
.
length
===
0
)
{
this
.
attrform
=
{
templateId
:
item
.
id
,
productType
:
item
.
productType
}
this
.
fileListAttr
=
[]
this
.
attrList
=
[]
}
else
{
this
.
fileListAttr
=
[]
const
attrList
=
JSON
.
parse
(
JSON
.
stringify
(
res
.
data
))
attrList
.
forEach
(
item
=>
{
item
.
children
.
forEach
(
el
=>
{
if
(
el
.
inputValue
)
{
el
.
children
=
el
.
inputValue
.
split
(
','
).
map
(
el
=>
{
return
{
inputValue
:
el
}
})
}
else
{
el
.
children
=
[]
}
})
})
this
.
attrList
=
attrList
}
this
.
attrVisible
=
true
})
},
attrFileSave
()
{
if
(
!
this
.
attrform
.
file
)
{
return
this
.
$message
.
warning
(
'请选择文件'
)
}
this
.
dialogLoading
=
true
const
data
=
new
FormData
()
data
.
append
(
'file'
,
this
.
attrform
.
file
)
data
.
append
(
'templateId'
,
this
.
attrform
.
templateId
)
data
.
append
(
'productType'
,
this
.
attrform
.
productType
)
post
(
'amazonProductTemplateProp/uploadSaveProp'
,
data
).
then
(
res
=>
{
if
(
res
.
code
===
200
)
{
this
.
attrList
=
res
.
data
this
.
$message
.
success
(
'操作成功'
)
}
this
.
dialogLoading
=
false
})
},
beforeUpload
(
f
)
{
this
.
fileList
=
[{
name
:
f
.
name
}]
this
.
templateform
.
file
=
f
return
false
},
beforeUploadAttr
(
f
)
{
this
.
fileListAttr
=
[{
name
:
f
.
name
}]
this
.
attrform
.
file
=
f
return
false
},
getProductType
()
{
axios
.
post
(
'amazonProductTypeTemplate/getProductTypeList'
)
.
then
(
res
=>
{
this
.
productTypeList
=
res
.
data
})
},
create
()
{
this
.
dialogVisible
=
true
this
.
is_title
=
1
this
.
templateform
=
{}
this
.
fileList
=
[]
},
onCurrentChange
(
currentPage
)
{
this
.
paginationOptions
.
currentPage
=
currentPage
this
.
getList
()
},
sizeChange
(
pageSize
)
{
this
.
paginationOptions
.
pageSize
=
pageSize
this
.
getList
()
},
cellClass
({
row
})
{
if
(
row
.
authAuditFlag
===
1
)
{
return
'first'
}
else
{
return
''
}
},
selectionChange
(
selection
)
{
if
(
selection
.
length
>
0
)
{
this
.
select
=
selection
}
},
search
()
{
this
.
paginationOptions
.
currentPage
=
1
this
.
getList
()
},
currentTabFn
(
val
)
{
if
(
val
.
row
)
{
this
.
formId
=
val
.
row
.
id
}
},
// 修改新增
addDialog
(
i
,
v
=
null
)
{
if
(
i
===
2
)
{
if
(
v
)
this
.
formId
=
v
.
id
if
(
!
this
.
formId
)
{
return
this
.
$message
(
'请勾选至少一条记录'
)
}
this
.
selectSection
()
}
else
{
this
.
$nextTick
(()
=>
{
this
.
templateform
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
templateform2
)
)
})
this
.
is_title
=
i
this
.
dialogVisible
=
true
}
if
(
this
.
$refs
.
templateform
)
{
this
.
$refs
.
templateform
.
resetFields
()
}
},
template
()
{
this
.
addSection
()
},
setpaginationOptions
(
opt
)
{
for
(
const
key
in
opt
)
{
this
.
paginationOptions
[
key
]
=
opt
[
key
]
}
this
.
getList
()
},
// 查询
getList
()
{
this
.
loading
=
true
const
{
pageSize
,
currentPage
}
=
this
.
paginationOptions
axios
.
post
(
'amazonProductTypeTemplate/list_page'
,
{
pageSize
,
currentPage
,
...
this
.
searchForm
})
.
then
(
res
=>
{
this
.
loading
=
false
if
(
res
.
code
===
200
)
{
this
.
sourceData
=
res
.
data
.
records
this
.
paginationOptions
.
total
=
res
.
data
.
total
}
else
{
this
.
$alert
(
res
.
message
,
'错误提示'
,
{
dangerouslyUseHTMLString
:
true
})
}
})
},
// 新增
addSection
()
{
const
url
=
this
.
is_title
===
0
?
'amazonProductTypeTemplate/update'
:
'amazonProductTypeTemplate/uploadAmazonTemplate'
if
(
this
.
is_title
!==
0
)
{
if
(
!
this
.
templateform
.
file
)
{
return
this
.
$message
.
warning
(
'请选择模板文件'
)
}
}
this
.
$refs
.
templateform
.
validate
(
valid
=>
{
if
(
valid
)
{
const
fm
=
new
FormData
()
for
(
const
k
in
this
.
templateform
)
{
fm
.
append
(
k
,
this
.
templateform
[
k
])
}
axios
.
post
(
url
,
fm
).
then
(
res
=>
{
if
(
res
.
code
===
200
)
{
this
.
dialogVisible
=
false
this
.
getList
()
}
})
}
})
},
// 删除
deleteSection
(
v
)
{
let
arr
=
[]
if
(
v
)
{
arr
.
push
(
v
)
}
else
{
arr
=
this
.
select
}
const
leng
=
arr
.
length
if
(
leng
===
0
)
{
return
this
.
$message
(
'请勾选至少一条记录'
)
}
let
ids
=
[]
ids
=
arr
.
map
(
v
=>
{
return
v
.
id
})
ids
=
ids
.
join
()
this
.
$confirm
(
'确定删除选中的信息?'
,
'提示'
,
{
confirmButtonText
:
'确定'
,
cancelButtonText
:
'取消'
,
type
:
'warning'
})
.
then
(()
=>
{
axios
.
get
(
'platform/user/delete'
,
{
params
:
{
ids
:
ids
}
})
.
then
(
res
=>
{
if
(
res
.
code
===
200
)
{
this
.
$message
({
type
:
'success'
,
message
:
'删除成功!'
})
this
.
getList
()
}
else
{
this
.
$alert
(
res
.
message
,
'错误提示'
,
{
dangerouslyUseHTMLString
:
true
})
}
})
})
.
catch
(()
=>
{
})
}
}
}
</
script
>
<
style
scoped
>
.wraper
{
display
:
flex
;
flex-direction
:
column
;
height
:
100%
;
}
.table_wrap
{
flex
:
1
;
}
.circle
{
display
:
inline-block
;
height
:
10px
;
width
:
10px
;
border-radius
:
5px
;
margin-right
:
5px
;
}
.my-table
>>>
.first
{
background-color
:
red
!important
;
color
:
#fff
!important
;
}
.attr-list
{
.li
{
padding
:
5px
;
margin
:
5px
10px
;
width
:
100%
;
height
:
37px
;
text-align
:
left
;
border
:
1px
solid
#ececec
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
.name
{
white-space
:
nowrap
;
flex
:
1
;
flex-shrink
:
0
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
.right
{
i
{
font-size
:
12px
;
margin-right
:
10px
;
}
}
.input
{
flex
:
1
;
flex-shrink
:
0
;
overflow
:
hidden
;
display
:
flex
;
align-items
:
center
;
i
{
margin
:
0
3px
;
}
}
i
{
color
:
gray
;
margin-left
:
5px
;
cursor
:
pointer
;
}
}
}
</
style
>
<
style
lang=
"scss"
>
.el-dialog__wrapper
{
.el-form
{
.el-form-item
{
display
:
flex
;
.el-form-item__content
{
flex-shrink
:
0
;
flex
:
1
;
overflow
:
hidden
;
}
}
}
}
</
style
>
vue.config.js
View file @
758d58ae
...
@@ -6,7 +6,7 @@ module.exports = defineConfig({
...
@@ -6,7 +6,7 @@ module.exports = defineConfig({
host
:
''
,
host
:
''
,
proxy
:
{
proxy
:
{
'/api'
:
{
'/api'
:
{
target
:
'http://10.168.31.
188
:8096'
,
target
:
'http://10.168.31.
222
:8096'
,
changeOrigin
:
true
,
changeOrigin
:
true
,
// pathRewrite: {
// pathRewrite: {
// '^/api': '',
// '^/api': '',
...
...
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