educode_sales 0.4.8 → 0.5.2

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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/educode_sales//345/233/236/346/224/266/347/253/231.png +0 -0
  3. data/app/controllers/educode_sales/businesses_controller.rb +84 -5
  4. data/app/controllers/educode_sales/follow_ups_controller.rb +4 -3
  5. data/app/controllers/educode_sales/home_controller.rb +1 -1
  6. data/app/controllers/educode_sales/operation_plans_controller.rb +34 -6
  7. data/app/controllers/educode_sales/operation_reports_controller.rb +33 -3
  8. data/app/controllers/educode_sales/operations_controller.rb +1 -1
  9. data/app/controllers/educode_sales/plans_controller.rb +43 -15
  10. data/app/controllers/educode_sales/recycles_controller.rb +95 -0
  11. data/app/controllers/educode_sales/roles_controller.rb +5 -0
  12. data/app/controllers/educode_sales/sale_reports_controller.rb +34 -4
  13. data/app/controllers/educode_sales/sale_trends_controller.rb +176 -5
  14. data/app/controllers/educode_sales/sales_controller.rb +6 -2
  15. data/app/controllers/educode_sales/staffs_controller.rb +4 -4
  16. data/app/controllers/educode_sales/upload_files_controller.rb +112 -0
  17. data/app/models/concerns/deletable.rb +8 -0
  18. data/app/models/educode_sales/application_record.rb +2 -0
  19. data/app/models/educode_sales/business.rb +15 -2
  20. data/app/models/educode_sales/common.rb +6 -1
  21. data/app/models/educode_sales/follow_up.rb +4 -2
  22. data/app/models/educode_sales/recycle.rb +5 -0
  23. data/app/models/educode_sales/sale_plan.rb +3 -0
  24. data/app/models/educode_sales/sale_report.rb +2 -0
  25. data/app/views/educode_sales/businesses/edit_follow_record.html.erb +15 -0
  26. data/app/views/educode_sales/businesses/edit_plan.html.erb +2 -2
  27. data/app/views/educode_sales/businesses/file.html.erb +155 -0
  28. data/app/views/educode_sales/businesses/index.html.erb +71 -4
  29. data/app/views/educode_sales/businesses/index.json.jbuilder +3 -1
  30. data/app/views/educode_sales/businesses/new_follow_record.html.erb +22 -1
  31. data/app/views/educode_sales/businesses/show_follow.html.erb +46 -9
  32. data/app/views/educode_sales/businesses/show_follow.json.jbuilder +3 -0
  33. data/app/views/educode_sales/businesses/show_follow_record.html.erb +80 -2
  34. data/app/views/educode_sales/businesses/time_line.html.erb +62 -0
  35. data/app/views/educode_sales/businesses/upload_file.html.erb +43 -0
  36. data/app/views/educode_sales/operation_plans/_monthly.html.erb +4 -4
  37. data/app/views/educode_sales/operation_plans/_weekly.html.erb +4 -4
  38. data/app/views/educode_sales/operation_plans/index.html.erb +6 -1
  39. data/app/views/educode_sales/operation_plans/new_month.html.erb +15 -1
  40. data/app/views/educode_sales/operation_plans/new_week.html.erb +20 -5
  41. data/app/views/educode_sales/operation_reports/audit.html.erb +23 -15
  42. data/app/views/educode_sales/operation_reports/edit.html.erb +9 -9
  43. data/app/views/educode_sales/operation_reports/show.html.erb +22 -19
  44. data/app/views/educode_sales/places/index.html.erb +6 -1
  45. data/app/views/educode_sales/places/index.json.jbuilder +11 -1
  46. data/app/views/educode_sales/plans/_monthly.html.erb +4 -4
  47. data/app/views/educode_sales/plans/_weekly.html.erb +4 -4
  48. data/app/views/educode_sales/plans/index.html.erb +6 -1
  49. data/app/views/educode_sales/plans/new_monthly.html.erb +6 -6
  50. data/app/views/educode_sales/plans/new_week.html.erb +1 -1
  51. data/app/views/educode_sales/plans/new_weekly.html.erb +7 -7
  52. data/app/views/educode_sales/recycles/_business.html.erb +122 -0
  53. data/app/views/educode_sales/recycles/_monthPlan.html.erb +123 -0
  54. data/app/views/educode_sales/recycles/_monthly.html.erb +121 -0
  55. data/app/views/educode_sales/recycles/_weekPlan.html.erb +128 -0
  56. data/app/views/educode_sales/recycles/_weekly.html.erb +122 -0
  57. data/app/views/educode_sales/recycles/business.json.jbuilder +16 -0
  58. data/app/views/educode_sales/recycles/index.html.erb +58 -0
  59. data/app/views/educode_sales/recycles/monthPlan.json.jbuilder +16 -0
  60. data/app/views/educode_sales/recycles/monthly.json.jbuilder +15 -0
  61. data/app/views/educode_sales/recycles/weekPlan.json.jbuilder +16 -0
  62. data/app/views/educode_sales/recycles/weekly.json.jbuilder +15 -0
  63. data/app/views/educode_sales/roles/index.html.erb +19 -1
  64. data/app/views/educode_sales/roles/rename.html.erb +50 -0
  65. data/app/views/educode_sales/sale_reports/audit.html.erb +24 -13
  66. data/app/views/educode_sales/sale_reports/edit.html.erb +7 -7
  67. data/app/views/educode_sales/sale_reports/show.html.erb +13 -10
  68. data/app/views/educode_sales/sale_trends/trends.html.erb +228 -8
  69. data/app/views/educode_sales/sale_trends/trends.json.jbuilder +14 -0
  70. data/app/views/educode_sales/sales/index.html.erb +72 -6
  71. data/app/views/educode_sales/sales/index.json.jbuilder +35 -1
  72. data/app/views/educode_sales/sales/operations.json.jbuilder +11 -1
  73. data/app/views/educode_sales/staffs/index.html.erb +6 -1
  74. data/app/views/educode_sales/staffs/index.json.jbuilder +11 -1
  75. data/app/views/educode_sales/teachers/add_keys.html.erb +3 -3
  76. data/app/views/educode_sales/teachers/index.html.erb +7 -2
  77. data/app/views/educode_sales/teachers/new.html.erb +1 -0
  78. data/app/views/educode_sales/upload_files/index.json.jbuilder +13 -0
  79. data/app/views/layouts/educode_sales/application.html.erb +3 -0
  80. data/config/routes.rb +30 -0
  81. data/db/migrate/20210902064109_create_educode_sales_role_permissions.rb +6 -0
  82. data/db/migrate/20211102085743_add_bidded_date_educode_sales_follow_ups.rb +6 -0
  83. data/db/migrate/20211109015617_create_educode_sales_recycles.rb +25 -0
  84. data/lib/educode_sales/version.rb +1 -1
  85. metadata +26 -2
