educode_sales 0.9.66 → 0.9.68

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/educode_sales/activities_controller.rb +122 -40
  3. data/app/controllers/educode_sales/businesses_controller.rb +83 -2
  4. data/app/controllers/educode_sales/operation_plans_controller.rb +8 -4
  5. data/app/controllers/educode_sales/plans_controller.rb +173 -11
  6. data/app/controllers/educode_sales/recycles_controller.rb +11 -1
  7. data/app/controllers/educode_sales/teachers_controller.rb +4 -4
  8. data/app/controllers/educode_sales/upload_files_controller.rb +9 -2
  9. data/app/models/educode_sales/activity.rb +21 -4
  10. data/app/models/educode_sales/activity_follow_up.rb +13 -0
  11. data/app/models/educode_sales/activity_staff.rb +1 -1
  12. data/app/models/educode_sales/assessments_setting.rb +2 -2
  13. data/app/models/educode_sales/business.rb +3 -0
  14. data/app/models/educode_sales/business_info.rb +9 -0
  15. data/app/models/educode_sales/business_level.rb +11 -0
  16. data/app/models/educode_sales/business_watch.rb +6 -0
  17. data/app/models/educode_sales/sale_plan.rb +3 -1
  18. data/app/models/educode_sales/staff.rb +2 -0
  19. data/app/views/educode_sales/activities/_follows.html.erb +222 -0
  20. data/app/views/educode_sales/activities/_index.html.erb +491 -0
  21. data/app/views/educode_sales/activities/edit.html.erb +109 -53
  22. data/app/views/educode_sales/activities/files.html.erb +157 -0
  23. data/app/views/educode_sales/activities/files.json.jbuilder +13 -0
  24. data/app/views/educode_sales/activities/follow_ups.json.jbuilder +19 -0
  25. data/app/views/educode_sales/activities/index.html.erb +13 -349
  26. data/app/views/educode_sales/activities/index.json.jbuilder +11 -3
  27. data/app/views/educode_sales/activities/new.html.erb +87 -46
  28. data/app/views/educode_sales/activities/new_follow_up.html.erb +56 -0
  29. data/app/views/educode_sales/activities/upload_file.html.erb +43 -0
  30. data/app/views/educode_sales/businesses/edit.html.erb +48 -6
  31. data/app/views/educode_sales/businesses/get_export_data.json.jbuilder +3 -0
  32. data/app/views/educode_sales/businesses/index.html.erb +10 -0
  33. data/app/views/educode_sales/businesses/new.html.erb +1 -1
  34. data/app/views/educode_sales/businesses/no_permission.html.erb +2 -0
  35. data/app/views/educode_sales/plans/_yearPlan.html.erb +234 -0
  36. data/app/views/educode_sales/plans/business_infos.json.jbuilder +23 -0
  37. data/app/views/educode_sales/plans/edit_bussiness_info.html.erb +79 -0
  38. data/app/views/educode_sales/plans/edit_bussiness_info_extra.html.erb +260 -0
  39. data/app/views/educode_sales/plans/edit_year_plan.html.erb +237 -0
  40. data/app/views/educode_sales/plans/index.html.erb +8 -0
  41. data/app/views/educode_sales/plans/new_year.html.erb +204 -0
  42. data/app/views/educode_sales/plans/plan_business_infos.json.jbuilder +42 -0
  43. data/app/views/educode_sales/plans/years_plan.json.jbuilder +17 -0
  44. data/app/views/educode_sales/recycles/_monthly.html.erb +1 -1
  45. data/app/views/educode_sales/recycles/_yearPlan.html.erb +118 -0
  46. data/app/views/educode_sales/recycles/index.html.erb +26 -22
  47. data/app/views/educode_sales/recycles/monthPlan.json.jbuilder +0 -1
  48. data/app/views/educode_sales/recycles/yearPlan.json.jbuilder +14 -0
  49. data/config/routes.rb +22 -0
  50. data/db/migrate/20230329135141_create_educode_sales_business_watches.rb +17 -0
  51. data/db/migrate/20230330141213_create_educode_sales_activity_follow_ups.rb +31 -0
  52. data/db/migrate/20230405074036_add_year_to_sale_plans.rb +38 -0
  53. data/lib/educode_sales/version.rb +1 -1
  54. metadata +31 -7
  55. data/app/assets/images/educode_sales/indexlogo.png +0 -0
@@ -51,22 +51,22 @@ module EducodeSales
51
51
  end if role
