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

dev_cs
杨树明 6 years ago
commit 678796219f

@ -378,6 +378,7 @@ DEPENDENCIES
kaminari (~> 1.1, >= 1.1.1)
listen (>= 3.0.5, < 3.2)
mysql2 (>= 0.4.4, < 0.6.0)
newrelic_rpm
oauth2
pdfkit
puma (~> 3.11)

@ -0,0 +1,4 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-schools-index-page').length > 0) {
}
});

@ -0,0 +1,3 @@
.admins-schools-index-page {
}

@ -0,0 +1,30 @@
class Admins::SchoolsController < Admins::BaseController
def index
params[:sort_by] ||= 'created_at'
params[:sort_direction] ||= 'desc'
schools = Admins::SchoolQuery.call(params)
@schools = paginate schools
school_ids = @schools.map(&:id)
@department_count = Department.where(school_id: school_ids).group(:school_id).count
end
def destroy
users = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id })
ActiveRecord::Base.transaction do
users.update_all(profile_completed: false)
current_school.destroy!
end
render_delete_success
end
private
def current_school
@_current_school ||= School.find(params[:id])
end
end

@ -14,6 +14,7 @@ class ApplicationController < ActionController::Base
#before_action :check_account
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
OPENKEY = "79e33abd4b6588941ab7622aed1e67e8"
helper_method :current_user
@ -246,6 +247,16 @@ class ApplicationController < ActionController::Base
User.current = find_current_user
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
# 开放课程通过链接访问的用户
if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank?
content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}"
if Digest::MD5.hexdigest(content) == params[:chinaoocKey]
user = User.open_class_user
start_user_session(user) if user
User.current = user
end
end
if !User.current.logged? && Rails.env.development?
User.current = User.find 1
end

@ -18,10 +18,18 @@ module Util::FileManage
File.exist?(disk_filename(source_type, source_id))
end
def exists?(source)
File.exist?(disk_filename(source.class, source.id))
end
def disk_file_url(source_type, source_id)
File.join('/images', relative_path, "#{source_type}", "#{source_id}")
end
def source_disk_file_url(source)
File.join('/images', relative_path, "#{source.class}", "#{source.id}")
end
def disk_auth_filename(source_type, source_id, type)
File.join(storage_path, "#{source_type}", "#{source_id}#{type}")
end

@ -5,7 +5,7 @@ class Department < ApplicationRecord
has_many :member_users, through: :department_members, source: :user
has_many :user_extensions, dependent: :nullify
has_many :apply_add_departments
has_many :apply_add_departments, dependent: :destroy
scope :without_deleted, -> { where(is_delete: false) }

@ -17,6 +17,7 @@ class School < ApplicationRecord
has_many :partners, dependent: :destroy
has_many :apply_add_departments, dependent: :destroy
has_many :user_extensions, dependent: :nullify
# 学校管理员
def manager?(user)

@ -610,6 +610,29 @@ class User < ApplicationRecord
admin? || business?
end
# 149课程的评审用户数据创建包含创建课堂学生
def open_class_user
user = User.find_by(login: "OpenClassUser")
unless user
ActiveRecord::Base.transaction do
user_params = {status: 1, login: "OpenClassUser", lastname: "开放课程",
nickname: "开放课程", professional_certification: 1, certification: 1, grade: 0,
password: "12345678", phone: "11122223333", profile_completed: 1}
user = User.create!(user_params)
UserExtension.create!(user_id: user.id, gender: 0, school_id: 117, :identity => 1, :student_id => "openclassuser")
subject = Subject.find_by(id: 149)
if subject
subject.courses.each do |course|
CourseMember.create!(course_id: course.id, role: 4, user_id: user.id) if !course.course_students.exists?(user_id: user.id)
end
end
end
end
user
end
protected
def validate_password_length
# 管理员的初始密码是5位

@ -0,0 +1,23 @@
class Admins::SchoolQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :users_count, :created_at, default_by: :created_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
schools = School.all
keyword = strip_param(:keyword)
schools = schools.where('schools.name LIKE ?', "%#{keyword}%") if keyword
schools = schools.joins(:user_extensions).group(:id)
schools = schools.select('schools.*, COUNT(*) AS users_count')
custom_sort schools, params[:sort_by], params[:sort_direction]
end
end

@ -0,0 +1,16 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('单位列表') %>
<% end %>
<div class="box search-form-container school-list-form">
<%= form_tag(admins_schools_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '部门名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
<%#= javascript_void_link '新建单位', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-school-modal' } %>
</div>
<div class="box school-list-container">
<%= render partial: 'admins/schools/shared/list', locals: { schools: @schools } %>
</div>

@ -0,0 +1 @@
$('.school-list-container').html("<%= j(render partial: 'admins/schools/shared/list', locals: { schools: @schools }) %>");

@ -0,0 +1,48 @@
<table class="table table-hover text-center school-list-table">
<thead class="thead-light">
<tr>
<th width="6%">ID</th>
<th width="6%">LOGO</th>
<th width="8%">标识码</th>
<th width="14%" class="text-left">单位名称</th>
<th width="6%">地区</th>
<th width="6%">城市</th>
<th width="16%">详细地址</th>
<th width="6%"><%= sort_tag('用户数', name: 'users_count', path: admins_schools_path) %></th>
<th width="6%">部门数</th>
<th width="12%"><%= sort_tag('创建时间', name: 'created_at', path: admins_schools_path) %></th>
<th width="14%">操作</th>
</tr>
</thead>
<tbody>
<% if schools.present? %>
<% schools.each do |school| %>
<tr class="school-item-<%= school.id %>">
<td><%= school.id %></td>
<td>
<% if Util::FileManage.exists?(school) %>
<%= image_tag(Util::FileManage.source_disk_file_url(school).to_s + "?#{Time.now.to_i}", width: 40, height: 40, class: 'preview-image') %>
<% else %>
<%= content_tag(:span, '--', class: 'text-secondary') %>
<% end %>
</td>
<td><%= display_text school.identifier %></td>
<td class="text-left"><%= school.name %></td>
<td><%= school.province %></td>
<td><%= school.city %></td>
<td class="text-left"><%= school.address %></td>
<td><%= school.users_count %></td>
<td><%= @department_count.fetch(school.id, 0) %></td>
<td><%= school.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
<td>
<%= delete_link '删除', admins_school_path(school, element: ".school-item-#{school.id}"), class: 'delete-school-action' %>
</td>
</tr>
<% end %>
<% else %>
<%= render 'admins/shared/no_data_for_table' %>
<% end %>
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: schools } %>