@@ -7,7 +7,7 @@ module EducodeSales
7
7
  def trends
8
8
  # authorize! :trends, EducodeSales::SaleTrend
9
9
  @year = params[:year] ? params[:year] : Time.now.year
10
- @years = (1..(Time.now.year - 2014)).map { |d| 2014 + d }
10
+ @years = (1..(Time.now.year - 2014)).reverse_each.map { |d| 2014 + d }
11
11
  year_time = "#{@year}-01-01 00:00:00"
12
12
  year_over_time = "#{@year}-12-31 23:59:59"
13
13
  x = Common.find_by(extras: EducodeSales::Common::XTYPE)&.id
@@ -15,14 +15,132 @@ module EducodeSales
15
15
  @sale_trend = SaleTrend.find_or_create_by(year: @year)
16
16
  @business_amount = Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ? AND educode_sales_follow_ups.clazz_id != ?", x, o).sum(:total_amount).round(2)
17
17
  stage_ids = Common.where(clazz: '商机阶段', name: ['已中标','已签单','已验收','回款中', '服务中','已结束']).pluck(:id)
18
- @goal_amount = Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.created_at >= ? AND educode_sales_follow_ups.created_at <= ? AND educode_sales_follow_ups.stage_id IN (?)", year_time, year_over_time, stage_ids).sum(:total_amount).round(2)
18
+ @goal_amount = Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.bidded_date >= ? AND educode_sales_follow_ups.bidded_date <= ? AND educode_sales_follow_ups.stage_id IN (?)", "#{@year}-01-01", "#{@year}-12-31", stage_ids).sum(:total_amount).round(2)
19
19
  s_stage_ids = Common.where(clazz: '商机阶段', name: ['已签单','已验收','回款中', '服务中','已结束']).pluck(:id)
20
- @service_amount = Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.created_at >= ? AND educode_sales_follow_ups.created_at <= ? AND educode_sales_follow_ups.stage_id IN (?)", year_time, year_over_time, s_stage_ids).sum(:total_amount).round(2)
20
+ @service_amount = Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.signed_date >= ? AND educode_sales_follow_ups.signed_date <= ? AND educode_sales_follow_ups.stage_id IN (?)", "#{@year}-01-01", "#{@year}-12-31", s_stage_ids).sum(:total_amount).round(2)
21
21
  @return_amount = Business.joins(last_follow_up: :money_plans).where("educode_sales_follow_ups.clazz_id != ?", x).where.not("educode_sales_money_plans.clazz!= ?", 1).where("educode_sales_money_plans.date_at >= ? AND educode_sales_money_plans.date_at <= ? ", year_time, year_over_time).sum(:amount).round(2)
