project package feature

project_pack
p31729568 5 years ago
parent 4b4a0d52e6
commit 4d9ccfc528

@ -166,6 +166,21 @@ module Mobile
return user if user
nil
end
def paginate(objs)
page = params[:page].to_i <= 0 ? 1 : params[:page].to_i
per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 20
Kaminari.paginate_array(objs).page(page).per(per_page)
end
def render_ok(data = {})
{ status: 0, message: 'success' }.merge(data)
end
def render_error(message)
{ status: -1, message: message }
end
end
mount Apis::Auth
@ -197,7 +212,7 @@ module Mobile
mount Apis::Ecloud
mount Apis::Cnmooc
mount Apis::ProjectPackages
# add_swagger_documentation ({host: 'educoder.0bug.info', api_version: 'v1', base_path: '/api'}) if Rails.env.development?
add_swagger_documentation ({api_version: 'v1', base_path: '/api'}) if Rails.env.development?

@ -0,0 +1,144 @@
module Mobile
module Apis
class ProjectPackages < Grape::API
helpers do
def current_package
@_current_package ||= ProjectPackage.find(params[:id])
end
def symbolize_params
params.to_hash.symbolize_keys
end
end
resources :project_packages do
desc 'project packages index'
params do
optional :category, type: String, desc: '类型'
optional :keyword, type: String, desc: '搜索关键字'
optional :sort_by, type: String, desc: '排序'
optional :page, type: Integer, desc: '页数'
optional :per_page, type: Integer, desc: '分页大小'
end
get do
packages = ProjectPackage.where(status: %w(published bidding_ended bidding_finished))
packages = packages.where(category: params[:category]) if params[:category].present?
keyword = params[:keyword].to_s.strip
packages = packages.where('title LIKE ?', "%#{keyword}%") if keyword.present?
count = packages.count
if params[:sort_by] == 'price'
packages = packages.order('min_price desc')
else
packages = packages.order('published_at desc')
end
packages = paginate packages.includes(:creator, :attachments, bidding_users: :user)
present :count, count
present :project_packages, packages, with: Mobile::Entities::ProjectPackage, type: :index, user: current_user
end
desc 'project package show'
params do
requires :id, type: Integer, desc: 'ID'
end
route_param :id do
get do
authenticate!
present current_package, with: Mobile::Entities::ProjectPackage, type: :show, user: current_user
end
resource :bidding_users do
desc 'user bidding'
params {}
post do
authenticate!
begin
::ProjectPackages::BiddingService.new(current_package, current_user).call
render_ok
rescue ::ProjectPackages::BiddingService::Error => ex
render_error(ex.message)
end
end
desc 'select bidding user win'
params do
requires :user_ids, type: Array[Integer], desc: '中标者用户ID数组'
end
post 'win' do
authenticate!
begin
package = current_user.project_packages.find(params[:id])
ProjectPackages::WinBiddingService.new(package, symbolize_params).call
rescue ProjectPackages::WinBiddingService::Error =>ex
render_error(ex.message)
end
end
end
end
desc 'create project packages'
params do
requires :category, type: String, desc: '类型'
requires :title, type: String, desc: '标题'
requires :content, type: String, desc: '描述'
optional :attachment_ids, type: Array[Integer], desc: '附件ID数组'
requires :deadline_at, type: DateTime, desc: '截止日期'
requires :min_price, type: Float, desc: '最小费用'
optional :max_price, type: Float, desc: '最大费用'
requires :contact_name, type: String, desc: '联系人姓名'
requires :contact_phone, type: String, desc: '联系人手机号'
optional :code, type: String, desc: '验证码'
optional :publish, type: Boolean, desc: '是否申请发布'
end
post do
authenticate!
begin
package = current_user.project_packages.new
::ProjectPackages::SaveService.new(package, symbolize_params).call
package.increment_visit_count!
render_ok
rescue ::ProjectPackages::SaveService::Error => ex
render_error(ex.message)
end
end
desc 'update project package'
params do
requires :id, type: Integer, desc: 'ID'
requires :category, type: String, desc: '类型'
requires :title, type: String, desc: '标题'
requires :content, type: String, desc: '描述'
optional :attachment_ids, type: Array[Integer], desc: '附件ID数组'
requires :deadline_at, type: DateTime, desc: '截止日期'
requires :min_price, type: Float, desc: '最小费用'
optional :max_price, type: Float, desc: '最大费用'
requires :contact_name, type: String, desc: '联系人姓名'
requires :contact_phone, type: String, desc: '联系人手机号'
optional :code, type: String, desc: '验证码'
optional :publish, type: Boolean, desc: '是否申请发布'
end
put ':id' do
authenticate!
begin
package = current_user.project_packages.find(params[:id])
return render_error('该状态下不能编辑') unless package.editable?
::ProjectPackages::SaveService.new(package, symbolize_params).call
package.increment_visit_count!
render_ok
rescue ::ProjectPackages::SaveService::Error => ex
render_error(ex.message)
end
end
end
end
end
end

