From c263a62514c1b0d34a27a1c2a044c98f7c89ca3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Fri, 2 Aug 2019 21:17:09 +0800
Subject: [PATCH 1/2] b

---
 .../src/modules/courses/busyWork/common/WorkDetailPageHeader.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js b/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js
index eef99bfcd..56460a44a 100644
--- a/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js
+++ b/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js
@@ -90,7 +90,7 @@ class WorkDetailPageHeader extends Component{
                 }
               `}</style>
               <CBreadcrumb items={[
-                { to: current_user.first_category_url, name: course_name},
+                { to: current_user&&current_user.first_category_url, name: course_name},
                 { to: `/courses/${courseId}/${moduleEngName}/${category_id}`, name: category_name },
                 window.location.pathname.indexOf('appraise') == -1 ? { } : { to: `/courses/${courseId}/${moduleEngName}/${workId}/list`, name: '作业详情' },
                 // 1.	与上一条联动,当匿评他人作品时,TA人作品的作者真实姓名切换为“匿名”

From 55b6c641593b02dd701f698416bcbe772377e75f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Fri, 2 Aug 2019 21:46:17 +0800
Subject: [PATCH 2/2] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/modules/courses/boards/BoardsNew.js   |  896 +++++-----
 .../src/modules/courses/boards/TopicDetail.js | 1452 ++++++++---------
 .../courses/busyWork/CommonWorkDetailIndex.js |    2 +-
 .../modules/courses/exercise/ExerciseNew.js   | 1140 ++++++-------
 .../graduation/topics/GraduateTopicDetail.js  |    2 +-
 .../graduation/topics/GraduateTopicNew.js     |    2 +-
 6 files changed, 1747 insertions(+), 1747 deletions(-)

diff --git a/public/react/src/modules/courses/boards/BoardsNew.js b/public/react/src/modules/courses/boards/BoardsNew.js
index 56dddff7c..cea4f47aa 100644
--- a/public/react/src/modules/courses/boards/BoardsNew.js
+++ b/public/react/src/modules/courses/boards/BoardsNew.js
@@ -1,449 +1,449 @@
-import React,{ Component } from "react";
-
-import {
-  Form, Input, InputNumber, Switch, Radio,
-  Slider, Button, Upload, Icon, Rate, Checkbox, message,
-  Row, Col, Select, Modal, Divider
-} from 'antd';
-import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
-import axios from 'axios'
-import './board.css'
-import "../common/formCommon.css"
-import AddDirModal from './AddDirModal'
-import { RouteHOC } from './common.js'
-import CBreadcrumb from '../common/CBreadcrumb'
-import {getUploadActionUrl, bytesToSize, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll} from 'educoder';
-
-const confirm = Modal.confirm;
-const $ = window.$
-const { Option } = Select;
-// https://lanhuapp.com/web/#/item/project/board/detail?pid=a3bcd4b1-99ce-4e43-8ead-5b8b0a410807&project_id=a3bcd4b1-99ce-4e43-8ead-5b8b0a410807&image_id=71072679-b925-4824-aceb-4649535e3652
-class BoardsNew extends Component{
-  constructor(props){
-    super(props);
-
-    this.mdRef = React.createRef();
-
-    this.state = {
-      fileList: [],
-      boards: [],
-      title_num: 60
-    }
-  }
-  addSuccess = () => {
-    this.fetchBoards()
-  }
-  fetchBoards = () => {
-    const isEdit = this.isEdit
-    const boardId = this.props.match.params.boardId
-
-    const boardsUrl = `/courses/board_list.json?board_id=${boardId}`
-    axios.get(boardsUrl, { })
-    .then((response) => {
-      if (response.data.status == 0) {
-        this.setState({
-          boards: response.data.data.boards || [],
-          course_id: response.data.data.course_id
-        })
-        if (!isEdit) {
-          response.data.data.boards.forEach( board => {
-            if (board.id == boardId) {
-              this.setState({ board_name: board.name })
-            }
-          })
-          // board_name
-        }
-      }
-    })
-    .catch(function (error) {
-      console.log(error);
-    });
-  }
-  componentDidMount = () => {
-    
-    const topicId = this.props.match.params.topicId
-    const isEdit = !!topicId
-    this.isEdit = isEdit
-
-    const boardId = this.props.match.params.boardId
-    
-    this.fetchBoards()
-
-    if (isEdit) {
-      const url = `/messages/${topicId}.json`
-      axios.get(url, {
-      })
-        .then((response) => {
-          if (response.data.status == 0) {
-            const { id, data } = response.data;
-            if (data) {
-              this.editTopic = data;
-              this.props.form.setFieldsValue({
-                sticky: !!data.sticky,
-                content: data.content,
-                subject: data.subject,
-                select_board_id: data.board_id // TODO 没返回给前端
-              });
-              this.mdRef.current.setValue(data.content)
-              const _fileList = data.attachments.map(item => {
-                return {
-                  id: item.id,
-                  uid: item.id,
-                  name: appendFileSizeToUploadFile(item),
-                  url: item.url,
-                  status: 'done'
-                }
-              })
-          
-              this.setState({ fileList: _fileList, board_name: data.board_name, title_num: 60 - parseInt(data.subject.length) })
-            }
-          }
-        })
-        .catch(function (error) {
-          console.log(error);
-        });
-    } else {
-      const boardId = this.props.match.params.boardId
-
-      this.props.form.setFieldsValue({
-        select_board_id: parseInt(boardId)
-      });
-    }
-  }
-  handleSubmit = (e) => {
-    e.preventDefault();
-    const cid = this.state.course_id
-    const boardId = this.props.match.params.boardId
-
-    this.props.form.validateFieldsAndScroll((err, values) => {
-      if (!err) {
-        console.log('Received values of form: ', values);
-        if (this.isEdit == true)  {
-          const editTopic = this.editTopic
-          const editUrl = `/messages/${editTopic.id}.json`
-
-          let attachment_ids = undefined
-          if (this.state.fileList) {
-            attachment_ids = this.state.fileList.map(item => {
-              return item.response ? item.response.id : item.id
-            })
-          }
-          axios.put(editUrl, {
-            subject: values.subject,
-            select_board_id: values.select_board_id,
-            content: values.content,
-            sticky: values.sticky,
-            attachment_ids,
-          })
-            .then((response) => {
-              if (response.data.status == 0) {
-                const { id } = response.data;
-                console.log('--- success')
-
-                this.props.toDetailPage(cid, values.select_board_id, editTopic.id)
-              }
-            })
-            .catch(function (error) {
-              console.log(error);
-            });
-        } else {
-          const url = `/boards/${boardId}/messages.json`
-          let attachment_ids = undefined
-          if (this.state.fileList) {
-            attachment_ids = this.state.fileList.map(item => {
-              return item.response.id
-            })
-          }
-          
-          axios.post(url, {
-            ...values,
-            course_id: cid,
-            attachment_ids,
-          })
-            .then((response) => {
-              if (response.data.data && response.data.status == 0) {
-                const { id } = response.data.data;
-                if (id) {
-                  console.log('--- success')
-                  this.props.toDetailPage(cid, values.select_board_id, id)
-                }
-              }
-            })
-            .catch(function (error) {
-              console.log(error);
-            });
-        }
-      } else {
-        $("html").animate({ scrollTop: $('html').scrollTop() - 100 })
-      }
-    });
-  }
-  // 附件相关 START
-  handleChange = (info) => {
-    let fileList = info.fileList;
-    this.setState({ fileList: appendFileSizeToUploadFileAll(fileList)
-    });
-  }
-  onAttachmentRemove = (file) => {
-    confirm({
-      // title: '确定要删除这个附件吗?',
-      title: '是否确认删除?',
-      
-      okText: '确定',
-      cancelText: '取消',
-      // content: 'Some descriptions',
-      onOk: () => {
-        this.deleteAttachment(file)
-      },
-      onCancel() {
-        console.log('Cancel');
-      },
-    });
-
-    
-    return false;
-  }
-  deleteAttachment = (file) => {
-    // 初次上传不能直接取uid
-    const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
-    axios.delete(url, {
-    })
-      .then((response) => {
-        if (response.data) {
-          const { status } = response.data;
-          if (status == 0) {
-            console.log('--- success')
-            
-            this.setState((state) => {
-              const index = state.fileList.indexOf(file);
-              const newFileList = state.fileList.slice();
-              newFileList.splice(index, 1);
-              return {
-                fileList: newFileList,
-              };
-            });
-          }
-        }
-      })
-      .catch(function (error) {
-        console.log(error);
-      });
-  }
-  // 附件相关 ------------ END
-  changeTitle=(e)=>{
-    console.log(e.target.value.length);
-    this.setState({
-      title_num: 60 - parseInt(e.target.value.length)
-    })
-  }
-  render() {
-    let { addGroup, fileList, course_id, title_num } = this.state;
-    const { getFieldDecorator } = this.props.form;
-    const { current_user } = this.props
-
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        // sm: { span: 8 },
-        sm: { span: 24 },
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        // sm: { span: 16 },
-        sm: { span: 24 },
-      },
-    };
-
-    const uploadProps = {
-      width: 600,
-      fileList,
-      multiple: true,
-      // https://github.com/ant-design/ant-design/issues/15505
-      // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
-      // showUploadList: false,
-      action: `${getUploadActionUrl()}`,
-      onChange: this.handleChange,
-      onRemove: this.onAttachmentRemove,
-      beforeUpload: (file) => {
-        console.log('beforeUpload', file.name);
-        const isLt150M = file.size / 1024 / 1024 < 150;
-        if (!isLt150M) {
-          message.error('文件大小必须小于150MB!');
-        }
-        return isLt150M;
-      },
-    };
-    const isAdmin = this.props.isAdmin()
-    const courseId=this.props.match.params.coursesId;
-    const boardId = this.props.match.params.boardId
-
-    return(
-        <div className="newMain ">
-          <AddDirModal {...this.props}
-            title="添加目录"
-            label="目录名称"
-            ref="addDirModal"
-            addSuccess={this.addSuccess}
-          ></AddDirModal>
-          <style>{`
-            .courseForm .ant-form {
-            }
-            .courseForm .formBlock {
-              padding: 20px 30px 30px 30px;
-              border-bottom: 1px solid #EDEDED;
-              margin-bottom: 0px;
-              background: #fff;
-            }
-            .courseForm .noBorder {
-              border-bottom: none;
-            }
-            
-          `}</style>
-          <div className="edu-class-container edu-position courseForm">
-            <CBreadcrumb items={[
-              { to: current_user.first_category_url, name: this.props.coursedata ? this.props.coursedata.name : ''},
-              { to: `/courses/${courseId}/boards/${boardId}`, name: this.state.board_name },
-              { name: this.isEdit ? '帖子编辑' : '帖子新建'}
-            ]}></CBreadcrumb>
-
-            <p className="clearfix mt20 mb20">
-              <span className="fl font-24 color-grey-3">{this.isEdit ? "编辑" : "新建"}帖子</span>
-              <a href="javascript:void(0)" className="color-grey-6 fr font-16 mr2" 
-                  onClick={() => this.props.history.goBack()}>
-                返回
-              </a>
-            </p>
-            {/* notRequired */}
-            <Form {...formItemLayout} onSubmit={this.handleSubmit}>
-              <div className="formBlock" style={{paddingBottom: '0px', position: 'relative'}}>
-                {  isAdmin && 
-                    <React.Fragment>
-                      {getFieldDecorator('sticky', {
-                        valuePropName: 'checked',
-                      })(
-                        isAdmin && <Checkbox style={{ right: '22px',
-                          top: '28px',
-                          position: 'absolute'
-                        }}>置顶</Checkbox>
-                      )}
-                      {/* checkbox 有个边距样式 .ant-checkbox-wrapper + span, */}
-                      <span style={{ "padding-left": 0, "padding-right": 0 }}></span>
-                    </React.Fragment>
-                  }
-                <Form.Item
-                  label="标题"
-                  className="topicTitle "
-                >
-                  
-                  {getFieldDecorator('subject', {
-                    rules: [{
-                      required: true, message: '请输入标题',
-                    }, {
-                      max: 60, message: '最大限制为60个字符',
-                    }],
-                  })(
-                    <Input placeholder="请输入帖子标题,最大限制60个字符" className="searchViewAfter" maxLength="60"
-                      onInput={this.changeTitle} addonAfter={String(title_num)} />
-                  )}
-                </Form.Item>
-
-                <Form.Item
-                  label=""
-                  style={{ display: 'inline-block' }}
-                >
-                  {getFieldDecorator('select_board_id', {
-                    // initialValue: '3779',
-                  })(
-                    <Select style={{ width: 230 }}
-                      dropdownRender={menu => (
-                        <div>
-                          {menu}
-                          <Divider style={{ margin: '4px 0' }} />
-                          <div style={{ padding: '8px', cursor: 'pointer' }} onMouseDown={() => this.refs['addDirModal'].open()}>
-                            <Icon type="plus" /> 添加目录
-                          </div>
-                        </div>
-                      )}
-                    >
-                      {this.state.boards.map(item => {
-                        return (
-                          <Option value={item.id}>{item.name}</Option>
-                        )
-                      })}
-                    </Select>
-                  )}
-                </Form.Item>
-
-                {/* { isAdmin && <Form.Item
-                  label=""
-                  style={{ display: 'inline-block', marginLeft: "14px" }}
-                >
-                  {getFieldDecorator('sticky', {
-                  })(
-                    <Checkbox>置顶</Checkbox>
-                  )}
-                </Form.Item> } */}
-              </div>
-
-              <style>{`
-                .courseMessageMD {
-                  width: 1140px;
-                }
-                
-                .uploadBtn.ant-btn {
-                  border: none;
-                  color: #4CACFF;
-                  box-shadow: none;
-                  background: transparent;
-                  padding: 0 6px;
-                }
-                .upload_1 .ant-upload-list {
-                  width: 350px;
-                }
-                
-              `}</style>
-
-              <div className="formBlock noBorder">
-
-              <Form.Item
-                label="内容"
-                className="mdInForm"
-              >
-              {getFieldDecorator('content', {
-                rules: [{
-                  required: true, message: '请输入帖子内容',
-                }, {
-                  max: 10000, message: '最大限制为10000个字符',
-                }],
-              })(
-                <TPMMDEditor ref={this.mdRef} placeholder={'请在此输入帖子详情,最大限制为10000个字符'} 
-                    mdID={'courseMessageMD'} initValue={this.editTopic ? this.editTopic.content : ''} className="courseMessageMD"></TPMMDEditor>
-              )}
-              </Form.Item>
-
-              <Upload {...uploadProps} className="upload_1">
-                <Button className="uploadBtn">
-                  <Icon type="upload" /> 上传附件
-                </Button>
-                (单个文件150M以内)
-              </Upload>
-              </div>
-              
-              <Form.Item>
-                <div className="clearfix mt30 mb30">
-                  <Button type="primary" htmlType="submit"  className="defalutSubmitbtn fl mr20">提交</Button>
-                  <a className="defalutCancelbtn fl" 
-                    onClick={() => this.isEdit ? 
-                      this.props.toDetailPage(Object.assign({}, this.props.match.params, {'coursesId': course_id})) : 
-                      this.props.toListPage(Object.assign({}, this.props.match.params, {'coursesId': course_id})) }>取消</ a>
-                </div>
-              </Form.Item>
-            </Form>
-          </div>
-        </div>
-      )
-    }
-}
-
-const WrappedBoardsNew = Form.create({ name: 'boardsNew' })(BoardsNew);
+import React,{ Component } from "react";
+
+import {
+  Form, Input, InputNumber, Switch, Radio,
+  Slider, Button, Upload, Icon, Rate, Checkbox, message,
+  Row, Col, Select, Modal, Divider
+} from 'antd';
+import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
+import axios from 'axios'
+import './board.css'
+import "../common/formCommon.css"
+import AddDirModal from './AddDirModal'
+import { RouteHOC } from './common.js'
+import CBreadcrumb from '../common/CBreadcrumb'
+import {getUploadActionUrl, bytesToSize, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll} from 'educoder';
+
+const confirm = Modal.confirm;
+const $ = window.$
+const { Option } = Select;
+// https://lanhuapp.com/web/#/item/project/board/detail?pid=a3bcd4b1-99ce-4e43-8ead-5b8b0a410807&project_id=a3bcd4b1-99ce-4e43-8ead-5b8b0a410807&image_id=71072679-b925-4824-aceb-4649535e3652
+class BoardsNew extends Component{
+  constructor(props){
+    super(props);
+
+    this.mdRef = React.createRef();
+
+    this.state = {
+      fileList: [],
+      boards: [],
+      title_num: 60
+    }
+  }
+  addSuccess = () => {
+    this.fetchBoards()
+  }
+  fetchBoards = () => {
+    const isEdit = this.isEdit
+    const boardId = this.props.match.params.boardId
+
+    const boardsUrl = `/courses/board_list.json?board_id=${boardId}`
+    axios.get(boardsUrl, { })
+    .then((response) => {
+      if (response.data.status == 0) {
+        this.setState({
+          boards: response.data.data.boards || [],
+          course_id: response.data.data.course_id
+        })
+        if (!isEdit) {
+          response.data.data.boards.forEach( board => {
+            if (board.id == boardId) {
+              this.setState({ board_name: board.name })
+            }
+          })
+          // board_name
+        }
+      }
+    })
+    .catch(function (error) {
+      console.log(error);
+    });
+  }
+  componentDidMount = () => {
+    
+    const topicId = this.props.match.params.topicId
+    const isEdit = !!topicId
+    this.isEdit = isEdit
+
+    const boardId = this.props.match.params.boardId
+    
+    this.fetchBoards()
+
+    if (isEdit) {
+      const url = `/messages/${topicId}.json`
+      axios.get(url, {
+      })
+        .then((response) => {
+          if (response.data.status == 0) {
+            const { id, data } = response.data;
+            if (data) {
+              this.editTopic = data;
+              this.props.form.setFieldsValue({
+                sticky: !!data.sticky,
+                content: data.content,
+                subject: data.subject,
+                select_board_id: data.board_id // TODO 没返回给前端
+              });
+              this.mdRef.current.setValue(data.content)
+              const _fileList = data.attachments.map(item => {
+                return {
+                  id: item.id,
+                  uid: item.id,
+                  name: appendFileSizeToUploadFile(item),
+                  url: item.url,
+                  status: 'done'
+                }
+              })
+          
+              this.setState({ fileList: _fileList, board_name: data.board_name, title_num: 60 - parseInt(data.subject.length) })
+            }
+          }
+        })
+        .catch(function (error) {
+          console.log(error);
+        });
+    } else {
+      const boardId = this.props.match.params.boardId
+
+      this.props.form.setFieldsValue({
+        select_board_id: parseInt(boardId)
+      });
+    }
+  }
+  handleSubmit = (e) => {
+    e.preventDefault();
+    const cid = this.state.course_id
+    const boardId = this.props.match.params.boardId
+
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        console.log('Received values of form: ', values);
+        if (this.isEdit == true)  {
+          const editTopic = this.editTopic
+          const editUrl = `/messages/${editTopic.id}.json`
+
+          let attachment_ids = undefined
+          if (this.state.fileList) {
+            attachment_ids = this.state.fileList.map(item => {
+              return item.response ? item.response.id : item.id
+            })
+          }
+          axios.put(editUrl, {
+            subject: values.subject,
+            select_board_id: values.select_board_id,
+            content: values.content,
+            sticky: values.sticky,
+            attachment_ids,
+          })
+            .then((response) => {
+              if (response.data.status == 0) {
+                const { id } = response.data;
+                console.log('--- success')
+
+                this.props.toDetailPage(cid, values.select_board_id, editTopic.id)
+              }
+            })
+            .catch(function (error) {
+              console.log(error);
+            });
+        } else {
+          const url = `/boards/${boardId}/messages.json`
+          let attachment_ids = undefined
+          if (this.state.fileList) {
+            attachment_ids = this.state.fileList.map(item => {
+              return item.response.id
+            })
+          }
+          
+          axios.post(url, {
+            ...values,
+            course_id: cid,
+            attachment_ids,
+          })
+            .then((response) => {
+              if (response.data.data && response.data.status == 0) {
+                const { id } = response.data.data;
+                if (id) {
+                  console.log('--- success')
+                  this.props.toDetailPage(cid, values.select_board_id, id)
+                }
+              }
+            })
+            .catch(function (error) {
+              console.log(error);
+            });
+        }
+      } else {
+        $("html").animate({ scrollTop: $('html').scrollTop() - 100 })
+      }
+    });
+  }
+  // 附件相关 START
+  handleChange = (info) => {
+    let fileList = info.fileList;
+    this.setState({ fileList: appendFileSizeToUploadFileAll(fileList)
+    });
+  }
+  onAttachmentRemove = (file) => {
+    confirm({
+      // title: '确定要删除这个附件吗?',
+      title: '是否确认删除?',
+      
+      okText: '确定',
+      cancelText: '取消',
+      // content: 'Some descriptions',
+      onOk: () => {
+        this.deleteAttachment(file)
+      },
+      onCancel() {
+        console.log('Cancel');
+      },
+    });
+
+    
+    return false;
+  }
+  deleteAttachment = (file) => {
+    // 初次上传不能直接取uid
+    const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
+    axios.delete(url, {
+    })
+      .then((response) => {
+        if (response.data) {
+          const { status } = response.data;
+          if (status == 0) {
+            console.log('--- success')
+            
+            this.setState((state) => {
+              const index = state.fileList.indexOf(file);
+              const newFileList = state.fileList.slice();
+              newFileList.splice(index, 1);
+              return {
+                fileList: newFileList,
+              };
+            });
+          }
+        }
+      })
+      .catch(function (error) {
+        console.log(error);
+      });
+  }
+  // 附件相关 ------------ END
+  changeTitle=(e)=>{
+    console.log(e.target.value.length);
+    this.setState({
+      title_num: 60 - parseInt(e.target.value.length)
+    })
+  }
+  render() {
+    let { addGroup, fileList, course_id, title_num } = this.state;
+    const { getFieldDecorator } = this.props.form;
+    const { current_user } = this.props
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        // sm: { span: 8 },
+        sm: { span: 24 },
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        // sm: { span: 16 },
+        sm: { span: 24 },
+      },
+    };
+
+    const uploadProps = {
+      width: 600,
+      fileList,
+      multiple: true,
+      // https://github.com/ant-design/ant-design/issues/15505
+      // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
+      // showUploadList: false,
+      action: `${getUploadActionUrl()}`,
+      onChange: this.handleChange,
+      onRemove: this.onAttachmentRemove,
+      beforeUpload: (file) => {
+        console.log('beforeUpload', file.name);
+        const isLt150M = file.size / 1024 / 1024 < 150;
+        if (!isLt150M) {
+          message.error('文件大小必须小于150MB!');
+        }
+        return isLt150M;
+      },
+    };
+    const isAdmin = this.props.isAdmin()
+    const courseId=this.props.match.params.coursesId;
+    const boardId = this.props.match.params.boardId
+
+    return(
+        <div className="newMain ">
+          <AddDirModal {...this.props}
+            title="添加目录"
+            label="目录名称"
+            ref="addDirModal"
+            addSuccess={this.addSuccess}
+          ></AddDirModal>
+          <style>{`
+            .courseForm .ant-form {
+            }
+            .courseForm .formBlock {
+              padding: 20px 30px 30px 30px;
+              border-bottom: 1px solid #EDEDED;
+              margin-bottom: 0px;
+              background: #fff;
+            }
+            .courseForm .noBorder {
+              border-bottom: none;
+            }
+            
+          `}</style>
+          <div className="edu-class-container edu-position courseForm">
+            <CBreadcrumb items={[
+              { to: current_user&&current_user.first_category_url, name: this.props.coursedata ? this.props.coursedata.name : ''},
+              { to: `/courses/${courseId}/boards/${boardId}`, name: this.state.board_name },
+              { name: this.isEdit ? '帖子编辑' : '帖子新建'}
+            ]}></CBreadcrumb>
+
+            <p className="clearfix mt20 mb20">
+              <span className="fl font-24 color-grey-3">{this.isEdit ? "编辑" : "新建"}帖子</span>
+              <a href="javascript:void(0)" className="color-grey-6 fr font-16 mr2" 
+                  onClick={() => this.props.history.goBack()}>
+                返回
+              </a>
+            </p>
+            {/* notRequired */}
+            <Form {...formItemLayout} onSubmit={this.handleSubmit}>
+              <div className="formBlock" style={{paddingBottom: '0px', position: 'relative'}}>
+                {  isAdmin && 
+                    <React.Fragment>
+                      {getFieldDecorator('sticky', {
+                        valuePropName: 'checked',
+                      })(
+                        isAdmin && <Checkbox style={{ right: '22px',
+                          top: '28px',
+                          position: 'absolute'
+                        }}>置顶</Checkbox>
+                      )}
+                      {/* checkbox 有个边距样式 .ant-checkbox-wrapper + span, */}
+                      <span style={{ "padding-left": 0, "padding-right": 0 }}></span>
+                    </React.Fragment>
+                  }
+                <Form.Item
+                  label="标题"
+                  className="topicTitle "
+                >
+                  
+                  {getFieldDecorator('subject', {
+                    rules: [{
+                      required: true, message: '请输入标题',
+                    }, {
+                      max: 60, message: '最大限制为60个字符',
+                    }],
+                  })(
+                    <Input placeholder="请输入帖子标题,最大限制60个字符" className="searchViewAfter" maxLength="60"
+                      onInput={this.changeTitle} addonAfter={String(title_num)} />
+                  )}
+                </Form.Item>
+
+                <Form.Item
+                  label=""
+                  style={{ display: 'inline-block' }}
+                >
+                  {getFieldDecorator('select_board_id', {
+                    // initialValue: '3779',
+                  })(
+                    <Select style={{ width: 230 }}
+                      dropdownRender={menu => (
+                        <div>
+                          {menu}
+                          <Divider style={{ margin: '4px 0' }} />
+                          <div style={{ padding: '8px', cursor: 'pointer' }} onMouseDown={() => this.refs['addDirModal'].open()}>
+                            <Icon type="plus" /> 添加目录
+                          </div>
+                        </div>
+                      )}
+                    >
+                      {this.state.boards.map(item => {
+                        return (
+                          <Option value={item.id}>{item.name}</Option>
+                        )
+                      })}
+                    </Select>
+                  )}
+                </Form.Item>
+
+                {/* { isAdmin && <Form.Item
+                  label=""
+                  style={{ display: 'inline-block', marginLeft: "14px" }}
+                >
+                  {getFieldDecorator('sticky', {
+                  })(
+                    <Checkbox>置顶</Checkbox>
+                  )}
+                </Form.Item> } */}
+              </div>
+
+              <style>{`
+                .courseMessageMD {
+                  width: 1140px;
+                }
+                
+                .uploadBtn.ant-btn {
+                  border: none;
+                  color: #4CACFF;
+                  box-shadow: none;
+                  background: transparent;
+                  padding: 0 6px;
+                }
+                .upload_1 .ant-upload-list {
+                  width: 350px;
+                }
+                
+              `}</style>
+
+              <div className="formBlock noBorder">
+
+              <Form.Item
+                label="内容"
+                className="mdInForm"
+              >
+              {getFieldDecorator('content', {
+                rules: [{
+                  required: true, message: '请输入帖子内容',
+                }, {
+                  max: 10000, message: '最大限制为10000个字符',
+                }],
+              })(
+                <TPMMDEditor ref={this.mdRef} placeholder={'请在此输入帖子详情,最大限制为10000个字符'} 
+                    mdID={'courseMessageMD'} initValue={this.editTopic ? this.editTopic.content : ''} className="courseMessageMD"></TPMMDEditor>
+              )}
+              </Form.Item>
+
+              <Upload {...uploadProps} className="upload_1">
+                <Button className="uploadBtn">
+                  <Icon type="upload" /> 上传附件
+                </Button>
+                (单个文件150M以内)
+              </Upload>
+              </div>
+              
+              <Form.Item>
+                <div className="clearfix mt30 mb30">
+                  <Button type="primary" htmlType="submit"  className="defalutSubmitbtn fl mr20">提交</Button>
+                  <a className="defalutCancelbtn fl" 
+                    onClick={() => this.isEdit ? 
+                      this.props.toDetailPage(Object.assign({}, this.props.match.params, {'coursesId': course_id})) : 
+                      this.props.toListPage(Object.assign({}, this.props.match.params, {'coursesId': course_id})) }>取消</ a>
+                </div>
+              </Form.Item>
+            </Form>
+          </div>
+        </div>
+      )
+    }
+}
+
+const WrappedBoardsNew = Form.create({ name: 'boardsNew' })(BoardsNew);
 export default RouteHOC()(WrappedBoardsNew);
\ No newline at end of file
diff --git a/public/react/src/modules/courses/boards/TopicDetail.js b/public/react/src/modules/courses/boards/TopicDetail.js
index 7aaecdd16..970cf798a 100644
--- a/public/react/src/modules/courses/boards/TopicDetail.js
+++ b/public/react/src/modules/courses/boards/TopicDetail.js
@@ -1,726 +1,726 @@
-import React, { Component } from 'react';
-import { Redirect } from 'react-router';
-
-import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
-
-import PropTypes from 'prop-types';
-
-import classNames from 'classnames'
-
-import axios from 'axios'
-
-import moment from 'moment'
-
-import Comments from '../../comment/Comments'
-
-import update from 'immutability-helper'
-import RewardDialog from '../../common/RewardDialog';
-import {ImageLayerOfCommentHOC} from '../../page/layers/ImageLayerOfCommentHOC'
-
-import MemoDetailMDEditor from '../../forums/MemoDetailMDEditor'
-import { RouteHOC } from './common.js'
-import '../../forums/Post.css'
-import '../../forums/RightSection.css'
-import './TopicDetail.css'
-import '../common/courseMessage.css'
-import { Pagination, Tooltip } from 'antd'
-import { bytesToSize, ConditionToolTip, markdownToHTML, MarkdownToHtml } from 'educoder'
-import SendToCourseModal from '../coursesPublic/modal/SendToCourseModal'
-import CBreadcrumb from '../common/CBreadcrumb'
-import { generateComments, generateChildComments, _findById, handleContentBeforeCreateNew, addNewComment
-  , addSecondLevelComment, NEED_TO_WRITE_CONTENT, handleContentBeforeCreateSecondLevelComment
-  , handleDeleteComment, handleCommentPraise, handleHiddenComment } from '../common/CommentsHelper'
-
-const $ = window.$
-const REPLY_PAGE_COUNT = 10
-function urlStringify(params) {
-  let noParams = true;
-  let paramsUrl = '';
-    for (let key in params) {
-      noParams = false;
-      paramsUrl += `${key}=${params[key]}&`
-    }
-    if (noParams) {
-      return '';
-    }
-    paramsUrl = paramsUrl.substring(0, paramsUrl.length - 1);
-    return paramsUrl;
-}
-class TopicDetail extends Component {
-    constructor(props) {
-      super(props)
-
-      this.state = {
-        memo: {},
-        memoLoading: true,
-        hasMoreComments: false,
-        pageCount: 1,
-        comments: [],
-        goldRewardDialogOpen: false,
-      }
-    }
-    componentDidMount() {
-      window.$("html,body").animate({"scrollTop":0})
-
-      const topicId = this.props.match.params.topicId
-      const bid = this.props.match.params.boardId
-      
-      const memoUrl = `/messages/${topicId}.json`;
-      this.setState({
-        memoLoading: true
-      })
-      axios.get(memoUrl,{
-          })
-          .then((response) => {
-            
-            if (response.data.status === -1) {
-              setTimeout(() => {
-                this.props.showNotification('帖子不存在!')
-              }, 300)
-              // this.props.toListPage(response.data.data.course_id, bid)
-              return;
-            } else  {
-              
-              this.setState({
-                memo: Object.assign({}, {
-                  ...response.data.data,
-                  replies_count: response.data.data.total_replies_count
-                }, {...this.state.memo})
-              }, () => {
-              })
-
-              // const { memo_replies, memo } = response.data;
-              // let hasMoreComments = false;
-              // if (memo_replies && memo_replies.length === 10 && memo.total_replies_count > 10) {  
-              //   // 遍历一遍,计算下是否还有评论未加载
-              //   let totalCount = 10;
-              //   memo_replies.forEach(item=>{
-              //     totalCount += item.children.length
-              //   })
-              //   if (totalCount < memo.total_replies_count) {
-              //     hasMoreComments = true;
-              //   }
-              // }
-              // this.setState({
-              //   hasMoreComments,
-              //   pageCount: 1,
-              //   comments: memo_replies
-              // })
-              // delete response.data.memo_replies;
-              // this.setState(response.data)
-              // const user = response.data.current_user;
-              // user.tidding_count = response.data.tidding_count;
-              // this.props.initCommonState(user)
-            }
-            this.setState({
-              memoLoading: false
-            })
-
-          }).catch((error) => {
-            console.log(error)
-          })
-
-      this.fetchReplies()
-        
-      $('body>#root').on('onMemoDelete', (event) => { 
-        // const val = $('body>#root').data('onMemoDelete')
-        const val = window.onMemoDelete ;
-        this.onMemoDelete( JSON.parse(decodeURIComponent(val)) )
-      })
-
-      
-    }
-
-    onPaginationChange = (pageCount) => {
-      this.setState({ pageCount }, () => {
-        this.fetchReplies()
-      })
-    }
-
-    componentWillUnmount() {
-      $('body>#root').off('onMemoDelete')
-    }
-    onMemoDelete(memo) {
-      const deleteUrl = `/commons/delete.json`;
-      // 获取memo list
-        axios.delete(deleteUrl, { data: {
-            object_id: memo.id,
-            object_type: 'message'
-          }
-        })
-        .then((response) => {
-          const status = response.data.status
-          if (status === 0) {
-
-            this.props.showNotification('删除成功');
-            const props = Object.assign({}, this.props, {})
-            this.props.toListPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id} ) )
-            
-          } else if (status === -1) {
-            this.props.showNotification('帖子已被删除');
-            this.props.history.push(`/forums`)
-          }
-        }).catch((error) => {
-          console.log(error)
-        })
-    }
-
-    componentDidUpdate(prevProps, prevState, snapshot) {
-      // if (this.state.memo && this.state.memo.content 
-      //     && (!prevProps.memo || prevProps.memo.content != this.state.memo.content) ) {
-      if (this.state.memo && this.state.memo.content && prevState.memoLoading === true && this.state.memoLoading === false) {
-        // md渲染content,等xhr执行完(即memoLoading变化),memo.content更新后初始化md
-        
-          setTimeout(()=>{
-            // var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
-            //     htmlDecode: "style,script,iframe",  // you can filter tags decode
-            //     taskList: true,
-            //     tex: true,  // 默认不解析
-            //     flowChart: true,  // 默认不解析
-            //     sequenceDiagram: true // 默认不解析
-            // });
-          }, 200)
-      }
-      
-    }
-
-    clickPraise(){
-        const { memo } = this.state;
-        // const url = `/api/v1/discusses/${memo.id}/plus`;
-        const url = memo.user_praise ? '/praise_tread/unlike.json' : `/praise_tread/like.json`;
-        const _method = memo.user_praise ? axios.delete : axios.post
-        let _data = {
-          object_id: memo.id,  
-          object_type: 'message',  //Discuss
-        }
-        if (memo.user_praise) {
-          _data = {
-            data: _data
-          }
-        }
-        _method(url, {
-              ..._data
-            },
-            {
-                
-            }
-        ).then((response) => {
-            
-            const newMemo = Object.assign({}, this.state.memo)
-            newMemo.praises_count = newMemo.user_praise ? newMemo.praises_count - 1 : newMemo.praises_count + 1
-            newMemo.total_praises_count = newMemo.user_praise ? newMemo.total_praises_count - 1 : newMemo.total_praises_count + 1
-            newMemo.user_praise = !newMemo.user_praise
-            this.setState({memo : newMemo })
-        }).catch((error) => {
-                console.log(error)
-        })
-    }
-    renderAttachment() {
-      const { memo } = this.state;
-      const attachments = []
-      memo.attachments.forEach((item, index) => {
-        const ar = item.url.split('/')
-        const fileName = item.title || ar[ar.length - 1]
-        let filesize = 0
-        if (item.filesize) {
-          filesize = item.filesize
-          // filesize = bytesToSize(item.filesize)
-        }
-        attachments.push(
-          // <p className="clearfix" key={index} >
-          //   <a href={item.url} className="color-green clearfix notefileDownload">
-          //     <i className="iconfont icon-fujian color-green ml5 fl"></i>
-          //     {fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }>
-          //       <span className="fl task-hide upload_item" style={{ color: '#333'}}>{fileName}</span>
-          //     </ConditionToolTip>}
-          //     <span className="fl" style={{ color: '#999', marginLeft: '6px'}}>{filesize? ` ${filesize.replace(' ', '')}` : ''}</span>
-          //   </a>
-          // </p>
-
-          <div className="color-grey df" key={index}>
-            <a className="color-grey ">
-              <i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
-            </a>
-            {/* {fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }> </ConditionToolTip>} */}
-              <a href={item.url} title={fileName.length > 30 ? fileName : ''}
-                  className="mr12 color9B9B overflowHidden1" length="58" style={{maxWidth: '480px'}}>
-                {fileName}
-              </a>
-           
-
-            <span className="color656565 mt2 color-grey-6 font-12 mr8">{item.filesize}</span>
-            
-          </div>
-          )
-      })
-      return attachments;
-    }
-    // ------------------------------------------------------------------------------------------- comments  START
-    // ------------------------------------------------------------------------------------------- comments  START
-    transformReply = (reply, children = []) => {
-      const isAdmin = this.props.isAdmin()
-      const isSuperAdmin = this.props.isSuperAdmin()
-      return {
-        isSuperAdmin: isSuperAdmin,
-        admin: isAdmin, //
-        permission: true, //
-        children: children,
-        child_message_count: reply.total_count,
-        hidden: reply.is_hidden, 
-        id: reply.id,
-        image_url: reply.author.image_url,
-        reward: null, //
-        time: moment(reply.created_on).fromNow(),
-        user_id: reply.author.id,
-        user_login: reply.author.login,
-        user_praise: reply.liked,
-        username: reply.author.name,
-        content: reply.content,
-        praise_count: reply.praises_count
-      }
-    }
-
-    fetchReplies = () => {
-      const topicId = this.props.match.params.topicId
-      const url = `/messages/${topicId}/reply_list.json?page=${this.state.pageCount}&page_size=${REPLY_PAGE_COUNT}`
-      axios.get(url,{
-      })
-      .then((response) => {
-        const { replies, liked, total_replies_count, total_count } = response.data.data
-        
-        const memo = Object.assign({}, this.state.memo)
-        memo.user_praise = liked
-        memo.total_replies_count = total_replies_count;
-        this.setState({
-          memo,
-          comments: generateComments(replies, this.transformReply, 'replies'),
-          // : this.state.comments.concat(comments),
-          total_count: total_count
-        })
-      }).catch((error) => {
-        console.log(error)
-      })
-    }
-
-    _getUser() {
-      const { current_user } = this.props;
-      current_user.user_url = `/users/${current_user.login}`;
-      return current_user;
-    }
-    _findById = _findById
-    replyComment = (commentContent, id, editor) => {
-      const { showNotification } = this.props;
-      // if (!commentContent || commentContent.length === 0) {
-      //   showNotification(NEED_TO_WRITE_CONTENT)
-      //   return;
-      // }
-
-      if (this.state.memo.id === id ) { // 回复帖子
-        this.createNewComment(commentContent, id, editor);
-        return;
-      }
-      const url = `/messages/${id}/reply.json`;
-      
-      const { comments } = this.state;
-      const user = this._getUser();
-      /*
-      移除末尾的空行
-      .replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g,'');
-        
-      */
-     
-      commentContent = handleContentBeforeCreateSecondLevelComment(commentContent)
-      if (!commentContent) {
-        this.props.showNotification('不能为空')
-        return;
-      }
-      axios.post(url, {
-            content: commentContent
-          },
-          {
-          }     
-        ).then((response) => {
-          if (response.data.data.id) { 
-            let newId = response.data.data.id;
-            const commentIndex = this._findById(id, comments);
-            const parentComment = comments[commentIndex]
-
-            this.setState({
-              // runTesting: false,
-              comments: addSecondLevelComment(comments, parentComment, commentIndex, newId, commentContent, user, editor)
-            }, ()=>{
-              // keditor代码美化
-              editor.html && window.prettyPrint()
-            })
-
-            const newMemo2 = Object.assign({}, this.state.memo);
-            newMemo2.total_replies_count = newMemo2.total_replies_count + 1;
-            this.setState({
-              memo: newMemo2
-            })
-          }
-          
-        }).catch((error) => {
-          console.log(error)
-        })
-    }
-    // 公共接口 --- 删除回复
-    deleteComment = (parrentComment, childCommentId) => {
-      handleDeleteComment(this, parrentComment, childCommentId, 'message')
-      
-    }
-    // 公共接口 --- 回复点赞
-    commentPraise = (discussId) => {
-      handleCommentPraise(this, discussId, 'message', (old_user_praise) => {
-        const newMemo2 = Object.assign({}, this.state.memo);
-
-        newMemo2.total_praises_count = old_user_praise 
-              ? newMemo2.total_praises_count - 1 : newMemo2.total_praises_count + 1;
-        this.setState({
-          memo: newMemo2
-        })
-      })
-    }
-    // 公共接口 --- 隐藏回复
-    hiddenComment = (item, childCommentId) => {
-      handleHiddenComment(this, item, childCommentId, 'message')
-    }
-    createNewComment = (commentContent, id, editor) => {
-      let content = handleContentBeforeCreateNew(commentContent);
-      const { memo } = this.props;
-      
-      const url = `/messages/${id}/reply.json`;
-
-      // const url = `/api/v1/memos/${memo.id}/reply`;
-      let { comments } = this.state;
-      axios.post(url, {
-          content: content
-        },
-        {
-        }        
-      ).then((response) => {
-        if (response.data.status === -1) {
-          console.error('服务端异常')
-          return;
-        }
-        // this.props.showNotification('帖子发表成功')
-
-        if (response.data) { 
-          const _id = response.data.data.id;
-          // ke
-          editor.html && editor.html('');
-          editor.afterBlur && editor.afterBlur()
-          // md
-          editor.setValue && editor.setValue('')
-          
-          
-          const user = this._getUser();
-          this.setState({
-            comments: addNewComment(comments, _id, content, user, this.props.isSuperAdmin(), this)
-          })
-          const newMemo2 = Object.assign({}, this.state.memo);
-          newMemo2.total_replies_count = newMemo2.total_replies_count + 1;
-          this.setState({
-            memo: newMemo2
-          })
-          this.refs.editor.showEditor();
-          this.refs.editor.close();
-          
-          
-        }
-      }).catch((error) => {
-        console.log(error)
-      })
-    }
-
-    /**
-     * parent.isAllChildrenLoaded 为 true的时候,表示已经没有更多子回复了
-     */
-    loadMoreChildComments = (parent) => {
-      const url = `/messages/${parent.id}/reply_list.json?page=1&page_size=500`
-      axios.get(url,{
-      })
-      .then((response) => {
-        const { replies, liked, total_replies_count } = response.data.data
-        
-        // const memo = Object.assign({}, this.state.memo)
-        // memo.total_replies_count = total_replies_count;
-        this.setState({
-          // memo,
-          comments: generateChildComments(replies, this.state.comments, parent, this.transformReply)
-        })
-      }).catch((error) => {
-        console.log(error)
-      })
-    }
-    // ------------------------------------------------------------------------------------------- comments  END
-    // ------------------------------------------------------------------------------------------- comments  END
-    // 置顶
-    setTop(memo) {
-      // const params = {
-      //   sticky: memo.sticky ? 0 : 1,  
-      // }
-      // if (this.state.p_s_order) { 
-      //   params.order = this.state.p_s_order;
-      // }
-      // if (this.state.p_forum_id) { 
-      //   params.forum_id = this.state.p_forum_id;
-      // }
-        // let paramsUrl = urlStringify(params)
-      const set_top_or_down_Url = `/messages/${memo.id}/sticky_top.json`;
-      // 获取memo list
-        axios.put(set_top_or_down_Url, {
-            
-        })
-        .then((response) => {
-          const status = response.data.status
-          if (status === 0) {
-            this.props.showNotification( memo.sticky ? '取消置顶成功' : '置顶成功');
-            memo.sticky = memo.sticky ? false : true
-            this.setState({
-              memo: Object.assign({}, memo)
-            })
-          }
-        }).catch((error) => {
-          console.log(error)
-        })
-    }
-   
-    setRewardDialogVisible = (visible) => {
-      this.setState({
-        goldRewardDialogOpen: visible
-      })
-    }
-    showRewardDialog = () => {
-      this.setState({
-        goldRewardDialogOpen: true
-      })
-    }
-    // --------------------------------------------------------------------------------------------帖子獎勵 END
-    showCommentInput = () => {
-      if (window.__useKindEditor === true) {
-        this.refs.editor.showEditor();
-      } else {
-        this.refs.editor.showEditor();
-      }
-    }
-    initReply = (parent) => {
-      if (!parent.isAllChildrenLoaded) {
-        this.loadMoreChildComments(parent)
-      }
-    }
-
-    
-  	render() {
-  		const { match, history } = this.props
-      const { recommend_shixun, current_user,author_info } = this.props;
-      const { memo, comments, hasMoreComments, goldRewardDialogOpen, pageCount, total_count } = this.state;
-      const messageId = match.params.topicId
-      if (this.state.memoLoading || !current_user) {
-        return <div className="edu-back-white" id="forum_index_list"></div>
-      }
-      current_user.user_url = `/users/${current_user.login}`;
-      const isCurrentUserTheAuthor = current_user.login == memo.author.login
-      const isAdmin = this.props.isAdmin()
-      // TODO 图片上传地址
-      const courseId=this.props.match.params.coursesId;
-      const boardId = this.props.match.params.boardId
-	    return (
-        <div className="edu-back-white edu-class-container edu-position course-message topicDetail" id="forum_index_list"> {/* fl with100 */}
-          <style>{`
-            .topicDetail #forum_list .return_btn.no_mr {
-              margin-right: 1px;
-            }
-            /* 有内容时,编辑器下方的边框*/
-            .topicDetail .borderBottom.commentInputs {
-              border-bottom: 1px solid rgb(238, 238, 238);
-            }
-            .independent {
-              background: rgb(250, 250, 250);
-              padding-bottom: 20px;
-              margin-bottom: 0px !important;
-            }
-
-            .course-message.topicDetail .panel-comment_item .comment_orig_content {
-                width: 1072px;
-            }
-          `}</style>
-          <CBreadcrumb className={'independent'} items={[
-            { to: current_user.first_category_url, name: this.props.coursedata.name},
-            { to: `/courses/${courseId}/boards/${boardId}`, name: memo.board_name },
-            { name: '帖子详情'}
-          ]}></CBreadcrumb>
-
-          <SendToCourseModal
-            ref="sendToCourseModal"
-            {...this.props}
-            moduleName="帖子"
-            selectedMessageIds={[messageId]}
-          ></SendToCourseModal>
-          <div className="clearfix">
-        		<div id="forum_list" className="forum_table mh650">
-    	        	<div className="padding30 bor-bottom-greyE" style={{paddingBottom: '20px'}}>
-                        <div className="font-16 cdefault clearfix pr pr35">
-                            <span className="noteDetailTitle">{memo.subject}</span>
-                            { !!memo.sticky && <span className="btn-cir btn-cir-red ml10" 
-                                style={{position: 'relative', bottom: '4px'}}>置顶</span>}
-                            { !!memo.reward && <span className="color-orange font-14 ml15"
-                              data-tip-down={`获得平台奖励金币:${memo.reward}`} >
-                              <i className="iconfont icon-gift mr5"></i>{memo.reward}
-                            </span> }
-                            {/* || current_user.user_id === author_info.user_id */}
-                            { current_user && (isAdmin || isCurrentUserTheAuthor)  &&
-                                <div className="edu-position-hidebox" style={{position: 'absolute', right: '2px',top:'4px'}}>
-                                    <a href="javascript:void(0);"><i className="fa fa-bars font-16"></i></a>
-                                    <ul className="edu-position-hide undis">
-                                        
-                                        { ( isCurrentUserTheAuthor || isAdmin ) && 
-                                            <li><a 
-                                              onClick={() => this.props.toEditPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id}) ) }
-                                            >编&nbsp;&nbsp;辑</a></li>}
-                                        { isAdmin &&
-                                          ( memo.sticky == true ?
-                                            <li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>取消置顶</a></li>
-                                            :
-                                            <li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>置&nbsp;&nbsp;顶</a></li> )
-                                        }
-                                        { isAdmin &&
-                                            <li><a href="javascript:void(0);" onClick={() => this.refs.sendToCourseModal.setVisible(true)}>发&nbsp;&nbsp;送</a></li> 
-                                        }
-                                        { ( isCurrentUserTheAuthor || isAdmin ) && <li>
-                                            <a href="javascript:void(0)" onClick={() =>
-                                                window.delete_confirm_box_2_react(`onMemoDelete`, '您确定要删除吗?' , memo)}>
-
-                                            删&nbsp;&nbsp;除</a>
-                                        </li>
-                                        }
-                                    </ul>
-                                </div>
-                            }
-                            
-                        </div>
-                        <div className="color-grey-9 clearfix">
-                            <span className="fl" style={{marginTop: "2px"}}>{moment(memo.created_on).fromNow()} 发布</span>
-                            <div className="fr">
-                                
-                            </div>
-                        </div>
-
-                        <div className="color-grey-9 clearfix">
-                            <span className="fl" style={{marginTop: '4px'}}>
-                              {/* { current_user.admin && <Tooltip title={ "帖子奖励" }>
-                                <span className="noteDetailNum rightline cdefault" style={{padding: '0 4px', cursor: 'pointer'}}>
-                                  <i className="iconfont icon-jiangli mr5" onClick={this.showRewardDialog}></i>
-                                </span>
-                                </Tooltip> } */}
-                                <Tooltip title={"浏览数"}>
-                                  <span className={`noteDetailNum `} style={{paddingLeft: '0px'}}>
-                                    <i className="iconfont icon-liulanyan mr5"></i>
-                                    <span style={{ top: "1px", position: "relative" }}>{memo.visits || '1'}</span>
-                                  </span>
-                                </Tooltip>
-                                { !!memo.total_replies_count && 
-                                <Tooltip title={"回复数"}>
-                                <a href="javascript:void(0)" className="noteDetailNum">
-                                  <i className="iconfont icon-huifu1 mr5" onClick={this.showCommentInput}></i>
-                                  <span style={{ top: "2px", position: "relative" }}>{ memo.total_replies_count }</span>
-                                </a>
-                                </Tooltip>
-                                 }
-                                 {!!memo.total_praises_count && 
-                                <Tooltip title={"点赞数"}>                                 
-                                  <span className={`noteDetailNum `} style={{}}>
-                                    <i className="iconfont icon-dianzan-xian mr5"></i>
-                                    <span style={{ top: "2px", position: "relative" }}>{ memo.total_praises_count }</span>
-                                  </span>
-                                </Tooltip>
-                                  }
-                            </span>
-                            <div className="fr">
-                            {/* || current_user.user_id === author_info.user_id */}
-                              <a className={`task-hide fr return_btn color-grey-6 ${ current_user && (isAdmin 
-                                  ) ? '': 'no_mr'} `} onClick={() => this.props.toListPage(Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id})) } >
-                                返回
-                              </a>
-                            </div>
-                        </div>
-                    </div>
-
-                    
-                    <div className="padding30 memoContent new_li" style={{ paddingBottom: '10px'}}>
-                      {memo.is_md == true ? <MarkdownToHtml content={memo.content}></MarkdownToHtml> : 
-                        <div dangerouslySetInnerHTML={{ __html: memo.content }}></div>
-                      }
-                    </div>
-                    <div className="padding30 bor-bottom-greyE" style={{paddingTop: '2px'}}>
-                        <div className="mt10 mb20">
-                          {/* ${memo.user_praise ? '' : ''}  */}
-                          <Tooltip title={`${memo.liked ? '取消点赞' : '点赞'}`}>
-                            <p className={`noteDetailPoint  ${memo.user_praise ? 'Pointed' : ''}`} onClick={()=>{this.clickPraise()}} >
-                              <i className="iconfont icon-dianzan"></i><br/>
-                              <span>{memo.praises_count}</span>
-                            </p>
-                          </Tooltip>
-                        </div>
-
-                        { memo.attachments && !!memo.attachments.length && 
-                        <div>
-                            {this.renderAttachment()}
-                        </div>
-                        }
-                    </div>
-                    
-                      <MemoDetailMDEditor ref="editor" memo={memo} usingMockInput={true} placeholder="说点什么" 
-                          height={160} showError={true} buttonText={'发表'} className={comments && comments.length && 'borderBottom'}></MemoDetailMDEditor>
-
-                  {/*  onClick={ this.createNewComment } 
-                        enableReplyTo={true}
-                  */}
-                    <div className="padding20  memoReplies commentsDelegateParent comments_hideSecondReplyUserHeader"
-                        style={{ display: (comments && !!comments.length) ? 'block' : 'none', paddingBottom: '0px' }}>
-                      <div className="replies_count">
-                        <span className="labal font-16">全部回复</span>
-                        <span className="count font-16">({memo.total_replies_count})</span>
-                      </div>
-
-                      <Comments comments={comments} user={current_user}
-                        replyComment={this.replyComment}
-                        deleteComment={this.deleteComment}
-                        commentPraise={this.commentPraise}
-                        rewardCode={this.rewardCode}
-                        hiddenComment={this.hiddenComment}
-                        buttonText={'发表'}
-
-                        usingAntdModal={true}
-                        isChildCommentPagination={true}
-                        loadMoreChildComments={this.loadMoreChildComments}
-                        initReply={this.initReply}
-                        showRewardButton={false}
-
-                        onlySuperAdminCouldHide={true}
-                      ></Comments>
-                     
-                        
-                        {/* { true ?  : 
-                        <div className="memoMore">
-                          <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
-                        </div>} */}
-                    </div>
-                    
-                    
-                    <div className="memoMore" style={{'margin-top': '20px'}}>
-                      { total_count > REPLY_PAGE_COUNT &&  
-                        <Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/>
-                      }
-                      <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
-                    </div> 
-                    
-    	        </div>
-            </div>
-          </div>
-
-	    );
-  	}
-}
-
-export default ImageLayerOfCommentHOC() ( RouteHOC()(TopicDetail) );
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames'
+
+import axios from 'axios'
+
+import moment from 'moment'
+
+import Comments from '../../comment/Comments'
+
+import update from 'immutability-helper'
+import RewardDialog from '../../common/RewardDialog';
+import {ImageLayerOfCommentHOC} from '../../page/layers/ImageLayerOfCommentHOC'
+
+import MemoDetailMDEditor from '../../forums/MemoDetailMDEditor'
+import { RouteHOC } from './common.js'
+import '../../forums/Post.css'
+import '../../forums/RightSection.css'
+import './TopicDetail.css'
+import '../common/courseMessage.css'
+import { Pagination, Tooltip } from 'antd'
+import { bytesToSize, ConditionToolTip, markdownToHTML, MarkdownToHtml } from 'educoder'
+import SendToCourseModal from '../coursesPublic/modal/SendToCourseModal'
+import CBreadcrumb from '../common/CBreadcrumb'
+import { generateComments, generateChildComments, _findById, handleContentBeforeCreateNew, addNewComment
+  , addSecondLevelComment, NEED_TO_WRITE_CONTENT, handleContentBeforeCreateSecondLevelComment
+  , handleDeleteComment, handleCommentPraise, handleHiddenComment } from '../common/CommentsHelper'
+
+const $ = window.$
+const REPLY_PAGE_COUNT = 10
+function urlStringify(params) {
+  let noParams = true;
+  let paramsUrl = '';
+    for (let key in params) {
+      noParams = false;
+      paramsUrl += `${key}=${params[key]}&`
+    }
+    if (noParams) {
+      return '';
+    }
+    paramsUrl = paramsUrl.substring(0, paramsUrl.length - 1);
+    return paramsUrl;
+}
+class TopicDetail extends Component {
+    constructor(props) {
+      super(props)
+
+      this.state = {
+        memo: {},
+        memoLoading: true,
+        hasMoreComments: false,
+        pageCount: 1,
+        comments: [],
+        goldRewardDialogOpen: false,
+      }
+    }
+    componentDidMount() {
+      window.$("html,body").animate({"scrollTop":0})
+
+      const topicId = this.props.match.params.topicId
+      const bid = this.props.match.params.boardId
+      
+      const memoUrl = `/messages/${topicId}.json`;
+      this.setState({
+        memoLoading: true
+      })
+      axios.get(memoUrl,{
+          })
+          .then((response) => {
+            
+            if (response.data.status === -1) {
+              setTimeout(() => {
+                this.props.showNotification('帖子不存在!')
+              }, 300)
+              // this.props.toListPage(response.data.data.course_id, bid)
+              return;
+            } else  {
+              
+              this.setState({
+                memo: Object.assign({}, {
+                  ...response.data.data,
+                  replies_count: response.data.data.total_replies_count
+                }, {...this.state.memo})
+              }, () => {
+              })
+
+              // const { memo_replies, memo } = response.data;
+              // let hasMoreComments = false;
+              // if (memo_replies && memo_replies.length === 10 && memo.total_replies_count > 10) {  
+              //   // 遍历一遍,计算下是否还有评论未加载
+              //   let totalCount = 10;
+              //   memo_replies.forEach(item=>{
+              //     totalCount += item.children.length
+              //   })
+              //   if (totalCount < memo.total_replies_count) {
+              //     hasMoreComments = true;
+              //   }
+              // }
+              // this.setState({
+              //   hasMoreComments,
+              //   pageCount: 1,
+              //   comments: memo_replies
+              // })
+              // delete response.data.memo_replies;
+              // this.setState(response.data)
+              // const user = response.data.current_user;
+              // user.tidding_count = response.data.tidding_count;
+              // this.props.initCommonState(user)
+            }
+            this.setState({
+              memoLoading: false
+            })
+
+          }).catch((error) => {
+            console.log(error)
+          })
+
+      this.fetchReplies()
+        
+      $('body>#root').on('onMemoDelete', (event) => { 
+        // const val = $('body>#root').data('onMemoDelete')
+        const val = window.onMemoDelete ;
+        this.onMemoDelete( JSON.parse(decodeURIComponent(val)) )
+      })
+
+      
+    }
+
+    onPaginationChange = (pageCount) => {
+      this.setState({ pageCount }, () => {
+        this.fetchReplies()
+      })
+    }
+
+    componentWillUnmount() {
+      $('body>#root').off('onMemoDelete')
+    }
+    onMemoDelete(memo) {
+      const deleteUrl = `/commons/delete.json`;
+      // 获取memo list
+        axios.delete(deleteUrl, { data: {
+            object_id: memo.id,
+            object_type: 'message'
+          }
+        })
+        .then((response) => {
+          const status = response.data.status
+          if (status === 0) {
+
+            this.props.showNotification('删除成功');
+            const props = Object.assign({}, this.props, {})
+            this.props.toListPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id} ) )
+            
+          } else if (status === -1) {
+            this.props.showNotification('帖子已被删除');
+            this.props.history.push(`/forums`)
+          }
+        }).catch((error) => {
+          console.log(error)
+        })
+    }
+
+    componentDidUpdate(prevProps, prevState, snapshot) {
+      // if (this.state.memo && this.state.memo.content 
+      //     && (!prevProps.memo || prevProps.memo.content != this.state.memo.content) ) {
+      if (this.state.memo && this.state.memo.content && prevState.memoLoading === true && this.state.memoLoading === false) {
+        // md渲染content,等xhr执行完(即memoLoading变化),memo.content更新后初始化md
+        
+          setTimeout(()=>{
+            // var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
+            //     htmlDecode: "style,script,iframe",  // you can filter tags decode
+            //     taskList: true,
+            //     tex: true,  // 默认不解析
+            //     flowChart: true,  // 默认不解析
+            //     sequenceDiagram: true // 默认不解析
+            // });
+          }, 200)
+      }
+      
+    }
+
+    clickPraise(){
+        const { memo } = this.state;
+        // const url = `/api/v1/discusses/${memo.id}/plus`;
+        const url = memo.user_praise ? '/praise_tread/unlike.json' : `/praise_tread/like.json`;
+        const _method = memo.user_praise ? axios.delete : axios.post
+        let _data = {
+          object_id: memo.id,  
+          object_type: 'message',  //Discuss
+        }
+        if (memo.user_praise) {
+          _data = {
+            data: _data
+          }
+        }
+        _method(url, {
+              ..._data
+            },
+            {
+                
+            }
+        ).then((response) => {
+            
+            const newMemo = Object.assign({}, this.state.memo)
+            newMemo.praises_count = newMemo.user_praise ? newMemo.praises_count - 1 : newMemo.praises_count + 1
+            newMemo.total_praises_count = newMemo.user_praise ? newMemo.total_praises_count - 1 : newMemo.total_praises_count + 1
+            newMemo.user_praise = !newMemo.user_praise
+            this.setState({memo : newMemo })
+        }).catch((error) => {
+                console.log(error)
+        })
+    }
+    renderAttachment() {
+      const { memo } = this.state;
+      const attachments = []
+      memo.attachments.forEach((item, index) => {
+        const ar = item.url.split('/')
+        const fileName = item.title || ar[ar.length - 1]
+        let filesize = 0
+        if (item.filesize) {
+          filesize = item.filesize
+          // filesize = bytesToSize(item.filesize)
+        }
+        attachments.push(
+          // <p className="clearfix" key={index} >
+          //   <a href={item.url} className="color-green clearfix notefileDownload">
+          //     <i className="iconfont icon-fujian color-green ml5 fl"></i>
+          //     {fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }>
+          //       <span className="fl task-hide upload_item" style={{ color: '#333'}}>{fileName}</span>
+          //     </ConditionToolTip>}
+          //     <span className="fl" style={{ color: '#999', marginLeft: '6px'}}>{filesize? ` ${filesize.replace(' ', '')}` : ''}</span>
+          //   </a>
+          // </p>
+
+          <div className="color-grey df" key={index}>
+            <a className="color-grey ">
+              <i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
+            </a>
+            {/* {fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }> </ConditionToolTip>} */}
+              <a href={item.url} title={fileName.length > 30 ? fileName : ''}
+                  className="mr12 color9B9B overflowHidden1" length="58" style={{maxWidth: '480px'}}>
+                {fileName}
+              </a>
+           
+
+            <span className="color656565 mt2 color-grey-6 font-12 mr8">{item.filesize}</span>
+            
+          </div>
+          )
+      })
+      return attachments;
+    }
+    // ------------------------------------------------------------------------------------------- comments  START
+    // ------------------------------------------------------------------------------------------- comments  START
+    transformReply = (reply, children = []) => {
+      const isAdmin = this.props.isAdmin()
+      const isSuperAdmin = this.props.isSuperAdmin()
+      return {
+        isSuperAdmin: isSuperAdmin,
+        admin: isAdmin, //
+        permission: true, //
+        children: children,
+        child_message_count: reply.total_count,
+        hidden: reply.is_hidden, 
+        id: reply.id,
+        image_url: reply.author.image_url,
+        reward: null, //
+        time: moment(reply.created_on).fromNow(),
+        user_id: reply.author.id,
+        user_login: reply.author.login,
+        user_praise: reply.liked,
+        username: reply.author.name,
+        content: reply.content,
+        praise_count: reply.praises_count
+      }
+    }
+
+    fetchReplies = () => {
+      const topicId = this.props.match.params.topicId
+      const url = `/messages/${topicId}/reply_list.json?page=${this.state.pageCount}&page_size=${REPLY_PAGE_COUNT}`
+      axios.get(url,{
+      })
+      .then((response) => {
+        const { replies, liked, total_replies_count, total_count } = response.data.data
+        
+        const memo = Object.assign({}, this.state.memo)
+        memo.user_praise = liked
+        memo.total_replies_count = total_replies_count;
+        this.setState({
+          memo,
+          comments: generateComments(replies, this.transformReply, 'replies'),
+          // : this.state.comments.concat(comments),
+          total_count: total_count
+        })
+      }).catch((error) => {
+        console.log(error)
+      })
+    }
+
+    _getUser() {
+      const { current_user } = this.props;
+      current_user.user_url = `/users/${current_user.login}`;
+      return current_user;
+    }
+    _findById = _findById
+    replyComment = (commentContent, id, editor) => {
+      const { showNotification } = this.props;
+      // if (!commentContent || commentContent.length === 0) {
+      //   showNotification(NEED_TO_WRITE_CONTENT)
+      //   return;
+      // }
+
+      if (this.state.memo.id === id ) { // 回复帖子
+        this.createNewComment(commentContent, id, editor);
+        return;
+      }
+      const url = `/messages/${id}/reply.json`;
+      
+      const { comments } = this.state;
+      const user = this._getUser();
+      /*
+      移除末尾的空行
+      .replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g,'');
+        
+      */
+     
+      commentContent = handleContentBeforeCreateSecondLevelComment(commentContent)
+      if (!commentContent) {
+        this.props.showNotification('不能为空')
+        return;
+      }
+      axios.post(url, {
+            content: commentContent
+          },
+          {
+          }     
+        ).then((response) => {
+          if (response.data.data.id) { 
+            let newId = response.data.data.id;
+            const commentIndex = this._findById(id, comments);
+            const parentComment = comments[commentIndex]
+
+            this.setState({
+              // runTesting: false,
+              comments: addSecondLevelComment(comments, parentComment, commentIndex, newId, commentContent, user, editor)
+            }, ()=>{
+              // keditor代码美化
+              editor.html && window.prettyPrint()
+            })
+
+            const newMemo2 = Object.assign({}, this.state.memo);
+            newMemo2.total_replies_count = newMemo2.total_replies_count + 1;
+            this.setState({
+              memo: newMemo2
+            })
+          }
+          
+        }).catch((error) => {
+          console.log(error)
+        })
+    }
+    // 公共接口 --- 删除回复
+    deleteComment = (parrentComment, childCommentId) => {
+      handleDeleteComment(this, parrentComment, childCommentId, 'message')
+      
+    }
+    // 公共接口 --- 回复点赞
+    commentPraise = (discussId) => {
+      handleCommentPraise(this, discussId, 'message', (old_user_praise) => {
+        const newMemo2 = Object.assign({}, this.state.memo);
+
+        newMemo2.total_praises_count = old_user_praise 
+              ? newMemo2.total_praises_count - 1 : newMemo2.total_praises_count + 1;
+        this.setState({
+          memo: newMemo2
+        })
+      })
+    }
+    // 公共接口 --- 隐藏回复
+    hiddenComment = (item, childCommentId) => {
+      handleHiddenComment(this, item, childCommentId, 'message')
+    }
+    createNewComment = (commentContent, id, editor) => {
+      let content = handleContentBeforeCreateNew(commentContent);
+      const { memo } = this.props;
+      
+      const url = `/messages/${id}/reply.json`;
+
+      // const url = `/api/v1/memos/${memo.id}/reply`;
+      let { comments } = this.state;
+      axios.post(url, {
+          content: content
+        },
+        {
+        }        
+      ).then((response) => {
+        if (response.data.status === -1) {
+          console.error('服务端异常')
+          return;
+        }
+        // this.props.showNotification('帖子发表成功')
+
+        if (response.data) { 
+          const _id = response.data.data.id;
+          // ke
+          editor.html && editor.html('');
+          editor.afterBlur && editor.afterBlur()
+          // md
+          editor.setValue && editor.setValue('')
+          
+          
+          const user = this._getUser();
+          this.setState({
+            comments: addNewComment(comments, _id, content, user, this.props.isSuperAdmin(), this)
+          })
+          const newMemo2 = Object.assign({}, this.state.memo);
+          newMemo2.total_replies_count = newMemo2.total_replies_count + 1;
+          this.setState({
+            memo: newMemo2
+          })
+          this.refs.editor.showEditor();
+          this.refs.editor.close();
+          
+          
+        }
+      }).catch((error) => {
+        console.log(error)
+      })
+    }
+
+    /**
+     * parent.isAllChildrenLoaded 为 true的时候,表示已经没有更多子回复了
+     */
+    loadMoreChildComments = (parent) => {
+      const url = `/messages/${parent.id}/reply_list.json?page=1&page_size=500`
+      axios.get(url,{
+      })
+      .then((response) => {
+        const { replies, liked, total_replies_count } = response.data.data
+        
+        // const memo = Object.assign({}, this.state.memo)
+        // memo.total_replies_count = total_replies_count;
+        this.setState({
+          // memo,
+          comments: generateChildComments(replies, this.state.comments, parent, this.transformReply)
+        })
+      }).catch((error) => {
+        console.log(error)
+      })
+    }
+    // ------------------------------------------------------------------------------------------- comments  END
+    // ------------------------------------------------------------------------------------------- comments  END
+    // 置顶
+    setTop(memo) {
+      // const params = {
+      //   sticky: memo.sticky ? 0 : 1,  
+      // }
+      // if (this.state.p_s_order) { 
+      //   params.order = this.state.p_s_order;
+      // }
+      // if (this.state.p_forum_id) { 
+      //   params.forum_id = this.state.p_forum_id;
+      // }
+        // let paramsUrl = urlStringify(params)
+      const set_top_or_down_Url = `/messages/${memo.id}/sticky_top.json`;
+      // 获取memo list
+        axios.put(set_top_or_down_Url, {
+            
+        })
+        .then((response) => {
+          const status = response.data.status
+          if (status === 0) {
+            this.props.showNotification( memo.sticky ? '取消置顶成功' : '置顶成功');
+            memo.sticky = memo.sticky ? false : true
+            this.setState({
+              memo: Object.assign({}, memo)
+            })
+          }
+        }).catch((error) => {
+          console.log(error)
+        })
+    }
+   
+    setRewardDialogVisible = (visible) => {
+      this.setState({
+        goldRewardDialogOpen: visible
+      })
+    }
+    showRewardDialog = () => {
+      this.setState({
+        goldRewardDialogOpen: true
+      })
+    }
+    // --------------------------------------------------------------------------------------------帖子獎勵 END
+    showCommentInput = () => {
+      if (window.__useKindEditor === true) {
+        this.refs.editor.showEditor();
+      } else {
+        this.refs.editor.showEditor();
+      }
+    }
+    initReply = (parent) => {
+      if (!parent.isAllChildrenLoaded) {
+        this.loadMoreChildComments(parent)
+      }
+    }
+
+    
+  	render() {
+  		const { match, history } = this.props
+      const { recommend_shixun, current_user,author_info } = this.props;
+      const { memo, comments, hasMoreComments, goldRewardDialogOpen, pageCount, total_count } = this.state;
+      const messageId = match.params.topicId
+      if (this.state.memoLoading || !current_user) {
+        return <div className="edu-back-white" id="forum_index_list"></div>
+      }
+      current_user.user_url = `/users/${current_user.login}`;
+      const isCurrentUserTheAuthor = current_user.login == memo.author.login
+      const isAdmin = this.props.isAdmin()
+      // TODO 图片上传地址
+      const courseId=this.props.match.params.coursesId;
+      const boardId = this.props.match.params.boardId
+	    return (
+        <div className="edu-back-white edu-class-container edu-position course-message topicDetail" id="forum_index_list"> {/* fl with100 */}
+          <style>{`
+            .topicDetail #forum_list .return_btn.no_mr {
+              margin-right: 1px;
+            }
+            /* 有内容时,编辑器下方的边框*/
+            .topicDetail .borderBottom.commentInputs {
+              border-bottom: 1px solid rgb(238, 238, 238);
+            }
+            .independent {
+              background: rgb(250, 250, 250);
+              padding-bottom: 20px;
+              margin-bottom: 0px !important;
+            }
+
+            .course-message.topicDetail .panel-comment_item .comment_orig_content {
+                width: 1072px;
+            }
+          `}</style>
+          <CBreadcrumb className={'independent'} items={[
+            { to: current_user&&current_user.first_category_url, name: this.props.coursedata.name},
+            { to: `/courses/${courseId}/boards/${boardId}`, name: memo.board_name },
+            { name: '帖子详情'}
+          ]}></CBreadcrumb>
+
+          <SendToCourseModal
+            ref="sendToCourseModal"
+            {...this.props}
+            moduleName="帖子"
+            selectedMessageIds={[messageId]}
+          ></SendToCourseModal>
+          <div className="clearfix">
+        		<div id="forum_list" className="forum_table mh650">
+    	        	<div className="padding30 bor-bottom-greyE" style={{paddingBottom: '20px'}}>
+                        <div className="font-16 cdefault clearfix pr pr35">
+                            <span className="noteDetailTitle">{memo.subject}</span>
+                            { !!memo.sticky && <span className="btn-cir btn-cir-red ml10" 
+                                style={{position: 'relative', bottom: '4px'}}>置顶</span>}
+                            { !!memo.reward && <span className="color-orange font-14 ml15"
+                              data-tip-down={`获得平台奖励金币:${memo.reward}`} >
+                              <i className="iconfont icon-gift mr5"></i>{memo.reward}
+                            </span> }
+                            {/* || current_user.user_id === author_info.user_id */}
+                            { current_user && (isAdmin || isCurrentUserTheAuthor)  &&
+                                <div className="edu-position-hidebox" style={{position: 'absolute', right: '2px',top:'4px'}}>
+                                    <a href="javascript:void(0);"><i className="fa fa-bars font-16"></i></a>
+                                    <ul className="edu-position-hide undis">
+                                        
+                                        { ( isCurrentUserTheAuthor || isAdmin ) && 
+                                            <li><a 
+                                              onClick={() => this.props.toEditPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id}) ) }
+                                            >编&nbsp;&nbsp;辑</a></li>}
+                                        { isAdmin &&
+                                          ( memo.sticky == true ?
+                                            <li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>取消置顶</a></li>
+                                            :
+                                            <li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>置&nbsp;&nbsp;顶</a></li> )
+                                        }
+                                        { isAdmin &&
+                                            <li><a href="javascript:void(0);" onClick={() => this.refs.sendToCourseModal.setVisible(true)}>发&nbsp;&nbsp;送</a></li> 
+                                        }
+                                        { ( isCurrentUserTheAuthor || isAdmin ) && <li>
+                                            <a href="javascript:void(0)" onClick={() =>
+                                                window.delete_confirm_box_2_react(`onMemoDelete`, '您确定要删除吗?' , memo)}>
+
+                                            删&nbsp;&nbsp;除</a>
+                                        </li>
+                                        }
+                                    </ul>
+                                </div>
+                            }
+                            
+                        </div>
+                        <div className="color-grey-9 clearfix">
+                            <span className="fl" style={{marginTop: "2px"}}>{moment(memo.created_on).fromNow()} 发布</span>
+                            <div className="fr">
+                                
+                            </div>
+                        </div>
+
+                        <div className="color-grey-9 clearfix">
+                            <span className="fl" style={{marginTop: '4px'}}>
+                              {/* { current_user.admin && <Tooltip title={ "帖子奖励" }>
+                                <span className="noteDetailNum rightline cdefault" style={{padding: '0 4px', cursor: 'pointer'}}>
+                                  <i className="iconfont icon-jiangli mr5" onClick={this.showRewardDialog}></i>
+                                </span>
+                                </Tooltip> } */}
+                                <Tooltip title={"浏览数"}>
+                                  <span className={`noteDetailNum `} style={{paddingLeft: '0px'}}>
+                                    <i className="iconfont icon-liulanyan mr5"></i>
+                                    <span style={{ top: "1px", position: "relative" }}>{memo.visits || '1'}</span>
+                                  </span>
+                                </Tooltip>
+                                { !!memo.total_replies_count && 
+                                <Tooltip title={"回复数"}>
+                                <a href="javascript:void(0)" className="noteDetailNum">
+                                  <i className="iconfont icon-huifu1 mr5" onClick={this.showCommentInput}></i>
+                                  <span style={{ top: "2px", position: "relative" }}>{ memo.total_replies_count }</span>
+                                </a>
+                                </Tooltip>
+                                 }
+                                 {!!memo.total_praises_count && 
+                                <Tooltip title={"点赞数"}>                                 
+                                  <span className={`noteDetailNum `} style={{}}>
+                                    <i className="iconfont icon-dianzan-xian mr5"></i>
+                                    <span style={{ top: "2px", position: "relative" }}>{ memo.total_praises_count }</span>
+                                  </span>
+                                </Tooltip>
+                                  }
+                            </span>
+                            <div className="fr">
+                            {/* || current_user.user_id === author_info.user_id */}
+                              <a className={`task-hide fr return_btn color-grey-6 ${ current_user && (isAdmin 
+                                  ) ? '': 'no_mr'} `} onClick={() => this.props.toListPage(Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id})) } >
+                                返回
+                              </a>
+                            </div>
+                        </div>
+                    </div>
+
+                    
+                    <div className="padding30 memoContent new_li" style={{ paddingBottom: '10px'}}>
+                      {memo.is_md == true ? <MarkdownToHtml content={memo.content}></MarkdownToHtml> : 
+                        <div dangerouslySetInnerHTML={{ __html: memo.content }}></div>
+                      }
+                    </div>
+                    <div className="padding30 bor-bottom-greyE" style={{paddingTop: '2px'}}>
+                        <div className="mt10 mb20">
+                          {/* ${memo.user_praise ? '' : ''}  */}
+                          <Tooltip title={`${memo.liked ? '取消点赞' : '点赞'}`}>
+                            <p className={`noteDetailPoint  ${memo.user_praise ? 'Pointed' : ''}`} onClick={()=>{this.clickPraise()}} >
+                              <i className="iconfont icon-dianzan"></i><br/>
+                              <span>{memo.praises_count}</span>
+                            </p>
+                          </Tooltip>
+                        </div>
+
+                        { memo.attachments && !!memo.attachments.length && 
+                        <div>
+                            {this.renderAttachment()}
+                        </div>
+                        }
+                    </div>
+                    
+                      <MemoDetailMDEditor ref="editor" memo={memo} usingMockInput={true} placeholder="说点什么" 
+                          height={160} showError={true} buttonText={'发表'} className={comments && comments.length && 'borderBottom'}></MemoDetailMDEditor>
+
+                  {/*  onClick={ this.createNewComment } 
+                        enableReplyTo={true}
+                  */}
+                    <div className="padding20  memoReplies commentsDelegateParent comments_hideSecondReplyUserHeader"
+                        style={{ display: (comments && !!comments.length) ? 'block' : 'none', paddingBottom: '0px' }}>
+                      <div className="replies_count">
+                        <span className="labal font-16">全部回复</span>
+                        <span className="count font-16">({memo.total_replies_count})</span>
+                      </div>
+
+                      <Comments comments={comments} user={current_user}
+                        replyComment={this.replyComment}
+                        deleteComment={this.deleteComment}
+                        commentPraise={this.commentPraise}
+                        rewardCode={this.rewardCode}
+                        hiddenComment={this.hiddenComment}
+                        buttonText={'发表'}
+
+                        usingAntdModal={true}
+                        isChildCommentPagination={true}
+                        loadMoreChildComments={this.loadMoreChildComments}
+                        initReply={this.initReply}
+                        showRewardButton={false}
+
+                        onlySuperAdminCouldHide={true}
+                      ></Comments>
+                     
+                        
+                        {/* { true ?  : 
+                        <div className="memoMore">
+                          <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
+                        </div>} */}
+                    </div>
+                    
+                    
+                    <div className="memoMore" style={{'margin-top': '20px'}}>
+                      { total_count > REPLY_PAGE_COUNT &&  
+                        <Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/>
+                      }
+                      <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
+                    </div> 
+                    
+    	        </div>
+            </div>
+          </div>
+
+	    );
+  	}
+}
+
+export default ImageLayerOfCommentHOC() ( RouteHOC()(TopicDetail) );
diff --git a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js
index eb53fa373..4d82f4182 100644
--- a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js
+++ b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js
@@ -223,7 +223,7 @@ class CommonWorkDetailIndex extends Component{
                 }
               `}</style>
               {current_user && <CBreadcrumb items={[
-                { to: current_user.first_category_url , name: course_name},
+                { to: current_user&&current_user.first_category_url , name: course_name},
                 { to: `/courses/${courseId}/${moduleEngName}/${category_id}`, name: category_name },
                 window.location.pathname.indexOf('appraise') == -1 ? { } : { to: `/courses/${courseId}/${moduleEngName}/${workId}/list`, name: '作业详情' },
                 // 1.	与上一条联动,当匿评他人作品时,TA人作品的作者真实姓名切换为“匿名”
diff --git a/public/react/src/modules/courses/exercise/ExerciseNew.js b/public/react/src/modules/courses/exercise/ExerciseNew.js
index f5332d56e..dac54f9e9 100644
--- a/public/react/src/modules/courses/exercise/ExerciseNew.js
+++ b/public/react/src/modules/courses/exercise/ExerciseNew.js
@@ -1,571 +1,571 @@
-import React,{ Component } from "react";
-
-import {
-  Form, Input, InputNumber, Switch, Radio,
-  Slider, Button, Upload, Icon, Rate, Checkbox, message,
-  Row, Col, Select, Modal, Tooltip
-} from 'antd';
-import  { Q_TYPE_SINGLE, Q_TYPE_MULTI, Q_TYPE_JUDGE, Q_TYPE_NULL, Q_TYPE_MAIN, Q_TYPE_SHIXUN } from './new/common'
-import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
-import axios from 'axios'
-// import './board.css'
-import "../common/formCommon.css"
-
-// import { RouteHOC } from './common.js'
-import CBreadcrumb from '../common/CBreadcrumb'
-import {getUrl, ActionBtn} from 'educoder';
-
-import SingleEditor from './new/SingleEditor'
-import SingleDisplay from './new/SingleDisplay'
-import JudgeEditor from './new/JudgeEditor'
-import JudgeDisplay from './new/JudgeDisplay'
-import NullEditor from './new/NullEditor'
-import NullDisplay from './new/NullDisplay'
-import MainEditor from './new/MainEditor'
-import MainDisplay from './new/MainDisplay'
-import ShixunEditor from './new/ShixunEditor'
-import ShixunDisplay from './new/ShixunDisplay'
-
-import ShixunChooseModal from '../coursesPublic/ShixunChooseModal'
-import update from 'immutability-helper'
-import './new/common.css'
-import '../css/Courses.css'
-const { TextArea } = Input;
-const confirm = Modal.confirm;
-const $ = window.$
-const { Option } = Select;
-
-class ExerciceNew extends Component{
-  constructor(props){
-    super(props);
-
-
-    this.state = {
-      exercise_questions: [],
-      exercise_name: '',
-      exercise_description: '',
-      exercise_types: {},
-      editMode: !this.props.match.params.Id,
-    }
-  }
-  fetchExercise = () => {
-    const Id = this.props.match.params.Id    
-    this.isEdit = !!Id
-    if (Id) {
-      const url = `/exercises/${Id}/edit.json`
-      axios.get(url)
-        .then((response) => {
-          if (response.data.status == 0) {
-            const { exercise, ...others } = response.data
-            this.setState({
-              ...exercise,
-              ...others,
-              editMode: false
-            })
-          }
-        })
-        .catch(function (error) {
-          console.log(error);
-        });
-    } else {
-      const courseId=this.props.match.params.coursesId;
-
-      const newUrl = `/courses/${courseId}/exercises/new.json`
-      axios.get(newUrl)
-        .then((response) => {
-          if (response.data.status == 0) {
-            this.setState({
-              ...response.data
-            })
-          }
-        })
-        .catch(function (error) {
-          console.log(error);
-        });
-    }
-  }
-  componentDidMount = () => {
-    this.fetchExercise()
-  }
-  handleSubmit = (e) => {
-    
-  }
-  onSaveExercise = () => {
-    const { exercise_name, exercise_description } = this.state;
-    const exercise_id = this.props.match.params.Id
-    const courseId = this.props.match.params.coursesId
-    if (this.isEdit) {
-      const editUrl = `/exercises/${exercise_id}.json`
-      axios.put(editUrl, {
-        exercise_name,
-        exercise_description
-      })
-        .then((response) => {
-          if (response.data.status == 0) {
-            this.setState({editMode: false})
-            this.props.showNotification('试卷编辑成功')
-          }
-        })
-        .catch(function (error) {
-            console.log(error);
-        });
-    } else {
-      const url = `/courses/${courseId}/exercises.json`
-      axios.post(url, {
-          exercise_name,
-          exercise_description
-      })
-        .then((response) => {
-          if (response.data.status == 0) {
-              this.setState({editMode: false})
-
-              this.props.showNotification('试卷新建成功')
-              const exercise_id = response.data.data.exercise_id;
-              this.isEdit = true;
-
-	            this.props.history.replace(`/courses/${courseId}/exercises/${exercise_id}/edit`);
-
-          }
-        })
-        .catch(function (error) {
-            console.log(error);
-        });
-    }
-  }
-  exercise_name_change = (e) => {
-      this.setState({exercise_name: e.target.value})
-  }
-  exercise_description_change = (e) => {
-      this.setState({exercise_description: e.target.value})
-  }
-  // #问题的类型,0为单选题,1为多选题,2为判断题,3为填空题,4为主观题,5为实训题
-  _checkIsEditing = () => {
-    if (this.editingId && $(this.editingId).length ) {
-      this.props.showNotification('请先保存或取消当前正在编辑的问题。')
-       $("html").animate({ scrollTop: $(this.editingId).offset().top - 100})
-      return true
-    }
-    return false
-  }
-  onEditorCancel = () => {
-    this.editingId = null;
-    // 找到编辑或新建的item,新建就删掉item,编辑就isNew改为false
-    const { exercise_questions } = this.state
-    let index = -1;
-    for(let i = 0; i < exercise_questions.length; i++) {
-      if (exercise_questions[i].isNew == true) {
-        index = i;
-        break;
-      }
-    }
-    if (exercise_questions[index].question_id) { // 编辑
-      this.setState(
-        (prevState) => ({ 
-          exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: false}}})
-          // update(prevState.exercise_questions, {$splice: [[index, 1]]}) 
-        })
-      )
-    } else { // 新建
-      this.setState(
-        (prevState) => ({ 
-          exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]}) 
-        })
-      )
-    }
-  }
-  addQuestion = (question_id_to_insert_after, type) => {
-    if (!this.isEdit) {
-      this.props.showNotification('请先输入试卷标题,并保存试卷')
-      return;
-    }
-    if (this._checkIsEditing()) {
-      return;
-    } 
-    if (type == Q_TYPE_SHIXUN) {
-      this.addShixun(question_id_to_insert_after)
-    } else {
-      this.addEditingQuestion(type, question_id_to_insert_after)
-    }
-  }
-  chooseShixun = (array) => {
-    this.addEditingQuestion(Q_TYPE_SHIXUN, this.question_id_to_insert_after, {
-      shixun_id: array[0]
-    })
-  }
-  chooseShixunSuccess = () => {
-    this.refs.shixunChooseModal.setVisible(false)
-  }
-  addShixun = (question_id_to_insert_after) => {
-    if (!this.isEdit) {
-      this.props.showNotification('请先输入试卷标题,并保存试卷')
-      return;
-    }
-    // TODO 弹框选择实训
-    if (this._checkIsEditing()) {
-      return;
-    } 
-    this.refs.shixunChooseModal.setVisible(true)
-    this.question_id_to_insert_after = question_id_to_insert_after;
-    return;
-    // 拉取实训items
-    this.addEditingQuestion(Q_TYPE_SHIXUN, question_id_to_insert_after, {
-      shixun_id: 50
-    })
-  }
-  editQestion = (index) => {
-    if (this._checkIsEditing()) {
-      return;
-    } 
-    this.editingId = `#question_${index}`
-
-    this.setState(
-      (prevState) => ({ 
-        exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: true}}})
-      })
-    )
-  }
-  onSort = (index, question_id, isUp) => {
-    if (this._checkIsEditing()) {
-      return;
-    } 
-    const url = `/exercise_questions/${question_id}/up_down.json`
-    axios.post(url, { opr: isUp ? 'up' : 'down'})
-        .then((response) => {
-          if (response.data.status == 0) {
-            // this.props.showNotification('移动成功')
-            this.fetchExercise()
-          }
-        })
-        .catch(function (error) {
-          console.log(error);
-        });
-  }
-  onSortDown = (index, question_id) => {
-    this.onSort(index, question_id, false)
-  }
-  onSortUp = (index, question_id) => {
-    this.onSort(index, question_id, true)
-  }
-  getInitScore = (question_type, question_id_to_insert_after) => {
-    /**
-      1.每个题型的首个题目默认值规则如下:
-        选择题:5分   01
-        判断题:2分    2
-        填空题:2分    3
-        简答题:10分   4
-        实训题:每个关卡5分   5
-     */
-    let init_question_score = 0;
-    if (question_type == 0 || question_type == 1) {
-      init_question_score = 5
-    } else if (question_type == 2) {
-      init_question_score = 2
-    } else if (question_type == 3) {
-      init_question_score = 2
-    } else if (question_type == 4) {
-      init_question_score = 10
-    } else if (question_type == 5) {
-      init_question_score = 5
-    }
-    const _indexBefore = question_id_to_insert_after ? this.findIndexById(question_id_to_insert_after) : this.state.exercise_questions.length - 1
-    for (let i = _indexBefore; i >= 0; i--) {
-      if(this.state.exercise_questions[i].question_type == question_type) {
-        init_question_score = this.state.exercise_questions[i].question_score 
-        break;
-      }
-    }
-    return init_question_score;
-  }
-  addEditingQuestion = (question_type, question_id_to_insert_after, otherAttributes) => {
-    
-    let init_question_score = this.getInitScore(question_type, question_id_to_insert_after)
-    
-    let questionObj  = {
-      question_type: question_type, // 需要这个通过类型判断
-      init_question_score: init_question_score,
-      isNew: true,  // 新建或编辑,用是否有id区分是新建还是编辑
-      question_id_to_insert_after,
-      ...otherAttributes
-    }
-    const { exercise_questions } = this.state;
-    let new_exercise_questions = exercise_questions.slice(0)
-    let newIndex = new_exercise_questions.length;
-    
-    if (question_id_to_insert_after) {
-      const _indexBefore = this.findIndexById(question_id_to_insert_after)
-      new_exercise_questions.splice(_indexBefore + 1, 0, questionObj)
-      newIndex = _indexBefore + 1
-    } else {
-      new_exercise_questions.push(questionObj)
-    }
-    this.editingId = `#question_${newIndex}`
-    this.setState({ exercise_questions: new_exercise_questions }, () => {
-      setTimeout(() => {
-        $(this.editingId).length && $("html").animate({ scrollTop: $(this.editingId).offset().top - 100})
-      }, 500)
-    })
-  }
-  findIndexById = (id) => {
-    const { exercise_questions } = this.state
-    for(let i = 0; i < exercise_questions.length; i++) {
-      if (exercise_questions[i].question_id == id) {
-        return i;
-      }
-    }
-  } 
-  onQestionDelete = (question_id) => {
-    this.props.confirm({
-      content: `确认要删除这个问题吗?`,
-      onOk: () => {
-        const url = `/exercise_questions/${question_id}.json`
-        axios.delete(url)
-        .then((response) => {
-          if (response.data.status == 0) {
-            this.props.showNotification('删除成功')
-            const { exercise_questions } = this.state
-            const index = this.findIndexById(question_id)
-
-            this.setState(
-              (prevState) => ({ 
-                exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]}) 
-              })
-            )
-          }
-        })
-        .catch(function (error) {
-          console.log(error);
-        });    
-      }
-    })
-  }
-  addSuccess = () => {
-    this.editingId = null;
-    this.fetchExercise()
-  }
-  goToPreview = () => {
-    const exercise_id = this.props.match.params.Id
-    const courseId = this.props.match.params.coursesId
-    this.props.history.push(`/courses/${courseId}/exercises/${exercise_id}/student_exercise_list?tab=2`)
-  }
-  render() {
-    let { exercise_name, exercise_description, course_id, exercise_types,
-      exercise_questions, left_banner_id  } = this.state;
-    // if (this.isEdit && !exercise_types) {
-    //   return ''
-    // }
-    // const { getFieldDecorator } = this.props.form;
-    const { q_counts, q_scores, q_doubles, q_doubles_scores, q_judges, q_judges_scores, 
-      q_mains, q_mains_scores, q_nulls, q_nulls_scores, q_shixuns, q_shixuns_scores, q_singles, q_singles_scores} = exercise_types;
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        // sm: { span: 8 },
-        sm: { span: 24 },
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        // sm: { span: 16 },
-        sm: { span: 24 },
-      },
-    };
-
-    const { current_user } = this.props
-    const isAdmin = this.props.isAdmin()
-    const courseId=this.props.match.params.coursesId;
-    const exercise_id = this.props.match.params.Id
-
-    const isEdit = this.isEdit
-    const commonHandler = {
-      onQestionDelete: this.onQestionDelete,
-      addSuccess: this.addSuccess,
-      addQuestion: this.addQuestion,
-      onEditorCancel: this.onEditorCancel,
-      editQestion: this.editQestion,
-      onSortDown: this.onSortDown,
-      onSortUp: this.onSortUp,
-      displayCount: exercise_questions.length,
-      exercise_status: this.state.exercise_status,
-      exerciseIsPublish: this.state.exercise_status >= 2
-    }
-    return(
-        <div className="newMain exerciseNew">
-          <ShixunChooseModal
-            ref="shixunChooseModal"
-            chooseShixun={this.chooseShixun}
-            {...this.props}
-            singleChoose={true}
-          ></ShixunChooseModal>
-          <style>{`
-            .courseForm .formBlock {
-              padding: 20px 30px 30px 30px;
-              border-bottom: 1px solid #EDEDED;
-              margin-bottom: 0px;
-              background: #fff;
-            }
-            .exerciseNew .markdown-body {
-              max-width: 1128px;
-            }
-          `}</style>
-          <div className="edu-class-container edu-position courseForm">
-            { current_user && <CBreadcrumb items={[
-              { to: current_user.first_category_url, name: this.props.coursedata ? this.props.coursedata.name : ''},
-              { to: `/courses/${courseId}/exercises/${left_banner_id}`, name: '试卷列表' },
-              { name: this.isEdit ? '编辑试卷' : '新建试卷'}
-            ]}></CBreadcrumb> }
-
-            <p className="clearfix mt20 mb20">
-              <span className="fl font-24 color-grey-3">{this.isEdit ? "编辑" : "新建"}试卷</span>
-              <a href="javascript:void(0)" className="color-grey-6 fr font-16 mr2" 
-                  onClick={() => this.props.history.length == 1 ? this.props.history.push(`/courses/${courseId}/exercises/${left_banner_id}`): this.props.history.goBack()}>
-                返回
-              </a>
-            </p>
-
-            {!this.state.editMode && <div className="padding20-30" style={{ background: '#fff'}}>
-              <div className="displayTitle font-16">
-                <span>{exercise_name}</span>
-                <a className="fr mr6" onClick={() => { this.setState({editMode: true}) }} style={{ lineHeight: '32px'}}>
-                  <Tooltip title="编辑"><i className="iconfont icon-bianjidaibeijing font-20 color-green"></i></Tooltip>
-                </a>
-              </div>
-              <div className="displayDescription color-grey-9" dangerouslySetInnerHTML={{__html: exercise_description}}
-                style={{whiteSpace: 'pre-wrap'}}
-              ></div>
-              
-            </div>}
-            {this.state.editMode && <Form {...formItemLayout} onSubmit={this.handleSubmit}>
-              <div className="formBlock" style={{paddingBottom: '2px',borderBottom:"none"}}>
-                <Form.Item
-                  label="试卷标题"
-                  required
-                  className="topicTitle "
-                >
-                  {/* {getFieldDecorator('subject', {
-                    rules: [{
-                      required: true, message: '请输入标题',
-                    }, {
-                      max: 20, message: '最大限制为20个字符',
-                    }],
-                  })( */}
-                    <Input placeholder="请输入试卷标题,最大限制60个字符" maxLength="60" className="input-100-40 mt5" value={exercise_name} onChange={this.exercise_name_change}/>
-                  {/* )} */}
-                </Form.Item>
-
-                <Form.Item
-                  label="&nbsp;&nbsp;试卷须知"
-                >
-                  {/* {getFieldDecorator('select_board_id', {
-                    // initialValue: '3779',
-                  })( */}
-                    <TextArea placeholder="请在此输入本次试卷答题的相关说明,最大限制100个字符" className="mt5" style={{height:"120px"}} value={exercise_description}
-                        onChange={this.exercise_description_change}
-                    />
-                  {/* )} */}
-                </Form.Item>
-                <Form.Item>
-                    {/* defalutSubmitbtn */}
-                    
-                    <a  className="task-btn task-btn-orange fr mt4" style={{height: '30px', width: '70px'}}
-                        onClick={this.onSaveExercise}
-                    >保存</a>
-
-                    { this.isEdit && <a onClick={() => this.setState({editMode: false})} className="defalutCancelbtn fr mt4" 
-                        style={{height: '30px', width: '70px', fontSize: '14px', lineHeight: '30px', marginRight: '16px'}}>取消</a>}
-                    {/* <Button type="primary" onClick={this.onSaveExercise} className="fr">保存</Button> */}
-                </Form.Item>
-                </div>
-                {/* <div className="clearfix mt30 mb30">
-                  <a className="defalutCancelbtn fl" onClick={() => {}}>取消</ a>
-                </div> */}
-            </Form>}
-          
-
-            <p className="clearfix padding20-30 color-grey-9">
-              <span className="fl">
-                { !!q_singles && <span className="mr20">单选题{q_singles}题,共{q_singles_scores}分</span>}
-                { !!q_doubles && <span className="mr20">多选题{q_doubles}题,共{q_doubles_scores}分</span>}
-                { !!q_judges && <span className="mr20">判断题{q_judges}题,共{q_judges_scores}分</span>}
-                { !!q_nulls && <span className="mr20">填空题{q_nulls}题,共{q_nulls_scores}分</span>}
-                { !!q_mains && <span className="mr20">简答题{q_mains}题,共{q_mains_scores}分</span>}
-                { !!q_shixuns && <span className="mr20">实训题{q_shixuns}题,共{q_shixuns_scores}分</span> }
-              </span>
-              <span className="fr">
-                { !!q_counts && 
-                  <span>
-                    合计 <span className="color-blue">{q_counts}</span> 题,
-                    共 <span className={`${q_scores > 100 ? 'color-red font-bd' : 'color-orange'}`}>{q_scores}</span> 分
-                  </span>
-                }
-              </span>
-            </p>
-            <div className="edu-back-white">
-              { exercise_questions.map((item, index) => {
-                if (item.question_type == 0 || item.question_type == 1) {
-                  if (item.isNew) {
-                    return <SingleEditor {...this.props} {...item} index={index} {...commonHandler} ></SingleEditor>
-                  } else {
-                    return <SingleDisplay {...this.props} {...item} index={index} {...commonHandler}
-                        displayCount={exercise_questions.length}
-                    ></SingleDisplay>
-                  }
-                } else if (item.question_type == 2) {
-                  if (item.isNew) {
-                    return <JudgeEditor {...this.props} {...item} index={index} {...commonHandler} ></JudgeEditor>
-                  } else {
-                    return <JudgeDisplay {...this.props} {...item} index={index} {...commonHandler} ></JudgeDisplay>
-                  }
-                } else if (item.question_type == 3) {
-                  if (item.isNew) {
-                    return <NullEditor {...this.props} {...item} index={index} {...commonHandler} ></NullEditor>
-                  } else {
-                    return <NullDisplay {...this.props} {...item} index={index} {...commonHandler} ></NullDisplay>
-                  }
-                } else if (item.question_type == 4) {
-                  if (item.isNew) {
-                    return <MainEditor {...this.props} {...item} index={index} {...commonHandler} ></MainEditor>
-                  } else {
-                    return <MainDisplay {...this.props} {...item} index={index} {...commonHandler} ></MainDisplay>
-                  }
-                } else if (item.question_type == 5) {
-                  if (item.isNew) {
-                    return <ShixunEditor {...this.props} {...item} index={index} {...commonHandler} 
-                        chooseShixunSuccess={this.chooseShixunSuccess}
-                    ></ShixunEditor>
-                  } else {
-                    return <ShixunDisplay {...this.props} {...item} index={index} {...commonHandler} ></ShixunDisplay>
-                  }
-                }
-                return <div></div>
-              })}
-
-              {!commonHandler.exerciseIsPublish && <div className="problemShow padding30">
-                <ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_SINGLE)}>
-                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>选择题
-                </ActionBtn>
-                <ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_JUDGE)}>
-                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>判断题
-                </ActionBtn>
-                <ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_NULL)}>
-                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>填空题
-                </ActionBtn>
-                <ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_MAIN)}>
-                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>简答题
-                </ActionBtn>
-                <ActionBtn style="green" className="mr20" onClick={() => this.addShixun(null)}>
-                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>实训题
-                </ActionBtn>
-
-                {exercise_id && <ActionBtn style="blue" className="fr" onClick={() => this.goToPreview()}>
-                  {/* <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i> */}
-                  试卷预览
-                </ActionBtn>}
-              </div>}
-            </div>
-
-          </div>
-        </div>
-      )
-    }
-}
-// RouteHOC()
+import React,{ Component } from "react";
+
+import {
+  Form, Input, InputNumber, Switch, Radio,
+  Slider, Button, Upload, Icon, Rate, Checkbox, message,
+  Row, Col, Select, Modal, Tooltip
+} from 'antd';
+import  { Q_TYPE_SINGLE, Q_TYPE_MULTI, Q_TYPE_JUDGE, Q_TYPE_NULL, Q_TYPE_MAIN, Q_TYPE_SHIXUN } from './new/common'
+import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
+import axios from 'axios'
+// import './board.css'
+import "../common/formCommon.css"
+
+// import { RouteHOC } from './common.js'
+import CBreadcrumb from '../common/CBreadcrumb'
+import {getUrl, ActionBtn} from 'educoder';
+
+import SingleEditor from './new/SingleEditor'
+import SingleDisplay from './new/SingleDisplay'
+import JudgeEditor from './new/JudgeEditor'
+import JudgeDisplay from './new/JudgeDisplay'
+import NullEditor from './new/NullEditor'
+import NullDisplay from './new/NullDisplay'
+import MainEditor from './new/MainEditor'
+import MainDisplay from './new/MainDisplay'
+import ShixunEditor from './new/ShixunEditor'
+import ShixunDisplay from './new/ShixunDisplay'
+
+import ShixunChooseModal from '../coursesPublic/ShixunChooseModal'
+import update from 'immutability-helper'
+import './new/common.css'
+import '../css/Courses.css'
+const { TextArea } = Input;
+const confirm = Modal.confirm;
+const $ = window.$
+const { Option } = Select;
+
+class ExerciceNew extends Component{
+  constructor(props){
+    super(props);
+
+
+    this.state = {
+      exercise_questions: [],
+      exercise_name: '',
+      exercise_description: '',
+      exercise_types: {},
+      editMode: !this.props.match.params.Id,
+    }
+  }
+  fetchExercise = () => {
+    const Id = this.props.match.params.Id    
+    this.isEdit = !!Id
+    if (Id) {
+      const url = `/exercises/${Id}/edit.json`
+      axios.get(url)
+        .then((response) => {
+          if (response.data.status == 0) {
+            const { exercise, ...others } = response.data
+            this.setState({
+              ...exercise,
+              ...others,
+              editMode: false
+            })
+          }
+        })
+        .catch(function (error) {
+          console.log(error);
+        });
+    } else {
+      const courseId=this.props.match.params.coursesId;
+
+      const newUrl = `/courses/${courseId}/exercises/new.json`
+      axios.get(newUrl)
+        .then((response) => {
+          if (response.data.status == 0) {
+            this.setState({
+              ...response.data
+            })
+          }
+        })
+        .catch(function (error) {
+          console.log(error);
+        });
+    }
+  }
+  componentDidMount = () => {
+    this.fetchExercise()
+  }
+  handleSubmit = (e) => {
+    
+  }
+  onSaveExercise = () => {
+    const { exercise_name, exercise_description } = this.state;
+    const exercise_id = this.props.match.params.Id
+    const courseId = this.props.match.params.coursesId
+    if (this.isEdit) {
+      const editUrl = `/exercises/${exercise_id}.json`
+      axios.put(editUrl, {
+        exercise_name,
+        exercise_description
+      })
+        .then((response) => {
+          if (response.data.status == 0) {
+            this.setState({editMode: false})
+            this.props.showNotification('试卷编辑成功')
+          }
+        })
+        .catch(function (error) {
+            console.log(error);
+        });
+    } else {
+      const url = `/courses/${courseId}/exercises.json`
+      axios.post(url, {
+          exercise_name,
+          exercise_description
+      })
+        .then((response) => {
+          if (response.data.status == 0) {
+              this.setState({editMode: false})
+
+              this.props.showNotification('试卷新建成功')
+              const exercise_id = response.data.data.exercise_id;
+              this.isEdit = true;
+
+	            this.props.history.replace(`/courses/${courseId}/exercises/${exercise_id}/edit`);
+
+          }
+        })
+        .catch(function (error) {
+            console.log(error);
+        });
+    }
+  }
+  exercise_name_change = (e) => {
+      this.setState({exercise_name: e.target.value})
+  }
+  exercise_description_change = (e) => {
+      this.setState({exercise_description: e.target.value})
+  }
+  // #问题的类型,0为单选题,1为多选题,2为判断题,3为填空题,4为主观题,5为实训题
+  _checkIsEditing = () => {
+    if (this.editingId && $(this.editingId).length ) {
+      this.props.showNotification('请先保存或取消当前正在编辑的问题。')
+       $("html").animate({ scrollTop: $(this.editingId).offset().top - 100})
+      return true
+    }
+    return false
+  }
+  onEditorCancel = () => {
+    this.editingId = null;
+    // 找到编辑或新建的item,新建就删掉item,编辑就isNew改为false
+    const { exercise_questions } = this.state
+    let index = -1;
+    for(let i = 0; i < exercise_questions.length; i++) {
+      if (exercise_questions[i].isNew == true) {
+        index = i;
+        break;
+      }
+    }
+    if (exercise_questions[index].question_id) { // 编辑
+      this.setState(
+        (prevState) => ({ 
+          exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: false}}})
+          // update(prevState.exercise_questions, {$splice: [[index, 1]]}) 
+        })
+      )
+    } else { // 新建
+      this.setState(
+        (prevState) => ({ 
+          exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]}) 
+        })
+      )
+    }
+  }
+  addQuestion = (question_id_to_insert_after, type) => {
+    if (!this.isEdit) {
+      this.props.showNotification('请先输入试卷标题,并保存试卷')
+      return;
+    }
+    if (this._checkIsEditing()) {
+      return;
+    } 
+    if (type == Q_TYPE_SHIXUN) {
+      this.addShixun(question_id_to_insert_after)
+    } else {
+      this.addEditingQuestion(type, question_id_to_insert_after)
+    }
+  }
+  chooseShixun = (array) => {
+    this.addEditingQuestion(Q_TYPE_SHIXUN, this.question_id_to_insert_after, {
+      shixun_id: array[0]
+    })
+  }
+  chooseShixunSuccess = () => {
+    this.refs.shixunChooseModal.setVisible(false)
+  }
+  addShixun = (question_id_to_insert_after) => {
+    if (!this.isEdit) {
+      this.props.showNotification('请先输入试卷标题,并保存试卷')
+      return;
+    }
+    // TODO 弹框选择实训
+    if (this._checkIsEditing()) {
+      return;
+    } 
+    this.refs.shixunChooseModal.setVisible(true)
+    this.question_id_to_insert_after = question_id_to_insert_after;
+    return;
+    // 拉取实训items
+    this.addEditingQuestion(Q_TYPE_SHIXUN, question_id_to_insert_after, {
+      shixun_id: 50
+    })
+  }
+  editQestion = (index) => {
+    if (this._checkIsEditing()) {
+      return;
+    } 
+    this.editingId = `#question_${index}`
+
+    this.setState(
+      (prevState) => ({ 
+        exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: true}}})
+      })
+    )
+  }
+  onSort = (index, question_id, isUp) => {
+    if (this._checkIsEditing()) {
+      return;
+    } 
+    const url = `/exercise_questions/${question_id}/up_down.json`
+    axios.post(url, { opr: isUp ? 'up' : 'down'})
+        .then((response) => {
+          if (response.data.status == 0) {
+            // this.props.showNotification('移动成功')
+            this.fetchExercise()
+          }
+        })
+        .catch(function (error) {
+          console.log(error);
+        });
+  }
+  onSortDown = (index, question_id) => {
+    this.onSort(index, question_id, false)
+  }
+  onSortUp = (index, question_id) => {
+    this.onSort(index, question_id, true)
+  }
+  getInitScore = (question_type, question_id_to_insert_after) => {
+    /**
+      1.每个题型的首个题目默认值规则如下:
+        选择题:5分   01
+        判断题:2分    2
+        填空题:2分    3
+        简答题:10分   4
+        实训题:每个关卡5分   5
+     */
+    let init_question_score = 0;
+    if (question_type == 0 || question_type == 1) {
+      init_question_score = 5
+    } else if (question_type == 2) {
+      init_question_score = 2
+    } else if (question_type == 3) {
+      init_question_score = 2
+    } else if (question_type == 4) {
+      init_question_score = 10
+    } else if (question_type == 5) {
+      init_question_score = 5
+    }
+    const _indexBefore = question_id_to_insert_after ? this.findIndexById(question_id_to_insert_after) : this.state.exercise_questions.length - 1
+    for (let i = _indexBefore; i >= 0; i--) {
+      if(this.state.exercise_questions[i].question_type == question_type) {
+        init_question_score = this.state.exercise_questions[i].question_score 
+        break;
+      }
+    }
+    return init_question_score;
+  }
+  addEditingQuestion = (question_type, question_id_to_insert_after, otherAttributes) => {
+    
+    let init_question_score = this.getInitScore(question_type, question_id_to_insert_after)
+    
+    let questionObj  = {
+      question_type: question_type, // 需要这个通过类型判断
+      init_question_score: init_question_score,
+      isNew: true,  // 新建或编辑,用是否有id区分是新建还是编辑
+      question_id_to_insert_after,
+      ...otherAttributes
+    }
+    const { exercise_questions } = this.state;
+    let new_exercise_questions = exercise_questions.slice(0)
+    let newIndex = new_exercise_questions.length;
+    
+    if (question_id_to_insert_after) {
+      const _indexBefore = this.findIndexById(question_id_to_insert_after)
+      new_exercise_questions.splice(_indexBefore + 1, 0, questionObj)
+      newIndex = _indexBefore + 1
+    } else {
+      new_exercise_questions.push(questionObj)
+    }
+    this.editingId = `#question_${newIndex}`
+    this.setState({ exercise_questions: new_exercise_questions }, () => {
+      setTimeout(() => {
+        $(this.editingId).length && $("html").animate({ scrollTop: $(this.editingId).offset().top - 100})
+      }, 500)
+    })
+  }
+  findIndexById = (id) => {
+    const { exercise_questions } = this.state
+    for(let i = 0; i < exercise_questions.length; i++) {
+      if (exercise_questions[i].question_id == id) {
+        return i;
+      }
+    }
+  } 
+  onQestionDelete = (question_id) => {
+    this.props.confirm({
+      content: `确认要删除这个问题吗?`,
+      onOk: () => {
+        const url = `/exercise_questions/${question_id}.json`
+        axios.delete(url)
+        .then((response) => {
+          if (response.data.status == 0) {
+            this.props.showNotification('删除成功')
+            const { exercise_questions } = this.state
+            const index = this.findIndexById(question_id)
+
+            this.setState(
+              (prevState) => ({ 
+                exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]}) 
+              })
+            )
+          }
+        })
+        .catch(function (error) {
+          console.log(error);
+        });    
+      }
+    })
+  }
+  addSuccess = () => {
+    this.editingId = null;
+    this.fetchExercise()
+  }
+  goToPreview = () => {
+    const exercise_id = this.props.match.params.Id
+    const courseId = this.props.match.params.coursesId
+    this.props.history.push(`/courses/${courseId}/exercises/${exercise_id}/student_exercise_list?tab=2`)
+  }
+  render() {
+    let { exercise_name, exercise_description, course_id, exercise_types,
+      exercise_questions, left_banner_id  } = this.state;
+    // if (this.isEdit && !exercise_types) {
+    //   return ''
+    // }
+    // const { getFieldDecorator } = this.props.form;
+    const { q_counts, q_scores, q_doubles, q_doubles_scores, q_judges, q_judges_scores, 
+      q_mains, q_mains_scores, q_nulls, q_nulls_scores, q_shixuns, q_shixuns_scores, q_singles, q_singles_scores} = exercise_types;
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        // sm: { span: 8 },
+        sm: { span: 24 },
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        // sm: { span: 16 },
+        sm: { span: 24 },
+      },
+    };
+
+    const { current_user } = this.props
+    const isAdmin = this.props.isAdmin()
+    const courseId=this.props.match.params.coursesId;
+    const exercise_id = this.props.match.params.Id
+
+    const isEdit = this.isEdit
+    const commonHandler = {
+      onQestionDelete: this.onQestionDelete,
+      addSuccess: this.addSuccess,
+      addQuestion: this.addQuestion,
+      onEditorCancel: this.onEditorCancel,
+      editQestion: this.editQestion,
+      onSortDown: this.onSortDown,
+      onSortUp: this.onSortUp,
+      displayCount: exercise_questions.length,
+      exercise_status: this.state.exercise_status,
+      exerciseIsPublish: this.state.exercise_status >= 2
+    }
+    return(
+        <div className="newMain exerciseNew">
+          <ShixunChooseModal
+            ref="shixunChooseModal"
+            chooseShixun={this.chooseShixun}
+            {...this.props}
+            singleChoose={true}
+          ></ShixunChooseModal>
+          <style>{`
+            .courseForm .formBlock {
+              padding: 20px 30px 30px 30px;
+              border-bottom: 1px solid #EDEDED;
+              margin-bottom: 0px;
+              background: #fff;
+            }
+            .exerciseNew .markdown-body {
+              max-width: 1128px;
+            }
+          `}</style>
+          <div className="edu-class-container edu-position courseForm">
+            { current_user && <CBreadcrumb items={[
+              { to: current_user&&current_user.first_category_url, name: this.props.coursedata ? this.props.coursedata.name : ''},
+              { to: `/courses/${courseId}/exercises/${left_banner_id}`, name: '试卷列表' },
+              { name: this.isEdit ? '编辑试卷' : '新建试卷'}
+            ]}></CBreadcrumb> }
+
+            <p className="clearfix mt20 mb20">
+              <span className="fl font-24 color-grey-3">{this.isEdit ? "编辑" : "新建"}试卷</span>
+              <a href="javascript:void(0)" className="color-grey-6 fr font-16 mr2" 
+                  onClick={() => this.props.history.length == 1 ? this.props.history.push(`/courses/${courseId}/exercises/${left_banner_id}`): this.props.history.goBack()}>
+                返回
+              </a>
+            </p>
+
+            {!this.state.editMode && <div className="padding20-30" style={{ background: '#fff'}}>
+              <div className="displayTitle font-16">
+                <span>{exercise_name}</span>
+                <a className="fr mr6" onClick={() => { this.setState({editMode: true}) }} style={{ lineHeight: '32px'}}>
+                  <Tooltip title="编辑"><i className="iconfont icon-bianjidaibeijing font-20 color-green"></i></Tooltip>
+                </a>
+              </div>
+              <div className="displayDescription color-grey-9" dangerouslySetInnerHTML={{__html: exercise_description}}
+                style={{whiteSpace: 'pre-wrap'}}
+              ></div>
+              
+            </div>}
+            {this.state.editMode && <Form {...formItemLayout} onSubmit={this.handleSubmit}>
+              <div className="formBlock" style={{paddingBottom: '2px',borderBottom:"none"}}>
+                <Form.Item
+                  label="试卷标题"
+                  required
+                  className="topicTitle "
+                >
+                  {/* {getFieldDecorator('subject', {
+                    rules: [{
+                      required: true, message: '请输入标题',
+                    }, {
+                      max: 20, message: '最大限制为20个字符',
+                    }],
+                  })( */}
+                    <Input placeholder="请输入试卷标题,最大限制60个字符" maxLength="60" className="input-100-40 mt5" value={exercise_name} onChange={this.exercise_name_change}/>
+                  {/* )} */}
+                </Form.Item>
+
+                <Form.Item
+                  label="&nbsp;&nbsp;试卷须知"
+                >
+                  {/* {getFieldDecorator('select_board_id', {
+                    // initialValue: '3779',
+                  })( */}
+                    <TextArea placeholder="请在此输入本次试卷答题的相关说明,最大限制100个字符" className="mt5" style={{height:"120px"}} value={exercise_description}
+                        onChange={this.exercise_description_change}
+                    />
+                  {/* )} */}
+                </Form.Item>
+                <Form.Item>
+                    {/* defalutSubmitbtn */}
+                    
+                    <a  className="task-btn task-btn-orange fr mt4" style={{height: '30px', width: '70px'}}
+                        onClick={this.onSaveExercise}
+                    >保存</a>
+
+                    { this.isEdit && <a onClick={() => this.setState({editMode: false})} className="defalutCancelbtn fr mt4" 
+                        style={{height: '30px', width: '70px', fontSize: '14px', lineHeight: '30px', marginRight: '16px'}}>取消</a>}
+                    {/* <Button type="primary" onClick={this.onSaveExercise} className="fr">保存</Button> */}
+                </Form.Item>
+                </div>
+                {/* <div className="clearfix mt30 mb30">
+                  <a className="defalutCancelbtn fl" onClick={() => {}}>取消</ a>
+                </div> */}
+            </Form>}
+          
+
+            <p className="clearfix padding20-30 color-grey-9">
+              <span className="fl">
+                { !!q_singles && <span className="mr20">单选题{q_singles}题,共{q_singles_scores}分</span>}
+                { !!q_doubles && <span className="mr20">多选题{q_doubles}题,共{q_doubles_scores}分</span>}
+                { !!q_judges && <span className="mr20">判断题{q_judges}题,共{q_judges_scores}分</span>}
+                { !!q_nulls && <span className="mr20">填空题{q_nulls}题,共{q_nulls_scores}分</span>}
+                { !!q_mains && <span className="mr20">简答题{q_mains}题,共{q_mains_scores}分</span>}
+                { !!q_shixuns && <span className="mr20">实训题{q_shixuns}题,共{q_shixuns_scores}分</span> }
+              </span>
+              <span className="fr">
+                { !!q_counts && 
+                  <span>
+                    合计 <span className="color-blue">{q_counts}</span> 题,
+                    共 <span className={`${q_scores > 100 ? 'color-red font-bd' : 'color-orange'}`}>{q_scores}</span> 分
+                  </span>
+                }
+              </span>
+            </p>
+            <div className="edu-back-white">
+              { exercise_questions.map((item, index) => {
+                if (item.question_type == 0 || item.question_type == 1) {
+                  if (item.isNew) {
+                    return <SingleEditor {...this.props} {...item} index={index} {...commonHandler} ></SingleEditor>
+                  } else {
+                    return <SingleDisplay {...this.props} {...item} index={index} {...commonHandler}
+                        displayCount={exercise_questions.length}
+                    ></SingleDisplay>
+                  }
+                } else if (item.question_type == 2) {
+                  if (item.isNew) {
+                    return <JudgeEditor {...this.props} {...item} index={index} {...commonHandler} ></JudgeEditor>
+                  } else {
+                    return <JudgeDisplay {...this.props} {...item} index={index} {...commonHandler} ></JudgeDisplay>
+                  }
+                } else if (item.question_type == 3) {
+                  if (item.isNew) {
+                    return <NullEditor {...this.props} {...item} index={index} {...commonHandler} ></NullEditor>
+                  } else {
+                    return <NullDisplay {...this.props} {...item} index={index} {...commonHandler} ></NullDisplay>
+                  }
+                } else if (item.question_type == 4) {
+                  if (item.isNew) {
+                    return <MainEditor {...this.props} {...item} index={index} {...commonHandler} ></MainEditor>
+                  } else {
+                    return <MainDisplay {...this.props} {...item} index={index} {...commonHandler} ></MainDisplay>
+                  }
+                } else if (item.question_type == 5) {
+                  if (item.isNew) {
+                    return <ShixunEditor {...this.props} {...item} index={index} {...commonHandler} 
+                        chooseShixunSuccess={this.chooseShixunSuccess}
+                    ></ShixunEditor>
+                  } else {
+                    return <ShixunDisplay {...this.props} {...item} index={index} {...commonHandler} ></ShixunDisplay>
+                  }
+                }
+                return <div></div>
+              })}
+
+              {!commonHandler.exerciseIsPublish && <div className="problemShow padding30">
+                <ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_SINGLE)}>
+                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>选择题
+                </ActionBtn>
+                <ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_JUDGE)}>
+                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>判断题
+                </ActionBtn>
+                <ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_NULL)}>
+                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>填空题
+                </ActionBtn>
+                <ActionBtn style="green" className="mr20" onClick={() => this.addQuestion(null, Q_TYPE_MAIN)}>
+                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>简答题
+                </ActionBtn>
+                <ActionBtn style="green" className="mr20" onClick={() => this.addShixun(null)}>
+                  <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i>实训题
+                </ActionBtn>
+
+                {exercise_id && <ActionBtn style="blue" className="fr" onClick={() => this.goToPreview()}>
+                  {/* <i className="iconfont icon-tianjiafangda color-white font-14 mr5" style={{ marginTop: '-1px', display: 'inline-block'}}></i> */}
+                  试卷预览
+                </ActionBtn>}
+              </div>}
+            </div>
+
+          </div>
+        </div>
+      )
+    }
+}
+// RouteHOC()
 export default (ExerciceNew);