22
- a = Common.where(clazz: '商机类型', name: 'A类-有预算主推').pluck(:id)
22
+ a = Common.where(clazz: '商机类型', name: Common.find_by(extras: EducodeSales::Common::ATYPE)&.name).pluck(:id)
23
23
  @a_amount = Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id IN (?)", a).sum(:total_amount).round(2)
24
- b = Common.where(clazz: '商机类型', name: 'B类-有预算不主推').pluck(:id)
24
+ b = Common.where(clazz: '商机类型', name: Common.find_by(extras: EducodeSales::Common::BTYPE)&.name).pluck(:id)
25
25
  @b_amount = Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id IN (?)", b).sum(:total_amount).round(2)
26
+
27
+ common = Common.find_by(clazz: 'staff_type', name: '销售')
28
+ names = Staff.includes(:user).where(job_type: common.id).map { |d| [d.user.real_name, d.id] }
29
+ x_business_ids = []
30
+ default_dates = (7.day.ago.to_date..Date.today).to_a #默认时间范围
31
+ Business.all.each do |d|
32
+ if d.last_follow_up&.clazz&.id == x
33
+ x_business_ids << d.id
34
+ end
35
+ end
36
+ colors = ['#FF0000', '#FF7F00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#8B00FF', 'rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)']
37
+ @follow_count_range = params[:follow_count_range] || "day"
38
+ @goal_count_range = params[:goal_count_range] || "day"
39
+ # 商机跟进数图表
40
+ @follow_count_data = day_follow_count_chart(default_dates,names,x_business_ids,colors)
41
+ if params[:follow_count_range].present?
42
+ case params[:follow_count_range]
43
+ when "week"
44
+ when "month" #按月
45
+ if params[:date_month].present?
46
+ # (Date.new(2020,12,1)..Date.new(2021,12,1)).map { |d| d.strftime("%Y-%m")}.uniq
47
+ date = params[:date_month].split(" - ")
48
+ dates = ((date[0]+"-01").to_date..(date[1]+"-01").to_date).map { |d| d.strftime("%Y-%m")}.uniq
49
+ @follow_count_data = month_follow_count_chart(dates,names,x_business_ids,colors)
50
+ end
51
+ when "year" #按年
52
+ if params[:date_year].present?
53
+ date = params[:date_year].split(" - ")
54
+ dates = (date[0]..date[1]).to_a
55
+ @follow_count_data = year_follow_count_chart(dates,names,x_business_ids,colors)
56
+ end
57
+ else #按天
58
+ if params[:date].present?
59
+ date = params[:date].split(" - ")
60
+ dates = (date[0].to_date..date[1].to_date).to_a
61
+ @follow_count_data = day_follow_count_chart(dates,names,x_business_ids,colors)
62
+ end
63
+ end
64
+ end
65
+
66
+
67
+ # 已中标图表
68
+ goal_default_dates = ("#{Time.now.year}-01".."#{Time.now.year}-#{Time.now.month}").to_a
69
+ sale_names = ['已中标','已签单','已回款']
70
+ @goal_count_data =
71
+ {
72
+ labels: goal_default_dates,
73
+ datasets: sale_names.map do |name|{
74
+ label: name,
75
+ data: goal_default_dates.map{ |d|
76
+ case sale_names.index(name)
77
+ when 0
78
+ Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.bidded_date >= ? AND educode_sales_follow_ups.bidded_date <= ? AND educode_sales_follow_ups.stage_id IN (?)", "#{d}-01", "#{d}-31", stage_ids).sum(:total_amount).round(2)
79
+ when 1
80
+ Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.signed_date >= ? AND educode_sales_follow_ups.signed_date <= ? AND educode_sales_follow_ups.stage_id IN (?)", "#{d}-01", "#{d}-31", s_stage_ids).sum(:total_amount).round(2)
81
+ else
82
+ Business.joins(last_follow_up: :money_plans).where("educode_sales_follow_ups.clazz_id != ?", x).where.not("educode_sales_money_plans.clazz!= ?", 1).where("educode_sales_money_plans.date_at >= ? AND educode_sales_money_plans.date_at <= ? ", "#{d}-01", "#{d}-31").sum(:amount).round(2)
83
+ end
84
+ },
85
+ backgroundColor: colors[sale_names.index(name)+1],
86
+ borderColor: colors[sale_names.index(name)+1],
87
+ borderWidth: 1
88
+ }
89
+ end
90
+ }
91
+ if params[:goal_count_range].present?
92
+ case params[:goal_count_range]
93
+ when "week"
94
+ when "month" #按月
95
+ if params[:goal_date_month].present?
96
+ date = params[:goal_date_month].split(" - ")
97
+ dates = ((date[0]+"-01").to_date..(date[1]+"-01").to_date).map { |d| d.strftime("%Y-%m")}.uniq
98
+ @goal_count_data = {
99
+ labels: dates,
100
+ datasets: sale_names.map do |name|{
101
+ label: name,
102
+ data: dates.map{ |d|
103
+ case sale_names.index(name)
104
+ when 0
105
+ Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.bidded_date >= ? AND educode_sales_follow_ups.bidded_date <= ? AND educode_sales_follow_ups.stage_id IN (?)", "#{d}-01", "#{d}-31", stage_ids).sum(:total_amount).round(2)
106
+ when 1
107
+ Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.signed_date >= ? AND educode_sales_follow_ups.signed_date <= ? AND educode_sales_follow_ups.stage_id IN (?)", "#{d}-01", "#{d}-31", s_stage_ids).sum(:total_amount).round(2)
108
+ else
109
+ Business.joins(last_follow_up: :money_plans).where("educode_sales_follow_ups.clazz_id != ?", x).where.not("educode_sales_money_plans.clazz!= ?", 1).where("educode_sales_money_plans.date_at >= ? AND educode_sales_money_plans.date_at <= ? ", "#{d}-01", "#{d}-31").sum(:amount).round(2)
110
+ end },
111
+ backgroundColor: colors[sale_names.index(name)+1],
112
+ borderColor: colors[sale_names.index(name)+1],
113
+ borderWidth: 1
114
+ }
115
+ end
116
+ }
117
+ end
118
+ else #按年
119
+ if params[:goal_date_year].present?
120
+ date = params[:goal_date_year].split(" - ")
121
+ dates = (date[0]..date[1]).to_a
122
+ @goal_count_data = {
123
+ labels: dates,
124
+ datasets:sale_names.map do |name| {
125
+ label: name,
126
+ data: dates.map{ |d|
127
+ case sale_names.index(name)
128
+ when 0
129
+ Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.bidded_date >= ? AND educode_sales_follow_ups.bidded_date <= ? AND educode_sales_follow_ups.stage_id IN (?)", "#{d}-01-01", "#{d}-12-31", stage_ids).sum(:total_amount).round(2)
130
+ when 1
131
+ Business.joins(:last_follow_up).where("educode_sales_follow_ups.clazz_id != ?", x).where("educode_sales_follow_ups.signed_date >= ? AND educode_sales_follow_ups.signed_date <= ? AND educode_sales_follow_ups.stage_id IN (?)", "#{d}-01-01", "#{d}-12-31", s_stage_ids).sum(:total_amount).round(2)
132
+ else
133
+ Business.joins(last_follow_up: :money_plans).where("educode_sales_follow_ups.clazz_id != ?", x).where.not("educode_sales_money_plans.clazz!= ?", 1).where("educode_sales_money_plans.date_at >= ? AND educode_sales_money_plans.date_at <= ? ", "#{d}-01-01", "#{d}-12-31").sum(:amount).round(2)
134
+ end },
135
+ backgroundColor: colors[sale_names.index(name)+1],
136
+ borderColor: colors[sale_names.index(name)+1],
137
+ borderWidth: 1
138
+ }
139
+ end
140
+ }
141
+ end
142
+ end
143
+ end
26
144
  end