@ -0,0 +1,65 @@
module Mobile
module Entities
class ProjectPackage < Grape::Entity
include ApplicationHelper
include ActionView::Helpers::NumberHelper
expose :id
expose :title
expose :category
expose :status
expose :visit_count, if: { type: :index }
expose :bidding_users_count, if: { type: :index }
expose :min_price
expose :max_price
expose :deadline_at do |package, _|
package.deadline_at.try(:utc).try(:iso8601)
end
expose :published_at do |package, _|
package.published_at.try(:utc).try(:iso8601)
end
expose :can_bidding, if: { type: :show } do |package, opts|
package.can_bidding?(opts[:user])
end
expose :can_select_bidding_user, if: { type: :show } do |package, opts|
opts[:user].id == package.creator_id && !package.bidding_end?
end
expose :creator, if: { type: :show } do |package, _|
{
id: package.creator.id,
login: package.creator.login,
name: package.creator.show_real_name,
avatar_url: "/images/#{url_to_avatar(package.creator)}"
}
end
expose :attachments, if: { type: :show } do |package, _|
package.attachments.map do |attachment|
{
id: attachment.id,
title: attachment.title,
filesize: number_to_human_size(attachment.filesize),
url: "attachments/download/#{attachment.id}",
}
end
end
expose :bidding_users, if: { type: :show } do |package, _|
package.bidding_users.map do |bidding_user|
user = bidding_user.user
{
id: user.id,
login: user.login,
name: user.name,
avatar_url: "/images/#{url_to_avatar(user)}",
status: bidding_user.status
}
end
end
end
end
end

