Merge branch 'dev_aliyun' into dev_hjm

dev_hjm^2
hjm 6 years ago
commit 7b556ee4bf

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

@ -1,3 +0,0 @@
// Place all the styles related to the forums controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

@ -241,14 +241,17 @@ class ApplicationController < ActionController::Base
User.current = User.find 57703
end
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
User.current = User.find 81403
elsif params[:debug] == 'student'
User.current = User.find 8686
elsif params[:debug] == 'admin'
User.current = User.find 1
end
# 测试版前端需求
if request.host == "47.96.87.25"
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
User.current = User.find 81403
elsif params[:debug] == 'student'
User.current = User.find 8686
elsif params[:debug] == 'admin'
User.current = User.find 1
end
end
# User.current = User.find 81403
end

@ -1,7 +1,7 @@
class DiscussesController < ApplicationController
LIMIT = 10
before_action :find_container, only: [:index, :hidden]
before_action :find_discuss, except: [:create, :index, :new_message, :reward_code]
before_action :find_discuss, except: [:create, :index, :new_message, :reward_code, :forum_discusses]
def index
page = params[:page].to_i
@ -28,6 +28,48 @@ class DiscussesController < ApplicationController
@current_user = current_user
end
def forum_discusses
page = params[:page] || 1
limit = params[:limit] || 15
offset = (page.to_i-1) * limit
search = params[:search]
tag = params[:tag_repertoire_id]
sql, sql1, sql2 = '', '', ''
sql1 =
unless search.blank?
"and d.content like '%#{search}%'"
end
sql2 =
if tag
shixun_ids = ShixunTagRepertoire.where(:tag_repertoire_id => tag).pluck(:shixun_id)
"and d.dis_id in(#{shixun_ids.join(",")})"
end
sql = "select d.id from discusses d join shixuns s on d.dis_id = s.id where s.status = 2 and s.hidden = false and d.root_id is null
and d.hidden = false #{sql1} #{sql2} order by d.created_at desc"
memo_ids = Discuss.find_by_sql(sql).pluck(:id)
@memo_count = memo_ids.size
memo_ids = memo_ids[offset, limit]
order_ids = memo_ids.size > 0 ? memo_ids.join(',') : -1
@memos = Discuss.where(id: memo_ids).order("field(id,#{order_ids})").includes(:praise_treads, dis: :tag_repertoires, user: :user_extension)
# @memos = memos.includes(:praise_treads, user: :user_extension).page(page).per(limit)
# 实训标签使用最多的9个
# @hot_tags = TagRepertoire.find_by_sql("select distinct(a.name), a.id from
# (select tr.id, tr.name, count(d.dis_id) cnt
# from tag_repertoires tr join (shixun_tag_repertoires str
# left join (shixuns s join discusses d on d.dis_id = s.id)
# on s.id = str.shixun_id) on tr.id = str.tag_repertoire_id
# group by d.dis_id order by cnt desc) a limit 9").map{|ht| ht.attributes.dup}
tag_id = ShixunTagRepertoire.joins(:shixun).order("myshixuns_count desc").pluck(:tag_repertoire_id).uniq.first(9)
@hot_tags = TagRepertoire.select([:id, :name]).where(id: tag_id).order("FIELD(id, #{tag_id.join(",")})").map{|ht| ht.attributes.dup} if tag_id
@memos = DiscussesService.new.memo_list @memos
@hot_memos = Memo.field_for_recommend.posts.hot.includes(:tag_repertoires).limit(4)
@recommend_shixuns = DiscussesService.new.recommends
end
def new_message
onclick_time = Myshixun.find(params[:myshixun_id]).try(:onclick_time)
ids = Discuss.where(user_id: User.current.id, dis_id: params[:container_id], dis_type: params[:container_type]).

@ -1,2 +0,0 @@
class ForumsController < ApplicationController
end

@ -336,7 +336,7 @@ class HomeworkCommonsController < ApplicationController
@messages = @messages.parent_comment
end
@messages = @messages.page(@page).per(@limit).order("created_on desc")
@messages = @messages.includes(:praise_treads).page(@page).per(@limit).order("created_on desc")
end
def reference_answer