27
145
 
28
146
  def sale_trends
@@ -44,5 +162,58 @@ module EducodeSales
44
162
  params.permit(:chance_money, :ballot_money, :sign_money, :returned_money)
45
163
  end
46
164
 
165
+ def day_follow_count_chart(dates,names,x_business_ids,colors)
166
+ {
167
+ labels: dates,
168
+ datasets:names.map do |name|
169
+ {
170
+ hidden: names.index(name) < 3 ? false : true,
171
+ label: name[0],
172
+ data: dates.map{ |d| @follow_up = FollowUp.where(staff_id: name[1], created_at: d.beginning_of_day..d.end_of_day).where.not(business: x_business_ids).count },
173
+ backgroundColor: "#fff",
174
+ pointBorderColor: "#fff",
175
+ borderColor: colors[names.index(name)%10],
176
+ pointBackgroundColor: colors[names.index(name)%10],
177
+ borderWidth: 1
178
+ }
179
+ end
180
+ }
181
+ end
182
+ def month_follow_count_chart(dates,names,x_business_ids,colors)
183
+ {
184
+ labels: dates,
185
+ datasets:names.map do |name|
186
+ {
187
+ hidden: names.index(name) < 3 ? false : true,
188
+ label: name[0],
189
+ data: dates.map { |d| @follow_up = FollowUp.where( staff_id: name[1]).where("created_at >= ? AND created_at <= ?", "#{d}-01", "#{d}-31").where.not(business: x_business_ids).count },
190
+ backgroundColor: "#fff",
191
+ pointBorderColor: "#fff",
192
+ borderColor: colors[names.index(name)%10],
193
+ pointBackgroundColor: colors[names.index(name)%10],
194
+ borderWidth: 1
195
+ }
196
+ end
197
+ }
198
+ end
199
+ def year_follow_count_chart(dates,names,x_business_ids,colors)
200
+ {
201
+ labels: dates,
202
+ datasets:names.map do |name|
203
+ {
204
+ hidden: names.index(name) < 3 ? false : true,
205
+ label: name[0],
206
+ data: dates.map { |d| @follow_up = FollowUp.where( staff_id: name[1]).where("created_at >= ? AND created_at <= ?", "#{d}-01-01", "#{d}-12-31").where.not(business: x_business_ids).count },
207
+ backgroundColor: "#fff",
208
+ pointBorderColor: "#fff",
209
+ borderColor: colors[names.index(name)%10],
210
+ pointBackgroundColor: colors[names.index(name)%10],
211
+ borderWidth: 1
212
+ }
213
+ end
214
+ }
215
+ end
216
+
217
+
47
218
  end