52
52
 
53
53
  if @current_admin.is_admin?
54
- @teachers = Teacher.where(is_key: false)
54
+ @teachers = Teacher
55
55
  else
56
56
  level = @current_admin.role.role_areas.find_by(clazz: '教师运营').level
57
57
  case level
58
58
  when '自己'
59
- @teachers = Teacher.where(is_key: false)
59
+ @teachers = Teacher
60
60
  @teachers = @teachers.where(staff_id: @current_admin.id)
61
61
  teacher_ids = EducodeSales::Teacher.where(staff_id: 0).pluck(:id) - EducodeSales::TeacherAssignFollow.all.pluck(:Teacher_id) + EducodeSales::TeacherAssignFollow.where(staff_id: @current_admin.id).pluck(:teacher_id) + @teachers.ids
62
62
  @teachers = Teacher.where(id: teacher_ids)
63
63
  when '区域'
64
64
  school_ids = School.where(province: @current_admin.areas.pluck(:name)).pluck(:id) + StaffSchool.where(staff_id: @current_admin.id).pluck(:school_id)
65
- @teachers = Teacher.joins("JOIN departments ON educode_sales_teachers.department_id = departments.id").where(is_key: false).where("departments.school_id in (?) OR educode_sales_teachers.staff_id = #{@current_admin.id}", school_ids)
65
+ @teachers = Teacher.joins("JOIN departments ON educode_sales_teachers.department_id = departments.id").where("departments.school_id in (?) OR educode_sales_teachers.staff_id = #{@current_admin.id}", school_ids)
66
66
  teacher_ids = EducodeSales::Teacher.where(staff_id: 0).pluck(:id) - EducodeSales::TeacherAssignFollow.all.pluck(:Teacher_id) + EducodeSales::TeacherAssignFollow.where(staff_id: @current_admin.id).pluck(:teacher_id) + @teachers.ids
67
67
  @teachers = Teacher.where(id: teacher_ids)
68
68
  else
69
- @teachers = Teacher.where(is_key: false)
69
+ @teachers = Teacher
70
70
  end
71
71
  end
72
72
 
@@ -33,13 +33,20 @@ module EducodeSales
33
33
  if @attachment.blank?
34
34
  @attachment = Attachment.new
35
35
  @attachment.filename = upload_file.original_filename
36
- @attachment.description = "business"
36
+ if params[:activity_id].present?
37
+ @attachment.container_id = params[:activity_id]
38
+ @attachment.container_type = 'EducodeSales::Activity'
39
+ else
40
+ @attachment.description = "business"
41
+ @attachment.container_id = params[:business_id]
42
+ end
43
+
37
44
  @attachment.disk_filename = local_path[save_path.size + 1, local_path.size]
38
45
  @attachment.filesize = upload_file.tempfile.size
39
46
  @attachment.content_type = content_type
40
47
  @attachment.digest = digest
41
48
  @attachment.author_id = @current_admin.user_id
42
- @attachment.container_id = params[:business_id]
49
+
43
50
  @attachment.save!
44
51
  else
45
52
  logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}"
@@ -3,13 +3,30 @@ module EducodeSales
3
3
  belongs_to :staff
4
4
  has_many :activity_teachers, dependent: :destroy
5
5
  has_many :teachers, through: :activity_teachers, dependent: :restrict_with_exception
6
- has_many :manages, -> {where("educode_sales_activity_staffs.clazz_id = 0")}, dependent: :destroy, class_name: 'ActivityStaff'
7
- has_many :assists, -> {where("educode_sales_activity_staffs.clazz_id = 1")}, dependent: :destroy, class_name: 'ActivityStaff'
8
- has_many :experts , -> {where("educode_sales_activity_staffs.clazz_id = 2")}, dependent: :destroy, class_name: 'ActivityStaff'
9
- has_many :activity_staffs
6
+ has_many :manages, -> {where("educode_sales_activity_staffs.clazz_id = 0")}, dependent: :destroy, class_name: 'ActivityStaff'
7
+ has_many :assists, -> {where("educode_sales_activity_staffs.clazz_id = 1")}, dependent: :destroy, class_name: 'ActivityStaff'
8
+ has_many :experts , -> {where("educode_sales_activity_staffs.clazz_id = 2")}, dependent: :destroy, class_name: 'ActivityStaff'
9
+ has_many :invitations , -> {where("educode_sales_activity_staffs.clazz_id = 3")}, dependent: :destroy, class_name: 'ActivityStaff'
10
+
11
+ has_many :activity_staffs, dependent: :destroy
12
+ has_many :activity_follow_ups, dependent: :destroy
13
+
14
+ has_many :attachments, as: :container, dependent: :destroy
15
+
16
+ belongs_to :last_follow_up, class_name: 'ActivityFollowUp', optional: true
17
+
18
+ belongs_to :sales, class_name: 'Staff', optional: true
10
19
 