@ -1,5 +1,9 @@
class MemosController < ApplicationController
before_action :set_memo, only: [:show, :edit, :update, :destroy]
before_action :require_login, except: [:show, :index]
before_action :set_memo, only: [:show, :edit, :update, :destroy, :sticky_or_cancel, :hidden, :more_reply]
before_action :validate_memo_params, only: [:create, :update]
before_action :owner_or_admin, only: [:edit, :update, :destroy]
before_action :is_admin, only: [:sticky_or_cancel, :hidden]
include ApplicationHelper
# GET /memos
@ -8,27 +12,21 @@ class MemosController < ApplicationController
@user = current_user
@memos = Memo.all
s_order = (params[:order] == "replies_count" ? "all_replies_count" : params[:order]) || "updated_at"
#@tidding_count = unviewed_tiddings(current_user) if current_user.present?
page = params[:page].to_i
# @tidding_count = unviewed_tiddings(current_user) if current_user.present?
page = params[:page] || 1
limit = params[:limit] || 15
search = params[:search]
offset = page * 15
forum_id = params[:forum]
user_id = params[:user_id]
if user_id == -1
user_id = current_user.try(:id)
end
tag_repertoire_id = params[:tag_repertoire_id]
sql =
if forum_id
search ? "forum_id = #{forum_id} and root_id is null and subject like '%#{search}%'" :
!search.blank? ? "forum_id = #{forum_id} and root_id is null and subject like '%#{search}%'" :
"forum_id = #{forum_id} and root_id is null"
elsif search
user_id ? "author_id = #{user_id.to_i} and forum_id in(3, 5) and root_id is null and subject like '%#{search}%'" :
"forum_id in(3, 5) and root_id is null and subject like '%#{search}%'"
elsif !search.blank?
"forum_id in(3, 5) and root_id is null and subject like '%#{search}%'"
else
user_id ? "author_id = #{user_id.to_i} and forum_id in(3, 5) and root_id is null" :
"forum_id in(3, 5) and root_id is null"
"forum_id in(3, 5) and root_id is null"
end
if tag_repertoire_id
@ -41,27 +39,27 @@ class MemosController < ApplicationController
sql += " and all_replies_count != 0"
end
memos = Memo.field_for_list.includes(:praise_tread, :author).where("#{sql}")
memos = Memo.field_for_list.where("#{sql}")
@memos_count = memos.length
@memos = memos.order("sticky = 1 desc, #{Memo.table_name}.#{s_order} desc").offset(offset).limit(15)
@my_memos_count = Memo.user_posts(current_user.try(:id)).count
@memos = memos.order("sticky = 1 desc, #{Memo.table_name}.#{s_order} desc").page(page).per(limit)
@memos = @memos.includes(:praise_treads, :tag_repertoires, author: :user_extension)
# @my_memos_count = Memo.user_posts(current_user.try(:id)).count
@tags_info = MemoTagRepertoire.find_by_sql("SELECT tag_repertoire_id, tr.name, count(*) cnt
FROM memo_tag_repertoires mtr join tag_repertoires tr on
tr.id = mtr.tag_repertoire_id group by tag_repertoire_id order by cnt desc,
tag_repertoire_id desc limit 9")
@hot_memos = Memo.field_for_recommend.posts.hot.limit(4)
@hot_memos = Memo.field_for_recommend.posts.hot.includes(:tag_repertoires).limit(4)
@recommend_shixuns = DiscussesService.new.recommends
end
# GET /memos/1
# GET /memos/1.json
def show
# tidding_count = unviewed_tiddings(current_user) if current_user
@user = current_user
# TODO 附件最后再做
# attachments_list =
@memo.update_column(:viewed_count, @memo.viewed_count+1)
@memos = @memo.reply_for_memo.includes(:praise_tread, :author).order("created_at desc").limit(10)
@memos = @memo.reply_for_memo.includes(:praise_treads, author: :user_extension).order("created_at desc").limit(10)
@attachments = @memo.attachments
@recommend_shixuns = DiscussesService.new.recommends
end
# GET /memos/new
@ -71,43 +69,44 @@ class MemosController < ApplicationController
# GET /memos/1/edit
def edit
@tag_list = TagRepertoire.field_for_list.order("name asc")
@memo_tags = @memo.tag_repertoires.field_for_list
@attachments = @memo.attachments
end
# POST /memos
# POST /memos.json
def create
ActiveRecord::Base.transaction do
begin
@memo = Memo.new(memo_params)
@memo.author = current_user
# TODO 保存附件
# @memo.save_attachments(params[:attachments]) if params[:attachments]
@memo.save!
Attachment.associate_container(params[:attachment_ids], @memo.id, @memo.class.name)
params[:tags].each do |tag|
MemoTagRepertoire.create(:memo_id => @memo.id, :tag_repertoire_id => tag)
MemoTagRepertoire.create!(memo_id: @memo.id, tag_repertoire_id: tag)
end
@status = 0
@message = "帖子创建成功!"
normal_status("帖子创建成功")
rescue Exception => e
@status = -1
@message = "帖子创建失败,原因:#{e}"
tip_exception("帖子创建失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
end
# PATCH/PUT /memos/1
# PATCH/PUT /memos/1.json
def update
respond_to do |format|
if @memo.update(memo_params)
format.html { redirect_to @memo, notice: 'Memo was successfully updated.' }
format.json { render :show, status: :ok, location: @memo }
else
format.html { render :edit }
format.json { render json: @memo.errors, status: :unprocessable_entity }
ActiveRecord::Base.transaction do
begin
@memo.update_attributes!(memo_params)
Attachment.associate_container(params[:attachment_ids], @memo.id, @memo.class.name)
@memo.memo_tag_repertoires.destroy_all
params[:tags].each do |tag|
MemoTagRepertoire.create!(memo_id: @memo.id, tag_repertoire_id: tag)
end
normal_status("帖子更新成功")
rescue Exception => e
tip_exception("帖子更新失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
end
@ -116,21 +115,88 @@ class MemosController < ApplicationController
# DELETE /memos/1.json
def destroy
@memo.destroy
respond_to do |format|
format.html { redirect_to memos_url, notice: 'Memo was successfully destroyed.' }
format.json { head :no_content }
normal_status("删除成功")
end
def sticky_or_cancel
tip_exception("只能对主贴进行置顶操作") unless @memo.parent_id.nil?
begin
@memo.update_attributes!(sticky: !@memo.sticky)
normal_status("更新成功")
rescue Exception => e
tip_exception("更新失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_memo
@memo = Memo.find(params[:id])
def hidden
tip_exception("不能对主贴进行隐藏操作") if @memo.parent_id.nil?
begin
@memo.update_attributes!(hidden: !@memo.hidden)
normal_status("更新成功")
rescue Exception => e
tip_exception("更新失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
def reply
tip_exception("parent_id不能为空") if params[:parent_id].blank?
tip_exception("content不能为空") if params[:content].blank?
# Never trust parameters from the scary internet, only allow the white list through.
def memo_params
params.fetch(:memo, {})
ActiveRecord::Base.transaction do
begin
memo = Memo.find_by!(id: params[:parent_id])
reply = Memo.new
reply.content = params[:content]
reply.author = current_user
reply.forum_id = memo.forum_id
reply.subject = memo.subject
reply.root_id = memo.root_id || memo.id
memo.children << reply
m = Memo.find_by!(id: reply.root_id)
m.increment!(:all_replies_count)
normal_status("回复成功")
rescue Exception => e
tip_exception("回复失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
end
def more_reply
@user = current_user
page = params[:page] || 2
limit = params[:limit] || 10
offset = (page.to_i - 1) * limit
@memos_count = Memo.where(parent_id: @memo.id).count
@memos = Memo.limit(limit).where(parent_id: @memo.id).includes(:author, :praise_treads).order("created_at desc").offset(offset)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_memo
@memo = Memo.find(params[:id])
end
def owner_or_admin
tip_exception(403, "无权限操作") unless @memo.author == current_user || current_user.admin? || current_user.business?
end
def is_admin
tip_exception(403, "无权限操作") unless current_user.admin? || current_user.business?
end
# Never trust parameters from the scary internet, only allow the white list through.
def memo_params
params.require(:memo).permit(:subject, :content, :forum_id)
end
def validate_memo_params
tip_exception("话题名称不能为空") if params[:subject].blank?
tip_exception("话题内容不能为空") if params[:content].blank?
tip_exception("话题类型不能为空") if params[:forum_id].blank?
tip_exception("技术标签不能为空") if params[:tags].blank?
end
end

@ -408,18 +408,16 @@ class ShixunsController < ApplicationController
@shixun.update_attributes(shixun_params)
@shixun.shixun_info.update_attributes(shixun_info_params)
@shixun.shixun_schools.delete_all
if params[:scope_partment].present? && params[:user_scope].to_i == 1
logger.info("##########scope_partment:###{params[:scope_partment]}")
# scope_partment: 高校的名称
if params[:scope_partment].present?
arr = []
ids = School.where(:name => params[:scope_partment]).pluck(:id).uniq
ids.each do |id|
arr << { :school_id => id, :shixun_id => @shixun.id }
end
ShixunSchool.create!(arr)
use_scope = 1
else
use_scope = 0
end
@shixun.update_attributes!(:use_scope => use_scope)
# 超级管理员和运营人员才能保存 中间层服务器pod信息的配置
if current_user.admin? || current_user.business?
@shixun.shixun_service_configs.destroy_all

@ -222,7 +222,7 @@ class SubjectsController < ApplicationController
@subject.update_attributes(status: 1)
ApplyAction.create(container_type: "ApplySubject", container_id: @subject.id, user_id: current_user.id, status: 0)
begin
status = Trustie::Sms.send(mobile: '18711011226', send_type:'publish_subject' , name: '管理员')
status = Educoder::Sms.send(mobile: '18711011226', send_type:'publish_subject' , name: '管理员')
rescue => e
uid_logger_error("发送验证码出错: #{e}")
end

@ -7,7 +7,7 @@ class Users::PrivateMessageDetailsController < Users::BaseController
messages = observed_user.private_messages.without_deleted.where(target: target_user)
@count = messages.count
@messages = messages.order(send_time: :asc).includes(sender: :user_extension)
@messages = paginate messages.order(send_time: :desc).includes(sender: :user_extension)
end
private

@ -329,6 +329,23 @@ module ApplicationHelper
content
end
def strip_html(text, len=0, endss="...")
ss = ""
if !text.nil? && text.length>0
ss=text.gsub(/<\/?.*?>/, '').strip
ss = ss.gsub(/&nbsp;*/, '')
ss = ss.gsub(/\r\n/,'') #新增
ss = ss.gsub(/\n/,'') #新增
if len > 0 && ss.length > len
ss = ss[0, len] + endss
elsif len > 0 && ss.length <= len
ss = ss
#ss = truncate(ss, :length => len)
end
end
ss
end
def strip_export_title(content)
con_ = ""
if content.length > 0

@ -1,2 +0,0 @@
module ForumsHelper
end

@ -8,6 +8,7 @@ class Discuss < ApplicationRecord
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
has_many :tidings, as: :container, dependent: :destroy
has_one :praise_tread_cache, as: :object, dependent: :destroy
belongs_to :dis, polymorphic: true
belongs_to :challenge
after_create :send_tiding
@ -44,6 +45,10 @@ class Discuss < ApplicationRecord
Discuss.where(parent_id: self.id).includes(:user).reorder(created_at: :asc)
end
def child_discuss_count
Discuss.where(root_id: id).count
end
private
def send_tiding

@ -6,7 +6,7 @@ class Memo < ApplicationRecord
has_many :memo_tag_repertoires, dependent: :destroy
has_many :tag_repertoires, :through => :memo_tag_repertoires
has_many :praise_tread, as: :praise_tread_object, dependent: :destroy
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
has_one :praise_tread_cache, as: :object, dependent: :destroy
belongs_to :author, class_name: 'User', foreign_key: 'author_id'
@ -14,6 +14,7 @@ class Memo < ApplicationRecord
has_many :descendants, foreign_key: :root_id, class_name: 'Memo'
has_many :children, foreign_key: :parent_id, class_name: 'Memo'
has_many :attachments, as: :container, dependent: :destroy
scope :field_for_list, lambda{
select([:id, :subject, :author_id, :sticky, :updated_at, :language, :reward, :all_replies_count, :viewed_count, :forum_id])

@ -440,7 +440,7 @@ class User < ApplicationRecord
end
def manager_of_memo?(memo)
id == memo.author_id || admin?
id == memo.author_id || admin? || business?
end
# 是否是项目管理者

@ -58,7 +58,7 @@ class DiscussesService
praise_count: 0, position: params[:position], challenge_id: params[:challenge_id], hidden: !current_user.admin?
)
# 发送手机通知
Trustie::Sms.send(mobile:'18173242757', send_type:'discuss', name:'管理员')
Educoder::Sms.send(mobile:'18173242757', send_type:'discuss', name:'管理员')
rescue Exception => e
raise(e.message)
end
@ -148,30 +148,6 @@ class DiscussesService
@discuss = Discuss.select([:id, :hidden, :reward, :dis_type, :dis_id, :position, :challenge_id, :root_id]).find(id)
end
protected
def memo_list memos
memos.map do |m|
user = User.find(m.user_id)
praise_count = m.praise_tread.where(:praise_or_tread => 1).count
replies_count = Discuss.where(:root_id => m.id).count
shixun_tag = m.dis.tag_repertoires.map(&:name)
m.attributes.dup.except("user_id", "dis_id", "dis_type", "root_id").merge({
subject: (message_content m.content),
username: user.show_name,
login: user.login,
praise_count: praise_count,
replies_count: replies_count,
image_url: url_to_avatar(user),
shixun_tag: shixun_tag,
tpm_url: "/shixuns/#{m.dis.identifier}/shixun_discuss"
})
end
end
def format_for_current_user current_user
{username: current_user.show_name, login: current_user.login, user_id: current_user.id, image_url: url_to_avatar(current_user), admin: current_user.admin?}
end
def recommends
hot_shixuns = Shixun.field_for_recommend.published.order("myshixuns_count desc").limit(2)
newest_shixuns = Shixun.field_for_recommend.published.order("created_at desc").limit(2)
@ -185,6 +161,30 @@ class DiscussesService
return recommend_shixuns
end
def memo_list memos
memos.map do |m|
user = m.user
# praise_count = m.praise_treads.select{|pt| pt.praise_or_tread == 1}.count
replies_count = m.child_discuss_count
shixun_tag = m.dis.tag_repertoires.map(&:name)
m.attributes.dup.except("user_id", "dis_id", "dis_type", "root_id", "praise_count", "content").merge({
subject: (message_content m.content),
username: user.full_name,
login: user.login,
replies_count: replies_count,
image_url: url_to_avatar(user),
shixun_tag: shixun_tag,
tpm_url: "/shixuns/#{m.dis.identifier}/shixun_discuss"
})
end
end
protected
def format_for_current_user current_user
{username: current_user.show_name, login: current_user.login, user_id: current_user.id, image_url: url_to_avatar(current_user), admin: current_user.admin?}
end
# 将数据库对象转换成哈希对象
def object_to_hash objects
objects.map{|o| o.attributes.dup}

@ -22,7 +22,7 @@ class Projects::ApplyJoinService < ApplicationService
apply.forge_activities.find_or_create_by!(user: user, project: project)
notify_project_manager!
notify_project_manager!(apply)
end
# notify_project_owner
@ -47,10 +47,13 @@ class Projects::ApplyJoinService < ApplicationService
end
end
def notify_project_manager!
def notify_project_manager!(apply)
columns = %i[user_id applied_id applied_type status viewed applied_user_id role project_id created_at updated_at]
AppliedMessage.bulk_insert(*columns) do |worker|
base_attr = { status: false, viewed: false, applied_user_id: user.id, role: role_value, project_id: project.id }
base_attr = {
applied_id: apply.id, applied_type: 'AppliedProject', status: false, viewed: false,
applied_user_id: user.id, role: role_value, project_id: project.id
}
project.manager_members.each do |manager|
worker.add(base_attr.merge(user_id: manager.user_id))

@ -1,96 +0,0 @@
class SearchShixunService < ApplicationService
include ElasticsearchAble
attr_reader :user, :params
def initialize(user, params)
@user = user
@params = params
end
def call
Shixun.search(keyword,
fields: search_fields,
where: where_clauses,
order: order_clauses,
includes: includes_clauses,
page: page,
per_page: per_page)
end
private
def tag_filter_shixun_ids
return [] if params[:tag_level].to_i == 0 || params[:tag_id].blank?
case params[:tag_level].to_i
when 1 then
Repertoire.find(params[:tag_id]).tag_repertoires.joins(:shixun_tag_repertoires)
.pluck('shixun_tag_repertoires.shixun_id')
when 2 then
SubRepertoire.find(params[:tag_id]).tag_repertoires.joins(:shixun_tag_repertoires)
.pluck('shixun_tag_repertoires.shixun_id')
when 3 then
TagRepertoire.find(params[:tag_id]).shixun_tag_repertoires.pluck(:shixun_id)
else
[]
end
end
def user_filter_shixun_ids
return [] if params[:order_by] != 'mine'
user.shixun_members.pluck(:shixun_id) + user.myshixuns.pluck(:shixun_id)
end
def keyword
params[:keyword].to_s.strip.presence || '*'
end
def search_fields
%w(name^10 author_name challenge_names description challenge_tag_names)
end
def where_clauses
hash = {}
ids = user_filter_shixun_ids + tag_filter_shixun_ids
hash[:id] = ids if ids.present?
if params[:order_by] == 'mine'
hash[:status] = { not: -1 }
else
hash.merge!(hidden: false, status: 2)
end
unless params[:status].to_i.zero?
params[:status] = [0, 1] if params[:status].to_i == 1
hash[:status] = params[:status]
end
hash[:trainee] = params[:diff].to_i unless params[:diff].to_i.zero?
hash
end
def includes_clauses
[]
end
def order_clauses
hash = { _score: :desc }
publish_order = { type: 'number', order: :desc, script: 'doc["status"].value=="2" ? 1 : 0' }
sort = params[:sort].to_s.strip == 'asc' ? 'asc' : 'desc'
clauses =
case params[:order_by].presence
when 'new' then { _script: publish_order, created_at: sort }
when 'hot' then { _script: publish_order, myshixuns_count: sort }
when 'mine' then { created_at: sort }
else { _script: publish_order, publish_time: sort }
end
hash.merge!(clauses)
hash
end
end

@ -51,6 +51,8 @@ class Users::UpdateAccountService < ApplicationService
if first_full_reward
RewardGradeService.call(user, container_id: user.id, container_type: 'Account', score: 500)
sms_notify_admin(user.lastname) if user.user_extension.teacher?
end
user
@ -65,4 +67,10 @@ class Users::UpdateAccountService < ApplicationService
def user_extension_attributes
params.slice(*%i[location location_city identity student_id technical_title school_id department_id])
end
def sms_notify_admin name
Educoder::Sms.send(mobile:'18182021083', send_type:'teacher_register', name: name, user_name:'管理员')
rescue => ex
Util.logger_error(ex)
end
end

@ -0,0 +1,27 @@
json.memo_list @memos
# do |memo|
# json.(memo, :id, :updated_at, :reward)
# json.subject message_content(memo.content)
# json.praise_count memo.praises_count
# json.replies_count memo.child_discuss_count
# json.shixun_tag memo.dis.tag_repertoires.map(&:name)
# json.username memo.user.full_name
# json.login memo.user.login
# json.image_url url_to_avatar(memo.user)
# json.tpm_url "/shixuns/#{memo.dis.identifier}/shixun_discuss"
# end
json.memo_count @memo_count
json.hot_memos do
json.array! @hot_memos do |hm|
json.(hm, :id, :subject, :language, :forum_id)
json.replies_count hm.all_replies_count
# json.praise_count hm.praise_tread.praise_count
json.tag hm.tag_repertoires.map(&:name)
end
end
json.hot_tags @hot_tags
json.recommend_shixuns @recommend_shixuns

@ -1 +1,2 @@
json.status 0
json.code @code

@ -25,29 +25,28 @@ elsif @type == "txt"
elsif @type =="qrcode"
json.qrcode_str @qrcode_str
elsif @type == "mp3" || @type == "mp4"
if @type == "mp4"
json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378171/123.mp4"}]
json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378172/456.mp4"}]
json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378173/789.mp4"}]
else
json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378174/58099.mp3"}]
json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}]
json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}]
end
# json.orignal_file do
# json.array! @orignal_picture do |file|
# json.file_url attachment_show_users_path(:file_name => file, :path => @original_path)
# end
# end
# json.user_file do
# json.array! @user_picture do |file|
# json.file_url attachment_show_users_path(:file_name => file, :path => @user_path, :time => Time.now.to_i)
# end
# end
# json.answer_file do
# json.array! @answer_picture do |file|
# json.file_url attachment_show_users_path(:file_name => file, :path => @answer_path)
# end
# if @type == "mp4"
# json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378171/123.mp4"}]
# json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378172/456.mp4"}]
# json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378173/789.mp4"}]
# else
# json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378174/58099.mp3"}]
# json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}]
# json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}]
# end
json.orignal_file do
json.array! @orignal_picture do |file|
json.file_url attachment_show_users_path(:file_name => file, :path => @original_path)
end
end
json.user_file do
json.array! @user_picture do |file|
json.file_url attachment_show_users_path(:file_name => file, :path => @user_path, :time => Time.now.to_i)
end
end
json.answer_file do
json.array! @answer_picture do |file|
json.file_url attachment_show_users_path(:file_name => file, :path => @answer_path)
end
end
end

@ -10,7 +10,7 @@ json.hidden message.hidden
if message.m_parent_id
json.can_delete message.can_delete(identity)
else
json.praise_count message.praise_treads.liker.count
json.user_praise message.praise_treads.user_liker(current_user).count
json.praise_count message.praise_treads.select{|pt| pt.praise_or_tread == 1}.count
json.user_praise message.praise_treads.select{|pt| pt.praise_or_tread == 1 && user_id == current_user.id}.count
json.child_message_count message.m_reply_count
end

@ -1,8 +1,14 @@
json.(memo, :id, :subject, :is_md, :content, :sticky, :reward, :viewed_count)
json.tag memo.tag_repertoires.map(&:name)
json.time memo.created_at
json.replies_count memo.all_replies_count
json.attachments_list []
json.user_praise memo.praise_tread.user_liker(@user.try(:id)) ? true : false
json.memo_praise_count = memo.praise_tread.liker.count
json.memo do
json.id memo.id
json.subject memo.subject
json.is_md memo.is_md
json.content memo.content
json.sticky memo.sticky
json.reward memo.reward
json.viewed_count memo.viewed_count
json.tag memo.tag_repertoires.map(&:name)
json.time memo.created_at
json.replies_count memo.all_replies_count
json.user_praise memo.praise_treads.user_liker(@user.try(:id)) ? true : false
json.memo_praise_count memo.praise_treads.liker.count
end

@ -1,7 +1,7 @@
json.(memo, :id, :subject, :author_id, :sticky,
:updated_at, :language, :reward, :all_replies_count,
:viewed_count, :forum_id)
json.praise_count memo.praise_tread.praise_count
json.praise_count memo.praise_treads.liker.count
json.replies_count memo.all_replies_count
json.tag memo.tag_repertoires.map(&:name)
json.user_name memo.author.full_name

@ -7,10 +7,10 @@ json.username memo.author.full_name
json.reward memo.reward
json.hidden memo.hidden
json.permission @user.manager_of_memo?(memo)
json.praise_count memo.praise_tread.liker.count
json.user_praise memo.praise_tread.select{|pt| pt.user_id == @user.id}.length > 0
json.praise_count memo.praise_treads.select{|pt| pt.praise_or_tread == 1}.count
json.user_praise memo.praise_treads.select{|pt| pt.praise_or_tread == 1 && pt.user_id == @user.id}.length > 0
json.user_login memo.author.login
json.admin @user.admin
json.admin @user.admin? || @user.business?
json.children do
json.array! memo.children_of_reply do |child|

@ -0,0 +1,7 @@
json.(@memo, :subject, :content, :forum_id)
json.memo_tags @memo_tags
json.attachments @attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}
end
json.tag_list @tag_list
json.forums forum_list

@ -8,22 +8,30 @@
# tidding_count: 消息数
# #
json.memo_list do
json.array! @memos do |memo|
json.partial! "memos/memo_list", locals: {memo: memo}
end
json.memo_list @memos do |memo|
json.(memo, :id, :subject, :sticky,
:updated_at, :language, :reward,
:viewed_count, :forum_id)
json.praise_count memo.praise_treads.select{|pt| pt.praise_or_tread == 1}.count
json.replies_count memo.all_replies_count
json.tag memo.tag_repertoires.map(&:name)
json.user_name memo.author.full_name
json.login memo.author.login
json.image_url url_to_avatar(memo.author)
end
json.memo_count @memos_count
json.hot_memos do
json.array! @hot_memos do |hm|
json.(hm, :id, :subject, :language, :forum_id, :all_replies_count)
json.(hm, :id, :subject, :language, :forum_id)
json.replies_count hm.all_replies_count
json.praise_count hm.praise_tread.praise_count
# json.praise_count hm.praise_tread.praise_count
json.tag hm.tag_repertoires.map(&:name)
end
end
json.hot_tags @tags_info.map{|o| o.attributes.dup.except("cnt", "id")}
json.recommend_shixuns @recommend_shixuns

@ -0,0 +1,7 @@
json.memo_replies do
json.array! @memos do |memo|
json.partial! "memos/replies_list", memo: memo
end
end
json.memos_count @memos_count

@ -1,3 +1,2 @@
json.tag_list @tag_list
json.forums @csrf_token
json.forums forum_list

@ -1,5 +1,9 @@
json.partial! "memos/memo", memo: @memo
json.attachments_list @attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}
end
json.memo_replies do
json.array! @memos do |memo|
json.partial! "memos/replies_list", memo: memo
@ -9,10 +13,11 @@ end
json.author_info do
json.username @memo.author.full_name
# TODO watched_by 插件没法用,等把lib文件载入后在打开代码
#json.watched @memo.author.watched_by?(@user)
json.watched @user.watched?(@memo.author)
json.image_url url_to_avatar(@memo.author)
json.identity @memo.author.identity
json.login @memo.author.login
json.user_id @memo.author.id
end
json.recommend_shixuns @recommend_shixuns