48
219
  end
@@ -12,8 +12,12 @@ module EducodeSales
12
12
  end
13
13
  format.json do
14
14
  common = Common.find_by(clazz: 'staff_type', name: '销售')
15
- @a_clazz = Common.find_by(clazz: 'business_type', name: 'A类-有预算主推')
16
- @b_clazz = Common.find_by(clazz: 'business_type', name: 'B类-有预算不主推')
15
+ @a_clazz = Common.find_by(clazz: 'business_type', name: Common.find_by(extras: EducodeSales::Common::ATYPE)&.name)
16
+ @b_clazz = Common.find_by(clazz: 'business_type', name: Common.find_by(extras: EducodeSales::Common::BTYPE)&.name)
17
+ @c_clazz = Common.find_by(clazz: 'business_type', name: Common.find_by(extras: EducodeSales::Common::CTYPE)&.name)
18
+ @d_clazz = Common.find_by(clazz: 'business_type', name: Common.find_by(extras: EducodeSales::Common::DTYPE)&.name)
19
+ @e_clazz = Common.find_by(clazz: 'business_type', name: Common.find_by(extras: EducodeSales::Common::ETYPE)&.name)
20
+ @o_clazz = Common.find_by(clazz: 'business_type', name: Common.find_by(extras: EducodeSales::Common::OTYPE)&.name)
17
21
  @x = Common.find_by(extras: EducodeSales::Common::XTYPE)
18
22
  @step_ids = Common.where(name: %w(已中标 已签单 已验收 回款中 服务中 已结束), clazz: 'business_step').pluck(:id)
19
23
 
@@ -8,7 +8,7 @@ module EducodeSales
8
8
  format.html do
9
9
  end
10
10
  format.json do
11
- @staffs = Staff.where(is_admin: false).page(params[:page]).per(params[:limit])
11
+ @staffs = Staff.where(is_admin: false, deleted_at: nil).page(params[:page]).per(params[:limit])
12
12
  end
13
13
  end
14
14
  end
@@ -37,10 +37,10 @@ module EducodeSales
37
37
 
38
38
  def destroy
39
39
  staff = Staff.find(params[:id])
40
- staff.destroy
40
+ staff.update(deleted_at: Time.now, expired_at: Time.now.days_ago(1))
41
41
  render_success
42
- rescue ActiveRecord::DeleteRestrictionError => e
43
- render_failure '该用户已有数据产生,暂不能删除'
42
+ # rescue ActiveRecord::DeleteRestrictionError => e
43
+ # render_failure '该用户已有数据产生,暂不能删除'
44
44
  end
45
45
 
46
46
  def disable
