Merge branches 'dev_aliyun' and 'dev_item_bank' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_item_bank

yslnewtiku
杨树林 5 years ago
commit 22f1921710

@ -32,7 +32,12 @@ class CommentsController < ApplicationController
# 列表
def index
discusses = @hack.discusses.where(root_id: nil)
discusses =
if current_user.admin_or_business?
@hack.discusses.where(root_id: nil)
else
@hack.discusses.where(root_id: nil, hidden: false)
end
@discusses_count = discusses.count
@discusses= paginate discusses
end
@ -45,8 +50,9 @@ class CommentsController < ApplicationController
# 隐藏、取消隐藏
def hidden
if @hack.manager?(current_user)
@discuss.update_attribute(:hidden, params[:hidden] == "1")
if current_user.admin_or_business?
@discuss = @hack.discusses.where(id: params[:id]).first
@discuss.update_attribute(:hidden, params[:hidden].to_i == 1)
sucess_status
else
Educoder::TipException(403, "..")

@ -98,12 +98,20 @@ class HacksController < ApplicationController
# 发布功能
def publish
@hack.update_attribute(:status, 1)
base_attrs = {
trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id,
}
@hack.tidings.create!(base_attrs)
render_ok
end
# 取消发布
def cancel_publish
@hack.update_attribute(:status, 0)
base_attrs = {
trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id
}
@hack.tidings.create!(base_attrs)
render_ok
end

@ -266,8 +266,20 @@ class ShixunsController < ApplicationController
# 如果是jupyter先创建一个目录,为了挂载(因为后续数据集开启Pod后环境在没销毁前你上传数据集是挂载不上目录的因此要先创建目录方便中间层挂载)
if @new_shixun.is_jupyter?
folder = EduSetting.get('shixun_folder')
raise "存储目录未定义" unless folder.present?
path = "#{folder}/#{@new_shixun.identifier}"
FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
# 复制数据集
save_path = File.join(folder, @shixun.identifier)
@shixun.data_sets.each do |set|
new_date_set = Attachment.new
new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory")
new_date_set.container_id = @new_shixun.id
new_date_set.disk_directory = @new_shixun.identifier
new_date_set.save!
FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path)
end
end
# 同步复制关卡
if @shixun.challenges.present?

@ -216,10 +216,10 @@ class SubjectsController < ApplicationController
@shixun.update_column(:repo_name, repo_path.split(".")[0])
mirror_id =
if @shixun.is_jupyter?
MirrorRepository.where("type_name like '%Jupyter%'").first&.id
folder = EduSetting.get('shixun_folder')
path = "#{folder}/#{identifier}"
FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
MirrorRepository.where("type_name like '%Jupyter%'").first&.id
else
MirrorRepository.find_by(type_name: 'Python3.6')&.id
end

@ -250,6 +250,9 @@ module TidingDecorator
when 'shixunPublish' then
name = Shixun.find_by(id: parent_container_id)&.name || '---'
I18n.t(locale_format(parent_container_type)) % [name, container.score]
when 'Hack' then
name = Hack.find_by(id: container_id)&.name || '---'
I18n.t(locale_format(parent_container_type)) % [name, container.score]
else
I18n.t(locale_format(parent_container_type)) % container.score
end

@ -52,16 +52,19 @@ class Discuss < ApplicationRecord
private
def send_tiding
if dis_type == 'Shixun'
user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id
parent_container_type = 'Challenge'
challenge_id = challenge_id
elsif dis_type == 'Hack'
user_id = has_parent? ? parent.user_id : Hack.find(dis_id).user_id
parent_container_type = 'Hack'
challenge_id = nil
end
base_attrs = {
trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: 'Challenge',
belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment'
trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: parent_container_type,
belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment'
}
user_id =
if dis_type == 'Shixun'
has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id
elsif dis_type == 'Hack'
has_parent? ? parent.user_id : Hack.find(dis_id).user_id
end
tidings.create!(base_attrs.merge(user_id: user_id))
end
end

@ -13,6 +13,8 @@ class Hack < ApplicationRecord
has_many :discusses, as: :dis, dependent: :destroy
# 点赞
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
# 消息
has_many :tidings, as: :container, dependent: :destroy
belongs_to :user
@ -21,6 +23,8 @@ class Hack < ApplicationRecord
scope :opening, -> {where(open_or_not: 1)}
scope :mine, -> (author_id){ where(user_id: author_id) }
after_destroy :send_delete_tiding
def language
if hack_codes.count == 1
hack_codes.first.language
@ -49,4 +53,12 @@ class Hack < ApplicationRecord
user_id == user.id || user.admin_or_business?
end
private
def send_delete_tiding
base_attrs = {
user_id: user_id, viewed: 0, tiding_type: 'Delete', trigger_user_id: current_user.id, content: "你删除了题目:#{name}"
}
tidings.create!(base_attrs)
end
end

@ -12,7 +12,7 @@ class PraiseTread < ApplicationRecord
case self.praise_tread_object_type
when "Memo","Message","Issue"
self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.author_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise")
when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask"
when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask", "Hack"
self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.user_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise")
end
end

@ -79,7 +79,7 @@ class Subjects::CopySubjectService < ApplicationService
copy_shixun_service_configs_data!(shixun, to_shixun)
copy_challenges_data!(shixun, to_shixun)
copy_shixun_members_data!(to_shixun)
copy_jupyter_data_sets(shixun, to_shixun) if shixun.is_jupyter?
# 云上实验室
if laboratory
laboratory.laboratory_shixuns.create(shixun: to_shixun)
@ -87,6 +87,25 @@ class Subjects::CopySubjectService < ApplicationService
to_shixun
end
# 复制jupyter的数据集
def copy_jupyter_data_sets(shixun, to_shixun)
return unless shixun.is_jupyter?
folder = EduSetting.get('shixun_folder')
raise "存储目录未定义" unless folder.present?
path = "#{folder}/#{to_shixun.identifier}"
FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
# 复制数据集
save_path = File.join(folder, shixun.identifier)
shixun.data_sets.each do |set|
new_date_set = Attachment.new
new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory")
new_date_set.container_id = to_shixun.id
new_date_set.disk_directory = to_shixun.identifier
new_date_set.save!
FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path)
end
end
# 创建实训长字段内容
def copy_shixun_info_data!(shixun, to_shixun)
to_shixun_info = ShixunInfo.new

@ -5,10 +5,12 @@ json.id discuss.id
json.content content_safe(discuss.content)
json.time time_from_now(discuss.created_at)
json.hack_id discuss.dis_id
json.hidden discuss.hidden
# 主贴和回复有一些不同点
if discuss.parent_id
json.can_delete discuss.can_deleted?(current_user)
else
json.praise_count discuss.praises_count
json.user_praise discuss.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0
json.can_delete discuss.can_deleted?(current_user) && child.count == 0
end

@ -1,6 +1,6 @@
json.disscuss_count @discusses_count
json.comments @discusses do |discuss|
json.partial! 'comments/discuss', locals: { discuss: discuss}
json.partial! 'comments/discuss', locals: { discuss: discuss, child: discuss.child_discuss(current_user)}
json.children discuss.child_discuss(current_user) do |c_d|
json.partial! 'comments/discuss', locals: { discuss: c_d }
end

@ -1,5 +1,5 @@
json.status 0
json.message "评测成"
json.message "评测成"
json.data do
json.(@result, :id, :status, :error_line, :error_msg,
:input, :output, :execute_time, :execute_memory)

@ -1,5 +1,5 @@
json.hack do
json.(@hack, :name, :difficult, :time_limit, :description, :score, :identifier, :status, :praises_count)
json.(@hack, :id, :name, :difficult, :time_limit, :description, :score, :identifier, :status, :praises_count)
json.language @hack.language
json.username @hack.user.real_name
json.code @my_hack.code
@ -7,6 +7,7 @@ json.hack do
json.submit_count @hack.submit_num
json.modify_code @modify
json.comments_count @hack.discusses.count
json.user_praise @hack.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0
end
json.test_case do
@ -16,5 +17,6 @@ end
json.user do
json.partial! 'users/user', user: current_user
json.hack_manager @hack.manager?(current_user)
json.admin current_user.admin_or_business?
end

@ -5,7 +5,10 @@ json.data_sets do
json.author set.author.real_name
json.created_on set.created_on
json.filesize number_to_human_size(set.filesize)
json.file_path "#{@absolute_folder}/#{set.relative_path_filename}"
# 这里需要去除shixunfiles目录后的标识因为Jupyter代码里面会写死这样的路径当实训fork后这个版本库的路径无法修改因此给用户展示的
# 还是/data/shixunfiles/+文件名这种形式
json.file_path "#{@absolute_folder}/#{set.relative_path_filename}".gsub("/#{@shixun.identifier}", "")
end
end
json.data_sets_count @data_count
json.folder_name @absolute_folder

@ -118,6 +118,7 @@
Answer:
true_end: "查看实训%s第%s关的参考答案消耗金币%s金币"
false_end: "查看实训的参考答案消耗金币:%s金币"
Hack_end: "完成题目解答:%s获得金币奖励%s金币"
Game_end: "通过实训%s的第%s关获得金币奖励%s金币"
Memo_end: "发布的评论或者帖子获得平台奖励:%s金币"
Discusses_end: "发布的评论获得金币奖励:%s金币"

@ -79,6 +79,8 @@ Rails.application.routes.draw do
resources :comments do
collection do
post :reply
end
member do
post :hidden
end
end

