Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun

chromesetting
daiao 5 years ago
commit 0248928d25

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

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

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

@ -3,104 +3,133 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-12-17 17:35:17 * @Date: 2019-12-17 17:35:17
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-19 18:02:28 * @LastEditTime : 2019-12-24 17:11:59
*/ */
import './index.scss'; import './index.scss';
import React, { useState } from 'react'; import React, { useState } from 'react';
import CommentIcon from './CommentIcon'; import CommentIcon from './CommentIcon';
import { getImageUrl, CNotificationHOC } from 'educoder' import { getImageUrl, CNotificationHOC } from 'educoder'
import { Icon } from 'antd'; import { Icon } from 'antd';
import moment from 'moment';
// import QuillForEditor from '../../quillForEditor';
import CommentForm from './CommentForm'; import CommentForm from './CommentForm';
// import {ModalConfirm} from '../ModalConfirm';
function CommentItem ({ function CommentItem ({
options, options,
confirm confirm,
comment,
submitDeleteComment,
submitChildComment,
likeComment,
showOrHideComment
}) { }) {
// 显示评论输入框 // 显示评论输入框
const [showQuill, setShowQuill] = useState(false); 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 [arrow, setArrow] = useState(false);
// 删除评论
const deleteComment = () => { const {
console.log('删除评论...'); 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({ confirm({
title: '提示', title: '提示',
content: (<p>确定要删除该条回复吗?</p>), content: ('确定要删除该条回复吗?'),
onOk () { onOk () {
console.log('点击了删除'); console.log('点击了删除', id);
submitDeleteComment && submitDeleteComment(id);
} }
}); });
// ModalConfirm('提示', (<p>确定要删除该条回复吗?</p>), () => {
// console.log('点击了删除');
// });
} }
// 评论头像 // 评论头像
const commentAvatar = (url) => ( const commentAvatar = (author) => (
<img className="item-flex flex-image" src='https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg' alt=""/> <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 = () => ( const commentInfo = (id, author, time, can_delete) => {
<p className="item-header"> const _classNames = can_delete ? 'item-close' : 'item-close hide';
<span className="item-name">用户名</span> return (
<span className="item-time">{moment(new Date(), 'YYYYMMDD HHmmss').fromNow()}</span> <div className="item-header">
<span className="item-close"><Icon type="close" onClick={deleteComment}/></span> <span className="item-name">{author.name || ''}</span>
</p> <span className="item-time">{time || ''}</span>
); <span className={_classNames}>
<Icon type="close" onClick={() => deleteComment(id)}/>
</span>
</div>
);
};
// 评论内容 // 评论内容
const commentCtx = (ctx) => ( const commentCtx = (ctx) => (
<p className="item-ctx"> <p className="item-ctx" dangerouslySetInnerHTML={{ __html: ctx}}></p>
这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容这是评论内容
</p>
); );
// 加载更多 // 加载更多
const handleOnLoadMore = () => { const handleOnLoadMore = (len) => {
if (!arrow) { setShowItemCount(!arrow ? len : 1);
// 展开所有
} else {
// 收起
}
setArrow(!arrow); 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 ( return (
<ul className="comment_item_append_list"> <ul className={_clazz}>
<li className="comment_item_area"> {renderChild(children)}
{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>
<li className="comment_item_loadmore" onClick={handleOnLoadMore}> <li className={_moreClass} onClick={() => handleOnLoadMore(len)}>
<p className="loadmore-txt">展开其余23条评论</p> <p className="loadmore-txt">展开其余{lastTxt}条评论</p>
<p className="loadmore-icon"> <p className="loadmore-icon">
<Icon type={!arrow ? 'down' : 'up'}/> <Icon type={!arrow ? 'down' : 'up'}/>
</p> </p>
@ -109,7 +138,14 @@ function CommentItem ({
); );
}; };
// 点击图标 // 点击图标
const handleIconClick = () => {} const handleShowOrHide = (id, hidden) => {
showOrHideComment && showOrHideComment(id, hidden);
}
// 点赞
const handleClickLick = (id) => {
likeComment && likeComment(id);
}
// 点击评论icon // 点击评论icon
const handleClickMessage = () => { const handleClickMessage = () => {
@ -122,23 +158,28 @@ function CommentItem ({
} }
// 点击保存 // 点击保存
const handleClickSubmit = (content) => { const handleClickSubmit = (id) => {
// 保存并关闭 return (ctx) => {
setShowQuill(false); setShowQuill(false);
console.log('获取保存内容', content); submitChildComment && submitChildComment(id, ctx);
}
} }
return ( return (
<li className="comment_item_area"> <li className="comment_item_area">
{commentAvatar()} {commentAvatar(author)}
<div className="item-flex item-desc"> <div className="item-flex item-desc">
{commentInfo()} {commentInfo(id, author, time, can_delete)}
{commentCtx()} {commentCtx(content)}
{commentAppend()} {commentAppend(children)}
<div className="comment_icon_area"> <div className="comment_icon_area">
<CommentIcon className='comment-icon-margin' type="eye" count="100" iconClick={handleIconClick}/> <CommentIcon
className='comment-icon-margin'
type={!hidden ? "eye" : 'eye-invisible'}
iconClick={() => handleShowOrHide(id, !hidden ? 1 : 0)}
/>
{/* 回复 */} {/* 回复 */}
<CommentIcon <CommentIcon
className='comment-icon-margin' className='comment-icon-margin'
@ -146,7 +187,14 @@ function CommentItem ({
iconClick={handleClickMessage} 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>
<div <div
@ -154,7 +202,7 @@ function CommentItem ({
className="comment_item_quill"> className="comment_item_quill">
<CommentForm <CommentForm
onCancel={handleClickCancel} onCancel={handleClickCancel}
onSubmit={handleClickSubmit} onSubmit={handleClickSubmit(id)}
/> />
</div> </div>
</div> </div>

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

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

@ -8,8 +8,14 @@ $ml: 20px;
.comment_list_wrapper{ .comment_list_wrapper{
box-sizing: border-box; box-sizing: border-box;
border-top: 1px solid $bdColor; // border-top: 1px solid $bdColor;
.comment_item_show{
display: block;
}
.comment_item_hide{
display: none;
}
.comment_item_area{ .comment_item_area{
display: flex; display: flex;
padding: 20px 0; padding: 20px 0;
@ -34,8 +40,13 @@ $ml: 20px;
margin-left: $ml; margin-left: $ml;
} }
.item-close{ .item-close{
float: right; display: inline-block;
cursor: pointer; cursor: pointer;
float: right;
}
.item-close.hide{
display: none;
} }
} }
.item-ctx{ .item-ctx{
@ -50,13 +61,16 @@ $ml: 20px;
margin-top: 10px; margin-top: 10px;
.comment-icon-margin{ .comment-icon-margin{
margin-left: 30px; margin-left: 20px;
}
.comment-icon-margin-10{
margin-left: 10px;
} }
} }
.comment_item_quill{ // .comment_item_quill{
margin-top: 20px; // // margin-top: 10px;
} // }
} }
.comment_icon_count{ .comment_icon_count{
cursor: pointer; cursor: pointer;
@ -71,6 +85,9 @@ $ml: 20px;
margin-left: 10px; margin-left: 10px;
transition: color .3s; transition: color .3s;
} }
.comment_count_none{
margin-left: 0;
}
&:hover{ &:hover{
.comment_icon, .comment_icon,
@ -80,11 +97,15 @@ $ml: 20px;
} }
} }
.comment_item_append_list{ .comment_item_append_list{
display: none;
position: relative; position: relative;
background-color: $bgColor; background-color: $bgColor;
border-radius: 5px; border-radius: 5px;
padding: 0 15px 10px; padding: 0 15px 10px;
margin: 15px 0; margin: 15px 0;
&.active{
display: block;
}
&::before { &::before {
position: absolute; position: absolute;
left: 15px; left: 15px;
@ -98,6 +119,7 @@ $ml: 20px;
} }
.comment_item_loadmore{ .comment_item_loadmore{
display: none;
padding-top: 10px; padding-top: 10px;
cursor: pointer; cursor: pointer;
.loadmore-txt, .loadmore-txt,
@ -106,6 +128,41 @@ $ml: 20px;
text-align: center; text-align: center;
font-size: $fz12; 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 * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-12-16 15:50:45 * @Date: 2019-12-16 15:50:45
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-17 16:44:48 * @LastEditTime : 2019-12-24 09:44:03
*/ */
import Quill from "quill"; import Quill from "quill";
@ -43,8 +43,8 @@ export default class ImageBlot extends BlockEmbed {
alt: node.getAttribute('alt'), alt: node.getAttribute('alt'),
url: node.getAttribute('src'), url: node.getAttribute('src'),
onclick: node.onclick, onclick: node.onclick,
// width: node.width, width: node.width,
// height: node.height, height: node.height,
display: node.getAttribute('display') display: node.getAttribute('display')
}; };
} }

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

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

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

@ -3,19 +3,112 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-11-27 09:49:35 * @Date: 2019-11-27 09:49:35
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-17 17:46:05 * @LastEditTime : 2019-12-24 17:10:14
*/ */
import './index.scss'; import './index.scss';
import React from 'react'; import React, { useEffect } from 'react';
import Comment from '../../../../../common/components/comment'; import Comment from '../../../../../common/components/comment';
import { connect } from 'react-redux';
import actions from '../../../../../redux/actions';
const CommentTask = (props) => { const CommentTask = (props) => {
const {
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 ( return (
<div className="task_comment_task"> <div className="task_comment_task">
<Comment /> <Comment
commentLists={commentLists}
addComment={handleAddComment}
addChildComment={handleAddChildComment}
likeComment={handleLikeComment}
showOrHideComment={handleShowOrHideComment}
submitDeleteComment={handleSubmitDeleteComment}
/>
</div> </div>
) )
} }
export default CommentTask; const mapStateToProps = (state) => {
const {
commentLists // 评论列表
} = state.commentReducer;
const {
comment_identifier
} = state.ojForUserReducer;
return {
commentLists,
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 * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-11-23 11:33:41 * @Date: 2019-11-23 11:33:41
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-19 18:03:22 * @LastEditTime : 2019-12-24 17:16:54
// */ // */
import './index.scss'; import './index.scss';
import React, { useState, useEffect, useMemo } from 'react'; import React, { useState, useEffect, useMemo } from 'react';
@ -15,12 +15,19 @@ import CommitRecord from './commitRecord';
import TaskDescription from './taskDescription'; import TaskDescription from './taskDescription';
import TextNumber from './../../components/textNumber'; import TextNumber from './../../components/textNumber';
import actions from '../../../../redux/actions'; import actions from '../../../../redux/actions';
import CommentForm from '../../../../common/components/comment/CommentForm';
// const { TabPane } = Tabs; // const { TabPane } = Tabs;
const LeftPane = (props) => { const LeftPane = (props) => {
const { hack, userCodeTab } = 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 [defaultActiveKey, setDefaultActiveKey] = useState('comment');
const navItem = [ const navItem = [
@ -32,10 +39,10 @@ const LeftPane = (props) => {
title: '提交记录', title: '提交记录',
key: 'record' key: 'record'
}, },
// { {
// title: '评论', title: '评论',
// key: 'comment' key: 'comment'
// } }
]; ];
const Comp = { const Comp = {
@ -45,7 +52,6 @@ const LeftPane = (props) => {
}; };
useEffect(() => { useEffect(() => {
console.log('====>>>>', userCodeTab);
setDefaultActiveKey(userCodeTab); setDefaultActiveKey(userCodeTab);
}, [userCodeTab]) }, [userCodeTab])
@ -69,18 +75,34 @@ const LeftPane = (props) => {
// 点击消息 // 点击消息
const handleClickMessage = () => { const handleClickMessage = () => {
console.log('点击的消息图标---------'); // 切换到评论tab
setDefaultActiveKey('comment');
} }
// 点击点赞 // 点击点赞
const handleClickLike = () => { const handleClickLike = () => {
console.log('点击的Like---------'); // 对OJ进行点赞
} const {id, identifier } = props.hack;
props.likeComment(identifier, id, {
container_type: 'Hack',
type: 1
});
};
// 点击不喜欢 // 点击不喜欢
const handleClickDisLike = () => { // const handleClickDisLike = () => {
console.log('点击的DisLike---------'); // console.log('点击的DisLike---------');
} // }
// 添加评论
const handleAddComment = (ctx) => {
console.log('添加的评论内容: ', ctx, props.identifier);
props.identifier && props.addComment(props.identifier, {
comments: {
content: ctx
}
});
};
return ( return (
<React.Fragment> <React.Fragment>
@ -91,26 +113,46 @@ const LeftPane = (props) => {
{ renderComp } { renderComp }
</div> </div>
<div className={'number_area'}> <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"/> <TextNumber text="通过次数" number={pass_count} position="vertical"/>
<Divider type="vertical" style={{ height: '20px', margin: '10px 20px' }}/> <Divider type="vertical" style={{ height: '20px', margin: '10px 20px' }}/>
<TextNumber text="提交次数" number={submit_count} position="vertical"/> <TextNumber text="提交次数" number={submit_count} position="vertical"/>
</div> </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> </div>
</React.Fragment> </React.Fragment>
); );
} }
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
const { hack, userCodeTab} = state.ojForUserReducer; const { hack, userCodeTab, comment_identifier} = state.ojForUserReducer;
return { return {
hack, hack,
userCodeTab userCodeTab,
identifier: comment_identifier
} }
} }
// changeUserCodeTab // changeUserCodeTab
const mapDispatchToProps = (dispatch) => ({ 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( export default connect(
mapStateToProps, mapStateToProps,

@ -21,13 +21,33 @@
background: #fff; background: #fff;
.flex_count, .flex_count,
.flex_info{ .flex_info,
.flex_quill{
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
} }
.flex_info{ .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;
} }
} }

@ -24,6 +24,7 @@ const types = {
DELETE_TEST_CASE: 'DELETE_TEST_CASE', // 删除测试用例 DELETE_TEST_CASE: 'DELETE_TEST_CASE', // 删除测试用例
SAVE_TEST_CASE: 'SAVE_TEST_CASE', // 保存测试用例 SAVE_TEST_CASE: 'SAVE_TEST_CASE', // 保存测试用例
SAVE_USE_TEST_CASE_VALUE: 'SAVE_USE_TEST_CASE_VALUE', // 用户自定义测试用例值 SAVE_USE_TEST_CASE_VALUE: 'SAVE_USE_TEST_CASE_VALUE', // 用户自定义测试用例值
CHANGE_PUBLISH_VALUE: 'CHANGE_PUBLISH_VALUE', // 改变发布状态值
CLEAR_JSFORM_STORE: 'CLEAR_JSFORM_STORE', // 清空测试用例 CLEAR_JSFORM_STORE: 'CLEAR_JSFORM_STORE', // 清空测试用例
SAVE_EDIT_OJ_FORM_AND_TEST_CASE: 'SAVE_EDIT_OJ_FORM_AND_TEST_CASE', // 保存根据id获取的表单及测试用例值 SAVE_EDIT_OJ_FORM_AND_TEST_CASE: 'SAVE_EDIT_OJ_FORM_AND_TEST_CASE', // 保存根据id获取的表单及测试用例值
TEST_CODE_STATUS: 'TEST_CODE_STATUS', // 代码调试状态 TEST_CODE_STATUS: 'TEST_CODE_STATUS', // 代码调试状态
@ -53,6 +54,7 @@ const types = {
SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码 SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码
CLICK_OPERATE_TYPE: 'CLICK_OPERATE_TYPE', // 点击类型 CLICK_OPERATE_TYPE: 'CLICK_OPERATE_TYPE', // 点击类型
CLEAR_OJ_FOR_USER_REDUCER: 'CLEAR_OJ_FOR_USER_REDUCER', // 退出时清空 ojForUserReducer保存内容 CLEAR_OJ_FOR_USER_REDUCER: 'CLEAR_OJ_FOR_USER_REDUCER', // 退出时清空 ojForUserReducer保存内容
ADD_OJ_LIKE_COUNT: 'ADD_OJ_LIKE_COUNT', // 增加点赞数
/*** jupyter */ /*** jupyter */
GET_JUPYTER_DATA_SETS: 'GET_JUPYTER_DATA_SETS', // jupyter 数据集 GET_JUPYTER_DATA_SETS: 'GET_JUPYTER_DATA_SETS', // jupyter 数据集
GET_JUPYTER_TPI_URL: 'GET_JUPYTER_TPI_URL', // 获取 jupyter url GET_JUPYTER_TPI_URL: 'GET_JUPYTER_TPI_URL', // 获取 jupyter url
@ -67,6 +69,12 @@ const types = {
CHANGE_JYPYTER_TIME: 'CHANGE_JYPYTER_TIME',//增加15分钟 CHANGE_JYPYTER_TIME: 'CHANGE_JYPYTER_TIME',//增加15分钟
CHANGE_EXTENDED_TIME: 'CHANGE_EXTENDED_TIME',//延时 CHANGE_EXTENDED_TIME: 'CHANGE_EXTENDED_TIME',//延时
CHANGE_UPDETA_SPIN: 'CHANGE_UPDETA_SPIN',//加载 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; 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 getUserInfoForNew
} from './user'; } from './user';
import {
addComment,
getCommentLists,
replayChildComment,
deleteComment,
likeComment,
showOrHideComment
} from './comment';
import { import {
getJupyterTpiDataSet, getJupyterTpiDataSet,
getJupyterTpiUrl, getJupyterTpiUrl,
@ -137,6 +146,13 @@ export default {
reset_with_tpi, reset_with_tpi,
addjypertime, addjypertime,
active_with_tpi, active_with_tpi,
updataspinning updataspinning,
// isUpdateCodeCtx // isUpdateCodeCtx
// 评论
addComment,
getCommentLists,
replayChildComment,
deleteComment,
likeComment,
showOrHideComment,
} }

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

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

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

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