@@ -0,0 +1,112 @@
1
+ require_dependency "educode_sales/application_controller"
2
+
3
+ module EducodeSales
4
+ class UploadFilesController < ApplicationController
5
+
6
+ def index
7
+ respond_to do |format|
8
+ format.html do
9
+ end
10
+ format.json do
11
+ @files = Attachment.where(description: "business", container_id:params[:business_id])
12
+ if params[:sort].present? && params[:sort][:field]
13
+ @files = @files.order("#{params[:sort][:field]} #{params[:sort][:order]}")
14
+ else
15
+ @files = @files.order("created_on desc")
16
+ end
17
+ @files = @files.page(params[:page]).per(params[:limit])
18
+ end
19
+ end
20
+ end
21
+
22
+ def create
23
+ folder = edu_setting('attachment_folder')
24
+ upload_file = params["file"]
25
+ raise "未上传文件" unless upload_file
26
+ save_path = File.join(folder)
27
+ ext = file_ext(upload_file.original_filename)
28
+ local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext)
29
+ content_type = upload_file.content_type.presence || 'application/octet-stream'
30
+ disk_filename = local_path[save_path.size + 1, local_path.size]
31
+ @attachment = Attachment.where(disk_filename: disk_filename,
32
+ author_id: @current_admin.id).first
33
+ if @attachment.blank?
34
+ @attachment = Attachment.new
35
+ @attachment.filename = upload_file.original_filename
36
+ @attachment.description = "business"
37
+ @attachment.disk_filename = local_path[save_path.size + 1, local_path.size]
38
+ @attachment.filesize = upload_file.tempfile.size
39
+ @attachment.content_type = content_type
40
+ @attachment.digest = digest
41
+ @attachment.author_id = @current_admin.id
42
+ @attachment.container_id = params[:business_id]
43
+ @attachment.save!
44
+ else
45
+ logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}"
46
+ end
47
+ render_success
48
+ end
49
+
50
+ def destroy
51
+ folder = edu_setting('attachment_folder')
52
+ file = Attachment.find(params[:id])
53
+ file.destroy
54
+ File.delete(folder.to_s + '/' + file.disk_filename) if FileTest::exist?(folder.to_s + '/' + file.disk_filename)
55
+ render_success
56
+ end
57
+
58
+ def download
59
+ folder = edu_setting('attachment_folder')
60
+ file = Attachment.find_by_id(params[:id])
61
+ raise "未找到文件" unless file
62
+ send_file(folder.to_s + '/' + file.disk_filename, filename: file.title, stream: true, type: file.content_type.presence || 'application/octet-stream')
63
+ end
64
+
65
+ def edu_setting name
66
+ EduSetting.get(name)
67
+ end
68
+
69
+
70
+ def file_ext(file_name)
71
+ ext = ''
72
+ exts = file_name.split(".")
73
+ if exts.size > 1
74
+ ext = ".#{exts.last}"
75
+ end
76
+ ext
77
+ end
78
+
79
+ def file_save_to_local(save_path, temp_file, ext)
80
+ unless Dir.exists?(save_path)
81
+ FileUtils.mkdir_p(save_path) ##不成功这里会抛异常
82
+ end
83
+
84
+ digest = md5_file(temp_file)
85
+ digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}"
86
+ local_file_path = File.join(save_path, digest) + ext
87
+ save_temp_file(temp_file, local_file_path)
88
+
89
+ [local_file_path, digest]
90
+ end
91
+
92
+
93
+ def md5_file(temp_file)
94
+ md5 = Digest::MD5.new
95
+ temp_file.rewind
96
+ while (buffer = temp_file.read(8192))
97
+ md5.update(buffer)
98
+ end
99
+ md5.hexdigest
100
+ end
101
+
102
+ def save_temp_file(temp_file, save_file_path)
103
+ File.open(save_file_path, 'wb') do |f|
104
+ temp_file.rewind
105
+ while (buffer = temp_file.read(8192))
106
+ f.write(buffer)
107
+ end
108
+ end
109
+ end
110
+
111
+ end
112
+ end
@@ -0,0 +1,8 @@
1
+ module Deletable
2
+ extend ActiveSupport::Concern
3
+
4
+ def soft_destroy(user_id)
5
+ self.update(deleted_at: Time.now)
6
+ EducodeSales::Recycle.create(source: self, deleter_id: user_id)
7
+ end
8
+ end
@@ -1,5 +1,7 @@
1
1
  module EducodeSales
2
2
  class ApplicationRecord < ActiveRecord::Base
3
3
  self.abstract_class = true
4
+
5
+
4
6
  end
5
7
  end
@@ -1,10 +1,23 @@
1
1
  module EducodeSales
2
2
  class Business < ApplicationRecord
3
+
3
4
  belongs_to :staff
4
5
  belongs_to :department
5
6
  belongs_to :last_follow_up, class_name: 'FollowUp', optional: true
6
7
 
7
- has_many :sale_plans, dependent: :destroy
8
- has_many :follow_ups, dependent: :destroy
8
+ has_many :sale_plans
9
+ has_many :follow_ups
10
+
11
+ default_scope -> {where(deleted_at: nil)}
12
+
13
+ def soft_destroy(user_id)
14
+ self.update(deleted_at: Time.now)
15
+ self.sale_plans.each do |d|
16
+ d.soft_destroy(user_id)
17
+ end
18
+ self.follow_ups.update_all(deleted_at: Time.now)
19
+ EducodeSales::Recycle.create(source: self, deleter_id: user_id)
20
+ end
21
+
9
22
  end
10
23
  end
@@ -4,6 +4,11 @@ module EducodeSales
4
4
 
5
5
  XTYPE = "x_class"
6
6
  OTYPE = 'o_class'
7
+ ATYPE = 'a_class'
8
+ BTYPE = 'b_class'
9
+ CTYPE = 'c_class'
10
+ DTYPE = 'd_class'
11
+ ETYPE = 'e_class'
7
12
 