@ -31,6 +31,7 @@
<li>
<%= sidebar_item_group('#schools-submenu', '单位管理', icon: 'building') do %>
<li><%= sidebar_item(admins_schools_path, '单位列表', icon: 'university', controller: 'admins-schools') %></li>
<li><%= sidebar_item(admins_departments_path, '部门列表', icon: 'sitemap', controller: 'admins-departments') %></li>
<% end %>
</li>

@ -926,6 +926,7 @@ Rails.application.routes.draw do
resources :mirror_scripts, only: [:index, :new, :create, :edit, :update, :destroy]
end
resources :choose_mirror_repositories, only: [:new, :create]
resources :schools, only: [:index, :destroy]
resources :departments, only: [:index, :create, :edit, :update, :destroy] do
resource :department_member, only: [:create, :update, :destroy]
post :merge, on: :collection

File diff suppressed because one or more lines are too long

@ -63,7 +63,7 @@ export { default as Clappr } from './components/media/Clappr'
export { default as AliyunUploader } from './components/media/AliyunUploader'
export { default as ImageLayerHook } from './hooks/ImageLayerHook'
export { default as ImageLayer2 } from './hooks/ImageLayer2'
// 外部
export { default as CBreadcrumb } from '../modules/courses/common/CBreadcrumb'