@ -20,7 +20,18 @@ Rails.application.routes.draw do
put 'commons/unhidden', to: 'commons#unhidden'
delete 'commons/delete', to: 'commons#delete'
resources :memos
resources :memos do
member do
post :sticky_or_cancel
post :hidden
get :more_reply
end
collection do
post :reply
end
end
resources :tem_tests
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
#
@ -222,6 +233,7 @@ Rails.application.routes.draw do
resources :discusses do
collection do
get :new_message
get :forum_discusses
end
member do
@ -703,7 +715,7 @@ Rails.application.routes.draw do
resources :libraries, only: [:index, :show, :create, :update, :destroy]
scope module: :projects do
resources :applied_projects, only: [:create]
resources :project_applies, only: [:create]
end
end

@ -21,7 +21,7 @@ module Educoder
def self.notify_admin(opt)
opt[:name] = '管理员'
opt[:mobile] = ENV['NOTIFY_ADMIN_PHONE'] || EduSetting.get('notify_admin_phone') || '17680641960'
opt[:mobile] = ENV['NOTIFY_ADMIN_PHONE'] || EduSetting.get('notify_admin_phone') || '18182021083'
send(opt)
end
@ -40,6 +40,8 @@ module Educoder
elsif send_type == 'competition_start'
params['text'] = "【Edu实训】亲爱的#{user_name},你参与的#{name}将于#{result}开始,请及时参赛"
Rails.logger.info "#{params['text']}"
elsif send_type == "teacher_register"
params['text'] = "【Edu实训】亲爱的#{user_name},有新的老师#{name}注册啦,请尽快处理"
elsif send_type == 'subject_authorization' || send_type == 'shixun_authorization'
params['text'] = "【Edu实训】亲爱的#{user_name},您提交的#{name}#{send_type=='subject_authorization'?'':''}发布申请#{result},请登录平台查看详情"
Rails.logger.info "#{params['text']}"