8
13
  validates :name, uniqueness: {scope: :clazz, message: '已存在'}
9
14
 
@@ -21,7 +26,7 @@ module EducodeSales
21
26
  }
22
27
 
23
28
  def self.job_type_name
24
- self.where(clazz: 'staff_type', name: ['销售', '运营']).pluck(:id, :name).to_h
29
+ self.where(clazz: 'staff_type').pluck(:id, :name).to_h
25
30
  end
26
31
 
27
32
  def self.teacher_source_name
@@ -1,14 +1,16 @@
1
1
  module EducodeSales
2
2
  class FollowUp < ApplicationRecord
3
+ include ::Deletable
3
4
  belongs_to :business, counter_cache: true
4
5
  belongs_to :place, optional: true
5
- has_many :money_plans, dependent: :destroy
6
+ has_many :money_plans
6
7
  has_many :key_person
7
8
  has_many :teachers, through: :key_person
8
- has_many :assign_follow_ups, dependent: :destroy
9
+ has_many :assign_follow_ups
9
10
  belongs_to :staff
10
11
  belongs_to :stage, class_name: 'Common'
11
12
  belongs_to :clazz, class_name: 'Common'
13
+ default_scope -> {where(deleted_at: nil)}
12
14
 
13
15
 
14
16
  end
@@ -0,0 +1,5 @@
1
+ module EducodeSales
2
+ class Recycle < ApplicationRecord
3
+ belongs_to :source, polymorphic: true
4
+ end
5
+ end
@@ -1,9 +1,12 @@
1
1
  module EducodeSales
2
2
  class SalePlan < ApplicationRecord
3
+ include ::Deletable
3
4
  belongs_to :business
4
5
  belongs_to :staff
5
6
  validates :business_id, presence: true
6
7
 
7
8
  validates :month, presence: true
9
+
10
+ default_scope -> {where(deleted_at: nil)}
8
11
  end
9
12
  end
@@ -1,5 +1,7 @@
1
1
  module EducodeSales
2
2
  class SaleReport < ApplicationRecord
3
+ include ::Deletable
3
4
  belongs_to :staff
5
+ default_scope -> {where(deleted_at: nil)}
4
6
  end
5
7
  end
@@ -41,6 +41,21 @@
41
41
  id="invitation_at_edit" placeholder="请选择日期">
42
42
  </div>
43
43
  </div>
44
+ <div class="layui-inline">
45
+ <label class="layui-form-label">中标时间</label>
46
+ <div class="layui-input-inline">
47
+ <input type="text" class="layui-input" value="<%= @follow_up.bidded_date %>" name="bidded_date"
48
+ id="invitation_at_edit" placeholder="请选择日期">
49
+ </div>
50
+ </div>
51
+ <br>
52
+ <div class="layui-inline">
53
+ <label class="layui-form-label">签单时间</label>
54
+ <div class="layui-input-inline">
55
+ <input type="text" class="layui-input" value="<%= @follow_up.signed_date %>" name="signed_date"
56
+ id="invitation_at_edit" placeholder="请选择日期">
57
+ </div>
58
+ </div>
44
59
  <div class="layui-inline">
45
60
  <label class="layui-form-label">验收时间</label>
46
61
  <div class="layui-input-inline">
@@ -56,13 +56,13 @@
56
56
  </div>
57
57
  </script>
58
58
  <script type="text/html" id="return_money_tabar">