@ -2,7 +2,7 @@ import React, { useState, useEffect, memo } from 'react';
import ImageLayer from '../../modules/page/layers/ImageLayer';
import { isImageExtension } from 'educoder';
const $ = window.$;
function ImageLayerHook(props) {
function ImageLayer2(props) {
const [showImage, setShowImage] = useState(false)
const [imageSrc, setImageSrc] = useState('')
@ -45,4 +45,4 @@ function ImageLayerHook(props) {
)
}
export default memo(ImageLayerHook)
export default memo(ImageLayer2)

@ -119,14 +119,14 @@ export function configShareForCourses () {
}
// detail
export function configShareForCustom (title, desc, path, imgUrl) {
export function configShareForCustom (title, desc, imgUrl, path) {
requestForSignatrue(() => {
console.log('configShareForCustom', host)
const _url = window.location.href.split('#')[0];
var shareData = {
title: title,
desc: desc,
link: `${host}/${path}`,
link: path ? `${host}/${path}` : _url,
imgUrl: imgUrl || window.__testImageUrl
|| host + '/react/build/images/share_logo_icon.jpg'
};

@ -2,7 +2,7 @@ import React,{Component} from "React";
import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal, Table, Divider, Tag,DatePicker,Radio,Tooltip} from "antd";
import {Link} from 'react-router-dom';
import locale from 'antd/lib/date-picker/locale/zh_CN';
import { WordsBtn, MarkdownToHtml, markdownToHTML } from 'educoder';
import { WordsBtn, MarkdownToHtml, markdownToHTML, ImageLayer2 } from 'educoder';
import axios from 'axios';
import Modals from '../../modals/Modals';
import CoursesListType from '../coursesPublic/CoursesListType';
@ -197,6 +197,7 @@ class CommonWorkAppraise extends Component{
border-bottom: none !important;
}
`}</style>
<ImageLayer2 parentSel=".workAppraise" childSel="a.imageTarget"></ImageLayer2>
<div className={"workAppraise"}>
{(description || (attachments && attachments.length != 0)) && <div className={"stud-class-set edu-back-white padding20-30"}>
<div className={"color-grey-6 mb15 font-16"}>

@ -73,7 +73,6 @@ class NewWorkForm extends Component{
setTimeout(() => {
this.contentMdRef.current.setValue(data.description || '')
this.answerMdRef.current.setValue(data.reference_answer || '')
}, 2000)
this.props.form.setFieldsValue({
@ -86,8 +85,13 @@ class NewWorkForm extends Component{
} else { // new
}
this._scrollToTop()
}
_scrollToTop = () => {
setTimeout(() => {
$("html").animate({ scrollTop: 0 })
}, 1500)
}
// 输入title
changeTitle=(e)=>{
@ -289,6 +293,7 @@ class NewWorkForm extends Component{
}
componentDidMount() {
window.$('.groupSetting .ant-form-item-label > label').addClass('ant-form-item-required')
this._scrollToTop()
}
render(){

@ -78,7 +78,7 @@ class NewShixunModel extends Component{
{item.map((list,key)=>{
return(
<Menu.Item key={key} id={list.id}>
<a target="_blank" href={`/paths/${list.id}`} className={"newshixun500"} title={list.name}>{list.name}</a>
<a target="_blank" href={`/paths/${list.id}`} className={"newshixun500"}>{list.name}</a>
</Menu.Item>
)
})}
@ -340,6 +340,12 @@ class NewShixunModel extends Component{
`body{ overflow: hidden !important; }
.ant-drawer-content{ overflow:auto !important; background: #f5f5f5; }
.yslbottomsj{position: absolute;bottom: -8px;}
.ant-drawer-close{
font-size:24px !important;
}
.ant-drawer-body {
padding:15px 24px 24px 0px;
}
`
}
</style>
@ -353,7 +359,7 @@ class NewShixunModel extends Component{
height={'100%'}
>
<Spin spinning={this.state.isspinning}>
<div className={"clearfix educontent pr mb100"}>
<div className={"clearfix educontent pr mb60shixun"}>
<div className={"square-list clearfix"}>
@ -365,11 +371,14 @@ class NewShixunModel extends Component{
.ant-input, .ant-input .ant-input-suffix{
background-color: #fff !important;
}
.packinput .ant-input{
border: 1px solid rgba(217,217,217,1) !important;
}
`
}
</style>
<Search
style={{ width: "800px"}}
style={{ width: "780px"}}
className="packinput"
placeholder="实训信息 / 院校名称 / 创建者"
value={this.state.keyword}
@ -419,7 +428,7 @@ class NewShixunModel extends Component{
{shixun_list===undefined?"":shixun_list.length===0?"":shixun_list.map((item,key)=>{
return(
<div className="mt20 edu-back-white pd20 relativef newshixunlist" key={key}>
<div className="mt10 edu-back-white pd20 relativef newshixunlist" key={key}>
<div className="clearfix">
<div className="item-body">
<div className="clearfix ds pr contentSection">
@ -429,7 +438,7 @@ class NewShixunModel extends Component{
className="fl task-hide edu-txt-left mt3"
name="shixun_homework[]"
></Checkbox>
<a target="_blank" href={`/shixuns/${item.identifier}/challenges`} title={item.title} className="ml15 fl font-16 color-dark maxwidth1100"
<a target="_blank" href={`/shixuns/${item.identifier}/challenges`} className="ml15 fl font-16 color-dark maxwidth1100"
dangerouslySetInnerHTML={{__html: item.title}}
>
</a>
@ -449,7 +458,7 @@ class NewShixunModel extends Component{
`
}
</style>
{JSON.stringify(item.description) == "{}"?"":<div className="newshixunmodelmidfont newradioStyles" title={item.description} dangerouslySetInnerHTML={{__html: item.description}}>
{JSON.stringify(item.description) == "{}"?"":<div className="newshixunmodelmidfont newradioStyles" dangerouslySetInnerHTML={{__html: item.description}}>
</div>}
{item.challenge_names.length===0?"":<div className="newshixunmodelbotfont">
@ -533,7 +542,7 @@ class NewShixunModel extends Component{
{
shixun_list===undefined?"":shixun_list.length===0?"":<div className={" edu-txt-center padding13-30"}>
<Button className={"mr20 newshixunmode"} onClick={()=>this.props.hideNewShixunModelType()}>取消</Button>
<Button className={"newshixunmode mr70"} type="primary" onClick={()=>this.savecouseShixunModal()} loading={this.state.hometypepvisible}>确定</Button>
<Button className={"newshixunmode mr40"} type="primary" onClick={()=>this.savecouseShixunModal()} loading={this.state.hometypepvisible}>确定</Button>
</div>}
</div>
</Spin>

@ -259,8 +259,8 @@
}
.mb100{
margin-bottom: 100px !important;
.mb60shixun{
margin-bottom: 60px !important;
}
.padding13-30 {

@ -408,7 +408,7 @@ class ShixunsHome extends Component {
<img src={getImageUrl("images/educoder/huangguan-two.png")} className="huangguan" />
<a href={"/users/"+item.login} className="color-dark">
<img src={'/images/'+item.image_url} />
<span className="task-hide rankName">{item.username}</span>
<p className="task-hide rankName mt5">{item.username}</p>
</a>
</li>
)
@ -422,7 +422,7 @@ class ShixunsHome extends Component {
<img src={getImageUrl("images/educoder/huangguan.png")} className="huangguan" />
<a href={"/users/"+item.login} className="color-dark">
<img src={'/images/'+item.image_url} />
<span className="task-hide rankName">{item.username}</span>
<p className="task-hide rankName mt5">{item.username}</p>
</a>
</li>
)
@ -436,7 +436,7 @@ class ShixunsHome extends Component {
<img src={getImageUrl("images/educoder/huangguan-three.png")} className="huangguan" />
<a href={"/users/"+item.login} className="color-dark">
<img src={'/images/'+item.image_url} />
<span className="task-hide rankName">{item.username}</span>
<p className="task-hide rankName mt5">{item.username}</p>
</a>
</li>
)
@ -452,7 +452,7 @@ class ShixunsHome extends Component {
<li key={key}>
<a href={"/users/"+item.login} className="color-dark">
<img src={'/images/'+item.image_url}/>
<span className="task-hide rankName">{item.username}</span>
<p className="task-hide rankName mt5">{item.username}</p>
</a>
</li>
)
@ -484,7 +484,7 @@ class ShixunsHome extends Component {
<img src={getImageUrl("images/educoder/huangguan-two.png")} className="huangguan" />
<a href={"/users/"+item.login} className="color-dark">
<img src={'/images/'+item.image_url} />
<span className="task-hide rankName">{item.username}</span>
<p className="task-hide rankName mt5">{item.username}</p>
</a>
</li>
)
@ -498,7 +498,7 @@ class ShixunsHome extends Component {
<img src={getImageUrl("images/educoder/huangguan.png")} className="huangguan" />
<a href={"/users/"+item.login} className="color-dark">
<img src={'/images/'+item.image_url} />
<span className="task-hide rankName">{item.username}</span>
<p className="task-hide rankName mt5">{item.username}</p>
</a>
</li>
)
@ -512,7 +512,7 @@ class ShixunsHome extends Component {
<img src={getImageUrl("images/educoder/huangguan-three.png")} className="huangguan" />
<a href={"/users/"+item.login} className="color-dark">
<img src={'/images/'+item.image_url} />
<span className="task-hide rankName">{item.username}</span>
<p className="task-hide rankName mt5">{item.username}</p>
</a>
</li>
)
@ -528,7 +528,7 @@ class ShixunsHome extends Component {
<li key={key}>
<a href={"/users/"+item.login} className="color-dark">
<img src={'/images/'+item.image_url}/>
<span className="task-hide rankName">{item.username}</span>
<p className="task-hide rankName mt5">{item.username}</p>
</a>
</li>
)

@ -5,7 +5,7 @@ import {
} from "antd";
import axios from 'axios';
import moment from 'moment';
import {getImageUrl,markdownToHTML,ImageLayerHook} from 'educoder';
import {getImageUrl,markdownToHTML,ImageLayer2} from 'educoder';
import "../css/messagemy.css"
import WriteaprivateletterModal from '../messagemodal/WriteaprivateletterModal';
//私信页面
@ -51,8 +51,8 @@ class Leftdialogue extends Component{
</a>
<div className="fl pr OtherSide-info">
<span className="trangle"></span>
<ImageLayerHook parentSel={`#Leftdialogue${this.props.keys}`} parentSel={`#Leftdialogue${this.props.keys}`}>
</ImageLayerHook>
<ImageLayer2 parentSel={`#Leftdialogue${this.props.keys}`} parentSel={`#Leftdialogue${this.props.keys}`}>
</ImageLayer2>
<div className="sms break_word markdown-body" id={`Leftdialogue${this.props.keys}`} dangerouslySetInnerHTML={{__html: markdownToHTML(this.props.objeysl.content).replace(/▁/g, "▁▁▁")}}></div>
<div className="edu-txt-right mt5">
<a className="color-grey-c" onClick={()=>this.mydelete(this.props.objeysl.sender.id,this.props.objeysl.id)} >删除</a>

@ -5,7 +5,7 @@ import {
} from "antd";
import axios from 'axios';
import moment from 'moment';
import {getImageUrl,markdownToHTML,ImageLayerHook} from 'educoder';
import {getImageUrl,markdownToHTML,ImageLayer2} from 'educoder';
import "../css/messagemy.css"
import WriteaprivateletterModal from '../messagemodal/WriteaprivateletterModal';
//私信页面
@ -51,8 +51,8 @@ class Rightdialogue extends Component{
</a>
<div className="fr pr ThisSide-info">
<span className="trangle"></span>
<ImageLayerHook parentSel={`#Rightdialogue${this.props.keys}`} parentSel={`#Rightdialogue${this.props.keys}`}>
</ImageLayerHook>
<ImageLayer2 parentSel={`#Rightdialogue${this.props.keys}`} parentSel={`#Rightdialogue${this.props.keys}`}>
</ImageLayer2>
<div className="sms break_word markdown-body" id={`Rightdialogue${this.props.keys}`} dangerouslySetInnerHTML={{__html: markdownToHTML(this.props.objeysl.content).replace(/▁/g, "▁▁▁")}}></div>
<div className="edu-txt-left mt5">
<a className="color-grey-c" onClick={()=>this.mydelete(this.props.objeysl.sender.id,this.props.objeysl.id)}

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import {getImageUrl,markdownToHTML} from 'educoder';
import {getImageUrl,markdownToHTML, configShareForCustom} from 'educoder';
import DetailTop from './DetailTop.js';
import DetailCards from './DetailCards.js'
import AddCollaborators from "./addCollaborators.js";
@ -164,6 +164,7 @@ class PathDetailIndex extends Component{
// window.location.href = "/403";
return;
}
configShareForCustom(result.data.name, result.data.description)
if(result.data.allow_visit===true){
this.setState({

@ -1,203 +1,212 @@
import React,{ Component } from "react";
import {Pagination} from 'antd';
import axios from 'axios';
const $ = window.$;
const echarts = require('echarts');
function InitChapterUsageSituation(_data){
var Color = ['#49A9EE', '#FFD86E', '#98D87D', '#8996E6','#F3857B', '#B97BF3','#4DE8B4','#f76d0c','#510cf7','#def70c','#3bf70c','#0cf7e1'];
var option = {
title: {
show:false
},
tooltip : {
trigger: 'item',
formatter: "{d}%"
},
legend: {
//orient: 'vertical',
// top: 'middle',
bottom: 30,
//left: 20,
data:["第1章", "第2章", "第3章", "第4章", "第5章"],
selectedMode:false
},
series : [{
name: '使用情况',
type: 'pie',
radius : '50%',
center: ['50%', '40%'],
selectedMode: 'single',
label: {
normal: {
// {abg|}
// {a|{a}}\n
formatter: ' {b|{b}} ',
backgroundColor: '#eee',
borderColor: '#aaa',
borderWidth: 1,
borderRadius: 4,
rich: {
a: {
color: '#999',
lineHeight: 22,
align: 'center'
},
hr: {
borderColor: '#aaa',
width: '100%',
borderWidth: 0.5,
height: 0
},
b: {
fontSize: 16,
lineHeight: 33
},
per: {
color: '#eee',
backgroundColor: '#334455',
padding: [2, 4],
borderRadius: 2
}
}
},
},
data: _data,
// [{"value":19,"name":"\u7b2c1\u7ae0"},{"value":45,"name":"\u7b2c2\u7ae0"},{"value":16,"name":"\u7b2c3\u7ae0"},{"value":10,"name":"\u7b2c4\u7ae0"},{"value":10,"name":"\u7b2c5\u7ae0"}],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
},
normal:{
show: true,
color: function(params) {
return Color[params.dataIndex]
}
}
}
}]
};
var myChart = echarts.init(document.getElementById('chapterUsageSituation'));
myChart.setOption(option);
}
class FirstTab extends Component{
constructor(props){
super(props);
this.state = {
page:1,
total:undefined
}
}
onChange=(pageNumber)=>{
this.setState({
page:pageNumber
})
this.getData(pageNumber);
}
getData=(page)=>{
var pathId = this.props.match.params.pathId;
const url = `/paths/${pathId}/statistics.json?page=`+page;
axios.get(url, {
})
.then((response) => {
// TODO 没用404返回的error
if (response.data.status == 404) {
this.props.showSnackbar('未找到对应数据,请查看地址是否正确。')
return
}
this.setState({ ...response.data })
const _data = response.data.stage_info.map( (item, index) => {
return {
value: item.value,
name: item.stage_no
}
})
InitChapterUsageSituation(_data);
const { course_count, learn_count, school_total_count, subject_name, subject_id } = response.data
this.props.initBannerData({
course_count,
learn_count,
school_total_count,
subject_name,
subject_id
})
this.setState({
total:response.data.school_total_count
})
})
.catch(function (error) {
console.log(error);
});
}
componentDidMount(){
let {page}=this.state;
this.getData(page);
}
render(){
const { schools, stage_info,page,total } = this.state;
return(
<div className="clearfix panelForm-1">
<div className="with60 pr40 fl">
<div className="static_shadow edu-back-white">
<p className="padding30-20 clearfix"><span className="font-24 fl">课堂使用概况</span><span className="fr color-grey-9">{total}</span></p>
<div className="minH-440">
<table className="edu-pop-table head-color edu-txt-center bor-top-greyE" cellSpacing="0" cellPadding="0">
<thead>
<tr><th>序号</th>
<th className="edu-txt-left" width="35%">所属院校</th>
<th>课堂</th>
<th>学生</th>
<th>选用实训</th>
</tr></thead>
{/*
course_count: 30
homework_count: 117
name: "国防科技大学"
student_count: 2700
*/}
<tbody>
{
schools && schools.map( (school, index) => {
return (
<tr>
<td>{ index + 1 }</td>
<td className="edu-txt-left task-hide" style={{"maxWidth":"238px"}}>{school.name}</td>
<td>{school.course_count}</td>
<td>{school.student_count}</td>
<td><span className="color-blue mr3">{school.homework_count}</span></td>
</tr>)
})
}
</tbody>
</table>
</div>
<div className="pt35 edu-txt-center" style={{"height":"102px"}}>
{
total > 10 &&
<Pagination showQuickJumper defaultCurrent={page} pageSize={10} total={total} onChange={this.onChange} />
}
</div>
</div>
</div>
<div className="with40 fl static_shadow edu-back-white">
<p className="font-24 padding30-20">章节使用情况</p>
<div id="chapterUsageSituation" style={{"width":"480px","height":"542px"}}></div>
</div>
</div>
)
}
}
import React,{ Component } from "react";
import {Pagination} from 'antd';
import axios from 'axios';
const $ = window.$;
const echarts = require('echarts');
function InitChapterUsageSituation(_data){
var myChart = echarts.init(document.getElementById('chapterUsageSituation'));
myChart.showLoading({
text: "数据获取中",
effect: 'whirling'
})
var Color = ['#49A9EE', '#FFD86E', '#98D87D', '#8996E6','#F3857B', '#B97BF3','#4DE8B4','#f76d0c','#510cf7','#def70c','#3bf70c','#0cf7e1'];
var option = {
title: {
show:false
},
tooltip : {
trigger: 'item',
formatter: "{d}%"
},
legend: {
//orient: 'vertical',
// top: 'middle',
bottom: 30,
//left: 20,
data:["第1章", "第2章", "第3章", "第4章", "第5章"],
selectedMode:false
},
series : [{
name: '使用情况',
type: 'pie',
radius : '50%',
center: ['50%', '40%'],
selectedMode: 'single',
label: {
normal: {
// {abg|}
// {a|{a}}\n
formatter: ' {b|{b}} ',
backgroundColor: '#eee',
borderColor: '#aaa',
borderWidth: 1,
borderRadius: 4,
rich: {
a: {
color: '#999',
lineHeight: 22,
align: 'center'
},
hr: {
borderColor: '#aaa',
width: '100%',
borderWidth: 0.5,
height: 0
},
b: {
fontSize: 16,
lineHeight: 33
},
per: {
color: '#eee',
backgroundColor: '#334455',
padding: [2, 4],
borderRadius: 2
}
}
},
},
data: _data,
// [{"value":19,"name":"\u7b2c1\u7ae0"},{"value":45,"name":"\u7b2c2\u7ae0"},{"value":16,"name":"\u7b2c3\u7ae0"},{"value":10,"name":"\u7b2c4\u7ae0"},{"value":10,"name":"\u7b2c5\u7ae0"}],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
},
normal:{
show: true,
color: function(params) {
return Color[params.dataIndex]
}
}
}
}]
};
setTimeout(() => {
myChart.setOption(option);
myChart.hideLoading();
}, 1000)
}
class FirstTab extends Component{
constructor(props){
super(props);
this.state = {
page:1,
total:undefined
}
}
onChange=(pageNumber)=>{
this.setState({
page:pageNumber
})
this.getData(pageNumber);
}
getData=(page)=>{
var pathId = this.props.match.params.pathId;
const url = `/paths/${pathId}/statistics.json?page=`+page;
axios.get(url, {
})
.then((response) => {
// TODO 没用404返回的error
if (response.data.status == 404) {
this.props.showSnackbar('未找到对应数据,请查看地址是否正确。')
return
}
this.setState({ ...response.data })
const _data = response.data.stage_info.map( (item, index) => {
return {
value: item.value,
name: item.stage_no
}
})
InitChapterUsageSituation(_data);
const { course_count, learn_count, school_total_count, subject_name, subject_id } = response.data
this.props.initBannerData({
course_count,
learn_count,
school_total_count,
subject_name,
subject_id
})
this.setState({
total:response.data.school_total_count
})
})
.catch(function (error) {
console.log(error);
});
}
componentDidMount(){
let {page}=this.state;
this.getData(page);
}
render(){
const { schools, stage_info,page,total } = this.state;
return(
<div className="clearfix panelForm-1">
<div className="with60 pr40 fl">
<div className="static_shadow edu-back-white">
<p className="padding30-20 clearfix"><span className="font-24 fl">课堂使用概况</span><span className="fr color-grey-9">{total}</span></p>
<div className="minH-440">
<table className="edu-pop-table head-color edu-txt-center bor-top-greyE" cellSpacing="0" cellPadding="0">
<thead>
<tr><th>序号</th>
<th className="edu-txt-left" width="35%">所属院校</th>
<th>课堂</th>
<th>学生</th>
<th>选用实训</th>
</tr></thead>
{/*
course_count: 30
homework_count: 117
name: "国防科技大学"
student_count: 2700
*/}
<tbody>
{
schools && schools.map( (school, index) => {
return (
<tr>
<td>{ index + 1 }</td>
<td className="edu-txt-left task-hide" style={{"maxWidth":"238px"}}>{school.name}</td>
<td>{school.course_count}</td>
<td>{school.student_count}</td>
<td><span className="color-blue mr3">{school.homework_count}</span></td>
</tr>)
})
}
</tbody>
</table>
</div>
<div className="pt35 edu-txt-center" style={{"height":"102px"}}>
{
total > 10 &&
<Pagination showQuickJumper defaultCurrent={page} pageSize={10} total={total} onChange={this.onChange} />
}
</div>
</div>
</div>
<div className="with40 fl static_shadow edu-back-white">
<p className="font-24 padding30-20">章节使用情况</p>
<div id="chapterUsageSituation" style={{"width":"480px","height":"542px"}}></div>
</div>
</div>
)
}
}
export default FirstTab;

@ -1,271 +1,281 @@
import React,{ Component } from "react";
import axios from 'axios';
const $ = window.$;
const echarts = require('echarts');
function InitShixunStudyStatistics(yAxisMonth_a, barData_a, mapByNumber, myChart){
let yAxisMonth = yAxisMonth_a
// [
// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1",
// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1",
// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", "3-2"];
let barData = barData_a
// [
// 1164, 739, 784, 720, 726, 556, 381, 432,
// 1164, 739, 784, 720, 726, 556, 381, 432,
// 1164, 739, 784, 720, 726, 556, 381, 432, 239];
// let yAxisMonth = yAxisMonth_a;
// let barData = barData_a;
let barDataTwo = [];
let coordData2 = [];
let coordData = [];
for (let i = 0; i < barData.length; i++) {
barDataTwo.push(Math.max.apply(Math, barData) + 5000);
coordData.push({
"coord": [Number(barData[i]) - 1, i]
});
coordData2.push({
"coord": [Math.max.apply(Math, barData) + 5000, i]
})
}
var option = {
backgroundColor: "#fff",
title: {
text: ''
},
legend: null,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'none'
},
formatter: function(params) {
return params[0].name + ":" + (mapByNumber[params[0].name] && mapByNumber[params[0].name].shixun_name) + "<br/>" + '学习人数: ' + params[0].value;
}
},
grid: {
containLabel: true,
left: "30px",
top: "0",
bottom:"10px"
},
yAxis: [{
data: yAxisMonth,
inverse: true,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
margin: 10,
textStyle: {
fontSize: 12,
color: '#747A7F'
},
formatter: function(value) {
return '{Sunny|' + value + '}';
},
rich: {
value: {
lineHeight: 20
},
Sunny: {
height: 25,
padding: [0, 8, 0, 8],
align: 'center',
backgroundColor: '#fff'
}
}
}
},{
data: yAxisMonth,
inverse: true,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: false
}
}
],
xAxis: [{
type: "value",
splitLine: {
show: false
},
axisLabel: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: false
}
}, {
type: "value",
splitLine: {
show: false
},
axisLabel: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: false
}
}],
series: [{
z: 10,
xAxisIndex: 0,
yAxisIndex: 0,
name: '',
type: 'pictorialBar',
data: barData,
barCategoryGap: '90%',
label: {
normal: {
show: true,
position: 'inside',
textStyle: {
fontSize: 12,
color: '#666'
}
}
},
symbolRepeat: false,
symbolSize: ['100%', 25],
symbolOffset: [-16.5, 0],
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#FFD86E'
}], false),
borderRadius:'10'
}
},
symbolClip: true,
symbolPosition: 'end',
symbol: 'rect'
}]
};
myChart.setOption(option);
}
class SecondTab extends Component{
constructor(props){
super(props);
this.state = {
}
}
componentDidMount(){
var pathId = this.props.match.params.pathId;
var myChart = echarts.init(document.getElementById('shixunStudyStatistics'));
myChart.showLoading({
text: "数据获取中",
effect: 'whirling'
})
const url = `/paths/${pathId}/shixun_report.json`
axios.get(url, {
})
.then((response) => {
// TODO 没用404返回的error
if (response.data.status == 404) {
this.props.showSnackbar('未找到对应数据,请查看地址是否正确。')
return
}
/**
let yAxisMonth = ["1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", "3-2"];
let barData = [1164, 739, 784, 720, 726, 556, 381, 432, 239];
{
"number": "6-1",
"shixun_name": "网页抓取及信息提取",
"member_count": 0,
"school_count": 0
}
*/
let yAxisMonth = []
let barData = []
let shixunList = []
let mapByNumber = {}
const _data = response.data.shixun_lists.forEach( (ar, index) => {
ar.forEach( (item, itemIndex) => {
shixunList.push(item)
yAxisMonth.push(item.number)
barData.push(item.member_count)
mapByNumber[item.number] = item
})
})
this.setState({ shixunList }, () => {
InitShixunStudyStatistics(yAxisMonth, barData, mapByNumber, myChart);
myChart.hideLoading()
})
})
.catch(function (error) {
console.log(error);
});
}
render(){
const { shixunList } = this.state;
return(
<div className="clearfix panelForm-2">
<div className="with60 pr40 fl">
<div className="static_shadow edu-back-white">
<p className="font-24 padding30-20">实训使用详情</p>
<div className="minH-440" id="tableHeight">
<table className="edu-pop-table head-color edu-txt-center bor-top-greyE" cellSpacing="0" cellPadding="0">
<thead>
<tr>
<th>章节</th>
<th className="edu-txt-left" width="40%">实训名称</th>
<th>学习人数</th>
<th>受用院校</th>
</tr>
</thead>
<tbody>
{
shixunList && shixunList.map( (shixun, index) => {
return (
<tr>
<td>{shixun.number}</td>
<td className="edu-txt-left task-hide" style={{"maxWidth":"272px"}}>{shixun.shixun_name}</td>
<td>{shixun.member_count}</td>
<td className="color-blue">{shixun.school_count}</td>
</tr>)
})
}
</tbody>
</table>
</div>
</div>
</div>
<div className="with40 fl static_shadow edu-back-white">
<p className="font-24 padding30-20">实训学习统计</p>
<div id="shixunStudyStatistics"
style={{"width":"480px","height": shixunList ? `${shixunList.length * 35 + 100}px` : "440px"}}></div>
</div>
</div>
)
}
}
import React,{ Component } from "react";
import axios from 'axios';
const $ = window.$;
const echarts = require('echarts');
function InitShixunStudyStatistics(yAxisMonth_a, barData_a, mapByNumber, myChart){
let yAxisMonth = yAxisMonth_a
// [
// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1",
// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1",
// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", "3-2"];
let barData = barData_a
// [
// 1164, 739, 784, 720, 726, 556, 381, 432,
// 1164, 739, 784, 720, 726, 556, 381, 432,
// 1164, 739, 784, 720, 726, 556, 381, 432, 239];
// let yAxisMonth = yAxisMonth_a;
// let barData = barData_a;
let barDataTwo = [];
let coordData2 = [];
let coordData = [];
for (let i = 0; i < barData.length; i++) {
barDataTwo.push(Math.max.apply(Math, barData) + 5000);
coordData.push({
"coord": [Number(barData[i]) - 1, i]
});
coordData2.push({
"coord": [Math.max.apply(Math, barData) + 5000, i]
})
}
var option = {
backgroundColor: "#fff",
title: {
text: ''
},
legend: null,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'none'
},
formatter: function(params) {
return params[0].name + ":" + (mapByNumber[params[0].name] && mapByNumber[params[0].name].shixun_name) + "<br/>" + '学习人数: ' + params[0].value;
}
},
grid: {
containLabel: true,
left: "30px",
top: "0",
bottom:"10px"
},
yAxis: [{
data: yAxisMonth,
inverse: true,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
margin: 10,
textStyle: {
fontSize: 12,
color: '#747A7F'
},
formatter: function(value) {
return '{Sunny|' + value + '}';
},
rich: {
value: {
lineHeight: 20
},
Sunny: {
height: 25,
padding: [0, 8, 0, 8],
align: 'center',
backgroundColor: '#fff'
}
}
}
},{
data: yAxisMonth,
inverse: true,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: false
}
}
],
xAxis: [{
type: "value",
splitLine: {
show: false
},
axisLabel: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: false
}
}, {
type: "value",
splitLine: {
show: false
},
axisLabel: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: false
}
}],
series: [{
z: 10,
xAxisIndex: 0,
yAxisIndex: 0,
name: '',
type: 'pictorialBar',
data: barData,
barCategoryGap: '90%',
label: {
normal: {
show: true,
position: 'inside',
textStyle: {
fontSize: 12,
color: '#666'
}
}
},
symbolRepeat: false,
symbolSize: ['100%', 25],
symbolOffset: [-16.5, 0],
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#FFD86E'
}], false),
borderRadius:'10'
}
},
symbolClip: true,
symbolPosition: 'end',
symbol: 'rect'
}]
};
myChart.setOption(option);
}
class SecondTab extends Component{
constructor(props){
super(props);
this.state = {
}
}
componentDidMount(){
var pathId = this.props.match.params.pathId;
var myCharts = echarts.init(document.getElementById('showloding'));
myCharts.showLoading({
text: "数据获取中",
effect: 'whirling'
})
const url = `/paths/${pathId}/shixun_report.json`
axios.get(url, {
})
.then((response) => {
// TODO 没用404返回的error
if (response.data.status == 404) {
this.props.showSnackbar('未找到对应数据,请查看地址是否正确。')
return
}
/**
let yAxisMonth = ["1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", "3-2"];
let barData = [1164, 739, 784, 720, 726, 556, 381, 432, 239];
{
"number": "6-1",
"shixun_name": "网页抓取及信息提取",
"member_count": 0,
"school_count": 0
}
*/
let yAxisMonth = []
let barData = []
let shixunList = []
let mapByNumber = {}
const _data = response.data.shixun_lists.forEach( (ar, index) => {
ar.forEach( (item, itemIndex) => {
shixunList.push(item)
yAxisMonth.push(item.number)
barData.push(item.member_count)
mapByNumber[item.number] = item
})
})
this.setState({
shixunList
})
var myChart = echarts.init(document.getElementById('shixunStudyStatistics'));
myChart.showLoading({
text: "数据获取中",
effect: 'whirling'
})
setTimeout(() => {
InitShixunStudyStatistics(yAxisMonth, barData, mapByNumber, myChart);
myCharts.hideLoading();
myChart.hideLoading();
}, 1000)
})
.catch(function (error) {
console.log(error);
});
}
render(){
const { shixunList } = this.state;
return(
<div className="clearfix panelForm-2">
<div className="with60 pr40 fl">
<div className="static_shadow edu-back-white">
<p className="font-24 padding30-20">实训使用详情</p>
<div className="minH-440" id="tableHeight">
<table className="edu-pop-table head-color edu-txt-center bor-top-greyE" cellSpacing="0" cellPadding="0">
<thead>
<tr>
<th>章节</th>
<th className="edu-txt-left" width="40%">实训名称</th>
<th>学习人数</th>
<th>受用院校</th>
</tr>
</thead>
<tbody>
{
shixunList && shixunList.map( (shixun, index) => {
return (
<tr>
<td>{shixun.number}</td>
<td className="edu-txt-left task-hide" style={{"maxWidth":"272px"}}>{shixun.shixun_name}</td>
<td>{shixun.member_count}</td>
<td className="color-blue">{shixun.school_count}</td>
</tr>)
})
}
</tbody>
</table>
</div>
</div>
</div>
<div className="with40 fl static_shadow edu-back-white">
<p className="font-24 padding30-20">实训学习统计</p>
{shixunList===undefined?<div id="showloding"
style={{"width":"480px","height":"440px"}}></div>:""}
{shixunList===undefined?"":<div id="shixunStudyStatistics"
style={{"width":"480px","minHeight":`${shixunList&&shixunList.length *50}px`}}></div>}
</div>
</div>
)
}
}
export default SecondTab;

