Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
B
biz.qingxiao.com
Project
Project
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
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wangxuelai
biz.qingxiao.com
Commits
91885b91
Commit
91885b91
authored
Aug 30, 2019
by
baixian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
积分
parent
4dbce1d0
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
594 additions
and
0 deletions
+594
-0
api.js
src/common/api.js
+5
-0
menuconfig.js
src/common/menuconfig.js
+13
-0
index.js
src/models/index.js
+2
-0
integral.js
src/models/integral.js
+95
-0
webapp.js
src/models/webapp.js
+19
-0
index.js
src/pages/integralmanage/index.js
+54
-0
index.less
src/pages/integralmanage/index.less
+7
-0
index.js
src/pages/integralmanage/integralsetting/index.js
+163
-0
index.less
src/pages/integralmanage/integralsetting/index.less
+43
-0
index.js
src/pages/integralmanage/storesetting/index.js
+150
-0
index.less
src/pages/integralmanage/storesetting/index.less
+10
-0
router.js
src/router.js
+14
-0
integral.js
src/services/integral.js
+19
-0
No files found.
src/common/api.js
View file @
91885b91
...
...
@@ -141,4 +141,9 @@ export default {
addShortWords
:
`
${
dakaapi
}
member/short_word/store`
,
destoryShortWords
:
`
${
dakaapi
}
member/short_word/destory`
,
},
integralsetting
:
{
goodsList
:
`
${
dakaapi
}
member/integral_goods`
,
goodsDelete
:
`
${
dakaapi
}
member/integral_goods/good_status`
,
},
};
src/common/menuconfig.js
View file @
91885b91
...
...
@@ -102,6 +102,19 @@ export default {
path
:
'/sjd/officialweb'
,
relativePath
:
[
'/sjd/officialweb'
,
'/sjd/officialwebeditor'
],
},
{
id
:
'9'
,
fatherId
:
'2'
,
name
:
'积分管理'
,
style
:
{
width
:
'20px'
,
height
:
'20px'
,
},
isFather
:
false
,
noIcon
:
true
,
path
:
'/sjd/integralmanage'
,
relativePath
:
[
'/sjd/integralmanage'
,
'/sjd/integralmanage'
],
},
],
},
],
...
...
src/models/index.js
View file @
91885b91
...
...
@@ -36,6 +36,7 @@ import thememgtModel from './thememgt';
import
clockmgtModel
from
'./clockmgt'
;
import
playaudioModel
from
'./playaudio'
;
import
hqstatistical
from
'./hqstatistical'
;
import
integralModel
from
'./integral'
;
export
default
{
loginModel
,
indexstaicModel
,
...
...
@@ -66,4 +67,5 @@ export default {
clockmgtModel
,
playaudioModel
,
hqstatistical
,
integralModel
,
};
src/models/integral.js
0 → 100644
View file @
91885b91
import
{
routerRedux
}
from
'dva/router'
;
import
{
message
}
from
'antd'
;
import
{
LocalStorage
,
SessionStorage
,
isExpired
,
}
from
'../utils/index'
;
import
errorcode
from
'../common/errorcode'
;
import
*
as
goodsAjax
from
'../services/integral'
;
import
*
as
courseAjax
from
'../services/course'
;
export
default
{
namespace
:
'integral'
,
state
:
{
goodsList
:
[],
sid
:
0
,
},
subscriptions
:
{
setup
({
dispatch
,
history
})
{
// eslint-disable-line
},
},
effects
:
{
*
integralModelList
({
payload
},
{
call
,
put
,
select
})
{
const
{
sid
}
=
yield
select
(
state
=>
state
.
webapp
);
console
.
log
(
sid
,
'dsa'
);
const
loadmessage
=
message
.
loading
(
'数据加载中...'
,
0
);
const
courselistinfo
=
yield
call
(
goodsAjax
.
goodsList
,
{
school_id
:
sid
,
});
setTimeout
(
loadmessage
);
if
(
courselistinfo
.
code
==
200
)
{
yield
put
({
type
:
'updateState'
,
payload
:
{
sid
,
goodsList
:
courselistinfo
.
data
&&
courselistinfo
.
data
.
list
,
},
});
}
else
{
yield
put
({
type
:
'webapp/errorrequestresolve'
,
payload
:
{
data
:
courselistinfo
,
},
});
}
},
*
integralModelDelete
({
payload
},
{
call
,
put
,
select
})
{
const
{
id
}
=
payload
;
const
loadmessage
=
message
.
loading
(
'数据提交中...'
,
0
);
const
coursedelete
=
yield
call
(
goodsAjax
.
goodsDelete
,
{
id
:
payload
.
id
,
});
setTimeout
(
loadmessage
);
if
(
coursedelete
.
code
==
200
)
{
yield
put
({
type
:
'webapp/updateState'
,
});
yield
put
({
type
:
'integralModelList'
,
payload
:
{
// 1
},
});
}
else
{
yield
put
({
type
:
'webapp/errorrequestresolve'
,
payload
:
{
data
:
coursedelete
,
},
});
// message.error(coursedelete.msg, 1);
}
},
*
pageInit
({
payload
},
{
call
,
put
,
select
})
{
yield
put
({
type
:
'updateState'
,
payload
:
{
sid
:
0
,
goodslist
:
[],
},
});
},
},
reducers
:
{
save
(
state
,
action
)
{
return
{
...
state
,
...
action
.
payload
,
};
},
updateState
(
state
,
action
)
{
return
{
...
state
,
...
action
.
payload
};
},
},
};
src/models/webapp.js
View file @
91885b91
...
...
@@ -514,6 +514,22 @@ export default {
});
}
dispatch
({
type
:
'menumatch'
,
payload
:
{
pathname
}
});
if
(
pathname
===
'/sjd/integralmanage'
)
{
dispatch
({
type
:
'integral/integralModelList'
,
payload
:
{
},
});
dispatch
({
type
:
'webapp/updateState'
,
payload
:
{
breadcrumbList
:
[{
path
:
pathname
,
name
:
'积分管理'
,
}],
},
});
}
});
},
},
...
...
@@ -617,6 +633,9 @@ export default {
yield
put
({
type
:
'thememgt/pageInit'
,
});
yield
put
({
type
:
'integral/pageInit'
,
});
},
*
onPageEnter
({
payload
},
{
put
,
call
,
select
})
{
const
{
pathname
}
=
payload
;
...
...
src/pages/integralmanage/index.js
0 → 100644
View file @
91885b91
import
{
connect
}
from
'dva'
;
import
React
from
'react'
;
import
{
Icon
,
Button
,
Tabs
,
Select
,
Form
}
from
'antd'
;
import
pageStyle
from
'./index.less'
;
import
{
pageIn
,
hasBtnPower
}
from
'../../utils/index'
;
import
Integralsetting
from
'./integralsetting/index'
;
import
Storesetting
from
'./storesetting/index'
;
const
{
TabPane
}
=
Tabs
;
class
Integralmanage
extends
React
.
Component
{
componentDidMount
()
{
// 挂载
pageIn
(
'轻校-积分管理'
);
}
componentDidUpdate
()
{
}
componentWillUnmount
()
{
// 卸载
}
callback
=
(
key
)
=>
{
console
.
log
(
key
);
}
integralBtn
=
()
=>
{
console
.
log
(
111
);
}
render
()
{
const
that
=
this
;
const
{
staticcenter
,
}
=
this
.
props
;
const
operations
=
<
Button
onClick
=
{()
=>
this
.
integralBtn
()}
type
=
"primary"
>
积分变动
<
/Button>
;
return
(
<
div
className
=
{
pageStyle
.
container
}
>
<
Tabs
defaultActiveKey
=
"2"
onChange
=
{
this
.
callback
}
tabBarExtraContent
=
{
operations
}
>
<
TabPane
tab
=
"积分设置"
key
=
"1"
>
<
Integralsetting
/>
<
/TabPane
>
<
TabPane
tab
=
"商城设置"
key
=
"2"
>
<
Storesetting
/>
<
/TabPane
>
<
TabPane
tab
=
"操作日志"
key
=
"3"
>
Content
of
Tab
Pane
3
<
/TabPane
>
<
/Tabs
>
<
/div
>
);
}
}
Integralmanage
.
propTypes
=
{
};
function
mapStateToProps
(
state
)
{
}
export
default
connect
(
mapStateToProps
)(
Integralmanage
);
src/pages/integralmanage/index.less
0 → 100644
View file @
91885b91
@import '../../less/variables.less';
.container {
background-color: #fff;
padding: 12px 20px 24px 20px;
position: relative;
overflow-y: hidden;
}
src/pages/integralmanage/integralsetting/index.js
0 → 100644
View file @
91885b91
import
{
connect
}
from
'dva'
;
import
React
from
'react'
;
import
{
Form
,
Icon
,
Button
,
Tabs
,
Select
,
Row
,
Col
,
Input
,
Checkbox
,
InputNumber
}
from
'antd'
;
import
pageStyle
from
'./index.less'
;
const
{
TabPane
}
=
Tabs
;
const
FormItem
=
Form
.
Item
;
@
Form
.
create
()
class
Integralsetting
extends
React
.
Component
{
componentDidUpdate
()
{
}
componentWillUnmount
()
{
// 卸载
}
handleSubmit
=
(
e
)
=>
{
this
.
props
.
form
.
validateFields
((
err
,
values
)
=>
{
if
(
!
err
)
{
console
.
log
(
'Received values of form: '
,
values
);
}
});
}
checkboxChange
=
(
checkedValues
)
=>
{
console
.
log
(
checkedValues
);
}
onChange
=
(
value
)
=>
{
console
.
log
(
value
);
}
render
()
{
const
{
staticcenter
,
form
:
{
getFieldDecorator
,
getFieldValue
},
}
=
this
.
props
;
const
formItemLayout
=
{
labelCol
:
{
xs
:
{
span
:
24
},
sm
:
{
span
:
5
},
},
wrapperCol
:
{
xs
:
{
span
:
24
},
sm
:
{
span
:
12
},
},
};
return
(
<
div
className
=
{
pageStyle
.
container
}
>
<
Form
{...
formItemLayout
}
>
<
Row
type
=
"flex"
justify
=
"space-between"
>
<
Col
span
=
{
124
}
>
<
div
className
=
{
pageStyle
.
tophead
}
>
<
div
className
=
{
pageStyle
.
topheadleft
}
>
<
span
className
=
{
pageStyle
.
line
}
><
/span>积分获取规
则
<
/div
>
<
div
className
=
{
pageStyle
.
topheadright
}
>
可自定义分值,当课程有学员参与后请谨慎修改,避免对部分学员积分产生异常
<
/div
>
<
/div
>
<
/Col
>
<
Col
span
=
{
6
}
>
<
div
style
=
{{
textAlign
:
'right'
}}
>
<
Button
type
=
"primary"
ghost
onClick
=
{()
=>
this
.
handleSubmit
()}
>
保存配置
<
/Button
>
<
/div
>
<
/Col
>
<
/Row
>
<
Checkbox
.
Group
style
=
{{
width
:
'100%'
}}
onChange
=
{
this
.
checkboxChange
}
>
<
Row
>
<
Col
span
=
{
24
}
>
<
Checkbox
value
=
"1"
>
<
div
style
=
{{
display
:
'inline-block'
}}
>
{
getFieldDecorator
(
'type'
,
{
initialValue
:
1
})(
<
Input
type
=
"hidden"
/>
)}
每日打卡
<
span
className
=
{
pageStyle
.
checkboxTip
}
>
(
学员每日登录打卡
)
<
/span
>
<
/div
>
<
Form
.
Item
label
=
"获得"
>
{
getFieldDecorator
(
'single'
,
{
initialValue
:
2
})(
<
InputNumber
min
=
{
0
}
/>
)
}
<
span
className
=
"ant-form-text"
>
积分
<
/span
>
<
/Form.Item
>
<
/Checkbox
>
<
/Col
>
<
Col
span
=
{
24
}
>
<
Checkbox
value
=
"2"
>
<
div
style
=
{{
display
:
'inline-block'
}}
>
点赞鼓励
<
span
className
=
{
pageStyle
.
checkboxTip
}
>
(
学员给同学的打卡内容点赞
)
<
/span
>
<
/div
>
<
Form
.
Item
label
=
"获得"
>
{
getFieldDecorator
(
'single'
,
{
initialValue
:
3
})(
<
InputNumber
min
=
{
0
}
/>
)
}
<
span
className
=
"ant-form-text"
>
积分
<
/span
>
<
/Form.Item
>
<
/Checkbox
>
<
/Col
>
<
Col
span
=
{
24
}
>
<
Checkbox
value
=
"3"
>
评论互动
<
span
className
=
{
pageStyle
.
checkboxTip
}
>
(
学员给同学的打卡内容评论
)
<
/span></
Checkbox
>
<
/Col
>
<
Col
span
=
{
24
}
>
<
Checkbox
value
=
"4"
>
分享打卡
<
span
className
=
{
pageStyle
.
checkboxTip
}
>
(
学员分享自己的打卡内容至群聊
)
<
/span></
Checkbox
>
<
/Col
>
<
Col
span
=
{
24
}
>
<
Checkbox
value
=
"5"
>
打卡内容被点赞
<
span
className
=
{
pageStyle
.
checkboxTip
}
>
(
学员的打卡内容被点赞获得积分
)
<
/span></
Checkbox
>
<
/Col
>
<
Col
span
=
{
24
}
>
<
Checkbox
value
=
"6"
>
打卡内容被围观
<
span
className
=
{
pageStyle
.
checkboxTip
}
>
(
新用户通过学员的二维码进入查看其打卡
)
<
/span></
Checkbox
>
<
/Col
>
<
Col
span
=
{
24
}
>
<
Checkbox
value
=
"7"
>
打卡内容被转发
<
span
className
=
{
pageStyle
.
checkboxTip
}
>
(
学员打卡内容被其他同学转发
)
<
/span></
Checkbox
>
<
/Col
>
<
Col
span
=
{
24
}
>
<
Checkbox
value
=
"8"
>
打卡内容被评论
<
span
className
=
{
pageStyle
.
checkboxTip
}
>
(
学员打卡内容被其他同学评论
)
<
/span></
Checkbox
>
<
/Col
>
<
Col
span
=
{
24
}
>
<
Checkbox
value
=
"9"
>
打卡内容被老师点评
<
span
className
=
{
pageStyle
.
checkboxTip
}
>
(
学员打卡内容被老师点评
)
<
/span></
Checkbox
>
<
/Col
>
<
/Row
>
<
/Checkbox.Group
>
<
/Form
>
<
/div
>
);
}
}
Integralsetting
.
propTypes
=
{
};
function
mapStateToProps
(
state
)
{
const
{
staticcenter
,
clockCharts
,
sid
,
days
,
clockChartsSuccess
,
renew
,
callData
,
birthday
,
assign
,
teacherList
,
courseList
,
classroomList
,
classRoomMgtShow
,
classRoomSubmitting
,
addCourseTimeShow
,
timeArr
,
addTimeSubmitting
,
chartEndDate
,
chartStartDate
,
}
=
state
.
indexstaic
;
return
{
staticcenter
,
clockCharts
,
sid
,
days
,
clockChartsSuccess
,
renew
,
callData
,
birthday
,
assign
,
teacherList
,
courseList
,
classroomList
,
classRoomMgtShow
,
classRoomSubmitting
,
addCourseTimeShow
,
timeArr
,
addTimeSubmitting
,
chartEndDate
,
chartStartDate
,
};
}
export
default
connect
(
mapStateToProps
)(
Integralsetting
);
src/pages/integralmanage/integralsetting/index.less
0 → 100644
View file @
91885b91
.container {
background-color: #fff;
padding: 24px 0 30px;
position: relative;
overflow-y: hidden;
}
.tophead {
display: flex;
align-items: center;
.line {
width: 3px;
height: 19px;
background-color: #1890FF;
display: inline-block;
vertical-align: middle;
margin-right: 6px;
}
.topheadleft {
display: flex;
align-items: center;
font-size:16px;
font-family:PingFangSC;
font-weight:500;
color:rgba(0,0,0,0.85);
line-height:24px;
margin-right: 30px;
}
.topheadright {
font-size:14px;
font-family:PingFangSC;
font-weight:400;
color:#515151;
line-height:24px;
}
}
.checkboxTip {
font-size:12px;
font-family:PingFangSC;
font-weight:400;
color:#999;
line-height:22px;
margin-left: 15px;
}
src/pages/integralmanage/storesetting/index.js
0 → 100644
View file @
91885b91
import
{
connect
}
from
'dva'
;
import
React
from
'react'
;
import
{
Form
,
Icon
,
Button
,
Tabs
,
Modal
,
Row
,
Col
,
Tag
,
Divider
,
Table
,
Pagination
,
message
}
from
'antd'
;
import
pageStyle
from
'./index.less'
;
import
{
hasBtnPower
,
imagify
}
from
'../../../utils'
;
const
{
TabPane
}
=
Tabs
;
const
FormItem
=
Form
.
Item
;
class
StoreMgt
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
previewVisible
:
false
,
previewImage
:
''
,
};
}
componentDidUpdate
()
{
}
componentWillUnmount
()
{
// 卸载
}
handlePreview
=
(
previewImage
)
=>
{
this
.
setState
({
previewImage
,
previewVisible
:
true
,
});
};
deleteItem
=
(
item
)
=>
{
console
.
log
(
item
);
const
me
=
this
;
const
{
dispatch
}
=
me
.
props
;
Modal
.
confirm
({
title
:
`确定删除“
${
item
.
title
}
”?`
,
content
:
'删除后不可恢复,请谨慎操作!'
,
okText
:
'确定'
,
cancelText
:
'取消'
,
onOk
()
{
dispatch
({
type
:
'integral/integralModelDelete'
,
payload
:
{
id
:
item
.
id
,
},
callback
(
res
)
{
if
(
res
.
code
===
1
)
{
message
.
success
(
res
.
msg
);
}
else
{
message
.
error
(
res
.
msg
);
}
},
});
},
});
};
render
()
{
const
{
goodsList
,
}
=
this
.
props
;
const
{
previewVisible
,
previewImage
,
}
=
this
.
state
;
const
columns
=
[
{
title
:
'商品名称'
,
dataIndex
:
'title'
,
},
{
title
:
'图片展示'
,
dataIndex
:
'cover'
,
render
:
(
text
)
=>
{
return
(
// eslint-disable-next-line jsx-a11y/alt-text
<
img
onClick
=
{()
=>
{
this
.
handlePreview
((
imagify
(
text
)));
}}
src
=
{(
imagify
(
text
))}
style
=
{{
height
:
70
,
width
:
80
,
cursor
:
'pointer'
}}
/
>
);
},
},
{
title
:
'积分兑换值'
,
dataIndex
:
'price'
,
},
{
title
:
'库存'
,
dataIndex
:
'inventory'
,
},
{
title
:
'操作'
,
dataIndex
:
'id'
,
render
:
(
text
,
row
)
=>
(
<
span
>
<
a
href
=
"javascript:;"
onClick
=
{()
=>
{
}}
>
编辑
<
/a
>
<
Divider
type
=
"vertical"
/>
<
a
href
=
"javascript:;"
onClick
=
{()
=>
{
this
.
deleteItem
(
row
);
}}
>
删除
<
/a
>
<
/span
>
),
},
];
return
(
<
div
className
=
{
pageStyle
.
container
}
>
<
Row
>
<
Col
span
=
{
2
}
>
<
Button
onClick
=
{()
=>
this
.
addCoupon
()}
type
=
"primary"
><
Icon
type
=
"credit-card"
/>
添加卡券
<
/Button></
Col
>
<
Col
span
=
{
2
}
>
<
Button
onClick
=
{()
=>
this
.
integralBtn
()}
type
=
"primary"
><
Icon
type
=
"shopping"
/>
添加商品
<
/Button></
Col
>
<
/Row
>
<
div
className
=
{
pageStyle
.
tablebox
}
>
<
Table
dataSource
=
{
goodsList
}
columns
=
{
columns
}
pagination
=
{
false
}
/
>
<
/div
>
<
Modal
visible
=
{
previewVisible
}
bodyStyle
=
{{
maxHeight
:
'inherit'
,
padding
:
0
}}
footer
=
{
null
}
onCancel
=
{()
=>
this
.
setState
({
previewVisible
:
false
})}
>
<
img
alt
=
"example"
style
=
{{
width
:
'100%'
}}
src
=
{
previewImage
}
/
>
<
/Modal
>
<
/div
>
);
}
}
StoreMgt
.
propTypes
=
{
};
function
mapStateToProps
(
state
)
{
const
{
goodsList
,
}
=
state
.
integral
;
return
{
goodsList
,
};
}
export
default
connect
(
mapStateToProps
)(
StoreMgt
);
src/pages/integralmanage/storesetting/index.less
0 → 100644
View file @
91885b91
.container {
background-color: #fff;
padding: 24px 0 0;
position: relative;
overflow-y: hidden;
}
.tablebox {
padding: 20px 0;
background: #fff;
}
src/router.js
View file @
91885b91
...
...
@@ -39,6 +39,17 @@ const IndexStaic = props => (
{
IndexStaic
=>
(
<
IndexStaic
{...
props
}
/>
)
}
<
/Bundle
>
);
const
Integralmanage
=
props
=>
(
<
Bundle
load
=
{()
=>
import
(
/* webpackChunkName:"officialweb" */
'./pages/integralmanage/index'
)}
>
{
Integralmanage
=>
(
<
Integralmanage
{...
props
}
/>
)
}
<
/Bundle
>
);
const
Storesetting
=
props
=>
(
<
Bundle
load
=
{()
=>
import
(
/* webpackChunkName:"officialweb" */
'./pages/integralmanage/storesetting/index'
)}
>
{
Storesetting
=>
(
<
Storesetting
{...
props
}
/>
)
}
<
/Bundle
>
);
const
Officialweb
=
props
=>
(
<
Bundle
load
=
{()
=>
import
(
/* webpackChunkName:"officialweb" */
'./pages/officialweb/index'
)}
>
{
Officialweb
=>
(
<
Officialweb
{...
props
}
/>
)
}
...
...
@@ -144,6 +155,7 @@ const Institutions = props => (
{
Institutions
=>
(
<
Institutions
{...
props
}
/>
)
}
<
/Bundle
>
);
function
RouterConfig
({
history
})
{
return
(
<
LocaleProvider
locale
=
{
zhCN
}
>
...
...
@@ -153,6 +165,8 @@ function RouterConfig({ history }) {
path
=
"/sjd"
render
=
{()
=>
(
<
SjdIndex
>
<
Route
path
=
"/sjd/storesetting"
exact
component
=
{
Storesetting
}
/
>
<
Route
path
=
"/sjd/integralmanage"
config
=
{{
needAuth
:
true
}}
exact
component
=
{
Integralmanage
}
/
>
<
Route
path
=
"/sjd/officialweb"
config
=
{{
needAuth
:
true
}}
exact
component
=
{
Officialweb
}
/
>
<
Route
path
=
"/sjd/officialwebeditor"
exact
component
=
{
OfficialwebEditor
}
/
>
<
Route
path
=
"/sjd"
exact
render
=
{()
=>
(
<
Redirect
to
=
"/sjd/indexstaic"
/>
)}
/
>
...
...
src/services/integral.js
0 → 100644
View file @
91885b91
import
qs
from
'qs'
;
import
request
from
'../utils/request'
;
import
api
from
'../common/api'
;
export
function
goodsList
(
parmas
)
{
const
data
=
qs
.
stringify
(
parmas
);
return
request
({
url
:
`
${
api
.
integralsetting
.
goodsList
}
?
${
data
}
`
,
method
:
'GET'
,
data
,
});
}
export
function
goodsDelete
(
params
)
{
const
data
=
qs
.
stringify
(
params
);
return
request
({
url
:
`
${
api
.
integralsetting
.
goodsDelete
}
`
,
method
:
'POST'
,
data
,
});
}
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