@ -1883,9 +1883,8 @@ a:hover.task_icons_close{background: url(../images/popup/sy_icons_close.png) -40
.newupload_nav li:last-child{ border-right: none;}
.newupload_nav li a{font-size:12px; color:#444;}
.newupload_nav_hover{ background: #3498db; }
.newupload_nav_nomal { }
.newupload_nav_hover a{color: #fff !important; }
.markdown-body { text-align: justify;word-break: break-all;}
.bor-reds{
border:1px solid #FF0000!important;
border-radius: 4px;
@ -1894,6 +1893,7 @@ a:hover.task_icons_close{background: url(../images/popup/sy_icons_close.png) -40
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
@charset "UTF-8";
/*!

@ -2934,7 +2934,7 @@ a.singlepublishtwo{
padding: 40px !important;
}
.editormd-html-preview{
width: 94% !important;
width: 100% !important;
color: #323232 !important;
}
#homework_editorMd_description hr{
@ -3478,3 +3478,9 @@ a.singlepublishtwo{
/*width: auto !important;*/
/*max-width: 600px !important;*/
/*}*/
.markdown-body {
text-align: justify;
word-break: break-all;
}

@ -52,7 +52,7 @@ export function initAxiosInterceptors(props) {
//proxy="http://47.96.87.25:48080"
proxy="https://pre-newweb.educoder.net"
proxy="https://test-newweb.educoder.net"
proxy="https://test-jupyterweb.educoder.net"
// proxy="https://test-jupyterweb.educoder.net"
//proxy="http://192.168.2.63:3001"
// 在这里使用requestMap控制避免用户通过双击等操作发出重复的请求

@ -3,22 +3,24 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-12-17 17:32:55
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-18 17:51:44
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 17:27:41
*/
import './index.scss';
import React, { useState } from 'react';
import { Form, Button, Input } from 'antd';
import QuillForEditor from '../../quillForEditor';
import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
// import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
import {formatDelta} from './util';
const FormItem = Form.Item;
function CommentForm (props) {
const {
commentCtxChagne,
onCancel,
onSubmit,
form
form,
type
} = props;
const { getFieldDecorator } = form;
@ -34,22 +36,25 @@ function CommentForm (props) {
// const { form: { getFieldDecorator } } = props;
const [showQuill, setShowQuill] = useState(false);
// 点击输入框
const handleInputClick = () => {
const handleInputClick = (type) => {
setShowQuill(true);
}
// 取消
const handleCancle = () => {
setShowQuill(false);
setCtx('');
props.form.resetFields();
onCancel && onCancel();
}
// 编辑器内容变化时
const handleContentChange = (content) => {
console.log('编辑器内容', content);
setCtx(content);
try {
const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert();
// const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert();
// props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')});
props.form.setFieldsValue({'comment': _html});
props.form.setFieldsValue({'comment': content});
} catch (error) {
console.log(error);
}
@ -63,13 +68,25 @@ function CommentForm (props) {
const content = ctx;
props.form.setFieldsValue({'comment': ''});
setCtx('');
console.log(content);
onSubmit && onSubmit(content);
const _html = formatDelta(content.ops);
onSubmit && onSubmit(_html);
}
});
}
const handleShowImage = (url) => {
alert(url);
}
// const _clazz = type === 'bottom' ? 'comment_form_bottom_area' : 'comment_form_area';
let _clazz;
if (type === 'bottom') {
_clazz = showQuill ? 'comment_form_bottom_area active' : 'comment_form_bottom_area';
} else {
_clazz = 'comment_form_area';
}
return (
<Form>
<Form className={_clazz}>
<FormItem>
{
getFieldDecorator('comment', {
@ -78,13 +95,13 @@ function CommentForm (props) {
],
})(
<Input
onClick={handleInputClick}
onClick={() => handleInputClick(type)}
placeholder="说点儿什么~"
className={showQuill ? '' : 'show_input'}
style={{
height: showQuill ? '0px' : '40px',
overflow: showQuill ? 'hidden' : 'auto',
opacity: showQuill ? 0 : 1,
transition: 'all .3s'
}}
/>
)
@ -98,14 +115,15 @@ function CommentForm (props) {
overflow: showQuill ? 'none' : 'hidden',
transition: 'all 0.3s'
}}
style={{ height: '150px', overflowY: 'auto' }}
style={{ height: '150px' }}
placeholder="说点儿什么~"
options={options}
value={ctx}
showUploadImage={handleShowImage}
onContentChange={handleContentChange}
/>
</FormItem>
<FormItem style={{ textAlign: 'right' }}>
<FormItem style={{ textAlign: 'right', display: showQuill ? 'block' : 'none' }}>
<Button onClick={handleCancle}>取消</Button>
<Button onClick={handleSubmit} type="primary" style={{ marginLeft: '10px'}}>发送</Button>
</FormItem>

@ -3,16 +3,19 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-12-18 10:49:46
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-18 11:39:23
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 18:04:52
*/
import './index.scss';
import React from 'react';
import { Icon } from 'antd';
// import MyIcon from '../MyIcon';
function CommentIcon ({
type, // 图标类型
count, // 评论数
iconClick,
iconColor,
theme,
...props
}) {
@ -21,10 +24,15 @@ function CommentIcon ({
iconClick && iconClick();
}
const _className = [undefined, null, ''].includes(count) ? 'comment_count_none' : 'comment_count';
return (
<span className={`comment_icon_count ${props.className}`} onClick={ handleSpanClick }>
<Icon className="comment_icon" type={type} />
<span className="comment_count">{ count }</span>
<span
style={props.style}
className={`comment_icon_count ${props.className}`}
onClick={ handleSpanClick }
>
<Icon className="comment_icon" type={type} style={{ color: iconColor }} theme={theme}/>
<span className={_className}>{ count }</span>
</span>
)
}

@ -3,104 +3,134 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-12-17 17:35:17
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-19 18:02:28
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 18:05:18
*/
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 ({
isAdmin,
options,
confirm
confirm,
comment,
submitDeleteComment,
submitChildComment,
likeComment,
showOrHideComment
}) {
// 显示评论输入框
const [showQuill, setShowQuill] = useState(false);
// 加载更多评论内容
const [showMore, setShowMore] = useState(false);
// const [showMore, setShowMore] = useState(false);
// 显示子列数
const [showItemCount, setShowItemCount] = useState(1);
// 箭头方向
const [arrow, setArrow] = useState(false);
// 删除评论
const deleteComment = () => {
console.log('删除评论...');
const {
author = {}, // 作者
id, // 评论id
content, // 回复内容
time, // 回复时间
hidden, // 是否隐藏
// hack_id, // OJ的ID
praise_count, // 点赞数
user_praise, // 当前用户是否点赞
can_delete,
children = [] // 子回复
} = comment;
// 删除评论 type: parent | child, id
const deleteComment = (id) => {
confirm({
title: '提示',
content: (<p>确定要删除该条回复吗?</p>),
content: ('确定要删除该条回复吗?'),
onOk () {
console.log('点击了删除');
console.log('点击了删除', id);
submitDeleteComment && submitDeleteComment(id);
}
});
// ModalConfirm('提示', (<p>确定要删除该条回复吗?</p>), () => {
// console.log('点击了删除');
// });
}
// 评论头像
const commentAvatar = (url) => (
<img className="item-flex flex-image" src='https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg' alt=""/>
const commentAvatar = (author) => (
<img
className="item-flex flex-image"
src={author.image_url ? getImageUrl(`images/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'}
alt=""
/>
);
// 评论信息
const commentInfo = () => (
<p className="item-header">
<span className="item-name">用户名</span>
<span className="item-time">{moment(new Date(), 'YYYYMMDD HHmmss').fromNow()}</span>
<span className="item-close"><Icon type="close" onClick={deleteComment}/></span>
</p>
);
const commentInfo = (id, author, time, can_delete) => {
const _classNames = can_delete ? 'item-close' : 'item-close hide';
return (
<div className="item-header">
<span className="item-name">{author.name || ''}</span>
<span className="item-time">{time || ''}</span>
<span className={_classNames}>
<Icon type="close" onClick={() => deleteComment(id)}/>
</span>
</div>
);
};
// 评论内容
const commentCtx = (ctx) => (
<p className="item-ctx">
这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容
</p>
<p className="item-ctx" dangerouslySetInnerHTML={{ __html: ctx}}></p>
);
// 加载更多
const handleOnLoadMore = () => {
if (!arrow) {
// 展开所有
} else {
// 收起
}
const handleOnLoadMore = (len) => {
setShowItemCount(!arrow ? len : 1);
setArrow(!arrow);
};
// 评论追加内容
const commentAppend = () => {
const commentAppend = (children = []) => {
const len = children.length;
const _moreClass = len > 1 ? 'comment_item_loadmore show' : 'comment_item_loadmore'
const lastTxt = len - showItemCount;
const renderChild = (children) => {
return children.map((child, i) => {
const {
id, // 评论id
author = {},
time,
content,
can_delete
} = child;
const showOrHide = i < showItemCount ? 'comment_item_show' : 'comment_item_hide';
return (
<li
key={`child_${i}`}
className={showOrHide}
>
<div className="comment_item_area">
{commentAvatar(author)}
<div className="item-flex item-desc">
{commentInfo(id, author, time, can_delete)}
{commentCtx(content)}
</div>
</div>
</li>
);
})
}
const _clazz = len > 0 ? 'comment_item_append_list active' : 'comment_item_append_list';
return (
<ul className="comment_item_append_list">
<li className="comment_item_area">
{commentAvatar()}
<div className="item-flex item-desc">
{commentInfo()}
{commentCtx()}
</div>
</li>
<li className="comment_item_area">
{commentAvatar()}
<div className="item-flex item-desc">
{commentInfo()}
{commentCtx()}
</div>
</li>
<li className="comment_item_area">
{commentAvatar()}
<div className="item-flex item-desc">
{commentInfo()}
{commentCtx()}
</div>
</li>
<ul className={_clazz}>
{renderChild(children)}
<li className="comment_item_loadmore" onClick={handleOnLoadMore}>
<p className="loadmore-txt">展开其余23条评论</p>
<li className={_moreClass} onClick={() => handleOnLoadMore(len)}>
<p className="loadmore-txt">展开其余{lastTxt}条评论</p>
<p className="loadmore-icon">
<Icon type={!arrow ? 'down' : 'up'}/>
</p>
@ -109,7 +139,14 @@ function CommentItem ({
);
};
// 点击图标
const handleIconClick = () => {}
const handleShowOrHide = (id, hidden) => {
showOrHideComment && showOrHideComment(id, hidden);
}
// 点赞
const handleClickLick = (id) => {
likeComment && likeComment(id);
}
// 点击评论icon
const handleClickMessage = () => {
@ -122,23 +159,29 @@ function CommentItem ({
}
// 点击保存
const handleClickSubmit = (content) => {
// 保存并关闭
setShowQuill(false);
console.log('获取保存内容', content);
const handleClickSubmit = (id) => {
return (ctx) => {
setShowQuill(false);
submitChildComment && submitChildComment(id, ctx);
}
}
return (
<li className="comment_item_area">
{commentAvatar()}
{commentAvatar(author)}
<div className="item-flex item-desc">
{commentInfo()}
{commentCtx()}
{commentInfo(id, author, time, can_delete)}
{commentCtx(content)}
{commentAppend()}
{commentAppend(children)}
<div className="comment_icon_area">
<CommentIcon className='comment-icon-margin' type="eye" count="100" iconClick={handleIconClick}/>
<CommentIcon
style={{ display: isAdmin ? 'inline-block' : 'none'}}
className='comment-icon-margin'
type={!hidden ? "eye" : 'eye-invisible'}
iconClick={() => handleShowOrHide(id, !hidden ? 1 : 0)}
/>
{/* 回复 */}
<CommentIcon
className='comment-icon-margin'
@ -146,7 +189,14 @@ function CommentItem ({
iconClick={handleClickMessage}
/>
{/* 点赞 */}
<CommentIcon/>
<CommentIcon
iconColor={ user_praise ? '#5091FF' : '' }
className='comment-icon-margin'
theme={user_praise ? 'filled' : ''}
type="like"
count={praise_count}
iconClick={() => handleClickLick(id)}
/>
</div>
<div
@ -154,7 +204,7 @@ function CommentItem ({
className="comment_item_quill">
<CommentForm
onCancel={handleClickCancel}
onSubmit={handleClickSubmit}
onSubmit={handleClickSubmit(id)}
/>
</div>
</div>

@ -3,16 +3,52 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-12-17 17:34:00
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-18 11:48:09
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 18:08:07
*/
import './index.scss';
import React from 'react';
import CommentItem from './CommentItem';
function CommentList ({}) {
import { Empty } from 'antd';
function CommentList (props) {
const {
isAdmin,
commentLists, // 评论列表
submitChildComment,
submitDeleteComment,
likeComment,
showOrHideComment
} = props;
const {comments = []} = commentLists;
const renderLi = () => {
if (comments.length > 0) {
return comments.map((item, index) => {
return (
<CommentItem
isAdmin={isAdmin}
key={`item_${index}`}
submitChildComment={submitChildComment}
submitDeleteComment={submitDeleteComment}
comment={item}
likeComment={likeComment}
showOrHideComment={showOrHideComment}
/>
);
});
} else {
return (
<div className="empty_comment">
<Empty />
</div>
);
}
}
return (
<ul className="comment_list_wrapper">
<CommentItem />
{renderLi()}
</ul>
);
}

@ -3,18 +3,42 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-12-17 17:31:33
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-18 11:47:39
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 18:03:21
*/
import React from 'react';
import CommentForm from './CommentForm';
// import CommentForm from './CommentForm';
import CommentList from './CommentList';
function Comment (props) {
const {
commentLists,
// addComment,
// cancelComment,
isAdmin,
addChildComment,
likeComment,
showOrHideComment,
submitDeleteComment
} = props;
// const handleCancelComment = () => {
// cancelComment && cancelComment();
// };
return (
<React.Fragment>
<CommentForm />
<CommentList />
{/* <CommentForm
onCancel={handleCancelComment}
onSubmit={addComment}
/> */}
<CommentList
isAdmin={isAdmin}
likeComment={likeComment}
showOrHideComment={showOrHideComment}
commentLists={commentLists}
submitChildComment={addChildComment}
submitDeleteComment={submitDeleteComment}
/>
</React.Fragment>
);
}

@ -8,8 +8,20 @@ $ml: 20px;
.comment_list_wrapper{
box-sizing: border-box;
border-top: 1px solid $bdColor;
// border-top: 1px solid $bdColor;
.empty_comment{
display: flex;
height: calc(100vh - 200px);
width: 100%;
justify-content: center;
align-items: center;
}
.comment_item_show{
display: block;
}
.comment_item_hide{
display: none;
}
.comment_item_area{
display: flex;
padding: 20px 0;
@ -34,8 +46,13 @@ $ml: 20px;
margin-left: $ml;
}
.item-close{
float: right;
display: inline-block;
cursor: pointer;
float: right;
}
.item-close.hide{
display: none;
}
}
.item-ctx{
@ -50,13 +67,16 @@ $ml: 20px;
margin-top: 10px;
.comment-icon-margin{
margin-left: 30px;
margin-left: 20px;
}
.comment-icon-margin-10{
margin-left: 10px;
}
}
.comment_item_quill{
margin-top: 20px;
}
// .comment_item_quill{
// // margin-top: 10px;
// }
}
.comment_icon_count{
cursor: pointer;
@ -71,6 +91,9 @@ $ml: 20px;
margin-left: 10px;
transition: color .3s;
}
.comment_count_none{
margin-left: 0;
}
&:hover{
.comment_icon,
@ -80,11 +103,15 @@ $ml: 20px;
}
}
.comment_item_append_list{
display: none;
position: relative;
background-color: $bgColor;
border-radius: 5px;
padding: 0 15px 10px;
margin: 15px 0;
&.active{
display: block;
}
&::before {
position: absolute;
left: 15px;
@ -98,6 +125,7 @@ $ml: 20px;
}
.comment_item_loadmore{
display: none;
padding-top: 10px;
cursor: pointer;
.loadmore-txt,
@ -106,6 +134,41 @@ $ml: 20px;
text-align: center;
font-size: $fz12;
}
&.show{
display: block;
}
}
}
}
.comment_form_area,
.comment_form_bottom_area{
width: 100%;
}
.comment_form_area{
position: relative;
background: #fff;
// top: 10px;
.ant-form-explain{
padding-left: 0px;
}
.show_input{
margin-top: 10px;
}
}
.comment_form_bottom_area{
position: relative;
background: #fff;
top: 10px;
&.active{
position: absolute;
background: #fff;
left: 0px;
right: 0px;
top: -220px;
padding: 0 20px;
}
}

@ -0,0 +1,78 @@
/*
* @Description: quill delta -> html
* @Author: tangjiang
* @Github:
* @Date: 2019-12-24 08:51:25
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 10:45:44
*/
export const formatDelta = (deltas) => {
let formatted = [];
deltas.forEach(element => {
let text = null;
// 没有图片时
if (!element['insert']['image']) {
text = element['insert']; // 获取插入的内容
// 元素有属性时
if (element['attributes']) {
// 获取所有的key值
const keys = Object.keys(element['attributes']);
keys.forEach(key => {
text = operate(text, key, element['attributes'][key]);
});
}
} else {
const image = element['insert']['image'];
const {url, alt} = image;
if (url && (url.startsWith('http') || url.startsWith('https'))) {
text = `
<img
src="${url}"
style="{display: 'inline-block'}"
width="60px"
height="30px"
alt="${alt}"
/>
`;
// text = "<img src="+url+" width='60px' height='30px' onclick='' alt="+alt+"/>";
}
}
formatted.push(text);
});
return formatted.join('');
}
/**
* @param {*} text 文本内容
* @param {*} key 属性key
* @param {*} value 属性key对应的值
*/
export const operate = (text, key, value) => {
let operatedText = null;
switch (key) {
case 'bold':
operatedText = `<strong>${text}</strong>`;
break;
case 'italic':
operatedText = `<i>${text}</i>`;
break;
case 'strike':
operatedText = `<s>${text}</s>`;
break;
case 'underline':
operatedText = `<u>${text}</u>`;
break;
case 'link':
operatedText = `<a href="${value}" target="blank">${text}</a>`;
break;
default:
operatedText = text;
}
return operatedText;
}

@ -3,8 +3,8 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-12-16 15:50:45
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-17 16:44:48
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 09:44:03
*/
import Quill from "quill";
@ -43,8 +43,8 @@ export default class ImageBlot extends BlockEmbed {
alt: node.getAttribute('alt'),
url: node.getAttribute('src'),
onclick: node.onclick,
// width: node.width,
// height: node.height,
width: node.width,
height: node.height,
display: node.getAttribute('display')
};
}

@ -178,16 +178,9 @@ class Exercisesetting extends Component{
}
if(result.data.exercise.unified_setting == true && moment(result.data.exercise.end_time) <= moment()){
// if(this.props.isSuperAdmin()===true){
// this.setState({
// end_timetype:false
// })
// }else{
this.setState({
end_timetype:true
})
// }
}
let group=result.data.published_course_groups;
@ -236,10 +229,10 @@ class Exercisesetting extends Component{
//提交form表单
handleSubmit = (e) => {
e.preventDefault();
if(this.props&&this.props.Commonheadofthetestpaper.exercise_status){
console.log("190");
console.log(this.props.Commonheadofthetestpaper.exercise_status);
}
// if(this.props&&this.props.Commonheadofthetestpaper.exercise_status){
// console.log("190");
// console.log(this.props.Commonheadofthetestpaper.exercise_status);
// }
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
@ -327,7 +320,7 @@ class Exercisesetting extends Component{
}
}
if(this.state.end_timetype === false){
if(this.state.end_timetype === false||this.props.isAdmin()==true){
if(moment(end_time,dataformat) <= moment(publish_time,dataformat)){
this.setState({
unit_e_tip:"截止时间不能小于发布时间"
@ -525,7 +518,7 @@ class Exercisesetting extends Component{
end_time:null
})
}else{
if(moment(date,"YYYY-MM-DD HH:mm") <= moment()){
if(dateString<=moment().format('YYYY-MM-DD HH:mm')){
this.setState({
unit_e_tip:"截止时间不能早于当前时间",
e_flag:true

@ -666,7 +666,7 @@ class GraduationTasks extends Component{
<React.Fragment>
{/*{this.props.isAdmin() ?<WordsBtn style="blue" className="mr30" onClick={() => this.addDir()}>题库选用</WordsBtn>:""}*/}
{/*{this.props.isAdmin() ?<a href={"/api/graduation_tasks/"+category_id+"/tasks_list.xls"} className={"fr color-blue font-16"}>导出成绩</a> :""}*/}
{this.props.isAdmin() ? <WordsBtn style="blue" className="mr10 fr font-16">
{this.props.isAdmin() ? <WordsBtn style="blue" className=" fr font-16">
<Link to={"/courses/" + coursesId + "/graduation_tasks/"+category_id+"/new"}>
<span className={"color-blue font-16"}>新建</span>
</Link>

@ -33,6 +33,11 @@ function disabledDateTime() {
// disabledSeconds: () => [55, 56],
};
}
function disabledDate(current) {
return current && current < moment().endOf('day').subtract(1, 'days');
}
const dataformat="YYYY-MM-DD HH:mm";
class PollDetailTabForth extends Component{
@ -584,7 +589,7 @@ class PollDetailTabForth extends Component{
<div className="clearfix">
<span className="mr15 fl mt10 font-16">截止时间</span>
<div className="fl">
<Tooltip placement="bottom" title={un_change_end ? this.props.isAdmin()?"":"截止时间已过,不能再修改":""}>
<Tooltip placement="bottom" title={un_change_end ? this.props.isAdmin()?"截止时间已过,不能再修改":"":""}>
<span>
<DatePicker
showToday={false}
@ -597,9 +602,10 @@ class PollDetailTabForth extends Component{
width={"240px"}
format="YYYY-MM-DD HH:mm"
disabledTime={disabledDateTime}
disabledDate={disabledDate}
onChange={this.onChangeTimeEnd}
value={ end_time && moment(end_time,dataformat) }
disabled={un_change_end == true ? this.props.isAdmin()?!flagPageEdit:true : !flagPageEdit }
disabled={un_change_end == true ?true : !flagPageEdit }
>
</DatePicker>
</span>

@ -447,7 +447,7 @@ class PollDetailTabForthRules extends Component{
</p>
</div>
<div className="fl mr20 yskspickersy">
<Tooltip placement="bottom" title={rule.e_timeflag ? this.props.isAdmin()?"截止时间已过,不能再修改":"":""}>
<Tooltip placement="bottom" title={rule.e_timeflag ? this.props.isAdmin()?"":"截止时间已过,不能再修改":""}>
<span>
<DatePicker
showToday={false}
@ -462,7 +462,7 @@ class PollDetailTabForthRules extends Component{
disabledTime={disabledDateTime}
disabledDate={disabledDate}
disabled={
this.props.type==="polls"||this.props.type==="Exercise"?
this.props.type==="Exercise"?
rule.e_timeflag === undefined ? rule.publish_time === null ? false : moment(rule.end_time, dataformat) <= moment() ?this.props.isAdmin()?!flagPageEdit: true : !flagPageEdit : rule.e_timeflag == true ? this.props.isAdmin()?!flagPageEdit :true : !flagPageEdit:
rule.e_timeflag === undefined ? rule.publish_time === null ? false : moment(rule.end_time, dataformat) <= moment() ? true : !flagPageEdit : rule.e_timeflag == true ? true : !flagPageEdit
}

@ -1,5 +1,5 @@
.editormd-html-preview, .editormd-preview-container {
width: 95% !important;
width: 100% !important;
}
.Finish_button{
height: 30px;

@ -1667,7 +1667,7 @@ class Listofworksstudentone extends Component {
],
yslpros: false,
datajs: [],
homework_status: [],
homework_status: undefined,
}
}
@ -3597,7 +3597,14 @@ class Listofworksstudentone extends Component {
starttimesend={this.state.starttimesend}
typs={this.state.typs}
/> : ""}
{
{homework_status===undefined?
<div className={"educontent "}>
<div className="edu-back-white">
<div className="edu-tab-con-box clearfix edu-txt-center" style={{ width:"100%",height:"200px" }}>
<Spin style={{ width:"100%","line-height":"200px" }}></Spin>
</div>
</div>
</div>:
homework_status && homework_status.length === 0 ?
<div className="edu-back-white">
<NoneData></NoneData>
@ -3609,11 +3616,7 @@ class Listofworksstudentone extends Component {
</div>
:
<div className={"educontent "}>
<div className="edu-back-white">
<style>
{`
.startbox{

@ -3,8 +3,8 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-27 10:58:37
* @LastEditors: tangjiang
* @LastEditTime: 2019-11-27 14:22:38
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 16:48:56
*/
import './index.scss';
import React from 'react';
@ -19,8 +19,17 @@ const TextNumber = (props) => {
* type: 内容 文字或图标
* onIconClick: 点击图标时的回调函数
*/
const { text, number, position = 'horizontal', type = 'label', onIconClick} = props;
const {
text,
number,
position = 'horizontal',
type = 'label',
onIconClick,
className,
theme = 'outlined'
} = props;
// console.log('style=====>>>>>>', style);
const handleIconClick = () => {
onIconClick && onIconClick();
}
@ -35,11 +44,17 @@ const TextNumber = (props) => {
}
return '';
}
const renderCtx = () => {
const renderCtx = (className, theme) => {
if (type === 'icon') { // 图标加文字时
const _className = `text_number_area text_icon_numb flex_${position} ${className}`;
return (
<div className={`text_number_area text_icon_numb flex_${position}`}>
<Icon onClick={handleIconClick} type={text} className={'numb_icon'}></Icon>
<div className={_className}>
<Icon
theme={theme}
onClick={handleIconClick}
type={text}
className={'numb_icon'}
></Icon>
{renderNumb()}
</div>
)
@ -54,7 +69,7 @@ const TextNumber = (props) => {
}
return (
<React.Fragment>
{renderCtx()}
{renderCtx(className, theme)}
</React.Fragment>
);
}

@ -9,7 +9,7 @@ import './index.scss';
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import SplitPane from 'react-split-pane';// import { Form } from 'antd';
import { Button, Modal } from 'antd';
import { Button } from 'antd';
import LeftPane from './leftpane';
import RightPane from './rightpane';
import { withRouter } from 'react-router';

@ -11,7 +11,6 @@ import React, { useState, useMemo } from 'react';
// import { Tabs } from 'antd';
import EditorTab from './editorTab';
import PrevTab from './prevTab';
import CommitTab from './commitTab';
// const { TabPane } = Tabs;

@ -3,19 +3,116 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-27 09:49:35
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-17 17:46:05
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 17:58:26
*/
import './index.scss';
import React from 'react';
import React, { useEffect } from 'react';
import Comment from '../../../../../common/components/comment';
import { connect } from 'react-redux';
import actions from '../../../../../redux/actions';
const CommentTask = (props) => {
const {
isAdmin,
identifier,
commentLists,
addComment,
likeComment,
deleteComment,
getCommentLists,
showOrHideComment,
replayChildComment
} = props;
useEffect(() => {
if (identifier) {
// 获取评论列表数据
getCommentLists(identifier);
}
}, [identifier]);
// 添加评论
const handleAddComment = (ctx) => {
console.log('添加的评论内容: ', ctx);
addComment(identifier, {
comments: {
content: ctx
}
});
};
// 添加子评论
const handleAddChildComment = (parentId, ctx) => {
replayChildComment(identifier, {
comments: {
content: ctx,
parent_id: parentId
}
});
}
// 删除评论
const handleSubmitDeleteComment = (id) => {
console.log('删除评论:', identifier, id);
deleteComment(identifier, id);
}
// 点赞
const handleLikeComment = (id) => {
likeComment(identifier, id, {
container_type: 'Discuss',
type: 1
});
}
// 显示或隐藏
const handleShowOrHideComment = (id, hidden) => {
showOrHideComment(identifier, id, {
hidden
});
}
return (
<div className="task_comment_task">
<Comment />
<Comment
isAdmin={isAdmin}
commentLists={commentLists}
addComment={handleAddComment}
addChildComment={handleAddChildComment}
likeComment={handleLikeComment}
showOrHideComment={handleShowOrHideComment}
submitDeleteComment={handleSubmitDeleteComment}
/>
</div>
)
}
export default CommentTask;
const mapStateToProps = (state) => {
const {
commentLists // 评论列表
} = state.commentReducer;
const {
comment_identifier
} = state.ojForUserReducer;
const { userInfo } = state.userReducer;
return {
commentLists,
isAdmin: userInfo.admin,
identifier: comment_identifier
}
}
const mapDispatchToProps = (dispatch) => ({
// getCommentLists: (identifier) => dispatch(action.getCommentLists(identifier))
getCommentLists: (identifier) => dispatch(actions.getCommentLists(identifier)),
addComment: (identifier, comments) => dispatch(actions.addComment(identifier, comments)),
replayChildComment: (identifier, comment) => dispatch(actions.replayChildComment(identifier, comment)),
deleteComment: (identifier, id) => dispatch(actions.deleteComment(identifier, id)),
likeComment: (identifier, id, params) => dispatch(actions.likeComment(identifier, id, params)),
showOrHideComment: (identifier, id, params) => dispatch(actions.showOrHideComment(identifier, id, params)),
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(CommentTask);

@ -3,8 +3,8 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-23 11:33:41
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-19 18:03:22
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 17:16:54
// */
import './index.scss';
import React, { useState, useEffect, useMemo } from 'react';
@ -15,12 +15,19 @@ import CommitRecord from './commitRecord';
import TaskDescription from './taskDescription';
import TextNumber from './../../components/textNumber';
import actions from '../../../../redux/actions';
import CommentForm from '../../../../common/components/comment/CommentForm';
// const { TabPane } = Tabs;
const LeftPane = (props) => {
const { hack, userCodeTab } = props;
const { pass_count, submit_count } = hack;
const {
pass_count,
submit_count,
praises_count, /* 点赞数 */
comments_count, /* 评论数*/
user_praise // 用户是否点赞
} = hack;
const [defaultActiveKey, setDefaultActiveKey] = useState('comment');
const navItem = [
@ -32,10 +39,10 @@ const LeftPane = (props) => {
title: '提交记录',
key: 'record'
},
// {
// title: '评论',
// key: 'comment'
// }
{
title: '评论',
key: 'comment'
}
];
const Comp = {
@ -45,7 +52,6 @@ const LeftPane = (props) => {
};
useEffect(() => {
console.log('====>>>>', userCodeTab);
setDefaultActiveKey(userCodeTab);
}, [userCodeTab])
@ -69,18 +75,34 @@ const LeftPane = (props) => {
// 点击消息
const handleClickMessage = () => {
console.log('点击的消息图标---------');
// 切换到评论tab
setDefaultActiveKey('comment');
}
// 点击点赞
const handleClickLike = () => {
console.log('点击的Like---------');
}
// 对OJ进行点赞
const {id, identifier } = props.hack;
props.likeComment(identifier, id, {
container_type: 'Hack',
type: 1
});
};
// 点击不喜欢
const handleClickDisLike = () => {
console.log('点击的DisLike---------');
}
// const handleClickDisLike = () => {
// console.log('点击的DisLike---------');
// }
// 添加评论
const handleAddComment = (ctx) => {
console.log('添加的评论内容: ', ctx, props.identifier);
props.identifier && props.addComment(props.identifier, {
comments: {
content: ctx
}
});
};
return (
<React.Fragment>
@ -91,26 +113,46 @@ const LeftPane = (props) => {
{ renderComp }
</div>
<div className={'number_area'}>
<div className="number_flex flex_count">
<div className="number_flex flex_count" style={{ display: defaultActiveKey !== 'comment' ? 'flex' : 'none'}}>
<TextNumber text="通过次数" number={pass_count} position="vertical"/>
<Divider type="vertical" style={{ height: '20px', margin: '10px 20px' }}/>
<TextNumber text="提交次数" number={submit_count} position="vertical"/>
</div>
<div className="number_flex flex_quill" style={{ display: defaultActiveKey === 'comment' ? 'flex' : 'none'}}>
<CommentForm
onSubmit={handleAddComment}
type="bottom"
/>
</div>
<div className="number_flex flex_info">
<TextNumber text="message" number={comments_count} type="icon" onIconClick={handleClickMessage}/>
<TextNumber
className={user_praise ? 'like active' : 'like'}
text="like"
number={praises_count}
theme={user_praise ? 'filled' : ''}
type="icon"
onIconClick={handleClickLike}/>
{/* <TextNumber text="dislike" number={0} type="icon" onIconClick={handleClickDisLike}/> */}
</div>
</div>
</React.Fragment>
);
}
const mapStateToProps = (state) => {
const { hack, userCodeTab} = state.ojForUserReducer;
const { hack, userCodeTab, comment_identifier} = state.ojForUserReducer;
return {
hack,
userCodeTab
userCodeTab,
identifier: comment_identifier
}
}
// changeUserCodeTab
const mapDispatchToProps = (dispatch) => ({
changeUserCodeTab: (key) => dispatch(actions.changeUserCodeTab(key))
changeUserCodeTab: (key) => dispatch(actions.changeUserCodeTab(key)),
likeComment: (identifier, id, params) => dispatch(actions.likeComment(identifier, id, params)),
addComment: (identifier, comments) => dispatch(actions.addComment(identifier, comments))
});
export default connect(
mapStateToProps,

@ -21,13 +21,33 @@
background: #fff;
.flex_count,
.flex_info{
.flex_info,
.flex_quill{
display: flex;
flex-direction: row;
justify-content: space-between;
}
.flex_info{
width: 200px;
// width: 140px;
justify-content: flex-end;
.like{
margin-left: 20px
}
.like.active{
.numb_icon{
color: #5091FF;
}
}
}
.flex_quill{
// position: relative;
flex: 1;
align-items: center;
height: 100%;
top: 10px;
margin-right: 20px;
}
}

@ -1,11 +1,12 @@
.float_button {
background-image: url(./images/float_switch.jpg);
height: 112px;
background-image: url(images/float_switch.jpg);
height: 141px;
width: 38px;
position: absolute;
left: -38px;
top: 32%;
cursor: pointer;
padding-top: 15px;
}
.float_button .text {
position: relative;
@ -17,8 +18,8 @@
}
.jupyter_float_button {
background-image: url(./images/float_switch.jpg);
height: 112px;
background-image: url(images/float_switch.jpg);
height: 141px;
width: 38px;
position: absolute;
right: 0px;
@ -26,6 +27,7 @@
cursor: pointer;
left:auto;
z-index: 99999999;
padding-top: 15px;
}
.jupyter_float_button .text {
@ -37,6 +39,16 @@
user-select: none;
}
@keyframes mymove
{
from {right:0px;}
to {right:330px;}
}
.newjupyter_float_button{
right: 330px;
/*right: 330px;*/
/*animation-duration:2s;*/
/*infinite*/
animation:mymove 0.35s;
animation-fill-mode:forwards;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -555,6 +555,9 @@ class PathDetailIndex extends Component{
.pathDetailIndex .markdown-body > p {
line-height: 28px;
}
// #shixuns_propaedeutics{
// width: 100% !important;
// }
`
}
</style>

@ -59,7 +59,8 @@ class TPMBanner extends Component {
openknow:false,
openshowpublictype:false,
Radiovalue:1,
TextAreaintshow:false
TextAreaintshow:false,
}
}
@ -112,6 +113,15 @@ class TPMBanner extends Component {
componentDidUpdate(prevProps, prevState) {
if (prevProps != this.props) {
if(prevProps.user != this.props.user){
if(this.props.user&&this.props.user.admin===true||this.props.user&&this.props.user.business===true){
this.setState({
TextArea:"云上实验室使用"
})
}
}
let shixunopenprocess=window.localStorage.shixunopenprocess;
let openopenpublictype=window.localStorage.openopenpublictype;
if(this.props.status===0&&this.props.openknows===false){
@ -173,8 +183,12 @@ class TPMBanner extends Component {
})
}
if (this.props.user && this.props.user.admin === true || this.props.user && this.props.user.business === true) {
this.setState({
TextArea: "云上实验室使用"
})
}
}
/*
* Fork
* */
@ -736,6 +750,11 @@ class TPMBanner extends Component {
this.setState({
Radiovalue:e.target.value
})
if(e.target.value!=4){
this.setState({
TextAreaintshow:false
})
}
}
render() {
@ -827,7 +846,7 @@ class TPMBanner extends Component {
};
//
// console.log(this.props.shixunsDetails&&this.props.shixunsDetails.is_jupyter)
// console.log(this.props)
// console.log(this.state)
return (
@ -838,7 +857,7 @@ class TPMBanner extends Component {
`
.shixunDetail_top{
height: 180px !important;
padding-top:35px !important;
padding-top:50px !important;
}
.ant-popover{
z-index:1000 !important;
@ -881,9 +900,9 @@ class TPMBanner extends Component {
}
</p>
<div className="clearfix mt30">
<div className="clearfix mt10">
<ul className="fl color-grey-c pathInfo">
<ul className="fl color-grey-c pathInfo mt20">
{shixunsDetails&&shixunsDetails.stu_num===0?"":<li>
<span>学习人数</span>
<span className="mt3">{shixunsDetails.stu_num}</span>
@ -954,7 +973,7 @@ class TPMBanner extends Component {
</div>
</div>
}>
<div className="pr fl" id="commentsStar">
<div className="pr fl mt15" id="commentsStar">
<div className={"color-grey-c ml15"} style={{color: "#fff", textAlign: "center"}}>学员评分</div>
<div className="rateYo">
<MyRate allowHalf defaultValue={star_info[0]} disabled/>
@ -1318,7 +1337,9 @@ class TPMBanner extends Component {
其它原因
</Radio>
{this.state.Radiovalue === 4 ?
<TextArea className={this.state.TextAreaintshow===true?"bor-red mt10":"mt10"} rows={4} style={{ width: '85%', marginLeft: '30px' }} onInput={this.changeTextArea}/>: null}
<TextArea className={this.state.TextAreaintshow===true?"bor-red mt10":"mt10"}
value={this.state.TextArea}
rows={4} style={{ width: '85%', marginLeft: '30px' }} onInput={this.changeTextArea}/>: null}
{this.state.TextAreaintshow===true?<div className={"color-red ml30"}>不能为空</div>:""}
</Radio.Group>
</div>

@ -35,14 +35,14 @@ if (!window['indexHOCLoaded']) {
// $('head').append($('<link rel="stylesheet" type="text/css" />')
// .attr('href', `${_url_origin}/stylesheets/educoder/antd.min.css?1525440977`));
$('head').append($('<link rel="stylesheet" type="text/css" />')
.attr('href', `${_url_origin}/stylesheets/css/edu-common.css?6`));
.attr('href', `${_url_origin}/stylesheets/css/edu-common.css?8`));
$('head').append($('<link rel="stylesheet" type="text/css" />')
.attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?6`));
.attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?8`));
// index.html有加载
$('head').append($('<link rel="stylesheet" type="text/css" />')
.attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?6`));
.attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?8`));
// $('head').append($('<link rel="stylesheet" type="text/css" />')

@ -295,6 +295,8 @@ export default class Shixuninformation extends Component {
const dateFormat = 'YYYY-MM-DD HH:mm';
// console.log()
console.log(this.props&&this.props.identity<8)
return (
<div>
<div className="educontent mb200 edu-back-white padding10-20 pdb30 mb50">
@ -308,8 +310,8 @@ export default class Shixuninformation extends Component {
</span>
</div>}
<div className="edu-back-white mb10 ml30 mt20">
<div>
<div className="edu-back-white mb10 ml30 mt20">
{this.props&&this.props.status>1&&this.state.use_scope===0&&this.props&&this.props.identity>7||this.props&&this.props.public===2&&this.state.use_scope===0&&this.props&&this.props.identity>7?"":<div>
<span className="color-grey-6 mt5 fl font-16" style={{minWidth: '45px'}}>公开程度:</span>
<span className="fl mt8 ml20">
<RadioGroup onChange={this.SelectOpenpublic} value={this.state.use_scope}>
@ -387,7 +389,7 @@ export default class Shixuninformation extends Component {
</span>
</div>
</div>}
<div className="clearfix mt20">
<span className="color-grey-6 mt5 fl font-16" style={{minWidth: '45px'}}>开启时间:</span>

@ -953,10 +953,10 @@ class Shixuninformation extends Component {
<div>
{this.state.mainvalues === undefined && this.state.subvalues === undefined || this.state.mainvalues === "" && this.state.subvalues === "" ? "" :
<div className={"font-12"} style={{'max-width': '600px'}}>
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `已安装软件:` + this.state.mainvalues}`}
{`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? `已安装软件:` + this.state.subvalues : this.state.subvalues}`}
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `说明:添加了` + this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
this.state.mainvalues === undefined || this.state.mainvalues === "" ? `说明:添加了` + this.state.subvalues : this.state.subvalues}`}
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : this.state.mainvalues}`}
{`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? this.state.subvalues : this.state.subvalues}`}
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
this.state.mainvalues === undefined || this.state.mainvalues === "" ? this.state.subvalues : this.state.subvalues}`}
</div>}
</div>
</span>
@ -1185,7 +1185,11 @@ class Shixuninformation extends Component {
closable={false}
footer={null}
>
<div className="task-popup-content"><p className="task-popup-text-center font-16">评测脚本生成成功</p></div>
<div className="task-popup-content">
{/*<p className="task-popup-text-center font-16">已根据您的选择,生成新的评测脚本!</p>*/}
{/*<p className="task-popup-text-center font-16 mt10">您之前使用的脚本已复制到剪贴板可通过Ctrl+C贴贴</p>*/}
<p className="task-popup-text-center font-16">评测脚本生成成功</p>
</div>
<div className="task-popup-sure clearfix">
<a className="task-btn task-btn-orange" onClick={() => this.hidestandard_scriptsModal()}>确定</a>
</div>

@ -82,18 +82,18 @@ class TPMRightSection extends Component {
<div className="flex1">
<div className="creatorname sortinxdirection space-between">
<div className={"creatornamelist"}>
<div className={"creatornamelist color-grey-3"}>
{TPMRightSectionData === undefined ? "" : TPMRightSectionData.creator === undefined ? "" : TPMRightSectionData.creator.name}
</div>
<div className={"creatornamelist width80center"}>
{TPMRightSectionData.user_shixuns_count}
<span className={"color888hezuo"}>共发布实训</span> <span className={"color-grey-3"}>{TPMRightSectionData.user_shixuns_count}</span> <span className={"color888hezuo"}></span>
</div>
</div>
<div className="clearfix">
<span className={"fr color888hezuo"}>发布实训项目</span>
{/*<span className="ml20">粉丝 <span id="user_h_fan_count">{TPMRightSectionData.fans_count}</span></span>*/}
{/* <a href="/watchers/unwatch?className=fr+user_watch_btn+edu-default-btn+edu-focus-btn&amp;object_id=3039&amp;object_type=user&amp;shixun_id=61&amp;target_id=3039" className="fr edu-default-btn user_watch_btn edu-focus-btn" data-method="post" data-remote="true" id="cancel_watch" rel="nofollow">取消关注</a> */}
</div>
{/*<div className="clearfix">*/}
{/* <span className={"fr color888hezuo"}>发布实训项目</span>*/}
{/* /!*<span className="ml20">粉丝 <span id="user_h_fan_count">{TPMRightSectionData.fans_count}</span></span>*!/*/}
{/* /!* <a href="/watchers/unwatch?className=fr+user_watch_btn+edu-default-btn+edu-focus-btn&amp;object_id=3039&amp;object_type=user&amp;shixun_id=61&amp;target_id=3039" className="fr edu-default-btn user_watch_btn edu-focus-btn" data-method="post" data-remote="true" id="cancel_watch" rel="nofollow">取消关注</a> *!/*/}
{/*</div>*/}
</div>
</div>

@ -98,14 +98,15 @@
}
.creatornamelist {
-o-text-overflow: ellipsis;
cursor: default;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: default;
width: 139px;
}
.width80center {
width: 80px;
font-size:12px;
text-align: center;
}

@ -146,12 +146,12 @@ function JupyterTPI (props) {
title: '更新通知',
content: (<div className="update_notice">
{stopposttpip(1)}
<p className="update_txt">关卡任务的代码文件有更新啦</p>
<p className="update_txt">更新操作将保留已完成的评测记录和成绩</p>
<p className="update_txt">还未完成评测的任务代码请自行保存</p>
<p className="update_txt">该实训已更新更新后您编写的实训代码将会丢失</p>
<p className="update_txt">如有需要请先导出代码再进行更新</p>
{/*<p className="update_txt">还未完成评测的任务代码,请自行保存</p>*/}
</div>),
okText: '确定',
cancelText: '取消',
okText: '立即更新',
cancelText: '稍后再说',
onOk () {
syncJupyterCode(myshixun_identifier, '同步成功');
},onCancel() {
@ -326,12 +326,12 @@ function JupyterTPI (props) {
</p>
<p className="jupyter_btn">
{/*sync | poweroff */}
{/*<Button*/}
{/* className="btn_common"*/}
{/* type="link"*/}
{/* icon="history"*/}
{/* onClick={handleClickResetTpi}*/}
{/*>重置实训</Button>*/}
<Button
className="btn_common"
type="link"
icon="history"
onClick={handleClickResetTpi}
>重置实训</Button>
<Button
className="btn_common"

@ -114,7 +114,7 @@
.ant-drawer-content-wrapper{
width:330px !important;
box-shadow: -2px 0 8px #070F1A !important;
//box-shadow: -2px 0 8px #070F1A !important;
}
.ant-drawer-body{
padding: 0px;

@ -620,10 +620,10 @@ class Newshixuns extends Component {
<div>
{this.state.mainvalues === undefined && this.state.subvalues === undefined || this.state.mainvalues === "" && this.state.subvalues === "" ? "" :
<div className={"font-12"} style={{'max-width': '600px'}}>
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `已安装软件:` + this.state.mainvalues}`}
{`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? `已安装软件:` + this.state.subvalues : this.state.subvalues}`}
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : `说明:添加了` + this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
this.state.mainvalues === undefined || this.state.mainvalues === "" ? `说明:添加了` + this.state.subvalues : this.state.subvalues}`}
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : this.state.mainvalues}`}
{`${this.state.subvalues === undefined || this.state.subvalues === "" ? "" : this.state.mainvalues === undefined || this.state.mainvalues === "" ? this.state.subvalues : this.state.subvalues}`}
{`${this.state.mainvalues === undefined || this.state.mainvalues === "" ? "" : this.state.mainvalues}${this.state.subvalues === undefined || this.state.subvalues === "" ? "" :
this.state.mainvalues === undefined || this.state.mainvalues === "" ? this.state.subvalues : this.state.subvalues}`}
</div>}
</div>

@ -122,7 +122,7 @@
}
.fabushixunwidth{
color: #000000;
font-size: 16px;
font-size: 12px;
}
.fabushixunwidthcolor{
color: #4CACFF;
@ -143,11 +143,11 @@
height:34px;
line-height: 34px;
}
.hezuozhe630{
width: 630px;
.hezuozhe655{
width: 655px;
}
.hezuozhe634{
width: 634px;
.hezuozhe655{
width: 655px;
}
.color333hezuo{
color:#333333;
@ -194,3 +194,7 @@
white-space: nowrap;
cursor: default;
}
.centertop20{
text-align: center;
padding-top: 20%;
}

@ -118,6 +118,7 @@ class Collaborators extends Component {
if (type === "cooperation") {
this.setState({
Collaboratorsvisibleadmin: true,
Collaboratorsvisible: false,
});
} else if ("admin") {
let id = this.props.match.params.shixunId;
@ -132,6 +133,7 @@ class Collaborators extends Component {
} else {
this.setState({
Collaboratorsvisible: true,
Collaboratorsvisibleadmin: false,
Collaboratorslist: response.data
})
}
@ -517,17 +519,16 @@ class Collaborators extends Component {
closable={false}
footer={null}
>
<div className="mb15 font-14 edu-txt-center color-orange-tip">
选择的成员将会成为新的管理员<br/> 您将不再拥有管理员的权限但您仍是合作团队的一员
</div>
<div className="clearfix mb15 edu-bg-light-blue edu-max-h200">
<ul className="">
<li className="clearfix">
<li className={Collaboratorslist&&Collaboratorslist.length===0?"centertop20 clearfix":"clearfix"}>
<span>
请先将新的管理员通过 <a className={"color-blue"} onClick={() => this.showCollaboratorsvisible("cooperation")}>"添加合作者"</a>
</span>
<RadioGroup onChange={this.onChange} value={this.state.value}>
{
Collaboratorslist.length === 0 ? "" : Collaboratorslist.map((item, key) => {
return (
@ -536,7 +537,6 @@ class Collaborators extends Component {
)
})
}
</RadioGroup>
</li>
</ul>
@ -642,7 +642,7 @@ class Collaborators extends Component {
<style>
{
`
.collaborators-item-middles{width: 100% !important; margin-left: 20px;}
.collaborators-item-middles{width: 100% !important;}
.ysltithead{
padding-bottom: 20px;
}
@ -665,7 +665,7 @@ class Collaborators extends Component {
<div className="fl collaborators-item-middles">
<p className="mb10 sortinxdirection space-between hezuozhe634">
<p className="mb10 sortinxdirection space-between hezuozhe655">
<a href={item.user.user_url} target="_blank" className="yslusername">{item.user.name}</a>
{item.user.shixun_manager === true ? "" : <span>
<i className={this.state.hovertype===true&&key===this.state.hoverkey?"fontnewreds iconfont icon-shanchu_Hover":"fontneweees iconfont icon-shanchu_moren"}
@ -681,10 +681,10 @@ class Collaborators extends Component {
</p>
<p className="color-grey-B2 font-12 mb10 sortinxdirection mt14">
<p className="hezuozhe630 sortinxdirection space-between">
<p className="hezuozhe655 sortinxdirection space-between">
{/*<p className={item.user.identity===null||item.user.identity===undefined||item.user.identity===""?" font-16 ":"mr20 font-16 w70"}>{item.user.identity}</p>*/}
<p
className={item.user.school_name === null || item.user.school_name === "" ? "" : " font-16 color888hezuo maxfont450"}>{item.user.school_name}</p>
className={item.user.school_name === null || item.user.school_name === "" ? "" : " font-12 color888hezuo maxfont450"}>{item.user.school_name}</p>
<p className="fabushixunwidth color888hezuo">发布实训项目&nbsp;&nbsp;<span
className="ml2">{item.user.user_shixuns_count}</span></p>
</p>

@ -129,7 +129,7 @@ class Ranking_list extends Component {
{/*<li className="fl with13 edu-txt-center color-grey-74">*/}
{/*/!*{item.accuracy} %准确率*!/*/}
{/*</li>*/}
<li className="fl with25 edu-txt-center">{this.formatSeconds(item.use_time)}</li>
<li className="fl with25 edu-txt-center">{item.use_time===null?"":this.formatSeconds(item.use_time)}</li>
<li className="fl with14 edu-txt-center color-yellow">+{item.gold}金币 </li>
</div>
)

@ -1,5 +1,5 @@
.editormd-html-preview, .editormd-preview-container {
width: 95% !important;
width: 100% !important;
}
.Finish_button{
height: 30px;

@ -24,6 +24,7 @@ const types = {
DELETE_TEST_CASE: 'DELETE_TEST_CASE', // 删除测试用例
SAVE_TEST_CASE: 'SAVE_TEST_CASE', // 保存测试用例
SAVE_USE_TEST_CASE_VALUE: 'SAVE_USE_TEST_CASE_VALUE', // 用户自定义测试用例值
CHANGE_PUBLISH_VALUE: 'CHANGE_PUBLISH_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', // 代码调试状态
@ -53,6 +54,7 @@ const types = {
SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码
CLICK_OPERATE_TYPE: 'CLICK_OPERATE_TYPE', // 点击类型
CLEAR_OJ_FOR_USER_REDUCER: 'CLEAR_OJ_FOR_USER_REDUCER', // 退出时清空 ojForUserReducer保存内容
ADD_OJ_LIKE_COUNT: 'ADD_OJ_LIKE_COUNT', // 增加点赞数
/*** jupyter */
GET_JUPYTER_DATA_SETS: 'GET_JUPYTER_DATA_SETS', // jupyter 数据集
GET_JUPYTER_TPI_URL: 'GET_JUPYTER_TPI_URL', // 获取 jupyter url
@ -67,6 +69,12 @@ const types = {
CHANGE_JYPYTER_TIME: 'CHANGE_JYPYTER_TIME',//增加15分钟
CHANGE_EXTENDED_TIME: 'CHANGE_EXTENDED_TIME',//延时
CHANGE_UPDETA_SPIN: 'CHANGE_UPDETA_SPIN',//加载
/*** 评论 */
ADD_COMMENTS: 'ADD_COMMENTS', // 添加评论
GET_COMMENT_LISTS: 'GET_COMMENT_LISTS', // 获取评论列表
REPLAY_CHILD_COMMENTS: 'REPLAY_CHILD_COMMENTS', // 子回复
DELETE_COMMENTS: 'DELETE_COMMENTS', // 删除评论
SAVE_COMMENT_IDENTIFIER: 'SAVE_COMMENT_IDENTIFIER' // 评论时的identifier
}
export default types;

@ -0,0 +1,114 @@
/*
* @Description:
* @Author: tangjiang
* @Github:
* @Date: 2019-12-23 10:53:25
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 16:17:00
*/
import types from "./actionTypes";
import {
fetchAddComment,
fetchCommentLists,
fetchAddChildComment,
fetchDeleteComment,
fetchLikeComment,
fetchShowOrHideComment
} from '../../services/commentService';
// 添加评论
export const addComment = (identifier, comments) => {
return (dispatch) => {
fetchAddComment(identifier, comments).then(res => {
if (res.status === 200) {
// 重新加载评论列表
dispatch(getCommentLists(identifier));
}
});
}
};
// 获取评论列表
export const getCommentLists = (identifier) => {
return (dispatch) => {
fetchCommentLists(identifier).then(res => {
console.log('获取评论列表: ====>>>>', res);
if (res.status === 200) {
const {data} = res;
dispatch({
type: types.GET_COMMENT_LISTS,
payload: data
})
}
});
}
}
// 子回复
export const replayChildComment = (identifier, comment) => {
return (dispatch) => {
fetchAddChildComment(identifier, comment).then(res => {
// console.log('添加子评论成功: ====>>>>', res);
if (res.status === 200) {
// 重新加载评论列表
dispatch(getCommentLists(identifier));
}
});
}
}
// 删除评论
export const deleteComment = (identifier, delId) => {
return (dispatch) => {
fetchDeleteComment(identifier, delId).then(res => {
if (res.status === 200) {
// 重新加载评论列表
dispatch(getCommentLists(identifier));
}
});
}
}
// 点赞
export const likeComment = (identifier, id, params, cb) => {
return (dispatch) => {
fetchLikeComment(id, params).then(res => {
if (res.status === 200) {
// 重新加载评论列表
const {container_type} = params;
// if (container_type === 'Discuss') {
// dispatch(getCommentLists(identifier))
// } else if {
// }
const {praise_count} = res.data;
switch (container_type) {
case 'Discuss':
dispatch(getCommentLists(identifier))
break;
case 'Hack':
dispatch({
type: types.ADD_OJ_LIKE_COUNT,
payload: praise_count
});
break;
default:
break;
}
}
})
}
}
// 显示或隐藏评论
export const showOrHideComment = (identifier, id, params) => {
return (dispatch) => {
fetchShowOrHideComment(identifier, id, params).then(res => {
if (res.status === 200) {
// 重新加载评论列表
dispatch(getCommentLists(identifier));
}
});
}
}

@ -65,6 +65,15 @@ import {
getUserInfoForNew
} from './user';
import {
addComment,
getCommentLists,
replayChildComment,
deleteComment,
likeComment,
showOrHideComment
} from './comment';
import {
getJupyterTpiDataSet,
getJupyterTpiUrl,
@ -137,6 +146,13 @@ export default {
reset_with_tpi,
addjypertime,
active_with_tpi,
updataspinning
updataspinning,
// isUpdateCodeCtx
// 评论
addComment,
getCommentLists,
replayChildComment,
deleteComment,
likeComment,
showOrHideComment,
}

@ -3,8 +3,8 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-27 13:42:11
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-20 19:30:30
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-23 11:55:48
*/
import types from "./actionTypes";
import { Base64 } from 'js-base64';

@ -3,8 +3,8 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-20 16:35:46
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-20 19:54:09
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-23 10:55:28
*/
import types from './actionTypes';
import CONST from '../../constants';
@ -86,16 +86,16 @@ const payloadInfo = (key, value, errMsg, validateInfo) => ({
});
// 接口调用成功后,跳转至列表页
function linkToDev (dispatch, props) {
toStore('oj_description', '');
dispatch({
type: types.IS_MY_SOURCE,
payload: true
});
setTimeout(() => {
props.history.push('/problems');
}, 1000);
}
// function linkToDev (dispatch, props) {
// toStore('oj_description', '');
// dispatch({
// type: types.IS_MY_SOURCE,
// payload: true
// });
// setTimeout(() => {
// props.history.push('/problems');
// }, 1000);
// }
// 表单提交验证
export const validateOjForm = (props, type) => {
@ -250,18 +250,24 @@ export const validateOjForm = (props, type) => {
if (type === 'publish') {
// 提示发布信息
publishTask(identifier).then(res => {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
if (res.data.status === 0) {
// message.success('发布成功!');
notification.success({
message: '提示',
description: '发布成功!'
});
linkToDev(dispatch, props);
// linkToDev(dispatch, props);
// 改变发布状态值 0 => 1
dispatch({
type: types.CHANGE_PUBLISH_VALUE,
payload: 1
});
}
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
}).catch(() => {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
@ -273,25 +279,32 @@ export const validateOjForm = (props, type) => {
fetchPostOjForm(paramsObj).then(res => {
if (res.status === 200) { // 保存成功后,重新跳转至列表页
if (res.data.status === 0) {
// 改变按钮loading状态
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
// message.success(paramsObj['submitType'] === 'update' ? '更新成功' : '保存成功');
notification.success({
message: '提示',
description: paramsObj['submitType'] === 'update' ? '更新成功' : '保存成功'
});
linkToDev(dispatch, props);
}
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
const {identifier} = res.data;
// 保存成功后的identifier
identifier && dispatch({
type: types.SAVE_OJ_FORM_ID,
payload: identifier
});
// 保存或更新后调用start接口
// linkToDev(dispatch, props);
}
}).catch(err => {
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
}
);
}}
).catch(err => {
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
});
}
}
}
@ -312,7 +325,12 @@ export const handleClickCancelPublish = (props, identifier) => {
message: '提示',
description: '撤销发布成功!'
});
linkToDev(dispatch, props);
// 改变发布状态值
dispatch({
type: types.CHANGE_PUBLISH_VALUE,
payload: 0
});
// linkToDev(dispatch, props);
}
}
}).catch(() => {

@ -0,0 +1,42 @@
import types from "../actions/actionTypes";
/*
* @Description: 评论reducer
* @Author: tangjiang
* @Github:
* @Date: 2019-12-23 10:35:31
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-23 14:51:42
*/
const initialState = {
comments: {
content: '' // 评论内容
},
commentLists: {}, // 评论列表
pages: {
limit: 20,
page: 1
}
};
const commentReducer = (state = initialState, action) => {
const { payload, type } = action;
switch (type) {
case types.ADD_COMMENTS:
return {
...state
}
case types.GET_COMMENT_LISTS:
return {
...state,
commentLists: Object.assign({}, payload)
}
default:
return {
...state
}
}
}
export default commentReducer;

@ -14,6 +14,7 @@ import ojForUserReducer from './ojForUserReducer';
import commonReducer from './commonReducer';
import userReducer from './userReducer';
import jupyterReducer from './jupyterReducer';
import commentReducer from './commentReducer';
export default combineReducers({
testReducer,
@ -22,5 +23,6 @@ export default combineReducers({
ojForUserReducer,
commonReducer,
userReducer,
jupyterReducer
jupyterReducer,
commentReducer
});

@ -3,11 +3,12 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-27 13:41:48
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-20 14:46:07
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 16:35:09
*/
import types from "../actions/actionTypes";
import { Base64 } from 'js-base64';
import actions from "../actions";
const initialState = {
user_program_identifier: '', // 开启OJ题的唯一标题
@ -26,6 +27,7 @@ const initialState = {
notice: false, // 通知
hadCodeUpdate: false, // 更新代码
operateType: '', // 点击类型: 调度或提交
comment_identifier: '' // 用户评论时使用的 identifier
};
const ojForUserReducer = (state = initialState, action) => {
@ -50,7 +52,8 @@ const ojForUserReducer = (state = initialState, action) => {
return {
...state,
hack: Object.assign({}, hack),
test_case: Object.assign({}, test_case)
test_case: Object.assign({}, test_case),
comment_identifier: hack.identifier
}
case types.COMMIT_RECORD_DETAIL:
let result = action.payload.data;
@ -179,6 +182,23 @@ const ojForUserReducer = (state = initialState, action) => {
hadCodeUpdate: false, // 更新代码
operateType: '', // 点击类型: 调度或提交
};
// 保存评论时用的 identifer
case types.SAVE_COMMENT_IDENTIFIER:
return {
...state,
comment_identifier: actions.payload
};
// 是否点赞
case types.ADD_OJ_LIKE_COUNT:
let _count = state.hack.praises_count;
let _user_praise = state.hack.user_praise;
_count = +action.payload > 0 ? _count + 1 : _count - 1;
_user_praise = +action.payload > 0 ? true : false;
const _hack = Object.assign({}, state.hack, {praises_count: _count, user_praise: _user_praise});
return {
...state,
hack: _hack
}
default:
return state;
}

@ -3,8 +3,8 @@
* @Author: tangjiang
* @Github:
* @Date: 2019-11-20 16:40:32
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-20 16:40:52
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-23 10:12:59
*/
import { Base64 } from 'js-base64';
import types from '../actions/actionTypes';
@ -158,9 +158,10 @@ const ojFormReducer = (state = initialState, action) => {
testCasesValidate: [...tempTestValicate]
};
case types.SAVE_OJ_FORM_ID:
state.identifier = action.payload;
// state.identifier = action.payload;
return {
...state
...state,
identifier: action.payload
}
case types.SAVE_EDIT_OJ_FORM_AND_TEST_CASE: // 保存编辑的值
/**
@ -211,6 +212,11 @@ const ojFormReducer = (state = initialState, action) => {
testCodeStatus: hack_sets.length > 0 ? 'userCase' : 'default',
isPublish: status
}
case types.CHANGE_PUBLISH_VALUE:
return {
...state,
isPublish: action.payload
};
case types.CLEAR_JSFORM_STORE:
state = Object.assign({}, init);
return {

@ -0,0 +1,45 @@
/*
* @Description: 评论 service
* @Author: tangjiang
* @Github:
* @Date: 2019-12-23 10:43:27
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 17:10:49
*/
import axios from 'axios';
// 添加评论
export async function fetchAddComment (identifier, params) {
const url = `/problems/${identifier}/comments.json`;
return axios.post(url, params);
}
// 获取评论列表
export async function fetchCommentLists (identifier) {
const url = `/problems/${identifier}/comments.json`;
return axios.get(url);
}
// 添加子评论
export async function fetchAddChildComment (identifier, params) {
const url = `/problems/${identifier}/comments/reply.json`;
return axios.post(url, params);
}
// 删除评论
export async function fetchDeleteComment (identifier, id) {
const url = `/problems/${identifier}/comments/${id}.json`;
return axios.delete(url);
}
// 点赞
export async function fetchLikeComment (id, params) {
const url = `/discusses/${id}/plus.json`;
return axios.post(url, params);
}
// 显示或隐藏
export async function fetchShowOrHideComment (identifier, id, params) {
const url = `/problems/${identifier}/comments/${id}/hidden.json`;
return axios.post(url, params);
}

@ -2939,7 +2939,7 @@ a.singlepublishtwo{
padding: 40px !important;
}
.editormd-html-preview{
width: 94% !important;
width:100% !important;
color: #323232 !important;
}
#homework_editorMd_description hr{
@ -3799,3 +3799,8 @@ a.singlepublishtwo{
.ant-drawer{
z-index: 10000 !important;
}
.markdown-body {
text-align: justify;
word-break: break-all;
}

@ -821,3 +821,7 @@ html>body #ajax-indicator { position: fixed; }
.footer_con-p{
color: #898989 !important;
}
.markdown-body {
text-align: justify;
word-break: break-all;
}
Loading…
Cancel
Save