@ -8,7 +8,7 @@ import PropTypes from 'prop-types';
import classNames from 'classnames';
import { getImageUrl ,markdownToHTML} from 'educoder'
import { getImageUrl ,markdownToHTML, configShareForCustom} from 'educoder'
import { CircularProgress } from 'material-ui/Progress';
@ -51,6 +51,7 @@ class Challenges extends Component {
if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
}else{
configShareForCustom(this.props.shixunsDetails.name, response.data.description)
this.setState({
ChallengesDataList: response.data,
sumidtype: false,

@ -2,7 +2,7 @@ import React, { Component } from "react";
import { message, Icon, Input, Form, Upload} from "antd";
import axios from 'axios'
import ModalWrapper from "../../courses/common/ModalWrapper"
import { City, getUploadActionUrl, getImageUrl, ImageLayerHook, getUploadActionUrlOfAuth } from 'educoder'
import { City, getUploadActionUrl, getImageUrl, ImageLayer2, getUploadActionUrlOfAuth } from 'educoder'
import '../account/common.css'
import authImg from '../../../images/account/auth.png'
@ -308,8 +308,8 @@ class RealNameCertificationModal extends Component{
<div className="df mt10 color-grey-9" style={{ justifyContent: 'center' }} >
<span className="fl mr20 edu-txt-center" style={{width:"160px"}}>示例图片</span>
<span className="fl edu-txt-center mr20" style={{width:"160px"}}>
<ImageLayerHook parentSel={'#imageLayerBtn'} parentSel={'#imageLayerBtn'}
></ImageLayerHook>
<ImageLayer2 parentSel={'#imageLayerBtn'} parentSel={'#imageLayerBtn'}
></ImageLayer2>
<a href="javascript:void(0)" id="imageLayerBtn" src={imageUrl || imageUrl2} className="color-orange" style={{borderBottom:"1px solid #ff6800"}}>查看大图</a>
</span>
</div>

@ -370,17 +370,17 @@ class InfosTopics extends Component{
{
`
::-webkit-scrollbar-thumb {
background-color: #cde5fe;
box-shadow: 0px 0px black;
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
background-color: #fff;
}
// ::-webkit-scrollbar-thumb {
// background-color: #cde5fe;
//
// box-shadow: 0px 0px black;
// }
//
//
// ::-webkit-scrollbar-track {
// -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
// background-color: #fff;
// }
.shaiContent li.shaiItem {
padding: 0px 9px;

@ -429,4 +429,8 @@
.topsicinline{
display: inline-block;
}
/* 防抖 */
.educontent .square-list {
min-height: 400px;
}

@ -1,3 +1,7 @@
/* 撑开滚动条,防抖 */
.educontent > .itemWrap {
min-height: 400px;
}
.itemWrap {
display: flex;
flex-wrap: wrap;

Loading…
Cancel
Save