diff --git a/app/controllers/admins/user_actions_controller.rb b/app/controllers/admins/user_actions_controller.rb
new file mode 100644
index 000000000..d96cdc97e
--- /dev/null
+++ b/app/controllers/admins/user_actions_controller.rb
@@ -0,0 +1,14 @@
+class Admins::UserActionsController < Admins::BaseController
+ before_action :require_admin
+
+ def index
+ @user_actions = UserAction.order(created_at: :desc)
+ @user_actions = @user_actions.where(action_type: params[:action_type]) if params[:action_type].present?
+ keyword = params[:keyword].to_s.strip.presence
+ if keyword
+ sql = 'login LIKE :keyword OR phone LIKE :keyword OR mail LIKE :keyword'
+ @user_actions = @user_actions.where(sql, keyword: "%#{keyword}%")
+ end
+ @user_actions = paginate @user_actions
+ end
+end
diff --git a/app/models/user_action.rb b/app/models/user_action.rb
index b4173fe77..7405c0c44 100644
--- a/app/models/user_action.rb
+++ b/app/models/user_action.rb
@@ -10,6 +10,10 @@
# updated_at :datetime not null
# ip :string(255)
# data_bank :text(65535)
+# login :string(255)
+# phone :string(255)
+# email :string(255)
+# memo :text(65535)
#
# Indexes
#
@@ -19,5 +23,51 @@
# index_user_actions_on_user_id (user_id)
#
-class UserAction < ApplicationRecord
-end
+class UserAction < ApplicationRecord
+
+ before_create :add_user_info
+
+ serialize :data_bank, JSON
+
+ def action_name
+ case action_type
+ when "DestroyUser" then "删除用户"
+ when "DestroyProject" then "删除项目"
+ when "Login" then "登录"
+ when "Logout" then "退出登录"
+ else self.action_type
+ end
+ end
+
+ def action_data
+ case action_type
+ when "DestroyUser" then build_mode("User")
+ when "DestroyProject" then build_mode("Project")
+ else nil
+ end
+ end
+
+ def user
+ action_user = User.find_by(id: self.user_id)
+ if action_user.blank?
+ action_user = self.action_data
+ end
+ action_user
+ end
+ def build_mode(model_name)
+ model = model_name.constantize.new
+ model_name.constantize.column_names.each do |col|
+ model[col] = self.data_bank[col]
+ end
+ model
+ end
+
+ private
+ def add_user_info
+ if user.present?
+ self.login = user.login
+ self.email = user.mail
+ self.phone = user.phone
+ end
+ end
+end
diff --git a/app/views/admins/user_actions/_user_action_list.html.erb b/app/views/admins/user_actions/_user_action_list.html.erb
new file mode 100644
index 000000000..8577b2f29
--- /dev/null
+++ b/app/views/admins/user_actions/_user_action_list.html.erb
@@ -0,0 +1,44 @@
+
+
+
+ 序号 |
+ 操作类型 |
+ 账号 |
+ 邮箱 |
+ 手机号 |
+ 姓名 |
+ 操作时间 |
+ 原因/备注 |
+
+
+
+ <% if user_actions.present? %>
+ <% user_actions.each_with_index do |action, index| %>
+
+ <%= list_index_no((params[:page] || 1).to_i, index) %> |
+ <%= action.action_name %> |
+
+ <%= link_to "/#{action.user&.login}", target: '_blank' do %>
+ <%= overflow_hidden_span action.user&.login, width: 100 %>
+ <% end %>
+ |
+
+ <%= overflow_hidden_span action.user&.mail, width: 150 %>
+ |
+ <%= action.user&.phone %> |
+
+ <%= link_to "/#{action.user&.login}", target: '_blank' do %>
+ <%= overflow_hidden_span action.user&.real_name, width: 100 %>
+ <% end %>
+ |
+ <%= display_text(action.created_at&.strftime('%Y-%m-%d %H:%M')) %> |
+ <%= action.memo %> |
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: user_actions } %>
diff --git a/app/views/admins/user_actions/index.html.erb b/app/views/admins/user_actions/index.html.erb
new file mode 100644
index 000000000..8821a8be0
--- /dev/null
+++ b/app/views/admins/user_actions/index.html.erb
@@ -0,0 +1,50 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('操作记录', admins_user_actions_path) %>
+<% end %>
+
+
+ <%= form_tag(admins_user_actions_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
+ 操作类型:
+ <% action_type_options = [['自定义',''],['删除用户','DestroyUser'], ['删除项目', 'DestroyProject']] %>
+ <%= select_tag(:action_type_select, options_for_select(action_type_options), class: 'form-control') %>
+ <%= text_field_tag(:action_type, params[:action_type], class: 'form-control col-sm-2 ml-3',style: 'display:none;', placeholder: '自定义操作类型检索') %>
+ <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '用户名/邮箱/手机号检索') %>
+ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
+ <% end %>
+
+
+
+
+
+
+
+ <%# @user_nps_mid = @score_total_count % 2 == 0 ? @score_total_count / 2 : (@score_total_count + 1) / 2 %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <%= render partial: 'admins/user_actions/user_action_list', locals: { user_actions: @user_actions } %>
+
+
+
diff --git a/app/views/admins/user_actions/index.js.erb b/app/views/admins/user_actions/index.js.erb
new file mode 100644
index 000000000..d624a61ae
--- /dev/null
+++ b/app/views/admins/user_actions/index.js.erb
@@ -0,0 +1 @@
+$('.users-list-container').html("<%= j( render partial: 'admins/user_actions/user_action_list', locals: { user_actions: @user_actions } ) %>");
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index 64d064b86..501a024b4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -92,7 +92,7 @@ Rails.application.routes.draw do
resources :project_rank, only: [:index]
resources :user_rank, only: [:index]
resources :nps, only: [:create]
-
+
resources :statistic, only: [:index] do
collection do
get :platform_profile
@@ -1025,6 +1025,7 @@ Rails.application.routes.draw do
post :drag, on: :collection
post :replace_image_url, on: :member
end
+ resources :user_actions , only:[:index]
resources :faqs
resources :nps do
post :switch_change, on: :collection
diff --git a/db/migrate/202410926031029_add_user_info_to_user_actions.rb b/db/migrate/202410926031029_add_user_info_to_user_actions.rb
new file mode 100644
index 000000000..e361d2b1d
--- /dev/null
+++ b/db/migrate/202410926031029_add_user_info_to_user_actions.rb
@@ -0,0 +1,20 @@
+class AddUserInfoToUserActions < ActiveRecord::Migration[5.2]
+ def change
+ add_column :user_actions, :login, :string
+ add_column :user_actions, :phone, :string
+ add_column :user_actions, :email, :string
+ add_column :user_actions, :memo, :text
+
+ UserAction.find_in_batches(batch_size: 1000) do |sw|
+ Parallel.each(sw, in_threads: 5) do |user_action|
+ next if user_action.user_id.blank?
+ user = User.find_by(id: user_action.user_id)
+ next if user.blank?
+ user_action.login = user.login
+ user_action.email = user.mail
+ user_action.phone = user.phone
+ user_action.save
+ end
+ end
+ end
+end