11
20
  has_one :attachment, as: :container, dependent: :destroy
12
21
 
13
22
  enum clazz_id: ['全国会议', '区域会议', '单校会议', '国赛', '省赛', '夏令营']
23
+ enum state_id: {
24
+ '策划中': 1,
25
+ '筹备中': 2,
26
+ '实施中': 3,
27
+ '已结束': 4,
28
+ '已撤销': 5,
29
+ '已推迟': 6
30
+ }
14
31
  end
15
32
  end
@@ -0,0 +1,13 @@
1
+ module EducodeSales
2
+ class ActivityFollowUp < ApplicationRecord
3
+ belongs_to :staff
4
+ belongs_to :activity
5
+
6
+ enum info_id: {
7
+ '': nil,
8
+ '跟进信息': 1,
9
+ '团队建议': 2,
10
+ '评价': 3,
11
+ }
12
+ end
13
+ end
@@ -4,6 +4,6 @@ module EducodeSales
4
4
  belongs_to :staff, optional: true
5
5
  belongs_to :user, optional: true
6
6
 
7
- enum clazz_id: ['manage', 'assist', 'expert']
7
+ enum clazz_id: ['manage', 'assist', 'expert', 'invitation']
8
8
  end
9
9
  end
@@ -8,7 +8,7 @@ module EducodeSales
8
8
 
9
9
 
10
10
  CLAZZ = {
11
- 7 => '销售指标', 1 => '签单指标', 2 => '回款指标', 3 => '商机跟进', 4 => '商机挖掘-A类商机', 5 => '商机挖掘-B类商机', 6 => '客户拜访-线下拜访', 8 => '客户拜访-线上拜访',
11
+ 7 => '商机目标', 18 => '中标目标', 1 => '签单目标', 2 => '回款目标', 3 => '商机跟进', 4 => '商机挖掘-A类商机', 5 => '商机挖掘-B类商机', 6 => '客户拜访-线下拜访', 8 => '客户拜访-线上拜访',
12
12
  9 => '注册数据-学生', 10 => '注册数据-老师', 11 => '会议组织-区域性会议', 12 => '会议组织-单校会议', 13 => '生态合作-虚拟教研室', 14 => '生态合作-特软', 15 => '生态合作-大V合作',
13
13
  16 => '重要事项', 17 => '临时任务'
14
14
  }
@@ -17,7 +17,7 @@ module EducodeSales
17
17
 
18
18
  def unit_name
19
19
  case self.assessment
20
- when 1, 2, 7
20
+ when 1, 2, 7, 18
21
21
  '万元'
22
22
  when 3
23
23
  '条'
@@ -11,6 +11,8 @@ module EducodeSales
11
11
  has_many :sale_plans
12
12
  has_many :follow_ups
13
13
  has_many :business_clazz_changes
14
+ has_many :business_levels, dependent: :destroy
15
+ has_many :business_watches, dependent: :destroy
14
16
 
15
17
  #关联关注
16
18
  has_many :users,:class_name => 'EducodeSales::BusinessRelationShip',foreign_key: 'business_id',:dependent => :destroy
@@ -18,6 +20,7 @@ module EducodeSales
18
20
  #每次查询时 默认的查询条件
19
21
  default_scope -> {where(deleted_at: nil)}
20
22
 
23
+
21
24
  def soft_destroy(user_id)
22
25
  self.update(deleted_at: Time.now, state_id: 2)
23
26
  self.sale_plans.each do |d|
