+
+ {
+ 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(
+
+
![用户头像]({getImageUrl(`images/${item.image_url}`)})
+
+
+ {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(
+
+ )
+ }
+}
+
+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(
+
+ )
+ })
+ }
+
+ )
+
+ // 全部帖子
+ const forumList = (
+
+ )
+
+
+ const pagination = (
+ data && data.memos && data.memos_count > pageSize &&
+
+ )
+
+ const dataList = (
+
+
+ {
+ 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}
+
+
+
+
+
+ );
+ }
+}
+
+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)}
+ />
+
+
+
+ 必填项
+
+
+
*/}
+
+ {/*
内容
*/}
+
+
+
+
+ {/* 请求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 ?
: 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
zcmXw6dmz*M8+N~6P7DjlWulr}E{EjSK^QZJCSt?ViO5PijO3aqY^=$s{KC6p6ePUg
zD9Wx&uZBfmTwnMUGr3J5%)Mi?W7w?nKNWs%Hh=K5fPz&%2v>KMV2O?sj_#+
zE0yFg_EUrXHQ1kAjEr<{T8N~YmsA_EXdoP=QO$bA0p+Rw3cIw=5(SW5K#{QECJssb
zK|HoEA{eQBvD-%@GQg(is;Natg=3@TZFh}`=23$M<a-ZasdMJv2yL>
z-~SM6sGh0MgJ{Z`tUUc!3MPK8H;LlN2Ul=Y$SG^$OXB2`
z#m*#Xno4e0{q_u2b-T!2_Ra?JJgIjfn>}RGV(mU$(|&i+a+^3?n7wR05|9w76c_$D
z+}6M0H+PkI18Xy;p@{EM(jFWNo2dNqqtvE65NpJE@+DjTI#bJK82r
zZN)-z4*o*C>>n#BYne4H7x~MJxzfgkTXV9b-|J7W2?_lZvAx;WoY1&4BihUsjPse}
zi)Xj5U0q*N>X`V3zb0UGX0m`yetB30GQ1XHn1%9pZ(!1okK(0_^UfO1qe_@7eA-Y~
z15^@oMTiAjM>R56#PIU2RVbg96)8NJ0d=ND>_*$aQ-w};f5_qm98vnHw7ah_-<9Zu
z+}H?T{S{`=5Ez-dDfGbd=y&Oe$vQ2zLYdgnuUpW|x-tYqs@grFlKExr#=n%&n4huTG9iW`~od26TxSfOcwX(>lk8A`-3i6A{4-o1$)
z&aVAF)DkVaoqgqM%(y%xy;qXgDC?T@4|L&T%0cU(w(CuoyT{7!4+qW8Qoo)c{>I<4
z&?^xAUd7Knz{b!Q*Pnhm62c`zTnN&H6D%O^^;>~@8A6S
zF-C}zBjZ8`$s5|ys)H~CfpWMn2sAQaoIn@2fsR%K#1W9bp8*54RKFff1yQ;^0d5Wr-(V_5P8(JviB9oHud#?
z=#YXF>KYlKfXO+4oDCmM-33)}a7w^~z78MV4Wa)8OW5^f!8^F2$8d05oOCr`k~rA@
z)AA;;kF-5-a9kmydQw`L_F~Tt1_J6x&$24b(>}!o6m6GXFrA}~;R2Gj6Bp#M{J4O^
z;%4RN;L*FDd=lQ93-a(DTtLD5?1I6ZX>P$m5?*sx^js%Fakq^c{9f){!oDInq)y$`
zMxVjPQfQci;;{2jV17Q_pAiDy|DO($8+g-$2u1MNRbaea_AuOmF+P@Y|2^-&$*Pn+S~jf%2I2yV=V6UH6?v@Me@^4Jx;uaAWedH*d5(4A~xT&=<`TL5wKbK55EF>-~!xKHXLEh`(AyQ>x-kQ^8V-Sq9sC
z5RE)71(l{eH%RF}aj?Aq)u&1&lKg6-IRBpX`b7_`aq&6QM9gaO#S&FRW%$NRb(eil
zXfC-EF-2Au9@11R_3sX-&tHm{Qt)EsFK!U(FFb$(-fdgG$b&jvv;OB01?U061KQUm
z11$aO<==G#J&~J!=33st|GyT7>Yt^ddE`Nwe8l~m8*ES;}z
z_f)9~_cTuWAT^$ST^J)Eokd-{)QKy9
z74@ZiZpG)Jx1>;ZB+!)rt@h+}h~<7ScHTfGf18lN-?vVVi?dDUBM$2{jM_^>r4<{l
z-8zg$1}k5#E4V13Y}l<%O90#4(o{WJMr#K|8|z}303gVUxc;d#Z-AOMe*Qb{J@$`p
zKcd92(M)=BUs2zp(%;XIOq-P9V&aZrP}B2ZYy4_sj|hw+*@wZszemvTt#u^gMDJT_
z1l2Vi(i!{jUVTkVQhXYxL)D)h7L$9i{F$HFF=Qp9E3}}&BKl2eK3c^hRZ8)ay~Sx5
z{9_F-m)epPTp^N`;_#T4TNg_Ipb8OmY}G{aR1rp)3zcP}fRn}J+$PXJ(A;F8;+gB=
zRh=D|t^d?#V_RMnDjUivJ{=9nCod3Dr+ZqG!c2^?K#RfCl1mmIK4JwtK|eht;4!h_
zaGvrw%D`i0%HjO<+({NTr9wgFs1a`EqSTh8Q{XDZGod{7o_?&In>Uz3IDyx5wK)dm
z_ZPnw?%MeGhqUmS}VjMp*(NQLeNQdiD%$Eswt
zB)ua8DaoJf8U7b*C+p0S`njH9DEte4I5C&bJR9eYto>#e?V2oXBn9)5tYj2dtU2vrcym|Iv~`&w<~Ke^PZL3(zu~Py2A4x<(RCodHT|18@I}z?ab7p3DAp!|$r3(o;{0tIEu1G-qCSra7f&>wf5D+7Q
z2rlW(&=o6?AiC`A%n|_x3!#1W
z%`TGZ|I3H3O-U_fL_clMcTEHT5(dhIF6N{o^!M`VshLYm(}cvAXwNdE3tGyg-~0To
z(L8Sv#LVrfY46``C0%{L#)Qteii}RwTwa2j&4v*u%Z{0zD_f$b5-Q@7XS10oVTfzu
zTPi@Oo918p`*e92zVo$&(|2oyt-YJlp?_mDAw$p4^to01s?Zld*}6RZuK^xRGhLn@
zkb(BKn+CpO$f_DcBHA)n0!&{HS<=L&Wf^2>ahT}l+_ZPE=;LVdDHEFT6*Bro^ZW_h
z(fl1Lvcw3GUuLE+d@Zvpe_OO>n`v4|N2G1q*WZ}Fvif_A2~A`Z8J$q6JFjN5WdzD`
zV5Vcsn)t1tdq?4=}o)Eqo>238nll(z{Qib{U^yb}FGtmS=C2eG$mh8J!_!vuT=?0UDo0h9=k|K+~?pZRl(=0|g)WWk3CM7tk{n`ZK1h&G!SBQRzr6M~Td>laIX4sBl=_hCerMd=u1=)<{$^nGZ2
ziT*4zP}ow25JoN^)#?UmmMN`KGfiLWjIPZ#r2~I!T66F8vqfZd0{FEdMAJ{>w)w4?
zF$}5I2$yjA@ZPB+tIaem7>Gl#X*OFlXc^YX&`eteZM~J*Q
z`_#4a5}#HgLltbvAklg(0ivH<0izScuOWU)w?;wB3ym9o9SJ!DW9YvO^9^oN1k3vk
z{0j*Fz>q>|tLzC9<%6*26^#N6EqP#0tt-9qTUVm=w&Fv1TPfY%M+asoUM&;#Q+wQt
zQF}76!sSu*D2@Xe*Rs!z>bja!Jf`Ouz>4%QygxNqk9+*z9Qh>A&LgHB_X~VD(ozI@
zZ9t;weadsn1K@w?z#n}|bd+c_ymcycCb6#cbjMmhpUINs5v{i_U<8bQ2)`!r?S0dp
zZ|SS(@fh8!D^sR^3mF%IG3h@(HW&2|LJlc1<)(40e*c7qWN>ieR*|~7+N7H5XU7a|8WVW7dzf9IQf72-oQXb^tgoEr{yapv~j#X
zB}xDRTCiuErc3^J#2z$AVrWJ2(^9K_%}v_XK3XP?$B+_AFN(xyg0RvTn?X%`?Kef4
zQGwCSr(jgm9{nlc_j#`0MV=_kr++9dH$HBMN@+U{HFz`
zM<`lFKBWQLG$e^6`;@k%nAxfCAEUS
zJa*^Zu4@zjiETx5cmDv0-dr4X47BEo8E$NN031DApQDZ7Ddn9jOzS=X({nIQkd(27
zA-t_b#o+Doqz0uk0x_$6F(Dkjeie53+Lmzu0+vs49d_Z=ge@(XbaQ~{{8tjAU*JLT
z86?g7$PxUkn1BLRTLz}DIHFqclIFDipp#jX6rFzdQ_?T>ueLI>-V4$hnf=-TqFLUQ
z7@ZJ)T?o^B9OACLTS*M97!-hJABhbbX_+B$ly(nQ;0z2fskcnIe_F0mLL0#8Q=%CW
zpp3oNwCvTtVSE(Go0r5;rts4OhY-p!1cwj`h^|AB#AqU5$rOtrP1EN$CJ#}7(UpkF
zn5JpOROPcq}{w_jD2KI!vq!MGwiliKKfdYKz0j5XDw_>=&88~1wjbs@~{wYoQ
zKyVxu!F<7-mh1ZWs@0|qG2Cg~X(Qi;KS?u2AavPy+nRM;-s)dy^{T92CGbK3?Ykna
z8b?*V!!A*t6W6?&g&8+6KbW#KMQCxpd?9M@hkX~SPN$Qt+KH_FCP1r0W3ac)kx})$p8O|y&
zv|>he1{j`EdWVR^hEPUdD07(ZCNPE>7@YNo5ZYTl8&ifq1`&-916JHlwxwnmEvb5Q
zyQ6nmXdIc*_RzL%_t!8BoSLty!c)x)Rc^pd7#-&=rrYraTY)i{K)0K0mfgx3+p1n$6RgSs(N+3!eElOZ08g#Z$%y-Xu(&m_^QLSCR0xw!P|0H{Nn}S#*rG
zSG`k~3$oH_82B=K3#F0{OxS{Bx`YTb{OD1Fm;%
z`|Mv87y}G^nYzn@S;*Ngo5{~SqAv~vskyppBatBz7f5uw+VbPv@}n>FmED(V%gp}i
zhE?VLc}d5?GTdS0$f=}9~x0_wVXI&<_bDM(<3Le-b4&w;3m
zKg1++KxXflX_rWhL=qUn4O)VAHVWuyMh%!H
z6h74c_M(*hBo!FSxKWJ}56)8hhm2cJg=1oqO<)YuFiq7{^uQZW49$Z@a^CbZg*Lyy
z5Dw_5UAim+%uE!#6@stdy~C~oLo2VfPK~R|w4P4!ovuk*j{oie00{
z2nI$h41mN0-$S%&}2~1xx
z98eXoClb;QCFF&LLOi+~nc3(91N=evL>JN`^DN}n5YSyv6Fy#RiF{
zEItBwi$~-xXv$?ef$2-aE=ukBNJxu7hjV(1yyOA{Fu`d_>7o(|46J7NJ^&MyFd~~p
zV6a5#qDH{S_yg~iR7)B;Lq37&YlUBfIzuBN3<1Q^^L%tj$=L-4m<1pC)PgRg0*A}H
z^Lp1V0@F2e?!k@)TcgN+4C
z*cnIqB?yS&5zJ5-VZ%dUdUOyN>7tCRz)}P^N6@SU29ScyvJjgMgLdJO?&Eo3R||Fm
zg9w444zbaE;`f6hrRgiI3$8Xs?^+gK|$W0N(Sryp=6)!NTY#2945dz(7Y@44t
z1g5Vks(ePqS*3NEhZ7j6Fbm_Xf(PYWLQ|E787jMHd&hy4_>+qBQW>?maO68hy=ju0{8rlZ9dQmVV&j|;And8@Znfs`qsovF}RAh
z#t_3miJ6^k>}Eoxu`m{!6&Pdy`u>N?yC@IitWHa*OEzl^a4)33igBTS%L0QLD(|Au
zbCzY}7i8qL(AKMu;r2XO64(kG0@G#3E(-4JsWGVIrZ^T^t6O14PHR<}d)JLy?Z#qO
z0)vG>-@l=*=9nqv+0q(HiAGM=n150qi({MG3rx=i7U0qMTUTPogrim3f{mPPAjB?6
zxnXe)UY@{lx^+4??fom)^7yB(d=U;jnQeB#E3M?LVGJ$k`yJJp$t#gv5V*iq#ewI&
z`~{}3G762Fj!EE+04|XPcmdb73lCGttdCmtE-4fxFaT^0n~&rTSg@^7aRP&lSuo(G3w)UZ)2o0^
zrI+Iw@_0Fvk>|
zss#pt0v8vl4Ui7ByI#M*^q*I%ub-olQ%sFArPY4%)t8_B_}_p0;y=$%-U0>HO$w(F7X)SzfHgpHO_$ji@7p(b|NX;ve)Plk`+xh@Ki|E)e>=-uu7}_*
z50p)tt3WA75U3aduk-XTJ=wYAaFDUE^xS{
zumdJ#C>Sb9U>enfjH8;H@~S|qBXL1s6#=k;@VKC8m1f45MSqQ|;v
z8D&R`N`(MSfna$c^VV{T>J+VD3?Og^k<$WVt-V`2*GeZFUfJV3=k6En@JM}3TQ#CL)QZ@nbPfeZLTQ!9et6_qU
zM0Y~~t!rTl#B*yoCN5Pg7y}f}Y5Qy8aLXIkYs_1T2mttZV&nOOZnEV3I);43mbS
zY>1;QipEO(K#rSMP+)KL8@|w?2-F;4|RfcU-5Lj`JeT^2^Cly)^
zi*+qmVcX^l*2M5Wr@@)|c-R7s`#3o%EY7jFf#r~bS`DkKT1s=2C0olJgvf&jSQ7&`
z77HiN#|nnhCntp)<<+e{%l$$W9@g>EmbY>z!S#Awv94t;Mr+Jn)QNMv5@;=vdbg}#
zXhvmU(AgODbN-tf`c~qM5g4YwaJ?=AM_J;yiLtb7u=f1ijaHgr3bc{KQo$H1lQ};M
ztjwVdJe(ucQPvLE>!PAlBNhpTA%Lb5Fa>({V%%;7Ge;Wc{2%m5;qvDEb5%ObGnks_
z>vhiw9c78*reZ}3XDl!c3Jm@Vh8B#1)G>p@aISNH%Cp1~0plnu*7dq#U0beXLB|6N
zwh==d1w$Az48r|F_YCIzgg1$~ngxL$WK_+wuqVQ_)~4g@l+iKSC8v_dfSQWnDy&^|-9yeT@o
z)NX{
z2_IxvFs3detKpm8M#FN>Z-_`l5D)~e5D45_zM>cKU_S*znI3IbCQ^NZCmg+=0mz$^kD*0r;A5f0A`5CuaZ
z6{}$ahD1{%z|p!kb)6~w<0%+gdt)`M&R)VUlsL+w=t$fbfx@?zeXBi}@7M~4ATrwW
z7DrhG8HrjUkl1mP6%Py(iGrCnia5%eA|ijUAdt&((+Uf$Ux|WQYaVfwwT8}d-|gVI
zsZ_8Xy5m=H8&%R2-;wt0`f
zwH&iyM8U*D(`v0-|8{
zZ-b5l7{Why*XuU7_v$|ATP~ax!AI?mn~G?J874)+%z(1{Bkd>)uh$hvS&Qufc1Ta)
zyS9GEO^X;Xe<2Ena|5B(usF&ZHIZ1?j^N<_hbS2CEu{H7xYe*&*J?p1>sJ&^S?$$v
zJF*&9m(bPfC=0ii)n#J`@LgM?7~1eG3dRN{wrRj>7@S9|(5mZoYjBh$j+?sntmJ=D
zFqJf9Q@EonaokjkAdc%H3TBK)9e=^p;-TB}#^VWGx4gx1QyucQQj7lsD{_%BFRDl?
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
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
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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