Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
sass-admin
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
hqzhdj_app
sass-admin
Commits
aed4885f
Commit
aed4885f
authored
May 09, 2025
by
yanglang123
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
优化
parent
71c88ce3
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
43 additions
and
210 deletions
+43
-210
RJump/jquery.min.js
+0
-0
dist.zip
+0
-0
src/common/Editor/editor.js
+18
-21
src/common/UpLoad/redux/actions.js
+0
-2
src/pages/SystemManagement/Information/addEditForm.jsx
+2
-35
src/pages/TrainingTools/Question/Create/AddTest.jsx
+2
-9
src/pages/TrainingTools/Question/Create/TestModal.jsx
+4
-71
src/pages/TrainingTools/Question/Details/index.jsx
+1
-60
src/pages/TrainingTools/Survey/Create/AddTest.jsx
+1
-1
src/pages/TrainingTools/Survey/Details/index.jsx
+1
-1
src/pages/TrainingTools/exam/examCheck/check/index.jsx
+11
-7
src/pages/TrainingTools/exam/questionBank/question/Question.jsx
+1
-1
src/pages/TrainingTools/exam/questionBank/question/change.jsx
+2
-2
No files found.
RJump/jquery.min.js
View file @
aed4885f
This source diff could not be displayed because it is too large. You can
view the blob
instead.
dist.zip
View file @
aed4885f
No preview for this file type
src/common/Editor/editor.js
View file @
aed4885f
...
...
@@ -16,30 +16,26 @@ class Editor extends PureComponent {
super
(...
arguments
);
this
.
state
=
{
editorState
:
""
,
defaultValue
:
"111"
,
defaultValue
:
""
,
readOnly
:
false
,
};
}
componentDidMount
()
{
// const { importContent } = this.props;
// if (importContent) {
// return {
// defaultValue: BraftEditor.createEditorState(importContent),
// importContent,
// };
// }
this
.
props
.
gupfetch
();
const
{
importContent
,
type
}
=
this
.
props
;
if
(
type
===
'look'
){
this
.
setState
({
readOnly
:
true
,
})
}
if
(
importContent
)
{
console
.
log
(
importContent
,
type
,
'22222222222222222222'
)
this
.
setState
({
defaultValue
:
BraftEditor
.
createEditorState
(
importContent
),
});
// static getDerivedStateFromProps(nextProps, prevState) {
// const { importContent } = nextProps;
// if (importContent !== prevState.importContent) {
// return {
// defaultValue: BraftEditor.createEditorState(importContent),
// importContent,
// };
// }
// return null;
// }
}
this
.
props
.
gupfetch
();
}
submitContent
=
()
=>
{
// 在编辑器获得焦点时按下ctrl+s会执行此方法
// 编辑器内容提交到服务端之前,可直接调用editorState.toHTML()来获取HTML格式的内容
...
...
@@ -68,7 +64,7 @@ class Editor extends PureComponent {
};
render
()
{
const
{
uploadParam
}
=
this
.
props
;
const
{
editorState
,
defaultValue
}
=
this
.
state
;
const
{
editorState
,
defaultValue
,
readOnly
}
=
this
.
state
;
const
set
=
[
"undo"
,
"redo"
,
...
...
@@ -321,10 +317,11 @@ class Editor extends PureComponent {
media
=
{{
uploadFn
:
myUploadFn
}}
className
=
{
styles
.
edit
}
// value={editorState} //动态赋值会造成光标位移
defaultV
alue
=
{
defaultValue
}
v
alue
=
{
defaultValue
}
fontFamilies
=
{
fontFamilies
}
fontSizes
=
{
fontSizes
}
controls
=
{
set
}
readOnly
=
{
readOnly
}
onChange
=
{
this
.
handleEditorChange
}
onSave
=
{
this
.
submitContent
}
/
>
...
...
src/common/UpLoad/redux/actions.js
View file @
aed4885f
...
...
@@ -49,7 +49,6 @@ export function upvideo(param, callback1, callback2) {
videoUpload
,
data
:
param
,
}).
then
(
res
=>
{
console
.
log
(
res
.
data
);
if
(
res
.
code
===
"1000"
)
{
dispatch
({
type
:
Types
.
UP_INFO
,
data
:
JSON
.
parse
(
res
.
data
)
});
if
(
callback1
)
{
...
...
@@ -67,7 +66,6 @@ export function videoInfo(param, callback) {
videoPlay
,
data
:
param
,
}).
then
(
res
=>
{
console
.
log
(
res
.
data
);
if
(
res
.
code
===
"1000"
)
{
dispatch
({
type
:
Types
.
VIDEO_INFO
,
data
:
res
.
data
});
if
(
callback
)
{
...
...
src/pages/SystemManagement/Information/addEditForm.jsx
View file @
aed4885f
...
...
@@ -14,7 +14,6 @@ import {
}
from
"antd"
;
const
Option
=
Select
.
Option
;
import
{
connect
}
from
"react-redux"
;
// import {gupList, gupfetch} from 'ACTIONS/upload';
import
{
gupList
,
gupfetch
}
from
"@/common/UpLoad/redux/actions"
;
import
{
getMenu
}
from
"./redux/action"
;
import
Editor
from
"@/common/Editor/editor"
;
...
...
@@ -56,7 +55,7 @@ class addEdit extends React.Component {
componentDidMount
()
{
const
{
seeEdit
,
type
,
treeData
}
=
this
.
props
;
// console.log(this.props.keyValue,seeEdit.conten
t,'查看是否有缓存')
console
.
log
(
this
.
props
.
keyValue
,
type
,
seeEdi
t
,
'查看是否有缓存'
)
this
.
props
.
getMenu
({
code
:
"topic_type"
,
});
...
...
@@ -125,7 +124,6 @@ class addEdit extends React.Component {
}
//123
handleUploadChange
({
file
,
fileList
})
{
// console.log(123,file.name.split('.')[1])
if
(
file
.
name
.
indexOf
(
"pdf"
)
==
-
1
&&
file
.
name
.
indexOf
(
"PDF"
)
==
-
1
)
{
message
.
error
(
"请上传pdf文件"
);
return
;
...
...
@@ -291,37 +289,6 @@ class addEdit extends React.Component {
}
});
}
const
uploadProps1
=
{
name
:
"封面logo"
,
required
:
this
.
state
.
noticeOrNews
==
"新闻"
,
disabled
:
type
==
"look"
,
layout
:
{
labelCol
:
{
xs
:
{
span
:
24
},
sm
:
{
span
:
4
},
},
wrapperCol
:
{
xs
:
{
span
:
24
},
sm
:
{
span
:
20
},
},
},
defaultUrl
:
this
.
props
.
logo
?
[
{
uid
:
1
,
status
:
"done"
,
reponse
:
"Server Error 500"
,
url
:
this
.
props
.
logo
,
},
]
:
[],
getUrl
:
url
=>
{
this
.
setState
({
logourl
:
url
,
});
},
};
const
option
=
menuList
?.
map
((
item
,
index
)
=>
{
return
(
<
Option
value=
{
item
.
id
}
key=
{
index
}
>
...
...
@@ -382,7 +349,6 @@ class addEdit extends React.Component {
// : [],
})(
<
div
style=
{
{
marginLeft
:
"2.5rem"
}
}
>
{
/* <UpLoad {...uploadProps1} ref={c => (this.validate = c)} /> */
}
<
UploadImageCover
details=
{
this
.
state
.
logourl
}
getImgUrl=
{
this
.
getImgUrl
}
...
...
@@ -621,6 +587,7 @@ class addEdit extends React.Component {
key=
{
this
.
props
.
keyValue
}
cbReceiver=
{
this
.
getEditorHtml
}
importContent=
{
seeEdit
&&
seeEdit
.
content
}
type=
"look"
/>
)
:
(
// <Input />
...
...
src/pages/TrainingTools/Question/Create/AddTest.jsx
View file @
aed4885f
...
...
@@ -429,16 +429,9 @@ class AddTest extends Component {
}
render
()
{
const
{
tlist
,
jumptests
}
=
this
.
props
;
let
{
resData
}
=
tlist
;
const
{
visible
,
confirmLoading
,
selectedRowKeys
,
testItem
}
=
this
.
state
;
/*uploadProps对象参数说明
* @uploadUtilName:按钮文字
* @getUrl 回调函数 参数1是从阿里云取得url参数是文件名字
*
* */
console
.
log
(
"xxxxxxxxxxxxaaaaa"
,
this
.
state
.
testItem
.
contentAppendixUrl
);
const
uploadProps
=
{
uploadUtilName
:
"上传图片/
音/视频
"
,
uploadUtilName
:
"上传图片/
文件
"
,
getUrl
:
(
fileUrl
,
fileName
)
=>
{
this
.
setState
({
fileUrl
,
...
...
@@ -451,7 +444,7 @@ class AddTest extends Component {
uid
:
1
,
status
:
"done"
,
url
:
this
.
state
.
testItem
.
contentAppendixUrl
,
name
:
this
.
state
.
testItem
.
contentAppendixUrl
,
name
:
this
.
state
.
testItem
.
contentAppendixUrl
.
split
(
'prefix='
)[
1
]
,
},
]
:
[],
...
...
src/pages/TrainingTools/Question/Create/TestModal.jsx
View file @
aed4885f
...
...
@@ -185,7 +185,6 @@ class TestModal extends Component {
}
getTags
=
tags
=>
{
this
.
setState
({
keywords
:
tags
.
join
()
});
console
.
log
(
tags
.
join
(),
"任务938"
);
};
render
()
{
const
{
defaultValue
,
jumptests
}
=
this
.
props
;
...
...
@@ -207,7 +206,6 @@ class TestModal extends Component {
labelCol
:
{
span
:
3
},
wrapperCol
:
{
span
:
20
},
};
console
.
log
(
"默认回显"
,
defaultValue
);
const
children
=
[];
for
(
let
i
=
0
;
i
<
jumptests
.
length
;
i
++
)
{
children
.
push
(
...
...
@@ -347,27 +345,6 @@ class TestModal extends Component {
})(<
TextArea
/>)
}
</
FormItem
>
</
Col
>
{
/* <Col className="gutter-row" span={4}>
<FormItem>
{getFieldDecorator(`editable[${item.no}]`, {
valuePropName: 'checked',
initialValue:item.editable?item.editable:"",
})(
<Checkbox />
)}</FormItem>
</Col>
<Col className="gutter-row" span={6}>
<FormItem>
{getFieldDecorator(`jumpNum[${item.no}]`, {
initialValue:item.jumpNum?item.jumpNum:"",
})(
<Select onChange={this.handleSelectChange}
getPopupContainer={() => document.getElementById('dselect')}>
{children}
</Select>
)}
</FormItem>
</Col>*/
}
{
keys1
.
length
>
1
?
(
<
Icon
className=
{
styles
.
survey_delete_button
}
...
...
@@ -381,17 +358,6 @@ class TestModal extends Component {
</
Row
>
);
})
}
{
/* <div style={{width:'300px'}}>
<div style={{width:'255px',border: '1px solid #ccc',borderRadius: '4px',display:'inline-block'}}>
<Input /><Checkbox />是否填空<Checkbox/>必填</div>
<div style={{display:'inline-block',marginLeft:'10px'}}>
<Icon
className="survey-delete-button"
type="minus-circle-o"
/>
</div>
</div>*/
}
{
this
.
state
.
addother
?
(
<
Row
gutter=
{
23
}
style=
{
{
paddingBottom
:
"14px"
}
}
>
<
Col
className=
"gutter-row"
span=
{
9
}
>
...
...
@@ -450,7 +416,7 @@ class TestModal extends Component {
<
Dquestion
/>
</
span
>
</
div
>
{
/* <Divider />*/
}
</
div
>
)
}
</
RadioGroup
>
...
...
@@ -480,12 +446,7 @@ class TestModal extends Component {
<
Col
className=
{
styles
.
gutter_row
}
span=
{
15
}
>
选项内容
</
Col
>
{
/* <Col className="gutter-row" span={4}>
允许填空
</Col>
<Col className="gutter-row" span={6}>
跳题
</Col>*/
}
</
Row
>
{
keys2
.
map
((
item
,
k
)
=>
{
return
(
...
...
@@ -495,16 +456,7 @@ class TestModal extends Component {
initialValue
:
item
.
no
,
})(<
a
/>)
}
</
FormItem
>
{
/* <Col className="gutter-row" span={4}>
<FormItem>
{getFieldDecorator(`correct[${k}]`, {
valuePropName: 'checked',
initialValue:item.correct?item.correct!==0:false
})(
<Radio />
)}
</FormItem>
</Col> */
}
<
Col
className=
{
styles
.
gutter_row
}
span=
{
15
}
>
<
FormItem
>
{
getFieldDecorator
(
`cont[${item.no}]`
,
{
...
...
@@ -519,26 +471,7 @@ class TestModal extends Component {
})(<
TextArea
/>)
}
</
FormItem
>
</
Col
>
{
/* <Col className="gutter-row" span={4}>
<FormItem>
{getFieldDecorator(`editable[${item.no}]`, {
valuePropName: 'checked',
initialValue:item.editable?item.editable:"",
})(
<Checkbox />
)}</FormItem>
</Col>
<Col className="gutter-row" span={6}>
<FormItem>
{getFieldDecorator(`jumpNum[${item.no}]`, {
initialValue:item.jumpNum?item.jumpNum:"",
})(
<Select onChange={this.handleSelectChange}>
{children}
</Select>
)}
</FormItem>
</Col> */
}
{
keys2
.
length
>
1
?
(
<
Icon
className=
{
styles
.
survey_delete_button
}
...
...
src/pages/TrainingTools/Question/Details/index.jsx
View file @
aed4885f
...
...
@@ -191,11 +191,6 @@ class Details extends Component {
if
(
errors
)
{
return
;
}
// dcomponent.validateFields((errors, vals) => {
// if (!!errors) {
// return;
// };
// 805 取出消息数据
this
.
messageRemind
.
props
.
form
.
validateFields
((
errors
,
vals
)
=>
{
if
(
errors
)
{
return
;
...
...
@@ -218,7 +213,6 @@ class Details extends Component {
}
else
{
messageRemindVo
.
hasDeleted
=
true
;
}
console
.
log
(
1111
,
values
,
vals
);
let
data
=
{
name
:
values
.
name
.
trim
(),
startTime
:
moment
(
values
.
time
[
0
]).
format
(
"YYYY-MM-DD HH:mm:ss"
),
...
...
@@ -240,7 +234,6 @@ class Details extends Component {
this
.
props
.
update
({
id
:
this
.
id
,
...
data
,
remindVo
:
vals
},
res
=>
{
if
(
res
===
"1000"
)
{
console
.
log
(
"跳转"
,
this
.
props
);
this
.
props
.
history
.
push
(
"/"
+
companyCode
+
...
...
@@ -256,7 +249,6 @@ class Details extends Component {
// 938
getTags
=
tags
=>
{
this
.
setState
({
keywords
:
tags
.
join
()
});
console
.
log
(
tags
.
join
(),
"任务938"
);
};
//设置日历任务状态
...
...
@@ -266,7 +258,6 @@ class Details extends Component {
});
};
handleTestView
(
item
)
{
// console.log(item)
this
.
setState
({
testItem
:
item
,
visibleQuestion
:
true
,
...
...
@@ -277,7 +268,6 @@ class Details extends Component {
this
.
props
.
jump
({
id
:
item
.
id
});
}
handleTestView1
(
item
)
{
// console.log(item)
this
.
setState
({
testItem
:
item
,
visibleQuestion
:
true
,
...
...
@@ -310,12 +300,7 @@ class Details extends Component {
handleOk
()
{
const
{
surid
}
=
this
.
props
;
const
{
order
,
editstate
,
editid
}
=
this
.
state
;
console
.
log
(
11111
,
this
.
addother
.
state
);
this
.
props
.
jumpreset
();
// this.setState({
// confirmLoading: true,
// });
this
.
newTest
.
validateFields
((
errors
,
values
)
=>
{
if
(
errors
)
{
this
.
setState
({
...
...
@@ -327,30 +312,22 @@ class Details extends Component {
if
(
values
.
type
===
1
)
{
for
(
let
i
=
0
;
i
<
values
.
cont
.
length
;
i
++
)
{
if
(
values
.
cont
[
i
]
==
null
)
continue
;
console
.
log
(
values
,
11111
);
objs
.
push
({
content
:
values
.
cont
[
i
],
//correct:values.correct[i]?1:0,
//editable:values.editable[i]?1:0,
//jumpNum:values.jumpNum[i]?values.jumpNum[i]:"",
no
:
values
.
no
[
i
],
researchId
:
surid
,
keywords
:
this
.
addother
.
state
.
keywords
,
});
}
console
.
log
(
"单选题其他"
,
objs
);
}
if
(
values
.
type
===
2
)
{
for
(
let
i
=
0
;
i
<
values
.
cont
.
length
;
i
++
)
{
objs
.
push
({
content
:
values
.
cont
[
i
],
//correct:values.correct[i]?1:0,
//editable:values.editable[i]?1:0,
no
:
values
.
no
[
i
],
researchId
:
surid
,
});
}
// console.log(objs)
}
if
(
values
.
type
===
4
)
{
for
(
let
i
=
0
;
i
<
values
.
cont
.
length
;
i
++
)
{
...
...
@@ -376,7 +353,6 @@ class Details extends Component {
const
param
=
{
type
:
values
.
type
,
content
:
values
.
content
,
//bug-9797-liyuan 附件回显
contentAppendixUrl
:
this
.
state
.
fileUrl
?
this
.
state
.
fileUrl
:
this
.
state
.
testItem
.
contentAppendixUrl
...
...
@@ -394,35 +370,10 @@ class Details extends Component {
required
:
this
.
addother
.
state
.
ismust
?
1
:
0
,
},
};
// console.log("777777777", param)
// return
// if( !(param.minSelectItem !== '' && param.minSelectItem <= param.questionOptions.length-1 && param.minSelectItem > 0)) {
// message.error('最少项错误')
// this.setState({
// confirmLoading: false,
// });
// return
// }
// // 判断最大可选
// if( param.maxSelectItem !== '' && param.maxSelectItem > param.questionOptions.length){
// message.error('最多项错误')
// this.setState({
// confirmLoading: false,
// });
// return
// }else if(param.maxSelectItem !== '' && param.minSelectItem !==''&& param.maxSelectItem < param.minSelectItem){
// message.error('最多项不能小于最少项')
// this.setState({
// confirmLoading: false,
// });
// return
// }
const
temp
=
{
questions
:
[{
id
:
editid
,
...
param
}],
researchId
:
surid
,
};
// console.log(temp)
this
.
props
.
edit
(
temp
,
surid
,
this
.
state
.
pageNo
,
this
.
state
.
pageSize
);
this
.
setState
({
fileUrl
:
""
});
}
else
{
...
...
@@ -436,7 +387,6 @@ class Details extends Component {
maxSelectItem
:
values
.
needAnswer2
?
values
.
maxSelectItem
:
""
,
minSelectItem
:
values
.
needAnswer1
?
values
.
minSelectItem
:
""
,
reseachId
:
surid
,
//no:tlist.list[0]?tlist.list[0].no+1:order,
hasOther
:
this
.
addother
.
state
.
addother
?
1
:
0
,
otherOption
:
{
content
:
this
.
addother
.
state
.
other
,
...
...
@@ -444,15 +394,6 @@ class Details extends Component {
required
:
this
.
addother
.
state
.
ismust
?
1
:
0
,
},
};
// 判断最大可选
// if( param.maxSelectItem !== '' && param.maxSelectItem > param.questionOptions.length){
// message.error('最多项错误')
// this.setState({
// confirmLoading: false,
// });
// return
// }
this
.
props
.
insert
(
param
,
this
.
state
.
pageNo
,
this
.
state
.
pageSize
);
this
.
setState
({
fileUrl
:
""
});
}
...
...
@@ -488,7 +429,7 @@ class Details extends Component {
const
{
details
,
tlist
,
newsList
,
jumptests
,
surid
}
=
this
.
props
;
const
uploadProps
=
{
uploadUtilName
:
"上传图片/
音/视频
"
,
uploadUtilName
:
"上传图片/
文件
"
,
getUrl
:
(
fileUrl
,
fileName
)
=>
{
this
.
setState
({
fileUrl
,
...
...
src/pages/TrainingTools/Survey/Create/AddTest.jsx
View file @
aed4885f
...
...
@@ -475,7 +475,7 @@ class AddTest extends Component {
uid
:
1
,
status
:
"done"
,
url
:
this
.
state
.
testItem
.
contentAppendixUrl
,
name
:
this
.
state
.
testItem
.
contentAppendixUrl
,
name
:
this
.
state
.
testItem
.
contentAppendixUrl
.
split
(
'prefix='
)[
1
]
,
},
]
:
[],
...
...
src/pages/TrainingTools/Survey/Details/index.jsx
View file @
aed4885f
...
...
@@ -480,7 +480,7 @@ class Details extends Component {
uid
:
1
,
status
:
"done"
,
url
:
this
.
state
.
testItem
.
contentAppendixUrl
,
name
:
this
.
state
.
testItem
.
contentAppendixUrl
,
name
:
this
.
state
.
testItem
.
contentAppendixUrl
.
split
(
'prefix='
)[
1
]
,
},
]
:
[],
...
...
src/pages/TrainingTools/exam/examCheck/check/index.jsx
View file @
aed4885f
...
...
@@ -4,7 +4,6 @@ import func from "@/util/commonFunc.js";
import
styles
from
"../style/examCheck.less"
;
import
{
connect
}
from
"react-redux"
;
import
{
getPaperList
,
getPaperDetail
,
checkExamPaper
}
from
"../redux/actions"
;
const
Grid
=
Card
.
Grid
;
const
style
=
{
width
:
"100%"
,
...
...
@@ -78,14 +77,19 @@ class Check extends Component {
key
:
"sum"
,
},
{
title
:
"客观题得分"
,
dataIndex
:
"impersonality"
,
key
:
"impersonality"
,
title
:
"交卷时间"
,
dataIndex
:
"submitTime"
,
key
:
"submitTime"
,
render
:
text
=>
(
<
div
>
<
p
>
{
func
.
formateTime
(
text
.
submitTime
)
}
</
p
>
</
div
>
),
},
{
title
:
"
主观题得分
"
,
dataIndex
:
"
subjectivity
"
,
key
:
"
subjectivity
"
,
title
:
"
答题用时(分)
"
,
dataIndex
:
"
duration
"
,
key
:
"
duration
"
,
},
{
title
:
"操作"
,
...
...
src/pages/TrainingTools/exam/questionBank/question/Question.jsx
View file @
aed4885f
...
...
@@ -369,7 +369,7 @@ class Question extends Component {
};
const
uploadProps
=
{
uploadUtilName
:
"上传图片/
音/视频
"
,
uploadUtilName
:
"上传图片/
文件
"
,
getUrl
:
(
originalFileUrl
,
fileName
)
=>
{
this
.
setState
({
originalFileUrl
,
...
...
src/pages/TrainingTools/exam/questionBank/question/change.jsx
View file @
aed4885f
...
...
@@ -298,7 +298,7 @@ class Question extends Component {
console
.
log
(
"1111111111111111111检测打印变量=info "
,
info
);
const
{
uploadParams
,
uploadAction
,
originalFileUrl
}
=
this
.
state
;
const
uploadProps
=
{
uploadUtilName
:
"上传图片/
音/视频
"
,
uploadUtilName
:
"上传图片/
文件
"
,
getUrl
:
(
originalFileUrl
,
fileName
)
=>
{
this
.
setState
({
originalFileUrl
,
...
...
@@ -318,7 +318,7 @@ class Question extends Component {
};
const
uploadProps2
=
{
uploadUtilName
:
"上传图片/
音/视频
"
,
uploadUtilName
:
"上传图片/
文件
"
,
getUrl
:
(
originalFileUrl
,
fileName
)
=>
{
this
.
setState
({
originalFileUrl
,
...
...
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