@ -3065,3 +3065,358 @@ a.singlepublishtwo{
/*课程目标VS毕业要求指标点*/
.CourseTargetPoint thead th{vertical-align: baseline;}
.CourseTargetPoint tbody tr td{vertical-align: top;}
/*众包*/
.packinput .ant-input{
height: 50px;
width:749px;
border-color: #E1EDF8 !important;
}
.packinput{
width:749px;
}
.packinput .ant-input-group-addon .ant-btn{
width:140px !important;
font-size: 18px;
height: 50px;
background:rgba(76,172,255,1);
}
.setissues{
width:280px;
height:50px;
background:rgba(76,172,255,1);
border-radius:4px;
margin-left: 15px;
}
.pagetype li{
color:#8F8F8F !important;
}
.maxwidth700{
max-width: 700px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mbf10{
margin-bottom:-10px;
}
.PackageIndexNEIBanner{
width:1200px;
height:110px;
background:rgba(255,255,255,1);
box-shadow:0px 2px 6px 0px rgba(125,125,125,0.26);
border-radius:8px;
}
.padding110{
padding: 39px 110px 0px;
box-sizing: border-box;
}
.borderccc{
border: 1px solid #ccc;
}
.input-100-40s{
width: 100%;
padding: 5px;
box-sizing: border-box;
}
.fafafas{
background-color: #fafafa!important;
height: 40px;
}
.fafafas:focus{
background-color: #fff!important;
}
.fafas .ant-input{
background-color: #fafafa!important;
height: 40px;
}
.fafas .ant-input:focus{
background-color: #fff!important;
}
.fafas .ant-input-group-addon .ant-btn{
width:140px !important;
font-size: 14px;
height: 40px;
background:rgba(76,172,255,1);
}
.newFormbox .upload_filename{
line-height: 32px;
}
.newFormbox .attachment span{
line-height: 23px;
}
.newFormbox .attachment .remove-upload{
line-height: 28px;
}
.pd26a0{
padding: 26px 26px 16px 26px;
}
.newFormbox .attachment .icon-fujian{
font-size: 14px !important;
line-height: 14px;
margin-top: 9px;
}
.newFormbox{
height:20px
}
.ml24{
margin-left:24px;
}
.defalutCancelbtns{
display: block;
border: 1px solid #4CACFF !important;
background-color: #fff;
color: #4CACFF !important;
width:130px;
height:40px;
text-align: center;
line-height: 40px;
border-radius: 4px;
}
.defalutSubmitbtns{
background-color: #4CACFF;
height:40px;
}
.defalutSubmitbtnmodels{
width:127px;
height:30px;
background-color: #4CACFF;
}
.ant-steps-item-process .ant-steps-item-icon{
background-color: #4CACFF !important;
}
.ant-steps-item-process .ant-steps-item-icon{
background-color: #4CACFF !important;
}
.padding200{
padding: 115px 200px 215px 200px;
}
.fontcircle{
font-size: 80px;
display: inherit;
}
.sumbtongs{
font-size: 24px;
display: inherit;
text-align: center;
}
.terraces{
font-size: 16px;
display: inherit;
text-align: center;
color:#999;
}
.padding251{
padding: 0px 245px;
}
.ant-modal-title{
text-align: center;
}
.ml17{
margin-left: 17px;
}
.project-package-items{
display: -webkit-flex;
display: flex;
flex-direction: row;
margin:0px !important;
padding: 20px;
background: white;
margin-bottom:0px !important;
box-shadow: none !important;
}
.mtf7{
margin-top:-7px;
}
.publicpart.orangeGreen {
border-left: 80px solid #29BD8B;
}
.publicwords{
left: 3px;
top: 18px;
}
.project-packages-list .project-package-items .item-image{
width:100px !important;
}
.height185{
height: 185px;
}
.ContacttheTA{
width: 80px;
height: 26px;
font-size: 14px;
line-height: 26px;
display: block;
border: 1px solid #4CACFF !important;
background-color: #fff;
color: #4CACFF !important;
text-align: center;
border-radius: 4px;
}
.ContacttheTAs{
width: 80px;
height: 26px;
font-size: 14px;
line-height: 24px;
/*display: block;*/
border: 1px solid #fff !important;
background-color: #4CACFF;
color: #fff !important;
text-align: center;
border-radius: 4px;
}
.ml28{
margin-left: 28px;
}
.longboxs{
font-size: 16px;
font-family: MicrosoftYaHei-Bold;
font-weight: bold;
color: rgba(5,16,26,1);
border-left: 4px solid rgba(76,172,255,1);
padding-left: 10px;
margin-bottom: 20px;
}
.padding020{
padding: 0px 20px 20px;
}
.mtf3{
margin-top:-3px;
}
.task-btn-nebules{
background: #fff!important;
color: #4CACFF!important;
border: 1px solid #4CACFF!important;
margin-left: 20px;
cursor: pointer;
display: inline-block;
padding: 0 12px;
letter-spacing: 1px;
text-align: center;
font-size: 14px;
height: 30px;
line-height: 30px;
border-radius: 2px;
}
.packageabsolute{
position: absolute;
right: -16px;
top: -7px;
}
.relativef{
position: relative;
}
.homehove:hover .ptext{
color: #4CACFF!important;
}
.homehove:hover .ContacttheTAs{
display: block;
}
.topsj{
position: absolute;
top: -6px;
}
.bottomsj{
position: absolute;
bottom: -6px;
}
.touchSelect .ant-spin-dot-spin{
margin-top: 30% !important;
}
.pagenoedits{
margin-left: 20px;
color: #ccc;
}
.pagemancenter{
text-align: center;
}
.ml0{
margin-left: 0px;
}
.tabelcli{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 850px;
display: table-cell;
}
.mtf10{
margin-top:-10px;
}
.padding26{
padding: 26px;
box-sizing: border-box;
}
.pd26{
padding: 26px;
}
.pd30a0{
padding: 30px 30px 16px 30px;
}
.shaiContent li.shaiItem:hover span{
color: #fff !important;
}
.shaiContent li.shaiItem:hover i.iconfont{
color: #4CACFF!important
}
.detail_for_paragraph p{
white-space: pre-wrap;
}

@ -50,4 +50,8 @@ html, body {
}
.ant-progress-textno{
color: #f5222d;
}
/* md多空格 */
.markdown-body p {
white-space: pre-wrap;
}

@ -292,8 +292,8 @@ class App extends Component {
<Router>
<Switch>
{/*众包创新*/}
<Route path={"/crowdsourcings"} component={ProjectPackages}/>
{/*/!*众包创新*!/*/}
{/*<Route path={"/crowdsourcing"} component={ProjectPackages}/>*/}
{/*认证*/}
<Route path="/account" component={AccountPage}/>

@ -9,7 +9,7 @@ export function markdownToHTML(oldContent, selector) {
window.$('#md_div').html('')
// markdown to html
if (selector && oldContent && oldContent.startsWith('<p')) { // 普通html处理
window.$(selector).html(oldContent)
window.$('#' + selector).html(oldContent)
} else {
try {
// selector ||

@ -195,7 +195,7 @@ class Testpapersettinghomepage extends Component{
}else {
this.setState({ donwloading: true })
downloadFile({
url: url+`?${queryString.stringify(params)}`+ '&export=true',
url: url+`?${queryString.stringify(params)}`,
successCallback: (url) => {
this.setState({ donwloading: false });
console.log('successCallback')

@ -222,7 +222,7 @@ export default class MDEditors extends Component {
const _placeholder = placeholder || "";
// amp;
// 编辑时要传memoId
const imageUrl = `/upload_with_markdown?container_id=&container_type=Memo`;
const imageUrl = `/api/attachments.json`;
// 创建editorMd
let react_id = `react_${_id}`;

@ -4,6 +4,9 @@ import axios from 'axios';
import { Input ,Icon,Button,Pagination} from 'antd';
import moment from 'moment';
import '../packageconcnet.css';
import AccountProfile from"../../user/AccountProfile";
import LoginDialog from '../../login/LoginDialog';
const { Search } = Input;
let categorylist=[
@ -45,7 +48,9 @@ class PackageConcent extends Component {
sort_direction:"desc",
page:1,
per_page:20,
categories:[]
categories:[],
isRender:false,
AccountProfiletype:false
}
}
//desc, desc, asc
@ -134,12 +139,66 @@ class PackageConcent extends Component {
this.setdatas(category,keyword,value,sort_directionvalue,page)
}
onReleaseRequirements=(url)=>{
let{current_user} =this.props;
if(current_user===undefined){
this.setState({
isRender:true
})
return
}
if(current_user&&current_user.login===""){
this.setState({
isRender:true
})
return;
}
if(current_user&&current_user.profile_completed===false){
this.setState({
AccountProfiletype:true
})
return;
}
if(url !== undefined || url!==""){
window.location.href = url;
}
}
// 登录
Modifyloginvalue=()=>{
this.setState({
isRender:false,
})
}
hideAccountProfile=()=>{
this.setState({
AccountProfiletype:false
})
}
render() {
let {data,page,category,sort_by,sort_direction,project_packages}=this.state;
let {data,page,category,sort_by,sort_direction,project_packages,
isRender,AccountProfiletype
}=this.state;
return (
<div className="educontent clearfix mtf10" style={{flex: "1 0 auto"}}>
{isRender===true?<LoginDialog
Modifyloginvalue={()=>this.Modifyloginvalue()}
{...this.state}
{...this.props}
/>:""}
{AccountProfiletype===true?<AccountProfile
hideAccountProfile={()=>this.hideAccountProfile()}
{...this.state}
{...this.props}
/>:""}
<div className="stud-class-set">
<div className="news">
<div className="edu-class-inner container clearfix">
@ -153,12 +212,12 @@ class PackageConcent extends Component {
<p className="clearfix" >
<p style={{height: '50px'}}>
<Search placeholder="输入标题名称进行检索"
style={{ width: 749}}
className="packinput"
enterButton={<span><Icon type="search" className="mr5"/> 搜索</span>}
onSearch={ (value)=>this.setdatafuns(value)} />
<Button type="primary" className="setissues fr" size={"large"}>
<a href="/crowdsourcings/new" >发布需求</a>
<a onClick={()=>this.onReleaseRequirements("/crowdsourcing/new")}>发布需求</a>
</Button>
</p>
</p>
@ -224,7 +283,7 @@ class PackageConcent extends Component {
<div className=" item-head-title">
<a className={"fl mt3 font-20 font-bd color-dark maxwidth700 "}
href={"/crowdsourcings/"+item.id}
onClick={()=>this.onReleaseRequirements("/crowdsourcing/"+item.id)}
title={item.title}
>{item.title}</a>
</div>

@ -230,7 +230,7 @@ class PackageIndexNEITaskDetails extends Component {
}
goback = () => {
// window.history.go(-1)
window.location.href="/crowdsourcings";
window.location.href="/crowdsourcing";
}
render() {
@ -252,7 +252,7 @@ class PackageIndexNEITaskDetails extends Component {
<Breadcrumb separator={'>'} className={"fl"}>
{/*<Breadcrumb.Item>{this.props.current_user.username}</Breadcrumb.Item>*/}
<Breadcrumb.Item>
<a href="/crowdsourcings">众包创新</a>
<a href="/crowdsourcing">众包创新</a>
</Breadcrumb.Item>
<Breadcrumb.Item><span className={"tabelcli"} title={data&&data.title}>{data&&data.title}</span></Breadcrumb.Item>
@ -353,7 +353,7 @@ class PackageIndexNEITaskDetails extends Component {
需求详情
{data&&data.status==="pending"&&data&&data.operation.can_select_bidding_user===true?<div className="fr">
<a className="task-btn-nebules fr" href={`/crowdsourcings/${this.props.match.params.id}/edit`}>编辑</a>
<a className="task-btn-nebules fr" href={`/crowdsourcing/${this.props.match.params.id}/edit`}>编辑</a>
<a className="task-btn-nebules fr" onClick={this.deletePackages}>删除</a>
</div>:""}

@ -43,6 +43,12 @@ function disabledDateTime() {
disabledMinutes: () => range(1, 30).concat(range(31, 60)),
};
}
function disabledDate(current) {
return current && current < moment().endOf('day').subtract(1, 'days');
}
class PackageIndexNEIBannerConcent extends Component {
constructor(props) {
super(props)
@ -50,7 +56,7 @@ class PackageIndexNEIBannerConcent extends Component {
this.state = {
modalCancel:false,
getverificationcodes:true,
seconds:35,
seconds:60,
springtype:false,
category:undefined,
title:undefined,
@ -83,7 +89,7 @@ class PackageIndexNEIBannerConcent extends Component {
deadline_at:moment(data.deadline_at),
min_price:data.min_price,
max_price:data.max_price,
contact_name:data.contact_name==null||data.contact_name==undefined?this.props.current_user.username:data.contact_name,
contact_name:data.contact_name==null||data.contact_name==undefined?this.props.current_user.real_name:data.contact_name,
phones:data.contact_phone,
attachments:data.attachments,
@ -93,7 +99,7 @@ class PackageIndexNEIBannerConcent extends Component {
})
}else{
console.log(this.props.current_user&&this.props.current_user.username)
console.log(this.props.current_user&&this.props.current_user.real_name)
}
let Url = `/project_package_categories.json`;
@ -112,7 +118,7 @@ class PackageIndexNEIBannerConcent extends Component {
})
this.setState({
contact_name:this.props.current_user&&this.props.current_user.username
contact_name:this.props.current_user&&this.props.current_user.real_name
})
// this.contentMdRef.current.setValue("测试赋值")
@ -123,7 +129,7 @@ class PackageIndexNEIBannerConcent extends Component {
if(prevProps.current_user!=this.props.current_user){
if(this.props.current_user!=undefined){
this.setState({
contact_name:this.props.current_user.username
contact_name:this.props.current_user.real_name
})
}
}
@ -151,7 +157,7 @@ class PackageIndexNEIBannerConcent extends Component {
clearInterval(timer);
this.setState({
getverificationcodes: false,
seconds: 35,
seconds: 60,
})
}
});
@ -170,7 +176,7 @@ class PackageIndexNEIBannerConcent extends Component {
clearInterval(timer);
this.setState({
getverificationcodes: false,
seconds: 35,
seconds: 60,
})
}
@ -187,7 +193,7 @@ class PackageIndexNEIBannerConcent extends Component {
axios.get((url), {
params: {
value: contact_phone,
type: 9,
type: 5,
}
}).then((result) => {
//验证有问题{"status":1,"message":"success"}
@ -452,7 +458,7 @@ class PackageIndexNEIBannerConcent extends Component {
deadline_at:deadline_at._i,
min_price:parseInt(min_price),
max_price:parseInt(max_price),
contact_name: contact_name===null||contact_name===undefined?this.props.current_user.username:contact_name,
contact_name: contact_name===null||contact_name===undefined?this.props.current_user.real_name:contact_name,
contact_phone: contact_phone===undefined?this.props.current_user&&this.props.current_user.phone:contact_phone,
code:code,
publish:types
@ -462,7 +468,7 @@ class PackageIndexNEIBannerConcent extends Component {
if(type===true){
this.props.setPublicationfun(response.data.id)
}else{
window.location.href="/crowdsourcings/"+response.data.id
window.location.href="/crowdsourcing/"+response.data.id
}
this.setState({
springtype:false
@ -500,7 +506,7 @@ class PackageIndexNEIBannerConcent extends Component {
deadline_at:deadline_at._i,
min_price:parseInt(min_price),
max_price:parseInt(max_price),
contact_name: contact_name===null||contact_name===undefined?this.props.current_user.username:contact_name,
contact_name: contact_name===null||contact_name===undefined?this.props.current_user.real_name:contact_name,
contact_phone: contact_phone===undefined?this.props.current_user&&this.props.current_user.phone:contact_phone,
code:code,
publish:types
@ -510,7 +516,7 @@ class PackageIndexNEIBannerConcent extends Component {
if(type===true){
this.props.setPublicationfun(response.data.id)
}else{
window.location.href="/crowdsourcings/"+response.data.id
window.location.href="/crowdsourcing/"+response.data.id
}
this.setState({
springtype:false
@ -714,9 +720,9 @@ class PackageIndexNEIBannerConcent extends Component {
<Spin size="large" spinning={this.state.springtype} >
<p className="clearfix" id={"publishtimestart"}>
<div className={"stud-class-set pd30a0 coursenavbox edu-back-white pb20"}>
<div className={"stud-class-set pd30a0 edu-back-white pb20"}>
<div className={"ant-row contentbox mdInForm mb20"}>
<div className="ant-form-item-label mb10">
<div className="ant-form-item-label mb20">
<label htmlFor="coursesNew_description" className="ant-form-item-requireds font-16">请选择需求类型</label>
</div>
@ -729,9 +735,10 @@ class PackageIndexNEIBannerConcent extends Component {
})}
</div>
</p>
{this.state.categorytypes===true?<div className={"color-red"}>请选择类型</div>:""}
<div className="ant-form-item-label mb10">
{this.state.categorytypes===true?<div className={"color-red mb10"}>请选择类型</div>:""}
<div className="ant-form-item-label mb15">
<label htmlFor="coursesNew_description" className="ant-form-item-requireds font-16" >需求标题和详情</label>
</div>
@ -805,6 +812,8 @@ class PackageIndexNEIBannerConcent extends Component {
placeholder="请选择任务的竞标截止日期"
className={"fafas"}
disabledTime={disabledDateTime}
disabledDate={disabledDate}
dropdownClassName="hideDisable"
value={this.state.deadline_at}
onChange={this.onChangeTimePicker}
/>
@ -848,7 +857,7 @@ class PackageIndexNEIBannerConcent extends Component {
<Input
className={"fafafas"}
style={{"width": "260px"}}
value={this.state.contact_name===null||this.state.contact_name===undefined?this.props.current_user&&this.props.current_user.username:this.state.contact_name}
value={this.state.contact_name===null||this.state.contact_name===undefined?this.props.current_user&&this.props.current_user.real_name:this.state.contact_name}
placeholder="请输入姓名"
onInput={(e)=>this.onChangeContact_name(e)}
/>

@ -14,10 +14,10 @@ class PackageIndexNEISubmit extends Component {
}
setageload=(sum)=>{
if(sum===undefined){
window.location.href="/crowdsourcings/new"
window.location.href="/crowdsourcing/new"
}else{
// this.props.history.push("/project_packages/"+sum)
window.location.href="/crowdsourcings/"+sum
window.location.href="/crowdsourcing/"+sum
}
}

@ -30,7 +30,7 @@ class PackageIndexNewandEditIndex extends Component{
goback = () => {
// window.history.go(-1)
window.location.href="/crowdsourcings";
window.location.href="/crowdsourcing";
}
render() {

@ -43,29 +43,29 @@ class ProjectPackageIndex extends Component {
<Switch>
{/*众包首页*/}
<Route path="/crowdsourcings/:id/edit"
render={
(props) => (<PackageIndexNewandEdit {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/crowdsourcings/new"
render={
(props) => (<PackageIndexNewandEdit {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/crowdsourcings/:id"
render={
(props) => (<PackageIndexNEITaskDetails {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/crowdsourcings"
render={
(props) => (<PackageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
{/*<Route path="/crowdsourcing/:id/edit"*/}
{/*render={*/}
{/*(props) => (<PackageIndexNewandEdit {...this.props} {...props} {...this.state} />)*/}
{/*}*/}
{/*></Route>*/}
{/*<Route path="/crowdsourcing/new"*/}
{/*render={*/}
{/*(props) => (<PackageIndexNewandEdit {...this.props} {...props} {...this.state} />)*/}
{/*}*/}
{/*></Route>*/}
{/*<Route path="/crowdsourcing/:id"*/}
{/*render={*/}
{/*(props) => (<PackageIndexNEITaskDetails {...this.props} {...props} {...this.state} />)*/}
{/*}*/}
{/*></Route>*/}
{/*<Route path="/crowdsourcing"*/}
{/*render={*/}
{/*(props) => (<PackageIndex {...this.props} {...props} {...this.state} />)*/}
{/*}*/}
{/*></Route>*/}
</Switch>
</div>

@ -7,6 +7,11 @@
border-color: #E1EDF8 !important;
}
.packinput{
width:749px;
}
.packinput .ant-input-group-addon .ant-btn{
width:140px !important;
font-size: 18px;

@ -617,8 +617,10 @@ submittojoinclass=(value)=>{
let activeShixuns = false;
let activePaths = false;
let coursestype=false;
let activePackages=false;
if (match.path === '/forums') {
if (match.path === '/forums') {
activeForums = true;
} else if (match.path.startsWith('/shixuns')) {
activeShixuns = true;
@ -626,14 +628,12 @@ submittojoinclass=(value)=>{
activePaths = true;
} else if (match.path.startsWith('/courses')) {
coursestype = true;
}else {
}else if (match.path.startsWith('/crowdsourcing')) {
activePackages = true;
}else {
activeIndex = true;
}
// join_course_url: "https://www.educoder.net/courses/join_course_multi_role"
// join_project_url: "https://www.educoder.net/applied_project/applied_project_info"
// rolearr:["",""],
// console.log("618");
// console.log(user_phone_binded);
return (
<div className="newHeader" id="nHeader" >
@ -716,10 +716,9 @@ submittojoinclass=(value)=>{
/>
</li>
<li className=""><a href={this.props.Headertop===undefined?"":this.props.Headertop.moop_cases_url}>教学案例</a></li>
<li className=""><a
// href={this.props.Headertop===undefined?"":this.props.Headertop.crowdsourcing_url}
href={'/crowdsourcings'}
>众包创新</a></li>
<li className={`${activePackages === true ? 'pr active' : 'pr'}`}>
<a href={'/crowdsourcing'}>众包创新</a>
</li>
<li className={`${activeForums === true ? 'active' : ''}`}><a href={this.props.Headertop===undefined?"":this.props.Headertop.topic_url}>交流问答</a></li>
<li
style={{display: this.props.Headertop === undefined ? 'none' : this.props.Headertop.auth===null? 'none' : 'block'}}

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

@ -339,9 +339,6 @@ export default class TPMevaluation extends Component {
goblakepath=(path,key)=>{
let {main,selectpath,pathtype} =this.state;
let newmain=[]
for(var i=0;i<=key;i++){
newmain.push(main[i])
@ -366,16 +363,20 @@ export default class TPMevaluation extends Component {
});
if(pathtype===2){
// var str=path;
// str.slice(0,str.length-1)
// debugger
// console.log(str)
let paths = path.substring(0,path.length-1);
console.log(paths)
this.setState({
selectpath: path,
selectpath: paths,
})
}
}
// delesavegetfilepath=(value)=>{
// let {selectpatharr} = this.state
// let newarr =selectpatharr;
@ -674,6 +675,7 @@ export default class TPMevaluation extends Component {
this.setState({
selectpath:e.target.value
})
}
updatepath=(e,name,type)=>{
this.setState({
@ -949,6 +951,8 @@ export default class TPMevaluation extends Component {
<Option value={2}>apk/exe</Option>
<Option value={3}>txt</Option>
<Option value={4}>html</Option>
{/*<Option value={5}>mp3</Option>*/}
{/*<Option value={6}>mp4</Option>*/}
</Select>
<a className="ml10" onClick={()=>this.showrepositoryurltip(1)}><img src={getImageUrl("images/educoder/problem.png")}/></a>
<div className="invite-tip clearfix repository_url_tippostion" style={{display:showrepositoryurltiptype===true?"block":"none"}} id="repository_url_tip"
@ -975,20 +979,20 @@ export default class TPMevaluation extends Component {
</div>
{pathoptionvalue===1?<div className="edu-back-white mb10 clearfix">
{pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6?<div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb20">待处理图片路径</p>
<div className="df">
<div className="flex1 mr20">
<input type="text" className="input-100-45" autoComplete="off"
id="shixun_file_expect_picture_path" name="challenge[original_picture_path]"
placeholder="请选择版本库中存储了待处理图片的路径。例src/step1/expectedimages"
placeholder="请选择版本库中存储了待处理文件(图片/MP3等)的路径。例src/step1/sourcefiles"
value={shixunfileexpectpicturepath}
onInput={(e)=>this.updatepath(e,"shixunfileexpectpicturepath",2)}
onClick={(e)=>this.getfilepath(e,"shixunfileexpectpicturepath",2)}
/>
<p className="color-grey-9 mt15">
该路径下的文件将在学员评测本关任务时作为原始图片显示在查看效果页供学员参考,任务为图片处理时请指定该路径并注意与程序文件所在文件夹分开
该路径下的文件将在学员评测本关任务时作为原始文件显示在查看效果页供学员参考任务为文件处理时请指定该路径并注意与程序文件所在文件夹分开
</p>
</div>
<div></div>
@ -997,20 +1001,20 @@ export default class TPMevaluation extends Component {
</div>:""}
{pathoptionvalue===1? <div className="edu-back-white mb10 clearfix">
{pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6? <div className="edu-back-white mb10 clearfix">
<div className="padding40-20">
<p className="color-grey-6 font-16 mb20">标准答案图片路径</p>
<div className="df">
<div className="flex1 mr20">
<input type="text" className="input-100-45" autoComplete="off"
id="shixun_file_standard_picture_path" name="challenge[expect_picture_path]"
placeholder="请选择版本库中存储了标准答案代码输出文件的路径。例src/step1/expectedimages"
placeholder="请选择版本库中存储了标准答案文件(图片/MP3等)的路径。例src/step1/expectedfiles"
value={shixunfilestandardpicturepath}
onInput={(e)=>this.updatepath(e,"shixunfilestandardpicturepath",2)}
onClick={(e)=>this.getfilepath(e,"shixunfilestandardpicturepath",2)}
/>
<p className="color-grey-9 mt15">
该路径下的文件将在学员评测本关任务时作为参考答案显示在查看效果页供学员参考任务输出结果为文件时请指定该路径并注意与程序文件所在文件夹分开
该路径下的文件将在学员评测本关任务时作为参考答案显示在查看效果页供学员参考任务输出结果为文件时请指定该路径并注意与程序文件所在文件夹分开
</p>
</div>
<div></div>
@ -1029,9 +1033,9 @@ export default class TPMevaluation extends Component {
value={shixunfilepicturepath}
onInput={(e)=>this.updatepath(e,"shixunfilepicturepath",2)}
onClick={(e)=>this.getfilepath(e,"shixunfilepicturepath",2)}
placeholder="请在版本库中指定用来保存学员代码实际输出结果的路径。例src/step1/outputimages"/>
placeholder="请在版本库中指定用来保存学员代码实际输出结果的路径。例src/step1/outputfiles"/>
<p className="color-grey-9 mt15">
学员评测本关任务时生成的文件将保存在该路径下并作为实际输出显示在查看效果页供学员确认任务输出结果为文件时请指定该路径并注意与程序文件所在文件夹分开
学员评测本关任务时生成的文件将保存在该路径下并作为实际输出显示在查看效果页供学员确认任务输出结果为文件时请指定该路径并注意与程序文件所在文件夹分开
</p>
</div>
<div></div>
@ -1066,16 +1070,16 @@ export default class TPMevaluation extends Component {
<p className="color-grey-9 mb20"
style={{width:'100%',height:'20px',display:scorevalue===true?'block':'none'}}
>
<span className={"headdfgf color979797"} style={{width:'500px'}} >
系统评分占比
<RadioGroup
value={markvalue}
onChange={this.onChangemarkvalue}
>
<Radio value={true}>均分比例</Radio>
<Radio value={false}>自定义比例</Radio>
</RadioGroup>
</span>
<span className={"headdfgf color979797"} style={{width:'500px'}} >
系统评分占比
<RadioGroup
value={markvalue}
onChange={this.onChangemarkvalue}
>
<Radio value={true}>均分比例</Radio>
<Radio value={false}>自定义比例</Radio>
</RadioGroup>
</span>
</p>

@ -404,11 +404,11 @@ class Infos extends Component{
{/* 众包 */}
{/* http://localhost:3007/courses/1309/homework/9300/setting */}
<Route exact path="/users/:username/package"
render={
(props) => (<InfosPackage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*<Route exact path="/users/:username/package"*/}
{/*render={*/}
{/*(props) => (<InfosPackage {...this.props} {...props} {...this.state} />)*/}
{/*}*/}
{/*></Route>*/}
{/* 课堂 */}
{/* http://localhost:3007/courses/1309/homework/9300/setting */}

@ -2,16 +2,35 @@ import React, { Component } from 'react';
import { SnackbarHOC } from 'educoder';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import {Tooltip,Menu,Pagination,Spin} from 'antd';
import Loadable from 'react-loadable';
import Loading from '../../../Loading';
import axios from 'axios';
import NoneData from '../../courses/coursesPublic/NoneData'
import {getImageUrl} from 'educoder';
import { TPMIndexHOC } from '../../tpm/TPMIndexHOC';
import { CNotificationHOC } from '../../courses/common/CNotificationHOC'
import NoneData from '../../courses/coursesPublic/NoneData'
import "./usersInfo.css"
import Create from './publicCreatNew'
import moment from 'moment';
let categorylist=[
{name:"全部",value:undefined},
{name:"前端开发",value:"front"},
{name:"后端开发",value:"backend"},
{name:"移动开发",value:"mobile"},
{name:"数据库",value:"database"},
{name:"云计算和大数据",value:"cloud_compute_and_big_data"},
{name:"人工智能",value:"ai"},
{name:"运维与测试",value:"devops_and_test"},
{name:"其他",value:"other"},
]
//
function setcategorylist(val){
let vals=""
categorylist.some((item,key)=> {
if (item.name === val) {
vals=item.value
return true
}
}
)
return vals
}
class InfosPackage extends Component{
constructor(props){
super(props);
@ -19,8 +38,8 @@ class InfosPackage extends Component{
category:undefined,
status:undefined,
page:1,
per_page:16,
per_page:20,
sort_direction:'desc',
totalCount:undefined,
data:undefined,
isSpin:false
@ -36,12 +55,14 @@ class InfosPackage extends Component{
}
getCourses=(category,status,page)=>{
let url=`/users/${this.props.match.params.username}/courses.json`;
let url=`/users/${this.props.match.params.username}/project_packages.json`;
axios.get((url),{params:{
category,
status,
page,
per_page: this.props.is_current && category && page ==1?17:16
sort_by:"published_at",
sort_direction:'desc',
per_page:20
}}).then((result)=>{
if(result){
this.setState({
@ -103,21 +124,98 @@ class InfosPackage extends Component{
} = this.state;
let is_current=this.props.is_current;
console.log(this.props.current_user&&this.props.current_user.user_identity==="学生")
// console.log(data)
return(
<div className="educontent">
<div className="educontent mb50">
<Spin size="large" spinning={isSpin}>
<div className="white-panel edu-back-white pt25 pb25 clearfix ">
<li className={category ? "" : "active"}><a href="javascript:void(0)" onClick={()=>this.changeCategory()}>全部</a></li>
<li className={category=="manage" ? "active" : ""}><a href="javascript:void(0)" onClick={()=>this.changeCategory("manage")}>{is_current ? "我":"TA"}管理的</a></li>
<li className={category=="study" ? "active" : ""}><a href="javascript:void(0)" onClick={()=>this.changeCategory("study")}>{is_current ? "我":"TA"}参与的</a></li>
<li className={category ? "" : "active"}><a onClick={()=>this.changeCategory()}>全部</a></li>
<li className={category=="manage" ? "active" : ""}><a onClick={()=>this.changeCategory("manage")}>{is_current ? "我":"TA"}管理的</a></li>
<li className={category=="bidden" ? "active" : ""}><a onClick={()=>this.changeCategory("bidden")}>{is_current ? "我":"TA"}参与的</a></li>
</div>
{
category=="manage"?
<div className="edu-back-white padding20-30 clearfix secondNav bor-top-greyE">
<li className={status ? "" : "active"}><a onClick={()=>this.changeStatus()}>全部</a></li>
<li className={status=="unpublished" ? "active" : ""}><a onClick={()=>this.changeStatus("unpublished")}>未发布</a></li>
<li className={status=="bidding" ? "active" : ""}><a onClick={()=>this.changeStatus("bidding")}>竞标中</a></li>
<li className={status=="finished" ? "active" : ""}><a onClick={()=>this.changeStatus("finished")}>已完成</a></li>
</div>: category=="bidden"?
<div className="edu-back-white padding20-30 clearfix secondNav bor-top-greyE">
<li className={status ? "" : "active"}><a onClick={()=>this.changeStatus()}>全部</a></li>
<li className={status=="bidding_lost" ? "active" : ""}><a onClick={()=>this.changeStatus("bidding_lost")}>未中标</a></li>
<li className={status=="bidding_won" ? "active" : ""}><a onClick={()=>this.changeStatus("bidding_won")}>已中标</a></li>
</div>:""
}
<p className="pl25 pr25 clearfix font-12 mb20 mt20">
<span className="fl color-grey-9">{0}</span>
<span className="fl color-grey-9">{totalCount}</span>
<span className="fr color-grey-9">发布时间</span>
</p>
{/*bidden_status: "pending"*/}
{/*category_id: 2*/}
{/*status: "published"*/}
{/*type: "bidden"*/}
{data===undefined?<NoneData></NoneData>:data.project_packages.length===0?<NoneData></NoneData>:data.project_packages.map((item,key)=>{
return(
<div className="educontent project-packages-list" key={key}>
<div className="project-package-item project-package-11">
<div className="item-image">
<img alt="图片" src={`/images/educoder/project_packages/${setcategorylist(item.category_name)}.png`} />
</div>
<div className="item-body">
<div className="item-head">
<div className="item-head-title" title={item.title}>
<a href={`/crowdsourcing/${item.id}`}>{item.title}</a>
</div>
<div className="item-head-tags">
</div>
<div className="item-head-blank"></div>
<div className="item-head-price">
{item.min_price===null?"":<span>{item.min_price}</span>}
{item.max_price===null||item.min_price===null?"":<span>~</span>}
{item.max_price===null?"":<span>{item.max_price}</span>}
{item.min_price===null&&item.max_price===null?<span>可议价</span>:""}
</div>
</div>
<div className="item-category">
<div className="item-category-item">{item.category_name}</div>
</div>
<div className="item-other">
<div className="item-group item-other-visit">
<span className="item-group-icon"><i className="fa fa-eye"></i></span>
<span className="item-group-text">{item.visit_count}人浏览</span>
</div>
<div className="item-group item-other-deadline">
<span className="item-group-icon"><i className="fa fa-clock-o"></i></span>
<span className="item-group-text">{moment(item.deadline_at).endOf('day').fromNow()}竞标截止</span>
</div>
<div className="item-group item-other-bidding">
<span className="item-group-icon"><i className="fa fa-user"></i></span>
<span className="item-group-text">{item.bidding_users_count}人竞标</span>
</div>
<div className="item-group"></div>
<div className="item-group item-other-publish-at">
发布于{item.published_at}
</div>
</div>
</div>
</div>
</div>
)})}
{
totalCount >20 &&
<div className="mt30 mb50 edu-txt-center">
<Pagination showQuickJumper total={totalCount} onChange={this.changePage} pageSize={20} current={page}/>
</div>
}
</Spin>
</div>
)

@ -3361,4 +3361,358 @@ a.singlepublishtwo{
#trophyreturn i{
font-size: 16px!important;
color: #AAAAAA;
}
/*众包*/
.packinput .ant-input{
height: 50px;
width:749px;
border-color: #E1EDF8 !important;
}
.packinput{
width:749px;
}
.packinput .ant-input-group-addon .ant-btn{
width:140px !important;
font-size: 18px;
height: 50px;
background:rgba(76,172,255,1);
}
.setissues{
width:280px;
height:50px;
background:rgba(76,172,255,1);
border-radius:4px;
margin-left: 15px;
}
.pagetype li{
color:#8F8F8F !important;
}
.maxwidth700{
max-width: 700px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mbf10{
margin-bottom:-10px;
}
.PackageIndexNEIBanner{
width:1200px;
height:110px;
background:rgba(255,255,255,1);
box-shadow:0px 2px 6px 0px rgba(125,125,125,0.26);
border-radius:8px;
}
.padding110{
padding: 39px 110px 0px;
box-sizing: border-box;
}
.borderccc{
border: 1px solid #ccc;
}
.input-100-40s{
width: 100%;
padding: 5px;
box-sizing: border-box;
}
.fafafas{
background-color: #fafafa!important;
height: 40px;
}
.fafafas:focus{
background-color: #fff!important;
}
.fafas .ant-input{
background-color: #fafafa!important;
height: 40px;
}
.fafas .ant-input:focus{
background-color: #fff!important;
}
.fafas .ant-input-group-addon .ant-btn{
width:140px !important;
font-size: 14px;
height: 40px;
background:rgba(76,172,255,1);
}
.newFormbox .upload_filename{
line-height: 32px;
}
.newFormbox .attachment span{
line-height: 23px;
}
.newFormbox .attachment .remove-upload{
line-height: 28px;
}
.pd26a0{
padding: 26px 26px 16px 26px;
}
.newFormbox .attachment .icon-fujian{
font-size: 14px !important;
line-height: 14px;
margin-top: 9px;
}
.newFormbox{
height:20px
}
.ml24{
margin-left:24px;
}
.defalutCancelbtns{
display: block;
border: 1px solid #4CACFF !important;
background-color: #fff;
color: #4CACFF !important;
width:130px;
height:40px;
text-align: center;
line-height: 40px;
border-radius: 4px;
}
.defalutSubmitbtns{
background-color: #4CACFF;
height:40px;
}
.defalutSubmitbtnmodels{
width:127px;
height:30px;
background-color: #4CACFF;
}
.ant-steps-item-process .ant-steps-item-icon{
background-color: #4CACFF !important;
}
.ant-steps-item-process .ant-steps-item-icon{
background-color: #4CACFF !important;
}
.padding200{
padding: 115px 200px 215px 200px;
}
.fontcircle{
font-size: 80px;
display: inherit;
}
.sumbtongs{
font-size: 24px;
display: inherit;
text-align: center;
}
.terraces{
font-size: 16px;
display: inherit;
text-align: center;
color:#999;
}
.padding251{
padding: 0px 245px;
}
.ant-modal-title{
text-align: center;
}
.ml17{
margin-left: 17px;
}
.project-package-items{
display: -webkit-flex;
display: flex;
flex-direction: row;
margin:0px !important;
padding: 20px;
background: white;
margin-bottom:0px !important;
box-shadow: none !important;
}
.mtf7{
margin-top:-7px;
}
.publicpart.orangeGreen {
border-left: 80px solid #29BD8B;
}
.publicwords{
left: 3px;
top: 18px;
}
.project-packages-list .project-package-items .item-image{
width:100px !important;
}
.height185{
height: 185px;
}
.ContacttheTA{
width: 80px;
height: 26px;
font-size: 14px;
line-height: 26px;
display: block;
border: 1px solid #4CACFF !important;
background-color: #fff;
color: #4CACFF !important;
text-align: center;
border-radius: 4px;
}
.ContacttheTAs{
width: 80px;
height: 26px;
font-size: 14px;
line-height: 24px;
/*display: block;*/
border: 1px solid #fff !important;
background-color: #4CACFF;
color: #fff !important;
text-align: center;
border-radius: 4px;
}
.ml28{
margin-left: 28px;
}
.longboxs{
font-size: 16px;
font-family: MicrosoftYaHei-Bold;
font-weight: bold;
color: rgba(5,16,26,1);
border-left: 4px solid rgba(76,172,255,1);
padding-left: 10px;
margin-bottom: 20px;
}
.padding020{
padding: 0px 20px 20px;
}
.mtf3{
margin-top:-3px;
}
.task-btn-nebules{
background: #fff!important;
color: #4CACFF!important;
border: 1px solid #4CACFF!important;
margin-left: 20px;
cursor: pointer;
display: inline-block;
padding: 0 12px;
letter-spacing: 1px;
text-align: center;
font-size: 14px;
height: 30px;
line-height: 30px;
border-radius: 2px;
}
.packageabsolute{
position: absolute;
right: -16px;
top: -7px;
}
.relativef{
position: relative;
}
.homehove:hover .ptext{
color: #4CACFF!important;
}
.homehove:hover .ContacttheTAs{
display: block;
}
.topsj{
position: absolute;
top: -6px;
}
.bottomsj{
position: absolute;
bottom: -6px;
}
.touchSelect .ant-spin-dot-spin{
margin-top: 30% !important;
}
.pagenoedits{
margin-left: 20px;
color: #ccc;
}
.pagemancenter{
text-align: center;
}
.ml0{
margin-left: 0px;
}
.tabelcli{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 850px;
display: table-cell;
}
.mtf10{
margin-top:-10px;
}
.padding26{
padding: 26px;
box-sizing: border-box;
}
.pd26{
padding: 26px;
}
.pd30a0{
padding: 30px 30px 16px 30px;
}
.shaiContent li.shaiItem:hover span{
color: #fff !important;
}
.shaiContent li.shaiItem:hover i.iconfont{
color: #4CACFF!important
}
.detail_for_paragraph p{
white-space: pre-wrap;
}

@ -1,5 +0,0 @@
require 'rails_helper'
RSpec.describe ForumsController, type: :controller do
end

@ -1,15 +0,0 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the ForumsHelper. For example:
#
# describe ForumsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe ForumsHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end
Loading…
Cancel
Save