@ -681,7 +681,7 @@ class AccountController < ApplicationController
render :json => req
end
# 发送验证码type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码
# 发送验证码type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码 9验证手机号有效
# 验证码是否有效
def valid_verification_code
req = Hash.new(false)
@ -700,7 +700,7 @@ class AccountController < ApplicationController
render :json => req
end
# 发送验证码type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码
# 发送验证码type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码 9验证手机号有效
def get_verification_code
code = %W(0 1 2 3 4 5 6 7 8 9)
type = params[:type].to_i
@ -787,6 +787,22 @@ class AccountController < ApplicationController
else
req[:status] = 2
end
elsif params[:type] == 9
if params[:value] =~ /^1\d{10}$/
begin
verification_code = code.sample(6).join
status = Trustie::Sms.send(mobile: params[:value], code: verification_code)
if status == 0
VerificationCode.create(:phone => params[:value], :status => 1, :code_type => type, :code => verification_code)
end
req[:msg] = code_msg status
rescue => e
Rails.logger.error "发送验证码出错: #{e}"
end
req[:status] = 1
else
req[:status] = 2
end
else
if params[:value] =~ /^[a-zA-Z0-9]+([._\\]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/
if User.where(:mail => params[:value]).count > 0

@ -0,0 +1,46 @@
class Managements::ProjectPackageAppliesController < Managements::BaseController
before_filter :set_menu_type
def index
applies = ProjectPackageApply.order('project_package_applies.updated_at desc')
search = params[:search].to_s.strip
if search.present?
applies = applies.joins(:project_package).where('project_packages.title like :search', search: "%#{search}%")
end
applies = applies.where(status: params[:status].presence || :pending)
@applies = paginateHelper applies.includes(project_package: { creator: :user_extensions })
respond_to do |format|
format.js
format.html
end
end
def agree
ProjectPackages::AgreeApplyService.new(current_apply).call
render json: { status: 0 }
rescue ProjectPackages::AgreeApplyService::Error => e
render json: { status: -1, message: e.message }
end
def refuse
ProjectPackages::RefuseApplyService.new(current_apply, reason: params[:reason]).call
render json: { status: 0 }
rescue ProjectPackages::RefuseApplyService::Error => e
render json: { status: -1, message: e.message }
end
private
def current_apply
@_current_apply ||= ProjectPackageApply.find(params[:id])
end
def set_menu_type
@menu_type = 10
@sub_type = 9
end
end

@ -754,6 +754,7 @@ module ApplicationHelper
when 6 then '实训课程发布'
when 7 then '职业认证'
when 8 then '教学案例发布'
when 9 then '众包需求发布'
else '职业认证'
end
when 11
@ -7453,6 +7454,8 @@ def tiding_url tiding
my_account_path
when 'Library'
tiding.tiding_type == 'Apply' ? library_applies_path : library_path(tiding.container_id)
when 'ProjectPackage'
tiding.container.present? ? "/project_packages/#{tiding.container_id}" : 'javascript:void(0)'
end
end

@ -0,0 +1,20 @@
class BiddingUser < ActiveRecord::Base
include AASM
belongs_to :user
belongs_to :project_package, counter_cache: true
aasm(:status) do
state :pending, initiali: true
state :bidding_won
state :bidding_lost
event :win do
transitions from: [:pending], to: :bid_won
end
event :lose do
transitions from: [:pending], to: :bid_lost
end
end
end

@ -0,0 +1,76 @@
class ProjectPackage < ActiveRecord::Base
include AASM
acts_as_attachable
CATEGORY_VALUES = %w(front backend mobile database cloud_compute_and_big_data devops_and_test ai other)
attr_accessible :title, :content, :category, :deadline_at, :contact_name, :contact_phone, :min_price, :max_price
belongs_to :creator, class_name: 'User'
has_many :project_package_applies, dependent: :destroy
has_one :process_project_package_apply, conditions: { status: :pending }, class_name: 'ProjectPackageApply'
has_many :bidding_users, dependent: :delete_all
has_many :win_bidding_users, conditions: { status: :bidding_won }, class_name: 'BiddingUser'
has_many :lose_bidding_users, conditions: { status: :bidding_lost }, class_name: 'BiddingUser'
has_many :attachments, as: :container, dependent: :destroy
validates :category, presence: true, inclusion: { in: CATEGORY_VALUES }
validates :title, presence: true, length: { maximum: 60 }
validates :content, presence: true
validates :deadline_at, presence: true
validates :contact_name, presence: true, length: { maximum: 20 }
validates :contact_phone, presence: true, format: { with: /1\d{10}/ }
validates :min_price, numericality: { greater_than: 0 }
validates :max_price, numericality: { greater_than: ->(obj){ obj.min_price } }, allow_blank: true
aasm(:status) do
state :pending, initiali: true
state :applying
state :refused
state :published
state :bidding_ended
state :bidding_finished
event :apply do
transitions from: [:pending, :refused], to: :applying
end
event :refuse do
transitions from: :applying, to: :refused
end
event :publish do
transitions from: :applying, to: :published
end
event :end_bidding do
transitions from: :published, to: :bidding_ended
end
event :finish_bidding do
transitions from: [:bidding_ended], to: :bidding_finished
end
end
def editable?
pending? || applying? || refused?
end
def bidding_end?
flag = deadline_at < Time.now
end_bidding! if flag && can_end_bidding?
flag
end
def can_bidding?(user)
published? && !bidding_end? && !bidding_users.exists?(user_id: user.id)
end
def increment_visit_count!
ProjectPackage.connection.execute("update project_packages set visit_count = COALESCE(visit_count, 0) + 1 where id = #{id}")
end
end

@ -0,0 +1,21 @@
class ProjectPackageApply < ActiveRecord::Base
include AASM
attr_accessible :project_package_id, :reason
belongs_to :project_package
aasm(:status) do
state :pending, initiali: true
state :refused
state :agreed
event :refuse do
transitions from: :pending, to: :refused
end
event :agree do
transitions from: :pending, to: :agreed
end
end
end

@ -365,6 +365,27 @@ class Tiding < ActiveRecord::Base
elsif tiding_type == 'System'
text = status == 1 ? "审核已通过" : "审核未通过,<br/>原因:#{extra}"
"你提交的发布教学案例申请:#{library.try(:title)}#{text}"
end
when 'ProjectPackage'
package = ProjectPackage.find_by_id(container_id)
case tiding_type
when 'Apply' then
"申请发布众包需求:#{package.try(:title)}"
when 'System' then
text = status == 1 ? "审核已通过" : "审核未通过,<br/>原因:#{extra}"
"你提交的众包需求申请:#{package.try(:title)}#{text}"
when 'Created' then
"你创建了众包需求:#{package.try(:title)}"
when 'Destroyed' then
"你删除了众包需求:#{extra}"
when 'Bidding' then
"应征了你发布的众包任务:#{package.try(:title)}"
when 'BiddingEnd' then
"你发布的众包任务:#{package.try(:title)},已进入选标阶段,请尽快进行选择确认!"
when 'BiddingWon' then
"恭喜,你应征的众包任务:#{package.try(:title)},在评选环节中标了"
when 'BiddingLost' then
"很遗憾,你应征投稿的众包任务:#{package.try(:title)},未中标"
end
else
logger.error "error type: 1"

@ -274,6 +274,9 @@ class User < Principal
has_one :user_source
# 众包
has_many :project_packages, foreign_key: :creator_id, dependent: :destroy
## end
# default_scope -> { includes(:user_extensions, :user_score) }

@ -2,4 +2,8 @@ class VerificationCode < ActiveRecord::Base
#status发送状态
#code_type发送类型type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码
attr_accessible :code, :code_type, :email, :phone, :status
def valid_code?
(Time.now.to_i - created_at.to_i) <= 10*60
end
end

@ -0,0 +1,36 @@
class ProjectPackages::AgreeApplyService
Error = Class.new(StandardError)
attr_reader :apply, :package
def initialize(apply)
@apply = apply
@package = apply.project_package
end
def call
raise Error, '该状态下不能进行此操作' unless apply.may_agree? && package.may_publish?
ActiveRecord::Base.transaction do
apply.agree!
# 发布
package.publish
package.published_at = Time.now
package.save!
# 消息
send_agree_notify!
end
end
private
def send_agree_notify!
Tiding.where(container_id: package.id, container_type: 'ProjectPackage',
tiding_type: 'Apply', status: 0).update_all(status: 1)
Tiding.create!(user_id: package.creator_id, trigger_user_id: 1,
container_id: package.id, container_type: 'ProjectPackage',
tiding_type: 'System', status: 1)
end
end

@ -0,0 +1,31 @@
class ProjectPackages::ApplyPublishService
Error = Class.new(StandardError)
attr_reader :package
def initialize(package)
@package = package
end
def call
return if package.applying?
raise Error, '该状态下不能申请发布' if package.can_apply?
ActiveRecord::Base.transaction do
package.apply!
package.project_package_applies.create!
send_project_package_apply_notify!
end
end
private
def send_project_package_apply_notify!
Tiding.create!(user_id: 1, trigger_user_id: package.creator_id,
container_id: package.id, container_type: 'ProjectPackage',
tiding_type: 'Apply', status: 0)
end
end

@ -0,0 +1,29 @@
class ProjectPackages::BiddingService
Error = Class.new(StandardError)
attr_reader :package, :user
def initialize(package, user)
@package = package
@user = user
end
def call
raise Error, '竞标已截止' if package.bidding_end?
raise Error, '不能参与自己发布的竞标' if package.creator_id == user.id
raise Error, '您已参与竞标' if package.bidding_users.exists?(user_id: user.id)
ActiveRecord::Base.transaction do
package.bidding_users.create!(user_id: user.id)
send_bidding_notify!
end
end
private
def send_bidding_notify!
Tiding.create!(user_id: package.creator_id, trigger_user_id: user.id,
container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'Bidding')
end
end

@ -0,0 +1,26 @@
class ProjectPackages::EndBiddingService
attr_reader :package
def initialize(package)
@package = package
end
def call
return unless package_deadline?
package.end_bidding!
send_bidding_end_notify!
end
private
def send_bidding_end_notify!
Tiding.create!(user_id: package.creator_id, trigger_user_id: 1,
container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'BiddingEnd')
end
def package_deadline?
package.deadline_at < Time.now
end
end

@ -0,0 +1,38 @@
class ProjectPackages::RefuseApplyService
Error = Class.new(StandardError)
attr_reader :apply, :package, :params
def initialize(apply, params)
@apply = apply
@package = apply.project_package
@params = params
end
def call
raise Error, '该状态下不能进行此操作' unless apply.may_refuse? && package.may_refuse?
ActiveRecord::Base.transaction do
apply.refuse
apply.reason = params[:reason].to_s.strip
apply.save!
# 发布
package.refuse!
# 消息
send_refuse_notify!
end
end
private
def send_refuse_notify!
Tiding.where(container_id: package.id, container_type: 'ProjectPackage',
tiding_type: 'Apply', status: 0).update_all(status: 1)
Tiding.create!(user_id: package.creator_id, trigger_user_id: 1,
container_id: package.id, container_type: 'ProjectPackage',
tiding_type: 'System', status: 2, extra: apply.reason)
end
end

@ -0,0 +1,66 @@
class ProjectPackages::SaveService
Error = Class.new(StandardError)
attr_reader :package, :params
def initialize(package, params)
@package = package
@params = params
end
def call
check_code_valid! if need_check_code?
is_create = package.new_record?
ActiveRecord::Base.transaction do
package.assign_attributes(params)
package.save!
# 处理附件
deal_attachments
send_create_notify! if is_create
ProjectPackages::ApplyPublishService.call(package) if with_publish?
end
package
rescue ProjectPackages::ApplyPublishService::Error => ex
raise Error, ex.message
end
private
def need_check_code?
(package.new_record? && params[:contact_phone] != package.creator.phone) || package.contact_phone != params[:contact_phone]
end
def check_code_valid!
raise Error, '验证码不能为空' if params[:code].blank?
code = VerificationCode.where(phone: params[:contact_phone], code_type: 9, code: params[:code]).last
raise Error, '无效的验证码' if code.blank? || !code.valid_code?
end
def deal_attachments
attachment_ids = Array.wrap(params[:attachment_ids]).compact.map(&:to_i) || []
old_attachment_ids = package.attachments.pluck(:id)
destroy_ids = old_attachment_ids - attachment_ids
package.attachments.where(id: destroy_ids).delete_all
new_ids = attachment_ids - old_attachment_ids
Attachment.where(id: new_ids).update_all(container_type: package.id, container_type: 'ProjectPackage') if new_ids.present?
end
def send_create_notify!
Tiding.create!(user_id: package.creator_id, trigger_user_id: 1,
container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'Created')
end
def with_publish?
params[:publish].to_s == 'true'
end
end

@ -0,0 +1,47 @@
class ProjectPackages::WinBiddingService
Error = Class.new(StandardError)
attr_reader :package, :params
def initialize(package, params)
@package = package
@params = params
end
def call
raise Error, '竞标报名还未结束' unless package.bidding_end?
raise Error, '该状态下不能选择中标者' unless package.can_finish_bidding?
win_user_ids = Array.wrap(params[:user_ids]).compact.map(&:to_i)
bidding_user_ids = package.bidding_users.pluck(:user_id)
win_user_ids = bidding_user_ids & win_user_ids
raise Error, '请选择中标者' if win_user_ids.blank?
ActiveRecord::Base.transaction do
package.finish_bidding!
# win bidding users
package.bidding_users.where(user_id: win_user_ids).update_all(status: :bidding_won)
# lose bidding users
lost_user_ids = bidding_user_ids - win_user_ids
package.bidding_users.where(user_id: lost_user_ids).update_all(status: :bidding_lost)
send_bidding_result_notify!('BiddingWon', win_user_ids)
send_bidding_result_notify!('BiddingLost', lost_user_ids)
end
package
end
private
def send_bidding_result_notify!(type, user_ids)
sql = 'insert into tidings(user_id, trigger_user_id, container_id, container_type, tiding_type) values'
base_opts = [package.creator_id, package.id, 'ProjectPackage', type]
values = '(' + user_ids.map { |id| base_opts.clone.unshift(id).join(',') }.join('),(') + ')'
sql + values
end
end

@ -117,6 +117,7 @@
<li><%= link_to '实训发布', shixun_authorization_managements_path %></li>
<li><%= link_to '实践课程发布', subject_authorization_managements_path %></li>
<li><%= link_to '教学案例发布', library_applies_path(status: :pending) %></li>
<li><%= link_to '众包需求发布', project_package_applies_path(status: :pending) %></li>
</ul>
</li>
<li class="fl edu-admin-nav-li edu-position"><a href="javascript:void(0);" class="edu-admin-nav-a">认证+</a>

@ -0,0 +1,76 @@
<% if @applies.present? %>
<% @applies.each do |apply| %>
<% user = apply.project_package.user %>
<% project_package = apply.project_package %>
<div class="admin-con-box apply-<%= apply.id %> clearfix">
<a href="<%= user_path(user) %>" target="_blank" class="fl with10 edu-ad-user">
<%= image_tag(url_to_avatar(user), :class => "fl with10 edu-ad-user", :alt => "头像", :width => "50", :height => "50" ) %>
</a>
<div class="fl with90">
<ul>
<li class="clearfix mb5">
<a href="<%= user_path(user) %>" class="fl"><%= user.try(:show_real_name) %></a>
<span class="fl ml30 font-12 mt3 color-grey"><%= time_from_now(apply.created_at) %></span>
<% if apply.pending? %>
<a href="javascript:void(0);" class="fr color-orange" onclick="reject_project_package_authentication_reason(this);" >拒绝</a>
<a href="javascript:void(0);" class="fr mr15 color-orange" data-remote="true" onclick="project_package_authorization_gree('<%= apply.id %>');">同意</a>
<% else %>
<a href="javascript:void(0);" class="<%= apply.agreed? ? 'task-btn-green' : '' %> task-btn fr"><%= apply.agreed? ? "已同意" : "已拒绝" %></a>
<% end %>
</li>
<li class="clearfix mb10">
<%= link_to project_package.title, project_package_path(project_package), :target => "_blank" %>
</li>
<% if apply.pending? %>
<div class="undis">
<li class="clearfix edu-form-border mb10">
<label class="edu-form-label fl">原因:</label>
<input type="text" class="task-form-90 task-height-40 panel-box-sizing fl edu-form-noborder" placeholder="我得说点儿什么最多200个字符">
</li>
<li class="clearfix">
<a href="javascript:void(0);" class="task-btn task-btn-orange fr" onclick="project_package_submit_reject_reason('<%= apply.id %>', this);" >确定</a>
<a href="javascript:void(0);" class="task-btn fr mr10" onclick="project_package_hide_reject_reason(this);" >取消</a>
</li>
</div>
<% else %>
<% if apply.refused? %>
<li>原因:<span class="color-orange"><%= apply.reason %></span></li>
<% end %>
<% end %>
</ul>
</div>
</div>
<% end %>
<div class="mt20 mb20" style="text-align:center;">
<div class="pages_user_show" style="width:auto; display:inline-block;">
<ul id="homework_pository_ref_pages">
<%= pagination_links_full @obj_pages, @obj_count, :per_page_links => false, :remote => true, :flag => true, :is_new => true %>
</ul>
<div class="cl"></div>
</div>
</div>
<% else %>
<%= render :partial => "welcome/no_data" %>
<% end %>
<script type="text/javascript">
function project_package_authorization_gree(id){
$.ajax({
url: '/managements/project_package_applies/' + id + '/agree',
type: 'post',
success: function(data){
if (data && data.status != -1) {
$('#authentication_list .admin-con-box.apply-' + id).remove();
if($('#authentication_list .admin-con-box').length == 0){
location.reload();
}
} else {
alert(data.message);
}
}
})
}
</script>

@ -0,0 +1,120 @@
<div class="edu-class-container mb15">
<div class="edu-con-top clearfix">
<p class="ml15 fl color-grey">众包需求发布</p>
</div>
<div class="edu-con-bg01 mt15">
<div class="edu-tab clearfix mb20">
<ul id="edu-tab-nav" class="border-bottom-orange">
<li id="edu-tab-nav-1" class="new-tab-nav background-orange" onclick="HoverLi(1);">
<%= link_to "待审批", project_package_applies_path(status: :pending), class: 'tab_type', remote: true %>
</li>
<li id="edu-tab-nav-2" class="new-tab-nav" onclick="HoverLi(2);">
<%= link_to "已审批", project_package_applies_path(status: [:refused, :agreed]), class: 'tab_type', remote: true %>
</li>
</ul>
<div class="cl"></div>
<div id="edu-tab-con-1">
<div class="mt10">
<div class="edu-position fr task-form-30 mb10 mr15">
<input class="task-form-100 panel-box-sizing" placeholder="输入众包需求标题进行检索" type="text" id="search_name">
<a href="javascript:void(0);" class="edu-btn-search font-16 color-grey mt10" id="search"><i class="fa fa-search"></i></a>
</div>
<div class="cl"></div>
<div id="authentication_list" class="auth_table">
<%= render :partial => "managements/project_package_applies/project_package_apply_list"%>
</div>
</div>
</div>
<div id="edu-tab-con-2" class="undis">
<div class="mt10">
<p class="fl task-form-60 mt8 ml15 clearfix">
<%= link_to "全部", project_package_applies_path(status: [:refused, :agreed]), :class => "edu-filter-cir-grey mr5 fl font-12 active", :id => "project_package_all_authentication", :remote => true %>
<%= link_to "同意", project_package_applies_path(status: :agreed), :class => "edu-filter-cir-grey mr5 fl font-12", :id => "project_package_agree_authentication", :remote => true %>
<%= link_to "拒绝", project_package_applies_path(status: :refused), :class => "edu-filter-cir-grey mr5 fl font-12", :id => "project_package_reject_authentication", :remote => true %>
</p>
<div class="edu-position fr task-form-30 mb10 fr mr15">
<input class="task-form-100 panel-box-sizing" placeholder="输入教学案例标题、编号进行检索" type="text" id="project_package_search_name">
<a href="javascript:void(0);" class="edu-btn-search font-16 color-grey mt10" id="project_package_search"><i class="fa fa-search"></i></a>
</div>
<div class="cl"></div>
<div id="project_package_authentication_list" class="auth_table">
</div>
</div>
</div>
<div class="cl"></div>
</div>
</div>
</div>
<script>
/* -------------------------- 拒绝 ------------------------------------ */
function reject_project_package_authentication_reason(nThis){
var reason = $(nThis).parent().parent().find('div');
reason.find("input").val("");
reason.toggle();
}
/* -------------------------- 取消 ------------------------------------ */
function project_package_hide_reject_reason(nThis){
var reason = $(nThis).parent().parent();
reason.find("input").val("");
reason.hide();
}
/* ------------------------- 提交拒绝原因 --------------------------------- */
function project_package_submit_reject_reason(id, nThis){
var nReason = $(nThis).parent().parent();
var reason = nReason.find("input").val();
if (reason == '') {
alert('请输入原因');
return;
}
$.ajax({
url: '/managements/project_package_applies/' + id + '/refuse',
type: 'post',
data: {reason: reason},
success: function(data){
if (data && data.status != -1) {
$('#authentication_list .admin-con-box.apply-' + id).remove();
if($('#authentication_list .admin-con-box').length == 0){
location.reload();
}
} else {
alert(data.message);
}
}
});
}
/* -------------------------- 按名字进行搜索(未审批) ----------------------------- */
$("#search").live("click", function(){
var iName = $("#search_name").val();
$.ajax({
url: "/managements/project_package_applies",
dataType: 'script',
data: { search: iName, status: 'pending' }
});
});
/* ------------------- 按名字进行搜索(已审批)-------------------- */
$("#project_package_search").live("click", function(){
var iName = $("#project_package_search_name").val();
var id = $("#project_package_all_authentication").parent().find(".active").attr("id");
var status = '';
if(id == "project_package_all_authentication"){
status = ['refused', 'agreed'];
}else if(id=="project_package_agree_authentication"){
status = 'agreed';
}else{
status = 'refused';
}
$.ajax({
url: "/managements/project_package_applies",
dataType: 'script',
data: { search: iName, status: status}
});
});
</script>

@ -0,0 +1,30 @@
var nTabIcon_1 = $("#edu-tab-con-1");
var nTabIcon_2 = $("#edu-tab-con-2");
var nTabNav_1 = $("#edu-tab-nav-1");
var nTabNav_2 = $("#edu-tab-nav-2");
var nAudit = $("#project_package_all_authentication").parent();
<% if params[:status].to_s == 'pending' %>
$("#authentication_list").html("<%= j( render :partial => "managements/project_package_applies/project_package_apply_list" ) %>");
nTabNav_1.addClass("background-orange");
nTabNav_2.removeClass("background-orange");
nTabIcon_1.show();
nTabIcon_2.hide();
<% else %>
$("#project_package_authentication_list").html("<%= j( render :partial => "managements/project_package_applies/project_package_apply_list" ) %>");
nTabNav_1.removeClass("background-orange");
nTabNav_2.addClass("background-orange");
nTabIcon_1.hide();
nTabIcon_2.show();
/* -------------------------- 未审批(全部、同意、拒绝点击时动态样式) ------------------------------ */
if(<%= params[:status].to_s == 'agreed' %>){
nAudit.find(".active").removeClass("active");
$("#project_package_agree_authentication").addClass("active");
}else if(<%= params[:status].to_s == 'refused' %>){
nAudit.find(".active").removeClass("active");
$("#project_package_reject_authentication").addClass("active");
}else{
nAudit.find(".active").removeClass("active");
$("#project_package_all_authentication").addClass("active");
}
<% end %>

@ -744,6 +744,13 @@ RedmineApp::Application.routes.draw do ## oauth相关
post :refuse
end
end
resources :project_package_applies, only: [:index] do
member do
post :agree
post :refuse
end
end
end
end
end

@ -0,0 +1,28 @@
class CreateProjectPackages < ActiveRecord::Migration
def change
create_table :project_packages do |t|
t.references :creator
t.string :category
t.string :status
t.string :title
t.text :content
t.string :contact_name
t.string :contact_phone
t.decimal :min_price
t.decimal :max_price
t.integer :visit_count, default: 0
t.integer :bidding_users_count, default: 0
t.datetime :deadline_at
t.datetime :published_at
t.datetime :bidding_finished_at
t.timestamps
end
add_index :project_packages, :published_at
end
end

@ -0,0 +1,12 @@
class CreateBiddingUsers < ActiveRecord::Migration
def change
create_table :bidding_users do |t|
t.references :project_package
t.references :user
t.string :status
t.timestamps
end
end
end

@ -0,0 +1,14 @@
class CreateProjectPackageApplies < ActiveRecord::Migration
def change
create_table :project_package_applies do |t|
t.references :project_package
t.string :status
t.string :reason
t.datetime :refused_at
t.timestamps
end
end
end
Loading…
Cancel
Save