@@ -1145,7 +1145,7 @@ class College extends Component {
学生排名
@@ -1218,7 +1218,7 @@ class College extends Component {
{b} : {c} ({d}%)"
+ formatter: "{d}%
"
},
legend: {
// orient: 'vertical',
// top: 'middle',
- bottom: 40,
+ bottom: 50,
left: 'center',
data: datanane
},
@@ -68,7 +68,7 @@ class Colleagechart extends Component {
diff --git a/public/react/src/college/colleagechart/Colleagechartzu.js b/public/react/src/college/colleagechart/Colleagechartzu.js
index c65d2f6f2..ff1b6fb6b 100644
--- a/public/react/src/college/colleagechart/Colleagechartzu.js
+++ b/public/react/src/college/colleagechart/Colleagechartzu.js
@@ -15,8 +15,8 @@ function startechart(names, values){
backgroundColor: '#fff',
grid: {
left: '3%',
- right: '4%',
- bottom: '10%',
+ right: '10%',
+ bottom: '15%',
containLabel: true
},
@@ -133,7 +133,7 @@ class Colleagechartzu extends Component {
From a0af31b2455869f5e654a58312eac490e2a10300 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com>
Date: Thu, 19 Dec 2019 16:54:09 +0800
Subject: [PATCH 13/61] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?=
=?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/src/AppConfig.js | 38 +++++++++++++++++------------------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js
index c51c0d5e1..ac39562a7 100644
--- a/public/react/src/AppConfig.js
+++ b/public/react/src/AppConfig.js
@@ -19,25 +19,25 @@ function locationurl(list){
let hashTimeout
// TODO 开发期多个身份切换
-// let debugType =""
-// if (isDev) {
-// const _search = window.location.search;
-// let parsed = {};
-// if (_search) {
-// parsed = queryString.parse(_search);
-// }
-// debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' :
-// window.location.search.indexOf('debug=s') != -1 ? 'student' :
-// window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || 'admin'
-// }
-// // 超管
-// // debugType="admin";
-// // 老师
-// //ebugType="teacher";
-// // 学生
-// // debugType="student";
-//
-// window._debugType = debugType;
+let debugType =""
+if (isDev) {
+ const _search = window.location.search;
+ let parsed = {};
+ if (_search) {
+ parsed = queryString.parse(_search);
+ }
+ debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' :
+ window.location.search.indexOf('debug=s') != -1 ? 'student' :
+ window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || 'admin'
+}
+// 超管
+// debugType="admin";
+// 老师
+//ebugType="teacher";
+// 学生
+// debugType="student";
+
+window._debugType = debugType;
export function initAxiosInterceptors(props) {
initOnlineOfflineListener()
From 0a34988f409da02fed284eca16afb6daeba5decb Mon Sep 17 00:00:00 2001
From: jingquan huang
Date: Thu, 19 Dec 2019 17:05:57 +0800
Subject: [PATCH 14/61] =?UTF-8?q?=E5=AE=9E=E9=AA=8C=E7=8E=AF=E5=A2=83?=
=?UTF-8?q?=E4=B8=BA=E7=A9=BA=E7=9A=84=E6=8F=90=E9=86=92=E9=94=99=E8=AF=AF?=
=?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/controllers/myshixuns_controller.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb
index 987f4873a..0e9ba477a 100644
--- a/app/controllers/myshixuns_controller.rb
+++ b/app/controllers/myshixuns_controller.rb
@@ -247,7 +247,7 @@ class MyshixunsController < ApplicationController
def update_file
begin
@hide_code = Shixun.where(id: @myshixun.shixun_id).pluck(:hide_code).first
- tip_exception("技术平台为空!") if @myshixun.mirror_name.blank?
+ tip_exception("实验环境不能为空,请查看实训模板的环境配置项是否正确!") if (@myshixun.mirror_name.blank? || @myshixun.mirror_name.first.to_s == "-1")
path = params[:path].strip unless params[:path].blank?
game_id = params[:game_id]
game = Game.find(game_id)
From 85bc2079d2578e8a9cac29ccccc53a1ecd02cbca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com>
Date: Thu, 19 Dec 2019 17:13:26 +0800
Subject: [PATCH 15/61] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?=
=?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/src/college/College.js | 14 +++++++-------
.../src/college/colleagechart/Colleagechart.js | 2 +-
.../src/college/colleagechart/Colleagechartzu.js | 4 ++--
public/react/src/college/colleagecss/colleage.css | 4 ++--
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/public/react/src/college/College.js b/public/react/src/college/College.js
index c204ab65b..bc43252b7 100644
--- a/public/react/src/college/College.js
+++ b/public/react/src/college/College.js
@@ -824,8 +824,8 @@ class College extends Component {
{school}
@@ -874,7 +874,7 @@ class College extends Component {
-
+
基本使用情况
@@ -956,7 +956,7 @@ class College extends Component {
-
+
课堂
@@ -974,7 +974,7 @@ class College extends Component {
:
-
+
diff --git a/public/react/src/modules/tpm/TPMIndex.js b/public/react/src/modules/tpm/TPMIndex.js
index d79bae95b..e032bb91f 100644
--- a/public/react/src/modules/tpm/TPMIndex.js
+++ b/public/react/src/modules/tpm/TPMIndex.js
@@ -385,6 +385,9 @@ class TPMIndex extends Component {
margin:0 40px 0 0;
padding:0px;
}
+ .ant-popover{
+ z-index:1000 !important;
+ }
`
}
diff --git a/public/react/src/modules/tpm/TPMsettings/LearningSettings.js b/public/react/src/modules/tpm/TPMsettings/LearningSettings.js
index 681cbc956..a98f68223 100644
--- a/public/react/src/modules/tpm/TPMsettings/LearningSettings.js
+++ b/public/react/src/modules/tpm/TPMsettings/LearningSettings.js
@@ -215,9 +215,9 @@ export default class Shixuninformation extends Component {
multi_webssh: false
})
} else {
- this.setState({
- multi_webssh: true
- })
+ // this.setState({
+ // multi_webssh: true
+ // })
}
this.setState({
opensshRadio: e.target.value
diff --git a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js
index 200880019..75ed88852 100644
--- a/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js
+++ b/public/react/src/modules/tpm/TPMsettings/Shixuninformation.js
@@ -50,7 +50,10 @@ class Shixuninformation extends Component {
}
componentDidMount() {
-
+ let anchorElement = document.getElementById("newcourseContentMD");
+ if(anchorElement){
+ this.scrollToAnchor("newcourseContentMD");
+ }
}
componentDidUpdate(prevProps, prevState) {
@@ -113,6 +116,7 @@ class Shixuninformation extends Component {
selectright: this.props.data && this.props.data.shixun.choice_small_type,
})
this.contentMdRef.current.setValue(this.props.data && this.props.data.shixun.description);
+
}
}
}
@@ -807,16 +811,20 @@ class Shixuninformation extends Component {
)}
+
+
+
diff --git a/public/react/src/modules/tpm/component/TPMRightSection.js b/public/react/src/modules/tpm/component/TPMRightSection.js
index 1d2a93796..88894794b 100644
--- a/public/react/src/modules/tpm/component/TPMRightSection.js
+++ b/public/react/src/modules/tpm/component/TPMRightSection.js
@@ -63,6 +63,8 @@ class TPMRightSection extends Component {
if(TPMRightSectionData&&TPMRightSectionData.complete_count!=null){
Progresssum=(parseInt(TPMRightSectionData&&TPMRightSectionData.complete_count) / parseInt(TPMRightSectionData&&TPMRightSectionData.challenge_count))*100;
}
+
+
return (
{
@@ -97,11 +99,11 @@ class TPMRightSection extends Component {
- {TPMRightSectionData&&TPMRightSectionData.complete_count!=null?
+ {this.props&&this.props.status>1?
学习统计
- 已完成 {TPMRightSectionData&&TPMRightSectionData.complete_count} 个 / 共 {TPMRightSectionData&&TPMRightSectionData.challenge_count} 关
+ 已完成 {TPMRightSectionData&&TPMRightSectionData.complete_count===null?0:TPMRightSectionData&&TPMRightSectionData.complete_count} 个 / 共 {TPMRightSectionData&&TPMRightSectionData.challenge_count} 关
diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js
index 307823ee8..e7b7ef261 100644
--- a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js
+++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js
@@ -34,7 +34,8 @@ class Challenges extends Component {
operationstrue:false,
isSpin:false,
boxoffsetHeigh:0,
- opentitletype:true
+ opentitletype:true,
+ isopentitletype:"Less",
}
}
@@ -73,15 +74,17 @@ class Challenges extends Component {
boxoffsetHeigh=box.offsetHeight
if(boxoffsetHeigh<260){
this.setState({
- opentitletype:false,
+ isopentitletype:"Less",
boxoffsetHeigh:boxoffsetHeigh
})
}else{
this.setState({
+ opentitletype:true,
+ isopentitletype:"greater",
boxoffsetHeigh:boxoffsetHeigh
})
}
-
+ console.log(boxoffsetHeigh)
}
}
@@ -322,7 +325,8 @@ class Challenges extends Component {
opentitle=()=>{
this.setState({
- opentitletype:!this.state.opentitletype
+ opentitletype:!this.state.opentitletype,
+
})
}
@@ -434,7 +438,8 @@ class Challenges extends Component {
- {this.state.opentitletype===true?
this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}>
+
+ {this.state.isopentitletype==="Less"?"":this.state.opentitletype===true?this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}>
阅读全文
:this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}>
收起全文
diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css
index 688dbb422..b059ab406 100644
--- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css
+++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.css
@@ -184,4 +184,13 @@
.fontneweees {
color: #BBBBBB;
+}
+
+.maxfont450{
+ width: 450px;
+ max-width:450px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ cursor: default;
}
\ No newline at end of file
diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js
index 15a956a0b..17b083cf7 100644
--- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js
+++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js
@@ -11,11 +11,9 @@ import NoneData from "../../../courses/coursesPublic/NoneData";
import './Collaborators.css';
-const $ = window.$;
-
const RadioGroup = Radio.Group;
-const Search = Input.Search;
+
class Collaborators extends Component {
constructor(props) {
@@ -685,7 +683,7 @@ class Collaborators extends Component {
{/*
{item.user.identity}
*/}
{item.user.school_name}
+ className={item.user.school_name === null || item.user.school_name === "" ? "" : " font-16 color888hezuo maxfont450"}>{item.user.school_name}
发布实训项目 {item.user.user_shixuns_count}
diff --git a/public/react/src/modules/tpm/shixuns/ShixunCardList.js b/public/react/src/modules/tpm/shixuns/ShixunCardList.js
index 3676ed361..937e96894 100644
--- a/public/react/src/modules/tpm/shixuns/ShixunCardList.js
+++ b/public/react/src/modules/tpm/shixuns/ShixunCardList.js
@@ -218,7 +218,7 @@ class ShixunCardList extends Component {
id="hot"
onClick={(e)=>this.latestHot(e,3)}>最热
- {shixuntype===true?"":
this.getUser("/shixuns/new")}>+新建实训项目}
+ {shixuntype===true?"":
this.getUser("/shixuns/new")}>+新建实训项目}
{/*
Date: Thu, 19 Dec 2019 17:55:39 +0800
Subject: [PATCH 17/61] =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/src/modules/tpm/challengesnew/TPManswer.js | 4 ++--
public/react/src/modules/tpm/challengesnew/TPManswer2.js | 4 ++--
.../react/src/modules/tpm/challengesnew/TPMchallengesnew.js | 4 ++--
public/react/src/modules/tpm/challengesnew/TPMevaluation.js | 4 ++--
public/react/src/modules/tpm/challengesnew/TPMquestion.js | 4 ++--
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/public/react/src/modules/tpm/challengesnew/TPManswer.js b/public/react/src/modules/tpm/challengesnew/TPManswer.js
index 9c9a23a12..9187e09b0 100644
--- a/public/react/src/modules/tpm/challengesnew/TPManswer.js
+++ b/public/react/src/modules/tpm/challengesnew/TPManswer.js
@@ -302,11 +302,11 @@ export default class TPManswer extends Component {
className="color-grey-6 fr font-15 mt3">返回
{prev_challenge === undefined ? "" :
-
上一关
+
上一关
}
{next_challenge === undefined ? "" :
-
下一关
+
下一关
}
返回
{prev_challenge === undefined ? "" :
- 上一关
+ 上一关
}
{next_challenge === undefined ? "" :
-
下一关
+
下一关
}
返回
{ next_challenge===undefined?"":
- 下一关
+ 下一关
}
{ prev_challenge===undefined?"":
-
上一关
+
上一关
}
diff --git a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js
index d70f22a0a..34eb1a075 100644
--- a/public/react/src/modules/tpm/challengesnew/TPMevaluation.js
+++ b/public/react/src/modules/tpm/challengesnew/TPMevaluation.js
@@ -824,11 +824,11 @@ export default class TPMevaluation extends Component {
className="color-grey-6 fr font-15 mt3">返回
{prev_challenge === undefined ? "" :
-
上一关
+
上一关
}
{next_challenge === undefined ? "" :
-
下一关
+
下一关
}
返回
{ prev_challenge===undefined?"":
- 上一关
+ 上一关
}
{ next_challenge===undefined?"":
-
下一关
+
下一关
}
Date: Thu, 19 Dec 2019 18:02:44 +0800
Subject: [PATCH 18/61] =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/src/modules/tpm/component/TPMright.css | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/public/react/src/modules/tpm/component/TPMright.css b/public/react/src/modules/tpm/component/TPMright.css
index a75160bf5..0d6b306fd 100644
--- a/public/react/src/modules/tpm/component/TPMright.css
+++ b/public/react/src/modules/tpm/component/TPMright.css
@@ -119,9 +119,14 @@
.padd252020px{
padding: 25px 20px 15px;
}
+
.rightjinengs{
height: 35px;
margin-top: 20px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
}
.borderbottomf4{
From 0712932812985d2486b2f2c3cc9647ddb598742e Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Thu, 19 Dec 2019 18:03:42 +0800
Subject: [PATCH 19/61] update oj
---
public/react/package.json | 1 +
.../common/components/comment/CommentForm.js | 116 ++++++++++++
.../common/components/comment/CommentIcon.js | 32 ++++
.../common/components/comment/CommentItem.js | 165 +++++++++++++++++
.../common/components/comment/CommentList.js | 20 +++
.../src/common/components/comment/index.js | 22 +++
.../src/common/components/comment/index.scss | 111 ++++++++++++
.../src/common/quillForEditor/ImageBlot.js | 54 ++++++
.../src/common/quillForEditor/deepEqual.js | 47 +++++
.../react/src/common/quillForEditor/index.js | 166 ++++++++++++++++++
.../react/src/common/reactQuill/ImageBlot.js | 54 ++++++
.../react/src/common/reactQuill/ReactQuill.js | 45 +++++
.../react/src/common/reactQuill/deepEqual.js | 47 +++++
public/react/src/common/reactQuill/flatten.js | 26 +++
public/react/src/common/reactQuill/index.js | 108 ++++++++++++
public/react/src/common/reactQuill/index.scss | 32 ++++
public/react/src/common/reactQuill/lib.js | 13 ++
.../src/common/reactQuill/useDeepEqualMemo.js | 27 +++
.../src/common/reactQuill/useMountQuill.js | 148 ++++++++++++++++
.../react/src/common/reactQuill/useQuill.js | 60 +++++++
.../src/common/reactQuill/useQuillOnChange.js | 33 ++++
.../common/reactQuill/useQuillPlaceholder.js | 22 +++
.../common/reactQuill/useQuillValueSync.js | 31 ++++
.../src/modules/developer/DeveloperHome.js | 21 ++-
.../components/controlSetting/index.js | 6 +-
.../components/controlSetting/index.scss | 7 +-
.../developer/components/execResult/index.js | 14 +-
.../developer/components/initTabCtx/index.js | 7 +-
.../components/initTabCtx/index.scss | 3 +-
.../components/monacoSetting/index.js | 3 +-
.../components/myMonacoEditor/index.js | 57 ++++--
.../components/myMonacoEditor/index.scss | 33 ++--
.../modules/developer/newOrEditTask/index.js | 102 ++++++-----
.../developer/newOrEditTask/index.scss | 16 +-
.../leftpane/editorTab/AddTestDemo.js | 24 ++-
.../newOrEditTask/leftpane/editorTab/index.js | 53 +++---
.../leftpane/editorTab/index.scss | 5 +
.../developer/newOrEditTask/leftpane/index.js | 22 ---
.../newOrEditTask/leftpane/prevTab/index.js | 77 +++-----
.../newOrEditTask/rightpane/index.scss | 2 +-
.../modules/developer/split_pane_resizer.scss | 6 +-
.../modules/developer/studentStudy/index.js | 56 ++++--
.../modules/developer/studentStudy/index.scss | 2 +-
.../studentStudy/leftpane/comment/index.js | 13 +-
.../studentStudy/leftpane/comment/index.scss | 8 +
.../developer/studentStudy/leftpane/index.js | 63 ++-----
.../studentStudy/leftpane/index.scss | 7 +
.../leftpane/taskDescription/index.js | 18 +-
.../developer/studentStudy/rightpane/index.js | 27 ++-
public/react/src/redux/actions/actionTypes.js | 5 +-
public/react/src/redux/actions/ojForUser.js | 45 ++++-
public/react/src/redux/actions/ojForm.js | 20 ++-
.../src/redux/reducers/ojForUserReducer.js | 24 ++-
.../react/src/redux/reducers/ojFormReducer.js | 4 +-
public/react/src/services/ojService.js | 15 +-
55 files changed, 1849 insertions(+), 296 deletions(-)
create mode 100644 public/react/src/common/components/comment/CommentForm.js
create mode 100644 public/react/src/common/components/comment/CommentIcon.js
create mode 100644 public/react/src/common/components/comment/CommentItem.js
create mode 100644 public/react/src/common/components/comment/CommentList.js
create mode 100644 public/react/src/common/components/comment/index.js
create mode 100644 public/react/src/common/components/comment/index.scss
create mode 100644 public/react/src/common/quillForEditor/ImageBlot.js
create mode 100644 public/react/src/common/quillForEditor/deepEqual.js
create mode 100644 public/react/src/common/quillForEditor/index.js
create mode 100644 public/react/src/common/reactQuill/ImageBlot.js
create mode 100644 public/react/src/common/reactQuill/ReactQuill.js
create mode 100644 public/react/src/common/reactQuill/deepEqual.js
create mode 100644 public/react/src/common/reactQuill/flatten.js
create mode 100644 public/react/src/common/reactQuill/index.js
create mode 100644 public/react/src/common/reactQuill/index.scss
create mode 100644 public/react/src/common/reactQuill/lib.js
create mode 100644 public/react/src/common/reactQuill/useDeepEqualMemo.js
create mode 100644 public/react/src/common/reactQuill/useMountQuill.js
create mode 100644 public/react/src/common/reactQuill/useQuill.js
create mode 100644 public/react/src/common/reactQuill/useQuillOnChange.js
create mode 100644 public/react/src/common/reactQuill/useQuillPlaceholder.js
create mode 100644 public/react/src/common/reactQuill/useQuillValueSync.js
create mode 100644 public/react/src/modules/developer/studentStudy/leftpane/comment/index.scss
diff --git a/public/react/package.json b/public/react/package.json
index 66db5e6f8..144292feb 100644
--- a/public/react/package.json
+++ b/public/react/package.json
@@ -61,6 +61,7 @@
"prop-types": "^15.6.1",
"qs": "^6.6.0",
"quill": "^1.3.7",
+ "quill-delta-to-html": "^0.11.0",
"raf": "3.4.0",
"rc-form": "^2.1.7",
"rc-pagination": "^1.16.2",
diff --git a/public/react/src/common/components/comment/CommentForm.js b/public/react/src/common/components/comment/CommentForm.js
new file mode 100644
index 000000000..73e36cff9
--- /dev/null
+++ b/public/react/src/common/components/comment/CommentForm.js
@@ -0,0 +1,116 @@
+/*
+ * @Description: 评论表单
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 17:32:55
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 17:51:44
+ */
+import React, { useState } from 'react';
+import { Form, Button, Input } from 'antd';
+import QuillForEditor from '../../quillForEditor';
+import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
+const FormItem = Form.Item;
+
+function CommentForm (props) {
+
+ const {
+ commentCtxChagne,
+ onCancel,
+ onSubmit,
+ form
+ } = props;
+
+ const { getFieldDecorator } = form;
+ const [ctx, setCtx] = useState('');
+
+ const options = [
+ ['bold', 'italic', 'underline'],
+ [{header: [1,2,3,false]}],
+ ['blockquote', 'code-block'],
+ ['link', 'image'],
+ ['formula']
+ ];
+ // const { form: { getFieldDecorator } } = props;
+ const [showQuill, setShowQuill] = useState(false);
+ // 点击输入框
+ const handleInputClick = () => {
+ setShowQuill(true);
+ }
+ // 取消
+ const handleCancle = () => {
+ setShowQuill(false);
+ onCancel && onCancel();
+ }
+
+ // 编辑器内容变化时
+ const handleContentChange = (content) => {
+ setCtx(content);
+ try {
+ const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert();
+ // props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')});
+ props.form.setFieldsValue({'comment': _html});
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ // 发送
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ props.form.validateFields((err, values) => {
+ if (!err) {
+ setShowQuill(false);
+ const content = ctx;
+ props.form.setFieldsValue({'comment': ''});
+ setCtx('');
+ console.log(content);
+ onSubmit && onSubmit(content);
+ }
+ });
+ }
+ return (
+
+ );
+}
+
+export default Form.create()(CommentForm);
diff --git a/public/react/src/common/components/comment/CommentIcon.js b/public/react/src/common/components/comment/CommentIcon.js
new file mode 100644
index 000000000..5440e2579
--- /dev/null
+++ b/public/react/src/common/components/comment/CommentIcon.js
@@ -0,0 +1,32 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-18 10:49:46
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 11:39:23
+ */
+import './index.scss';
+import React from 'react';
+import { Icon } from 'antd';
+function CommentIcon ({
+ type, // 图标类型
+ count, // 评论数
+ iconClick,
+ ...props
+}) {
+
+ // 点击图标
+ const handleSpanClick = () => {
+ iconClick && iconClick();
+ }
+
+ return (
+
+
+ { count }
+
+ )
+}
+
+export default CommentIcon;
diff --git a/public/react/src/common/components/comment/CommentItem.js b/public/react/src/common/components/comment/CommentItem.js
new file mode 100644
index 000000000..19da645f5
--- /dev/null
+++ b/public/react/src/common/components/comment/CommentItem.js
@@ -0,0 +1,165 @@
+/*
+ * @Description: 评论单列
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 17:35:17
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-19 18:02:28
+ */
+import './index.scss';
+import React, { useState } from 'react';
+import CommentIcon from './CommentIcon';
+import { getImageUrl, CNotificationHOC } from 'educoder'
+import { Icon } from 'antd';
+import moment from 'moment';
+// import QuillForEditor from '../../quillForEditor';
+import CommentForm from './CommentForm';
+
+// import {ModalConfirm} from '../ModalConfirm';
+function CommentItem ({
+ options,
+ confirm
+}) {
+ // 显示评论输入框
+ const [showQuill, setShowQuill] = useState(false);
+ // 加载更多评论内容
+ const [showMore, setShowMore] = useState(false);
+ // 箭头方向
+ const [arrow, setArrow] = useState(false);
+ // 删除评论
+ const deleteComment = () => {
+ console.log('删除评论...');
+ confirm({
+ title: '提示',
+ content: (确定要删除该条回复吗?
),
+ onOk () {
+ console.log('点击了删除');
+ }
+ });
+ // ModalConfirm('提示', (确定要删除该条回复吗?
), () => {
+ // console.log('点击了删除');
+ // });
+ }
+
+ // 评论头像
+ const commentAvatar = (url) => (
+
+ );
+
+ // 评论信息
+ const commentInfo = () => (
+
+ 用户名
+ {moment(new Date(), 'YYYYMMDD HHmmss').fromNow()}
+
+
+ );
+
+ // 评论内容
+ const commentCtx = (ctx) => (
+
+ 这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容
+
+ );
+
+ // 加载更多
+ const handleOnLoadMore = () => {
+ if (!arrow) {
+ // 展开所有
+ } else {
+ // 收起
+ }
+ setArrow(!arrow);
+ };
+
+ // 评论追加内容
+ const commentAppend = () => {
+
+ return (
+
+ -
+ {commentAvatar()}
+
+ {commentInfo()}
+ {commentCtx()}
+
+
+ -
+ {commentAvatar()}
+
+ {commentInfo()}
+ {commentCtx()}
+
+
+ -
+ {commentAvatar()}
+
+ {commentInfo()}
+ {commentCtx()}
+
+
+
+ -
+
展开其余23条评论
+
+
+
+
+
+ );
+ };
+ // 点击图标
+ const handleIconClick = () => {}
+
+ // 点击评论icon
+ const handleClickMessage = () => {
+ setShowQuill(true);
+ }
+
+ // 点击取消
+ const handleClickCancel = () => {
+ setShowQuill(false);
+ }
+
+ // 点击保存
+ const handleClickSubmit = (content) => {
+ // 保存并关闭
+ setShowQuill(false);
+ console.log('获取保存内容', content);
+ }
+
+ return (
+
+ {commentAvatar()}
+
+ {commentInfo()}
+ {commentCtx()}
+
+ {commentAppend()}
+
+
+
+ {/* 回复 */}
+
+ {/* 点赞 */}
+
+
+
+
+
+
+
+
+ );
+}
+
+export default CNotificationHOC() (CommentItem);
diff --git a/public/react/src/common/components/comment/CommentList.js b/public/react/src/common/components/comment/CommentList.js
new file mode 100644
index 000000000..9d8cde87b
--- /dev/null
+++ b/public/react/src/common/components/comment/CommentList.js
@@ -0,0 +1,20 @@
+/*
+ * @Description: 评论列表页
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 17:34:00
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 11:48:09
+ */
+import './index.scss';
+import React from 'react';
+import CommentItem from './CommentItem';
+function CommentList ({}) {
+ return (
+
+ );
+}
+
+export default CommentList;
diff --git a/public/react/src/common/components/comment/index.js b/public/react/src/common/components/comment/index.js
new file mode 100644
index 000000000..f0ecf3309
--- /dev/null
+++ b/public/react/src/common/components/comment/index.js
@@ -0,0 +1,22 @@
+/*
+ * @Description: 评论组件
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 17:31:33
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 11:47:39
+ */
+import React from 'react';
+import CommentForm from './CommentForm';
+import CommentList from './CommentList';
+function Comment (props) {
+
+ return (
+
+
+
+
+ );
+}
+
+export default Comment;
diff --git a/public/react/src/common/components/comment/index.scss b/public/react/src/common/components/comment/index.scss
new file mode 100644
index 000000000..816e6da6c
--- /dev/null
+++ b/public/react/src/common/components/comment/index.scss
@@ -0,0 +1,111 @@
+$bdColor: rgba(244,244,244,1);
+$bgColor: rgba(250,250,250,1);
+$lh14: 14px;
+$lh22: 22px;
+$fz14: 14px;
+$fz12: 12px;
+$ml: 20px;
+
+.comment_list_wrapper{
+ box-sizing: border-box;
+ border-top: 1px solid $bdColor;
+
+ .comment_item_area{
+ display: flex;
+ padding: 20px 0;
+ box-sizing: border-box;
+ border-bottom: 1px solid $bdColor;
+ .flex-image{
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ }
+ .item-desc{
+ flex: 1;
+ margin-left: $ml;
+ }
+ .item-header{
+ font-size: $fz14;
+ line-height: $lh14;
+ color: #333;
+ .item-time{
+ font-size: $fz12;
+ line-height: $lh14;
+ margin-left: $ml;
+ }
+ .item-close{
+ float: right;
+ cursor: pointer;
+ }
+ }
+ .item-ctx{
+ line-height: $lh22;
+ font-size: $fz12;
+ color: #333;
+ margin-top: 10px;
+ }
+ .comment_icon_area{
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 10px;
+
+ .comment-icon-margin{
+ margin-left: 30px;
+ }
+ }
+
+ .comment_item_quill{
+ margin-top: 20px;
+ }
+ }
+ .comment_icon_count{
+ cursor: pointer;
+ font-size: 12px;
+ line-height: 1.5;
+
+ .comment_icon{
+ color: #333;
+ }
+ .comment_count{
+ color: #999999;
+ margin-left: 10px;
+ transition: color .3s;
+ }
+
+ &:hover{
+ .comment_icon,
+ .comment_count{
+ color: #5091FF;
+ }
+ }
+ }
+ .comment_item_append_list{
+ position: relative;
+ background-color: $bgColor;
+ border-radius: 5px;
+ padding: 0 15px 10px;
+ margin: 15px 0;
+ &::before {
+ position: absolute;
+ left: 15px;
+ bottom: 100%;
+ height: 0;
+ width: 0;
+ content: '';
+ // border: 5px solid transparent;
+ border: 10px solid transparent;
+ border-bottom-color: $bgColor;
+ }
+
+ .comment_item_loadmore{
+ padding-top: 10px;
+ cursor: pointer;
+ .loadmore-txt,
+ .loadmore-icon{
+ color: #999;
+ text-align: center;
+ font-size: $fz12;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/react/src/common/quillForEditor/ImageBlot.js b/public/react/src/common/quillForEditor/ImageBlot.js
new file mode 100644
index 000000000..091bd2c1f
--- /dev/null
+++ b/public/react/src/common/quillForEditor/ImageBlot.js
@@ -0,0 +1,54 @@
+/*
+ * @Description: 重写图片
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-16 15:50:45
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 16:44:48
+ */
+import Quill from "quill";
+
+const BlockEmbed = Quill.import('blots/block/embed');
+
+export default class ImageBlot extends BlockEmbed {
+
+ static create(value) {
+
+ const node = super.create();
+
+ node.setAttribute('alt', value.alt);
+ node.setAttribute('src', value.url);
+
+ if (value.width) {
+ node.setAttribute('width', value.width);
+ }
+ if (value.height) {
+ node.setAttribute('height', value.height);
+ }
+ // 宽度和高度都不存在时,
+ if (!value.width && !value.height) {
+ node.setAttribute('display', 'block');
+ node.setAttribute('width', '100%');
+ }
+ // 给图片添加点击事件
+ node.onclick = () => {
+ value.onClick && value.onClick(value.url);
+ }
+ return node;
+ }
+
+ static value (node) {
+
+ return {
+ alt: node.getAttribute('alt'),
+ url: node.getAttribute('src'),
+ onclick: node.onclick,
+ // width: node.width,
+ // height: node.height,
+ display: node.getAttribute('display')
+ };
+ }
+}
+
+ImageBlot.blotName = 'image';
+ImageBlot.tagName = 'img';
\ No newline at end of file
diff --git a/public/react/src/common/quillForEditor/deepEqual.js b/public/react/src/common/quillForEditor/deepEqual.js
new file mode 100644
index 000000000..6f2b276bf
--- /dev/null
+++ b/public/react/src/common/quillForEditor/deepEqual.js
@@ -0,0 +1,47 @@
+function deepEqual (prev, current) {
+ if (prev === current) { // 基本类型比较,值,类型都相同 或者同为 null or undefined
+ return true;
+ }
+
+ if ((!prev && current)
+ || (prev && !current)
+ || (!prev && !current)
+ ) {
+ return false;
+ }
+
+ if (Array.isArray(prev)) {
+ if (!Array.isArray(current)) return false;
+ if (prev.length !== current.length) return false;
+
+ for (let i = 0; i < prev.length; i++) {
+ if (!deepEqual(current[i], prev[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (typeof current === 'object') {
+ if (typeof prev !== 'object') return false;
+ const prevKeys = Object.keys(prev);
+ const curKeys = Object.keys(current);
+
+ if (prevKeys.length !== curKeys.length) return false;
+
+ prevKeys.sort();
+ curKeys.sort();
+
+ for (let i = 0; i < prevKeys.length; i++) {
+ if (prevKeys[i] !== curKeys[i]) return false;
+ const key = prevKeys[i];
+ if (!deepEqual(prev[key], current[key])) return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+export default deepEqual;
diff --git a/public/react/src/common/quillForEditor/index.js b/public/react/src/common/quillForEditor/index.js
new file mode 100644
index 000000000..6e6c01886
--- /dev/null
+++ b/public/react/src/common/quillForEditor/index.js
@@ -0,0 +1,166 @@
+/*
+ * @Description: quill 编辑器
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-18 08:49:30
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-19 16:58:50
+ */
+import 'quill/dist/quill.core.css'; // 核心样式
+import 'quill/dist/quill.snow.css'; // 有工具栏
+import 'quill/dist/quill.bubble.css'; // 无工具栏
+import 'katex/dist/katex.min.css'; // katex 表达式样式
+import React, { useState, useRef, useEffect } from 'react';
+import Quill from 'quill';
+import katex from 'katex';
+import deepEqual from './deepEqual.js'
+import { fetchUploadImage } from '../../services/ojService.js';
+import { getImageUrl } from 'educoder'
+import ImageBlot from './ImageBlot';
+
+window.Quill = Quill;
+window.katex = katex;
+Quill.register(ImageBlot);
+
+function QuillForEditor ({
+ placeholder,
+ readOnly,
+ options,
+ value,
+ imgAttrs = {}, // 指定图片的宽高
+ style = {},
+ wrapStyle = {},
+ showUploadImage,
+ onContentChange
+}) {
+ // toolbar 默认值
+ const defaultConfig = [
+ ['bold', 'italic', 'underline'],
+ [{align: []}, {list: 'ordered'}, {list: 'bullet'}], // 列表
+ [{script: 'sub'}, {script: 'super'}],
+ [{ 'color': [] }, { 'background': [] }],
+ [{header: [1,2,3,4,5,false]}],
+ ['blockquote', 'code-block'],
+ ['link', 'image', 'video'],
+ ['formula'],
+ ['clean']
+ ];
+
+ const editorRef = useRef(null);
+ // quill 实例
+ const [quill, setQuill] = useState(null);
+ const [selection, setSelection] = useState(null);
+
+ // 文本内容变化时
+ const handleOnChange = content => {
+ // console.log('编辑器内容====》》》》', content);
+ onContentChange && onContentChange(content);
+ };
+
+ const renderOptions = options || defaultConfig;
+ // quill 配置信息
+ const quillOption = {
+ modules: {
+ toolbar: renderOptions
+ },
+ readOnly,
+ placeholder,
+ theme: readOnly ? 'bubble' : 'snow'
+ };
+
+
+ useEffect(() => {
+ const _quill = new Quill(editorRef.current, quillOption);
+ setQuill(_quill);
+
+ // 处理图片上传功能
+ _quill.getModule('toolbar').addHandler('image', (e) => {
+ const input = document.createElement('input');
+ input.setAttribute('type', 'file');
+ input.setAttribute('accept', 'image/*');
+ input.click();
+
+ input.onchange = async (e) => {
+ const file = input.files[0]; // 获取文件信息
+ const formData = new FormData();
+ formData.append('file', file);
+
+ const range = _quill.getSelection(true);
+ let fileUrl = ''; // 保存上传成功后图片的url
+ // 上传文件
+ const result = await fetchUploadImage(formData);
+ // 获取上传图片的url
+ if (result.data && result.data.id) {
+ fileUrl = getImageUrl(`api/attachments/${result.data.id}`);
+ }
+ // 根据id获取文件路径
+ const { width, height } = imgAttrs;
+ // console.log('上传图片的url:', fileUrl);
+ if (fileUrl) {
+ _quill.insertEmbed(range.index, 'image', {
+ url: fileUrl,
+ alt: '图片信息',
+ onClick: showUploadImage,
+ width,
+ height
+ });
+ }
+ }
+ });
+ }, []);
+
+ // 设置值
+ useEffect(() => {
+ if (!quill) return
+ const previous = quill.getContents()
+ const current = value
+
+ if (!deepEqual(previous, current)) {
+ setSelection(quill.getSelection())
+ if (typeof value === 'string') {
+ quill.clipboard.dangerouslyPasteHTML(value, 'api')
+ } else {
+ quill.setContents(value)
+ }
+ }
+ }, [quill, value, setQuill]);
+
+ // 清除选择区域
+ useEffect(() => {
+ if (quill && selection) {
+ quill.setSelection(selection)
+ setSelection(null)
+ }
+ }, [quill, selection, setSelection]);
+
+ // 设置placeholder值
+ useEffect(() => {
+ if (!quill || !quill.root) return;
+ quill.root.dataset.placeholder = placeholder;
+ }, [quill, placeholder]);
+
+ // 处理内容变化
+ useEffect(() => {
+ if (!quill) return;
+ if (typeof handleOnChange !== 'function') return;
+ let handler;
+ quill.on(
+ 'text-change',
+ (handler = () => {
+ handleOnChange(quill.getContents()); // getContents: 检索编辑器内容
+ })
+ );
+ return () => {
+ quill.off('text-change', handler);
+ }
+ }, [quill, handleOnChange]);
+
+ // 返回结果
+ return (
+
+ );
+}
+
+export default QuillForEditor;
diff --git a/public/react/src/common/reactQuill/ImageBlot.js b/public/react/src/common/reactQuill/ImageBlot.js
new file mode 100644
index 000000000..091bd2c1f
--- /dev/null
+++ b/public/react/src/common/reactQuill/ImageBlot.js
@@ -0,0 +1,54 @@
+/*
+ * @Description: 重写图片
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-16 15:50:45
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 16:44:48
+ */
+import Quill from "quill";
+
+const BlockEmbed = Quill.import('blots/block/embed');
+
+export default class ImageBlot extends BlockEmbed {
+
+ static create(value) {
+
+ const node = super.create();
+
+ node.setAttribute('alt', value.alt);
+ node.setAttribute('src', value.url);
+
+ if (value.width) {
+ node.setAttribute('width', value.width);
+ }
+ if (value.height) {
+ node.setAttribute('height', value.height);
+ }
+ // 宽度和高度都不存在时,
+ if (!value.width && !value.height) {
+ node.setAttribute('display', 'block');
+ node.setAttribute('width', '100%');
+ }
+ // 给图片添加点击事件
+ node.onclick = () => {
+ value.onClick && value.onClick(value.url);
+ }
+ return node;
+ }
+
+ static value (node) {
+
+ return {
+ alt: node.getAttribute('alt'),
+ url: node.getAttribute('src'),
+ onclick: node.onclick,
+ // width: node.width,
+ // height: node.height,
+ display: node.getAttribute('display')
+ };
+ }
+}
+
+ImageBlot.blotName = 'image';
+ImageBlot.tagName = 'img';
\ No newline at end of file
diff --git a/public/react/src/common/reactQuill/ReactQuill.js b/public/react/src/common/reactQuill/ReactQuill.js
new file mode 100644
index 000000000..1b4209409
--- /dev/null
+++ b/public/react/src/common/reactQuill/ReactQuill.js
@@ -0,0 +1,45 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:09:42
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 08:46:20
+ */
+import 'quill/dist/quill.core.css'; // 核心样式
+import 'quill/dist/quill.snow.css'; // 有工具栏
+import 'quill/dist/quill.bubble.css'; // 无工具栏
+import 'katex/dist/katex.min.css'; // katex 表达式样式
+import React, { useState, useReducer, useEffect } from 'react';
+import useQuill from './useQuill';
+
+function ReactQuill ({
+ disallowColors, // 不可见时颜色
+ placeholder, // 提示信息
+ uploadImage, // 图片上传
+ onChange, // 内容变化时
+ options, // 配置信息
+ value, // 显示的内容
+ style,
+ showUploadImage // 显示上传图片
+}) {
+
+ const [element, setElement] = useState(); // quill 渲染节点
+
+ useQuill({
+ disallowColors,
+ placeholder,
+ uploadImage,
+ onChange,
+ options,
+ value,
+ showUploadImage,
+ element
+ });
+
+ return (
+
+ );
+}
+
+export default ReactQuill;
diff --git a/public/react/src/common/reactQuill/deepEqual.js b/public/react/src/common/reactQuill/deepEqual.js
new file mode 100644
index 000000000..6f2b276bf
--- /dev/null
+++ b/public/react/src/common/reactQuill/deepEqual.js
@@ -0,0 +1,47 @@
+function deepEqual (prev, current) {
+ if (prev === current) { // 基本类型比较,值,类型都相同 或者同为 null or undefined
+ return true;
+ }
+
+ if ((!prev && current)
+ || (prev && !current)
+ || (!prev && !current)
+ ) {
+ return false;
+ }
+
+ if (Array.isArray(prev)) {
+ if (!Array.isArray(current)) return false;
+ if (prev.length !== current.length) return false;
+
+ for (let i = 0; i < prev.length; i++) {
+ if (!deepEqual(current[i], prev[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (typeof current === 'object') {
+ if (typeof prev !== 'object') return false;
+ const prevKeys = Object.keys(prev);
+ const curKeys = Object.keys(current);
+
+ if (prevKeys.length !== curKeys.length) return false;
+
+ prevKeys.sort();
+ curKeys.sort();
+
+ for (let i = 0; i < prevKeys.length; i++) {
+ if (prevKeys[i] !== curKeys[i]) return false;
+ const key = prevKeys[i];
+ if (!deepEqual(prev[key], current[key])) return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+export default deepEqual;
diff --git a/public/react/src/common/reactQuill/flatten.js b/public/react/src/common/reactQuill/flatten.js
new file mode 100644
index 000000000..237cb543f
--- /dev/null
+++ b/public/react/src/common/reactQuill/flatten.js
@@ -0,0 +1,26 @@
+/*
+ * @Description: 将多维数组转变成一维数组
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:35:01
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:36:22
+ */
+function flatten (array) {
+ return flatten.rec(array, []);
+}
+
+flatten.rec = function flatten (array, result) {
+
+ for (let item of array) {
+ if (Array.isArray(item)) {
+ flatten(item, result);
+ } else {
+ result.push(item);
+ }
+ }
+
+ return result;
+}
+
+export default flatten;
diff --git a/public/react/src/common/reactQuill/index.js b/public/react/src/common/reactQuill/index.js
new file mode 100644
index 000000000..56a1a8d1f
--- /dev/null
+++ b/public/react/src/common/reactQuill/index.js
@@ -0,0 +1,108 @@
+/*
+ * @Description: 入口文件
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 10:41:48
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 20:34:40
+ */
+import React, { useState, useCallback, useEffect } from 'react';
+import ReactQuill from './lib';
+
+function Wrapper (props) {
+ // 默认工具栏配置项
+ const toolbarConfig = [
+ ['bold', 'italic', 'underline'],
+ [{align: []}, {list: 'ordered'}, {list: 'bullet'}], // 列表
+ [{script: 'sub'}, {script: 'super'}],
+ [{header: [1,2,3,4,5,false]}],
+ ['blockquote', 'code-block'],
+ ['link', 'image', 'video'],
+ ['formula'],
+ ['clean']
+ ];
+
+ const [placeholder] = useState(props.placeholder || 'placeholder');
+ const [disableBold] = useState(false);
+ const [value, setValue] = useState(props.value || '');
+ const [toolbar, setToolbar] = useState(toolbarConfig);
+ const [theme, setTheme] = useState(props.theme || 'snow');
+ const [readOnly] = useState(props.readOnly || false);
+
+ const {
+ onContentChagne, // 当编辑器内容变化时调用该函数
+ showUploadImage, // 显示上传图片, 返回url,主要用于点击图片放大
+ } = props;
+
+ // 配置信息
+ const options = {
+ modules: {
+ toolbar: toolbar,
+ clipboard: {
+ matchVisual: false
+ }
+ },
+ readOnly: readOnly,
+ theme: theme
+ }
+ // 配置信息
+ useEffect (() => {
+ if (props.options) {
+ setToolbar(props.options);
+ }
+ setTheme(props.theme || 'snow');
+ setValue(props.value);
+ }, [props]);
+
+ // 当内容变化时
+ const handleOnChange = useCallback(
+ contents => {
+ if (disableBold) {
+ setValue({
+ ops: contents.ops.map(x => {
+ x = {...x};
+ if (x && x.attributes && x.attributes.bold) {
+ x.attributes = { ...x.attributes };
+ delete x.attributes.bold;
+ if (!Object.keys(x.attributes).length) {
+ delete x.attributes;
+ }
+ }
+ return x;
+ })
+ });
+ } else {
+ setValue(contents);
+ }
+ onContentChagne && onContentChagne(contents);
+ }, [disableBold]
+ );
+
+ // 图片上传
+ const handleUploadImage = (files) => {
+ console.log('选择的图片信息', files);
+ }
+
+ // 显示图片
+ const handleShowUploadImage = (url) => {
+ // console.log('上传的图片url:', url);
+ showUploadImage && showUploadImage(url);
+ }
+
+ return (
+
+ handleShowUploadImage(url)}
+ />
+
+ );
+}
+
+export default Wrapper;
+// ReactDOM.render(
, document.querySelector('#root'));
diff --git a/public/react/src/common/reactQuill/index.scss b/public/react/src/common/reactQuill/index.scss
new file mode 100644
index 000000000..b6da52bf5
--- /dev/null
+++ b/public/react/src/common/reactQuill/index.scss
@@ -0,0 +1,32 @@
+#quill-toolbar{
+ .quill-btn{
+ vertical-align: middle;
+ }
+ .quill_image{
+ display: inline-block;
+ position: relative;
+ vertical-align: middle;
+ width: 28px;
+ height: 24px;
+ overflow: hidden;
+ .image_input{
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ opacity: 0;
+ }
+ .ql-image{
+ position: relative;
+ left: 0;
+ top: 0;
+ }
+ }
+}
+
+.react_quill_area{
+ .ql-toolbar:not(:last-child) {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/public/react/src/common/reactQuill/lib.js b/public/react/src/common/reactQuill/lib.js
new file mode 100644
index 000000000..430a95bb7
--- /dev/null
+++ b/public/react/src/common/reactQuill/lib.js
@@ -0,0 +1,13 @@
+/*
+ * @Description: 导出 ReactQuill
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:08:24
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:37:13
+ */
+import ReactQuill from './ReactQuill';
+import useQuill from './useQuill';
+
+export default ReactQuill;
+export { useQuill };
diff --git a/public/react/src/common/reactQuill/useDeepEqualMemo.js b/public/react/src/common/reactQuill/useDeepEqualMemo.js
new file mode 100644
index 000000000..948e21781
--- /dev/null
+++ b/public/react/src/common/reactQuill/useDeepEqualMemo.js
@@ -0,0 +1,27 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-12 19:48:55
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:38:16
+ */
+import { useState, useEffect } from 'react';
+import deepEqual from './deepEqual';
+
+function useDeepEqual (input) {
+
+ const [value, setValue] = useState(input);
+
+ useEffect(() => {
+
+ if (!deepEqual(input, value)) {
+ setValue(input)
+ }
+
+ }, [input, value]);
+
+ return value;
+}
+
+export default useDeepEqual;
diff --git a/public/react/src/common/reactQuill/useMountQuill.js b/public/react/src/common/reactQuill/useMountQuill.js
new file mode 100644
index 000000000..c2313c480
--- /dev/null
+++ b/public/react/src/common/reactQuill/useMountQuill.js
@@ -0,0 +1,148 @@
+/*
+ * @Description: 创建 reactQuill实例
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:31:42
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 20:42:05
+ */
+import Quill from 'quill'; // 导入quill
+import { useState, useEffect, useMemo } from 'react';
+import flatten from './flatten.js';
+import useDeepEqualMemo from './useDeepEqualMemo';
+import Katex from 'katex';
+import ImageBlot from './ImageBlot';
+import { fetchUploadImage } from '../../services/ojService.js';
+import { getImageUrl } from 'educoder'
+window.katex = Katex;
+
+Quill.register(ImageBlot);
+
+function useMountQuill ({
+ element,
+ options: passedOptions,
+ uploadImage,
+ showUploadImage,
+ imgAttrs = {} // 指定图片的宽高属性
+}) {
+
+ // 是否引入 katex
+ const [katexLoaded, setKatexLoaded] = useState(Boolean(window.katex))
+ const [quill, setQuill] = useState(null);
+
+ const options = useDeepEqualMemo(passedOptions);
+ console.log('use mount quill: ', passedOptions);
+
+ // 判断options中是否包含公式
+ const requireKatex = useMemo(() => {
+ return flatten(options.modules.toolbar).includes('formula');
+ }, [options]);
+
+ // 加载katex
+ useEffect(() => {
+ if (!requireKatex) return;
+ if (katexLoaded) return;
+
+ const interval = setInterval(() => {
+ if (window.katex) {
+ setKatexLoaded(true);
+ clearInterval(interval);
+ }
+ });
+
+ return () => { // 定义回调清除定时器
+ clearInterval(interval);
+ }
+
+ }, [
+ setKatexLoaded,
+ katexLoaded,
+ requireKatex
+ ]);
+
+ // 加载 quill
+ useEffect(() => {
+ if (!element) return;
+ if (requireKatex && !katexLoaded) {
+ element.innerHTML = `
+
+ Loading Katex...
+
+ `
+ }
+ // 清空内容
+ element.innerHTML = '';
+ console.log(element);
+ // 创建 quill 节点
+ const quillNode = document.createElement('div');
+ element.appendChild(quillNode); // 将quill节点追回到 element 元素中
+
+ const quill = new Quill(element, options);
+ setQuill(quill);
+ // 加载上传图片功能
+ if (typeof uploadImage === 'function') {
+ quill.getModule('toolbar').addHandler('image', (e) => {
+ // 创建type类型输入框加载本地图片
+ const input = document.createElement('input');
+ input.setAttribute('type', 'file');
+ input.setAttribute('accept', 'image/*');
+ input.click();
+
+ input.onchange = async (e) => {
+ const file = input.files[0]; // 获取文件信息
+ const formData = new FormData();
+ formData.append('file', file);
+
+ // const reader = new FileReader();
+ // reader.readAsDataURL(file);
+ // console.log('文件信息===>>', reader);
+ // reader.onload = function (e) {
+ // debugger;
+ // console.log('文件信息===>>', e.target.result);
+ // const image = new Image();
+ // image.src = e.target.result;
+
+ // image.onload = function () {
+ // // file.width =
+ // console.log(image.width, image.height);
+ // }
+ // }
+
+ const range = quill.getSelection(true);
+ let fileUrl = ''; // 保存上传成功后图片的url
+ // 上传文件
+ const result = await fetchUploadImage(formData);
+ // 获取上传图片的url
+ if (result.data && result.data.id) {
+ fileUrl = getImageUrl(`api/attachments/${result.data.id}`);
+ }
+ // 根据id获取文件路径
+ const { width, height } = imgAttrs;
+ // console.log('上传图片的url:', fileUrl);
+ if (fileUrl) {
+ quill.insertEmbed(range.index, 'image', {
+ url: fileUrl,
+ alt: '',
+ onClick: showUploadImage,
+ width,
+ height
+ });
+ }
+ }
+ });
+ }
+
+ return () => {
+ element.innerHTML = '';
+ }
+ }, [
+ element,
+ options,
+ requireKatex,
+ katexLoaded,
+ ]);
+
+ return quill;
+}
+
+export default useMountQuill;
diff --git a/public/react/src/common/reactQuill/useQuill.js b/public/react/src/common/reactQuill/useQuill.js
new file mode 100644
index 000000000..b959dbc52
--- /dev/null
+++ b/public/react/src/common/reactQuill/useQuill.js
@@ -0,0 +1,60 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:09:50
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 15:46:50
+ */
+import useQuillPlaceholder from './useQuillPlaceholder';
+import useQuillValueSync from './useQuillValueSync';
+import useQuillOnChange from './useQuillOnChange';
+import useMountQuill from './useMountQuill';
+import { useEffect } from 'react';
+
+function useQuill ({
+ disallowColors,
+ placeholder,
+ uploadImage,
+ onChange,
+ options,
+ value,
+ element,
+ showUploadImage
+}) {
+
+ // 获取 quill 实例
+ const quill = useMountQuill({
+ element,
+ options,
+ uploadImage,
+ showUploadImage
+ });
+
+ useEffect(() => {
+ if (disallowColors && quill) {
+ quill.clipboard.addMatcher(Node.ELEMENT_NODE, (node, delta) => {
+ delta.ops = delta.ops.map(op => {
+ if (op.attributes && op.attributes.color) {
+ const { color, ...attributes } = op.attributes;
+ return {
+ ...op,
+ attributes
+ }
+ }
+ return op;
+ });
+ return delta;
+ });
+ }
+ }, [
+ disallowColors,
+ quill
+ ]);
+
+ useQuillPlaceholder(quill, placeholder);
+ useQuillValueSync(quill, value);
+ useQuillOnChange(quill, onChange);
+}
+
+export default useQuill;
diff --git a/public/react/src/common/reactQuill/useQuillOnChange.js b/public/react/src/common/reactQuill/useQuillOnChange.js
new file mode 100644
index 000000000..45333a4e1
--- /dev/null
+++ b/public/react/src/common/reactQuill/useQuillOnChange.js
@@ -0,0 +1,33 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-12 19:49:11
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:39:27
+ */
+import { useEffect } from 'react';
+
+function useQuillOnChange (quill, onChange) {
+
+ useEffect(() => {
+
+ if (!quill) return;
+ if (typeof onChange !== 'function') return;
+
+ let handler;
+
+ quill.on(
+ 'text-change',
+ (handler = () => {
+ onChange(quill.getContents()); // getContents: 检索编辑器内容
+ })
+ );
+
+ return () => {
+ quill.off('text-change', handler);
+ }
+ }, [quill, onChange]);
+}
+
+export default useQuillOnChange;
diff --git a/public/react/src/common/reactQuill/useQuillPlaceholder.js b/public/react/src/common/reactQuill/useQuillPlaceholder.js
new file mode 100644
index 000000000..ccc341568
--- /dev/null
+++ b/public/react/src/common/reactQuill/useQuillPlaceholder.js
@@ -0,0 +1,22 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:28:34
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:39:48
+ */
+import { useEffect } from 'react'
+
+function useQuillPlaceholder (
+ quill,
+ placeholder
+) {
+
+ useEffect(() => {
+ if (!quill || !quill.root) return;
+ quill.root.dataset.placeholder = placeholder;
+ }, [quill, placeholder]);
+}
+
+export default useQuillPlaceholder;
diff --git a/public/react/src/common/reactQuill/useQuillValueSync.js b/public/react/src/common/reactQuill/useQuillValueSync.js
new file mode 100644
index 000000000..696d88949
--- /dev/null
+++ b/public/react/src/common/reactQuill/useQuillValueSync.js
@@ -0,0 +1,31 @@
+import { useEffect, useState } from 'react'
+import deepEqual from './deepEqual.js'
+
+function useQuillValueSync(quill, value) {
+ const [selection, setSelection] = useState(null)
+
+ useEffect(() => {
+ if (!quill) return
+
+ const previous = quill.getContents()
+ const current = value
+
+ if (!deepEqual(previous, current)) {
+ setSelection(quill.getSelection())
+ if (typeof value === 'string') {
+ quill.clipboard.dangerouslyPasteHTML(value, 'api')
+ } else {
+ quill.setContents(value)
+ }
+ }
+ }, [quill, value, setSelection])
+
+ useEffect(() => {
+ if (quill && selection) {
+ quill.setSelection(selection)
+ setSelection(null)
+ }
+ }, [quill, selection, setSelection])
+}
+
+export default useQuillValueSync
diff --git a/public/react/src/modules/developer/DeveloperHome.js b/public/react/src/modules/developer/DeveloperHome.js
index 5f787659e..73a5c37a1 100644
--- a/public/react/src/modules/developer/DeveloperHome.js
+++ b/public/react/src/modules/developer/DeveloperHome.js
@@ -16,7 +16,7 @@ import MultipTags from './components/multiptags';
// import { Link } from 'react-router-dom';
import CONST from '../../constants';
import { withRouter } from 'react-router';
-import { toStore } from 'educoder';
+import { toStore, CNotificationHOC } from 'educoder';
// import MyIcon from '../../common/components/MyIcon';
const {tagBackground, diffText} = CONST;
@@ -249,17 +249,26 @@ class DeveloperHome extends React.PureComponent {
// 删除
handleClickDelete = (record) => {
const { deleteItem } = this.props;
- Modal.confirm({
- title: '删除',
+ this.props.confirm({
+ title: '提示',
content: `确定要删除${record.name}吗?`,
- okText: '确定',
- cancelText: '取消',
onOk () {
// 调用删除接口
console.log(record.identifier);
deleteItem(record.identifier);
}
});
+ // Modal.confirm({
+ // title: '删除',
+ // content: `确定要删除${record.name}吗?`,
+ // okText: '确定',
+ // cancelText: '取消',
+ // onOk () {
+ // // 调用删除接口
+ // console.log(record.identifier);
+ // deleteItem(record.identifier);
+ // }
+ // });
}
// table条件变化时
handleTableChange = (pagination, filters, sorter) => {
@@ -562,5 +571,5 @@ const mapDispatchToProps = (dispatch) => ({
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
-)(DeveloperHome));
+)(CNotificationHOC() (DeveloperHome)));
// export default DeveloperHome;
diff --git a/public/react/src/modules/developer/components/controlSetting/index.js b/public/react/src/modules/developer/components/controlSetting/index.js
index 587e1bee9..b5c9222ef 100644
--- a/public/react/src/modules/developer/components/controlSetting/index.js
+++ b/public/react/src/modules/developer/components/controlSetting/index.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 16:02:36
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 17:32:33
+ * @LastEditTime: 2019-12-19 10:47:44
*/
import './index.scss';
import React, { useState, useRef } from 'react';
@@ -30,7 +30,7 @@ const ControlSetting = (props) => {
// debuggerCode,
// startDebuggerCode, // 外部存入
onDebuggerCode,
- updateCode,
+ // updateCode,
onSubmitForm
} = props;
const [defaultActiveKey, setDefaultActiveKey] = useState('1'); // 当前选中的tab
@@ -84,7 +84,7 @@ const ControlSetting = (props) => {
diff --git a/public/react/src/modules/developer/components/controlSetting/index.scss b/public/react/src/modules/developer/components/controlSetting/index.scss
index 97838ce5c..31beda8a5 100644
--- a/public/react/src/modules/developer/components/controlSetting/index.scss
+++ b/public/react/src/modules/developer/components/controlSetting/index.scss
@@ -2,7 +2,8 @@
position: absolute;
bottom: 0;
width: 100%;
- background:rgba(30,30,30,1);
+ // background: red;
+ // background:rgba(30,30,30,1);
// height: 56px;
.control_tab{
position: absolute;
@@ -52,8 +53,8 @@
height: 56px;
padding-right: 30px;
padding-left: 10px;
- // background: #000;
- background:rgba(48,48,48,1);
+ background: rgba(18,28,36,1);
+ // background:rgba(48,48,48,1);
}
.setting_drawer{
diff --git a/public/react/src/modules/developer/components/execResult/index.js b/public/react/src/modules/developer/components/execResult/index.js
index 32bbbee91..6f9341b9a 100644
--- a/public/react/src/modules/developer/components/execResult/index.js
+++ b/public/react/src/modules/developer/components/execResult/index.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-28 08:44:54
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-10 09:24:02
+ * @LastEditTime: 2019-12-19 10:44:16
*/
import './index.scss';
import React, { useState, useEffect } from 'react';
@@ -38,6 +38,15 @@ function ExecResult (props) {
);
+
+ const renderError = () => (
+
+
+ 未知异常
+
+
+ )
+
const renderFinish = () => {
const {
error_line,
@@ -60,6 +69,7 @@ function ExecResult (props) {
)
}
+ // console.log('执行结果====》》》》', status);
const excuteCtx = (state) => {
if (state === 0) {
return (
@@ -118,6 +128,8 @@ function ExecResult (props) {
setRenderCtx(() => (readerLoaded));
} else if ('finish' === excuteState) {
setRenderCtx(() => (renderFinish));
+ } else if ('error' === excuteState) {
+ setRenderCtx(() => (renderError))
}
}, [excuteState]);
diff --git a/public/react/src/modules/developer/components/initTabCtx/index.js b/public/react/src/modules/developer/components/initTabCtx/index.js
index 3834a3e11..3e707daa1 100644
--- a/public/react/src/modules/developer/components/initTabCtx/index.js
+++ b/public/react/src/modules/developer/components/initTabCtx/index.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 19:46:14
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 17:38:42
+ * @LastEditTime: 2019-12-19 10:47:05
*/
import './index.scss';
import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react';
@@ -26,6 +26,7 @@ function InitTabCtx (props, ref) {
const { inputValue, onDebuggerCode } = props;
+ console.log('default value', inputValue);
useImperativeHandle(ref, () => ({
handleTestCodeFormSubmit: (cb) => {
// console.log('父组件调用我啦~~~~~~~~~');
@@ -33,6 +34,10 @@ function InitTabCtx (props, ref) {
}
}));
+ useEffect(() => {
+ console.log('初始值: ========', props);
+ }, [props]);
+
// 渲染文本提示信息
const renderText = () => (请在这里添加测试用例,点击“调试代码”时将从这里读取输入来测试你的代码...);
// 渲染表单信息
diff --git a/public/react/src/modules/developer/components/initTabCtx/index.scss b/public/react/src/modules/developer/components/initTabCtx/index.scss
index 449db1d2a..5427aa374 100644
--- a/public/react/src/modules/developer/components/initTabCtx/index.scss
+++ b/public/react/src/modules/developer/components/initTabCtx/index.scss
@@ -49,7 +49,8 @@
}
.input_textarea_style{
- background:rgba(30,30,30,1) !important;
+ // background:rgba(30,30,30,1) !important;
+ background:rgba(7,15,25,1) !important;
color: #fff;
border-color: transparent;
outline: none;
diff --git a/public/react/src/modules/developer/components/monacoSetting/index.js b/public/react/src/modules/developer/components/monacoSetting/index.js
index a101819e0..c1215f9af 100644
--- a/public/react/src/modules/developer/components/monacoSetting/index.js
+++ b/public/react/src/modules/developer/components/monacoSetting/index.js
@@ -4,10 +4,11 @@
* @Github:
* @Date: 2019-11-25 17:50:33
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-06 16:51:48
+ * @LastEditTime: 2019-12-19 15:26:46
*/
import React, { useState } from 'react';
import { fromStore, toStore } from 'educoder';
+import { Icon } from 'antd';
// import { Select } from 'antd';
// const { Option } = Select;
const SettingDrawer = (props) => {
diff --git a/public/react/src/modules/developer/components/myMonacoEditor/index.js b/public/react/src/modules/developer/components/myMonacoEditor/index.js
index 60f54ee0a..df3c2b5e3 100644
--- a/public/react/src/modules/developer/components/myMonacoEditor/index.js
+++ b/public/react/src/modules/developer/components/myMonacoEditor/index.js
@@ -4,12 +4,12 @@
* @Github:
* @Date: 2019-11-27 15:02:52
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 16:16:56
+ * @LastEditTime: 2019-12-19 17:52:31
*/
import './index.scss';
import React, { useState, useRef, useEffect } from 'react';
-import { Drawer, Modal } from 'antd';
-import { fromStore } from 'educoder';
+import { Drawer, Modal, Icon, Badge } from 'antd';
+import { fromStore, CNotificationHOC } from 'educoder';
import { connect } from 'react-redux';
import MonacoEditor from '@monaco-editor/react';
import SettingDrawer from '../../components/monacoSetting';
@@ -19,16 +19,25 @@ import MyIcon from '../../../../common/components/MyIcon';
// import actions from '../../../../redux/actions';
const { fontSetting, opacitySetting } = CONST;
+const maps = {
+ 'c': 'main.c',
+ 'c++': 'main.cc',
+ 'java': 'main.java',
+ 'pythone': 'main.py'
+};
function MyMonacoEditor (props, ref) {
const {
+ notice,
language,
identifier,
+ hadCodeUpdate,
showOrHideControl,
// saveUserInputCode,
onCodeChange,
- onRestoreInitialCode
+ onRestoreInitialCode,
+ onUpdateNotice
} = props;
const [showDrawer, setShowDrawer] = useState(false); // 控制配置滑框
@@ -50,7 +59,7 @@ function MyMonacoEditor (props, ref) {
}, [props]);
useEffect(() => {
- setHeight(showOrHideControl ? 'calc(100% - 382px)' : 'calc(100% - 56px)');
+ setHeight(showOrHideControl ? 'calc(100% - 378px)' : 'calc(100% - 56px)');
}, [showOrHideControl]);
// 控制侧边栏设置的显示
@@ -93,28 +102,51 @@ function MyMonacoEditor (props, ref) {
// 恢复初始代码
const handleRestoreCode = () => {
- Modal.confirm({
+ props.confirm({
+ title: '提示',
content: '确定要恢复代码吗?',
- okText: '确定',
- cancelText: '取消',
onOk () {
onRestoreInitialCode && onRestoreInitialCode();
}
})
+ // Modal.confirm({
+ // content: '确定要恢复代码吗?',
+ // okText: '确定',
+ // cancelText: '取消',
+ // onOk () {
+ // onRestoreInitialCode && onRestoreInitialCode();
+ // }
+ // })
+ }
+
+ const handleUpdateNotice = () => {
+ if (props.notice) {
+ onUpdateNotice && onUpdateNotice();
+ }
}
const renderRestore = identifier ? (
) : '';
+
+ // lex_has_save ${hadCodeUpdate} ? : ''
+ const _classnames = hadCodeUpdate ? `flex_strict flex_has_save` : 'flex_strict';
return (
{/* 未保存时 ? '学员初始代码文件' : main.x */}
- {identifier ? '' : '学员初始代码文件'}
- {identifier ? '已保存' : ''}
+ {identifier ? language ? maps[language.toLowerCase()] : '' : '学员初始代码文件'}
+ {identifier ? '已保存' : ''}
+
+
+
{renderRestore}
- {/* */}
@@ -161,4 +192,4 @@ const mapDispatchToProps = (dispatch) => ({
export default connect(
mapStateToProps,
mapDispatchToProps
-)(MyMonacoEditor);
+)(CNotificationHOC() (MyMonacoEditor));
diff --git a/public/react/src/modules/developer/components/myMonacoEditor/index.scss b/public/react/src/modules/developer/components/myMonacoEditor/index.scss
index 7a7c4f030..61689b51e 100644
--- a/public/react/src/modules/developer/components/myMonacoEditor/index.scss
+++ b/public/react/src/modules/developer/components/myMonacoEditor/index.scss
@@ -1,19 +1,17 @@
.monaco_editor_area{
height: 100%;
- background-color: rgba(30,30,30,1);
+ background-color: rgba(7,15,25,1);
.code_title{
display: flex;
align-items: center;
- // justify-content: space-between;
- // background: #000;
- // background: #333333;
- background-color: rgba(48,48,48,1);
+ background-color: rgba(18,28,36,1);
color: #fff;
height: 56px;
padding: 0 30px;
.flex_strict{
flex: 1;
}
+
.flex_normal{
color: #E51C24;
cursor: pointer;
@@ -25,21 +23,21 @@
.flex_strict,
.flex_normal,
.code-icon{
- color: #888;
+ color: #666;
}
}
}
.setting_drawer{
- // .ant-drawer-body{
- // // height: calc(100vh - 120px);
- // // overflow-y: auto;
- // }
+ .ant-drawer-close{
+ color: #ffffff;
+ }
.ant-drawer-content{
top: 120px;
bottom: 56px;
height: calc(100vh - 176px);
- background: #333333;
+ // background: #333333;
+ background: rgba(7,15,25,1);
color: #fff;
.setting_h2{
color: #fff;
@@ -57,4 +55,17 @@
color: #fff;
}
}
+}
+
+.flex_has_save{
+ // animation: blink 3s line 3;
+ animation-name: blink;
+ animation-duration: .4s;
+ animation-iteration-count: 3;
+}
+
+@keyframes blink{
+ 50% {
+ color: #fff;
+ }
}
\ No newline at end of file
diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
index bc905fdf7..1c451c669 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -13,11 +13,11 @@ import { Button, Modal } from 'antd';
import LeftPane from './leftpane';
import RightPane from './rightpane';
import { withRouter } from 'react-router';
-import { toStore } from 'educoder';
+import { toStore, CNotificationHOC } from 'educoder';
import UserInfo from '../components/userInfo';
// import RightPane from './rightpane/index';
import actions from '../../../redux/actions';
-import {ModalConfirm} from '../../../common/components/ModalConfirm';
+// import {ModalConfirm} from '../../../common/components/ModalConfirm';
const NewOrEditTask = (props) => {
const {
@@ -69,10 +69,13 @@ const NewOrEditTask = (props) => {
// 模拟挑战
const imitationChallenge = () => {
+ // 调用 start 接口, 成功后跳转到模拟页面
+ startProgramQuestion(identifier, props);
}
// 开始挑战
const startChallenge = () => {
- // 调用 start 接口, 成功后跳转到模拟页面
+ // 调用 start 接口, 成功后跳转到开启实战
+ // TODO
startProgramQuestion(identifier, props);
}
@@ -82,27 +85,38 @@ const NewOrEditTask = (props) => {
props.clearOJFormStore();
// 清空描述信息
toStore('oj_description', '');
- setInterval(function () {
- props.history.push('/problems');
- }, 500);
+ props.history.push('/problems');
}
// 发布
const handleClickPublish = () => {
- ModalConfirm('提示', (发布后即可应用到自己管理的课堂
是否确认发布?
), () => {
- changePublishLoadingStatus(true);
- handlePublish(props, 'publish');
+ // ModalConfirm('提示', (发布后即可应用到自己管理的课堂
是否确认发布?
), () => {
+ // changePublishLoadingStatus(true);
+ // handlePublish(props, 'publish');
+ // });
+ props.confirm({
+ title: '提示',
+ content: (发布后即可应用到自己管理的课堂
是否确认发布?
),
+ onOk () {
+ changePublishLoadingStatus(true);
+ handlePublish(props, 'publish');
+ }
});
-
-
}
// 撤销发布
const handleClickCancelPublish = () => {
- ModalConfirm('提示', (是否确认撤销发布?
), () => {
- changePublishLoadingStatus(true);
- handleCancelPublish(props, identifier);
+ // ModalConfirm('提示', (是否确认撤销发布?
), () => {
+ // changePublishLoadingStatus(true);
+ // handleCancelPublish(props, identifier);
+ // });
+ props.confirm({
+ title: '提示',
+ content: ((是否确认撤销发布?
)),
+ onOk () {
+ changePublishLoadingStatus(true);
+ handleCancelPublish(props, identifier);
+ }
});
-
}
// 取消保存/取消按钮
@@ -125,6 +139,7 @@ const NewOrEditTask = (props) => {
const renderPubOrFight = () => {
const pubButton = isPublish
? (
- {/*
-
-
-
-
*/}
);
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/index.scss b/public/react/src/modules/developer/studentStudy/leftpane/index.scss
index 9e6f019f6..1582c033f 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/index.scss
+++ b/public/react/src/modules/developer/studentStudy/leftpane/index.scss
@@ -13,6 +13,8 @@
bottom: 0px;
height: 56px;
width: 100%;
+ box-sizing: border-box;
+ border-top: 1px solid rgba(244,244,244,1);
// background: pink;
padding: 0 30px;
// background-color: rgba(250,250,250,1);
@@ -79,4 +81,9 @@
margin-right: 5px;
}
}
+}
+
+.add_editor_list_area{
+ box-sizing: border-box;
+ border-bottom: 1px solid rgba(244,244,244,1);
}
\ No newline at end of file
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js b/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js
index 28fe51765..981770b8c 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js
+++ b/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js
@@ -4,14 +4,15 @@
* @Github:
* @Date: 2019-11-27 09:49:30
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-09 19:21:55
+ * @LastEditTime: 2019-12-19 09:22:52
*/
import '../index.scss';
import React from 'react';
import { Tag } from 'antd';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
-import QuillEditor from '../../../quillEditor';
+import QuillForEditor from '../../../../../common/quillForEditor';
+
import CONST from '../../../../../constants';
const {tagBackground, diffText} = CONST;
@@ -36,22 +37,15 @@ const TaskDescription = (props) => {
出题者:
- {username}
+ {username}
-
- {/*
*/}
- {/*
*/}
)
}
diff --git a/public/react/src/modules/developer/studentStudy/rightpane/index.js b/public/react/src/modules/developer/studentStudy/rightpane/index.js
index 669a8a693..5661ea32e 100644
--- a/public/react/src/modules/developer/studentStudy/rightpane/index.js
+++ b/public/react/src/modules/developer/studentStudy/rightpane/index.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 14:59:51
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 16:50:40
+ * @LastEditTime: 2019-12-19 15:06:49
*/
import React, { useState, useEffect } from 'react';
import {connect} from 'react-redux';
@@ -20,8 +20,11 @@ const RightPane = (props) => {
submitUserCode,
input,
hack,
+ notice,
updateCode,
+ hadCodeUpdate,
editor_code,
+ updateNotice,
saveUserInputCode,
restoreInitialCode,
saveUserCodeForInterval
@@ -48,7 +51,8 @@ const RightPane = (props) => {
// 代码块内容变化时
const handleCodeChange = (code) => {
// 保存用户提交的代码块
- console.log(code);
+ // console.log(code);
+ setEditorCode(code);
if (!timer) {
timer = setInterval(() => {
clearInterval(timer);
@@ -69,13 +73,21 @@ const RightPane = (props) => {
restoreInitialCode(identifier, '恢复初始代码成功');
}
+ // 更新代码
+ const handleUpdateNotice = () => {
+ updateNotice && updateNotice();
+ };
+
return (
{
const mapStateToProps = (state) => {
- const {user_program_identifier, hack, userTestInput, editor_code} = state.ojForUserReducer;
+ const {
+ user_program_identifier,
+ hack,
+ userTestInput,
+ editor_code,
+ notice,
+ hadCodeUpdate
+ } = state.ojForUserReducer;
// const { language, code } = hack;
return {
hack,
+ notice,
+ hadCodeUpdate,
editor_code,
input: userTestInput,
submitInput: hack.input,
diff --git a/public/react/src/redux/actions/actionTypes.js b/public/react/src/redux/actions/actionTypes.js
index 0f33b435c..c872486e2 100644
--- a/public/react/src/redux/actions/actionTypes.js
+++ b/public/react/src/redux/actions/actionTypes.js
@@ -22,7 +22,8 @@ const types = {
SAVE_OJ_FORM: 'SAVE_OJ_FORM', // 保存表单
ADD_TEST_CASE: 'ADD_TEST_CASE', // 添加测试用例
DELETE_TEST_CASE: 'DELETE_TEST_CASE', // 删除测试用例
- SAVE_TEST_CASE: '保存测试用例', // 保存测试用例
+ SAVE_TEST_CASE: 'SAVE_TEST_CASE', // 保存测试用例
+ SAVE_USE_TEST_CASE_VALUE: 'SAVE_USE_TEST_CASE_VALUE', // 用户自定义测试用例值
CLEAR_JSFORM_STORE: 'CLEAR_JSFORM_STORE', // 清空测试用例
SAVE_EDIT_OJ_FORM_AND_TEST_CASE: 'SAVE_EDIT_OJ_FORM_AND_TEST_CASE', // 保存根据id获取的表单及测试用例值
TEST_CODE_STATUS: 'TEST_CODE_STATUS', // 代码调试状态
@@ -50,6 +51,8 @@ const types = {
SAVE_USER_INFO: 'SAVE_USER_INFO', // 只在用户信息
SAVE_HACK_IDENTIFIER: 'SAVE_HACK_IDENTIFIER', // 用户界面跑到编辑界面需要用的id值
SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码
+ SAVE_NOTICE_COUNT: 'SAVE_NOTICE_COUNT', // 保存代码块是否更新
+ AUTO_UPDATE_CODE: 'AUTO_UPDATE_CODE', // 自动更新代码
}
export default types;
diff --git a/public/react/src/redux/actions/ojForUser.js b/public/react/src/redux/actions/ojForUser.js
index 79e2045d6..9cb814d80 100644
--- a/public/react/src/redux/actions/ojForUser.js
+++ b/public/react/src/redux/actions/ojForUser.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 13:42:11
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 16:49:42
+ * @LastEditTime: 2019-12-19 15:11:56
*/
import types from "./actionTypes";
import { Base64 } from 'js-base64';
@@ -82,6 +82,20 @@ export const getUserProgramDetail = (identifier, type) => {
payload: data
});
}
+ // 保存默认测试用例
+ dispatch({
+ type: types.SAVE_USE_TEST_CASE_VALUE,
+ payload: data.test_case || {}
+ });
+ // 代码是否更新
+ let _modify_code = false;
+ if (data.hack) {
+ _modify_code = data.hack.modify_code;
+ }
+ dispatch({
+ type: types.SAVE_NOTICE_COUNT,
+ payload: _modify_code
+ })
// 保存用户登录信息
dispatch({
type: types.SAVE_USER_INFO,
@@ -94,13 +108,29 @@ export const getUserProgramDetail = (identifier, type) => {
export const saveUserCodeForInterval = (identifier, code) => {
return (dispatch) => {
+ dispatch({
+ type: types.AUTO_UPDATE_CODE,
+ payload: true
+ });
fetchUpdateCode(identifier, {
code: Base64.encode(code)
}).then(res => {
if (res.data.status === 401) {
return;
};
+
+ setTimeout(() => {
+ dispatch({
+ type: types.AUTO_UPDATE_CODE,
+ payload: false
+ })
+ }, 1000);
console.log('代码保存成功', res);
+ }).catch(() => {
+ dispatch({
+ type: types.AUTO_UPDATE_CODE,
+ payload: false
+ })
});
}
}
@@ -259,7 +289,11 @@ export const debuggerCode = (identifier,value, type) => {
}).catch(() => {
dispatch({
type: types.TEST_CODE_STATUS,
- payload: ''
+ payload: 'error'
+ });
+ dispatch({
+ type: types.LOADING_STATUS,
+ payload: false
});
dispatch({
type: types.SUBMIT_LOADING_STATUS,
@@ -400,6 +434,10 @@ export const restoreInitialCode = (identifier, msg) => {
message: '提示',
description: msg
});
+ dispatch({
+ type: types.SAVE_NOTICE_COUNT,
+ payload: false
+ });
}
});
}
@@ -412,3 +450,6 @@ export const saveEditorCodeForDetail = (code) => {
payload: code
}
}
+
+// 更新通知状态
+
diff --git a/public/react/src/redux/actions/ojForm.js b/public/react/src/redux/actions/ojForm.js
index 3eaac9023..740bad895 100644
--- a/public/react/src/redux/actions/ojForm.js
+++ b/public/react/src/redux/actions/ojForm.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 16:35:46
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 16:56:22
+ * @LastEditTime: 2019-12-19 17:20:48
*/
import types from './actionTypes';
import CONST from '../../constants';
@@ -15,7 +15,7 @@ import {
cancelPublicTask
} from '../../services/ojService';
import { Base64 } from 'js-base64';
-import { message, notification, Modal } from 'antd';
+import { notification } from 'antd';
import { toStore } from 'educoder';
const { jcLabel } = CONST;
// 表单字段映射
@@ -160,7 +160,7 @@ export const validateOjForm = (props, type) => {
if (testCases.length === 0) {
hasSuccess = false;
notification['error']({
- message: '必填',
+ message: '提示',
description: '测试用例必须输入!'
});
}
@@ -200,7 +200,7 @@ export const validateOjForm = (props, type) => {
let paramsObj = {};
const hack = { // 编程题干
name,
- description,
+ description: JSON.stringify(description),
difficult,
category,
'open_or_not': openOrNot,
@@ -449,9 +449,13 @@ export const testCaseInputChange = (value, index) => {
let validate = emptyValidate('input', value)['input'];
if (!validate.errMsg) {
// 唯一性校验
+ let _errMsg = '';
const {testCases} = getState().ojFormReducer;
const bool = testCases.some((item, i) => {
if (i !== index) {
+ if (item['input'] === value) {
+ _errMsg=`与测试用例${index}的输入值重复了,请重新填写`;
+ }
return item['input'] === value;
} else {
return false;
@@ -460,7 +464,7 @@ export const testCaseInputChange = (value, index) => {
if (bool) {
validate = {
validateStatus: 'error',
- errMsg: '输入值必须唯一'
+ errMsg: _errMsg
};
}
}
@@ -492,8 +496,12 @@ export const testCaseOutputChange = (value, index) => {
if (!validate.errMsg) {
// 唯一性校验
const {testCases} = getState().ojFormReducer;
+ let _errMsg = '';
const bool = testCases.some((item, i) => {
if (i !== index) {
+ if (item['output'] === value) {
+ _errMsg=`与测试用例${index}的输入值重复了,请重新填写`;
+ }
return item['output'] === value;
} else {
return false;
@@ -502,7 +510,7 @@ export const testCaseOutputChange = (value, index) => {
if (bool) {
validate = {
validateStatus: 'error',
- errMsg: '输入值必须唯一'
+ errMsg: _errMsg
};
}
}
diff --git a/public/react/src/redux/reducers/ojForUserReducer.js b/public/react/src/redux/reducers/ojForUserReducer.js
index 6520f8954..60e7e6fd1 100644
--- a/public/react/src/redux/reducers/ojForUserReducer.js
+++ b/public/react/src/redux/reducers/ojForUserReducer.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 13:41:48
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-10 10:09:59
+ * @LastEditTime: 2019-12-19 14:49:03
*/
import types from "../actions/actionTypes";
import { Base64 } from 'js-base64';
@@ -21,7 +21,9 @@ const initialState = {
userTestInput: '', // 用户自定义输入值
recordDetail: {}, // 根据id号获取的记录详情
hack_identifier: '', // 用户界面编辑时
- editor_code: '' // 保存编辑代码
+ editor_code: '', // 保存编辑代码
+ notice: false, // 通知
+ hadCodeUpdate: false, // 更新代码
};
const ojForUserReducer = (state = initialState, action) => {
@@ -36,7 +38,8 @@ const ojForUserReducer = (state = initialState, action) => {
const { hack, test_case } = action.payload;
const { code }= hack;
let tempCode = Base64.decode(code)
- Object.assign(hack, {code: tempCode});
+ let tempDesc = JSON.parse(hack.description);
+ Object.assign(hack, {code: tempCode, description: tempDesc});
return {
...state,
hack: Object.assign({}, hack),
@@ -121,6 +124,21 @@ const ojForUserReducer = (state = initialState, action) => {
...state,
editor_code: action.payload
}
+ case types.SAVE_USE_TEST_CASE_VALUE:
+ return {
+ ...state,
+ userTestInput: action.payload.input
+ }
+ case types.SAVE_NOTICE_COUNT:
+ return {
+ ...state,
+ notice: action.payload
+ };
+ case types.AUTO_UPDATE_CODE:
+ return {
+ ...state,
+ hadCodeUpdate: action.payload
+ };
default:
return state;
}
diff --git a/public/react/src/redux/reducers/ojFormReducer.js b/public/react/src/redux/reducers/ojFormReducer.js
index c2ba0f4d8..39af4a5f8 100644
--- a/public/react/src/redux/reducers/ojFormReducer.js
+++ b/public/react/src/redux/reducers/ojFormReducer.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-20 16:40:32
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 11:54:35
+ * @LastEditTime: 2019-12-17 16:19:04
*/
import { Base64 } from 'js-base64';
import types from '../actions/actionTypes';
@@ -176,7 +176,7 @@ const ojFormReducer = (state = initialState, action) => {
const currentOjForm = {
name, // 任务名称
language,
- description,
+ description: JSON.parse(description),
difficult,
category,
openOrNot: 1,
diff --git a/public/react/src/services/ojService.js b/public/react/src/services/ojService.js
index e13b66397..373805b73 100644
--- a/public/react/src/services/ojService.js
+++ b/public/react/src/services/ojService.js
@@ -4,10 +4,11 @@
* @Github:
* @Date: 2019-11-20 10:55:38
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 17:03:47
+ * @LastEditTime: 2019-12-17 14:10:37
*/
import axios from 'axios';
+import { func } from 'prop-types';
export async function fetchOJList (params) {
console.log('传递的参数: ', params);
@@ -125,3 +126,15 @@ export async function fetchUserInfoForNew () {
const url = `/problems/new.json`;
return axios.get(url);
}
+
+// 文件上传
+export async function fetchUploadImage (file) {
+ const url = `/attachments.json`;
+ return axios.post(url, file)
+}
+
+// 根据id号获取图片url
+export async function fetchUploadImageUrl (id) {
+ const url = `/attachments/${id}`;
+ return axios.get(url);
+}
From c69f06b746b1e41c577530df9d33357073210aed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com>
Date: Thu, 19 Dec 2019 18:24:30 +0800
Subject: [PATCH 20/61] =?UTF-8?q?=E6=96=B0=E7=89=88=E5=AD=A6=E9=99=A2?=
=?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/src/App.js | 10 +-
public/react/src/college/College.js | 1259 +++++++++++++++++
.../college/colleagechart/Colleagechart.js | 84 ++
.../college/colleagechart/Colleagechartzu.js | 149 ++
.../src/college/colleagecss/colleage.css | 213 +++
5 files changed, 1714 insertions(+), 1 deletion(-)
create mode 100644 public/react/src/college/College.js
create mode 100644 public/react/src/college/colleagechart/Colleagechart.js
create mode 100644 public/react/src/college/colleagechart/Colleagechartzu.js
create mode 100644 public/react/src/college/colleagecss/colleage.css
diff --git a/public/react/src/App.js b/public/react/src/App.js
index 4694d57da..03cad7110 100644
--- a/public/react/src/App.js
+++ b/public/react/src/App.js
@@ -71,6 +71,11 @@ const Otherlogin=Loadable({
loader: () => import('./modules/login/Otherlogin'),
loading: Loading,
})
+// 学院统计
+const College = Loadable({
+ loader: () => import('./college/College'),
+ loading: Loading
+})
const Otherloginstart=Loadable({
loader: () => import('./modules/login/Otherloginstart'),
@@ -614,7 +619,10 @@ class App extends Component {
{/*/>*/}
-
+ ()
+ }/>
{/* jupyter */}
(
+ {
+ record.name
+ }
+ )
+ },
+ {
+ title: '管理教师',
+ dataIndex: 'teachers',
+ key: 'teachers',
+ align: 'center',
+ className: "edu-txt-center font-14 maxnamewidth340",
+ render: (text, record) => (
+
+ {
+ record.teachers
+ }
+
+ )
+ },
+ {
+ title: '评测次数',
+ dataIndex: 'times',
+ key: 'times',
+ align: 'center',
+ className: "edu-txt-center font-14 maxnamewidth175",
+ render: (text, record) => (
+
+ {
+ record.evaluating_count
+ }
+
+ ),
+ },
+ {
+ title: '学生',
+ key: 'student',
+ dataIndex: 'student',
+ align: 'center',
+ className: "edu-txt-center font-14 maxnamewidth255",
+ render: (text, record) => (
+
+ {
+ record.student_count
+ }
+
+ )
+ },
+ {
+ title: '实训作业',
+ dataIndex: 'training',
+ key: 'training',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.shixun_work_count
+ }
+
+ )
+
+ },
+ {
+ title: '资源',
+ dataIndex: 'resources',
+ key: 'resources',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.attachment_count
+ }
+
+ ),
+ },
+ {
+ title: '帖子',
+ dataIndex: 'posts',
+ key: 'posts',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+ {
+ record.message_count
+ }
+ )
+ },
+ {
+ title: '其它任务',
+ dataIndex: 'othertasks',
+ key: 'othertasks',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.other_work_count
+ }
+
+ )
+ },
+ {
+ title: '状态',
+ dataIndex: 'states',
+ key: 'states',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.is_end?
+ "已结束"
+ :
+ "正在进行"
+ }
+
+ )
+ },
+ {
+ title: '时间',
+ dataIndex: 'timemy',
+ key: 'timemy',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.activity_time
+ }
+
+ )
+ },
+ ],
+ page:1,
+ limit:10,
+ total_users:50,
+ teachersloading:false,
+ teacherranking:[
+ {
+ title: '排名',
+ dataIndex: 'ranking',
+ key: 'ranking',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.id
+ }
+
+ )
+ },
+ {
+ title: '姓名',
+ dataIndex: 'name',
+ key: 'name',
+ align: 'center',
+ className: "edu-txt-center font-14 maxnamewidth105",
+ render: (text, record) => (
+ {
+ record.name
+ }
+
+ )
+ },
+ {
+ title: '管理课堂',
+ dataIndex: 'classroom',
+ key: 'classroom',
+ align: 'center',
+ className: "edu-txt-center font-14 maxnamewidth175",
+ render: (text, record) => (
+
+ {
+ record.course_count
+ }
+
+ ),
+ },
+ {
+ title: '已发布实训作业',
+ key: 'assignment',
+ dataIndex: 'assignment',
+ align: 'center',
+ className: "edu-txt-center font-14 maxnamewidth255",
+ render: (text, record) => (
+
+ {
+ record.shixun_work_count
+ }
+
+ )
+ },
+ {
+ title: '未发布实训作业',
+ dataIndex: 'released',
+ key: 'released',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.un_shixun_work_count
+ }
+
+ )
+
+ },
+ {
+ title: '学生数',
+ dataIndex: 'studentnumber',
+ key: 'studentnumber',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.student_count
+ }
+
+ ),
+ },
+ {
+ title: '完成率',
+ dataIndex: 'completionrate',
+ key: 'completionrate',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.complete_rate+"%"
+ }
+
+ )
+ },
+ {
+ title: '发布实训',
+ dataIndex: 'releasetraining',
+ key: 'releasetraining',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.publish_shixun_count
+ }
+
+ )
+ }
+ ],
+ studentranking:[
+ {
+ title: '排名',
+ dataIndex: 'ranking',
+ key: 'ranking',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ width:'100px',
+ render: (text, record) => (
+
+ {
+ record.id===1?
+ :record.id===2?
+
+ :record.id===3?
+
+ :record.id
+ }
+
+ )
+ },
+ {
+ title: '姓名',
+ dataIndex: 'name',
+ key: 'name',
+ align: 'center',
+ className: "edu-txt-center font-14 maxnamewidth105",
+ width:'100px',
+ render: (text, record) => (
+ {
+ record.name
+ }
+
+ )
+ },
+ {
+ title: '学号',
+ dataIndex: 'studentid',
+ key: 'studentid',
+ align: 'center',
+ className: "edu-txt-center font-14 maxnamewidth175",
+ render: (text, record) => (
+
+ {
+ record.student_id
+ }
+
+ ),
+ },
+ {
+ title: '完成实训',
+ key: 'training',
+ dataIndex: 'training',
+ align: 'center',
+ className: "edu-txt-center font-14 maxnamewidth255",
+ render: (text, record) => (
+
+ {
+ record.shixun_count
+ }
+
+ )
+ },
+ {
+ title: '在学实训',
+ dataIndex: 'learning',
+ key: 'learning',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.study_shixun_count
+ }
+
+ )
+
+ },
+ {
+ title: '金币',
+ dataIndex: 'goldcoin',
+ key: 'goldcoin',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.grade
+ }
+
+ ),
+ },
+ {
+ title: '经验值',
+ dataIndex: 'empirical',
+ key: 'empirical',
+ align: 'center',
+ className: "edu-txt-center font-14",
+ render: (text, record) => (
+
+ {
+ record.experience
+ }
+
+ )
+ },
+ ],
+ school:"",
+ teachers_count:null,
+ students_count:null,
+ courses_count:null,
+ shixuns_count:null,
+ shixun_report_count:null,
+ shixun_time:null,
+ courses:null,
+ course_count:0,
+ pages:1,
+ limits:10,
+ teachers:null,
+ teacher_count:0,
+ students:null,
+ student_count:0,
+ shixun_chart_data:null,
+ shixun_chart_datanames:null,
+ studentionsnames:null,
+ studentionsvalues:null
+ }
+
+ }
+
+
+ componentDidMount(){
+ console.log("College");
+ console.log(this.props.match.params.id);
+ this.gettop();
+ this.Numberofinternshipreports();
+ this.Actualcombattimeoftrainees();
+ this.Classnumber(1,10);
+ this.Teacherranking(1,10);
+ this.Studentranking(1,10);
+ this.Onlinetraining();
+ this.Hottest();
+ }
+ //头部
+ gettop=()=>{
+ const id =this.props.match.params.id;
+ const url=`/colleges/${id}/statistics.json`;
+ axios.get(url).then((response) => {
+ if(response===null||response===undefined){
+ this.setState({
+ teachers_count:0,
+ students_count:0,
+ courses_count:0,
+ shixuns_count:0,
+ school:"",
+ })
+ return
+ }
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ teachers_count:0,
+ students_count:0,
+ courses_count:0,
+ shixuns_count:0,
+ school:"",
+ })
+ }else{
+ this.setState({
+ teachers_count:response.data.teachers_count,
+ students_count:response.data.students_count,
+ courses_count:response.data.courses_count,
+ shixuns_count:response.data.shixuns_count,
+ school:response.data.school,
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ this.setState({
+ teachers_count:0,
+ students_count:0,
+ courses_count:0,
+ shixuns_count:0,
+ school:"",
+ })
+ });
+ }
+
+ //获取实训报告数
+ Numberofinternshipreports=()=>{
+ const id =this.props.match.params.id;
+ const url=`/colleges/${id}/shixun_report_count.json`;
+ axios.get(url).then((response) => {
+ if(response===null||response===undefined){
+ this.setState({
+ shixun_report_count:0,
+ })
+ return
+ }
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ shixun_report_count:0,
+ })
+ }else{
+ if (response.data.status === -1){
+ this.setState({
+ shixun_report_count:0,
+ })
+ return
+ }
+ this.setState({
+ shixun_report_count:response.data.shixun_report_count,
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ this.setState({
+ shixun_report_count:0,
+ })
+ });
+ }
+
+ //学员实战时间
+ Actualcombattimeoftrainees=()=>{
+ const id =this.props.match.params.id;
+ const url=`/colleges/${id}/shixun_time.json`;
+ axios.get(url).then((response) => {
+ if(response===null||response===undefined){
+ this.setState({
+ shixun_time:0,
+ })
+ return
+ }
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ shixun_time:0,
+ })
+ }else{
+ if (response.data.status === -1){
+ this.setState({
+ shixun_time:0,
+ })
+ return
+ }
+ this.setState({
+ shixun_time:response.data.shixun_time,
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ this.setState({
+ shixun_time:0,
+ })
+ });
+ }
+
+ //课堂信息
+ Classnumber=(page,per_page)=>{
+ const id =this.props.match.params.id;
+ const url=`/colleges/${id}/course_statistics.json`;
+ this.setState({
+ coursesloading:true
+ })
+ axios.get(url,{params:{
+ page:page,
+ per_page:per_page,
+ }
+ }).then((response) => {
+ if(response===null||response===undefined){
+ this.setState({
+ courses:[],
+ course_count:0
+ })
+ return
+ }
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ courses:[],
+ course_count:0
+ })
+ }else{
+ if (response.data.status === -1){
+ this.setState({
+ courses:[],
+ course_count:0
+ })
+ return
+ }
+ this.setState({
+ courses:response.data.courses,
+ course_count:response.data.course_count,
+ page:page,
+ limit:per_page
+ })
+ }
+ this.setState({
+ coursesloading:false
+ })
+ }).catch((error) => {
+ this.setState({
+ courses:[],
+ course_count:0,
+ coursesloading:false
+ })
+ });
+ }
+
+ //教师排名
+ Teacherranking=(page,per_page)=>{
+ const id =this.props.match.params.id;
+ const url=`/colleges/${id}/teachers.json`;
+ this.setState({
+ teachersloading:true
+ })
+ axios.get(url,{params:{
+ page:page,
+ per_page:per_page,
+ }
+ }).then((response) => {
+ if(response===null||response===undefined){
+ this.setState({
+ teachers:[],
+ teacher_count:0
+ })
+ return
+ }
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ teachers:[],
+ teacher_count:0
+ })
+ }else{
+ if (response.data.status === -1){
+ this.setState({
+ teachers:[],
+ teacher_count:0
+ })
+ return
+ }
+ let teachers=[];
+ if(response.data.teachers){
+ for(let i=0;i {
+ this.setState({
+ teachers:[],
+ teacher_count:0,
+ teachersloading:false
+ })
+ });
+ }
+ //学生排名
+
+ Studentranking=(page,per_page)=>{
+ const id =this.props.match.params.id;
+ const url=`/colleges/${id}/student_shixun.json`;
+ this.setState({
+ studentsloading:true
+ })
+ axios.get(url,{params:{
+ page:page,
+ per_page:per_page,
+ }
+ }).then((response) => {
+ if(response===null||response===undefined){
+ this.setState({
+ students:[],
+ student_count:0,
+ })
+ return
+ }
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ students:[],
+ student_count:0,
+ })
+ }else{
+ if (response.data.status === -1){
+ this.setState({
+ students:[],
+ student_count:0,
+ })
+ return
+ }
+ let students=[];
+ if(response.data.teachers){
+ for(let i=0;i {
+ this.setState({
+ students:[],
+ student_count:0,
+ studentsloading:false
+ })
+ });
+ }
+
+ //在线实训情况
+ Onlinetraining=()=>{
+ const id =this.props.match.params.id;
+ const url=`/colleges/${id}/shixun_chart_data.json`;
+ axios.get(url).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ shixun_chart_data:[],
+ shixun_chart_datanames:[]
+ })
+ }else{
+ if (response.data.status === -1){
+ this.setState({
+ shixun_chart_data:[],
+ shixun_chart_datanames:[]
+ })
+ return
+ }
+
+ this.setState({
+ shixun_chart_data:response.data.data,
+ shixun_chart_datanames:response.data.names
+ })
+ }
+ }).catch((error) => {
+ this.setState({
+ shixun_chart_data:[],
+ shixun_chart_datanames:[]
+ })
+ });
+ }
+ //最热测评
+ Hottest=()=>{
+ const id =this.props.match.params.id;
+ const url=`/colleges/${id}/student_hot_evaluations.json`;
+ axios.get(url).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ studentionsnames: [],
+ studentionsvalues: []
+ })
+ }else {
+ if (response.data.status === -1) {
+ this.setState({
+ studentionsnames: [],
+ studentionsvalues: []
+ })
+ return
+ }
+ this.setState({
+ studentionsnames: response.data.names,
+ studentionsvalues: response.data.values
+ })
+ }
+ }).catch((error) => {
+ this.setState({
+ studentionsnames: [],
+ studentionsvalues: []
+ })
+ });
+ }
+
+ table1handleChange(){
+
+ }
+
+ //塞选
+ paginationonChange=(pageNumber)=>{
+ this.Classnumber(pageNumber,10);
+ }
+
+ paginationonChanges=(pageNumber)=>{
+ this.Teacherranking(pageNumber,10);
+ }
+ paginationonChangess=(pageNumber)=>{
+ this.Studentranking(pageNumber,10);
+ }
+ render() {
+ let {columns,page,limit,total_users,teacherranking,studentranking,
+ teachers_count,students_count, courses_count, shixuns_count,shixun_report_count,shixun_time,courses,course_count,school,teachers,
+ pages,limits, teacher_count,teachersloading,coursesloading,pagess,limitss,studentsloading,students,student_count,shixun_chart_data,
+ shixun_chart_datanames, studentionsnames,studentionsvalues
+ } = this.state;
+
+ return (
+
+
+
+
{school}
+
+
+ {/*//教师1*/}
+
+ 教师
+
+
+ {teachers_count?teachers_count:0}
+
+
+
+
+
+ 学生
+
+
+ {students_count?students_count:0}
+
+
+
+
+
+ 课堂
+
+
+ {courses_count?courses_count:0}
+
+
+
+
+
+ 共建实训
+
+
+ {shixuns_count?shixuns_count:0}
+
+
+ {/*//教师2*/}
+
+
+
+
+
+
+
+
+
+ 基本使用情况
+
+ {/*基本使用情况1*/}
+
+
+ 教师
+
+
+ 学生
+
+
+ 课堂
+
+
+ 共建实训
+
+
+ 实习报告
+
+
+ 学员实战时间
+
+
+
+
+ {/*基本使用情况2*/}
+
+
+ {
+ teachers_count?
+
{teachers_count}人
+ :
+
+ }
+
+
+ {
+ students_count?
+
{students_count}人
+ :
+
+ }
+
+
+ {
+ courses_count?
+
{courses_count}个
+ :
+
+ }
+
+
+ {
+ shixuns_count?
+
{shixuns_count}个
+ :
+
+ }
+
+
+ {
+ shixun_report_count?
+
{shixun_report_count}个
+ :
+
+ }
+
+
+ {
+ shixun_time?
+
{shixun_time}天
+ :
+
+ }
+
+
+ {/*基本使用情况3结束*/}
+
+
+
+
+
+ 课堂
+
+ {
+ courses===null?
+
+
+
+
+ :
+ JSON.stringify(courses) === "[]" ?
+
+
+
+ :
+
+
+
+
+ {courses === undefined ? "" :
}
+
+
+ {
+ course_count>=11?
+
+ :""
+ }
+
+
+ }
+
+
+
+
+
+
+
+
+ 教师排名
+
+ {
+ teachers===null?
+
+
+
+
+ :
+ JSON.stringify(teachers) === "[]" ?
+
+
+
+ :
+
+
+
+ {teachers === undefined ? "" :
}
+
+
+ }
+
+
+
+ {/*
*/}
+
+
+
+
+ 在线实训情况
+
+ {
+ shixun_chart_data===null?
+
+
+
+
+ :
+ JSON.stringify(shixun_chart_data) === "[]" ?
+
+
+
+ :
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+ 学生排名
+
+ {
+ students === null ?
+
+
+
+
+ :
+ JSON.stringify(students) === "[]" ?
+
+
+
+ :
+
+
+
+ {students === undefined ? "" :
}
+
+
+ }
+ {/*
*/}
+
+
+
+
+
+
+
+
+ 最热评测
+
+ {
+ studentionsnames===null?
+
+
+
+
+ :
+ JSON.stringify(studentionsnames) === "[]" ?
+
+
+
+ :
+
+
+
+ }
+
+
+
+
+
+
+ )
+ }
+}
+export default SnackbarHOC() (TPMIndexHOC ( College ));
+
+
diff --git a/public/react/src/college/colleagechart/Colleagechart.js b/public/react/src/college/colleagechart/Colleagechart.js
new file mode 100644
index 000000000..fca01280a
--- /dev/null
+++ b/public/react/src/college/colleagechart/Colleagechart.js
@@ -0,0 +1,84 @@
+import React, {Component} from "react";
+import {WordsBtn} from 'educoder';
+import {Table} from "antd";
+import {Link,Switch,Route,Redirect} from 'react-router-dom';
+const echarts = require('echarts');
+
+
+
+function startechart(data,datanane){
+ var effChart = echarts.init(document.getElementById('shixun_skill_chart'));
+
+ var option = {
+
+ tooltip : {
+ trigger: 'item',
+ formatter: "{d}%
"
+ },
+ legend: {
+ // orient: 'vertical',
+ // top: 'middle',
+ bottom: 50,
+ left: 'center',
+ data: datanane
+ },
+ series : [
+ {
+ type: 'pie',
+ radius : '65%',
+ center: ['50%', '35%'],
+ selectedMode: 'single',
+ data:data,
+ itemStyle: {
+ emphasis: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: 'rgba(0, 0, 0, 0.5)'
+ }
+ }
+ }
+ ]
+ };
+ effChart.setOption(option);
+}
+class Colleagechart extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ }
+ }
+
+ componentDidMount() {
+ startechart(this.props.data,this.props.datanane)
+ }
+
+
+ componentDidUpdate = (prevProps) => {
+ if (prevProps.data!= this.props.data) {
+ startechart(this.props.data,this.props.datanane)
+ }
+ }
+
+
+ render() {
+ let {data}=this.props;
+
+ return (
+
+
+ )
+ }
+}
+
+export default Colleagechart;
diff --git a/public/react/src/college/colleagechart/Colleagechartzu.js b/public/react/src/college/colleagechart/Colleagechartzu.js
new file mode 100644
index 000000000..5c0269700
--- /dev/null
+++ b/public/react/src/college/colleagechart/Colleagechartzu.js
@@ -0,0 +1,149 @@
+import React, {Component} from "react";
+import {WordsBtn} from 'educoder';
+import {Table} from "antd";
+import {Link,Switch,Route,Redirect} from 'react-router-dom';
+const echarts = require('echarts');
+
+
+
+function startechart(names, values){
+ var effChart = echarts.init(document.getElementById('shixun_skill_charts'));
+
+ var Color = ['#962e66', '#623363', '#CCCCCC', '#9A9A9A', '#FF8080', '#FF80C2', '#B980FF', '#80B9FF', '#6FE9FF', '#4DE8B4', '#F8EF63', '#FFB967'];
+
+ var option = {
+ backgroundColor: '#fff',
+ grid: {
+ left: '3%',
+ right: '8%',
+ bottom: '15%',
+ containLabel: true
+ },
+
+ tooltip: {
+ show: "true",
+ trigger: 'item',
+ formatter: '{c0}',
+ backgroundColor: 'rgba(0,0,0,0.7)', // 背景
+ padding: [8, 10], //内边距
+ extraCssText: 'box-shadow: 0 0 3px rgba(255, 255, 255, 0.4);', //添加阴影
+ axisPointer: { // 坐标轴指示器,坐标轴触发有效
+ type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
+ }
+ },
+ xAxis: {
+ type: 'value',
+ axisTick: {
+ show: false
+ },
+ axisLine: {
+ show: true,
+ lineStyle: {
+ color: '#CCCCCC'
+ }
+ },
+ splitLine: {
+ show: false,
+ lineStyle: {
+ color: '#CCCCCC'
+ }
+ },
+ axisLabel: {
+ textStyle: {
+ color: '#656565',
+ fontWeight: 'normal',
+ fontSize: '12'
+ },
+ formatter: '{value}'
+ }
+ },
+ yAxis: {
+ type: 'category',
+ axisLine: {
+ lineStyle: {
+ color: '#cccccc'
+ }
+ },
+ splitLine: {
+ show: false
+ },
+ axisTick: {
+ show: false
+ },
+ splitArea: {
+ show: false
+ },
+ axisLabel: {
+ inside: false,
+ textStyle: {
+ color: '#656565',
+ fontWeight: 'normal',
+ fontSize: '12'
+ }
+ },
+ data: names
+ },
+ series: [{
+ name: '',
+ type: 'bar',
+ itemStyle: {
+ normal: {
+ show: true,
+ color: function(params) {
+ return Color[params.dataIndex]
+ },
+ barBorderRadius: 50,
+ borderWidth: 0,
+ borderColor: '#333'
+ }
+ },
+ barGap: '0%',
+ barCategoryGap: '50%',
+ data: values
+ }
+
+ ]
+ };
+ effChart.setOption(option);
+}
+class Colleagechartzu extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ }
+ }
+
+ componentDidMount() {
+ startechart(this.props.data,this.props.datavule)
+ }
+
+
+ componentDidUpdate = (prevProps) => {
+ if (prevProps.data!= this.props.data) {
+ startechart(this.props.data,this.props.datavule)
+ }
+ }
+
+
+ render() {
+ let {data}=this.props;
+
+ return (
+
+
+ )
+ }
+}
+
+export default Colleagechartzu;
diff --git a/public/react/src/college/colleagecss/colleage.css b/public/react/src/college/colleagecss/colleage.css
new file mode 100644
index 000000000..801b86603
--- /dev/null
+++ b/public/react/src/college/colleagecss/colleage.css
@@ -0,0 +1,213 @@
+.yslstatistic-header {
+ width: 100%;
+ height: 240px;
+ background-image: url('/images/educoder/statistics.jpg');
+ background-size: 100% 100%;
+}
+.yslborder{
+ border: 1px solid;
+}
+.yslstatistic-header-title{
+ flex: 1;
+ display: flex;
+ align-items: center;
+ color: #4CACFF;
+ font-size: 32px;
+}
+.yslstatistic-header-content{
+ width: 100%;
+ display: flex;
+ justify-content: space-around;
+}
+.yslstatistic-header-item{
+ margin-bottom: 22px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ color: #fff;
+}
+.yslstatistic-header-item-label{
+ color: #989898;
+}
+
+.yslstatistic-base-item-label{
+ width: 217px;
+ text-align: center;
+ font-size: 16px;
+ height: 48px;
+ line-height: 48px;
+ color: #686868;
+ background: #F5F5F5;
+ border-top: 1px solid #EBEBEB;
+}
+.yslstatistic-base-item-labels{
+ width: 217px;
+ text-align: center;
+ height: 100px;
+ line-height: 100px;
+ background: #ffffff;
+ border-top: 1px solid #EBEBEB;
+ border-bottom: 1px solid #EBEBEB;
+}
+.yslstatistic-base-item-labelsp{
+ color: #000000;
+ font-size: 24px;
+}
+.yslstatistic-base-item-labelsspan{
+ color: #000000;
+ margin-left: 5px;
+ font-size: 16px;
+}
+.jibenshiyong100{
+ width: 100%;
+}
+
+.yslstatistic-header-item-content{
+ font-size: 24px;
+}
+/* 中间居中 */
+.intermediatecenter{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+/* 简单居中 */
+.intermediatecenterysls{
+ display: flex;
+ align-items: center;
+}
+.spacearound{
+ display: flex;
+ justify-content: space-around;
+
+}
+.spacebetween{
+ display: flex;
+ justify-content: space-between;
+}
+/* 头顶部居中 */
+.topcenter{
+ display: -webkit-flex;
+ flex-direction: column;
+ align-items: center;
+
+}
+
+
+/* x轴正方向排序 */
+/* 一 二 三 四 五 六 七 八 */
+.sortinxdirection{
+ display: flex;
+ flex-direction:row;
+}
+/* x轴反方向排序 */
+/* 八 七 六 五 四 三 二 一 */
+.xaxisreverseorder{
+ display: flex;
+ flex-direction:row-reverse;
+}
+/* 垂直布局 正方向*/
+/* 一
+ 二
+ 三
+ 四
+ 五
+ 六
+ 七
+ 八 */
+.verticallayout{
+ display: flex;
+ flex-direction:column;
+}
+/* 垂直布局 反方向*/
+.reversedirection{
+ display: flex;
+ flex-direction:column-reverse;
+}
+
+.h4{
+ font-size: 1.5rem;
+ font-weight: 500 !important;
+}
+.ysllinjibenshiyong{
+ font-weight: 500;
+ line-height: 1.2;
+ padding: 2rem 1.25rem;
+ border-bottom: unset;
+ background:#fff;
+}
+.linjibenshiyong{
+ font-weight: 500;
+ line-height: 1.2;
+ padding: 2rem 1.25rem;
+ border-bottom: unset;
+ background:#fff;
+ box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1);
+ border-radius:2px;
+}
+.yslslinjibenshiyong{
+ font-weight: 500;
+ line-height: 1.2;
+ border-bottom: unset;
+ box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1);
+ border-radius:2px;
+}
+.yinyin{
+ background: #fff;
+ box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1);
+ border-radius:2px;
+}
+.edu-back-eeee{
+ background:#EEEEEE !important;
+}
+.mt-4{
+ margin-top: 1.5rem !important;
+}
+
+.statistic-label{
+ padding: 2rem 1.25rem;
+ font-size: 1.5rem;
+ font-weight: 400 !important;
+}
+.mb50{
+ padding-bottom: 50px !important;
+}
+.mt40{
+ margin-top: 40px;
+}
+.mb80{
+ margin-bottom: 80px;
+}
+.task-hide{overflow:hidden; white-space: nowrap; text-overflow:ellipsis;}
+a:hover{
+ color:#0056b3;
+}
+.color-blue{
+ color: #4CACFF;
+}
+
+.color-huang{
+ color:#ffc107 !important
+}
+.maxnamewidth105{
+ max-width: 105px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+.maxnamewidth247{
+ max-width: 247px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+.maxnamewidth340{
+ max-width: 340px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
From 893c4840f77c29288819cd6f2e5ed51ec9f8525b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Thu, 19 Dec 2019 18:55:19 +0800
Subject: [PATCH 21/61] =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/src/modules/tpm/TPMBanner.js | 16 ++++++----------
public/react/src/modules/tpm/TPMIndex.js | 8 +-------
2 files changed, 7 insertions(+), 17 deletions(-)
diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js
index 141bd87d9..77b82c6c6 100644
--- a/public/react/src/modules/tpm/TPMBanner.js
+++ b/public/react/src/modules/tpm/TPMBanner.js
@@ -58,15 +58,6 @@ class TPMBanner extends Component {
}
}
- // star_info:[0, 0, 0, 0, 0, 0],
- // star_infos:[0, 0, 0, 0, 0, 0],
- // shixunsDetails:{},
- // shixunId: undefined,
- // componentWillReceiveProps(newProps, newContext){
- // this.setState({
- // shixunsDetails: newProps.shixunsDetails
- // });
- // }
IEVersion = () => {
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
@@ -141,8 +132,11 @@ class TPMBanner extends Component {
})
}
}
+
}
}
+
+
componentDidMount() {
let thiisie = this.IEVersion();
@@ -155,6 +149,7 @@ class TPMBanner extends Component {
isIE: false
})
}
+
}
/*
@@ -784,7 +779,8 @@ class TPMBanner extends Component {
};
//
// console.log(this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter)
-
+ console.log(this.props)
+ console.log(this.state)
return (
shixunsDetails === undefined ? "" :
diff --git a/public/react/src/modules/tpm/TPMIndex.js b/public/react/src/modules/tpm/TPMIndex.js
index e032bb91f..c44d8ce51 100644
--- a/public/react/src/modules/tpm/TPMIndex.js
+++ b/public/react/src/modules/tpm/TPMIndex.js
@@ -207,6 +207,7 @@ class TPMIndex extends Component {
propaedeutics:response.data.propaedeutics,
status: response.data.shixun_status,
secret_repository: response.data.secret_repository,
+ public:response.data.public,
is_jupyter:response.data.is_jupyter=== undefined||response.data.is_jupyter===null?false:response.data.is_jupyter,
});
@@ -295,10 +296,6 @@ class TPMIndex extends Component {
// this.getnavdatas()
}
- // componentDidUpdate=()=>{
- // this.getnavdatas()
- // }
-
setLoadingContent = (isLoadingContent) => {
this.setState({ loadingContent: isLoadingContent })
}
@@ -307,9 +304,6 @@ class TPMIndex extends Component {
getnavdatas=()=>{
let selectedKeys;
const {location} = this.props;
-
- console.log(location.pathname)
-
if(location.pathname.indexOf('/challenges')!=-1){
selectedKeys="1"
}else if(location.pathname.indexOf('/propaedeutics')!=-1){
From 8fb90e6e20dca4f7d4176d5202c4f564045c2a6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Thu, 19 Dec 2019 18:56:56 +0800
Subject: [PATCH 22/61] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/src/App.js | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/public/react/src/App.js b/public/react/src/App.js
index 07c68e5e0..07fd13e49 100644
--- a/public/react/src/App.js
+++ b/public/react/src/App.js
@@ -71,11 +71,7 @@ const Otherlogin=Loadable({
loader: () => import('./modules/login/Otherlogin'),
loading: Loading,
})
-// 学院统计
-const College = Loadable({
- loader: () => import('./college/College'),
- loading: Loading
-})
+
const Otherloginstart=Loadable({
loader: () => import('./modules/login/Otherloginstart'),
From ae415cf38249725235db370da0eb3d593ad1d7ce Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Thu, 19 Dec 2019 19:29:54 +0800
Subject: [PATCH 23/61] 1
---
app/controllers/hacks_controller.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb
index cab952a04..dbddd9105 100644
--- a/app/controllers/hacks_controller.rb
+++ b/app/controllers/hacks_controller.rb
@@ -12,6 +12,7 @@ class HacksController < ApplicationController
user_hack = @hack.hack_user_lastest_codes.mine(current_user.id)
identifier =
if user_hack.present?
+ logger.info("#####user_hack_id:#{user_hack.id}")
user_hack.identifier
else
user_identifier = generate_identifier HackUserLastestCode, 12
From 992045a5cffc9571f7d311d2b86cd56cd2ef607c Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Thu, 19 Dec 2019 19:34:54 +0800
Subject: [PATCH 24/61] 1
---
app/models/hack_user_lastest_code.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/models/hack_user_lastest_code.rb b/app/models/hack_user_lastest_code.rb
index b4a707603..830f16dde 100644
--- a/app/models/hack_user_lastest_code.rb
+++ b/app/models/hack_user_lastest_code.rb
@@ -8,7 +8,7 @@ class HackUserLastestCode < ApplicationRecord
belongs_to :user
has_many :hack_user_codes, dependent: :destroy
has_one :hack_user_debug
- scope :mine, ->(author_id){ find_by(user_id: author_id) }
+ scope :mine, ->(author_id){ where(user_id: author_id).first }
scope :mine_hack, ->(author_id){ where(user_id: author_id) }
scope :passed, -> {where(status: 1)}
From 0074b6d183e5b3a293f341b9ad73196bf79e947e Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Thu, 19 Dec 2019 19:36:18 +0800
Subject: [PATCH 25/61] 1
---
app/controllers/hacks_controller.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb
index dbddd9105..a2ca85f34 100644
--- a/app/controllers/hacks_controller.rb
+++ b/app/controllers/hacks_controller.rb
@@ -10,6 +10,7 @@ class HacksController < ApplicationController
# 未发布的编程题,只能作者、或管理员访问
start_hack_auth
user_hack = @hack.hack_user_lastest_codes.mine(current_user.id)
+ logger.info("#user_hack: #{user_hack}")
identifier =
if user_hack.present?
logger.info("#####user_hack_id:#{user_hack.id}")
From a0deef9d09a42d4388a0ba8340e43b5bf2156603 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Thu, 19 Dec 2019 19:38:05 +0800
Subject: [PATCH 26/61] 1
---
app/controllers/hacks_controller.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb
index a2ca85f34..b7f6a30a2 100644
--- a/app/controllers/hacks_controller.rb
+++ b/app/controllers/hacks_controller.rb
@@ -9,7 +9,7 @@ class HacksController < ApplicationController
def start
# 未发布的编程题,只能作者、或管理员访问
start_hack_auth
- user_hack = @hack.hack_user_lastest_codes.mine(current_user.id)
+ user_hack = @hack.hack_user_lastest_codes.where(user_id: current_user.id).first
logger.info("#user_hack: #{user_hack}")
identifier =
if user_hack.present?
From b7db555654fa0f7122c23e950c4396ca0e90cac8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Thu, 19 Dec 2019 20:08:59 +0800
Subject: [PATCH 27/61] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../tpm/shixunchild/Challenges/Challenges.js | 23 +++++++++--
.../Challenges/Challengesjupyter.js | 39 ++++++++++++++-----
.../Collaborators/Collaborators.js | 2 +-
3 files changed, 50 insertions(+), 14 deletions(-)
diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js
index e7b7ef261..0480c208a 100644
--- a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js
+++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js
@@ -53,6 +53,13 @@ class Challenges extends Component {
ChallengesDataList: response.data,
sumidtype: false,
});
+
+ if(response.data.description=== ""||response.data.description===null||response.data.description===undefined){
+ this.setState({
+ isopentitletype:"Less",
+ })
+ }
+
}
}
}).catch((error) => {
@@ -72,7 +79,7 @@ class Challenges extends Component {
let box=document.getElementById("shixunchallengesid");
if(box){
boxoffsetHeigh=box.offsetHeight
- if(boxoffsetHeigh<260){
+ if(boxoffsetHeigh<300){
this.setState({
isopentitletype:"Less",
boxoffsetHeigh:boxoffsetHeigh
@@ -338,6 +345,7 @@ class Challenges extends Component {
}
let id = this.props.match.params.shixunId;
const antIcon = ;
+
return (
{AccountProfiletype===true?
-
+ {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined?
+
+ {this.props.identity < 5?
![]({getImageUrl("images/educoder/shixunnodata.png")})
:
![]({getImageUrl("images/educoder/nodata.png")})
}
+
暂时还没有相关数据哦!
+
+ :
{ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":
}
-
+ }
diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js
index fcdbed408..c8cbc2fbc 100644
--- a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js
+++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js
@@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { Link } from "react-router-dom";
-import { markdownToHTML, configShareForCustom} from 'educoder'
+import { markdownToHTML, configShareForCustom,getImageUrl} from 'educoder'
import { Divider, Tooltip } from 'antd';
import LoadingSpin from '../../../../common/LoadingSpin';
import 'antd/lib/pagination/style/index.css';
@@ -23,7 +23,8 @@ class Challengesjupyter extends Component {
booljupyterurls:false,
loading:false,
boxoffsetHeigh:0,
- opentitletype:true
+ opentitletype:true,
+ isopentitletype:"Less",
}
}
@@ -41,6 +42,11 @@ class Challengesjupyter extends Component {
ChallengesDataList: response.data,
sumidtype: false,
});
+ if(response.data.description=== ""||response.data.description===null||response.data.description===undefined){
+ this.setState({
+ isopentitletype:"Less",
+ })
+ }
}
}
}).catch((error) => {
@@ -55,13 +61,15 @@ class Challengesjupyter extends Component {
let box=document.getElementById("shixunchallengesid");
if(box){
boxoffsetHeigh=box.offsetHeight
- if(boxoffsetHeigh<260){
+ if(boxoffsetHeigh<300){
this.setState({
- opentitletype:false,
+ isopentitletype:"Less",
boxoffsetHeigh:boxoffsetHeigh
})
}else{
this.setState({
+ isopentitletype:"greater",
+ opentitletype:true,
boxoffsetHeigh:boxoffsetHeigh
})
}
@@ -229,7 +237,7 @@ class Challengesjupyter extends Component {
{
`
#shixunchallengesid{
- max-height: 260px;
+ max-height: 300px;
overflow: hidden;
}
`
@@ -239,9 +247,22 @@ class Challengesjupyter extends Component {
- {ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":
-
- }
+ {/*{ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":*/}
+ {/*
*/}
+ {/*}*/}
+
+ {ChallengesDataList === undefined || ChallengesDataList&&ChallengesDataList.description=== ""||ChallengesDataList&&ChallengesDataList.description===null||ChallengesDataList&&ChallengesDataList.description===undefined?
+
+ {this.props.identity < 5?
![]({getImageUrl("images/educoder/shixunnodata.png")})
:
![]({getImageUrl("images/educoder/nodata.png")})
}
+
暂时还没有相关数据哦!
+
+ :
+ {ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":
+
+ }
+ }
{
booljupyterurls===true?
@@ -259,7 +280,7 @@ class Challengesjupyter extends Component {
}
- {this.state.opentitletype===true?
this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}>
+ {this.state.isopentitletype==="Less"?"":this.state.opentitletype===true?this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}>
阅读全文
:this.opentitle()} className={"pointer Breadcrumbfont color-grey-9 "}>
收起全文
diff --git a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js
index 17b083cf7..9799d060c 100644
--- a/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js
+++ b/public/react/src/modules/tpm/shixunchild/Collaborators/Collaborators.js
@@ -656,7 +656,7 @@ class Collaborators extends Component {
-
{item.user.shixun_manager === true ? "创建者" : ""}
From e6a0239c2970eb3c31c830ed0de4bbe14aa84a0c Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Thu, 19 Dec 2019 20:11:12 +0800
Subject: [PATCH 28/61] update oj
---
.../components/controlSetting/index.js | 20 ++++++++++++-------
.../components/monacoSetting/index.js | 4 ++--
.../components/myMonacoEditor/index.js | 4 ++--
.../newOrEditTask/rightpane/index.scss | 3 ++-
.../modules/developer/studentStudy/index.js | 9 +++++++--
.../developer/studentStudy/rightpane/index.js | 9 +++++++--
public/react/src/redux/actions/common.js | 4 ++--
public/react/src/redux/actions/index.js | 4 ++--
.../src/redux/reducers/ojForUserReducer.js | 9 +++++++--
9 files changed, 44 insertions(+), 22 deletions(-)
diff --git a/public/react/src/modules/developer/components/controlSetting/index.js b/public/react/src/modules/developer/components/controlSetting/index.js
index b5c9222ef..1d4d7834c 100644
--- a/public/react/src/modules/developer/components/controlSetting/index.js
+++ b/public/react/src/modules/developer/components/controlSetting/index.js
@@ -4,10 +4,10 @@
* @Github:
* @Date: 2019-11-27 16:02:36
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-19 10:47:44
+ * @LastEditTime: 2019-12-19 19:47:32
*/
import './index.scss';
-import React, { useState, useRef } from 'react';
+import React, { useState, useRef, useEffect } from 'react';
import { Tabs, Button, Icon } from 'antd';
import { connect } from 'react-redux';
import InitTabCtx from '../initTabCtx';
@@ -23,10 +23,11 @@ const ControlSetting = (props) => {
submitLoading,
identifier,
excuteState,
+ showOrHideControl,
commitRecordDetail,
changeLoadingState,
changeSubmitLoadingStatus,
- showOrHideControl,
+ changeShowOrHideControl,
// debuggerCode,
// startDebuggerCode, // 外部存入
onDebuggerCode,
@@ -44,10 +45,14 @@ const ControlSetting = (props) => {
setDefaultActiveKey(key);
}
+ useEffect(() => {
+ setShowTextResult(props.showOrHideControl);
+ }, [props]);
+
// 显示/隐藏tab
const handleShowControl = () => {
setShowTextResult(!showTextResult);
- showOrHideControl(!showTextResult);
+ changeShowOrHideControl(!showTextResult);
}
// 调试代码
@@ -55,7 +60,7 @@ const ControlSetting = (props) => {
// console.log(formRef.current.handleTestCodeFormSubmit);
// 调出控制台界面
setShowTextResult(true);
- showOrHideControl(true);
+ changeShowOrHideControl(true);
formRef.current.handleTestCodeFormSubmit(() => {
setDefaultActiveKey('2');
});
@@ -131,19 +136,20 @@ const ControlSetting = (props) => {
const mapStateToProps = (state) => {
const {commonReducer, ojForUserReducer} = state;
- const {loading, excuteState, submitLoading } = commonReducer;
+ const {loading, excuteState, submitLoading, showOrHideControl } = commonReducer;
const { commitRecordDetail } = ojForUserReducer;
return {
loading,
submitLoading,
excuteState,
+ showOrHideControl,
// identifier: user_program_identifier,
commitRecordDetail // 提交详情
};
};
// changeSubmitLoadingStatus
const mapDispatchToProps = (dispatch) => ({
- showOrHideControl: (flag) => dispatch(actions.showOrHideControl(flag)),
+ changeShowOrHideControl: (flag) => dispatch(actions.changeShowOrHideControl(flag)),
changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag)),
changeSubmitLoadingStatus: (flag) => dispatch(actions.changeSubmitLoadingStatus(flag)),
debuggerCode: (identifier, values) => dispatch(actions.debuggerCode(identifier, values)),
diff --git a/public/react/src/modules/developer/components/monacoSetting/index.js b/public/react/src/modules/developer/components/monacoSetting/index.js
index c1215f9af..669439577 100644
--- a/public/react/src/modules/developer/components/monacoSetting/index.js
+++ b/public/react/src/modules/developer/components/monacoSetting/index.js
@@ -4,11 +4,11 @@
* @Github:
* @Date: 2019-11-25 17:50:33
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-19 15:26:46
+ * @LastEditTime: 2019-12-19 19:32:08
*/
import React, { useState } from 'react';
import { fromStore, toStore } from 'educoder';
-import { Icon } from 'antd';
+// import { Icon } from 'antd';
// import { Select } from 'antd';
// const { Option } = Select;
const SettingDrawer = (props) => {
diff --git a/public/react/src/modules/developer/components/myMonacoEditor/index.js b/public/react/src/modules/developer/components/myMonacoEditor/index.js
index df3c2b5e3..948d5a4f5 100644
--- a/public/react/src/modules/developer/components/myMonacoEditor/index.js
+++ b/public/react/src/modules/developer/components/myMonacoEditor/index.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 15:02:52
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-19 17:52:31
+ * @LastEditTime: 2019-12-19 19:36:24
*/
import './index.scss';
import React, { useState, useRef, useEffect } from 'react';
@@ -146,7 +146,7 @@ function MyMonacoEditor (props, ref) {
>
- {renderRestore}
+ {renderRestore}
{
+ changeShowOrHideControl(false);
props.saveEditorCodeForDetail();
props.history.push(`/problems/${_hack_id}/edit`);
}
// 处理退出
const handleClickQuit = () => {
+ // 将控制台关闭
+ changeShowOrHideControl(false);
props.saveEditorCodeForDetail();
props.history.push('/problems');
}
@@ -164,6 +168,7 @@ const mapDispatchToProps = (dispatch) => ({
saveEditorCodeForDetail: (code) => dispatch(actions.saveEditorCodeForDetail(code)),
// 恢复初始代码
restoreInitialCode: (identifier, msg) => dispatch(actions.restoreInitialCode(identifier, msg)),
+ changeShowOrHideControl: (flag) => dispatch(actions.changeShowOrHideControl(flag))
});
export default withRouter(connect(
diff --git a/public/react/src/modules/developer/studentStudy/rightpane/index.js b/public/react/src/modules/developer/studentStudy/rightpane/index.js
index 5661ea32e..af46d0aef 100644
--- a/public/react/src/modules/developer/studentStudy/rightpane/index.js
+++ b/public/react/src/modules/developer/studentStudy/rightpane/index.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 14:59:51
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-19 15:06:49
+ * @LastEditTime: 2019-12-19 19:13:05
*/
import React, { useState, useEffect } from 'react';
import {connect} from 'react-redux';
@@ -32,6 +32,7 @@ const RightPane = (props) => {
const [editorCode, setEditorCode] = useState('');
+ let initFlag = true;
useEffect(() => {
if (editor_code) {
setEditorCode(editor_code);
@@ -51,8 +52,12 @@ const RightPane = (props) => {
// 代码块内容变化时
const handleCodeChange = (code) => {
// 保存用户提交的代码块
- // console.log(code);
setEditorCode(code);
+ // 第一次回填代码内容时不更新;
+ if (initFlag) {
+ initFlag = false;
+ return;
+ }
if (!timer) {
timer = setInterval(() => {
clearInterval(timer);
diff --git a/public/react/src/redux/actions/common.js b/public/react/src/redux/actions/common.js
index bcd451481..b95d2d2bb 100644
--- a/public/react/src/redux/actions/common.js
+++ b/public/react/src/redux/actions/common.js
@@ -4,12 +4,12 @@
* @Github:
* @Date: 2019-11-27 16:30:50
* @LastEditors: tangjiang
- * @LastEditTime: 2019-11-28 21:15:34
+ * @LastEditTime: 2019-12-19 19:42:10
*/
import types from "./actionTypes";
// 切换控制台显示与隐藏
-export const showOrHideControl = (flag) => {
+export const changeShowOrHideControl = (flag) => {
return {
type: types.SHOW_OR_HIDE_CONTROL,
payload: flag
diff --git a/public/react/src/redux/actions/index.js b/public/react/src/redux/actions/index.js
index ad33061ba..b42c4c2b6 100644
--- a/public/react/src/redux/actions/index.js
+++ b/public/react/src/redux/actions/index.js
@@ -52,7 +52,7 @@ import {
} from './ojForUser';
import {
- showOrHideControl,
+ changeShowOrHideControl,
changeLoadingState,
changeSubmitLoadingStatus,
changePublishLoadingStatus,
@@ -97,7 +97,7 @@ export default {
testCaseOutputChange,
debuggerCode,
startProgramQuestion,
- showOrHideControl,
+ changeShowOrHideControl,
changeLoadingState,
getUserCommitRecord,
getUserCommitRecordDetail,
diff --git a/public/react/src/redux/reducers/ojForUserReducer.js b/public/react/src/redux/reducers/ojForUserReducer.js
index 60e7e6fd1..0c7594dd2 100644
--- a/public/react/src/redux/reducers/ojForUserReducer.js
+++ b/public/react/src/redux/reducers/ojForUserReducer.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 13:41:48
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-19 14:49:03
+ * @LastEditTime: 2019-12-19 20:10:39
*/
import types from "../actions/actionTypes";
import { Base64 } from 'js-base64';
@@ -38,7 +38,12 @@ const ojForUserReducer = (state = initialState, action) => {
const { hack, test_case } = action.payload;
const { code }= hack;
let tempCode = Base64.decode(code)
- let tempDesc = JSON.parse(hack.description);
+ let tempDesc;
+ try {
+ tempDesc = JSON.parse(hack.description);
+ } catch (error) {
+ tempDesc = hack.description;
+ }
Object.assign(hack, {code: tempCode, description: tempDesc});
return {
...state,
From 1cdd29cfd29e1afac3582e38e4e5a70420a7e89c Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Thu, 19 Dec 2019 20:20:46 +0800
Subject: [PATCH 29/61] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AD=97=E6=AE=B5?=
=?UTF-8?q?=E9=95=BF=E5=BA=A6=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../20191219120819_modify_description_for_hacks.rb | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 db/migrate/20191219120819_modify_description_for_hacks.rb
diff --git a/db/migrate/20191219120819_modify_description_for_hacks.rb b/db/migrate/20191219120819_modify_description_for_hacks.rb
new file mode 100644
index 000000000..3cc45fd5d
--- /dev/null
+++ b/db/migrate/20191219120819_modify_description_for_hacks.rb
@@ -0,0 +1,10 @@
+class ModifyDescriptionForHacks < ActiveRecord::Migration[5.2]
+ def change
+ change_column :hacks, :description, :longtext
+ change_column :hack_codes, :code, :longtext
+ change_column :hack_user_lastest_codes, :code, :longtext
+ change_column :hack_user_codes, :code, :longtext
+ change_column :hack_user_debugs, :code, :longtext
+
+ end
+end
From e176abc4bbc759ad634aa409ec03f7f60ed01555 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Thu, 19 Dec 2019 20:42:41 +0800
Subject: [PATCH 30/61] =?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/tpm/shixunchild/Challenges/Challenges.js | 4 ++--
.../modules/tpm/shixunchild/Challenges/Challengesjupyter.js | 6 +++---
.../modules/tpm/shixunchild/Collaborators/Collaborators.js | 3 ++-
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js
index 0480c208a..8890efbd2 100644
--- a/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js
+++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challenges.js
@@ -407,10 +407,10 @@ class Challenges extends Component {
简介
{this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status < 3 ?
-
+
{/*
*/}
编辑
- :""}
+ :""}
{this.props.user && this.props.user.main_site === true ?
this.props.identity < 5?实训制作指南 : "":""}
diff --git a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js
index c8cbc2fbc..e04ad17c9 100644
--- a/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js
+++ b/public/react/src/modules/tpm/shixunchild/Challenges/Challengesjupyter.js
@@ -227,10 +227,10 @@ class Challengesjupyter extends Component {
{this.state.opentitletype===true?
+
+ {courses === undefined ? "" :
}
+
+
+ {
+ course_count>=11?
+
+ :""
+ }
+
+
+ }
+
+
+
+
+
+
+
+
+ 教师排名
+
+ {
+ teachers===null?
+
+
+
+
+ :
+ JSON.stringify(teachers) === "[]" ?
+
+
+
+ :
+
+
+
+ {teachers === undefined ? "" :
}
+
+
+ }
+
+
+
+ {/*
*/}
+
+
+
+
+ 在线实训情况
+
+ {
+ shixun_chart_data===null?
+
+
+
+
+ :
+ JSON.stringify(shixun_chart_data) === "[]" ?
+
+
+
+ :
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+ 学生排名
+
+ {
+ students === null ?
+
+
+
+
+ :
+ JSON.stringify(students) === "[]" ?
+
+
+
+ :
+
+
+
+ {students === undefined ? "" :
}
+
+
+ }
+ {/*
*/}
+
+
+
+
+
+
+
+
+ 最热评测
+
+ {
+ studentionsnames===null?
+
+
+
+
+ :
+ JSON.stringify(studentionsnames) === "[]" ?
+
+
+
+ :
+
+
+
+ }
+
+
+
+
+
+
+ )
+ }
+}
+export default SnackbarHOC() (TPMIndexHOC ( College ));
+
+
diff --git a/public/react/src/college/colleagechart/Colleagechart.js b/public/react/src/college/colleagechart/Colleagechart.js
new file mode 100644
index 000000000..fca01280a
--- /dev/null
+++ b/public/react/src/college/colleagechart/Colleagechart.js
@@ -0,0 +1,84 @@
+import React, {Component} from "react";
+import {WordsBtn} from 'educoder';
+import {Table} from "antd";
+import {Link,Switch,Route,Redirect} from 'react-router-dom';
+const echarts = require('echarts');
+
+
+
+function startechart(data,datanane){
+ var effChart = echarts.init(document.getElementById('shixun_skill_chart'));
+
+ var option = {
+
+ tooltip : {
+ trigger: 'item',
+ formatter: "{d}%
"
+ },
+ legend: {
+ // orient: 'vertical',
+ // top: 'middle',
+ bottom: 50,
+ left: 'center',
+ data: datanane
+ },
+ series : [
+ {
+ type: 'pie',
+ radius : '65%',
+ center: ['50%', '35%'],
+ selectedMode: 'single',
+ data:data,
+ itemStyle: {
+ emphasis: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: 'rgba(0, 0, 0, 0.5)'
+ }
+ }
+ }
+ ]
+ };
+ effChart.setOption(option);
+}
+class Colleagechart extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ }
+ }
+
+ componentDidMount() {
+ startechart(this.props.data,this.props.datanane)
+ }
+
+
+ componentDidUpdate = (prevProps) => {
+ if (prevProps.data!= this.props.data) {
+ startechart(this.props.data,this.props.datanane)
+ }
+ }
+
+
+ render() {
+ let {data}=this.props;
+
+ return (
+
+
+ )
+ }
+}
+
+export default Colleagechart;
diff --git a/public/react/src/college/colleagechart/Colleagechartzu.js b/public/react/src/college/colleagechart/Colleagechartzu.js
new file mode 100644
index 000000000..5c0269700
--- /dev/null
+++ b/public/react/src/college/colleagechart/Colleagechartzu.js
@@ -0,0 +1,149 @@
+import React, {Component} from "react";
+import {WordsBtn} from 'educoder';
+import {Table} from "antd";
+import {Link,Switch,Route,Redirect} from 'react-router-dom';
+const echarts = require('echarts');
+
+
+
+function startechart(names, values){
+ var effChart = echarts.init(document.getElementById('shixun_skill_charts'));
+
+ var Color = ['#962e66', '#623363', '#CCCCCC', '#9A9A9A', '#FF8080', '#FF80C2', '#B980FF', '#80B9FF', '#6FE9FF', '#4DE8B4', '#F8EF63', '#FFB967'];
+
+ var option = {
+ backgroundColor: '#fff',
+ grid: {
+ left: '3%',
+ right: '8%',
+ bottom: '15%',
+ containLabel: true
+ },
+
+ tooltip: {
+ show: "true",
+ trigger: 'item',
+ formatter: '{c0}',
+ backgroundColor: 'rgba(0,0,0,0.7)', // 背景
+ padding: [8, 10], //内边距
+ extraCssText: 'box-shadow: 0 0 3px rgba(255, 255, 255, 0.4);', //添加阴影
+ axisPointer: { // 坐标轴指示器,坐标轴触发有效
+ type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
+ }
+ },
+ xAxis: {
+ type: 'value',
+ axisTick: {
+ show: false
+ },
+ axisLine: {
+ show: true,
+ lineStyle: {
+ color: '#CCCCCC'
+ }
+ },
+ splitLine: {
+ show: false,
+ lineStyle: {
+ color: '#CCCCCC'
+ }
+ },
+ axisLabel: {
+ textStyle: {
+ color: '#656565',
+ fontWeight: 'normal',
+ fontSize: '12'
+ },
+ formatter: '{value}'
+ }
+ },
+ yAxis: {
+ type: 'category',
+ axisLine: {
+ lineStyle: {
+ color: '#cccccc'
+ }
+ },
+ splitLine: {
+ show: false
+ },
+ axisTick: {
+ show: false
+ },
+ splitArea: {
+ show: false
+ },
+ axisLabel: {
+ inside: false,
+ textStyle: {
+ color: '#656565',
+ fontWeight: 'normal',
+ fontSize: '12'
+ }
+ },
+ data: names
+ },
+ series: [{
+ name: '',
+ type: 'bar',
+ itemStyle: {
+ normal: {
+ show: true,
+ color: function(params) {
+ return Color[params.dataIndex]
+ },
+ barBorderRadius: 50,
+ borderWidth: 0,
+ borderColor: '#333'
+ }
+ },
+ barGap: '0%',
+ barCategoryGap: '50%',
+ data: values
+ }
+
+ ]
+ };
+ effChart.setOption(option);
+}
+class Colleagechartzu extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ }
+ }
+
+ componentDidMount() {
+ startechart(this.props.data,this.props.datavule)
+ }
+
+
+ componentDidUpdate = (prevProps) => {
+ if (prevProps.data!= this.props.data) {
+ startechart(this.props.data,this.props.datavule)
+ }
+ }
+
+
+ render() {
+ let {data}=this.props;
+
+ return (
+
+
+ )
+ }
+}
+
+export default Colleagechartzu;
diff --git a/public/react/src/college/colleagecss/colleage.css b/public/react/src/college/colleagecss/colleage.css
new file mode 100644
index 000000000..801b86603
--- /dev/null
+++ b/public/react/src/college/colleagecss/colleage.css
@@ -0,0 +1,213 @@
+.yslstatistic-header {
+ width: 100%;
+ height: 240px;
+ background-image: url('/images/educoder/statistics.jpg');
+ background-size: 100% 100%;
+}
+.yslborder{
+ border: 1px solid;
+}
+.yslstatistic-header-title{
+ flex: 1;
+ display: flex;
+ align-items: center;
+ color: #4CACFF;
+ font-size: 32px;
+}
+.yslstatistic-header-content{
+ width: 100%;
+ display: flex;
+ justify-content: space-around;
+}
+.yslstatistic-header-item{
+ margin-bottom: 22px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ color: #fff;
+}
+.yslstatistic-header-item-label{
+ color: #989898;
+}
+
+.yslstatistic-base-item-label{
+ width: 217px;
+ text-align: center;
+ font-size: 16px;
+ height: 48px;
+ line-height: 48px;
+ color: #686868;
+ background: #F5F5F5;
+ border-top: 1px solid #EBEBEB;
+}
+.yslstatistic-base-item-labels{
+ width: 217px;
+ text-align: center;
+ height: 100px;
+ line-height: 100px;
+ background: #ffffff;
+ border-top: 1px solid #EBEBEB;
+ border-bottom: 1px solid #EBEBEB;
+}
+.yslstatistic-base-item-labelsp{
+ color: #000000;
+ font-size: 24px;
+}
+.yslstatistic-base-item-labelsspan{
+ color: #000000;
+ margin-left: 5px;
+ font-size: 16px;
+}
+.jibenshiyong100{
+ width: 100%;
+}
+
+.yslstatistic-header-item-content{
+ font-size: 24px;
+}
+/* 中间居中 */
+.intermediatecenter{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+/* 简单居中 */
+.intermediatecenterysls{
+ display: flex;
+ align-items: center;
+}
+.spacearound{
+ display: flex;
+ justify-content: space-around;
+
+}
+.spacebetween{
+ display: flex;
+ justify-content: space-between;
+}
+/* 头顶部居中 */
+.topcenter{
+ display: -webkit-flex;
+ flex-direction: column;
+ align-items: center;
+
+}
+
+
+/* x轴正方向排序 */
+/* 一 二 三 四 五 六 七 八 */
+.sortinxdirection{
+ display: flex;
+ flex-direction:row;
+}
+/* x轴反方向排序 */
+/* 八 七 六 五 四 三 二 一 */
+.xaxisreverseorder{
+ display: flex;
+ flex-direction:row-reverse;
+}
+/* 垂直布局 正方向*/
+/* 一
+ 二
+ 三
+ 四
+ 五
+ 六
+ 七
+ 八 */
+.verticallayout{
+ display: flex;
+ flex-direction:column;
+}
+/* 垂直布局 反方向*/
+.reversedirection{
+ display: flex;
+ flex-direction:column-reverse;
+}
+
+.h4{
+ font-size: 1.5rem;
+ font-weight: 500 !important;
+}
+.ysllinjibenshiyong{
+ font-weight: 500;
+ line-height: 1.2;
+ padding: 2rem 1.25rem;
+ border-bottom: unset;
+ background:#fff;
+}
+.linjibenshiyong{
+ font-weight: 500;
+ line-height: 1.2;
+ padding: 2rem 1.25rem;
+ border-bottom: unset;
+ background:#fff;
+ box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1);
+ border-radius:2px;
+}
+.yslslinjibenshiyong{
+ font-weight: 500;
+ line-height: 1.2;
+ border-bottom: unset;
+ box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1);
+ border-radius:2px;
+}
+.yinyin{
+ background: #fff;
+ box-shadow:0px 6px 12px 0px rgba(0,0,0,0.1);
+ border-radius:2px;
+}
+.edu-back-eeee{
+ background:#EEEEEE !important;
+}
+.mt-4{
+ margin-top: 1.5rem !important;
+}
+
+.statistic-label{
+ padding: 2rem 1.25rem;
+ font-size: 1.5rem;
+ font-weight: 400 !important;
+}
+.mb50{
+ padding-bottom: 50px !important;
+}
+.mt40{
+ margin-top: 40px;
+}
+.mb80{
+ margin-bottom: 80px;
+}
+.task-hide{overflow:hidden; white-space: nowrap; text-overflow:ellipsis;}
+a:hover{
+ color:#0056b3;
+}
+.color-blue{
+ color: #4CACFF;
+}
+
+.color-huang{
+ color:#ffc107 !important
+}
+.maxnamewidth105{
+ max-width: 105px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+.maxnamewidth247{
+ max-width: 247px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
+.maxnamewidth340{
+ max-width: 340px;
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ cursor: default;
+}
diff --git a/public/react/src/common/components/comment/CommentForm.js b/public/react/src/common/components/comment/CommentForm.js
new file mode 100644
index 000000000..73e36cff9
--- /dev/null
+++ b/public/react/src/common/components/comment/CommentForm.js
@@ -0,0 +1,116 @@
+/*
+ * @Description: 评论表单
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 17:32:55
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 17:51:44
+ */
+import React, { useState } from 'react';
+import { Form, Button, Input } from 'antd';
+import QuillForEditor from '../../quillForEditor';
+import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
+const FormItem = Form.Item;
+
+function CommentForm (props) {
+
+ const {
+ commentCtxChagne,
+ onCancel,
+ onSubmit,
+ form
+ } = props;
+
+ const { getFieldDecorator } = form;
+ const [ctx, setCtx] = useState('');
+
+ const options = [
+ ['bold', 'italic', 'underline'],
+ [{header: [1,2,3,false]}],
+ ['blockquote', 'code-block'],
+ ['link', 'image'],
+ ['formula']
+ ];
+ // const { form: { getFieldDecorator } } = props;
+ const [showQuill, setShowQuill] = useState(false);
+ // 点击输入框
+ const handleInputClick = () => {
+ setShowQuill(true);
+ }
+ // 取消
+ const handleCancle = () => {
+ setShowQuill(false);
+ onCancel && onCancel();
+ }
+
+ // 编辑器内容变化时
+ const handleContentChange = (content) => {
+ setCtx(content);
+ try {
+ const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert();
+ // props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')});
+ props.form.setFieldsValue({'comment': _html});
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ // 发送
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ props.form.validateFields((err, values) => {
+ if (!err) {
+ setShowQuill(false);
+ const content = ctx;
+ props.form.setFieldsValue({'comment': ''});
+ setCtx('');
+ console.log(content);
+ onSubmit && onSubmit(content);
+ }
+ });
+ }
+ return (
+
+ );
+}
+
+export default Form.create()(CommentForm);
diff --git a/public/react/src/common/components/comment/CommentIcon.js b/public/react/src/common/components/comment/CommentIcon.js
new file mode 100644
index 000000000..5440e2579
--- /dev/null
+++ b/public/react/src/common/components/comment/CommentIcon.js
@@ -0,0 +1,32 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-18 10:49:46
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 11:39:23
+ */
+import './index.scss';
+import React from 'react';
+import { Icon } from 'antd';
+function CommentIcon ({
+ type, // 图标类型
+ count, // 评论数
+ iconClick,
+ ...props
+}) {
+
+ // 点击图标
+ const handleSpanClick = () => {
+ iconClick && iconClick();
+ }
+
+ return (
+
+
+ { count }
+
+ )
+}
+
+export default CommentIcon;
diff --git a/public/react/src/common/components/comment/CommentItem.js b/public/react/src/common/components/comment/CommentItem.js
new file mode 100644
index 000000000..19da645f5
--- /dev/null
+++ b/public/react/src/common/components/comment/CommentItem.js
@@ -0,0 +1,165 @@
+/*
+ * @Description: 评论单列
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 17:35:17
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-19 18:02:28
+ */
+import './index.scss';
+import React, { useState } from 'react';
+import CommentIcon from './CommentIcon';
+import { getImageUrl, CNotificationHOC } from 'educoder'
+import { Icon } from 'antd';
+import moment from 'moment';
+// import QuillForEditor from '../../quillForEditor';
+import CommentForm from './CommentForm';
+
+// import {ModalConfirm} from '../ModalConfirm';
+function CommentItem ({
+ options,
+ confirm
+}) {
+ // 显示评论输入框
+ const [showQuill, setShowQuill] = useState(false);
+ // 加载更多评论内容
+ const [showMore, setShowMore] = useState(false);
+ // 箭头方向
+ const [arrow, setArrow] = useState(false);
+ // 删除评论
+ const deleteComment = () => {
+ console.log('删除评论...');
+ confirm({
+ title: '提示',
+ content: (
确定要删除该条回复吗?
),
+ onOk () {
+ console.log('点击了删除');
+ }
+ });
+ // ModalConfirm('提示', (
确定要删除该条回复吗?
), () => {
+ // console.log('点击了删除');
+ // });
+ }
+
+ // 评论头像
+ const commentAvatar = (url) => (
+
![](https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg)
+ );
+
+ // 评论信息
+ const commentInfo = () => (
+
+ 用户名
+ {moment(new Date(), 'YYYYMMDD HHmmss').fromNow()}
+
+
+ );
+
+ // 评论内容
+ const commentCtx = (ctx) => (
+
+ 这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容
+
+ );
+
+ // 加载更多
+ const handleOnLoadMore = () => {
+ if (!arrow) {
+ // 展开所有
+ } else {
+ // 收起
+ }
+ setArrow(!arrow);
+ };
+
+ // 评论追加内容
+ const commentAppend = () => {
+
+ return (
+
+ -
+ {commentAvatar()}
+
+ {commentInfo()}
+ {commentCtx()}
+
+
+ -
+ {commentAvatar()}
+
+ {commentInfo()}
+ {commentCtx()}
+
+
+ -
+ {commentAvatar()}
+
+ {commentInfo()}
+ {commentCtx()}
+
+
+
+ -
+
展开其余23条评论
+
+
+
+
+
+ );
+ };
+ // 点击图标
+ const handleIconClick = () => {}
+
+ // 点击评论icon
+ const handleClickMessage = () => {
+ setShowQuill(true);
+ }
+
+ // 点击取消
+ const handleClickCancel = () => {
+ setShowQuill(false);
+ }
+
+ // 点击保存
+ const handleClickSubmit = (content) => {
+ // 保存并关闭
+ setShowQuill(false);
+ console.log('获取保存内容', content);
+ }
+
+ return (
+
+ {commentAvatar()}
+
+ {commentInfo()}
+ {commentCtx()}
+
+ {commentAppend()}
+
+
+
+ {/* 回复 */}
+
+ {/* 点赞 */}
+
+
+
+
+
+
+
+
+ );
+}
+
+export default CNotificationHOC() (CommentItem);
diff --git a/public/react/src/common/components/comment/CommentList.js b/public/react/src/common/components/comment/CommentList.js
new file mode 100644
index 000000000..9d8cde87b
--- /dev/null
+++ b/public/react/src/common/components/comment/CommentList.js
@@ -0,0 +1,20 @@
+/*
+ * @Description: 评论列表页
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 17:34:00
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 11:48:09
+ */
+import './index.scss';
+import React from 'react';
+import CommentItem from './CommentItem';
+function CommentList ({}) {
+ return (
+
+ );
+}
+
+export default CommentList;
diff --git a/public/react/src/common/components/comment/index.js b/public/react/src/common/components/comment/index.js
new file mode 100644
index 000000000..f0ecf3309
--- /dev/null
+++ b/public/react/src/common/components/comment/index.js
@@ -0,0 +1,22 @@
+/*
+ * @Description: 评论组件
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 17:31:33
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 11:47:39
+ */
+import React from 'react';
+import CommentForm from './CommentForm';
+import CommentList from './CommentList';
+function Comment (props) {
+
+ return (
+
+
+
+
+ );
+}
+
+export default Comment;
diff --git a/public/react/src/common/components/comment/index.scss b/public/react/src/common/components/comment/index.scss
new file mode 100644
index 000000000..816e6da6c
--- /dev/null
+++ b/public/react/src/common/components/comment/index.scss
@@ -0,0 +1,111 @@
+$bdColor: rgba(244,244,244,1);
+$bgColor: rgba(250,250,250,1);
+$lh14: 14px;
+$lh22: 22px;
+$fz14: 14px;
+$fz12: 12px;
+$ml: 20px;
+
+.comment_list_wrapper{
+ box-sizing: border-box;
+ border-top: 1px solid $bdColor;
+
+ .comment_item_area{
+ display: flex;
+ padding: 20px 0;
+ box-sizing: border-box;
+ border-bottom: 1px solid $bdColor;
+ .flex-image{
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ }
+ .item-desc{
+ flex: 1;
+ margin-left: $ml;
+ }
+ .item-header{
+ font-size: $fz14;
+ line-height: $lh14;
+ color: #333;
+ .item-time{
+ font-size: $fz12;
+ line-height: $lh14;
+ margin-left: $ml;
+ }
+ .item-close{
+ float: right;
+ cursor: pointer;
+ }
+ }
+ .item-ctx{
+ line-height: $lh22;
+ font-size: $fz12;
+ color: #333;
+ margin-top: 10px;
+ }
+ .comment_icon_area{
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 10px;
+
+ .comment-icon-margin{
+ margin-left: 30px;
+ }
+ }
+
+ .comment_item_quill{
+ margin-top: 20px;
+ }
+ }
+ .comment_icon_count{
+ cursor: pointer;
+ font-size: 12px;
+ line-height: 1.5;
+
+ .comment_icon{
+ color: #333;
+ }
+ .comment_count{
+ color: #999999;
+ margin-left: 10px;
+ transition: color .3s;
+ }
+
+ &:hover{
+ .comment_icon,
+ .comment_count{
+ color: #5091FF;
+ }
+ }
+ }
+ .comment_item_append_list{
+ position: relative;
+ background-color: $bgColor;
+ border-radius: 5px;
+ padding: 0 15px 10px;
+ margin: 15px 0;
+ &::before {
+ position: absolute;
+ left: 15px;
+ bottom: 100%;
+ height: 0;
+ width: 0;
+ content: '';
+ // border: 5px solid transparent;
+ border: 10px solid transparent;
+ border-bottom-color: $bgColor;
+ }
+
+ .comment_item_loadmore{
+ padding-top: 10px;
+ cursor: pointer;
+ .loadmore-txt,
+ .loadmore-icon{
+ color: #999;
+ text-align: center;
+ font-size: $fz12;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/react/src/common/quillForEditor/ImageBlot.js b/public/react/src/common/quillForEditor/ImageBlot.js
new file mode 100644
index 000000000..091bd2c1f
--- /dev/null
+++ b/public/react/src/common/quillForEditor/ImageBlot.js
@@ -0,0 +1,54 @@
+/*
+ * @Description: 重写图片
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-16 15:50:45
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 16:44:48
+ */
+import Quill from "quill";
+
+const BlockEmbed = Quill.import('blots/block/embed');
+
+export default class ImageBlot extends BlockEmbed {
+
+ static create(value) {
+
+ const node = super.create();
+
+ node.setAttribute('alt', value.alt);
+ node.setAttribute('src', value.url);
+
+ if (value.width) {
+ node.setAttribute('width', value.width);
+ }
+ if (value.height) {
+ node.setAttribute('height', value.height);
+ }
+ // 宽度和高度都不存在时,
+ if (!value.width && !value.height) {
+ node.setAttribute('display', 'block');
+ node.setAttribute('width', '100%');
+ }
+ // 给图片添加点击事件
+ node.onclick = () => {
+ value.onClick && value.onClick(value.url);
+ }
+ return node;
+ }
+
+ static value (node) {
+
+ return {
+ alt: node.getAttribute('alt'),
+ url: node.getAttribute('src'),
+ onclick: node.onclick,
+ // width: node.width,
+ // height: node.height,
+ display: node.getAttribute('display')
+ };
+ }
+}
+
+ImageBlot.blotName = 'image';
+ImageBlot.tagName = 'img';
\ No newline at end of file
diff --git a/public/react/src/common/quillForEditor/deepEqual.js b/public/react/src/common/quillForEditor/deepEqual.js
new file mode 100644
index 000000000..6f2b276bf
--- /dev/null
+++ b/public/react/src/common/quillForEditor/deepEqual.js
@@ -0,0 +1,47 @@
+function deepEqual (prev, current) {
+ if (prev === current) { // 基本类型比较,值,类型都相同 或者同为 null or undefined
+ return true;
+ }
+
+ if ((!prev && current)
+ || (prev && !current)
+ || (!prev && !current)
+ ) {
+ return false;
+ }
+
+ if (Array.isArray(prev)) {
+ if (!Array.isArray(current)) return false;
+ if (prev.length !== current.length) return false;
+
+ for (let i = 0; i < prev.length; i++) {
+ if (!deepEqual(current[i], prev[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (typeof current === 'object') {
+ if (typeof prev !== 'object') return false;
+ const prevKeys = Object.keys(prev);
+ const curKeys = Object.keys(current);
+
+ if (prevKeys.length !== curKeys.length) return false;
+
+ prevKeys.sort();
+ curKeys.sort();
+
+ for (let i = 0; i < prevKeys.length; i++) {
+ if (prevKeys[i] !== curKeys[i]) return false;
+ const key = prevKeys[i];
+ if (!deepEqual(prev[key], current[key])) return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+export default deepEqual;
diff --git a/public/react/src/common/quillForEditor/index.js b/public/react/src/common/quillForEditor/index.js
new file mode 100644
index 000000000..6e6c01886
--- /dev/null
+++ b/public/react/src/common/quillForEditor/index.js
@@ -0,0 +1,166 @@
+/*
+ * @Description: quill 编辑器
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-18 08:49:30
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-19 16:58:50
+ */
+import 'quill/dist/quill.core.css'; // 核心样式
+import 'quill/dist/quill.snow.css'; // 有工具栏
+import 'quill/dist/quill.bubble.css'; // 无工具栏
+import 'katex/dist/katex.min.css'; // katex 表达式样式
+import React, { useState, useRef, useEffect } from 'react';
+import Quill from 'quill';
+import katex from 'katex';
+import deepEqual from './deepEqual.js'
+import { fetchUploadImage } from '../../services/ojService.js';
+import { getImageUrl } from 'educoder'
+import ImageBlot from './ImageBlot';
+
+window.Quill = Quill;
+window.katex = katex;
+Quill.register(ImageBlot);
+
+function QuillForEditor ({
+ placeholder,
+ readOnly,
+ options,
+ value,
+ imgAttrs = {}, // 指定图片的宽高
+ style = {},
+ wrapStyle = {},
+ showUploadImage,
+ onContentChange
+}) {
+ // toolbar 默认值
+ const defaultConfig = [
+ ['bold', 'italic', 'underline'],
+ [{align: []}, {list: 'ordered'}, {list: 'bullet'}], // 列表
+ [{script: 'sub'}, {script: 'super'}],
+ [{ 'color': [] }, { 'background': [] }],
+ [{header: [1,2,3,4,5,false]}],
+ ['blockquote', 'code-block'],
+ ['link', 'image', 'video'],
+ ['formula'],
+ ['clean']
+ ];
+
+ const editorRef = useRef(null);
+ // quill 实例
+ const [quill, setQuill] = useState(null);
+ const [selection, setSelection] = useState(null);
+
+ // 文本内容变化时
+ const handleOnChange = content => {
+ // console.log('编辑器内容====》》》》', content);
+ onContentChange && onContentChange(content);
+ };
+
+ const renderOptions = options || defaultConfig;
+ // quill 配置信息
+ const quillOption = {
+ modules: {
+ toolbar: renderOptions
+ },
+ readOnly,
+ placeholder,
+ theme: readOnly ? 'bubble' : 'snow'
+ };
+
+
+ useEffect(() => {
+ const _quill = new Quill(editorRef.current, quillOption);
+ setQuill(_quill);
+
+ // 处理图片上传功能
+ _quill.getModule('toolbar').addHandler('image', (e) => {
+ const input = document.createElement('input');
+ input.setAttribute('type', 'file');
+ input.setAttribute('accept', 'image/*');
+ input.click();
+
+ input.onchange = async (e) => {
+ const file = input.files[0]; // 获取文件信息
+ const formData = new FormData();
+ formData.append('file', file);
+
+ const range = _quill.getSelection(true);
+ let fileUrl = ''; // 保存上传成功后图片的url
+ // 上传文件
+ const result = await fetchUploadImage(formData);
+ // 获取上传图片的url
+ if (result.data && result.data.id) {
+ fileUrl = getImageUrl(`api/attachments/${result.data.id}`);
+ }
+ // 根据id获取文件路径
+ const { width, height } = imgAttrs;
+ // console.log('上传图片的url:', fileUrl);
+ if (fileUrl) {
+ _quill.insertEmbed(range.index, 'image', {
+ url: fileUrl,
+ alt: '图片信息',
+ onClick: showUploadImage,
+ width,
+ height
+ });
+ }
+ }
+ });
+ }, []);
+
+ // 设置值
+ useEffect(() => {
+ if (!quill) return
+ const previous = quill.getContents()
+ const current = value
+
+ if (!deepEqual(previous, current)) {
+ setSelection(quill.getSelection())
+ if (typeof value === 'string') {
+ quill.clipboard.dangerouslyPasteHTML(value, 'api')
+ } else {
+ quill.setContents(value)
+ }
+ }
+ }, [quill, value, setQuill]);
+
+ // 清除选择区域
+ useEffect(() => {
+ if (quill && selection) {
+ quill.setSelection(selection)
+ setSelection(null)
+ }
+ }, [quill, selection, setSelection]);
+
+ // 设置placeholder值
+ useEffect(() => {
+ if (!quill || !quill.root) return;
+ quill.root.dataset.placeholder = placeholder;
+ }, [quill, placeholder]);
+
+ // 处理内容变化
+ useEffect(() => {
+ if (!quill) return;
+ if (typeof handleOnChange !== 'function') return;
+ let handler;
+ quill.on(
+ 'text-change',
+ (handler = () => {
+ handleOnChange(quill.getContents()); // getContents: 检索编辑器内容
+ })
+ );
+ return () => {
+ quill.off('text-change', handler);
+ }
+ }, [quill, handleOnChange]);
+
+ // 返回结果
+ return (
+
+ );
+}
+
+export default QuillForEditor;
diff --git a/public/react/src/common/reactQuill/ImageBlot.js b/public/react/src/common/reactQuill/ImageBlot.js
new file mode 100644
index 000000000..091bd2c1f
--- /dev/null
+++ b/public/react/src/common/reactQuill/ImageBlot.js
@@ -0,0 +1,54 @@
+/*
+ * @Description: 重写图片
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-16 15:50:45
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 16:44:48
+ */
+import Quill from "quill";
+
+const BlockEmbed = Quill.import('blots/block/embed');
+
+export default class ImageBlot extends BlockEmbed {
+
+ static create(value) {
+
+ const node = super.create();
+
+ node.setAttribute('alt', value.alt);
+ node.setAttribute('src', value.url);
+
+ if (value.width) {
+ node.setAttribute('width', value.width);
+ }
+ if (value.height) {
+ node.setAttribute('height', value.height);
+ }
+ // 宽度和高度都不存在时,
+ if (!value.width && !value.height) {
+ node.setAttribute('display', 'block');
+ node.setAttribute('width', '100%');
+ }
+ // 给图片添加点击事件
+ node.onclick = () => {
+ value.onClick && value.onClick(value.url);
+ }
+ return node;
+ }
+
+ static value (node) {
+
+ return {
+ alt: node.getAttribute('alt'),
+ url: node.getAttribute('src'),
+ onclick: node.onclick,
+ // width: node.width,
+ // height: node.height,
+ display: node.getAttribute('display')
+ };
+ }
+}
+
+ImageBlot.blotName = 'image';
+ImageBlot.tagName = 'img';
\ No newline at end of file
diff --git a/public/react/src/common/reactQuill/ReactQuill.js b/public/react/src/common/reactQuill/ReactQuill.js
new file mode 100644
index 000000000..1b4209409
--- /dev/null
+++ b/public/react/src/common/reactQuill/ReactQuill.js
@@ -0,0 +1,45 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:09:42
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-18 08:46:20
+ */
+import 'quill/dist/quill.core.css'; // 核心样式
+import 'quill/dist/quill.snow.css'; // 有工具栏
+import 'quill/dist/quill.bubble.css'; // 无工具栏
+import 'katex/dist/katex.min.css'; // katex 表达式样式
+import React, { useState, useReducer, useEffect } from 'react';
+import useQuill from './useQuill';
+
+function ReactQuill ({
+ disallowColors, // 不可见时颜色
+ placeholder, // 提示信息
+ uploadImage, // 图片上传
+ onChange, // 内容变化时
+ options, // 配置信息
+ value, // 显示的内容
+ style,
+ showUploadImage // 显示上传图片
+}) {
+
+ const [element, setElement] = useState(); // quill 渲染节点
+
+ useQuill({
+ disallowColors,
+ placeholder,
+ uploadImage,
+ onChange,
+ options,
+ value,
+ showUploadImage,
+ element
+ });
+
+ return (
+
+ );
+}
+
+export default ReactQuill;
diff --git a/public/react/src/common/reactQuill/deepEqual.js b/public/react/src/common/reactQuill/deepEqual.js
new file mode 100644
index 000000000..6f2b276bf
--- /dev/null
+++ b/public/react/src/common/reactQuill/deepEqual.js
@@ -0,0 +1,47 @@
+function deepEqual (prev, current) {
+ if (prev === current) { // 基本类型比较,值,类型都相同 或者同为 null or undefined
+ return true;
+ }
+
+ if ((!prev && current)
+ || (prev && !current)
+ || (!prev && !current)
+ ) {
+ return false;
+ }
+
+ if (Array.isArray(prev)) {
+ if (!Array.isArray(current)) return false;
+ if (prev.length !== current.length) return false;
+
+ for (let i = 0; i < prev.length; i++) {
+ if (!deepEqual(current[i], prev[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (typeof current === 'object') {
+ if (typeof prev !== 'object') return false;
+ const prevKeys = Object.keys(prev);
+ const curKeys = Object.keys(current);
+
+ if (prevKeys.length !== curKeys.length) return false;
+
+ prevKeys.sort();
+ curKeys.sort();
+
+ for (let i = 0; i < prevKeys.length; i++) {
+ if (prevKeys[i] !== curKeys[i]) return false;
+ const key = prevKeys[i];
+ if (!deepEqual(prev[key], current[key])) return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+export default deepEqual;
diff --git a/public/react/src/common/reactQuill/flatten.js b/public/react/src/common/reactQuill/flatten.js
new file mode 100644
index 000000000..237cb543f
--- /dev/null
+++ b/public/react/src/common/reactQuill/flatten.js
@@ -0,0 +1,26 @@
+/*
+ * @Description: 将多维数组转变成一维数组
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:35:01
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:36:22
+ */
+function flatten (array) {
+ return flatten.rec(array, []);
+}
+
+flatten.rec = function flatten (array, result) {
+
+ for (let item of array) {
+ if (Array.isArray(item)) {
+ flatten(item, result);
+ } else {
+ result.push(item);
+ }
+ }
+
+ return result;
+}
+
+export default flatten;
diff --git a/public/react/src/common/reactQuill/index.js b/public/react/src/common/reactQuill/index.js
new file mode 100644
index 000000000..56a1a8d1f
--- /dev/null
+++ b/public/react/src/common/reactQuill/index.js
@@ -0,0 +1,108 @@
+/*
+ * @Description: 入口文件
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-17 10:41:48
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 20:34:40
+ */
+import React, { useState, useCallback, useEffect } from 'react';
+import ReactQuill from './lib';
+
+function Wrapper (props) {
+ // 默认工具栏配置项
+ const toolbarConfig = [
+ ['bold', 'italic', 'underline'],
+ [{align: []}, {list: 'ordered'}, {list: 'bullet'}], // 列表
+ [{script: 'sub'}, {script: 'super'}],
+ [{header: [1,2,3,4,5,false]}],
+ ['blockquote', 'code-block'],
+ ['link', 'image', 'video'],
+ ['formula'],
+ ['clean']
+ ];
+
+ const [placeholder] = useState(props.placeholder || 'placeholder');
+ const [disableBold] = useState(false);
+ const [value, setValue] = useState(props.value || '');
+ const [toolbar, setToolbar] = useState(toolbarConfig);
+ const [theme, setTheme] = useState(props.theme || 'snow');
+ const [readOnly] = useState(props.readOnly || false);
+
+ const {
+ onContentChagne, // 当编辑器内容变化时调用该函数
+ showUploadImage, // 显示上传图片, 返回url,主要用于点击图片放大
+ } = props;
+
+ // 配置信息
+ const options = {
+ modules: {
+ toolbar: toolbar,
+ clipboard: {
+ matchVisual: false
+ }
+ },
+ readOnly: readOnly,
+ theme: theme
+ }
+ // 配置信息
+ useEffect (() => {
+ if (props.options) {
+ setToolbar(props.options);
+ }
+ setTheme(props.theme || 'snow');
+ setValue(props.value);
+ }, [props]);
+
+ // 当内容变化时
+ const handleOnChange = useCallback(
+ contents => {
+ if (disableBold) {
+ setValue({
+ ops: contents.ops.map(x => {
+ x = {...x};
+ if (x && x.attributes && x.attributes.bold) {
+ x.attributes = { ...x.attributes };
+ delete x.attributes.bold;
+ if (!Object.keys(x.attributes).length) {
+ delete x.attributes;
+ }
+ }
+ return x;
+ })
+ });
+ } else {
+ setValue(contents);
+ }
+ onContentChagne && onContentChagne(contents);
+ }, [disableBold]
+ );
+
+ // 图片上传
+ const handleUploadImage = (files) => {
+ console.log('选择的图片信息', files);
+ }
+
+ // 显示图片
+ const handleShowUploadImage = (url) => {
+ // console.log('上传的图片url:', url);
+ showUploadImage && showUploadImage(url);
+ }
+
+ return (
+
+ handleShowUploadImage(url)}
+ />
+
+ );
+}
+
+export default Wrapper;
+// ReactDOM.render(
, document.querySelector('#root'));
diff --git a/public/react/src/common/reactQuill/index.scss b/public/react/src/common/reactQuill/index.scss
new file mode 100644
index 000000000..b6da52bf5
--- /dev/null
+++ b/public/react/src/common/reactQuill/index.scss
@@ -0,0 +1,32 @@
+#quill-toolbar{
+ .quill-btn{
+ vertical-align: middle;
+ }
+ .quill_image{
+ display: inline-block;
+ position: relative;
+ vertical-align: middle;
+ width: 28px;
+ height: 24px;
+ overflow: hidden;
+ .image_input{
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ opacity: 0;
+ }
+ .ql-image{
+ position: relative;
+ left: 0;
+ top: 0;
+ }
+ }
+}
+
+.react_quill_area{
+ .ql-toolbar:not(:last-child) {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/public/react/src/common/reactQuill/lib.js b/public/react/src/common/reactQuill/lib.js
new file mode 100644
index 000000000..430a95bb7
--- /dev/null
+++ b/public/react/src/common/reactQuill/lib.js
@@ -0,0 +1,13 @@
+/*
+ * @Description: 导出 ReactQuill
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:08:24
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:37:13
+ */
+import ReactQuill from './ReactQuill';
+import useQuill from './useQuill';
+
+export default ReactQuill;
+export { useQuill };
diff --git a/public/react/src/common/reactQuill/useDeepEqualMemo.js b/public/react/src/common/reactQuill/useDeepEqualMemo.js
new file mode 100644
index 000000000..948e21781
--- /dev/null
+++ b/public/react/src/common/reactQuill/useDeepEqualMemo.js
@@ -0,0 +1,27 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-12 19:48:55
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:38:16
+ */
+import { useState, useEffect } from 'react';
+import deepEqual from './deepEqual';
+
+function useDeepEqual (input) {
+
+ const [value, setValue] = useState(input);
+
+ useEffect(() => {
+
+ if (!deepEqual(input, value)) {
+ setValue(input)
+ }
+
+ }, [input, value]);
+
+ return value;
+}
+
+export default useDeepEqual;
diff --git a/public/react/src/common/reactQuill/useMountQuill.js b/public/react/src/common/reactQuill/useMountQuill.js
new file mode 100644
index 000000000..c2313c480
--- /dev/null
+++ b/public/react/src/common/reactQuill/useMountQuill.js
@@ -0,0 +1,148 @@
+/*
+ * @Description: 创建 reactQuill实例
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:31:42
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 20:42:05
+ */
+import Quill from 'quill'; // 导入quill
+import { useState, useEffect, useMemo } from 'react';
+import flatten from './flatten.js';
+import useDeepEqualMemo from './useDeepEqualMemo';
+import Katex from 'katex';
+import ImageBlot from './ImageBlot';
+import { fetchUploadImage } from '../../services/ojService.js';
+import { getImageUrl } from 'educoder'
+window.katex = Katex;
+
+Quill.register(ImageBlot);
+
+function useMountQuill ({
+ element,
+ options: passedOptions,
+ uploadImage,
+ showUploadImage,
+ imgAttrs = {} // 指定图片的宽高属性
+}) {
+
+ // 是否引入 katex
+ const [katexLoaded, setKatexLoaded] = useState(Boolean(window.katex))
+ const [quill, setQuill] = useState(null);
+
+ const options = useDeepEqualMemo(passedOptions);
+ console.log('use mount quill: ', passedOptions);
+
+ // 判断options中是否包含公式
+ const requireKatex = useMemo(() => {
+ return flatten(options.modules.toolbar).includes('formula');
+ }, [options]);
+
+ // 加载katex
+ useEffect(() => {
+ if (!requireKatex) return;
+ if (katexLoaded) return;
+
+ const interval = setInterval(() => {
+ if (window.katex) {
+ setKatexLoaded(true);
+ clearInterval(interval);
+ }
+ });
+
+ return () => { // 定义回调清除定时器
+ clearInterval(interval);
+ }
+
+ }, [
+ setKatexLoaded,
+ katexLoaded,
+ requireKatex
+ ]);
+
+ // 加载 quill
+ useEffect(() => {
+ if (!element) return;
+ if (requireKatex && !katexLoaded) {
+ element.innerHTML = `
+
+ Loading Katex...
+
+ `
+ }
+ // 清空内容
+ element.innerHTML = '';
+ console.log(element);
+ // 创建 quill 节点
+ const quillNode = document.createElement('div');
+ element.appendChild(quillNode); // 将quill节点追回到 element 元素中
+
+ const quill = new Quill(element, options);
+ setQuill(quill);
+ // 加载上传图片功能
+ if (typeof uploadImage === 'function') {
+ quill.getModule('toolbar').addHandler('image', (e) => {
+ // 创建type类型输入框加载本地图片
+ const input = document.createElement('input');
+ input.setAttribute('type', 'file');
+ input.setAttribute('accept', 'image/*');
+ input.click();
+
+ input.onchange = async (e) => {
+ const file = input.files[0]; // 获取文件信息
+ const formData = new FormData();
+ formData.append('file', file);
+
+ // const reader = new FileReader();
+ // reader.readAsDataURL(file);
+ // console.log('文件信息===>>', reader);
+ // reader.onload = function (e) {
+ // debugger;
+ // console.log('文件信息===>>', e.target.result);
+ // const image = new Image();
+ // image.src = e.target.result;
+
+ // image.onload = function () {
+ // // file.width =
+ // console.log(image.width, image.height);
+ // }
+ // }
+
+ const range = quill.getSelection(true);
+ let fileUrl = ''; // 保存上传成功后图片的url
+ // 上传文件
+ const result = await fetchUploadImage(formData);
+ // 获取上传图片的url
+ if (result.data && result.data.id) {
+ fileUrl = getImageUrl(`api/attachments/${result.data.id}`);
+ }
+ // 根据id获取文件路径
+ const { width, height } = imgAttrs;
+ // console.log('上传图片的url:', fileUrl);
+ if (fileUrl) {
+ quill.insertEmbed(range.index, 'image', {
+ url: fileUrl,
+ alt: '',
+ onClick: showUploadImage,
+ width,
+ height
+ });
+ }
+ }
+ });
+ }
+
+ return () => {
+ element.innerHTML = '';
+ }
+ }, [
+ element,
+ options,
+ requireKatex,
+ katexLoaded,
+ ]);
+
+ return quill;
+}
+
+export default useMountQuill;
diff --git a/public/react/src/common/reactQuill/useQuill.js b/public/react/src/common/reactQuill/useQuill.js
new file mode 100644
index 000000000..b959dbc52
--- /dev/null
+++ b/public/react/src/common/reactQuill/useQuill.js
@@ -0,0 +1,60 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:09:50
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-17 15:46:50
+ */
+import useQuillPlaceholder from './useQuillPlaceholder';
+import useQuillValueSync from './useQuillValueSync';
+import useQuillOnChange from './useQuillOnChange';
+import useMountQuill from './useMountQuill';
+import { useEffect } from 'react';
+
+function useQuill ({
+ disallowColors,
+ placeholder,
+ uploadImage,
+ onChange,
+ options,
+ value,
+ element,
+ showUploadImage
+}) {
+
+ // 获取 quill 实例
+ const quill = useMountQuill({
+ element,
+ options,
+ uploadImage,
+ showUploadImage
+ });
+
+ useEffect(() => {
+ if (disallowColors && quill) {
+ quill.clipboard.addMatcher(Node.ELEMENT_NODE, (node, delta) => {
+ delta.ops = delta.ops.map(op => {
+ if (op.attributes && op.attributes.color) {
+ const { color, ...attributes } = op.attributes;
+ return {
+ ...op,
+ attributes
+ }
+ }
+ return op;
+ });
+ return delta;
+ });
+ }
+ }, [
+ disallowColors,
+ quill
+ ]);
+
+ useQuillPlaceholder(quill, placeholder);
+ useQuillValueSync(quill, value);
+ useQuillOnChange(quill, onChange);
+}
+
+export default useQuill;
diff --git a/public/react/src/common/reactQuill/useQuillOnChange.js b/public/react/src/common/reactQuill/useQuillOnChange.js
new file mode 100644
index 000000000..45333a4e1
--- /dev/null
+++ b/public/react/src/common/reactQuill/useQuillOnChange.js
@@ -0,0 +1,33 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-12 19:49:11
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:39:27
+ */
+import { useEffect } from 'react';
+
+function useQuillOnChange (quill, onChange) {
+
+ useEffect(() => {
+
+ if (!quill) return;
+ if (typeof onChange !== 'function') return;
+
+ let handler;
+
+ quill.on(
+ 'text-change',
+ (handler = () => {
+ onChange(quill.getContents()); // getContents: 检索编辑器内容
+ })
+ );
+
+ return () => {
+ quill.off('text-change', handler);
+ }
+ }, [quill, onChange]);
+}
+
+export default useQuillOnChange;
diff --git a/public/react/src/common/reactQuill/useQuillPlaceholder.js b/public/react/src/common/reactQuill/useQuillPlaceholder.js
new file mode 100644
index 000000000..ccc341568
--- /dev/null
+++ b/public/react/src/common/reactQuill/useQuillPlaceholder.js
@@ -0,0 +1,22 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-12-09 09:28:34
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-16 11:39:48
+ */
+import { useEffect } from 'react'
+
+function useQuillPlaceholder (
+ quill,
+ placeholder
+) {
+
+ useEffect(() => {
+ if (!quill || !quill.root) return;
+ quill.root.dataset.placeholder = placeholder;
+ }, [quill, placeholder]);
+}
+
+export default useQuillPlaceholder;
diff --git a/public/react/src/common/reactQuill/useQuillValueSync.js b/public/react/src/common/reactQuill/useQuillValueSync.js
new file mode 100644
index 000000000..696d88949
--- /dev/null
+++ b/public/react/src/common/reactQuill/useQuillValueSync.js
@@ -0,0 +1,31 @@
+import { useEffect, useState } from 'react'
+import deepEqual from './deepEqual.js'
+
+function useQuillValueSync(quill, value) {
+ const [selection, setSelection] = useState(null)
+
+ useEffect(() => {
+ if (!quill) return
+
+ const previous = quill.getContents()
+ const current = value
+
+ if (!deepEqual(previous, current)) {
+ setSelection(quill.getSelection())
+ if (typeof value === 'string') {
+ quill.clipboard.dangerouslyPasteHTML(value, 'api')
+ } else {
+ quill.setContents(value)
+ }
+ }
+ }, [quill, value, setSelection])
+
+ useEffect(() => {
+ if (quill && selection) {
+ quill.setSelection(selection)
+ setSelection(null)
+ }
+ }, [quill, selection, setSelection])
+}
+
+export default useQuillValueSync
diff --git a/public/react/src/modules/developer/DeveloperHome.js b/public/react/src/modules/developer/DeveloperHome.js
index 5f787659e..73a5c37a1 100644
--- a/public/react/src/modules/developer/DeveloperHome.js
+++ b/public/react/src/modules/developer/DeveloperHome.js
@@ -16,7 +16,7 @@ import MultipTags from './components/multiptags';
// import { Link } from 'react-router-dom';
import CONST from '../../constants';
import { withRouter } from 'react-router';
-import { toStore } from 'educoder';
+import { toStore, CNotificationHOC } from 'educoder';
// import MyIcon from '../../common/components/MyIcon';
const {tagBackground, diffText} = CONST;
@@ -249,17 +249,26 @@ class DeveloperHome extends React.PureComponent {
// 删除
handleClickDelete = (record) => {
const { deleteItem } = this.props;
- Modal.confirm({
- title: '删除',
+ this.props.confirm({
+ title: '提示',
content: `确定要删除${record.name}吗?`,
- okText: '确定',
- cancelText: '取消',
onOk () {
// 调用删除接口
console.log(record.identifier);
deleteItem(record.identifier);
}
});
+ // Modal.confirm({
+ // title: '删除',
+ // content: `确定要删除${record.name}吗?`,
+ // okText: '确定',
+ // cancelText: '取消',
+ // onOk () {
+ // // 调用删除接口
+ // console.log(record.identifier);
+ // deleteItem(record.identifier);
+ // }
+ // });
}
// table条件变化时
handleTableChange = (pagination, filters, sorter) => {
@@ -562,5 +571,5 @@ const mapDispatchToProps = (dispatch) => ({
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
-)(DeveloperHome));
+)(CNotificationHOC() (DeveloperHome)));
// export default DeveloperHome;
diff --git a/public/react/src/modules/developer/components/controlSetting/index.js b/public/react/src/modules/developer/components/controlSetting/index.js
index 587e1bee9..1d4d7834c 100644
--- a/public/react/src/modules/developer/components/controlSetting/index.js
+++ b/public/react/src/modules/developer/components/controlSetting/index.js
@@ -4,10 +4,10 @@
* @Github:
* @Date: 2019-11-27 16:02:36
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 17:32:33
+ * @LastEditTime: 2019-12-19 19:47:32
*/
import './index.scss';
-import React, { useState, useRef } from 'react';
+import React, { useState, useRef, useEffect } from 'react';
import { Tabs, Button, Icon } from 'antd';
import { connect } from 'react-redux';
import InitTabCtx from '../initTabCtx';
@@ -23,14 +23,15 @@ const ControlSetting = (props) => {
submitLoading,
identifier,
excuteState,
+ showOrHideControl,
commitRecordDetail,
changeLoadingState,
changeSubmitLoadingStatus,
- showOrHideControl,
+ changeShowOrHideControl,
// debuggerCode,
// startDebuggerCode, // 外部存入
onDebuggerCode,
- updateCode,
+ // updateCode,
onSubmitForm
} = props;
const [defaultActiveKey, setDefaultActiveKey] = useState('1'); // 当前选中的tab
@@ -44,10 +45,14 @@ const ControlSetting = (props) => {
setDefaultActiveKey(key);
}
+ useEffect(() => {
+ setShowTextResult(props.showOrHideControl);
+ }, [props]);
+
// 显示/隐藏tab
const handleShowControl = () => {
setShowTextResult(!showTextResult);
- showOrHideControl(!showTextResult);
+ changeShowOrHideControl(!showTextResult);
}
// 调试代码
@@ -55,7 +60,7 @@ const ControlSetting = (props) => {
// console.log(formRef.current.handleTestCodeFormSubmit);
// 调出控制台界面
setShowTextResult(true);
- showOrHideControl(true);
+ changeShowOrHideControl(true);
formRef.current.handleTestCodeFormSubmit(() => {
setDefaultActiveKey('2');
});
@@ -84,7 +89,7 @@ const ControlSetting = (props) => {
@@ -131,19 +136,20 @@ const ControlSetting = (props) => {
const mapStateToProps = (state) => {
const {commonReducer, ojForUserReducer} = state;
- const {loading, excuteState, submitLoading } = commonReducer;
+ const {loading, excuteState, submitLoading, showOrHideControl } = commonReducer;
const { commitRecordDetail } = ojForUserReducer;
return {
loading,
submitLoading,
excuteState,
+ showOrHideControl,
// identifier: user_program_identifier,
commitRecordDetail // 提交详情
};
};
// changeSubmitLoadingStatus
const mapDispatchToProps = (dispatch) => ({
- showOrHideControl: (flag) => dispatch(actions.showOrHideControl(flag)),
+ changeShowOrHideControl: (flag) => dispatch(actions.changeShowOrHideControl(flag)),
changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag)),
changeSubmitLoadingStatus: (flag) => dispatch(actions.changeSubmitLoadingStatus(flag)),
debuggerCode: (identifier, values) => dispatch(actions.debuggerCode(identifier, values)),
diff --git a/public/react/src/modules/developer/components/controlSetting/index.scss b/public/react/src/modules/developer/components/controlSetting/index.scss
index 97838ce5c..31beda8a5 100644
--- a/public/react/src/modules/developer/components/controlSetting/index.scss
+++ b/public/react/src/modules/developer/components/controlSetting/index.scss
@@ -2,7 +2,8 @@
position: absolute;
bottom: 0;
width: 100%;
- background:rgba(30,30,30,1);
+ // background: red;
+ // background:rgba(30,30,30,1);
// height: 56px;
.control_tab{
position: absolute;
@@ -52,8 +53,8 @@
height: 56px;
padding-right: 30px;
padding-left: 10px;
- // background: #000;
- background:rgba(48,48,48,1);
+ background: rgba(18,28,36,1);
+ // background:rgba(48,48,48,1);
}
.setting_drawer{
diff --git a/public/react/src/modules/developer/components/execResult/index.js b/public/react/src/modules/developer/components/execResult/index.js
index 32bbbee91..6f9341b9a 100644
--- a/public/react/src/modules/developer/components/execResult/index.js
+++ b/public/react/src/modules/developer/components/execResult/index.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-28 08:44:54
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-10 09:24:02
+ * @LastEditTime: 2019-12-19 10:44:16
*/
import './index.scss';
import React, { useState, useEffect } from 'react';
@@ -38,6 +38,15 @@ function ExecResult (props) {
);
+
+ const renderError = () => (
+
+
+ 未知异常
+
+
+ )
+
const renderFinish = () => {
const {
error_line,
@@ -60,6 +69,7 @@ function ExecResult (props) {
)
}
+ // console.log('执行结果====》》》》', status);
const excuteCtx = (state) => {
if (state === 0) {
return (
@@ -118,6 +128,8 @@ function ExecResult (props) {
setRenderCtx(() => (readerLoaded));
} else if ('finish' === excuteState) {
setRenderCtx(() => (renderFinish));
+ } else if ('error' === excuteState) {
+ setRenderCtx(() => (renderError))
}
}, [excuteState]);
diff --git a/public/react/src/modules/developer/components/initTabCtx/index.js b/public/react/src/modules/developer/components/initTabCtx/index.js
index 3834a3e11..3e707daa1 100644
--- a/public/react/src/modules/developer/components/initTabCtx/index.js
+++ b/public/react/src/modules/developer/components/initTabCtx/index.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 19:46:14
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 17:38:42
+ * @LastEditTime: 2019-12-19 10:47:05
*/
import './index.scss';
import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react';
@@ -26,6 +26,7 @@ function InitTabCtx (props, ref) {
const { inputValue, onDebuggerCode } = props;
+ console.log('default value', inputValue);
useImperativeHandle(ref, () => ({
handleTestCodeFormSubmit: (cb) => {
// console.log('父组件调用我啦~~~~~~~~~');
@@ -33,6 +34,10 @@ function InitTabCtx (props, ref) {
}
}));
+ useEffect(() => {
+ console.log('初始值: ========', props);
+ }, [props]);
+
// 渲染文本提示信息
const renderText = () => (
请在这里添加测试用例,点击“调试代码”时将从这里读取输入来测试你的代码...);
// 渲染表单信息
diff --git a/public/react/src/modules/developer/components/initTabCtx/index.scss b/public/react/src/modules/developer/components/initTabCtx/index.scss
index 449db1d2a..5427aa374 100644
--- a/public/react/src/modules/developer/components/initTabCtx/index.scss
+++ b/public/react/src/modules/developer/components/initTabCtx/index.scss
@@ -49,7 +49,8 @@
}
.input_textarea_style{
- background:rgba(30,30,30,1) !important;
+ // background:rgba(30,30,30,1) !important;
+ background:rgba(7,15,25,1) !important;
color: #fff;
border-color: transparent;
outline: none;
diff --git a/public/react/src/modules/developer/components/monacoSetting/index.js b/public/react/src/modules/developer/components/monacoSetting/index.js
index a101819e0..669439577 100644
--- a/public/react/src/modules/developer/components/monacoSetting/index.js
+++ b/public/react/src/modules/developer/components/monacoSetting/index.js
@@ -4,10 +4,11 @@
* @Github:
* @Date: 2019-11-25 17:50:33
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-06 16:51:48
+ * @LastEditTime: 2019-12-19 19:32:08
*/
import React, { useState } from 'react';
import { fromStore, toStore } from 'educoder';
+// import { Icon } from 'antd';
// import { Select } from 'antd';
// const { Option } = Select;
const SettingDrawer = (props) => {
diff --git a/public/react/src/modules/developer/components/myMonacoEditor/index.js b/public/react/src/modules/developer/components/myMonacoEditor/index.js
index 60f54ee0a..948d5a4f5 100644
--- a/public/react/src/modules/developer/components/myMonacoEditor/index.js
+++ b/public/react/src/modules/developer/components/myMonacoEditor/index.js
@@ -4,12 +4,12 @@
* @Github:
* @Date: 2019-11-27 15:02:52
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 16:16:56
+ * @LastEditTime: 2019-12-19 19:36:24
*/
import './index.scss';
import React, { useState, useRef, useEffect } from 'react';
-import { Drawer, Modal } from 'antd';
-import { fromStore } from 'educoder';
+import { Drawer, Modal, Icon, Badge } from 'antd';
+import { fromStore, CNotificationHOC } from 'educoder';
import { connect } from 'react-redux';
import MonacoEditor from '@monaco-editor/react';
import SettingDrawer from '../../components/monacoSetting';
@@ -19,16 +19,25 @@ import MyIcon from '../../../../common/components/MyIcon';
// import actions from '../../../../redux/actions';
const { fontSetting, opacitySetting } = CONST;
+const maps = {
+ 'c': 'main.c',
+ 'c++': 'main.cc',
+ 'java': 'main.java',
+ 'pythone': 'main.py'
+};
function MyMonacoEditor (props, ref) {
const {
+ notice,
language,
identifier,
+ hadCodeUpdate,
showOrHideControl,
// saveUserInputCode,
onCodeChange,
- onRestoreInitialCode
+ onRestoreInitialCode,
+ onUpdateNotice
} = props;
const [showDrawer, setShowDrawer] = useState(false); // 控制配置滑框
@@ -50,7 +59,7 @@ function MyMonacoEditor (props, ref) {
}, [props]);
useEffect(() => {
- setHeight(showOrHideControl ? 'calc(100% - 382px)' : 'calc(100% - 56px)');
+ setHeight(showOrHideControl ? 'calc(100% - 378px)' : 'calc(100% - 56px)');
}, [showOrHideControl]);
// 控制侧边栏设置的显示
@@ -93,28 +102,51 @@ function MyMonacoEditor (props, ref) {
// 恢复初始代码
const handleRestoreCode = () => {
- Modal.confirm({
+ props.confirm({
+ title: '提示',
content: '确定要恢复代码吗?',
- okText: '确定',
- cancelText: '取消',
onOk () {
onRestoreInitialCode && onRestoreInitialCode();
}
})
+ // Modal.confirm({
+ // content: '确定要恢复代码吗?',
+ // okText: '确定',
+ // cancelText: '取消',
+ // onOk () {
+ // onRestoreInitialCode && onRestoreInitialCode();
+ // }
+ // })
+ }
+
+ const handleUpdateNotice = () => {
+ if (props.notice) {
+ onUpdateNotice && onUpdateNotice();
+ }
}
const renderRestore = identifier ? (
) : '';
+
+ // lex_has_save ${hadCodeUpdate} ? : ''
+ const _classnames = hadCodeUpdate ? `flex_strict flex_has_save` : 'flex_strict';
return (
{/* 未保存时 ? '学员初始代码文件' : main.x */}
- {identifier ? '' : '学员初始代码文件'}
- {identifier ? '已保存' : ''}
- {renderRestore}
- {/* */}
+ {identifier ? language ? maps[language.toLowerCase()] : '' : '学员初始代码文件'}
+ {identifier ? '已保存' : ''}
+
+
+
+ {renderRestore}
@@ -161,4 +192,4 @@ const mapDispatchToProps = (dispatch) => ({
export default connect(
mapStateToProps,
mapDispatchToProps
-)(MyMonacoEditor);
+)(CNotificationHOC() (MyMonacoEditor));
diff --git a/public/react/src/modules/developer/components/myMonacoEditor/index.scss b/public/react/src/modules/developer/components/myMonacoEditor/index.scss
index 7a7c4f030..61689b51e 100644
--- a/public/react/src/modules/developer/components/myMonacoEditor/index.scss
+++ b/public/react/src/modules/developer/components/myMonacoEditor/index.scss
@@ -1,19 +1,17 @@
.monaco_editor_area{
height: 100%;
- background-color: rgba(30,30,30,1);
+ background-color: rgba(7,15,25,1);
.code_title{
display: flex;
align-items: center;
- // justify-content: space-between;
- // background: #000;
- // background: #333333;
- background-color: rgba(48,48,48,1);
+ background-color: rgba(18,28,36,1);
color: #fff;
height: 56px;
padding: 0 30px;
.flex_strict{
flex: 1;
}
+
.flex_normal{
color: #E51C24;
cursor: pointer;
@@ -25,21 +23,21 @@
.flex_strict,
.flex_normal,
.code-icon{
- color: #888;
+ color: #666;
}
}
}
.setting_drawer{
- // .ant-drawer-body{
- // // height: calc(100vh - 120px);
- // // overflow-y: auto;
- // }
+ .ant-drawer-close{
+ color: #ffffff;
+ }
.ant-drawer-content{
top: 120px;
bottom: 56px;
height: calc(100vh - 176px);
- background: #333333;
+ // background: #333333;
+ background: rgba(7,15,25,1);
color: #fff;
.setting_h2{
color: #fff;
@@ -57,4 +55,17 @@
color: #fff;
}
}
+}
+
+.flex_has_save{
+ // animation: blink 3s line 3;
+ animation-name: blink;
+ animation-duration: .4s;
+ animation-iteration-count: 3;
+}
+
+@keyframes blink{
+ 50% {
+ color: #fff;
+ }
}
\ No newline at end of file
diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
index bc905fdf7..1c451c669 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -13,11 +13,11 @@ import { Button, Modal } from 'antd';
import LeftPane from './leftpane';
import RightPane from './rightpane';
import { withRouter } from 'react-router';
-import { toStore } from 'educoder';
+import { toStore, CNotificationHOC } from 'educoder';
import UserInfo from '../components/userInfo';
// import RightPane from './rightpane/index';
import actions from '../../../redux/actions';
-import {ModalConfirm} from '../../../common/components/ModalConfirm';
+// import {ModalConfirm} from '../../../common/components/ModalConfirm';
const NewOrEditTask = (props) => {
const {
@@ -69,10 +69,13 @@ const NewOrEditTask = (props) => {
// 模拟挑战
const imitationChallenge = () => {
+ // 调用 start 接口, 成功后跳转到模拟页面
+ startProgramQuestion(identifier, props);
}
// 开始挑战
const startChallenge = () => {
- // 调用 start 接口, 成功后跳转到模拟页面
+ // 调用 start 接口, 成功后跳转到开启实战
+ // TODO
startProgramQuestion(identifier, props);
}
@@ -82,27 +85,38 @@ const NewOrEditTask = (props) => {
props.clearOJFormStore();
// 清空描述信息
toStore('oj_description', '');
- setInterval(function () {
- props.history.push('/problems');
- }, 500);
+ props.history.push('/problems');
}
// 发布
const handleClickPublish = () => {
- ModalConfirm('提示', (发布后即可应用到自己管理的课堂
是否确认发布?
), () => {
- changePublishLoadingStatus(true);
- handlePublish(props, 'publish');
+ // ModalConfirm('提示', (发布后即可应用到自己管理的课堂
是否确认发布?
), () => {
+ // changePublishLoadingStatus(true);
+ // handlePublish(props, 'publish');
+ // });
+ props.confirm({
+ title: '提示',
+ content: (发布后即可应用到自己管理的课堂
是否确认发布?
),
+ onOk () {
+ changePublishLoadingStatus(true);
+ handlePublish(props, 'publish');
+ }
});
-
-
}
// 撤销发布
const handleClickCancelPublish = () => {
- ModalConfirm('提示', (是否确认撤销发布?
), () => {
- changePublishLoadingStatus(true);
- handleCancelPublish(props, identifier);
+ // ModalConfirm('提示', (是否确认撤销发布?
), () => {
+ // changePublishLoadingStatus(true);
+ // handleCancelPublish(props, identifier);
+ // });
+ props.confirm({
+ title: '提示',
+ content: ((是否确认撤销发布?
)),
+ onOk () {
+ changePublishLoadingStatus(true);
+ handleCancelPublish(props, identifier);
+ }
});
-
}
// 取消保存/取消按钮
@@ -125,6 +139,7 @@ const NewOrEditTask = (props) => {
const renderPubOrFight = () => {
const pubButton = isPublish
? ( {
模拟挑战
);
- // 更新
- // const updateBtn = isPublish
- // ? ''
- // : (
- // 更新
- // );
- return (
-
- 更新
- {pubButton}
- {challengeBtn}
-
- )
+ if (isPublish) {
+ return (
+
+ {pubButton}
+ 保存
+ {challengeBtn}
+
+ );
+ } else {
+ return (
+
+ 保存
+ {pubButton}
+ {challengeBtn}
+
+ );
+ }
+
}
// 渲染退出
const renderQuit = () => {
return identifier ? (
退出
) : ''
@@ -255,4 +271,4 @@ const mapDispatchToProps = (dispatch) => ({
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
-)(NewOrEditTask));
+)(CNotificationHOC() (NewOrEditTask)));
diff --git a/public/react/src/modules/developer/newOrEditTask/index.scss b/public/react/src/modules/developer/newOrEditTask/index.scss
index ba0ed8503..ad668fcc8 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.scss
+++ b/public/react/src/modules/developer/newOrEditTask/index.scss
@@ -10,9 +10,23 @@
align-items: center;
justify-content: center;
height: 56px;
- background: #333333;
+ // background: #333333;
+ background: rgba(18,28,36,1);
> button{
margin-right: 20px;
}
}
+.quite_btn{
+ position: absolute;
+ right: 10px;
+ top: 15px;
+ margin-left: 30px;
+ color: #888888;
+ transition: all .3s;
+ cursor: pointer;
+ &:hover{
+ color: #5091FF;
+ }
+}
+
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js
index 4c4131fa9..8e7aa70fc 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js
@@ -4,13 +4,14 @@
* @Github:
* @Date: 2019-11-21 09:19:38
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 11:58:46
+ * @LastEditTime: 2019-12-19 17:54:28
*/
import './index.scss';
import React, { useState } from 'react';
-import { Collapse, Icon, Input, Form, Button, Modal } from 'antd';
+import { Collapse, Icon, Input, Form, Button } from 'antd';
import { connect } from 'react-redux';
import actions from '../../../../../redux/actions';
+import { CNotificationHOC} from 'educoder';
const { Panel } = Collapse;
const { TextArea } = Input;
const FormItem = Form.Item;
@@ -31,15 +32,22 @@ const AddTestDemo = (props) => {
// console.log('点击的删除按钮')
e.preventDefault();
e.stopPropagation();
- Modal.confirm({
- title: '删除',
+ props.confirm({
+ title: '提示',
content: '确定要删除当前测试用例吗?',
- okText: '确定',
- cancelText: '取消',
onOk() {
onDeleteTest(testCase);
}
- })
+ });
+ // Modal.confirm({
+ // title: '删除',
+ // content: '确定要删除当前测试用例吗?',
+ // okText: '确定',
+ // cancelText: '取消',
+ // onOk() {
+ // onDeleteTest(testCase);
+ // }
+ // })
}
// 输入框值改变时
@@ -189,4 +197,4 @@ const mapDispatchToProps = (dispatch) => ({
export default connect(
mapStateToProps,
mapDispatchToProps
-)(Form.create()(AddTestDemo));
+)(Form.create()(CNotificationHOC()(AddTestDemo)));
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
index 762d1d3ba..da31754bd 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
@@ -4,21 +4,20 @@
* @Github:
* @Date: 2019-11-20 10:35:40
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 11:39:52
+ * @LastEditTime: 2019-12-19 17:23:10
*/
-import 'quill/dist/quill.core.css';
-import 'quill/dist/quill.bubble.css';
-import 'quill/dist/quill.snow.css';
import './index.scss';
// import 'katex/dist/katex.css';
import React from 'react';
import { Form, Input, Select, InputNumber, Button } from 'antd';
import { connect } from 'react-redux';
import AddTestDemo from './AddTestDemo';
-import QuillEditor from '../../../quillEditor';
+// import QuillEditor from '../../../quillEditor';
import actions from '../../../../../redux/actions';
import CONST from '../../../../../constants';
-import { fromStore, toStore } from 'educoder'; // 保存和读取store值
+import { toStore } from 'educoder'; // 保存和读取store值
+// import Wrapper from '../../../../../common/reactQuill';
+import QuillForEditor from '../../../../../common/quillForEditor';
const scrollIntoView = require('scroll-into-view');
const {jcLabel} = CONST;
const FormItem = Form.Item;
@@ -26,9 +25,9 @@ const { Option } = Select;
const maps = {
language: [
{ title: 'C', key: 'C' },
- // { title: 'C++', key: 'C++' },
- // { title: 'Python', key: 'Python' },
- // { title: 'Java', key: 'Java' }
+ { title: 'C++', key: 'C++' },
+ { title: 'Python', key: 'Python' },
+ { title: 'Java', key: 'Java' }
],
difficult: [
{ title: '简单', key: '1' },
@@ -146,9 +145,6 @@ class EditTab extends React.Component {
testCasesValidate,
openTestCodeIndex = []
} = this.props;
- // console.log('当前位置: ', position);
- // console.log('OJForm: ', ojForm);
- // console.log('当前位置: ', testCases);
// 表单label
const myLabel = (name, subTitle) => {
if (subTitle) {
@@ -185,7 +181,6 @@ class EditTab extends React.Component {
};
const renderTestCase = () => {
return this.props.testCases.map((item, i) => {
- console.log(111);
return {
+ console.log('描述信息为: ', content);
+ // 保存获取的描述信息至redux中
+ this.handleChangeDescription(content);
+ }
// 编辑器配置信息
const quillConfig = [
[{ header: [1, 2, 3, 4, 5, 6, false] }],
['bold', 'italic', 'underline', 'strike'], // 切换按钮
['blockquote', 'code-block'], // 代码块
- [{ 'list': 'ordered' }, { 'list': 'bullet' }], // 列表
+ [{align: []}, { 'list': 'ordered' }, { 'list': 'bullet' }], // 列表
[{ 'script': 'sub'}, { 'script': 'super' }],
[{ 'color': [] }, { 'background': [] }], // 字体颜色与背景色
- ['formula', 'image', 'video'], // 数学公式、图片、视频
+ ['image', 'formula'], // 数学公式、图片、视频
['clean'], // 清除格式
];
+
return (
{/* 添加测试用例 */}
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss
index f8fa3bd71..17f3eae34 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss
@@ -49,6 +49,11 @@
.test_demo_ctx,
.editor_form{
margin: 0 30px;
+
+ .ant-form-explain{
+ margin-top: 5px;
+ margin-left: -10px;
+ }
}
.test_demo_title{
display: flex;
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
index 8b10413a9..781b82699 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
@@ -34,28 +34,6 @@ function LeftPane (props) {
const [defaultActiveKey, setDefaultActiveKey] = useState('editor');
- // const tabArrs = [
- // { title: '编辑', key: 'editor', content: (
) },
- // { title: '预览', key: 'prev', content: (
) },
- // // { title: '提交记录', key: 'commit', content: (
) },
- // ];
-
- // const tabs = tabArrs.map((tab) => {
- // const Comp = tab.content;
- // return (
- //
- // { Comp }
- //
- // )
- // });
-
- // tab切换时
- // const handleTabChange = (key) => {
- // setDefaultActiveKey(key);
- // }
-
- // 执行表单提交函数
-
const renderComp = useMemo(() => {
return Comp[defaultActiveKey];
}, [defaultActiveKey]);
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js
index c45628973..6b41d3489 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js
@@ -4,74 +4,47 @@
* @Github:
* @Date: 2019-11-24 10:09:55
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-04 23:38:37
+ * @LastEditTime: 2019-12-18 10:02:24
*/
import './index.scss';
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import {Empty} from 'antd';
-// import QuillEditor from '../../../quillEditor';
-const Quill = window.Quill;
+// import Wrapper from '../../../../../common/reactQuill';
+import QuillForEditor from '../../../../../common/quillForEditor';
const PrevTab = (props) => {
- const {
- description
- } = props;
const prevRef = useRef(null);
- const [desc, setDesc] = useState('');
- const [renderCtx, setRenderCtx] = useState(() => {
- return function () {
- return '';
- }
- });
-
- // 空内容
- const renderTxt = () => (
-
-
-
- );
+ // const [desc, setDesc] = useState('');
+ const [renderCtx, setRenderCtx] = useState(() => '');
+
// 渲染内容
- const renderQuill = () => (
-
-
- );
-
useEffect(() => {
- setDesc(description);
- }, [description]);
-
- useEffect(() => {
- if (description) {
- setRenderCtx(() => renderQuill);
- let count = 0;
- let timer = setInterval(() => {
- count++;
- if (count >= 10 || prevRef.current) {
- clearInterval(timer);
- timer = null;
- if (prevRef.current) {
- const quillEditor = new Quill(prevRef.current, {
- readOnly: true,
- theme: 'bubble'
- });
- quillEditor.container.firstChild.innerHTML = description;
- }
- }
- }, 50);
+ if (props.description) {
+ setRenderCtx(() => (
+
+
+
+ ));
} else {
- setRenderCtx(() => renderTxt);
+ setRenderCtx(() => (
+
+
+
+ ));
}
-
- }, [description]);
+ }, [props]);
return (
- {renderCtx()}
+ {renderCtx}
)
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss
index 48f5a7bb9..9c472b641 100644
--- a/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss
+++ b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss
@@ -1,7 +1,7 @@
.right_pane_code_wrap{
position: relative;
// justify-content: center;
- background-color: #222;
+ // background-color: #222;
height: 100%;
// height: calc(100vh - 178px);
.code-title,
@@ -11,7 +11,8 @@
align-items: center;
justify-content: space-between;
// padding: 0 30px;
- background: #000;
+ // background: #000;
+ background: rgba(18,28,36,1);
color: #fff;
}
.code-title,
diff --git a/public/react/src/modules/developer/split_pane_resizer.scss b/public/react/src/modules/developer/split_pane_resizer.scss
index 498370dd6..2898d966c 100644
--- a/public/react/src/modules/developer/split_pane_resizer.scss
+++ b/public/react/src/modules/developer/split_pane_resizer.scss
@@ -8,7 +8,8 @@
.record_detail_header{
height: 65px;
// background:rgba(34,34,34,1);
- background: #1E1E1E;
+ // background: #1E1E1E;
+ background: rgba(7,15,25,1);
padding:0 30px;
}
@@ -123,7 +124,8 @@
.split-pane-area,
.split-pane-left{
.ant-tabs-nav-wrap{
- padding: 0 30px;
+ // padding: 0 30px;
+ padding: 0 20px;
}
.ant-tabs-bar{
margin: 0;
diff --git a/public/react/src/modules/developer/studentStudy/index.js b/public/react/src/modules/developer/studentStudy/index.js
index e4b296a20..15c87e64c 100644
--- a/public/react/src/modules/developer/studentStudy/index.js
+++ b/public/react/src/modules/developer/studentStudy/index.js
@@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-23 10:53:19
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 17:19:15
+ * @LastEditTime: 2019-12-19 19:48:20
*/
import './index.scss';
import React, { useEffect, useState } from 'react';
@@ -15,10 +15,10 @@ import RightPane from './rightpane';
// import { Link } from 'react-router-dom';
// import { getImageUrl } from 'educoder'
// import RightPane from '../newOrEditTask/rightpane';
-import { Icon, Modal } from 'antd';
+import { Icon } from 'antd';
import UserInfo from '../components/userInfo';
import actions from '../../../redux/actions';
-import { fromStore} from 'educoder';
+import { fromStore, CNotificationHOC} from 'educoder';
import { withRouter } from 'react-router';
function StudentStudy (props) {
@@ -29,7 +29,8 @@ function StudentStudy (props) {
userInfo,
hack_identifier,
// user_program_identifier,
- restoreInitialCode
+ restoreInitialCode,
+ changeShowOrHideControl
} = props;
const {
@@ -51,32 +52,51 @@ function StudentStudy (props) {
const { hack = {} } = props;
if (hack.modify_code && hasUpdate) { // 代码更改,提示是否需要更新代码
setHasUpdate(false);
- Modal.confirm({
- title: '提示',
- content: (
-
- 代码文件有更新啦
- 还未提交的代码,请自行保存
-
- ),
- okText: '立即更新',
- cancelText: '稍后再说',
- onOk () {
- restoreInitialCode(id, '更新成功');
- }
- });
+ handleUpdateNotice();
}
}, [props, hasUpdate, setHasUpdate]);
+ const handleUpdateNotice = () => {
+ console.log(props);
+ props.confirm({
+ title: '提示',
+ content: (
+
+ 代码文件有更新啦
+ 还未提交的代码,请自行保存
+
+ ),
+ onOk () {
+ restoreInitialCode(id, '更新成功');
+ }
+ })
+ // Modal.confirm({
+ // title: '提示',
+ // content: (
+ //
+ // 代码文件有更新啦
+ // 还未提交的代码,请自行保存
+ //
+ // ),
+ // okText: '立即更新',
+ // cancelText: '稍后再说',
+ // onOk () {
+ // restoreInitialCode(id, '更新成功');
+ // }
+ // });
+ }
const _hack_id = hack_identifier || fromStore('hack_identifier');
// 处理编辑
const handleClickEditor = () => {
+ changeShowOrHideControl(false);
props.saveEditorCodeForDetail();
props.history.push(`/problems/${_hack_id}/edit`);
}
// 处理退出
const handleClickQuit = () => {
+ // 将控制台关闭
+ changeShowOrHideControl(false);
props.saveEditorCodeForDetail();
props.history.push('/problems');
}
@@ -117,7 +137,9 @@ function StudentStudy (props) {
-
+
@@ -146,11 +168,12 @@ const mapDispatchToProps = (dispatch) => ({
saveEditorCodeForDetail: (code) => dispatch(actions.saveEditorCodeForDetail(code)),
// 恢复初始代码
restoreInitialCode: (identifier, msg) => dispatch(actions.restoreInitialCode(identifier, msg)),
+ changeShowOrHideControl: (flag) => dispatch(actions.changeShowOrHideControl(flag))
});
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
-)(StudentStudy));
+)(CNotificationHOC()(StudentStudy)));
diff --git a/public/react/src/modules/developer/studentStudy/index.scss b/public/react/src/modules/developer/studentStudy/index.scss
index bbf66aebb..68835f2ce 100644
--- a/public/react/src/modules/developer/studentStudy/index.scss
+++ b/public/react/src/modules/developer/studentStudy/index.scss
@@ -5,6 +5,6 @@
.right_pane_code_wrap{
position: relative;
- background-color: #222;
+ // background-color: #222;
height: 100%;
}
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js
index 329e8fba1..ca7160117 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js
+++ b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.js
@@ -4,15 +4,18 @@
* @Github:
* @Date: 2019-11-27 09:49:35
* @LastEditors: tangjiang
- * @LastEditTime: 2019-11-27 09:52:53
+ * @LastEditTime: 2019-12-17 17:46:05
*/
+import './index.scss';
import React from 'react';
-
-const Comment = (props) => {
+import Comment from '../../../../../common/components/comment';
+const CommentTask = (props) => {
return (
- Comment
+
+
+
)
}
-export default Comment;
+export default CommentTask;
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/comment/index.scss b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.scss
new file mode 100644
index 000000000..ba9c132d9
--- /dev/null
+++ b/public/react/src/modules/developer/studentStudy/leftpane/comment/index.scss
@@ -0,0 +1,8 @@
+.task_comment_task{
+ background: #fff;
+ padding: 20px 30px 0;
+ height: calc(100vh - 177px);
+ box-sizing: border-box;
+ overflow-y: auto;
+ border-bottom: 1px solid rgba(244,244,244,1);
+}
\ No newline at end of file
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/index.js b/public/react/src/modules/developer/studentStudy/leftpane/index.js
index 69f49b9b1..347f4b4f8 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/index.js
+++ b/public/react/src/modules/developer/studentStudy/leftpane/index.js
@@ -4,11 +4,11 @@
* @Github:
* @Date: 2019-11-23 11:33:41
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-09 19:57:21
+ * @LastEditTime: 2019-12-19 18:03:22
// */
import './index.scss';
import React, { useState, useEffect, useMemo } from 'react';
-import { Tabs, Divider } from 'antd';
+import { Divider } from 'antd';
import { connect } from 'react-redux';
import Comment from './comment';
import CommitRecord from './commitRecord';
@@ -19,17 +19,10 @@ import actions from '../../../../redux/actions';
const LeftPane = (props) => {
- const { hack, userCodeTab, changeUserCodeTab } = props;
+ const { hack, userCodeTab } = props;
const { pass_count, submit_count } = hack;
- const [defaultActiveKey, setDefaultActiveKey] = useState('task');
+ const [defaultActiveKey, setDefaultActiveKey] = useState('comment');
- console.log(pass_count, submit_count);
- const tabArrs = [
- { title: '任务描述', key: 'task', content: () },
- { title: '提交记录', key: 'record', content: () },
- // { title: '评论', key: 'comment', content: () },
- ];
-
const navItem = [
{
title: '任务描述',
@@ -38,38 +31,30 @@ const LeftPane = (props) => {
{
title: '提交记录',
key: 'record'
- }
+ },
+ // {
+ // title: '评论',
+ // key: 'comment'
+ // }
];
const Comp = {
task: (),
- record: ()
+ record: (),
+ comment: ()
};
useEffect(() => {
+ console.log('====>>>>', userCodeTab);
setDefaultActiveKey(userCodeTab);
}, [userCodeTab])
- // const tabs = tabArrs.map((tab) => {
- // const Comp = tab.content;
- // return (
- //
- // { Comp }
- //
- // )
- // });
-
- // // tab切换时
- // const handleTabChange = (key) => {
- // // setDefaultActiveKey(key);
- // changeUserCodeTab(key);
- // }
-
const renderComp = useMemo(() => {
return Comp[defaultActiveKey];
- }, [defaultActiveKey]);
+ }, [defaultActiveKey, setDefaultActiveKey]);
const renderNavItem = navItem.map((item) => {
+
const _classes = item.key === defaultActiveKey ? 'add_editor_item active' : 'add_editor_item';
return (
{
return (
- {/*
- { tabs }
-
- */}
@@ -126,11 +96,6 @@ const LeftPane = (props) => {
- {/*
-
-
-
-
*/}
);
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/index.scss b/public/react/src/modules/developer/studentStudy/leftpane/index.scss
index 9e6f019f6..1582c033f 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/index.scss
+++ b/public/react/src/modules/developer/studentStudy/leftpane/index.scss
@@ -13,6 +13,8 @@
bottom: 0px;
height: 56px;
width: 100%;
+ box-sizing: border-box;
+ border-top: 1px solid rgba(244,244,244,1);
// background: pink;
padding: 0 30px;
// background-color: rgba(250,250,250,1);
@@ -79,4 +81,9 @@
margin-right: 5px;
}
}
+}
+
+.add_editor_list_area{
+ box-sizing: border-box;
+ border-bottom: 1px solid rgba(244,244,244,1);
}
\ No newline at end of file
diff --git a/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js b/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js
index 28fe51765..981770b8c 100644
--- a/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js
+++ b/public/react/src/modules/developer/studentStudy/leftpane/taskDescription/index.js
@@ -4,14 +4,15 @@
* @Github:
* @Date: 2019-11-27 09:49:30
* @LastEditors: tangjiang
- * @LastEditTime: 2019-12-09 19:21:55
+ * @LastEditTime: 2019-12-19 09:22:52
*/
import '../index.scss';
import React from 'react';
import { Tag } from 'antd';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
-import QuillEditor from '../../../quillEditor';
+import QuillForEditor from '../../../../../common/quillForEditor';
+
import CONST from '../../../../../constants';
const {tagBackground, diffText} = CONST;
@@ -36,22 +37,15 @@ const TaskDescription = (props) => {