Merge remote-tracking branch 'origin/dev_aliyun' into dev_aliyun

dev_tpm_ui
杨树明 5 years ago
commit 6133e45a5b

@ -5,9 +5,10 @@ class Admins::ShixunSettingsController < Admins::BaseController
shixun_settings = Admins::ShixunSettingsQuery.call(params) shixun_settings = Admins::ShixunSettingsQuery.call(params)
@editing_shixuns = shixun_settings.where(status:0).size @editing_shixuns = shixun_settings.where(status:0).size
@pending_shixuns = shixun_settings.where(status:1).size @processed_shixuns = shixun_settings.where(status:2, public: 0).size
@processed_shixuns = shixun_settings.where(status:2).size
@closed_shixuns = shixun_settings.where(status:3).size @closed_shixuns = shixun_settings.where(status:3).size
@pending_public_shixuns = shixun_settings.where(public:1).size
@processed_pubic_shixuns = shixun_settings.where(public:2).size
@sort_json = { @sort_json = {
can_copy: params[:can_copy].present? ? params[:can_copy] : false, can_copy: params[:can_copy].present? ? params[:can_copy] : false,

@ -5,10 +5,8 @@ class Admins::ShixunsController < Admins::BaseController
params[:sort_direction] = params[:sort_direction].presence || 'desc' params[:sort_direction] = params[:sort_direction].presence || 'desc'
shixuns = Admins::ShixunQuery.call(params) shixuns = Admins::ShixunQuery.call(params)
@editing_shixuns = shixuns.where(status:0).size @editing_shixuns = shixuns.where(status:0).size
@pending_shixuns = shixuns.where(status:1).size @processed_shixuns = shixuns.where(status:2, public: 0).size
@processed_shixuns = shixuns.where(status:2).size
@closed_shixuns = shixuns.where(status:3).size @closed_shixuns = shixuns.where(status:3).size
@none_public_shixuns = shixuns.where(public:0).size
@pending_public_shixuns = shixuns.where(public:1).size @pending_public_shixuns = shixuns.where(public:1).size
@processed_pubic_shixuns = shixuns.where(public:2).size @processed_pubic_shixuns = shixuns.where(public:2).size
@shixuns_type_check = MirrorRepository.pluck(:type_name,:id) @shixuns_type_check = MirrorRepository.pluck(:type_name,:id)

@ -1,10 +1,10 @@
class HackUserLastestCodesController < ApplicationController class HackUserLastestCodesController < ApplicationController
before_action :require_login, except: [:listen_result] before_action :require_login, except: [:listen_result]
before_action :find_my_hack, only: [:show, :code_debug, :code_submit, :update_code, :sync_code, before_action :find_my_hack, only: [:show, :code_debug, :code_submit, :update_code, :sync_code, :add_notes,
:listen_result, :result, :submit_records, :restore_initial_code] :listen_result, :result, :submit_records, :restore_initial_code]
before_action :update_user_hack_status, only: [:code_debug, :code_submit] before_action :update_user_hack_status, only: [:code_debug, :code_submit]
before_action :require_auth_identity, only: [:update_code, :restore_initial_code, :sync_code] before_action :require_auth_identity, only: [:add_notes]
before_action :require_manager_identity, only: [:update_code] before_action :require_manager_identity, only: [:show, :update_code, :restore_initial_code, :sync_code]
def show def show
@my_hack.update_attribute(:submit_status, 0) if @my_hack.submit_status == 1 @my_hack.update_attribute(:submit_status, 0) if @my_hack.submit_status == 1
@ -67,7 +67,6 @@ class HackUserLastestCodesController < ApplicationController
end end
# 提交记录详情 # 提交记录详情
def record_detail def record_detail
@hack_user = HackUserCode.find params[:id] @hack_user = HackUserCode.find params[:id]
@ -109,6 +108,11 @@ class HackUserLastestCodesController < ApplicationController
end end
def add_notes
@my_hack.update_attribute(:notes, params[:notes])
render_ok
end
private private
def find_my_hack def find_my_hack
@my_hack = HackUserLastestCode.find_by(identifier: params[:identifier]) @my_hack = HackUserLastestCode.find_by(identifier: params[:identifier])
@ -168,7 +172,7 @@ class HackUserLastestCodesController < ApplicationController
# 编程题已经发布,且之前未通关奖励积分 # 编程题已经发布,且之前未通关奖励积分
@hack.increment!(:pass_num) @hack.increment!(:pass_num)
if @hack.status == 1 && !@my_hack.passed? if @hack.status == 1 && !@my_hack.passed?
reward_attrs = { container_id: game.id, container_type: 'Hack', score: @hack.score } reward_attrs = { container_id: @hack.id, container_type: 'Hack', score: @hack.score }
RewardGradeService.call(@my_hack.user, reward_attrs) RewardGradeService.call(@my_hack.user, reward_attrs)
RewardExperienceService.call(@my_hack.user, reward_attrs) RewardExperienceService.call(@my_hack.user, reward_attrs)
# 评测完成更新通过数 # 评测完成更新通过数

@ -188,10 +188,13 @@ class HacksController < ApplicationController
def param_update_sets sets, all_sets_id def param_update_sets sets, all_sets_id
delete_set_ids = all_sets_id - sets.map{|set|set[:id]} delete_set_ids = all_sets_id - sets.map{|set|set[:id]}
@hack.hack_sets.where(id: delete_set_ids).destroy_all @hack.hack_sets.where(id: delete_set_ids).destroy_all
logger.info("#######sets:#{sets}")
sets.each do |set| sets.each do |set|
logger.info("###set[:id] #{set[:id]}")
logger.info("###all_sets #{all_sets_id.include?(set[:id])}")
if all_sets_id.include?(set[:id]) if all_sets_id.include?(set[:id])
update_attrs = {input: set[:input], output: set[:output], position: set[:position]} update_attrs = {input: set[:input], output: set[:output], position: set[:position]}
@hack.hack_sets.find_by!(id: set[:id]).update_attributes(update_attrs) @hack.hack_sets.find_by!(id: set[:id]).update_attributes!(update_attrs)
end end
end end
end end

@ -1,5 +1,5 @@
class HackSet < ApplicationRecord class HackSet < ApplicationRecord
#validates :input, presence: { message: "测试集输入不能为空" } validates :input, presence: { message: "测试集输入不能为空" }
validates :output, presence: { message: "测试集输出不能为空" } validates :output, presence: { message: "测试集输出不能为空" }
validates_uniqueness_of :input, scope: [:hack_id, :input], message: "多个测试集的输入不能相同" validates_uniqueness_of :input, scope: [:hack_id, :input], message: "多个测试集的输入不能相同"
# 编程题测试集 # 编程题测试集

@ -12,4 +12,6 @@ class HackUserLastestCode < ApplicationRecord
scope :mine_hack, ->(author_id){ where(user_id: author_id) } scope :mine_hack, ->(author_id){ where(user_id: author_id) }
scope :passed, -> {where(status: 1)} scope :passed, -> {where(status: 1)}
validates_length_of :notes, maximum: 5000, message: "笔记不能超过5000个字"
end end

@ -13,25 +13,14 @@ class Admins::ShixunQuery < ApplicationQuery
all_shixuns = Shixun.all all_shixuns = Shixun.all
status = status =
case params[:status] case params[:status]
when "editing" then [0] when "editing" then {status: 0}
when "pending" then [1] when "processed" then {status: 2, public: 0}
when "processed" then [2] when "pending" then {public: 1}
when "closed" then [3] when "publiced" then {public: 2}
else when "closed" then {status: 3}
[0,1,2,3]
end end
public = all_shixuns = all_shixuns.where(status) if status.present?
case params[:public]
when "editing" then [0]
when "pending" then [1]
when "processed" then [2]
else
[0,1,2]
end
all_shixuns = all_shixuns.where(status: status) if status.present?
all_shixuns = all_shixuns.where(public: public) if public.present?
if params[:fork_status].present? if params[:fork_status].present?
all_shixuns = all_shixuns.where.not(fork_from: nil) all_shixuns = all_shixuns.where.not(fork_from: nil)

@ -15,16 +15,15 @@ class Admins::ShixunSettingsQuery < ApplicationQuery
all_shixuns = all_shixuns.where(id: params[:id]) if params[:id].present? all_shixuns = all_shixuns.where(id: params[:id]) if params[:id].present?
status = status =
case params[:status] case params[:status]
when "editing" then [0] when "editing" then {status: 0}
when "pending" then [1] when "processed" then {status: 2, public: 0}
when "processed" then [2] when "pending" then {public: 1}
when "closed" then [3] when "publiced" then {public: 2}
else when "closed" then {status: 3}
[0,1,2,3] end
end
all_shixuns = all_shixuns.where(status) if status.present?
all_shixuns = all_shixuns.where(status: status) if status.present?
if params[:tag].present? if params[:tag].present?
all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i) all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i)

