From f7fa5291c646f5a494d3d87c6eb1ae0331f20524 Mon Sep 17 00:00:00 2001 From: caishi <1149225589@qq.com> Date: Wed, 14 Oct 2020 18:15:36 +0800 Subject: [PATCH] =?UTF-8?q?exchange-=E6=9D=BF=E5=9D=97=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 11 + src/AppConfig.js | 4 +- src/common/FileList.js | 32 + src/common/MDEditor.js | 343 +++++++++ src/common/mdEditor.css | 269 +++++++ src/exchange/Comments/CommentsItem.js | 40 ++ src/exchange/Comments/CommentsItemImg.js | 17 + src/exchange/Comments/CommentsSend.js | 72 ++ src/exchange/Comments/comment.css | 0 src/exchange/CustomComponent/Index.js | 17 + src/exchange/CustomComponent/custom.css | 34 + src/exchange/Empty.js | 15 + src/exchange/ExchangeIndex.js | 164 +++++ src/exchange/ExchangeItem.js | 198 ++++++ src/exchange/ExchangeRight.js | 68 ++ src/exchange/ExchangeRightSearch.js | 64 ++ src/exchange/InfoComponent/Index.js | 19 + src/exchange/Manage/AddModeratorModal.js | 171 +++++ src/exchange/Manage/CheckPublic.js | 54 ++ src/exchange/Manage/ItemLeft.js | 40 ++ src/exchange/Manage/ModeratorNav.js | 87 +++ src/exchange/Manage/PassItem.js | 35 + src/exchange/Manage/PreApplyPlate.js | 122 ++++ src/exchange/Manage/PreCreate.js | 87 +++ src/exchange/Manage/PreModerator.js | 77 ++ src/exchange/Manage/PrePlateManage.js | 285 ++++++++ src/exchange/Manage/SubCheckItem.js | 146 ++++ src/exchange/Manage/SubCheckReplyItem.js | 148 ++++ src/exchange/Manage/SubSendItem.js | 174 +++++ src/exchange/Manage/manage.css | 134 ++++ src/exchange/MenuComponent/Menu.css | 18 + src/exchange/MenuComponent/Menu.js | 51 ++ src/exchange/MyExchange/Index.js | 115 +++ src/exchange/MyExchange/MyEnshrine.js | 17 + src/exchange/MyExchange/MyInteresting.js | 101 +++ src/exchange/MyExchange/MyTopic.js | 59 ++ src/exchange/MyExchange/MyTopicItem.js | 239 +++++++ src/exchange/MyExchange/myExchange.css | 56 ++ src/exchange/NavComponent/Index.js | 28 + src/exchange/NavComponent/nav.css | 13 + src/exchange/Plate/All.js | 36 + src/exchange/Plate/Index.js | 264 +++++++ src/exchange/Plate/PlateRight.js | 93 +++ src/exchange/Plate/plate.css | 45 ++ src/exchange/Post/CommentsIndex.js | 155 +++++ src/exchange/Post/ImageUpload.js | 128 ++++ src/exchange/Post/Index.js | 248 +++++++ src/exchange/Post/MemoNew.css | 128 ++++ src/exchange/Post/MemoNew.js | 811 ++++++++++++++++++++++ src/exchange/Post/New.js | 277 ++++++++ src/exchange/Post/Parse.js | 33 + src/exchange/Post/post.css | 157 +++++ src/exchange/SearchInfoComponent/Index.js | 16 + src/exchange/TagComponent/Index.js | 18 + src/exchange/exchange.css | 289 ++++++++ src/exchange/images/box1.png | Bin 0 -> 3503 bytes src/exchange/images/box2.png | Bin 0 -> 6245 bytes src/exchange/images/box3.png | Bin 0 -> 6119 bytes src/exchange/images/box4.png | Bin 0 -> 1824 bytes src/exchange/images/box5.png | Bin 0 -> 5217 bytes src/exchange/images/box6.png | Bin 0 -> 6265 bytes src/exchange/images/more.png | Bin 0 -> 121 bytes src/exchange/images/nodata.png | Bin 0 -> 77734 bytes src/exchange/index.js | 91 +++ src/forums/New.jsx | 1 - 65 files changed, 6411 insertions(+), 3 deletions(-) create mode 100644 src/common/FileList.js create mode 100644 src/common/MDEditor.js create mode 100644 src/common/mdEditor.css create mode 100644 src/exchange/Comments/CommentsItem.js create mode 100644 src/exchange/Comments/CommentsItemImg.js create mode 100644 src/exchange/Comments/CommentsSend.js create mode 100644 src/exchange/Comments/comment.css create mode 100644 src/exchange/CustomComponent/Index.js create mode 100644 src/exchange/CustomComponent/custom.css create mode 100644 src/exchange/Empty.js create mode 100644 src/exchange/ExchangeIndex.js create mode 100644 src/exchange/ExchangeItem.js create mode 100644 src/exchange/ExchangeRight.js create mode 100644 src/exchange/ExchangeRightSearch.js create mode 100644 src/exchange/InfoComponent/Index.js create mode 100644 src/exchange/Manage/AddModeratorModal.js create mode 100644 src/exchange/Manage/CheckPublic.js create mode 100644 src/exchange/Manage/ItemLeft.js create mode 100644 src/exchange/Manage/ModeratorNav.js create mode 100644 src/exchange/Manage/PassItem.js create mode 100644 src/exchange/Manage/PreApplyPlate.js create mode 100644 src/exchange/Manage/PreCreate.js create mode 100644 src/exchange/Manage/PreModerator.js create mode 100644 src/exchange/Manage/PrePlateManage.js create mode 100644 src/exchange/Manage/SubCheckItem.js create mode 100644 src/exchange/Manage/SubCheckReplyItem.js create mode 100644 src/exchange/Manage/SubSendItem.js create mode 100644 src/exchange/Manage/manage.css create mode 100644 src/exchange/MenuComponent/Menu.css create mode 100644 src/exchange/MenuComponent/Menu.js create mode 100644 src/exchange/MyExchange/Index.js create mode 100644 src/exchange/MyExchange/MyEnshrine.js create mode 100644 src/exchange/MyExchange/MyInteresting.js create mode 100644 src/exchange/MyExchange/MyTopic.js create mode 100644 src/exchange/MyExchange/MyTopicItem.js create mode 100644 src/exchange/MyExchange/myExchange.css create mode 100644 src/exchange/NavComponent/Index.js create mode 100644 src/exchange/NavComponent/nav.css create mode 100644 src/exchange/Plate/All.js create mode 100644 src/exchange/Plate/Index.js create mode 100644 src/exchange/Plate/PlateRight.js create mode 100644 src/exchange/Plate/plate.css create mode 100644 src/exchange/Post/CommentsIndex.js create mode 100644 src/exchange/Post/ImageUpload.js create mode 100644 src/exchange/Post/Index.js create mode 100644 src/exchange/Post/MemoNew.css create mode 100644 src/exchange/Post/MemoNew.js create mode 100644 src/exchange/Post/New.js create mode 100644 src/exchange/Post/Parse.js create mode 100644 src/exchange/Post/post.css create mode 100644 src/exchange/SearchInfoComponent/Index.js create mode 100644 src/exchange/TagComponent/Index.js create mode 100644 src/exchange/exchange.css create mode 100644 src/exchange/images/box1.png create mode 100644 src/exchange/images/box2.png create mode 100644 src/exchange/images/box3.png create mode 100644 src/exchange/images/box4.png create mode 100644 src/exchange/images/box5.png create mode 100644 src/exchange/images/box6.png create mode 100644 src/exchange/images/more.png create mode 100644 src/exchange/images/nodata.png create mode 100644 src/exchange/index.js diff --git a/src/App.js b/src/App.js index aed2f9a3..4d953e6b 100644 --- a/src/App.js +++ b/src/App.js @@ -61,6 +61,10 @@ const Shixunnopage = Loadable({ loader: () => import('./modules/404/Shixunnopage'), loading: Loading, }) +const ExchangeForums = Loadable({ + loader: () => import("./exchange/index"), + loading: Loading, +}); // 新版论坛交流 const Forums = Loadable({ loader: () => import("./forums/Index"), @@ -245,6 +249,13 @@ class App extends Component { )} > + {/* 论坛交流板块管理 */} + ( + + )} + > {/* 问吧、论坛交流 */} { + return( +
  • + + {item.filename} + ({bytesToSize(`${item.filesize}`)}) +
  • + ) + }) + return( + + ) + } +} + +export default FileList; \ No newline at end of file diff --git a/src/common/MDEditor.js b/src/common/MDEditor.js new file mode 100644 index 00000000..1b57d79b --- /dev/null +++ b/src/common/MDEditor.js @@ -0,0 +1,343 @@ +import React, {Component} from 'react'; + + + +// import "antd/dist/antd.css"; + +import { getUrl } from 'educoder'; + + +import './mdEditor.css'; +require('codemirror/lib/codemirror.css'); + + +let path = '/editormd/lib/' + path = getUrl("/editormd/lib/") +const $ = window.$; + +// 保存数据 +function md_add_data(k,mdu,d){ + window.sessionStorage.setItem(k+mdu,d); +} + +// 清空保存的数据 +function md_clear_data(k,mdu,id){ + window.sessionStorage.removeItem(k+mdu); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + if(k == 'content'){ + $(id2).html(" "); + }else{ + $(id1).html(" "); + } +} +window.md_clear_data = md_clear_data +// editor 存在了jquery对象上,应用不需要自己写md_rec_data方法了 +function md_rec_data(k, mdu, id) { + if (window.sessionStorage.getItem(k + mdu) !== null) { + var editor = $("#e_tips_" + id).data('editor'); + editor.setValue(window.sessionStorage.getItem(k + mdu)); + // debugger; + // /shixuns/b5hjq9zm/challenges/3977/tab=3 setValue可能导致editor样式问题 + md_clear_data(k, mdu, id); + } +} +window.md_rec_data = md_rec_data; + +function md_elocalStorage(editor,mdu,id){ + if (window.sessionStorage){ + var oc = window.sessionStorage.getItem('content'+mdu); + if(oc !== null && oc != editor.getValue()){ + console.log("#e_tips_"+id) + $("#e_tips_"+id).data('editor', editor); + var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; + $("#e_tips_"+id).html(h); + } + setInterval(function() { + var d = new Date(); + var h = d.getHours(); + var m = d.getMinutes(); + var s = d.getSeconds(); + h = h < 10 ? '0' + h : h; + m = m < 10 ? '0' + m : m; + s = s < 10 ? '0' + s : s; + if(editor.getValue().trim() != ""){ + md_add_data("content",mdu,editor.getValue()); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + + var textStart = " 数据已于 " + var text = textStart + h + ':' + m + ':' + s +" 保存 "; + // 占位符 + var oldHtml = $(id2).html(); + if (oldHtml && oldHtml != ' ' && oldHtml.startsWith(textStart) == false) { + $(id2).html( oldHtml.split(' (')[0] + ` (${text})`); + } else { + $(id2).html(text); + } + // $(id2).html(""); + } + },10000); + + }else{ + $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); + } +} + + +function create_editorMD(id, width, high, placeholder, imageUrl, callback, initValue, + onchange, watch, { noStorage, showNullButton, emoji }, that) { + // 还是出现了setting只有一份,被共用的问题 + + var editorName = window.editormd(id, { + width: width, + height: high===undefined?400:high, + path: path, // "/editormd/lib/" + markdown : initValue, + + dialogLockScreen: false, + watch:watch===undefined?true:watch, + syncScrolling: "single", + tex: true, + tocm: true, + emoji: !!emoji , + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + + // mine + + toolbarIcons: function (mdEditor) { + let react_id = `react_${mdEditor.id}`; + const __that = window[react_id] + + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + const icons = ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "link", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]; + // 试卷处用到的填空题新增按钮 + if (__that.props.showNullButton) { + icons.push('nullBtton') + } + return icons + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    ", + nullBtton: "
    点击插入填空项
    ", + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onchange: onchange, + onload: function() { + let _id = this.id // 如果要使用this,这里不能使用箭头函数 + let _editorName = this; + let react_id = `react_${_editorName.id}`; + const __that = window[react_id] + + // this.previewing(); + // let _id = id; + $("#" + _id + " [type=\"latex\"]").bind("click", function () { + _editorName.cm.replaceSelection("```latex"); + _editorName.cm.replaceSelection("\n"); + _editorName.cm.replaceSelection("\n"); + _editorName.cm.replaceSelection("```"); + var __Cursor = _editorName.cm.getDoc().getCursor(); + _editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + _id + " [type=\"inline\"]").bind("click", function () { + _editorName.cm.replaceSelection("`$$$$`"); + var __Cursor = _editorName.cm.getDoc().getCursor(); + _editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3); + _editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + if (__that.props.showNullButton) { + const NULL_CH = '▁' + // const NULL_CH = '〇' + // const NULL_CH = '🈳' + + $("#" + _id + " [type=\"nullBtton\"]").bind("click", function () { + _editorName.cm.replaceSelection(NULL_CH); + // var __Cursor = _editorName.cm.getDoc().getCursor(); + // _editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + } + + if (noStorage == true) { + + } else { + md_elocalStorage(_editorName, `MDEditor__${_id}`, _id); + } + + callback && callback(_editorName) + } + }); + return editorName; +} + + +export default class MDEditor extends Component { + constructor(props) { + super(props) + this.state = { + initValue: '' + } + } + componentDidUpdate(prevProps, prevState) { + // 不能加,影响了试卷填空题 + // if (this.props.initValue != prevProps.initValue) { + // this.answers_editormd.setValue(this.props.initValue) + // } + } + + // react_mdEditor_ + componentDidMount = () => { + const { mdID, initValue, placeholder, showNullButton} = this.props; + + let _id = `mdEditor_${mdID}` + this.contentChanged = false; + const _placeholder = placeholder || ""; + // amp; + // 编辑时要传memoId + const imageUrl = `/upload_with_markdown?container_id=${mdID || ''}&container_type=Memo`; + // 创建editorMd + let react_id = `react_${_id}`; + // 将实例存到了window + window[react_id] = this + const answers_editormd = create_editorMD(_id, '100%', this.props.height, _placeholder, imageUrl, (_editorName) => { + const __editorName = _editorName; + react_id = `react_${__editorName.id}`; + const that = window[react_id] + + // 一个延迟的recreate或resize,不加这段代码,md初始化可能会出现样式问题 + setTimeout(() => { + if (that.props.needRecreate == true) { + __editorName.recreate() // 注意 必须在setValue之前触发,不然会清空 + } else { + __editorName.resize() + } + console.log('timeout', __editorName.id) + __editorName.cm && __editorName.cm.refresh() + }, that.props.refreshTimeout || 500) + if (this.props.noSetValueOnInit) { + that.onEditorChange() + } else { + if (that.props.initValue != undefined && that.props.initValue != '') { + __editorName.setValue(that.props.initValue) + } + if (that.state.initValue) { + __editorName.setValue(that.state.initValue) + } + } + + __editorName.cm.on("change", (_cm, changeObj) => { + that.contentChanged = true; + if (that.state.showError) { + that.setState({showError: false}) + } + that.onEditorChange() + }) + that.props.onCMBlur && __editorName.cm.on('blur', () => { + that.props.onCMBlur() + }) + that.props.onCMBeforeChange && __editorName.cm.on('beforeChange', (cm,change) => { + that.props.onCMBeforeChange(cm,change) + }) + that.answers_editormd = __editorName; + // 这里应该可以去掉了,方便调试加的 + window[__editorName.id+'_'] = __editorName; + }, initValue, this.onEditorChange,this.props.watch, { + noStorage: this.props.noStorage, + showNullButton: this.props.showNullButton, + emoji: this.props.emoji + }, this); + + } + // 用在form里时,validate失败时出现一个红色边框 + showError = () => { + this.setState({showError: true}) + } + onEditorChange = () => { + if (!this.answers_editormd) return; + const val = this.answers_editormd.getValue(); + //console.log('onEditorChange', this.props.id, val) + try { + this.props.onChange && this.props.onChange(val) + } catch(e) { + // http://localhost:3007/courses/1309/common_homeworks/6566/setting + // 从这个页面,跳转到编辑页面,再在编辑页面点击返回的时候,这里会报错 + console.error('出错') + console.error(e) + } + } + resize = () => { + if (!this.answers_editormd) { // 还未初始化 + return; + } + this.answers_editormd.resize() + this.answers_editormd.cm && this.answers_editormd.cm.refresh() + this.answers_editormd.cm.focus() + } + + getValue = () => { + try { + return this.answers_editormd.getValue() + } catch (e) { + return '' + } + } + setValue = (val) => { + try { + this.answers_editormd.setValue(val) + } catch (e) { + // TODO 这里多实例的时候,前一个实例的state会被后面这个覆盖 参考NewWork.js http://localhost:3007/courses/1309/homework/9300/edit/1 + // 未初始化 + this.setState({ initValue: val }) + } + } + + render() { + + let { + showError + } = this.state; + let { mdID, className, noStorage, imageExpand } = this.props; + let _style = {} + if (showError) { + _style.border = '1px solid red' + } + return ( + +
    + {/* padding10-20 */} +
    + +
    +
    +
    +
    + { + noStorage == true ? '' : +
    +

     

    + {/* {noStorage == true ? ' ' :

     

    } */} +
    + } +
    + ) + } +} + + diff --git a/src/common/mdEditor.css b/src/common/mdEditor.css new file mode 100644 index 00000000..37a65ef9 --- /dev/null +++ b/src/common/mdEditor.css @@ -0,0 +1,269 @@ +.CodeMirror-scroll { + overflow: auto !important; + margin-bottom: -30px; + margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; + position: relative; +} +a.white-btn.orange-btn:hover { + border: 1px solid #F06200; + color: #FFF !important; +} +.flex1 a.white-btn.orange-btn:hover { + border: 1px solid #F06200; + color: #FFF !important; +} + +/*.challenge_nav li a{*/ + /*color:#000 !important;*/ +/*}*/ + +.questionli{ + width: 95%; + margin-left: 37px; +} +#directory_file{ + height:200px; + overflow-y:auto; + background:#f5f5f5; + padding:10px; +} +.directory_filepath{ + width:120px; + text-align:left; +} + +a{ + text-decoration: none; + color: #05101a; +} +.repository_url_tippostion{ + position: absolute; + left: 22%; + width: 500px; + top: 100%; +} + +.top-black-trangleft { + display: block; + border-width: 8px; + position: absolute; + top: -16px; + /* right: 4px; */ + border-style: dashed solid dashed dashed; + border-color: transparent transparent rgba(5,16,26,0.6) transparent; + font-size: 0; + line-height: 0; +} + +#exercisememoMD .CodeMirror { + margin-top: 31px !important; + height: 370px !important; + /*width: 579px !important;*/ +} + +#exercisememoMD .editormd-preview { + top: 40px !important; + height: 370px !important; + width: 578px !important; +} +#exercisememoMD{ + /*height: 700px !important;*/ +} +#questioMD{ + /*width: 95% !important;*/ + height: 417px !important; + margin-left: 0% !important; +} + + +#questioMD .CodeMirror { + /*width: 550.5px !important;*/ + margin-top: 31px !important; + height: 374px !important; +} + +#questioMD .editormd-preview { + top: 40px !important; + height: 375px !important; + width: 550px !important; +} + +#newquestioMD .CodeMirror { + /*width: 549px !important;*/ + margin-top: 31px !important; + height: 364px !important; +} + +#newquestioMD .editormd-preview { + top: 40px !important; + height: 364px !important; + width: 578px !important; +} + +#challenge_choose_answer .CodeMirror { + margin-top: 31px !important; + height: 364px !important; + /*width: 578px !important;*/ +} + + +#challenge_choose_answer .editormd-preview { + top: 40px !important; + height: 364px !important; + width: 578px !important; +} + +#neweditanswer .CodeMirror { + margin-top: 31px !important; + height: 364px !important; + /*width: 549.5px !important;*/ +} + +#neweditanswer .editormd-preview { + top: 40px !important; + height: 364px !important; + width: 551px !important; +} + +#repository_url_tip { + top: 30px !important; + left: 249px !important; + width: 292px !important; +} + +#editanswers .CodeMirror{ + /*width: 548px !important;*/ + height: 358px !important; + margin-top: 30px !important; +} +#editanswers .editormd-preview{ + width: 578px !important; + height: 358px !important; + +} +#newquestioMDs .CodeMirror{ + /*width: 510px !important;*/ + height: 358px !important; + margin-top: 30px !important; +} + +#newquestioMDs .editormd-preview{ + width: 578px !important; + height: 358px !important; +} + +.choose_names{ + width: 80px; + margin-left: 20px; +} + +#answerMD .CodeMirror{ + /*width: 569px !important;*/ + height: 600px !important; + margin-top: 30px !important; +} + +#answerMD .editormd-preview{ + width: 578px !important; + height: 600px !important; +} + +#answerMD { + height: 600px !important; +} + +.textareavalue{ + width: 100%; + padding: 5px; + + box-sizing: border-box; +} +.greyInput{ + width: 107%; +} +.greyInpus{ + width: 100%; +} + +.pdr20{ + padding-right:20px; +} + +.winput-240-40s { + background-color: #F5F5F5; +} + + +.winput-240-40s:focus{ + background-color: #fff; +} +.input-100-45{ + background-color: #F5F5F5; +} +.input-100-45:focus{ + background-color: #fff; + } + +.wind100{ + width:100% !important; +} + +.color-bule-tip { + color: #5485f7 !important; +} +.martopf4{ + margin-top:-4px; +} + +.headdfgf{ + display: block; + width: 100px; + height: 30px; + line-height: 30px; + float: left; +} + +.color979797{ + color: #979797 !important; +} + +.border-left{ + width: 0; + height: 0; + border-bottom: 6px solid transparent; + border-right: 6px solid #cccbcb; + border-top: 6px solid transparent; + position: absolute; + left: 30px; + top: 12px; +} +.border-left span{ + display: block; + width: 0; + height: 0; + border-bottom: 6px solid transparent; + border-right: 6px solid #fff; + border-top: 6px solid transparent; + position: absolute; + left: 1px; + top: -6px; + z-index: 10; +} +.fillTip{ + position: absolute; + left: 36px; + top: 2px; + width: 125px; + font-size: 12px; + display: block; + padding: 5px; + border: 1px solid #eaeaea; + border-radius: 5px; + box-sizing: border-box; + height: 32px; + line-height: 20px; + font-family: "微软雅黑","宋体"; +} \ No newline at end of file diff --git a/src/exchange/Comments/CommentsItem.js b/src/exchange/Comments/CommentsItem.js new file mode 100644 index 00000000..1dd4850a --- /dev/null +++ b/src/exchange/Comments/CommentsItem.js @@ -0,0 +1,40 @@ +import React, { PureComponent } from 'react'; +import { Popconfirm } from 'antd'; +import './comment.css'; +import RenderHtml from "../../components/render-html"; + +class CommentsItem extends PureComponent{ + + cancelEvent=()=>{} + + render(){ + const { username , time , content , id , admin , deleteReplyEvent } = this.props + + // 当前用户是否是管理员或者版主,true为有权限删除评论 + const adminDelete = ( + admin && + deleteReplyEvent(id)} + onCancel={this.cancelEvent} + okText="确定" + cancelText="取消" + > + 删除 + + ) + return( + +

    + {username} + {time} + + { adminDelete } +

    + +
    + ) + } +} + +export default CommentsItem; \ No newline at end of file diff --git a/src/exchange/Comments/CommentsItemImg.js b/src/exchange/Comments/CommentsItemImg.js new file mode 100644 index 00000000..83db6ceb --- /dev/null +++ b/src/exchange/Comments/CommentsItemImg.js @@ -0,0 +1,17 @@ +import React, { PureComponent } from 'react'; +import { getImageUrl } from 'educoder'; + +import './comment.css'; + + +class CommentsItemImg extends PureComponent{ + render(){ + const { image_url } = this.props + + return( + 用户头像 + ) + } +} + +export default CommentsItemImg; \ No newline at end of file diff --git a/src/exchange/Comments/CommentsSend.js b/src/exchange/Comments/CommentsSend.js new file mode 100644 index 00000000..a0a5c713 --- /dev/null +++ b/src/exchange/Comments/CommentsSend.js @@ -0,0 +1,72 @@ +import React, { Component } from 'react'; +import MDEditor from '../../common/MDEditor'; +import { Form , Button } from "antd"; +import ItemImg from './CommentsItemImg' + +import '../exchange.css' +import axios from 'axios'; + + +class CommentsSend extends Component{ + constructor(props){ + super(props); + this.contentMdRef = React.createRef(); + + } + + // 发送评论 + handleSubmit=()=>{ + this.props.form.validateFieldsAndScroll((err, values) => { + if(!err){ + let { id , refresh } = this.props; + const url = `/memos/${id}/reply`; + axios.post(url,{ + content:values.replyContent, + parent_id:id + }).then(result=>{ + if(result){ + this.contentMdRef.current.setValue(' '); + refresh(); + } + }).catch(error=>{ + + }) + } + }) + } + + render(){ + const { getFieldDecorator } = this.props.form; + + // 唯一键 + const { unique , image_url } = this.props; + + const imgWrap = ( + image_url && + ) + return( +
    + { imgWrap } +
    + + {getFieldDecorator('replyContent', { + rules: [{ + required: true, message: '请输入评论内容', + },{ + max: 5000 , message:'最大限制5000个字符' + }], + })( + + )} + +

    + +

    +
    +
    + ) + } +} +const WrappedCommentsSendForm = Form.create({ name: 'CommentsSend' })(CommentsSend); +export default WrappedCommentsSendForm; diff --git a/src/exchange/Comments/comment.css b/src/exchange/Comments/comment.css new file mode 100644 index 00000000..e69de29b diff --git a/src/exchange/CustomComponent/Index.js b/src/exchange/CustomComponent/Index.js new file mode 100644 index 00000000..df5c0ff8 --- /dev/null +++ b/src/exchange/CustomComponent/Index.js @@ -0,0 +1,17 @@ +import React, { PureComponent } from 'react'; +import './custom.css' +class Index extends PureComponent { + + render() { + + let { img_url , name ,hrefUrl} = this.props; + return ( + + 用户头像 + {name} + + ) + } +} + +export default Index; \ No newline at end of file diff --git a/src/exchange/CustomComponent/custom.css b/src/exchange/CustomComponent/custom.css new file mode 100644 index 00000000..c9ab33df --- /dev/null +++ b/src/exchange/CustomComponent/custom.css @@ -0,0 +1,34 @@ +/* 论坛主页 */ +.custom-wrap{ + display: flex; + align-items: center +} +.custom-wrap .wrap-name{ + color:#333; + font-size: 16px; +} +.custom-wrap .custom-img{ + width:36px; + height:36px; + margin-right: 8px; +} +/* 版块主页 */ +.moderatorInfo{ + width: 82px; + text-align: center; + display: flex; + flex-direction:column; + align-items: center; + margin:10px 2px 20px 2px; +} +.moderatorInfo .custom-img{ + height: 48px; + width: 48px; +} +.moderatorInfo .wrap-name{ + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + max-width: 80px; +} \ No newline at end of file diff --git a/src/exchange/Empty.js b/src/exchange/Empty.js new file mode 100644 index 00000000..e4d98252 --- /dev/null +++ b/src/exchange/Empty.js @@ -0,0 +1,15 @@ +import React, { PureComponent } from 'react'; + +import nodata from './images/nodata.png'; +class Empty extends PureComponent{ + + render(){ + return( +
    + 暂无数据 +

    暂无数据

    +
    + ) + } +} +export default Empty; \ No newline at end of file diff --git a/src/exchange/ExchangeIndex.js b/src/exchange/ExchangeIndex.js new file mode 100644 index 00000000..3a4f2040 --- /dev/null +++ b/src/exchange/ExchangeIndex.js @@ -0,0 +1,164 @@ +import React, { Component } from 'react'; +import { Menu, Dropdown , Pagination ,Spin} from 'antd'; +import { Link } from 'react-router-dom' + +import ExchangeItem from './ExchangeItem'; + +import ExchangeRight from './ExchangeRight' + +import './exchange.css'; + +import Empty from './Empty' + +import axios from 'axios'; + +class ExchangeIndex extends Component { + constructor(props){ + super(props); + this.state={ + // 热门话题 + hottest_memos:undefined, + // 版主推荐 + recommend_memos:undefined, + // 列表数据 + memos:undefined, + // 列表总数量 + memos_count:0, + // 板块导航 + forum_sections:undefined, + page:1, + current_user:undefined, + // 默认一页数据 + pageSize:15, + search:undefined, + //是否出现加载中的样式 + loading:false + } + } + + componentDidMount = () =>{ + this.InitData(); + } + + // 数据加载 + InitData=(page,search)=>{ + let url = `/memos`; + axios.get((url),{params:{ + page,search + }}).then((result)=>{ + if(result){ + this.setState({ + loading:false, + hottest_memos:result.data.hottest_memos, + recommend_memos:result.data.recommend_memos, + forum_sections:result.data.forum_sections, + memos:result.data.memos, + memos_count:result.data.memos_count, + current_user:result.data.current_user + }) + } + }).catch((error)=>{ + }) + } + + // 搜索 + searchEvent=(search)=>{ + + this.setState({ + loading:true, + search, + page:1 + }) + this.InitData(0,search); + + } + + // 分页 + changePageEvent = (pageNumber) =>{ + this.setState({ + page:pageNumber + }) + const { search } = this.state; + this.InitData(pageNumber,search); + } + + + render(){ + + let { hottest_memos , recommend_memos , memos , memos_count , forum_sections , page , pageSize , current_user } = this.state; + // 板块导航dropdown显示内容 + const menu = ( +
    + { + forum_sections && forum_sections.map(item => { + return( +
    + {item.name} +
      + { + item.children_tags && item.children_tags.map(i=>{ + return(
    • {i.title}
    • ) + }) + } +
    +
    + ) + }) + } +
    + ); + + + + // 数据列表和暂无数据 + const dataList = memos && memos.length > 0 ? + + : +
    + + return( +
    +
    +
    +
    + +
      +
    • 我的话题
    • +
    • 我的收藏
    • +
    • 我感兴趣的论坛
    • +
    +
    + + { dataList } + +
    + { + memos_count > pageSize && +
    + } +
    + +
    + ) + } +} +export default ExchangeIndex; \ No newline at end of file diff --git a/src/exchange/ExchangeItem.js b/src/exchange/ExchangeItem.js new file mode 100644 index 00000000..cf0911ae --- /dev/null +++ b/src/exchange/ExchangeItem.js @@ -0,0 +1,198 @@ +import React, { Component, memo } from 'react'; +import { Dropdown , Menu } from 'antd'; +import {Link} from 'react-router-dom' +import { getImageUrl } from 'educoder'; + +import Tags from './TagComponent/Index'; +import Infos from './InfoComponent/Index'; +import Custom from './CustomComponent/Index'; +import "./exchange.css" +import axios from 'axios'; + + +class ExchangeItem extends Component { + + // 右侧dropdown + InitItemMenu = (id,sticky,is_fine,memo_watched) => { + const { current_user , detail }= this.props; + if(current_user){ + if(current_user.admin || current_user.banned_permission){ + return( + + + + ) + }else if(detail){ + return( + this.enShrineEvent(id,memo_watched)}> + { memo_watched ? '取消收藏' : '收藏' } + + ) + } + } + } + + // 右侧dropdown的选项 + InitlistMenu = (id,sticky,is_fine,memo_watched) => ( + + this.topEvent(sticky,id)} > { sticky ? '取消置顶' : '置顶' } + this.bestEvent(is_fine,id)}> { is_fine ? '取消推荐' : '推荐' } + this.enShrineEvent(id,memo_watched)}> { memo_watched ? '取消收藏' : '收藏' } + this.editEvent(id)}> 编辑 + this.deleteEvent(id)}> 删除 + + ) + + + // 取消收藏+收藏 + enShrineEvent=(id,memo_watched)=>{ + const { refresh } = this.props; + const url = `/memos/${id}/watch_memo`; + // is_watch:1为添加关注 + axios.post(url,{ + is_watch:memo_watched ? 0 : 1 + }).then((result)=>{ + if(result){ + this.props.showNotification(result.data.message); + refresh(); + } + }).catch((error)=>{ + + }) + } + + + // 取消置顶+置顶 + topEvent = (sticky,id) =>{ + const { refresh } = this.props; + const url =`/memos/${id}/set-top-or-down`; + + axios.get(url,{params:{ + sticky:sticky ? 0 : 1 + }}).then((result)=>{ + if(result){ + // 调用父级方法刷新 + this.props.showNotification(result.data.message); + refresh(); + } + }).catch((error)=>{ + + }) + } + + // 取消推荐+推荐 + bestEvent = (is_fine,id) =>{ + const { refresh } = this.props; + const url =`/memos/${id}/is_fine`; + + axios.post(url,{ + is_fine:is_fine ? 0 : 1 + }).then((result)=>{ + if(result){ + // 调用父级方法刷新 + this.props.showNotification(result.data.message); + refresh(); + } + }).catch((error)=>{ + + }) + } + // 编辑 + editEvent=(id)=>{ + this.props.history.push(`/forums/${id}/edit`); + } + + // 删除 + deleteEvent = (id) =>{ + this.props.confirm({ + content: '确认删除帖子?', + + onOk: () => { + const url =`/memos/${id}/destroy.json`; + axios.post(url).then((result)=>{ + if(result){ + if(result.data.status === 0){ + this.props.showNotification(result.data.message); + const { page , refresh } = this.props; + if(page){ + refresh(page); + }else{ + this.props.history.push("/forums"); + } + } + } + }).catch((error)=>{ + + }) + }, + onCancel() { + console.log('Cancel'); + }, + }); + + } + + // 跳转页面 + turnToEvent=(id,detail)=>{ + {/*传了enshine就代表底部右侧操作按钮只有收藏或者取消收藏,否则就是置顶、推荐等 */} + const { enShrine} = this.props; + if(enShrine){return} + if(detail!=true){ + const w= window.open('about:blank'); + w.location.href=`/forums/${id}`; + } + + } + + render(){ + /**detail:true为详情,否则为列表 */ + const { memos , current_user , detail} = this.props; + console.log(memos) + const ListItem = memos && memos.map(item=>{ + return( +
  • +
    +
    + +

    this.turnToEvent(item.id,detail)} className={ detail ? "exchangeItem-subject task-hide justify color_black" : "exchangeItem-subject task-hide justify c_point is_onclick" }> + {item.subject} +

    + {/* 右侧的下拉操作菜单项:登录后才能有右侧信息 */} + { current_user && this.InitItemMenu(item.id,item.sticky,item.is_fine,item.memo_watched) } +
    +
    +
    + {/* 判断用户是否登录 */} + + { item.forum_section_title && 发表在{item.forum_section_title} } + { item.time && {item.time} } + + { + item.new_reply && item.new_reply.username && + + 最新回复: + {item.new_reply.username} + {item.new_reply.time} + + + } + + {/* 论坛首页和论坛详情公用,不同情况下左浮动或者有浮动 */} + + + + + + +
    +
  • + ) + }) + return( +
    + { ListItem } +
    + ) + } +} +export default ExchangeItem; diff --git a/src/exchange/ExchangeRight.js b/src/exchange/ExchangeRight.js new file mode 100644 index 00000000..24cc677a --- /dev/null +++ b/src/exchange/ExchangeRight.js @@ -0,0 +1,68 @@ +import React, { PureComponent } from 'react'; +import { Link } from "react-router-dom" + +import { getImageUrl } from 'educoder'; + +import ExchangeRightSearch from './ExchangeRightSearch' +import './exchange.css' +class ExchangeRight extends PureComponent { + + render(){ + + const { searchEvent , hottest_memos , recommend_memos , hideSearchPanel} = this.props; + + // 热门话题 + const hotList = hottest_memos && hottest_memos.length > 0 && ( +
    +

    + + 热门话题 +

    +
      + { + hottest_memos.map((apply)=>{ + return( +
    • {apply.subject}
    • + ) + }) + } +
    +
    + ) + + // 版主推荐 + const moderatorList = recommend_memos && recommend_memos.length > 0 && ( +
    +

    + + 版主推荐 +

    +
      + { + recommend_memos.map((apply)=>{ + return( +
    • {apply.subject}
    • + ) + }) + } +
    +
    + ) + + return( +
    + { + !hideSearchPanel && + } + + + {/* 热门话题 */} + {hotList} + + {/* 版主推荐 */} + { moderatorList } +
    + ) + } +} +export default ExchangeRight; \ No newline at end of file diff --git a/src/exchange/ExchangeRightSearch.js b/src/exchange/ExchangeRightSearch.js new file mode 100644 index 00000000..f11ffaa1 --- /dev/null +++ b/src/exchange/ExchangeRightSearch.js @@ -0,0 +1,64 @@ +import React, { Component } from 'react'; +import { Input } from 'antd' +import { Link } from 'react-router-dom' + +const Search = Input.Search; +class ExchangeRightSearch extends Component { + constructor(props) { + super(props) + this.state={ + searchDefault:true + } + } + + // 有关搜索部分 + activeSearch =(e)=>{ + this.props.searchEvent(e); + if(!e){ + this.setState({ + searchDefault:true + }) + } + } + showSearchPanel = () =>{ + this.setState({ + searchDefault:false + }) + } + + + render(){ + let { searchDefault } = this.state; + const { current_user } = this.props; + + const sendBtn =()=> { + if(current_user){ + return(发布话题) + }else{ + return(发布话题) + } + } + return( +
    + {sendBtn()} + { + searchDefault ? + + : + + } +
    + ) + } +} +export default ExchangeRightSearch; \ No newline at end of file diff --git a/src/exchange/InfoComponent/Index.js b/src/exchange/InfoComponent/Index.js new file mode 100644 index 00000000..7d1d69ad --- /dev/null +++ b/src/exchange/InfoComponent/Index.js @@ -0,0 +1,19 @@ +import React, { PureComponent } from 'react'; + +class Index extends PureComponent { + + render() { + const { icon , count = 0 , ...props } = this.props; + + return ( + + + + {count} + + + ) + } +} + +export default Index; \ No newline at end of file diff --git a/src/exchange/Manage/AddModeratorModal.js b/src/exchange/Manage/AddModeratorModal.js new file mode 100644 index 00000000..f403d3ce --- /dev/null +++ b/src/exchange/Manage/AddModeratorModal.js @@ -0,0 +1,171 @@ +import React, { Component } from 'react'; +import { Modal , Input , Table ,Pagination } from 'antd' +import './manage.css' +import '../exchange.css'; +import axios from 'axios'; + +const Search = Input.Search; +class AddModeratorModal extends Component { + constructor(props){ + super(props); + this.state={ + data:undefined, + page:1, + user_name:undefined, + limit:10, + total:undefined, + selectedRowKeys:undefined + } + } + + + componentDidUpdate=(prevState)=>{ + if(prevState.operationPlateId !== this.props.operationPlateId && this.props.visible){ + this.setState({ + user_name:undefined, + page:1 + }) + this.getTabData(undefined , 1); + } + } + + getTabData=(user_name,page)=>{ + const { operationPlateId } = this.props; + + const url =`/forum_sections/${operationPlateId}/search_users.json`; + axios.get(url,{ + params:{ + user_name, + page + } + }).then(result=>{ + if(result){ + const user_lists = result.data.user_lists; + let array = []; + for(var i = 0;i{ + + }) + } + getSelectKeys=(selectedRowKeys,selectedRows)=>{ + this.setState({ + selectedRowKeys + }) + } + + // 搜索 + searchEvent=(value)=>{ + this.setState({ + user_name:value, + page:1 + }) + this.getTabData(value,1); + } + + // 翻页 + changePageEvent=(page)=>{ + const { user_name } = this.state; + this.setState({ + page + }) + this.getTabData(user_name,page); + } + + // 取消 + cancel=()=>{ + const { hideAddBox }=this.props; + this.setState({ + user_name:undefined, + page:1 + }) + hideAddBox(); + } + // 确定 + modalSave=()=>{ + const { selectedRowKeys } = this.state; + console.log(selectedRowKeys); + + const { plateId } = this.props.match.params; + const { operationPlateId , hideAddBox , getSubModerator } = this.props; + const url = `/forum_sections/${plateId}/add_users.json`; + axios.post(url,{ + user_ids:selectedRowKeys, + children_section_id:operationPlateId + }).then(result=>{ + if(result){ + this.props.showNotification(result.data.message); + hideAddBox(); + getSubModerator(); + } + }).catch(error=>{ + + }) + } + + render(){ + const { visible } = this.props; + let { data , total , page , limit } = this.state; + const rowSelection = { + onChange: (selectedRowKeys, selectedRows) => this.getSelectKeys(selectedRowKeys,selectedRows) + }; + const columns = [{ + title:"姓名", + dataIndex:"username" + },{ + title:"昵称", + dataIndex:"nickname" + }]; + + return( + +
    +
    +
    + this.searchEvent(value)} + /> +
    +
    + + + { + total && total > limit ? +
    + +
    :"" + } + +
    + 取消 + 确定 +
    + + + ) + } +} +export default AddModeratorModal; \ No newline at end of file diff --git a/src/exchange/Manage/CheckPublic.js b/src/exchange/Manage/CheckPublic.js new file mode 100644 index 00000000..a10b008e --- /dev/null +++ b/src/exchange/Manage/CheckPublic.js @@ -0,0 +1,54 @@ +import React, { Component } from 'react'; + + +import MenuWraps from '../MenuComponent/Menu'; +import SendItem from './SubSendItem'; +import CheckItem from './SubCheckItem' +import CheckReplyItem from './SubCheckReplyItem' + +const menu_nav = [ + { + name:"待审查帖子", + key:`checkPost`, + content:CheckItem + }, + { + name:"待审查回复", + key:`checkReply`, + content:CheckReplyItem + }, + { + name:"已发布的帖子", + key:`sendPost`, + content:SendItem + } +] +class CheckPublic extends Component { + constructor(props){ + super(props); + this.state={ + activeKey:undefined + } + } + changeTab=(activeKey)=>{ + this.setState({ + activeKey + }) + } + + render(){ + return( +
    + +
    + ) + } +} + +export default CheckPublic; \ No newline at end of file diff --git a/src/exchange/Manage/ItemLeft.js b/src/exchange/Manage/ItemLeft.js new file mode 100644 index 00000000..dd693e13 --- /dev/null +++ b/src/exchange/Manage/ItemLeft.js @@ -0,0 +1,40 @@ +import React, { Component } from 'react'; +import {Link} from 'react-router-dom'; +import { getImageUrl } from 'educoder'; +import RenderHtml from "../../components/render-html"; + +import Customers from '../CustomComponent/Index' +import "./manage.css" + +class ItemLeft extends Component { + + render(){ + // user_url,username , time , image_url :用户链接,用户名,时间,头像, + // memo_title , forum_title(待审查帖子以及已发布帖子:帖子名称,发表的论坛名) + // source_title , reply_content(待审查回复:帖子来源,回复内容) + //memo_id,forum_id,source_id( 待审查帖子id,发表在版块id,来源版块id) + const {user_url,id, memo_id,username , time , image_url , memo_title , forum_title ,source_title , reply_content,forum_id,source_id} = this.props; + const title_Url= id || memo_id; + return( + +
    +

    + + {time} + { forum_title && 发表在 {forum_title} } + { source_title && 来源 {source_title} } +

    + { memo_title &&

    {memo_title}

    } + { + reply_content && + + + + } +
    + + ) + } +} + +export default ItemLeft; \ No newline at end of file diff --git a/src/exchange/Manage/ModeratorNav.js b/src/exchange/Manage/ModeratorNav.js new file mode 100644 index 00000000..07dc9f3f --- /dev/null +++ b/src/exchange/Manage/ModeratorNav.js @@ -0,0 +1,87 @@ +import React, { Component } from 'react'; +import { Dropdown } from 'antd'; +import { Link } from 'react-router-dom'; +import Nav from '../NavComponent/Index'; + + +class ModeratorNav extends Component { + + render(){ + const { current_user , bread_crumb }=this.props; + + const forum_tag = bread_crumb && bread_crumb.forum_tag; + const forum = bread_crumb && bread_crumb.forum; + // { + // name:current_user && current_user.username, + // url:`/users/${current_user && current_user.login}` + // }, + const routerMap = [ + { + name: forum && forum.title, + url:"/forums" + }, + { + url:`/forums/theme/${forum_tag && forum_tag.id}`, + name:forum_tag && forum_tag.title + }, + { + url:`/forums/theme/${forum_tag && forum_tag.children_bread_crumb && forum_tag.children_bread_crumb.id}`, + name:forum_tag && forum_tag.children_bread_crumb && forum_tag.children_bread_crumb.title + },{ + name:"版主管理" + } + ]; + + // 板块导航dropdown显示内容 + const menu =(item)=> { + // console.log("item",item); + + if(item){ + return( +
    +
    +
      + { + item.map((i,key)=>{ + return(
    • {i.title}
    • ) + }) + } +
    +
    +
    + ) + } + } + + const titleFlag = () => { + if (forum_tag ) { + console.log(forum_tag.children_bread_crumb); + if (bread_crumb && bread_crumb.is_children) { + return (
    {forum_tag.children_bread_crumb && forum_tag.children_bread_crumb.title}
    ) + } else { + + return ( +
    + { forum_tag.children_bread_crumb ? + +
    {forum_tag.title}
    +
    + : + {forum_tag.title} + } +
    + ) + } + } + + } + return( +
    + + {titleFlag()} +
    + ) + } +} + +export default ModeratorNav; \ No newline at end of file diff --git a/src/exchange/Manage/PassItem.js b/src/exchange/Manage/PassItem.js new file mode 100644 index 00000000..91496e0d --- /dev/null +++ b/src/exchange/Manage/PassItem.js @@ -0,0 +1,35 @@ +import React, { Component } from 'react'; + + + +import '../exchange.css'; +import './manage.css'; +import axios from 'axios' + + +class PassItem extends Component { + + passEvent=(checked)=>{ + const { id , refresh ,page } = this.props; + const url = `/memos/${id}/memo_hidden`; + axios.post(url,{ + checked + }).then((result)=>{ + if(result){ + this.props.showNotification(result.data.message); + refresh(page); + } + }) + } + + render(){ + return( +

    + this.passEvent(true)}>通过 + this.passEvent(false)}>不通过 +

    + ) + } +} + +export default PassItem; \ No newline at end of file diff --git a/src/exchange/Manage/PreApplyPlate.js b/src/exchange/Manage/PreApplyPlate.js new file mode 100644 index 00000000..6c67f166 --- /dev/null +++ b/src/exchange/Manage/PreApplyPlate.js @@ -0,0 +1,122 @@ +import React, { Component } from 'react'; +import { getImageUrl } from 'educoder'; + +import axios from 'axios'; +import './manage.css' +import { Link } from 'react-router-dom'; + +class PreApplyPlate extends Component { + constructor(props){ + super(props); + this.state={ + applylist:undefined + } + } + + componentDidMount=()=>{ + const { plateId } = this.props.match.params; + this.getApplyInfo(plateId); + } + + getApplyInfo=(id)=>{ + const url=`/forum_sections/${id}/applied_forums`; + axios.get(url).then((result)=>{ + if(result){ + this.setState({ + applylist:result.data.applied_moderators + }) + } + }).catch(error=>{ + + }) + } + + // 通过,拒绝 + passApplyEvent=(flag,applyId)=>{ + this.props.confirm({ + content: `确认${flag?"通过":"拒绝"}版主申请?`, + + onOk: () => { + const { plateId } = this.props.match.params; + + const url = `/forum_sections/${plateId}/deal_applies/${applyId}` + axios.post(url,{ + deal_type:flag?1:2 + }).then((result)=>{ + if(result){ + this.props.showNotification(result.data.message); + this.getApplyInfo(plateId); + } + }).catch((error)=>{ + + }) + }, + onCancel() { + console.log('Cancel'); + } + }) + } + + render(){ + const { applylist } = this.state; + // const applylist = [ + // { + // apply_id: 5, + // username: "OpenGCC", + // login: "innov", + // image_url: "avatars/User/girl.jpg", + // user_url: "/users/innov", + // user_ip: null, + // user_ip_address: "--", + // time: "14小时前", + // forum_title: "MAC安全", + // forum_id: 9, + // forum_url: "/memos/forum_memos/9", + // parent_forum: { + // forum_title: "网络安全网络安全333", + // forum_id: 6, + // forum_url: "/memos/forum_memos/6" + // } + // } + // ] + const listItem= () => { + if(applylist && applylist.length > 0){ + return( +
    +

    版主申请

    +
    + { applylist.map((item,key)=>{ + return( +
    + 用户头像 +
    +

    + {item.username} + { item.user_ip && IP:{item.user_ip}({item.user_ip_address}) } +

    +

    申请成为”{item.forum_title}“的版主

    +
    +
    +

    {item.time}

    +

    + this.passApplyEvent(true,item.apply_id)}>通过 + this.passApplyEvent(false,item.apply_id)}>拒绝 +

    +
    +
    + ) + }) + } +
    +
    + ) + } + } + return( + + {listItem()} + + ) + } +} +export default PreApplyPlate; \ No newline at end of file diff --git a/src/exchange/Manage/PreCreate.js b/src/exchange/Manage/PreCreate.js new file mode 100644 index 00000000..ec133f97 --- /dev/null +++ b/src/exchange/Manage/PreCreate.js @@ -0,0 +1,87 @@ +import React, { Component } from 'react'; + +import { Modal , Form , Input } from 'antd'; +import '../exchange.css'; +import axios from 'axios'; + +class PreCreate extends Component { + + componentDidUpdate=(preState)=>{ + const { subId , subName } = this.props; + if(preState.subId !== subId){ + if(subId){ + this.props.form.setFieldsValue({ + title:subName + }) + } + } + } + + // 确定 + modalSave=()=>{ + this.props.form.validateFieldsAndScroll((err, values) => { + if(!err){ + // subId存在就是编辑否则就是新增 + const { refresh , subId } = this.props; + const { plateId } = this.props.match.params; + const url = `/forum_sections/${plateId}${subId ? "/rename":""}.json`; + axios.post(url,{ + title:values.title, + children_section_id:subId + }).then((result)=>{ + if(result){ + refresh(); + this.props.showNotification(result.data.message); + } + }).catch((error)=>{ + + }) + } + }) + } + modalCancel=()=>{ + this.props.close(); + } + + render(){ + const { getFieldDecorator } = this.props.form; + + const { title , visible } = this.props + return( + +
    +
    + + {getFieldDecorator('title', { + rules: [{ + required: true, message: '请输入板块名称', + },{ + max: 5000 , message:'最大限制20个字符' + }], + })( + + )} + +
    + 取消 + 确定 +
    + +
    +
    + ) + } +} +const WrappedPreCreate = Form.create({ name: 'PreCreate' })(PreCreate); +export default WrappedPreCreate; \ No newline at end of file diff --git a/src/exchange/Manage/PreModerator.js b/src/exchange/Manage/PreModerator.js new file mode 100644 index 00000000..f72c4ac3 --- /dev/null +++ b/src/exchange/Manage/PreModerator.js @@ -0,0 +1,77 @@ +import React, { Component } from 'react'; + +import CheckPublic from './CheckPublic' +import ModeratorNav from './ModeratorNav'; + +import ApplyPlate from './PreApplyPlate'; +import PrePlateManage from './PrePlateManage' +import axios from 'axios'; + +class PreModerator extends Component { + constructor(props){ + super(props); + this.state={ + activeKey:undefined, + bread_crumb:undefined, + is_children:false, + } + } + changeTab=(activeKey)=>{ + this.setState({ + activeKey + }) + } + componentDidMount=()=>{ + const { plateId } = this.props.match.params; + this.getPlateInfo(plateId); + } + componentDidUpdate=(prevState)=>{ + let prePlateId = prevState.match.params.plateId; + const { plateId } = this.props.match.params; + if(prePlateId !== prePlateId){ + this.getPlateInfo(plateId); + } + } + getPlateInfo=(plateId)=>{ + const url = `/forum_sections/${plateId}/forum_section_header`; + axios.get(url).then((result)=>{ + if(result){ + this.setState({ + bread_crumb:result.data.bread_crumb, + is_children:result.data.bread_crumb && result.data.bread_crumb.is_children + }) + } + }).catch(error=>{ + + }) + } + + render(){ + const { bread_crumb , is_children } = this.state; + const parentManage =()=> { + if(!is_children){ + return( + + + + {/* 板块申请 */} + + + ) + } + } + return( +
    + + + + {parentManage()} + + {/* 审批(二级版主只有这一块) */} + +
    + ) + } +} + +export default PreModerator; \ No newline at end of file diff --git a/src/exchange/Manage/PrePlateManage.js b/src/exchange/Manage/PrePlateManage.js new file mode 100644 index 00000000..0bfbe443 --- /dev/null +++ b/src/exchange/Manage/PrePlateManage.js @@ -0,0 +1,285 @@ +import React, { Component } from 'react'; +import { getImageUrl} from 'educoder'; +import PreCreate from './PreCreate'; +import './manage.css' +import '../exchange.css' +import {Link} from 'react-router-dom' +import axios from 'axios'; +import update from 'immutability-helper' + +import AddModeratorModal from './AddModeratorModal' + + + +class PrePlateManage extends Component { + constructor(props){ + super(props); + this.state={ + visible:false, + children_tags:undefined, + subId:undefined, + subName:undefined, + // 新增版主有关 + addVisible:undefined, + operationPlateId:undefined + } + } + componentDidMount=()=>{ + this.getSubModerator(); + } + // 获取所有二级板块 + getSubModerator=()=>{ + const { plateId } = this.props.match.params; + const url = `/forum_sections/${plateId}/managements`; + axios.get(url).then((result)=>{ + if(result){ + this.setState({ + children_tags:result.data.forum_tag && result.data.forum_tag.children_tags + }) + } + }).catch((error)=>{ + + }) + } + // 新建板块和重命名板块后的刷新方法 + reSetInfo=()=>{ + this.setState({ + visible:false, + subId:undefined, + subName:undefined + }) + this.getSubModerator(); + const { plateId } = this.props.match.params; + const { getPlateInfo } = this.props; + getPlateInfo(plateId); + } + + // 展开 + expandEvent=(index,flag)=>{ + this.setState( + (prevState) => ({ + children_tags : update(prevState.children_tags, {[index]: { expand: {$set: flag} }}), + }) + ) + } + + // 显示删除版主的按钮 + deleteManageEvent=(index,flag)=>{ + console.log(index) + this.setState( + (prevState) => ({ + children_tags : update(prevState.children_tags, {[index]: { isDeleting: {$set: flag} }}), + }) + ) + } + + // 新建二级板块 + createSubPlateEvent=()=>{ + this.setState({ + visible:true, + subId:undefined, + subName:undefined + }) + } + // 二级板块重命名 + RenamneSubPlateEvent=(id,name)=>{ + this.setState({ + visible:true, + subId:id, + subName:name + }) + } + + // 删除二级板块 + DeleteSubPlateEvent=(id)=>{ + this.props.confirm({ + content: '确认删除二级板块?', + onOk: () => { + const { plateId } = this.props.match.params; + const url=`/forum_sections/${plateId}/destroy.json` + axios.post(url,{ + children_section_id:id + }).then(result=>{ + if(result){ + this.props.showNotification(result.data.message); + this.getSubModerator(); + const { getPlateInfo } = this.props; + getPlateInfo(plateId); + } + }).catch((error)=>{ + + }) + }, + onCancel() { + console.log('Cancel'); + } + }) + + } + + // 关闭新建弹框 + colseModalEvent=()=>{ + this.setState({ + visible:false + }) + } + + // 删除版主 + deletePlateEvent=(id,name,index,key)=>{ + console.log(index,'dddd',key); + this.props.confirm({ + content: `是否确认解除“${name}”的二级版主权限?`, + onOk: () => { + const { plateId } = this.props.match.params; + const url=`/forum_sections/${plateId}/destroy_moderator/${id}` + axios.post(url).then(result=>{ + if(result){ + this.props.showNotification(result.data.message); + const { children_tags } = this.state; + // 去掉当前选中的版主 + let tempObj = children_tags[index].forum_moderators; + tempObj = tempObj.filter((_, i) => i !== key) ; + children_tags[index].forum_moderators = tempObj; + this.setState({ children_tags }) + } + }).catch((error)=>{ + + }) + }, + onCancel() { + console.log('Cancel'); + } + }) + } + + // 新增版主弹框 + showAddBox=(flag,plateId)=>{ + this.setState({ + addVisible:true, + operationPlateId:plateId + }) + } + hideAddBox=()=>{ + this.setState({ + addVisible:false, + operationPlateId:undefined + }) + } + + + render(){ + const { visible ,children_tags , subId , subName , addVisible , operationPlateId } = this.state; + // console.log("child",children_tags); + const forumTagList = ()=>{ + if(children_tags && children_tags.length>0){ + return( +
    + { + children_tags.map((item,key)=>{ + return( +
    +
    +

    + {item.title} + + this.RenamneSubPlateEvent(item.id,item.title)}>重命名 + this.DeleteSubPlateEvent(item.id)}>删除板块 + +

    +

    二级版主

    +
    + { renderSubList(item.forum_moderators,key,item.isDeleting) } + + {/* 展开 */} + { + item.forum_moderators && item.forum_moderators.length > 5 && !item.expand && + this.expandEvent(key,true)}> + } + {/* 收起 */} + { + item.forum_moderators && item.forum_moderators.length > 5 && item.expand && + this.expandEvent(key,false)}> + } + {/* 新增版主 */} + this.showAddBox(true,item.id)}> + {/* 删除版主 */} + { + item.forum_moderators && item.forum_moderators.length > 0 && !item.isDeleting && + this.deleteManageEvent(key,true)}> + } + { + item.isDeleting && this.deleteManageEvent(key,false)}>完成 + } + + +
    +
    +
    + ) + }) + } +
    + ) + } + } + + const renderSubList = (item,index,deletingFlag) =>{ + if(item){ + return( +
      + { + item.map((i,key)=>{ + return( + + { + !i.isDelete && +
    • + + { + deletingFlag && + this.deletePlateEvent(`${i.moderator_id}`,`${i.username}`,index,key)}> + } + {i.username} +
    • + } +
      + + ) + }) + } +
    + ) + } + } + return( +
    +
    + + + + 二级板块管理 + 新建板块 +
    + {forumTagList()} +
    + ) + } +} + +export default PrePlateManage; \ No newline at end of file diff --git a/src/exchange/Manage/SubCheckItem.js b/src/exchange/Manage/SubCheckItem.js new file mode 100644 index 00000000..97654782 --- /dev/null +++ b/src/exchange/Manage/SubCheckItem.js @@ -0,0 +1,146 @@ +import React, { Component } from 'react'; +import { Spin , Pagination } from 'antd'; +import '../exchange.css'; +import './manage.css'; +import Empty from '../Empty' +import ItemLeft from './ItemLeft'; +import PassItem from './PassItem'; +import axios from 'axios' + +class SubCheckItem extends Component { + constructor(props){ + super(props); + this.state={ + page:1, + data:undefined, + isSpin:true, + limit:10 + } + } + + componentDidMount=()=>{ + this.getList(1); + } + + getList = (page) =>{ + this.setState({ + isSpin:true + }) + const { plateId } = this.props.match.params; + const url = `/forum_sections/${plateId}/unchecked_memos.json`; + axios.get(url,{params:{ + page + }}).then((result)=>{ + if(result){ + this.setState({ + data:result.data, + isSpin:false + }) + } + }).catch((error)=>{ + + }) + } + + // 禁言 + stopEvent=(id,banned,user_id)=>{ + const { current_user } = this.props; + const url =`/memos/${id}/banned_user.json` + axios.post((url),{ + user_id:user_id, + banned + }).then((result)=>{ + if(result){ + const { page } = this.state; + this.props.showNotification(result.data.message); + this.getList(page); + } + }).catch((error)=>{ + + }) + console.log("banned",banned); + } + + // 分页 + changePageEvent=(page)=>{ + this.setState({ + page + }) + this.getList(page); + } + + render(){ + const { data , page , isSpin , limit } = this.state; + const { current_user } = this.props; + + const pageCom = ( + data && data.memos_count > limit && +
    + +
    + ) + + const dataList = ( + + data && data.memos_lists && data.memos_lists.length > 0 ? +
    + { + data.memos_lists.map((item,key)=>{ + const userInfo = { + forum_id:item.forum_id, + memo_id:item.memo_id, + user_url:item.user_url, + username:item.username, + time:item.time, + image_url:item.image_url, + memo_title:item.memo_title, + forum_title:item.forum_title, + user_id:item.user_id + } + const passItem = { + refresh:this.getList, + page, + id:item.memo_id + } + + + return( +
    +
    + +
    + { + current_user && current_user.admin && + ( item.is_banned ? +

    this.stopEvent(item.memo_id,0,item.user_id)}>已禁言

    + : +

    this.stopEvent(item.memo_id,1,item.user_id)}>禁言

    + ) + } + + +
    + +
    + +
    + ) + }) + } + { pageCom } +
    + : +
    + +
    + ) + + return( + + { dataList } + + ) + } +} + +export default SubCheckItem; \ No newline at end of file diff --git a/src/exchange/Manage/SubCheckReplyItem.js b/src/exchange/Manage/SubCheckReplyItem.js new file mode 100644 index 00000000..7c92542f --- /dev/null +++ b/src/exchange/Manage/SubCheckReplyItem.js @@ -0,0 +1,148 @@ +import React, { Component } from 'react'; +import { Spin , Pagination } from 'antd'; +import '../exchange.css'; +import './manage.css'; +import Empty from '../Empty' +import ItemLeft from './ItemLeft'; +import PassItem from './PassItem'; +import axios from 'axios' + +class SubCheckReplyItem extends Component { + constructor(props){ + super(props); + this.state={ + page:1, + data:undefined, + isSpin:true, + limit:10 + } + } + + componentDidMount=()=>{ + this.getList(1); + } + + getList = (page) =>{ + this.setState({ + isSpin:true + }) + const { plateId } = this.props.match.params; + const url = `/forum_sections/${plateId}/unchecked_replies.json`; + axios.get(url,{params:{ + page + }}).then((result)=>{ + if(result){ + this.setState({ + data:result.data, + isSpin:false + }) + } + }).catch((error)=>{ + + }) + } + + // 禁言 + stopEvent=(id,banned,user_id)=>{ + const { current_user } = this.props; + const url =`/memos/${id}/banned_user.json` + axios.post((url),{ + user_id:user_id, + banned + }).then((result)=>{ + if(result){ + const { page } = this.state; + this.props.showNotification(result.data.message); + this.getList(page); + } + }).catch((error)=>{ + + }) + } + + // 分页 + changePageEvent=(page)=>{ + this.setState({ + page + }) + this.getList(page); + } + + render(){ + const { data , page , isSpin , limit } = this.state; + const { current_user } = this.props; + + const pageCom = ( + data && data.memos_count > limit && +
    + +
    + ) + + const dataList = ( + data && data.replies_lists && data.replies_lists.length > 0 ? +
    + { + data.replies_lists.map((item,key)=>{ + const userInfo = { + source_id:item.source_id, + user_url:item.user_url, + username:item.username, + time:item.time, + image_url:item.image_url, + reply_content:item.reply_content, + source_title:item.source_title, + user_id:item.user_id, + id:item.reply_id + } + const passItem = { + refresh:this.getList, + page, + id:item.reply_id + } + + + return( + +
    +
    + +
    + { + current_user && current_user.admin && + ( item.is_banned ? +

    this.stopEvent(item.reply_id,0,item.user_id)}>已禁言

    + : +

    this.stopEvent(item.reply_id,1,item.user_id)}>禁言

    + ) + } + + +
    +
    + +
    + + + ) + }) + } + + { pageCom } +
    + : +
    + +
    + ) + + return( + + { dataList } + + ) + } +} + + +export default SubCheckReplyItem; \ No newline at end of file diff --git a/src/exchange/Manage/SubSendItem.js b/src/exchange/Manage/SubSendItem.js new file mode 100644 index 00000000..2a0e49d4 --- /dev/null +++ b/src/exchange/Manage/SubSendItem.js @@ -0,0 +1,174 @@ +import React, { Component } from 'react'; +import { Spin , Pagination } from 'antd'; +import Tags from '../TagComponent/Index'; +import '../exchange.css'; +import './manage.css'; +import Empty from '../Empty' +import ItemLeft from './ItemLeft'; +import PassItem from './PassItem'; +import axios from 'axios' + +class SubSendItem extends Component { + constructor(props){ + super(props); + this.state={ + page:1, + data:undefined, + isSpin:true, + limit:10 + } + } + + componentDidMount=()=>{ + this.getList(1); + } + + getList = (page) =>{ + this.setState({ + isSpin:true + }) + const { plateId } = this.props.match.params; + const url = `/forum_sections/${plateId}/checked_memos.json`; + axios.get(url,{params:{ + page + }}).then((result)=>{ + if(result){ + this.setState({ + data:result.data, + isSpin:false + }) + } + }).catch((error)=>{ + + }) + } + + // 删除-已发布的帖子 + deleteEvent=(id)=>{ + const { page } = this.state; + const url = `/memos/${id}/destroy.json`; + axios.post(url).then(result=>{ + if(result){ + this.props.showNotification(result.data.message); + this.getList(page); + } + }).catch(error=>{ + + }) + } + // 取消推荐/推荐-已发布的帖子 + isFineEvent=(id,flag)=>{ + const { page } = this.state; + const url = `/memos/${id}/is_fine`; + axios.post(url,{ + is_fine:flag ? 0 : 1 + }).then(result=>{ + if(result){ + this.props.showNotification(result.data.message); + this.getList(page); + } + }).catch(error=>{ + + }) + } + // 取消置顶/置顶-已发布的帖子 + stickyEvent=(id,flag)=>{ + const { page } = this.state; + const url = `/memos/${id}/set-top-or-down`; + axios.get(url,{params:{ + sticky:flag ? 0 : 1 + }}).then(result=>{ + if(result){ + this.props.showNotification(result.data.message); + this.getList(page); + } + }).catch(error=>{ + + }) + } + + // 禁言 + stopEvent=(id,banned)=>{ + const { current_user } = this.props; + const url =`/memos/${id}/banned_user.json` + axios.post((url),{ + user_id:current_user && current_user.user_id, + banned + }).then((result)=>{ + if(result){ + const { page } = this.state; + this.props.showNotification(result.data.message); + this.getList(page); + } + }).catch((error)=>{ + + }) + } + + // 分页 + changePageEvent=(page)=>{ + this.setState({ + page + }) + this.getList(page); + } + + render(){ + const { data , page , isSpin , limit } = this.state; + + const pageCom = ( + data && data.memos_count > limit && +
    + +
    + ) + const dataList = ( + data && data.memos_lists && data.memos_lists.length > 0 ? +
    + { + data.memos_lists.map((item,key)=>{ + const userInfo = { + forum_id:item.forum_id, + memo_id:item.memo_id, + user_url:item.user_url, + username:item.username, + time:item.time, + image_url:item.image_url, + memo_title:item.memo_title, + forum_title:item.forum_title + } + return( +
    +
    + +
    +

    + +

    +

    + this.stickyEvent(item.memo_id,item.sticky)}>{item.sticky?"取消置顶":"置顶"} + this.isFineEvent(item.memo_id,item.is_fine)}>{item.is_fine?"取消推荐":"推荐"} + this.deleteEvent(item.memo_id)}>删除 +

    +
    +
    +
    + ) + }) + } + { pageCom } +
    + : +
    + +
    + ) + + return( + + { dataList } + + ) + } +} +export default SubSendItem; \ No newline at end of file diff --git a/src/exchange/Manage/manage.css b/src/exchange/Manage/manage.css new file mode 100644 index 00000000..d698800a --- /dev/null +++ b/src/exchange/Manage/manage.css @@ -0,0 +1,134 @@ + +.moderatorMenu .ant-tabs-ink-bar{ + display: none!important; +} +.moderatorItems{ + padding:20px 0px; + border-bottom: 1px solid #eaeaea; +} +.moderatorItems:last-child{ + border-bottom: none; +} +.ItemsHeadPhoto .custom-img{ + width:36px; + height: 36px; + margin-right: 15px; +} +.reply_manage_content img{ + width: 30px +} + +/* 一级板块管理-版主申请 */ +.applyList{ + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between +} +.applyList > div{ + background: #fff; + width: 585px; + display: flex; + padding:20px 30px; + box-sizing: border-box; + margin-bottom: 20px; +} + +/* 表单form---标题和内容在统一行 */ +.formInline .ant-row.ant-form-item{ + display: flex +} +.formInline .ant-col.ant-form-item-control-wrapper{ + flex: 1; +} +/* 二级板块管理 */ +.subPlateList{ + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content:space-between; +} +.subPlateList > div{ + width:585px; + height: 180px; + background: #fff; + position: relative; + margin-bottom: 20px; +} +.subPlateList > div .subPlateItem{ + position: absolute; + width: 100%; + left: 0px; + top:0px; + padding-left:30px; + box-sizing: border-box; + background: #fff; +} +.subPlateList > div .subPlateItem.active{ + box-shadow: 0px 5px 26px rgba(0,0,0,0.1); + z-index: 1; +} +.subPlateItem_head{ + display: flex; + justify-content: space-between; + height: 50px; + line-height: 50px; + border-bottom: 1px solid #f4f4f4; + margin-right: 30px; +} +.subPlateItem.active .plateManager > ul{ + width: auto; + height: auto; + display: inline +} +.plateManager > ul{ + display: inline-block; + width: 345px; + height: 60px; + overflow: hidden; +} +.font-36{font-size: 36px!important;} +.plateManager > ul > li{ + display: flex; + flex-direction: column; + font-size: 12px; + align-items: center; + float: left; + margin-right: 30px; + text-align: center; + margin-bottom: 20px; + position: relative; +} +.deletePlateIcon{ + position: absolute; + top: -11px; + right: -8px; + font-size: 18px; + color: #FF5555; + cursor: pointer; +} +.completeIcon{ + background: #5091FF; + width: 36px; + height: 36px; + line-height: 36px; + font-size: 12px; + color: #fff; + text-align: center; + float: right; + border-radius: 50%; + margin-top: 18px; +} + +/* 添加版主弹框 */ +.addPlateModal .ant-modal-body{ + padding:30px 0px!important; +} +/* .addPlateModal .ant-table-tbody > tr > td{ + padding:10px 5px; +} */ +/*禁言两端对齐*/ +.between_{ + flex-direction: column; + justify-content: space-between; +} \ No newline at end of file diff --git a/src/exchange/MenuComponent/Menu.css b/src/exchange/MenuComponent/Menu.css new file mode 100644 index 00000000..303e3150 --- /dev/null +++ b/src/exchange/MenuComponent/Menu.css @@ -0,0 +1,18 @@ + +.plate-left-Menu .ant-tabs-tab{ + height: 80px; + line-height: 80px; + font-size: 16px; + margin-left: 30px; + margin-right: 0px; + padding:0px; +} +.plate-left-Menu .ant-tabs-bar{ + margin-bottom: 0px; + border-bottom: 1px solid #f4f4f4; + background: #fff; +} +.plate-left-Menu .ant-tabs-extra-content{ + margin-top: 18px; + margin-right: 30px; +} \ No newline at end of file diff --git a/src/exchange/MenuComponent/Menu.js b/src/exchange/MenuComponent/Menu.js new file mode 100644 index 00000000..2dd8c0e8 --- /dev/null +++ b/src/exchange/MenuComponent/Menu.js @@ -0,0 +1,51 @@ +import React, { Component } from 'react'; +import { Tabs } from 'antd'; +import './Menu.css'; + + +const { TabPane } = Tabs; + +class MenuCom extends Component{ + constructor(props){ + super(props); + this.state={ + activeKey: '' + } + } + + componentDidMount () { + const { defaultUrlKey } = this.props; + this.setState({ + activeKey: defaultUrlKey + }) + } + changeTabs=(activeKey)=>{ + this.setState({ + activeKey:activeKey + }) + const { changeTab } = this.props; + changeTab(activeKey); + } + + render(){ + const { menu_nav , btn , ...props } = this.props; + + const tabs = menu_nav.map((tab)=>{ + const Content = tab.content; + return( + + + + ) + }) + + let { activeKey } = this.state; + + return( + + { tabs } + + ) + } +} +export default MenuCom; \ No newline at end of file diff --git a/src/exchange/MyExchange/Index.js b/src/exchange/MyExchange/Index.js new file mode 100644 index 00000000..19b914c9 --- /dev/null +++ b/src/exchange/MyExchange/Index.js @@ -0,0 +1,115 @@ +import React, { Component } from 'react'; + +import ExchangeRight from '../ExchangeRight' + +import '../exchange.css'; +import './myExchange.css'; + +import Nav from '../NavComponent/Index' + +import MyTopic from './MyTopic'; +import MyInteresting from './MyInteresting'; +import MyEnshrine from './MyEnshrine'; +import MenuWraps from '../MenuComponent/Menu' + +import axios from 'axios'; + +const menu_nav = [ + { + name:"我的话题", + key:`MyTopic`, + content:MyTopic + }, + { + name:"我的收藏", + key:`MyEnshrine`, + content:MyEnshrine + }, + { + name:"我感兴趣的论坛", + key:`MyInteresting`, + content:MyInteresting + } +] +class Index extends Component { + constructor(props){ + super(props); + this.state={ + activeKey:"MyTopic", + data:undefined + } + } + + componentDidMount=()=>{ + this.getMain(); + } + + getMain=()=>{ + const url =`/my_memos/recommend_memos`; + axios.get(url).then(result=>{ + if(result){ + this.setState({ + data:result.data + }) + } + }).catch(error=>{ + + }) + } + + // 切换第一个nav + changeTab=(activeKey)=>{ + // console.log('1--',activeKey); + this.setState({ + activeKey + }) + } + render(){ + let pathname = this.props.location.pathname; + let urllength = pathname.split("/").length; + let urlLast = pathname.split("/")[urllength-1]; + + const { current_user } = this.props; + const { activeKey , data } = this.state; + + const NavMap=[ + { + url:current_user && current_user.user_url, + name:current_user && current_user.username + }, + { + url:"/forums", + name:"论坛交流" + }, + { + name:activeKey === "MyTopic" ? "我的话题" :activeKey === "MyEnshrine" ? "我的收藏" : "我感兴趣的论坛" + } + ] + + return( +
    + +
    +
    +
    + +
    +
    + +
    +
    + + ) + } +} +export default Index; \ No newline at end of file diff --git a/src/exchange/MyExchange/MyEnshrine.js b/src/exchange/MyExchange/MyEnshrine.js new file mode 100644 index 00000000..ec4b1a93 --- /dev/null +++ b/src/exchange/MyExchange/MyEnshrine.js @@ -0,0 +1,17 @@ +import React, { Component } from 'react'; + +import MyTopicItem from './MyTopicItem'; + + +class MyEnshrine extends Component { + + render(){ + return( +
    + +
    + ) + } +} + +export default MyEnshrine; \ No newline at end of file diff --git a/src/exchange/MyExchange/MyInteresting.js b/src/exchange/MyExchange/MyInteresting.js new file mode 100644 index 00000000..73bcd785 --- /dev/null +++ b/src/exchange/MyExchange/MyInteresting.js @@ -0,0 +1,101 @@ +import React, { Component } from 'react'; +import { Spin } from 'antd'; +import { Link } from 'react-router-dom' + +import Empty from '../Empty'; +import './myExchange.css'; + +import box1 from '../images/box1.png'; +import box2 from '../images/box2.png'; +import box3 from '../images/box3.png'; +import box4 from '../images/box4.png'; +import box5 from '../images/box5.png'; +import box6 from '../images/box6.png'; + +import axios from 'axios'; + +const backImgArray = [box1,box2,box3,box4,box5,box6]; +class MyInteresting extends Component { + constructor(props){ + super(props); + this.state={ + forum_details:undefined, + isSpin:true + } + } + + componentDidMount = () =>{ + this.getInfo(); + } + + getInfo = () =>{ + this.setState({ + isSpin:true + }) + const url = `/my_memos/my_interested`; + axios.get(url).then((result)=>{ + if(result){ + this.setState({ + forum_details:result.data.forum_details, + isSpin:false + }) + } + }).catch(error=>{ + + }) + } + + // 取消收藏 + cancelEnshrineEvent=(id)=>{ + const url = `/memos/forum_memos/${id}/is_watch.json`; + axios.post((url),{ + is_watch:0 + }).then(result=>{ + if(result){ + this.getInfo(); + } + }).catch(error=>{ + + }) + } + + render(){ + const { forum_details , isSpin } = this.state; + + const divList = ( forum_details && forum_details.length > 0 ? +
    + { + forum_details.map((item,key) => { + const index = Number(Number((key)%6)+1)-1; + // console.log(index); + return( +
    +
    +
    +

    {item.title}

    +

    {item.memos_count} 个话题

    +
    +
    + + this.cancelEnshrineEvent(`${item.id}`)}>取消收藏 + 查看 + +
    + ) + }) + } +
    + : +
    + ) + return( + +
    + { divList } +
    +
    + ) + } +} + +export default MyInteresting; \ No newline at end of file diff --git a/src/exchange/MyExchange/MyTopic.js b/src/exchange/MyExchange/MyTopic.js new file mode 100644 index 00000000..541cd2aa --- /dev/null +++ b/src/exchange/MyExchange/MyTopic.js @@ -0,0 +1,59 @@ +import React, { Component } from 'react'; + +import MenuWraps from '../MenuComponent/Menu'; +import MyTopicItem from './MyTopicItem'; + +import './myExchange.css'; + + +const menu_nav = [ + { + name:"发表的话题", + key:`published`, + content:MyTopicItem + }, + { + name:"回复的话题", + key:`replied`, + content:MyTopicItem + }, + { + name:"看过的话题", + key:`watched`, + content:MyTopicItem + } +] +class MyTopic extends Component { + constructor(props){ + super(props); + this.state={ + activeKey:"published" + } + } + + // 切换第2个nav:发表的话题、回复的话题、看过的话题 + changeTab=(activeKey)=>{ + this.setState({ + activeKey + }) + } + render(){ + let { activeKey } = this.state; + return( +
    + +
    + ) + } +} + +export default MyTopic; \ No newline at end of file diff --git a/src/exchange/MyExchange/MyTopicItem.js b/src/exchange/MyExchange/MyTopicItem.js new file mode 100644 index 00000000..f3728d70 --- /dev/null +++ b/src/exchange/MyExchange/MyTopicItem.js @@ -0,0 +1,239 @@ +import React, { Component } from 'react'; +import { Dropdown , Menu , Icon , DatePicker , Pagination , Spin } from 'antd'; +import { Link } from 'react-router-dom' + +import moment from 'moment' +import Empty from '../Empty' + +import ExchangeItems from '../ExchangeItem'; +import './myExchange.css' +import '../exchange.css' + +import axios from 'axios'; +const { SubMenu } = Menu; + +const dateFormat = 'YYYY-MM-DD'; + +class MyTopicItem extends Component { + constructor(props){ + super(props); + this.state={ + // 筛选条件 + memo_type:undefined, + forum_section_id:undefined, + is_hidden:undefined, + is_hidden_name:undefined, + start_time:undefined, + end_time:undefined, + page:1, + plateName:undefined, + // 分页 + pageSize:15, + // 数据 + data:undefined, + isSpin:true + } + } + + // 搜索 + searchEvent=()=>{} + + // 清除 + clearEvent=()=>{} + + componentDidMount=()=>{ + this.refresh(); + } + + // 我的话题和我的收藏公用当前组件,但接口不同,根据url判断调用哪个接口 + getMytopicInfo = (forum_section_id,is_hidden,start_time,end_time,page) =>{ + this.setState({ + isSpin:true + }) + const { subActiveKey , urlName } = this.props; + + const url = `/${urlName}`; + axios.get(url,{params:{ + memo_type:subActiveKey, + forum_section_id, + is_hidden, + start_time, + end_time, + page + }}).then(result=>{ + if(result){ + this.setState({ + data:result.data, + isSpin:false + }) + } + }).catch(error=>{ + + }) + } + + // 刷新时需要用到 + refresh=()=>{ + const {forum_section_id,is_hidden,start_time,end_time } = this.state; + this.getMytopicInfo(forum_section_id,is_hidden,start_time,end_time,1); + } + + // 切换分页 + changePageEvent = (page) =>{ + this.setState({ + page + }) + const {forum_section_id,is_hidden,start_time,end_time } = this.state; + this.getMytopicInfo(forum_section_id,is_hidden,start_time,end_time,page); + } + + // 选择板块 + changeForumId=(plateId,name)=>{ + this.setState({ + forum_section_id:plateId, + plateName:name + }) + const {is_hidden,start_time,end_time , page } = this.state; + this.getMytopicInfo(plateId,is_hidden,start_time,end_time,page); + } + + // 选择帖子状态 + forumType=(type)=>{ + this.setState({ + is_hidden:type, + is_hidden_name:type === "show" ? "已发布的话题":"待审查的话题" + }) + const {forum_section_id,start_time,end_time , page } = this.state; + this.getMytopicInfo(forum_section_id,type,start_time,end_time,page); + } + + // 清除搜索条件 + clearEvent=()=>{ + this.setState({ + forum_section_id:undefined, + plateName:undefined, + is_hidden:undefined, + is_hidden_name:undefined, + start_time:undefined, + end_time:undefined + }) + this.getMytopicInfo(undefined,undefined,undefined,undefined,1); + } + + // 选择开始时间 + changeBeginEvent=(e,dateString)=>{ + this.setState({ + start_time:dateString + }) + } + + // 选择结束时间 + changeEndEvent=(e,dateString)=>{ + this.setState({ + end_time:dateString + }) + } + + // 搜索 + searchEvent=()=>{ + this.setState({ + page:1 + }) + const {forum_section_id,is_hidden,start_time,end_time } = this.state; + this.getMytopicInfo(forum_section_id , is_hidden , start_time , end_time , 1); + } + + render(){ + const { data , pageSize , page , plateName , is_hidden_name , start_time , end_time , isSpin } = this.state; + + // 选择板块 + const menuList =( +
    + { + data && data.forum_sections && data.forum_sections.map(item => { + return( +
    + this.changeForumId(item.id,item.name)}>{item.name} + +
    + ) + }) + } +
    + ) + + // 全部帖子 + const forumList = ( + + this.forumType('hidden')}>待审查的话题 + this.forumType('show')}>已发布的话题 + + ) + + + const pagination = ( + data && data.memos && data.memos_count > pageSize && +
    + +
    + ) + + const dataList = ( + +
    + + + {plateName || "选择板块"} + + + + + { is_hidden_name || '全部帖子' } + + +
    + 开始日期 + + 结束日期 + +
    + + 搜索 + 清除 + + { data && data.memos_count }个结果 +
    + { + data && data.memos && data.memos.length>0 ? +
    + + { pagination } +
    + : +
    + +
    + } +
    + ) + return( dataList ) + } +} + +export default MyTopicItem; \ No newline at end of file diff --git a/src/exchange/MyExchange/myExchange.css b/src/exchange/MyExchange/myExchange.css new file mode 100644 index 00000000..291a69aa --- /dev/null +++ b/src/exchange/MyExchange/myExchange.css @@ -0,0 +1,56 @@ +.MyTopicSearch{ + display: flex; + border-bottom: 1px solid #f4f4f4; + padding:20px 30px; + align-items: center; + justify-content: space-between; + background: #fff; +} + +/* 我感兴趣的论坛 */ +.ForumList{ + display: flex; + flex-flow: row; + flex-wrap:wrap; + justify-content: space-between; +} +.interestItem{ + width: 280px; + margin:20px 0px; + background: #FFFFFF; +} +.interestItem .interestingUpper{ + height: 150px; + background-repeat:no-repeat; + background-size:100% 100%; + background-color:#fff ; + display: flex; + flex-flow: row; + align-items: center; + justify-content: center; +} +.interestingOperate{ + display: flex; + height: 50px; + line-height: 50px; +} +.interestingOperate .operateBtn{ + width: 50%; + display: block; + text-align: center; + position: relative; + color: #666666; +} +.interestingOperate .operateBtn:first-child::after{ + height: 24px; + width:1px; + top:13px; + position: absolute; + right: 0px; + content: ''; + background: #eee; +} + +.mainNav-style > .ant-tabs-bar .ant-tabs-ink-bar{ + display: none!important; +} \ No newline at end of file diff --git a/src/exchange/NavComponent/Index.js b/src/exchange/NavComponent/Index.js new file mode 100644 index 00000000..915158cb --- /dev/null +++ b/src/exchange/NavComponent/Index.js @@ -0,0 +1,28 @@ +import React , { PureComponent } from "react"; +import { Link } from 'react-router-dom'; + +import './nav.css' + +class Index extends PureComponent{ + render(){ + const { NavMap , ...props } = this.props; + let navRouter = NavMap && NavMap.map((item) => { + return( + + { + item.name ? (item.url ? + { item.name } + : + { item.name }) + :"" + } + + ) + }) + return( +

    { navRouter }

    + ) + } + +} +export default Index; \ No newline at end of file diff --git a/src/exchange/NavComponent/nav.css b/src/exchange/NavComponent/nav.css new file mode 100644 index 00000000..b453349b --- /dev/null +++ b/src/exchange/NavComponent/nav.css @@ -0,0 +1,13 @@ +.nav_Link{ + position: relative; + margin-right: 20px; +} +.nav_Link::after{ + position: absolute; + right: -15px; + content: '>'; + top:0px; + color: #999; + height: 20px; + line-height: 18px; +} \ No newline at end of file diff --git a/src/exchange/Plate/All.js b/src/exchange/Plate/All.js new file mode 100644 index 00000000..07e403a5 --- /dev/null +++ b/src/exchange/Plate/All.js @@ -0,0 +1,36 @@ +import React, { PureComponent } from 'react'; +import ExchangeItem from '../ExchangeItem' +import Empty from '../Empty' + +import '../exchange.css' +import './plate.css' +class All extends PureComponent{ + state = { + condition:"all" + } + + componentDidMount = () =>{ + const { condition } = this.props; + this.setState({ + condition + }) + } + + render(){ + + const { memos } = this.props; + + const memosList = ( + memos && memos.length > 0 ? + + : +
    + +
    + ) + return( + memosList + ) + } +} +export default All; \ No newline at end of file diff --git a/src/exchange/Plate/Index.js b/src/exchange/Plate/Index.js new file mode 100644 index 00000000..e931978f --- /dev/null +++ b/src/exchange/Plate/Index.js @@ -0,0 +1,264 @@ +import React, { Component } from 'react'; +import { Pagination , Spin } from 'antd' +import {Link} from 'react-router-dom' +import '../exchange.css'; +import './plate.css' + +import Nav from '../NavComponent/Index'; +import MenuWraps from '../MenuComponent/Menu'; + + + +import PlateRight from './PlateRight' + +import axios from 'axios'; +import All from './All' + +const menu_nav = [ + { + name:"全部", + key:`all`, + content:All + }, + { + name:"推荐精华", + key:`is_fine`, + content:All + }, + { + name:"我的话题", + key:`my_memos`, + content:All + }, + { + name:"我参与的话题", + key:`my_topics`, + content:All + } +] +class Index extends Component { + constructor(props){ + super(props); + this.state = { + collectFlag:false, + + // 列表搜索相关 + page:1, + search:undefined, + pageSize:10, + select_type:"all", + + memos:undefined, + memos_count:0, + // 接口返回的所有数据 + data:undefined, + forum_tag :undefined, + forum_moders:undefined, + forum_sections:undefined, + bread_crumb:undefined, + current_user:undefined, + isSpin:true + } + } + + componentDidMount () { + this.InitData(); + } + + InitData=()=>{ + this.setState({ + isSpin:true + }) + const { plateid } = this.props.match.params; + const { page , search , select_type} = this.state; + this.getInfos(plateid , page , search , select_type); + } + + getInfos = (plateid , page , search , select_type) =>{ + const url= `/memos/forum_memos/${plateid}.json`; + axios.get(url,{params:{ + page, + search, + select_type + }}).then(result=>{ + if(result){ + this.setState({ + data:result.data, + memos:result.data.memos, + memos_count:result.data.memos_count, + collectFlag:result.data.watched, + forum_tag :result.data.bread_crumb && result.data.bread_crumb.forum_tag, + forum_moders:result.data.forum_moders, + forum_sections:result.data.forum_sections, + bread_crumb:result.data.bread_crumb, + current_user:result.data.current_user, + isSpin:false + }) + } + }).catch(error=>{ + + }) + } + + + // 点击收藏 + colectPlate = () =>{ + const { collectFlag } = this.state; + const { plateid } = this.props.match.params; + const url = `/memos/forum_memos/${plateid}/is_watch.json`; + // is_watch:1为添加关注 + axios.post(url,{ + is_watch: collectFlag ? 0 : 1 + }).then((result)=>{ + if(result){ + if(result.data.status === 0){ + this.setState({ + collectFlag:!collectFlag + }) + this.props.showNotification(result.data.message); + } + } + }).catch((error)=>{ + + }) + } + + // 搜索 + searchEvent=(e)=>{ + this.setState({ + search:e + }) + const { plateid } = this.props.match.params; + const { select_type } = this.state; + this.getInfos(plateid , 1 , e , select_type); + } + + // 切换菜单项 + changeTabEvent = (key) =>{ + this.setState({ + select_type:key, + isSpin:true + }) + const { plateid } = this.props.match.params; + + const { search} = this.state; + this.getInfos(plateid , 1 , search , key); + } + + // 切换分页 + changePageEvent=(pageNum)=>{ + this.setState({ + page:pageNum + }) + const { plateid } = this.props.match.params; + + const { search , select_type} = this.state; + this.getInfos(plateid , pageNum , search , select_type); + } + + render(){ + let { + title, + collectFlag , + memos , + forum_tag , + select_type, + forum_moders , + forum_sections , + page, + data, + pageSize, + bread_crumb , + current_user, + isSpin } = this.state; + + const { plateid } = this.props.match.params; + let pathname = this.props.location.pathname; + let urlLastLength = pathname.split("/").length; + let urlLast = pathname.split("/")[urlLastLength-1]; + + const children_bread_crumb = forum_tag && forum_tag.children_bread_crumb; + //获取当前版块标题 + const title_post=forum_tag && ((children_bread_crumb && children_bread_crumb.title) || forum_tag.title); + + console.log("c",children_bread_crumb) + // 顶部导航栏 + const routerMap = [ + { + name:current_user && current_user.username, + url:current_user && current_user.user_url + }, + { + name:bread_crumb && bread_crumb.forum && bread_crumb.forum.title, + url:"/forums" + }, + { + name:forum_tag && ((children_bread_crumb && children_bread_crumb.title) || forum_tag.title) + } + ]; + + let collectMap = current_user? this.colectPlate()}>{collectFlag ?'取消收藏':'收藏'}: 收藏 ; + + // 菜单行右侧按钮 + //只有登录管理员可见 + + const btn = (current_user && current_user.admin_permission) ?版块管理 : undefined; + console.log(btn); + + + // 操作列表item需要刷新页面以及切换菜单项需要重新调用参数 + const commonEvent = { + refresh:this.InitData, + changeTab:this.changeTabEvent + } + + // 列表分页 + const pageination = ( + data && data.memos_count > pageSize && +
    + +
    + ) + + + return( +
    + + + +

    + {title_post} + { collectMap } +

    + +
    +
    +
    + + + +
    + { pageination } +
    + +
    +
    +
    + ) + } +} +export default Index; \ No newline at end of file diff --git a/src/exchange/Plate/PlateRight.js b/src/exchange/Plate/PlateRight.js new file mode 100644 index 00000000..20a96c3f --- /dev/null +++ b/src/exchange/Plate/PlateRight.js @@ -0,0 +1,93 @@ +import React, { PureComponent } from 'react'; +import { getImageUrl } from 'educoder'; +import { Link } from 'react-router-dom'; +import '../exchange.css'; +import './plate.css' + +import ExchangeRightSearch from '../ExchangeRightSearch' +import Custom from '../CustomComponent/Index'; + +import axios from 'axios'; +class PlateRight extends PureComponent { + + // 申请版主 + applyModerator = () =>{ + this.props.confirm({ + content: '是否确认申请版主?', + + onOk: () => { + const { plateid } = this.props.match.params; + const url = `/forum_sections/${plateid}/user_apply`; + axios.post(url).then(result=>{ + if(result){ + this.props.showNotification(result.data.message); + } + }).catch(error=>{ + + }) + }, + onCancel() { + console.log('Cancel'); + }, + }); + } + + render(){ + + const { forum_sections , forum_moders , searchEvent , current_user }= this.props; + + // admin_permission:是否是版主 + const moderatorInfo = ( forum_moders && forum_moders.length > 0 && +
    +

    + + 版主 + { + current_user && current_user.admin_permission === false && 申请版主 + } +

    +
    + { forum_moders.map((item,key)=>{ + return( + + ) + }) } +
    +
    + ) + + + const choiceInfo = ( forum_sections && forum_sections.length > 0 && +
    +

    + + 精选版块 +

    + +
    + ) + + + return( +
    + + + { moderatorInfo } + + { choiceInfo } +
    + ) + } +} +export default PlateRight; \ No newline at end of file diff --git a/src/exchange/Plate/plate.css b/src/exchange/Plate/plate.css new file mode 100644 index 00000000..f1bb1cad --- /dev/null +++ b/src/exchange/Plate/plate.css @@ -0,0 +1,45 @@ + +/* plate */ +.collecting{ + height: 22px; + padding:0px 11px; + border: 1px solid #5091FF; + color: #5091FF; + border-radius: 4px; + line-height: 22px; + font-size: 12px; + float: left; + cursor: pointer; +} +.collected{ + color: #999999; + border:1px solid #999999; +} + +.applyBtn{ + border:1px solid #5091FF; + color: #5091FF; + height: 26px; + line-height: 26px; + padding:0px 8px; + border-radius: 4px; +} + +/* 版主 */ +.moderatorPanel{ + display: flex; + flex-wrap:wrap; + padding: 10px 15px 0px; +} + +/* 精选版块 */ +.choicePlate{ + padding:10px 20px 0px 20px; +} +.choicePlate > li{ + padding: 10px 0px; +} + +.searchForHide .ant-tabs-bar.ant-tabs-top-bar{ + display: none; +} \ No newline at end of file diff --git a/src/exchange/Post/CommentsIndex.js b/src/exchange/Post/CommentsIndex.js new file mode 100644 index 00000000..ed878d8d --- /dev/null +++ b/src/exchange/Post/CommentsIndex.js @@ -0,0 +1,155 @@ +import React, { PureComponent } from 'react'; +import './post.css' +import Item from '../Comments/CommentsItem' +import ItemImg from '../Comments/CommentsItemImg' +import axios from 'axios'; + +import CommentsSend from '../Comments/CommentsSend'; + + + +class CommentsIndex extends PureComponent{ + + // 调用父组件的刷新方法 + refreshReply=()=>{ + let { refresh , page} = this.props; + refresh(page); + } + + // 删除评论 + deleteReplyEvent=(id)=>{ + const url = `/memos/${id}/destroy.json` + axios.post(url).then((result)=>{ + if(result){ + this.props.showNotification(result.data.message); + this.refreshReply(); + } + }).catch((error)=>{ + + }) + } + + commentReplyEvent=(index,flag)=>{ + console.log("1",flag); + this.props.showCommentEvent(index,true); + } + + + + // 点赞评论 + praiseEvent=(id)=>{ + const url = `/discusses/${id}/plus.json`; + axios.post(url,{ + container_type:'Memo', + type:1 + }).then(result=>{ + if(result){ + this.refreshReply(); + } + }).catch(error=>{ + + }) + } + + parseCommentContent = (oldContent) => { + if (oldContent && oldContent.startsWith('<') && oldContent.endsWith('>')) { + } else if (window.$('#md_div').length) { // 有这个临时处理md内容的dom + window.$('#md_div').html('') + // markdown to html + try { + var markdwonParser = window.editormd.markdownToHTML("md_div", { + markdown: oldContent, + emoji: true, + htmlDecode: "style,script,iframe", // you can filter tags decode + taskList: true, + tex: true, // 默认不解析 + flowChart: true, // 默认不解析 + sequenceDiagram: true // 默认不解析 + }); + oldContent = window.$('#md_div').html() + } catch (e) { + // TODO 可能公式parse时报错了 + console.error(e) + } + } + return oldContent; + } + + render(){ + // 评论列表,当前用户信息 + const { repliesData , current_user , page } = this.props; + const renderNum = (arrs,flag) =>{ + return(

    展开其余1条评论

    ) + } + + //二级评论 + const renderChild = (arrs) => { + return( +
    + { + arrs.map((child)=>{ + return( +
    + +
    + +
    +
    + ) + }) + } +
    + ) + } + + const replyInfoWrap = (i,index)=> ( + +

    + this.praiseEvent(i.id)}> + + {i.praise_count} + + { + current_user && (current_user.is_banned === false || current_user.admin) && + this.commentReplyEvent(index,i.commentsFlag)}> + {i.replies_count} + + } +

    + { + i.commentsFlag && + + } +
    + ) + + // 判断是否是管理员或者版主 + const manage = current_user && (current_user.admin || current_user.banned_permission); + const itemMap = repliesData && repliesData.map((i,index)=>{ + let _content = this.parseCommentContent(i.content); + return( +
    +
    + +
    + + { + i.children && i.children.length > 0 && +
    + {renderChild(i.children)} + {/* { i.children.length > 1 && renderNum(i.children)} */} +
    + } + + {replyInfoWrap(i,index)} +
    +
    +
    + ) + }) + + return( itemMap ) + } +} + +export default CommentsIndex; \ No newline at end of file diff --git a/src/exchange/Post/ImageUpload.js b/src/exchange/Post/ImageUpload.js new file mode 100644 index 00000000..dc15691a --- /dev/null +++ b/src/exchange/Post/ImageUpload.js @@ -0,0 +1,128 @@ +import React, { Component } from 'react'; + +import moment from 'moment' +import Select, {Option, OptGroup} from 'rc-select'; +import 'rc-select/assets/index.css'; + +import { Upload, Icon, Modal, message } from 'antd'; + + +import 'antd/lib/upload/style/index.css' +import 'antd/lib/modal/style/index.css' +import 'antd/lib/style/index.css' +import 'antd/lib/message/style/index.css' +import './MemoNew.css' +// ------------------------------------------- + + +let uploadValidateFailed = false; +function beforeUpload(file) { + const isJPG = file.type === 'image/jpeg'; + const isPNG = file.type === 'image/png'; + const isGIF = file.type === 'image/gif'; + if (!isJPG && !isPNG && !isGIF) { + message.error('只能上传图片文件!(jpg、png或gif)'); + uploadValidateFailed = true; + return false; + } + const isLt2M = (file.size / 1024 / 1024) < 2; + if (!isLt2M) { + uploadValidateFailed = true; + message.error('图片大小必须小于 2MB!'); + return false; + } + uploadValidateFailed = false; + return true; +} + +class ImageUpload extends Component { + state = { + previewVisible: false, + previewImage: '', + fileList: [ + // { + // uid: -1, + // name: 'xxx.png', + // status: 'done', + // url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', + // } + ], + }; + + handleCancel = () => { + + this.setState({ previewVisible: false }) + } + + handlePreview = (file) => { + this.setState({ + previewImage: file.url || file.thumbUrl, + previewVisible: true, + }); + } + + handleRemove = () => { + const { onImageUploadRemove } = this.props; + onImageUploadRemove() + } + + componentWillReceiveProps(newProps, oldProps) { + // 初始化值 + if (newProps.fileList && this.props.fileList.length != newProps.fileList.length) { + this.setState({ + fileList: newProps.fileList + }) + } + } + + handleChange = ({ fileList }) => { + + const { onImageUploadDone } = this.props; + if (fileList.length && fileList[0].status === 'done') { + onImageUploadDone(fileList[0]) + } + if (!uploadValidateFailed) { + this.setState({ fileList }) + } + } + + + + render() { + const { previewVisible, previewImage, fileList } = this.state; + const { currentMemoId } = this.props; + const uploadButton = ( +
    +
    +
    点击上传封面
    +
    只支持JPG、PNG、JPEG大小不超过2M
    +
    建议尺寸4:3
    +
    + ); + + return ( +
    + + {fileList.length >= 1 ? null : uploadButton} + + + example + +
    + ); + } +} + +export default ImageUpload; diff --git a/src/exchange/Post/Index.js b/src/exchange/Post/Index.js new file mode 100644 index 00000000..90beaa1d --- /dev/null +++ b/src/exchange/Post/Index.js @@ -0,0 +1,248 @@ + +import React, { Component } from 'react'; +import { Pagination , Spin } from 'antd'; + +import '../exchange.css' +import './post.css' + +import Nav from '../NavComponent/Index' +import Parse from './Parse'; +import ExchangeItem from '../ExchangeItem' + +import CommentsIndex from './CommentsIndex'; +import CommentsSend from '../Comments/CommentsSend'; +import RenderHtml from "../../components/render-html"; + +import FileList from '../../common/FileList'; + +import update from 'immutability-helper' + +import axios from 'axios'; + +class Index extends Component{ + constructor(props){ + super(props); + this.state={ + // 当前用户是否点赞 + judge:true, + parseNum:0, + // 帖子用户信息 + author_info:undefined, + // 当前用户信息 + current_user:undefined, + // 面包屑 + bread_crumb:undefined, + // 当前帖子详情 + memos:undefined, + // 帖子评论 + repliesData:undefined, + // 帖子评论分页相关 + replyPage:1, + replyPageSize:10, + replyCount:0, + is_Spin:true + } + } + + componentDidMount = () =>{ + this.getInfo(); + } + + getInfo=()=>{ + this.InitDetailInfo(); + this.getReply(1); + } + + InitDetailInfo = ()=>{ + let postid = this.props.match.params.postid; + const url = `/memos/${postid}.json`; + axios.get(url).then((result)=>{ + if(result.data && result.data.status === -1){ + this.props.history.push("/forums"); + } + if(result){ + this.setState({ + judge:result.data.memo.user_praise, + parseNum:result.data.memo && result.data.memo.praises_count, + author_info:result.data.author_info, + current_user:result.data.current_user, + bread_crumb:result.data.bread_crumb, + memos:result.data.memo, + is_Spin:false + }) + } + }).catch((error)=>{ + + }) + } + + getReply = (replyPage) =>{ + let postid = this.props.match.params.postid; + const url = `/memos/${postid}/more_reply.json`; + axios.get(url,{params:{ + page:replyPage + }}).then((result)=>{ + if(result){ + this.setState({ + repliesData:result.data.memo_replies, + replyCount:result.data.memos_count, + is_Spin:false + }) + } + }).catch((error)=>{ + + }) + } + + // 点赞 + thumbForum = () =>{ + let postid = this.props.match.params.postid; + const url = `/discusses/${postid}/plus.json` + axios.post(url,{ + container_type:'Memo', + type:1 + }).then((result)=>{ + if(result){ + this.InitDetailInfo(); + } + }).catch((error)=>{ + + }) + } + + // 切换评论分页 + changeReplyEvent=(pageNumber)=>{ + this.setState({ + replyPage:pageNumber + }) + this.getReply(pageNumber); + } + + // 点击显示评论输入框 + commentReplyEvent=(index,flag)=>{ + console.log("2",flag); + + this.setState( + (prevState) => ({ + repliesData : update(prevState.repliesData, {[index]: { commentsFlag: {$set: flag} }}), + }) + ) + } + + // 删除评论 + deleteReplyEvent=(id)=>{ + const url = `/memos/${id}/destroy.json` + axios.post(url).then((result)=>{ + if(result){ + this.props.showNotification(result.data.message); + let{ replyPage } = this.state; + this.getReply(replyPage); + } + }).catch((error)=>{ + + }) + } + + render(){ + let { + judge , parseNum , author_info , current_user , bread_crumb , memos , repliesData , + replyPage, + replyPageSize, + replyCount, + is_Spin + } = this.state; + let postid = this.props.match.params.postid; + + const NavMap=[ + { + url:`/users/${current_user && current_user.login}`, + name:current_user && current_user.username + }, + { + url:"/forums", + name:bread_crumb && bread_crumb.forum && bread_crumb.forum.title + }, + { + url:`/forums/theme/${bread_crumb && bread_crumb.forum_tag && bread_crumb.forum_tag.id}`, + name:bread_crumb && bread_crumb.forum_tag && bread_crumb.forum_tag.title + }, + { + name:"帖子详情" + } + ] + + //插入字段从author_info表内选取 + const memos_list = [{ + ...memos, + image_url:author_info && author_info.image_url, + username:author_info && author_info.username, + user_login:author_info && author_info.login + }]; + + // 评论列表 + const memo_replies = repliesData; + const repliesList = ( + memo_replies && memo_replies.length > 0 && +
    +

    + 全部回复 + {replyCount} +

    + +
    + ) + + // 附件显示 + const fileListCom = ( memos && memos.attachment_url && ) + + return( + +
    + + +
    + + {/* 调用和首页共用的列表item,传了enshine就代表底部右侧操作按钮只有收藏或者取消收藏,否则就是置顶、推荐等 */} + + +
    + {/* 帖子详情 */} + + {/* 文件列表 */} + { fileListCom } + + {/* 点赞 */} +
    + +
    + + {/* 发送评论部分 */} + { + current_user && (current_user.is_banned === false || current_user.admin) && + this.getReply(replyPage)}/> + } + {/* 评论列表 */} + { repliesList } +
    +
    + { + replyCount && replyCount > replyPageSize ? +
    + +
    :"" + } + +
    +
    + ) + } +} + +export default Index; \ No newline at end of file diff --git a/src/exchange/Post/MemoNew.css b/src/exchange/Post/MemoNew.css new file mode 100644 index 00000000..7a7cc758 --- /dev/null +++ b/src/exchange/Post/MemoNew.css @@ -0,0 +1,128 @@ +.compilegoback{ + float:right; + color:#676767 !important; + cursor: pointer; +} + +.compilegodell{ + float:right; + margin-right:20px; + color:#dadada; + cursor: pointer; +} + +.Releasethetitle{ + height: 48px !important; + padding-left: 20px !important; + background:#f4f4f4 !important; +} +.Releasethetitle:focus{ + background:#FFF !important; +} +.Releasethetitle::-webkit-input-placeholder{ + color:#999999; +} +.Releasethetitle:-moz-placeholder{ + color:#999999; +} +.Releasethetitle::-moz-placeholder{ + color:#999999; +} +.Releasethetitle:-ms-input-placeholder{ + color:#999999; +} +.ecSelectbox{ + margin-top: 30px; +} + +.ant-select-selection__placeholder{ + color:#999999; +} + +.antuploadName{ + width: 280px; + height: 170px; +} + +.antuploadName div:nth-child(2){ + color:#999898; + font-size:16px; +} +.antuploadName div:nth-child(3){ + margin-top: 10px; + color:#d2d2d2; +} +.antuploadName div:nth-child(4){ + margin-top: 10px; + color:#d2d2d2; +} +.antIconName{ + width: 30px; + height: 30px; + background: #21B351; + border: 1px solid #21B351; + border-radius: 50%; + color: #FFF; + text-align: center; + line-height: 25px; + margin: 40px auto 12px; + font-size: 20px; + position: relative; + } + .antIconName i{ + position: absolute; + top: 4px; + left: 3.8px; + } + .ReleasTopic{ + color:#333; + font-size:18px; + } + +.ant-calendar-picker-input::-webkit-input-placeholder{ + color:#999999; +} +.ant-calendar-picker-input:-moz-placeholder{ + color:#999999; +} +.ant-calendar-picker-input::-moz-placeholder{ + color:#999999; +} +.ant-calendar-picker-input:-ms-input-placeholder{ + color:#999999; +} +.ml57{ + margin-left:57px; +} +.newdefalutSubmitbtn{ + width: 120px !important; + height: 38px !important; + line-height: 38px !important; + margin-top: -5px; +} +.newdefalutCancelbtn{ + width: 120px !important; + height: 38px !important; + line-height: 38px !important; + margin-top: -5px; + border: 1px solid #CDCDCD; + +} +.ecSelect{ + background: #f4f4f4 !important; + padding-left: 4px !important; + height: 48px; + overflow: hidden; + width: 526px; + position: relative; +} +.newLeftgrey{ + margin-left: 18px; +} +.uploadBtnclick{ + margin-left: 34px; +} +.ant-select-selection--multiple{ + height:100%; + border: 1px solid transparent; +} diff --git a/src/exchange/Post/MemoNew.js b/src/exchange/Post/MemoNew.js new file mode 100644 index 00000000..23a55717 --- /dev/null +++ b/src/exchange/Post/MemoNew.js @@ -0,0 +1,811 @@ +import React, { Component } from 'react'; + + +import axios from 'axios'; + + + +import { Select } from 'antd'; + +import 'antd/lib/select/style/index.css' + +import 'antd/lib/date-picker/style/index.css' + +import zhCN from 'antd/lib/date-picker/locale/zh_CN'; + +import './MemoNew.css' +import './post.css' +import '../exchange.css' + + +import ImageUpload from './ImageUpload' + +const Option = Select.Option; + + +const $ = window.$; +const isDevServer = window.location.port === "3007"; +let origin = window.location.origin; +let path = "/editormd/lib/" // origin + '/react/build/js/editormd/lib/' +if (isDevServer) { + origin = 'http://localhost:3000' + path = 'http://localhost:3000/editormd/lib/' +} + +// load +if (!window.postUpMsg) { + $.getScript( + `${origin}/javascripts/attachments.js`, + (data, textStatus, jqxhr) => { + + }); +} + +// editorMD to create +/** + * + * @param id 渲染DOM的id + * @param width 宽度 + * @param high 高度 + * @param placeholder + * @param imageUrl 上传图片的url + * @returns {*} 返回一个editorMD实例 + */ +function create_editorMD(id, width, high, placeholder, imageUrl, callback){ + var editorName = window.editormd(id, { + width : width, + height : high, + syncScrolling : "single", + //你的lib目录的路径,我这边用JSP做测试的 + path : path , // "/editormd/lib/" + tex : true, + tocm : true, + emoji : true, + taskList : true, + codeFold : true, + searchReplace : true, + htmlDecode : "style,script,iframe", + sequenceDiagram : true, + autoFocus: false, + toolbarIcons : function() { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear" ] + }, + toolbarCustomIcons : { + testIcon : "
    ", + testIcon1 : "
    " + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea : true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity : 0.6, + placeholder: placeholder, + imageUpload : true, + imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL : imageUrl,//url + onload: function(){ + // this.previewing(); + $("#"+ id +" [type=\"latex\"]").bind("click", function(){ + editorName.cm.replaceSelection("```latex"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("\n"); + editorName.cm.replaceSelection("```"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line-1, 0); + }); + + $("#"+ id +" [type=\"inline\"]").bind("click", function(){ + editorName.cm.replaceSelection("$$$$"); + var __Cursor = editorName.cm.getDoc().getCursor(); + editorName.cm.setCursor(__Cursor.line, __Cursor.ch-2); + editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + callback && callback() + } + }); + return editorName; +} + + +class MemoNew extends Component { + constructor(props) { + super(props) + + this.state = { + memoSubject: '', + memoContent: '', + memoType: undefined, + memoTime: undefined, + memoRepertoire: '', + memoLanguage: [], + fileList: [], + memoSubjectLength:undefined, + repertoires: [], + currentSelectRepertoiresIndex: -1, + repertoiresTagMap: {}, + // 主题板块 + smallOption:undefined, + bigPlateId:undefined, + smallPlateId:undefined, + } + } + onCommit() { + const { memoSubject , memoLanguage, currentMemoId, attachmentData , bigPlateId , smallPlateId} = this.state; + const { showSnackbar } = this.props; + + this.setState({ + memoSubjectLength : memoSubject.length + }) + + if (!memoSubject) { + showSnackbar('请先输入标题') + return + } + let mdVal; + try { + mdVal = this.taskpass_editormd.getValue() + + } catch (e) { + showSnackbar('编辑器还未加载完毕,请稍后') + return + } + + if (!mdVal) { + showSnackbar('请输入话题内容') + return + } + if (!bigPlateId) { + showSnackbar('请选择一级板块'); + return + } + /* + + + + 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 = {}; + let lastIndex = 0; + $('#attachments_fields .attachment').each(( index, item ) => { + const filename = $(item).find('.upload_filename').val(); + // $($('#attachments_fields .attachment')[0]).find('input:nth-child(6)').val() + const token = $(item).find('input:nth-child(6)').val() + const attachment_id = $(item).find('input:nth-child(7)').val() + attachmentsMap[index] = { + filename, + token, + attachment_id + } + lastIndex = index; + }) + + if (attachmentData) { + const { response } = attachmentData + lastIndex++; + attachmentsMap[lastIndex] = { + filename: attachmentData.name, + token: '', + attachment_id: response.attachment_id + } + } + + if (currentMemoId) { + this.updateMemo(attachmentsMap) + } else { + this.newMemo(attachmentsMap) + } + } + onCancel() { + const { currentMemoId } = this.state; + if (currentMemoId) { // 编辑 + this.props.history.push(`/forums/${currentMemoId}`) + } else { // 新建 + this.props.history.push(`/forums`) + } + } + onOkTime(value, dateString){ + this.setState({ + memoTime:dateString + }) + } + updateMemo(attachmentsMap) { + const { memoSubject , currentMemoId, content, attachmentData , smallPlateId , bigPlateId} = this.state; + + const mdVal = this.taskpass_editormd.getValue() + console.log('isContentEdit: ', mdVal === content); + const newMemoUrl = `/memos/${currentMemoId}/update` + const params = { + content_changed: this.contentChanged, + memo: { + subject: memoSubject , + content: mdVal, + }, + forum_id:bigPlateId, + attachments: attachmentsMap, + children_forum_id:smallPlateId + } + + if (attachmentData) { + const attachment_id = attachmentData.response.attachment_id + if (attachment_id) { + params.attachment_id = attachment_id; + } + } + axios.post(newMemoUrl, params) + .then((response) => { + const { status, message } = response.data; + if (status === 0) { + window.$("html,body").animate({"scrollTop":0}) + this.props.history.push(`/forums/${currentMemoId}`) + } else { + if (message.indexOf("Couldn't find Attachment with") !== -1) { + this.props.showSnackbar('附件不存在或正在被删除中,请稍后再试。。。') + } else { + this.props.showSnackbar(message) + } + } + }).catch((error) => { + console.log(error) + }) + } + newMemo(attachmentsMap) { + const { memoSubject , attachmentData , smallPlateId , bigPlateId } = this.state; + const mdVal = this.taskpass_editormd.getValue() + const newMemoUrl = `/memos/create` + const params = { + memo: { + subject: memoSubject , + content: mdVal + }, + forum_id:bigPlateId, + attachments: attachmentsMap, + children_forum_id:smallPlateId, + } + if (attachmentData) { + const attachment_id = attachmentData.response.attachment_id + if (attachment_id) { + params.attachment_id = attachment_id; + // params.filename = attachmentData.name // 服务端处理 服务端使用默认的origin_filename + } + } + axios.post(newMemoUrl, params).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 { + if (message.indexOf("Couldn't find Attachment with") !== -1) { + this.props.showSnackbar('附件不存在或正在被删除中,请稍后再试。。。') + } else { + this.props.showNotification(message) + } + } + }).catch((error) => { + console.log(error) + }) + } + onMemoDelete(memo) { + const deleteUrl = `/memos/${memo.id}`; + // 获取memo list + axios.delete(deleteUrl, { + withCredentials: true, + }) + .then((response) => { + const status = response.data.status + if (status === 0) { + this.props.showSnackbar('删除成功'); + this.props.history.push(`/forums`) + } + }).catch((error) => { + console.log(error) + }) + } + componentWillUnmount() { + $('body>#root').off('onMemoDelete') + } + componentDidMount(){ + $('body>#root').on('onMemoDelete', (event) => { + // const val = $('body>#root').data('onMemoDelete') + const val = window.onMemoDelete ; + this.onMemoDelete( JSON.parse(decodeURIComponent(val)) ) + }) + const newMemoUrl = `/memos/new` + axios.get(newMemoUrl,{ + // withCredentials: true, + }) + .then((response) => { + const data = response.data; + + if ( data.current_user ) { + this.setState({ + memo_tag: data.memo_type, + memoTime:"" + }) + + const user = response.data.current_user; + user.tidding_count = response.data.tidding_count; + // this.props.initCommonState(user) + + // 初始化 csrf meta + const $ = window.$ + $('head').append( $('') ) + $('head').append( $(``) ) + } + }).catch((error) => { + console.log(error) + }) + + // 如果是编辑 + const { match } = this.props + const memoId = match.params.memoId; + if (memoId) { + const memoUrl = `/memos/${match.params.memoId}/edit`; + + axios.get(memoUrl).then((response) => { + const current_user = response.data.current_user; + if (current_user) { + + const { content, forum_section, id, subject , attachments_url, memo_image_info, + memo_type, published_at , children_forum_section} = response.data; + let date; + let date_value; + this.initMD(content, memoId); + if(published_at){ + date = new Date(published_at); + date_value=date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds(); + } + const newState = { + currentMemoId: id, + attachments_url, + memoSubject: subject, + memo_tag: memo_type, + memoLanguage: forum_section.forum_id, + memoTime:date_value, + content, + bigPlateId: forum_section.forum_id, + smallPlateId: children_forum_section.children_forum_id + } + // 编辑,初始化小板块的下拉选项(如果大板块有值) + this.getChildPlate(memo_type,forum_section && forum_section.forum_id); + + if (memo_image_info && memo_image_info.id) { + newState.fileList = [{ + uid: memo_image_info.id, + name: memo_image_info.filename, + status: 'done', + url: memo_image_info.url, + }] + + newState.attachmentData = { // 初始化 + name: memo_image_info.filename, + response: { + attachment_id: memo_image_info.id, + } + } + } + this.setState({...newState}) + + + // 加载完后滚动条滚动 + window.$("html,body").animate({"scrollTop":0}) + + // this.props.initForumState({ + // current_user, + // tag_list + // }) + } + + }).catch((error) => { + console.log(error) + }) + } else { + this.initMD(); + } + } + initMD(initValue, memoId) { + this.contentChanged = false; + const placeholder = ""; + // amp; + // 编辑时要传memoId + const imageUrl = `/upload_with_markdown?container_id=${memoId?memoId:''}&container_type=Memo`; + // 创建editorMd + + setTimeout(()=>{ + const taskpass_editormd = create_editorMD("memoMD", '100%', 400, placeholder, imageUrl, () => { + setTimeout(()=>{ + taskpass_editormd.resize() + taskpass_editormd.cm && taskpass_editormd.cm.refresh() + }, 500) + + if (initValue) { + taskpass_editormd.setValue(initValue) + } + taskpass_editormd.cm.on("change", (_cm, changeObj) =>{ + console.log('....contentChanged') + this.contentChanged = true; + }) + }); + this.taskpass_editormd = taskpass_editormd; + window.taskpass_editormd = taskpass_editormd; + }, 300) + + + } + + renderOptions(array) { + const elementArray = []; + array.forEach(( item, index ) => { + elementArray.push( + + ) + }) + return elementArray + } + onRepertoiresChange(value) { + + const index = this.state.repertoires.indexOf(value) + + this.setState({ + currentSelectRepertoiresIndex: index, + memoRepertoire: value, + memoLanguage: [] + }); + }; + onTagChange(value) { + if (value && value.length > 3) { + this.props.showSnackbar(`最多选择3个技术标签`) + + return; + } + this.setState({ + memoLanguage: value + }) + } + onTypeChange(value) { + + this.setState({ + memoType: value + }) + } + onMemoNameChange(e) { + this.setState({ + memoSubject: e.target.value + }) + } + renderMemoType() { + const { memo_type } = this.state; + if (!memo_type || memo_type.length === 0) { + return '' + } + const result = [] + // memo_type.map((item, index) => ) + memo_type.forEach((item, index) => { + result.push() + }) + + return result; + } + renderTag() { + let { memo_tag } = this.state; + if (!memo_tag || memo_tag.length === 0) { + return '' + } + const result = [] + + memo_tag.forEach((item, index) => { + result.push() + }) + + return result; + + } + renderAttachment() { + const { attachments_url } = this.state; + const attachments = [] + attachments_url.forEach((item, index) => { + const ar = item.url.split('/') + + attachments.push( + + + + + + + +
    + + +
    +
    +
    + ) + }) + return attachments; + } + _findById(id, arg_items) { + if (!arg_items) { + return undefined + } + const items = arg_items; + for(let i = 0; i < items.length; i++) { + if (id === items[i].id) { + return i; + } + } + } + // 是否是技术动态吧 + _isTechShare() { + const { memoType, memo_type } = this.state + const index = this._findById(memoType, memo_type) + return !!index && memo_type[index] && memo_type[index].name.indexOf('技术问答') !== -1 + } + onImageUploadDone = (data) => { + this.setState({ + attachmentData: data + }) + } + onImageUploadRemove = () => { + const { attachment_id } = this.state.attachmentData.response; + const deleteUrl = `/attachments/${attachment_id}.js?attachment_id=1`; + // 获取memo list + axios.delete(deleteUrl, { + withCredentials: true, + }) + .then((response) => { + const data = response.data + if (data) { + this.setState({ + attachmentData: undefined + }) + this.props.showSnackbar('删除成功'); + } + }).catch((error) => { + console.log(error) + }) + } + + // 切换大板块 + changeLargeOption=(value)=>{ + const { memo_tag } = this.state; + this.getChildPlate(memo_tag,value); + } + + getChildPlate =(memo_tag,value)=>{ + let listFilter = memo_tag && memo_tag.length > 0 && memo_tag.filter((item=> item.id === value))[0]; + let list = listFilter && listFilter.children_tags; + this.setState({ + smallOption:list && list.map(item=>{ + return( + + ) + }), + bigPlateId:value, + smallPlateId: list && list.length > 0 ? (list[0].id || undefined) : undefined + }) + } + + // 切换二级板块 + changeSmallOption=(value)=>{ + this.setState({ + smallPlateId:value + }) + } + + render() { + const { match } = this.props + const { + memoSubject , + attachments_url, + currentMemoId, + fileList, + memoSubjectLength , + memo_tag, + smallOption, + bigPlateId, + smallPlateId + } = this.state; + const memoId = match.params.memoId; + console.log("bigPlateId",bigPlateId); + return ( +
    +

    { memoId ? '编辑' : '新建'}

    + +
    +
    +
    + *标题: +
    + this.onMemoNameChange(val)} placeholder="请输入发布标题,最大限制50字符"> + +
    +
    + + 必填项 + +
    +
    + + + {/* 发布时间 */} + {/*
    + +
    + this.onOkTime(value, dateString)} + /> +
    +
    + + 必填项 + +
    +
    */} + + {/*

    内容

    */} +
    + *内容: +
    +
    + +
    +
    +
    + + 必填项 + +
    +
    + +
    + + { attachments_url && !!attachments_url.length && + this.renderAttachment() + } + + + {debugger;window.addInputFiles( window.$('.file_selector')[0] ) }} + style={{'display':'none'}} type="file"> + + + + + {/* 请求status 422 X-CSRF-Token: eVo38laEF880o3cwZ/0F9kH01q4jMkriuVRemIBq06Y= */} + + + {/* 选择了技术问答才显示树标签 */} + {/* this._isTechShare() && +
    +
    +

    技术标签

    +
    + * + +
    + +
    + +
    + + 必填项 + +
    +
    +
    +
    */} +
    + *主题板块: +
    + {/* */} + {/* */} + + +
    +
    + + 必填项 + +
    +
    + + {/* */} +
    + 上传封面: +
    + +
    +
    + + 必填项 + +
    +
    +
    +
    + + +
    + ); + } +} + +const children = []; +for (let i = 10; i < 36; i++) { + children.push(); +} + +export default MemoNew; diff --git a/src/exchange/Post/New.js b/src/exchange/Post/New.js new file mode 100644 index 00000000..889e36e3 --- /dev/null +++ b/src/exchange/Post/New.js @@ -0,0 +1,277 @@ +import React, { PureComponent } from 'react'; + +import {appendFileSizeToUploadFileAll ,appendFileSizeToUploadFile} from 'educoder'; +import { Form , Input , Upload ,Button , Select , Icon , message } from "antd"; +import './post.css' +import '../exchange.css' + +import axios from 'axios'; + +import MDEditor from '../../common/MDEditor'; + +const Option = Select.Option; +const uploadButton = ( +
    + +
    点击上传封面
    +

    只支持JPG、PNG、JPEG大小不超过2M建议尺寸4:3

    +
    +) + +function getBase64(img, callback) { + debugger; + const reader = new FileReader(); + reader.addEventListener('load', () => callback(reader.result)); + reader.readAsDataURL(img); +} + + +class New extends PureComponent{ + constructor(props){ + super(props); + this.contentMdRef = React.createRef(); + this.state={ + // 封面图 + imageUrl:undefined, + // 大板块下拉选项 + memo_type:undefined, + // 小板块 + smallOption:undefined, + // 附件列表 + contentFileList:undefined, + } + } + + componentDidMount = () =>{ + this.getInfo(); + } + + // 获取信息 + getInfo = () =>{ + let url = '/memos/new'; + axios.get((url)).then((result)=>{ + if(result){ + this.setState({ + memo_type:result.data.memo_type + }) + } + }).catch((error)=>{ + + }) + } + + changeUploadImage =(info)=>{ + if (info.file.status === 'done') { + // Get this url from response in real world. + getBase64(info.file.originFileObj, imageUrl => + this.setState({ + imageUrl + }), + ); + } + } + + // 切换大板块 + changeLargeOption=(value)=>{ + // console.log(value); + const { memo_type } = this.state; + let list = memo_type.filter((item=> item.id === value))[0].children_tags; + // console.log(list); + this.setState({ + smallOption:list && list.map(item=>{ + return( + + ) + }) + }) + } + + // 提交 + handleSubmit=()=>{ + this.props.form.validateFieldsAndScroll((err, values) => { + console.log(values); + if(!err){ + let url=`/memos.json`; + axios.post((url),{ + forum_id:values.bigPlate, + children_forum_id:values.smallPlate, + memo:{ + subject:values.title, + content:values.description + } + }).then(result=>{ + if(result){ + this.props.showNotification(result.data.message); + this.props.history.push(`/forums/${result.data && result.data.memo_id}`); + } + }).catch(error=>{ + + }) + } + }) + } + + // 上传附件 + handleContentUploadChange = (info) => { + console.log("changeFIle==================>",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 + }) + } + } + // 上传附件-删除确认框 + 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,list)=>{ + console.log("delete===============>",file) + } + + + render(){ + const { getFieldDecorator } = this.props.form; + + /** 上传封面图 */ + let { imageUrl , memo_type , smallOption , contentFileList } = this.state; + + const largeOption = memo_type && memo_type.length > 0 && memo_type.map(item=>{ + return( + + ) + }) + + let uploadImg = ( imageUrl ? avatar : uploadButton ) + + // 上传封面图 + const uploadCover = { + listType:"picture-card", + className:"avatar-uploader", + showUploadList:false, + action:`/uploads.js`, + data: { attachment_id: 1 }, + onChange:this.changeUploadImage, + } + + /**上传附件 */ + const uploadProps = { + width: 600, + fileList: contentFileList, + multiple: true, + action: 'http://127.0.0.1:3000/uploads.js', + onChange: this.handleContentUploadChange, + onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'), + beforeUpload: (file) => { + console.log('beforeUpload', file.name); + const isLt150M = file.size / 1024 / 1024 < 150; + if (!isLt150M) { + this.props.showNotification('文件大小必须小于150MB!'); + } + return isLt150M; + }, + }; + return( +
    +

    新建

    +
    +
    + + + {getFieldDecorator('title', { + rules: [{ + required: true, message: '请输入帖子标题', + },{ + max: 5000 , message:'最大限制60个字符' + }], + })( + + )} + + + {getFieldDecorator('description', { + rules: [{ + required: true, message: '请输入帖子内容', + },{ + max: 5000 , message:'最大限制5000个字符' + }], + })( + + )} + + + + +
    + + { + getFieldDecorator('bigPlate',{ + rules:[{ + required:true,message:'请选择大板块' + }] + })( + + ) + } + + + { + getFieldDecorator('smallPlate',{ + rules:[{ + required:true,message:'请选择小板块' + }] + })( + + ) + } + +
    +
    + + + {uploadImg} + +
    + +
    +

    + + 取消 + + +

    + +
    + ) + } +} + +const WrappedNewPostForm = Form.create({ name: 'New' })(New); +export default WrappedNewPostForm; \ No newline at end of file diff --git a/src/exchange/Post/Parse.js b/src/exchange/Post/Parse.js new file mode 100644 index 00000000..2cb38398 --- /dev/null +++ b/src/exchange/Post/Parse.js @@ -0,0 +1,33 @@ +import React, { PureComponent } from 'react'; + +class Parse extends PureComponent{ + + render(){ + let { judge , num , clickEvent ,current_user} = this.props; + + const info = ( + current_user? (judge ? + + + {num} + + : + + + {num} + + ): + + + {num} + + ) + return( + + { info } + + ) + } +} + +export default Parse; \ No newline at end of file diff --git a/src/exchange/Post/post.css b/src/exchange/Post/post.css new file mode 100644 index 00000000..f9062c42 --- /dev/null +++ b/src/exchange/Post/post.css @@ -0,0 +1,157 @@ +.postDetail{ + padding:20px 0px; +} +.postContent{ + margin:0px 30px; + border-top: 1px solid #f4f4f4; +} + +.fileTeam{ + padding-bottom: 40px; +} +.fileTeam > li { + height: 18px; + line-height: 18px; + margin-bottom: 10px; +} + +/* parse.js */ +.forumParse{ + width: 72px; + height: 72px; + display: inline-flex; + align-items: center; + flex-flow: column; + background: #5091FF; + color: #fff!important; + border-radius: 50%; + padding-top: 7px; +} +.forumParse.parsed{ + background:#999999; +} + +/* 评论 */ +.replyTitle{ + line-height: 30px; + padding:20px; + border-bottom: 1px solid #f4f4f4; +} +.pre_stage{ + border-bottom: 1px solid #f4f4f4; + padding : 10px 0px; +} +.pre_stage:last-child{ + border-bottom: none; +} +.pre_stage .sub_stage{ + padding: 10px 20px; + box-sizing: border-box; + background: #fafafa; + position: relative; + margin-top: 20px; + border-radius:4px; +} +.pre_stage .sub_stage::before{ + position: absolute; + content: ""; + top:-20px; + z-index: 1; + left: 20px; + width: 0; + height: 0; + border-width: 10px; + border-style: solid; + border-color: transparent transparent #fafafa transparent; +} +.commentsItem_infos{ + display: flex; + padding:10px 0px 10px; +} +.commentsItem_infos .markdown-body{ + padding:0px; +} +.commentsItem_infos .editormd-html-preview,.commentsItem_infos .editormd-preview-container{ + background-color: unset; +} + +/* 新建 */ +.postNewform.ant-form .ant-row{ + display: flex; + align-items: top; +} +.postNewform.ant-form .ant-form-item-control-wrapper{ + flex: 1; +} +.postNewform.ant-form .ant-form-item-label,.postNewform .new_label{ + width: 90px; + text-align: right; + margin-right: 8px; + height: 40px; + line-height: 40px; + margin-top: 3px; + font-size: 16px +} +.postNewform.ant-form label{ + font-size: 16px; + color: #333; +} +.editorFromItem { + align-items: flex-start!important; + margin-bottom: 0px!important; +} +.editorFromItem .editormd.editormd-vertical{ + margin-bottom: 0px; +} +.editorFromItem .rememberTip{ + height: 20px; + line-height: 20px; +} +.newPostUpload{ + margin-left: 84px; +} +.newPostUpload .uploadBtn{ + border:none; + box-shadow: none; + color:#5091FF; + line-height: 30px; +} +.newPostUpload .ant-upload-list{ + padding-left: 100px; +} +.newPostUpload .ant-upload-list-item-info{ + padding:0px; + font-size: 15px; + height: 24px; + line-height: 24px; + max-width: 500px; + position: relative; +} +.selectItem .ant-select-selection--single{ + width: 200px; + margin-right: 20px; + height: 40px; +} +.selectItem .ant-select-selection__rendered{ + line-height: 40px; +} +/* 上传封面 */ +.uploadImageBox .ant-upload-picture-card-wrapper{ + width: 340px; + height: 248px; + border:none; + background: #fafafa; + display: flex; + flex-direction: column; + padding:0px 60px; + color: #999; +} +.uploadImageBox .ant-upload.ant-upload-select-picture-card{ + width: 100%; + height: 100%; + border: none; +} +.uploadImageBox .ant-upload.ant-upload-select-picture-card i{ + font-size: 44px!important; + color:#999; +} \ No newline at end of file diff --git a/src/exchange/SearchInfoComponent/Index.js b/src/exchange/SearchInfoComponent/Index.js new file mode 100644 index 00000000..0e527b23 --- /dev/null +++ b/src/exchange/SearchInfoComponent/Index.js @@ -0,0 +1,16 @@ +import React, { PureComponent } from 'react'; + +class Index extends PureComponent { + + render(){ + const {count, returnEvent} = this.props; + return( +

    + 共找到相关结果{count} + 返回 +

    + ) + } +} + +export default Index; diff --git a/src/exchange/TagComponent/Index.js b/src/exchange/TagComponent/Index.js new file mode 100644 index 00000000..2b670f44 --- /dev/null +++ b/src/exchange/TagComponent/Index.js @@ -0,0 +1,18 @@ +import React, { PureComponent } from 'react'; + +import { getImageUrl } from 'educoder'; + +class Index extends PureComponent { + + render(){ + let { topClass , bestClass } = this.props; + return( + + { topClass && } + { bestClass && } + + ) + } +} + +export default Index; \ No newline at end of file diff --git a/src/exchange/exchange.css b/src/exchange/exchange.css new file mode 100644 index 00000000..439cc4c4 --- /dev/null +++ b/src/exchange/exchange.css @@ -0,0 +1,289 @@ +.newContainer{ + padding:60px 0px 120px 0px; +} +ul,p{ + margin: 0px; +} +.flex1{ + flex: 1; + width: 0 +} +.ant-tabs-nav .ant-tabs-tab-active,.ant-tabs-nav .ant-tabs-tab:hover{ + color:#21B350!important; +} +/* shownotification的z-index */ +.ant-notification{ + z-index: 100000; +} +/* 小按钮 */ +.small-default-btn{ + height: 24px; + line-height: 24px; + padding: 0px 15px; + font-size: 12px; + background:rgba(244,244,244,1); + border-radius:2px; + color: #999; + display: inline-block; +} +.middle-default-btn{ + height: 30px; + line-height: 30px; + padding: 0px 15px; + font-size: 12px; + background:rgba(244,244,244,1); + border-radius:2px; + color: #999; + display: inline-block; +} +.small-blue-btn{ + background:rgba(80,145,255,1); + color:rgba(255,255,255,1); +} +.small-green-btn{ + background:#21B350; + color:rgba(255,255,255,1)!important; +} +.educontent{ + width: 1200px; + margin:0px auto; +} +.educontent-min{ + width: 960px; + margin:0px auto; +} +.F_panel{ + width: 1200px; + display: flex; + margin:30px auto; +} +.f_left_head{ + display: flex; + justify-content:space-between; + border-bottom: 1px solid #eaeaea; + padding-left:30px; + background: #fff; +} +.f_left_head > ul{ + display: flex; + align-items: center; + height:80px; + margin-bottom: 0px; +} +.f_left_head > ul >li{ + margin-right: 30px; + color: #666666 +} +.f_left_head > ul >li a{ + color: #666666 +} +.f_left_head > ul:first-child > li{ + font-size: 16px; + position: relative; + color: #333; +} +.f_left_head > ul:first-child > li.active a{ + color: #5091FF; +} +.f_left_head > ul:first-child > li.active a:after{ + position: absolute; + width: 100%; + bottom: -25px; + height: 2px; + background: #5091FF; + content: ''; + left: 0px; +} +.platePanel{ + top: 24px; + background: #fff; + left: 0px; + box-shadow:0px 6px 16px 0px rgba(7,12,70,0.2); + border-radius:4px; + max-width: 770px; + max-height: 500px; + padding:10px 10px 0px 10px; + overflow: auto; + box-sizing: border-box; +} +.platePanel .plateItem{ + display: flex; + padding-bottom:10px; + box-sizing: border-box; +} +.platePanel .plateItem .plateItem_h{ + color: #333; + margin:5px 20px 0px 10px; +} +.plateUl{ + flex: 1; +} +.plateUl li{ + position: relative; + margin-right: 11px; + color: #666; + float: left; + padding:5px 0px; + box-sizing: border-box; + margin-left: 10px; +} +.plateUl li:after{ + width: 1px; + position: absolute; + right: -12px; + height:10px; + background: #ccc; + top:11px; + content: '' +} +.plateUl li:last-child:after{ + display:none; +} +.radius{ + border-radius: 50%; +} +.flex1{ + flex: 1; +} +.color-blue { + color: #5091FF!important; +} +.flex-align-center{ + display: flex; + align-items: center; +} +.flex-align-top{ + display: flex; + align-items: flex-start; +} +.flex-align-bottom{ + display: flex; + align-items: flex-end; +} +/* 列表 */ +.plateTabulation{ + padding: 0px 30px; + box-sizing: border-box; + background: #fff; +} +.plateTabulation > li{ + border-bottom: 1px solid #f4f4f4; + padding:20px 0px; +} +.plateTabulation > li:last-child{ + border-bottom: none; +} +.exchangeItem-subject{ + font-size: 16px; + color: #333; + flex:1; + height: 20px; + line-height: 20px; + margin-right: 20px; +} +.flex_h{ + display: flex; + align-items: center +} +.sendPoint{ + font-size: 12px; + color: #999; + position: relative; + margin-left: 20px; + height: 18px; + line-height: 18px; +} +.sendPoint::before{ + position: absolute; + left: -10px; + top:3px; + height:12px; + width:1px ; + content: ''; + background: #ccc; +} +p{ + margin:0px;padding:0px +} +.edu-txt-center .ant-dropdown-menu-item,.edu-txt-center .ant-dropdown-menu-submenu-title{ + text-align: center; +} +.c_point{ + cursor: pointer; +} + +.top_Operate{ + position: relative; + background: #fff; + padding:20px; + margin-bottom: 20px; +} + +.top_Operate .send_btn{ + width: 188px; + height: 40px; + background: #5091ff; + text-align: center; + color: #fff; + font-size: 16px; + line-height: 40px; + display: block; + border-radius: 4px; +} +.top_Operate .searchfrom{ + position: absolute; + width: 40px; + right:20px; + top:20px; +} +.top_Operate .searchfrom.ant-input-affix-wrapper .ant-input-suffix{ + right:-2px +} +.top_Operate .searchfrom .ant-input-search-icon svg{ + width: 3em; + height: 1.3em; +} +.top_Operate .searchfrom.active{ + width: 250px; + z-index: 10; +} +.r_part_title{ + border-bottom: 1px solid #F4F4F4; + padding:20px; +} +.r_part_list{ + padding:20px; +} +.r_part_list li{ + margin-bottom: 20px; + color: #333; +} +.r_part_list li:last-child{ + margin-bottom: 0px; +} +/* InfoComponent */ +.icon-wrap{ + margin-left: 30px; + color: #ccc; + float: left; + line-height: 20px; +} +.icon-wrap > i{ + margin-right: 5px; + float: left; +} +/*給下拉列表的……添加高宽*/ +.addheight{ + background: url(./images/more.png) no-repeat right; + width: 30px; + height: 20px; + +} +/*帖子列表标题点击变颜色*/ +.is_onclick:hover{ + color: #5091FF; +} +/*帖子详情标题颜色不变*/ +.color_black{ + color: black; +} \ No newline at end of file diff --git a/src/exchange/images/box1.png b/src/exchange/images/box1.png new file mode 100644 index 0000000000000000000000000000000000000000..dacf54e348b381aa986acbbf901e98429d789252 GIT binary patch literal 3503 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 P00000NkvXXu0mjf0VHmA literal 0 HcmV?d00001 diff --git a/src/exchange/images/box3.png b/src/exchange/images/box3.png new file mode 100644 index 0000000000000000000000000000000000000000..f1fb2e4fa954f0da2da1568e8686a19f70af0764 GIT binary patch literal 6119 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 literal 0 HcmV?d00001 diff --git a/src/exchange/images/box4.png b/src/exchange/images/box4.png new file mode 100644 index 0000000000000000000000000000000000000000..34054d3e68bcad7370d9690417f7099d0f8a7c65 GIT binary patch literal 1824 zcmeAS@N?(olHy`uVBq!ia0y~yV3Yu|r*W_WSw$|(ffNH{age(c!@6@aFBurvZh5*m zhEy=Vy=#~k6Dq>?VCD@cJtmEi2&3!;3l}bNSkw5Xku@MdIZ)`Dz_i8{9WVB#TeKmSo_QuuB6^!;%)pD%VFet-Pm*7(z% zG754s(T~6GuMbr(-c?=k?bk`!uOC;X%<(yO=;ga_dVg>Jk1L-kv~zmdq=_@D6_d~3 z={~(>mi6A}>HX`%KVP!jx!W@S>`9rTEvqJf-1;(Z&zA6MlH2G0y|U(w(a*k5axu$7 zQ`17#A8*?%e}C#-r!~*E8E49_-nUBp@fN!!mU2sV3>#&6W+(`p z5)w`bE8Q)5?xRL(C+C|4rk>w37?ceYnjAE|eHuPKwL0JdQ}%7Y{oh9~t;6kW<^I)7 zej0E0`yKQ9pKadnm$ImFv}`)kz{#{w$B^;ZZ9Yb~qysFC0n;Q592KUhviS&bq;@h2 zvpC(X-p6>%n-k8DOk(QUF3Z#d)e5#0VjDBaM3B^UA+RICe6X@N!Lu3NcIrR4yrx$C zs=|ZppoYMA+#EjlT}?SSe9+lHW;lZ+ZWw^HC>VfrC=kJZ@OU*yL&D)Nu_4V32UsMY z?rS)J!R|K)OYmMU59DQH5>A-%n~8}Cw%xr8APr_1jz#vwoArA0WB2@j9Bx1V&fPiR zqeD2~l-0-7{Q0}Pf4J(;fOC+ESi^D!#mIgXDmw5LR<**+wd4Y~K zBij9_4%@STS4~;rzr)j~^Z)zx*;a;yLqJ0D!};j^|7CwqUYCFO|KGRE@&51f&bjlL zHZw3Xt!J4x-*#7B!p=R9K3Fp{DYNqJKKlKNvg=tThXsNg5~TRpSvYz`HYB)Z&2nvU zP);~#BEttXQZwOT&lQtyhDNsoO_>%l0tyB}2bv^TW{NQ~^)|3xF0fE=NLbRqY8-S~ zhlxdsk$c(00*8hJ9*qCD|Mc+P%ps7$a)&~bxYL#_i)7(2VG{E>{IG$caUzr08K}`Z zGujR_g8ZU0W8$ndL4^w(5eB^N%uFn9ToDG!ri8p!uxs~TY0L9KhjZvKy-N_|;s<(I z7wBOz(|(3V*8@$F8a6=hZ2@{O>WU2$ix?w!+QJV&CtL(NAtUfJhd>02&WzSWAPc!8 z3>LedRdz@Kh9ype4!nH#@aBt|&jb}59@sOM8#Dof$^>Yr)Y^kAK&KngmD_mv?%TUt z9h%Jq+hQ9Mw$=W%t!4@a#=y!wZNfLUHLz}e`}+M&;Tc*92YsHJ&N;9RD3u#u ye}3M95TH-B)<0y~1`Ohy-@mHAu`J{I!+onT<#vPx}8%ab#RCodHUCXZQI2BD*Qja6`q?xtU2r*#@bA-fqz$Y+d!e20C&>sN*z=c}gIllB4 zzk?x^pMQAP6q}X3jBzo-mWaN-%cxdkbR@O}hU`Op<@J_bE~WMIMgsdbM5hkEHN|Z; zrs-rIp^tA{8qw7BzAUoutjPGtxoaGsuGv@77z5*@GN$#`u0vhy^DNKXmDjxHa=vD_ z@@DR8-R?AI%u{{0e~ez&Tbe9-Jli;Hj1fjO51Ts9CZnE=(HA_#;`xV8qi)pQ7=420 zbX%iCnq^sL*K_rFPl=1Nr87|(b0@G%@z|cY_3OJTQuXuk zySFiY3@{Tg&+ltkr!i)vW@0Yehy$;&=hLEDZdTZ4c-mUVj;eiZQj33%B$4A z8eYx^8`5#1S74CY`rAN9`n?Xr`H4?gsMn{v&Tl(D7?^`{V1@Ntw;66bW~)69Wm|7x zY>C>8i)~+>ZA~o}b-P=ESt=OyOq#!S>xtgibo)I4lOh-z1lzZnUlSw+jCs&@@mlt2 z9Pk8;=5;?N@KtppCWB(Kq0@Mo_9jRAKXNpYcr3;|V z@BZ=O&wu|u`^`*tMw#q4Ki&M8KHr9->F-8sh#=M71g4>62@HX0K%ika8PfnvuX;?w zwS#t}YhW(TCmZ?KC*W=SicV2RC+9cu=uCwC1~~O02X|nakPB&0OmXWDPg;A_ zt+aMf%mUI_uu6V@BL$LlY8yV%uWUj2CKuX*A{RX00F2>T%h%UzA)$$GermrjBY3Pl@av5%3t0A z>uP@Je}LD88-|G+UeIs*f79h0Coe5&uEwmJcG zl)A`NPaL1X0UT8~a)`7yFbesO3YtT@lb^bmZnrLl+6$PWbeuf*9SK4P@EX!5bOIAw z2j@PSYCC6No57{&T=v>*LWcXT2(UM+6&CJnLZDN6n=a)3bs|8*th3w)=bD5W4Ba{} zBw^NB?t^np!VHFPofnSsg2x0ITytB@)g-NPF$J_WqxYklO2BdQ@|g0WZCMOq3UMsO zMg|RH+c(Ms6BC)CJdZ-g<84G9e6?uS5q#C6*^wSF;HXALF{#)Dz9 zMTTV{U=Ff|#d;)`tMyKVS?a5;D=2F?-+Ustkf)O{RFd@R<3b)QVbHnT$5b!rL!Dj@ zHF=sU%@2f`Vny8aAWkz!W~CX+DT6==iZGg0X=a_d8jFBlU>v?4j>;d4=8CR|uP3gi z-4%hq)U1*)OD(yX>?UDm0)DBu!rCiO4fu4B%Mm-L)2lFkX zS6z9XZ-t{lhC5!A1Yt1Dv+o#KM|^spuDXbBW$~hx_O+0!KJ_+qSJE4th-ajhZl+S^#%$$^rSS&vtN@j!;uCDbN?=s0dTY^i}LKA?6`deLm=yow6p5uL+(v-+uh~^&kH8`p-|-?5kx%L+e8#@T)Jf zzx?T!Kl?2wMGT2@VsV2sBurw38ag}d4-*>U#NsDm5-ZTq*&$&E7mlvf#hP{V8U?892c15I9IQMbd`or zEE+l_IKS)S@k6ow%jvwP(Zmt3W zX`hm(N>hLNC&E-Gv)jQcxY3eHtXppDr*tQben)SKgNIgz03K0z+L%ER2283SFi+z4 zdJ(7#$rgQ8z$6AD(1w710g|<=?@y(+^LdO2sLC+eLLxXJK*Bh|#gj=Ga=-}z62=KG zo=n1!15OB#FivpsWDR!)sAfV?{) zFFpvElJ&fhdF@XT(Gy1X_&P>!=HPPD3z4I)bCDsev4?0&0!mWNgBLr5e(ckgX3Q9V zKE*p{Z*+u7T~WH|g&PHRomlHRQ4!{d9_sRT!60s*w|Wj{TDV5^Y90k)QmM>_AUga? z_?$jpqVO)yN*K815Ax>2(2c-B)E7+>rbEI#-xS-E5e7touYtiY0(eAC>HVIh1l4nQ zzQ?ZL5{fW3yk+V}&d}xsB@F5-APYly1fbqiyhH>e3}lk^mGDF{Q&4YFfnO+s5C+{3 z*3=GU7TWCFfmPi*VIYk$c4(TtASX5;R8_z$VN}Paw;pB_~tTZod8a@$29J`}JSn z-?AUgn=7VH1c*Q?2z;^4{`be9Y<{u%_1`}H_tQ1|DwT{eA4Gr%#DTzaKxQhr70Y3;(VEo|7Scm`- zupmHzv4Fx|M1TnRL4X3|2S>(21c-nI0Sb%-6z(DdM8FRM6c|4^G8Q601S|+pU@V|; z7ZD%=eh{F*_`#8}5CI}!L4aeREuf^f3zL6gX+rglrR9v@dZ9U;XAF&h2yZ{tdBy>? zq9K0Q)||u2hW8+wI8W`8Kh>f7@B7)@NDu)E%mNA(H$5gG!)FTtz<>OnaVds-+I2mu z3zP?Zl}KUrO!Lx4u zDgi=m2sI=I?+8#}MnI}WM5Z9doYfE#hUFljLdkUbRYDV|=Z(omB`7R^Q2`s{7Q(V;GNk6%pu-fO^&1Kl*vl zyk1^QB|N<&TIh+%2@FIe-@#|{{O-KaGNRduApnjRyFxzi87oT>oQpV=tKNw32Nu4y zc!5E+w24 zUp4}0t=b=})+&s}D#d?;=JC11ECPc8w}rf4vJcAK#n1FpL;w$Jvz4l<-CW(i3WED6&MTxL`{XFG98(i5)o)a0Qchl zP<6mjEmI;kw}4{fU0_tJk2q=RPiZS=9wP$tBcL3`T5QB`11GWXAq`#xhOa;KlZ6%# zfiVc6LZJKI_mYU(m_lBE%r4FG!bHo601+6AfaxH{ zcqzO_xrANgOD86_}lf3j3<8lT6Gt5okg{ z`D@;s!+3?dh}blRCxJmLkaqSoUBvxFfCvx)Ab<+U;ic+hgZ?%3R;atc(6>Uu5CI}E z1_50$F?}_~{KcVzyyPq5fcF-K!G6#hyW1?h5!X77_^L-2oM1Z3^_mqh(Is| zC@{gGWyC~)2vA_i0U|&If+0YG2?i}ACIUp@J{E~kq=NuDXJeK@>87oQfuKjF-WNkI zG2t|pV8+a8_}uXQwl43zn8?aqiHA&?kuO+4d_xLB0v@@FxcY0R0Rbu@K;msX;ai|D-jc<_1!!3nwYVI9CoQM(&`J=%gJqw;-!kyy zTrc$Fv=#q5T5V^o=op-_#SRWx)>2kf?1QpewFFjv9JP@A1ua%=tun!+zz7=3;U_f} z1|l#N0X&d)vg)aBtwPO4IgE!!n8PI=@%i(tc=y&MzP6f8@&Z%&RM;^P)uyAC zw{@HdpbbI$Y|!j|mStB{?BJJ_z~oX5-O*Va=N(0>8WF&Q@F**+B3w|bL2u$jLJ|U_ zYAfvgmIx)+oeex7@j<6PRjXMz9E%kgGz;zz@U8GQXyF{B`4$Awsqgr*QxkHXPw33I z%mGr16ByN-Qv53nL|_dF-~oC#R(wZ|1~r={g~i;dXbpl>jDZNO6#=*c5H9ECv_3^I zFm&9m^>$*un-I{gPfKtJM=LO_u{6<(`-wn>fOZJST%(CjV9;c@KSXC1IZXtjML^eR z&L{EFNS~URLNs?W8iOD#Y!!-$9<*gi2;lxfYZHVfmPV&21cv=smPBLP8Z!b_tJ5x; bel-6FvfpnerU1FX00000NkvXXu0mjf%XWRU literal 0 HcmV?d00001 diff --git a/src/exchange/images/box6.png b/src/exchange/images/box6.png new file mode 100644 index 0000000000000000000000000000000000000000..0215a25d6776af287b95c12aa2a53d6b99edc87e GIT binary patch literal 6265 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 literal 0 HcmV?d00001 diff --git a/src/exchange/images/more.png b/src/exchange/images/more.png new file mode 100644 index 0000000000000000000000000000000000000000..c665263f2a77b7f85c97d60081b8873558146e8b GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W-!3HGz;^n6SDF;s%#}JL+WSjDLbDr<7|DR@L z00f4HOQj_xbJ;g0HiT3jGfqEela!D!p;hX`jUz`~_-;A`Jzbfvurf|bM1|qJkLUME Ts)siN&0_F$^>bP0l+XkKux}=Y literal 0 HcmV?d00001 diff --git a/src/exchange/images/nodata.png b/src/exchange/images/nodata.png new file mode 100644 index 0000000000000000000000000000000000000000..7c01edf3b5400c3714100cf992a2ff00235a97ee GIT binary patch literal 77734 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 YA6@G1X_dUJw*UYD07*qoM6N<$f|+DWrvLx| literal 0 HcmV?d00001 diff --git a/src/exchange/index.js b/src/exchange/index.js new file mode 100644 index 00000000..761e4f0b --- /dev/null +++ b/src/exchange/index.js @@ -0,0 +1,91 @@ +import React, { Component } from 'react'; +import { Route , Switch } from 'react-router-dom'; + +import { TPMIndexHOC } from '../modules/tpm/TPMIndexHOC'; +import { SnackbarHOC , CNotificationHOC } from 'educoder'; + +import ExchangeIndex from './ExchangeIndex'; + +import Post from './Post/Index' +import PostNew from './Post/MemoNew'; +import PlateIndex from './Plate/Index'; +import MyExchange from './MyExchange/Index' +import PreManager from './Manage/PreModerator' +import axios from 'axios'; +import './exchange.css'; + +class Index extends Component{ + constructor(props){ + super(props); + this.state={ + current_user:undefined + } + } + + componentDidMount=()=>{ + const url = `/users/get_user_info.json`; + axios.get(url).then(result=>{ + if(result){ + this.setState({ + current_user:result.data.current_user + }) + // 给NewHeader传值,当前用户的信息 + if(result.data.current_user && result.data.current_user.login){ + this.props.initCommonState(result.data.current_user); + } + } + }).catch(error=>{ + + }) + } + + render(){ + return( + + {/* 帖子列表 */} + () + } > + {/* 编辑帖子 */} + { + return ()} + }> + {/* 新建帖子 */} + { + return ()} + }> + {/* 版主管理 */} + { + return ()} + }> + + {/* 我的话题 */} + { + return ()} + }> + { + return ()} + }> + { + return ()} + }> + {/* 帖子详情 */} + { + return ()} + }> + {/* 论坛首页 */} + () + }> + + ) + } +} +export default SnackbarHOC() (CNotificationHOC() (TPMIndexHOC ( Index ))) ; \ No newline at end of file diff --git a/src/forums/New.jsx b/src/forums/New.jsx index ddb6efe9..b20d6027 100644 --- a/src/forums/New.jsx +++ b/src/forums/New.jsx @@ -8,7 +8,6 @@ import Attachments from '../forge/Upload/attachment'; import "./css/All.scss"; import axios from "axios"; -const TextArea = Input.TextArea; const Option = Select.Option; // forum_id: values.forum_id, //大主题版块的id, int类型 (必填)