educode_sales 1.10.41 → 1.10.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/educode_sales/plans_controller.rb +14 -0
- data/app/controllers/educode_sales/sale_trends_controller.rb +65 -0
- data/app/controllers/educode_sales/teachers_controller.rb +7 -2
- data/app/helpers/educode_sales/sale_trends_helper.rb +410 -0
- data/app/views/educode_sales/plans/_target_track.html.erb +178 -0
- data/app/views/educode_sales/plans/index.html.erb +5 -0
- data/app/views/educode_sales/plans/target_track.js.erb +1 -0
- data/app/views/educode_sales/sale_trends/_return_money_forecast.html.erb +176 -0
- data/app/views/educode_sales/sale_trends/return_money_forecast.js.erb +1 -0
- data/app/views/educode_sales/sale_trends/trends.html.erb +6 -0
- data/app/views/educode_sales/teachers/_index.html.erb +21 -9
- data/config/routes.rb +2 -0
- data/lib/educode_sales/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ee0e4fc5519c5e1dc171f8d0402f6f3e681e9b89636a7f424a642aaf88a23ce9
|
|
4
|
+
data.tar.gz: c060d33dfc08508f868182e5c3b8f8d780a20c03d8c300631a7a7c39316bfccc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5d82966240ed50554d5525c93254d1f282fe9a604e350f9ae81309726187f43d419e9849b1047f6b996bd6bebd91c12d57b0ea1c9691e5913eb41a29da0df206
|
|
7
|
+
data.tar.gz: 433b7c1181791a6a47a5d35ff5df90363607e9d8c1592056d9fbf546b373c42a29d0bc67d92bdfc67b7f6f504970ff61edf55a2b5b992e3d993dc2fe3861cc14
|
|
@@ -510,6 +510,20 @@ module EducodeSales
|
|
|
510
510
|
@months = (1..12).map { |d| d }
|
|
511
511
|
end
|
|
512
512
|
|
|
513
|
+
|
|
514
|
+
def target_track
|
|
515
|
+
respond_to do |format|
|
|
516
|
+
format.html do
|
|
517
|
+
|
|
518
|
+
end
|
|
519
|
+
format.js do
|
|
520
|
+
common = Common.find_by(clazz: 'staff_type', name: '销售')
|
|
521
|
+
@staffs = Staff.joins(:user).where(job_type: common.id).map { |d| [d.user.real_name, d.id]}
|
|
522
|
+
gon.school_tags = SchoolTag.where(for_missions: true).map { |d| {value: d.id, name: d.name } }
|
|
523
|
+
end
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
513
527
|
private
|
|
514
528
|
|
|
515
529
|
def plan_params
|
|
@@ -418,6 +418,15 @@ module EducodeSales
|
|
|
418
418
|
end
|
|
419
419
|
end
|
|
420
420
|
|
|
421
|
+
#回款预测图
|
|
422
|
+
def return_money_forecast
|
|
423
|
+
respond_to do |format|
|
|
424
|
+
format.js do
|
|
425
|
+
return_forecast_by_money
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
421
430
|
def user_stat
|
|
422
431
|
respond_to do |format|
|
|
423
432
|
format.html do
|
|
@@ -927,5 +936,61 @@ module EducodeSales
|
|
|
927
936
|
|
|
928
937
|
visit_analysis_charts(visit_count_year, visit_count_season, visit_count_month, visit_count_week, visit_type, title_names)
|
|
929
938
|
end
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
def return_forecast_by_money
|
|
942
|
+
property = params[:property] || nil
|
|
943
|
+
staff_id = params[:staff_id] || nil
|
|
944
|
+
@forecast_count_range = params[:forecast_count_range] || "month"
|
|
945
|
+
forecast_default_dates = ("#{Time.now.year}-01-01".to_date.."#{Time.now.year}-#{Time.now.month}-01".to_date).map { |d| d.strftime("%Y-%m") }.uniq
|
|
946
|
+
sale_names = %w[实际回款额 计划回款额 实际回款 计划回款额-全部 计划回款额-o类]
|
|
947
|
+
case @forecast_count_range
|
|
948
|
+
when "week"
|
|
949
|
+
# 年初第一天周数是0会导致周数重复计算
|
|
950
|
+
if params[:forecast_date_day].present?
|
|
951
|
+
date = params[:forecast_date_day].split(" - ")
|
|
952
|
+
dates = (date[0].to_date..date[1].to_date).map { |d| d.strftime("%Y-%W") }.uniq.select { |d| d.split("-")[1] != '00' }
|
|
953
|
+
@return_forecast_count_data = return_money_forecast_week(dates, sale_names, staff_id, property)
|
|
954
|
+
else
|
|
955
|
+
forecast_default_dates = ("#{Time.now.year}-01-01".to_date.."#{Time.now.year}-#{Time.now.month}-01".to_date).map { |d| d.strftime("%Y-%W") }.uniq.select { |d| d.split("-")[1] != '00' }
|
|
956
|
+
@return_forecast_count_data = return_money_forecast_week(forecast_default_dates, sale_names, staff_id, property)
|
|
957
|
+
end
|
|
958
|
+
when "quarter"
|
|
959
|
+
# 按年
|
|
960
|
+
if params[:forecast_date_year].present?
|
|
961
|
+
date = params[:forecast_date_year].split(" - ")
|
|
962
|
+
dates = (date[0]..date[1]).to_a
|
|
963
|
+
dates = dates.map { |d| [d.to_s + "-" + "1", d.to_s + "-" + "2", d.to_s + "-" + "3", d.to_s + "-" + "4"] }.flatten
|
|
964
|
+
@return_forecast_count_data = return_money_forecast_quarter(dates, sale_names, staff_id, property)
|
|
965
|
+
else
|
|
966
|
+
forecast_default_dates = ("#{Time.now.year}-01-01".to_date.."#{Time.now.year}-#{Time.now.month}-01".to_date).map { |d| d.strftime("%Y") }.uniq
|
|
967
|
+
forecast_default_dates = forecast_default_dates.map { |d| [d.to_s + "-" + "1", d.to_s + "-" + "2", d.to_s + "-" + "3", d.to_s + "-" + "4"] }.flatten
|
|
968
|
+
@return_forecast_count_data = return_money_forecast_quarter(forecast_default_dates, sale_names, staff_id, property)
|
|
969
|
+
end
|
|
970
|
+
when "month" # 按月
|
|
971
|
+
if params[:forecast_date_month].present?
|
|
972
|
+
date = params[:forecast_date_month].split(" - ")
|
|
973
|
+
date[0] = (date[0] + "-01").to_date.to_s
|
|
974
|
+
date[1] = (date[1] + "-01").to_date.end_of_month.to_s
|
|
975
|
+
dates = ((date[0] + "-01").to_date..(date[1] + "-01").to_date).map { |d| d.strftime("%Y-%m") }.uniq
|
|
976
|
+
@return_forecast_count_data = return_money_forecast_month(dates, sale_names, staff_id, property)
|
|
977
|
+
else
|
|
978
|
+
@return_forecast_count_data = return_money_forecast_month(forecast_default_dates, sale_names, staff_id, property)
|
|
979
|
+
end
|
|
980
|
+
else
|
|
981
|
+
# 按年
|
|
982
|
+
if params[:forecast_date_year].present?
|
|
983
|
+
date = params[:forecast_date_year].split(" - ")
|
|
984
|
+
dates = (date[0]..date[1]).to_a
|
|
985
|
+
@return_forecast_count_data = return_money_forecast_year(dates, sale_names, staff_id, property)
|
|
986
|
+
else
|
|
987
|
+
forecast_default_dates = ("#{Time.now.year}-01-01".to_date.."#{Time.now.year}-#{Time.now.month}-01".to_date).map { |d| d.strftime("%Y") }.uniq
|
|
988
|
+
@return_forecast_count_data = return_money_forecast_year(forecast_default_dates, sale_names, staff_id, property)
|
|
989
|
+
end
|
|
990
|
+
end
|
|
991
|
+
@return_forecast_count_data_0 = @return_forecast_count_data[0]
|
|
992
|
+
@return_forecast_count_data_1 = @return_forecast_count_data[1]
|
|
993
|
+
end
|
|
994
|
+
|
|
930
995
|
end
|
|
931
996
|
end
|
|
@@ -204,7 +204,7 @@ module EducodeSales
|
|
|
204
204
|
end
|
|
205
205
|
|
|
206
206
|
if params[:q].present? && params[:q][:is_contact].present?
|
|
207
|
-
@teachers = @teachers.where("last_follow.is_contact = ?"
|
|
207
|
+
@teachers = @teachers.where("last_follow.is_contact = ?", params[:q][:is_contact].to_i)
|
|
208
208
|
end
|
|
209
209
|
|
|
210
210
|
if params[:sort].present? && params[:sort][:field]
|
|
@@ -212,7 +212,12 @@ module EducodeSales
|
|
|
212
212
|
else
|
|
213
213
|
@teachers = @teachers.order("educode_sales_teachers.created_at desc")
|
|
214
214
|
end
|
|
215
|
-
@teachers = @teachers.
|
|
215
|
+
@teachers = @teachers.includes(:teacher_assign_follows, :department, :user, :follow_up, :activity_teachers, [assign_staffs: :staff])
|
|
216
|
+
if params[:type].to_s == 'export'
|
|
217
|
+
@teachers = @teachers.page(1).per(1000)
|
|
218
|
+
else
|
|
219
|
+
@teachers = @teachers.page(params[:page]).per(params[:limit])
|
|
220
|
+
end
|
|
216
221
|
end
|
|
217
222
|
|
|
218
223
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module EducodeSales
|
|
2
2
|
module SaleTrendsHelper
|
|
3
3
|
NAMES = %w[计划投标额 计划投标额累计 实际中标额 实际中标额累计]
|
|
4
|
+
RETURN_NAMES = %w[实际回款额 计划回款额 实际回款 计划回款额-全部 计划回款额-o类]
|
|
4
5
|
|
|
5
6
|
def goal_forecast_quarter(labels, selects, staff_id = nil, property)
|
|
6
7
|
plan_get = plan_get(staff_id, labels, "quarter", property)
|
|
@@ -337,6 +338,274 @@ module EducodeSales
|
|
|
337
338
|
end
|
|
338
339
|
end
|
|
339
340
|
|
|
341
|
+
|
|
342
|
+
def return_money_forecast_week(labels, selects, staff_id = nil, property)
|
|
343
|
+
plan_return = plan_return(staff_id, labels, "week", property)
|
|
344
|
+
actual_return = actual_return(staff_id, labels, "week", property)
|
|
345
|
+
plan_return_by_o = plan_return_by_o(staff_id, labels, "week", property)
|
|
346
|
+
datasets = selects.map.with_index do |select, i|
|
|
347
|
+
data = if select == RETURN_NAMES[0]
|
|
348
|
+
labels.map do |d|
|
|
349
|
+
week = d.split("-").last
|
|
350
|
+
year = d.split("-").first
|
|
351
|
+
yearweek = "#{year}#{week}".to_i
|
|
352
|
+
actual_return[yearweek].to_f.round(3)
|
|
353
|
+
end
|
|
354
|
+
elsif select == RETURN_NAMES[1]
|
|
355
|
+
arr = labels.map do |d|
|
|
356
|
+
week = d.split("-").last
|
|
357
|
+
year = d.split("-").first
|
|
358
|
+
yearweek = "#{year}#{week}".to_i
|
|
359
|
+
plan_return[yearweek].to_f.round(3)
|
|
360
|
+
end
|
|
361
|
+
arr.map.with_index(1) { |num, i| arr.first(i).inject(:+) }
|
|
362
|
+
elsif select == RETURN_NAMES[2]
|
|
363
|
+
labels.map do |d|
|
|
364
|
+
week = d.split("-").last
|
|
365
|
+
year = d.split("-").first
|
|
366
|
+
yearweek = "#{year}#{week}".to_i
|
|
367
|
+
actual_return[yearweek].to_f.round(3)
|
|
368
|
+
end
|
|
369
|
+
elsif select == RETURN_NAMES[3]
|
|
370
|
+
labels.map do |d|
|
|
371
|
+
week = d.split("-").last
|
|
372
|
+
year = d.split("-").first
|
|
373
|
+
yearweek = "#{year}#{week}".to_i
|
|
374
|
+
plan_return[yearweek].to_f.round(3)
|
|
375
|
+
end
|
|
376
|
+
elsif select == RETURN_NAMES[4]
|
|
377
|
+
arr = labels.map do |d|
|
|
378
|
+
week = d.split("-").last
|
|
379
|
+
year = d.split("-").first
|
|
380
|
+
yearweek = "#{year}#{week}".to_i
|
|
381
|
+
plan_return_by_o[yearweek].to_f.round(3)
|
|
382
|
+
end
|
|
383
|
+
arr.map.with_index(1) { |num, i| arr.first(i).inject(:+) }
|
|
384
|
+
end
|
|
385
|
+
type = if select == RETURN_NAMES[0] || select == RETURN_NAMES[1]
|
|
386
|
+
'bar'
|
|
387
|
+
else
|
|
388
|
+
"line"
|
|
389
|
+
end
|
|
390
|
+
backgroundColor = if select == RETURN_NAMES[0] || select == RETURN_NAMES[1]
|
|
391
|
+
'rgba(54, 162, 235, 1)'
|
|
392
|
+
else
|
|
393
|
+
SaleTrend::COLORS[i]
|
|
394
|
+
'rgba(54, 162, 235, 0)'
|
|
395
|
+
end
|
|
396
|
+
{
|
|
397
|
+
type: type,
|
|
398
|
+
label: select,
|
|
399
|
+
data: data&.map { |d| d.round(2) },
|
|
400
|
+
backgroundColor: backgroundColor,
|
|
401
|
+
borderColor: SaleTrend::COLORS[i],
|
|
402
|
+
borderWidth: 1
|
|
403
|
+
}
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
hash_a = {
|
|
407
|
+
labels: labels,
|
|
408
|
+
datasets: [datasets[0], datasets[1]]
|
|
409
|
+
}
|
|
410
|
+
hash_b = {
|
|
411
|
+
labels: labels,
|
|
412
|
+
datasets: [datasets[2], datasets[3], datasets[4]]
|
|
413
|
+
}
|
|
414
|
+
[hash_a, hash_b]
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def return_money_forecast_quarter(labels, selects, staff_id = nil, property)
|
|
418
|
+
plan_return = plan_return(staff_id, labels, "quarter", property)
|
|
419
|
+
actual_return = actual_return(staff_id, labels, "quarter", property)
|
|
420
|
+
plan_return_by_o = plan_return_by_o(staff_id, labels, "quarter", property)
|
|
421
|
+
datasets = selects.map.with_index do |select, i|
|
|
422
|
+
data = if select == RETURN_NAMES[0]
|
|
423
|
+
labels.map do |d|
|
|
424
|
+
quarter = d.split("-").last.to_i
|
|
425
|
+
year = d.split("-").first.to_i
|
|
426
|
+
actual_return[[year, quarter]]&.pluck(:amount)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
427
|
+
end
|
|
428
|
+
elsif select == RETURN_NAMES[1]
|
|
429
|
+
arr = labels.map do |d|
|
|
430
|
+
quarter = d.split("-").last.to_i
|
|
431
|
+
year = d.split("-").first.to_i
|
|
432
|
+
plan_return[[year, quarter]]&.pluck(:plan_return_money)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
433
|
+
end
|
|
434
|
+
arr.map.with_index(1) { |num, i| arr.first(i).inject(:+) }
|
|
435
|
+
elsif select == RETURN_NAMES[2]
|
|
436
|
+
labels.map do |d|
|
|
437
|
+
quarter = d.split("-").last.to_i
|
|
438
|
+
year = d.split("-").first.to_i
|
|
439
|
+
actual_return[[year, quarter]]&.pluck(:amount)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
440
|
+
end
|
|
441
|
+
elsif select == RETURN_NAMES[3]
|
|
442
|
+
labels.map do |d|
|
|
443
|
+
quarter = d.split("-").last.to_i
|
|
444
|
+
year = d.split("-").first.to_i
|
|
445
|
+
plan_return[[year, quarter]]&.pluck(:plan_return_money)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
446
|
+
end
|
|
447
|
+
elsif select == RETURN_NAMES[4]
|
|
448
|
+
arr = labels.map do |d|
|
|
449
|
+
quarter = d.split("-").last.to_i
|
|
450
|
+
year = d.split("-").first.to_i
|
|
451
|
+
plan_return_by_o[[year, quarter]]&.pluck(:plan_return_money)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
452
|
+
end
|
|
453
|
+
arr.map.with_index(1) { |num, i| arr.first(i).inject(:+) }
|
|
454
|
+
end
|
|
455
|
+
type = if select == RETURN_NAMES[0] || select == RETURN_NAMES[1]
|
|
456
|
+
'bar'
|
|
457
|
+
else
|
|
458
|
+
"line"
|
|
459
|
+
end
|
|
460
|
+
backgroundColor = if select == RETURN_NAMES[0] || select == RETURN_NAMES[1]
|
|
461
|
+
'rgba(54, 162, 235, 1)'
|
|
462
|
+
else
|
|
463
|
+
SaleTrend::COLORS[i]
|
|
464
|
+
'rgba(54, 162, 235, 0)'
|
|
465
|
+
end
|
|
466
|
+
{
|
|
467
|
+
type: type,
|
|
468
|
+
label: select,
|
|
469
|
+
data: data.map { |d| d.round(2) },
|
|
470
|
+
backgroundColor: backgroundColor,
|
|
471
|
+
borderColor: SaleTrend::COLORS[i],
|
|
472
|
+
borderWidth: 1
|
|
473
|
+
}
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
hash_a = {
|
|
477
|
+
labels: labels,
|
|
478
|
+
datasets: [datasets[0], datasets[1]]
|
|
479
|
+
}
|
|
480
|
+
hash_b = {
|
|
481
|
+
labels: labels,
|
|
482
|
+
datasets: [datasets[2], datasets[3], datasets[4]]
|
|
483
|
+
}
|
|
484
|
+
[hash_a, hash_b]
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
def return_money_forecast_month(labels, selects, staff_id = nil, property)
|
|
489
|
+
plan_return = plan_return(staff_id, labels, "month", property)
|
|
490
|
+
actual_return = actual_return(staff_id, labels, "month", property)
|
|
491
|
+
plan_return_by_o = plan_return_by_o(staff_id, labels, "month", property)
|
|
492
|
+
datasets = selects.map.with_index do |select, i|
|
|
493
|
+
data = if select == RETURN_NAMES[0]
|
|
494
|
+
labels.map do |d|
|
|
495
|
+
quarter = d.split("-").last.to_i
|
|
496
|
+
year = d.split("-").first.to_i
|
|
497
|
+
actual_return[[year, quarter]]&.pluck(:amount)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
498
|
+
end
|
|
499
|
+
elsif select == RETURN_NAMES[1]
|
|
500
|
+
arr = labels.map do |d|
|
|
501
|
+
quarter = d.split("-").last.to_i
|
|
502
|
+
year = d.split("-").first.to_i
|
|
503
|
+
plan_return[[year, quarter]]&.pluck(:plan_return_money)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
504
|
+
end
|
|
505
|
+
arr.map.with_index(1) { |num, i| arr.first(i).inject(:+) }
|
|
506
|
+
elsif select == RETURN_NAMES[2]
|
|
507
|
+
labels.map do |d|
|
|
508
|
+
quarter = d.split("-").last.to_i
|
|
509
|
+
year = d.split("-").first.to_i
|
|
510
|
+
actual_return[[year, quarter]]&.pluck(:amount)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
511
|
+
end
|
|
512
|
+
elsif select == RETURN_NAMES[3]
|
|
513
|
+
labels.map do |d|
|
|
514
|
+
quarter = d.split("-").last.to_i
|
|
515
|
+
year = d.split("-").first.to_i
|
|
516
|
+
plan_return[[year, quarter]]&.pluck(:plan_return_money)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
517
|
+
end
|
|
518
|
+
elsif select == RETURN_NAMES[4]
|
|
519
|
+
arr = labels.map do |d|
|
|
520
|
+
quarter = d.split("-").last.to_i
|
|
521
|
+
year = d.split("-").first.to_i
|
|
522
|
+
plan_return_by_o[[year, quarter]]&.pluck(:plan_return_money)&.reject(&:blank?)&.sum.to_f.round(3)
|
|
523
|
+
end
|
|
524
|
+
arr.map.with_index(1) { |num, i| arr.first(i).inject(:+) }
|
|
525
|
+
end
|
|
526
|
+
type = if select == RETURN_NAMES[0] || select == RETURN_NAMES[1]
|
|
527
|
+
'bar'
|
|
528
|
+
else
|
|
529
|
+
"line"
|
|
530
|
+
end
|
|
531
|
+
backgroundColor = if select == RETURN_NAMES[0] || select == RETURN_NAMES[1]
|
|
532
|
+
'rgba(54, 162, 235, 1)'
|
|
533
|
+
else
|
|
534
|
+
SaleTrend::COLORS[i]
|
|
535
|
+
'rgba(54, 162, 235, 0)'
|
|
536
|
+
end
|
|
537
|
+
{
|
|
538
|
+
type: type,
|
|
539
|
+
label: select,
|
|
540
|
+
data: data.map { |d| d.round(2) },
|
|
541
|
+
backgroundColor: backgroundColor,
|
|
542
|
+
borderColor: SaleTrend::COLORS[i],
|
|
543
|
+
borderWidth: 1
|
|
544
|
+
}
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
hash_a = {
|
|
548
|
+
labels: labels,
|
|
549
|
+
datasets: [datasets[0], datasets[1]]
|
|
550
|
+
}
|
|
551
|
+
hash_b = {
|
|
552
|
+
labels: labels,
|
|
553
|
+
datasets: [datasets[2], datasets[3], datasets[4]]
|
|
554
|
+
}
|
|
555
|
+
[hash_a, hash_b]
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
def return_money_forecast_year(labels, selects, staff_id = nil, property)
|
|
559
|
+
plan_return = plan_return(staff_id, labels, "year", property)
|
|
560
|
+
actual_return = actual_return(staff_id, labels, "year", property)
|
|
561
|
+
plan_return_by_o = plan_return_by_o(staff_id, labels, "year", property)
|
|
562
|
+
datasets = selects.map.with_index do |select, i|
|
|
563
|
+
data = if select == RETURN_NAMES[0]
|
|
564
|
+
labels.map { |d| actual_return[d.to_i] || 0 }
|
|
565
|
+
elsif select == RETURN_NAMES[1]
|
|
566
|
+
arr = labels.map { |d| plan_return[d.to_i] || 0 }
|
|
567
|
+
arr.map.with_index(1) { |num, i| arr.first(i).inject(:+) }
|
|
568
|
+
elsif select == RETURN_NAMES[2]
|
|
569
|
+
labels.map { |d| actual_return[d.to_i] || 0 }
|
|
570
|
+
elsif select == RETURN_NAMES[3]
|
|
571
|
+
labels.map { |d| plan_return[d.to_i] || 0 }
|
|
572
|
+
elsif select == RETURN_NAMES[4]
|
|
573
|
+
arr = labels.map { |d| plan_return_by_o[d.to_i] || 0 }
|
|
574
|
+
arr.map.with_index(1) { |num, i| arr.first(i).inject(:+) }
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
type = if select == RETURN_NAMES[0] || select == RETURN_NAMES[1]
|
|
578
|
+
'bar'
|
|
579
|
+
else
|
|
580
|
+
"line"
|
|
581
|
+
end
|
|
582
|
+
backgroundColor = if RETURN_NAMES[0] || select == RETURN_NAMES[1]
|
|
583
|
+
'rgba(54, 162, 235, 1)'
|
|
584
|
+
else
|
|
585
|
+
SaleTrend::COLORS[i]
|
|
586
|
+
'rgba(54, 162, 235, 0)'
|
|
587
|
+
end
|
|
588
|
+
{
|
|
589
|
+
type: type,
|
|
590
|
+
label: select,
|
|
591
|
+
data: data.map { |d| d.round(2) },
|
|
592
|
+
backgroundColor: backgroundColor,
|
|
593
|
+
borderColor: SaleTrend::COLORS[i],
|
|
594
|
+
borderWidth: 1
|
|
595
|
+
}
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
hash_a = {
|
|
599
|
+
labels: labels,
|
|
600
|
+
datasets: [datasets[0], datasets[1]]
|
|
601
|
+
}
|
|
602
|
+
hash_b = {
|
|
603
|
+
labels: labels,
|
|
604
|
+
datasets: [datasets[2], datasets[3], datasets[4]]
|
|
605
|
+
}
|
|
606
|
+
[hash_a, hash_b]
|
|
607
|
+
end
|
|
608
|
+
|
|
340
609
|
private
|
|
341
610
|
|
|
342
611
|
def plan_get(staff_id, time_range, type, property)
|
|
@@ -433,5 +702,146 @@ module EducodeSales
|
|
|
433
702
|
end
|
|
434
703
|
end
|
|
435
704
|
|
|
705
|
+
def plan_return(staff_id, time_range, type, property)
|
|
706
|
+
# plan_return_money 计划回款额
|
|
707
|
+
start_time = case type
|
|
708
|
+
when "month"
|
|
709
|
+
time_range.first + "-01"
|
|
710
|
+
when "year"
|
|
711
|
+
time_range.first + "-01-01"
|
|
712
|
+
when "week"
|
|
713
|
+
time_range.first.split("-").first + "-01-01"
|
|
714
|
+
when "quarter"
|
|
715
|
+
time_range.first.split("-").first + "-01-01"
|
|
716
|
+
end
|
|
717
|
+
end_time = case type
|
|
718
|
+
when "month"
|
|
719
|
+
time_range.last + "-31"
|
|
720
|
+
when "year"
|
|
721
|
+
time_range.last + "-12-31"
|
|
722
|
+
when "week"
|
|
723
|
+
time_range.last.split("-").first + "-12-31"
|
|
724
|
+
when "quarter"
|
|
725
|
+
time_range.last.split("-").first + "-12-31"
|
|
726
|
+
end
|
|
727
|
+
staff_id = staff_id.present? ? Array(staff_id) : nil
|
|
728
|
+
data = Business.joins(:last_follow_up)
|
|
729
|
+
.where("educode_sales_follow_ups.plan_return_date >= ? and educode_sales_follow_ups.plan_return_date <= ?", start_time, end_time)
|
|
730
|
+
if staff_id.present?
|
|
731
|
+
data = data.joins("LEFT JOIN educode_sales_follow_ups AS last_follow_up ON educode_sales_businesses.last_follow_up_id = last_follow_up.id AND last_follow_up.deleted_at IS NULL
|
|
732
|
+
LEFT JOIN educode_sales_assign_follow_ups ON educode_sales_assign_follow_ups.follow_up_id = last_follow_up.id").
|
|
733
|
+
where("(educode_sales_assign_follow_ups.id IS NOT NULL AND educode_sales_assign_follow_ups.staff_id = ?) OR (educode_sales_assign_follow_ups.id IS NULL AND educode_sales_businesses.staff_id = ?)", staff_id, staff_id)
|
|
734
|
+
end
|
|
735
|
+
if property.present?
|
|
736
|
+
data = data.joins(department: [school: :school_tags]).where("school_tags.id = ?", property)
|
|
737
|
+
end
|
|
738
|
+
case type
|
|
739
|
+
when "week"
|
|
740
|
+
data.select("educode_sales_follow_ups.*, yearweek(educode_sales_follow_ups.plan_return_date) as week").group("yearweek(educode_sales_follow_ups.plan_return_date)").sum("educode_sales_follow_ups.plan_return_money")
|
|
741
|
+
when "quarter"
|
|
742
|
+
data = data.select("educode_sales_follow_ups.*, quarter(educode_sales_follow_ups.plan_return_date) as quarter, year(educode_sales_follow_ups.invitation_at) as year")
|
|
743
|
+
data.group_by { |d| [d.year, d.quarter] }
|
|
744
|
+
when "month"
|
|
745
|
+
data = data.select("educode_sales_follow_ups.*, year(educode_sales_follow_ups.plan_return_date) as year, month(educode_sales_follow_ups.plan_return_date) as month")
|
|
746
|
+
data.group_by { |d| [d.year, d.month] }
|
|
747
|
+
when "year"
|
|
748
|
+
data.select("educode_sales_follow_ups.*, year(educode_sales_follow_ups.plan_return_date) as year").group("year(educode_sales_follow_ups.plan_return_date)").sum("educode_sales_follow_ups.plan_return_money")
|
|
749
|
+
end
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
def actual_return(staff_id, time_range, type, property)
|
|
754
|
+
# money_plan_records表中 amount: 回款金额
|
|
755
|
+
start_time = case type
|
|
756
|
+
when "month"
|
|
757
|
+
time_range.first + "-01"
|
|
758
|
+
when "year"
|
|
759
|
+
time_range.first + "-01-01"
|
|
760
|
+
when "week"
|
|
761
|
+
time_range.first.split("-").first + "-01-01"
|
|
762
|
+
when "quarter"
|
|
763
|
+
time_range.first.split("-").first + "-01-01"
|
|
764
|
+
end
|
|
765
|
+
end_time = case type
|
|
766
|
+
when "month"
|
|
767
|
+
time_range.last + "-31"
|
|
768
|
+
when "year"
|
|
769
|
+
time_range.last + "-12-31"
|
|
770
|
+
when "week"
|
|
771
|
+
time_range.last.split("-").first + "-12-31"
|
|
772
|
+
when "quarter"
|
|
773
|
+
time_range.last.split("-").first + "-12-31"
|
|
774
|
+
end
|
|
775
|
+
staff_id = staff_id.present? ? Array(staff_id) : nil
|
|
776
|
+
data = MoneyPlanRecord.joins(business: [department: [school: :school_tags]]).where("educode_sales_money_plan_records.date_at >= ? and educode_sales_money_plan_records.date_at <= ?", start_time, end_time)
|
|
777
|
+
if staff_id.present?
|
|
778
|
+
data = data.joins("LEFT JOIN educode_sales_follow_ups AS last_follow_up ON educode_sales_businesses.last_follow_up_id = last_follow_up.id AND last_follow_up.deleted_at IS NULL
|
|
779
|
+
LEFT JOIN educode_sales_assign_follow_ups ON educode_sales_assign_follow_ups.follow_up_id = last_follow_up.id").
|
|
780
|
+
where("(educode_sales_assign_follow_ups.id IS NOT NULL AND educode_sales_assign_follow_ups.staff_id = ?) OR (educode_sales_assign_follow_ups.id IS NULL AND educode_sales_businesses.staff_id = ?)", staff_id, staff_id)
|
|
781
|
+
end
|
|
782
|
+
if property.present?
|
|
783
|
+
data = data.where("school_tags.id = ?", property)
|
|
784
|
+
end
|
|
785
|
+
case type
|
|
786
|
+
when "week"
|
|
787
|
+
data.select("educode_sales_money_plan_records.*, yearweek(educode_sales_money_plan_records.date_at) as week").group("yearweek(educode_sales_money_plan_records.date_at)").sum("educode_sales_money_plan_records.amount")
|
|
788
|
+
when "quarter"
|
|
789
|
+
data = data.select("educode_sales_money_plan_records.*, quarter(educode_sales_money_plan_records.date_at) as quarter, year(educode_sales_money_plan_records.date_at) as year")
|
|
790
|
+
data.group_by { |d| [d.year, d.quarter] }
|
|
791
|
+
when "month"
|
|
792
|
+
data = data.select("educode_sales_money_plan_records.*, year(educode_sales_money_plan_records.date_at) as year, month(educode_sales_money_plan_records.date_at) as month")
|
|
793
|
+
data.group_by { |d| [d.year, d.month] }
|
|
794
|
+
when "year"
|
|
795
|
+
data.select("educode_sales_money_plan_records.*, year(educode_sales_money_plan_records.date_at) as year").group("year(educode_sales_money_plan_records.date_at)").sum("educode_sales_money_plan_records.amount")
|
|
796
|
+
end
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
def plan_return_by_o(staff_id, time_range, type, property)
|
|
800
|
+
# plan_return_money 计划回款额-o类
|
|
801
|
+
clazz_id = Common.find_by(name: "O类-中标商机", clazz: "business_type", extras: "o_class").id
|
|
802
|
+
start_time = case type
|
|
803
|
+
when "month"
|
|
804
|
+
time_range.first + "-01"
|
|
805
|
+
when "year"
|
|
806
|
+
time_range.first + "-01-01"
|
|
807
|
+
when "week"
|
|
808
|
+
time_range.first.split("-").first + "-01-01"
|
|
809
|
+
when "quarter"
|
|
810
|
+
time_range.first.split("-").first + "-01-01"
|
|
811
|
+
end
|
|
812
|
+
end_time = case type
|
|
813
|
+
when "month"
|
|
814
|
+
time_range.last + "-31"
|
|
815
|
+
when "year"
|
|
816
|
+
time_range.last + "-12-31"
|
|
817
|
+
when "week"
|
|
818
|
+
time_range.last.split("-").first + "-12-31"
|
|
819
|
+
when "quarter"
|
|
820
|
+
time_range.last.split("-").first + "-12-31"
|
|
821
|
+
end
|
|
822
|
+
staff_id = staff_id.present? ? Array(staff_id) : nil
|
|
823
|
+
data = Business.joins(:last_follow_up).where("educode_sales_businesses.clazz_id = ?", clazz_id)
|
|
824
|
+
.where("educode_sales_follow_ups.plan_return_date >= ? and educode_sales_follow_ups.plan_return_date <= ?", start_time, end_time)
|
|
825
|
+
if staff_id.present?
|
|
826
|
+
data = data.joins("LEFT JOIN educode_sales_follow_ups AS last_follow_up ON educode_sales_businesses.last_follow_up_id = last_follow_up.id AND last_follow_up.deleted_at IS NULL
|
|
827
|
+
LEFT JOIN educode_sales_assign_follow_ups ON educode_sales_assign_follow_ups.follow_up_id = last_follow_up.id").
|
|
828
|
+
where("(educode_sales_assign_follow_ups.id IS NOT NULL AND educode_sales_assign_follow_ups.staff_id = ?) OR (educode_sales_assign_follow_ups.id IS NULL AND educode_sales_businesses.staff_id = ?)", staff_id, staff_id)
|
|
829
|
+
end
|
|
830
|
+
if property.present?
|
|
831
|
+
data = data.joins(department: [school: :school_tags]).where("school_tags.id = ?", property)
|
|
832
|
+
end
|
|
833
|
+
case type
|
|
834
|
+
when "week"
|
|
835
|
+
data.select("educode_sales_follow_ups.*, yearweek(educode_sales_follow_ups.plan_return_date) as week").group("yearweek(educode_sales_follow_ups.plan_return_date)").sum("educode_sales_follow_ups.plan_return_money")
|
|
836
|
+
when "quarter"
|
|
837
|
+
data = data.select("educode_sales_follow_ups.*, quarter(educode_sales_follow_ups.plan_return_date) as quarter, year(educode_sales_follow_ups.invitation_at) as year")
|
|
838
|
+
data.group_by { |d| [d.year, d.quarter] }
|
|
839
|
+
when "month"
|
|
840
|
+
data = data.select("educode_sales_follow_ups.*, year(educode_sales_follow_ups.plan_return_date) as year, month(educode_sales_follow_ups.plan_return_date) as month")
|
|
841
|
+
data.group_by { |d| [d.year, d.month] }
|
|
842
|
+
when "year"
|
|
843
|
+
data.select("educode_sales_follow_ups.*, year(educode_sales_follow_ups.plan_return_date) as year").group("year(educode_sales_follow_ups.plan_return_date)").sum("educode_sales_follow_ups.plan_return_money")
|
|
844
|
+
end
|
|
845
|
+
end
|
|
436
846
|
end
|
|
437
847
|
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
<%= Gon::Base.render_data %>
|
|
2
|
+
<div id="target_track_wraper">
|
|
3
|
+
<div class="layuimini-main min-height-table" id="monthly_table_wraper">
|
|
4
|
+
<form class="layui-form layui-form-pane" lay-filter="assessment_progress_form">
|
|
5
|
+
<div class="layui-form-item">
|
|
6
|
+
<div class="layui-inline">
|
|
7
|
+
<label class="layui-form-label">人员</label>
|
|
8
|
+
<div class="layui-input-inline large-select">
|
|
9
|
+
<%= select_tag "staff_id", options_for_select(@staffs), { id: 'weekly_staff_id', include_blank: true} %>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="layui-inline">
|
|
13
|
+
<label class="layui-form-label">年度</label>
|
|
14
|
+
<div class="layui-input-inline">
|
|
15
|
+
<input type="text" class="layui-input" autocomplete="off" name="assessment_year" value="<%= Time.now.year %>" id="assessment_year">
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="layui-inline">
|
|
19
|
+
<label class="layui-form-label">客户类型</label>
|
|
20
|
+
<div class="layui-input-inline">
|
|
21
|
+
<div id="property" style="width: 190px;"></div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="layui-inline">
|
|
25
|
+
<label class="layui-form-label">目标类别</label>
|
|
26
|
+
<div class="layui-input-inline">
|
|
27
|
+
<div id="clazz" style="width: 190px;"></div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="layui-inline">
|
|
31
|
+
<button type="reset" class="layui-btn layui-btn-primary" lay-submit lay-filter="progress_resert_btn">重置
|
|
32
|
+
</button>
|
|
33
|
+
<button type="submit" class="layui-btn layui-btn-primary" lay-submit lay-filter="progress_search_btn">检索
|
|
34
|
+
</button>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</form>
|
|
38
|
+
<table class="layui-tab" id="finished_table" lay-filter="progressTable"></table>
|
|
39
|
+
</div>
|
|
40
|
+
<script type="text/html" id="progress_Toolbar">
|
|
41
|
+
<div class="layui-btn-container">
|
|
42
|
+
<button class="layui-btn layui-btn-default layui-btn-sm data-add-btn pull-right" lay-event="add"> 导出</button>
|
|
43
|
+
<button class="layui-btn layui-btn-primary layui-btn-sm data-add-btn pull-right" lay-event="add"> 人员显示</button>
|
|
44
|
+
<button class="layui-btn layui-btn-primary layui-btn-sm data-add-btn pull-right" lay-event="add"> 分类显示</button>
|
|
45
|
+
</div>
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<script>
|
|
49
|
+
layui.use(['form', 'table', 'miniPage', 'element', 'rate', 'laydate', 'request', 'xmSelect'], function () {
|
|
50
|
+
|
|
51
|
+
var $ = layui.jquery,
|
|
52
|
+
form = layui.form,
|
|
53
|
+
laydate = layui.laydate,
|
|
54
|
+
request = layui.request,
|
|
55
|
+
table = layui.table,
|
|
56
|
+
rate = layui.rate,
|
|
57
|
+
xmSelect = layui.xmSelect,
|
|
58
|
+
miniPage = layui.miniPage,
|
|
59
|
+
dropdown = layui.dropdown;
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
laydate.render({
|
|
63
|
+
elem: '#assessment_year',
|
|
64
|
+
type: 'year'
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
var property_list = xmSelect.render({
|
|
68
|
+
el: '#property',
|
|
69
|
+
data: gon.school_tags
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
var clazz = xmSelect.render({
|
|
73
|
+
el: '#clazz',
|
|
74
|
+
data: [{value: '中标', name: '中标'}, {value: '回款', name: '回款'}, {value: '商机', name: '商机'}]
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
var progress_table = table.render({
|
|
79
|
+
elem: '#finished_table'
|
|
80
|
+
,toolbar: '#progress_Toolbar'
|
|
81
|
+
,totalRow:true
|
|
82
|
+
,title: "绩效考核指标完成情况" // 目前发现的作用(导出文件的文件名)
|
|
83
|
+
,defaultToolbar: ['filter']
|
|
84
|
+
,cols:[
|
|
85
|
+
[ //标题栏
|
|
86
|
+
{field: 'id', title: '序号', width: 120, rowspan: 2, colspan: 9},
|
|
87
|
+
{field: 'name', title: '姓名', width: 120, rowspan: 2, colspan: 9},
|
|
88
|
+
{field: 'assessment', title: '类别', width: 120, rowspan: 2},
|
|
89
|
+
,{field: 'year', align: 'center', title: '年度目标', width: 100, rowspan: 2}
|
|
90
|
+
,{align: 'center', title: '客户类型', width: 120,rowspan: 2}
|
|
91
|
+
,{align: 'center', title: '分项目标', width: 120, rowspan: 2}
|
|
92
|
+
,{field: 'name', title: '年度计划', width: 120, rowspan: 2}
|
|
93
|
+
,{field: 'name', title: '年度完成', width: 120, rowspan: 2}
|
|
94
|
+
|
|
95
|
+
,{align: 'center', title: '1月', colspan: 3}
|
|
96
|
+
,{align: 'center', title: '2月', colspan: 3}
|
|
97
|
+
,{align: 'center', title: '3月', colspan: 3}
|
|
98
|
+
,{align: 'center', title: '4月', colspan: 3}
|
|
99
|
+
,{align: 'center', title: '5月', colspan: 3}
|
|
100
|
+
,{align: 'center', title: '6月', colspan: 3}
|
|
101
|
+
,{align: 'center', title: '7月', colspan: 3}
|
|
102
|
+
,{align: 'center', title: '8月', colspan: 3}
|
|
103
|
+
,{align: 'center', title: '9月', colspan: 3}
|
|
104
|
+
,{align: 'center', title: '10月', colspan: 3}
|
|
105
|
+
,{align: 'center', title: '11月', colspan: 3}
|
|
106
|
+
,{align: 'center', title: '12月', colspan: 3}
|
|
107
|
+
],
|
|
108
|
+
[
|
|
109
|
+
{field: 'target_1', title: '目标', width: 100, totalRow:true}
|
|
110
|
+
,{field: 'plan_1', title: '计划', width: 100, totalRow:true}
|
|
111
|
+
,{field: 'finish_1', title: '完成', width: 100, totalRow:true}
|
|
112
|
+
|
|
113
|
+
,{field: 'target_2', title: '目标', width: 100, totalRow:true}
|
|
114
|
+
,{field: 'plan_2', title: '计划', width: 100, totalRow:true}
|
|
115
|
+
,{field: 'finish_2', title: '完成', width: 100, totalRow:true}
|
|
116
|
+
|
|
117
|
+
,{field: 'target_3', title: '目标', width: 100, totalRow:true}
|
|
118
|
+
,{field: 'plan_3', title: '计划', width: 100, totalRow:true}
|
|
119
|
+
,{field: 'finish_3', title: '完成', width: 100, totalRow:true}
|
|
120
|
+
|
|
121
|
+
,{field: 'target_4', title: '目标', width: 100, totalRow:true}
|
|
122
|
+
,{field: 'plan_4', title: '计划', width: 100, totalRow:true}
|
|
123
|
+
,{field: 'finish_4', title: '完成', width: 100, totalRow:true}
|
|
124
|
+
|
|
125
|
+
,{field: 'target_5', title: '目标', width: 100, totalRow:true}
|
|
126
|
+
,{field: 'plan_5', title: '计划', width: 100, totalRow:true}
|
|
127
|
+
,{field: 'finish_5', title: '完成', width: 100, totalRow:true}
|
|
128
|
+
|
|
129
|
+
,{field: 'target_6', title: '目标', width: 100, totalRow:true}
|
|
130
|
+
,{field: 'plan_6', title: '计划', width: 100, totalRow:true}
|
|
131
|
+
,{field: 'finish_6', title: '完成', width: 100, totalRow:true}
|
|
132
|
+
|
|
133
|
+
,{field: 'target_7', title: '目标', width: 100, totalRow:true}
|
|
134
|
+
,{field: 'plan_7', title: '计划', width: 100, totalRow:true}
|
|
135
|
+
,{field: 'finish_7', title: '完成', width: 100, totalRow:true}
|
|
136
|
+
|
|
137
|
+
,{field: 'target_8', title: '目标', width: 100, totalRow:true}
|
|
138
|
+
,{field: 'plan_8', title: '计划', width: 100, totalRow:true}
|
|
139
|
+
,{field: 'finish_8', title: '完成', width: 100, totalRow:true}
|
|
140
|
+
|
|
141
|
+
,{field: 'target_9', title: '目标', width: 100, totalRow:true}
|
|
142
|
+
,{field: 'plan_9', title: '计划', width: 100, totalRow:true}
|
|
143
|
+
,{field: 'finish_9', title: '完成', width: 100, totalRow:true}
|
|
144
|
+
|
|
145
|
+
,{field: 'target_10', title: '目标', width: 100, totalRow:true}
|
|
146
|
+
,{field: 'plan_10', title: '计划', width: 100, totalRow:true}
|
|
147
|
+
,{field: 'finish_10', title: '完成', width: 100, totalRow:true}
|
|
148
|
+
|
|
149
|
+
,{field: 'target_11', title: '目标', width: 100, totalRow:true}
|
|
150
|
+
,{field: 'plan_11', title: '计划', width: 100, totalRow:true}
|
|
151
|
+
,{field: 'finish_11', title: '完成', width: 100, totalRow:true}
|
|
152
|
+
|
|
153
|
+
,{field: 'target_12', title: '目标', width: 100, totalRow:true}
|
|
154
|
+
,{field: 'plan_12', title: '计划', width: 100, totalRow:true}
|
|
155
|
+
,{field: 'finish_12', title: '完成', width: 100, totalRow:true}
|
|
156
|
+
|
|
157
|
+
]]
|
|
158
|
+
});
|
|
159
|
+
loadFinishTable(form.val('assessment_progress_form'))
|
|
160
|
+
|
|
161
|
+
form.on('submit(progress_search_btn)', function (data) {
|
|
162
|
+
var search = data.field;
|
|
163
|
+
search.assessment_id = assement_list.getValue('valueStr').split(",");
|
|
164
|
+
loadFinishTable(search);
|
|
165
|
+
return false;
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
function loadFinishTable(search) {
|
|
169
|
+
table.reload('finished_table', {
|
|
170
|
+
where: search,
|
|
171
|
+
url: '/missions/assessments/finished'
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
</script>
|
|
178
|
+
</div>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<li data="month">月计划</li>
|
|
6
6
|
<li data="monthly">月报</li>
|
|
7
7
|
<li data="year">年计划</li>
|
|
8
|
+
<!-- <li data="target_track">年度执行</li> -->
|
|
8
9
|
</ul>
|
|
9
10
|
<div class="layui-tab-content">
|
|
10
11
|
<div class="layui-tab-item layui-show">
|
|
@@ -22,6 +23,8 @@
|
|
|
22
23
|
<div class="layui-tab-item">
|
|
23
24
|
<div id="year_plan_tab_wraper"></div>
|
|
24
25
|
</div>
|
|
26
|
+
<div class="layui-tab-item" id="target_track_tab">
|
|
27
|
+
</div>
|
|
25
28
|
</div>
|
|
26
29
|
</div>
|
|
27
30
|
|
|
@@ -70,6 +73,8 @@
|
|
|
70
73
|
loadPage('/missions/plans/monthly')
|
|
71
74
|
} else if (data.index == 4 && $("#year_table_wraper").length == 0) {
|
|
72
75
|
loadPage('/missions/plans/year_plan')
|
|
76
|
+
} else if (data.index == 5 && $("#target_track_wraper").length == 0) {
|
|
77
|
+
loadPage('/missions/plans/target_track')
|
|
73
78
|
}
|
|
74
79
|
});
|
|
75
80
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$("#target_track_tab").html("<%= j render 'target_track' %>");
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
<div id="tab_9">
|
|
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_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
|
+
<% common = EducodeSales::Common.find_by(clazz: 'staff_type', name: '销售')
|
|
10
|
+
staffs = EducodeSales::Staff.where(job_type: common.id) %>
|
|
11
|
+
<%= select_tag "staff_id", options_for_select(staffs.includes(:user).map { |d| [d.user.real_name, d.id] }, params[:staff_id]), {'lay-filter': 'staff_id', include_blank: true} %>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="layui-inline m-t-10">
|
|
15
|
+
<label class="layui-form-label">视图</label>
|
|
16
|
+
<div class="layui-input-inline">
|
|
17
|
+
<%= select_tag "forecast_count_range", options_for_select([['按周', 'week'], ['按月', 'month'], ['按季', 'quarter'], ['按年', 'year']], params[:forecast_count_range] || "month"), {'lay-filter': 'return_forecast_count'} %>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="layui-inline m-t-10">
|
|
21
|
+
<label class="layui-form-label">时间范围</label>
|
|
22
|
+
<div class="layui-input-inline">
|
|
23
|
+
<input type="text" class="layui-input forecast_month " id="return_forecast_date_month" name="forecast_date_month" placeholder=" - " value="<%= params[:forecast_date_month].present? ? params[:forecast_date_month] : Time.now.year.to_s + "-01" + " - " + Time.now.strftime("%Y-%m") %>" autocomplete="off">
|
|
24
|
+
<input type="text" class="layui-input forecast_year layui-hide" id="return_forecast_date_year" name="forecast_date_year" placeholder=" - " value="<%= params[:forecast_date_year] %>" autocomplete="off">
|
|
25
|
+
<input type="text" class="layui-input forecast_day layui-hide" id="return_forecast_date_day" name="forecast_date_day" placeholder=" - " value="<%= params[:forecast_date_day] %>" autocomplete="off">
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="layui-inline m-t-10">
|
|
29
|
+
<label class="layui-form-label">客户类型</label>
|
|
30
|
+
<div class="layui-input-inline">
|
|
31
|
+
<%= select_tag "property", options_for_select(SchoolTag.where(for_missions: true).pluck(:name, :id), params[:property]), {include_blank: true} %>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="layui-inline m-t-10">
|
|
35
|
+
<button type="reset" class="layui-btn layui-btn-primary" lay-submit lay-filter="reset_search">重 置</button>
|
|
36
|
+
<button type="button" class="forecast_count_bt layui-btn layui-btn-primary" lay-submit lay-filter="search_sales">确 定</button>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</form>
|
|
40
|
+
</div>
|
|
41
|
+
<canvas id="return_forecast_myChart2" width="960" height="350"></canvas>
|
|
42
|
+
<canvas id="return_forecast_myChart2_1" width="960" height="350" style="margin-top: 30px;"></canvas>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<script>
|
|
47
|
+
layui.use(['form', 'jquery', 'request', 'laydate', 'element'], function () {
|
|
48
|
+
var $ = layui.jquery,
|
|
49
|
+
form = layui.form,
|
|
50
|
+
request = layui.request,
|
|
51
|
+
laydate = layui.laydate;
|
|
52
|
+
|
|
53
|
+
form.render();
|
|
54
|
+
|
|
55
|
+
var opt = {
|
|
56
|
+
events: false,
|
|
57
|
+
tooltips: {
|
|
58
|
+
enabled: false
|
|
59
|
+
},
|
|
60
|
+
layout: {
|
|
61
|
+
padding: {
|
|
62
|
+
left: 20,
|
|
63
|
+
right: 20,
|
|
64
|
+
top: 20,
|
|
65
|
+
bottom: 0
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
hover: {
|
|
69
|
+
animationDuration: 1
|
|
70
|
+
},
|
|
71
|
+
animation: {
|
|
72
|
+
duration: 1,
|
|
73
|
+
onComplete: function () {
|
|
74
|
+
var chartInstance = this.chart, ctx = chartInstance.ctx;
|
|
75
|
+
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
|
|
76
|
+
ctx.textAlign = 'center';
|
|
77
|
+
ctx.textBaseline = 'bottom';
|
|
78
|
+
|
|
79
|
+
this.data.datasets.forEach(function (dataset, i) {
|
|
80
|
+
ctx.fillStyle = "#444";
|
|
81
|
+
var meta = chartInstance.controller.getDatasetMeta(i);
|
|
82
|
+
meta.data.forEach(function (bar, index) {
|
|
83
|
+
var data = dataset.data[index];
|
|
84
|
+
ctx.fillText(data, bar._model.x, bar._model.y - 5);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
laydate.render({
|
|
92
|
+
type: 'year',
|
|
93
|
+
elem: '#return_forecast_date_year',
|
|
94
|
+
range: true
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
laydate.render({
|
|
98
|
+
elem: '#return_forecast_date_day',
|
|
99
|
+
range: true
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
laydate.render({
|
|
103
|
+
type: 'month',
|
|
104
|
+
elem: '#return_forecast_date_month',
|
|
105
|
+
range: true
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
var forecast_type = "month";
|
|
109
|
+
if (forecast_type === "month") {
|
|
110
|
+
$(".forecast_year").addClass('layui-hide');
|
|
111
|
+
$(".forecast_day").addClass('layui-hide');
|
|
112
|
+
$(".forecast_month").removeClass('layui-hide')
|
|
113
|
+
} else if (forecast_type === "year" || forecast_type === "quarter") {
|
|
114
|
+
$(".forecast_month").addClass('layui-hide');
|
|
115
|
+
$(".forecast_year").removeClass('layui-hide');
|
|
116
|
+
$(".forecast_day").addClass('layui-hide')
|
|
117
|
+
} else {
|
|
118
|
+
$(".forecast_day").removeClass('layui-hide');
|
|
119
|
+
$(".forecast_month").addClass('layui-hide');
|
|
120
|
+
$(".forecast_year").addClass('layui-hide')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
form.on('select(return_forecast_count)', function (data) {
|
|
124
|
+
const value = data.value;
|
|
125
|
+
if (value === "month") {
|
|
126
|
+
$(".forecast_year").addClass('layui-hide');
|
|
127
|
+
$(".forecast_day").addClass('layui-hide');
|
|
128
|
+
$(".forecast_month").removeClass('layui-hide')
|
|
129
|
+
} else if (value === "year" || value === "quarter") {
|
|
130
|
+
$(".forecast_month").addClass('layui-hide');
|
|
131
|
+
$(".forecast_year").removeClass('layui-hide');
|
|
132
|
+
$(".forecast_day").addClass('layui-hide')
|
|
133
|
+
} else {
|
|
134
|
+
$(".forecast_day").removeClass('layui-hide');
|
|
135
|
+
$(".forecast_month").addClass('layui-hide');
|
|
136
|
+
$(".forecast_year").addClass('layui-hide')
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
//重置按钮
|
|
141
|
+
form.on('submit(reset_search)', function () {
|
|
142
|
+
form.val('search_form', {
|
|
143
|
+
staff_id: "",
|
|
144
|
+
property: ""
|
|
145
|
+
});
|
|
146
|
+
return false;
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
var ctx = document.getElementById('return_forecast_myChart2');
|
|
150
|
+
var return_forecast_myChart2 = new Chart(ctx, {
|
|
151
|
+
type: 'bar',
|
|
152
|
+
data: <%=raw @return_forecast_count_data_0.to_json %>,
|
|
153
|
+
options: opt
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
var ctx01 = document.getElementById('return_forecast_myChart2_1');
|
|
157
|
+
var return_forecast_myChart2_1 = new Chart(ctx01, {
|
|
158
|
+
type: 'bar',
|
|
159
|
+
data: <%=raw @return_forecast_count_data_1.to_json %>,
|
|
160
|
+
options: opt
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
form.on("submit(search_sales)", function (data) {
|
|
164
|
+
var layer_index = layer.load(0, {shade: [0.1, '#fff']});
|
|
165
|
+
Rails.ajax({
|
|
166
|
+
url: '/missions/sale_trends/return_money_forecast',
|
|
167
|
+
type: 'GET',
|
|
168
|
+
data: $.param(data.field, true),
|
|
169
|
+
dataType: "script",
|
|
170
|
+
success: function (res) {
|
|
171
|
+
layer.close(layer_index);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
</script>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$("#page_9").html("<%= j render 'return_money_forecast' %>");
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
<li class="">中标预测图</li>
|
|
9
9
|
<li class="">用户分析</li>
|
|
10
10
|
<li class="">拜访分析</li>
|
|
11
|
+
<li class="">回款预测图</li>
|
|
11
12
|
</ul>
|
|
12
13
|
<div class="layui-tab-content">
|
|
13
14
|
<div class="layui-tab-item layui-show">
|
|
@@ -242,6 +243,9 @@
|
|
|
242
243
|
<div class="layui-tab-item">
|
|
243
244
|
<div id="page_8"></div>
|
|
244
245
|
</div>
|
|
246
|
+
<div class="layui-tab-item">
|
|
247
|
+
<div id="page_9"></div>
|
|
248
|
+
</div>
|
|
245
249
|
</div>
|
|
246
250
|
</div>
|
|
247
251
|
|
|
@@ -270,6 +274,8 @@
|
|
|
270
274
|
loadPage('/missions/sale_trends/user_stat')
|
|
271
275
|
} else if (data.index == 7 && $("#tab_8").length == 0) {
|
|
272
276
|
loadPage('/missions/sale_trends/visit_analysis')
|
|
277
|
+
} else if (data.index == 8 && $("#tab_9").length == 0) {
|
|
278
|
+
loadPage('/missions/sale_trends/return_money_forecast')
|
|
273
279
|
}
|
|
274
280
|
});
|
|
275
281
|
|
|
@@ -111,12 +111,14 @@
|
|
|
111
111
|
<% if can? :create, EducodeSales::Teacher %>
|
|
112
112
|
<button class="layui-btn layui-btn-normal layui-btn-sm data-add-btn pull-right" lay-event="import">导入数据</button>
|
|
113
113
|
<button class="layui-btn layui-btn-normal layui-btn-sm data-add-btn pull-right" lay-event="add">添加老师</button>
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
<% end %>
|
|
115
|
+
<% if can? :export_teacher_list, EducodeSales::Teacher %>
|
|
116
|
+
<button class="layui-btn layui-btn-normal layui-btn-sm data-add-btn pull-right" lay-event="export">导出</button>
|
|
117
|
+
<% end %>
|
|
116
118
|
</div>
|
|
117
119
|
</script>
|
|
118
120
|
<div class="">
|
|
119
|
-
<table class="layui-hide" id="teachers_table" style="min-height: 300px;" lay-filter="teachers_table"></table>
|
|
121
|
+
<table class="layui-hide" id="teachers_table" style="min-height: 300px;" lay-filter="teachers_table"></table>
|
|
120
122
|
</div>
|
|
121
123
|
<script type="text/html" id="currentTableBar">
|
|
122
124
|
<% if can? :create, EducodeSales::TeacherFollow %>
|
|
@@ -295,7 +297,8 @@
|
|
|
295
297
|
field: 'followup_at',
|
|
296
298
|
width: 180,
|
|
297
299
|
title: '最新跟进时间',
|
|
298
|
-
hide: gon.filter.followup_at
|
|
300
|
+
hide: gon.filter.followup_at,
|
|
301
|
+
sort: true
|
|
299
302
|
},
|
|
300
303
|
{
|
|
301
304
|
field: 'latest_time',
|
|
@@ -401,16 +404,16 @@
|
|
|
401
404
|
]];
|
|
402
405
|
|
|
403
406
|
table = layui.table;
|
|
404
|
-
table.render({
|
|
407
|
+
var teachers_table = table.render({
|
|
405
408
|
elem: '#teachers_table',
|
|
406
409
|
url: '/missions/teachers',
|
|
407
410
|
where: {q: form.val('search_form')},
|
|
408
411
|
toolbar: '#toolbarDemo',
|
|
409
|
-
totalRow:true,
|
|
412
|
+
totalRow: true,
|
|
410
413
|
defaultToolbar: ['filter'],
|
|
411
414
|
cols: cols_table,
|
|
412
415
|
limit: 20,
|
|
413
|
-
|
|
416
|
+
limits: [10, 15, 20, 30, 40, 50, 60, 70, 80, 90],
|
|
414
417
|
page: true,
|
|
415
418
|
done: function (res) {
|
|
416
419
|
drowpdwonRender()
|
|
@@ -418,11 +421,11 @@
|
|
|
418
421
|
});
|
|
419
422
|
var dropmenu = gon.menus;
|
|
420
423
|
|
|
421
|
-
drowpdwonRender = function() {
|
|
424
|
+
drowpdwonRender = function () {
|
|
422
425
|
dropdown.render({
|
|
423
426
|
elem: '.more-btn',
|
|
424
427
|
data: dropmenu,
|
|
425
|
-
click: function(data, othis){
|
|
428
|
+
click: function (data, othis) {
|
|
426
429
|
var elem = $(this.elem);
|
|
427
430
|
id = elem.data('id');
|
|
428
431
|
switch (data.event) {
|
|
@@ -640,6 +643,15 @@
|
|
|
640
643
|
$(window).on("resize", function () {
|
|
641
644
|
layer.full(index);
|
|
642
645
|
});
|
|
646
|
+
} else if (obj.event === 'export') {
|
|
647
|
+
layer.load(0, {});
|
|
648
|
+
var data = form.val('search_teachers');
|
|
649
|
+
console.log(data)
|
|
650
|
+
request.authGet("missions/teachers?type=export&" + $.param({q: data}), {}, function (res) {
|
|
651
|
+
data = res.data;
|
|
652
|
+
table.exportFile(teachers_table.config.id, data, 'xls')
|
|
653
|
+
layer.closeAll('loading');
|
|
654
|
+
})
|
|
643
655
|
}
|
|
644
656
|
});
|
|
645
657
|
|
data/config/routes.rb
CHANGED
|
@@ -174,6 +174,7 @@ EducodeSales::Engine.routes.draw do
|
|
|
174
174
|
get :goal_forecast
|
|
175
175
|
get :user_stat
|
|
176
176
|
get :visit_analysis
|
|
177
|
+
get :return_money_forecast
|
|
177
178
|
end
|
|
178
179
|
end
|
|
179
180
|
|
|
@@ -266,6 +267,7 @@ EducodeSales::Engine.routes.draw do
|
|
|
266
267
|
get :month_plan
|
|
267
268
|
get :monthly
|
|
268
269
|
get :year_plan
|
|
270
|
+
get :target_track
|
|
269
271
|
end
|
|
270
272
|
member do
|
|
271
273
|
delete :delete_business_info
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
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.46
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- anke1460
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-07-
|
|
11
|
+
date: 2023-07-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -503,6 +503,7 @@ files:
|
|
|
503
503
|
- app/views/educode_sales/places/new.html.erb
|
|
504
504
|
- app/views/educode_sales/plans/_monthPlan.html.erb
|
|
505
505
|
- app/views/educode_sales/plans/_monthly.html.erb
|
|
506
|
+
- app/views/educode_sales/plans/_target_track.html.erb
|
|
506
507
|
- app/views/educode_sales/plans/_weekPlan.html.erb
|
|
507
508
|
- app/views/educode_sales/plans/_weekly.html.erb
|
|
508
509
|
- app/views/educode_sales/plans/_yearPlan.html.erb
|
|
@@ -532,6 +533,7 @@ files:
|
|
|
532
533
|
- app/views/educode_sales/plans/show_monthly.html.erb
|
|
533
534
|
- app/views/educode_sales/plans/show_week.html.erb
|
|
534
535
|
- app/views/educode_sales/plans/show_weekly.html.erb
|
|
536
|
+
- app/views/educode_sales/plans/target_track.js.erb
|
|
535
537
|
- app/views/educode_sales/plans/weekly.js.erb
|
|
536
538
|
- app/views/educode_sales/plans/year_plan.js.erb
|
|
537
539
|
- app/views/educode_sales/plans/years_plan.json.jbuilder
|
|
@@ -577,6 +579,7 @@ files:
|
|
|
577
579
|
- app/views/educode_sales/sale_trends/_business_area.html.erb
|
|
578
580
|
- app/views/educode_sales/sale_trends/_business_followup_analysis.html.erb
|
|
579
581
|
- app/views/educode_sales/sale_trends/_goal_forecast.html.erb
|
|
582
|
+
- app/views/educode_sales/sale_trends/_return_money_forecast.html.erb
|
|
580
583
|
- app/views/educode_sales/sale_trends/_sales_analysis.html.erb
|
|
581
584
|
- app/views/educode_sales/sale_trends/_sales_followup_analysis.html.erb
|
|
582
585
|
- app/views/educode_sales/sale_trends/_user_stat.html.erb
|
|
@@ -585,6 +588,7 @@ files:
|
|
|
585
588
|
- app/views/educode_sales/sale_trends/business_followup_analysis.js.erb
|
|
586
589
|
- app/views/educode_sales/sale_trends/goal_forecast.js.erb
|
|
587
590
|
- app/views/educode_sales/sale_trends/operations.html.erb
|
|
591
|
+
- app/views/educode_sales/sale_trends/return_money_forecast.js.erb
|
|
588
592
|
- app/views/educode_sales/sale_trends/sales_analysis.js.erb
|
|
589
593
|
- app/views/educode_sales/sale_trends/sales_followup_analysis.js.erb
|
|
590
594
|
- app/views/educode_sales/sale_trends/trends.html.erb
|
|
@@ -772,7 +776,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
772
776
|
- !ruby/object:Gem::Version
|
|
773
777
|
version: '0'
|
|
774
778
|
requirements: []
|
|
775
|
-
rubygems_version: 3.0.
|
|
779
|
+
rubygems_version: 3.0.0
|
|
776
780
|
signing_key:
|
|
777
781
|
specification_version: 4
|
|
778
782
|
summary: Summary of EducodeSales.
|