Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
liuzhen@situdata.com
/
yunxiao-admin-fe
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
6c579989
authored
2020-11-04 20:02:23 +0800
by
zhen
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
产品资料管理联调
1 parent
cfc77b88
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
497 additions
and
185 deletions
.env.development
src/api/productInforManagement.js
src/router/index.js
src/utils/mappingData.js
src/views/editProduct.vue
src/views/productInforManagement.vue
.env.development
View file @
6c57998
...
...
@@ -3,4 +3,5 @@ ENV = 'development'
# base api
# VUE_APP_BASE_API = 'http://192.168.11.67:8096'
VUE_APP_BASE_API = 'https://beta-salecloud-hengan.situdata.com'
VUE_APP_BASE_API = 'http://192.168.10.89:8096'
# VUE_APP_BASE_API = 'https://beta-salecloud-hengan.situdata.com'
...
...
src/api/productInforManagement.js
0 → 100644
View file @
6c57998
import
request
from
'@/utils/request'
/**
* 产品资料管理-列表
* @param {*} data
*/
export
function
getProductList
(
data
)
{
return
request
({
url
:
'/saleCloud/web/product/list'
,
method
:
'post'
,
data
})
}
/**
* 产品资料管理-查看详情
* @param {*} data
*/
export
function
productDetail
(
data
)
{
return
request
({
url
:
'/saleCloud/web/product/detail'
,
method
:
'post'
,
data
})
}
/**
* 产品资料管理-查看详情-编号重复校验
* @param {*} data
*/
export
function
productCodeCheck
(
data
)
{
return
request
({
url
:
'/saleCloud/web/product/code-check'
,
method
:
'post'
,
data
})
}
/**
* 产品资料管理-修改
* @param {*} data
*/
export
function
productEdit
(
data
)
{
return
request
({
url
:
'/saleCloud/web/product/edit'
,
method
:
'post'
,
data
})
}
/**
* 产品资料管理-新增
* @param {*} data
*/
export
function
productAdd
(
data
)
{
return
request
({
url
:
'/saleCloud/web/product/add'
,
method
:
'post'
,
headers
:
{
'Content-Type'
:
'multipart/form-data'
},
data
})
}
src/router/index.js
View file @
6c57998
...
...
@@ -86,6 +86,7 @@ export const constantRoutes = [
name
:
'edit-product'
,
hidden
:
true
,
component
:
()
=>
import
(
'@/views/editProduct'
),
props
:
route
=>
({
idAndCode
:
route
.
query
}),
meta
:
{
title
:
'新增产品'
,
icon
:
'report'
...
...
src/utils/mappingData.js
View file @
6c57998
...
...
@@ -21,3 +21,116 @@ export const PERMISSION_USER_MAP = {
}
export
const
inputMaxLength
=
21
/**
* 产品资料----产品类型
*/
export
const
productTypes
=
[
{
label
:
'全部'
,
value
:
''
},
{
label
:
'健康险'
,
value
:
1
},
{
label
:
'普通险'
,
value
:
2
},
{
label
:
'分红险'
,
value
:
3
},
{
label
:
'万能险'
,
value
:
4
},
{
label
:
'投资连结险'
,
value
:
5
}
]
/**
* 产品资料----险别
*/
export
const
riskTypes
=
[
{
label
:
'全部'
,
value
:
''
},
{
label
:
'主险'
,
value
:
1
},
{
label
:
'附加险'
,
value
:
2
}
]
/**
* 产品资料----上架状态
*/
export
const
shelfType
=
[
{
label
:
'全部'
,
value
:
''
},
{
label
:
'未上架'
,
value
:
0
},
{
label
:
'上架'
,
value
:
1
}
]
/**
* 产品资料----产品渠道
*/
export
const
productChannel
=
[
{
label
:
'全部'
,
value
:
''
},
{
label
:
'个险渠道(FC)'
,
value
:
1
},
{
label
:
'银保渠道(BK)'
,
value
:
2
},
{
label
:
'团险渠道(GP)'
,
value
:
3
},
{
label
:
'多元渠道(AD)'
,
value
:
4
},
{
label
:
'续期渠道(RP)'
,
value
:
5
},
{
label
:
'多元代理渠道'
,
value
:
6
}
]
/**
* 产品资料----文件类型
*/
export
const
fileList
=
[
{
id
:
1
,
type
:
'产品条款'
},
{
id
:
2
,
type
:
'产品说明书'
},
{
id
:
3
,
type
:
'免责条款'
}
]
...
...
src/views/editProduct.vue
View file @
6c57998
<
template
>
<Card>
<h4
class=
"mb10"
>
产品基本属性
</h4>
<el-form
class=
"count-form"
ref=
"form"
size=
"mini"
inline
:model=
"form"
>
<el-form
class=
"count-form"
ref=
"form"
size=
"mini"
inline
:model=
"form"
:rules=
"rules"
>
<div>
<el-form-item
label=
"产品名称"
>
<el-form-item
label=
"产品名称"
prop=
"name"
>
<el-input
v-model
.
trim=
"form.name"
placeholder=
"请输入产品名称"
...
...
@@ -11,41 +18,44 @@
>
</el-input>
</el-form-item>
<el-form-item
label=
"产品类型"
>
<el-form-item
label=
"产品类型"
prop=
"type"
>
<el-select
v-model=
"form.type"
>
<el-option
v-for=
"
(item, index) of p
roductTypes"
:key=
"
`option-$
{index}`
"
v-for=
"
item of comP
roductTypes"
:key=
"
item.value
"
:label=
"item.label"
:value=
"item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"产品编号"
>
<el-form-item
label=
"产品编号"
prop=
"code"
>
<el-input
v-model
.
trim=
"form.
id
"
v-model
.
trim=
"form.
code
"
placeholder=
"请输入产品编号"
:maxlength=
"inputMaxLength"
:disabled=
"!!idAndCode.code"
>
</el-input>
</el-form-item>
<el-form-item
label=
"险别"
>
<el-select
v-model=
"form.
insurance
"
>
<el-form-item
label=
"险别"
prop=
"risk"
>
<el-select
v-model=
"form.
risk
"
>
<el-option
v-for=
"
(item, index) of insurance
Types"
:key=
"
`option-$
{index}`
"
v-for=
"
item of comRisk
Types"
:key=
"
item.value
"
:label=
"item.label"
:value=
"item.value"
></el-option>
</el-select>
</el-form-item>
</div>
<el-form-item
label=
"产品渠道"
>
<el-form-item
label=
"产品渠道"
prop=
"channel"
>
<el-checkbox-group
v-model=
"form.channel"
>
<el-checkbox
label=
"选项一"
></el-checkbox>
<el-checkbox
label=
"选项二"
></el-checkbox>
<el-checkbox
label=
"选项三"
></el-checkbox>
<el-checkbox
label=
"选项四"
></el-checkbox>
<el-checkbox
v-for=
"item of comProductChannel"
:key=
"item.value"
:label=
"item.value"
>
{{
item
.
label
}}
</el-checkbox
>
</el-checkbox-group>
</el-form-item>
</el-form>
...
...
@@ -79,14 +89,14 @@
:auto-upload=
"false"
:on-change=
"onChange"
>
<el-button
type=
"text"
@
click=
"
updateFile(
scope.row.id)"
<el-button
type=
"text"
@
click=
"
trapClick(1,
scope.row.id)"
>
上传
</el-button
>
</el-upload>
<el-button
type=
"text"
@
click=
"
previewFile(
scope.row.id)"
<el-button
type=
"text"
@
click=
"
trapClick(2,
scope.row.id)"
>
预览
</el-button
>
<el-button
type=
"text"
@
click=
"
deleteFile(
scope.row.id)"
<el-button
type=
"text"
@
click=
"
trapClick(3,
scope.row.id)"
>
删除
</el-button
>
</div>
...
...
@@ -94,7 +104,12 @@
</el-table-column>
</el-table>
<div
class=
"title"
>
产品链接
<el-button
type=
"text"
style=
"margin-left:20px"
@
click=
"previewLink"
>
预览
</el-button>
产品链接
<el-button
type=
"text"
style=
"margin-left:20px"
@
click=
"previewLink"
>
预览
</el-button
>
</div>
<el-input
class=
"mb10"
...
...
@@ -104,71 +119,114 @@
v-model=
"productLink"
></el-input>
<div
class=
"bottom"
>
<el-button
type=
"primary"
>
提交
</el-button>
<el-button
type=
"primary"
@
click=
"submit"
>
提交
</el-button>
</div>
</Card>
</template>
<
script
>
import
{
inputMaxLength
}
from
'@/utils/mappingData'
const
productTypes
=
[
{
label
:
'团险'
,
value
:
'1'
}
]
const
insuranceTypes
=
[
{
label
:
'主险'
,
value
:
'1'
},
{
label
:
'附加险'
,
value
:
'2'
}
]
import
{
inputMaxLength
,
riskTypes
,
productTypes
,
productChannel
}
from
'@/utils/mappingData'
import
{
productDetail
,
productCodeCheck
,
productEdit
,
productAdd
}
from
'@/api/productInforManagement'
export
default
{
props
:
[
'idAndCode'
],
data
()
{
const
validateCode
=
async
(
rule
,
value
,
callback
)
=>
{
if
(
!
value
)
{
return
callback
(
new
Error
(
'请输入产品编号'
))
}
const
{
result
}
=
await
productCodeCheck
({
code
:
value
})
if
(
!
result
)
{
return
callback
(
new
Error
(
'产品代码已存在,请重新输入'
))
}
callback
()
}
return
{
inputMaxLength
,
productTypes
,
insuranceTypes
,
form
:
{
name
:
''
,
type
:
''
,
id
:
''
,
insurance
:
''
,
channel
:
''
},
fileList
:
[
{
id
:
0
,
id
:
1
,
type
:
'产品条款'
,
nam
e
:
null
,
fil
e
:
null
fil
e
:
null
,
nam
e
:
null
},
{
id
:
1
,
id
:
2
,
type
:
'产品说明书'
,
nam
e
:
null
,
fil
e
:
null
fil
e
:
null
,
nam
e
:
null
},
{
id
:
2
,
id
:
3
,
type
:
'免责条款'
,
nam
e
:
null
,
fil
e
:
null
fil
e
:
null
,
nam
e
:
null
}
],
form
:
{
name
:
'lztest'
,
type
:
'1'
,
code
:
'123123'
,
risk
:
'1'
,
channel
:
[
1
]
},
rules
:
{
name
:
[{
required
:
true
,
message
:
'请输入产品名称'
,
trigger
:
'blur'
}],
type
:
[
{
required
:
true
,
message
:
'请选择产品类型'
,
trigger
:
'change'
}
],
code
:
[{
required
:
true
,
validator
:
validateCode
,
trigger
:
'blur'
}],
risk
:
[{
required
:
true
,
message
:
'请选择险别'
,
trigger
:
'change'
}],
channel
:
[
{
required
:
true
,
message
:
'请选择产品渠道'
,
trigger
:
'change'
}
]
},
currentFileIndex
:
0
,
productLink
:
''
}
},
computed
:
{
comRiskTypes
()
{
return
riskTypes
.
slice
(
1
)
},
comProductTypes
()
{
return
productTypes
.
slice
(
1
)
},
comProductChannel
()
{
return
productChannel
.
slice
(
1
)
}
},
mounted
()
{
if
(
this
.
idAndCode
.
code
)
{
this
.
handleProductDetail
()
}
},
methods
:
{
updateFile
(
id
)
{
this
.
currentFileIndex
=
id
trapClick
(
type
,
id
)
{
this
.
currentFileIndex
=
this
.
fileList
.
findIndex
(
item
=>
item
.
id
===
id
)
switch
(
type
)
{
case
1
:
break
case
2
:
this
.
previewFile
()
break
case
3
:
this
.
deleteFile
()
break
}
},
async
onChange
(
file
,
fileList
)
{
async
onChange
(
file
)
{
if
(
file
.
raw
.
type
!==
'application/pdf'
)
{
this
.
$message
.
error
(
'支持文件为pdf根式'
)
return
...
...
@@ -177,7 +235,7 @@ export default {
await
this
.
uploadConfirm
()
}
this
.
fileList
[
this
.
currentFileIndex
].
name
=
file
.
name
this
.
fileList
[
this
.
currentFileIndex
].
file
=
file
this
.
fileList
[
this
.
currentFileIndex
].
file
=
file
.
raw
},
uploadConfirm
()
{
return
new
Promise
((
resolve
,
reject
)
=>
{
...
...
@@ -192,11 +250,11 @@ export default {
.
catch
(
e
=>
{})
})
},
previewFile
(
id
)
{
if
(
!
this
.
fileList
[
id
].
file
)
{
previewFile
()
{
if
(
!
this
.
fileList
[
this
.
currentFileIndex
].
file
)
{
return
}
const
file
=
this
.
fileList
[
id
].
file
.
raw
const
file
=
this
.
fileList
[
this
.
currentFileIndex
].
file
.
raw
const
myBlob
=
new
Blob
([
file
],
{
type
:
'application/pdf'
})
...
...
@@ -210,8 +268,8 @@ export default {
link
.
remove
()
URL
.
revokeObjectURL
(
link
.
href
)
},
async
deleteFile
(
id
)
{
if
(
!
this
.
fileList
[
id
].
name
)
{
async
deleteFile
()
{
if
(
!
this
.
fileList
[
this
.
currentFileIndex
].
name
)
{
return
}
await
this
.
deleteConfirm
()
...
...
@@ -236,6 +294,51 @@ export default {
link
.
href
=
this
.
productLink
link
.
target
=
'_blank'
link
.
click
()
},
submit
()
{
this
.
$refs
.
form
.
validate
(
valid
=>
{
if
(
valid
)
{
this
.
editOrAdd
()
}
else
{
return
false
}
})
},
async
editOrAdd
()
{
const
formData
=
this
.
constructorFormData
()
if
(
this
.
idAndCode
.
code
)
{
productEdit
()
}
else
{
const
res
=
await
productAdd
(
formData
)
debugger
}
},
constructorFormData
()
{
const
formData
=
new
FormData
()
for
(
const
key
in
this
.
form
)
{
if
(
key
===
'channel'
)
{
formData
.
append
(
key
,
this
.
form
[
key
].
join
())
}
else
{
formData
.
append
(
key
,
this
.
form
[
key
])
}
}
this
.
fileList
.
forEach
(
item
=>
{
if
(
item
.
name
)
{
formData
.
append
(
`file
${
item
.
id
}
`
,
item
.
file
)
}
})
formData
.
append
(
'link'
,
this
.
productLink
)
return
formData
},
async
handleProductDetail
()
{
const
res
=
await
productDetail
({
id
:
this
.
idAndCode
.
id
,
code
:
this
.
idAndCode
.
code
})
debugger
}
}
}
...
...
src/views/productInforManagement.vue
View file @
6c57998
...
...
@@ -2,10 +2,19 @@
<Card>
<div>
<el-form
class=
"count-form"
ref=
"form"
size=
"mini"
inline
:model=
"form"
>
<el-form-item
label=
"
查询条件
"
>
<el-form-item
label=
"
产品名称
"
>
<el-input
v-model
.
trim=
"form.product"
placeholder=
"产品名称/产品编号"
v-model
.
trim=
"form.name"
placeholder=
"请输入产品名称"
:maxlength=
"inputMaxLength"
>
<i
slot=
"prefix"
class=
"el-icon-search"
></i
></el-input>
</el-form-item>
<el-form-item
label=
"产品编号"
>
<el-input
v-model
.
trim=
"form.code"
placeholder=
"请输入产品编号"
:maxlength=
"inputMaxLength"
>
<i
slot=
"prefix"
class=
"el-icon-search"
></i
...
...
@@ -22,9 +31,9 @@
</el-select>
</el-form-item>
<el-form-item
label=
"险别"
>
<el-select
v-model=
"form.
insurance
"
>
<el-select
v-model=
"form.
risk
"
>
<el-option
v-for=
"(item, index) of
insurance
Types"
v-for=
"(item, index) of
risk
Types"
:key=
"`option-$
{index}`"
:label="item.label"
:value="item.value"
...
...
@@ -32,7 +41,7 @@
</el-select>
</el-form-item>
<el-form-item
label=
"上架状态"
>
<el-select
v-model=
"form.
shelf
"
>
<el-select
v-model=
"form.
ifShelve
"
>
<el-option
v-for=
"(item, index) of shelfType"
:key=
"`option-$
{index}`"
...
...
@@ -68,7 +77,7 @@
v-loading=
"loading"
>
<el-table-column
prop=
"
index
"
prop=
"
code
"
align=
"center"
label=
"产品编号"
fixed
...
...
@@ -79,154 +88,181 @@
align=
"center"
label=
"产品名称"
></el-table-column>
<el-table-column
prop=
"updateTime"
align=
"center"
label=
"更新时间"
></el-table-column>
<el-table-column
prop=
"prodType"
align=
"center"
label=
"产品类型"
></el-table-column>
<el-table-column
prop=
"insurance"
align=
"center"
label=
"险别"
></el-table-column>
<el-table-column
prop=
"channel"
align=
"center"
label=
"产品渠道"
></el-table-column>
<el-table-column
prop=
"index"
align=
"center"
label=
"文件类型"
></el-table-column>
<el-table-column
prop=
"status"
align=
"center"
label=
"上架状态"
></el-table-column>
<el-table-column
align=
"center"
label=
"更新时间"
width=
"160"
>
<template
slot-scope=
"scope"
>
<span>
{{
parseTime
(
scope
.
row
.
updateTime
)
}}
</span>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"产品类型"
>
<
template
slot-scope=
"scope"
>
{{
transformTarget
(
productTypes
,
scope
.
row
.
type
).
label
}}
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"险别"
>
<
template
slot-scope=
"scope"
>
{{
transformTarget
(
riskTypes
,
scope
.
row
.
risk
).
label
}}
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"产品渠道"
>
<
template
slot-scope=
"scope"
>
<div
v-for=
"item of transformChanel(scope.row.channel)"
:key=
"item.value"
>
{{
item
.
label
}}
</div>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"文件类型"
>
<
template
slot-scope=
"scope"
>
<div
v-for=
"item of transformFile(scope.row.materialType)"
:key=
"item.id"
>
{{
item
.
type
}}
</div>
</
template
>
</el-table-column>
<el-table-column
prop=
"ifShelve"
align=
"center"
label=
"上架状态"
>
<
template
slot-scope=
"scope"
>
{{
scope
.
row
.
ifShelve
===
0
?
'未上架'
:
'上架'
}}
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"操作"
fixed=
"right"
width=
"130"
>
<
template
slot-scope=
"scope"
>
<el-button
type=
"text"
@
click=
"editOrAdd(scope.row)"
>
编辑
</el-button>
<el-button
type=
"text"
@
click=
"putOnShelf"
>
上架
</el-button>
<el-button
type=
"text"
@
click=
"putOnShelf"
>
{{
scope
.
row
.
ifShelve
===
0
?
'上架'
:
'下架'
}}
</el-button>
</
template
>
</el-table-column>
</el-table>
<FooterPagination
from
:pagination=
"pagination"
></FooterPaginationfrom
>
<FooterPagination
:pagination=
"pagination"
></FooterPagination
>
</Card>
</template>
<
script
>
import
{
inputMaxLength
}
from
'@/utils/mappingData'
import
FooterPaginationfrom
from
'./components/FooterPagination'
const
productTypes
=
[
{
label
:
'全部'
,
value
:
''
},
{
label
:
'团险'
,
value
:
'1'
}
]
const
insuranceTypes
=
[
{
label
:
'全部'
,
value
:
''
},
{
label
:
'主险'
,
value
:
'1'
},
{
label
:
'附加险'
,
value
:
'2'
}
]
const
shelfType
=
[
{
label
:
'全部'
,
value
:
''
},
{
label
:
'未上架'
,
value
:
'1'
},
{
label
:
'上架'
,
value
:
'2'
}
]
import
{
inputMaxLength
,
productTypes
,
riskTypes
,
shelfType
,
productChannel
,
fileList
}
from
'@/utils/mappingData'
import
FooterPagination
from
'./components/FooterPagination'
import
{
getProductList
}
from
'@/api/productInforManagement'
import
{
parseTime
}
from
'@/utils/util'
const
productChannel
=
[
{
label
:
'全部'
,
value
:
''
},
{
label
:
'产品说明书'
,
value
:
'1'
},
{
label
:
'产品条款'
,
value
:
'2'
},
{
label
:
'免责条款'
,
value
:
'3'
},
{
label
:
'产品投保链接'
,
value
:
'4'
}
]
export
default
{
components
:
{
FooterPagination
from
FooterPagination
},
data
()
{
return
{
parseTime
,
inputMaxLength
,
productTypes
,
insurance
Types
,
risk
Types
,
shelfType
,
productChannel
,
form
:
{
product
:
''
,
type
:
''
,
insurance
:
''
,
shelf
:
''
,
channel
:
''
name
:
''
,
// 产品名称
code
:
''
,
// 产品编号
type
:
''
,
// 产品类型
risk
:
''
,
// 险别
ifShelve
:
''
,
// 上架状态
channel
:
''
// 渠道
},
pagination
:
{
size
:
10
,
total
:
0
,
page
:
1
},
tableData
:
[
{}
],
tableData
:
[],
loading
:
false
}
},
watch
:
{
'pagination.size'
()
{
this
.
handleGetProductList
()
},
'pagination.page'
()
{
this
.
handleGetProductList
()
}
},
mounted
()
{
this
.
handleGetProductList
()
},
methods
:
{
editOrAdd
(
row
)
{
if
(
row
)
{
}
this
.
$router
.
push
({
const
url
=
{
path
:
'edit-product'
})
}
if
(
row
.
id
&&
row
.
code
)
{
const
{
id
,
code
}
=
row
url
.
query
=
{
id
,
code
}
}
this
.
$router
.
push
(
url
)
},
submit
()
{
if
(
this
.
pagination
.
page
===
1
)
{
this
.
handleGetProductList
()
}
else
{
this
.
pagination
.
page
=
1
}
},
submit
()
{},
onReset
()
{
this
.
form
=
{
product
:
''
,
name
:
''
,
code
:
''
,
type
:
''
,
insurance
:
''
,
shelf
:
''
,
risk
:
''
,
ifShelve
:
''
,
channel
:
''
}
this
.
submit
()
},
putOnShelf
()
{},
async
handleGetProductList
()
{
try
{
this
.
loading
=
true
const
{
result
:
{
data
,
totalCount
}
}
=
await
getProductList
({
currPage
:
this
.
pagination
.
page
,
perPage
:
this
.
pagination
.
size
,
name
:
this
.
form
.
name
,
type
:
this
.
form
.
type
,
code
:
this
.
form
.
code
,
risk
:
this
.
form
.
risk
,
channel
:
this
.
form
.
channel
,
ifShelve
:
this
.
form
.
ifShelve
})
this
.
pagination
.
total
=
totalCount
this
.
tableData
=
data
}
catch
(
error
)
{
console
.
log
(
error
)
}
finally
{
this
.
loading
=
false
}
},
putOnShelf
()
{}
transformTarget
(
arr
,
value
)
{
return
arr
.
find
(
item
=>
item
.
value
===
value
)
},
transformFile
(
value
)
{
if
(
!
value
)
{
return
[{
id
:
''
,
type
:
''
}]
}
const
arr
=
value
.
split
(
','
)
const
res
=
arr
.
map
(
item
=>
{
return
fileList
.
find
(
file
=>
file
.
id
===
item
-
0
)
})
return
res
},
transformChanel
(
value
)
{
const
arr
=
value
.
split
(
','
)
const
res
=
arr
.
map
(
item
=>
{
return
productChannel
.
find
(
chan
=>
chan
.
value
===
item
-
0
)
})
return
res
}
}
}
</
script
>
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
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 post a comment