fix mdtohtml bug

dev_aliyun2
harry 5 years ago
parent 6fa8808a01
commit c2677bace1

@ -3,13 +3,6 @@ import React, { Component } from 'react';
import { Spin } from 'antd'; import { Spin } from 'antd';
class Loading extends Component { class Loading extends Component {
componentDidUpdate(prevProps, prevState) {
if (!prevProps.error && this.props.error) {
console.log(this.props.error)
window.location.reload()
}
}
render() { render() {
return ( return (
<div className="App" style={{ minHeight: '800px', width: "100%" }}> <div className="App" style={{ minHeight: '800px', width: "100%" }}>

@ -1,14 +1,25 @@
import { bytesToSize, getUrl, getUrl2 } from 'educoder'; import { bytesToSize, getUrl, getUrl2 } from 'educoder';
const $ = window.$ const $ = window.$
import showdown from 'showdown' import showdown from 'showdown'
import showdownKatex from 'showdown-katex'
export function isImageExtension(fileName) { export function isImageExtension(fileName) {
return fileName ? !!(fileName.match(/.(jpg|jpeg|png|gif)$/i)) : false return fileName ? !!(fileName.match(/.(jpg|jpeg|png|gif)$/i)) : false
} }
const katex = showdownKatex()
const converter = new showdown.Converter({
extensions: [katex]
})
// const katexRex = /(?:\$\$)([^\$]+)(?:\$\$)/g
export function markdownToHTML(oldContent) { export function markdownToHTML(oldContent) {
var converter = new showdown.Converter() if (oldContent) {
return converter.makeHtml(oldContent); //let rs = oldContent.replace(katexRex, (_, p1) => `$${p1}$`)
let rs = converter.makeHtml(oldContent)
return rs
}
return oldContent
} }
function _doDownload(options) { function _doDownload(options) {
$.fileDownload(getUrl() + "/api" + options.url, { $.fileDownload(getUrl() + "/api" + options.url, {

@ -5,13 +5,12 @@ import _ from 'lodash';
import ImageLayerOfCommentHOC from '../../../page/layers/ImageLayerOfCommentHOC'; import ImageLayerOfCommentHOC from '../../../page/layers/ImageLayerOfCommentHOC';
import GraduationTasksappraiseMainEditor from '../../graduation/tasks/GraduationTasksappraiseMainEditor'; import GraduationTasksappraiseMainEditor from '../../graduation/tasks/GraduationTasksappraiseMainEditor';
import CCommentItem from '../../common/comments/CCommentItem'; import CCommentItem from '../../common/comments/commonent-item';
import '../../../forums/Post.css'; import '../../../forums/Post.css';
import '../../../comment/Comment.css'; import '../../../comment/Comment.css';
import '../../common/courseMessage.css'; import '../../common/courseMessage.css';
import '../../graduation/tasks/GraduationTasksappraiseReply.css'; import '../../graduation/tasks/GraduationTasksappraiseReply.css';
import './CommonWorkAppraiseReply.css';
import ModulationModal from "../../coursesPublic/ModulationModal"; import ModulationModal from "../../coursesPublic/ModulationModal";
import Modals from '../../../modals/Modals'; import Modals from '../../../modals/Modals';
@ -156,20 +155,12 @@ class CommonWorkAppraiseReply extends Component {
console.log(value, num) console.log(value, num)
let { operationId } = this.state; let { operationId } = this.state;
let studentWorkId = this.props.match.params.studentWorkId; let studentWorkId = this.props.match.params.studentWorkId;
// console.log(value,num)
let url = "/student_works/" + studentWorkId + "/adjust_score.json"; let url = "/student_works/" + studentWorkId + "/adjust_score.json";
axios.post(url, { axios.post(url, {
score: num, score: num,
comment: value comment: value
}).then((result) => { }).then((result) => {
// console.log(result)
if (result.data.status === 0) { if (result.data.status === 0) {
// this.setState({
// Modalstype:true,
// Allocationtype:false,
// Modalstopval:result.data.message,
// ModalSave:this.cancelmodel,
// })
this.cancelmodel() this.cancelmodel()
this.props.showNotification('调分成功') this.props.showNotification('调分成功')
this.props.onReplySuccess && this.props.onReplySuccess() this.props.onReplySuccess && this.props.onReplySuccess()

@ -1,7 +1,7 @@
import '../../katex.css'; import '../../katex.css';
import React,{ Component } from "react"; import React, { Component } from "react";
import { getImageUrl, markdownToHTML, WordsBtn, getUrl } from 'educoder'; import { getImageUrl, markdownToHTML, WordsBtn, getUrl } from 'educoder';
import { Tooltip } from 'antd'; import { Tooltip } from 'antd';
import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor'; import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor';
import axios from 'axios'; import axios from 'axios';
import moment from 'moment'; import moment from 'moment';
@ -14,152 +14,154 @@ const _origin = ''
*/ */
const ACCEPT = 3 const ACCEPT = 3
const REFUSE = 4 const REFUSE = 4
class CCommentItem extends Component{ class CCommentItem extends Component {
constructor(props){ constructor(props) {
super(props); super(props);
this.state = { this.state = {
show_reply: false, show_reply: false,
show_appeal: false, show_appeal: false,
}
}
cancelReply = () => {
this.setState({ show_reply: false })
}
showReply = () => {
this.setState({ show_reply: true, show_appeal: false })
}
showAppeal = () => {
this.setState({ show_appeal: true, show_reply: false })
}
cancelAppeal = () => {
this.setState({ show_appeal: false })
}
onCancel = () => {
this.state.show_reply ? this.cancelReply() : this.cancelAppeal()
} }
}
cancelReply = () => {
this.setState({ show_reply: false })
}
showReply = () => {
this.setState({ show_reply: true, show_appeal: false })
}
showAppeal = () => {
this.setState({ show_appeal: true, show_reply: false })
}
cancelAppeal = () => {
this.setState({ show_appeal: false })
}
onCancel = () => {
this.state.show_reply ? this.cancelReply() : this.cancelAppeal()
}
cancelMyAppeal = () => { cancelMyAppeal = () => {
this.props.confirm({ this.props.confirm({
content: <div> content: <div>
<div>撤销申诉后无法再对本评阅记录进行申诉</div> <div>撤销申诉后无法再对本评阅记录进行申诉</div>
<div>是否确认撤销申诉</div> <div>是否确认撤销申诉</div>
</div>, </div>,
onOk: () => { onOk: () => {
let studentWorkId =this.props.match.params.studentWorkId; let studentWorkId = this.props.match.params.studentWorkId;
let { item, commentIndex }=this.props; let { item, commentIndex } = this.props;
const url = `/student_works/${studentWorkId}/cancel_appeal.json` const url = `/student_works/${studentWorkId}/cancel_appeal.json`
axios.post(url, { axios.post(url, {
score_id: item.id score_id: item.id
}) })
.then((response) => { .then((response) => {
if (response.data.status == 0) { if (response.data.status == 0) {
this.props.showNotification('撤销成功') this.props.showNotification('撤销成功')
this.props.replySuccess() this.props.replySuccess()
} }
}) })
.catch(function (error) { .catch(function (error) {
console.log(error); console.log(error);
}); });
} }
}) })
} }
onSubmit = () => { onSubmit = () => {
let workId=this.props.match.params.workId; let workId = this.props.match.params.workId;
let studentWorkId =this.props.match.params.studentWorkId; let studentWorkId = this.props.match.params.studentWorkId;
let { item, commentIndex }=this.props; let { item, commentIndex } = this.props;
if (!this.state.secondReplyContent || !this.state.secondReplyContent.trim()) { if (!this.state.secondReplyContent || !this.state.secondReplyContent.trim()) {
this.props.showNotification('内容不能为空') this.props.showNotification('内容不能为空')
return; return;
}
if (this.state.show_reply) {
const url = `/student_works/${studentWorkId}/add_score_reply.json`
axios.post(url, {
score_id: item.id,
comment: this.state.secondReplyContent
}).then((result) => {
if (result.data.status == 0) {
this.props.replySuccess()
this.cancelReply()
}
}).catch((error) => {
console.log(error)
})
} else {
const appealUrl = `/student_works/${studentWorkId}/appeal_anonymous_score.json`
axios.post(appealUrl, {
score_id: item.id,
comment: this.state.secondReplyContent
}).then((result) => {
if (result.data.status == 0) {
this.props.replySuccess()
this.cancelAppeal()
}
}).catch((error) => {
console.log(error)
})
}
} }
if (this.state.show_reply) { onDeleteSecondReply = (item) => {
const url = `/student_works/${studentWorkId}/add_score_reply.json` this.props.confirm({
axios.post(url, { // content: `确认要删除所选的${len}个帖子吗?`,
score_id: item.id, content: `是否确认删除?`,
comment: this.state.secondReplyContent onOk: () => {
}).then((result)=>{
if(result.data.status == 0){ const url = `/commons/delete.json`
this.props.replySuccess() axios.delete(url, {
this.cancelReply() data: {
object_id: item.id,
object_type: 'journals_for_message'
}
})
.then((response) => {
if (response.data.status == 0) {
this.props.replySuccess()
this.cancelAppeal()
}
})
.catch(function (error) {
console.log(error);
});
} }
}).catch((error)=>{
console.log(error)
}) })
} else { }
const appealUrl = `/student_works/${studentWorkId}/appeal_anonymous_score.json` on_deal_appeal_score = (mode, item) => {
axios.post(appealUrl, { this.props.confirm({
score_id: item.id, // content: `确认要删除所选的${len}个帖子吗?`,
comment: this.state.secondReplyContent content:
}).then((result)=>{ <div>
if(result.data.status == 0){ <div>{mode == ACCEPT ? '此匿评成绩将被废弃,评阅人的作品将被违规扣分' : '此匿评成绩将被认为合理'}</div>
this.props.replySuccess() <div>是否确认{mode == ACCEPT ? '接受申诉' : '拒绝申诉'}</div>
this.cancelAppeal() </div>
,
onOk: () => {
let studentWorkId = this.props.match.params.studentWorkId;
const url = `/student_works/${studentWorkId}/deal_appeal_score.json`
axios.post(url, {
score_id: item.score_id,
status: mode
})
.then((response) => {
if (response.data.status == 0) {
this.props.showNotification(`${mode == ACCEPT ? '接受申诉' : '拒绝申诉'}成功`)
this.props.replySuccess()
}
})
.catch(function (error) {
console.log(error);
});
} }
}).catch((error)=>{
console.log(error)
}) })
} }
}
onDeleteSecondReply = (item) => { parseCommentContent = (oldContent) => {
this.props.confirm({
// content: `确认要删除所选的${len}个帖子吗?`,
content: `是否确认删除?`,
onOk: () => {
const url = `/commons/delete.json`
axios.delete(url, { data: {
object_id: item.id,
object_type: 'journals_for_message'
}})
.then((response) => {
if (response.data.status == 0) {
this.props.replySuccess()
this.cancelAppeal()
}
})
.catch(function (error) {
console.log(error);
});
}
})
}
on_deal_appeal_score = (mode, item) => {
this.props.confirm({
// content: `确认要删除所选的${len}个帖子吗?`,
content:
<div>
<div>{mode == ACCEPT ? '此匿评成绩将被废弃,评阅人的作品将被违规扣分' : '此匿评成绩将被认为合理'}</div>
<div>是否确认{mode == ACCEPT ? '接受申诉' : '拒绝申诉'}</div>
</div>
,
onOk: () => {
let studentWorkId =this.props.match.params.studentWorkId;
const url = `/student_works/${studentWorkId}/deal_appeal_score.json`
axios.post(url, {
score_id: item.score_id,
status: mode
})
.then((response) => {
if (response.data.status == 0) {
this.props.showNotification(`${mode == ACCEPT ? '接受申诉' : '拒绝申诉'}成功`)
this.props.replySuccess()
}
})
.catch(function (error) {
console.log(error);
});
}
})
}
parseCommentContent = (oldContent) => {
return markdownToHTML(oldContent); return markdownToHTML(oldContent);
} }
exportMdtoHtml=(md)=> { exportMdtoHtml = (md) => {
let newmd=md; let newmd = md;
const converter = new showdown.Converter({ const converter = new showdown.Converter({
extensions: [ extensions: [
showdownKatex({ showdownKatex({
@ -175,8 +177,8 @@ class CCommentItem extends Component{
return converter.makeHtml(newmd); return converter.makeHtml(newmd);
} }
renderChildenComments = (parent) => { renderChildenComments = (parent) => {
if (parent.journals.length == 0) { if (parent.journals.length == 0) {
return ''; return '';
} }
const isAdmin = this.props.isAdmin() const isAdmin = this.props.isAdmin()
@ -203,39 +205,39 @@ class CCommentItem extends Component{
{item.is_appeal_info == true ? {item.is_appeal_info == true ?
<a href={`javascript:void(0)`} target="_blank"> <a href={`javascript:void(0)`} target="_blank">
<img alt="用户头像" height="50" <img alt="用户头像" height="50"
src={`${getUrl()}/images/edu_user/anony.png`} width="50"/> src={`${getUrl()}/images/edu_user/anony.png`} width="50" />
</a> </a>
: <a href={`${_origin}/users/${item.user_info.user_login}`} target="_blank"> : <a href={`${_origin}/users/${item.user_info.user_login}`} target="_blank">
<img alt="用户头像" height="50" <img alt="用户头像" height="50"
src={`${getImageUrl(`images/`+imgSrc)}`} src={`${getImageUrl(`images/` + imgSrc)}`}
width="50"/> width="50" />
</a>} </a>}
</div> </div>
<div className="t_content fl"> <div className="t_content fl">
<div className="J_Comment_Reply"> <div className="J_Comment_Reply">
<div className="comment_orig_content" style={{ margin:"0px" }}> <div className="comment_orig_content" style={{ margin: "0px" }}>
<div className="J_Comment_Info clearfix mt3"> <div className="J_Comment_Info clearfix mt3">
<div className="t_info fl"> <div className="t_info fl">
{item.user_info.user_login==="--"? {item.user_info.user_login === "--" ?
<a className="content-username hide fl"> <a className="content-username hide fl">
{item.user_info.user_name} {item.user_info.user_name}
</a> </a>
:<a href={`${_origin}/users/${item.user_info.user_login}`} className="content-username hide fl"> : <a href={`${_origin}/users/${item.user_info.user_login}`} className="content-username hide fl">
{item.user_info.user_name} {item.user_info.user_name}
</a>} </a>}
<span className="t_area fl">{moment(item.time).format('YYYY-MM-DD HH:mm')}</span> <span className="t_area fl">{moment(item.time).format('YYYY-MM-DD HH:mm')}</span>
{item.is_appeal_info && (item.appeal_status == 1 ? {item.is_appeal_info && (item.appeal_status == 1 ?
<span className={"edu-filter-btn edu-filter-btn-4CACFF ml15 fl typestyle "} >申诉中</span> : <span className={"edu-filter-btn edu-filter-btn-4CACFF ml15 fl typestyle "} >申诉中</span> :
item.appeal_status == 2 ? item.appeal_status == 2 ?
<span className={"edu-filter-btn edu-filter-btn-EDEDED ml15 fl typestyle color666666 "} >申诉已撤销</span> : <span className={"edu-filter-btn edu-filter-btn-EDEDED ml15 fl typestyle color666666 "} >申诉已撤销</span> :
item.appeal_status == 3 ? item.appeal_status == 3 ?
<span className={"edu-filter-btn edu-filter-btn-4CACFF ml15 fl typestyle "} >申诉成功</span> : <span className={"edu-filter-btn edu-filter-btn-4CACFF ml15 fl typestyle "} >申诉成功</span> :
item.appeal_status == 4 ? item.appeal_status == 4 ?
<span className={"edu-filter-btn edu-filter-btn-EDEDED ml15 fl typestyle color666666 "} >申诉被拒绝</span> : <span className={"edu-filter-btn edu-filter-btn-EDEDED ml15 fl typestyle color666666 "} >申诉被拒绝</span> :
item.appeal_status == 5 ? item.appeal_status == 5 ?
<span className={"edu-filter-btn edu-filter-btn-EDEDED ml15 fl typestyle color666666 "} >申诉失败</span> : '') <span className={"edu-filter-btn edu-filter-btn-EDEDED ml15 fl typestyle color666666 "} >申诉失败</span> : '')
} }
@ -246,14 +248,14 @@ class CCommentItem extends Component{
<i className="iconfont icon-shanchu mr5 fr font-14" onClick={() => this.onDeleteSecondReply(item)} <i className="iconfont icon-shanchu mr5 fr font-14" onClick={() => this.onDeleteSecondReply(item)}
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
></i> ></i>
</Tooltip> } </Tooltip>}
{/* </React.Fragment> {/* </React.Fragment>
} */} } */}
{item.is_appeal_info && isAdmin && item.appeal_status == 1 && this.props.isAdmin()===true&&<React.Fragment> {item.is_appeal_info && isAdmin && item.appeal_status == 1 && this.props.isAdmin() === true && <React.Fragment>
<WordsBtn style="grey" onClick={() => this.on_deal_appeal_score(REFUSE, item)} className="fr ml6">拒绝申诉</WordsBtn> <WordsBtn style="grey" onClick={() => this.on_deal_appeal_score(REFUSE, item)} className="fr ml6">拒绝申诉</WordsBtn>
<WordsBtn style="orange" onClick={() => this.on_deal_appeal_score(ACCEPT, item)} className="fr">接受申诉</WordsBtn> <WordsBtn style="orange" onClick={() => this.on_deal_appeal_score(ACCEPT, item)} className="fr">接受申诉</WordsBtn>
</React.Fragment>} </React.Fragment>}
{item.appeal_status == 1 && this.props.is_author == true && this.props.isStudent()===true && {item.appeal_status == 1 && this.props.is_author == true && this.props.isStudent() === true &&
<WordsBtn style="blue" className="fr mr5" onClick={() => this.cancelMyAppeal()}>撤销申诉</WordsBtn>} <WordsBtn style="blue" className="fr mr5" onClick={() => this.cancelMyAppeal()}>撤销申诉</WordsBtn>}
</div> </div>
@ -261,8 +263,8 @@ class CCommentItem extends Component{
<div className="comment_content clearfix" id={`reply_content_${item.id}`}> <div className="comment_content clearfix" id={`reply_content_${item.id}`}>
<div className="color-grey-3" id={`reply_content_${item.id}`}> <div className="color-grey-3" id={`reply_content_${item.id}`}>
<div className={"markdown-body"} <div className={"markdown-body"}
dangerouslySetInnerHTML={{__html:markdownToHTML(item.content)}}></div> dangerouslySetInnerHTML={{ __html: markdownToHTML(item.content) }}></div>
<div className="cl"></div> <div className="cl"></div>
</div> </div>
</div> </div>
@ -274,61 +276,61 @@ class CCommentItem extends Component{
</div> </div>
) )
}) })
} }
render(){ render() {
let { item, commentIndex, homework_status, is_author }=this.props; let { item, commentIndex, homework_status, is_author } = this.props;
let { show_reply, show_appeal }=this.state; let { show_reply, show_appeal } = this.state;
const _content = item.content ? markdownToHTML(item.content): '' const _content = item.content ? markdownToHTML(item.content) : ''
const isAnonymous = homework_status && homework_status.indexOf('匿评中') != -1 const isAnonymous = homework_status && homework_status.indexOf('匿评中') != -1
const isAppealing = homework_status && homework_status.indexOf('申诉中') != -1 const isAppealing = homework_status && homework_status.indexOf('申诉中') != -1
const attachments = item.attachments; const attachments = item.attachments;
const isAdmin = this.props.isAdmin() const isAdmin = this.props.isAdmin()
return( return (
<div className="ccomment comment_item_cont df clearfix" key={item.id}> <div className="ccomment comment_item_cont df clearfix" key={item.id}>
<div className="J_Comment_Face fl"> <div className="J_Comment_Face fl">
{item.image_url == '--' ? {item.image_url == '--' ?
<a href={`javascript:void(0)`} > <a href={`javascript:void(0)`} >
<img alt="用户头像" height="50" <img alt="用户头像" height="50"
src={`${getUrl()}/images/edu_user/anony.png`} width="50"/> src={`${getUrl()}/images/edu_user/anony.png`} width="50" />
</a> </a>
: <a href={`${_origin}/users/${item.user_login}`} target="_blank"> : <a href={`${_origin}/users/${item.user_login}`} target="_blank">
<img alt="用户头像" height="50" <img alt="用户头像" height="50"
src={`${getUrl()}/images/${item.image_url}`} src={`${getUrl()}/images/${item.image_url}`}
width="50"/> width="50" />
</a>} </a>}
{/* <a href={`${_origin}/users/${item.user_login}`} target="_blank"> {/* <a href={`${_origin}/users/${item.user_login}`} target="_blank">
<img alt="用户头像" height="50" src={getImageUrl(`images/${item.image_url}`)} width="50"/> <img alt="用户头像" height="50" src={getImageUrl(`images/${item.image_url}`)} width="50"/>
</a> */} </a> */}
</div> </div>
<div className="t_content fl"> <div className="t_content fl">
<div className="J_Comment_Reply"> <div className="J_Comment_Reply">
<div className="comment_orig_content" style={{ margin:"0px" }}> <div className="comment_orig_content" style={{ margin: "0px" }}>
<div className="J_Comment_Info clearfix mt3"> <div className="J_Comment_Info clearfix mt3">
<div className="t_info fl"> <div className="t_info fl">
{ {
item.user_login==="--"? <a className="content-username hide fl"> item.user_login === "--" ? <a className="content-username hide fl">
{item.username}{item.comment_role} {item.username}{item.comment_role}
</a> </a>
: :
<a href={`${_origin}/users/${item.user_login}`} className="content-username hide fl"> <a href={`${_origin}/users/${item.user_login}`} className="content-username hide fl">
{item.username}{item.comment_role} {item.username}{item.comment_role}
</a> </a>
} }
<span className="t_area fl">{item.time}</span> <span className="t_area fl">{item.time}</span>
{/* 分数 */} {/* 分数 */}
{item.score !== null && <span className="score_area fl">{item.score}</span>} {item.score !== null && <span className="score_area fl">{item.score}</span>}
{/* item.is_invalid && */} {/* item.is_invalid && */}
{/* { item.delete && isAdmin && <Tooltip title={ "" } > {/* { item.delete && isAdmin && <Tooltip title={ "" } >
<i className="iconfont icon-shanchu mr5 fr" style={{marginLeft: '6px'}} <i className="iconfont icon-shanchu mr5 fr" style={{marginLeft: '6px'}}
onClick={() => this.props.onDelete(item)}> onClick={() => this.props.onDelete(item)}>
</i> </i>
@ -336,9 +338,9 @@ class CCommentItem extends Component{
{/* fr */} {/* fr */}
{/* <WordsBtn style="blue" className="fr">回复</WordsBtn> */} {/* <WordsBtn style="blue" className="fr">回复</WordsBtn> */}
{ item.is_invalid ? <span className="validate_area fr">失效</span> : {item.is_invalid ? <span className="validate_area fr">失效</span> :
<React.Fragment> <React.Fragment>
<WordsBtn style="blue" className="fr" onClick={this.state.show_reply ? this.cancelReply : this.showReply}>回复</WordsBtn> <WordsBtn style="blue" className="fr" onClick={this.state.show_reply ? this.cancelReply : this.showReply}>回复</WordsBtn>
{(isAppealing || isAnonymous) && item.can_appeal && item.appeal_status == 0 && {(isAppealing || isAnonymous) && item.can_appeal && item.appeal_status == 0 &&
@ -346,85 +348,85 @@ class CCommentItem extends Component{
</React.Fragment> </React.Fragment>
} }
{item.delete && isAdmin {item.delete && isAdmin
&& <WordsBtn style="blue" className="fr mr12" && <WordsBtn style="blue" className="fr mr12"
onClick={() => this.props.onDelete(item)}>删除</WordsBtn>} onClick={() => this.props.onDelete(item)}>删除</WordsBtn>}
</div>
</div> </div>
</div>
{!!_content && _content !== 'null' && <div className="comment_content clearfix mt8" id={`reply_content_${item.id}`}> {!!_content && _content !== 'null' && <div className="comment_content clearfix mt8" id={`reply_content_${item.id}`}>
<div className="color-grey-3" id={`reply_content_${item.id}`}> <div className="color-grey-3" id={`reply_content_${item.id}`}>
<div className={"markdown-body"} dangerouslySetInnerHTML={{__html: _content}}></div> <div className={"markdown-body"} dangerouslySetInnerHTML={{ __html: _content }}></div>
<div className="cl"></div> <div className="cl"></div>
</div>
</div>}
{!_content && <span className="color656565 mt2 color-grey-9 font-12 mr8" style={{ display: 'inline-block'}}>{"暂未写评语"}</span>}
<div className="mt6">
{attachments && attachments.map((attaItem, key)=>{
return(
<div className="color-grey attachItem" key={key}>
<a className="color-grey ">
<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
</a>
<a href={attaItem.url}
className="mr12 color9B9B" length="58">
{attaItem.title}
</a>
<span className="color656565 mt2 color-grey-6 font-12 mr8">{attaItem.filesize}</span>
{/*{item.delete===true?<i className="font-14 iconfont icon-guanbi " id={item.id} aria-hidden="true" onClick={()=>this.onAttachmentRemove(item.id)}></i>:""}*/}
</div>
)
})}
</div> </div>
</div>}
{!_content && <span className="color656565 mt2 color-grey-9 font-12 mr8" style={{ display: 'inline-block' }}>{"暂未写评语"}</span>}
<div className="mt6">
{attachments && attachments.map((attaItem, key) => {
return (
<div className="color-grey attachItem" key={key}>
<a className="color-grey ">
<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
</a>
<a href={attaItem.url}
className="mr12 color9B9B" length="58">
{attaItem.title}
</a>
<span className="color656565 mt2 color-grey-6 font-12 mr8">{attaItem.filesize}</span>
{/*{item.delete===true?<i className="font-14 iconfont icon-guanbi " id={item.id} aria-hidden="true" onClick={()=>this.onAttachmentRemove(item.id)}></i>:""}*/}
</div>
)
})}
</div>
<style>{` <style>{`
.ccomment .childrenCommentsView .comment_item_cont .break_word_comments { .ccomment .childrenCommentsView .comment_item_cont .break_word_comments {
margin-top: 4px; margin-top: 4px;
width: 94%; width: 94%;
font-size: 14px; font-size: 14px;
} }
`}</style> `}</style>
<div className="childrenCommentsView" style={{background: '#fff'}}> <div className="childrenCommentsView" style={{ background: '#fff' }}>
{/* {(item && item.journals && item.journals.length) ? <div className="trangle"></div>: ''} */} {/* {(item && item.journals && item.journals.length) ? <div className="trangle"></div>: ''} */}
{this.renderChildenComments(item)} {this.renderChildenComments(item)}
{/* { item.isAllChildrenLoaded != true && item.journals && this.props.isChildCommentPagination == true && item.journals.length >= 5? {/* { item.isAllChildrenLoaded != true && item.journals && this.props.isChildCommentPagination == true && item.journals.length >= 5?
<Tooltip title={ "点击查看更多回复" } disableFocusListener={true}> <Tooltip title={ "点击查看更多回复" } disableFocusListener={true}>
<div className="loadMoreChildComments" onClick={() => {this.props.loadMoreChildComments && this.props.loadMoreChildComments(item)}}> <div className="loadMoreChildComments" onClick={() => {this.props.loadMoreChildComments && this.props.loadMoreChildComments(item)}}>
<i className="iconfont icon-xiajiantou"></i> <i className="iconfont icon-xiajiantou"></i>
</div> </div>
</Tooltip> </Tooltip>
: ''} */} : ''} */}
</div> </div>
{/* 去掉了orig_reply 影响到i标签 */} {/* 去掉了orig_reply 影响到i标签 */}
<p className="" > <p className="" >
{/* 第二排右侧按钮区域 */} {/* 第二排右侧按钮区域 */}
{/* ${this.state.show_reply ? '回复' : '申诉'} */} {/* ${this.state.show_reply ? '回复' : '申诉'} */}
{(show_reply || show_appeal) && {(show_reply || show_appeal) &&
<React.Fragment> <React.Fragment>
<TPMMDEditor mdID={`${commentIndex}`} watch={false} <TPMMDEditor mdID={`${commentIndex}`} watch={false}
height={130} onChange={(val) => this.setState({ secondReplyContent: val})} height={130} onChange={(val) => this.setState({ secondReplyContent: val })}
placeholder={`请输入内容`} noStorage={true} placeholder={`请输入内容`} noStorage={true}
></TPMMDEditor> ></TPMMDEditor>
<div className="fr"> <div className="fr">
<a className="task-btn task-btn-orange fr" style={{height: '26px', lineHeight: '26px', width: '60px'}} <a className="task-btn task-btn-orange fr" style={{ height: '26px', lineHeight: '26px', width: '60px' }}
onClick={this.onSubmit} onClick={this.onSubmit}
>{this.state.show_reply ? '回复' : '申诉'}</a> >{this.state.show_reply ? '回复' : '申诉'}</a>
<a onClick={this.onCancel} className="defalutCancelbtn fr" <a onClick={this.onCancel} className="defalutCancelbtn fr"
style={{height: '26px', width: '60px', fontSize: '14px', lineHeight: '26px', marginRight: '10px'}}>取消</a> style={{ height: '26px', width: '60px', fontSize: '14px', lineHeight: '26px', marginRight: '10px' }}>取消</a>
</div> </div>
</React.Fragment> </React.Fragment>
} }
</p> </p>
</div>
</div> </div>
</div> </div>
</div> </div>
) </div>
} )
}
} }
export default CCommentItem; export default CCommentItem;

@ -0,0 +1,13 @@
import React from 'react'
export default ({ url, title, filesize }) => {
return (
<div className="color-grey attachItem" >
<a className="color-grey ">
<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
</a>
<a href={url} className="mr12 color9B9B" length="58"> {title} </a>
<span className="color656565 mt2 color-grey-6 font-12 mr8">{filesize}</span>
</div>
)
}

@ -0,0 +1,114 @@
import React, { useMemo } from 'react'
import { markdownToHTML, WordsBtn, getUrl, getImageUrl } from 'educoder'
const appealStatus = {
1: '申诉中',
2: '申诉已撤销',
3: '申诉成功',
4: '申诉被拒绝',
5: '申诉失败'
}
/**
can_delete: true
content: "qwe"
id: 81136
time: "2019-06-04T11:00:21.000+08:00"
user_image_url: "avatars/User/1"
user_login: "innov"
user_name: "社区导师"
*/
// is_appeal_info true 使
export default ({ isStudent = false, isAdmin, callback, is_author, ...item }) => {
const pre = getUrl()
const _origin = ''
function onDeleteReply() {
callback('del-replay-item', item)
}
function cancelMyAppeal() {
callback('cancel-my-appeal', item)
}
function refuseAppealScore() {
callback('refuse-appeal-score', item)
}
function acceptAppealScore() {
callback('accept-appeal-score', item)
}
const { id, user_info, time, appeal_status, content, is_appeal_info, can_delete } = item
const { user_image_url, user_login, user_name } = user_info
const imgSrc = (!user_image_url || user_image_url === '--') ? `edu_user/anony.png` : user_image_url;
const md = useMemo(() => {
return markdownToHTML(content)
}, [content])
return (
<div className="ccomment comment_item_cont df clearfix" key={id}>
<div className="J_Comment_Face fl">
{is_appeal_info == true ?
<a href={`javascript:void(0)`} target="_blank">
<img alt="用户头像" height="50"
src={`${pre}/images/edu_user/anony.png`} width="50" />
</a>
: <a href={`${_origin}/users/${user_login}`} target="_blank">
<img alt="用户头像" height="50"
src={`${getImageUrl(`images/` + imgSrc)}`}
width="50" />
</a>}
</div>
<div className="t_content fl">
<div className="J_Comment_Reply">
<div className="comment_orig_content" style={{ margin: "0px" }}>
<div className="J_Comment_Info clearfix mt3">
<div className="t_info fl">
{user_login === "--" ?
<a className="content-username hide fl">
{user_name}
</a>
: <a href={`${_origin}/users/${user_login}`} className="content-username hide fl">
{user_name}
</a>}
<span className="t_area fl">{time}</span>
{is_appeal_info ? <span className="edu-filter-btn edu-filter-btn-4CACFF ml15 fl typestyle " >{appealStatus[appeal_status]}</span> : null}
{
!is_appeal_info && can_delete == true && <a title="删除">
<i className="iconfont icon-shanchu mr5 fr font-14" onClick={onDeleteReply}
style={{ cursor: 'pointer' }}
></i>
</a>
}
{
is_appeal_info && isAdmin && appeal_status == 1 ? <React.Fragment>
<WordsBtn style="grey" onClick={refuseAppealScore} className="fr ml6">拒绝申诉</WordsBtn>
<WordsBtn style="orange" onClick={acceptAppealScore} className="fr">接受申诉</WordsBtn>
</React.Fragment> : null
}
{
appeal_status == 1 && isStudent === true && is_author &&
<WordsBtn style="blue" className="fr mr5" onClick={cancelMyAppeal}>撤销申诉</WordsBtn>
}
</div>
</div>
<div className="comment_content clearfix" id={`reply_content_${id}`}>
<div className="color-grey-3" id={`reply_content_${id}`}>
<div className={"markdown-body"} dangerouslySetInnerHTML={{ __html: md }}></div>
<div className="cl"></div>
</div>
</div>
</div>
</div>
</div>
</div >
)
}

@ -0,0 +1,5 @@
.ccomment .childrenCommentsView .comment_item_cont .break_word_comments {
margin-top: 4px;
width: 94%;
font-size: 14px;
}

@ -0,0 +1,226 @@
import React, { Fragment, useState, useMemo } from 'react'
import AttachmentItem from '../attachment-item'
import CommentItemReplay from '../commonent-item-replay'
import { useParams } from 'react-router-dom'
import TPMMDEditor from '../../../../tpm/challengesnew/TPMMDEditor'
import axios from 'axios'
import { markdownToHTML, WordsBtn, getUrl } from 'educoder'
import './index.css'
const ACCEPT = 3
const REFUSE = 4
export default ({ confirm, item, showNotification, replySuccess, isStudent, isAdmin, homework_status, callback, is_author, commentIndex, onDelete }) => {
const [data, setData] = useState({
value: '',
isShow: false,
mode: 'reply'
})
const { studentWorkId, workId } = useParams()
const { value, isShow, mode } = data
function onCancelMyAppeal() {
confirm({
content: <div>
<p>撤销申诉后无法再对本评阅记录进行申诉</p>
<p>是否确认撤销申诉</p>
</div>,
onOk: () => {
const url = `/student_works/${studentWorkId}/cancel_appeal.json`
axios.post(url, {
score_id: item.id
})
.then((response) => {
if (response.data.status == 0) {
showNotification('撤销成功')
replySuccess()
}
})
.catch(function (error) {
console.log(error)
})
}
})
}
function onDeleteReply(source) {
confirm({
content: `是否确认删除?`,
onOk: () => {
const url = `/commons/delete.json`
axios.delete(url, {
data: {
object_id: source.id,
object_type: 'journals_for_message'
}
})
.then((response) => {
if (response.data.status == 0) {
replySuccess()
setData({ ...data, isShow: false })
}
})
.catch(function (error) {
console.log(error)
})
}
})
}
function onDeleteHandler() {
onDelete(item)
}
function onSubmit() {
if (!value || !value.trim()) {
showNotification('内容不能为空')
return
}
let url = `/student_works/${studentWorkId}/appeal_anonymous_score.json`
if (mode === 'reply') {
url = `/student_works/${studentWorkId}/add_score_reply.json`
axios.post(url, {
score_id: item.id,
comment: value
}).then((result) => {
if (result.data.status == 0) {
replySuccess()
setData({ ...data, isShow: false })
}
}).catch((error) => {
console.log(error)
})
}
}
function callback(type, source) {
if (type === 'refuse-appeal-score') {
onDealAppealScore(REFUSE, source)
}
if (type === 'accept-appeal-score') {
onDealAppealScore(ACCEPT, source)
}
if (type === 'cancel-my-appeal') {
onCancelMyAppeal()
}
if (type === 'del-replay-item') {
onDeleteReply(source)
}
}
function onDealAppealScore(mode, source) {
confirm({
content:
<div>
<div>{mode == ACCEPT ? '此匿评成绩将被废弃,评阅人的作品将被违规扣分' : '此匿评成绩将被认为合理'}</div>
<div>是否确认{mode == ACCEPT ? '接受申诉' : '拒绝申诉'}</div>
</div>
,
onOk: () => {
const url = `/student_works/${studentWorkId}/deal_appeal_score.json`
axios.post(url, {
score_id: source.score_id,
status: mode
})
.then((response) => {
if (response.data.status == 0) {
showNotification(`${mode == ACCEPT ? '接受申诉' : '拒绝申诉'}成功`)
replySuccess()
}
})
.catch(function (error) {
console.log(error);
});
}
})
}
const pre = getUrl()
const _origin = ''
function onChangeHandler(value) {
setData({ ...data, value })
}
function onReplayHandler() {
setData({ ...data, isShow: true, mode: 'reply' })
}
function onAppealHandler() {
setData({ ...data, isShow: true, mode: 'appeal' })
}
function onCancel() {
setData({ ...data, isShow: false })
}
const { id, image_url, user_login, username, comment_role, time, score, is_invalid, can_appeal, appeal_status, content, attachments, journals } = item
const isAnonymous = homework_status && homework_status.indexOf('匿评中') != -1
const isAppealing = homework_status && homework_status.indexOf('申诉中') != -1
const md = useMemo(() => {
let rs = markdownToHTML(content)
return rs
}, [content, id])
return (
<div className="ccomment comment_item_cont df clearfix" key={id}>
<div className="J_Comment_Face fl">
<a href={image_url === '--' ? `${_origin}/users/${user_login}` : 'javascript:void(0)'} target="_blank">
<img alt="用户头像" height="50"
src={`${pre}/images/${image_url}`}
width="50" />
</a>
</div>
<div className="t_content fl">
<div className="J_Comment_Reply">
<div className="comment_orig_content" style={{ margin: "0px" }}>
<div className="J_Comment_Info clearfix mt3">
<div className="t_info fl">
<a href={user_login === "--" ? `${_origin}/users/${user_login}` : 'javascript:void(0)'} className="content-username hide fl"> {username}{comment_role}</a>
<span className="t_area fl">{time}</span>
{score !== null && <span className="score_area fl">{score}</span>}
{is_invalid ? <span className="validate_area fr">失效</span> :
<Fragment>
<WordsBtn style="blue" className="fr" onClick={onReplayHandler}>回复</WordsBtn>
{(isAppealing || isAnonymous) && can_appeal && appeal_status == 0 &&
<WordsBtn style="blue" className="fr mr20" onClick={onAppealHandler}>申诉</WordsBtn>}
</Fragment>
}
{item.delete && isAdmin() && <WordsBtn style="blue" className="fr mr12" onClick={onDeleteHandler}>删除</WordsBtn>}
</div>
</div>
{!!md ? <div className="comment_content clearfix" id={`reply_content_${id}`}>
<div className="color-grey-3" id={`reply_content_${id}`}>
<div className={"markdown-body"} dangerouslySetInnerHTML={{ __html: md }}></div>
<div className="cl"></div>
</div>
</div> : <span className="color656565 mt2 color-grey-9 font-12 mr8" style={{ display: 'inline-block' }}>{"暂未写评语"}</span>}
{attachments && attachments.length > 0 ? <div className="mt6"> {attachments.map((attaItem, key) => <AttachmentItem {...attaItem} key={key} />)} </div> : null}
{journals && journals.length > 0 ?
<div className="childrenCommentsView" style={{ background: '#fff' }}>
{journals.map(journal => <CommentItemReplay key={journal.id} {...journal} callback={callback} isAdmin={isAdmin()} is_author={is_author} isStudent={isStudent()} />)}
</div> : null
}
<div>
{isShow &&
<Fragment>
<TPMMDEditor mdID={`${commentIndex}`} watch={false}
height={130} onChange={onChangeHandler}
placeholder={`请输入内容`} noStorage={true}
></TPMMDEditor>
<div className="fr">
<a className="task-btn task-btn-orange fr" style={{ height: '26px', lineHeight: '26px', width: '60px' }}
onClick={onSubmit}
>{mode === 'reply' ? '回复' : '申诉'}</a>
<a onClick={onCancel} className="defalutCancelbtn fr"
style={{ height: '26px', width: '60px', fontSize: '14px', lineHeight: '26px', marginRight: '10px' }}>取消</a>
</div>
</Fragment>
}
</div>
</div>
</div>
</div>
</div >
)
}

@ -880,11 +880,6 @@ export default class TPMquestion extends Component {
gochooseid = (url) => { gochooseid = (url) => {
window.location.href = url window.location.href = url
// window.location.Reload(url)
// this.props.history.replace( url );
// this.props.history.push( url );
// 返回
// this.props.history.goBack();
} }
render() { render() {

Loading…
Cancel
Save