Commit 5a946728 by Ngo Trung Hung

created ID 234

parent 24b53533
...@@ -13,7 +13,7 @@ gem 'sass-rails', '~> 5.0' ...@@ -13,7 +13,7 @@ gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0' gem 'uglifier', '>= 1.3.0'
# See https://github.com/rails/execjs#readme for more supported runtimes # See https://github.com/rails/execjs#readme for more supported runtimes
# gem 'mini_racer', platforms: :ruby # gem 'mini_racer', platforms: :ruby
gem "breadcrumbs_on_rails"
# Use CoffeeScript for .coffee assets and views # Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2' gem 'coffee-rails', '~> 4.2'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
...@@ -23,6 +23,8 @@ gem 'jbuilder', '~> 2.5' ...@@ -23,6 +23,8 @@ gem 'jbuilder', '~> 2.5'
gem 'nokogiri' gem 'nokogiri'
gem 'rubyzip' gem 'rubyzip'
gem 'whenever' gem 'whenever'
gem 'kaminari'
gem 'jquery-rails'
gem 'rails-asset-jqueryui' gem 'rails-asset-jqueryui'
# Use Redis adapter to run Action Cable in production # Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0' # gem 'redis', '~> 4.0'
......
...@@ -51,6 +51,8 @@ GEM ...@@ -51,6 +51,8 @@ GEM
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.4.6) bootsnap (1.4.6)
msgpack (~> 1.0) msgpack (~> 1.0)
breadcrumbs_on_rails (4.0.0)
rails (>= 5.0)
builder (3.2.4) builder (3.2.4)
byebug (11.1.3) byebug (11.1.3)
capybara (3.33.0) capybara (3.33.0)
...@@ -90,6 +92,18 @@ GEM ...@@ -90,6 +92,18 @@ GEM
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
kaminari (1.2.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.1)
kaminari-activerecord (= 1.2.1)
kaminari-core (= 1.2.1)
kaminari-actionview (1.2.1)
actionview
kaminari-core (= 1.2.1)
kaminari-activerecord (1.2.1)
activerecord
kaminari-core (= 1.2.1)
kaminari-core (1.2.1)
libv8 (3.16.14.19) libv8 (3.16.14.19)
listen (3.1.5) listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4) rb-fsevent (~> 0.9, >= 0.9.4)
...@@ -234,11 +248,14 @@ PLATFORMS ...@@ -234,11 +248,14 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
bootsnap (>= 1.1.0) bootsnap (>= 1.1.0)
breadcrumbs_on_rails
byebug byebug
capybara (>= 2.15) capybara (>= 2.15)
chromedriver-helper chromedriver-helper
coffee-rails (~> 4.2) coffee-rails (~> 4.2)
jbuilder (~> 2.5) jbuilder (~> 2.5)
jquery-rails
kaminari
listen (>= 3.0.5, < 3.2) listen (>= 3.0.5, < 3.2)
mysql2 (= 0.5.3) mysql2 (= 0.5.3)
nokogiri nokogiri
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives. // about supported directives.
// //
//= require jquery
//= require rails-ujs //= require rails-ujs
//= require activestorage //= require activestorage
//= require turbolinks //= require turbolinks
......
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
...@@ -17,9 +17,20 @@ $(document).on("turbolinks:load", function(){ ...@@ -17,9 +17,20 @@ $(document).on("turbolinks:load", function(){
}); });
$(".btn-scroll-top").click(function (e){ $(".btn-scroll-top").click(function (e){
var body = $("html, body"); var body = $("html, body");
body.stop().animate({scrollTop:0}, 700, 'swing') body.stop().animate({ scrollTop: 0}, 700, 'swing')
}); });
// => end // => end
$(".btn_option_location-vn").click(function (){
var body = $("html, body");
$('.btn_option_location-vn').addClass('active');
body.stop().animate({ scrollTop: $('.title_list_city_vn').offset().top}, 700, 'swing');
});
$(".btn_option_location-qt").click(function (){
var body = $("html, body");
console.log('bam')
body.stop().animate({ scrollTop: $('.title_list_city_qt').offset().top}, 700, 'swing');
});
}); });
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
// Place all the styles related to the city controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
...@@ -7,6 +7,12 @@ body { ...@@ -7,6 +7,12 @@ body {
overflow: hidden; overflow: hidden;
// background-color: #f0f0f0; // background-color: #f0f0f0;
} }
.pre_desc {
white-space: pre-wrap;
text-overflow: clip;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 16px;
}
// scroll to top // scroll to top
.btn-scroll-top { .btn-scroll-top {
position: fixed; position: fixed;
...@@ -24,6 +30,9 @@ body { ...@@ -24,6 +30,9 @@ body {
&:hover { &:hover {
background-color: rgba($color: #000000, $alpha: 0.7); background-color: rgba($color: #000000, $alpha: 0.7);
transition: 0.3; transition: 0.3;
.icon-scroll {
color: #fff !important;
}
} }
} }
...@@ -874,6 +883,11 @@ $main-color: #23303D; ...@@ -874,6 +883,11 @@ $main-color: #23303D;
color: unset; color: unset;
} }
} }
.link_ct.apply_job {
&:hover {
color: blue !important;
}
}
.ct_name { .ct_name {
cursor: pointer; cursor: pointer;
color: white; color: white;
...@@ -902,6 +916,236 @@ $main-color: #23303D; ...@@ -902,6 +916,236 @@ $main-color: #23303D;
margin: auto; margin: auto;
text-align: center; text-align: center;
} }
// City
.box_option_location {
z-index: 1;
position: relative;
margin: 100px auto 50px;
padding: 25px 25px;
width: 70%;
height: auto;
box-shadow: 0px 1px 10px 1px #c9c9c9e8;
background-color: rgba($color: #fff, $alpha: 0.9);
// border-radius: 4px;
// border: 1px solid rgba($color: #000000, $alpha: 0.5)
}
.icon_box_option_location {
position: absolute;
top: -25%;
left: 50%;
transform: translateX(-50%);
width: 100px;
height: 100px;
border-radius: 50%;
border: 6px solid #fff;
box-shadow: 0px 0px 10px 1px #aca9a9e8;
background-color: #fff000;
background-image: linear-gradient(315deg, #fff000 0%, #ed008c 74%);
z-index: 20;
text-align: center;
}
.kl_icon_box_option_location {
color: white;
font-size: 58px;
}
.box_option_location_header {
text-align: center;
font-size: 26px;
margin: 30px 0px 20px;
}
.btn_option_location {
width: 100%;
height: 50px;
margin-bottom: 10px;
outline: none;
border: none;
border-radius: 4px;
color: white;
font-size: 18px;
background-color: #06bcfb;
background-image: linear-gradient(315deg, #06bcfb 0%, #4884ee 74%);
&:hover {
font-weight: bold;
border: 1px solid #5de6de;
background-color: #fff000;
background-image: linear-gradient(315deg, #fff000 0%, #ed008c 74%);
}
&:focus {
outline: none;
}
}
.title_list_city {
height: 50px;
width: 100%;
border-radius: 4px;
background-color: #fff000;
background-image: linear-gradient(315deg, #fff000 0%, #ed008c 74%);
box-shadow: 0px 0px 5px 2px rgba($color: #c0c0c0, $alpha: 0.3);
margin: 40px 0px;
padding-left: 20px;
span {
line-height: 50px;
color: #fff;
font-size: 18px;
font-weight: 600;
}
}
.box_cityjobs {
position: relative;
width: 100%;
height: 100px;
text-align: center;
padding: 25px 20px;
margin-bottom: 20px;
overflow: hidden;
transition: 0.2s;
background-color: #fff;
box-shadow: 0px 0px 5px 2px rgba($color: #000000, $alpha: 0.2);
&::before {
position: absolute;
content: 'Hot';
width: 80px;
height: 18px;
color: #fff;
line-height: 18px;
background-image: linear-gradient(315deg, #ff4e00 0%, #ec9f05 74%);
transform: rotate(-45deg) translateY(-10px) translateX(-25px);
top: 0;
left: 0;
}
&:hover {
transition: 0.2s;
transform: scale(1.05);
}
}
.box_cityjobs_name {
font-size: 18px;
font-weight: 600;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.cityjobs_link {
line-height: 18px;
color: black;
&:hover {
text-decoration: none;
color: unset;
}
}
// End city
// begin detail
.banner_detail {
width: 100%;
height: 300px;
background-image: url('11');
background-repeat: no-repeat;
background-size: cover;
}
.breadcrumb li a{
text-decoration: none;
&:hover {
text-decoration: none !important;
}
}
.job_title {
h1 {
font-size: 30px;
}
}
.btn-apply_job {
width: 100%;
height: 100%;
color: #fff;
background-color: #d4418e;
background-image: linear-gradient(315deg, #d4418e 0%, #0652c5 74%);
outline: none !important;
border: none !important;
&:hover {
color: #fff !important;
font-weight: 600 !important;
}
}
.btn-apply_job_favorite {
width: 100%;
height: 100%;
color: #fff;
background-color: #fc9842;
background-image: linear-gradient(315deg, #fc9842 0%, #fe5f75 74%);
outline: none !important;
border: none !important;
&:hover {
color: #fff !important;
font-weight: 600 !important;
}
}
.box_detail_jobs {
width: 100%;
height: auto;
margin: 30px 0px 20px;
padding: 20px;
box-shadow: 0px 0px 5px 2px rgba($color: #000000, $alpha: 0.2);
}
.link_optimize {
&::after {
content: '';
position: relative;
border-right: 1px solid rgba($color: #000000, $alpha: 0.4);
width: 1px;
height: 20px;
top: 0;
}
&:last-child {
&::after {
content: '';
position: relative;
border-right: 0px solid black !important;
width: 0px;
height: 0px;
top: 0;
}
}
}
.detail_info {
margin: 6px 0px !important;
span {
color: #666;
}
}
.welfare-list {
display: flex;
list-style: none;
flex-wrap: wrap;
li {
margin: 5px 0px;
flex-basis: 33.22% !important;
flex-shrink: 1;
justify-content: space-between;
}
}
.breadcrumb_total_search {
background-color: #e9ecef;
height: 48px;
font-size: 16px;
line-height: 48px;
border-radius: 4px;
max-width: 970px;
margin: 0px auto 20px;
padding: 0px 0px 0px 20px;
}
// end detail
@media only screen and (min-width: $breakpoint-tablet) { @media only screen and (min-width: $breakpoint-tablet) {
.btn_search_submit { .btn_search_submit {
width: 101%; width: 101%;
...@@ -954,8 +1198,23 @@ $main-color: #23303D; ...@@ -954,8 +1198,23 @@ $main-color: #23303D;
background-color: white; background-color: white;
margin-bottom: 10px; margin-bottom: 10px;
} }
.icon_box_option_location {
top: -20% !important;
}
}
.breadcrumb_total_search_pagination_jobs {
background-color: transparent;
height: 48px;
font-size: 16px;
line-height: 48px;
border-radius: 4px;
max-width: 970px;
margin: 20px auto 20px;
padding: 0px 0px 0px 20px;
}
.pagination_jobs {
float: right;
} }
@media only screen and (max-width: 768px) { @media only screen and (max-width: 768px) {
// index // index
.padding_index { .padding_index {
...@@ -966,7 +1225,10 @@ $main-color: #23303D; ...@@ -966,7 +1225,10 @@ $main-color: #23303D;
font-size: 23px; font-size: 23px;
} }
} }
.box_option_location_header {
font-size: 20px;
}
} }
@media only screen and (max-width: 660px) { @media only screen and (max-width: 660px) {
......
// Place all the styles related to the industry controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// Place all the styles related to the job controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
class CityController < ApplicationController
def index
@data_jobs_vn = City.top_hot_vn
@data_jobs_qt = City.top_hot_qt
end
end
class HomeController < ApplicationController class HomeController < ApplicationController
add_breadcrumb "Trang chủ", :root_path
def index def index
@industries = Industry.sort_asc.all @industries = Industry.sort_asc.all
@job_count = Job.all.count @job_count = Job.all.count
@five_jobs = Job.order(created_at: :desc).limit(5) @five_jobs = Job.order(created_at: :desc).limit(5)
@cities = City.all @cities = City.all
@top_city = City.top_hot.take(11) @top_city = City.top_hot.take(11)
@top_industry = Industry.top_hot.take(11) @top_industry = Industry.top_hot.take(11)
end end
end end
class IndustryController < ApplicationController
def index
@data_industries_hot = Industry.top_hot
end
end
class JobController < ApplicationController
def index
end
def detail
add_breadcrumb "Trang chủ&nbsp;".html_safe, root_path
@job = Job.find(params[:id])
city = []
industry = []
@job.cities.each do |val|
city << val.name
end
@job.industries.each do |val|
industry << val.name
end
add_breadcrumb "&nbsp;#{city[0]}&nbsp;".html_safe, "/jobs/city/#{city[0]}"
add_breadcrumb "&nbsp;#{industry[0]}&nbsp;".html_safe, "/jobs/industry/#{industry[0]}"
add_breadcrumb "&nbsp;#{@job.name}".html_safe
end
def find_data_by_industry
@industries = Industry.sort_asc.all
@cities = City.all
id_industry = Industry.find_by(name: params[:key_industry])
@fill_data = id_industry.jobs.page(params[:page]).per(20)
render 'find_data'
end
def find_data_by_city
@industries = Industry.sort_asc.all
@cities = City.all
id_city = City.find_by(name: params[:key_city])
@fill_data = id_city.jobs.page(params[:page]).per(20)
render 'find_data'
end
def find_data_by_company
@industries = Industry.sort_asc.all
@cities = City.all
company = Company.find_by(name: params[:key_company])
@fill_data = company.jobs.page(params[:page]).per(20)
render 'find_data'
end
end
module CityHelper
end
module IndustryHelper
end
module JobHelper
end
...@@ -10,4 +10,24 @@ class City < ApplicationRecord ...@@ -10,4 +10,24 @@ class City < ApplicationRecord
end end
hash.sort_by { |k,v| v }.reverse hash.sort_by { |k,v| v }.reverse
end end
def self.top_hot_vn
hash = {}
data_cities = City.select('*').where('area = 1')
data_cities.each do |val|
hash[val.name] = val.jobs.count
end
hash = hash.select { |k,v| v > 0}
hash.sort_by { |k,v| v }.reverse
end
def self.top_hot_qt
hash = {}
data_cities = City.select('*').where('area = 0')
data_cities.each do |val|
hash[val.name] = val.jobs.count
end
hash = hash.select { |k,v| v > 0}
hash.sort_by { |k,v| v }.reverse
end
end end
...@@ -9,6 +9,7 @@ class Industry < ApplicationRecord ...@@ -9,6 +9,7 @@ class Industry < ApplicationRecord
data_industries.each do |val| data_industries.each do |val|
hash[val.name] = val.jobs.count hash[val.name] = val.jobs.count
end end
hash = hash.select { |k,v| v > 0}
hash.sort_by { |k,v| v }.reverse hash.sort_by { |k,v| v }.reverse
end end
end end
<div class="box_cityjobs">
<div class="box_cityjobs_name">
<%= link_to name_city, "jobs/city/#{name_city}",class: 'cityjobs_link' %>
</div>
<div class="box_cityjobs_count">
<span><%= jobs_count %> Công việc</span>
</div>
</div>
\ No newline at end of file
<div class="box_cityjobs">
<div class="box_cityjobs_name">
<%= link_to name_city, "jobs/city/#{name_city}",class: 'cityjobs_link' %>
</div>
<div class="box_cityjobs_count">
<span><%= jobs_count %> Công việc</span>
</div>
</div>
\ No newline at end of file
<% provide(:title,'Top thành phố') %>
<%= render 'shared/scroll_top' %>
<div class="container">
<div class="box_option_location">
<div class="icon_box_option_location">
<span class="kl_icon_box_option_location">
<i class="fas fa-search-location"></i>
</span>
</div>
<div class="row">
<div class="col-lg-12">
<div class="box_option_location_header">
<span>Bạn muốn tìm việc trong hay ngoài nước?</span>
</div>
</div>
<div class="col-lg-6">
<button class="btn_option_location btn_option_location-vn">Việt Nam</button>
</div>
<div class="col-lg-6">
<button class="btn_option_location btn_option_location-qt">Nước ngoài</button>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="title_list_city title_list_city_vn">
<span>Các tỉnh, thành phố thuôc Việt Nam</span>
</div>
</div>
<div class="container">
<div class="row">
<% @data_jobs_vn.each do |k,v| %>
<div class="col-lg-3 col-md-4">
<%= render 'block_cityjobs_vn', name_city: k, jobs_count: v %>
</div>
<% end %>
</div>
</div>
<div class="col-lg-12">
<div class="title_list_city title_list_city_qt">
<span>Quốc tế</span>
</div>
</div>
<div class="container">
<div class="row">
<% @data_jobs_qt.each do |k,v| %>
<div class="col-lg-3 col-md-4">
<%= render 'block_cityjobs_qt', name_city: k, jobs_count: v %>
</div>
<% end %>
</div>
</div>
</div>
</div>
...@@ -17,7 +17,11 @@ ...@@ -17,7 +17,11 @@
<div class="box-search"> <div class="box-search">
<div class="search_scaffold"> <div class="search_scaffold">
<div class = "total_job"> <div class = "total_job">
<h4 class="show_total_job">Khám phá ngay <b><%=@job_count%></b> việc làm tốt nhất trên VenJob</h4> <% if @job_count.blank? %>
<h4 class="show_total_job">Khám phá ngay những việc làm tốt nhất trên VenJob</h4>
<% else %>
<h4 class="show_total_job">Khám phá ngay <b><%= @job_count%></b> việc làm tốt nhất trên VenJob</h4>
<% end %>
</div> </div>
<div class="filter_box"> <div class="filter_box">
<div class="search_input"> <div class="search_input">
......
<div class="box_cityjobs">
<div class="box_cityjobs_name">
<%= link_to industry, "jobs/industry/#{industry}",class: 'cityjobs_link' %>
</div>
<div class="box_cityjobs_count">
<span><%= jobs_count %> Công việc</span>
</div>
</div>
\ No newline at end of file
<% provide(:title,'Top nghành') %>
<%= render 'shared/scroll_top' %>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="title_list_city title_list_city_vn">
<span>Top nghành</span>
</div>
</div>
<div class="container">
<div class="row">
<% @data_industries_hot.each do |k,v| %>
<div class="col-lg-3 col-md-4">
<%= render 'block_industries_hot', industry: k, jobs_count: v %>
</div>
<% end %>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-sm-12">
<div class="aaa">
<% @fill_data.each do |data| %>
<div class="box_jobs">
<div class="col-sm-12 d-block d-sm-none">
<button type="submit" class="btn_favorite_outline xs">
<i class="far fa-heart"></i>
</button>
</div>
<div class="row">
<div class="col-sm-10 col-md-9 col-lg-10">
<div class="box_info">
<div class="lol">
<%= link_to data.name, "/detail/#{data.id}" , class: 'job_name' %>
</div>
<div class="cop">
<h5 class="box_info_copany_name"><i class="far fa-building"></i> <%= data.company.name %></h5>
</div>
<div class="loc">
<h5 class="box_info_location"><i class="fas fa-map-marker-alt"></i>
<% dt = [] %>
<% data.cities.each do |x| %>
<% dt << (x.name << ' | ') %>
<% end %>
<%= dt.join('').chomp('| ')%>
</h5>
</div>
<h5 class="box_info_salary"><i class="fas fa-dollar-sign"></i>&nbsp; Lương: <%= data.salary %></h5>
<div class="coc">
<h5 class="box_info_des"><%= strip_tags(data.description) %></h5>
</div>
</div>
</div>
<div class="col-sm-2 col-md-3 d-none d-sm-block col-lg-2">
<div class="box_btn_favotite">
<button type="submit" class="btn_favorite_outline">
<i class="far fa-heart"></i> Yêu thích
</button>
<button type="submit" class="btn_favorite_outline small">
<i class="far fa-heart"></i>
</button>
</div>
</div>
</div>
</div>
<%end%>
</div>
</div>
</div>
</div>
\ No newline at end of file
<% provide(:title, @job.name) %>
<div class="container">
<div class="banner_detail">
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<%= render_breadcrumbs :tag => :li, :separator => "/" %>
</ol>
</nav>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-9">
<div class="job_title">
<h1><%= @job.name %></h1>
<span><i class="far fa-building"></i> <%= link_to @job.company.name, "/jobs/company/#{@job.company.name}",class: "link_ct apply_job"%></span>
</div>
</div>
<div class="col-lg-3 ">
<div class="btn_apply_job">
<%= link_to 'Nộp CV ngay', '#', class: "btn btn-apply_job" %>
</div>
</div>
<div class="col-lg-12 col-md-12">
<div class="box_detail_jobs">
<div class="box_detail_jobs_location">
<span><i class="fas fa-map-marker-alt"></i> Địa điểm làm việc: </span>
<% dt = [] %>
<% @job.cities.each do |x| %>
<%= link_to "&nbsp;#{x.name}&nbsp; ".html_safe , '#', class: "link_ct apply_job link_optimize"%>
<% end %>
</div>
<div class="box_detail_jobs_salary">
<br>
<div class="row">
<div class="col-lg-4 col-md-6">
<div class="detail_info">
<span><i class="fab fa-linode"></i> Lương: <%= @job.salary%></span>
</div>
</div>
<div class="col-lg-4 col-md-6">
<div class="detail_info">
<span><i class="fab fa-linode"></i> Ngày đăng tin: <%=@job.created_at.strftime('%d - %m - %Y')%></span>
</div>
</div>
<div class="col-lg-4 col-md-6">
<div class="detail_info">
<% if @job.expiration_date.present? %>
<span><i class="fab fa-linode"></i> Ngày hết hạn: <%=@job.expiration_date.strftime('%d - %m - %Y')%></span>
<% else %>
<span><i class="fab fa-linode"></i> Ngày hết hạn: đang cập nhật</span>
<% end %>
</div>
</div>
<div class="col-lg-4 col-md-6">
<div class="detail_info">
<span><i class="fab fa-linode"></i> Kinh nghiệm: <%=@job.experience%></span>
</div>
</div>
<div class="col-lg-4 col-md-6">
<div class="detail_info">
<span><i class="fab fa-linode"></i> Cấp bậc: <%= "#{@job.level}" %></span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-12 col-md-12">
<div class="box_detail_jobs">
<% if @job.description.include?('div') %>
<%= @job.description.html_safe %>
<% else %>
<pre class="pre_desc"><%= @job.description %></pre>
<% end %>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-6">
<div class="btn_apply_job">
<%= link_to 'Nộp CV ngay', '#', class: "btn btn-apply_job" %>
</div>
</div>
<div class="col-lg-6 col-md-6">
<div class="btn_apply_job">
<%= link_to 'Yêu thích', '#', class: "btn btn-apply_job_favorite" %>
</div>
</div>
</div>
</div>
<%= render 'shared/scroll_top' %>
\ No newline at end of file
<% provide(:title ,'Kết quả tìm kiếm') %>
<%= render 'home/banner_and_search' %>
<div class="padding_index"></div>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="breadcrumb_total_search">
<% if params[:key_city].present? %>
<span class="breadcrumb-item active">&nbsp;<b><%= @fill_data.total_count %></b>&nbsp;kết quả phù hợp với từ khóa&nbsp;<b><%= params[:key_city] %></b>&nbsp;</span>
<% elsif params[:key_industry].present? %>
<span class="breadcrumb-item active">&nbsp;<b><%= @fill_data.total_count%></b>&nbsp;kết quả phù hợp với từ khóa&nbsp;<b><%= params[:key_industry] %></b>&nbsp;</span>
<% else %>
<span class="breadcrumb-item active">&nbsp;<b><%= @fill_data.total_count%></b>&nbsp;kết quả phù hợp với từ khóa&nbsp;<b><%= params[:key_company] %></b>&nbsp;</span>
<% end %>
</div>
</div>
<div class="col-lg-12">
<div class="breadcrumb_total_search_pagination_jobs">
<div class="pagination_jobs">
<div class="paginator">
<%= paginate @fill_data, remote: true %>
</div>
</div>
</div>
</div>
</div>
</div>
<%= render 'block_info_job' %>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="col-lg-12">
<div class="breadcrumb_total_search_pagination_jobs">
<div class="pagination_jobs">
<div class="paginator">
<%= paginate @fill_data, remote: true %>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<%= render 'shared/scroll_top' %>
\ No newline at end of file
$('body .aaa').html("<%= j render('block_info_job', data: @fill_data) %>");
$(".paginator").html("<%= j paginate(@fill_data, remote: true) %>");
\ No newline at end of file
<li class="page-item">
<%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link' %>
</li>
<li class='page-item disabled'>
<%= link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link' %>
</li>
<li class="page-item">
<%= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, remote: remote, class: 'page-link' %>
</li>
<li class="page-item">
<%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote, class: 'page-link' %>
</li>
<% if page.current? %>
<li class="page-item active">
<%= content_tag :a, page, data: { remote: remote }, rel: page.rel, class: 'page-link' %>
</li>
<% else %>
<li class="page-item">
<%= link_to page, url, remote: remote, rel: page.rel, class: 'page-link' %>
</li>
<% end %>
<%= paginator.render do %>
<nav>
<ul class="pagination">
<%= first_page_tag unless current_page.first? %>
<%= prev_page_tag unless current_page.first? %>
<% each_page do |page| %>
<% if page.left_outer? || page.right_outer? || page.inside_window? %>
<%= page_tag page %>
<% elsif !page.was_truncated? -%>
<%= gap_tag %>
<% end %>
<% end %>
<%= next_page_tag unless current_page.last? %>
<%= last_page_tag unless current_page.last? %>
</ul>
</nav>
<% end %>
<li class="page-item">
<%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote, class: 'page-link' %>
</li>
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
<%= csp_meta_tag %> <%= csp_meta_tag %>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/js/all.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.7/css/all.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.7/css/all.css">
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@200&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Raleway:wght@200&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Raleway&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Raleway&display=swap" rel="stylesheet">
......
<div class="box_info_city"> <div class="box_info_city">
<div class="ct_name"> <div class="ct_name">
<%= link_to name_city, '#' ,class: 'link_ct'%> <%= link_to name_city, "/jobs/city/#{name_city}" ,class: 'link_ct'%>
</div> </div>
<div class="ct_jobs_count"> <div class="ct_jobs_count">
<%= link_to "#{jobs_count} công việc", '#' ,class: 'link_ct'%> <%= link_to "#{jobs_count} công việc", "/jobs/city/#{name_city}" ,class: 'link_ct'%>
</div> </div>
</div> </div>
\ No newline at end of file
<div class="box_info_city"> <div class="box_info_city">
<div class="ct_name"> <div class="ct_name">
<%= link_to industry, '#' ,class: 'link_ct'%> <%= link_to industry, "/jobs/industry/#{industry}",class: 'link_ct'%>
</div> </div>
<div class="ct_jobs_count"> <div class="ct_jobs_count">
<%= link_to "#{jobs_count} công việc", '#' ,class: 'link_ct'%> <%= link_to "#{jobs_count} công việc", "/jobs/industry/#{industry}",class: 'link_ct'%>
</div> </div>
</div> </div>
\ No newline at end of file
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<div class="box_info"> <div class="box_info">
<div class="lol"> <div class="lol">
<!-- <%= image_tag 'trophy',class: 'img_job_name' %> --> <!-- <%= image_tag 'trophy',class: 'img_job_name' %> -->
<%= link_to val.name, '#', class: 'job_name' %> <%= link_to val.name, "/detail/#{val.id}" , class: 'job_name' %>
</div> </div>
<div class="cop"> <div class="cop">
<h5 class="box_info_copany_name"><i class="far fa-building"></i> <%= val.company.name %></h5> <h5 class="box_info_copany_name"><i class="far fa-building"></i> <%= val.company.name %></h5>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
</div> </div>
<% end %> <% end %>
<div class="col-lg-4 col-md-4 col-sm-6 col-xs-12"> <div class="col-lg-4 col-md-4 col-sm-6 col-xs-12">
<%= render 'shared/load_more_city' %> <%= render 'shared/load_more_industries' %>
</div> </div>
</div> </div>
</div> </div>
......
<div class="box_info_city"> <div class="box_info_city">
<div class="ct_name"> <div class="ct_name">
<%= link_to 'Xem Thêm', '#' ,class: 'link_ct'%> <%= link_to 'Xem Thêm', cities_path ,class: 'link_ct'%>
</div> </div>
<div class="ct_jobs_count"> <div class="ct_jobs_count">
<i class="fas fa-ellipsis-h"></i> <i class="fas fa-ellipsis-h"></i>
......
<div class="box_info_city">
<div class="ct_name">
<%= link_to 'Xem Thêm', industries_path ,class: 'link_ct'%>
</div>
<div class="ct_jobs_count">
<i class="fas fa-ellipsis-h"></i>
</div>
</div>
\ No newline at end of file
crumb :root do
link "Home", root_path
end
# crumb :projects do
# link "Projects", projects_path
# end
# crumb :project do |project|
# link project.name, project_path(project)
# parent :projects
# end
# crumb :project_issues do |project|
# link "Issues", project_issues_path(project)
# parent :project, project
# end
# crumb :issue do |issue|
# link issue.title, issue_path(issue)
# parent :project_issues, issue.project
# end
# If you want to split your breadcrumbs configuration over multiple files, you
# can create a folder named `config/breadcrumbs` and put your configuration
# files there. All *.rb files (e.g. `frontend.rb` or `products.rb`) in that
# folder are loaded and reloaded automatically when you change them, just like
# this file (`config/breadcrumbs.rb`).
\ No newline at end of file
...@@ -14,7 +14,7 @@ default: &default ...@@ -14,7 +14,7 @@ default: &default
encoding: utf8 encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root username: root
password: '1' password: '12345678'
socket: /var/run/mysqld/mysqld.sock socket: /var/run/mysqld/mysqld.sock
......
# frozen_string_literal: true
Kaminari.configure do |config|
# config.default_per_page = 20
# config.max_per_page = nil
# config.window = 4
# config.outer_window = 0
# config.left = 0
# config.right = 0
# config.page_method_name = :page
# config.param_name = :page
# config.max_pages = nil
# config.params_on_first_page = false
end
...@@ -30,4 +30,4 @@ ...@@ -30,4 +30,4 @@
# available at http://guides.rubyonrails.org/i18n.html. # available at http://guides.rubyonrails.org/i18n.html.
en: en:
hello: "Hello world" hello: "Hello world"
\ No newline at end of file
Rails.application.routes.draw do Rails.application.routes.draw do
get 'ftp/upload'
post 'ftp/new'
get 'ftp/new', to: 'ftp#index'
match '/ftp', to: 'ftp#index', via: 'get'
post 'ftp/new'
# match '/ftp', to: 'ftp#index', via: 'post' root 'home#index'
# get 'home/index'
root 'home#index' # match 'jobs', to: 'job#index', via: 'get'
match 'detail/:id', to: 'job#detail', via: 'get'
match 'jobs/city/(:key_city)', to: 'job#find_data_by_city', via: 'get', constraints: { key_city: /.*/}
match 'jobs/industry/(:key_industry)', to: 'job#find_data_by_industry', via: 'get', constraints: { key_industry: /.*/}
match 'jobs/company/(:key_company)', to: 'job#find_data_by_company', via: 'get', constraints: { key_company: /.*/}
match 'cities', to: 'city#index', via: 'get'
match 'industries', to: 'industry#index', via: 'get'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end end
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -29,3 +29,50 @@ Mysql2::Error::ConnectionError: MySQL server has gone away ...@@ -29,3 +29,50 @@ Mysql2::Error::ConnectionError: MySQL server has gone away
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>' /home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>'
Tasks: TOP => crawler:populate Tasks: TOP => crawler:populate
(See full trace by running task with --trace) (See full trace by running task with --trace)
rake aborted!
SocketError: Failed to open TCP connection to careerbuilder.vn:443 (getaddrinfo: Temporary failure in name resolution)
/home/hungnt/venjob/lib/src/interface_web.rb:40:in `craw_data_cities'
/home/hungnt/venjob/lib/tasks/crawler.rake:7:in `block (2 levels) in <main>'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `load'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>'
Caused by:
SocketError: getaddrinfo: Temporary failure in name resolution
/home/hungnt/venjob/lib/src/interface_web.rb:40:in `craw_data_cities'
/home/hungnt/venjob/lib/tasks/crawler.rake:7:in `block (2 levels) in <main>'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `load'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>'
Tasks: TOP => crawler:populate
(See full trace by running task with --trace)
rake aborted!
Net::OpenTimeout: execution expired
/home/hungnt/venjob/lib/src/interface_web.rb:40:in `craw_data_cities'
/home/hungnt/venjob/lib/tasks/crawler.rake:7:in `block (2 levels) in <main>'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `load'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>'
Tasks: TOP => crawler:populate
(See full trace by running task with --trace)
rake aborted!
Net::OpenTimeout: execution expired
/home/hungnt/venjob/lib/src/interface_web.rb:40:in `craw_data_cities'
/home/hungnt/venjob/lib/tasks/crawler.rake:7:in `block (2 levels) in <main>'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `load'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>'
Tasks: TOP => crawler:populate
(See full trace by running task with --trace)
rake aborted!
Net::OpenTimeout: execution expired
/home/hungnt/venjob/lib/src/interface_web.rb:40:in `craw_data_cities'
/home/hungnt/venjob/lib/tasks/crawler.rake:7:in `block (2 levels) in <main>'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `load'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>'
Tasks: TOP => crawler:populate
(See full trace by running task with --trace)
rake aborted!
Net::OpenTimeout: execution expired
/home/hungnt/venjob/lib/src/interface_web.rb:40:in `craw_data_cities'
/home/hungnt/venjob/lib/tasks/crawler.rake:7:in `block (2 levels) in <main>'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `load'
/home/hungnt/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>'
Tasks: TOP => crawler:populate
(See full trace by running task with --trace)
=> 2020-07-26 00:45:16 +0700 IMPORT SUCCESS
\ No newline at end of file
...@@ -21,7 +21,7 @@ class FtpSever ...@@ -21,7 +21,7 @@ class FtpSever
end end
def self.data_csv def self.data_csv
donwload_csv() # donwload_csv()
table = CSV.parse(File.read("lib/csv/jobs.csv"), headers: true) table = CSV.parse(File.read("lib/csv/jobs.csv"), headers: true)
end end
...@@ -71,7 +71,7 @@ class FtpSever ...@@ -71,7 +71,7 @@ class FtpSever
def self.parse_csv_jobs(data) def self.parse_csv_jobs(data)
Job.update_all(newdata: 0) Job.update_all(newdata: 0)
data['name'].each_with_index do |name, index| data['name'].each_with_index do |name, index|
desc = (data['requirement'][index]).to_s + '\n' << (data['description'][index]).to_s desc = (data['requirement'][index]).to_s << (data['description'][index]).to_s
id_company = Company.find_by name: data['company name'][index].to_s.strip id_company = Company.find_by name: data['company name'][index].to_s.strip
id_company = id_company.blank? ? 1 : id_company.id id_company = id_company.blank? ? 1 : id_company.id
begin begin
......
...@@ -52,9 +52,10 @@ class InterfaceWeb ...@@ -52,9 +52,10 @@ class InterfaceWeb
city.name = val city.name = val
city.area = area city.area = area
end end
end end
end end
@logger ||= Logger.new("#{Rails.root}/log/bug_crawler.log")
def self.craw_data_companies def self.craw_data_companies
puts 'Crawl data companies' puts 'Crawl data companies'
link_crawl = get_link_job_and_companies link_crawl = get_link_job_and_companies
...@@ -72,31 +73,41 @@ class InterfaceWeb ...@@ -72,31 +73,41 @@ class InterfaceWeb
address = page.search(".company-info .info .content p:nth-child(3)").text address = page.search(".company-info .info .content p:nth-child(3)").text
desc = page.search(".main-about-us .content").text desc = page.search(".main-about-us .content").text
end end
if (name.present? && address.present? && desc.present?) begin
Company.find_or_create_by(name: name.strip) do |company| if (name.present? && address.present? && desc.present?)
company.name = name.strip Company.find_or_create_by(name: name.strip) do |company|
company.address = address company.name = name.strip
company.short_description = desc company.address = address
end company.short_description = desc
puts name end
end puts name
end
rescue => exception
@logger.error "#{exception.message} - Link: #{url}"
end
end end
end end
@logger_jobs ||= Logger.new("#{Rails.root}/log/bug_crawler_jobs.log")
def self.add_data(name, company_name, city_name, created_date, expiration_date, salary, industry_name, description, level, exprience) def self.add_data(name, company_name, city_name, created_date, expiration_date, salary, industry_name, description, level, exprience)
id_company = Company.find_by name: company_name begin
id_company = id_company.present? ? id_company.id : 1 id_company = Company.find_by name: company_name
id_job = Job.create!(name: name, id_company = id_company.present? ? id_company.id : 1
company_id: id_company, id_job = Job.create!(name: name,
level: level, company_id: id_company,
experience: exprience, level: level,
salary: salary, experience: exprience,
create_date: created_date, salary: salary,
expiration_date: expiration_date, create_date: created_date,
description: description) expiration_date: expiration_date,
make_foreign_industries_table(industry_name, id_job.id) description: description)
make_foreign_cities_table(city_name, id_job.id) make_foreign_industries_table(industry_name, id_job.id)
make_foreign_cities_table(city_name, id_job.id)
rescue => exception
@logger_jobs.error "#{exception.message} - Job: #{name} - Company_id: #{id_company}"
end
end end
def self.crawl_data_jobs_interface_1(page) def self.crawl_data_jobs_interface_1(page)
...@@ -114,15 +125,15 @@ class InterfaceWeb ...@@ -114,15 +125,15 @@ class InterfaceWeb
industries = page.search(".item-blue .detail-box:nth-child(1) ul li:nth-child(2) a").text industries = page.search(".item-blue .detail-box:nth-child(1) ul li:nth-child(2) a").text
industries = industries.delete!("[\n,\t,\r]").split(' ').select { |v| v != ''} industries = industries.delete!("[\n,\t,\r]").split(' ').select { |v| v != ''}
industry_name = industries.join(',') industry_name = industries.join(',')
description = page.search(".tabs .tab-content .detail-row:nth-child(n)").to_s.delete!("[\n,\t,\r]") description = page.search(".tabs .tab-content .detail-row:nth-child(n)").to_s
get_level = page.search(".item-blue .detail-box:last ul li:nth-child(3)").text.delete!("[\n,\t,\r]").lstrip.split('Cấp bậc') get_level = page.search(".item-blue .detail-box:last ul li:nth-child(3)").text.delete!("[\n,\t,\r]").lstrip.split('Cấp bậc')
get_level = get_level[1].to_s.strip get_level = get_level[1].to_s.strip
if get_level == "" if get_level.blank?
g_level = page.search(".item-blue .detail-box:last ul li:nth-child(2)").text.delete!("[\n,\t,\r]").lstrip.split('Cấp bậc') g_level = page.search(".item-blue .detail-box:last ul li:nth-child(2)").text.delete!("[\n,\t,\r]").lstrip.split('Cấp bậc')
level = g_level[1].to_s.strip level = g_level[1].to_s.strip
else else
g_level = get_level g_level = get_level
level = g_level[1].to_s.strip level = g_level
end end
exp = page.search(".item-blue .detail-box:last ul li:nth-child(2)").text.delete!("[\n,\t,\r]").split('Kinh nghiệm') exp = page.search(".item-blue .detail-box:last ul li:nth-child(2)").text.delete!("[\n,\t,\r]").split('Kinh nghiệm')
exp = exp[1].to_s.strip exp = exp[1].to_s.strip
...@@ -148,7 +159,7 @@ class InterfaceWeb ...@@ -148,7 +159,7 @@ class InterfaceWeb
end end
salary = page.search(".info li:nth-child(3)").text.split("Lương").last.strip salary = page.search(".info li:nth-child(3)").text.split("Lương").last.strip
industry_name = page.search(".info li:nth-child(5) .value").text industry_name = page.search(".info li:nth-child(5) .value").text
description = page.search(".left-col").to_s.delete!("[\n,\t,\r]") description = page.search(".left-col").to_s
lv = page.search(".boxtp .info li:nth-child(2)").text lv = page.search(".boxtp .info li:nth-child(2)").text
if lv.blank? if lv.blank?
level = "" level = ""
...@@ -173,7 +184,7 @@ class InterfaceWeb ...@@ -173,7 +184,7 @@ class InterfaceWeb
expiration_date = page.search(".DetailJobNew li:nth-child(9) span").text.strip expiration_date = page.search(".DetailJobNew li:nth-child(9) span").text.strip
salary = page.search(".DetailJobNew li:nth-child(3) span").text.strip salary = page.search(".DetailJobNew li:nth-child(3) span").text.strip
industry_name = page.search(".DetailJobNew li:nth-child(2) span").text.strip industry_name = page.search(".DetailJobNew li:nth-child(2) span").text.strip
description = page.search(".left-col .detail-row").to_s.delete!("[\n,\t,\r]") description = page.search(".left-col .detail-row")
level = page.search(".DetailJobNew ul li:nth-child(6) span").text.strip level = page.search(".DetailJobNew ul li:nth-child(6) span").text.strip
exprience = page.search(".DetailJobNew li:nth-child(5) span").text.strip exprience = page.search(".DetailJobNew li:nth-child(5) span").text.strip
add_data(name, company_name, city_name, created_date, expiration_date, salary, industry_name, description, level, exprience) add_data(name, company_name, city_name, created_date, expiration_date, salary, industry_name, description, level, exprience)
......
...@@ -8,7 +8,7 @@ namespace :crawler do ...@@ -8,7 +8,7 @@ namespace :crawler do
InterfaceWeb.craw_data_companies() InterfaceWeb.craw_data_companies()
InterfaceWeb.make_data() InterfaceWeb.make_data()
File.open('log/crawler.log','a') do |f| File.open('log/crawler.log','a') do |f|
f.puts "#{Time.now} - INFO: OK" f.puts "#{Time.now} - INFO: Crawler data don't have error!"
end end
end end
end end
require 'test_helper'
class CityControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
get city_index_url
assert_response :success
end
end
require 'test_helper'
class IndustryControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
get industry_index_url
assert_response :success
end
end
require 'test_helper'
class JobControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
get job_index_url
assert_response :success
end
test "should get detail" do
get job_detail_url
assert_response :success
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment