educode_sales 0.9.72 → 0.9.73

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: c3ce2eed15225b67592420332087c3ca7284c2908a17643d6199ac829859196f
4
- data.tar.gz: eec810ee5dd968d2c0b6af7053138a1ea8649fe57986dd054a91c15aa1f9afc6
3
+ metadata.gz: bd2b28526eb6deff3149781638110e6f86c717287996bf7740437727adfd2ee3
4
+ data.tar.gz: cd3c64540eed97347f0f5b640136cc2fab13d74635246d54d5ca1e95dc1b4a43
5
5
  SHA512:
6
- metadata.gz: 2dfefa8e8e30235cdbd3ff7c0e17044788cf76d3d62698455da06d77fe0007571a16ff0dd39cc2e4b60faccede54df20da14dd1cbce40eecc6ebf48c4a87c7b2
7
- data.tar.gz: b6765899a3cbeda621f0fa85940e1fec3702b74c88685a90bacff2ac57fdd6b9701fb5f89aaab13e577b5b2bb764ac4050a5a681b56ccf2d1006f381f8e5cb30
6
+ metadata.gz: f07f190aa90d48f53aa734204c86c77f7caa7fd3a374b71bd4b6a8080428542354d67b9eefd4037490da5b3784b3219fcc3286d1cba6dd1279489e6a3edabb3f
7
+ data.tar.gz: 27b899f64fe009157232ccaf573e83f4562a5496fbb69bdb5650105df89ca8599b26715c22e70af9aeff1bf355f75fcaab5ff8ef6768371ddf48ec35d85efab5
@@ -0,0 +1,145 @@
1
+ require_dependency "educode_sales/application_controller"
2
+
3
+ module EducodeSales
4
+ class ProjectChartsController < ApplicationController
5
+ # authorize_resource class: false
6
+
7
+ def trends
8
+ end
9
+ # 销售额分析
10
+ def sales_analysis
11
+ respond_to do |format|
12
+ format.html do
13
+ end
14
+ format.js do
15
+ x = EducodeSales::Common.find_by(extras: EducodeSales::Common::XTYPE)&.id
16
+ count_type = params[:count_type] || "actual_amount"
17
+ stage_ids = Common.where(clazz: '商机阶段', name: ['已中标', '已签单', '已验收', '回款中', '服务中', '已结束']).pluck(:id)
18
+ s_stage_ids = Common.where(clazz: '商机阶段', name: ['已签单', '已验收', '回款中', '服务中', '已结束']).pluck(:id)
19
+ @goal_count_range = params[:goal_count_range] || "month"
20
+
21
+ goal_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
22
+ sale_names = ['已中标', '已签单', '已回款']
23
+ @goal_count_data = month_sale_chart(goal_default_dates, sale_names, SaleTrend::COLORS, x, stage_ids, s_stage_ids, count_type, ["#{Time.now.year}-01", "#{Time.now.year}-#{Time.now.month}"])
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+
31
+
32
+ def month_sale_chart(dates, names, colors, x, stage_ids, s_stage_ids, count_type, range)
33
+ begin_at = range[0]
34
+ end_at = range[1]
35
+
36
+ data_1 = EducodeSales::Business.joins(:last_follow_up).
37
+ where("educode_sales_follow_ups.clazz_id != ?", x).
38
+ where("educode_sales_follow_ups.stage_id IN (?)", stage_ids).
39
+ where("educode_sales_follow_ups.bidded_date >= ? AND educode_sales_follow_ups.bidded_date <= ?", begin_at, end_at).
40
+ select("SUM(#{count_type}) AS count_type, DATE_FORMAT(bidded_date, '%Y-%m') AS month").
41
+ group("DATE_FORMAT(bidded_date, '%Y-%m')").
42
+ order("DATE_FORMAT(bidded_date, '%Y-%m')")
43
+ data_1_hash = {}
44
+ data_1_total_hash = {}
45
+ data_1.each do |d|
46
+ data_1_hash[d.month] = d.count_type.round(2)
47
+ end
48
+
49
+ last_month = 0
50
+ last_sum = 0
51
+ dates.each do |month|
52
+ # 只累计当前年份
53
+ if last_month != month.split("-")[0]
54
+ last_sum = 0
55
+ end
56
+ data_1_total_hash[month] = ((data_1_hash[month] || 0) + last_sum).round(2)
57
+ last_sum += data_1_hash[month] || 0
58
+ last_month = month.split("-")[0]
59
+ end
60
+
61
+ data_2 = EducodeSales::Business.joins(:last_follow_up).
62
+ where("educode_sales_follow_ups.clazz_id != ?", x).
63
+ where("educode_sales_follow_ups.stage_id IN (?)", s_stage_ids).
64
+ where("educode_sales_follow_ups.signed_date >= ? AND educode_sales_follow_ups.signed_date <= ?", begin_at, end_at).
65
+ select("SUM(#{count_type}) AS count_type, DATE_FORMAT(signed_date, '%Y-%m') AS month").
66
+ group("DATE_FORMAT(signed_date, '%Y-%m')").
67
+ order("DATE_FORMAT(signed_date, '%Y-%m')")
68
+ data_2_hash = {}
69
+ data_2_total_hash = {}
70
+ data_2.each do |d|
71
+ data_2_hash[d.month] = d.count_type.round(2)
72
+ end
73
+
74
+ last_month = 0
75
+ last_sum = 0
76
+ dates.each do |month|
77
+ # 只累计当前年份
78
+ if last_month != month.split("-")[0]
79
+ last_sum = 0
80
+ end
81
+ data_2_total_hash[month] = ((data_2_hash[month] || 0) + last_sum).round(2)
82
+ last_sum += data_2_hash[month] || 0
83
+ last_month = month.split("-")[0]
84
+ end
85
+
86
+ data_3 = EducodeSales::Business.joins(last_follow_up: :money_plans).
87
+ where("educode_sales_follow_ups.clazz_id != ?", x).
88
+ where.not("educode_sales_money_plans.clazz!= ?", 1).
89
+ where("educode_sales_money_plans.date_at >= ? AND educode_sales_money_plans.date_at <= ?", begin_at, end_at).
90
+ select("SUM(amount) AS count_type, DATE_FORMAT(date_at, '%Y-%m') AS month").
91
+ group("DATE_FORMAT(date_at, '%Y-%m')").
92
+ order("DATE_FORMAT(date_at, '%Y-%m')")
93
+ data_3_hash = {}
94
+ data_3.each do |d|
95
+ data_3_hash[d.month] = d.count_type.round(2)
96
+ end
97
+
98
+ data_3_total_hash = {}
99
+ last_month = 0
100
+ last_sum = 0
101
+ dates.each do |month|
102
+ # 只累计当前年份
103
+ if last_month != month.split("-")[0]
104
+ last_sum = 0
105
+ end
106
+ data_3_total_hash[month] = ((data_3_hash[month] || 0) + last_sum).round(2)
107
+ last_sum += data_3_hash[month] || 0
108
+ last_month = month.split("-")[0]
109
+ end
110
+
111
+ {
112
+ labels: dates,
113
+ datasets: names.map.with_index do |name, i|
114
+ {
115
+ label: name,
116
+ data: dates.map { |d|
117
+ case i
118
+ when 0
119
+ data_1_hash[d] || 0
120
+ when 1
121
+ data_2_hash[d] || 0
122
+ else
123
+ data_3_hash[d] || 0
124
+ end
125
+ },
126
+ data1: dates.map { |d|
127
+ case i
128
+ when 0
129
+ data_1_total_hash[d] || 0
130
+ when 1
131
+ data_2_total_hash[d] || 0
132
+ else
133
+ data_3_total_hash[d] || 0
134
+ end
135
+ },
136
+ backgroundColor: colors[i],
137
+ borderColor: colors[i],
138
+ borderWidth: 1
139
+ }
140
+ end
141
+ }
142
+ end
143
+
144
+ end
145
+ end
@@ -103,15 +103,162 @@ module EducodeSales
103
103
 
