| @@ -28,6 +28,41 @@ class Admins::DashboardsController < Admins::BaseController | |||||
| @day_new_project_count = Project.where(created_on: today).count | @day_new_project_count = Project.where(created_on: today).count | ||||
| @weekly_new_project_count = Project.where(created_on: current_week).count | @weekly_new_project_count = Project.where(created_on: current_week).count | ||||
| @month_new_project_count = Project.where(created_on: current_month).count | @month_new_project_count = Project.where(created_on: current_month).count | ||||
| # 总的平台用户数 | |||||
| # 总的平台项目数 | |||||
| # 总的平台组织数 | |||||
| # 总的平台Issue数、评论数、PR数、Commit数 | |||||
| @user_count = User.count | |||||
| @project_count = Project.count | |||||
| @organization_count = Organization.count | |||||
| @issue_count = Issue.count | |||||
| @comment_count = Journal.count | |||||
| @pr_count = PullRequest.count | |||||
| @commit_count = CommitLog.count | |||||
| @subject_name = ["用户数", "项目数", "组织数", "Issue数", "Issue评论数", "PR数", "Commit数"] | |||||
| @subject_icon = ["fa-user","fa-git", "fa-sitemap", "fa-warning", "fa-comments", "fa-share-alt", "fa-upload"] | |||||
| @subject_data = [@user_count, @project_count, @organization_count, @issue_count, @comment_count, @pr_count, @commit_count] | |||||
| tongji_service = Baidu::TongjiService.new | |||||
| @access_token = tongji_service.access_token | |||||
| Rails.logger.info "baidu_tongji_auth access_token ===== #{@access_token}" | |||||
| # @overview_data = tongji_service.api_overview | |||||
| last_date = DailyPlatformStatistic.order(:date).last | |||||
| start_date = last_date.date | |||||
| end_date = Time.now | |||||
| if @access_token.present? | |||||
| @overview_data = tongji_service.overview_batch_add(start_date, end_date) | |||||
| tongji_service.source_from_batch_add(start_date, end_date) | |||||
| end | |||||
| @current_week_statistic = DailyPlatformStatistic.where(date: current_week) | |||||
| @pre_week_statistic = DailyPlatformStatistic.where(date: pre_week) | |||||
| end | end | ||||
| def month_active_user | def month_active_user | ||||
| @@ -42,6 +77,19 @@ class Admins::DashboardsController < Admins::BaseController | |||||
| render_ok(data: data) | render_ok(data: data) | ||||
| end | end | ||||
| def baidu_tongji | |||||
| tongji_service = Baidu::TongjiService.new | |||||
| redirect_to tongji_service.code_url | |||||
| end | |||||
| def baidu_tongji_auth | |||||
| if params[:code].present? | |||||
| tongji_service = Baidu::TongjiService.new | |||||
| tongji_service.get_access_token(params[:code]) | |||||
| end | |||||
| redirect_to "/admins/" | |||||
| end | |||||
| def evaluate | def evaluate | ||||
| names = [] | names = [] | ||||
| data = [] | data = [] | ||||
| @@ -63,8 +111,12 @@ class Admins::DashboardsController < Admins::BaseController | |||||
| Time.now.beginning_of_day..Time.now.end_of_day | Time.now.beginning_of_day..Time.now.end_of_day | ||||
| end | end | ||||
| def current_week | |||||
| def pre_7_days | |||||
| 7.days.ago.end_of_day..Time.now.end_of_day | 7.days.ago.end_of_day..Time.now.end_of_day | ||||
| end | |||||
| def current_week | |||||
| Time.now.beginning_of_week..Time.now.end_of_day | |||||
| end | end | ||||
| def current_month | def current_month | ||||
| @@ -72,6 +124,7 @@ class Admins::DashboardsController < Admins::BaseController | |||||
| end | end | ||||
| def pre_week | def pre_week | ||||
| 14.days.ago.end_of_day..7.days.ago.end_of_day | |||||
| # 14.days.ago.end_of_day..7.days.ago.end_of_day | |||||
| Time.now.prev_week..Time.now.prev_week.end_of_week | |||||
| end | end | ||||
| end | end | ||||
| @@ -15,6 +15,7 @@ class Admins::IdentityVerificationsController < Admins::BaseController | |||||
| def update | def update | ||||
| if @identity_verification.update(update_params) | if @identity_verification.update(update_params) | ||||
| UserAction.create(action_id: @identity_verification.id, action_type: "UpdateIdentityVerifications", user_id: current_user.id, :ip => request.remote_ip, data_bank: @identity_verification.attributes.to_json) | |||||
| redirect_to admins_identity_verifications_path | redirect_to admins_identity_verifications_path | ||||
| flash[:success] = "更新成功" | flash[:success] = "更新成功" | ||||
| else | else | ||||
| @@ -29,8 +29,12 @@ class Admins::SitePagesController < Admins::BaseController | |||||
| end | end | ||||
| def update | def update | ||||
| @site_page.update(update_params) | |||||
| flash[:success] = '保存成功' | |||||
| if update_params[:state] == "false" && update_params[:state_description].blank? | |||||
| flash[:danger] = '关闭站点理由不能为空' | |||||
| else | |||||
| @site_page.update(update_params) | |||||
| flash[:success] = '保存成功' | |||||
| end | |||||
| render 'edit' | render 'edit' | ||||
| end | end | ||||
| @@ -1,12 +1,12 @@ | |||||
| class Organizations::CreateForm < BaseForm | class Organizations::CreateForm < BaseForm | ||||
| NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 | |||||
| NAME_REGEX = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*$/ #只含有数字、字母、下划线不能以下划线开头和结尾 | |||||
| attr_accessor :name, :description, :website, :location, :repo_admin_change_team_access, :visibility, :max_repo_creation, :nickname, :original_name | attr_accessor :name, :description, :website, :location, :repo_admin_change_team_access, :visibility, :max_repo_creation, :nickname, :original_name | ||||
| validates :name, :nickname, :visibility, presence: true | validates :name, :nickname, :visibility, presence: true | ||||
| validates :name, :nickname, length: { maximum: 100 } | validates :name, :nickname, length: { maximum: 100 } | ||||
| validates :location, length: { maximum: 50 } | validates :location, length: { maximum: 50 } | ||||
| validates :description, length: { maximum: 200 } | validates :description, length: { maximum: 200 } | ||||
| validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } | |||||
| validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能以数字或字母开头,仅支持横杠、下划线、点三种符号,不允许符号连续排列,长度4-50个字符" } | |||||
| validate do | validate do | ||||
| check_name(name) unless name.blank? || name == original_name | check_name(name) unless name.blank? || name == original_name | ||||
| @@ -0,0 +1,44 @@ | |||||
| # 按天获取百度统计数据,pv,访问,ip和来源分类占比 | |||||
| # 其他统计:前一周用户留存率 | |||||
| class DailyPlatformStatisticsJob < ApplicationJob | |||||
| queue_as :default | |||||
| def perform(*args) | |||||
| Rails.logger.info("*********开始统计*********") | |||||
| tongji_service = Baidu::TongjiService.new | |||||
| access_token = tongji_service.access_token | |||||
| Rails.logger.info "job baidu_tongji_auth access_token ===== #{access_token}" | |||||
| ActiveJob::Base.logger.info "job baidu_tongji_auth access_token ===== #{access_token}" | |||||
| # 从最后一个记录日期开始,如果遗漏日期数据可以补充数据 | |||||
| last_date = DailyPlatformStatistic.order(:date).last | |||||
| start_date = last_date.date | |||||
| end_date = Time.now | |||||
| if access_token.present? | |||||
| tongji_service.overview_batch_add(start_date, end_date) | |||||
| # 本周访问来源占比,每天记录一次,如果遗漏日期数据可以补充数据 | |||||
| tongji_service.source_from_batch_add(start_date, end_date) | |||||
| end | |||||
| # 周用户留存率 | |||||
| pre_week_user_ids = User.where(created_on: pre_week).pluck(:id).uniq | |||||
| weekly_keep_user_count = User.where(id: pre_week_user_ids).where(last_login_on: current_week).count | |||||
| weekly_keep_rate = format("%.2f", pre_week_user_ids.size > 0 ? weekly_keep_user_count.to_f / pre_week_user_ids.size : 0) | |||||
| job_date = 1.days.ago | |||||
| daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: job_date) | |||||
| daily_statistic.weekly_keep_rate = weekly_keep_rate | |||||
| daily_statistic.save | |||||
| end | |||||
| private | |||||
| def current_week | |||||
| Time.now.beginning_of_week..Time.now.end_of_day | |||||
| end | |||||
| def pre_week | |||||
| # 7.days.ago.beginning_of_week..7.days.ago.beginning_of_week.end_of_week | |||||
| Time.now.prev_week..Time.now.prev_week.end_of_week | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,24 @@ | |||||
| # == Schema Information | |||||
| # | |||||
| # Table name: daily_platform_statistics | |||||
| # | |||||
| # id :integer not null, primary key | |||||
| # date :date | |||||
| # pv :integer default("0") | |||||
| # visitor :integer default("0") | |||||
| # ip :integer default("0") | |||||
| # weekly_keep_rate :float(24) default("0") | |||||
| # source_through :float(24) default("0") | |||||
| # source_link :float(24) default("0") | |||||
| # source_search :float(24) default("0") | |||||
| # source_custom :float(24) default("0") | |||||
| # created_at :datetime not null | |||||
| # updated_at :datetime not null | |||||
| # | |||||
| # Indexes | |||||
| # | |||||
| # index_daily_platform_statistics_on_date (date) UNIQUE | |||||
| # | |||||
| class DailyPlatformStatistic < ApplicationRecord | |||||
| end | |||||
| @@ -64,7 +64,7 @@ | |||||
| class Organization < Owner | class Organization < Owner | ||||
| alias_attribute :name, :login | alias_attribute :name, :login | ||||
| NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 | |||||
| NAME_REGEX = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*$/ #只含有数字、字母、下划线不能以下划线开头和结尾 | |||||
| default_scope { where(type: "Organization") } | default_scope { where(type: "Organization") } | ||||
| @@ -79,7 +79,7 @@ class Organization < Owner | |||||
| validates :login, presence: true | validates :login, presence: true | ||||
| validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false | validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false | ||||
| validates :login, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } | |||||
| validates :login, format: { with: NAME_REGEX, multiline: true, message: "只能以数字或字母开头,仅支持横杠、下划线、点三种符号,不允许符号连续排列,长度4-50个字符" } | |||||
| delegate :description, :website, :location, :repo_admin_change_team_access, :recommend, | delegate :description, :website, :location, :repo_admin_change_team_access, :recommend, | ||||
| :visibility, :max_repo_creation, :num_projects, :num_users, :num_teams, | :visibility, :max_repo_creation, :num_projects, :num_users, :num_teams, | ||||
| @@ -0,0 +1,221 @@ | |||||
| module Baidu | |||||
| class TongjiService < ApplicationService | |||||
| attr_reader :client_id, :client_secret, :site_id | |||||
| # login、code、password、password_confirmation | |||||
| def initialize | |||||
| @client_id = "6dMO2kqKUaMZkBrMaUMxQSNAT49v0Mjq" | |||||
| @client_secret = "qvWqF33AOmGs1tPCgsROvis9EQCuNmd3" | |||||
| @site_id = 18657013 | |||||
| end | |||||
| def call | |||||
| end | |||||
| def init_overview_data_by(start_date = nil, end_date = nil) | |||||
| start_date = Time.now.prev_year.beginning_of_year if start_date.nil? | |||||
| end_date = Time.now | |||||
| Rails.logger.info("*********开始百度统计-概览:#{start_date}-#{end_date}*********") | |||||
| sql_connection = ActiveRecord::Base.connection | |||||
| sql_connection.begin_db_transaction | |||||
| # 如果存在数据 先清空 | |||||
| # sql_connection.execute("delete from daily_platform_statistics where date between '#{start_date}' and '#{end_date}'") | |||||
| multiple_days_data = overview_multiple_days_data(start_date, end_date) | |||||
| if multiple_days_data.present? | |||||
| sql = "replace into daily_platform_statistics (date,pv,visitor,ip,created_at,updated_at) values #{multiple_days_data.join(",")}" | |||||
| sql_connection.execute(sql) | |||||
| end | |||||
| sql_connection.commit_db_transaction | |||||
| Rails.logger.info("*********结束百度统计-概览:#{start_date}-#{end_date}*********") | |||||
| end | |||||
| def init_source_from_data_by(start_date = nil, end_date = nil) | |||||
| start_date = Time.now.prev_year.beginning_of_year if start_date.nil? | |||||
| end_date = Time.now | |||||
| Rails.logger.info("*********开始百度统计-来源:#{start_date}-#{end_date}*********") | |||||
| source_from_batch_add(start_date, end_date) | |||||
| Rails.logger.info("*********结束百度统计-来源:#{start_date}-#{end_date}*********") | |||||
| end | |||||
| # 按日期获取来源数据 | |||||
| def source_from_batch_add(start_date,end_date) | |||||
| # 补充更新开始时间的当天数据 | |||||
| source_from_by_date(start_date) | |||||
| diff_days(start_date, end_date).times.each do |t| | |||||
| new_start_date = start_date + (t + 1).days | |||||
| source_from_by_date(new_start_date) | |||||
| end | |||||
| # 补充更新最后时间一天数据 | |||||
| source_from_by_date(end_date) | |||||
| end | |||||
| # 按天获取来源数据 | |||||
| def source_from_by_date(start_date) | |||||
| return [] unless access_token.present? && start_date.present? | |||||
| source_from_data = api("source/all/a", start_date, start_date, "pv_count,visitor_count,ip_count") | |||||
| source_from = [] | |||||
| source_from_data['items'][1].each_with_index do |source, index| | |||||
| source_from.push(((source[0].to_f / source_from_data['sum'][0][0].to_f) * 100).round(2)) | |||||
| end | |||||
| daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: start_date) | |||||
| daily_statistic.source_through = source_from[0] | |||||
| daily_statistic.source_link = source_from[1] | |||||
| daily_statistic.source_search = source_from[2] | |||||
| daily_statistic.source_custom = source_from[3] | |||||
| daily_statistic.save | |||||
| end | |||||
| def diff_days(start_date, end_date) | |||||
| (end_date.beginning_of_day.to_i - start_date.beginning_of_day.to_i) / (24 * 3600) | |||||
| end | |||||
| def overview_batch_add(start_date, end_date) | |||||
| return [] unless access_token.present? && start_date.present? && end_date.present? | |||||
| start_date = Time.now - 1.days if start_date.strftime("%Y%m%d") == end_date.strftime("%Y%m%d") | |||||
| overview_data = api("overview/getTimeTrendRpt", start_date, end_date, "pv_count,visitor_count,ip_count") | |||||
| overview_data['items'][0].each_with_index do |date, index| | |||||
| pv = overview_data['items'][1][index][0] | |||||
| visitor = overview_data['items'][1][index][1] | |||||
| ip = overview_data['items'][1][index][2] | |||||
| job_date = date[0].to_s.gsub("/", "-") | |||||
| daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: job_date) | |||||
| daily_statistic.date = job_date | |||||
| daily_statistic.pv = pv | |||||
| daily_statistic.visitor = visitor | |||||
| daily_statistic.ip = ip | |||||
| daily_statistic.save | |||||
| end | |||||
| overview_data | |||||
| end | |||||
| def overview_multiple_days_data(start_date, end_date) | |||||
| return [] unless access_token.present? && start_date.present? && end_date.present? | |||||
| overview_data = api("overview/getTimeTrendRpt", start_date, end_date, "pv_count,visitor_count,ip_count") | |||||
| data = [] | |||||
| created_at = Time.now.strftime("%Y-%m-%d 00:00:00") | |||||
| overview_data['items'][0].each_with_index do |date, index| | |||||
| pv = overview_data['items'][1][index][0] | |||||
| visitor = overview_data['items'][1][index][1] | |||||
| ip = overview_data['items'][1][index][2] | |||||
| data.push("('#{date[0].to_s.gsub("/", "-")}', #{pv.to_s.gsub("--","0")}, #{visitor.to_s.gsub("--","0")}, #{ip.to_s.gsub("--","0")},\"#{created_at}\",\"#{created_at}\")") | |||||
| end | |||||
| data | |||||
| end | |||||
| def code_url | |||||
| "http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=#{client_id}&redirect_uri=oob&scope=basic&display=popup" | |||||
| end | |||||
| def oauth_url(code) | |||||
| "http://openapi.baidu.com/oauth/2.0/token?grant_type=authorization_code&code=#{code}&client_id=#{client_id}&client_secret=#{client_secret}&redirect_uri=oob" | |||||
| end | |||||
| def get_access_token(code) | |||||
| uri = URI.parse(oauth_url(code)) | |||||
| response = Net::HTTP.get_response(uri) | |||||
| Rails.logger.info "baidu_tongji_auth response.body ===== #{response.body}" | |||||
| if response.code.to_i == 200 | |||||
| data = JSON.parse(response.body) | |||||
| access_token = data['access_token'] | |||||
| refresh_token = data['refresh_token'] | |||||
| expires_in = data['expires_in'] | |||||
| if access_token.present? | |||||
| Rails.cache.write("baidu_tongji_auth/access_token", access_token, expires_in: expires_in) | |||||
| Rails.cache.write("baidu_tongji_auth/refresh_token", refresh_token, expires_in: 1.year) | |||||
| end | |||||
| end | |||||
| end | |||||
| def refresh_access_token | |||||
| url = "http://openapi.baidu.com/oauth/2.0/token?grant_type=refresh_token&refresh_token=#{refresh_token}&client_id=#{client_id}&client_secret=#{client_secret}" | |||||
| uri = URI.parse(url) | |||||
| response = Net::HTTP.get_response(uri) | |||||
| Rails.logger.info "baidu_tongji_auth response.body ===== #{response.body}" | |||||
| if response.code.to_i == 200 | |||||
| data = JSON.parse(response.body) | |||||
| access_token = data['access_token'] | |||||
| refresh_token = data['refresh_token'] | |||||
| expires_in = data['expires_in'] | |||||
| if access_token.present? | |||||
| Rails.cache.write("baidu_tongji_auth/access_token", access_token, expires_in: expires_in) | |||||
| Rails.cache.write("baidu_tongji_auth/refresh_token", refresh_token, expires_in: 1.year) | |||||
| end | |||||
| end | |||||
| end | |||||
| def access_token | |||||
| access_token = Rails.cache.read("baidu_tongji_auth/access_token") | |||||
| if access_token.blank? | |||||
| refresh_access_token | |||||
| access_token = Rails.cache.read("baidu_tongji_auth/access_token") | |||||
| end | |||||
| access_token | |||||
| end | |||||
| def refresh_token | |||||
| refresh_token = Rails.cache.read("baidu_tongji_auth/refresh_token") | |||||
| # 如果刷新token失效,access_token也重置 | |||||
| if refresh_token.blank? | |||||
| Rails.cache.delete("baidu_tongji_auth/access_token") | |||||
| end | |||||
| refresh_token | |||||
| end | |||||
| # 网站概况(趋势数据) | |||||
| def api_overview | |||||
| start_date = Time.now.beginning_of_week | |||||
| end_date = Time.now | |||||
| start_date = Time.now - 1.days if start_date.strftime("%Y%m%d") == end_date.strftime("%Y%m%d") | |||||
| api("overview/getTimeTrendRpt", start_date, end_date, "pv_count,visitor_count,ip_count") | |||||
| end | |||||
| # 网站概况(来源网站、搜索词、入口页面、受访页面) | |||||
| def api_overview_getCommonTrackRpt | |||||
| start_date = Time.now.beginning_of_week | |||||
| end_date = Time.now | |||||
| api("overview/getCommonTrackRpt", start_date, end_date, "pv_count") | |||||
| end | |||||
| # 全部来源 | |||||
| def source_from | |||||
| start_date = Time.now.beginning_of_week | |||||
| end_date = Time.now | |||||
| api("source/all/a", start_date, end_date, "pv_count,visitor_count,ip_count") | |||||
| end | |||||
| def api(api_method, start_date, end_date, metrics = nil) | |||||
| start_date_fmt = start_date.strftime("%Y%m%d") | |||||
| end_date_fmt = end_date.strftime("%Y%m%d") | |||||
| api_url = "https://openapi.baidu.com/rest/2.0/tongji/report/getData?access_token=#{access_token}&site_id=#{site_id}&method=#{api_method}&start_date=#{start_date_fmt}&end_date=#{end_date_fmt}&metrics=#{metrics}" | |||||
| data = url_http_post(api_url, {}) | |||||
| data['result'] | |||||
| end | |||||
| def url_http_post(api_url, params) | |||||
| Rails.logger.info "api_url==#{api_url}" | |||||
| uri = URI.parse(api_url) | |||||
| http = Net::HTTP.new uri.host, uri.port | |||||
| http.open_timeout = 60 | |||||
| http.read_timeout = 60 | |||||
| if uri.scheme == 'https' | |||||
| http.verify_mode = OpenSSL::SSL::VERIFY_NONE | |||||
| http.use_ssl = true | |||||
| end | |||||
| begin | |||||
| request = Net::HTTP::Post.new(uri) | |||||
| request.set_form_data(params) if params.present? | |||||
| request['Content-Type'] = 'application/json;charset=utf-8' | |||||
| # request['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8' | |||||
| response = http.start { |http| http.request(request) } | |||||
| Rails.logger.info "api response.body==#{response.body}" | |||||
| JSON.parse response.body | |||||
| rescue => err | |||||
| Rails.logger.error("#############api_url:#{api_url},error:#{err.message.size}") | |||||
| # Rails.logger.error("#############api_url:#{api_url},error:#{err.message}") | |||||
| return {} | |||||
| end | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,50 @@ | |||||
| <div> | |||||
| 数据来源百度统计,本周 [<%= @current_week_statistic.first&.date %> / <%= @current_week_statistic.last&.date %>] | |||||
| </div> | |||||
| <table class="table table-hover text-center subject-list-table"> | |||||
| <thead class="thead-light"> | |||||
| <tr> | |||||
| <th width="20%">日期</th> | |||||
| <th width="15%">访问量</th> | |||||
| <th width="15%">访客数</th> | |||||
| <th width="15%">IP数</th> | |||||
| <th width="15%">直接访问占比</th> | |||||
| <th width="15%">外部链接占比</th> | |||||
| <th width="15%">搜索引擎占比</th> | |||||
| <th width="20%">自定义</th> | |||||
| </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <% @current_week_statistic.each_with_index do |week, index| %> | |||||
| <tr class=""> | |||||
| <td><%= week.date %> </td> | |||||
| <td><%= week.pv %></td> | |||||
| <td><%= week.visitor %></td> | |||||
| <td><%= week.ip %></td> | |||||
| <td><%= week.source_through %>%</td> | |||||
| <td><%= week.source_link %>%</td> | |||||
| <td><%= week.source_search %>%</td> | |||||
| <td><%= week.source_custom.to_f %>%</td> | |||||
| </td> | |||||
| </tr> | |||||
| <% end %> | |||||
| <!-- <tr class="">--> | |||||
| <!-- <td><span style="color: #ff8200">合计</span></td>--> | |||||
| <!-- <td><span style="color: #ff8200"><%#= @current_week_statistic.sum(:pv) %></span></td>--> | |||||
| <!-- <td><span style="color: #ff8200"><%#= @current_week_statistic.sum(:visitor) %></span></td>--> | |||||
| <!-- <td><span style="color: #ff8200"><%#= @current_week_statistic.sum(:ip) %></span></td>--> | |||||
| <!-- </td>--> | |||||
| <!-- </tr>--> | |||||
| </tbody> | |||||
| </table> | |||||
| <% unless @access_token.present? && @overview_data.present? %> | |||||
| <div> | |||||
| <a href="/admins/baidu_tongji" target="_blank">1.百度统计需人工授权,点击去授权</a> | |||||
| </div> | |||||
| <div> | |||||
| <a href="/admins/baidu_tongji_auth" onclick="this.href = '/admins/baidu_tongji_auth?code=' + document.getElementById('auth_code').value">2.获取百度统计授权码</a> | |||||
| <input name="code" id="auth_code" style="width: 380px" placeholder="请输入1.百度统计返回的code后,点击2.获取百度统计Token"/> | |||||
| </div> | |||||
| <% end %> | |||||
| @@ -0,0 +1,67 @@ | |||||
| <% if @access_token.present? && @overview_data.present? %> | |||||
| <div> | |||||
| 数据来源百度统计,本周 <%= @overview_data['timeSpan'] %> | |||||
| </div> | |||||
| <table class="table table-hover text-center subject-list-table"> | |||||
| <thead class="thead-light"> | |||||
| <tr> | |||||
| <th width="20%">日期</th> | |||||
| <th width="15%">访问量</th> | |||||
| <th width="15%">访客数</th> | |||||
| <th width="15%">IP数</th> | |||||
| </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <% pv_count = [] %> | |||||
| <% visitor_count = [] %> | |||||
| <% ip_count = [] %> | |||||
| <% @overview_data['items'][0].each_with_index do |date, index| %> | |||||
| <% pv = @overview_data['items'][1][index][0] %> | |||||
| <% visitor = @overview_data['items'][1][index][1] %> | |||||
| <% ip = @overview_data['items'][1][index][2] %> | |||||
| <tr class=""> | |||||
| <td><%= date[0] %> </td> | |||||
| <td><%= pv %></td> | |||||
| <td><%= visitor %></td> | |||||
| <td><%= ip %></td> | |||||
| </td> | |||||
| </tr> | |||||
| <% pv_count.push(pv) %> | |||||
| <% visitor_count.push(visitor) %> | |||||
| <% ip_count.push(ip) %> | |||||
| <% end %> | |||||
| <tr class=""> | |||||
| <td><span style="color: #ff8200">合计</span></td> | |||||
| <td><span style="color: #ff8200"><%= pv_count %></span></td> | |||||
| <td><span style="color: #ff8200"><%= visitor_count %></span></td> | |||||
| <td><span style="color: #ff8200"><%= ip_count %></span></td> | |||||
| </td> | |||||
| </tr> | |||||
| </tbody> | |||||
| </table> | |||||
| <table class="table table-hover text-center subject-list-table"> | |||||
| <thead class="thead-light"> | |||||
| <tr> | |||||
| <th width="15%">直接访问占比</th> | |||||
| <th width="15%">外部链接占比</th> | |||||
| <th width="15%">搜索引擎占比</th> | |||||
| <th width="20%">自定义</th> | |||||
| </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <tr class=""> | |||||
| <% @source_from_data['items'][1].each_with_index do |source, index| %> | |||||
| <td><%= ((source[0].to_f / @source_from_data['sum'][0][0].to_f) * 100).round(2).to_s %>%</td> | |||||
| <% end %> | |||||
| </tr> | |||||
| </tbody> | |||||
| </table> | |||||
| <% else %> | |||||
| <div> | |||||
| <a href="/admins/baidu_tongji" target="_blank">1.百度统计需人工授权,点击去授权</a> | |||||
| </div> | |||||
| <div> | |||||
| <a href="/admins/baidu_tongji_auth" onclick="this.href = '/admins/baidu_tongji_auth?code=' + document.getElementById('auth_code').value">2.获取百度统计授权码</a> | |||||
| <input name="code" id="auth_code" style="width: 380px" placeholder="请输入1.百度统计返回的code后,点击2.获取百度统计Token"/> | |||||
| </div> | |||||
| <% end %> | |||||
| @@ -1,6 +1,35 @@ | |||||
| <% define_admin_breadcrumbs do %> | <% define_admin_breadcrumbs do %> | ||||
| <% add_admin_breadcrumb('概览', admins_path) %> | <% add_admin_breadcrumb('概览', admins_path) %> | ||||
| <% end %> | <% end %> | ||||
| <div class="header bg-gradient-primary pb-8 pt-md-8"> | |||||
| <div class="container-fluid"> | |||||
| <div class="header-body"> | |||||
| <!-- Card stats --> | |||||
| <div class="row"> | |||||
| <%@subject_name.each_with_index do |subject, index| %> | |||||
| <div class="col-xl-3 col-lg-6" style="padding-bottom: 15px;"> | |||||
| <div class="card card-stats mb-4 mb-xl-0"> | |||||
| <div class="card-body"> | |||||
| <div class="row"> | |||||
| <div class="col"> | |||||
| <h5 class="card-title text-uppercase11 text-muted mb-0"><%=subject %></h5> | |||||
| <span class="h2 font-weight-bold mb-0"><%= @subject_data[index] %></span> | |||||
| </div> | |||||
| <div class="col-auto"> | |||||
| <div class="icon icon-shape rounded-circle shadow"> | |||||
| <i class="fa <%=@subject_icon[index] %>"></i> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <% end %> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="box admin-list-container project-language-list-container"> | <div class="box admin-list-container project-language-list-container"> | ||||
| <table class="table table-hover text-center subject-list-table"> | <table class="table table-hover text-center subject-list-table"> | ||||
| @@ -53,6 +82,7 @@ | |||||
| </tr> | </tr> | ||||
| </tbody> | </tbody> | ||||
| </table> | </table> | ||||
| <%= render partial: 'admins/dashboards/baidu_tongji' %> | |||||
| </div> | </div> | ||||
| <div id="project-language-modals"> | <div id="project-language-modals"> | ||||
| </div> | </div> | ||||
| @@ -795,6 +795,8 @@ Rails.application.routes.draw do | |||||
| namespace :admins do | namespace :admins do | ||||
| mount Sidekiq::Web => '/sidekiq' | mount Sidekiq::Web => '/sidekiq' | ||||
| get '/', to: 'dashboards#index' | get '/', to: 'dashboards#index' | ||||
| get '/baidu_tongji', to: 'dashboards#baidu_tongji' | |||||
| get '/baidu_tongji_auth', to: 'dashboards#baidu_tongji_auth' | |||||
| namespace :topic do | namespace :topic do | ||||
| resources :activity_forums | resources :activity_forums | ||||
| resources :banners | resources :banners | ||||
| @@ -11,4 +11,9 @@ delay_expired_issue: | |||||
| create_daily_project_statistics: | create_daily_project_statistics: | ||||
| cron: "0 1 * * *" | cron: "0 1 * * *" | ||||
| class: "DailyProjectStatisticsJob" | class: "DailyProjectStatisticsJob" | ||||
| queue: cache | |||||
| queue: cache | |||||
| daily_platform_statistics: | |||||
| cron: "0 1 * * *" | |||||
| class: "DailyPlatformStatisticsJob" | |||||
| queue: default | |||||
| @@ -0,0 +1,18 @@ | |||||
| class CreateDailyPlatformStatistics < ActiveRecord::Migration[5.2] | |||||
| def change | |||||
| create_table :daily_platform_statistics do |t| | |||||
| t.date :date | |||||
| t.index :date, unique: true | |||||
| t.bigint :pv, default: 0 | |||||
| t.bigint :visitor, default: 0 | |||||
| t.bigint :ip, default: 0 | |||||
| t.float :weekly_keep_rate, default: 0 | |||||
| t.float :source_through, default: 0 | |||||
| t.float :source_link, default: 0 | |||||
| t.float :source_search, default: 0 | |||||
| t.float :source_custom, default: 0 | |||||
| t.timestamps | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,5 @@ | |||||
| require 'rails_helper' | |||||
| RSpec.describe DailyPlatformStatistic, type: :model do | |||||
| pending "add some examples to (or delete) #{__FILE__}" | |||||
| end | |||||