@@ -0,0 +1,9 @@
1
+ module EducodeSales
2
+ class BusinessInfo < ApplicationRecord
3
+ belongs_to :staff
4
+ belongs_to :business
5
+ belongs_to :sale_plan, optional: true
6
+ end
7
+
8
+ end
9
+
@@ -0,0 +1,11 @@
1
+ module EducodeSales
2
+ class BusinessLevel < ApplicationRecord
3
+ belongs_to :business
4
+
5
+ enum level_id: {
6
+ '保密型': 1,
7
+ '战略型': 2
8
+ }
9
+ end
10
+ end
11
+
@@ -0,0 +1,6 @@
1
+ module EducodeSales
2
+ class BusinessWatch < ApplicationRecord
3
+ belongs_to :business
4
+ belongs_to :staff
5
+ end
6
+ end
@@ -5,7 +5,9 @@ module EducodeSales
5
5
  belongs_to :staff
6
6
  validates :business_id, presence: true
7
7
 
8
- validates :month, presence: true
8
+ # validates :month, presence: true
9
+
10
+ CLAZZ_NAME = {'商机目标' => 7, '中标目标' => 18, '签单目标' => 1, '回款目标' => 2}
9
11
 
10
12
  default_scope -> {where(deleted_at: nil)}
11
13
  end
@@ -25,6 +25,8 @@ module EducodeSales
25
25
 
26
26
  has_many :staff_school_tags, dependent: :destroy
27
27
 
28
+ has_many :business_infos, dependent: :destroy
29
+
28
30
  has_many :market_areas, dependent: :destroy
29
31
  has_many :areas, through: :market_areas
30
32
  validates :user_id, uniqueness: { message: '已存在' }
