educode_sales 1.10.22 → 1.10.23

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2b8c0d76ccb06751726aeef62b4b04f234424db8b848d62f086b530b1213d25
4
- data.tar.gz: 88f36d9731d556cdfedd495e0ad198e90baeecf454352fc8faf17d9dd373c3a9
3
+ metadata.gz: ac157bfbdbc5c1aceeef3b0d0af4b81e74b6835ddda09a5beae4188f23720391
4
+ data.tar.gz: a4f7c4077fc9af0f5374fc3efec8bf42e5c3a57a27dc78090a5727cabe2f5510
5
5
  SHA512:
6
- metadata.gz: 99412e792e86479290e2d09a62aced8ae6bc6cd32d448450d9e0b4898d5df54358e683a70b94038eb37474ba663b6d1cbe9e4b24a8440dcef2e6ca17a3d19e06
7
- data.tar.gz: cb3ba8ffa9e9cf91ade0cf3a74fe5e5fc13767d05a1dfa12180fb699abbb70cbc380469b55b11b0900a7c0930afd2ba395148f532c23f3fcba70f7794fca7913
6
+ metadata.gz: 804531ab845025fe61054b79b248a5f1f83e4194d0c23cad2f0fb4c49978db71eb695815723d50e7255fa35a4aa0b0154babb156fdd5cd953808bb2a1b56a9e9
7
+ data.tar.gz: 13484d3b014be703413f41b03938881aeb56bd1b7cf97f721f055f9a0aa869dfedc6b948ddbd57bb7b3174c2e3aa171dc7efa5823821f3e2b903e1e1ec9b2591
@@ -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
@@ -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
 
@@ -1,3 +1,3 @@
1
1
  module EducodeSales
2
- VERSION = '1.10.22'
2
+ VERSION = '1.10.23'
3
3
  end
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.22
4
+ version: 1.10.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - anke1460
@@ -574,6 +574,7 @@ files:
574
574
  - app/views/educode_sales/sale_trends/_sales_analysis.html.erb
575
575
  - app/views/educode_sales/sale_trends/_sales_followup_analysis.html.erb
576
576
  - app/views/educode_sales/sale_trends/_user_stat.html.erb
577
+ - app/views/educode_sales/sale_trends/_visit_analysis.html.erb
577
578
  - app/views/educode_sales/sale_trends/business_area.js.erb
578
579
  - app/views/educode_sales/sale_trends/business_followup_analysis.js.erb
579
580
  - app/views/educode_sales/sale_trends/goal_forecast.js.erb
@@ -583,6 +584,7 @@ files:
583
584
  - app/views/educode_sales/sale_trends/trends.html.erb
584
585
  - app/views/educode_sales/sale_trends/trends.json.jbuilder
585
586
  - app/views/educode_sales/sale_trends/user_stat.js.erb
587
+ - app/views/educode_sales/sale_trends/visit_analysis.js.erb
586
588
  - app/views/educode_sales/sales/index.html.erb
587
589
  - app/views/educode_sales/sales/index.json.jbuilder
588
590
  - app/views/educode_sales/sales/operations.html.erb