@ -33,6 +33,10 @@ class ShixunSearchService < ApplicationService
@shixuns = status == "published" ? @shixuns.where(status: 2) : @shixuns.where(status: [0, 1]) @shixuns = status == "published" ? @shixuns.where(status: 2) : @shixuns.where(status: [0, 1])
end end
if params[:no_jupyter]
@shixuns = @shixuns.where(is_jupyter: 0)
end
## 筛选 难度 ## 筛选 难度
if params[:diff].present? && params[:diff].to_i != 0 if params[:diff].present? && params[:diff].to_i != 0
@shixuns = @shixuns.where(trainee: params[:diff]) @shixuns = @shixuns.where(trainee: params[:diff])

@ -8,7 +8,7 @@
<div class="d-flex position-r"> <div class="d-flex position-r">
<div class="form-group mr-2"> <div class="form-group mr-2">
<label for="status">状态:</label> <label for="status">状态:</label>
<% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["待审核(#{@pending_shixuns})", 'pending'], ["已发布(#{@processed_shixuns})", 'processed'],["已关闭(#{@closed_shixuns})",'closed']] %> <% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["已发布未公开(#{@processed_shixuns})", 'processed'], ["待审核(#{@pending_public_shixuns})", 'pending'], ["已公开(#{@processed_pubic_shixuns})", 'publiced'], ["已关闭(#{@closed_shixuns})",'closed']] %>
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %> <%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div> </div>
<div class="form-group mr-2"> <div class="form-group mr-2">

@ -8,16 +8,10 @@
<div class="d-flex position-r"> <div class="d-flex position-r">
<div class="form-group"> <div class="form-group">
<label for="status">状态:</label> <label for="status">状态:</label>
<% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["待审核(#{@pending_shixuns})", 'pending'], ["已发布(#{@processed_shixuns})", 'processed'],["已关闭(#{@closed_shixuns})",'closed']] %> <% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["已发布未公开(#{@processed_shixuns})", 'processed'], ["待审核(#{@pending_public_shixuns})", 'pending'], ["已公开(#{@processed_pubic_shixuns})", 'publiced'], ["已关闭(#{@closed_shixuns})",'closed']] %>
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %> <%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div> </div>
<div class="form-group mr-2">
<label for="status">公开:</label>
<% public_options = [['全部', ''], ["未公开(#{@none_public_shixuns})", "editing"], ["待审核(#{@pending_public_shixuns})", 'pending'], ["已公开(#{@processed_pubic_shixuns})", 'processed']] %>
<%= select_tag(:public, options_for_select(public_options), class: 'form-control') %>
</div>
<div class="form-group mr-2"> <div class="form-group mr-2">
<label for="tag-choosed">技术平台:</label> <label for="tag-choosed">技术平台:</label>
<%= select_tag(:tag, options_for_select(@shixuns_type_check.unshift(["",nil])), class: 'form-control',id:"tag-choosed") %> <%= select_tag(:tag, options_for_select(@shixuns_type_check.unshift(["",nil])), class: 'form-control',id:"tag-choosed") %>