59
- {{# if(parent.is_latest){ }}
59
+ {{# if(parent.is_latest && parent.flag){ }}
60
60
  <a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="edit">保存</a>
61
61
  <a class="layui-btn layui-btn-danger layui-btn-xs data-count-edit" lay-event="delete">删除</a>
62
62
  {{# } }}
63
63
  </script>
64
64
  <script>
65
- if(!parent.is_latest){
65
+ if(!parent.is_latest || !parent.flag){
66
66
  document.getElementById("show_plan_box").style.display="none";//隐藏
67
67
  }
68
68
  layui.use(['form', 'table', 'upload', 'laytpl', 'request', 'laydate'], function () {
@@ -0,0 +1,155 @@
1
+ <%= Gon::Base.render_data %>
2
+ <script type="text/html" id="toolbarDemo">
3
+ <div class="layui-btn-container">
4
+ <span class="table-label">附件信息</span>
5
+ <%# if can? :create, EducodeSales::file %>
6
+ <button class="layui-btn layui-btn-normal layui-btn-sm data-add-btn pull-right" lay-event="upload_file">上传文件</button>
7
+ <%# end %>
8
+ </div>
9
+ </script>
10
+
11
+ <table class="layui-hide" id="file" lay-filter="file"></table>
12
+
13
+ <script type="text/html" id="currentTableBar_file">
14
+ <a class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="preview">预览</a>
15
+ <a href="/missions/upload_files/download?id={{d.id}}" class="layui-btn layui-btn-normal layui-btn-xs data-count-edit" lay-event="download">下载</a>
16
+ <a class="layui-btn layui-btn-xs layui-btn-danger data-count-delete" lay-event="delete">删除</a>
17
+ </script>
18
+
19
+ <script type="text/html" id="showchance">
20
+ <a href="/missions/businesses" class="layui-table-link">{{ d.chance }}</a>
21
+ </script>
22
+
23
+ <script>
24
+ layui.use(['form', 'table', 'miniPage', 'element', 'request'], function () {
25
+ var $ = layui.jquery,
26
+ form = layui.form,
27
+ table = layui.table,
28
+ request = layui.request,
29
+ upload = layui.upload;
30
+ miniPage = layui.miniPage;
31
+
32
+
33
+ var business_id = parent.id
34
+ table.render({
35
+ elem: '#file',
36
+ url: '/missions/upload_files?business_id='+business_id,
37
+ toolbar: '#toolbarDemo',
38
+ defaultToolbar: [],
39
+ cols: [
40
+ [
41
+ {
42
+ field: 'id',
43
+ width: 80,
44
+ title:'序号',type: 'numbers',
45
+ },
46
+ {
47
+ field: 'name',
48
+ title: '文件名'
49
+ },
50
+ {
51
+ field: 'size',
52
+ width: 100,
53
+ title: '文件大小',
54
+ },
55
+ {
56
+ field: 'created_on',
57
+ width: 200,
58
+ title: '上传时间',
59
+ sort: true
60
+ },
61
+ {
62
+ field: 'upload_person',
63
+ width: 80,
64
+ totalRow:true,
65
+ title: '上传人',
66
+ },
67
+ {
68
+ title: '操作',
69
+ width: 200,
70
+ toolbar: '#currentTableBar_file',
71
+ align: "center"
72
+ }
73
+ ]
74
+ ],
75
+ limit: 20,
76
+ limits: [10,15,20,30,40,50,60,70,80,90],
77
+ page: true
78
+ });
79
+
80
+
81
+ var sort = {};
82
+ table.on('sort(file)', function (obj) {
83
+ sort.field = obj.field;
84
+ sort.order = obj.type;
85
+ table.reload('file', {
86
+ initSort: obj,
87
+ where: {
88
+ sort: sort
89
+ }
90
+ });
91
+ })
92
+
93
+
94
+ table.on('toolbar(file)', function (obj) {
95
+ if (obj.event === 'upload_file') { //
96
+ id =parent.id
97
+ var content = miniPage.getHrefContent('/missions/businesses/upload_file');
98
+ var openWH = miniPage.getOpenWidthHeight();
99
+ import_index = layer.open({
100
+ title: '上传文件',
101
+ type: 1,
102
+ shade: 0.2,
103
+ shadeClose: true,
104
+ area: ['200px', '100px'],
105
+ offset: 'auto',
106
+ closeBtn: 0,
107
+ content: content,
108
+ });
109
+ $(window).on("resize", function () {
110
+ layer.full(index);
111
+ });
112
+ }
113
+ });
114
+
115
+
116
+ table.on('tool(file)', function (obj) {
117
+ var data = obj.data;
118
+ var id = data.id
119
+ name = data.disk_filename
120
+ folder = gon.folder
121
+ console.log(folder);
122
+ if (obj.event === 'preview') {
123
+ if (data.content_type.split("/")[0] === "image"){
124
+ layer.photos({
125
+ photos: { "data": [{"src": '/business_file/' + name}] }
126
+ ,anim: 5 //0-6的选择,指定弹出图片动画类型,默认随机
127
+ });
128
+ }else if (data.content_type.split("/")[1] === "pdf"){
129
+ var pdf = '/business_file/' + name;
130
+ console.log(pdf);
131
+ var openWH = miniPage.getOpenWidthHeight();
132
+ layer.open({
133
+ title: data.name,
134
+ type: 2,
135
+ area: ['1000px', '750px'],
136
+ fixed: false, //不固定
137
+ maxmin: true,
138
+ content: pdf
139
+ });
140
+ }else{
141
+ layer.msg("附件不支持预览,请下载查看!")
142
+ }
143
+ return false;
144
+ }else if (obj.event === 'delete') {
145
+ layer.confirm('确定删除' + data.name, function (index) {
146
+ request.delete('missions/upload_files/' + data.id + '?disk_filename=' + data.disk_filename, {}, function (res) {
147
+ layer.close(index);
148
+ table.reload("file")
149
+ })
150
+ });
151
+ }
152
+ });
153
+
154
+ });
155
+ </script>