\ No newline at end of file
diff --git a/public/react/src/modules/courses/graduation/topics/GraduateTopicDetail.js b/public/react/src/modules/courses/graduation/topics/GraduateTopicDetail.js
index c0e8fe185..b24277a2c 100644
--- a/public/react/src/modules/courses/graduation/topics/GraduateTopicDetail.js
+++ b/public/react/src/modules/courses/graduation/topics/GraduateTopicDetail.js
@@ -105,7 +105,7 @@ class GraduateTopicDetail extends Component{
       <div className="newMain">
         <div className="educontent mt10 mb50">
           <p className="clearfix mb15 lineh-20">
-            <WordsBtn style="grey" className="fl" to={current_user.first_category_url}>{tableData && tableData.course_name}</WordsBtn>
+            <WordsBtn style="grey" className="fl" to={current_user&&current_user.first_category_url}>{tableData && tableData.course_name}</WordsBtn>
             <span className="color-grey-9 fl ml3 mr3">&gt;</span>
             <WordsBtn style="grey" className="fl" to={`/courses/${tableData.course_id}/graduation_topics/${tableData.graduation_id}`}>{tableData.graduation_name}</WordsBtn>
             <span className="color-grey-9 fl ml3 mr3">&gt;</span>
diff --git a/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js b/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js
index 43a0e31f5..8c46bfa0e 100644
--- a/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js
+++ b/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js
@@ -323,7 +323,7 @@ class GraduateTopicNew extends Component{
           `}</style>
           <div className="edu-class-container edu-position courseForm">
             <p className="clearfix mb20 mt10">
-              <WordsBtn style="grey" className="fl" to={current_user.first_category_url}>{course_name}</WordsBtn>
+              <WordsBtn style="grey" className="fl" to={current_user&&current_user.first_category_url}>{course_name}</WordsBtn>
               <span className="color-grey-9 fl ml3 mr3">&gt;</span>
               <WordsBtn style="grey" className="fl" to={`/courses/${coursesId}/graduation_topics/${left_banner_id}`}>{left_banner_name}</WordsBtn>
               <span className="color-grey-9 fl ml3 mr3">&gt;</span>