forked from Gitlink/build
移除教学案例、论坛交流的代码
This commit is contained in:
parent
1eba2fa5f2
commit
c9719b72ec
|
@ -5,7 +5,6 @@ import Comments from '../../comment/Comments'
|
|||
import { ImageLayerOfCommentHOC } from '../../page/layers/ImageLayerOfCommentHOC'
|
||||
import MemoDetailMDEditor from '../../forums/MemoDetailMDEditor'
|
||||
import { RouteHOC } from './common.js'
|
||||
import '../../forums/Post.css'
|
||||
import '../../forums/RightSection.css'
|
||||
import './TopicDetail.css'
|
||||
import '../common/courseMessage.css'
|
||||
|
|
|
@ -9,7 +9,6 @@ import _ from 'lodash';
|
|||
import {ImageLayerOfCommentHOC} from '../../../page/layers/ImageLayerOfCommentHOC';
|
||||
import GraduationTasksappraiseMainEditor from '../../graduation/tasks/GraduationTasksappraiseMainEditor';
|
||||
import CCommentItem from '../../common/comments/CCommentItem';
|
||||
import '../../../forums/Post.css';
|
||||
import '../../../comment/Comment.css';
|
||||
import '../../common/courseMessage.css';
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import moment from 'moment'
|
|||
import { getImageUrl,WordsBtn } from 'educoder';
|
||||
import {ImageLayerOfCommentHOC} from '../../../page/layers/ImageLayerOfCommentHOC';
|
||||
import GraduationTasksappraiseReplyChild from './GraduationTasksappraiseReplyChild';
|
||||
import '../../../forums/Post.css'
|
||||
import '../../../comment/Comment.css'
|
||||
import '../../common/courseMessage.css'
|
||||
import './GraduationTasksappraiseReply.css'
|
||||
|
|
|
@ -3,7 +3,6 @@ import { Pagination } from "antd";
|
|||
import {ImageLayerOfCommentHOC} from '../../../page/layers/ImageLayerOfCommentHOC'
|
||||
import GraduationTasksappraiseMainEditor from './GraduationTasksappraiseMainEditor'
|
||||
import Graduationtaskitem from './Graduationtaskitem'
|
||||
import '../../../forums/Post.css'
|
||||
import '../../../comment/Comment.css'
|
||||
import '../../common/courseMessage.css'
|
||||
import './GraduationTasksappraiseReply.css'
|
||||
|
|
|
@ -5,7 +5,6 @@ import update from 'immutability-helper'
|
|||
import axios from 'axios'
|
||||
import MemoDetailMDEditor from '../../../forums/MemoDetailMDEditor'
|
||||
|
||||
import '../../../forums/Post.css'
|
||||
import '../../../forums/RightSection.css'
|
||||
import {ImageLayerOfCommentHOC} from '../../../page/layers/ImageLayerOfCommentHOC'
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import update from 'immutability-helper'
|
|||
import axios from 'axios'
|
||||
import MemoDetailMDEditor from '../../../forums/MemoDetailMDEditor'
|
||||
|
||||
import '../../../forums/Post.css'
|
||||
import '../../../forums/RightSection.css'
|
||||
import {ImageLayerOfCommentHOC} from '../../../page/layers/ImageLayerOfCommentHOC'
|
||||
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*Nav START*/
|
||||
._forum_tab {
|
||||
padding-bottom: 26px;
|
||||
}
|
||||
.discuss-tab {
|
||||
height: 90px;
|
||||
}
|
||||
.discuss-tab ._forum_tab a.navItem {
|
||||
line-height: 2;
|
||||
}
|
||||
.discuss-tab ._forum_tab a.navItem:hover {
|
||||
color: #4CACFF !important;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
.discuss-tab ._forum_tab a.navItem.active {
|
||||
border-bottom: none !important;
|
||||
border: 1px solid #4CACFF !important;
|
||||
color: #4CACFF !important;
|
||||
border-radius:24px;
|
||||
}
|
||||
.discuss-tab a.returnBtnA:hover {
|
||||
border-bottom: none!important;
|
||||
}
|
||||
/*Nav END*/
|
||||
|
||||
#forum_list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.rc-pagination {
|
||||
padding: 30px 20px;
|
||||
background: #FAFAFA;
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
|
||||
}
|
||||
|
||||
/*分页*/
|
||||
.ec-pagination .rc-pagination-item{
|
||||
border-radius: 2px;
|
||||
width: 30px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
.ec-pagination a{outline: none;}
|
||||
.ec-pagination .rc-pagination-jump-next{
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
.ec-pagination .rc-pagination-item:hover{
|
||||
border: 1px solid #4cacff;
|
||||
color: #4cacff;
|
||||
}
|
||||
.ec-pagination .rc-pagination-item-active{
|
||||
background-color: #4CACFF;
|
||||
}
|
||||
.ec-pagination .rc-pagination-prev, .ec-pagination .rc-pagination-next{display: none}
|
||||
.ec-pagination .rc-pagination-options-quick-jumper input{
|
||||
height: 32px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.ec-pagination .rc-pagination-options-quick-jumper{
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
margin-left: 0px;
|
||||
}
|
|
@ -1,266 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Loading from '../../Loading'
|
||||
|
||||
import Loadable from 'react-loadable';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import MemoTechShare from './MemoTechShare'
|
||||
// import MemoGuide from './MemoGuide'
|
||||
// import MemoNewest from './MemoNewest'
|
||||
// import MemoHottest from './MemoHottest'
|
||||
|
||||
import MemoDetail from './MemoDetail'
|
||||
import MemoNew from './MemoNew'
|
||||
import MemoMyPublish from './MemoMyPublish'
|
||||
import MemoShixun from './shixun/MemoShixun'
|
||||
|
||||
|
||||
import { TPMIndexHOC } from '../tpm/TPMIndexHOC'
|
||||
|
||||
import RightMyPublish from './RightMyPublish'
|
||||
import UserSection from './UserSection'
|
||||
import RightHotLabel from './RightHotLabel'
|
||||
import RightHotQuestion from './RightHotQuestion'
|
||||
import RightMemoLabel from './RightMemoLabel'
|
||||
import RecommendShixun from './RecommendShixun'
|
||||
|
||||
|
||||
import ForumsNavTab from './ForumsNavTab'
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
|
||||
import 'rc-select/assets/index.css';
|
||||
import './ForumsIndex.css'
|
||||
import './RightSection.css'
|
||||
|
||||
import { SnackbarHOC, getUrl } from 'educoder'
|
||||
import { CNotificationHOC } from '../courses/common/CNotificationHOC'
|
||||
|
||||
|
||||
let _url_origin = getUrl()
|
||||
|
||||
const $ = window.$
|
||||
$('head').append( $('<link rel="stylesheet" type="text/css" />')
|
||||
.attr('href', `${_url_origin}/stylesheets/css/edu-admin.css?6`) );
|
||||
$('head').append( $('<link rel="stylesheet" type="text/css" />')
|
||||
.attr('href', `${_url_origin}/stylesheets/css/edu-forum.css?1525440977`) );
|
||||
$('head').append( $('<link rel="stylesheet" type="text/css" />')
|
||||
.attr('href', `${_url_origin}/stylesheets/educoder/magic-check.css?1525440977`) );
|
||||
|
||||
setTimeout(()=>{
|
||||
// 附件上传滚动条 \public\stylesheets\jquery\jquery-ui-1.9.2.css
|
||||
$('head').append( $('<link rel="stylesheet" type="text/css" />')
|
||||
.attr('href', `${_url_origin}/stylesheets/jquery/jquery-ui-1.9.2.css`) );
|
||||
}, 1000)
|
||||
|
||||
class ForumsIndex extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
searchValue: '',
|
||||
enterKeyFlag: false,
|
||||
showSearchValue: false,
|
||||
selectedHotLabelIndex: -1,
|
||||
}
|
||||
}
|
||||
|
||||
setSearchValue = (searchValue, enterKeyFlag) => {
|
||||
if (enterKeyFlag === true) {
|
||||
this.setState({
|
||||
selectedHotLabelIndex: -1
|
||||
})
|
||||
}
|
||||
this.setState({
|
||||
searchValue,
|
||||
showSearchValue: (enterKeyFlag && searchValue) ? true : false,
|
||||
enterKeyFlag: enterKeyFlag === true ? !this.state.enterKeyFlag : this.state.enterKeyFlag
|
||||
})
|
||||
}
|
||||
|
||||
setHotLabelIndex = (index, callback) => {
|
||||
const newState = {
|
||||
selectedHotLabelIndex: index,
|
||||
}
|
||||
if (index != -1) {
|
||||
newState.searchValue = ''
|
||||
newState.showSearchValue = false
|
||||
}
|
||||
this.setState({
|
||||
...newState
|
||||
}, callback)
|
||||
}
|
||||
|
||||
initForumState(data) {
|
||||
this.setState({...data})
|
||||
}
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
window.document.title = '交流问答'
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
componentWillReceiveProps(newProps, newContext) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
const { match, history, resLoading } = this.props
|
||||
const { memo } = this.state;
|
||||
|
||||
const techSharePath = `${match.path}/categories/:memoType`
|
||||
const guidePath = `${match.path}/categories/:memoType`
|
||||
const hottestPath = `${match.path}/categories/:memoType` // ?order=hottest
|
||||
const newestPath = `${match.path}/categories/:memoType` // ?order=newest
|
||||
|
||||
const shixunDiscussPath = `/forums/categories/shixun_discuss`
|
||||
const locationPath = history.location.pathname
|
||||
|
||||
|
||||
const isWidth100 = (locationPath.indexOf('forums/new') !== -1
|
||||
|| locationPath.indexOf('/edit') !== -1) ? true : false
|
||||
|
||||
const pathArray = locationPath.split('/');
|
||||
const isMemoDetail = (!isWidth100 &&
|
||||
pathArray.length === 3 && !isNaN(parseInt(pathArray[2])) ) ? true : false
|
||||
|
||||
const isGuide = locationPath.indexOf('/forums/categories/3') !== -1
|
||||
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
<div className="educontent mt30 clearfix">
|
||||
{/* 左边栏 component={TechShare}
|
||||
<ForumsNavTab {...this.props}></ForumsNavTab> */}
|
||||
<div className={classNames('fl', { with75: !isWidth100}, { width100: isWidth100}) }>
|
||||
|
||||
|
||||
<Switch>
|
||||
<Route path={`/forums/categories/my_published`} render={
|
||||
(props) => (<MemoMyPublish {...this.props} {...this.state} {...props}
|
||||
initForumState={(data)=>this.initForumState(data)}
|
||||
setSearchValue={this.setSearchValue}
|
||||
setHotLabelIndex={this.setHotLabelIndex}
|
||||
/>)
|
||||
}></Route>
|
||||
<Route path={`${shixunDiscussPath}`} render={
|
||||
(props) => (<MemoShixun {...this.props} {...this.state} {...props}
|
||||
initForumState={(data)=>this.initForumState(data)}
|
||||
setSearchValue={this.setSearchValue}
|
||||
setHotLabelIndex={this.setHotLabelIndex}
|
||||
/>)
|
||||
}></Route>
|
||||
<Route path={`${techSharePath}`} render={
|
||||
(props) => (<MemoTechShare {...this.props} {...this.state} {...props}
|
||||
initForumState={(data)=>this.initForumState(data)}
|
||||
setSearchValue={this.setSearchValue}
|
||||
setHotLabelIndex={this.setHotLabelIndex}
|
||||
/>)
|
||||
}></Route>
|
||||
|
||||
|
||||
{/*
|
||||
<Route path={`${guidePath}`} render={
|
||||
(props) => (<MemoGuide {...this.props} {...this.state} {...props}
|
||||
initForumState={(data)=>this.initForumState(data)} />)
|
||||
}></Route>
|
||||
<Route path={`${hottestPath}`} render={
|
||||
(props) => (<MemoHottest {...this.props} {...this.state} {...props}
|
||||
initForumState={(data)=>this.initForumState(data)} />)
|
||||
}></Route>
|
||||
<Route path={`${newestPath}`} render={
|
||||
(props) => (<MemoNewest {...this.props} {...this.state} {...props}
|
||||
initForumState={(data)=>this.initForumState(data)} />)
|
||||
}></Route> */}
|
||||
|
||||
{/* :forumTypeId/ */}
|
||||
<Route path={`/forums/new`} render={
|
||||
(props) => (<MemoNew {...this.props} {...this.state} {...props}
|
||||
initForumState={(data)=>this.initForumState(data)}
|
||||
/>)
|
||||
}></Route>
|
||||
|
||||
<Route path={`/forums/:memoId/edit`} render={
|
||||
(props) => (<MemoNew {...this.props} {...this.state} {...props}
|
||||
initForumState={(data)=>this.initForumState(data)}
|
||||
/>)
|
||||
}></Route>
|
||||
|
||||
|
||||
|
||||
<Route path={`${match.path}/:memoId`} render={
|
||||
(props) => (<MemoDetail {...this.props} {...this.state} {...props}
|
||||
initForumState={(data)=>this.initForumState(data)}
|
||||
/>)
|
||||
}></Route>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<Redirect from={`${match.url}`} to={`/forums/categories/all?order=newest`} />
|
||||
</Switch>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{/* 右边栏 */}
|
||||
{ !isWidth100 && <div className="with25 fl">
|
||||
<div className="ml20">
|
||||
{isMemoDetail ?
|
||||
<React.Fragment>
|
||||
<UserSection {...this.props} {...this.state} initForumState={(data)=>this.initForumState(data)} ></UserSection>
|
||||
{/*todo 新增RightMemoLabel 和 推荐实训RecommendShixun */}
|
||||
{ memo && memo.tag && <RightMemoLabel {...this.props} {...this.state}></RightMemoLabel> }
|
||||
<RecommendShixun {...this.props} {...this.state}></RecommendShixun>
|
||||
</React.Fragment>
|
||||
:
|
||||
<React.Fragment>
|
||||
<RightMyPublish {...this.props} {...this.state} setSearchValue={this.setSearchValue}></RightMyPublish>
|
||||
{ !isGuide && <RightHotLabel {...this.props} {...this.state} ></RightHotLabel> }
|
||||
<RightHotQuestion {...this.props} {...this.state} ></RightHotQuestion>
|
||||
<RecommendShixun {...this.props} {...this.state}></RecommendShixun>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CNotificationHOC() (SnackbarHOC() ( TPMIndexHOC ( ForumsIndex ) ));
|
||||
|
||||
/*
|
||||
:
|
||||
列表所有:
|
||||
http://localhost:3000/forums/categories/all
|
||||
:
|
||||
详情:
|
||||
:
|
||||
http://localhost:3000/forums/5
|
||||
:
|
||||
http://localhost:3000/forums/new
|
||||
:
|
||||
http://localhost:3000/forums/categories/my_published
|
||||
*/
|
|
@ -1,106 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
class ForumsNavTab extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onNavClick(active) {
|
||||
// TODO 为什么事件发不过去
|
||||
// https://github.com/facebook/react/issues/3249#issuecomment-177750141
|
||||
// window.$(window).trigger('setSearchValue', '', true);
|
||||
this.props.setSearchValue('')
|
||||
|
||||
if (!active) {
|
||||
this.props.initForumState({
|
||||
selectedHotLabelIndex: -1,
|
||||
})
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const { match, history, currentPage } = this.props
|
||||
|
||||
const techSharePath = `/forums/categories/5`
|
||||
const guidePath = `/forums/categories/3`
|
||||
const guidePaths = `/forums/categories/16`
|
||||
const hottestPath = `/forums/categories/all?order=hottest` // ?order=hottest
|
||||
const newestPath = `/forums/categories/all?order=newest` // ?order=newest
|
||||
|
||||
const shixunDiscussPath = `/forums/categories/shixun_discuss`
|
||||
const locationPath = history.location.pathname + history.location.search
|
||||
/*
|
||||
<ul>
|
||||
<li className={classNames({'selected': locationPath.indexOf(techSharePath) === 0 })}>
|
||||
<Link to={`${techSharePath}`} >techShare</Link>
|
||||
</li>
|
||||
<li className={classNames({'selected': locationPath.indexOf(guidePath) === 0 })}>
|
||||
<Link to={`${guidePath}`}>guide</Link>
|
||||
</li>
|
||||
</ul>
|
||||
*/
|
||||
return (
|
||||
<div className="discuss-tab pl20 bor-bottom-greyE clearfix pr edu-back-white">
|
||||
<p className="_forum_tab clearfix">
|
||||
{/*<a href="/forums" className="fl font-16 ptl5-10 block mr20 active">
|
||||
<span className="fl">技术分享</span>
|
||||
<span className="forum_filtrate_span2 forum_filtrate_span2_bg mt10 ml10 fl">219</span>
|
||||
</a>*/}
|
||||
<Link to={`${newestPath}`} className={classNames("fl font-16 padding5-20 block mr30 navItem"
|
||||
, {'active': locationPath.indexOf('order=newest') !== -1 })}
|
||||
onClick={()=>this.onNavClick(locationPath.indexOf('order=newest') !== -1)}
|
||||
>
|
||||
<span className="fl">最新回复</span>
|
||||
</Link>
|
||||
<Link to={`${hottestPath}`} className={classNames("fl font-16 padding5-20 block mr30 navItem"
|
||||
, {'active': locationPath.indexOf('order=hottest') !== -1 })}
|
||||
onClick={()=>this.onNavClick(locationPath.indexOf('order=hottest') !== -1)}
|
||||
>
|
||||
<span className="fl">热门话题</span>
|
||||
</Link>
|
||||
<Link to={`${shixunDiscussPath}`} className={classNames("fl font-16 padding5-20 block mr30 navItem"
|
||||
, {'active': locationPath.indexOf('shixun_discuss') !== -1 })}
|
||||
onClick={()=>this.onNavClick(locationPath.indexOf('shixun_discuss') !== -1)}
|
||||
>
|
||||
<span className="fl">实训回复</span>
|
||||
</Link>
|
||||
|
||||
<Link to={`${techSharePath}`} className={classNames("fl font-16 padding5-20 block mr30 navItem"
|
||||
, {'active': locationPath.indexOf(techSharePath) === 0 })}
|
||||
onClick={()=>this.onNavClick(locationPath.indexOf(techSharePath) === 0)}
|
||||
>
|
||||
<span className="fl">技术分享</span>
|
||||
</Link>
|
||||
<Link to={`${guidePath}`} className={classNames("fl font-16 padding5-20 block mr30 navItem"
|
||||
, {'active': locationPath.indexOf(guidePath) === 0 })}
|
||||
onClick={()=>this.onNavClick(locationPath.indexOf(guidePath) === 0)}
|
||||
>
|
||||
<span className="fl">操作指南</span>
|
||||
</Link>
|
||||
<Link to={`${guidePaths}`} className={classNames("fl font-16 padding5-20 block mr30 navItem"
|
||||
, {'active': locationPath.indexOf(guidePaths) === 0 })}
|
||||
onClick={()=>this.onNavClick(locationPath.indexOf(guidePaths) === 0)}
|
||||
>
|
||||
<span className="fl">通知公告</span>
|
||||
</Link>
|
||||
{/*<a href="/forums?type=discuss" className="fl font-16 ptl5-10 block mr20">
|
||||
<span className="fl">实训交流</span>
|
||||
<span className="forum_filtrate_span2 mt10 ml10 fl">1391</span>
|
||||
</a>*/}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ForumsNavTab;
|
|
@ -1,834 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Link } from "react-router-dom";
|
||||
import axios from 'axios'
|
||||
|
||||
import moment from 'moment'
|
||||
|
||||
import Comments from '../comment/Comments'
|
||||
|
||||
import update from 'immutability-helper'
|
||||
import RewardDialog from '../common/RewardDialog';
|
||||
|
||||
import { ImageLayerOfCommentHOC } from '../page/layers/ImageLayerOfCommentHOC'
|
||||
|
||||
import MemoDetailMDEditor from './MemoDetailMDEditor'
|
||||
|
||||
import { CBreadcrumb, htmlEncode } from 'educoder'
|
||||
import { Tooltip } from 'antd'
|
||||
|
||||
// import CBreadcrumb from '../courses/common/CBreadcrumb'
|
||||
import { typeNameMap2 } from './MemoNew'
|
||||
const $ = window.$
|
||||
function urlStringify(params) {
|
||||
let noParams = true;
|
||||
let paramsUrl = '';
|
||||
for (let key in params) {
|
||||
noParams = false;
|
||||
paramsUrl += `${key}=${params[key]}&`
|
||||
}
|
||||
if (noParams) {
|
||||
return '';
|
||||
}
|
||||
paramsUrl = paramsUrl.substring(0, paramsUrl.length - 1);
|
||||
return paramsUrl;
|
||||
}
|
||||
class MemoDetail extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
memoLoading: true,
|
||||
hasMoreComments: false,
|
||||
pageCount: 2,
|
||||
|
||||
goldRewardDialogOpen: false
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
// window.$("html,body").animate({"scrollTop":0})
|
||||
|
||||
const { match } = this.props
|
||||
|
||||
const memoUrl = `/memos/${match.params.memoId}.json`;
|
||||
this.setState({
|
||||
memoLoading: true
|
||||
})
|
||||
axios.get(memoUrl, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const memo = response.data.memo
|
||||
if (response.data.status === -1) {
|
||||
setTimeout(() => {
|
||||
this.props.showNotification('帖子不存在!')
|
||||
}, 300)
|
||||
this.props.history.push(`/forums`)
|
||||
return;
|
||||
} else if (memo) {
|
||||
// this.setState({...response.data})
|
||||
|
||||
const { memo_replies, memo } = response.data;
|
||||
let hasMoreComments = false;
|
||||
if (memo_replies && memo_replies.length === 10 && memo.replies_count > 10) {
|
||||
// 遍历一遍,计算下是否还有评论未加载
|
||||
let totalCount = 10;
|
||||
memo_replies.forEach(item => {
|
||||
totalCount += item.children.length
|
||||
})
|
||||
if (totalCount < memo.replies_count) {
|
||||
hasMoreComments = true;
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
hasMoreComments,
|
||||
pageCount: 2,
|
||||
comments: memo_replies
|
||||
})
|
||||
delete response.data.memo_replies;
|
||||
// reset
|
||||
response.data.memo.praise_count = response.data.memo.memo_praise_count
|
||||
this.props.initForumState(response.data)
|
||||
// const user = response.data.current_user;
|
||||
// user.tidding_count = response.data.tidding_count;
|
||||
// this.props.initCommonState(user)
|
||||
}
|
||||
this.setState({
|
||||
memoLoading: false
|
||||
})
|
||||
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
$('body>#root').on('onMemoDelete', (event) => {
|
||||
// const val = $('body>#root').data('onMemoDelete')
|
||||
const val = window.onMemoDelete;
|
||||
this.onMemoDelete(JSON.parse(decodeURIComponent(val)))
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
componentWillUnmount() {
|
||||
$('body>#root').off('onMemoDelete')
|
||||
}
|
||||
onMemoDelete(memo) {
|
||||
const deleteUrl = `/memos/${memo.id}.json`;
|
||||
// 获取memo list
|
||||
axios.delete(deleteUrl, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const status = response.data.status
|
||||
if (status === 0) {
|
||||
|
||||
this.props.showNotification('删除成功');
|
||||
this.props.history.push(`/forums`)
|
||||
|
||||
} else if (status === -1) {
|
||||
this.props.showNotification('帖子已被删除');
|
||||
this.props.history.push(`/forums`)
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
// if (this.props.memo && this.props.memo.content
|
||||
// && (!prevProps.memo || prevProps.memo.content != this.props.memo.content) ) {
|
||||
if (this.props.memo && this.props.memo.content && prevState.memoLoading === true && this.state.memoLoading === false) {
|
||||
// md渲染content,等xhr执行完(即memoLoading变化),memo.content更新后初始化md
|
||||
if (this.props.memo.is_md) {
|
||||
setTimeout(() => {
|
||||
var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
|
||||
htmlDecode: "style,script,iframe", // you can filter tags decode
|
||||
taskList: true,
|
||||
tex: true, // 默认不解析
|
||||
flowChart: true, // 默认不解析
|
||||
sequenceDiagram: true // 默认不解析
|
||||
});
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clickPraise() {
|
||||
const { memo } = this.props;
|
||||
const url = `/discusses/${memo.id}/plus.json`;
|
||||
console.log(url)
|
||||
axios.post(url, {
|
||||
container_type: 'Memo',
|
||||
type: 1 // "踩0;赞1"
|
||||
},
|
||||
{
|
||||
// withCredentials: true
|
||||
}
|
||||
).then((response) => {
|
||||
|
||||
const newMemo = Object.assign({}, this.props.memo)
|
||||
newMemo.praise_count = response.data.praise_count
|
||||
newMemo.user_praise = !newMemo.user_praise
|
||||
this.props.initForumState({ memo: newMemo })
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
renderAttachment() {
|
||||
const { memo, attachments_list } = this.props;
|
||||
const attachments = []
|
||||
attachments_list.forEach((item, index) => {
|
||||
const ar = item.url.split('/')
|
||||
const fileName = item.title
|
||||
let filesize = item.filesize
|
||||
|
||||
attachments.push(
|
||||
<div className="color-grey df" key={index} style={{ lineHeight: '17px' }}>
|
||||
<a className="color-grey ">
|
||||
<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
|
||||
</a>
|
||||
<a href={item.url} title={fileName.length > 30 ? fileName : ''}
|
||||
className="mr12 color9B9B overflowHidden1" length="58" style={{ maxWidth: '480px' }}>
|
||||
{fileName}
|
||||
</a>
|
||||
<span className="color656565 mt2 color-grey-6 font-12 mr8">{filesize}</span>
|
||||
|
||||
</div>
|
||||
)
|
||||
})
|
||||
return attachments;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------- comments START
|
||||
// ------------------------------------------------------------------------------------------- comments START
|
||||
_getUser() {
|
||||
const { current_user } = this.props;
|
||||
current_user.user_url = `/users/${current_user.login}`;
|
||||
return current_user;
|
||||
}
|
||||
_findById(id, arg_comments) {
|
||||
const comments = arg_comments;
|
||||
for (let i = 0; i < comments.length; i++) {
|
||||
if (id === comments[i].id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
replyComment = (commentContent, id, editor) => {
|
||||
const { showNotification } = this.props;
|
||||
if (!commentContent || commentContent.length === 0) {
|
||||
showNotification('必须填写内容!')
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.props.memo.id === id) { // 回复帖子
|
||||
this.createNewComment(commentContent, id, editor);
|
||||
return;
|
||||
}
|
||||
// /${id}
|
||||
const url = `/memos/reply.json`;
|
||||
const { comments } = this.state;
|
||||
const user = this._getUser();
|
||||
/*
|
||||
移除末尾的空行
|
||||
.replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g,'');
|
||||
|
||||
*/
|
||||
if (commentContent) {
|
||||
commentContent = commentContent.replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g, '');
|
||||
}
|
||||
|
||||
commentContent = htmlEncode(commentContent)
|
||||
axios.post(url, {
|
||||
parent_id: id,
|
||||
content: commentContent
|
||||
},
|
||||
{
|
||||
// withCredentials: true
|
||||
}
|
||||
).then((response) => {
|
||||
response.data.memo = response.data
|
||||
if (response.data.memo) {
|
||||
let newDiscuss = response.data.memo;
|
||||
|
||||
var commentIndex = this._findById(id, comments);
|
||||
let comment = comments[commentIndex];
|
||||
if (!comment.children) {
|
||||
comment.children = []
|
||||
}
|
||||
// TODO userName iamge_url
|
||||
comment.children.push({
|
||||
"can_delete": true,
|
||||
"content": commentContent,
|
||||
|
||||
"image_url": user.image_url,
|
||||
"username": user.username,
|
||||
"user_login": user.login,
|
||||
|
||||
"id": newDiscuss.id,
|
||||
// "position": newDiscuss.position,
|
||||
"time": "1分钟前",
|
||||
"praise_count": 0,
|
||||
|
||||
"user_id": newDiscuss.author_id,
|
||||
})
|
||||
|
||||
|
||||
comments[commentIndex] = comment
|
||||
// ke
|
||||
editor.html && editor.html('')
|
||||
// md
|
||||
if (editor.setValue) {
|
||||
editor.setValue('')
|
||||
const $ = window.$
|
||||
var view_selector = `.commentItemMDEditorView_${id}`
|
||||
$(view_selector).hide();
|
||||
}
|
||||
|
||||
|
||||
this.setState({
|
||||
// runTesting: false,
|
||||
comments: comments
|
||||
}, () => {
|
||||
// keditor代码美化
|
||||
editor.html && window.prettyPrint()
|
||||
})
|
||||
|
||||
const newMemo2 = Object.assign({}, this.props.memo);
|
||||
newMemo2.replies_count = newMemo2.replies_count + 1;
|
||||
this.props.initForumState({
|
||||
memo: newMemo2
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
deleteComment = (parrentComment, childCommentId) => {
|
||||
let deleteCommentId = parrentComment.id
|
||||
if (childCommentId) {
|
||||
deleteCommentId = childCommentId;
|
||||
}
|
||||
const url = `/memos/${deleteCommentId}.json`
|
||||
let comments = this.state.comments;
|
||||
|
||||
axios.delete(url,
|
||||
{
|
||||
// withCredentials: true
|
||||
}
|
||||
).then((response) => {
|
||||
// TODO 删除成功或失败
|
||||
if (response.data && response.data.status === 0) {
|
||||
const commentIndex = this._findById(parrentComment.id, comments);
|
||||
|
||||
// https://stackoverflow.com/questions/29527385/removing-element-from-array-in-component-state
|
||||
if (!childCommentId) {
|
||||
this.setState((prevState) => ({
|
||||
comments: update(prevState.comments, { $splice: [[commentIndex, 1]] })
|
||||
}))
|
||||
|
||||
// if (this.state.comments.length <= 5) {
|
||||
// this.fetchComment()
|
||||
// }
|
||||
} else {
|
||||
let childCommentIndex = this._findById(childCommentId, comments[commentIndex].children);
|
||||
comments[commentIndex].children = update(comments[commentIndex].children, { $splice: [[childCommentIndex, 1]] })
|
||||
this.setState({ comments })
|
||||
}
|
||||
|
||||
const newMemo = Object.assign({}, this.props.memo);
|
||||
newMemo.replies_count = newMemo.replies_count - 1;
|
||||
this.props.initForumState({
|
||||
memo: newMemo
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
// 评论点赞
|
||||
commentPraise = (discussId) => {
|
||||
const { comments } = this.state;
|
||||
const commentIndex = this._findById(discussId, comments);
|
||||
|
||||
const url = `/discusses/${discussId}/plus.json`
|
||||
axios.post(url, {
|
||||
// id: discussId,
|
||||
// container_id: challenge.id,
|
||||
container_type: 'Memo', //Discuss
|
||||
type: comments[commentIndex].user_praise === true ? 0 : 1, // "踩0;赞1"
|
||||
},
|
||||
{
|
||||
// withCredentials: true
|
||||
}
|
||||
).then((response) => {
|
||||
if (response.data.praise_count === 0 || response.data.praise_count) {
|
||||
|
||||
comments[commentIndex].user_praise = !comments[commentIndex].user_praise;
|
||||
comments[commentIndex].praise_count = response.data.praise_count;
|
||||
|
||||
this.setState({
|
||||
comments
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
rewardCode = (parrentComment, childComment, amount) => {
|
||||
const { showNotification } = this.props;
|
||||
const { comments } = this.state;
|
||||
let handleComment = parrentComment
|
||||
if (childComment) {
|
||||
handleComment = childComment;
|
||||
}
|
||||
let handleCommentId = handleComment.id;
|
||||
const url = `/discusses/${handleCommentId}/reward_code.json`
|
||||
|
||||
axios.post(url, {
|
||||
id: handleCommentId,
|
||||
|
||||
container_type: 'Memo',
|
||||
score: amount,
|
||||
user_id: handleComment.user_id
|
||||
},
|
||||
{
|
||||
// withCredentials: true
|
||||
}
|
||||
).then((response) => {
|
||||
if (response.data && response.data.code) {
|
||||
const commentIndex = this._findById(parrentComment.id, comments);
|
||||
|
||||
if (childComment) {
|
||||
const childCommentIndex = this._findById(handleComment.id, parrentComment.children);
|
||||
const newChildComment = Object.assign({}, childComment);
|
||||
newChildComment.reward = response.data.code
|
||||
parrentComment.children[childCommentIndex] = newChildComment
|
||||
|
||||
comments[commentIndex] = parrentComment;
|
||||
|
||||
this.setState({
|
||||
comments
|
||||
})
|
||||
} else {
|
||||
comments[commentIndex].reward = response.data.code;
|
||||
|
||||
this.setState({
|
||||
comments
|
||||
})
|
||||
}
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
showNotification('奖励失败,请联系系统管理员!')
|
||||
})
|
||||
}
|
||||
hiddenComment = (item, childCommentId) => {
|
||||
const id = item.id
|
||||
const { showNotification } = this.props;
|
||||
const user = this._getUser();
|
||||
const url = `/memos/${id}/hidden.json`
|
||||
const { comments } = this.state;
|
||||
|
||||
const commentIndex = this._findById(id, comments);
|
||||
const comment = comments[commentIndex];
|
||||
axios.post(url, {
|
||||
hidden: !comment.hidden ? "1" : "0"
|
||||
},
|
||||
{
|
||||
// withCredentials: true
|
||||
}
|
||||
).then((response) => {
|
||||
if (response.data.status === -1) {
|
||||
showNotification(response.data.message)
|
||||
return;
|
||||
}
|
||||
if (response.data.status === 0) {
|
||||
|
||||
if (!childCommentId) {
|
||||
comment.hidden = !comment.hidden;
|
||||
this.setState({
|
||||
comments: comments
|
||||
})
|
||||
} else { // TODO 目前子回复没hidden字段
|
||||
let childCommentIndex = this._findById(childCommentId, comments[commentIndex].children);
|
||||
const childComment = comments[commentIndex].children[childCommentIndex]
|
||||
childComment.hidden = !childComment.hidden;
|
||||
this.setState({ comments })
|
||||
}
|
||||
|
||||
}
|
||||
// {"message":"Couldn't find Discuss with id=911","status":-1}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
createNewComment = (commentContent, id, editor) => {
|
||||
let content = commentContent;
|
||||
const { memo } = this.props;
|
||||
if (content != undefined) {
|
||||
content = content.replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g, '');
|
||||
|
||||
var beforeImage = content.split("<img");
|
||||
var afterImage = content.split("/>");
|
||||
if (beforeImage[0] == "" && afterImage[1] == "") {
|
||||
window.notice_box('不支持纯图片评论<br/>请在评论中增加文字信息');
|
||||
return;
|
||||
}
|
||||
}
|
||||
// /${memo.id}
|
||||
const url = `/memos/reply.json`;
|
||||
let { comments } = this.state;
|
||||
const user = this._getUser();
|
||||
content = htmlEncode(content)
|
||||
axios.post(url, {
|
||||
parent_id: memo.id,
|
||||
content: content
|
||||
},
|
||||
{
|
||||
// withCredentials: true
|
||||
}
|
||||
).then((response) => {
|
||||
if (response.data.status === -1) {
|
||||
console.error('服务端异常')
|
||||
return;
|
||||
}
|
||||
if (response.data) {
|
||||
response.data.memo = response.data
|
||||
const newMemo = response.data.memo;
|
||||
// ke
|
||||
editor.html && editor.html('');
|
||||
editor.afterBlur && editor.afterBlur()
|
||||
// md
|
||||
editor.setValue && editor.setValue('')
|
||||
if (!comments) {
|
||||
comments = [];
|
||||
}
|
||||
comments.unshift({
|
||||
"can_delete": true,
|
||||
"admin": user.admin,
|
||||
"content": content,
|
||||
|
||||
"image_url": user.image_url,
|
||||
"username": user.username,
|
||||
"user_login": user.login,
|
||||
|
||||
"id": newMemo.id,
|
||||
"reward": null,
|
||||
"hidden": newMemo.hidden,
|
||||
|
||||
"user_praise": false,
|
||||
"time": "1分钟前",
|
||||
"praise_count": 0,
|
||||
|
||||
"user_id": user.user_id,
|
||||
})
|
||||
|
||||
|
||||
this.setState({
|
||||
comments
|
||||
})
|
||||
const newMemo2 = Object.assign({}, this.props.memo);
|
||||
newMemo2.replies_count = newMemo2.replies_count + 1;
|
||||
this.props.initForumState({
|
||||
memo: newMemo2
|
||||
})
|
||||
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
moreMemos = () => {
|
||||
let { comments, pageCount } = this.state;
|
||||
let { memo } = this.props;
|
||||
const user = this._getUser();
|
||||
const url = `/memos/${memo.id}/more_reply.json?page=${pageCount}`;
|
||||
axios.get(url, {
|
||||
|
||||
},
|
||||
{
|
||||
// withCredentials: true
|
||||
}
|
||||
).then((response) => {
|
||||
if (response.data.status === -1) {
|
||||
console.error('服务端异常')
|
||||
return;
|
||||
}
|
||||
let { memo_replies } = response.data;
|
||||
if (!memo_replies || memo_replies.length === 0) {
|
||||
this.setState({
|
||||
hasMoreComments: false
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (response.data.memos_count) {
|
||||
const newComments = comments.concat(memo_replies);
|
||||
const hasMoreComments = memo_replies.length === 10
|
||||
this.setState({
|
||||
comments: newComments,
|
||||
hasMoreComments,
|
||||
pageCount: pageCount + 1
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------- comments END
|
||||
// ------------------------------------------------------------------------------------------- comments END
|
||||
// 置顶
|
||||
setTop(memo) {
|
||||
const params = {
|
||||
sticky: memo.sticky ? 0 : 1,
|
||||
}
|
||||
if (this.state.p_s_order) {
|
||||
params.order = this.state.p_s_order;
|
||||
}
|
||||
if (this.state.p_forum_id) {
|
||||
params.forum_id = this.state.p_forum_id;
|
||||
}
|
||||
let paramsUrl = urlStringify(params)
|
||||
const set_top_or_down_Url = `/memos/${memo.id}/sticky_or_cancel.json?${paramsUrl}`;
|
||||
// 获取memo list
|
||||
axios.post(set_top_or_down_Url, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const status = response.data.status
|
||||
if (status === 0) {
|
||||
this.props.showNotification(memo.sticky ? '取消置顶成功' : '置顶成功');
|
||||
memo.sticky = memo.sticky ? false : true
|
||||
this.setState({
|
||||
memo: Object.assign({}, memo)
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
// --------------------------------------------------------------------------------------------帖子獎勵
|
||||
rewardCodeMemo = (inputVal) => {
|
||||
console.log(inputVal)
|
||||
const { memo, author_info } = this.props;
|
||||
const newMemo = Object.assign({}, memo);
|
||||
const _reward = parseInt(inputVal)
|
||||
|
||||
const url = `/discusses/${memo.id}/reward_code.json`
|
||||
|
||||
axios.post(url, {
|
||||
id: memo.id,
|
||||
|
||||
container_type: 'Memo',
|
||||
score: _reward,
|
||||
user_id: author_info.user_id
|
||||
}, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const { code } = response.data;
|
||||
if (code > 0) {
|
||||
newMemo.reward = code
|
||||
this.props.initForumState({
|
||||
memo: newMemo
|
||||
})
|
||||
this.props.showNotification('奖励成功');
|
||||
} else {
|
||||
this.props.showNotification('奖励失败,请联系系统管理员!');
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
setRewardDialogVisible = (visible) => {
|
||||
this.setState({
|
||||
goldRewardDialogOpen: visible
|
||||
})
|
||||
}
|
||||
showRewardDialog = () => {
|
||||
this.setState({
|
||||
goldRewardDialogOpen: true
|
||||
})
|
||||
}
|
||||
// --------------------------------------------------------------------------------------------帖子獎勵 END
|
||||
showCommentInput = () => {
|
||||
this.refs.editor.showEditor();
|
||||
}
|
||||
render() {
|
||||
const { match, history } = this.props
|
||||
const { memo, recommend_shixun, current_user, author_info } = this.props;
|
||||
const { comments, hasMoreComments, goldRewardDialogOpen } = this.state;
|
||||
document.title = memo && memo.subject != undefined ? memo && memo.subject : "交流问答";
|
||||
if (!memo || this.state.memoLoading) {
|
||||
return <div className="edu-back-white" id="forum_index_list"></div>
|
||||
}
|
||||
let _current_user = {}
|
||||
if (current_user) {
|
||||
_current_user = current_user
|
||||
}
|
||||
(_current_user.user_url = `/users/${_current_user.login}`);
|
||||
memo.isDetailPage = true;
|
||||
// TODO 图片上传地址
|
||||
return (
|
||||
<React.Fragment>
|
||||
<CBreadcrumb items={[
|
||||
{ to: `/forums/categories/${memo.forum_id}`, name: typeNameMap2[memo.forum_id] },
|
||||
{ name: '详情' },
|
||||
]}
|
||||
separator={' / '}
|
||||
></CBreadcrumb>
|
||||
<div className="edu-back-white memoDetail" id="forum_index_list"> {/* fl with100 */}
|
||||
<style>{`
|
||||
.memoDetail .commentsbtn {
|
||||
margin-top: 6px;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
<RewardDialog goldRewardDialogOpen={goldRewardDialogOpen}
|
||||
setRewardDialogVisible={this.setRewardDialogVisible}
|
||||
rewardCode={this.rewardCodeMemo}
|
||||
{...this.props}
|
||||
></RewardDialog>
|
||||
<div className="clearfix">
|
||||
<div id="forum_list" className="forum_table mh650">
|
||||
<div className="padding40-30 bor-bottom-greyE">
|
||||
<div className="font-16 mb5 cdefault clearfix pr pr35" style={{ display: 'flex', alignItems: 'center' }}>
|
||||
{/* overflowHidden1 */}
|
||||
<span className="noteDetailTitle " style={{ maxWidth: '634px' }}>{memo.subject}</span>
|
||||
{memo.sticky && <span className="btn-cir btn-cir-red ml10 "
|
||||
style={{ height: '20px', alignSelf: 'flex-start', marginTop: '10px' }}
|
||||
>置顶</span>}
|
||||
{!!memo.reward &&
|
||||
<Tooltip title={`获得平台奖励金币:${memo.reward}`}>
|
||||
<span className="color-orange font-14 ml15"
|
||||
style={{ height: '20px', alignSelf: 'flex-start', marginTop: '1px' }}
|
||||
>
|
||||
<i className="iconfont icon-gift mr5"></i>
|
||||
<span style={{ 'vertical-align': 'sub' }}>{memo.reward}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
}
|
||||
|
||||
<div style={{ flex: 1, alignSelf: 'flex-start' }}>
|
||||
{_current_user && (_current_user.admin === true || _current_user.user_id === author_info.user_id) &&
|
||||
<div className="edu-position-hidebox" style={{ position: 'absolute', right: '12px', top: '4px' }}>
|
||||
<a href="javascript:void(0);"><i className="fa fa-bars font-16"></i></a>
|
||||
<ul className="edu-position-hide undis">
|
||||
{_current_user.admin === true &&
|
||||
(memo.sticky === true ?
|
||||
<li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>取消置顶</a></li>
|
||||
:
|
||||
<li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>置 顶</a></li>)
|
||||
}
|
||||
<li><Link to={`/forums/${memo.id}/edit`}>编 辑</Link></li>
|
||||
<li>
|
||||
<a onClick={() =>
|
||||
window.delete_confirm_box_2_react(`onMemoDelete`, '您确定要删除吗?', memo)}>
|
||||
|
||||
删 除</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className="color-grey-9 clearfix">
|
||||
<span className="fl">{moment(memo.time).fromNow()} 发布</span>
|
||||
<div className="fr detailIcons">
|
||||
<style>{`
|
||||
.detailIcons i{
|
||||
vertical-align: sub;
|
||||
}
|
||||
`}</style>
|
||||
{_current_user.admin && <Tooltip title={"帖子奖励"}>
|
||||
<span className="noteDetailNum rightline cdefault" style={{ padding: '0 4px', cursor: 'pointer' }}>
|
||||
<i className="iconfont icon-jiangli mr5" onClick={this.showRewardDialog}></i>
|
||||
</span>
|
||||
</Tooltip>}
|
||||
<span className={`noteDetailNum ${!!memo.replies_count ? 'rightline' : ''} cdefault`}>
|
||||
<i className="iconfont icon-liulanyan mr5"></i>{memo.viewed_count}
|
||||
</span>
|
||||
{!!memo.replies_count &&
|
||||
<Tooltip title={"写评论"}>
|
||||
<a className="noteDetailNum">
|
||||
<i className="iconfont icon-huifu1 mr5" onClick={this.showCommentInput}></i>{memo.replies_count}
|
||||
</a>
|
||||
</Tooltip>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="padding40 memoContent new_li">
|
||||
{!memo.is_md ?
|
||||
<div dangerouslySetInnerHTML={{ __html: memo.content }}></div> :
|
||||
|
||||
<div id="memo_content_editorMd" className="new_li">
|
||||
<textarea style={{ 'display': 'none' }}>
|
||||
{memo.content}
|
||||
</textarea>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="padding40 bor-bottom-greyE" style={{ paddingTop: '0px' }}>
|
||||
|
||||
|
||||
<div className="mt10 mb20">
|
||||
<p className={`noteDetailPoint ${memo.user_praise ? 'Pointed' : ''} `} onClick={() => { this.clickPraise() }} >
|
||||
<i className="iconfont icon-dianzan"></i><br />
|
||||
<span>{memo.praise_count}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{this.props.attachments_list &&
|
||||
<div>
|
||||
{this.renderAttachment()}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
{window.__useKindEditor === true ? null : <MemoDetailMDEditor ref="editor" memo={memo} {...this.props}></MemoDetailMDEditor>}
|
||||
{/* onClick={ this.createNewComment } */}
|
||||
<div className="padding40 bor-bottom-greyE memoReplies commentsDelegateParent"
|
||||
style={{ display: (comments && !!comments.length) ? 'block' : 'none' }}>
|
||||
<div className="replies_count">
|
||||
<span className="labal">全部回复</span>
|
||||
<span className="count">{memo.replies_count}</span>
|
||||
</div>
|
||||
|
||||
<Comments comments={comments} user={_current_user}
|
||||
replyComment={this.replyComment}
|
||||
deleteComment={this.deleteComment}
|
||||
commentPraise={this.commentPraise}
|
||||
rewardCode={this.rewardCode}
|
||||
hiddenComment={this.hiddenComment}
|
||||
|
||||
|
||||
></Comments>
|
||||
{hasMoreComments ?
|
||||
<div className="memoMore" style={{ cursor: 'default' }}>
|
||||
<a onClick={this.moreMemos}>查看更多评论</a>
|
||||
<div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
|
||||
</div>
|
||||
:
|
||||
<div className="memoMore">
|
||||
<div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
|
||||
</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ImageLayerOfCommentHOC()(MemoDetail);
|
|
@ -1,25 +0,0 @@
|
|||
|
||||
.editorMD ol, .editorMD ul, .editorMD li {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
/*md编辑器 resizeBar*/
|
||||
.editor__resize {
|
||||
position: absolute;
|
||||
width: 120px;
|
||||
height: 4px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
margin-top: 2px;
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
cursor: row-resize;
|
||||
text-indent: 110%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-transform: capitalize;
|
||||
|
||||
box-sizing: border-box;
|
||||
/*transform: translateX(-22%);*/
|
||||
}
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import { getUploadActionUrl } from 'educoder';
|
||||
|
||||
import './MemoDetailEditor.css';
|
||||
|
||||
require('codemirror/lib/codemirror.css');
|
||||
|
||||
const $ = window.$;
|
||||
|
||||
class MemoDetailMDEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
isInited: this.props.usingMockInput ? false : true,
|
||||
isError: false,
|
||||
errorMsg: ''
|
||||
}
|
||||
}
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (this.props.memo && (!prevProps.memo || this.props.memo.id != prevProps.memo.id)) {
|
||||
// this.keEditor = window.sd_create_editor_from_data(this.props.memo.id, null, "100%", "Memo");
|
||||
// window._kk = this.keEditor
|
||||
}
|
||||
}
|
||||
|
||||
initMDEditor = () => {
|
||||
|
||||
// 因为props.memo不存在时,本组件不会被加载,这里直接在didMount里初始化即可
|
||||
const placeholder = '我要回复...'
|
||||
// const imageUrl = `/upload_with_markdown?container_id=${this.props.memo.id}&container_type=Memo`;
|
||||
const imageUrl = `${getUploadActionUrl()}`;
|
||||
if (this.isMDInited) {
|
||||
return;
|
||||
}
|
||||
this.isMDInited = true
|
||||
|
||||
// 执行太快了,样式不正常
|
||||
window.__tt = 400;
|
||||
setTimeout(() => {
|
||||
var commentMDEditor = window.create_editorMD_4comment("memo_comment_editorMd", '', this.props.height || 240, placeholder, imageUrl, () => {
|
||||
// commentMDEditor.focus()
|
||||
|
||||
this.initDrag()
|
||||
|
||||
commentMDEditor.cm.on("change", (_cm, changeObj) => {
|
||||
this.setState({
|
||||
isError: false,
|
||||
errorMsg: ''
|
||||
})
|
||||
})
|
||||
// commentMDEditor.cm.focus()
|
||||
}, {
|
||||
watch: false,
|
||||
dialogLockScreen: false,
|
||||
});
|
||||
this.commentMDEditor = commentMDEditor;
|
||||
window.commentMDEditor = commentMDEditor;
|
||||
|
||||
}, window.__tt)
|
||||
}
|
||||
componentDidMount() {
|
||||
!this.props.usingMockInput && this.initMDEditor()
|
||||
}
|
||||
initDrag = () => {
|
||||
window.initMDEditorDragResize(".editor__resize", this.commentMDEditor)
|
||||
}
|
||||
|
||||
onCommit = () => {
|
||||
if (this.props.checkIfLogin() === false) {
|
||||
this.props.showLoginDialog()
|
||||
return
|
||||
}
|
||||
if (this.props.checkIfProfileCompleted() === false) {
|
||||
this.props.showaccountprofileDialog()
|
||||
return
|
||||
}
|
||||
const content = this.commentMDEditor.getValue();
|
||||
// this.props.showError ==
|
||||
if (this.props.showError == true) {
|
||||
if (!content || content.trim() == "") {
|
||||
this.setState({
|
||||
isError: true,
|
||||
errorMsg: '不能为空'
|
||||
})
|
||||
return;
|
||||
} else if (content.length > 2000) {
|
||||
this.setState({
|
||||
isError: true,
|
||||
errorMsg: '不能超过2000个字符'
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isError: false,
|
||||
errorMsg: ''
|
||||
})
|
||||
}
|
||||
if (this.props.replyComment) {
|
||||
this.props.replyComment(content, this.props.memo.id, this.commentMDEditor)
|
||||
} else {
|
||||
window.$(document).trigger("onReply", {
|
||||
commentContent: content
|
||||
, id: this.props.memo.id, editor: this.commentMDEditor
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
showEditor() {
|
||||
$("html, body").animate({ scrollTop: $('.commentInput:visible').offset().top - 100 }, 1000, () => {
|
||||
if (this.commentMDEditor) {
|
||||
this.commentMDEditor.cm.focus()
|
||||
} else {
|
||||
this.onMockInputClick()
|
||||
}
|
||||
});
|
||||
}
|
||||
close = () => {
|
||||
this.setState({ isInited: false })
|
||||
}
|
||||
onMockInputClick = () => {
|
||||
this.setState({ isInited: true })
|
||||
if (!this.isMDInited) {
|
||||
this.initMDEditor()
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.commentMDEditor && this.commentMDEditor.cm.focus()
|
||||
}, 10)
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const { match, history, memo, placeholder, className, imageExpand } = this.props
|
||||
const { isInited, errorMsg } = this.state
|
||||
if (!memo) {
|
||||
return <div></div>
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<style>{`
|
||||
.mockInputWrapper {
|
||||
display: flex;
|
||||
padding: 20px 30px 20px 30px;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
}
|
||||
.mockInputWrapper input {
|
||||
flex:1;
|
||||
padding-left: 10px;
|
||||
height: 40px;
|
||||
background: rgb(246,246,246);
|
||||
margin-right: 20px;
|
||||
}
|
||||
.mockInputWrapper a.commentsbtn {
|
||||
height: 40px;
|
||||
display: inline-block;
|
||||
margin-top: 0px !important;
|
||||
vertical-align: text-top;
|
||||
padding-top: 6px;
|
||||
width: 60px;
|
||||
margin-right: 0px !important;
|
||||
}
|
||||
.commentInput {
|
||||
}
|
||||
.commentInput .editormd{
|
||||
width:100%!important;
|
||||
}
|
||||
`}</style>
|
||||
<div style={{ display: isInited ? 'none' : '', borderBottom: `${this.props.commentsLength == 0 ? 'none' : '1px solid #EEEEEE'}` }}
|
||||
className={`mockInputWrapper commentInput ${className}`} >
|
||||
<input onClick={this.onMockInputClick} placeholder={placeholder || '我要回复'}></input>
|
||||
<a
|
||||
onClick={this.onMockInputClick} className="commentsbtn task-btn task-btn-blue">
|
||||
{this.props.buttonText || '发送'}
|
||||
</a>
|
||||
</div>
|
||||
<style>
|
||||
{/*
|
||||
先注释了,影响到了md的拖拽
|
||||
{
|
||||
`
|
||||
.commentInputs{
|
||||
height: 250px;
|
||||
}
|
||||
`
|
||||
} */}
|
||||
</style>
|
||||
<div nhname={`new_message_${memo.id}`}
|
||||
className={`commentInput commentInputs ${className} ${imageExpand && 'editormd-image-click-expand'}`}
|
||||
style={{ padding: '30px', boxSizing: "border-box", display: isInited ? '' : 'none', paddingBottom: '40px' }} >
|
||||
<div id="memo_comment_editorMd" className="editorMD" style={{
|
||||
marginBottom: '0px'
|
||||
, border: errorMsg ? '1px solid red' : '1px solid #ddd'
|
||||
}}>
|
||||
<textarea style={{ 'display': 'none' }}>
|
||||
</textarea>
|
||||
</div>
|
||||
<div className="editor__resize" href="javascript:void(0);">调整高度</div>
|
||||
{errorMsg && <span className="fl" style={{
|
||||
color: 'red', marginTop: '6px',
|
||||
marginLeft: '4px'
|
||||
}}>{errorMsg}</span>}
|
||||
<div style={{ height: "16px" }}>
|
||||
<a id={`new_message_submit_btn_${memo.id}`}
|
||||
onClick={this.onCommit} className="commentsbtn task-btn task-btn-blue fr">
|
||||
{this.props.buttonText || '发送'}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default (MemoDetailMDEditor);
|
|
@ -1,79 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
import { Redirect } from "react-router";
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import classNames from "classnames";
|
||||
|
||||
import Pagination from "rc-pagination";
|
||||
|
||||
import { getImageUrl, toPath } from "educoder";
|
||||
|
||||
import { postPaginationHOC } from "./PostPaginationHOC";
|
||||
|
||||
import PostItem from "./PostItem";
|
||||
|
||||
import ForumsNavTab from "./ForumsNavTab";
|
||||
|
||||
import { queryString, ThemeContext } from "educoder";
|
||||
import styled from "styled-components";
|
||||
import 'rc-pagination/assets/index.css';
|
||||
|
||||
class MemoList extends Component {
|
||||
render() {
|
||||
const {
|
||||
match,
|
||||
history,
|
||||
currentPage,
|
||||
memo_count,
|
||||
memo_list,
|
||||
renderMemoList,
|
||||
onPaginationChange,
|
||||
} = this.props;
|
||||
let theme = this.context;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div id="forum_list" className="forum_table">
|
||||
<style>{`
|
||||
.forum_table_item .item_name:hover {
|
||||
color: ${theme.foreground_select}
|
||||
}
|
||||
`}</style>
|
||||
<div className="mh650 edu-back-white">
|
||||
{!memo_list || memo_list.length === 0 ? (
|
||||
<div className="edu-tab-con-box clearfix edu-txt-center">
|
||||
<img
|
||||
className="edu-nodata-img mb20"
|
||||
src={getImageUrl("images/educoder/nodata.png")}
|
||||
/>
|
||||
<p className="edu-nodata-p mb30">暂时还没有相关数据哦!</p>
|
||||
</div>
|
||||
) : (
|
||||
renderMemoList()
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{!!memo_count && memo_count > 15 && (
|
||||
<div style={{ width: "100%", background: "#FAFAFA"}}>
|
||||
<Pagination
|
||||
className={"ec-pagination"}
|
||||
onChange={(pageNum, pageSize) =>
|
||||
onPaginationChange(pageNum, pageSize)
|
||||
}
|
||||
showQuickJumper
|
||||
current={currentPage}
|
||||
total={memo_count}
|
||||
pageSize={15}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
MemoList.contextType = ThemeContext;
|
||||
|
||||
export default MemoList;
|
|
@ -1,73 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import Pagination from 'rc-pagination';
|
||||
|
||||
import { postPaginationHOC } from './PostPaginationHOC'
|
||||
|
||||
import PostItem from './PostItem'
|
||||
|
||||
import ForumsNavTab from './ForumsNavTab'
|
||||
|
||||
// import queryString from 'query-string'
|
||||
import { queryString } from 'educoder'
|
||||
import MemoList from './MemoList'
|
||||
|
||||
|
||||
class MemoMyPublish extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onPaginationChange(pageNum, pageSize) {
|
||||
this.props.onPaginationChange(pageNum, pageSize)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
}
|
||||
componentWillReceiveProps(newProps, newContext) {
|
||||
|
||||
}
|
||||
renderMemoList() {
|
||||
|
||||
|
||||
return this.props.renderMemoList();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { match, history, currentPage, memo_count, memo_list } = this.props
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="discuss-tab bor-bottom-greyE clearfix pr boxsizing">
|
||||
<p className="_forum_tab pl20 pr20 clearfix boxsizing" style={{fontSize:'18px', color:'rgba(5,16,26,1)'}}>
|
||||
我的发布
|
||||
<Link className="returnBtnA fr mr10" to={`/forums`}><span className="color-grey-9 font-16">返回</span></Link>
|
||||
</p>
|
||||
</div>
|
||||
<MemoList {...this.props} renderMemoList={() => this.renderMemoList()}
|
||||
onPaginationChange={ (pageNum, pageSize) => this.props.onPaginationChange(pageNum, pageSize) }
|
||||
>
|
||||
</MemoList>
|
||||
</React.Fragment>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default postPaginationHOC({ isMyPublish: true }) ( MemoMyPublish );
|
|
@ -1,617 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Select, Icon, Upload, Button } from 'antd';
|
||||
import axios from 'axios'
|
||||
|
||||
import 'antd/lib/select/style/index.css'
|
||||
import TPMMDEditor from '../tpm/challengesnew/TPMMDEditor'
|
||||
|
||||
import { getUrl, getUploadActionUrl, appendFileSizeToUploadFileAll, appendFileSizeToUploadFile } from 'educoder'
|
||||
const Option = Select.Option;
|
||||
const $ = window.$;
|
||||
|
||||
let origin = getUrl();
|
||||
|
||||
// load
|
||||
if (!window.postUpMsg) {
|
||||
$.getScript(
|
||||
`${origin}/javascripts/attachments.js`,
|
||||
(data, textStatus, jqxhr) => {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const typeNameMap = {
|
||||
'技术分享': 5,
|
||||
'操作指南': 3,
|
||||
'通知公告': 16,
|
||||
}
|
||||
export const typeNameMap2 = {
|
||||
5: '技术分享',
|
||||
3: '操作指南',
|
||||
16: '通知公告',
|
||||
}
|
||||
const defaultType = '技术分享'
|
||||
|
||||
class MemoNew extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.mdRef = React.createRef();
|
||||
|
||||
this.uploaderProps = {
|
||||
action: '/uploads.js',
|
||||
data: { attachment_id: 1 }, // , filename: 2
|
||||
headers: {
|
||||
Authorization: 'authorization-text',
|
||||
},
|
||||
multiple: true,
|
||||
beforeUpload(file) {
|
||||
// console.log('beforeUpload', file.name);
|
||||
},
|
||||
onStart: (file) => {
|
||||
console.log('onStart', file.name);
|
||||
// this.refs.inner.abort(file);
|
||||
},
|
||||
onSuccess(file) {
|
||||
console.log('onSuccess', file);
|
||||
},
|
||||
onProgress(step, file) {
|
||||
console.log('onProgress', Math.round(step.percent), file.name);
|
||||
},
|
||||
onError(err) {
|
||||
console.log('onError', err);
|
||||
},
|
||||
};
|
||||
|
||||
this.state = {
|
||||
memoSubject: '',
|
||||
memoContent: '',
|
||||
memoType: typeNameMap[defaultType],
|
||||
memoRepertoire: '',
|
||||
memoLanguage: [],
|
||||
|
||||
repertoires: [],
|
||||
currentSelectRepertoiresIndex: -1,
|
||||
repertoiresTagMap: {},
|
||||
|
||||
fileList: [],
|
||||
forums: [{ id: 5, name: "技术分享" }, { id: 3, name: "技术指南" }, { id: 16, name: "通知公告" }],
|
||||
}
|
||||
}
|
||||
onCommit() {
|
||||
const { memoSubject, memoRepertoire, memoLanguage, currentMemoId, memoType } = this.state;
|
||||
const { showNotification } = this.props;
|
||||
if (!memoSubject) {
|
||||
showNotification('请先输入话题名称')
|
||||
return
|
||||
}
|
||||
let mdVal;
|
||||
try {
|
||||
mdVal = this.mdRef.current.getValue()
|
||||
|
||||
} catch (e) {
|
||||
showNotification('编辑器还未加载完毕,请稍后')
|
||||
return
|
||||
}
|
||||
|
||||
if (!mdVal) {
|
||||
showNotification('请先输入话题内容')
|
||||
return
|
||||
}
|
||||
// !memoRepertoire ||
|
||||
if (memoType === 5 && (!memoLanguage || memoLanguage.length === 0)) {
|
||||
showNotification('请先选择技术标签')
|
||||
return
|
||||
}
|
||||
/*
|
||||
<meta content="authenticity_token" name="csrf-param" />
|
||||
<meta content="G7peAyb1T37RvdwxnVUKmTXuL8T7FaBze5mK0j6MCKs=" name="csrf-token" />
|
||||
|
||||
http://localhost:3000/attachments/download/185790/Git-2.17.1.2-32-bit.exe
|
||||
https://www.educoder.net/attachments/205112.js?attachment_id=1
|
||||
*/
|
||||
// collect attachments
|
||||
const $ = window.$;
|
||||
const attachmentsMap = {};
|
||||
const attachmentIds = this.state.fileList.map(item => {
|
||||
return item.response ? item.response.id : item.id
|
||||
})
|
||||
|
||||
if (currentMemoId) {
|
||||
this.updateMemo(attachmentIds)
|
||||
} else {
|
||||
this.newMemo(attachmentIds)
|
||||
}
|
||||
}
|
||||
onCancel() {
|
||||
const { currentMemoId, memoType } = this.state;
|
||||
if (currentMemoId) { // 编辑
|
||||
this.props.history.push(`/forums/${currentMemoId}`)
|
||||
} else { // 新建
|
||||
this.props.history.push(`/forums`)
|
||||
}
|
||||
; this.props.history.goBack()
|
||||
}
|
||||
updateMemo(attachmentsMap) {
|
||||
const { memoSubject, memoRepertoire, memoLanguage, memoType, currentMemoId, content } = this.state;
|
||||
const mdVal = this.mdRef.current.getValue()
|
||||
console.log('isContentEdit: ', mdVal === content);
|
||||
const newMemoUrl = `/memos/${currentMemoId}.json`
|
||||
axios.put(newMemoUrl, {
|
||||
content_changed: this.contentChanged,
|
||||
tags: memoLanguage,
|
||||
// memo:{
|
||||
subject: memoSubject,
|
||||
content: mdVal,
|
||||
forum_id: memoType,
|
||||
repertoire_name: memoRepertoire,
|
||||
// language: memoLanguage.join(languageSeparator),
|
||||
//
|
||||
// },
|
||||
attachment_ids: attachmentsMap
|
||||
}, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const { status, message, memo_id } = response.data;
|
||||
if (status === 0) {
|
||||
window.$("html,body").animate({ "scrollTop": 0 })
|
||||
this.props.history.push(`/forums/${currentMemoId}`)
|
||||
} else {
|
||||
this.props.showNotification(message)
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
newMemo(attachmentsMap) {
|
||||
const { memoSubject, memoRepertoire, memoLanguage, memoType } = this.state;
|
||||
const mdVal = this.mdRef.current.getValue()
|
||||
|
||||
const newMemoUrl = `/memos.json`
|
||||
axios.post(newMemoUrl, {
|
||||
tags: memoLanguage,
|
||||
// memo:{
|
||||
subject: memoSubject,
|
||||
content: mdVal,
|
||||
forum_id: memoType,
|
||||
// repertoire_name: memoRepertoire,
|
||||
|
||||
// },
|
||||
attachment_ids: attachmentsMap
|
||||
}, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const { status, message, memo_id } = response.data;
|
||||
if (status === 0) {
|
||||
window.$("html,body").animate({ "scrollTop": 0 })
|
||||
this.props.history.push(`/forums/${memo_id}`)
|
||||
} else {
|
||||
this.props.showNotification(message)
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
componentDidMount() {
|
||||
const newMemoUrl = `/memos/new.json`
|
||||
axios.get(newMemoUrl, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const data = response.data;
|
||||
if (data.tag_list) {
|
||||
document.title = "交流问答";
|
||||
this.setState({
|
||||
tag_list: data.tag_list
|
||||
})
|
||||
|
||||
// 初始化 csrf meta
|
||||
const $ = window.$
|
||||
$('head').append($('<meta content="authenticity_token" name="csrf-param" />'))
|
||||
$('head').append($(`<meta content="${response.data.csrf_token}" name="csrf-token" />`))
|
||||
}
|
||||
if (data.forums) {
|
||||
this.setState({
|
||||
forums: data.forums === undefined || data.forums === null || data.forums.length === 0 ? this.state.forums : data.forums
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
// 如果是编辑
|
||||
const { match } = this.props
|
||||
const memoId = match.params.memoId;
|
||||
if (memoId) {
|
||||
const memoUrl = `/memos/${match.params.memoId}/edit.json`;
|
||||
axios.get(memoUrl, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const tag_list = response.data.tag_list
|
||||
if (tag_list) {
|
||||
// this.setState({...response.data})
|
||||
|
||||
document.title = response.data.subject;
|
||||
const { content, forum_id, id, repertoire_name, subject,
|
||||
current_user, tag_list, attachments_url, memo_tags, attachments } = response.data;
|
||||
this.initMD(content);
|
||||
// this.onRepertoiresChange(repertoire_name)
|
||||
// tag -> memo_tags
|
||||
const tag = memo_tags;
|
||||
let memoLanguage = []
|
||||
if (tag) {
|
||||
memoLanguage = tag.map((item, index) => {
|
||||
return item.id + ""
|
||||
})
|
||||
}
|
||||
const fileList = attachments.map(item => {
|
||||
return {
|
||||
id: item.id,
|
||||
uid: item.id,
|
||||
name: appendFileSizeToUploadFile(item),
|
||||
url: item.url,
|
||||
filesize: item.filesize,
|
||||
status: 'done'
|
||||
}
|
||||
})
|
||||
this.setState({
|
||||
fileList,
|
||||
currentMemoId: memoId,
|
||||
memoSubject: subject,
|
||||
memoType: forum_id,
|
||||
memoRepertoire: repertoire_name,
|
||||
memoLanguage,
|
||||
attachments_url,
|
||||
content
|
||||
|
||||
// repertoires: [],
|
||||
// currentSelectRepertoiresIndex: -1,
|
||||
}, () => {
|
||||
// 解决有时候编辑时内容不显示的问题
|
||||
setTimeout(() => {
|
||||
this.mdRef.current && this.mdRef.current.setValue(content || '')
|
||||
}, 2000)
|
||||
|
||||
$('.upload_filename').each((index, item) => {
|
||||
var width = window._textWidth($(item), '14px');
|
||||
console.log(width)
|
||||
$(item).css('width', width + 20)
|
||||
})
|
||||
|
||||
})
|
||||
// 加载完后滚动条滚动
|
||||
window.$("html,body").animate({ "scrollTop": 0 })
|
||||
|
||||
this.props.initForumState({
|
||||
// current_user,
|
||||
tag_list
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
} else {
|
||||
this.initMD();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
renderOptions(array) {
|
||||
const elementArray = [];
|
||||
array.forEach((item, index) => {
|
||||
elementArray.push(
|
||||
<Option key={index} value={item}>{item}</Option>
|
||||
)
|
||||
})
|
||||
return elementArray
|
||||
}
|
||||
onRepertoiresChange(value) {
|
||||
|
||||
const index = this.state.repertoires.indexOf(value)
|
||||
|
||||
this.setState({
|
||||
currentSelectRepertoiresIndex: index,
|
||||
memoRepertoire: value,
|
||||
memoLanguage: ''
|
||||
});
|
||||
};
|
||||
|
||||
renderTag() {
|
||||
const { tag_list } = this.state;
|
||||
if (!tag_list || tag_list.length === 0) {
|
||||
return ''
|
||||
}
|
||||
const result = []
|
||||
|
||||
tag_list.forEach((item, index) => {
|
||||
result.push(<Option value={item.id + ''} key={index} >{item.name}</Option>)
|
||||
})
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
onTagChange(value) {
|
||||
if (value && value.length > 3) {
|
||||
this.props.showNotification(`最多选择3个技术标签`)
|
||||
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
memoLanguage: value
|
||||
})
|
||||
}
|
||||
|
||||
onTypeChange(value) {
|
||||
|
||||
this.setState({
|
||||
memoType: typeNameMap[value]
|
||||
})
|
||||
}
|
||||
onMemoNameChange(e) {
|
||||
this.setState({
|
||||
memoSubject: e.target.value
|
||||
})
|
||||
}
|
||||
renderAttachment() {
|
||||
const { attachments_url } = this.state;
|
||||
const attachments = []
|
||||
attachments_url.forEach((item, index) => {
|
||||
const ar = item.url.split('/')
|
||||
attachments.push(
|
||||
<React.Fragment>
|
||||
<span id={`attachments_10${index}`} className="attachment">
|
||||
<label className="panel-form-label fl"> </label>
|
||||
<i className="iconfont icon-fujian ml20mr20Color" aria-hidden="true"></i>
|
||||
<input type="text" className="upload_filename readonly hidden" name="attachments[2][filename]" readonly="readonly"
|
||||
style={{
|
||||
border: 'none', whiteSpace: 'nowrap', textOverflow: 'ellipsis', fontFamily: 'Consolas'
|
||||
, color: '#676767', marginLeft: '20px', verticalAlign: 'middle'
|
||||
}}
|
||||
size="8" value={item.filename}></input>
|
||||
<font className="mr20 ml20mr20Color" style={{ marginLeft: '10px', verticalAlign: 'middle' }}>{window.conver_size(item.id)}</font>
|
||||
<a href={`/attachments/${item.id}.js?attachment_id=10${index}`} className="remove-upload"
|
||||
style={{ verticalAlign: 'top', display: 'inlineBlock' }} data-remote="true"
|
||||
data-method="delete">
|
||||
<i className="iconfont ml20mr20Color"></i>
|
||||
</a>
|
||||
<div className="div_attachments" name="div_attachments_xx"></div>
|
||||
{/**/}<input type="hidden" name="attachments[xx][token]"
|
||||
value="185811.24305bb2c4912f715629aa3615cdbabc"></input>
|
||||
<input type="hidden" name="attachments[xx][attachment_id]" value={item.id}></input>
|
||||
</span>
|
||||
<div className="cl"></div>
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
})
|
||||
return attachments;
|
||||
}
|
||||
handleChange = (info) => {
|
||||
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
|
||||
let fileList = info.fileList;
|
||||
this.setState({
|
||||
fileList: appendFileSizeToUploadFileAll(fileList)
|
||||
});
|
||||
}
|
||||
}
|
||||
onAttachmentRemove = (file) => {
|
||||
if (!file.percent || file.percent == 100) {
|
||||
this.props.confirm({
|
||||
// title: '确定要删除这个附件吗?',
|
||||
content: '是否确认删除?',
|
||||
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
// content: 'Some descriptions',
|
||||
onOk: () => {
|
||||
this.deleteAttachment(file)
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
deleteAttachment = (file) => {
|
||||
// 初次上传不能直接取uid
|
||||
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
|
||||
axios.delete(url, {
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
const { status } = response.data;
|
||||
if (status == 0) {
|
||||
console.log('--- success')
|
||||
|
||||
this.setState((state) => {
|
||||
const index = state.fileList.indexOf(file);
|
||||
const newFileList = state.fileList.slice();
|
||||
newFileList.splice(index, 1);
|
||||
return {
|
||||
fileList: newFileList,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const { match, history, forums } = this.props
|
||||
const {
|
||||
// repertoires, repertoiresTagMap, currentSelectRepertoiresIndex, memoRepertoire,
|
||||
tag_list,
|
||||
memoSubject, memoType,
|
||||
memoLanguage, attachments_url, fileList } = this.state;
|
||||
const memoId = match.params.memoId;
|
||||
|
||||
const uploadProps = {
|
||||
width: 600,
|
||||
fileList,
|
||||
multiple: true,
|
||||
// https://github.com/ant-design/ant-design/issues/15505
|
||||
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
|
||||
// showUploadList: false,
|
||||
action: `${getUploadActionUrl()}`,
|
||||
onChange: this.handleChange,
|
||||
onRemove: this.onAttachmentRemove,
|
||||
beforeUpload: (file) => {
|
||||
console.log('beforeUpload', file.name);
|
||||
const isLt150M = file.size / 1024 / 1024 < 150;
|
||||
if (!isLt150M) {
|
||||
this.props.showNotification('文件大小必须小于150MB!');
|
||||
}
|
||||
return isLt150M;
|
||||
},
|
||||
};
|
||||
return (
|
||||
<div >
|
||||
<p className="clearfix mb10 undefined cBreadcrumb"><a className="btn colorgrey fl hovercolorblue"
|
||||
href="/forums">交流问答</a><span
|
||||
className="color-grey-9 fl ml3 mr3"> / </span><span>详情</span></p>
|
||||
<div className="pt20 pl20 pr20 pb20 bor-bottom-greyE clearfix" style={{ background: '#fff' }}>
|
||||
<span className="fl font-16">{memoId ? '编辑话题' : '发布话题'}</span>
|
||||
{/*<a href="/shixuns/mf98sgi3/settings" className="ring-green mt7 fr" id="edit_setting"
|
||||
data-remote="true" data-tip-down="编辑"><img src="/images/educoder/icon/edit.svg" className="fl ml2 mt3">
|
||||
</a>*/}
|
||||
</div>
|
||||
|
||||
<div className="edu-back-white mb10 clearfix" id="memoSubject">
|
||||
<div className="padding30-20">
|
||||
<p className="color-grey-6 font-16 mb30">话题名称</p>
|
||||
<div className="df">
|
||||
<span className="mr30 color-orange pt10">*</span>
|
||||
<div className="flex1 mr20">
|
||||
<input type="text" className="input-100-45 greyInput" maxlength="50"
|
||||
value={memoSubject} onChange={(val) => this.onMemoNameChange(val)} placeholder="">
|
||||
</input>
|
||||
</div>
|
||||
<div style={{ width: '57px' }}>
|
||||
<span className="color-orange mt8 fl none" >
|
||||
<i className="fa fa-exclamation-circle mr3"></i>必填项
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="edu-back-white mb10 clearfix">
|
||||
<div className="padding30-20">
|
||||
<p className="color-grey-6 font-16 mb30">内容</p>
|
||||
<div className="df">
|
||||
<span className="mr30 color-orange pt10">*</span>
|
||||
<div className="flex1 mr20">
|
||||
<TPMMDEditor ref={this.mdRef} placeholder={''} watch={false}
|
||||
mdID={'memoMD'} initValue={this.state.content} className="memoMD">
|
||||
</TPMMDEditor>
|
||||
{/* <div className="flex1 break_word show_content_grey new_li" id="memoMD">
|
||||
<textarea style={{'display':'none'}}></textarea>
|
||||
</div> */}
|
||||
<p id="e_tip_memoNew" className="edu-txt-right color-grey-cd font-12"></p>
|
||||
<p id="e_tips_memoNew" className="edu-txt-right color-grey-cd font-12"></p>
|
||||
</div>
|
||||
<div style={{ width: '57px' }}>
|
||||
<span className="color-orange mt8 fl none" >
|
||||
<i className="fa fa-exclamation-circle mr3"></i>必填项
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>{`
|
||||
.memo_upload.upload_1 {
|
||||
margin-left: 36px;
|
||||
}
|
||||
.memo_upload.upload_1 .ant-upload-list {
|
||||
margin-left: 30px;
|
||||
}
|
||||
.memo_upload.upload_1 .ant-upload-list-item-info .anticon-paper-clip {
|
||||
top: 4px;
|
||||
}
|
||||
`}</style>
|
||||
{/*<Upload {...this.uploaderProps} ref="inner"><a>开始上传</a></Upload>*/}
|
||||
<Upload {...uploadProps} className="upload_1 memo_upload" >
|
||||
<Button className="uploadBtn">
|
||||
<Icon type="upload" /> 上传附件
|
||||
</Button>
|
||||
(单个文件150M以内)
|
||||
</Upload>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/* TODOTODO 这里重复的html代码太多,如果有其他页面有类似需求,需要封装*/}
|
||||
|
||||
<div className="edu-back-white mb10 clearfix">
|
||||
<div className="padding30-20">
|
||||
<p className="color-grey-6 font-16 mb30">话题类型</p>
|
||||
<div className="df">
|
||||
<span className="mr30 color-orange pt10">*</span>
|
||||
<div className="flex1 mr20">
|
||||
<Select className="ecSelect" value={typeNameMap2[memoType]}
|
||||
onChange={(val) => this.onTypeChange(val)}>
|
||||
<Option value="技术分享">技术分享</Option>
|
||||
<Option value="操作指南">操作指南</Option>
|
||||
<Option value="通知公告">通知公告</Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div style={{ width: '57px' }}>
|
||||
<span className="color-orange mt8 fl none" >
|
||||
<i className="fa fa-exclamation-circle mr3"></i>必填项
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{memoType === typeNameMap['技术分享'] &&
|
||||
<div className="edu-back-white mb10 clearfix">
|
||||
<div className="padding30-20">
|
||||
<p className="color-grey-6 font-16 mb30">技术标签</p>
|
||||
<div className="df">
|
||||
<span className="mr30 color-orange pt10">*</span>
|
||||
|
||||
<div className="flex1 mr20">
|
||||
<Select
|
||||
className="ecSelect"
|
||||
value={memoLanguage}
|
||||
placeholder="请选择技术标签"
|
||||
onChange={(e) => this.onTagChange(e)}
|
||||
dropdownStyle={{ 'maxHeight': '300px', 'overflow': 'auto' }}
|
||||
mode="multiple"
|
||||
filterOption={(inputValue, option) => { return option.props.children.toLocaleLowerCase().indexOf(inputValue.toLocaleLowerCase()) != -1 }}
|
||||
tokenSeparators={[';']} >
|
||||
{this.renderTag()}
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div style={{ width: '57px' }}>
|
||||
<span className="color-orange mt8 fl none" >
|
||||
<i className="fa fa-exclamation-circle mr3"></i>必填项
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<div className="clearfix mt30">
|
||||
<a className="defalutSubmitbtn fl mr20"
|
||||
onClick={() => { this.onCommit() }}>提交</a>
|
||||
<a onClick={() => { this.onCancel() }} className="defalutCancelbtn fl">取消</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MemoNew;
|
|
@ -1,65 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import Pagination from 'rc-pagination';
|
||||
|
||||
import { postPaginationHOC } from './PostPaginationHOC'
|
||||
|
||||
import PostItem from './PostItem'
|
||||
|
||||
|
||||
import ForumsNavTab from './ForumsNavTab'
|
||||
|
||||
class MemoGuide extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onPaginationChange(pageNum, pageSize) {
|
||||
|
||||
this.props.onPaginationChange(pageNum, pageSize)
|
||||
}
|
||||
|
||||
|
||||
renderMemoList() {
|
||||
// const { memo_list, user } = this.props;
|
||||
// if (!memo_list) {
|
||||
// return ''
|
||||
// }
|
||||
// return memo_list.map( (item, index) => {
|
||||
// return (
|
||||
// <PostItem key={item.id} memo={item} user={user} index={index} {...this.props}></PostItem>
|
||||
// )
|
||||
// })
|
||||
return this.props.renderMemoList();
|
||||
}
|
||||
render() {
|
||||
const { match, history, currentPage, memo_count } = this.props
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ForumsNavTab {...this.props}></ForumsNavTab>
|
||||
<div id="forum_list" className="forum_table mh650">
|
||||
|
||||
{this.renderMemoList()}
|
||||
|
||||
{ !!memo_count && <Pagination onChange={(pageNum, pageSize) => this.onPaginationChange(pageNum, pageSize)}
|
||||
showQuickJumper current={currentPage} total={memo_count} pageSize={15}/> }
|
||||
</div>
|
||||
</React.Fragment>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default postPaginationHOC( MemoGuide );
|
|
@ -1,84 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import Pagination from 'rc-pagination';
|
||||
|
||||
import { postPaginationHOC } from './PostPaginationHOC'
|
||||
|
||||
import PostItem from './PostItem'
|
||||
|
||||
|
||||
import ForumsNavTab from './ForumsNavTab'
|
||||
|
||||
class MemoHottest extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.handleLocationChange = this.handleLocationChange.bind(this);
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onPaginationChange(pageNum, pageSize) {
|
||||
|
||||
this.props.onPaginationChange(pageNum, pageSize)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// this.handleLocationChange(this.props.history.location);
|
||||
this.unlisten = this.props.history.listen(this.handleLocationChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unlisten();
|
||||
}
|
||||
|
||||
handleLocationChange(location) {
|
||||
// your staff here
|
||||
console.log(`- - - location: '${location.pathname}'`);
|
||||
if (location.pathname && location.pathname.indexOf('/forums/categories/all') != -1
|
||||
&& this.locationSearch != location.search) {
|
||||
this.props.fetchMemos();
|
||||
}
|
||||
this.locationSearch = location.search;
|
||||
}
|
||||
|
||||
renderMemoList() {
|
||||
// const { memo_list, user } = this.props;
|
||||
// if (!memo_list) {
|
||||
// return ''
|
||||
// }
|
||||
// return memo_list.map( (item, index) => {
|
||||
// return (
|
||||
// <PostItem key={item.id} memo={item} user={user} index={index} {...this.props}></PostItem>
|
||||
// )
|
||||
// })
|
||||
return this.props.renderMemoList();
|
||||
}
|
||||
render() {
|
||||
const { match, history, currentPage, memo_count } = this.props
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ForumsNavTab {...this.props}></ForumsNavTab>
|
||||
<div id="forum_list" className="forum_table mh650">
|
||||
|
||||
{this.renderMemoList()}
|
||||
|
||||
{ !!memo_count && <Pagination onChange={(pageNum, pageSize) => this.onPaginationChange(pageNum, pageSize)}
|
||||
showQuickJumper current={currentPage} total={memo_count} pageSize={15}/> }
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default postPaginationHOC( MemoHottest );
|
|
@ -1,63 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import Pagination from 'rc-pagination';
|
||||
|
||||
import { postPaginationHOC } from './PostPaginationHOC'
|
||||
|
||||
import PostItem from './PostItem'
|
||||
|
||||
|
||||
import ForumsNavTab from './ForumsNavTab'
|
||||
|
||||
class MemoNewest extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onPaginationChange(pageNum, pageSize) {
|
||||
|
||||
this.props.onPaginationChange(pageNum, pageSize)
|
||||
}
|
||||
|
||||
|
||||
renderMemoList() {
|
||||
// const { memo_list, user } = this.props;
|
||||
// if (!memo_list) {
|
||||
// return ''
|
||||
// }
|
||||
// return memo_list.map( (item, index) => {
|
||||
// return (
|
||||
// <PostItem key={item.id} memo={item} user={user} index={index} {...this.props}></PostItem>
|
||||
// )
|
||||
// })
|
||||
return this.props.renderMemoList();
|
||||
}
|
||||
render() {
|
||||
const { match, history, currentPage, memo_count } = this.props
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ForumsNavTab {...this.props}></ForumsNavTab>
|
||||
<div id="forum_list" className="forum_table mh650">
|
||||
{this.renderMemoList()}
|
||||
|
||||
{ !!memo_count && <Pagination onChange={(pageNum, pageSize) => this.onPaginationChange(pageNum, pageSize)}
|
||||
showQuickJumper current={currentPage} total={memo_count} pageSize={15}/> }
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default postPaginationHOC( MemoNewest );
|
|
@ -1,116 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import Pagination from 'rc-pagination';
|
||||
|
||||
import { postPaginationHOC } from './PostPaginationHOC'
|
||||
|
||||
import PostItem from './PostItem'
|
||||
|
||||
import ForumsNavTab from './ForumsNavTab'
|
||||
|
||||
// import queryString from 'query-string'
|
||||
import { queryString } from 'educoder'
|
||||
|
||||
import MemoList from './MemoList'
|
||||
|
||||
|
||||
class MemoTechShare extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.handleLocationChange = this.handleLocationChange.bind(this);
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onPaginationChange(pageNum, pageSize) {
|
||||
this.props.onPaginationChange(pageNum, pageSize)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// this.handleLocationChange(this.props.history.location);
|
||||
// this.unlisten = this.props.history.listen(this.handleLocationChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// this.unlisten();
|
||||
}
|
||||
componentDidUpdate(prevProps) {
|
||||
if(this.props.match.params.memoType !== prevProps.match.params.memoType) {
|
||||
// do something
|
||||
console.log(`memoType changed`)
|
||||
this.props.fetchMemos();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(newProps, newContext) {
|
||||
if (newProps.match.url === this.props.match.url) {
|
||||
const oldParsed = queryString.parse(this.props.location.search);
|
||||
const newParsed = queryString.parse(newProps.location.search);
|
||||
if (!newParsed.page && oldParsed.page ||
|
||||
(oldParsed.order && newParsed.order && oldParsed.order != newParsed.order)) {
|
||||
this.props.fetchMemos();
|
||||
}
|
||||
// console.log('componentWillReceiveProps...')
|
||||
}
|
||||
}
|
||||
|
||||
handleLocationChange(location) {
|
||||
console.log(`- - - location: '${location.pathname}'`);
|
||||
if (location.pathname) {
|
||||
if (location.pathname.indexOf('/forums/categories/all') != -1
|
||||
&& this.props.location.search && this.props.location.search.indexOf('order=') != -1
|
||||
&& location.search.indexOf('order=') != -1) {
|
||||
const oldParsed = queryString.parse(this.props.location.search);
|
||||
const newParsed = queryString.parse(location.search);
|
||||
if (oldParsed.order != newParsed.order) { // 只有在热门和最新间跳转时,才需要处理
|
||||
this.props.fetchMemos();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderMemoList() {
|
||||
|
||||
|
||||
// const { memo_list, user } = this.props;
|
||||
// if (!memo_list) {
|
||||
// return ''
|
||||
// }
|
||||
// return memo_list.map( (item, index) => {
|
||||
|
||||
// return (
|
||||
// <PostItem key={item.id} user={user} index={index} {...this.props}
|
||||
// setTop={(memo)=>this.setTop(memo)}
|
||||
// setDown={(memo)=>this.setDown(memo)} memo={item}
|
||||
// ></PostItem>
|
||||
// )
|
||||
// })
|
||||
return this.props.renderMemoList();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { match, history, currentPage, memo_count ,memo_list } = this.props
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ForumsNavTab {...this.props}></ForumsNavTab>
|
||||
<MemoList {...this.props} renderMemoList={() => this.renderMemoList()}
|
||||
onPaginationChange={ (pageNum, pageSize) => this.props.onPaginationChange(pageNum, pageSize) }
|
||||
>
|
||||
</MemoList>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default postPaginationHOC() ( MemoTechShare );
|
|
@ -1,224 +0,0 @@
|
|||
/*MemoDetail --------------------------------- START */
|
||||
.educontent {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 左侧区域最小高度*/
|
||||
#forum_index_list {
|
||||
min-height: 400px;
|
||||
position: relative;
|
||||
}
|
||||
#forum_index_list .forum_table .forum_table_item {
|
||||
background: #fff;
|
||||
}
|
||||
.noMemosTip {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 58px;
|
||||
z-index: 999;
|
||||
}
|
||||
#forum_list {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
#forum_list .return_btn {
|
||||
line-height: 38px;
|
||||
/* margin-right: 15px; */
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#forum_list .return_btn.no_mr {
|
||||
margin-right: -24px !important;
|
||||
}
|
||||
div#forum_list>div {
|
||||
background: #fff;
|
||||
}
|
||||
.memoContent img {
|
||||
max-width: 815px;
|
||||
}
|
||||
.memoReplies {
|
||||
position: relative;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.memoReplies .-fit {
|
||||
position: static;
|
||||
}
|
||||
.replies_count {
|
||||
margin-left: 12px;
|
||||
}
|
||||
.replies_count .label {
|
||||
color: #666666;
|
||||
}
|
||||
.replies_count .count {
|
||||
color: #999999;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.memoMore {
|
||||
padding-top: 10px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
color: rgba(69,155,230,1);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.memoMore .writeCommentBtn{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
color: #666666;
|
||||
top: 15px;
|
||||
}
|
||||
.memoMore .writeCommentBtn:hover {
|
||||
color: #4DACFF;
|
||||
}
|
||||
/*使用md編輯器用为子回复时,宽度会变*/
|
||||
.panel-comment_item .comment_orig_content {
|
||||
width: 705px;
|
||||
}
|
||||
|
||||
.iconfont.icon-xiazai {
|
||||
font-size: 22px!important;
|
||||
margin-right: 6px;
|
||||
}
|
||||
/* MemoDetail --------------------------------- END */
|
||||
|
||||
/* PostItem --------------------------------- START */
|
||||
.forum_table_item {
|
||||
padding-left: 20px;
|
||||
}
|
||||
/* 置顶 */
|
||||
.forum_table_item .btn-top {
|
||||
border-radius: 11px;
|
||||
padding: 0px 6px;
|
||||
background: #FF4343;
|
||||
|
||||
}
|
||||
|
||||
/* 管理员操作 */
|
||||
.edu-position-hide {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: -20px;
|
||||
box-shadow: 0px 2px 8px rgba(146, 153, 169, 0.5);
|
||||
background: #fff;
|
||||
z-index: 1001;
|
||||
padding: 5px 0;
|
||||
z-index: 999999;
|
||||
}
|
||||
.edu-position-hide li a:hover {
|
||||
background: #4CACFF;
|
||||
color: #fff;
|
||||
}
|
||||
.edu-position-hidebox>a:link{
|
||||
color: #4CACFF;
|
||||
}
|
||||
.edu-position-hidebox:hover .edu-position-hide {
|
||||
display: block;
|
||||
}
|
||||
.edu-position-hide li a {
|
||||
display: inline-block;
|
||||
height: 30px;
|
||||
width: 100px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
font-size: 12px!important;
|
||||
}
|
||||
/* PostItem --------------------------------- END */
|
||||
|
||||
|
||||
/* MemoNew --------------------------------- START */
|
||||
|
||||
#attachments_fields div.ui-progressbar {
|
||||
width: 120px;
|
||||
height: 10px;
|
||||
margin: 2px 0 -2px 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ui-widget-header {
|
||||
border: 1px solid #4CACFF;
|
||||
background: #4CACFF;
|
||||
}
|
||||
.iconfont.icon-fujian {
|
||||
color: #29BD8B
|
||||
}
|
||||
|
||||
/* rc-select样式覆写*/
|
||||
.ecSelect {
|
||||
width: 300px;
|
||||
}
|
||||
.ecSelect .rc-select-selection {
|
||||
height: 40px;
|
||||
}
|
||||
.ecSelect .rc-select-search--inline .rc-select-search__field {
|
||||
padding-top: 6px;
|
||||
}
|
||||
.ecSelect .rc-select-selection--single .rc-select-selection-selected-value
|
||||
, .ecSelect .rc-select-selection__placeholder {
|
||||
top: 6px;
|
||||
|
||||
}
|
||||
.ecSelect .rc-select-arrow {
|
||||
top: 6px;
|
||||
}
|
||||
.defalutCancelbtn {
|
||||
cursor: pointer;
|
||||
}
|
||||
.defalutSubmitbtnysl{
|
||||
display: block;border: 1px solid #4CACFF;background-color: #4CACFF;color: #fff!important;width: 120px;text-align: center;line-height: 40px;border-radius: 2px;
|
||||
width: 130px;
|
||||
height: 40px;
|
||||
background: rgba(76,172,255,1);
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHei;
|
||||
font-weight: 400;
|
||||
color: rgba(255,255,255,1);
|
||||
}
|
||||
#attachments_fields {
|
||||
margin-left: -77px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.uploadBtn {
|
||||
/* margin-left: 46px; */
|
||||
}
|
||||
#memoMD.show_content_grey {
|
||||
padding: 0;
|
||||
}
|
||||
.newForm .attachments_fields {
|
||||
/*margin-left: -39px !important*/
|
||||
}
|
||||
#attachments_fields div.ui-progressbar {
|
||||
width: 120px;
|
||||
height: 10px;
|
||||
margin: 2px 0 -2px 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ui-progressbar-value.ui-widget-header {
|
||||
border: 1px solid #4CACFF;
|
||||
background: #4CACFF;
|
||||
}
|
||||
/* MemoNew --------------------------------- END */
|
||||
|
||||
|
||||
/*RightMyPublish*/
|
||||
.publishMemoSection {
|
||||
padding-bottom: 0px !important;
|
||||
}
|
||||
.advertisement {
|
||||
margin-top: 10px;
|
||||
height: 155px;
|
||||
}
|
||||
.advertisement img{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* MyPublish*/
|
||||
.returnBtn {
|
||||
font-size:16px;
|
||||
color:rgba(153,153,153,1);
|
||||
float: right;
|
||||
margin-right: 50px;
|
||||
position: relative;
|
||||
bottom: 12px;
|
||||
}
|
|
@ -1,222 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
import { Redirect } from "react-router";
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import classNames from "classnames";
|
||||
|
||||
import { getImageUrl, toPath, ThemeContext } from "educoder";
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import { Tooltip } from "antd";
|
||||
import styled from "styled-components";
|
||||
|
||||
const Container = styled.div`
|
||||
&:last-child .forum_table_item {
|
||||
border-bottom: none;
|
||||
}
|
||||
.forum_table .forum_table_item:nth-child(odd) {
|
||||
background: #fafbfb;
|
||||
}
|
||||
.forum_table_item {
|
||||
padding: 20px 15px;
|
||||
display: flex;
|
||||
}
|
||||
.forum_table_item .item_name {
|
||||
color: #333;
|
||||
}
|
||||
.forum_table_item .item_name:hover {
|
||||
color: #4cacff;
|
||||
}
|
||||
.forum_table_item {
|
||||
padding-left: 20px;
|
||||
}
|
||||
/* 置顶 */
|
||||
.forum_table_item .btn-top {
|
||||
border-radius: 11px;
|
||||
padding: 0px 6px;
|
||||
background: #ff4343;
|
||||
}
|
||||
.bor-radius-all {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.forum_table_item {
|
||||
padding: 20px 15px;
|
||||
display: flex;
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
}
|
||||
`;
|
||||
|
||||
class PostItem extends Component {
|
||||
_toTenThousand(num) {
|
||||
if (num > 10000) {
|
||||
return ((num - 500) / 10000).toFixed(1) + "万";
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
match,
|
||||
history,
|
||||
currentPage,
|
||||
memo,
|
||||
user,
|
||||
setTop,
|
||||
setDown,
|
||||
} = this.props;
|
||||
return (
|
||||
<Container className="pl20">
|
||||
<div className="forum_table_item" id={`memo_detail_${memo.id}`}>
|
||||
<a href={`/users/${memo.login}`} className="fr mr15">
|
||||
<img
|
||||
alt="用户头像"
|
||||
className="bor-radius-all mt3"
|
||||
height="50"
|
||||
src={getImageUrl(`images/` + memo.image_url)}
|
||||
width="50"
|
||||
/>
|
||||
</a>
|
||||
<div className="fl pr" style={{ flex: 1 }}>
|
||||
<p className="font-16 clearfix" style={{ lineHeight: 2 }}>
|
||||
{/* target="_blank" */}
|
||||
<a
|
||||
href={`/forums/${memo.id}`}
|
||||
target="_blank"
|
||||
title={
|
||||
memo.subject && memo.subject.length > 46 ? memo.subject : ""
|
||||
}
|
||||
className="clearfix task-hide item_name fl"
|
||||
style={{ maxWidth: "600px" }}
|
||||
>
|
||||
{memo.subject}
|
||||
</a>
|
||||
|
||||
{memo.sticky && (
|
||||
<span className="btn-top btn-cir-orange mt6 ml5 fl">置顶</span>
|
||||
)}
|
||||
|
||||
{memo.reward && (
|
||||
<Tooltip title={`获得平台奖励金币:${memo.reward}`}>
|
||||
<span className=" ml10 fl color-orange03 fl">
|
||||
<i className="iconfont icon-gift font-16 mr5 fl"></i>
|
||||
<span className="fl mt3 font-14">{memo.reward}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</p>
|
||||
|
||||
<div className="clearfix mt5 color-grey-9">
|
||||
<span className="fl">{memo.user_name}</span>
|
||||
{/*最后回复:todo{memo.username}
|
||||
memo.language && memo.language != 'other' && <span className="fl language-cir-orange mr10 mt3 ml6">{memo.language}</span>
|
||||
*/}
|
||||
{/* <span className="fl ml50">{moment(memo.updated_at).fromNow()}</span> */}
|
||||
{memo.tag && memo.tag.length ? (
|
||||
<span className="fl ml50">来自 {memo.tag.join("/")}</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
|
||||
{/*<span className="fl language-cir-orange mr10 mt3">C++</span>*/}
|
||||
|
||||
<p
|
||||
className="font-12 fr mr8 color-grey-6"
|
||||
style={{ marginTop: "4px" }}
|
||||
>
|
||||
{/* data-tip-down="回复数" <i className="fa fa-comments-o mr5"></i>{memo.replies_count}
|
||||
<i className="fa fa-thumbs-o-up mr5"></i>{memo.praise_count}*/}
|
||||
{memo.replies_count ? (
|
||||
<span
|
||||
className="mr10 ml10 fl edu-txt-right"
|
||||
style={{ cursor: "default" }}
|
||||
>
|
||||
{memo.replies_count} 回复
|
||||
</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
|
||||
{memo.praise_count ? (
|
||||
<span
|
||||
className="mr10 ml10 fl edu-txt-right"
|
||||
style={{ cursor: "default" }}
|
||||
>
|
||||
{memo.praise_count} 赞
|
||||
</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
|
||||
{memo.viewed_count ? (
|
||||
<span
|
||||
className="mr10 ml10 fl edu-txt-right"
|
||||
style={{ cursor: "default", minWidth: "55px" }}
|
||||
>
|
||||
{this._toTenThousand(memo.viewed_count)} 浏览
|
||||
</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
{user && (user.admin === true || user.login === memo.login) && (
|
||||
<div
|
||||
className="edu-position-hidebox"
|
||||
style={{ position: "absolute", right: "18px", top: "0px" }}
|
||||
>
|
||||
<a href="javascript:void(0);">
|
||||
<i className="fa fa-bars font-16"></i>
|
||||
</a>
|
||||
<ul className="edu-position-hide undis">
|
||||
{user.admin === true &&
|
||||
(memo.sticky === true ? (
|
||||
<li>
|
||||
<a
|
||||
href="javascript:void(0);"
|
||||
onClick={() => setDown(memo)}
|
||||
>
|
||||
取消置顶
|
||||
</a>
|
||||
</li>
|
||||
) : (
|
||||
<li>
|
||||
<a
|
||||
href="javascript:void(0);"
|
||||
onClick={() => setTop(memo)}
|
||||
>
|
||||
置 顶
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
<li>
|
||||
<Link to={`/forums/${memo.id}/edit`}>编 辑</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
onClick={() =>
|
||||
window.delete_confirm_box_2_react(
|
||||
`onMemoDelete`,
|
||||
"您确定要删除吗?",
|
||||
memo
|
||||
)
|
||||
}
|
||||
>
|
||||
删 除
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
PostItem.contextType = ThemeContext;
|
||||
|
||||
export default PostItem;
|
|
@ -1,352 +0,0 @@
|
|||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import axios from 'axios'
|
||||
import update from 'immutability-helper'
|
||||
import PostItem from './PostItem'
|
||||
|
||||
import { CircularProgress } from 'material-ui/Progress';
|
||||
|
||||
import { queryString } from 'educoder'
|
||||
import { on, off, updatePageParams } from 'educoder'
|
||||
import './Post.css'
|
||||
const $ = window.$
|
||||
|
||||
function urlStringify(params) {
|
||||
let noParams = true;
|
||||
let paramsUrl = '';
|
||||
for (let key in params) {
|
||||
noParams = false;
|
||||
paramsUrl += `${key}=${params[key]}&`
|
||||
}
|
||||
if (noParams) {
|
||||
return '';
|
||||
}
|
||||
paramsUrl = paramsUrl.substring(0, paramsUrl.length - 1);
|
||||
return paramsUrl;
|
||||
}
|
||||
export function postPaginationHOC(options = {}) {
|
||||
// options.isMyPublish
|
||||
return function wrap(WrappedComponent) {
|
||||
|
||||
return class II extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
currentPage: 1,
|
||||
loadingMemos: true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
$('body>#root').on('onMemoDelete', (event) => {
|
||||
// const val = $('body>#root').data('onMemoDelete')
|
||||
const val = window.onMemoDelete ;
|
||||
this.onMemoDelete( JSON.parse(decodeURIComponent(val)) )
|
||||
})
|
||||
window.$('#shixun_search_input').val('')
|
||||
|
||||
this.props.setSearchValue('')
|
||||
|
||||
this.fetchMemos(null, '')
|
||||
|
||||
const that = this;
|
||||
$(window).on('popstate', (e) => {
|
||||
var state = e.originalEvent.state;
|
||||
console.log('popstate', state)
|
||||
if (state !== null) {
|
||||
|
||||
let currentPage = that.state.currentPage;;
|
||||
// // 浏览器地址改变了
|
||||
const search = that.props.history.location.search
|
||||
const parsed = queryString.parse(search);
|
||||
if (parsed.page != currentPage) {
|
||||
currentPage = parseInt( parsed.page || 1)
|
||||
// that.setSearchValue('')
|
||||
that.fetchMemos(currentPage)
|
||||
this.setState({
|
||||
currentPage,
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// RightMyPublish组件发过来的消息
|
||||
// $(window).on('setSearchValue', (event, val, noFetch)=>{
|
||||
|
||||
// })
|
||||
|
||||
on('hotTagClick', (event, tagName, index) => {
|
||||
this.props.setHotLabelIndex(tagName.selectedHotLabelIndex, () => {
|
||||
this.fetchMemos(1, undefined)
|
||||
})
|
||||
})
|
||||
}
|
||||
componentWillReceiveProps(newProps, newContext) {
|
||||
if (newProps.enterKeyFlag !== this.props.enterKeyFlag) {
|
||||
const childPath = this.props.match.path.split('/:')[0]
|
||||
// 加入一个浏览地址
|
||||
const _search = this.props.location.search;
|
||||
if (_search) {
|
||||
const parsed = queryString.parse(_search);
|
||||
if (parsed.page != 1) {
|
||||
parsed.page = 1;
|
||||
this.props.history.push(`${this.props.match.url}?${queryString.stringify(parsed)}`)
|
||||
}
|
||||
}
|
||||
this.fetchMemos(1, newProps.searchValue, newProps.selectedHotLabelIndex) // 搜索框模糊搜索,重置为第一页
|
||||
|
||||
}
|
||||
}
|
||||
componentWillUnmount() {
|
||||
// 要移除掉,不然到了MemoDetail页面,可能会有2个onMemoDelete监听
|
||||
$('body>#root').off('onMemoDelete')
|
||||
$(window).off('setSearchValue')
|
||||
$(window).off('popstate')
|
||||
off('hotTagClick')
|
||||
}
|
||||
fetchMemos(arg_currentPage, arg_searchValue, arg_selectedHotLabelIndex) {
|
||||
let { match, history } = this.props
|
||||
|
||||
let searchValue = arg_searchValue != undefined ? arg_searchValue : this.props.searchValue
|
||||
// 根据参数初始化页数
|
||||
|
||||
const memoType = match.params.memoType;
|
||||
const urlArray = match.url.split('/')
|
||||
const lastPath = urlArray[2]
|
||||
|
||||
// 1 问题反馈
|
||||
// 3 操作指南 5 技术分享
|
||||
|
||||
const memoTypeMap = {
|
||||
'guide': 3,
|
||||
'techShare': 5
|
||||
}
|
||||
const orderTypeMap = {
|
||||
'hottest': 'replies_count',
|
||||
'newest': 'updated_at', // 'created_at',
|
||||
}
|
||||
const _search = this.props.history.location.search;
|
||||
const parsed = queryString.parse(_search);
|
||||
|
||||
let currentPage = parseInt( arg_currentPage ? arg_currentPage : (parsed.page || 1) )
|
||||
|
||||
const params = {
|
||||
// replies_count最热 created_at 最新
|
||||
// s_order: 'replies_count',
|
||||
page: currentPage,
|
||||
|
||||
// forum: // forum_id
|
||||
// user_id
|
||||
}
|
||||
if (searchValue) {
|
||||
params.search = searchValue.trim()
|
||||
}
|
||||
let orderType = ''
|
||||
if (memoType==='all') {
|
||||
orderType = parsed.order || 'hottest';
|
||||
params.order = orderTypeMap[orderType]
|
||||
} else if (options.isMyPublish) {
|
||||
params.user_id = -1
|
||||
} else if (memoType) {
|
||||
params.forum = memoType
|
||||
if (memoType == 5) { // 讨论区的技术分享tab按照创建时间倒序
|
||||
params.order = 'created_at'
|
||||
}
|
||||
}
|
||||
|
||||
let { selectedHotLabelIndex, hot_tags } = this.props;
|
||||
selectedHotLabelIndex = arg_selectedHotLabelIndex ? arg_selectedHotLabelIndex : selectedHotLabelIndex
|
||||
if (selectedHotLabelIndex !== -1 && hot_tags[selectedHotLabelIndex]) {
|
||||
params.tag_repertoire_id = hot_tags[selectedHotLabelIndex].tag_repertoire_id // encodeURIComponent()
|
||||
}
|
||||
|
||||
|
||||
let paramsUrl = queryString.stringify(params)
|
||||
const memosUrl = '/memos.json?' + paramsUrl // /${challenge.identifier}/star
|
||||
|
||||
this.setState({
|
||||
currentPage,
|
||||
loadingMemos: true,
|
||||
orderType: orderType
|
||||
})
|
||||
// 获取memo list
|
||||
axios.get(memosUrl,{
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const memo_count = response.data.memo_count
|
||||
if (memo_count>=0) {
|
||||
|
||||
const maxPage = Math.ceil( memo_count / 15 )
|
||||
// page超出,显示最后一页
|
||||
if (maxPage != 0 && maxPage < currentPage) {
|
||||
this.fetchMemos(maxPage);
|
||||
return;
|
||||
}
|
||||
// const user = response.data.current_user;
|
||||
// user.tidding_count = response.data.tidding_count;
|
||||
// this.props.initCommonState(user)
|
||||
this.props.initForumState(response.data)
|
||||
this.setState({
|
||||
p_forum_id: params.forum,
|
||||
p_s_order: params.s_order,
|
||||
loadingMemos: false
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
onCurrentPageChange(pageNum) {
|
||||
this.setState({
|
||||
currentPage: pageNum
|
||||
})
|
||||
}
|
||||
|
||||
onPaginationChange(pageNum, pageSize) {
|
||||
window.$("html,body").animate({"scrollTop":0})
|
||||
|
||||
updatePageParams(pageNum, this.props)
|
||||
|
||||
// 加入一个浏览地址
|
||||
// const params = {
|
||||
// page: pageNum
|
||||
// }
|
||||
// if (this.state.orderType) {
|
||||
// params.order = this.state.orderType;
|
||||
// }
|
||||
// this.props.history.push(`${url}?${queryString.stringify(parsed)}`)
|
||||
|
||||
this.fetchMemos(pageNum);
|
||||
|
||||
// this.setState({
|
||||
// currentPage: pageNum
|
||||
// })
|
||||
}
|
||||
|
||||
// 置顶
|
||||
setTop(memo) {
|
||||
const params = {
|
||||
sticky: memo.sticky ? 0 : 1,
|
||||
}
|
||||
if (this.state.p_s_order) {
|
||||
params.order = this.state.p_s_order;
|
||||
}
|
||||
if (this.state.p_forum_id) {
|
||||
params.forum_id = this.state.p_forum_id;
|
||||
}
|
||||
let paramsUrl = urlStringify(params)
|
||||
const set_top_or_down_Url = `/memos/${memo.id}/sticky_or_cancel.json?${paramsUrl}`;
|
||||
// 获取memo list
|
||||
axios.post(set_top_or_down_Url, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const status = response.data.status
|
||||
if (status === 0) {
|
||||
this.fetchMemos(1, '')
|
||||
|
||||
// const { memo_list } = response.data;
|
||||
// this.props.initForumState({ memo_list })
|
||||
// 刷新列表
|
||||
// TODO 服务端直接返回第一页列表
|
||||
// this.props.history.replace('/')
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
// 取消置顶
|
||||
setDown(memo) {
|
||||
this.setTop(memo);
|
||||
}
|
||||
onMemoDelete(memo) {
|
||||
const deleteUrl = `/memos/${memo.id}.json`;
|
||||
// 获取memo list
|
||||
axios.delete(deleteUrl, {
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
const status = response.data.status
|
||||
if (status === 0) {
|
||||
|
||||
this.props.showNotification('删除成功');
|
||||
// 刷新列表
|
||||
this.fetchMemos();
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
// item渲染
|
||||
//
|
||||
renderMemoList() {
|
||||
const { memo_list, user } = this.props;
|
||||
if (!memo_list) {
|
||||
return ''
|
||||
}
|
||||
return memo_list.map( (item, index) => {
|
||||
return (
|
||||
<PostItem key={item.id} user={user} index={index} {...this.props}
|
||||
setTop={(memo)=>this.setTop(memo)}
|
||||
setDown={(memo)=>this.setDown(memo)}
|
||||
memo={item}
|
||||
></PostItem>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { loadingMemos } = this.state;
|
||||
const { memo_list, searchValue, showSearchValue, memo_count, selectedHotLabelIndex, hot_tags} = this.props;
|
||||
|
||||
// 规则: 搜索框输入了值 或者 选择了热门标签的时候显示该提示
|
||||
const _showSearchValue = showSearchValue || selectedHotLabelIndex != -1
|
||||
let _searchValue;
|
||||
if (showSearchValue) {
|
||||
_searchValue = searchValue
|
||||
} else if (selectedHotLabelIndex != -1){
|
||||
_searchValue = hot_tags[selectedHotLabelIndex].name || hot_tags[selectedHotLabelIndex]
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
<div className="edu-back-white" id="forum_index_list"> {/* fl with100 */}
|
||||
<div className="clearfix">
|
||||
{ _showSearchValue &&
|
||||
<div className="noMemosTip" style={{display: loadingMemos ? 'none' : 'block'}}>
|
||||
<span className="fr pr20" id="search_result">
|
||||
共找到
|
||||
<span className="color-orange03">{memo_count}</span>个"
|
||||
<span className="color-orange03">{_searchValue}</span>"相关的结果
|
||||
</span>
|
||||
</div> }
|
||||
|
||||
<CircularProgress size={40} thickness={3}
|
||||
style={{ marginLeft: 'auto', marginRight: 'auto', paddingTop: '20%'
|
||||
, display: loadingMemos ? 'block': 'none' }}/>
|
||||
{ !loadingMemos &&
|
||||
<WrappedComponent {...this.props} {...this.state}
|
||||
|
||||
onPaginationChange={(pageNum, pageSize) => this.onPaginationChange(pageNum, pageSize)}
|
||||
onCurrentPageChange={(pageNum, pageSize) => this.onCurrentPageChange(pageNum, pageSize)}
|
||||
|
||||
renderMemoList={() => this.renderMemoList()}
|
||||
fetchMemos={(arg1, arg2) => this.fetchMemos(arg1, arg2)}
|
||||
|
||||
></WrappedComponent>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
class RecommendShixun extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
showRecommandShixun(){
|
||||
const { recommend_shixuns } = this.props;
|
||||
if (!recommend_shixuns) {
|
||||
return '';
|
||||
}
|
||||
const result = [];
|
||||
recommend_shixuns.forEach((shixun, index) => {
|
||||
const _shixun = shixun
|
||||
result.push(
|
||||
<div className="recomments clearfix df" key={index}>
|
||||
<a href={`/shixuns/${_shixun.identifier}/challenges`} style={{height:'76px'}} target="_blank">
|
||||
|
||||
<img alt={`${_shixun.id}`} style={{maxHeight:'76px'}} src={`/${_shixun.image_url}`} width="100" >
|
||||
</img>
|
||||
</a>
|
||||
<div className="ml10 flex1">
|
||||
<a href={`/shixuns/${_shixun.identifier}/challenges`} target="_blank" title={_shixun.name && _shixun.name.length > 9 ? _shixun.name : ''}
|
||||
className="color-grey-6 task-hide mb10 recomment-name" style={{maxWidth:'147px'}}>
|
||||
{_shixun.name}
|
||||
</a>
|
||||
<p className="color-grey-9">{_shixun.myshixuns_count} 人学习</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
return result;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { match, history, currentPage } = this.props
|
||||
|
||||
// 参考 TPMShixunDiscuss.js 推荐实训, 页面路径:http://localhost:3007/shixuns/uznmbg54/shixun_discuss
|
||||
return (
|
||||
<div className="padding10">
|
||||
<p className="mb20 font-16 clearfix" style={{ lineHeight: 2 }}>推荐实训</p>
|
||||
<div className="recommend-list">
|
||||
{this.showRecommandShixun()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RecommendShixun;
|
|
@ -1,56 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { trigger } from 'educoder'
|
||||
|
||||
class RightHotLabel extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
renderTags() {
|
||||
const { hot_tags, selectedHotLabelIndex } = this.props;
|
||||
if (!hot_tags) {
|
||||
return ''
|
||||
}
|
||||
const result = hot_tags.map((item, index) => {
|
||||
let params = {}
|
||||
if (typeof item === 'string') {
|
||||
params.name = item;
|
||||
} else {
|
||||
params = item;
|
||||
}
|
||||
params.selectedHotLabelIndex = index;
|
||||
return (
|
||||
<a onClick={() => trigger('hotTagClick', params)} key={index}
|
||||
className={classNames({ "selected": selectedHotLabelIndex === index })}>
|
||||
{item.name || item}
|
||||
</a>)
|
||||
})
|
||||
return result
|
||||
}
|
||||
render() {
|
||||
const { match, history, currentPage, selectedHotLabelIndex } = this.props
|
||||
|
||||
return (
|
||||
<div className="clearfix padding40-20 edu-back-white mt10">
|
||||
<p className="font-16">热门标签</p>
|
||||
<div className="mt30 HotLabelList clearfix" id="HotLabelList">
|
||||
{this.renderTags()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RightHotLabel;
|
|
@ -1,53 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
class RightHotQuestion extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
renderHotMemos() {
|
||||
const { hot_memos } = this.props;
|
||||
if (!hot_memos) {
|
||||
return ''
|
||||
}
|
||||
return hot_memos.map((item, index) => {
|
||||
return <div className="hotQuestionItem" key={index}>
|
||||
<Link to={`/forums/${item.id}`} className="color-grey-6 task-hide mb5 questiontName"
|
||||
title={ item.subject && item.subject.length > 15 ? item.subject : '' }
|
||||
>
|
||||
{item.subject}
|
||||
</Link>
|
||||
<p className="clearfix font-12 color-grey-9">
|
||||
<span className="fl">{item.replies_count} 回答</span>
|
||||
{ !!item.tag && item.tag.length ? <span className="fr">来自 {item.tag.join('/')}</span> : ''}
|
||||
</p>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
render() {
|
||||
const { match, history, currentPage } = this.props
|
||||
|
||||
return (
|
||||
<div className="clearfix padding40-20 edu-back-white mt10">
|
||||
<p className="font-16">热门问题</p>
|
||||
<div className="mt10 hotQuestionList clearfix" id="hotQuestionList">
|
||||
{this.renderHotMemos()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RightHotQuestion;
|
|
@ -1,47 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { trigger } from 'educoder'
|
||||
|
||||
class MemoLabel extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
renderTags() {
|
||||
const { memo } = this.props;
|
||||
|
||||
const arrays = memo.tag.map((item, index) => {
|
||||
return <a key={index}>{item}</a>
|
||||
})
|
||||
return arrays
|
||||
}
|
||||
render() {
|
||||
const { match, history, currentPage, memo } = this.props
|
||||
|
||||
if (!memo || !memo.tag || memo.tag.length === 0) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="clearfix padding30-20 edu-back-white mt10">
|
||||
<p className="font-16">话题标签</p>
|
||||
<div className="mt30 HotLabelList clearfix" id="HotLabelList">
|
||||
{this.renderTags()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MemoLabel;
|
|
@ -1,75 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { getImageUrl, toPath, LinkAfterLogin } from 'educoder'
|
||||
|
||||
import match_adImg from '../../images/ad/match_ad.jpg'
|
||||
const $ = window.$
|
||||
|
||||
class RightMyPublish extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyPress = (event) => {
|
||||
if(event.type !== 'keypress' || event.key == 'Enter'){
|
||||
this.props.setSearchValue( this.props.searchValue, true);
|
||||
// $(window).trigger('setSearchValue', $('#shixun_search_input').val())
|
||||
}
|
||||
}
|
||||
handleInput = (event) => {
|
||||
this.props.setSearchValue(event.target.value);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { match, history, currentPage, my_memos_count, setSearchValue, searchValue } = this.props
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="clearfix edu-back-white padding40-20 publishMemoSection">
|
||||
{/*<div className="searchFor h40 mt15 mb5 ml20">
|
||||
<div className="searchCon fl">
|
||||
<input type="text" className="searchinput" name="search" value="" placeholder="请输入帖子标题的关键字进行搜索">
|
||||
</input>
|
||||
<span className="search_close" onclick="colse_searchbox();" data-tip-down="清除">×</span>
|
||||
</div>
|
||||
<i className="fa fa-search mr5 fl color-dark-grey search_icon"
|
||||
onClick="$('#search_memos').submit();" style={{margin:'8px'}} data-tip-down="搜索"></i>
|
||||
</div>*/}
|
||||
<div className="search-new">
|
||||
<input type="text" className="search-new-input fl" placeholder="搜索您想了解的话题" id="shixun_search_input"
|
||||
onKeyPress={this.handleKeyPress} onChange={ this.handleInput } value={searchValue}
|
||||
>
|
||||
</input>
|
||||
<span className="search-span"></span>
|
||||
<img src={getImageUrl("images/educoder/icon/search.svg")} className="fl mt5"
|
||||
onClick={ this.handleKeyPress }>
|
||||
|
||||
</img>
|
||||
</div>
|
||||
<LinkAfterLogin {...this.props} to={'/forums/new'} className="sendMyQuestion edu-default-btn edu-blueback-btn edu-txt-center font-16 mb30">发布话题</LinkAfterLogin>
|
||||
{/*<p className="edu-txt-center font-16">
|
||||
<span>我的发布</span><br/>
|
||||
<Link to={`/forums/categories/my_published`} className="color-blue">{my_memos_count}</Link>
|
||||
</p>*/}
|
||||
</div>
|
||||
|
||||
<div className="clearfix edu-back-white advertisement" >
|
||||
<a href="/competitions" target="_blank"><img src={match_adImg}></img></a>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RightMyPublish;
|
|
@ -1,61 +0,0 @@
|
|||
/* 右侧搜索区域*/
|
||||
.searchFor .searchCon {
|
||||
width: 215px;
|
||||
}
|
||||
|
||||
.search-new {
|
||||
width:237px!important;
|
||||
height: 30px;
|
||||
margin-bottom: 30px;
|
||||
/*margin-right: 35px;*/
|
||||
}
|
||||
.search-newysl {
|
||||
|
||||
height: 30px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.search-newyslw{
|
||||
width:237px!important;
|
||||
}
|
||||
.search-new-input {
|
||||
padding-left: 16px;
|
||||
height: 30px;
|
||||
}
|
||||
.search-span {
|
||||
border-radius: 17px;
|
||||
}
|
||||
|
||||
.search-new img {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* 右侧 热门标签 */
|
||||
.HotLabelList a{display: block;float: left;padding: 0px 9px;height: 28px;line-height: 28px;border-radius: 14px;background-color: #f5f5f5;color: #666;margin-right: 10px;margin-bottom: 9px;}
|
||||
.HotLabelList a.selected {
|
||||
background: #4CACFF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 右侧 热门问题 */
|
||||
.hotQuestionItem{padding:20px 0px;border-bottom: 1px solid #eee;}
|
||||
.questiontName{max-width: 100%;display: block;}
|
||||
|
||||
|
||||
|
||||
/* 用户信息-UserSection*/
|
||||
.user_default_btn {width: 114px;}
|
||||
.userPrivateName{line-height: 25px;margin-bottom: 9px;}
|
||||
.userPrivatePost{line-height: 20px;}
|
||||
.noteDetailTitle{line-height: 38px;font-size: 24px;font-weight: normal;text-align:justify }
|
||||
|
||||
.noteDetailNum{float: left;padding:0px 12px;position: relative;color: #999!important;height: 28px;line-height: 26px;}
|
||||
.noteDetailNum.rightline:after{position: absolute;content: '';right: 0px;width: 1px;background-color: #EAEAEA;height: 8px;top:10px;}
|
||||
|
||||
/*帖子详情点赞*/
|
||||
.noteDetailPoint{width: 100px;height: 70px;background-color: #4cacff;border-radius: 35px;color: #FFFFff;text-align: center;margin: 0px auto;box-sizing: border-box;padding: 2px 0px;cursor: pointer; line-height: 22px;
|
||||
padding-top: 12px;}
|
||||
.Pointed{background-color:#f0f0f0;color: #b3b3b3; cursor: default}
|
||||
.notefileDownload{height: 25px;line-height: 22px;}
|
|
@ -1,87 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
class UserSection extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
/*点击关注或者取消关注*/
|
||||
AboutFocus() {
|
||||
const { author_info } = this.props
|
||||
/*http://localhost:3000/api/v1/users/155/watch?object_id=156&object_type=user*/
|
||||
|
||||
// const focusUrl = `/api/v1/users/${author_info.user_id}/${this.props.author_info.watched ? 'unwatch' : 'watch'}?object_id=${author_info.user_id}&object_type=user`
|
||||
|
||||
// axios.get(focusUrl,{
|
||||
// })
|
||||
// .then((response) => {
|
||||
// const status = response.data.status;
|
||||
// console.log(status);
|
||||
// if(status == 1){
|
||||
// const new_author_info = Object.assign({}, this.props.author_info)
|
||||
// new_author_info.watched = !new_author_info.watched
|
||||
// this.props.initForumState({author_info: new_author_info})
|
||||
// }
|
||||
// }).catch((error) => {
|
||||
// console.log(error)
|
||||
// })
|
||||
|
||||
let url = `/users/${author_info.user_id}/watch.json`;
|
||||
// 取消关注
|
||||
if (author_info.watched) {
|
||||
axios.delete(url).then((result) => {
|
||||
if (result) {
|
||||
const new_author_info = Object.assign({}, this.props.author_info)
|
||||
new_author_info.watched = !new_author_info.watched
|
||||
this.props.initForumState({ author_info: new_author_info })
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
} else {
|
||||
// 关注
|
||||
axios.post(url).then((result) => {
|
||||
if (result) {
|
||||
const new_author_info = Object.assign({}, this.props.author_info)
|
||||
new_author_info.watched = !new_author_info.watched
|
||||
this.props.initForumState({ author_info: new_author_info })
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { match, history, author_info, current_user } = this.props
|
||||
if (!author_info || !current_user) {
|
||||
return <div className="edu-back-white" id="forum_index_list"></div>
|
||||
}
|
||||
return (
|
||||
<div className="edu-back-white padding40-20 edu-txt-center">
|
||||
<a href={`/users/${author_info.login}`} target="_blank"><img src={`/images/${author_info.image_url}`} width="90" height="90" className="radius mb5" /></a>
|
||||
<p className="font-20 userPrivateName">{author_info.username}</p>
|
||||
<p className="color-grey-9 userPrivatePost">{author_info.identity}</p>
|
||||
{author_info.user_id !== current_user.user_id &&
|
||||
<p className="clearfix mt30">
|
||||
<a className="fl font-16 mr10 user_default_btn edu-blueback-btn" onClick={() => { this.AboutFocus() }}>{author_info.watched == true ? "取消关注" : "关注"}</a>
|
||||
<a href={`/messages/${current_user.login}/message_detail?target_ids=${author_info.user_id}`} className="fr font-16 user_default_btn user_private_btn" target="_blank">私信</a>
|
||||
</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default UserSection;
|
|
@ -1,21 +0,0 @@
|
|||
.sxReturnItem{
|
||||
width: 100%;
|
||||
padding-left:20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ItemLine{
|
||||
border-bottom: 1px solid #EBEBEB;
|
||||
padding:30px 0px;
|
||||
}
|
||||
.ItemLineHeadPhoto{
|
||||
height:48px;
|
||||
width: 48px;
|
||||
float: left;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.shixunReply{
|
||||
max-width: 604px;
|
||||
}
|
||||
.sxReturnItem:last-child .ItemLine{
|
||||
border-bottom: none;
|
||||
}
|
|
@ -1,227 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import Pagination from 'rc-pagination';
|
||||
|
||||
import ShiXunPostItem from './ShiXunPostItem'
|
||||
import ForumsNavTab from '../ForumsNavTab'
|
||||
import { CircularProgress } from 'material-ui/Progress';
|
||||
import { on, off } from 'educoder'
|
||||
import './MemoShixun.css'
|
||||
|
||||
// import queryString from 'query-string'
|
||||
import { queryString, updatePageParams } from 'educoder'
|
||||
import MemoList from '../MemoList'
|
||||
import axios from 'axios'
|
||||
|
||||
const $ = window.$;
|
||||
class MemoShixun extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
currentPage: 1,
|
||||
loadingMemos: true
|
||||
}
|
||||
}
|
||||
|
||||
onPaginationChange(pageNum, pageSize) {
|
||||
window.$("html,body").animate({"scrollTop":0})
|
||||
updatePageParams(pageNum, this.props)
|
||||
this.fetchShixunMemos(pageNum);
|
||||
}
|
||||
componentWillReceiveProps(newProps, newContext) {
|
||||
if (newProps.enterKeyFlag !== this.props.enterKeyFlag) {
|
||||
// const childPath = this.props.match.path.split('/:')[0]
|
||||
// // 加入一个浏览地址
|
||||
// const _search = this.props.location.search;
|
||||
// if (_search) {
|
||||
// const parsed = queryString.parse(_search);
|
||||
// if (parsed.page != 1) {
|
||||
// parsed.page = 1;
|
||||
|
||||
// this.props.history.push(`${this.props.match.url}?${queryString.stringify(parsed)}`)
|
||||
// }
|
||||
// }
|
||||
this.fetchShixunMemos(1, newProps.searchValue, newProps.selectedHotLabelIndex) // 搜索框模糊搜索,重置为第一页
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fetchShixunMemos(arg_currentPage, arg_searchValue, arg_selectedHotLabelIndex) {
|
||||
/*
|
||||
page = params[:page].to_i
|
||||
offset = page * 15
|
||||
search = params[:search]
|
||||
tag = params[:tag_repertoire_id]
|
||||
*/
|
||||
|
||||
const _search = this.props.history.location.search;
|
||||
const parsed = queryString.parse(_search);
|
||||
|
||||
let currentPage = parseInt( arg_currentPage ? arg_currentPage : (parsed.page || 1) )
|
||||
|
||||
const paramsObject = {
|
||||
page: currentPage // - 1 从1开始
|
||||
}
|
||||
|
||||
let searchValue = arg_searchValue != undefined ? arg_searchValue : this.props.searchValue
|
||||
|
||||
if (searchValue) {
|
||||
paramsObject.search = searchValue
|
||||
}
|
||||
let { selectedHotLabelIndex, hot_tags } = this.props;
|
||||
selectedHotLabelIndex = arg_selectedHotLabelIndex ? arg_selectedHotLabelIndex : selectedHotLabelIndex
|
||||
if (selectedHotLabelIndex !== -1 && hot_tags[selectedHotLabelIndex]) {
|
||||
paramsObject.tag_repertoire_id = hot_tags[selectedHotLabelIndex].id
|
||||
}
|
||||
|
||||
const stringifid = queryString.stringify(paramsObject);
|
||||
const url = `/discusses/forum_discusses.json?${stringifid}` // /${challenge.identifier}/star
|
||||
|
||||
// 获取memo list
|
||||
this.setState({
|
||||
currentPage: currentPage ,
|
||||
loadingMemos: true
|
||||
})
|
||||
axios.get(url,{
|
||||
// withCredentials: true,
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
// const user = response.data.current_user;
|
||||
// user.tidding_count = response.data.tidding_count;
|
||||
// this.props.initCommonState(user)
|
||||
this.props.initForumState(response.data)
|
||||
|
||||
// const { hot_tags } = response.data;
|
||||
// if (hot_tags && hot_tags.length) {
|
||||
// this.tagNameIdMap = {}
|
||||
// hot_tags.forEach( (item, index) => {
|
||||
// this.tagNameIdMap[item.name] = item.id
|
||||
// })
|
||||
// }
|
||||
|
||||
this.setState({
|
||||
|
||||
// p_forum_id: params.forum,
|
||||
// p_s_order: params.s_order,
|
||||
loadingMemos: false
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
componentDidMount() {
|
||||
this.fetchShixunMemos();
|
||||
|
||||
on('hotTagClick', (event, tagName) => {
|
||||
this.props.setHotLabelIndex(tagName.selectedHotLabelIndex, () => {
|
||||
this.fetchShixunMemos(1, undefined)
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
$(window).on('popstate', (e) => {
|
||||
var state = e.originalEvent.state;
|
||||
console.log('popstate', state)
|
||||
if (state !== null) {
|
||||
|
||||
let currentPage = this.state.currentPage;;
|
||||
// // 浏览器地址改变了
|
||||
const search = this.props.history.location.search
|
||||
const parsed = queryString.parse(search);
|
||||
if (parsed.page != currentPage) {
|
||||
currentPage = parseInt( parsed.page || 1)
|
||||
// this.setSearchValue('')
|
||||
this.fetchShixunMemos(currentPage)
|
||||
this.setState({
|
||||
currentPage,
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
off('hotTagClick')
|
||||
$(window).off('popstate')
|
||||
}
|
||||
|
||||
renderMemoList() {
|
||||
|
||||
const { memo_list, user } = this.props;
|
||||
if (!memo_list) {
|
||||
return ''
|
||||
}
|
||||
/*
|
||||
<PostItem key={item.id} user={user} index={index} {...this.props}
|
||||
setTop={(memo)=>this.setTop(memo)}
|
||||
setDown={(memo)=>this.setDown(memo)}
|
||||
memo={item}
|
||||
></PostItem>
|
||||
*/
|
||||
return memo_list.map( (item, index) => {
|
||||
return (<React.Fragment>
|
||||
<ShiXunPostItem key={item.id} user={user} index={index} {...this.props} memo={item}></ShiXunPostItem>
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { match, history , memo_count ,memo_list, showSearchValue, searchValue
|
||||
, selectedHotLabelIndex, hot_tags } = this.props;
|
||||
const { currentPage, loadingMemos } = this.state;
|
||||
|
||||
// 规则: 搜索框输入了值 或者 选择了热门标签的时候显示该提示
|
||||
const _showSearchValue = showSearchValue || selectedHotLabelIndex != -1
|
||||
let _searchValue;
|
||||
if (showSearchValue) {
|
||||
_searchValue = searchValue
|
||||
} else if (selectedHotLabelIndex != -1){
|
||||
_searchValue = hot_tags[selectedHotLabelIndex].name || hot_tags[selectedHotLabelIndex]
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="edu-back-white" id="forum_index_list"> {/* fl with100 */}
|
||||
<div className="clearfix">
|
||||
{ _showSearchValue &&
|
||||
<div className="noMemosTip" style={{display: loadingMemos ? 'none' : 'block'}}>
|
||||
<span className="fr pr20" id="search_result">
|
||||
共找到
|
||||
<span className="color-orange03">{memo_count}</span>个"
|
||||
<span className="color-orange03">{_searchValue}</span>"相关的结果
|
||||
</span>
|
||||
</div> }
|
||||
|
||||
<CircularProgress size={40} thickness={3}
|
||||
style={{ marginLeft: 'auto', marginRight: 'auto', paddingTop: '20%'
|
||||
, display: loadingMemos ? 'block': 'none' }}/>
|
||||
{ !loadingMemos &&
|
||||
<React.Fragment>
|
||||
<ForumsNavTab {...this.props}></ForumsNavTab>
|
||||
<MemoList {...this.props}
|
||||
renderMemoList={() => this.renderMemoList()}
|
||||
onPaginationChange={ (pageNum, pageSize) => this.onPaginationChange(pageNum, pageSize) }
|
||||
{...this.state}
|
||||
>
|
||||
</MemoList>
|
||||
</React.Fragment>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MemoShixun;
|
|
@ -1,69 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import moment from 'moment'
|
||||
import './MemoShixun.css'
|
||||
|
||||
class ShiXunPostItem extends Component
|
||||
{
|
||||
constructor(props)
|
||||
{
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { memo } = this.props;
|
||||
let tagStr = ''
|
||||
if (memo.shixun_tag && memo.shixun_tag.length) {
|
||||
|
||||
memo.shixun_tag.forEach( tag => {
|
||||
tagStr += ` ${tag}`
|
||||
})
|
||||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="sxReturnItem">
|
||||
<div className="ItemLine clearfix df">
|
||||
<a href={`/users/${memo.login}`} className="ItemLineHeadPhoto">
|
||||
<img src={`/images/${memo.image_url}`}
|
||||
width="48px" height="48px" className="radius"/>
|
||||
</a>
|
||||
<div className="flex1 ml10 pr20">
|
||||
<div className="clearfix" style={{ height: '32px' }}>
|
||||
<p className="shixunReply task-hide font-16 fl">
|
||||
<Link to={`${memo.tpm_url}`} title={memo.subject} target="_blank">{memo.subject}</Link>
|
||||
</p>
|
||||
{ memo.reward &&
|
||||
<span className="color-orange ml20 fl" data-tip-down={`获得平台奖励金币:${memo.reward}`}
|
||||
style={{ lineHeight: '20px' }}
|
||||
>
|
||||
<i className="iconfont icon-gift font-16 mr5 fl"></i><span className="fl mt3">{memo.reward}</span>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
<p className="clearfix mt5">
|
||||
<span className="fl color-grey-9">{memo.username}</span>
|
||||
{/* <span className="fl color-grey-9 ml40">{moment(memo.updated_at).fromNow()}</span> */}
|
||||
{ !!tagStr && <span className="fl color-grey-9 ml40">来自 {tagStr}</span>}
|
||||
{ !!memo.praises_count && <span className="fr color-grey-6 ml20 font-12">{memo.praises_count} 赞</span>}
|
||||
{ !!memo.replies_count && <span className="fr color-grey-6 font-12">{memo.replies_count} 回复</span>}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
export default ShiXunPostItem
|
|
@ -1,172 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
import './css/moopCases.css'
|
||||
import '../courses/css/Courses.css'
|
||||
|
||||
import { getImageUrl, MarkdownToHtml, ActionBtn, AttachmentList } from 'educoder';
|
||||
|
||||
import Tags from './CaseTags'
|
||||
|
||||
import axios from 'axios';
|
||||
import Modals from '../modals/Modals'
|
||||
|
||||
// import AttachmentList from '../../common/components/attachment/AttachmentList'
|
||||
|
||||
class CaseDetail extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
modalsType: "",
|
||||
modalsTopval: "",
|
||||
modalsBottomval: "",
|
||||
modalCancel: "",
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
let caseID = this.props.match.params.caseID;
|
||||
this.props.getDetail(caseID);
|
||||
}
|
||||
// 是否删除
|
||||
delCases = () => {
|
||||
this.setState({
|
||||
modalsType: true,
|
||||
modalsTopval: "是否确认删除?",
|
||||
modalsBottomval: ""
|
||||
})
|
||||
}
|
||||
|
||||
// 取消删除
|
||||
cancelDelClasses = () => {
|
||||
this.setState({
|
||||
modalsType: false,
|
||||
modalsTopval: "",
|
||||
modalsBottomval: ""
|
||||
})
|
||||
}
|
||||
// 确定删除
|
||||
sureDelClasses = () => {
|
||||
let caseID = this.props.match.params.caseID;
|
||||
let url = `/libraries/${caseID}.json`;
|
||||
axios.delete(url).then((result) => {
|
||||
if (result) {
|
||||
this.props.showNotification("删除成功");
|
||||
this.props.history.push("/moop_cases");
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
let { CaseDetail, praise_count, creator, operation, user_praised, tags, attachments } = this.props
|
||||
let {
|
||||
modalsType,
|
||||
modalsTopval,
|
||||
modalsBottomval,
|
||||
} = this.state;
|
||||
document.title = CaseDetail && CaseDetail.title != undefined ? CaseDetail && CaseDetail.title : "教学案例";
|
||||
return (
|
||||
<div className="educontent mt10 mb50">
|
||||
{
|
||||
CaseDetail &&
|
||||
<React.Fragment>
|
||||
<Modals
|
||||
modalsType={modalsType}
|
||||
modalsTopval={modalsTopval}
|
||||
modalsBottomval={modalsBottomval}
|
||||
modalCancel={this.cancelDelClasses}
|
||||
modalSave={this.sureDelClasses}
|
||||
>
|
||||
</Modals>
|
||||
<p className="mt10 mb20 clearfix lineh-20">
|
||||
<a href="/moop_cases" className="color-grey-9">教学案例</a> > <span className="color-grey-3">{CaseDetail.title}</span>
|
||||
</p>
|
||||
<p className="lineh-25 mb20 clearfix">
|
||||
<span className="font-22 fl mr10 task-hide lineh-30" style={{ maxWidth: "800px" }}>
|
||||
{CaseDetail.title}
|
||||
</span>
|
||||
<span className="mt10 fl">
|
||||
<Tags tags={tags}></Tags>
|
||||
{
|
||||
CaseDetail.status == "pending" && <span className="edu-filter-btn fl cdefault edu-activity-green ml10">草稿</span>
|
||||
}
|
||||
{
|
||||
CaseDetail.status == "processing" && <span className="edu-filter-btn fl cdefault edu-activity-green ml10">审核中</span>
|
||||
}
|
||||
{
|
||||
CaseDetail.status == "refused" && <span className="edu-filter-btn fl cdefault edu-activity-orange ml10">未通过</span>
|
||||
}
|
||||
</span>
|
||||
<a href="/moop_cases" className="fr color-grey-9 mt5">返回</a>
|
||||
</p>
|
||||
<div className="edu-back-white">
|
||||
<div className="padding30">
|
||||
<div className="df mb5">
|
||||
<a href="/users/moop"><img alt="82274?1563067098" className="radius mr15 mt3" height="50" src={getImageUrl(`images/${creator && creator.image_url}`)} width="50" /></a>
|
||||
<div className="flex1">
|
||||
<li className="clearfix mb5">
|
||||
<span className="font-16 fl">{creator && creator.name}</span>
|
||||
{
|
||||
operation && operation.can_deletable ? <ActionBtn style="greyLine" onClick={this.delCases} className="fr">删除</ActionBtn> : ""
|
||||
}
|
||||
|
||||
{
|
||||
operation && operation.can_editable ? <ActionBtn style=" colorBlue" to={`/moop_cases/${this.props.match.params.caseID}/edit`} className="fr mr20">编辑</ActionBtn> : ""
|
||||
}
|
||||
</li>
|
||||
<li className="clearfix lineh-20">
|
||||
<span className="fl color-grey-9 mr20">{creator && creator.school_name}</span>
|
||||
<span className="fr">
|
||||
<span className="fl color-grey-9 mr30">编码:<span className="color-grey-6">{CaseDetail.uuid}</span></span>
|
||||
{
|
||||
CaseDetail && CaseDetail.status == "published" ?
|
||||
<span className="fl color-grey-9">发布时间:<span className="color-grey-6">{CaseDetail.published_at}</span></span>
|
||||
:
|
||||
<span className="fl color-grey-9">上传时间:<span className="color-grey-6">{CaseDetail.created_at}</span></span>
|
||||
}
|
||||
</span>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="fl color-grey-9">作者:</span>{CaseDetail.author_name}/{CaseDetail.author_school_name}
|
||||
</div>
|
||||
<style>
|
||||
{`
|
||||
.setMDStyle .editormd-html-preview{
|
||||
width:100%!important;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<div className="mt20 setMDStyle">
|
||||
{CaseDetail.content && <MarkdownToHtml content={CaseDetail.content} id="casesDetail" selector="casesDetail" style={{ width: "100%!important" }}></MarkdownToHtml>}
|
||||
</div>
|
||||
{attachments &&
|
||||
<div className="mt10">
|
||||
<AttachmentList {...this.props} {...this.state} attachments={attachments}></AttachmentList>
|
||||
</div>
|
||||
}
|
||||
<div className="mt40">
|
||||
{
|
||||
user_praised ?
|
||||
<p className="pointsBtn pointedBtn">
|
||||
<span>已赞</span>
|
||||
<span>{praise_count}</span>
|
||||
</p>
|
||||
:
|
||||
<p onClick={() => this.props.praisePoint(this.props.match.params.caseID)} className="pointsBtn">
|
||||
<span><i className="iconfont icon-dianzan"></i></span>
|
||||
<span>{praise_count}</span>
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CaseDetail;
|
|
@ -1,59 +0,0 @@
|
|||
import React,{ Component } from "react";
|
||||
import './css/moopCases.css'
|
||||
import '../courses/css/Courses.css'
|
||||
|
||||
import { getUrl } from 'educoder';
|
||||
|
||||
import Tags from './CaseTags'
|
||||
|
||||
class CaseItem extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
render(){
|
||||
let { libraries } = this.props;
|
||||
console.log(libraries)
|
||||
return(
|
||||
<div className="library-list-container">
|
||||
{
|
||||
libraries && libraries.map((item,key)=>{
|
||||
return(
|
||||
<a href={`/moop_cases/${item.id}`} target="_blank">
|
||||
<li className="library_list_item pointer">
|
||||
<img alt={item.id} className="mr15 mt3 radius4" height="90" src={getUrl(`${item.cover_url || "/images/educoder/library-default-cover.png"}`)} width="120" />
|
||||
<div className="flex1">
|
||||
<p className="clearfix mb25 lineh-40">
|
||||
<a className="task-hide font-22 library_l_name">{item.title}</a>
|
||||
<span className="fl mt10"><Tags tags={item.tags}></Tags></span>
|
||||
</p>
|
||||
<p className="clearfix lineh-20">
|
||||
<span className="color-grey-3 mr10">{item.author_name}</span>
|
||||
<span className="color-grey-3 mr20">{item.author_school_name}</span>
|
||||
<span className="color-grey-c fr">
|
||||
{
|
||||
item.visited_count && item.visited_count != 0 ?
|
||||
<span className="color-grey-c ml20"><span className=" item-group-icon mr5"><i className="fa fa-eye"></i></span>{item.visited_count} 浏览</span>:""
|
||||
}
|
||||
{
|
||||
item.praise_count && item.praise_count != 0 ?
|
||||
<span className="color-grey-c ml20"><span className=" item-group-icon mr5"><i className="fa fa-thumbs-o-up"></i></span>{item.praise_count} 赞</span>:""
|
||||
}
|
||||
{
|
||||
item.download_count && item.download_count != 0 ?
|
||||
<span className="color-grey-c ml20" style={{"marginRight":'1px'}}><span className=" item-group-icon mr5"><i className="fa fa-download"></i></span>{item.download_count} 下载</span>:""
|
||||
}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</a>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CaseItem;
|
|
@ -1,173 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
import { Input, Spin, Pagination } from "antd";
|
||||
import './css/moopCases.css'
|
||||
import '../courses/css/Courses.css'
|
||||
|
||||
import { ActionBtn, LinkAfterLogin, getImageUrl } from 'educoder';
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
import NoneData from '../courses/coursesPublic/NoneData'
|
||||
|
||||
import mainImg from '../../images/moop_cases/teach_ex.jpg'
|
||||
import CaseItem from './CaseItem'
|
||||
|
||||
|
||||
|
||||
|
||||
const Search = Input.Search;
|
||||
class CaseList extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
type: 0,
|
||||
search: undefined,
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
libraries: undefined,
|
||||
totalCount: undefined,
|
||||
isSpin: true
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
window.document.title = '教学案例'
|
||||
let { type, search, page, pageSize } = this.state;
|
||||
this.InitList(type, search, page, pageSize);
|
||||
}
|
||||
|
||||
// 列表
|
||||
InitList = (type, search, page, pageSize) => {
|
||||
let url = `/libraries.json`;
|
||||
axios.get(url, {
|
||||
params: {
|
||||
type: type == 0 ? undefined : "mine",
|
||||
keyword: search,
|
||||
page,
|
||||
per_page: pageSize
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
libraries: result.data.libraries,
|
||||
totalCount: result.data.count,
|
||||
isSpin: false
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
isSpin: false
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({
|
||||
isSpin: false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// tab切换
|
||||
changeType = (type) => {
|
||||
this.setState({
|
||||
type,
|
||||
page: 1,
|
||||
isSpin: true
|
||||
})
|
||||
let { search, page, pageSize } = this.state;
|
||||
this.InitList(type, search, page, pageSize);
|
||||
}
|
||||
|
||||
// 输入搜索内容
|
||||
inputStudent = (e) => {
|
||||
this.setState({
|
||||
search: e.target.value
|
||||
})
|
||||
}
|
||||
|
||||
// 搜索
|
||||
searchInfo = () => {
|
||||
this.setState({
|
||||
isSpin: true
|
||||
})
|
||||
let { type, search, pageSize } = this.state;
|
||||
this.InitList(type, search, 1, pageSize);
|
||||
}
|
||||
|
||||
// 切换分页
|
||||
onChangePage = (pageNumber) => {
|
||||
this.setState({
|
||||
page: pageNumber
|
||||
})
|
||||
let { type, search, pageSize } = this.state;
|
||||
this.InitList(type, search, pageNumber, pageSize);
|
||||
}
|
||||
|
||||
render() {
|
||||
let { type, search, libraries, totalCount, pageSize, page } = this.state;
|
||||
let { checkIfLogin } = this.props;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<style>
|
||||
{
|
||||
`
|
||||
.imgmoop_cases{width: 100%;
|
||||
height: 300px;
|
||||
background-color: #000a4f;
|
||||
background-position: 50%;
|
||||
background-repeat: no-repeat;}
|
||||
`
|
||||
}
|
||||
</style>
|
||||
<img className={"imgmoop_cases"} src={this.props.mygetHelmetapi && this.props.mygetHelmetapi.moop_cases_banner_url === null ? mainImg : getImageUrl(this.props.mygetHelmetapi && this.props.mygetHelmetapi.moop_cases_banner_url)} />
|
||||
<div className="educontent">
|
||||
<div className="edu-back-white mb30 mt30">
|
||||
<p className="padding20-30 clearfix bor-bottom-greyE">
|
||||
<span className="font-18 fl color-grey-3">教学案例</span>
|
||||
<LinkAfterLogin {...this.props} to={'/moop_cases/new'} className="fr edu-default-btn edu-blueline-btn" checkProfileComplete={true}
|
||||
|
||||
>发布案例</LinkAfterLogin>
|
||||
{/* <ActionBtn style="colorBlue" className="fr" to="/moop_cases/new">发布案例</ActionBtn> */}
|
||||
</p>
|
||||
<div className="clearfix pl30 pr30">
|
||||
<ul className="fl library_nav mt25">
|
||||
<li className={type == 0 ? "active" : ""} onClick={() => this.changeType(0)}>
|
||||
<a >全部</a>
|
||||
</li>
|
||||
{
|
||||
checkIfLogin() &&
|
||||
<li className={type == 1 ? "active" : ""} onClick={() => this.changeType(1)}>
|
||||
<a >我的</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<div className="fr mt16 mb16 searchView" style={{ width: "300px" }}>
|
||||
<Search
|
||||
value={search}
|
||||
placeholder="输入教学案例标题、作者、单位进行检索"
|
||||
onInput={this.inputStudent}
|
||||
onSearch={this.searchInfo}
|
||||
></Search>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Spin size="large" spinning={this.state.isSpin} tip="正在获取相关数据...">
|
||||
{
|
||||
libraries && libraries.length > 0 && <CaseItem {...this.props} {...this.state} libraries={libraries}></CaseItem>
|
||||
}
|
||||
{
|
||||
libraries && libraries.length == 0 && <div className="mb50"><NoneData></NoneData></div>
|
||||
}
|
||||
{
|
||||
totalCount && totalCount > pageSize &&
|
||||
<div className="mb50 edu-txt-center clearfix">
|
||||
<Pagination defaultCurrent={page} current={page} pageSize={pageSize} showQuickJumper onChange={this.onChangePage} total={totalCount}></Pagination>
|
||||
</div>
|
||||
}
|
||||
</Spin>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CaseList
|
|
@ -1,475 +0,0 @@
|
|||
import React,{ Component } from "react";
|
||||
import './css/moopCases.css'
|
||||
import '../courses/css/Courses.css'
|
||||
import { Form , Input , Upload , Button , Icon , message , Tooltip } from "antd";
|
||||
|
||||
import { getImageUrl , setImagesUrl , MarkdownToHtml , ActionBtn , appendFileSizeToUploadFile , appendFileSizeToUploadFileAll , getUrl , getUploadActionUrl } from 'educoder';
|
||||
|
||||
import Tags from './CaseTags'
|
||||
|
||||
import axios from 'axios';
|
||||
import TPMMDEditor from '../tpm/challengesnew/TPMMDEditor';
|
||||
import _ from 'lodash'
|
||||
const { Dragger } = Upload;
|
||||
function beforeUpload(file) {
|
||||
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
|
||||
if (!isJpgOrPng) {
|
||||
message.error('You can only upload JPG/PNG file!');
|
||||
}
|
||||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
if (!isLt2M) {
|
||||
message.error('Image must smaller than 2MB!');
|
||||
}
|
||||
return isJpgOrPng && isLt2M;
|
||||
}
|
||||
function getBase64(img, callback) {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => callback(reader.result));
|
||||
reader.readAsDataURL(img);
|
||||
}
|
||||
const $ = window.$;
|
||||
class CaseNew extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.DescMdRef = React.createRef();
|
||||
|
||||
this.state={
|
||||
casesTags:[],
|
||||
contentFileList:[],
|
||||
filesID:[],
|
||||
imageUrl:undefined,
|
||||
loading: false,
|
||||
checkTag:false,
|
||||
checkFile:false,
|
||||
coverID:undefined,
|
||||
library_tags:undefined
|
||||
}
|
||||
}
|
||||
|
||||
// 上传附件-删除确认框
|
||||
onAttachmentRemove = (file, stateName) => {
|
||||
if(!file.percent || file.percent == 100){
|
||||
this.props.confirm({
|
||||
content: '是否确认删除?',
|
||||
onOk: () => {
|
||||
this.deleteAttachment(file, stateName)
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 上传附件-确认删除
|
||||
deleteAttachment = (file, stateName) => {
|
||||
// 初次上传不能直接取uid
|
||||
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
|
||||
axios.delete(url, {
|
||||
}).then((response) => {
|
||||
if (response.data) {
|
||||
const { status } = response.data;
|
||||
if (status == 0) {
|
||||
console.log('--- success')
|
||||
|
||||
this.setState((state) => {
|
||||
const index = state[stateName].indexOf(file);
|
||||
const newFileList = state[stateName].slice();
|
||||
newFileList.splice(index, 1);
|
||||
console.log("newFileList");
|
||||
console.log(newFileList.map(item =>{ return( item.id )}));
|
||||
return {
|
||||
[stateName]: newFileList,
|
||||
filesID:newFileList.map(item =>{ return( item.id )})
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
// 上传附件-change
|
||||
handleContentUploadChange = (info) => {
|
||||
if (info.file.status === 'done' || info.file.status === 'uploading' || info.file.status === 'removed') {
|
||||
let contentFileList = info.fileList;
|
||||
this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList)});
|
||||
let list = appendFileSizeToUploadFileAll(contentFileList);
|
||||
let arr = list.map(item=>{
|
||||
return ( item.response && item.response.id )
|
||||
})
|
||||
this.setState({
|
||||
filesID:arr,
|
||||
checkFile:arr.length > 0 ? false : true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 上传封面图-change
|
||||
handleChange = (info) => {
|
||||
if (info.file.status === 'uploading') {
|
||||
this.setState({ loading: true });
|
||||
return;
|
||||
}
|
||||
if (info.file.status === 'done') {
|
||||
// Get this url from response in real world.
|
||||
getBase64(info.file.originFileObj, imageUrl =>
|
||||
this.setState({
|
||||
imageUrl,
|
||||
loading: false
|
||||
}),
|
||||
);
|
||||
console.log(info.file);
|
||||
this.setState({
|
||||
coverID:info.file.response && info.file.response.id
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// 编辑时加载数据
|
||||
componentDidMount=()=>{
|
||||
|
||||
if(this.props.match.params.caseID){
|
||||
this.InitEditData();
|
||||
}else{
|
||||
window.document.title = '教学案例'
|
||||
}
|
||||
let url=`/library_tags.json`;
|
||||
axios.get(url).then((result) => {
|
||||
console.log(result)
|
||||
if(result.data.status===0){
|
||||
this.setState({
|
||||
library_tags:result.data.library_tags
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
componentDidUpdate=(prevState)=>{
|
||||
if(this.props.CaseDetail && prevState.CaseDetail != this.props.CaseDetail){
|
||||
this.props.form.setFieldsValue({
|
||||
caseTitle:this.props.CaseDetail.title,
|
||||
userName:this.props.CaseDetail.author_name,
|
||||
userUnit:this.props.CaseDetail.author_school_name,
|
||||
})
|
||||
this.setState({
|
||||
contentFileList:this.props.attachments.map(item => {
|
||||
return {
|
||||
id: item.id,
|
||||
uid: item.id,
|
||||
name: appendFileSizeToUploadFile(item),
|
||||
url: item.url,
|
||||
filesize: item.filesize,
|
||||
status: 'done'
|
||||
}
|
||||
}),
|
||||
filesID:this.props.attachments.map(item => {
|
||||
return ( item.id )
|
||||
}),
|
||||
coverID:this.props.cover && this.props.cover.id,
|
||||
imageUrl:this.props.CaseDetail.cover && setImagesUrl(this.props.CaseDetail.cover.url),
|
||||
casesTags:this.props.tags.map(item=>{
|
||||
return (item.id);
|
||||
})
|
||||
})
|
||||
console.log(this.props.attachments.map(item => {
|
||||
return ( item.id )
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
InitEditData=()=>{
|
||||
let caseID = this.props.match.params.caseID;
|
||||
this.props.getDetail(caseID);
|
||||
}
|
||||
|
||||
// 申请提交和保存
|
||||
handleSubmit = (type) => {
|
||||
let caseID = this.props.match.params.caseID;
|
||||
console.log(type);
|
||||
this.props.form.validateFieldsAndScroll((err, values) => {
|
||||
let { casesTags , filesID } = this.state;
|
||||
if(casesTags.length == 0){
|
||||
$("html").animate({ scrollTop: $("#tagFormItem").offset().top - 100 });
|
||||
this.setState({
|
||||
checkTag:true
|
||||
})
|
||||
return;
|
||||
}
|
||||
if(filesID.length == 0){
|
||||
$("html").animate({ scrollTop: $("#fileFormItem").offset().top - 100 });
|
||||
this.setState({
|
||||
checkFile:true
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
const mdContnet = this.DescMdRef.current.getValue().trim();
|
||||
console.log(mdContnet)
|
||||
values.description = mdContnet;
|
||||
|
||||
console.log(values);
|
||||
let url = caseID ? `/libraries/${caseID}.json`: `/libraries.json`;
|
||||
if(caseID){
|
||||
axios.put((url),{
|
||||
title:values.caseTitle,
|
||||
author_name:values.userName,
|
||||
author_school_name:values.userUnit,
|
||||
content:values.description,
|
||||
attachment_ids:this.state.contentFileList.map(item=>{
|
||||
return (item.response ? item.response.id : item.id )
|
||||
}),
|
||||
tag_ids:this.state.casesTags,
|
||||
cover_id:this.state.coverID,
|
||||
publish:type == 'save' ? false : true
|
||||
}).then((result)=>{
|
||||
if(result){
|
||||
this.props.showNotification(type == 'save' ? `案例保存成功!`: `提交成功!`);
|
||||
this.props.history.push(type == 'save' ? `/moop_cases/${result.data.id}` : `/moop_cases/${result.data.id}/publish_success`);
|
||||
}
|
||||
}).catch((error)=>{
|
||||
console.log(error);
|
||||
})
|
||||
}else{
|
||||
axios.post((url),{
|
||||
title:values.caseTitle,
|
||||
author_name:values.userName,
|
||||
author_school_name:values.userUnit,
|
||||
content:values.description,
|
||||
attachment_ids:this.state.filesID,
|
||||
tag_ids:this.state.casesTags,
|
||||
cover_id:this.state.coverID,
|
||||
publish:type == 'save' ? false : true
|
||||
}).then((result)=>{
|
||||
if(result){
|
||||
this.props.showNotification(type == 'save' ? `案例保存成功!`: `提交成功!`);
|
||||
this.props.history.push(type == 'save' ? `/moop_cases/${result.data.id}` : `/moop_cases/${result.data.id}/publish_success`);
|
||||
}
|
||||
}).catch((error)=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 选择标签
|
||||
changeType=(type)=>{
|
||||
// console.log(this.state.casesTags);
|
||||
|
||||
let tags = [];
|
||||
|
||||
if(this.state.casesTags.indexOf(type) > -1){
|
||||
tags = this.state.casesTags.filter(item => item != type);
|
||||
}else{
|
||||
tags = this.state.casesTags.concat(type);
|
||||
}
|
||||
const tagUniqed = _.uniq(tags);
|
||||
this.setState({
|
||||
casesTags: tagUniqed,
|
||||
checkTag:tags.length > 0 ? false : true
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
let { caseID } = this.props.match.params;
|
||||
let { CaseDetail } = this.props;
|
||||
let { casesTags , contentFileList , imageUrl , checkTag , checkFile,library_tags } = this.state;
|
||||
const {getFieldDecorator} = this.props.form;
|
||||
|
||||
|
||||
// 上传附件点击事件
|
||||
const uploadProps = {
|
||||
width: 600,
|
||||
multiple: true,
|
||||
fileList:contentFileList,
|
||||
action: `${getUploadActionUrl()}`,
|
||||
onChange: this.handleContentUploadChange,
|
||||
onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'),
|
||||
beforeUpload: (file) => {
|
||||
const isLt150M = file.size / 1024 / 1024 < 150;
|
||||
if (!isLt150M) {
|
||||
//this.props.showNotification('文件大小必须小于150MB!');
|
||||
this.props.define({
|
||||
title:'提示',
|
||||
content:"该文件无法上传。超过文件大小限制(150MB),建议上传到百度云等其它共享工具里,然后再txt文档里给出链接以及共享密码并上传"
|
||||
})
|
||||
return isLt150M;
|
||||
}
|
||||
}
|
||||
};
|
||||
// 上传封面图-html
|
||||
const uploadButton = (
|
||||
<div>
|
||||
<Icon className='font-36 color-grey-c' type={this.state.loading ? 'loading' : 'plus'} />
|
||||
</div>
|
||||
);
|
||||
// 上传封面图点击事件
|
||||
const uploadCover = {
|
||||
listType:"picture-card",
|
||||
className:"avatar-uploader",
|
||||
showUploadList:false,
|
||||
action:`${getUploadActionUrl()}`,
|
||||
onChange:this.handleChange,
|
||||
}
|
||||
// console.log('111');
|
||||
// console.log(!caseID || (CaseDetail && CaseDetail.status == "pending"));
|
||||
return(
|
||||
<div className="educontent mt10 mb50">
|
||||
<style>
|
||||
{
|
||||
`
|
||||
.newCases .ant-col.ant-form-item-label{
|
||||
float:left;
|
||||
margin-right:20px;
|
||||
height:35px;
|
||||
line-height:35px;
|
||||
}
|
||||
|
||||
.newCaseUpload{
|
||||
width: 100%;
|
||||
background: #F2F9FF;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: -webkit-flex;
|
||||
text-align: center;
|
||||
height: 120px;
|
||||
border-radius: 4px;
|
||||
border: 1px dashed #4cacff;
|
||||
}
|
||||
.newCases .ant-form-item{
|
||||
margin-bottom:20px!important ;
|
||||
}
|
||||
.newCases .ant-col.ant-form-item-control-wrapper{
|
||||
position:relative;
|
||||
}
|
||||
.newCases .ant-form-explain{
|
||||
position:absolute;
|
||||
bottom:-18px;
|
||||
left:76px;
|
||||
padding-left: 7px;
|
||||
}
|
||||
.newCases .resetLeft .ant-form-explain{
|
||||
left:0px;
|
||||
}
|
||||
.newCases .resetBottom .ant-form-explain{
|
||||
bottom:2px;
|
||||
}
|
||||
`
|
||||
}
|
||||
</style>
|
||||
<p className="mt10 mb20 clearfix lineh-20">
|
||||
<a href="/moop_cases" className="color-grey-9">教学案例</a> > <span className="color-grey-3">{ caseID ? "编辑" : "新建" }</span>
|
||||
</p>
|
||||
<p class="lineh-25 font-22 mb20">上传教学案例</p>
|
||||
<Form onSubmit={this.handleSubmit} className={"newCases"}>
|
||||
<div className="padding30 edu-back-white">
|
||||
<Form.Item label="标题">
|
||||
{getFieldDecorator('caseTitle', {
|
||||
rules: [{required: true, message: "案例标题不能为空"}],
|
||||
})(
|
||||
<Input placeholder="例如:软件工程教学案例" className="greyInput winput-300-35 mr20 fl"/>
|
||||
)}
|
||||
<span className="color-grey-c font-12 fl">简明扼要介绍文档/视频所包含的主要的内容</span>
|
||||
</Form.Item>
|
||||
<div className="clearfix">
|
||||
<Form.Item label="作者" className="fl with22">
|
||||
{getFieldDecorator('userName', {
|
||||
rules: [{required: true, message: "请输入作者姓名"}],
|
||||
})(
|
||||
<Input placeholder="请输入姓名" className="greyInput winput-120-35 mr20 fl winput150"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item className="fl resetLeft">
|
||||
{getFieldDecorator('userUnit', {
|
||||
rules: [{required: true, message: "请输入作者单位名称"}],
|
||||
})(
|
||||
<Input placeholder="请输入作者单位名称" className="greyInput winput-300-35 mr20 fl"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div className={checkTag==true ? "clearfix mb20 pr has-error" : "clearfix mb20"} id="tagFormItem">
|
||||
<span className="upload_Title must">标签</span>
|
||||
<ul className="fl libraries_tab">
|
||||
{library_tags&&library_tags.map((item,key)=>{
|
||||
return(
|
||||
<li key={key} className={ casesTags.indexOf(item.id) > -1 ? "active" :"" } onClick={()=>this.changeType(item.id)}>{item.name}</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
{
|
||||
checkTag && <div class="ant-form-explain">请选择标签</div>
|
||||
}
|
||||
</div>
|
||||
<Form.Item label="描述" className="resetBottom" style={{marginBottom:"0px"}}>
|
||||
{getFieldDecorator('description', {
|
||||
rules: [{
|
||||
required: true, message: '请输入描述内容'
|
||||
}],
|
||||
})(
|
||||
<TPMMDEditor ref={this.DescMdRef} placeholder="请添加描述" mdID={'caseContentMD'} refreshTimeout={1500}
|
||||
watch={true} className="caseMessageMD" initValue={CaseDetail && CaseDetail.content}></TPMMDEditor>
|
||||
)}
|
||||
</Form.Item>
|
||||
<div className={checkFile == true ? "clearfix mb20 pr has-error" : "clearfix mb20"} id="fileFormItem" style={{marginLeft:"76px"}}>
|
||||
<Dragger {...uploadProps} className="librariesField upload_1">
|
||||
<p className="ant-upload-text color-blue font-18 mb20">上传附件</p>
|
||||
<p className="ant-upload-text color-grey-c">从我的电脑选择要上传的文档:按住CTRL可以上传多份文档。单个文件最大限制:150MB</p>
|
||||
</Dragger>
|
||||
{
|
||||
checkFile == true && <div style={{left:"0px",bottom:"-21px"}} class="ant-form-explain">请先上传附件</div>
|
||||
}
|
||||
</div>
|
||||
<p className="lineh-25 mt20 mb10 clearfix">
|
||||
<span className="upload_Title" style={{marginRight:"12px"}}>封面图</span><span class="color-grey-c fl lineh-35">(上传尺寸:120*90 px)</span>
|
||||
</p>
|
||||
<div style={{marginLeft:"76px"}} className="uploadImage">
|
||||
<Upload {...uploadCover}>
|
||||
{ imageUrl ?
|
||||
<Tooltip title="重新上传">
|
||||
<img src={imageUrl} alt="avatar" style={{ width: '100%' }} />
|
||||
</Tooltip>
|
||||
:
|
||||
<Tooltip title="上传图片">
|
||||
{uploadButton}
|
||||
</Tooltip>
|
||||
}
|
||||
</Upload>
|
||||
</div>
|
||||
</div>
|
||||
<div className="padding30 bor-top-greyE edu-back-white">
|
||||
<li className="lineh-25 color-grey-6 font-18 mb20">审核说明</li>
|
||||
<ul className="font-16">
|
||||
<li>平台管理员将对每天新上传的文档进行审核,审核通过的文档将公开显示,否则将私有化或移除</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="padding30 bor-top-greyE edu-back-white">
|
||||
<li className="lineh-25 color-grey-6 font-18 mb20">温馨提示</li>
|
||||
<ul className="font-16 lineh-30">
|
||||
<li>1.请勿上传已设置加密口令的文档资源;</li>
|
||||
<li>2.可以上传符合教学案例标准的文档资料,如
|
||||
<a className="color-blue" target="_blank" href="https://www.educoder.net/courses/1309/boards/5909/messages/34799">案例入库标准</a>、
|
||||
<a target="_blank" className="color-blue" href="https://www.educoder.net/courses/1309/boards/5909/messages/34798">案例使用说明书</a>以及其他资料等,上传支持的文件最大容量:100MB;</li>
|
||||
<li>3.请确保上传内容无侵权或违反国家关于互联网政策的不良行为;</li>
|
||||
<li>4.请使用Chrome,Firefox,Safari,IE11(及以上版本)浏览器;</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Form.Item>
|
||||
<div className="clearfix mt30 mb30">
|
||||
{
|
||||
(!caseID || (CaseDetail && CaseDetail.status == "pending" || CaseDetail && CaseDetail.status == "refused")) ? <Button type="primary" onClick={()=>this.handleSubmit("submit")} className="defalutSubmitbtn fl mr20">申请发布</Button> : ""
|
||||
}
|
||||
<a className="defalutCancelbtn fl" onClick={()=>this.handleSubmit("save")}>保存</ a>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
const WrappedCoursesNewApp = Form.create({name: 'CaseNew'})(CaseNew);
|
||||
export default WrappedCoursesNewApp;
|
|
@ -1,37 +0,0 @@
|
|||
import React,{ Component } from "react";
|
||||
import './css/moopCases.css'
|
||||
import '../courses/css/Courses.css'
|
||||
|
||||
class CaseTags extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
render(){
|
||||
let { tags } = this.props;
|
||||
return(
|
||||
<React.Fragment>
|
||||
{
|
||||
tags && tags.map((item,key)=>{
|
||||
return(
|
||||
<React.Fragment>
|
||||
{
|
||||
item.name == "获奖案例" ?
|
||||
<span key={key} className="edu-filter-btn fl cdefault edu-activity-red ml10">{item.name}</span>
|
||||
:
|
||||
item.name == "入库案例" ?
|
||||
<span key={key} className="edu-filter-btn fl cdefault edu-activity-blue ml10">{item.name}</span>
|
||||
:item.name =='企业案例'?
|
||||
<span key={key} className="edu-filter-btn fl cdefault edu-activity-orange-sub ml10">{item.name}</span>
|
||||
: <span key={key} className="edu-filter-btn fl cdefault edu-activity-36c53c-sub ml10">{item.name}</span>
|
||||
}
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
}
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CaseTags;
|
|
@ -1,28 +0,0 @@
|
|||
import React,{ Component } from "react";
|
||||
import './css/moopCases.css'
|
||||
import '../courses/css/Courses.css'
|
||||
import { getImageUrl } from 'educoder';
|
||||
import success from '../../images/moop_cases/success.png'
|
||||
|
||||
class Success extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
render(){
|
||||
return(
|
||||
<div className="educontent edu-back-white mt20 successPage">
|
||||
<div>
|
||||
<img src={success} width="100" className="mb30" />
|
||||
<p className="lineh-30 ed-txt-center font-24 color-grey-3 font-bd">恭喜!</p>
|
||||
<p className="lineh-30 ed-txt-center font-24 color-grey-3 font-bd mb20">提交成功</p>
|
||||
<p className="lineh-30 ed-txt-center font-16 color-grey-9 font-bd mb20">平台正在审核您的申请,审核结果将以平台消息的形式通知您</p>
|
||||
<li className="inline">
|
||||
<a href={`/moop_cases/${this.props.match.params.caseID}`} className="white-btn edu-blueline-btn changebtn mr20 fl">查看已上传文档</a>
|
||||
<a href="/moop_cases/new" className="white-btn edu-blueback-btn changebtn fl">继续上传</a>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default Success;
|
|
@ -1,178 +0,0 @@
|
|||
.winput-300-35{
|
||||
width: 300px;
|
||||
height: 35px;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.library_nav li {
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
margin-right: 30px;
|
||||
position: relative;
|
||||
color: #05101A;
|
||||
height: 40px;
|
||||
line-height: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.library_nav li.active a, .library_nav li:hover a{
|
||||
color: #4cacff!important;
|
||||
}
|
||||
.library_list {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.library_list_item:hover {
|
||||
box-shadow: 0px 4px 8px rgba(158,158,158,0.16);
|
||||
}
|
||||
.library_list_item {
|
||||
background: #fff;
|
||||
padding: 20px 30px;
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
}
|
||||
.library_list_item .library_l_name {
|
||||
max-width: 600px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.edu-activity-red {
|
||||
background-color: #FC2B6A;
|
||||
color: #fff!important;
|
||||
cursor: pointer;
|
||||
border: 1px solid #FC2B6A;
|
||||
line-height: 17px;
|
||||
}
|
||||
.edu-activity-green {
|
||||
background-color: green;
|
||||
color: #fff!important;
|
||||
cursor: pointer;
|
||||
border: 1px solid green;
|
||||
line-height: 17px;
|
||||
}
|
||||
.edu-activity-orange {
|
||||
background-color: #ff6800;
|
||||
color: #fff!important;
|
||||
cursor: pointer;
|
||||
border: 1px solid #ff6800;
|
||||
line-height: 17px;
|
||||
}
|
||||
.edu-activity-blue {
|
||||
background-color: #4CACFF;
|
||||
color: #fff!important;
|
||||
cursor: pointer;
|
||||
border: 1px solid #4CACFF;
|
||||
line-height: 17px;
|
||||
}
|
||||
.edu-activity-orange-sub {
|
||||
background-color: #FF781B;
|
||||
color: #fff!important;
|
||||
cursor: pointer;
|
||||
border: 1px solid #ff6800;
|
||||
line-height: 17px;
|
||||
}
|
||||
.edu-activity-36c53c-sub {
|
||||
background-color: #36c53c;
|
||||
color: #fff!important;
|
||||
cursor: pointer;
|
||||
border: 1px solid #36c53c;
|
||||
line-height: 17px;
|
||||
}
|
||||
.pointsBtn {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
background-color: #4cacff;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 2px 0;
|
||||
cursor: pointer;
|
||||
line-height: 22px;
|
||||
padding-top: 12px;
|
||||
}
|
||||
.pointedBtn{
|
||||
background: #BCD1E3;
|
||||
cursor: default
|
||||
}
|
||||
.pointsBtn span{
|
||||
display: block;
|
||||
}
|
||||
.upload_Title {
|
||||
position: relative;
|
||||
margin-right: 20px;
|
||||
float: left;
|
||||
line-height: 35px;
|
||||
font-size: 16px;
|
||||
/*width: 56px;*/
|
||||
color:rgba(0, 0, 0, 0.85);
|
||||
text-align: center
|
||||
}
|
||||
.upload_Title.must:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
color: #f5222d;
|
||||
font-size: 14px;
|
||||
font-family: SimSun, sans-serif;
|
||||
line-height: 1;
|
||||
content: '*';
|
||||
}
|
||||
.upload_Title:after{
|
||||
content: ':';
|
||||
position: relative;
|
||||
top: -0.5px;
|
||||
margin: 0 8px 0 2px;
|
||||
}
|
||||
.libraries_tab li {
|
||||
width: 120px;
|
||||
height: 35px;
|
||||
line-height: 33px;
|
||||
border-radius: 18px;
|
||||
border: 1px solid #4C98FF;
|
||||
color: #4C98FF;
|
||||
cursor: pointer;
|
||||
margin-right: 30px;
|
||||
float: left;
|
||||
text-align: center;
|
||||
}
|
||||
.libraries_tab li.active {
|
||||
background: #4C98FF;
|
||||
color: #fff;
|
||||
}
|
||||
.librariesField .ant-upload{
|
||||
width: 100%;
|
||||
background: #F2F9FF;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: -webkit-flex;
|
||||
text-align: center;
|
||||
height: 120px!important;
|
||||
border-radius: 4px;
|
||||
border: 1px dashed #4cacff!important;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
}
|
||||
.librariesField .ant-upload.ant-upload-drag{
|
||||
border:none!important;
|
||||
}
|
||||
.uploadImage .ant-upload.ant-upload-select-picture-card{
|
||||
width:120px;
|
||||
height: 90px;
|
||||
}
|
||||
.uploadImage .ant-upload.ant-upload-select-picture-card > .ant-upload{
|
||||
padding:0px!important;
|
||||
}
|
||||
.successPage {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: -webkit-flex;
|
||||
height: 570px;
|
||||
text-align: center;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.changebtn {
|
||||
width:166px;
|
||||
font-size: 16px;
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
import React,{ Component } from "react";
|
||||
import './css/moopCases.css'
|
||||
import '../courses/css/Courses.css'
|
||||
|
||||
import { SnackbarHOC } from 'educoder';
|
||||
|
||||
import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
|
||||
import { CNotificationHOC } from '../courses/common/CNotificationHOC'
|
||||
|
||||
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
|
||||
import Loading from '../../Loading';
|
||||
import Loadable from 'react-loadable';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
const CaseList = Loadable({
|
||||
loader: () => import('./CaseList'),
|
||||
loading:Loading,
|
||||
})
|
||||
const CaseDetail = Loadable({
|
||||
loader: () => import('./CaseDetail'),
|
||||
loading:Loading,
|
||||
})
|
||||
const CaseNew = Loadable({
|
||||
loader: () => import('./CaseNew'),
|
||||
loading:Loading,
|
||||
})
|
||||
const CaseSuccess = Loadable({
|
||||
loader: () => import('./Success'),
|
||||
loading:Loading,
|
||||
})
|
||||
|
||||
|
||||
|
||||
class Index extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state={
|
||||
praise_count:0,
|
||||
CaseDetail:undefined,
|
||||
cover:undefined,
|
||||
creator:undefined,
|
||||
operation:undefined,
|
||||
tags:undefined,
|
||||
attachments:undefined,
|
||||
user_praised:true,
|
||||
}
|
||||
}
|
||||
componentDidMount(){
|
||||
|
||||
}
|
||||
// 获取案例详情
|
||||
getDetail = (caseID) =>{
|
||||
let url=`/libraries/${caseID}.json`
|
||||
axios.get(url).then((result)=>{
|
||||
if(result){
|
||||
this.setState({
|
||||
CaseDetail:result.data,
|
||||
praise_count:result.data.praise_count,
|
||||
cover:result.data.cover,
|
||||
creator:result.data.creator,
|
||||
operation:result.data.operation,
|
||||
user_praised:result.data.operation.user_praised,
|
||||
tags:result.data.tags,
|
||||
attachments:result.data.attachments
|
||||
})
|
||||
window.document.title = result.data.title;
|
||||
}
|
||||
}).catch((error)=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
// 点赞
|
||||
praisePoint=(caseID)=>{
|
||||
let { praise_count }=this.state;
|
||||
let url =`/praise_tread/like.json`;
|
||||
axios.post(url,{
|
||||
object_id:caseID,
|
||||
object_type:"library"
|
||||
}).then((result)=>{
|
||||
if(result){
|
||||
this.setState({
|
||||
praise_count: parseInt(praise_count)+1,
|
||||
user_praised:true
|
||||
})
|
||||
}
|
||||
}).catch((error)=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
return(
|
||||
<div className="newMain">
|
||||
<Switch {...this.props}>
|
||||
|
||||
<Route exact path="/moop_cases"
|
||||
render={
|
||||
(props) => (<CaseList {...this.props} {...props} {...this.state} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
<Route exact path="/moop_cases/new"
|
||||
render={
|
||||
(props) => (<CaseNew {...this.props} {...props} {...this.state} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
<Route exact path="/moop_cases/:caseID"
|
||||
render={
|
||||
(props) => (<CaseDetail {...this.props} {...props} {...this.state} getDetail={this.getDetail} praisePoint ={this.praisePoint}/>)
|
||||
}
|
||||
></Route>
|
||||
|
||||
|
||||
<Route exact path="/moop_cases/:caseID/edit"
|
||||
render={
|
||||
(props) => (<CaseNew {...this.props} {...props} {...this.state} getDetail={this.getDetail} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
<Route exact path="/moop_cases/:caseID/publish_success"
|
||||
render={
|
||||
(props) => (<CaseSuccess {...this.props} {...props} {...this.state} getDetail={this.getDetail} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(Index) ));
|
Loading…
Reference in New Issue