104
104
  ids_a_b = Common.where(extras: %w[a_class b_class ]).pluck(:id)
105
105
  ids_c_d = Common.where(extras: %w[c_class d_class]).pluck(:id)
106
- @businesses_a_b_count = @businesses.joins("JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id").where("educode_sales_follow_ups.clazz_id in (?)",ids_a_b)
107
- .where("educode_sales_businesses.staff_id = ?",staff_id)
108
- .where("educode_sales_businesses.created_at >= ? and educode_sales_businesses.created_at <= ?", "#{@assessment_year}-#{start_time} 00:00:00".to_date,
106
+ @businesses_a_b_count = @businesses.joins("JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id").where("educode_sales_follow_ups.clazz_id in (?)", ids_a_b)
107
+ .where("educode_sales_businesses.staff_id = ?", staff_id)
108
+ .where("educode_sales_businesses.created_at >= ? and educode_sales_businesses.created_at <= ?", "#{@assessment_year}-#{start_time} 00:00:00".to_date,
109
109
  "#{@assessment_year}-#{end_time} 23:59:00".to_date)
110
- @businesses_c_d_count = @businesses.joins("JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id").where("educode_sales_follow_ups.clazz_id in (?)",ids_c_d)
111
- .where("educode_sales_businesses.staff_id = ?",staff_id)
110
+ @businesses_c_d_count = @businesses.joins("JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id").where("educode_sales_follow_ups.clazz_id in (?)", ids_c_d)
111
+ .where("educode_sales_businesses.staff_id = ?", staff_id)
112
112
  .where("educode_sales_businesses.created_at >= ? and educode_sales_businesses.created_at <= ?", "#{@assessment_year}-#{start_time} 00:00:00".to_date,
113
113
  "#{@assessment_year}-#{end_time} 23:59:00".to_date)
114
- @businesses_a_b_count.count.to_i*10 + @businesses_c_d_count.count.to_i*5
114
+ @businesses_a_b_count.count.to_i * 10 + @businesses_c_d_count.count.to_i * 5
115
+ end
116
+
117
+ def get_businesses_chart(year, month)
118
+ contract_ids = EducodeSales::Common.where(clazz: '商机阶段', name: ['已中标', '已签单', '已验收', '回款中', '服务中', '已结束']).pluck(:id)
119
+ @businesses = EducodeSales::Business.joins("
120
+ JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id
121
+ ").where("educode_sales_follow_ups.stage_id in (?)", contract_ids)
122
+
123
+ # 逾期id
124
+ late_ids = EducodeSales::Business.joins("JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id JOIN educode_sales_commons on educode_sales_commons.id = educode_sales_follow_ups.stage_id")
125
+ .where("educode_sales_follow_ups.bidded_date is not null")
126
+ .where("NOW() > DATE_ADD(educode_sales_follow_ups.bidded_date, INTERVAL 1 MONTH)")
127
+ .where("educode_sales_businesses.p_stage is null")
128
+ .where("educode_sales_commons.name = '已中标'")
129
+ .or(EducodeSales::Business.joins("JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id JOIN educode_sales_commons on educode_sales_commons.id = educode_sales_follow_ups.stage_id")
130
+ .where("NOW() > educode_sales_businesses.p_pre_money_time")
131
+ .where("educode_sales_businesses.p_pre_money_time is not null")
132
+ .where("educode_sales_businesses.p_actual_money_time is null")
133
+ ).or(EducodeSales::Business.joins("JOIN educode_sales_follow_ups ON educode_sales_businesses.last_follow_up_id = educode_sales_follow_ups.id JOIN educode_sales_commons on educode_sales_commons.id = educode_sales_follow_ups.stage_id")
134
+ .where("NOW() > educode_sales_businesses.p_pre_accept_time")
135
+ .where("educode_sales_businesses.p_pre_accept_time is not null")
136
+ .where("educode_sales_businesses.p_accept_time is null")).ids
137
+
138
+ # 待交付项目
139
+ data_4 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
140
+ .count("distinct educode_sales_businesses.id")
141
+ # 实际交付
142
+ data_5 = @businesses.where("educode_sales_businesses.p_deploy_time > ? AND educode_sales_businesses.p_deploy_time < ?", year + "-" + month + "-01", year + "-" + month + "-31")
143
+ .count("distinct educode_sales_businesses.id")
144
+ # 待准备项目
145
+ data_6 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
146
+ .count("distinct educode_sales_businesses.id")
147
+ # 完成准备
148
+ data_7 = @businesses.where("educode_sales_businesses.p_status = 1")
149
+ .where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
150
+ .count("distinct educode_sales_businesses.id")
151
+ # 待验收平台包
152
+ data_8 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
153
+ .count("distinct educode_sales_businesses.id")
154
+ # 实际验收平台包
155
+ data_9 = @businesses.where("educode_sales_businesses.p_platform_time is not null")
156
+ .where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
157
+ .count("distinct educode_sales_businesses.id")
158
+ # 待验收课程包
159
+ data_10 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
160
+ .count("distinct educode_sales_businesses.id")
161
+ # 实际验收课程包
162
+ data_11 = @businesses.where("educode_sales_businesses.p_course_time is not null")
163
+ .where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
164
+ .count("distinct educode_sales_businesses.id")
165
+ data_2 = data_4 + data_6 + data_8 + data_10 # 本月总任务
166
+ data_3 = data_5 + data_7 + data_9 + data_11 # 本月完成任务
167
+ # 本月任务完成度
168
+ data_1 = data_2.zero? ? 0 : (data_3.to_f / data_2.to_f).round(2) * 100
169
+
170
+ # 历史遗漏项目
171
+ data_12 = @businesses.where("educode_sales_follow_ups.reception_at < ?", year + "-01-01")
172
+ .where("educode_sales_businesses.p_course_time IS NULL
173
+ OR educode_sales_businesses.p_platform_time IS NULL
174
+ OR educode_sales_businesses.p_deploy_time IS NULL
175
+ OR educode_sales_businesses.p_actual_money_time IS NULL
176
+ OR educode_sales_businesses.p_accept_time IS NULL
177
+ ").count("distinct educode_sales_businesses.id")
178
+ # 年度待交付项目
179
+ data_13 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-01-01", year + "-12-31")
180
+ .count("distinct educode_sales_businesses.id")
181
+ # 年度已交付项目
182
+ data_14 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-01-01", year + "-12-31")
183
+ .where("educode_sales_businesses.p_course_time IS NOT NULL
184
+ AND educode_sales_businesses.p_platform_time IS NOT NULL
185
+ AND educode_sales_businesses.p_deploy_time IS NOT NULL
186
+ AND educode_sales_businesses.p_actual_money_time IS NOT NULL
187
+ AND educode_sales_businesses.p_accept_time IS NOT NULL
188
+ ").count("distinct educode_sales_businesses.id")
189
+ # 年度延期项目
190
+ data_15 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-01-01", year + "-12-31")
191
+ .where(id: late_ids)
192
+ .count("distinct educode_sales_businesses.id")
193
+
194
+ year_data_all_1 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-01-01", year + "-12-31")
195
+ .group(:p_staff_id).sum("case when educode_sales_businesses.p_course_time is not null then 1 else 0 end + case when educode_sales_businesses.p_platform_time is not null then 1 else 0 end + case when educode_sales_businesses.p_deploy_time is not null then 1 else 0 end + case when educode_sales_businesses.p_actual_money_time is not null then 1 else 0 end + case when educode_sales_businesses.p_accept_time is not null then 1 else 0 end")
196
+ year_data_all_2 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-01-01", year + "-12-31")
197
+ .group(:p_sale_staff_id).sum("case when educode_sales_businesses.p_course_time is not null then 1 else 0 end + case when educode_sales_businesses.p_platform_time is not null then 1 else 0 end + case when educode_sales_businesses.p_deploy_time is not null then 1 else 0 end + case when educode_sales_businesses.p_actual_money_time is not null then 1 else 0 end + case when educode_sales_businesses.p_accept_time is not null then 1 else 0 end")
198
+ month_data_all_1 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
199
+ .group(:p_staff_id).sum("case when educode_sales_businesses.p_course_time is not null then 1 else 0 end + case when educode_sales_businesses.p_platform_time is not null then 1 else 0 end + case when educode_sales_businesses.p_deploy_time is not null then 1 else 0 end + case when educode_sales_businesses.p_actual_money_time is not null then 1 else 0 end + case when educode_sales_businesses.p_accept_time is not null then 1 else 0 end")
200
+ month_data_all_2 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
201
+ .group(:p_sale_staff_id).sum("case when educode_sales_businesses.p_course_time is not null then 1 else 0 end + case when educode_sales_businesses.p_platform_time is not null then 1 else 0 end + case when educode_sales_businesses.p_deploy_time is not null then 1 else 0 end + case when educode_sales_businesses.p_actual_money_time is not null then 1 else 0 end + case when educode_sales_businesses.p_accept_time is not null then 1 else 0 end")
202
+
203
+ year_merged_hash = month_data_all_1.merge(month_data_all_2) { |key, v1, v2| v1 + v2 }.sort_by { |k, v| v }.reverse.to_h
204
+ month_merged_hash = year_data_all_1.merge(year_data_all_2) { |key, v1, v2| v1 + v2 }.sort_by { |k, v| v }.reverse.to_h
205
+
206
+ not_finish_year_data_all_1 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-01-01", year + "-12-31")
207
+ .group(:p_staff_id).sum("case when educode_sales_businesses.p_course_time is null then 1 else 0 end + case when educode_sales_businesses.p_platform_time is null then 1 else 0 end + case when educode_sales_businesses.p_deploy_time is null then 1 else 0 end + case when educode_sales_businesses.p_actual_money_time is null then 1 else 0 end + case when educode_sales_businesses.p_accept_time is null then 1 else 0 end")
208
+ not_finish_year_data_all_2 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-01-01", year + "-12-31")
209
+ .group(:p_sale_staff_id).sum("case when educode_sales_businesses.p_course_time is null then 1 else 0 end + case when educode_sales_businesses.p_platform_time is null then 1 else 0 end + case when educode_sales_businesses.p_deploy_time is null then 1 else 0 end + case when educode_sales_businesses.p_actual_money_time is null then 1 else 0 end + case when educode_sales_businesses.p_accept_time is null then 1 else 0 end")
210
+ not_finish_month_data_all_1 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
211
+ .group(:p_staff_id).sum("case when educode_sales_businesses.p_course_time is null then 1 else 0 end + case when educode_sales_businesses.p_platform_time is null then 1 else 0 end + case when educode_sales_businesses.p_deploy_time is null then 1 else 0 end + case when educode_sales_businesses.p_actual_money_time is null then 1 else 0 end + case when educode_sales_businesses.p_accept_time is null then 1 else 0 end")
212
+ not_finish_month_data_all_2 = @businesses.where("educode_sales_follow_ups.reception_at > ? AND educode_sales_follow_ups.reception_at < ?", year + "-" + month + "-01", year + "-" + month + "-31")
213
+ .group(:p_sale_staff_id).sum("case when educode_sales_businesses.p_course_time is null then 1 else 0 end + case when educode_sales_businesses.p_platform_time is null then 1 else 0 end + case when educode_sales_businesses.p_deploy_time is null then 1 else 0 end + case when educode_sales_businesses.p_actual_money_time is null then 1 else 0 end + case when educode_sales_businesses.p_accept_time is null then 1 else 0 end")
214
+ not_finish_year_merged_hash = not_finish_year_data_all_1.merge(not_finish_year_data_all_2) { |key, v1, v2| v1 + v2 }.sort_by { |k, v| v }.reverse.to_h
215
+ not_finish_month_merged_hash = not_finish_month_data_all_1.merge(not_finish_month_data_all_2) { |key, v1, v2| v1 + v2 }.sort_by { |k, v| v }.reverse.to_h
216
+
217
+ all_year_merged_hash = year_merged_hash.merge(not_finish_year_merged_hash) { |key, v1, v2| v1 + v2 }.sort_by { |k, v| v }.reverse.to_h
218
+ all_month_merged_hash = month_merged_hash.merge(not_finish_month_merged_hash) { |key, v1, v2| v1 + v2 }.sort_by { |k, v| v }.reverse.to_h
219
+ staffs = EducodeSales::Staff.all.includes(:user)
220
+ colors = SaleTrend::COLORS
221
+ chart1 = {
222
+ labels: staffs.map { |d| d.user.real_name },
223
+ datasets: %w[已完成 未完成].map.with_index do |d, i|
224
+ {
225
+ label: d,
226
+ data: staffs.map { |s|
227
+ case d
228
+ when "已完成"
229
+ month_merged_hash[s.id].to_i
230
+ when "未完成"
231
+ not_finish_month_merged_hash[s.id].to_i
232
+ end
233
+ },
234
+ backgroundColor: colors[i],
235
+ borderColor: colors[i],
236
+ borderWidth: 1
237
+ }
238
+ end
239
+ }
240
+ chart2 = {
241
+ labels: staffs.map { |d| d.user.real_name },
242
+ datasets: %w[已完成 未完成].map.with_index do |d, i|
243
+ {
244
+ label: d,
245
+ data: staffs.map { |s|
246
+ case d
247
+ when "已完成"
248
+ year_merged_hash[s.id].to_i
249
+ when "未完成"
250
+ not_finish_year_merged_hash[s.id].to_i
251
+ end
252
+ },
253
+ backgroundColor: colors[i],
254
+ borderColor: colors[i],
255
+ borderWidth: 1
256
+ }
257
+ end
258
+ }
259
+ staff_data = EducodeSales::Staff.where(id: year_merged_hash.keys).limit(3).map { |d| [d.user.real_name, all_year_merged_hash[d.id], year_merged_hash[d.id]] }
260
+
261
+ [data_1, data_2, data_3, data_4, data_5, data_6, data_7, data_8, data_9, data_10, data_11, data_12, data_13, data_14, data_15, staff_data, chart1, chart2]
115
262
  end
116
263
 
117
264
  end
@@ -0,0 +1,436 @@
1
+ <%
2
+ date = params[:goal_date_month].present? ? params[:goal_date_month] : "2023-04"
3
+ year = date.to_s.split("-")[0]
4
+ month = date.to_s.split("-")[1]
5
+ data_arr = get_businesses_chart(year, month) # 本月任务完成度, 本月总任务, 本月完成任务, 待交付项目, 实际交付, 本月任务完成度, 本月总任务, 本月完成任务, 待交付项目, 实际交付, 本月任务完成度, 本月总任务, 本月完成任务, 待交付项目, 实际交付, hash, chart1, chart2
6
+ data_1, data_2, data_3, data_4, data_5, data_6, data_7, data_8, data_9, data_10, data_11, data_12, data_13, data_14, data_15 =
7
+ data_arr[0], data_arr[1], data_arr[2], data_arr[3], data_arr[4], data_arr[5], data_arr[6], data_arr[7], data_arr[8], data_arr[9], data_arr[10], data_arr[11], data_arr[12], data_arr[13], data_arr[14]
8
+ staff_data = data_arr[15]
9
+ chart1 = data_arr[16]
10
+ chart2 = data_arr[17]
11
+ %>
12
+ <div id="tab_3" lay-filter="test1">
13
+ <div class="" style="padding-right: 50px">
14
+ <div style="margin: 10px 10px 10px 10px">
15
+ <form class="layui-form layui-form-pane" lay-filter="search_form">
16
+ <div class="layui-form-item">
17
+ <div class="layui-inline">
18
+ <label class="layui-form-label">时间</label>
19
+ <div class="layui-input-inline">
20
+ <input type="text" class="layui-input goal_month " id="goal_date_month" name="goal_date_month" placeholder=" - " value="<%= date %>" autocomplete="off">
21
+ </div>
22
+ </div>
23
+ <div class="layui-inline">
24
+ <button type="button" id="search_bt" class="goal_count_bt layui-btn layui-btn-primary" lay-submit lay-filter="search_sales">确定
25
+ </button>
26
+ </div>
27
+ </div>
28
+ </form>
29
+ </div>
30
+
31
+ <div class="layui-panel">
32
+ <br>
33
+
34
+ <h1 style="padding-left: 10px">任务分布</h1>
35
+ <br>
36
+
37
+ <br>
38
+
39
+ <form class="layui-form layui-panel">
40
+ <div class="welcome">
41
+ <div class="content-body">
42
+ <div class="layui-card-bodys">
43
+ <div class="operation_trend_panel">
44
+ <div class="layui-row layui-col-space30">
45
+ <div class="layui-col-xs3">
46
+ <div class="panel layui-bg-number">
47
+ <div class="panel-body">
48
+ <div class="panel-title">
49
+ <h5>本月任务完成度</h5>
50
+ </div>
51
+ <div class="panel-content y-t-10">
52
+ <h1 class="no-margins" id="users_count_value"><span><%= data_1 %></span>%
53
+ </h1>
54
+ <div id="users_count_field" class="layui-hide">
55
+ <input type="text" name="users_count" autocomplete="off" class="layui-input" id="users_count">
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ <div class="layui-col-xs3">
62
+ <div class="panel layui-bg-number">
63
+ <div class="panel-body">
64
+ <div class="panel-title">
65
+ <h5>本月总任务</h5>
66
+ </div>
67
+ <div class="panel-content y-t-10">
68
+ <h1 class="no-margins" id="teachers_count_value">
69
+ <span><%= data_2 %></span>个</h1>
70
+ <div id="teachers_count_field" class="layui-hide">
71
+ <input type="text" name="teachers_count" autocomplete="off" class="layui-input" id="teachers_count">
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ </div>
77
+ <div class="layui-col-xs3">
78
+ <div class="panel layui-bg-number">
79
+ <div class="panel-body">
80
+ <div class="panel-title">
81
+ <h5>本月完成任务</h5>
82
+ </div>
83
+ <div class="panel-content y-t-10">
84
+ <h1 class="no-margins" id="courses_count_value">
85
+ <span><%= data_3 %></span>个</h1>
86
+ <div id="courses_count_field" class="layui-hide">
87
+ <input type="text" name="courses_count" autocomplete="off" class="layui-input" id="courses_count">
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ <div class="layui-col-xs3">
94
+ <div class="panel layui-bg-number">
95
+ <div class="panel-body">
96
+ <div class="panel-title">
97
+ <h5>
98
+ 待交付项目</h5>
99
+ </div>
100
+ <div class="panel-content y-t-10">
101
+ <h1 class="no-margins" id="top_teachers_count_value">
102
+ <span><%= data_4 %></span>
103
+ </h1>
104
+ <div id="top_teachers_count_field" class="layui-hide">
105
+ <input type="text" name="top_teachers_count" autocomplete="off" class="layui-input"
106
+ id="top_teachers_count">
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ </div>
112
+
113
+ <div class="layui-col-xs3">
114
+ <div class="panel layui-bg-number">
115
+ <div class="panel-body">
116
+ <div class="panel-title">
117
+ <h5>实际交付</h5>
118
+ </div>
119
+ <div class="panel-content y-t-10">
120
+ <h1 class="no-margins"><%= data_5 %></h1>
121
+ </div>
122
+ </div>
123
+ </div>
124
+ </div>
125
+
126
+ <div class="layui-col-xs3">
127
+ <div class="panel layui-bg-number">
128
+ <div class="panel-body">
129
+ <div class="panel-title">
130
+ <h5>待准备项目</h5>
131
+ </div>
132
+ <div class="panel-content y-t-10">
133
+ <h1 class="no-margins"><%= data_6 %></h1>
134
+ </div>
135
+ </div>
136
+ </div>
137
+ </div>
138
+
139
+ <div class="layui-col-xs3">
140
+ <div class="panel layui-bg-number">
141
+ <div class="panel-body">
142
+ <div class="panel-title">
143
+ <h5>完成准备</h5>
144
+ </div>
145
+ <div class="panel-content y-t-10">
146
+ <h1 class="no-margins"><%= data_7 %></h1>
147
+ </div>
148
+ </div>
149
+ </div>
150
+ </div>
151
+
152
+ <div class="layui-col-xs3">
153
+ <div class="panel layui-bg-number">
154
+ <div class="panel-body">
155
+ <div class="panel-title">
156
+ <h5>待验收平台包</h5>
157
+ </div>
158
+ <div class="panel-content y-t-10">
159
+ <h1 class="no-margins"><%= data_8 %></h1>
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ <div class="layui-col-xs3">
165
+ <div class="panel layui-bg-number">
166
+ <div class="panel-body">
167
+ <div class="panel-title">
168
+ <h5>实际验收平台包</h5>
169
+ </div>
170
+ <div class="panel-content y-t-10">
171
+ <h1 class="no-margins"><%= data_9 %></h1>
172
+ </div>
173
+ </div>
174
+ </div>
175
+ </div>
176
+ <div class="layui-col-xs3">
177
+ <div class="panel layui-bg-number">
178
+ <div class="panel-body">
179
+ <div class="panel-title">
180
+ <h5>待验收课程包</h5>
181
+ </div>
182
+ <div class="panel-content y-t-10">
183
+ <h1 class="no-margins"><%= data_10 %></h1>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ </div>
188
+ <div class="layui-col-xs3">
189
+ <div class="panel layui-bg-number">
190
+ <div class="panel-body">
191
+ <div class="panel-title">
192
+ <h5>实际验收课程包</h5>
193
+ </div>
194
+ <div class="panel-content y-t-10">
195
+ <h1 class="no-margins"><%= data_11 %></h1>
196
+ </div>
197
+ </div>
198
+ </div>
199
+ </div>
200
+
201
+ </div>
202
+ </div>
203
+ </div>
204
+ </div>
205
+ </div>
206
+ </form>
207
+ <br>
208
+ <br>
209
+
210
+ <div class="layui-panel">
211
+ <canvas id="myChart2" width="960" height="350"></canvas>
212
+ </div>
213
+ </div>
214
+
215
+ <br>
216
+ <br>
217
+ <div class="layui-panel">
218
+ <br>
219
+
220
+ <h1 style="padding-left: 10px">总体分析</h1>
221
+ <br>
222
+
223
+ <form class="layui-form layui-panel">
224
+ <div class="welcome">
225
+ <div class="content-body">
226
+ <div class="layui-card-bodys">
227
+ <div class="operation_trend_panel">
228
+ <div class="layui-row layui-col-space30">
229
+ <div class="layui-col-xs3">
230
+ <div class="panel layui-bg-number">
231
+ <div class="panel-body">
232
+ <div class="panel-title">
233
+ <h5>历史遗漏项目</h5>
234
+ </div>
235
+ <div class="panel-content y-t-10">
236
+ <h1 class="no-margins" id="users_count_value"><span><%= data_12 %></span>个
237
+ </h1>
238
+ <div id="users_count_field" class="layui-hide">
239
+ <input type="text" name="users_count" autocomplete="off" class="layui-input" id="users_count">
240
+ </div>
241
+ </div>
242
+ </div>
243
+ </div>
244
+ </div>
245
+ <div class="layui-col-xs3">
246
+ <div class="panel layui-bg-number">
247
+ <div class="panel-body">
248
+ <div class="panel-title">
249
+ <h5>年度待交付项目</h5>
250
+ </div>
251
+ <div class="panel-content y-t-10">
252
+ <h1 class="no-margins" id="teachers_count_value">
253
+ <span><%= data_13 %></span>个</h1>
254
+ <div id="teachers_count_field" class="layui-hide">
255
+ <input type="text" name="teachers_count" autocomplete="off" class="layui-input" id="teachers_count">
256
+ </div>
257
+ </div>
258
+ </div>
259
+ </div>
260
+ </div>
261
+ <div class="layui-col-xs3">
262
+ <div class="panel layui-bg-number">
263
+ <div class="panel-body">
264
+ <div class="panel-title">
265
+ <h5>年度已交付项目</h5>
266
+ </div>
267
+ <div class="panel-content y-t-10">
268
+ <h1 class="no-margins" id="courses_count_value">
269
+ <span><%= data_14 %></span>个</h1>
270
+ <div id="courses_count_field" class="layui-hide">
271
+ <input type="text" name="courses_count" autocomplete="off" class="layui-input" id="courses_count">
272
+ </div>
273
+ </div>
274
+ </div>
275
+ </div>
276
+ </div>
277
+ <div class="layui-col-xs3">
278
+ <div class="panel layui-bg-number">
279
+ <div class="panel-body">
280
+ <div class="panel-title">
281
+ <h5>
282
+ 年度延期项目</h5>
283
+ </div>
284
+ <div class="panel-content y-t-10">
285
+ <h1 class="no-margins" id="top_teachers_count_value">
286
+ <span><%= data_15 %></span>个
287
+ </h1>
288
+ <div id="top_teachers_count_field" class="layui-hide">
289
+ <input type="text" name="top_teachers_count" autocomplete="off" class="layui-input"
290
+ id="top_teachers_count">
291
+ </div>
292
+ </div>
293
+ </div>
294
+ </div>
295
+ </div>
296
+
297
+ </div>
298
+ </div>
299
+ </div>
300
+ </div>
301
+ </div>
302
+ </form>
303
+ <br>
304
+ <br>
305
+
306
+
307
+ <form class="layui-form form-value layui-panel">
308
+ <div class="layui-form-item" style="padding: 10px 25px 0;">
309
+ <% staff_data.each_with_index do |d, i| %>
310
+ <div class="layui-inline">
311
+ <label class="layui-form-label">Top<%= i +1 %>:</label>
312
+ <div class="layui-input-inline">
313
+ <%= d[0] %>
314
+ </div>
315
+ </div>
316
+ <div class="layui-inline">
317
+ <label class="layui-form-label">完成率:</label>
318
+ <div class="layui-input-inline">
319
+ <%= d[2].present? ? (d[2].to_f / d[1].to_f * 100.0).round(2).to_s + "%" : 0 %>
320
+ </div>
321
+ </div>
322
+ <div class="layui-inline">
323
+ <label class="layui-form-label">总任务数:</label>
324
+ <div class="layui-input-inline">
325
+ <%= d[1] %>
326
+ </div>
327
+ </div>
328
+ <div class="layui-inline">
329
+ <label class="layui-form-label" style="width: 100px">完成任务数:</label>
330
+ <div class="layui-input-inline">
331
+ <%= d[2] %>
332
+ </div>
333
+ </div>
334
+ <br>
335
+ <% end %>
336
+ </div>
337
+ </form>
338
+ <br>
339
+ <br>
340
+
341
+ <div class="layui-panel">
342
+ <canvas id="myChart2_1" width="960" height="350"></canvas>
343
+ </div>
344
+ </div>
345
+ </div>
346
+ </div>
347
+ <script>
348
+ var goal_type = "<%=@goal_count_range %>";
349
+ layui.use(['form', 'jquery', 'request', 'element'], function () {
350
+ form = layui.form;
351
+
352
+ var opt = {
353
+ events: false,
354
+ tooltips: {
355
+ enabled: false
356
+ },
357
+ layout: {
358
+ padding: {
359
+ left: 50,
360
+ right: 50,
361
+ top: 0,
362
+ bottom: 0
363
+ }
364
+ },
365
+ hover: {
366
+ animationDuration: 0
367
+ },
368
+ animation: {
369
+ duration: 1,
370
+ onComplete: function () {
371
+ var chartInstance = this.chart, ctx = chartInstance.ctx;
372
+ ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
373
+ ctx.textAlign = 'center';
374
+ ctx.textBaseline = 'bottom';
375
+
376
+ this.data.datasets.forEach(function (dataset, i) {
377
+ ctx.fillStyle = "#444";
378
+ var meta = chartInstance.controller.getDatasetMeta(i);
379
+ meta.data.forEach(function (bar, index) {
380
+ var data = dataset.data[index];
381
+ ctx.fillText(data, bar._model.x, bar._model.y - 5);
382
+ });
383
+ });
384
+ }
385
+ }
386
+ };
387
+
388
+ var res_data = <%=raw @goal_count_data.to_json %>;
389
+ var datasets = [];
390
+ var color = ['#44D7B6', '#4CACFF', '#F7B500', '#FF0000', '#FF7F00'];
391
+ res_data.datasets.forEach(function (d, i) {
392
+ datasets.push({
393
+ label: d.label,
394
+ type: 'line',
395
+ data: d.data1,
396
+ borderColor: color[i],
397
+ pointRadius: 1,
398
+ fill: false,
399
+ lineTension: 0
400
+ })
401
+ })
402
+
403
+ laydate.render({
404
+ type: 'month',
405
+ min: '2023-04',
406
+ elem: '#goal_date_month',
407
+ });
408
+
409
+
410
+ var ctx = document.getElementById('myChart2');
411
+ var myChart2 = new Chart(ctx, {
412
+ type: 'bar',
413
+ data: <%=raw chart1.to_json %>,
414
+ options: opt
415
+ });
416
+ var ctx = document.getElementById('myChart2_1');
417
+ var myChart2_1 = new Chart(ctx, {
418
+ type: 'bar',
419
+ data: <%=raw chart2.to_json %>,
420
+ options: opt
421
+ });
422
+ form.render();
423
+ form.on("submit(search_sales)", function (data) {
424
+ var layer_index = layer.load(0, {shade: [0.1, '#fff']});
425
+ Rails.ajax({
426
+ url: '/missions/project_charts/sales_analysis',
427
+ type: 'GET',
428
+ data: $.param(data.field, true),
429
+ dataType: "script",
430
+ success: function (res) {
431
+ layer.close(layer_index);
432
+ }
433
+ });
434
+ })
435
+ })
436
+ </script>
@@ -0,0 +1 @@
1
+ $("#page_3").html("<%= j render 'sales_analysis' %>");
@@ -0,0 +1,81 @@
1
+ <div class="layui-tab" lay-filter="sale_trend_tab">
2
+ <ul class="layui-tab-title">
3
+ <li class="">统计分析</li>
4
+ </ul>
5
+ <div class="layui-tab-content">
6
+
7
+ <div class="layui-tab-item layui-show">
8
+ <div id="page_3"></div>
9
+ </div>
10
+ </div>
11
+ </div>
12
+
13
+
14
+ <script>
15
+ layui.use(['form', 'jquery', 'request', 'element'], function () {
16
+ var $ = layui.jquery,
17
+ form = layui.form,
18
+ request = layui.request;
19
+ var year = "<%= @year %>";
20
+ var element = layui.element;
21
+ laydate = layui.laydate;
22
+ element.render();
23
+ loadPage('/missions/project_charts/sales_analysis')
24
+ // element.on('tab(sale_trend_tab)', function (data) {
25
+ // loadPage('/missions/sale_trends/sales_analysis')
26
+ // });
27
+
28
+
29
+ function loadPage(url) {
30
+ var layer_index = layer.load(0, {shade: [0.1, '#fff']});
31
+ Rails.ajax({
32
+ url: url,
33
+ type: 'GET',
34
+ dataType: "script",
35
+ success: function (res) {
36
+ layer.close(layer_index);
37
+ }
38
+ });
39
+ }
40
+
41
+ function editForm(el) {
42
+ $("#" + el + "_edit").click(function () {
43
+ if ($("#" + el + "_field")[0].classList.contains("layui-hide")) {
44
+ $("#" + el + "_field").removeClass("layui-hide")
45
+ $("#" + el + "_value").addClass("layui-hide")
46
+ } else {
47
+ $("#" + el + "_field").addClass("layui-hide")
48
+ $("#" + el + "_value").removeClass("layui-hide")
49
+ }
50
+ })
51
+ $("#" + el).blur(function () {
52
+ if (this.value == '') {
53
+ layer.msg("不能为空")
54
+ } else {
55
+ var data = {};
56
+ data[el] = this.value;
57
+ var self = this;
58
+ data['year'] = year;
59
+ request.post( 'missions/sale_trends/sale_trends',
60
+ data,
61
+ function(res) {
62
+ $("#" + el + "_field").addClass("layui-hide");
63
+ $("#" + el + "_value").removeClass("layui-hide");
64
+ $("#" + el + "_value")[0].innerText = self.value + "万";
65
+ }
66
+ )
67
+ }
68
+ })
69
+ }
70
+
71
+ form.on('select(year)', function(data){
72
+ year = data.value
73
+ window.location.href = "/missions/sale_trends/trends?year=" + data.value
74
+ })
75
+
76
+ editForm("chance_money");
77
+ editForm("ballot_money");
78
+ editForm("sign_money");
79
+ editForm("returned_money");
80
+ })
81
+ </script>
@@ -0,0 +1,4 @@
1
+ json.data1 @follow_count_data
2
+ json.data2 @goal_count_data
3
+ json.data3 @business_data
4
+ json.data4 @customer_data
@@ -163,9 +163,9 @@
163
163
  <dd>
164
164
  <a href="/missions/projects" class="<%= current?('layui-this', projects_path) %>"><i style="padding-right: 35px"></i><%= image_tag "educode_sales/7.运营活动.png", size: "15" %>
165
165
  <i style="font-size: 25px; padding-right: 15px"></i>项目交付管理</a></dd>
166
- <!-- <dd>-->
167
- <!-- <a href="/missions/idea_recycles" class="<%#= current?('layui-this', idea_recycles_path) %>"><i style="padding-right: 35px"></i><%#= image_tag "educode_sales/回收站.png", size: "15" %>-->
168
- <!-- <i style="font-size: 25px; padding-right: 15px"></i>方案回收站</a></dd>-->
166
+ <dd>
167
+ <a href="/missions/project_charts/trends" class="<%= current?('layui-this', trends_project_charts_path) %>"><i style="padding-right: 35px"></i><%= image_tag "educode_sales/2.市场态势.png", size: "15" %>
168
+ <i style="font-size: 25px; padding-right: 15px"></i>统计分析</a></dd>
169
169
  </dl>
170
170
  </li>
171
171
  <% end %>
data/config/routes.rb CHANGED
@@ -276,6 +276,17 @@ EducodeSales::Engine.routes.draw do
276
276
  member do
277
277
  end
278
278
  end
279
+
280
+ resources :project_charts do
281
+ collection do
282
+ get :trends
283
+ post :sale_trends
284
+ get :business_followup_analysis
285
+ get :sales_analysis
286
+ get :business_area
287
+ get :sales_followup_analysis
288
+ end
289
+ end
279
290
  resources :ideas do
280
291
  collection do
281
292
  get :detail
@@ -1,3 +1,3 @@
1
1
  module EducodeSales
2
- VERSION = '0.9.72'
2
+ VERSION = '0.9.73'
3
3
  end
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: educode_sales
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.72
4
+ version: 0.9.73
5
5
  platform: ruby
6
6
  authors:
7
7
  - anke1460
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2023-04-28 00:00:00.000000000 Z
@@ -105,6 +105,7 @@ files:
105
105
  - app/assets/images/educode_sales/icon-login.png
106
106
  - app/assets/images/educode_sales/icon.png
107
107
  - app/assets/images/educode_sales/indexLogo.png
108
+ - app/assets/images/educode_sales/indexlogo.png
108
109
  - app/assets/images/educode_sales/loading-0.gif
109
110
  - app/assets/images/educode_sales/loading-1.gif
110
111
  - app/assets/images/educode_sales/loading-2.gif
@@ -163,6 +164,7 @@ files:
163
164
  - app/controllers/educode_sales/operations_controller.rb
164
165
  - app/controllers/educode_sales/places_controller.rb
165
166
  - app/controllers/educode_sales/plans_controller.rb
167
+ - app/controllers/educode_sales/project_charts_controller.rb
166
168
  - app/controllers/educode_sales/projects_controller.rb
167
169
  - app/controllers/educode_sales/recycles_controller.rb
168
170
  - app/controllers/educode_sales/results_controller.rb
@@ -444,6 +446,10 @@ files:
444
446
  - app/views/educode_sales/plans/show_week.html.erb
445
447
  - app/views/educode_sales/plans/show_weekly.html.erb
446
448
  - app/views/educode_sales/plans/years_plan.json.jbuilder
449
+ - app/views/educode_sales/project_charts/_sales_analysis.html.erb
450
+ - app/views/educode_sales/project_charts/sales_analysis.js.erb
451
+ - app/views/educode_sales/project_charts/trends.html.erb
452
+ - app/views/educode_sales/project_charts/trends.json.jbuilder
447
453
  - app/views/educode_sales/projects/detail.html.erb
448
454
  - app/views/educode_sales/projects/edit.html.erb
449
455
  - app/views/educode_sales/projects/history.html.erb
@@ -627,7 +633,7 @@ homepage: https://www.educoder.net
627
633
  licenses:
628
634
  - MIT
629
635
  metadata: {}
630
- post_install_message:
636
+ post_install_message:
631
637
  rdoc_options: []
632
638
  require_paths:
633
639
  - lib
@@ -642,8 +648,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
642
648
  - !ruby/object:Gem::Version
643
649
  version: '0'
644
650
  requirements: []
645
- rubygems_version: 3.0.0
646
- signing_key:
651
+ rubygems_version: 3.0.9
652
+ signing_key:
647
653
  specification_version: 4
648
654
  summary: Summary of EducodeSales.
649
655
  test_files: []