Merge branch 'master' of https://bdgit.educoder.net/Hjqreturn/educoder
commit
bde518aaef
@ -0,0 +1,24 @@
|
|||||||
|
class BiddingUsersController < ApplicationController
|
||||||
|
before_action :require_login, :check_auth
|
||||||
|
|
||||||
|
def create
|
||||||
|
ProjectPackages::BiddingService.call(current_package, current_user)
|
||||||
|
render_ok
|
||||||
|
rescue ProjectPackages::BiddingService::Error => ex
|
||||||
|
render_error(ex.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def win
|
||||||
|
package = current_user.project_packages.find(params[:project_package_id])
|
||||||
|
ProjectPackages::WinBiddingService.call(package, params)
|
||||||
|
render_ok
|
||||||
|
rescue ProjectPackages::WinBiddingService::Error => ex
|
||||||
|
render_error(ex.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_package
|
||||||
|
@_current_package ||= ProjectPackage.find(params[:project_package_id])
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,6 @@
|
|||||||
|
class ProjectPackageCategoriesController < ApplicationController
|
||||||
|
def index
|
||||||
|
categories = ProjectPackageCategory.cached_data
|
||||||
|
render_ok(count: categories.size, categories: categories)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,78 @@
|
|||||||
|
class ProjectPackagesController < ApplicationController
|
||||||
|
include PaginateHelper
|
||||||
|
|
||||||
|
before_action :require_login, :check_auth, only: %i[create update destroy]
|
||||||
|
|
||||||
|
helper_method :current_package, :package_manageable?
|
||||||
|
|
||||||
|
def index
|
||||||
|
packages = ProjectPackage.where(status: %w(published bidding_ended bidding_finished))
|
||||||
|
|
||||||
|
packages = packages.where(project_package_category_id: params[:category_id]) if params[:category_id].present?
|
||||||
|
|
||||||
|
keyword = params[:keyword].to_s.strip
|
||||||
|
packages = packages.where('title LIKE ?', "%#{keyword}%") if keyword.present?
|
||||||
|
|
||||||
|
@count = packages.count
|
||||||
|
|
||||||
|
direction = params[:sort_direction] == 'asc' ? 'asc' : 'desc'
|
||||||
|
sort = params[:sort_by] == 'price' ? 'min_price' : 'published_at'
|
||||||
|
packages = packages.order("#{sort} #{direction}")
|
||||||
|
|
||||||
|
@packages = paginate packages.includes(:creator, :attachments, :project_package_category, bidding_users: :user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
return render_forbidden unless current_package.visitable? || package_manageable?
|
||||||
|
|
||||||
|
current_package.increment!(:visit_count)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
package = current_user.project_packages.new
|
||||||
|
ProjectPackages::SaveService.call(package, save_params)
|
||||||
|
|
||||||
|
package.increment!(:visit_count)
|
||||||
|
render_ok(id: package.id)
|
||||||
|
rescue ProjectPackages::SaveService::Error => ex
|
||||||
|
render_error(ex.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
package = current_user.project_packages.find(params[:id])
|
||||||
|
return render_error('该状态下不能编辑') unless package.editable?
|
||||||
|
|
||||||
|
ProjectPackages::SaveService.call(package, save_params)
|
||||||
|
package.increment!(:visit_count)
|
||||||
|
render_ok(id: package.id)
|
||||||
|
rescue ProjectPackages::SaveService::Error => ex
|
||||||
|
render_error(ex.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
package = ProjectPackage.find(params[:id])
|
||||||
|
return render_forbidden unless package.deletable? && package_manageable?
|
||||||
|
|
||||||
|
package.destroy!
|
||||||
|
|
||||||
|
Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, container_id: package.id,
|
||||||
|
container_type: 'ProjectPackage', tiding_type: 'Destroyed', extra: package.title)
|
||||||
|
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_package
|
||||||
|
@_current_package ||= ProjectPackage.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def package_manageable?
|
||||||
|
current_user&.id == current_package.creator_id || admin_or_business?
|
||||||
|
end
|
||||||
|
|
||||||
|
def save_params
|
||||||
|
params.permit(*%i[category_id title content attachment_ids deadline_at min_price max_price
|
||||||
|
contact_name contact_phone code publish])
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
module ProjectPackageDecorator
|
||||||
|
extend ApplicationDecorator
|
||||||
|
|
||||||
|
display_time_method :updated_at, :deadline_at, :published_at
|
||||||
|
end
|
@ -0,0 +1,15 @@
|
|||||||
|
class ProjectPackages::SaveForm
|
||||||
|
include ActiveModel::Model
|
||||||
|
|
||||||
|
attr_accessor :category_id, :title, :content, :attachment_ids, :deadline_at,
|
||||||
|
:min_price, :max_price, :contact_name, :contact_phone, :code, :publish
|
||||||
|
|
||||||
|
validates :category_id, presence: true
|
||||||
|
validates :title, presence: true, length: { maximum: 60 }
|
||||||
|
validates :content, presence: true
|
||||||
|
validates :deadline_at, presence: true
|
||||||
|
validates :min_price, numericality: { greater_than: 0 }, allow_blank: true
|
||||||
|
validates :max_price, numericality: { greater_than: ->(obj){ obj.min_price.to_i } }, allow_blank: true
|
||||||
|
validates :contact_name, presence: true, length: { maximum: 20 }
|
||||||
|
validates :contact_phone, presence: true, format: { with: /1\d{10}/ }
|
||||||
|
end
|
@ -0,0 +1,24 @@
|
|||||||
|
class BiddingUser < ApplicationRecord
|
||||||
|
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
|
||||||
|
|
||||||
|
def status_text
|
||||||
|
I18n.t("bidding_user.status.#{status}")
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,78 @@
|
|||||||
|
class ProjectPackage < ApplicationRecord
|
||||||
|
include AASM
|
||||||
|
|
||||||
|
belongs_to :creator, class_name: 'User'
|
||||||
|
belongs_to :project_package_category
|
||||||
|
|
||||||
|
has_many :project_package_applies, dependent: :destroy
|
||||||
|
has_one :process_project_package_apply, -> { where(status: :pending) }, class_name: 'ProjectPackageApply'
|
||||||
|
|
||||||
|
has_many :bidding_users, dependent: :delete_all
|
||||||
|
has_many :win_bidding_users, -> { where(status: :bidding_won) }, class_name: 'BiddingUser'
|
||||||
|
has_many :lose_bidding_users, -> { where(status: :bidding_lost) }, class_name: 'BiddingUser'
|
||||||
|
|
||||||
|
has_many :attachments, as: :container, dependent: :destroy
|
||||||
|
|
||||||
|
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 category_name
|
||||||
|
project_package_category.name
|
||||||
|
end
|
||||||
|
|
||||||
|
def visitable?
|
||||||
|
!editable?
|
||||||
|
end
|
||||||
|
|
||||||
|
def editable?
|
||||||
|
pending? || applying? || refused?
|
||||||
|
end
|
||||||
|
|
||||||
|
def deletable?
|
||||||
|
pending? || refused?
|
||||||
|
end
|
||||||
|
|
||||||
|
def deadline?
|
||||||
|
deadline_at < Time.now
|
||||||
|
end
|
||||||
|
|
||||||
|
def bidding_end?
|
||||||
|
flag = deadline?
|
||||||
|
ProjectPackages::EndBiddingService.call(self) if flag && may_end_bidding?
|
||||||
|
flag
|
||||||
|
end
|
||||||
|
|
||||||
|
def can_bidding?(user)
|
||||||
|
published? && !bidding_end? && user.id != creator_id && !bidding_users.exists?(user_id: user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def status_text
|
||||||
|
I18n.t("project_package.status.#{status}")
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,19 @@
|
|||||||
|
class ProjectPackageApply < ApplicationRecord
|
||||||
|
include AASM
|
||||||
|
|
||||||
|
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
|
@ -0,0 +1,23 @@
|
|||||||
|
class ProjectPackageCategory < ApplicationRecord
|
||||||
|
default_scope { order(position: :asc) }
|
||||||
|
|
||||||
|
has_many :project_packages, dependent: :destroy
|
||||||
|
|
||||||
|
after_commit :reset_cache_data
|
||||||
|
|
||||||
|
def self.cached_data
|
||||||
|
Rails.cache.fetch(data_cache_key, expires_in: 1.days) do
|
||||||
|
ProjectPackageCategory.select(:id, :name).as_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.data_cache_key
|
||||||
|
'project_package_category/cached_data'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def reset_cache_data
|
||||||
|
Rails.cache.delete(self.class.data_cache_key)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,36 @@
|
|||||||
|
class ProjectPackages::AgreeApplyService < ApplicationService
|
||||||
|
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 < ApplicationService
|
||||||
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
|
attr_reader :package
|
||||||
|
|
||||||
|
def initialize(package)
|
||||||
|
@package = package
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
return if package.applying?
|
||||||
|
|
||||||
|
raise Error, '该状态下不能申请发布' unless package.may_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 < ApplicationService
|
||||||
|
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 < ApplicationService
|
||||||
|
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.may_end_bidding? && package.deadline_at < Time.now
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,38 @@
|
|||||||
|
class ProjectPackages::RefuseApplyService < ApplicationService
|
||||||
|
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,79 @@
|
|||||||
|
class ProjectPackages::SaveService < ApplicationService
|
||||||
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
|
attr_reader :package, :params
|
||||||
|
|
||||||
|
def initialize(package, params)
|
||||||
|
@package = package
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
ProjectPackages::SaveForm.new(params).validate!
|
||||||
|
|
||||||
|
check_code_valid! if need_check_code?
|
||||||
|
|
||||||
|
is_create = package.new_record?
|
||||||
|
raise Error, '类型不存在' unless ProjectPackageCategory.where(id: params[:category_id]).exists?
|
||||||
|
params[:project_package_category_id] = params[:category_id].to_i
|
||||||
|
|
||||||
|
raise Error, '竞标截止时间不能小于当前时间' if params[:deadline_at].present? && params[:deadline_at].to_time < Time.now
|
||||||
|
|
||||||
|
if params[:min_price].blank? && params[:max_price].present?
|
||||||
|
params[:min_price] = params[:max_price]
|
||||||
|
params[:max_price] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
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.new_record? && 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
|
||||||
|
if new_ids.present?
|
||||||
|
Attachment.where(id: new_ids, container_id: nil).update_all(container_id: package.id, container_type: 'ProjectPackage')
|
||||||
|
end
|
||||||
|
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,50 @@
|
|||||||
|
class ProjectPackages::WinBiddingService < ApplicationService
|
||||||
|
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.may_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)
|
||||||
|
columns = %i[user_id trigger_user_id container_id container_type tiding_type created_at updated_at]
|
||||||
|
|
||||||
|
Tiding.bulk_insert(*columns) do |worker|
|
||||||
|
base_attr = { trigger_user_id: package.creator_id, container_id: package.id,
|
||||||
|
container_type: 'ProjectPackage', tiding_type: type }
|
||||||
|
user_ids.each do |user_id|
|
||||||
|
worker.add(base_attr.merge(user_id: user_id))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,12 @@
|
|||||||
|
class CheckProjectPackageDeadlineTask
|
||||||
|
def call
|
||||||
|
ProjectPackage.where(status: :published).where('deadline_at < ?', Time.now).find_each do |package|
|
||||||
|
begin
|
||||||
|
ProjectPackages::EndBiddingService.new(package).call
|
||||||
|
rescue => ex
|
||||||
|
Rails.logger.error ex.message
|
||||||
|
Rails.logger.error ex.backtrace.join('\n')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,13 @@
|
|||||||
|
json.count @count
|
||||||
|
json.project_packages do
|
||||||
|
json.array! @packages.each do |package|
|
||||||
|
json.extract! package, :id, :title, :content, :category_name, :status,
|
||||||
|
:visit_count, :bidding_users_count, :min_price, :max_price
|
||||||
|
|
||||||
|
json.category_id package.project_package_category_id
|
||||||
|
|
||||||
|
json.updated_at package.display_updated_at
|
||||||
|
json.deadline_at package.display_deadline_at
|
||||||
|
json.published_at package.display_published_at
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,43 @@
|
|||||||
|
package = current_package
|
||||||
|
|
||||||
|
json.extract! package, :id, :title, :content, :category_name, :status,
|
||||||
|
:visit_count, :bidding_users_count, :min_price, :max_price
|
||||||
|
|
||||||
|
json.category_id package.project_package_category_id
|
||||||
|
|
||||||
|
# 只有自己和管理员才返回私人信息
|
||||||
|
if package_manageable?
|
||||||
|
json.contact_name package.contact_name
|
||||||
|
json.contact_phone package.contact_phone
|
||||||
|
end
|
||||||
|
|
||||||
|
json.updated_at package.display_updated_at
|
||||||
|
json.deadline_at package.display_deadline_at
|
||||||
|
json.published_at package.display_published_at
|
||||||
|
|
||||||
|
json.creator do
|
||||||
|
json.partial! 'users/user_simple', user: package.creator
|
||||||
|
end
|
||||||
|
|
||||||
|
json.attachments do
|
||||||
|
json.array! package.attachments, partial: 'attachments/attachment_simple', as: :attachment
|
||||||
|
end
|
||||||
|
|
||||||
|
json.bidding_users do
|
||||||
|
json.array! package.bidding_users.includes(:user).each do |bidding_user|
|
||||||
|
json.partial! 'users/user_simple', user: bidding_user.user
|
||||||
|
|
||||||
|
json.status bidding_user.status
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
json.operation do
|
||||||
|
if current_user
|
||||||
|
manageable = package_manageable?
|
||||||
|
|
||||||
|
json.can_bidding package.can_bidding?(current_user)
|
||||||
|
json.can_select_bidding_user package.bidding_end? && package.bidding_ended? && manageable
|
||||||
|
json.can_edit package.editable? && manageable
|
||||||
|
json.can_delete package.deletable? && manageable
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,6 @@
|
|||||||
|
'zh-CN':
|
||||||
|
bidding_user:
|
||||||
|
status:
|
||||||
|
pending: 竞标中
|
||||||
|
bidding_won: 已中标
|
||||||
|
bidding_lost: 未中标
|
@ -0,0 +1,13 @@
|
|||||||
|
'zh-CN':
|
||||||
|
activemodel:
|
||||||
|
attributes:
|
||||||
|
project_packages/save_form:
|
||||||
|
category_id: 类型
|
||||||
|
title: 标题
|
||||||
|
content: 描述
|
||||||
|
deadline_at: 截止日期
|
||||||
|
min_price: 最小价格
|
||||||
|
max_price: 最大价格
|
||||||
|
contact_name: 联系人姓名
|
||||||
|
contact_phone: 联系人电话
|
||||||
|
code: 验证码
|
@ -0,0 +1,9 @@
|
|||||||
|
zh-CN:
|
||||||
|
project_package:
|
||||||
|
status:
|
||||||
|
pending: 已创建
|
||||||
|
applying: 审核中
|
||||||
|
refused: 已拒绝
|
||||||
|
published: 竞标中
|
||||||
|
bidding_ended: 待选标
|
||||||
|
bidding_finished: 已完成
|
@ -0,0 +1,291 @@
|
|||||||
|
import React, {Component} from 'react';
|
||||||
|
import {Button,notification} from 'antd';
|
||||||
|
import {broadcastChannelPostMessage} from 'educoder';
|
||||||
|
import MyEduCoderModal from './MyEduCoderModal';
|
||||||
|
// import Notcompleted from '../../common/Notcompleted';
|
||||||
|
import axios from 'axios';
|
||||||
|
import './commontwo.css';
|
||||||
|
import mytc from './img/mytc.png';
|
||||||
|
import skzbdx from './img/skzbdx.png';
|
||||||
|
import zyrs1 from './img/zyrs1.png';
|
||||||
|
import gouxuan from './img/gouxuan.png';
|
||||||
|
import meigouxuan from './img/meigouxuan.png';
|
||||||
|
import qdkf from './img/qdkf.png';
|
||||||
|
import hdkf from './img/hdkf.png';
|
||||||
|
import ydkf from './img/ydkf.png';
|
||||||
|
import sjk from './img/sjk.png';
|
||||||
|
import ysj from './img/ysj.png';
|
||||||
|
import yunwei from './img/yunwei.png';
|
||||||
|
import rgzn from './img/rgzn.png';
|
||||||
|
import qita from './img/qita.png';
|
||||||
|
|
||||||
|
//父组件 EducoderLogin.js
|
||||||
|
class InterestpageMax extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
gouxuans: "",
|
||||||
|
gouxuans2:0,
|
||||||
|
gouxuans4:[],
|
||||||
|
namezh:this.props.namezh,
|
||||||
|
passmm:this.props.passmm,
|
||||||
|
homedatalist:undefined,
|
||||||
|
hometypepvisible: undefined,
|
||||||
|
MyEduCoderModals:false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
openNotification = (messge) => {
|
||||||
|
// type 1 成功提示绿色 2提醒颜色黄色 3错误提示红色
|
||||||
|
notification.open({
|
||||||
|
message: "提示",
|
||||||
|
description: messge,
|
||||||
|
onClick: () => {
|
||||||
|
console.log('Notification Clicked!');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
componentDidMount(){
|
||||||
|
console.log("max");
|
||||||
|
let{gouxuans4} =this.state;
|
||||||
|
let url=`/repertoires.json`;
|
||||||
|
axios.get(url).then((response)=> {
|
||||||
|
if(response){
|
||||||
|
console.log("53");
|
||||||
|
console.log(response.data);
|
||||||
|
for(var i=0;i<response.data.repertoires.length;i++){
|
||||||
|
var qdkfys="";
|
||||||
|
if(response.data.repertoires[i].id===1){
|
||||||
|
qdkfys=qdkf;
|
||||||
|
}if(response.data.repertoires[i].id===2){
|
||||||
|
qdkfys=hdkf;
|
||||||
|
}if(response.data.repertoires[i].id===3){
|
||||||
|
qdkfys=ydkf;
|
||||||
|
}if(response.data.repertoires[i].id===4){
|
||||||
|
qdkfys=sjk;
|
||||||
|
}if(response.data.repertoires[i].id===5){
|
||||||
|
qdkfys=ysj;
|
||||||
|
}if(response.data.repertoires[i].id===6){
|
||||||
|
qdkfys=yunwei;
|
||||||
|
}if(response.data.repertoires[i].id===8){
|
||||||
|
qdkfys=qita;
|
||||||
|
}if(response.data.repertoires[i].id===9){
|
||||||
|
qdkfys=rgzn;
|
||||||
|
}
|
||||||
|
var datas={id:response.data.repertoires[i].id,name:response.data.repertoires[i].name,bool:false,url:qdkfys};
|
||||||
|
gouxuans4.push(datas);
|
||||||
|
this.setState({
|
||||||
|
gouxuans4:gouxuans4,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
console.log("75");
|
||||||
|
console.log(gouxuans4);
|
||||||
|
|
||||||
|
}
|
||||||
|
}).catch((error)=>{
|
||||||
|
console.log(error)
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
// console.log("46");
|
||||||
|
// console.log(nextProps);
|
||||||
|
// console.log(this.props);
|
||||||
|
if (nextProps.namezh != this.props.namezh) {
|
||||||
|
// console.log("50");
|
||||||
|
// console.log(nextProps.user);
|
||||||
|
if (nextProps.namezh !== undefined) {
|
||||||
|
// console.log("53");
|
||||||
|
// console.log(nextProps.user);
|
||||||
|
this.setState({
|
||||||
|
namezh: nextProps.namezh,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
if (nextProps.passmm != this.props.passmm) {
|
||||||
|
// console.log("50");
|
||||||
|
// console.log(nextProps.user);
|
||||||
|
if (nextProps.passmm !== undefined) {
|
||||||
|
// console.log("53");
|
||||||
|
// console.log(nextProps.user);
|
||||||
|
this.setState({
|
||||||
|
passmm: nextProps.passmm,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Clickteacher=(e)=>{
|
||||||
|
console.log(e);
|
||||||
|
if(e === "teacher"){
|
||||||
|
this.setState({
|
||||||
|
gouxuans:"teacher",
|
||||||
|
})
|
||||||
|
}else if(e ==="student"){
|
||||||
|
this.setState({
|
||||||
|
gouxuans:"student",
|
||||||
|
})
|
||||||
|
}else if(e === "professional"){
|
||||||
|
this.setState({
|
||||||
|
gouxuans:"professional",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Clickteacher2=(e)=>{
|
||||||
|
console.log(e);
|
||||||
|
let {gouxuans4} =this.state;
|
||||||
|
for (var i=0;i<gouxuans4.length;i++){
|
||||||
|
if(gouxuans4[i].id === e){
|
||||||
|
console.log("51");
|
||||||
|
console.log(e);
|
||||||
|
if(gouxuans4[i].bool === true){
|
||||||
|
gouxuans4[i].bool=false;
|
||||||
|
}else{
|
||||||
|
gouxuans4[i].bool=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(gouxuans4);
|
||||||
|
this.setState({
|
||||||
|
gouxuans4:gouxuans4,
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setMyEduCoderModals=()=>{
|
||||||
|
this.setState({
|
||||||
|
MyEduCoderModals:true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//兴趣页面点击
|
||||||
|
Interestcompletionpage(){
|
||||||
|
if(this.state.gouxuans.length === 0){
|
||||||
|
this.openNotification("请选择您的职业");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var ints=[];
|
||||||
|
for (var i =0;i<this.state.gouxuans4.length;i++) {
|
||||||
|
if(this.state.gouxuans4[i].bool === true){
|
||||||
|
ints.push(this.state.gouxuans4[i].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ints.length<1){
|
||||||
|
this.openNotification("内容是最少得选一个");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var url = "/users/interest.json";
|
||||||
|
axios.post(url, {
|
||||||
|
identity:this.state.gouxuans,
|
||||||
|
interest_ids: ints,
|
||||||
|
}).then((response) => {
|
||||||
|
if (response !== undefined) {
|
||||||
|
// this.Jumptotheinterestpage();
|
||||||
|
// window.location.href = "/"
|
||||||
|
this.setMyEduCoderModals()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// //跳转然后登入
|
||||||
|
// Jumptotheinterestpage=()=>{
|
||||||
|
// console.log(this.state.login);
|
||||||
|
// console.log(this.state.password);
|
||||||
|
// var url = "/accounts/login.json";
|
||||||
|
// axios.post(url, {
|
||||||
|
// login: this.props.login,
|
||||||
|
// password: this.props.password,
|
||||||
|
// }).then((response) => {
|
||||||
|
// if (response === undefined) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if (response.status === 200) {
|
||||||
|
// // if (response.data.status === 402) {
|
||||||
|
// // window.location.href = response.data.url;
|
||||||
|
// // } else {
|
||||||
|
// // broadcastChannelPostMessage('refreshPage')
|
||||||
|
// // this.setState({
|
||||||
|
// // isRender: false
|
||||||
|
// // })
|
||||||
|
// window.location.href = "/"
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }).catch((error) => {
|
||||||
|
// console.log(error);
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
setNotcompleteds=()=>{
|
||||||
|
this.setState({
|
||||||
|
Notcompleteds:true,
|
||||||
|
MyEduCoderModals:false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
gouxuans,
|
||||||
|
gouxuans4,
|
||||||
|
} = this.state
|
||||||
|
// height: 346px;
|
||||||
|
return (
|
||||||
|
|
||||||
|
<div className="ysllogin_register_contents2" style={{width:"800px",height: "550px"}}>
|
||||||
|
|
||||||
|
<MyEduCoderModal
|
||||||
|
modalsType={this.state.MyEduCoderModals}
|
||||||
|
setNotcompleteds={()=>{this.setNotcompleteds()}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="ysllogin_section2">
|
||||||
|
<div className="mt15"><span className="yslspans12">请选择你的职业</span></div>
|
||||||
|
<div className="ysldivhome12" >
|
||||||
|
<div className="ysldivhomediv222" style={{marginLeft:"30px"}} >
|
||||||
|
<div className="ysldivhomedivtxt2" onClick={()=>this.Clickteacher("teacher")}>{gouxuans ==="teacher"? <img src={gouxuan} className="gouxuanimg2"/>:<img className="gouxuanimg2" src={meigouxuan}/>}老师</div>
|
||||||
|
<div className="ysldivhomedivimg2" ><img src={skzbdx} className="ysldivhomedivimg2"/></div>
|
||||||
|
</div>
|
||||||
|
<div className="ysldivhomediv222" style={{ marginLeft:"101px",marginRight:"101px"}}>
|
||||||
|
<div className="ysldivhomedivtxt2" onClick={()=>this.Clickteacher("student")}>{gouxuans==="student"? <img src={gouxuan} className="gouxuanimg2"/>:<img className="gouxuanimg2" src={meigouxuan}/>}学生</div>
|
||||||
|
<div className="ysldivhomedivimg2"><img src={mytc} className="ysldivhomedivimg2"/></div>
|
||||||
|
</div>
|
||||||
|
<div className="ysldivhomediv222" >
|
||||||
|
<div className="ysldivhomedivtxt2" onClick={()=>this.Clickteacher("professional")}>{gouxuans==="professional"?<img src={gouxuan} className="gouxuanimg2"/>:<img className="gouxuanimg2" src={meigouxuan}/>}专业人士</div>
|
||||||
|
<div className="ysldivhomedivimg2"><img src={zyrs1} className="ysldivhomedivimg2"/></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div><span className="yslspans22">选择你可能感兴趣的内容</span></div>
|
||||||
|
<div ><span className="yslspans32">基于你关注的内容推荐</span></div>
|
||||||
|
<div className="ysldivhome22">
|
||||||
|
|
||||||
|
{gouxuans4&&gouxuans4.map((item,key)=>{
|
||||||
|
return(
|
||||||
|
<div className={item.id<5?"ysldivhomediv12":"ysldivhomediv22"} onClick={()=>this.Clickteacher2(item.id)}>
|
||||||
|
{item.bool===true?<img src={gouxuan} className="yslgouxuanimg2"/>:<div className="yslgouxuanimg22"></div>}
|
||||||
|
<img className="div1img2" src={item.url}/>
|
||||||
|
<span className="textall2">{item.name}</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<Button className="yslbutton2" size={"large"} type="primary"onClick={()=>this.Interestcompletionpage()} style={{width:"255px",height: "35px",background: "#4CACFF",marginTop: "17px"} }>完成</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (InterestpageMax);
|
@ -0,0 +1,3 @@
|
|||||||
|
.yslfont {
|
||||||
|
font-size: 10%;
|
||||||
|
}
|
@ -0,0 +1,265 @@
|
|||||||
|
/*.login_register_content, .login_register_content .ant-tabs-tabpane {*/
|
||||||
|
/* !*display: flex;*!*/
|
||||||
|
/* justify-content: center;*/
|
||||||
|
/*}*/
|
||||||
|
.login_register_content .ant-input {
|
||||||
|
background:rgb(244,244,244);
|
||||||
|
}
|
||||||
|
.login_register_content .loginInputzhucheyslass{
|
||||||
|
border:1px solid red !important;
|
||||||
|
}
|
||||||
|
.login_register_content .loginInputzhucheyslass:hover{
|
||||||
|
border:1px solid red !important;
|
||||||
|
}
|
||||||
|
.login_register_content {
|
||||||
|
width: 434px;
|
||||||
|
box-shadow:3px 10px 21px 0px rgba(76,76,76,0.15);
|
||||||
|
border-radius:6px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.login_register_content .ant-tabs-ink-bar {
|
||||||
|
width: 21px !important;
|
||||||
|
left: 19px;
|
||||||
|
}
|
||||||
|
.login_register_content .ant-tabs {
|
||||||
|
width: 354px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login_section {
|
||||||
|
width: 100%;
|
||||||
|
display:flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.login_sectionysl{
|
||||||
|
width: 100%;
|
||||||
|
display:flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.loginInput {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.educouddiv {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.left_right {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.login_btn {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 26px;
|
||||||
|
margin-bottom: 26px;
|
||||||
|
}
|
||||||
|
.dragValidator {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.ysldivhome12{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-left: 100px;
|
||||||
|
margin-right: 129px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.ysldivhome22{
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
align-content:stretch;
|
||||||
|
}
|
||||||
|
.ysldivhomediv222{
|
||||||
|
width: 101px;
|
||||||
|
height: 130px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.ysldivhomediv12{
|
||||||
|
width: 110px;
|
||||||
|
height: 110px;
|
||||||
|
border-radius:50%;
|
||||||
|
box-shadow:3px 10px 21px 0px rgba(76,76,76,0.15);
|
||||||
|
background: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction:column;
|
||||||
|
margin-left: 73px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
.ysldivhomediv22{
|
||||||
|
width: 110px;
|
||||||
|
height: 110px;
|
||||||
|
border-radius:50%;
|
||||||
|
box-shadow:3px 10px 21px 0px rgba(76,76,76,0.15);
|
||||||
|
background: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction:column;
|
||||||
|
margin-left: 73px;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
.ysldivhomedivtxt2{
|
||||||
|
width:101px;
|
||||||
|
height:27px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
}
|
||||||
|
.ysldivhomedivimg2{
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
}
|
||||||
|
.ysllogin_register_contents2{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow:3px 10px 21px 0px rgba(76,76,76,0.15);
|
||||||
|
border-radius:6px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.ysllogin_section2 {
|
||||||
|
width:800px;
|
||||||
|
height: 600px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.yslspans12{
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #111C24;
|
||||||
|
}
|
||||||
|
.yslspans22{
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #05101A;
|
||||||
|
}
|
||||||
|
.yslspans32{
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #656565;
|
||||||
|
}
|
||||||
|
.yslbutton2{
|
||||||
|
width:255px;
|
||||||
|
height: 36px;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.mt22{
|
||||||
|
margin-top: 22px;
|
||||||
|
}
|
||||||
|
.gouxuanimg2{
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.textall2{
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #4B4B4B;
|
||||||
|
}
|
||||||
|
.div1img2{
|
||||||
|
display: flex;
|
||||||
|
justify-content:center;
|
||||||
|
width: 60px;
|
||||||
|
margin-left: 26px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.yslgouxuanimg22{
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-left: 75px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.yslgouxuanimg2{
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yslbutondls{
|
||||||
|
display: flex;
|
||||||
|
flex-direction:row;
|
||||||
|
}
|
||||||
|
。yslinpulsy input{
|
||||||
|
|
||||||
|
}
|
||||||
|
.loginInputzhuche{
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff!important;
|
||||||
|
height: 45px !important;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.loginInputzhucheyslass {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff!important;
|
||||||
|
height: 45px !important;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.loginInputzhucheyslass .ant-input{
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff!important;
|
||||||
|
height: 45px !important;
|
||||||
|
padding: 5px;
|
||||||
|
position: relative;
|
||||||
|
right: 5px;
|
||||||
|
width: 103%;
|
||||||
|
border: 1px solid #FF0000!important;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
}
|
||||||
|
.loginInputzhucheyslass .ant-input:hover{
|
||||||
|
border: 1px solid #FF0000!important;
|
||||||
|
|
||||||
|
}
|
||||||
|
.loginInputzhuche .ant-input{
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff!important;
|
||||||
|
height: 45px !important;
|
||||||
|
padding: 5px;
|
||||||
|
position: relative;
|
||||||
|
right: 5px;
|
||||||
|
width: 103%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loginInputzhucheysl{
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff!important;
|
||||||
|
height: 45px !important;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.loginInputzhucheysl .ant-input{
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff!important;
|
||||||
|
height: 45px !important;
|
||||||
|
padding: 5px;
|
||||||
|
position: relative;
|
||||||
|
right: 5px;
|
||||||
|
width: 103%;
|
||||||
|
border: 1px solid #FF0000!important;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
}
|
||||||
|
.loginInputzhucheysl .ant-input:hover{
|
||||||
|
border: 1px solid #FF0000!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bth100{
|
||||||
|
width: 100px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
Loading…
Reference in new issue