@ -14,7 +14,7 @@ if @tab == 0
elsif @tab == 1 elsif @tab == 1
# 评测设置的编辑模式 # 评测设置的编辑模式
json.(@challenge, :id, :path, :exec_path, :show_type, :original_picture_path, :expect_picture_path, :picture_path, json.(@challenge, :id, :path, :exec_path, :show_type, :original_picture_path, :expect_picture_path, :picture_path,
:web_route, :test_set_score, :test_set_average) :web_route, :test_set_score, :test_set_average, :exec_time)
json.has_web_route @shixun.has_web_route? json.has_web_route @shixun.has_web_route?
json.test_sets @challenge.test_sets do |set| json.test_sets @challenge.test_sets do |set|
json.hidden (set.is_public ? 0 : 1) json.hidden (set.is_public ? 0 : 1)

@ -5,6 +5,7 @@ json.hack do
json.code @my_hack.code json.code @my_hack.code
json.pass_count @hack.pass_num json.pass_count @hack.pass_num
json.submit_count @hack.submit_num json.submit_count @hack.submit_num
json.notes @my_hack.notes
json.modify_code @modify json.modify_code @modify
json.comments_count @hack.discusses.count json.comments_count @hack.discusses.count
json.user_praise @hack.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0 json.user_praise @hack.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0

@ -90,6 +90,7 @@ Rails.application.routes.draw do
get :submit_records get :submit_records
post :restore_initial_code post :restore_initial_code
post :sync_code post :sync_code
post :add_notes
end end
collection do collection do

@ -0,0 +1,5 @@
class AddNotesHackUserLastestCodes < ActiveRecord::Migration[5.2]
def change
add_column :hack_user_lastest_codes, :notes, :longtext
end
end

@ -0,0 +1,8 @@
class ModifyTaskPass2ForChallenges < ActiveRecord::Migration[5.2]
def change
challenges = Challenge.where("task_pass like '%frac%'")
challenges.find_each do |c|
c.update_column(:task_pass, c.task_pass.gsub('\f\frac', '\frac'))
end
end
end

Binary file not shown.

@ -4,14 +4,14 @@
* @Github: * @Github:
* @Date: 2019-12-17 17:32:55 * @Date: 2019-12-17 17:32:55
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 17:27:41 * @LastEditTime : 2019-12-26 11:11:57
*/ */
import './index.scss'; 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'; // import {formatDelta} from './util';
const FormItem = Form.Item; const FormItem = Form.Item;
function CommentForm (props) { function CommentForm (props) {
@ -68,8 +68,9 @@ function CommentForm (props) {
const content = ctx; const content = ctx;
props.form.setFieldsValue({'comment': ''}); props.form.setFieldsValue({'comment': ''});
setCtx(''); setCtx('');
const _html = formatDelta(content.ops); // const _html = formatDelta(content.ops);
onSubmit && onSubmit(_html); console.log('保存的内容=====》》》》', content);
onSubmit && onSubmit(JSON.stringify(content));
} }
}); });
} }

