educode_sales 1.10.21 → 1.10.23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/educode_sales/ideas_controller.rb +36 -10
- data/app/controllers/educode_sales/sale_trends_controller.rb +102 -0
- data/app/helpers/educode_sales/sale_trends_helper.rb +80 -0
- data/app/models/educode_sales/sale_trend.rb +2 -0
- data/app/views/educode_sales/ideas/_index.html.erb +37 -1
- data/app/views/educode_sales/ideas/assign.html.erb +45 -0
- data/app/views/educode_sales/ideas/assign_sale_staff.html.erb +45 -0
- data/app/views/educode_sales/ideas/edit.html.erb +9 -9
- data/app/views/educode_sales/ideas/new.html.erb +9 -9
- data/app/views/educode_sales/sale_trends/_visit_analysis.html.erb +187 -0
- data/app/views/educode_sales/sale_trends/trends.html.erb +6 -0
- data/app/views/educode_sales/sale_trends/visit_analysis.js.erb +1 -0
- data/config/routes.rb +5 -0
- data/lib/educode_sales/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac157bfbdbc5c1aceeef3b0d0af4b81e74b6835ddda09a5beae4188f23720391
|
4
|
+
data.tar.gz: a4f7c4077fc9af0f5374fc3efec8bf42e5c3a57a27dc78090a5727cabe2f5510
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 804531ab845025fe61054b79b248a5f1f83e4194d0c23cad2f0fb4c49978db71eb695815723d50e7255fa35a4aa0b0154babb156fdd5cd953808bb2a1b56a9e9
|
7
|
+
data.tar.gz: 13484d3b014be703413f41b03938881aeb56bd1b7cf97f721f055f9a0aa869dfedc6b948ddbd57bb7b3174c2e3aa171dc7efa5823821f3e2b903e1e1ec9b2591
|
@@ -3,7 +3,35 @@ require_dependency "educode_sales/application_controller"
|
|
3
3
|
module EducodeSales
|
4
4
|
class IdeasController < ApplicationController
|
5
5
|
|
6
|
-
before_action :find_idea, only: [:edit, :destroy, :detail, :history, :update]
|
6
|
+
before_action :find_idea, only: [:edit, :destroy, :detail, :history, :update, :assign, :assign_staff, :assign_sale_staff, :update_sale_staff]
|
7
|
+
|
8
|
+
def assign
|
9
|
+
selected_staff_ids = @idea.assist_staff_ids.map(&:to_i)
|
10
|
+
staffs = Staff.where.not(role_id: 11).includes(:user)
|
11
|
+
gon.ideas_staffs = staffs.map { |d| { name: d.user.real_name, value: d.id, selected: selected_staff_ids.include?(d.id) } }
|
12
|
+
render layout: false
|
13
|
+
end
|
14
|
+
|
15
|
+
# 指派协作人 assist_staff_ids协作人
|
16
|
+
def assign_staff
|
17
|
+
@idea.assist_staff_ids = params[:to_id].to_s.split(",")
|
18
|
+
@idea.save
|
19
|
+
render_success
|
20
|
+
end
|
21
|
+
|
22
|
+
def assign_sale_staff
|
23
|
+
selected_staff_ids = Array(@idea.staff_id)
|
24
|
+
staffs = Staff.where.not(role_id: 11).includes(:user)
|
25
|
+
gon.sales_staffs = staffs.map { |d| { name: d.user.real_name, value: d.id, selected: selected_staff_ids.include?(d.id) } }
|
26
|
+
render layout: false
|
27
|
+
end
|
28
|
+
|
29
|
+
# 指派方案经理 staff_id
|
30
|
+
def update_sale_staff
|
31
|
+
@idea.staff_id = params[:to_id]
|
32
|
+
@idea.save
|
33
|
+
render_success
|
34
|
+
end
|
7
35
|
|
8
36
|
def index
|
9
37
|
respond_to do |format|
|
@@ -24,16 +52,14 @@ module EducodeSales
|
|
24
52
|
level = @current_admin.role.role_areas.find_by(clazz: '方案管理').try(:level)
|
25
53
|
case level
|
26
54
|
when '自己'
|
27
|
-
|
28
|
-
# @businesses = Business.where("educode_sales_businesses.staff_id = ? OR educode_sales_businesses.id in (?)", @current_admin.id, business_ids)
|
29
|
-
idea_ids = Idea.all.select { |d| Array(d.other_staff_ids).include?(@current_admin.id) }.map { |d| d.id }
|
55
|
+
idea_ids = Idea.all.select { |d| Array(d.other_staff_ids).include?(@current_admin.id) || d.sale_staff_id == @current_admin.id || Array(d.assist_staff_ids).include?(@current_admin.id) || d.staff_id == @current_admin.id }.map { |d| d.id }
|
30
56
|
@ideas = Idea.where("educode_sales_ideas.creator_id = ? OR educode_sales_ideas.id in (?)", @current_admin.id, idea_ids)
|
31
57
|
when '区域'
|
32
58
|
# 查看区域商机,需要排除掉其它人员手上的监管学校
|
33
59
|
other_staff_school_id = EducodeSales::StaffSchool.where.not(staff_id: @current_admin.id).where("school_id IN (SELECT school_id FROM educode_sales_staff_schools WHERE staff_id = #{@current_admin.id}) IS NOT TRUE").distinct.pluck :school_id
|
34
60
|
|
35
61
|
school_ids = School.where(province: @current_admin.areas.pluck(:name)).pluck(:id) + StaffSchool.where(staff_id: @current_admin.id).pluck(:school_id) - other_staff_school_id
|
36
|
-
idea_ids = Idea.all.select { |d| Array(d.other_staff_ids).include?(@current_admin.id) }.map { |d| d.id }
|
62
|
+
idea_ids = Idea.all.select { |d| Array(d.other_staff_ids).include?(@current_admin.id) || d.sale_staff_id == @current_admin.id || Array(d.assist_staff_ids).include?(@current_admin.id) || d.staff_id == @current_admin.id }.map { |d| d.id }
|
37
63
|
@ideas = @ideas.joins(department: :school).where("schools.id in (?) OR educode_sales_ideas.creator_id = ? OR educode_sales_ideas.id in (?)", school_ids, @current_admin.id, idea_ids)
|
38
64
|
else
|
39
65
|
@ideas = @ideas
|
@@ -116,8 +142,8 @@ module EducodeSales
|
|
116
142
|
idea.department_id = idea.business&.department_id
|
117
143
|
end
|
118
144
|
idea.attachment_ids = attachment_ids
|
119
|
-
idea.assist_staff_ids = assist_staff_ids
|
120
|
-
idea.other_staff_ids = other_staff_ids
|
145
|
+
# idea.assist_staff_ids = assist_staff_ids
|
146
|
+
# idea.other_staff_ids = other_staff_ids
|
121
147
|
idea.save
|
122
148
|
render_success
|
123
149
|
end
|
@@ -134,11 +160,11 @@ module EducodeSales
|
|
134
160
|
@idea.assign_attributes(idea_params)
|
135
161
|
# @idea.school_id = Department.find_by_id(@idea.department_id)&.school_id
|
136
162
|
assist_staff_ids = Array(params[:assist_staff_ids].to_s.split(","))
|
137
|
-
@idea.assist_staff_ids = assist_staff_ids
|
163
|
+
# @idea.assist_staff_ids = assist_staff_ids
|
138
164
|
attachment_ids = Array(params[:attachment_ids].to_s.split(","))
|
139
165
|
@idea.attachment_ids = attachment_ids
|
140
166
|
other_staff_ids = Array(params[:other_staff_ids].to_s.split(","))
|
141
|
-
@idea.other_staff_ids = other_staff_ids
|
167
|
+
# @idea.other_staff_ids = other_staff_ids
|
142
168
|
if @idea.business_id.present?
|
143
169
|
@idea.school_id = @idea.business&.department&.school_id
|
144
170
|
@idea.department_id = @idea.business&.department_id
|
@@ -267,7 +293,7 @@ module EducodeSales
|
|
267
293
|
params.permit(:name, :level, :staff_id,
|
268
294
|
:status, :types, :model, :hardware, :project,
|
269
295
|
:money, :end_time, :content, :department_id, :school_id,
|
270
|
-
:manager_name, :manager_phone, :school_name, :department_name, :
|
296
|
+
:manager_name, :manager_phone, :school_name, :department_name, :attachment_id, :idea_type, :business_id)
|
271
297
|
end
|
272
298
|
|
273
299
|
def find_idea
|
@@ -417,6 +417,49 @@ module EducodeSales
|
|
417
417
|
end
|
418
418
|
end
|
419
419
|
|
420
|
+
#拜访分析
|
421
|
+
def visit_analysis
|
422
|
+
sort_by = params[:sort_by].present? ? params[:sort_by] : "desc"
|
423
|
+
user_name = params[:user_name]
|
424
|
+
visit_type = params[:visit_type].present? ? params[:visit_type].split(",") : ""
|
425
|
+
title_names = %w[本年拜访数 本季拜访数 本月拜访数 本周拜访数]
|
426
|
+
respond_to do |format|
|
427
|
+
format.js do
|
428
|
+
@user_names = EducodeSales::Attendance.pluck(:name).uniq.map{|d| {name: d, value: d}}
|
429
|
+
@visit_types = SaleTrend::VISIT_TYPE.map {|d| {name: d[0], value: d[1]}}
|
430
|
+
sql = "SELECT name, count(*) as name_count FROM `educode_sales_attendances` WHERE (attendance_date >= '#{Time.now.beginning_of_year}' and attendance_date <= '#{Time.now.end_of_year}') group by name order by name_count desc limit 30"
|
431
|
+
visit_count = EducodeSales::Attendance.find_by_sql(sql).map{|d| [d.name, d.name_count]}
|
432
|
+
#年拜访量前30的用户名
|
433
|
+
top_thirty_username = visit_count.map{ |d| d[0]}
|
434
|
+
@visit_count_data = visit_user_type_name(top_thirty_username, sort_by, visit_type, title_names)
|
435
|
+
end
|
436
|
+
format.json do
|
437
|
+
if params[:user_type].present? && params[:user_type] == "name"
|
438
|
+
if user_name.present?
|
439
|
+
sql_by_name = "SELECT name, count(*) as name_count FROM `educode_sales_attendances` WHERE (attendance_date >= '#{Time.now.beginning_of_year}' and attendance_date <= '#{Time.now.end_of_year}') and name like '%#{user_name}%' group by name"
|
440
|
+
else
|
441
|
+
sql_by_name = "SELECT name, count(*) as name_count FROM `educode_sales_attendances` WHERE (attendance_date >= '#{Time.now.beginning_of_year}' and attendance_date <= '#{Time.now.end_of_year}') group by name order by name_count desc limit 30"
|
442
|
+
end
|
443
|
+
visit_count = EducodeSales::Attendance.find_by_sql(sql_by_name).map{|d| [d.name, d.name_count]}
|
444
|
+
#年拜访量前30的用户名
|
445
|
+
top_thirty_username = visit_count.map{ |d| d[0]}
|
446
|
+
@visit_count_data = visit_user_type_name(top_thirty_username, sort_by, visit_type, title_names)
|
447
|
+
else
|
448
|
+
if user_name.present?
|
449
|
+
sql_by_customer = "SELECT name, customer, count(*) as customer_count FROM `educode_sales_attendances` WHERE (attendance_date >= '#{Time.now.beginning_of_year}' and attendance_date <= '#{Time.now.end_of_year}') and name like '%#{user_name}%' group by customer order by customer_count desc limit 30"
|
450
|
+
else
|
451
|
+
sql_by_customer = "SELECT name, customer, count(*) as customer_count FROM `educode_sales_attendances` WHERE (attendance_date >= '#{Time.now.beginning_of_year}' and attendance_date <= '#{Time.now.end_of_year}') group by customer order by customer_count desc limit 30"
|
452
|
+
end
|
453
|
+
visit_count = EducodeSales::Attendance.find_by_sql(sql_by_customer).map{|d| [d.customer, d.customer_count]}
|
454
|
+
#年拜访量前30的用户名
|
455
|
+
top_thirty_customer = visit_count.map{ |d| d[0]}
|
456
|
+
@visit_count_data = visit_user_type_customer(top_thirty_customer, sort_by, visit_type, title_names)
|
457
|
+
end
|
458
|
+
render json: {data: @visit_count_data }
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
420
463
|
private
|
421
464
|
|
422
465
|
def sale_trend_params
|
@@ -802,5 +845,64 @@ module EducodeSales
|
|
802
845
|
@forecast_count_data_1 = @forecast_count_data[1]
|
803
846
|
end
|
804
847
|
|
848
|
+
def visit_user_type_name(top_thirty_username, sort_by, visit_type, title_names)
|
849
|
+
#本年拜访数
|
850
|
+
visit_count_year = EducodeSales::Attendance.where("name in (?)", top_thirty_username)
|
851
|
+
.where(" attendance_date >= '#{Time.now.beginning_of_year}' and attendance_date <= '#{Time.now.end_of_year}' ")
|
852
|
+
.group(:name).select("name, count(*) name_count").order("name_count #{sort_by}")&.map{ |d| [d.name, d.name_count]}
|
853
|
+
|
854
|
+
#本季拜访数
|
855
|
+
current_year = Time.now.year
|
856
|
+
current_month = Time.now.month
|
857
|
+
start_month = (current_month - 1) / 3 * 3 + 1
|
858
|
+
end_month = start_month + 2
|
859
|
+
start_date = Date.new(current_year, start_month, 1).strftime("%Y-%m-%d") + " 00:00:00"
|
860
|
+
end_date = Date.new(current_year, end_month, -1).strftime("%Y-%m-%d") + " 23:59:59"
|
861
|
+
visit_count_season = EducodeSales::Attendance.where("name in (?)", top_thirty_username)
|
862
|
+
.where("attendance_date >= '#{start_date}' and attendance_date <= '#{end_date}'")
|
863
|
+
.group(:name).select("name, count(*) name_count").order("name_count #{sort_by}")&.map{ |d| [d.name, d.name_count]}
|
864
|
+
|
865
|
+
#本月拜访数
|
866
|
+
visit_count_month = EducodeSales::Attendance.where("name in (?)", top_thirty_username)
|
867
|
+
.where("attendance_date >= '#{Time.now.beginning_of_month}' and attendance_date <= '#{Time.now.end_of_month}'")
|
868
|
+
.group(:name).select("name, count(*) name_count").order("name_count #{sort_by}")&.map{ |d| [d.name, d.name_count]}
|
869
|
+
|
870
|
+
#本周拜访数
|
871
|
+
visit_count_week = EducodeSales::Attendance.where("name in (?)", top_thirty_username)
|
872
|
+
.where("attendance_date >= '#{Time.now.beginning_of_week}' and attendance_date <= '#{Time.now.end_of_week}'")
|
873
|
+
.group(:name).select("name, count(*) name_count").order("name_count #{sort_by}")&.map{ |d| [d.name, d.name_count]}
|
874
|
+
|
875
|
+
visit_analysis_charts(visit_count_year, visit_count_season, visit_count_month, visit_count_week, visit_type, title_names)
|
876
|
+
end
|
877
|
+
|
878
|
+
def visit_user_type_customer(top_thirty_customer, sort_by, visit_type, title_names)
|
879
|
+
#本年拜访数
|
880
|
+
visit_count_year = EducodeSales::Attendance.where("customer in (?)", top_thirty_customer)
|
881
|
+
.where(" attendance_date >= '#{Time.now.beginning_of_year}' and attendance_date <= '#{Time.now.end_of_year}' ")
|
882
|
+
.group(:customer).select("customer, count(*) customer_count").order("customer_count #{sort_by}")&.map{ |d| [d.customer, d.customer_count]}
|
883
|
+
|
884
|
+
#本季拜访数
|
885
|
+
current_year = Time.now.year
|
886
|
+
current_month = Time.now.month
|
887
|
+
start_month = (current_month - 1) / 3 * 3 + 1
|
888
|
+
end_month = start_month + 2
|
889
|
+
start_date = Date.new(current_year, start_month, 1).strftime("%Y-%m-%d") + " 00:00:00"
|
890
|
+
end_date = Date.new(current_year, end_month, -1).strftime("%Y-%m-%d") + " 23:59:59"
|
891
|
+
visit_count_season = EducodeSales::Attendance.where("customer in (?)", top_thirty_customer)
|
892
|
+
.where("attendance_date >= '#{start_date}' and attendance_date <= '#{end_date}'")
|
893
|
+
.group(:customer).select("customer, count(*) customer_count").order("customer_count #{sort_by}")&.map{ |d| [d.customer, d.customer_count]}
|
894
|
+
|
895
|
+
#本月拜访数
|
896
|
+
visit_count_month = EducodeSales::Attendance.where("customer in (?)", top_thirty_customer)
|
897
|
+
.where("attendance_date >= '#{Time.now.beginning_of_month}' and attendance_date <= '#{Time.now.end_of_month}'")
|
898
|
+
.group(:customer).select("customer, count(*) customer_count").order("customer_count #{sort_by}")&.map{ |d| [d.customer, d.customer_count]}
|
899
|
+
|
900
|
+
#本周拜访数
|
901
|
+
visit_count_week = EducodeSales::Attendance.where("customer in (?)", top_thirty_customer)
|
902
|
+
.where("attendance_date >= '#{Time.now.beginning_of_week}' and attendance_date <= '#{Time.now.end_of_week}'")
|
903
|
+
.group(:customer).select("customer, count(*) customer_count").order("customer_count #{sort_by}")&.map{ |d| [d.customer, d.customer_count]}
|
904
|
+
|
905
|
+
visit_analysis_charts(visit_count_year, visit_count_season, visit_count_month, visit_count_week, visit_type, title_names)
|
906
|
+
end
|
805
907
|
end
|
806
908
|
end
|
@@ -247,6 +247,86 @@ module EducodeSales
|
|
247
247
|
[hash_a, hash_b]
|
248
248
|
end
|
249
249
|
|
250
|
+
def visit_analysis_charts(visit_count_year, visit_count_season, visit_count_month, visit_count_week, visit_type, title_names)
|
251
|
+
names = visit_count_year.map{|d| d[0]}
|
252
|
+
|
253
|
+
visit_count_season_data = []
|
254
|
+
names.each do |name|
|
255
|
+
data = visit_count_season.find { |d| d[0] == name}
|
256
|
+
if data
|
257
|
+
visit_count_season_data << data
|
258
|
+
else
|
259
|
+
visit_count_season_data << [name, 0]
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
visit_count_month_data = []
|
264
|
+
names.each do |name|
|
265
|
+
data = visit_count_month.find { |d| d[0] == name}
|
266
|
+
if data
|
267
|
+
visit_count_month_data << data
|
268
|
+
else
|
269
|
+
visit_count_month_data << [name, 0]
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
visit_count_week_data = []
|
274
|
+
names.each do |name|
|
275
|
+
data = visit_count_week.find { |d| d[0] == name}
|
276
|
+
if data
|
277
|
+
visit_count_week_data << data
|
278
|
+
else
|
279
|
+
visit_count_week_data << [name, 0]
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
year = {
|
284
|
+
label: title_names[0],
|
285
|
+
data: visit_count_year.map {|d| d[1].to_i},
|
286
|
+
backgroundColor: 'rgba(255, 99, 132, 1)'}
|
287
|
+
|
288
|
+
season = {
|
289
|
+
label: title_names[1],
|
290
|
+
data: visit_count_season_data.map {|d| d[1].to_i},
|
291
|
+
backgroundColor: 'rgba(255, 159, 64, 1)'}
|
292
|
+
|
293
|
+
month = {
|
294
|
+
label: title_names[2],
|
295
|
+
data:visit_count_month_data.map {|d| d[1].to_i},
|
296
|
+
backgroundColor: 'rgba(54, 162, 235, 1)'}
|
297
|
+
|
298
|
+
week = {
|
299
|
+
label: title_names[3],
|
300
|
+
data: visit_count_week_data.map {|d| d[1].to_i},
|
301
|
+
backgroundColor: 'rgba(153, 102, 255, 1)'}
|
302
|
+
|
303
|
+
final_data = []
|
304
|
+
if visit_type.include?("1")
|
305
|
+
final_data << year
|
306
|
+
end
|
307
|
+
if visit_type.include?("2")
|
308
|
+
final_data << season
|
309
|
+
end
|
310
|
+
if visit_type.include?("3")
|
311
|
+
final_data << month
|
312
|
+
end
|
313
|
+
if visit_type.include?("4")
|
314
|
+
final_data << week
|
315
|
+
end
|
316
|
+
|
317
|
+
if visit_type.present?
|
318
|
+
{
|
319
|
+
labels: names,
|
320
|
+
datasets: final_data
|
321
|
+
}
|
322
|
+
else
|
323
|
+
{
|
324
|
+
labels: names,
|
325
|
+
datasets: [year, season, month, week]
|
326
|
+
}
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
250
330
|
private
|
251
331
|
|
252
332
|
def plan_get(staff_id, time_range, type, property)
|
@@ -9,5 +9,7 @@ module EducodeSales
|
|
9
9
|
'#DC7633', '#839192', '#6C3483', '#B03A2E', '#7B7D7D', '#4D5656', '#28B463', '#0E6655', '#F39C12', '#0E6251', '#1B4F72',
|
10
10
|
'#FAE5D3', '#82E0AA', '#FF00FF', '#663399', '#4B0082', '#7CFC00'
|
11
11
|
]
|
12
|
+
|
13
|
+
VISIT_TYPE = [["本年拜访数", 1],["本季拜访数", 2],["本月拜访数", 3],["本周拜访数", 4]]
|
12
14
|
end
|
13
15
|
end
|
@@ -102,6 +102,8 @@
|
|
102
102
|
<a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="idea_recycle_s">恢复</a>
|
103
103
|
<% end %>
|
104
104
|
{{# }else{}}
|
105
|
+
<a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="assign">指派协作人</a>
|
106
|
+
<a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="assign_sale_staff">指派方案经理</a>
|
105
107
|
<% if can? :add_follow, EducodeSales::Idea %>
|
106
108
|
<a class="layui-btn layui-btn-normal layui-btn-xs data-count-add_follow" lay-event="add_follows">添加跟进</a>
|
107
109
|
<% end %>
|
@@ -256,7 +258,7 @@
|
|
256
258
|
},
|
257
259
|
{
|
258
260
|
title: '操作',
|
259
|
-
minWidth:
|
261
|
+
minWidth: 700,
|
260
262
|
toolbar: '#currentTableBar',
|
261
263
|
align: "center",
|
262
264
|
fixed: 'right'
|
@@ -453,6 +455,40 @@
|
|
453
455
|
$(window).on("resize", function () {
|
454
456
|
layer.full(followup_index);
|
455
457
|
});
|
458
|
+
} else if (obj.event === 'assign') { //协作人
|
459
|
+
var content = miniPage.getHrefContent('/missions/ideas/' + id + '/assign');
|
460
|
+
var openWH = miniPage.getOpenWidthHeight();
|
461
|
+
var name = data.name;
|
462
|
+
sindex = layer.open({
|
463
|
+
title: '指派协作人',
|
464
|
+
type: 1,
|
465
|
+
shade: 0.2,
|
466
|
+
maxmin: true,
|
467
|
+
shadeClose: true,
|
468
|
+
area: ['600px', '300px'],
|
469
|
+
content: content
|
470
|
+
});
|
471
|
+
$(window).on("resize", function () {
|
472
|
+
layer.full(sindex);
|
473
|
+
});
|
474
|
+
return false;
|
475
|
+
} else if (obj.event === 'assign_sale_staff') { //指派方案经理
|
476
|
+
var content = miniPage.getHrefContent('/missions/ideas/' + id + '/assign_sale_staff');
|
477
|
+
var openWH = miniPage.getOpenWidthHeight();
|
478
|
+
var name = data.name;
|
479
|
+
sindex = layer.open({
|
480
|
+
title: "指派方案经理",
|
481
|
+
type: 1,
|
482
|
+
shade: 0.2,
|
483
|
+
maxmin: true,
|
484
|
+
shadeClose: true,
|
485
|
+
area: ['600px', '300px'],
|
486
|
+
content: content
|
487
|
+
});
|
488
|
+
$(window).on("resize", function () {
|
489
|
+
layer.full(sindex);
|
490
|
+
});
|
491
|
+
return false;
|
456
492
|
} else if (obj.event === 'idea_recycle') {
|
457
493
|
layer.confirm('确定删除' + data.name, function (index) {
|
458
494
|
request.delete('missions/ideas/' + id, {}, function (res) {
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<%= Gon::Base.render_data %>
|
2
|
+
<div class="layui-form layuimini-form" style="padding:30px">
|
3
|
+
<div class="layui-form-item">
|
4
|
+
<label class="layui-form-label required">选择协作人:</label>
|
5
|
+
<div class="layui-input-block" style="width: 300px">
|
6
|
+
<div id="sales_staff_id"></div>
|
7
|
+
</div>
|
8
|
+
</div>
|
9
|
+
<hr>
|
10
|
+
<div class="layui-form-item">
|
11
|
+
<div class="layui-input-block">
|
12
|
+
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">确认保存</button>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<script>
|
18
|
+
layui.use(['form', 'table', 'upload', 'laytpl', 'request', 'selectInput'], function () {
|
19
|
+
var form = layui.form,
|
20
|
+
layer = layui.layer,
|
21
|
+
table = layui.table,
|
22
|
+
laytpl = layui.laytpl,
|
23
|
+
request = layui.request,
|
24
|
+
$ = layui.$;
|
25
|
+
|
26
|
+
form.render();
|
27
|
+
staff_list_select = xmSelect.render({
|
28
|
+
el: '#sales_staff_id',
|
29
|
+
data: gon.ideas_staffs,
|
30
|
+
filterable: true,
|
31
|
+
radio: false,
|
32
|
+
})
|
33
|
+
var parentIndex = layer.index;
|
34
|
+
form.on('submit(saveBtn)', function (data) {
|
35
|
+
layer.confirm('确定指派协作人?', function (index) {
|
36
|
+
request.post('missions/ideas/' + parent.id + "/assign_staff", {to_id: staff_list_select.getValue('valueStr')}, function (res) {
|
37
|
+
layer.close(index);
|
38
|
+
layer.close(parentIndex)
|
39
|
+
parent.table.reload('ideas_table')
|
40
|
+
})
|
41
|
+
});
|
42
|
+
return false;
|
43
|
+
});
|
44
|
+
});
|
45
|
+
</script>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<%= Gon::Base.render_data %>
|
2
|
+
<div class="layui-form layuimini-form" style="padding:30px">
|
3
|
+
<div class="layui-form-item">
|
4
|
+
<label class="layui-form-label required">选择方案经理:</label>
|
5
|
+
<div class="layui-input-block" style="width: 300px">
|
6
|
+
<div id="sales_id"></div>
|
7
|
+
</div>
|
8
|
+
</div>
|
9
|
+
<hr>
|
10
|
+
<div class="layui-form-item">
|
11
|
+
<div class="layui-input-block">
|
12
|
+
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">确认保存</button>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<script>
|
18
|
+
layui.use(['form', 'table', 'upload', 'laytpl', 'request', 'selectInput'], function () {
|
19
|
+
var form = layui.form,
|
20
|
+
layer = layui.layer,
|
21
|
+
table = layui.table,
|
22
|
+
laytpl = layui.laytpl,
|
23
|
+
request = layui.request,
|
24
|
+
$ = layui.$;
|
25
|
+
|
26
|
+
form.render();
|
27
|
+
staff_list_select = xmSelect.render({
|
28
|
+
el: '#sales_id',
|
29
|
+
data: gon.sales_staffs,
|
30
|
+
filterable: true,
|
31
|
+
radio: true,
|
32
|
+
})
|
33
|
+
var parentIndex = layer.index;
|
34
|
+
form.on('submit(saveBtn)', function (data) {
|
35
|
+
layer.confirm('确定指派方案经理?', function (index) {
|
36
|
+
request.post('missions/ideas/' + parent.id + "/update_sale_staff", {to_id: staff_list_select.getValue('valueStr')}, function (res) {
|
37
|
+
layer.close(index);
|
38
|
+
layer.close(parentIndex)
|
39
|
+
parent.table.reload('ideas_table')
|
40
|
+
})
|
41
|
+
});
|
42
|
+
return false;
|
43
|
+
});
|
44
|
+
});
|
45
|
+
</script>
|
@@ -41,20 +41,20 @@
|
|
41
41
|
</div>
|
42
42
|
</div>
|
43
43
|
<div class="layui-col-md6">
|
44
|
-
<labeL class="layui-form-label"
|
44
|
+
<labeL class="layui-form-label required">项目名称:</labeL>
|
45
45
|
<div class="layui-input-block">
|
46
|
-
<div id="
|
46
|
+
<div id="business_id" style="width: 600px;"></div>
|
47
47
|
</div>
|
48
48
|
</div>
|
49
|
-
|
50
|
-
|
51
|
-
<div class="layui-col-md6">
|
52
|
-
<labeL class="layui-form-label required">项目名称:</labeL>
|
49
|
+
<div class="layui-col-md6" style="display: none">
|
50
|
+
<labeL class="layui-form-label">协作人:</labeL>
|
53
51
|
<div class="layui-input-block">
|
54
|
-
<div id="
|
52
|
+
<div id="assist_staff_ids"></div>
|
55
53
|
</div>
|
56
54
|
</div>
|
57
|
-
|
55
|
+
</div>
|
56
|
+
<div class="layui-row" style="padding-top: 15px;display: none">
|
57
|
+
<div class="layui-col-md6" style="display: none">
|
58
58
|
<labeL class="layui-form-label">方案经理:</labeL>
|
59
59
|
<div class="layui-input-block">
|
60
60
|
<div id="new_staff_id"></div>
|
@@ -96,7 +96,7 @@
|
|
96
96
|
<%= select_tag "idea_type", options_for_select(EducodeSales::Idea.idea_types.keys, @idea&.idea_type), { 'lay-filter': 'idea_type', include_blank: false } %>
|
97
97
|
</div>
|
98
98
|
</div>
|
99
|
-
<div class="layui-col-md6">
|
99
|
+
<div class="layui-col-md6" style="display: none">
|
100
100
|
<labeL class="layui-form-label">指派人:</labeL>
|
101
101
|
<div class="layui-input-block">
|
102
102
|
<div id="other_staff_ids"></div>
|
@@ -41,20 +41,20 @@
|
|
41
41
|
</div>
|
42
42
|
</div>
|
43
43
|
<div class="layui-col-md6">
|
44
|
-
<labeL class="layui-form-label"
|
44
|
+
<labeL class="layui-form-label required">项目名称:</labeL>
|
45
45
|
<div class="layui-input-block">
|
46
|
-
<div id="
|
46
|
+
<div id="business_id" style="width: 600px;"></div>
|
47
47
|
</div>
|
48
48
|
</div>
|
49
|
-
|
50
|
-
|
51
|
-
<div class="layui-col-md6">
|
52
|
-
<labeL class="layui-form-label required">项目名称:</labeL>
|
49
|
+
<div class="layui-col-md6" style="display: none">
|
50
|
+
<labeL class="layui-form-label">协作人:</labeL>
|
53
51
|
<div class="layui-input-block">
|
54
|
-
<div id="
|
52
|
+
<div id="assist_staff_ids"></div>
|
55
53
|
</div>
|
56
54
|
</div>
|
57
|
-
|
55
|
+
</div>
|
56
|
+
<div class="layui-row" style="padding-top: 15px;display: none">
|
57
|
+
<div class="layui-col-md6" style="display: none">
|
58
58
|
<labeL class="layui-form-label">方案经理:</labeL>
|
59
59
|
<div class="layui-input-block">
|
60
60
|
<div id="new_staff_id"></div>
|
@@ -96,7 +96,7 @@
|
|
96
96
|
<%= select_tag "idea_type", options_for_select(EducodeSales::Idea.idea_types.keys, @idea&.idea_type), { 'lay-filter': 'idea_type', include_blank: false } %>
|
97
97
|
</div>
|
98
98
|
</div>
|
99
|
-
<div class="layui-col-md6">
|
99
|
+
<div class="layui-col-md6" style="display: none">
|
100
100
|
<labeL class="layui-form-label">指派人:</labeL>
|
101
101
|
<div class="layui-input-block">
|
102
102
|
<div id="other_staff_ids"></div>
|
@@ -0,0 +1,187 @@
|
|
1
|
+
<div id="tab_8">
|
2
|
+
<div class="" style="padding-right: 50px">
|
3
|
+
<div style="margin: 10px 10px 10px 10px">
|
4
|
+
<form class="layui-form layui-form-pane" lay-filter="search_visit_form">
|
5
|
+
<div class="layui-form-item">
|
6
|
+
<div class="layui-inline m-t-10">
|
7
|
+
<label class="layui-form-label">维度</label>
|
8
|
+
<div class="layui-input-inline">
|
9
|
+
<%= select_tag "user_type", options_for_select([['按销售经理','name'],['按客户','customer']],params[:user_type]), {'lay-filter': 'user_type'}%>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
<div class="layui-inline m-t-10">
|
13
|
+
<label class="layui-form-label">拜访统计</label>
|
14
|
+
<div class="layui-input-inline">
|
15
|
+
<div id="visit_type"></div>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
<div class="layui-inline m-t-10">
|
19
|
+
<label class="layui-form-label">销售经理</label>
|
20
|
+
<div class="layui-input-inline">
|
21
|
+
<div id="user_name"></div>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
<div class="layui-inline m-t-10">
|
25
|
+
<label class="layui-form-label">排序</label>
|
26
|
+
<div class="layui-input-inline">
|
27
|
+
<%= select_tag "sort_by", options_for_select([['', ''], ['升序', 'asc'], ['降序', 'desc']], params[:sort_by]), { include_blank: true } %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
<div class="layui-inline">
|
31
|
+
<button type="reset" class="layui-btn layui-btn-primary" lay-submit lay-filter="reset_visit_search">重 置</button>
|
32
|
+
<button type="submit" class="layui-btn layui-btn-primary" lay-submit lay-filter="search_visit">搜 索</button>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</form>
|
36
|
+
</div>
|
37
|
+
<canvas id="visit_myChart" width="960" height="350"></canvas>
|
38
|
+
<div class="two-header" style="margin-top: 30px;">
|
39
|
+
<table id="visit_table" lay-filter="visit_table"></table>
|
40
|
+
</div>
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
<script>
|
44
|
+
layui.use(['form', 'jquery', 'request', 'element', 'laydate', 'table', 'miniPage'], function () {
|
45
|
+
var $ = layui.jquery,
|
46
|
+
form = layui.form,
|
47
|
+
table = layui.table,
|
48
|
+
request = layui.request;
|
49
|
+
|
50
|
+
//拜访统计选择
|
51
|
+
var visit_type_select = xmSelect.render({
|
52
|
+
el: '#visit_type',
|
53
|
+
name: 'visit_type',
|
54
|
+
data: <%=raw @visit_types.to_json %>,
|
55
|
+
});
|
56
|
+
//销售经理选择
|
57
|
+
var user_name_select = xmSelect.render({
|
58
|
+
el: '#user_name',
|
59
|
+
name: 'user_name',
|
60
|
+
data: <%=raw @user_names.to_json %>,
|
61
|
+
filterable: true,
|
62
|
+
radio: true
|
63
|
+
});
|
64
|
+
|
65
|
+
var options = {
|
66
|
+
events: false,
|
67
|
+
scales: {
|
68
|
+
yAxes: [{
|
69
|
+
ticks: {
|
70
|
+
suggestedMin: 0,
|
71
|
+
suggestedMax: 200,
|
72
|
+
stepSize: 20
|
73
|
+
}
|
74
|
+
}]
|
75
|
+
},
|
76
|
+
hover: {
|
77
|
+
animationDuration: 1
|
78
|
+
},
|
79
|
+
animation: {
|
80
|
+
duration: 1,
|
81
|
+
onComplete: function () {
|
82
|
+
var chartInstance = this.chart,
|
83
|
+
ctx = chartInstance.ctx;
|
84
|
+
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
|
85
|
+
ctx.textAlign = 'center';
|
86
|
+
ctx.textBaseline = 'bottom';
|
87
|
+
|
88
|
+
this.data.datasets.forEach(function (dataset, i) {
|
89
|
+
var meta = chartInstance.controller.getDatasetMeta(i);
|
90
|
+
meta.data.forEach(function (bar, index) {
|
91
|
+
var data = dataset.data[index];
|
92
|
+
ctx.fillText(data, bar._model.x, bar._model.y - 5);
|
93
|
+
});
|
94
|
+
});
|
95
|
+
}
|
96
|
+
}
|
97
|
+
};
|
98
|
+
|
99
|
+
visit_count_data = <%=raw @visit_count_data.to_json %>;
|
100
|
+
|
101
|
+
//条形图
|
102
|
+
var ctx = document.getElementById('visit_myChart').getContext("2d");
|
103
|
+
var visit_myChart = new Chart(ctx, {
|
104
|
+
type: 'bar',
|
105
|
+
data: visit_count_data,
|
106
|
+
options: options
|
107
|
+
});
|
108
|
+
|
109
|
+
//重置按钮
|
110
|
+
form.on('submit(reset_visit_search)', function () {
|
111
|
+
form.val('search_visit_form', {
|
112
|
+
sort_by: ""
|
113
|
+
});
|
114
|
+
visit_type_select.setValue([]);
|
115
|
+
user_name_select.setValue([]);
|
116
|
+
return false;
|
117
|
+
});
|
118
|
+
|
119
|
+
//渲染表格
|
120
|
+
function renderTable(visit_count_data) {
|
121
|
+
var labels = [];
|
122
|
+
fields = [{field: 'col0', title: '', width:100}];
|
123
|
+
visit_count_data.labels.forEach(function (data, i) {
|
124
|
+
labels.push(data);
|
125
|
+
fields.push({field: 'col' + (i + 1), title: data, width: 100, align: 'center'})
|
126
|
+
});
|
127
|
+
var table_data = [];
|
128
|
+
visit_count_data.datasets.forEach(function (visit_data) {
|
129
|
+
var value = {};
|
130
|
+
value['col0'] = visit_data.label;
|
131
|
+
visit_data.data.forEach(function (v, i) {
|
132
|
+
value['col' + (i + 1)] = v
|
133
|
+
});
|
134
|
+
table_data.push(value)
|
135
|
+
});
|
136
|
+
table.render({
|
137
|
+
elem: '#visit_table',
|
138
|
+
height: 230,
|
139
|
+
limit: 1000,
|
140
|
+
page: false,
|
141
|
+
data: table_data,
|
142
|
+
cols: [fields]
|
143
|
+
});
|
144
|
+
}
|
145
|
+
|
146
|
+
renderTable(visit_count_data);
|
147
|
+
form.render();
|
148
|
+
|
149
|
+
//搜索监听
|
150
|
+
form.on("submit(search_visit)", function(data) {
|
151
|
+
var layer_index = layer.load(0, {shade: [0.1, '#fff']});
|
152
|
+
var visit_type_value = [];
|
153
|
+
if (document.getElementById('visit_type')) {
|
154
|
+
visit_type_select.getValue().forEach(function (d) {
|
155
|
+
visit_type_value.push(d.value)
|
156
|
+
})
|
157
|
+
}
|
158
|
+
data.field.visit_type = visit_type_value.join(",");
|
159
|
+
Rails.ajax({
|
160
|
+
url: '/missions/sale_trends/visit_analysis',
|
161
|
+
type: 'GET',
|
162
|
+
dataType: "json",
|
163
|
+
data: $.param(data.field, true),
|
164
|
+
success: function (res) {
|
165
|
+
visit_myChart.data.datasets = res.data.datasets;
|
166
|
+
visit_myChart.data.labels = res.data.labels;
|
167
|
+
visit_myChart.update();
|
168
|
+
renderTable(res.data);
|
169
|
+
layer.close(layer_index);
|
170
|
+
|
171
|
+
}
|
172
|
+
});
|
173
|
+
return false;
|
174
|
+
});
|
175
|
+
});
|
176
|
+
</script>
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
|
@@ -7,6 +7,7 @@
|
|
7
7
|
<li class="">销售人员跟进分析</li>
|
8
8
|
<li class="">中标预测图</li>
|
9
9
|
<li class="">用户分析</li>
|
10
|
+
<li class="">拜访分析</li>
|
10
11
|
</ul>
|
11
12
|
<div class="layui-tab-content">
|
12
13
|
<div class="layui-tab-item layui-show">
|
@@ -238,6 +239,9 @@
|
|
238
239
|
<div class="layui-tab-item">
|
239
240
|
<div id="page_7"></div>
|
240
241
|
</div>
|
242
|
+
<div class="layui-tab-item">
|
243
|
+
<div id="page_8"></div>
|
244
|
+
</div>
|
241
245
|
</div>
|
242
246
|
</div>
|
243
247
|
|
@@ -264,6 +268,8 @@
|
|
264
268
|
loadPage('/missions/sale_trends/goal_forecast')
|
265
269
|
} else if (data.index == 6 && $("#tab_7").length == 0) {
|
266
270
|
loadPage('/missions/sale_trends/user_stat')
|
271
|
+
} else if (data.index == 7 && $("#tab_8").length == 0) {
|
272
|
+
loadPage('/missions/sale_trends/visit_analysis')
|
267
273
|
}
|
268
274
|
});
|
269
275
|
|
@@ -0,0 +1 @@
|
|
1
|
+
$("#page_8").html("<%= j render 'visit_analysis' %>");
|
data/config/routes.rb
CHANGED
@@ -173,6 +173,7 @@ EducodeSales::Engine.routes.draw do
|
|
173
173
|
get :sales_followup_analysis
|
174
174
|
get :goal_forecast
|
175
175
|
get :user_stat
|
176
|
+
get :visit_analysis
|
176
177
|
end
|
177
178
|
end
|
178
179
|
|
@@ -383,6 +384,10 @@ EducodeSales::Engine.routes.draw do
|
|
383
384
|
get :upload_file
|
384
385
|
end
|
385
386
|
member do
|
387
|
+
get :assign
|
388
|
+
post :assign_staff
|
389
|
+
get :assign_sale_staff
|
390
|
+
post :update_sale_staff
|
386
391
|
get :show_schools
|
387
392
|
post :follow_up
|
388
393
|
put :update_advise
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: educode_sales
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.10.
|
4
|
+
version: 1.10.23
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- anke1460
|
@@ -418,6 +418,8 @@ files:
|
|
418
418
|
- app/views/educode_sales/ideas/add_courses.html.erb
|
419
419
|
- app/views/educode_sales/ideas/add_event.html.erb
|
420
420
|
- app/views/educode_sales/ideas/add_keys.html.erb
|
421
|
+
- app/views/educode_sales/ideas/assign.html.erb
|
422
|
+
- app/views/educode_sales/ideas/assign_sale_staff.html.erb
|
421
423
|
- app/views/educode_sales/ideas/course_list.json.jbuilder
|
422
424
|
- app/views/educode_sales/ideas/course_subject.json.jbuilder
|
423
425
|
- app/views/educode_sales/ideas/daily_paper.html.erb
|
@@ -572,6 +574,7 @@ files:
|
|
572
574
|
- app/views/educode_sales/sale_trends/_sales_analysis.html.erb
|
573
575
|
- app/views/educode_sales/sale_trends/_sales_followup_analysis.html.erb
|
574
576
|
- app/views/educode_sales/sale_trends/_user_stat.html.erb
|
577
|
+
- app/views/educode_sales/sale_trends/_visit_analysis.html.erb
|
575
578
|
- app/views/educode_sales/sale_trends/business_area.js.erb
|
576
579
|
- app/views/educode_sales/sale_trends/business_followup_analysis.js.erb
|
577
580
|
- app/views/educode_sales/sale_trends/goal_forecast.js.erb
|
@@ -581,6 +584,7 @@ files:
|
|
581
584
|
- app/views/educode_sales/sale_trends/trends.html.erb
|
582
585
|
- app/views/educode_sales/sale_trends/trends.json.jbuilder
|
583
586
|
- app/views/educode_sales/sale_trends/user_stat.js.erb
|
587
|
+
- app/views/educode_sales/sale_trends/visit_analysis.js.erb
|
584
588
|
- app/views/educode_sales/sales/index.html.erb
|
585
589
|
- app/views/educode_sales/sales/index.json.jbuilder
|
586
590
|
- app/views/educode_sales/sales/operations.html.erb
|