@@ -0,0 +1,222 @@
1
+ <div style="margin: 10px 10px 10px 10px">
2
+ <form class="layui-form layui-form-pane">
3
+ <div class="layui-form-item">
4
+ <div class="layui-inline">
5
+ <label class="layui-form-label">活动名称</label>
6
+ <div class="layui-input-inline">
7
+ <input type="text" name="name" class="layui-input">
8
+ </div>
9
+ </div>
10
+ <div class="layui-inline">
11
+ <label class="layui-form-label">最新进展</label>
12
+ <div class="layui-input-inline">
13
+ <input type="text" name="description" class="layui-input">
14
+ </div>
15
+ </div>
16
+ <div class="layui-inline">
17
+ <label class="layui-form-label">销售经理</label>
18
+ <div class="layui-input-inline">
19
+ <%= select_tag "sales_id", options_for_select(@staffs), { include_blank: true } %>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="layui-inline">
24
+ <button type="reset" class="layui-btn layui-btn-primary" lay-submit lay-filter="reset_follows_search">重置
25
+ </button>
26
+ <button type="submit" class="layui-btn layui-btn-primary" lay-submit lay-filter="search_follows">搜 索
27
+ </button>
28
+ </div>
29
+ </div>
30
+ </form>
31
+ </div>
32
+ <div class="">
33
+ <table class="layui-hide" id="activity_followp_table" style="min-height: 300px;" lay-filter="activity_followp_table"></table>
34
+ </div>
35
+ <script type="text/html" id="currentTableBar_follows">
36
+ <% if can? :advise, EducodeSales::ActivityFollowUp %>
37
+ <a class="layui-btn layui-btn-default layui-btn-xs data-count-edit" lay-event="advise">团队建议</a>
38
+ <% end %>
39
+ </script>
40
+
41
+ <script>
42
+ layui.use(['form', 'table', 'miniPage', 'element', 'request', 'laydate'], function () {
43
+ var $ = layui.jquery,
44
+ form = layui.form,
45
+ request = layui.request,
46
+ dropdown = layui.dropdown,
47
+ miniPage = layui.miniPage,
48
+ laydate = layui.laydate;
49
+
50
+ var table = layui.table;
51
+ table.render({
52
+ elem: '#activity_followp_table',
53
+ url: '/missions/activities/follow_ups',
54
+ defaultToolbar: ['filter'],
55
+ initSort: {
56
+ field: 'created_at' ,type: 'desc'
57
+ },
58
+ cols: [
59
+ [
60
+ {
61
+ field: 'id',
62
+ width: 60,
63
+ title:'序号',type: 'numbers',
64
+ },
65
+ {
66
+ field: 'description',
67
+ title: '最新进展',
68
+ width: 300,
69
+ templet:'<div><span title="{{d.description}}">{{d.description}}</span></div>'
70
+ },
71
+ {
72
+ width: 120,
73
+ title: '活动名称',
74
+ field: 'name'
75
+ },
76
+ {
77
+ field: 'state_id',
78
+ width: 150,
79
+ title: '活动状态',
80
+ },
81
+ {
82
+ field: 'staff',
83
+ width: 150,
84
+ title: '销售经理',
85
+ },
86
+ {
87
+ field: 'staff_manage',
88
+ title: '生态经理',
89
+ width: 150,
90
+ },
91
+ {
92
+ field: 'info_id',
93
+ width: 160,
94
+ title: '信息类型',
95
+ },
96
+ {
97
+ field: 'follow_up',
98
+ width: 120,
99
+ title: '最新跟进人',
100
+ },
101
+ {
102
+ field: 'created_at',
103
+ width: 180,
104
+ title: '最新跟进时间',
105
+ sort: true,
106
+ },
107
+ {
108
+ field: 'advise',
109
+ width: 300,
110
+ title: '团队建议',
111
+ templet:'<div><span title="{{d.advise}}">{{d.advise}}</span></div>'
112
+ },
113
+ {
114
+ title: '操作',
115
+ width: 200,
116
+ toolbar: '#currentTableBar_follows',
117
+ align: "center",
118
+ fixed: 'right'
119
+ }
120
+ ]
121
+ ],
122
+ limit: 20,
123
+ page: true,
124
+ limits: [10,15,20,30,40,50,60,70,80,90]
125
+ });
126
+
127
+ var sort = {}, search = {};
128
+ table.on('sort(activity_followp_table)', function (obj) {
129
+ sort.field = obj.field;
130
+ sort.order = obj.type;
131
+ table.reload('activity_followp_table', {
132
+ initSort: obj,
133
+ where: {
134
+ sort: sort,
135
+ q: search
136
+ }
137
+ });
138
+ })
139
+
140
+ // 监听搜索操作
141
+ form.on('submit(search_follows)', function (data) {
142
+ search = data.field
143
+ table.reload('activity_followp_table', {
144
+ page: {
145
+ curr: 1
146
+ },
147
+ where: {q: search, sort: sort}
148
+ }, 'data');
149
+
150
+ return false;
151
+ });
152
+
153
+ form.on('submit(reset_follows_search)', function (data) {
154
+ var field = data.field;
155
+ form.val('search_follows', {
156
+ name: "",
157
+ description: "",
158
+ staff_id: ""
159
+ })
160
+ return false;
161
+ });
162
+
163
+
164
+ table.on('tool(activity_followp_table)', function (obj) {
165
+ var data = obj.data;
166
+ id = data.teacher_id;
167
+ if (obj.event === 'detail') { // 监听添加操作
168
+ content = miniPage.getHrefContent('/missions/teachers/show_follow?id=' + data.teacher_id);
169
+ openWH = miniPage.getOpenWidthHeight();
170
+ index = layer.open({
171
+ title: '跟进记录',
172
+ type: 1,
173
+ shade: 0.2,
174
+ maxmin: true,
175
+ shadeClose: true,
176
+ area: [openWH[0] + 'px', openWH[1] + 'px'],
177
+ offset: [openWH[2] + 'px', openWH[3] + 'px'],
178
+ content: content
179
+ });
180
+ $(window).on("resize", function () {
181
+ layer.full(index);
182
+ });
183
+ } else if (obj.event == 'advise') {
184
+ layer.open({
185
+ title: '添加团队建议',
186
+ closeBtn: 0,
187
+ type: 1,
188
+ area: '400px;',
189
+ id: 'LAY_layuipro',
190
+ content: '<div class="layui-form" lay-filter="edit_project" style="padding: 20px;"><textarea autocomplete="off" type="text" name="name" lay-verify="required" class="layui-textarea">' + data.advise + '</textarea></div>' ,
191
+ btn: ['保存', '取消'],
192
+ btn1: function(index, l) {
193
+ if (l.find("textarea").val().trim() == '') {
194
+ layer.msg('内容不能为空')
195
+ return false;
196
+ } else {
197
+ request.authPost("/missions/activities/add_advise", {content: l.find("textarea").val().trim(), id: data.id}, function(res) {
198
+ if (res.success == false) {
199
+ layer.alert(res.msg);
200
+ } else {
201
+ layer.close(index);
202
+ table.reload('activity_followp_table');
203
+ }
204
+ })
205
+ }
206
+
207
+ return false
208
+ },
209
+ btn2: function(index, l) {
210
+ layer.close(index)
211
+ }
212
+ });
213
+ }
214
+ });
215
+
216
+ });
217
+ </script>
218
+ <style>
219
+ .layui-table-tool-temp{
220
+ padding-right: 30px; !important;
221
+ }
222
+ </style>