@ -4,14 +4,19 @@
* @Github: * @Github:
* @Date: 2019-12-17 17:35:17 * @Date: 2019-12-17 17:35:17
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 14:53:41 * @LastEditTime : 2019-12-26 11:30:32
*/ */
import './index.scss'; import './index.scss';
import 'quill/dist/quill.core.css'; // 核心样式
import 'quill/dist/quill.snow.css'; // 有工具栏
import 'quill/dist/quill.bubble.css'; // 无工具栏
import 'katex/dist/katex.min.css'; // katex 表达式样式
import React, { useState } 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 CommentForm from './CommentForm'; import CommentForm from './CommentForm';
import QuillForEditor from '../../quillForEditor';
function CommentItem ({ function CommentItem ({
isAdmin, isAdmin,
@ -81,9 +86,19 @@ function CommentItem ({
}; };
// 评论内容 // 评论内容
const commentCtx = (ctx) => ( const commentCtx = (ctx) => {
<p className="item-ctx" dangerouslySetInnerHTML={{ __html: ctx}}></p> let _ctx = null;
); try {
_ctx = JSON.parse(ctx);
} catch (e) {
_ctx = ctx;
}
return (
<QuillForEditor
readOnly={true}
value={_ctx}
/>
)};
// 加载更多 // 加载更多
const handleOnLoadMore = (len) => { const handleOnLoadMore = (len) => {
@ -182,6 +197,13 @@ function CommentItem ({
type={!hidden ? "xianshi" : 'yincang1'} type={!hidden ? "xianshi" : 'yincang1'}
iconClick={() => handleShowOrHide(id, !hidden ? 1 : 0)} iconClick={() => handleShowOrHide(id, !hidden ? 1 : 0)}
/> />
<CommentIcon
style={{ display: can_delete ? 'inline-block' : 'none'}}
className='comment-icon-margin'
type={'shanchu'}
iconClick={() => deleteComment(id)}
/>
{/* 回复 */} {/* 回复 */}
<CommentIcon <CommentIcon
className='comment-icon-margin' className='comment-icon-margin'

@ -64,10 +64,12 @@ $ml: 20px;
} }
.item-ctx{ .item-ctx{
position: relative;
line-height: $lh22; line-height: $lh22;
font-size: $fz12; font-size: $fz12;
color: #333; color: #333;
margin-top: 10px; margin-top: 10px;
vertical-align: top;
} }
.comment_icon_area{ .comment_icon_area{
display: flex; display: flex;

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-12-24 08:51:25 * @Date: 2019-12-24 08:51:25
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 10:45:44 * @LastEditTime : 2019-12-26 09:30:11
*/ */
export const formatDelta = (deltas) => { export const formatDelta = (deltas) => {
@ -22,6 +22,8 @@ export const formatDelta = (deltas) => {
keys.forEach(key => { keys.forEach(key => {
text = operate(text, key, element['attributes'][key]); text = operate(text, key, element['attributes'][key]);
}); });
} else if (element['insert']['formula']) {
text = element['insert']['formula'];
} }
} else { } else {
const image = element['insert']['image']; const image = element['insert']['image'];
@ -42,7 +44,7 @@ export const formatDelta = (deltas) => {
formatted.push(text); formatted.push(text);
}); });
console.log(formatted);
return formatted.join(''); return formatted.join('');
} }
@ -53,7 +55,7 @@ export const formatDelta = (deltas) => {
*/ */
export const operate = (text, key, value) => { export const operate = (text, key, value) => {
let operatedText = null; let operatedText = null;
debugger;
switch (key) { switch (key) {
case 'bold': case 'bold':
operatedText = `<strong>${text}</strong>`; operatedText = `<strong>${text}</strong>`;
@ -68,7 +70,7 @@ export const operate = (text, key, value) => {
operatedText = `<u>${text}</u>`; operatedText = `<u>${text}</u>`;
break; break;
case 'link': case 'link':
operatedText = `<a href="${value}" target="blank">${text}</a>`; operatedText = `<a href="${value}" style="color: #5091ff; text-decoration: underline;" target="bland">${text}</a>`;
break; break;
default: default:
operatedText = text; operatedText = text;

@ -3,8 +3,8 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-12-18 08:49:30 * @Date: 2019-12-18 08:49:30
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-20 16:07:37 * @LastEditTime : 2019-12-26 10:22:26
*/ */
import './index.scss'; import './index.scss';
import 'quill/dist/quill.core.css'; // 核心样式 import 'quill/dist/quill.core.css'; // 核心样式
@ -32,7 +32,8 @@ function QuillForEditor ({
style = {}, style = {},
wrapStyle = {}, wrapStyle = {},
showUploadImage, showUploadImage,
onContentChange onContentChange,
// getQuillContent
}) { }) {
// toolbar 默认值 // toolbar 默认值
const defaultConfig = [ const defaultConfig = [
@ -54,8 +55,8 @@ function QuillForEditor ({
// 文本内容变化时 // 文本内容变化时
const handleOnChange = content => { const handleOnChange = content => {
// console.log('编辑器内容====》》》》', content); // getQuillContent && getQuillContent(quill);
onContentChange && onContentChange(content); onContentChange && onContentChange(content, quill);
}; };
const renderOptions = options || defaultConfig; const renderOptions = options || defaultConfig;

@ -3,8 +3,8 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-11-27 16:02:36 * @Date: 2019-11-27 16:02:36
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-20 14:37:39 * @LastEditTime : 2019-12-26 15:17:28
*/ */
import './index.scss'; import './index.scss';
import React, { useState, useRef, useEffect } from 'react'; import React, { useState, useRef, useEffect } from 'react';
@ -23,7 +23,7 @@ const ControlSetting = (props) => {
submitLoading, submitLoading,
identifier, identifier,
excuteState, excuteState,
showOrHideControl, // showOrHideControl,
commitTestRecordDetail, commitTestRecordDetail,
changeLoadingState, changeLoadingState,
changeSubmitLoadingStatus, changeSubmitLoadingStatus,

@ -31,6 +31,14 @@
opacity: 0; opacity: 0;
} }
} }
.ant-tabs-bar{
padding: 0;
}
.ant-tabs-nav .ant-tabs-tab{
padding: 12px 0px;
}
} }
@ -52,7 +60,7 @@
z-index: 20; z-index: 20;
height: 56px; height: 56px;
padding-right: 20px; padding-right: 20px;
padding-left: 10px; padding-left: 5px;
background: rgba(18,28,36,1); background: rgba(18,28,36,1);
// background:rgba(48,48,48,1); // background:rgba(48,48,48,1);
} }

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-28 08:44:54 * @Date: 2019-11-28 08:44:54
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 11:42:10 * @LastEditTime : 2019-12-26 08:51:21
*/ */
import './index.scss'; import './index.scss';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
@ -80,6 +80,13 @@ function ExecResult (props) {
</React.Fragment> </React.Fragment>
); );
} else if (state === 4){ } else if (state === 4){
return (
<p className={'result_info_style'}>
{/* 系统繁忙,请稍后重试 */}
{error_msg}
</p>
)
} else if (state === 3) {
return ( return (
<p className={'result_info_style'}> <p className={'result_info_style'}>
系统繁忙请稍后重试 系统繁忙请稍后重试

@ -41,7 +41,7 @@
} }
} }
.flex_l{ .flex_l{
padding: 0 10px 0 20px; padding: 0 10px 0 10px;
color: #fff; color: #fff;
} }
.flex_r{ .flex_r{

@ -3,8 +3,8 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-11-27 15:02:52 * @Date: 2019-11-27 15:02:52
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-20 20:07:11 * @LastEditTime : 2019-12-26 15:19:34
*/ */
import './index.scss'; import './index.scss';
import React, { useState, useRef, useEffect } from 'react'; import React, { useState, useRef, useEffect } from 'react';
@ -155,7 +155,7 @@ function MyMonacoEditor (props, ref) {
onClick={handleUpdateNotice} onClick={handleUpdateNotice}
> >
{/* <Icon type="bell" /> */} {/* <Icon type="bell" /> */}
<MyIcon type="iconxiaoxi1" /> <MyIcon type="iconxiaoxi1" style={{fontSize: '18px'}}/>
</Badge> </Badge>
</Tooltip> </Tooltip>
<Tooltip <Tooltip
@ -166,7 +166,7 @@ function MyMonacoEditor (props, ref) {
className="flex_normal" className="flex_normal"
onClick={handleRestoreCode} onClick={handleRestoreCode}
type="iconzaicizairu" type="iconzaicizairu"
style={{ display: identifier ? 'inline-block' : 'none'}} style={{ display: identifier ? 'inline-block' : 'none', fontSize: '18px'}}
/> />
{/* <span onClick={handleRestoreCode} className="flex_normal" style={{ display: identifier ? 'inline-block' : 'none'}}>{renderRestore}</span> */} {/* <span onClick={handleRestoreCode} className="flex_normal" style={{ display: identifier ? 'inline-block' : 'none'}}>{renderRestore}</span> */}
</Tooltip> </Tooltip>
@ -174,7 +174,7 @@ function MyMonacoEditor (props, ref) {
placement="bottom" placement="bottom"
title="设置" title="设置"
> >
<MyIcon className='code-icon' type="iconshezhi" onClick={handleShowDrawer}/> <MyIcon className='code-icon' type="iconshezhi" onClick={handleShowDrawer} style={{fontSize: '18px'}}/>
</Tooltip> </Tooltip>
</div> </div>
<MonacoEditor <MonacoEditor

@ -26,6 +26,18 @@
color: #666; color: #666;
} }
} }
.margin,
.margin-view-overlays,
.current-line{
width: 40px !important;
}
.monaco-editor .margin-view-overlays .line-numbers{
text-align: center;
}
.monaco-scrollable-element{
left: 40px !important;
}
} }
.setting_drawer{ .setting_drawer{

@ -3,8 +3,8 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-11-21 09:19:38 * @Date: 2019-11-21 09:19:38
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-20 17:32:10 * @LastEditTime : 2019-12-26 15:33:01
*/ */
import './index.scss'; import './index.scss';
import React from 'react'; import React from 'react';
@ -17,7 +17,7 @@ const { TextArea } = Input;
const FormItem = Form.Item; const FormItem = Form.Item;
const AddTestDemo = (props) => { const AddTestDemo = (props) => {
const { const {
key, // key,
// onSubmitTest, // onSubmitTest,
onDeleteTest, onDeleteTest,
testCase, testCase,

@ -3,8 +3,8 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-11-20 10:35:40 * @Date: 2019-11-20 10:35:40
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-20 16:53:55 * @LastEditTime : 2019-12-26 16:00:57
*/ */
import './index.scss'; import './index.scss';
// import 'katex/dist/katex.css'; // import 'katex/dist/katex.css';
@ -222,10 +222,16 @@ class EditTab extends React.Component {
} }
// 描述信息变化时 // 描述信息变化时
const handleContentChange = (content) => { const handleContentChange = (content, quill) => {
console.log('描述信息为: ', content); console.log('描述信息为: ', content);
// 保存获取的描述信息至redux中 // if (quill.getText())
this.handleChangeDescription(content); console.log('========>>>>>', quill.getText().length);
if (quill.getText().length === 1) {
this.handleChangeDescription('');
} else {
// 保存获取的描述信息至redux中
this.handleChangeDescription(content);
}
} }
// 编辑器配置信息 // 编辑器配置信息
const quillConfig = [ const quillConfig = [

@ -58,7 +58,7 @@ function LeftPane (props) {
<ul className={'add_editor_list_area'}> <ul className={'add_editor_list_area'}>
{ renderNavItem } { renderNavItem }
</ul> </ul>
<div className="comp_ctx"> <div className="comp_ctx" style={{ height: 'calc(100vh - 177px)' }}>
{ renderComp } { renderComp }
</div> </div>
</React.Fragment> </React.Fragment>

@ -3,8 +3,8 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-12-01 10:18:35 * @Date: 2019-12-01 10:18:35
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-09 11:38:15 * @LastEditTime : 2019-12-26 13:51:40
*/ */
import './index.scss'; import './index.scss';
import React from 'react'; import React from 'react';
@ -25,15 +25,15 @@ function RightPane (props, ref) {
// let timer = null; // let timer = null;
// 代码改变时,保存 // 代码改变时,保存
const handleCodeChange = (updateCode) => { const handleCodeChange = (updateCode) => {
// 保存用户输入的代码 // if (props.identifier) {
// if (!timer) { // // 保存用户输入的代码
// timer = setInterval(() => { // if (!timer) {
// clearInterval(timer); // timer = setInterval(() => {
// timer = null; // clearInterval(timer);
// if (updateCode) { // timer = null;
// console.log('调用更新代码------>>>>>>', updateCode);
// } // }, 3000);
// }, 3000); // }
// } // }
saveOjFormCode(updateCode); saveOjFormCode(updateCode);
} }

@ -41,7 +41,7 @@
} }
} }
.flex_l{ .flex_l{
padding: 0 10px 0 20px; padding: 0 10px 0 10px;
color: #fff; color: #fff;
} }
.flex_r{ .flex_r{

@ -3,8 +3,8 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-12-04 08:36:21 * @Date: 2019-12-04 08:36:21
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-20 20:05:57 * @LastEditTime : 2019-12-26 14:04:16
*/ */
import './index.scss'; import './index.scss';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
@ -15,6 +15,7 @@ import { Link } from 'react-router-dom';
import MonacoEditor from '@monaco-editor/react'; import MonacoEditor from '@monaco-editor/react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
// import { getImageUrl } from 'educoder'; // import { getImageUrl } from 'educoder';
import { withRouter } from 'react-router'
import actions from '../../../redux/actions'; import actions from '../../../redux/actions';
import CONST from '../../../constants'; import CONST from '../../../constants';
import UserInfo from '../components/userInfo'; import UserInfo from '../components/userInfo';
@ -53,6 +54,12 @@ function RecordDetail (props) {
} }
}, [recordDetail]); }, [recordDetail]);
const handleReturn = (identifier) => {
if (identifier) {
saveEditorCodeForDetail('');
props.history.push(`/myproblems/${identifier}`);
}
}
return ( return (
<div className="record_detail_area"> <div className="record_detail_area">
<div className="record_detail_header"> <div className="record_detail_header">
@ -67,8 +74,9 @@ function RecordDetail (props) {
<span>{detail.name || 'test'}</span> <span>{detail.name || 'test'}</span>
</div> </div>
<div className={'study_quit'}> <div className={'study_quit'}>
<Button style={{ visibility: identifier ? 'visible' : 'hidden'}}> <Button style={{ visibility: identifier ? 'visible' : 'hidden'}} onClick={() => handleReturn(identifier)}>
<Link to={`/myproblems/${identifier}`}>返回该题</Link> 返回该题
{/* <Link to={`/myproblems/${identifier}`}>返回该题</Link> */}
</Button> </Button>
</div> </div>
</div> </div>
@ -89,7 +97,7 @@ function RecordDetail (props) {
语言: <span className="status_label_sub">{detail.language}</span> 语言: <span className="status_label_sub">{detail.language}</span>
</span> </span>
<span className="status_label" style={{ visibility: detail.status === 0 ? 'visible' : 'hidden'}}> <span className="status_label" style={{ visibility: detail.status === 0 ? 'visible' : 'hidden'}}>
执行用时: <span className="status_label_sub">{`${detail.execute_time && (+detail.execute_time * 1000)}ms`}</span> 执行用时: <span className="status_label_sub">{`${detail.execute_time && Number(detail.execute_time * 1000).toFixed(2)}ms`}</span>
</span> </span>
</div> </div>
<div className="result_error_area"> <div className="result_error_area">
@ -134,7 +142,7 @@ const mapDispatchToProps = (dispatch) => ({
saveEditorCodeForDetail: (code) => dispatch(actions.saveEditorCodeForDetail(code)) saveEditorCodeForDetail: (code) => dispatch(actions.saveEditorCodeForDetail(code))
}); });
export default connect( export default withRouter(connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(RecordDetail); )(RecordDetail));

@ -148,8 +148,9 @@
} }
.Resizer { .Resizer {
position: relative;
background: #000; background: #000;
opacity: 0.2; // opacity: 0.2;
z-index: 1; z-index: 1;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;

@ -3,8 +3,8 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-11-23 10:53:19 * @Date: 2019-11-23 10:53:19
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-20 14:54:39 * @LastEditTime : 2019-12-26 15:02:12
*/ */
import './index.scss'; import './index.scss';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
@ -25,9 +25,9 @@ function StudentStudy (props) {
const [hasUpdate, setHasUpdate] = useState(true); const [hasUpdate, setHasUpdate] = useState(true);
const { const {
// hack, hack,
userInfo, userInfo,
hack_identifier, // hack_identifier,
// user_program_identifier, // user_program_identifier,
restoreInitialCode, restoreInitialCode,
changeShowOrHideControl changeShowOrHideControl
@ -85,13 +85,13 @@ function StudentStudy (props) {
// } // }
// }); // });
} }
const _hack_id = hack_identifier || fromStore('hack_identifier'); // const _hack_id = hack_identifier || fromStore('hack_identifier');
// 处理编辑 // 处理编辑
const handleClickEditor = () => { const handleClickEditor = (identifier) => {
if (!identifier) return;
changeShowOrHideControl(false); changeShowOrHideControl(false);
props.saveEditorCodeForDetail(); props.saveEditorCodeForDetail();
props.history.push(`/problems/${_hack_id}/edit`); props.history.push(`/problems/${identifier}/edit`);
props.clearOjForUserReducer(); props.clearOjForUserReducer();
} }
// 处理退出 // 处理退出
@ -115,13 +115,13 @@ function StudentStudy (props) {
</div> */} </div> */}
<UserInfo userInfo={userInfo}/> <UserInfo userInfo={userInfo}/>
<div className={'study_name'}> <div className={'study_name'}>
<span>乘积最大序列 {hasUpdate}</span> <span>{hack.name}</span>
</div> </div>
<div className={'study_quit'}> <div className={'study_quit'}>
{/* to={`/problems/${_hack_id}/edit`} */} {/* to={`/problems/${_hack_id}/edit`} */}
<span <span
style={{ display: userInfo.hack_manager ? 'inline-block' : 'none' }} style={{ display: userInfo.hack_manager ? 'inline-block' : 'none' }}
onClick={handleClickEditor} onClick={() => handleClickEditor(hack.identifier)}
className={`quit-btn`} className={`quit-btn`}
> >
<Icon type="form" className="quit-icon"/> 编辑 <Icon type="form" className="quit-icon"/> 编辑

@ -1,6 +1,52 @@
@import '../split_pane_resizer.scss'; @import '../split_pane_resizer.scss';
.split-pane-area{ .split-pane-area{
height: calc(100vh - 65px); height: calc(100vh - 65px);
.right_pane_code_wrap{
position: relative;
.editor_nodte_area,
.student_notes{
position: absolute;
z-index: 100;
}
.student_notes{
right: 0px;
top: 50%;
width: 36px;
height: 36px;
margin-top: -18px;
border-radius: 50%;
background: #5091FF;
color: #fff;
font-size: 18px;
text-align: center;
transform: translateX(18px);
cursor: pointer;
opacity: 0.5;
transition: all .3s;
&:hover{
opacity: 1;
transform: translateX(-10px);
}
}
.editor_nodte_area{
right: 10px;
top: 50%;
width: 450px;
height: 200px;
margin-top: -100px;
background: #fff;
border-radius: 5px;
padding: 14px 10px 0;
// opacity: ;
transform: translateX(500px);
transition: all .3s;
&.active{
transform: translateX(0px);
}
}
}
} }
.right_pane_code_wrap{ .right_pane_code_wrap{

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 09:49:35 * @Date: 2019-11-27 09:49:35
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 10:55:44 * @LastEditTime : 2019-12-26 10:43:45
*/ */
import './index.scss'; import './index.scss';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';

@ -3,15 +3,20 @@
* @Author: tangjiang * @Author: tangjiang
* @Github: * @Github:
* @Date: 2019-11-27 14:59:51 * @Date: 2019-11-27 14:59:51
* @LastEditors: tangjiang * @LastEditors : tangjiang
* @LastEditTime: 2019-12-20 14:01:57 * @LastEditTime : 2019-12-26 17:56:51
*/ */
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import MyMonacoEditor from '../../components/myMonacoEditor'; import MyMonacoEditor from '../../components/myMonacoEditor';
import ControlSetting from '../../components/controlSetting'; import ControlSetting from '../../components/controlSetting';
import actions from '../../../../redux/actions'; import actions from '../../../../redux/actions';
// import QuillForEditor from '../../../../common/quillForEditor';
// import TextArea from 'antd/lib/input/TextArea';
import { Input, Form, Button } from 'antd';
// import FormItem from 'antd/lib/form/FormItem';
const { TextArea } = Input;
const FormItem = Form.Item;
const RightPane = (props) => { const RightPane = (props) => {
const { const {
@ -20,6 +25,7 @@ const RightPane = (props) => {
submitUserCode, submitUserCode,
input, input,
hack, hack,
loading,
notice, notice,
updateCode, updateCode,
hadCodeUpdate, hadCodeUpdate,
@ -27,12 +33,15 @@ const RightPane = (props) => {
updateNotice, updateNotice,
saveUserInputCode, saveUserInputCode,
restoreInitialCode, restoreInitialCode,
saveOpacityType, // saveOpacityType,
saveUserCodeForInterval saveUserCodeForInterval,
addNotes,
changeLoadingState
} = props; } = props;
const [editorCode, setEditorCode] = useState(''); const [editorCode, setEditorCode] = useState('');
const [noteClazz, setNoteClazz] = useState('editor_nodte_area');
const [noteCount] = useState(5000);
let initFlag = true; let initFlag = true;
useEffect(() => { useEffect(() => {
if (editor_code) { if (editor_code) {
@ -86,6 +95,28 @@ const RightPane = (props) => {
updateNotice && updateNotice(); updateNotice && updateNotice();
}; };
const handleClickNote = () => {
setNoteClazz('editor_nodte_area active');
}
const handleCancelNote = () => {
props.form.resetFields();
setNoteClazz('editor_nodte_area');
}
const handleSubmitNote = () => {
props.form.validateFields((err, values) => {
if (!err) {
changeLoadingState(true);
addNotes(identifier, values, function () {
setNoteClazz('editor_nodte_area');
props.form.resetFields();
});
}
});
}
const { getFieldDecorator } = props.form;
return ( return (
<div className={'right_pane_code_wrap'}> <div className={'right_pane_code_wrap'}>
<MyMonacoEditor <MyMonacoEditor
@ -98,6 +129,40 @@ const RightPane = (props) => {
onUpdateNotice={handleUpdateNotice} onUpdateNotice={handleUpdateNotice}
onRestoreInitialCode={handleRestoreInitialCode} onRestoreInitialCode={handleRestoreInitialCode}
/> />
<span
className="iconfont icon-biji student_notes"
onClick={handleClickNote}
></span>
{/* <div className="student_notes">
<TextArea rows={5} />
</div> */}
<div className={noteClazz}>
<Form>
<FormItem>
{
getFieldDecorator('notes',{
rules: [
{ required: true, message: '笔记不能为空' },
{ max: noteCount, message: `笔记最大字数为${noteCount}` }
],
initialValue: (hack && hack.notes) || ''
})(<TextArea
max={noteCount}
placeholder="请输入笔记内容"
rows="5"
/>)
}
</FormItem>
<FormItem style={{ textAlign: 'right' }}>
<Button loading={loading} style={{ marginRight: '10px' }} onClick={handleCancelNote}>取消</Button>
<Button type="primary" onClick={handleSubmitNote}>提交</Button>
</FormItem>
</Form>
</div>
<ControlSetting <ControlSetting
identifier={identifier} identifier={identifier}
inputValue={input} inputValue={input}
@ -117,10 +182,14 @@ const mapStateToProps = (state) => {
notice, notice,
hadCodeUpdate hadCodeUpdate
} = state.ojForUserReducer; } = state.ojForUserReducer;
const {
loading
} = state.commonReducer;
// const { language, code } = hack; // const { language, code } = hack;
return { return {
hack, hack,
notice, notice,
loading,
hadCodeUpdate, hadCodeUpdate,
editor_code, editor_code,
input: userTestInput, input: userTestInput,
@ -141,9 +210,12 @@ const mapDispatchToProps = (dispatch) => ({
// 恢复初始代码 // 恢复初始代码
restoreInitialCode: (identifier, msg) => dispatch(actions.restoreInitialCode(identifier, msg)), restoreInitialCode: (identifier, msg) => dispatch(actions.restoreInitialCode(identifier, msg)),
// saveOpacityType: (type) => dispatch(actions.saveOpacityType(type)) // saveOpacityType: (type) => dispatch(actions.saveOpacityType(type))
// 添加笔记
addNotes: (identifier, params, cb) => dispatch(actions.addNotes(identifier, params, cb)),
changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag))
}); });
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(RightPane); )(Form.create()(RightPane));

@ -56,7 +56,8 @@ const types = {
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', // 增加点赞数 ADD_OJ_LIKE_COUNT: 'ADD_OJ_LIKE_COUNT', // 增加点赞数
CHANGE_RECORD_PAGINATION_PAGE: 'CHANGE_RECORD_PAGINATION_PAGE', // 改变提交分页 CHANGE_RECORD_PAGINATION_PAGE: 'CHANGE_RECORD_PAGINATION_PAGE', // 改变提交分页
UPDATE_OJ_FOR_USER_COMMENT_COUNT: 'UPDATE_OJ_FOR_USER_COMMENT_COUNT', // 更新 hack 中的评论数 UPDATE_OJ_FOR_USER_COMMENT_COUNT: 'UPDATE_OJ_FOR_USER_COMMENT_COUNT', // 更新 hack 中的评论数,
UPDATE_NOTE_CONTENT: 'UPDATE_NOTE_CONTENT', // 更新笔记内容
/*** 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

@ -50,7 +50,8 @@ import {
saveEditorCodeForDetail, saveEditorCodeForDetail,
saveOpacityType, saveOpacityType,
clearOjForUserReducer, clearOjForUserReducer,
changeRecordPagination changeRecordPagination,
addNotes
// isUpdateCodeCtx // isUpdateCodeCtx
} from './ojForUser'; } from './ojForUser';
@ -137,6 +138,7 @@ export default {
saveOpacityType, saveOpacityType,
clearOjForUserReducer, clearOjForUserReducer,
changeRecordPagination, changeRecordPagination,
addNotes,
// jupyter // jupyter
getJupyterTpiDataSet, getJupyterTpiDataSet,
getJupyterTpiUrl, getJupyterTpiUrl,

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 13:42:11 * @Date: 2019-11-27 13:42:11
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 14:27:58 * @LastEditTime : 2019-12-26 18:32:08
*/ */
import types from "./actionTypes"; import types from "./actionTypes";
import { Base64 } from 'js-base64'; import { Base64 } from 'js-base64';
@ -17,7 +17,8 @@ import {
fetchUserCommitRecordDetail, fetchUserCommitRecordDetail,
fetchUpdateCode, fetchUpdateCode,
fetchUserCodeSubmit, fetchUserCodeSubmit,
fetchRestoreInitialCode fetchRestoreInitialCode,
fetchAddNotes
} from "../../services/ojService"; } from "../../services/ojService";
import { notification } from "antd"; import { notification } from "antd";
@ -488,3 +489,33 @@ export const changeRecordPagination = (page) => {
} }
} }
// 更新通知状态 // 更新通知状态
// 添加笔记
export const addNotes = (identifier, params, cb) => {
return (dispatch) => {
fetchAddNotes(identifier, params).then(res => {
// console.log('添加笔记成功===>>', res);
dispatch({
type: types.LOADING_STATUS,
payload: false
});
const { data } = res;
if (data.status === 0) {
cb && cb();
notification.success({
message: '提示',
description: '添加笔记成功'
});
dispatch({
type: types.UPDATE_NOTE_CONTENT,
payload: params.notes
})
}
}).catch(() => {
dispatch({
type: types.LOADING_STATUS,
payload: false
});
})
}
}

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-20 16:35:46 * @Date: 2019-11-20 16:35:46
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-23 10:55:28 * @LastEditTime : 2019-12-26 15:45:28
*/ */
import types from './actionTypes'; import types from './actionTypes';
import CONST from '../../constants'; import CONST from '../../constants';
@ -58,7 +58,8 @@ const maps = {
// 非空校验 // 非空校验
const emptyValidate = (key, value) => { const emptyValidate = (key, value) => {
if ([undefined, '', null].includes(value)) { const reg = /^[\s\S]*.*[^\s][\s\S]*$/;
if (!reg.test(value)) {
return { return {
[key]: { [key]: {
validateStatus: 'error', validateStatus: 'error',
@ -472,7 +473,7 @@ export const testCaseInputChange = (value, index) => {
const bool = testCases.some((item, i) => { const bool = testCases.some((item, i) => {
if (i !== index) { if (i !== index) {
if (item['input'] === value) { if (item['input'] === value) {
_errMsg=`与测试用例${index}的输入值重复了,请重新填写`; _errMsg=`与测试用例${i + 1}的输入值重复了,请重新填写`;
} }
return item['input'] === value; return item['input'] === value;
} else { } else {
@ -566,4 +567,4 @@ export const updateOpenTestCaseIndex = (value) => {
type: types.UPDATE_OPEN_TESTCASE_INDEX, type: types.UPDATE_OPEN_TESTCASE_INDEX,
payload: value payload: value
} }
} }

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 13:41:48 * @Date: 2019-11-27 13:41:48
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 17:09:53 * @LastEditTime : 2019-12-26 18:34:56
*/ */
import types from "../actions/actionTypes"; import types from "../actions/actionTypes";
import { Base64 } from 'js-base64'; import { Base64 } from 'js-base64';
@ -111,7 +111,7 @@ const ojForUserReducer = (state = initialState, action) => {
userCodeTab: action.payload userCodeTab: action.payload
} }
case types.GET_COMMIT_RECORD_DETAIL_BY_ID: case types.GET_COMMIT_RECORD_DETAIL_BY_ID:
tempDetail = action.payload; tempDetail = action.payload.data;
if (tempDetail['error_msg']) { if (tempDetail['error_msg']) {
tempDetail['error_msg'] = Base64.decode(tempDetail['error_msg']); tempDetail['error_msg'] = Base64.decode(tempDetail['error_msg']);
} }
@ -218,6 +218,13 @@ const ojForUserReducer = (state = initialState, action) => {
...state, ...state,
hack: Object.assign({}, state.hack, { comments_count: _comments_count }) hack: Object.assign({}, state.hack, { comments_count: _comments_count })
} }
// 修改笔记内容
case types.UPDATE_NOTE_CONTENT:
const _hack1 = Object.assign({}, state.hack, {notes: action.payload });
return {
...state,
hack: _hack1
}
default: default:
return state; return state;
} }

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-20 10:55:38 * @Date: 2019-11-20 10:55:38
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 14:27:30 * @LastEditTime : 2019-12-26 17:37:38
*/ */
import axios from 'axios'; import axios from 'axios';
@ -137,3 +137,9 @@ export async function fetchUploadImageUrl (id) {
const url = `/attachments/${id}`; const url = `/attachments/${id}`;
return axios.get(url); return axios.get(url);
} }
// 添加笔记
export async function fetchAddNotes (identifier, params) {
const url = `/myproblems/${identifier}/add_notes.json`;
return axios.post(url, params);
}
Loading…
Cancel
Save